Skip to content

Commit c935ffa

Browse files
committed
fix: suppress all notifications for subagent sessions
1 parent e84dc32 commit c935ffa

1 file changed

Lines changed: 45 additions & 25 deletions

File tree

src/index.ts

Lines changed: 45 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ import { truncate, extractTextFromParts } from "./utils"
1212
const PLUGIN_VERSION = "0.1.7"
1313
const NOTIFICATION_TITLE = "warp://cli-agent"
1414

15-
function sendPermissionNotification(perm: Permission, cwd: string): void {
16-
const sessionId = perm.sessionID
15+
function buildPermissionPayload(perm: Permission, cwd: string) {
1716
const toolName = perm.type || "unknown"
1817
const metadata = perm.metadata || {}
1918

@@ -34,12 +33,11 @@ function sendPermissionNotification(perm: Permission, cwd: string): void {
3433
summary += `: ${truncate(toolPreview, 120)}`
3534
}
3635

37-
const body = buildPayload("permission_request", sessionId, cwd, {
36+
return buildPayload("permission_request", perm.sessionID, cwd, {
3837
summary,
3938
tool_name: toolName,
4039
tool_input: metadata,
4140
})
42-
warpNotify(NOTIFICATION_TITLE, body)
4341
}
4442

4543
export const WarpPlugin: Plugin = async ({ client, directory }) => {
@@ -73,34 +71,49 @@ export const WarpPlugin: Plugin = async ({ client, directory }) => {
7371
console.error("[opencode-warp] failed to emit init log:", err)
7472
})
7573

74+
const subagentCache = new Map<string, boolean>()
75+
76+
async function isSubagentSession(sessionId?: string): Promise<boolean> {
77+
if (!sessionId) return false
78+
if (subagentCache.has(sessionId)) return subagentCache.get(sessionId)!
79+
try {
80+
const session = await client.session.get({
81+
path: { id: sessionId },
82+
})
83+
const result = !!session.data?.parentID
84+
subagentCache.set(sessionId, result)
85+
return result
86+
} catch {
87+
// If we can't fetch the session, fall through and notify anyway
88+
return false
89+
}
90+
}
91+
92+
async function maybeWarpNotify(sessionId: string | undefined, body: string): Promise<void> {
93+
if (await isSubagentSession(sessionId)) return
94+
warpNotify(NOTIFICATION_TITLE, body)
95+
}
96+
7697
return {
7798
event: async ({ event }: { event: Event }) => {
7899
const cwd = directory || ""
79100

80101
switch (event.type) {
81102
case "session.created": {
82-
const sessionId = event.properties.info.id
83-
const body = buildPayload("session_start", sessionId, cwd, {
103+
const info = event.properties.info
104+
if (info.parentID) return
105+
const body = buildPayload("session_start", info.id, cwd, {
84106
plugin_version: PLUGIN_VERSION,
85107
})
86-
warpNotify(NOTIFICATION_TITLE, body)
108+
await maybeWarpNotify(info.id, body)
87109
return
88110
}
89111

90112
case "session.idle": {
91113
const sessionId = event.properties.sessionID
92114

93-
if (sessionId) {
94-
try {
95-
const session = await client.session.get({
96-
path: { id: sessionId },
97-
})
98-
if (session.data?.parentID) return
99-
} catch {
100-
// If we can't fetch the session, fall through and notify anyway
101-
}
102-
}
103-
115+
// Fetch the conversation to extract last query and response
116+
// (port of on-stop.sh transcript parsing)
104117
let query = ""
105118
let response = ""
106119

@@ -138,28 +151,34 @@ export const WarpPlugin: Plugin = async ({ client, directory }) => {
138151
response: truncate(response, 200),
139152
transcript_path: "",
140153
})
141-
warpNotify(NOTIFICATION_TITLE, body)
154+
await maybeWarpNotify(sessionId, body)
142155
return
143156
}
144157

145158
case "permission.updated": {
146-
sendPermissionNotification(event.properties, cwd)
159+
await maybeWarpNotify(
160+
event.properties.sessionID,
161+
buildPermissionPayload(event.properties, cwd),
162+
)
147163
return
148164
}
149165

150166
case "permission.replied": {
151167
const { sessionID, response } = event.properties
152168
if (response === "reject") return
153169
const body = buildPayload("permission_replied", sessionID, cwd)
154-
warpNotify(NOTIFICATION_TITLE, body)
170+
await maybeWarpNotify(sessionID, body)
155171
return
156172
}
157173

158174
default: {
159175
// permission.asked is listed in the opencode docs but has no SDK type.
160176
// Handle it with the same logic as permission.updated.
161177
if ((event as any).type === "permission.asked") {
162-
sendPermissionNotification((event as any).properties, cwd)
178+
await maybeWarpNotify(
179+
(event as any).properties?.sessionID,
180+
buildPermissionPayload((event as any).properties, cwd),
181+
)
163182
}
164183
}
165184
}
@@ -171,13 +190,14 @@ export const WarpPlugin: Plugin = async ({ client, directory }) => {
171190
// completion notification.)
172191
"chat.message": async (input, output) => {
173192
const cwd = directory || ""
193+
174194
const queryText = extractTextFromParts(output.parts)
175195
if (!queryText) return
176196

177197
const body = buildPayload("prompt_submit", input.sessionID, cwd, {
178198
query: truncate(queryText, 200),
179199
})
180-
warpNotify(NOTIFICATION_TITLE, body)
200+
await maybeWarpNotify(input.sessionID, body)
181201
},
182202

183203
// Fires before a tool executes — used to detect the built-in
@@ -189,7 +209,7 @@ export const WarpPlugin: Plugin = async ({ client, directory }) => {
189209
const body = buildPayload("question_asked", input.sessionID, cwd, {
190210
tool_name: input.tool,
191211
})
192-
warpNotify(NOTIFICATION_TITLE, body)
212+
await maybeWarpNotify(input.sessionID, body)
193213
},
194214

195215
// Tool completion — fires after every tool call
@@ -201,7 +221,7 @@ export const WarpPlugin: Plugin = async ({ client, directory }) => {
201221
const body = buildPayload("tool_complete", sessionId, cwd, {
202222
tool_name: toolName,
203223
})
204-
warpNotify(NOTIFICATION_TITLE, body)
224+
await maybeWarpNotify(sessionId, body)
205225
},
206226
}
207227
}

0 commit comments

Comments
 (0)