From e84dc3200a6c9d2c2f924cef23dfac920a5186df Mon Sep 17 00:00:00 2001 From: Abdullah Alaqeel Date: Mon, 1 Jun 2026 14:04:58 +0300 Subject: [PATCH 1/3] fix: suppress stop notifications for subagent sessions Fetch the session on session.idle to check for parentID. If the session is a child (subagent) session, return early without sending a stop notification. Falls through on fetch failure so notifications are never silently dropped. Bump version to 0.1.7. --- package.json | 2 +- src/index.ts | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 99dbb95..9b06eb9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@warp-dot-dev/opencode-warp", - "version": "0.1.6", + "version": "0.1.7", "description": "Warp terminal integration for OpenCode — native notifications and more", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/src/index.ts b/src/index.ts index 1ad5f90..5544438 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,7 +9,7 @@ import { truncate, extractTextFromParts } from "./utils" // NOTE: do not `export` this constant — opencode's legacy plugin loader // treats every named export as a plugin function and throws if any export // is not a function ("Plugin export is not a function"). -const PLUGIN_VERSION = "0.1.6" +const PLUGIN_VERSION = "0.1.7" const NOTIFICATION_TITLE = "warp://cli-agent" function sendPermissionNotification(perm: Permission, cwd: string): void { @@ -90,8 +90,17 @@ export const WarpPlugin: Plugin = async ({ client, directory }) => { case "session.idle": { const sessionId = event.properties.sessionID - // Fetch the conversation to extract last query and response - // (port of on-stop.sh transcript parsing) + if (sessionId) { + try { + const session = await client.session.get({ + path: { id: sessionId }, + }) + if (session.data?.parentID) return + } catch { + // If we can't fetch the session, fall through and notify anyway + } + } + let query = "" let response = "" From c935ffa024ae5acd0c39ac0938fdd5f19dfa30a7 Mon Sep 17 00:00:00 2001 From: Abdullah Alaqeel Date: Tue, 2 Jun 2026 20:03:21 +0300 Subject: [PATCH 2/3] fix: suppress all notifications for subagent sessions --- src/index.ts | 70 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 25 deletions(-) diff --git a/src/index.ts b/src/index.ts index 5544438..c9ace13 100644 --- a/src/index.ts +++ b/src/index.ts @@ -12,8 +12,7 @@ import { truncate, extractTextFromParts } from "./utils" const PLUGIN_VERSION = "0.1.7" const NOTIFICATION_TITLE = "warp://cli-agent" -function sendPermissionNotification(perm: Permission, cwd: string): void { - const sessionId = perm.sessionID +function buildPermissionPayload(perm: Permission, cwd: string) { const toolName = perm.type || "unknown" const metadata = perm.metadata || {} @@ -34,12 +33,11 @@ function sendPermissionNotification(perm: Permission, cwd: string): void { summary += `: ${truncate(toolPreview, 120)}` } - const body = buildPayload("permission_request", sessionId, cwd, { + return buildPayload("permission_request", perm.sessionID, cwd, { summary, tool_name: toolName, tool_input: metadata, }) - warpNotify(NOTIFICATION_TITLE, body) } export const WarpPlugin: Plugin = async ({ client, directory }) => { @@ -73,34 +71,49 @@ export const WarpPlugin: Plugin = async ({ client, directory }) => { console.error("[opencode-warp] failed to emit init log:", err) }) + const subagentCache = new Map() + + async function isSubagentSession(sessionId?: string): Promise { + if (!sessionId) return false + if (subagentCache.has(sessionId)) return subagentCache.get(sessionId)! + try { + const session = await client.session.get({ + path: { id: sessionId }, + }) + const result = !!session.data?.parentID + subagentCache.set(sessionId, result) + return result + } catch { + // If we can't fetch the session, fall through and notify anyway + return false + } + } + + async function maybeWarpNotify(sessionId: string | undefined, body: string): Promise { + if (await isSubagentSession(sessionId)) return + warpNotify(NOTIFICATION_TITLE, body) + } + return { event: async ({ event }: { event: Event }) => { const cwd = directory || "" switch (event.type) { case "session.created": { - const sessionId = event.properties.info.id - const body = buildPayload("session_start", sessionId, cwd, { + const info = event.properties.info + if (info.parentID) return + const body = buildPayload("session_start", info.id, cwd, { plugin_version: PLUGIN_VERSION, }) - warpNotify(NOTIFICATION_TITLE, body) + await maybeWarpNotify(info.id, body) return } case "session.idle": { const sessionId = event.properties.sessionID - if (sessionId) { - try { - const session = await client.session.get({ - path: { id: sessionId }, - }) - if (session.data?.parentID) return - } catch { - // If we can't fetch the session, fall through and notify anyway - } - } - + // Fetch the conversation to extract last query and response + // (port of on-stop.sh transcript parsing) let query = "" let response = "" @@ -138,12 +151,15 @@ export const WarpPlugin: Plugin = async ({ client, directory }) => { response: truncate(response, 200), transcript_path: "", }) - warpNotify(NOTIFICATION_TITLE, body) + await maybeWarpNotify(sessionId, body) return } case "permission.updated": { - sendPermissionNotification(event.properties, cwd) + await maybeWarpNotify( + event.properties.sessionID, + buildPermissionPayload(event.properties, cwd), + ) return } @@ -151,7 +167,7 @@ export const WarpPlugin: Plugin = async ({ client, directory }) => { const { sessionID, response } = event.properties if (response === "reject") return const body = buildPayload("permission_replied", sessionID, cwd) - warpNotify(NOTIFICATION_TITLE, body) + await maybeWarpNotify(sessionID, body) return } @@ -159,7 +175,10 @@ export const WarpPlugin: Plugin = async ({ client, directory }) => { // permission.asked is listed in the opencode docs but has no SDK type. // Handle it with the same logic as permission.updated. if ((event as any).type === "permission.asked") { - sendPermissionNotification((event as any).properties, cwd) + await maybeWarpNotify( + (event as any).properties?.sessionID, + buildPermissionPayload((event as any).properties, cwd), + ) } } } @@ -171,13 +190,14 @@ export const WarpPlugin: Plugin = async ({ client, directory }) => { // completion notification.) "chat.message": async (input, output) => { const cwd = directory || "" + const queryText = extractTextFromParts(output.parts) if (!queryText) return const body = buildPayload("prompt_submit", input.sessionID, cwd, { query: truncate(queryText, 200), }) - warpNotify(NOTIFICATION_TITLE, body) + await maybeWarpNotify(input.sessionID, body) }, // Fires before a tool executes — used to detect the built-in @@ -189,7 +209,7 @@ export const WarpPlugin: Plugin = async ({ client, directory }) => { const body = buildPayload("question_asked", input.sessionID, cwd, { tool_name: input.tool, }) - warpNotify(NOTIFICATION_TITLE, body) + await maybeWarpNotify(input.sessionID, body) }, // Tool completion — fires after every tool call @@ -201,7 +221,7 @@ export const WarpPlugin: Plugin = async ({ client, directory }) => { const body = buildPayload("tool_complete", sessionId, cwd, { tool_name: toolName, }) - warpNotify(NOTIFICATION_TITLE, body) + await maybeWarpNotify(sessionId, body) }, } } From 8a67195fb64ebd4ac62b0bb77ff1651d4c65a728 Mon Sep 17 00:00:00 2001 From: harryalbert Date: Fri, 5 Jun 2026 10:52:51 -0400 Subject: [PATCH 3/3] bump package-lock.json --- package-lock.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9eaefed..56c152c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@warp-dot-dev/opencode-warp", - "version": "0.1.6", + "version": "0.1.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@warp-dot-dev/opencode-warp", - "version": "0.1.6", + "version": "0.1.7", "license": "MIT", "dependencies": { "undici-types": "^7.18.2",