From 6ffe837588606ff5ae1d60f162c6dfda6a9a9dd6 Mon Sep 17 00:00:00 2001 From: Andrew White Date: Sat, 21 Feb 2026 15:37:59 -0600 Subject: [PATCH 1/5] feat: add name parameter to session tool for custom session titles --- index.ts | 48 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/index.ts b/index.ts index cabfe6c..522c56a 100644 --- a/index.ts +++ b/index.ts @@ -321,6 +321,11 @@ ${agentList} If omitted, continues with current agent. +NAME PARAMETER (optional): + +Custom name for new or forked sessions. Helps identify sessions in the session list. +Only used in 'new' and 'fork' modes. Ignored in 'message' and 'compact' modes. + EXAMPLES: # COLLABORATE: Multi-agent problem solving @@ -331,13 +336,14 @@ EXAMPLES: }) # Plan reviews, responds, can pass back to build - # HANDOFF: Clean phase transition + # HANDOFF: Clean phase transition with named session session({ mode: "new", agent: "researcher", + name: "API Research", text: "Research best practices for API design" }) - # Fresh session, no baggage from previous implementation work + # Fresh session titled "API Research", no baggage from previous work # COMPRESS: Long conversation with handoff session({ @@ -347,18 +353,20 @@ EXAMPLES: }) # Compacts history, adds handoff context, plan agent responds - # PARALLELIZE: Try multiple approaches + # PARALLELIZE: Named forked sessions for comparison session({ mode: "fork", - agent: "build", + agent: "plan", + name: "Redux Architecture", text: "Implement using Redux" }) session({ mode: "fork", - agent: "build", + agent: "plan", + name: "Context API Architecture", text: "Implement using Context API" }) - # Two independent sessions, compare results + # Two named sessions for easy identification, compare results `, args: { @@ -374,6 +382,12 @@ EXAMPLES: .describe( "Primary agent name (e.g., 'build', 'plan') for agent switching", ), + name: tool.schema + .string() + .optional() + .describe( + "Custom name for the session (used in 'new' and 'fork' modes)", + ), }, async execute(args, toolCtx) { @@ -388,11 +402,12 @@ EXAMPLES: case "new": // Create session via SDK for agent control + const sessionTitle = args.name || (args.agent + ? `Session via ${args.agent}` + : "New session") const newSession = await ctx.client.session.create({ body: { - title: args.agent - ? `Session via ${args.agent}` - : "New session", + title: sessionTitle, }, }) @@ -405,7 +420,9 @@ EXAMPLES: }, }) - return `New session created with ${args.agent || "build"} agent (ID: ${newSession.data.id})` + return args.name + ? `New session "${args.name}" created with ${args.agent || "build"} agent (ID: ${newSession.data.id})` + : `New session created with ${args.agent || "build"} agent (ID: ${newSession.data.id})` case "compact": try { @@ -470,6 +487,13 @@ EXAMPLES: body: {}, }) + if (args.name) { + await ctx.client.session.update({ + path: { id: forkedSession.data.id }, + body: { title: args.name }, + }) + } + // Send new message in forked session await ctx.client.session.prompt({ path: { id: forkedSession.data.id }, @@ -479,7 +503,9 @@ EXAMPLES: }, }) - return `Forked session with ${args.agent || "build"} agent - history preserved (ID: ${forkedSession.data.id})` + return args.name + ? `Forked session "${args.name}" with ${args.agent || "build"} agent - history preserved (ID: ${forkedSession.data.id})` + : `Forked session with ${args.agent || "build"} agent - history preserved (ID: ${forkedSession.data.id})` } } catch (error) { const message = From 3089f76b9726b4b64956e58dd80d4d0a87f5b975 Mon Sep 17 00:00:00 2001 From: Andrew White Date: Sat, 21 Feb 2026 15:51:00 -0600 Subject: [PATCH 2/5] feat: add session_list tool with title support --- index.ts | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/index.ts b/index.ts index 522c56a..9f7b1a9 100644 --- a/index.ts +++ b/index.ts @@ -524,6 +524,98 @@ EXAMPLES: } }, }), + + session_list: tool({ + description: `List all OpenCode sessions with optional filtering. + +Returns a list of available sessions with metadata including title, message count, date range, and agents used. + +Arguments: +- limit (optional): Maximum number of sessions to return +- from_date (optional): Filter sessions from this date (ISO 8601 format) +- to_date (optional): Filter sessions until this date (ISO 8601 format) + +Example output: +| Session ID | Title | Messages | First | Last | Agents | +|------------|-------|----------|-------|------|--------| +| ses_abc123 | API Research | 45 | 2026-02-21 | 2026-02-21 | build, plan | +| ses_def456 | Auth Implementation | 12 | 2026-02-20 | 2026-02-20 | build |`, + + args: { + limit: tool.schema + .number() + .optional() + .describe("Maximum number of sessions to return"), + from_date: tool.schema + .string() + .optional() + .describe("Filter sessions from this date (ISO 8601 format)"), + to_date: tool.schema + .string() + .optional() + .describe("Filter sessions until this date (ISO 8601 format)"), + }, + + async execute(args) { + try { + const response = await ctx.client.session.list() + + if (!response.data) { + return "No sessions found." + } + + let sessions = response.data + + if (args.from_date) { + const fromDate = new Date(args.from_date).getTime() + sessions = sessions.filter((s) => { + const created = s.time?.created + ? new Date(s.time.created).getTime() + : 0 + return created >= fromDate + }) + } + + if (args.to_date) { + const toDate = new Date(args.to_date).getTime() + sessions = sessions.filter((s) => { + const created = s.time?.created + ? new Date(s.time.created).getTime() + : 0 + return created <= toDate + }) + } + + if (args.limit && args.limit > 0) { + sessions = sessions.slice(0, args.limit) + } + + if (sessions.length === 0) { + return "No sessions found matching criteria." + } + + const header = + "| Session ID | Title | Created |" + const separator = + "|------------|-------|---------|" + + const rows = sessions.map((s) => { + const id = s.id || "unknown" + const title = s.title || "Untitled" + const created = s.time?.created + ? new Date(s.time.created).toISOString().split("T")[0] + : "N/A" + return `| ${id} | ${title} | ${created} |` + }) + + return [header, separator, ...rows].join("\n") + } catch (error) { + const message = + error instanceof Error ? error.message : String(error) + return `Error listing sessions: ${message}` + } + }, + }), }, } } From db66a905da8bae47c22b3675c0343e937bcf51c4 Mon Sep 17 00:00:00 2001 From: Andrew White Date: Sat, 21 Feb 2026 16:03:10 -0600 Subject: [PATCH 3/5] feat: add Continue AI checks for PR review Adds 4 custom checks based on AGENTS.md conventions: - TypeScript type check - Code style review - Commit message format - Architecture review --- .continue/agents/architecture.check | 21 +++++++++++++++++++++ .continue/agents/code-style.check | 26 ++++++++++++++++++++++++++ .continue/agents/commit-format.check | 24 ++++++++++++++++++++++++ .continue/agents/typecheck.check | 20 ++++++++++++++++++++ 4 files changed, 91 insertions(+) create mode 100644 .continue/agents/architecture.check create mode 100644 .continue/agents/code-style.check create mode 100644 .continue/agents/commit-format.check create mode 100644 .continue/agents/typecheck.check diff --git a/.continue/agents/architecture.check b/.continue/agents/architecture.check new file mode 100644 index 0000000..20dc497 --- /dev/null +++ b/.continue/agents/architecture.check @@ -0,0 +1,21 @@ +name: Architecture Review +description: Ensure changes align with single-file plugin architecture +triggers: + - pull_request + +steps: + - name: Review architecture + prompt: | + Review the changes for architectural consistency: + + **Project constraints:** + - Single-file plugin architecture (index.ts is the main entry) + - Event-driven hooks (tool.execute.before, event listeners) + - Plugin should remain lightweight + + **Watch for:** + - Adding new files when the feature could fit in index.ts + - Introducing heavy dependencies + - Breaking the plugin's event-driven pattern + + If changes violate these constraints, suggest alternatives that align with the architecture. diff --git a/.continue/agents/code-style.check b/.continue/agents/code-style.check new file mode 100644 index 0000000..f8e1edc --- /dev/null +++ b/.continue/agents/code-style.check @@ -0,0 +1,26 @@ +name: Code Style Review +description: Enforce code style conventions from AGENTS.md +triggers: + - pull_request + +steps: + - name: Check code style + prompt: | + Review the changed TypeScript files against these conventions from AGENTS.md: + + **Imports:** + - Named imports preferred (not `import *`) + - Type imports must be separate: `import type { X }` + + **Naming:** + - camelCase for variables and functions + - PascalCase for types, interfaces, classes, and exports + + **Async:** + - Prefer async/await over raw promises + + **Error Handling:** + - Try-catch blocks with proper cleanup + - No silent failures (empty catch blocks) + + For each violation, leave a comment on the specific line explaining the issue and suggesting a fix. diff --git a/.continue/agents/commit-format.check b/.continue/agents/commit-format.check new file mode 100644 index 0000000..1098737 --- /dev/null +++ b/.continue/agents/commit-format.check @@ -0,0 +1,24 @@ +name: Commit Message Format +description: Ensure commit messages follow Conventional Commits +triggers: + - pull_request + +steps: + - name: Check commit messages + prompt: | + Review the commit messages in this PR for Conventional Commits format: + + **Required format:** `type: description` + + **Valid types:** + - `feat:` - New feature + - `fix:` - Bug fix + - `docs:` - Documentation changes + - `chore:` - Maintenance tasks + - `refactor:` - Code refactoring + - `test:` - Adding/modifying tests + - `perf:` - Performance improvements + + **Breaking changes:** Use `!` suffix (e.g., `feat!: change API`) + + If any commit message doesn't follow this format, leave a comment suggesting the correct format. diff --git a/.continue/agents/typecheck.check b/.continue/agents/typecheck.check new file mode 100644 index 0000000..aba0d48 --- /dev/null +++ b/.continue/agents/typecheck.check @@ -0,0 +1,20 @@ +name: TypeScript Type Check +description: Verify TypeScript compiles without errors +triggers: + - pull_request + +steps: + - name: Run typecheck + run: npm run typecheck + fail_on_error: true + + - name: Review for type issues + prompt: | + Review the changed files for TypeScript type issues: + + - Check for implicit `any` types that should be explicit + - Verify return types are consistent with function signatures + - Ensure type imports use `import type { X }` syntax + - Look for potential null/undefined issues + + If issues found, leave a comment on the specific line. From 636482d3facd16bb3eec719f60d6aa86196775e4 Mon Sep 17 00:00:00 2001 From: "continue[bot]" <230936708+continue[bot]@users.noreply.github.com> Date: Sat, 21 Feb 2026 22:10:11 +0000 Subject: [PATCH 4/5] refactor: clean up session_list tool description and inline constants Remove filler documentation that described non-existent columns (Messages, First, Last, Agents) and inline single-use header/separator variables. Generated with [Continue](https://continue.dev) Co-Authored-By: Continue Co-authored-by: andrew-white-1 --- index.ts | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/index.ts b/index.ts index 9f7b1a9..1f2808f 100644 --- a/index.ts +++ b/index.ts @@ -528,18 +528,7 @@ EXAMPLES: session_list: tool({ description: `List all OpenCode sessions with optional filtering. -Returns a list of available sessions with metadata including title, message count, date range, and agents used. - -Arguments: -- limit (optional): Maximum number of sessions to return -- from_date (optional): Filter sessions from this date (ISO 8601 format) -- to_date (optional): Filter sessions until this date (ISO 8601 format) - -Example output: -| Session ID | Title | Messages | First | Last | Agents | -|------------|-------|----------|-------|------|--------| -| ses_abc123 | API Research | 45 | 2026-02-21 | 2026-02-21 | build, plan | -| ses_def456 | Auth Implementation | 12 | 2026-02-20 | 2026-02-20 | build |`, +Returns a table of sessions with ID, title, and creation date.`, args: { limit: tool.schema @@ -594,11 +583,6 @@ Example output: return "No sessions found matching criteria." } - const header = - "| Session ID | Title | Created |" - const separator = - "|------------|-------|---------|" - const rows = sessions.map((s) => { const id = s.id || "unknown" const title = s.title || "Untitled" @@ -608,7 +592,7 @@ Example output: return `| ${id} | ${title} | ${created} |` }) - return [header, separator, ...rows].join("\n") + return ["| Session ID | Title | Created |", "|------------|-------|---------|", ...rows].join("\n") } catch (error) { const message = error instanceof Error ? error.message : String(error) From ffbed3ece79cf4914ac6efa06cf95b23ba572ef9 Mon Sep 17 00:00:00 2001 From: Andrew White Date: Fri, 24 Jul 2026 13:37:54 -0500 Subject: [PATCH 5/5] fix: log errors instead of silently swallowing prompt failures Two try/catch blocks around session.prompt calls silently discarded errors. Log them to console.error so operators can diagnose why messages are not being delivered after idle/compaction events. Signed-off-by: Andrew White --- index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.ts b/index.ts index 1f2808f..2111d7a 100644 --- a/index.ts +++ b/index.ts @@ -229,7 +229,7 @@ export const SessionPlugin: Plugin = async (ctx) => { }, }) } catch (error) { - // Silently fail - error handling could be added here if needed + console.error(`Failed to send pending message to session ${sessionID}:`, error) } return } @@ -284,7 +284,7 @@ export const SessionPlugin: Plugin = async (ctx) => { }, }) } catch (error) { - // Silently fail - error handling could be added here if needed + console.error(`Failed to send compacted message to session ${sessionID}:`, error) } } }