Skip to content

Commit 9023e74

Browse files
committed
🐛 fix(notification): fix message.updated handler and add event handler safety net
- Extract sessionId from info.sessionID instead of non-existent event.properties.sessionID - Remove invalid info.parts extraction (message.updated does not carry parts) - Add try/catch around entire event handler to prevent handler errors from blocking subsequent events
1 parent 2d29ab6 commit 9023e74

1 file changed

Lines changed: 98 additions & 99 deletions

File tree

src/index.ts

Lines changed: 98 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -64,126 +64,125 @@ export const WarpPlugin: Plugin = async ({ client, directory }) => {
6464
event: async ({ event }: { event: Event }) => {
6565
const cwd = directory || ""
6666

67-
switch (event.type) {
68-
case "session.created": {
69-
const sessionId = event.properties.info.id
70-
const body = buildPayload("session_start", sessionId, cwd, {
71-
plugin_version: PLUGIN_VERSION,
72-
})
73-
warpNotify(NOTIFICATION_TITLE, body)
74-
return
75-
}
76-
77-
case "session.idle": {
78-
const sessionId = event.properties.sessionID
79-
80-
let query = ""
81-
let response = ""
82-
83-
if (sessionId) {
84-
try {
85-
const result = await client.session.messages({
86-
path: { id: sessionId },
87-
})
88-
const messages = result.data
89-
90-
if (messages) {
91-
const reversed = [...messages].reverse()
92-
93-
const lastUser = reversed.find(
94-
(m) => m.info.role === "user",
95-
)
96-
if (lastUser) {
97-
query = extractTextFromParts(lastUser.parts)
98-
}
67+
try {
68+
switch (event.type) {
69+
case "session.created": {
70+
const sessionId = event.properties.info.id
71+
const body = buildPayload("session_start", sessionId, cwd, {
72+
plugin_version: PLUGIN_VERSION,
73+
})
74+
warpNotify(NOTIFICATION_TITLE, body)
75+
return
76+
}
9977

100-
const lastAssistant = reversed.find(
101-
(m) => m.info.role === "assistant",
102-
)
103-
if (lastAssistant) {
104-
response = extractTextFromParts(lastAssistant.parts)
78+
case "session.idle": {
79+
const sessionId = event.properties.sessionID
80+
81+
let query = ""
82+
let response = ""
83+
84+
if (sessionId) {
85+
try {
86+
const result = await client.session.messages({
87+
path: { id: sessionId },
88+
})
89+
const messages = result.data
90+
91+
if (messages) {
92+
const reversed = [...messages].reverse()
93+
94+
const lastUser = reversed.find(
95+
(m) => m.info.role === "user",
96+
)
97+
if (lastUser) {
98+
query = extractTextFromParts(lastUser.parts)
99+
}
100+
101+
const lastAssistant = reversed.find(
102+
(m) => m.info.role === "assistant",
103+
)
104+
if (lastAssistant) {
105+
response = extractTextFromParts(lastAssistant.parts)
106+
}
105107
}
108+
} catch {
109+
// If we can't fetch messages, send the notification without query/response
106110
}
107-
} catch {
108-
// If we can't fetch messages, send the notification without query/response
109111
}
112+
113+
const body = buildPayload("stop", sessionId, cwd, {
114+
query: truncate(query, 200),
115+
response: truncate(response, 200),
116+
transcript_path: "",
117+
})
118+
warpNotify(NOTIFICATION_TITLE, body)
119+
return
110120
}
111121

112-
const body = buildPayload("stop", sessionId, cwd, {
113-
query: truncate(query, 200),
114-
response: truncate(response, 200),
115-
transcript_path: "",
116-
})
117-
warpNotify(NOTIFICATION_TITLE, body)
118-
return
119-
}
122+
case "permission.updated": {
123+
sendPermissionNotification(event.properties, cwd)
124+
return
125+
}
120126

121-
case "permission.updated": {
122-
sendPermissionNotification(event.properties, cwd)
123-
return
124-
}
127+
case "permission.replied": {
128+
const { sessionID, response } = event.properties
129+
if (response === "reject") return
130+
const body = buildPayload("permission_replied", sessionID, cwd)
131+
warpNotify(NOTIFICATION_TITLE, body)
132+
return
133+
}
125134

126-
case "permission.replied": {
127-
const { sessionID, response } = event.properties
128-
if (response === "reject") return
129-
const body = buildPayload("permission_replied", sessionID, cwd)
130-
warpNotify(NOTIFICATION_TITLE, body)
131-
return
132-
}
135+
case "message.part.updated": {
136+
const part = (event.properties as { part: unknown }).part as {
137+
type: string
138+
tool?: string
139+
state?: { status: string }
140+
sessionID?: string
141+
}
142+
if (part?.type !== "tool" || !part?.state) return
133143

134-
case "message.part.updated": {
135-
const part = (event.properties as { part: unknown }).part as {
136-
type: string
137-
tool?: string
138-
state?: { status: string }
139-
callID?: string
140-
}
141-
if (part?.type !== "tool" || !part?.state) return
144+
const sessionId = part.sessionID || ""
142145

143-
const sessionId = (event.properties as { sessionID?: string }).sessionID || ""
146+
if (part.tool === "question" && part.state.status === "running") {
147+
const body = buildPayload("question_asked", sessionId, cwd, {
148+
tool_name: part.tool,
149+
})
150+
warpNotify(NOTIFICATION_TITLE, body)
151+
return
152+
}
144153

145-
if (part.tool === "question" && part.state.status === "running") {
146-
const body = buildPayload("question_asked", sessionId, cwd, {
147-
tool_name: part.tool,
148-
})
149-
warpNotify(NOTIFICATION_TITLE, body)
154+
if (part.state.status === "completed") {
155+
const body = buildPayload("tool_complete", sessionId, cwd, {
156+
tool_name: part.tool || "unknown",
157+
})
158+
warpNotify(NOTIFICATION_TITLE, body)
159+
return
160+
}
150161
return
151162
}
152163

153-
if (part.state.status === "completed") {
154-
const body = buildPayload("tool_complete", sessionId, cwd, {
155-
tool_name: part.tool || "unknown",
164+
case "message.updated": {
165+
const info = (event.properties as { info: { role?: string; sessionID?: string } }).info
166+
if (info?.role !== "user") return
167+
168+
const sessionId = info.sessionID || ""
169+
const body = buildPayload("prompt_submit", sessionId, cwd, {
170+
query: "",
156171
})
157172
warpNotify(NOTIFICATION_TITLE, body)
158173
return
159174
}
160-
return
161-
}
162-
163-
case "message.updated": {
164-
const info = (event.properties as { info: { role?: string; parts?: unknown[]; id?: string } }).info
165-
if (info?.role !== "user") return
166-
167-
const sessionId = (event.properties as { sessionID?: string }).sessionID || ""
168-
const queryText = extractTextFromParts(
169-
info.parts as unknown as Parameters<typeof extractTextFromParts>[0],
170-
)
171-
if (!queryText) return
172-
173-
const body = buildPayload("prompt_submit", sessionId, cwd, {
174-
query: truncate(queryText, 200),
175-
})
176-
warpNotify(NOTIFICATION_TITLE, body)
177-
return
178-
}
179175

180-
default: {
181-
// permission.asked is listed in the opencode docs but has no SDK type.
182-
// Handle it with the same logic as permission.updated.
183-
if ((event as any).type === "permission.asked") {
184-
sendPermissionNotification((event as any).properties, cwd)
176+
default: {
177+
// permission.asked is listed in the opencode docs but has no SDK type.
178+
// Handle it with the same logic as permission.updated.
179+
if ((event as any).type === "permission.asked") {
180+
sendPermissionNotification((event as any).properties, cwd)
181+
}
185182
}
186183
}
184+
} catch (err) {
185+
console.error(`[opencode-warp] event handler error for "${event.type}":`, err)
187186
}
188187
},
189188
}

0 commit comments

Comments
 (0)