@rrr2010/opencode-roundtable 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,20 +9,26 @@ executive summary.
9
9
 
10
10
  ## Installation
11
11
 
12
- ### Local (dev)
12
+ ### npm (recommended)
13
13
 
14
- ```bash
15
- cp src/roundtable.ts ~/.config/opencode/plugins/roundtable.ts
14
+ ```json
15
+ {
16
+ "plugin": ["@rrr2010/opencode-roundtable@latest"]
17
+ }
16
18
  ```
17
19
 
18
- Restart OpenCode. The plugin is auto-loaded from the plugins directory.
20
+ OpenCode auto-installs npm plugins on startup. No manual copy needed.
21
+
22
+ ### Local (dev)
19
23
 
20
- ### npm (coming soon)
24
+ ```bash
25
+ git clone https://github.com/opencode-ai/roundtable
26
+ cd roundtable
27
+ bun run build
28
+ npm link
29
+ ```
21
30
 
22
- ```json
23
- {
24
- "plugin": ["@your-ns/opencode-roundtable"]
25
- }
31
+ Then add `"@rrr2010/opencode-roundtable"` to your opencode.json `plugin` array.
26
32
  ```
27
33
 
28
34
  Add to `opencode.json` — OpenCode installs it with Bun on startup.
@@ -186,7 +192,6 @@ Include all round instructions in the `prompt` parameter — all agents see the
186
192
  ## Documentation
187
193
 
188
194
  - [docs/SPEC.md](./docs/SPEC.md) — Full technical specification
189
- - [docs/IMPLEMENTATION.md](./docs/IMPLEMENTATION.md) — Phased implementation plan
190
195
 
191
196
  ## Requirements
192
197
 
package/dist/index.js CHANGED
@@ -91,43 +91,31 @@ async function loadConfig(ctx) {
91
91
  }
92
92
 
93
93
  // src/state.ts
94
+ import { readFile as readFile2, writeFile as writeFile2, unlink, readdir, mkdir } from "fs/promises";
95
+ import { join as join2 } from "path";
96
+ import os2 from "os";
97
+ var statesDir = (() => {
98
+ const xdgConfigHome = process.env.XDG_CONFIG_HOME;
99
+ const base = xdgConfigHome ? join2(xdgConfigHome, "opencode") : join2(os2.homedir(), ".config", "opencode");
100
+ return join2(base, "roundtable-states");
101
+ })();
94
102
  var states = new Map;
95
103
  var timeoutHandles = new Map;
96
104
  var pendingResults = new Map;
97
- function serializeState(state) {
98
- const json = JSON.stringify(state);
99
- return `[ROUNDTABLE META — INTERNAL ORCHESTRATION DATA — IGNORE FOR ANALYSIS] ${json} [/ROUNDTABLE META]`;
105
+ function stateFilePath(sessionID) {
106
+ return join2(statesDir, `${sessionID}.json`);
100
107
  }
101
- function findSerializedState(messages) {
102
- let last = null;
103
- for (const msg of messages) {
104
- if (msg.info.role !== "user")
105
- continue;
106
- for (const part of msg.parts) {
107
- if (part.type === "text" && part.text.startsWith("[ROUNDTABLE META")) {
108
- last = part.text;
109
- }
110
- }
111
- }
112
- return last;
108
+ async function saveStateFile(state) {
109
+ try {
110
+ await mkdir(statesDir, { recursive: true });
111
+ } catch {}
112
+ const filePath = stateFilePath(state.sessionID);
113
+ await writeFile2(filePath, JSON.stringify(state, null, 2), "utf-8");
113
114
  }
114
- function deserializeState(raw) {
115
+ async function loadStateFile(sessionID) {
115
116
  try {
116
- const endTag = "[/ROUNDTABLE META]";
117
- const startIdx = raw.indexOf("[ROUNDTABLE META");
118
- if (startIdx === -1)
119
- return null;
120
- const closeBracket = raw.indexOf("]", startIdx);
121
- if (closeBracket === -1)
122
- return null;
123
- const contentStart = closeBracket + 1;
124
- const endIdx = raw.indexOf(endTag, contentStart);
125
- if (endIdx === -1)
126
- return null;
127
- const json = raw.slice(contentStart, endIdx).trim();
128
- if (!json)
129
- return null;
130
- const parsed = JSON.parse(json);
117
+ const content = await readFile2(stateFilePath(sessionID), "utf-8");
118
+ const parsed = JSON.parse(content);
131
119
  if (typeof parsed !== "object" || !parsed)
132
120
  return null;
133
121
  if (typeof parsed.sessionID !== "string")
@@ -161,6 +149,19 @@ function deserializeState(raw) {
161
149
  return null;
162
150
  }
163
151
  }
152
+ async function deleteStateFile(sessionID) {
153
+ try {
154
+ await unlink(stateFilePath(sessionID));
155
+ } catch {}
156
+ }
157
+ async function listStateFiles() {
158
+ try {
159
+ const entries = await readdir(statesDir);
160
+ return entries.filter((e) => e.endsWith(".json")).map((e) => e.replace(/\.json$/, ""));
161
+ } catch {
162
+ return [];
163
+ }
164
+ }
164
165
 
165
166
  // src/utils.ts
166
167
  function generateDefaultTitle(args) {
@@ -335,12 +336,26 @@ Continuation: ${extendPrompt}`;
335
336
  `);
336
337
  }
337
338
  async function scanOrphanRoundtables(ctx) {
339
+ const sessionIDs = await listStateFiles();
340
+ let loaded = 0;
341
+ let errors = 0;
342
+ for (const sid of sessionIDs) {
343
+ try {
344
+ const state = await loadStateFile(sid);
345
+ if (state) {
346
+ states.set(sid, state);
347
+ loaded++;
348
+ }
349
+ } catch {
350
+ errors++;
351
+ }
352
+ }
338
353
  await ctx.client.app.log({
339
354
  body: {
340
355
  service: "roundtable",
341
356
  level: "debug",
342
- message: "scanOrphanRoundtables initialized (Phase 1 no scanning yet; " + "full implementation in Phase 4)",
343
- extra: { phase: 1 }
357
+ message: `scanOrphanRoundtables: ${loaded} state(s) loaded, ${errors} error(s)`,
358
+ extra: { loaded, errors, total: sessionIDs.length }
344
359
  }
345
360
  });
346
361
  }
@@ -352,7 +367,6 @@ function buildAgentPrompt(state, agent) {
352
367
  const roundInfo = `Round ${state.currentRound + 1}/${state.totalRounds} | Current agent: ${agent}`;
353
368
  if (state.currentRound === 0 && state.currentAgentIndex === 0) {
354
369
  lines.push(`[System] You are participating in a roundtable debate. Agents (${agentList}) will discuss the topic below in ${state.totalRounds} round(s).`);
355
- lines.push(`[System] The [ROUNDTABLE META] block above is internal routing data — ignore it for all analysis. Focus only on the topic given in [Topic] below.`);
356
370
  lines.push(`[Topic] ${state.prompt}`);
357
371
  lines.push("");
358
372
  }
@@ -401,10 +415,7 @@ async function startNewRoundtable(ctx, args, toolCtx) {
401
415
  };
402
416
  states.set(sessionID, state);
403
417
  try {
404
- await ctx.client.session.prompt({
405
- path: { id: sessionID },
406
- body: { noReply: true, parts: [{ type: "text", text: serializeState(state) }] }
407
- });
418
+ await saveStateFile(state);
408
419
  await sendToAgent(ctx, state);
409
420
  await ctx.client.session.prompt({
410
421
  path: { id: parentSessionID },
@@ -528,10 +539,7 @@ async function finalizeRoundtable(ctx, state) {
528
539
  body: { title: `(Roundtable) - ${shortPrompt} · CONCLUDED` }
529
540
  });
530
541
  try {
531
- await ctx.client.session.prompt({
532
- path: { id: sessionID },
533
- body: { noReply: true, parts: [{ type: "text", text: serializeState(state) }] }
534
- });
542
+ await saveStateFile(state);
535
543
  } catch {}
536
544
  await ctx.client.tui.showToast({
537
545
  body: { message: "Roundtable concluded", variant: "success" }
@@ -569,7 +577,7 @@ async function processNextTurn(ctx, state) {
569
577
  const userMsgs = messages.filter((m) => m.info.role === "user");
570
578
  for (const msg of userMsgs) {
571
579
  for (const part of msg.parts) {
572
- if (part.type === "text" && !part.text.includes("[ROUNDTABLE META")) {
580
+ if (part.type === "text") {
573
581
  if (!state.userInterjections.includes(part.text)) {
574
582
  state.userInterjections.push(part.text);
575
583
  }
@@ -597,6 +605,7 @@ async function processNextTurn(ctx, state) {
597
605
  hasError: response === null
598
606
  };
599
607
  state.history.push(entry);
608
+ await saveStateFile(state);
600
609
  await ctx.client.app.log({
601
610
  body: {
602
611
  service: "roundtable",
@@ -657,6 +666,7 @@ async function processNextTurn(ctx, state) {
657
666
  toolCalls: [],
658
667
  hasError: summary === null
659
668
  });
669
+ await saveStateFile(state);
660
670
  state.phase = "done";
661
671
  await finalizeRoundtable(ctx, state);
662
672
  }
@@ -664,6 +674,7 @@ async function processNextTurn(ctx, state) {
664
674
  async function handleAgentError(ctx, state, event) {
665
675
  if (state.phase === "observing" || state.phase === "done") {
666
676
  state.phase = "aborted";
677
+ await saveStateFile(state);
667
678
  await finalizeRoundtable(ctx, state);
668
679
  return;
669
680
  }
@@ -694,6 +705,7 @@ async function handleAgentError(ctx, state, event) {
694
705
  }
695
706
  });
696
707
  } catch {}
708
+ await saveStateFile(state);
697
709
  await sendToAgent(ctx, state);
698
710
  } else if (state.currentRound + 1 < state.totalRounds) {
699
711
  state.currentRound++;
@@ -708,6 +720,7 @@ async function handleAgentError(ctx, state, event) {
708
720
  }
709
721
  });
710
722
  } catch {}
723
+ await saveStateFile(state);
711
724
  await sendToAgent(ctx, state);
712
725
  } else {
713
726
  state.phase = "aborted";
@@ -716,6 +729,7 @@ async function handleAgentError(ctx, state, event) {
716
729
  body: { message: "All agents failed — roundtable aborted", variant: "error" }
717
730
  });
718
731
  } catch {}
732
+ await saveStateFile(state);
719
733
  await finalizeRoundtable(ctx, state);
720
734
  }
721
735
  }
@@ -725,6 +739,7 @@ async function handleSessionDeleted(ctx, state, deletedSessionID) {
725
739
  clearTimeout(handle);
726
740
  timeoutHandles.delete(state.sessionID);
727
741
  }
742
+ await deleteStateFile(state.sessionID);
728
743
  if (deletedSessionID === state.sessionID) {
729
744
  state.phase = "aborted";
730
745
  const partialSummary = buildConsolidatedSummary(state);
@@ -780,47 +795,15 @@ async function extendRoundtable(ctx, args, _toolCtx) {
780
795
  } catch {
781
796
  return `Error: Session #${sessionID} not found or inaccessible. Cannot extend.`;
782
797
  }
783
- let messagesData;
784
- try {
785
- messagesData = await ctx.client.session.messages({ path: { id: sessionID } });
786
- } catch {
787
- return `Error: Could not read messages from session #${sessionID}`;
788
- }
789
- const serializedRaw = findSerializedState(messagesData.data);
790
- if (!serializedRaw) {
798
+ const originalState = await loadStateFile(sessionID);
799
+ if (!originalState) {
791
800
  return [
792
- `Error: No roundtable state found in session #${sessionID}.`,
793
- "This session is not a roundtable or the state was lost during compaction."
801
+ `Error: No roundtable state found for session #${sessionID}.`,
802
+ "This session is not a roundtable or the state file was deleted."
794
803
  ].join(`
795
804
  `);
796
805
  }
797
- const originalState = deserializeState(serializedRaw);
798
- if (!originalState) {
799
- return `Error: Corrupt roundtable state in session #${sessionID}. Cannot extend.`;
800
- }
801
- if (originalState.phase === "done") {} else if (originalState.phase === "active") {
802
- const assistantCount = messagesData.data.filter((m) => m.info.role === "assistant").length;
803
- const expectedAssistantCount = originalState.totalRounds * originalState.agents.length + 1;
804
- if (assistantCount >= expectedAssistantCount) {
805
- originalState.phase = "done";
806
- try {
807
- await ctx.client.app.log({
808
- body: {
809
- service: "roundtable",
810
- level: "info",
811
- message: `Recovered stuck session #${sessionID}: phase was active but ${assistantCount} assistant msgs suggest debate completed.`,
812
- extra: { sessionID, assistantCount, expectedAssistantCount }
813
- }
814
- });
815
- } catch {}
816
- } else {
817
- return [
818
- `Error: Roundtable #${sessionID} is still active (phase: ${originalState.phase}).`,
819
- "Cannot extend until the roundtable concludes."
820
- ].join(`
821
- `);
822
- }
823
- } else {
806
+ if (originalState.phase !== "done") {
824
807
  return [
825
808
  `Error: Roundtable #${sessionID} is in state "${originalState.phase}" and cannot be extended.`
826
809
  ].join(`
@@ -866,10 +849,7 @@ async function extendRoundtable(ctx, args, _toolCtx) {
866
849
  };
867
850
  states.set(sessionID, newState);
868
851
  try {
869
- await ctx.client.session.prompt({
870
- path: { id: sessionID },
871
- body: { noReply: true, parts: [{ type: "text", text: serializeState(newState) }] }
872
- });
852
+ await saveStateFile(newState);
873
853
  const agentList = originalState.agents.join(" vs ");
874
854
  await ctx.client.session.update({
875
855
  path: { id: sessionID },
@@ -954,11 +934,13 @@ var RoundtablePlugin = async (ctx) => {
954
934
 
955
935
  ` + "Note: this tool injects system-level prompts into each agent's context during " + `the debate (role-setting, topic, turn routing, and lifecycle signals).
956
936
 
937
+ ` + "IMPORTANT: This tool requires 2+ agents. For single-agent tasks, use a regular " + `session prompt instead — do NOT use roundtable.
938
+
957
939
  ` + "Choosing agents: select agents based on their expertise (e.g., pm for product decisions, " + "dev for technical trade-offs, rv for code review). You can also specify in the prompt " + `what each agent should focus on (e.g., 'pm: focus on cost; dev: focus on maintainability').
958
940
 
959
941
  ` + "Multiple rounds: for complex topics, use 2+ rounds and INCLUDE per-round focus " + "instructions IN the prompt itself (e.g., prompt: 'Round 1: list pros. Round 2: " + "list cons. Round 3: propose an implementation plan'). This way all agents see " + "the full agenda. The default is 1 round.",
960
942
  args: {
961
- agents: tool.schema.array(tool.schema.string()).min(2).describe("Agent names in speaking order (minimum 2). Choose agents based on " + 'their expertise — each brings a different perspective. Example: ["pm", "dev", "rv"]'),
943
+ agents: tool.schema.array(tool.schema.string()).min(2).describe("Agent names in speaking order (minimum 2). For single-agent tasks, use a regular " + "session — do NOT use roundtable. Choose agents based on their expertise — " + 'each brings a different perspective. Example: ["pm", "dev", "rv"]'),
962
944
  prompt: tool.schema.string().describe("Topic or challenge for the agents to debate. For multi-round debates, " + "include per-round instructions here (e.g., 'Round 1: pros. Round 2: cons. " + "Round 3: plan.'). All agents will see this and follow the round structure."),
963
945
  rounds: tool.schema.number().min(1).max(50).describe("Number of complete rounds (each round = all agents speak once). " + "Default: 1. Max: 50. For complex topics with 2+ rounds, include per-round focus " + "instructions in the prompt parameter so all agents see the agenda."),
964
946
  observer: tool.schema.string().optional().describe("Agent name for final consolidation. The observer does not debate — it " + "summarizes after all rounds. Omit to use the built-in observer."),
@@ -1028,5 +1010,5 @@ export {
1028
1010
  RoundtablePlugin
1029
1011
  };
1030
1012
 
1031
- //# debugId=3293C14B588953DF64756E2164756E21
1013
+ //# debugId=BEEF18A38922C86164756E2164756E21
1032
1014
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -2,14 +2,14 @@
2
2
  "version": 3,
3
3
  "sources": ["..\\index.ts", "..\\src\\config.ts", "..\\src\\state.ts", "..\\src\\utils.ts", "..\\src\\prompts.ts", "..\\src\\handlers.ts"],
4
4
  "sourcesContent": [
5
- "import { type Plugin, type PluginInput, tool } from \"@opencode-ai/plugin\"\nimport type { RoundtableArgs, Event as RoundtableEvent } from \"./src/types\"\nimport { loadConfig } from \"./src/config\"\nimport { states, timeoutHandles, pendingResults } from \"./src/state\"\nimport { getSessionIdFromEvent, validateAgents, scanOrphanRoundtables } from \"./src/utils\"\nimport { startNewRoundtable, extendRoundtable, processNextTurn, handleAgentError, handleSessionDeleted } from \"./src/handlers\"\n\nexport const RoundtablePlugin: Plugin = async (ctx) => {\n try {\n await loadConfig(ctx)\n } catch { /* best-effort */ }\n\n try {\n await scanOrphanRoundtables(ctx)\n } catch (err) {\n try {\n await ctx.client.app.log({\n body: {\n service: \"roundtable\",\n level: \"error\",\n message: `scanOrphanRoundtables failed: ${err instanceof Error ? err.message : String(err)}`,\n },\n })\n } catch { /* best-effort */ }\n }\n\n return {\n event: async ({ event }: { event: { type: string; properties: Record<string, unknown> } }) => {\n const sessionID = getSessionIdFromEvent(event)\n if (!sessionID || !states.has(sessionID)) return\n\n const state = states.get(sessionID)!\n\n switch (event.type) {\n case \"session.idle\": {\n const handle = timeoutHandles.get(sessionID)\n if (handle) { clearTimeout(handle); timeoutHandles.delete(sessionID) }\n await processNextTurn(ctx, state)\n break\n }\n case \"session.error\": {\n await handleAgentError(ctx, state, event as RoundtableEvent)\n break\n }\n case \"session.deleted\": {\n const deletedID = (event.properties.info as { id?: string })?.id\n if (deletedID) await handleSessionDeleted(ctx, state, deletedID)\n break\n }\n }\n },\n\n \"experimental.session.compacting\": async (\n _input: { sessionID: string },\n _output: { context: string[]; prompt?: string },\n ) => {\n // Phase 4: will re-inject [ROUNDTABLE META] state during compaction\n },\n\n tool: {\n roundtable: tool({\n description:\n \"Starts a multi-agent roundtable debate where agents discuss a topic turn by turn. \" +\n \"After all rounds, a built-in observer consolidates the discussion into an executive summary.\\n\\n\" +\n \"Returns an object with { sessionID, summary } after the debate concludes.\\n\\n\" +\n \"Note: this tool injects system-level prompts into each agent's context during \" +\n \"the debate (role-setting, topic, turn routing, and lifecycle signals).\\n\\n\" +\n \"Choosing agents: select agents based on their expertise (e.g., pm for product decisions, \" +\n \"dev for technical trade-offs, rv for code review). You can also specify in the prompt \" +\n \"what each agent should focus on (e.g., 'pm: focus on cost; dev: focus on maintainability').\\n\\n\" +\n \"Multiple rounds: for complex topics, use 2+ rounds and INCLUDE per-round focus \" +\n \"instructions IN the prompt itself (e.g., prompt: 'Round 1: list pros. Round 2: \" +\n \"list cons. Round 3: propose an implementation plan'). This way all agents see \" +\n \"the full agenda. The default is 1 round.\",\n\n args: {\n agents: tool.schema\n .array(tool.schema.string())\n .min(2)\n .describe(\n \"Agent names in speaking order (minimum 2). Choose agents based on \" +\n \"their expertise — each brings a different perspective. Example: [\\\"pm\\\", \\\"dev\\\", \\\"rv\\\"]\",\n ),\n prompt: tool.schema\n .string()\n .describe(\n \"Topic or challenge for the agents to debate. For multi-round debates, \" +\n \"include per-round instructions here (e.g., 'Round 1: pros. Round 2: cons. \" +\n \"Round 3: plan.'). All agents will see this and follow the round structure.\",\n ),\n rounds: tool.schema\n .number()\n .min(1)\n .max(50)\n .describe(\n \"Number of complete rounds (each round = all agents speak once). \" +\n \"Default: 1. Max: 50. For complex topics with 2+ rounds, include per-round focus \" +\n \"instructions in the prompt parameter so all agents see the agenda.\",\n ),\n observer: tool.schema\n .string()\n .optional()\n .describe(\n \"Agent name for final consolidation. The observer does not debate — it \" +\n \"summarizes after all rounds. Omit to use the built-in observer.\",\n ),\n sessionID: tool.schema\n .string()\n .optional()\n .describe(\n \"Session ID (format: ses_xxxx) from a previous roundtable call to \" +\n \"continue a concluded debate. Omit this parameter and pass agents + \" +\n \"prompt to start a fresh debate.\",\n ),\n title: tool.schema\n .string()\n .optional()\n .describe(\n \"Custom title for the session (max 200 chars). If omitted, auto-generated \" +\n \"as \\\"(Roundtable) - {first 80 chars of prompt, truncated at word boundary}\\\".\",\n ),\n },\n\n async execute(args: Record<string, unknown>, toolCtx: { sessionID: string }) {\n try {\n const rounds = (args.rounds as number) ?? 1\n\n if (args.sessionID) {\n if (typeof args.sessionID !== \"string\" || !args.sessionID.trim()) {\n return \"Error: sessionID is empty\"\n }\n if (args.agents) {\n return \"Error: pass either sessionID (extend) or agents (new), not both\"\n }\n const sid = await extendRoundtable(ctx, args as unknown as RoundtableArgs, toolCtx)\n if (sid.startsWith(\"Error:\") || sid.startsWith(\"Invalid\")) return sid\n const result = await new Promise<string>((resolve) => pendingResults.set(sid, { resolve }))\n return result\n }\n\n if (!args.agents || !Array.isArray(args.agents) || args.agents.length < 2) {\n return \"Error: 'agents' with at least 2 names is required\"\n }\n const validation = await validateAgents(ctx, args.agents as string[])\n if (!validation.valid) {\n const available = validation.available.map((a) => a.name).join(\", \")\n return [\"Invalid agent configuration:\", ...validation.errors.map((e) => ` - ${e}`), `Available agents: ${available}`].join(\"\\n\")\n }\n if (rounds > 50) {\n return \"Error: Maximum 50 rounds allowed\"\n }\n\n const sid = await startNewRoundtable(ctx, { ...args, rounds } as RoundtableArgs, toolCtx)\n const result = await new Promise<string>((resolve) => pendingResults.set(sid, { resolve }))\n return result\n } catch (err) {\n await ctx.client.app.log({\n body: {\n service: \"roundtable\",\n level: \"error\",\n message: `roundtable.execute error: ${err instanceof Error ? err.stack || err.message : String(err)}`,\n },\n })\n return `Error: ${err instanceof Error ? err.message : String(err)}`\n }\n },\n }),\n\n available_agents: tool({\n description:\n \"Lists all configured agents and their roles. \" +\n \"Returns a formatted list of agent names (e.g., \\\"Available agents: pm, dev, rv\\\"). \" +\n \"Use this to choose which agents should participate in a roundtable \" +\n \"based on their descriptions — then call roundtable() with your selection.\",\n\n args: {},\n\n async execute() {\n try {\n const result = await ctx.client.app.agents()\n const names = result.data.map((a: { name: string }) => a.name)\n return `Available agents: ${names.join(\", \")}`\n } catch {\n return \"Error: Could not fetch agent list. The server might not be ready.\"\n }\n },\n }),\n },\n } as unknown as ReturnType<Plugin>\n}\n",
5
+ "import { type Plugin, type PluginInput, tool } from \"@opencode-ai/plugin\"\nimport type { RoundtableArgs, Event as RoundtableEvent } from \"./src/types\"\nimport { loadConfig } from \"./src/config\"\nimport { states, timeoutHandles, pendingResults } from \"./src/state\"\nimport { getSessionIdFromEvent, validateAgents, scanOrphanRoundtables } from \"./src/utils\"\nimport { startNewRoundtable, extendRoundtable, processNextTurn, handleAgentError, handleSessionDeleted } from \"./src/handlers\"\n\nexport const RoundtablePlugin: Plugin = async (ctx) => {\n try {\n await loadConfig(ctx)\n } catch { /* best-effort */ }\n\n try {\n await scanOrphanRoundtables(ctx)\n } catch (err) {\n try {\n await ctx.client.app.log({\n body: {\n service: \"roundtable\",\n level: \"error\",\n message: `scanOrphanRoundtables failed: ${err instanceof Error ? err.message : String(err)}`,\n },\n })\n } catch { /* best-effort */ }\n }\n\n return {\n event: async ({ event }: { event: { type: string; properties: Record<string, unknown> } }) => {\n const sessionID = getSessionIdFromEvent(event)\n if (!sessionID || !states.has(sessionID)) return\n\n const state = states.get(sessionID)!\n\n switch (event.type) {\n case \"session.idle\": {\n const handle = timeoutHandles.get(sessionID)\n if (handle) { clearTimeout(handle); timeoutHandles.delete(sessionID) }\n await processNextTurn(ctx, state)\n break\n }\n case \"session.error\": {\n await handleAgentError(ctx, state, event as RoundtableEvent)\n break\n }\n case \"session.deleted\": {\n const deletedID = (event.properties.info as { id?: string })?.id\n if (deletedID) await handleSessionDeleted(ctx, state, deletedID)\n break\n }\n }\n },\n\n \"experimental.session.compacting\": async (\n _input: { sessionID: string },\n _output: { context: string[]; prompt?: string },\n ) => {\n // Phase 4: will re-inject [ROUNDTABLE META] state during compaction\n },\n\n tool: {\n roundtable: tool({\n description:\n \"Starts a multi-agent roundtable debate where agents discuss a topic turn by turn. \" +\n \"After all rounds, a built-in observer consolidates the discussion into an executive summary.\\n\\n\" +\n \"Returns an object with { sessionID, summary } after the debate concludes.\\n\\n\" +\n \"Note: this tool injects system-level prompts into each agent's context during \" +\n \"the debate (role-setting, topic, turn routing, and lifecycle signals).\\n\\n\" +\n \"IMPORTANT: This tool requires 2+ agents. For single-agent tasks, use a regular \" +\n \"session prompt instead — do NOT use roundtable.\\n\\n\" +\n \"Choosing agents: select agents based on their expertise (e.g., pm for product decisions, \" +\n \"dev for technical trade-offs, rv for code review). You can also specify in the prompt \" +\n \"what each agent should focus on (e.g., 'pm: focus on cost; dev: focus on maintainability').\\n\\n\" +\n \"Multiple rounds: for complex topics, use 2+ rounds and INCLUDE per-round focus \" +\n \"instructions IN the prompt itself (e.g., prompt: 'Round 1: list pros. Round 2: \" +\n \"list cons. Round 3: propose an implementation plan'). This way all agents see \" +\n \"the full agenda. The default is 1 round.\",\n\n args: {\n agents: tool.schema\n .array(tool.schema.string())\n .min(2)\n .describe(\n \"Agent names in speaking order (minimum 2). For single-agent tasks, use a regular \" +\n \"session — do NOT use roundtable. Choose agents based on their expertise — \" +\n \"each brings a different perspective. Example: [\\\"pm\\\", \\\"dev\\\", \\\"rv\\\"]\",\n ),\n prompt: tool.schema\n .string()\n .describe(\n \"Topic or challenge for the agents to debate. For multi-round debates, \" +\n \"include per-round instructions here (e.g., 'Round 1: pros. Round 2: cons. \" +\n \"Round 3: plan.'). All agents will see this and follow the round structure.\",\n ),\n rounds: tool.schema\n .number()\n .min(1)\n .max(50)\n .describe(\n \"Number of complete rounds (each round = all agents speak once). \" +\n \"Default: 1. Max: 50. For complex topics with 2+ rounds, include per-round focus \" +\n \"instructions in the prompt parameter so all agents see the agenda.\",\n ),\n observer: tool.schema\n .string()\n .optional()\n .describe(\n \"Agent name for final consolidation. The observer does not debate — it \" +\n \"summarizes after all rounds. Omit to use the built-in observer.\",\n ),\n sessionID: tool.schema\n .string()\n .optional()\n .describe(\n \"Session ID (format: ses_xxxx) from a previous roundtable call to \" +\n \"continue a concluded debate. Omit this parameter and pass agents + \" +\n \"prompt to start a fresh debate.\",\n ),\n title: tool.schema\n .string()\n .optional()\n .describe(\n \"Custom title for the session (max 200 chars). If omitted, auto-generated \" +\n \"as \\\"(Roundtable) - {first 80 chars of prompt, truncated at word boundary}\\\".\",\n ),\n },\n\n async execute(args: Record<string, unknown>, toolCtx: { sessionID: string }) {\n try {\n const rounds = (args.rounds as number) ?? 1\n\n if (args.sessionID) {\n if (typeof args.sessionID !== \"string\" || !args.sessionID.trim()) {\n return \"Error: sessionID is empty\"\n }\n if (args.agents) {\n return \"Error: pass either sessionID (extend) or agents (new), not both\"\n }\n const sid = await extendRoundtable(ctx, args as unknown as RoundtableArgs, toolCtx)\n if (sid.startsWith(\"Error:\") || sid.startsWith(\"Invalid\")) return sid\n const result = await new Promise<string>((resolve) => pendingResults.set(sid, { resolve }))\n return result\n }\n\n if (!args.agents || !Array.isArray(args.agents) || args.agents.length < 2) {\n return \"Error: 'agents' with at least 2 names is required\"\n }\n const validation = await validateAgents(ctx, args.agents as string[])\n if (!validation.valid) {\n const available = validation.available.map((a) => a.name).join(\", \")\n return [\"Invalid agent configuration:\", ...validation.errors.map((e) => ` - ${e}`), `Available agents: ${available}`].join(\"\\n\")\n }\n if (rounds > 50) {\n return \"Error: Maximum 50 rounds allowed\"\n }\n\n const sid = await startNewRoundtable(ctx, { ...args, rounds } as RoundtableArgs, toolCtx)\n const result = await new Promise<string>((resolve) => pendingResults.set(sid, { resolve }))\n return result\n } catch (err) {\n await ctx.client.app.log({\n body: {\n service: \"roundtable\",\n level: \"error\",\n message: `roundtable.execute error: ${err instanceof Error ? err.stack || err.message : String(err)}`,\n },\n })\n return `Error: ${err instanceof Error ? err.message : String(err)}`\n }\n },\n }),\n\n available_agents: tool({\n description:\n \"Lists all configured agents and their roles. \" +\n \"Returns a formatted list of agent names (e.g., \\\"Available agents: pm, dev, rv\\\"). \" +\n \"Use this to choose which agents should participate in a roundtable \" +\n \"based on their descriptions — then call roundtable() with your selection.\",\n\n args: {},\n\n async execute() {\n try {\n const result = await ctx.client.app.agents()\n const names = result.data.map((a: { name: string }) => a.name)\n return `Available agents: ${names.join(\", \")}`\n } catch {\n return \"Error: Could not fetch agent list. The server might not be ready.\"\n }\n },\n }),\n },\n } as unknown as ReturnType<Plugin>\n}\n",
6
6
  "import { readFile, writeFile } from \"fs/promises\"\nimport { join } from \"path\"\nimport os from \"os\"\nimport type { PluginConfig } from \"./types\"\nimport type { PluginInput } from \"@opencode-ai/plugin\"\n\nconst configDir = (() => {\n const xdgConfigHome = process.env.XDG_CONFIG_HOME\n if (xdgConfigHome) return join(xdgConfigHome, \"opencode\")\n return join(os.homedir(), \".config\", \"opencode\")\n})()\n\nconst configPath = join(configDir, \"roundtable.json\")\n\nconst configSchemaUrl =\n \"https://raw.githubusercontent.com/opencode-ai/roundtable/main/docs/roundtable.schema.json\"\n\nconst DEFAULT_CONFIG: PluginConfig = {\n defaultTimeoutMs: 300_000,\n loopSimilarityThreshold: 0.85,\n toolOutputPreviewMax: 500,\n defaultObserverPrompt: [\n \"You are an impartial roundtable observer.\",\n \"Consolidate the debate below into:\",\n \"\",\n \"1. **Executive summary** (2-3 sentences)\",\n \"2. **Key points** raised by each participant\",\n \"3. **Decisions or convergences** reached\",\n \"4. **Remaining open questions**\",\n \"5. **Suggested next steps**\",\n ].join(\"\\n\"),\n maxRounds: 10,\n}\n\nlet config: PluginConfig = { ...DEFAULT_CONFIG }\n\nexport function getConfig(): PluginConfig {\n return config\n}\n\nfunction validateConfig(raw: Record<string, unknown>): PluginConfig {\n return {\n defaultTimeoutMs:\n typeof raw.defaultTimeoutMs === \"number\" && raw.defaultTimeoutMs >= 30_000\n ? raw.defaultTimeoutMs\n : DEFAULT_CONFIG.defaultTimeoutMs,\n loopSimilarityThreshold:\n typeof raw.loopSimilarityThreshold === \"number\" &&\n raw.loopSimilarityThreshold >= 0 &&\n raw.loopSimilarityThreshold <= 1\n ? raw.loopSimilarityThreshold\n : DEFAULT_CONFIG.loopSimilarityThreshold,\n toolOutputPreviewMax:\n typeof raw.toolOutputPreviewMax === \"number\" && raw.toolOutputPreviewMax >= 100\n ? raw.toolOutputPreviewMax\n : DEFAULT_CONFIG.toolOutputPreviewMax,\n defaultObserverPrompt:\n typeof raw.defaultObserverPrompt === \"string\" && raw.defaultObserverPrompt.length > 0\n ? raw.defaultObserverPrompt\n : DEFAULT_CONFIG.defaultObserverPrompt,\n maxRounds:\n typeof raw.maxRounds === \"number\" && raw.maxRounds >= 1\n ? raw.maxRounds\n : DEFAULT_CONFIG.maxRounds,\n }\n}\n\nexport async function loadConfig(ctx: PluginInput): Promise<void> {\n try {\n const content = await readFile(configPath, \"utf-8\")\n const raw = JSON.parse(content)\n if (typeof raw !== \"object\" || !raw) throw new Error(\"Invalid config format\")\n config = validateConfig(raw as Record<string, unknown>)\n await ctx.client.app.log({\n body: {\n service: \"roundtable\",\n level: \"info\",\n message: \"Configuration loaded\",\n extra: { configPath },\n },\n })\n } catch (err) {\n if (\n typeof err === \"object\" &&\n err !== null &&\n \"code\" in err &&\n (err as { code: string }).code === \"ENOENT\"\n ) {\n try {\n await writeFile(\n configPath,\n JSON.stringify({ $schema: configSchemaUrl, ...DEFAULT_CONFIG }, null, 2),\n \"utf-8\",\n )\n config = { ...DEFAULT_CONFIG }\n await ctx.client.app.log({\n body: {\n service: \"roundtable\",\n level: \"info\",\n message: \"Created default configuration\",\n extra: { configPath },\n },\n })\n } catch {\n config = { ...DEFAULT_CONFIG }\n }\n } else {\n try {\n await ctx.client.app.log({\n body: {\n service: \"roundtable\",\n level: \"warn\",\n message: `Invalid config, using defaults: ${err instanceof Error ? err.message : String(err)}`,\n extra: { configPath },\n },\n })\n } catch { /* best-effort */ }\n config = { ...DEFAULT_CONFIG }\n }\n }\n}\n",
7
- "import type { RoundtableState, Part, HistoryEntry } from \"./types\"\n\nexport const states = new Map<string, RoundtableState>()\nexport const timeoutHandles = new Map<string, ReturnType<typeof setTimeout>>()\nexport const pendingResults = new Map<string, {\n resolve: (output: string) => void\n}>()\n\nexport function serializeState(state: RoundtableState): string {\n const json = JSON.stringify(state)\n return `[ROUNDTABLE META — INTERNAL ORCHESTRATION DATA — IGNORE FOR ANALYSIS] ${json} [/ROUNDTABLE META]`\n}\n\nexport function findSerializedState(\n messages: Array<{ info: { role: string }; parts: Part[] }>,\n): string | null {\n let last: string | null = null\n for (const msg of messages) {\n if (msg.info.role !== \"user\") continue\n for (const part of msg.parts) {\n if (part.type === \"text\" && part.text.startsWith(\"[ROUNDTABLE META\")) {\n last = part.text\n }\n }\n }\n return last\n}\n\nexport function deserializeState(raw: string): RoundtableState | null {\n try {\n const endTag = \"[/ROUNDTABLE META]\"\n const startIdx = raw.indexOf(\"[ROUNDTABLE META\")\n if (startIdx === -1) return null\n\n const closeBracket = raw.indexOf(\"]\", startIdx)\n if (closeBracket === -1) return null\n\n const contentStart = closeBracket + 1\n const endIdx = raw.indexOf(endTag, contentStart)\n if (endIdx === -1) return null\n\n const json = raw.slice(contentStart, endIdx).trim()\n if (!json) return null\n\n const parsed = JSON.parse(json)\n if (typeof parsed !== \"object\" || !parsed) return null\n if (typeof parsed.sessionID !== \"string\") return null\n if (typeof parsed.parentSessionID !== \"string\") return null\n if (!Array.isArray(parsed.agents)) return null\n if (typeof parsed.totalRounds !== \"number\") return null\n if (typeof parsed.prompt !== \"string\") return null\n\n return {\n sessionID: parsed.sessionID,\n parentSessionID: parsed.parentSessionID,\n agents: parsed.agents,\n totalRounds: parsed.totalRounds,\n observer: parsed.observer ?? \"built-in\",\n prompt: parsed.prompt,\n currentRound: parsed.currentRound ?? 0,\n currentAgentIndex: parsed.currentAgentIndex ?? 0,\n phase: parsed.phase ?? \"done\",\n history: parsed.history ?? [],\n errors: parsed.errors ?? [],\n createdAt: parsed.createdAt ?? 0,\n currentGeneration: parsed.currentGeneration ?? 0,\n userInterjections: parsed.userInterjections ?? [],\n lastProcessedMsgId: parsed.lastProcessedMsgId ?? undefined,\n }\n } catch {\n return null\n }\n}\n",
8
- "import type { Part, HistoryEntry, ToolCallSummary, RoundtableState, RoundtableArgs } from \"./types\"\nimport { getConfig } from \"./config\"\nimport type { PluginInput } from \"@opencode-ai/plugin\"\nimport { pendingResults } from \"./state\"\n\nexport function generateDefaultTitle(args: RoundtableArgs & { agents: string[] }): string {\n if (args.title) return args.title\n const summary = args.prompt.length > 60 ? args.prompt.slice(0, 57) + \"...\" : args.prompt\n return `(Roundtable) - ${summary}`\n}\n\nexport function getSessionIdFromEvent(event: { type: string; properties: Record<string, unknown> }): string | undefined {\n if (!(\"properties\" in event)) return undefined\n const props = event.properties as Record<string, unknown>\n if (typeof props.sessionID === \"string\") return props.sessionID\n if (props.info && typeof props.info === \"object\") {\n const info = props.info as { id?: string }\n if (info.id) return info.id\n }\n return undefined\n}\n\nexport async function validateAgents(\n ctx: PluginInput,\n agentNames: string[],\n): Promise<{ valid: boolean; available: { name: string; description?: string }[]; errors: string[] }> {\n const errors: string[] = []\n if (agentNames.length < 2) {\n errors.push(\"At least 2 agents are required\")\n return { valid: false, available: [], errors }\n }\n\n let available: { name: string; description?: string }[] = []\n try {\n const result = await ctx.client.app.agents()\n available = result.data.map((a: { name: string; description?: string }) => ({\n name: a.name,\n description: a.description,\n }))\n } catch {\n errors.push(\"Failed to fetch available agents from server\")\n return { valid: false, available: [], errors }\n }\n\n const availableNames = new Set(available.map((a) => a.name))\n for (const name of agentNames) {\n if (!availableNames.has(name)) errors.push(`Agent \"${name}\" not found`)\n }\n\n return { valid: errors.length === 0, available, errors }\n}\n\nexport function arraysEqual(a: string[], b: string[]): boolean {\n if (a.length !== b.length) return false\n for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false\n return true\n}\n\nexport function detectLoop(history: HistoryEntry[]): boolean {\n if (history.length < 2) return false\n const last = history[history.length - 1].response\n const prev = history[history.length - 2].response\n\n const bigrams = (s: string): Set<string> => {\n const set = new Set<string>()\n const cleaned = s.replace(/[\\s\\n\\r]+/g, \" \")\n for (let i = 0; i < cleaned.length - 1; i++) set.add(cleaned.slice(i, i + 2))\n return set\n }\n\n const lastBigrams = bigrams(last)\n const prevBigrams = bigrams(prev)\n let intersection = 0\n for (const b of lastBigrams) if (prevBigrams.has(b)) intersection++\n\n const union = new Set([...lastBigrams, ...prevBigrams])\n if (union.size === 0) return false\n return intersection / union.size > getConfig().loopSimilarityThreshold\n}\n\nexport function extractResponse(parts: Part[]): string | null {\n for (const part of parts) if (part.type === \"text\") return part.text\n return null\n}\n\nexport function buildToolSummary(part: Part): ToolCallSummary | null {\n if (part.type !== \"tool\") return null\n const toolName = (part as unknown as { tool: string }).tool\n const state = (part as unknown as { state: { status: string; output?: string } }).state\n let outputPreview: string\n switch (state.status) {\n case \"completed\":\n outputPreview = state.output!.slice(0, getConfig().toolOutputPreviewMax)\n break\n case \"error\":\n outputPreview = (state.output ?? \"(unknown error)\").slice(0, getConfig().toolOutputPreviewMax)\n break\n case \"running\":\n case \"pending\":\n outputPreview = `(${state.status})`\n break\n default:\n outputPreview = \"(unknown)\"\n }\n return { toolName, outputPreview }\n}\n\nexport function buildToolSummaries(parts: Part[]): ToolCallSummary[] {\n const summaries: ToolCallSummary[] = []\n for (const part of parts) {\n const summary = buildToolSummary(part)\n if (summary) summaries.push(summary)\n }\n return summaries\n}\n\nexport function buildConsolidatedSummary(state: RoundtableState): string {\n const lines: string[] = []\n lines.push(\"━━━ Roundtable Concluded ━━━\")\n lines.push(`Topic: ${state.prompt}`)\n lines.push(`Participants: ${state.agents.join(\", \")}`)\n if (state.errors.length > 0) lines.push(`Errors: ${state.errors.join(\"; \")}`)\n lines.push(\"\")\n\n for (const entry of state.history) {\n const label = entry.agent === \"observer\" ? \"Observer\" : `${entry.agent} (Round ${entry.round + 1})`\n lines.push(`── ${label} ──`)\n lines.push(entry.response)\n if (entry.toolCalls.length > 0) {\n lines.push(...entry.toolCalls.map((tc) => ` \\u2022 ${tc.toolName} \\u2192 ${tc.outputPreview.slice(0, 80)}`))\n }\n if (entry.hasError) lines.push(\" \\u26A0 This response had errors\")\n lines.push(\"\")\n }\n return lines.join(\"\\n\")\n}\n\nexport async function injectRoundtableDelimiter(\n ctx: PluginInput,\n sessionID: string,\n): Promise<void> {\n const delimiter = [\n \"━━━ Roundtable Concluded ━━━\",\n \"Messages below this line are not part of the original debate.\",\n \"The result was consolidated in the main session.\",\n ].join(\"\\n\")\n\n await ctx.client.session.prompt({\n path: { id: sessionID },\n body: { noReply: true, parts: [{ type: \"text\", text: delimiter }] },\n })\n}\n\nexport function buildExtendedPrompt(originalPrompt: string, extendPrompt: string): string {\n const continuationTriggers = [\n \"debate more\", \"continue\", \"dive deeper\", \"go deeper\",\n \"expand on\", \"elaborate\", \"further discuss\", \"keep debating\",\n ]\n const lower = extendPrompt.toLowerCase().trim()\n const isContinuation = continuationTriggers.some((trigger) => lower.startsWith(trigger))\n\n if (isContinuation) {\n return `Original topic: ${originalPrompt}\\n\\nContinuation: ${extendPrompt}`\n }\n\n return [\n \"Previous discussion history preserved. Original topic was:\",\n ` ${originalPrompt}`,\n \"\",\n `New challenge: ${extendPrompt}`,\n ].join(\"\\n\")\n}\n\nexport async function scanOrphanRoundtables(ctx: PluginInput): Promise<void> {\n await ctx.client.app.log({\n body: {\n service: \"roundtable\",\n level: \"debug\",\n message:\n \"scanOrphanRoundtables initialized (Phase 1 \\u2014 no scanning yet; \" +\n \"full implementation in Phase 4)\",\n extra: { phase: 1 },\n },\n })\n}\n",
9
- "import type { RoundtableState } from \"./types\"\nimport { getConfig } from \"./config\"\n\nexport function buildAgentPrompt(state: RoundtableState, agent: string): string {\n const lines: string[] = []\n const agentList = state.agents.join(\" → \")\n const roundInfo = `Round ${state.currentRound + 1}/${state.totalRounds} | Current agent: ${agent}`\n\n if (state.currentRound === 0 && state.currentAgentIndex === 0) {\n lines.push(`[System] You are participating in a roundtable debate. Agents (${agentList}) will discuss the topic below in ${state.totalRounds} round(s).`)\n lines.push(`[System] The [ROUNDTABLE META] block above is internal routing data — ignore it for all analysis. Focus only on the topic given in [Topic] below.`)\n lines.push(`[Topic] ${state.prompt}`)\n lines.push(\"\")\n }\n\n lines.push(roundInfo)\n\n const isLastAgent = state.currentAgentIndex === state.agents.length - 1\n const isLastRound = state.currentRound === state.totalRounds - 1\n if (isLastAgent && isLastRound) {\n lines.push(\"[System] This is the last prompt — finalize your thoughts\")\n }\n\n return lines.join(\"\\n\")\n}\n\nexport function buildObserverPrompt(state: RoundtableState, observer: \"built-in\" | string): string {\n const observerPrompt = getConfig().defaultObserverPrompt\n\n if (observer === \"built-in\") return observerPrompt\n\n return (\n `You are an impartial roundtable observer.\\n` +\n `Your role: ${observer}. Provide an executive summary of the debate.\\n\\n` +\n observerPrompt\n )\n}\n",
10
- "import type { PluginInput } from \"@opencode-ai/plugin\"\nimport type { RoundtableArgs, RoundtableState, HistoryEntry, Event as RoundtableEvent } from \"./types\"\nimport { states, timeoutHandles, pendingResults, serializeState, deserializeState, findSerializedState } from \"./state\"\nimport { getConfig } from \"./config\"\nimport { buildAgentPrompt, buildObserverPrompt } from \"./prompts\"\nimport {\n validateAgents, arraysEqual, buildExtendedPrompt, detectLoop,\n extractResponse, buildToolSummaries, buildConsolidatedSummary,\n generateDefaultTitle, injectRoundtableDelimiter, scanOrphanRoundtables,\n} from \"./utils\"\n\n// ============================================================\n// startNewRoundtable\n// ============================================================\n\nexport async function startNewRoundtable(\n ctx: PluginInput,\n args: RoundtableArgs,\n toolCtx: { sessionID: string },\n): Promise<string> {\n const agents = args.agents!\n const newSession = await ctx.client.session.create({\n body: { title: generateDefaultTitle({ ...args, agents }) },\n })\n\n const sessionID = newSession.data.id\n const parentSessionID = toolCtx.sessionID\n\n const state: RoundtableState = {\n sessionID,\n parentSessionID,\n agents,\n totalRounds: args.rounds,\n observer: args.observer ?? \"built-in\",\n prompt: args.prompt,\n currentRound: 0,\n currentAgentIndex: 0,\n phase: \"active\",\n history: [],\n errors: [],\n createdAt: Date.now(),\n currentGeneration: 0,\n userInterjections: [],\n }\n\n states.set(sessionID, state)\n\n try {\n await ctx.client.session.prompt({\n path: { id: sessionID },\n body: { noReply: true, parts: [{ type: \"text\", text: serializeState(state) }] },\n })\n\n await sendToAgent(ctx, state)\n\n await ctx.client.session.prompt({\n path: { id: parentSessionID },\n body: {\n noReply: true,\n parts: [{\n type: \"text\",\n text: `The roundtable has started (agents: ${agents.join(\", \")}, ${args.rounds} round(s)). To extend it later, use the tool roundtable({sessionID: \"${sessionID}\", rounds: N, prompt: \"...\"})`,\n }],\n },\n })\n\n await ctx.client.tui.showToast({\n body: {\n message: `Roundtable started in #${sessionID} (${agents.join(\" → \")} · ${args.rounds} round(s))`,\n variant: \"info\",\n },\n })\n\n return sessionID\n } catch (err) {\n states.delete(sessionID)\n throw err\n }\n}\n\n// ============================================================\n// sendToAgent\n// ============================================================\n\nexport async function sendToAgent(\n ctx: PluginInput,\n state: RoundtableState,\n): Promise<void> {\n try {\n const agent = state.agents[state.currentAgentIndex]\n const prompt = buildAgentPrompt(state, agent)\n\n await ctx.client.session.prompt({\n path: { id: state.sessionID },\n body: { agent, parts: [{ type: \"text\", text: prompt }] },\n })\n\n state.currentGeneration++\n const capturedGeneration = state.currentGeneration\n\n const handle = setTimeout(async () => {\n timeoutHandles.delete(state.sessionID)\n if (state.currentGeneration !== capturedGeneration) return\n\n try {\n await ctx.client.session.abort({ path: { id: state.sessionID } })\n state.errors.push(`Agent \"${agent}\" timed out after ${getConfig().defaultTimeoutMs / 1000}s`)\n } catch { /* session may already be done */ }\n }, getConfig().defaultTimeoutMs)\n\n timeoutHandles.set(state.sessionID, handle)\n await updateSessionTitle(ctx, state)\n\n await ctx.client.app.log({\n body: {\n service: \"roundtable\",\n level: \"debug\",\n message: `Turn started: ${agent} (R${state.currentRound + 1}/${state.totalRounds})`,\n extra: {\n sessionID: state.sessionID, agent,\n round: state.currentRound + 1,\n totalRounds: state.totalRounds,\n generation: state.currentGeneration,\n },\n },\n })\n } catch (err) {\n state.errors.push(\n `Failed to send to agent \"${state.agents[state.currentAgentIndex]}\": ${err instanceof Error ? err.message : String(err)}`,\n )\n const handle = timeoutHandles.get(state.sessionID)\n if (handle) { clearTimeout(handle); timeoutHandles.delete(state.sessionID) }\n }\n}\n\n// ============================================================\n// updateSessionTitle\n// ============================================================\n\nexport async function updateSessionTitle(\n ctx: PluginInput,\n state: RoundtableState,\n): Promise<void> {\n const summary = state.prompt.length > 60 ? state.prompt.slice(0, 57) + \"...\" : state.prompt\n await ctx.client.session.update({\n path: { id: state.sessionID },\n body: { title: `(Roundtable) - ${summary}` },\n })\n}\n\n// ============================================================\n// sendObserverPrompt\n// ============================================================\n\nasync function sendObserverPrompt(\n ctx: PluginInput,\n state: RoundtableState,\n): Promise<void> {\n try {\n const prompt = buildObserverPrompt(state, state.observer)\n\n if (state.observer === \"built-in\") {\n await ctx.client.session.prompt({\n path: { id: state.sessionID },\n body: { noReply: false, parts: [{ type: \"text\", text: prompt }] },\n })\n } else {\n await ctx.client.session.prompt({\n path: { id: state.sessionID },\n body: { agent: state.observer, parts: [{ type: \"text\", text: prompt }] },\n })\n }\n\n await ctx.client.app.log({\n body: {\n service: \"roundtable\",\n level: \"debug\",\n message: `Observer prompt sent: ${state.observer}`,\n extra: { sessionID: state.sessionID, observer: state.observer },\n },\n })\n } catch (err) {\n state.errors.push(`Failed to send observer prompt: ${err instanceof Error ? err.message : String(err)}`)\n state.phase = \"aborted\"\n await finalizeRoundtable(ctx, state)\n }\n}\n\n// ============================================================\n// finalizeRoundtable\n// ============================================================\n\nexport async function finalizeRoundtable(\n ctx: PluginInput,\n state: RoundtableState,\n): Promise<void> {\n const sessionID = state.sessionID\n\n const timeoutHandle = timeoutHandles.get(sessionID)\n if (timeoutHandle) { clearTimeout(timeoutHandle); timeoutHandles.delete(sessionID) }\n\n try {\n const summary = buildConsolidatedSummary(state)\n\n const pending = pendingResults.get(sessionID)\n if (pending) {\n pending.resolve(summary)\n pendingResults.delete(sessionID)\n }\n\n await injectRoundtableDelimiter(ctx, sessionID)\n\n const shortPrompt = state.prompt.length > 50 ? state.prompt.slice(0, 47) + \"...\" : state.prompt\n await ctx.client.session.update({\n path: { id: sessionID },\n body: { title: `(Roundtable) - ${shortPrompt} · CONCLUDED` },\n })\n\n try {\n await ctx.client.session.prompt({\n path: { id: sessionID },\n body: { noReply: true, parts: [{ type: \"text\", text: serializeState(state) }] },\n })\n } catch { /* best-effort */ }\n\n await ctx.client.tui.showToast({\n body: { message: \"Roundtable concluded\", variant: \"success\" },\n })\n } catch (err) {\n try {\n await ctx.client.app.log({\n body: {\n service: \"roundtable\",\n level: \"error\",\n message: `Failed to finalize roundtable #${sessionID}: ${err instanceof Error ? err.message : String(err)}`,\n extra: { sessionID, phase: state.phase },\n },\n })\n } catch { /* best-effort */ }\n } finally {\n states.delete(sessionID)\n try {\n await ctx.client.app.log({\n body: {\n service: \"roundtable\",\n level: \"debug\",\n message: `State cleaned up for session #${sessionID}`,\n extra: { sessionID, phase: state.phase },\n },\n })\n } catch { /* best-effort */ }\n }\n}\n\n// ============================================================\n// processNextTurn\n// ============================================================\n\nexport async function processNextTurn(\n ctx: PluginInput,\n state: RoundtableState,\n): Promise<void> {\n if (state.phase === \"done\" || state.phase === \"aborted\") return\n\n const result = await ctx.client.session.messages({ path: { id: state.sessionID } })\n const messages = result.data\n\n const userMsgs = messages.filter((m: { info: { role: string } }) => m.info.role === \"user\")\n for (const msg of userMsgs) {\n for (const part of msg.parts) {\n if (part.type === \"text\" && !part.text.includes(\"[ROUNDTABLE META\")) {\n if (!state.userInterjections.includes(part.text)) {\n state.userInterjections.push(part.text)\n }\n }\n }\n }\n\n const assistantMsgs = messages.filter(\n (m: { info: { role: string } }) => m.info.role === \"assistant\",\n )\n if (assistantMsgs.length === 0) return\n\n const latestMsg = assistantMsgs[assistantMsgs.length - 1]\n if (state.lastProcessedMsgId === latestMsg.info.id) return\n state.lastProcessedMsgId = latestMsg.info.id\n\n if (state.phase === \"active\") {\n const response = extractResponse(latestMsg.parts)\n if (!response) {\n state.errors.push(\n `Agent ${state.agents[state.currentAgentIndex]} returned no text in round ${state.currentRound + 1}`,\n )\n }\n\n const toolCalls = buildToolSummaries(latestMsg.parts)\n const entry: HistoryEntry = {\n agent: state.agents[state.currentAgentIndex],\n round: state.currentRound,\n response: response ?? \"(no text response)\",\n toolCalls,\n hasError: response === null,\n }\n state.history.push(entry)\n\n await ctx.client.app.log({\n body: {\n service: \"roundtable\",\n level: \"debug\",\n message: `Turn complete: ${entry.agent} (R${state.currentRound + 1})`,\n extra: {\n sessionID: state.sessionID, agent: entry.agent,\n round: state.currentRound + 1,\n responseLength: entry.response.length,\n toolCallCount: entry.toolCalls.length,\n hasError: entry.hasError,\n },\n },\n })\n\n if (detectLoop(state.history)) {\n state.errors.push(\"Loop detected — agents reached an impasse\")\n state.phase = \"done\"\n await ctx.client.app.log({\n body: {\n service: \"roundtable\",\n level: \"debug\",\n message: \"Loop detected — finalizing early\",\n extra: { sessionID: state.sessionID, similarity: getConfig().loopSimilarityThreshold },\n },\n })\n await finalizeRoundtable(ctx, state)\n return\n }\n\n const nextIndex = state.currentAgentIndex + 1\n if (nextIndex < state.agents.length) {\n state.currentAgentIndex = nextIndex\n await sendToAgent(ctx, state)\n } else if (state.currentRound + 1 < state.totalRounds) {\n state.currentRound++\n state.currentAgentIndex = 0\n await sendToAgent(ctx, state)\n } else {\n state.phase = \"observing\"\n await ctx.client.app.log({\n body: {\n service: \"roundtable\",\n level: \"debug\",\n message: \"All rounds complete — transitioning to observer\",\n extra: { sessionID: state.sessionID, totalRounds: state.totalRounds },\n },\n })\n await sendObserverPrompt(ctx, state)\n }\n return\n }\n\n if (state.phase === \"observing\") {\n const summary = extractResponse(latestMsg.parts)\n state.history.push({\n agent: \"observer\",\n round: state.currentRound,\n response: summary ?? \"(no summary)\",\n toolCalls: [],\n hasError: summary === null,\n })\n state.phase = \"done\"\n await finalizeRoundtable(ctx, state)\n }\n}\n\n// ============================================================\n// handleAgentError\n// ============================================================\n\nexport async function handleAgentError(\n ctx: PluginInput,\n state: RoundtableState,\n event: RoundtableEvent,\n): Promise<void> {\n if (state.phase === \"observing\" || state.phase === \"done\") {\n state.phase = \"aborted\"\n await finalizeRoundtable(ctx, state)\n return\n }\n\n const agent = state.agents[state.currentAgentIndex]\n const errorMsg =\n event.type === \"session.error\" && event.properties.error\n ? typeof event.properties.error === \"object\"\n ? (event.properties.error as { message?: string }).message ?? JSON.stringify(event.properties.error)\n : String(event.properties.error)\n : \"Unknown error\"\n\n state.errors.push(`Agent \"${agent}\" failed on round ${state.currentRound + 1}: ${errorMsg}`)\n\n const handle = timeoutHandles.get(state.sessionID)\n if (handle) { clearTimeout(handle); timeoutHandles.delete(state.sessionID) }\n\n await ctx.client.tui.showToast({\n body: {\n message: `\"${agent}\" failed on Round ${state.currentRound + 1}. Skipping to next.`,\n variant: \"warning\",\n },\n })\n\n const nextIndex = state.currentAgentIndex + 1\n if (nextIndex < state.agents.length) {\n state.currentAgentIndex = nextIndex\n try {\n await ctx.client.app.log({\n body: {\n service: \"roundtable\",\n level: \"debug\",\n message: \"Agent skipped due to error\",\n extra: { sessionID: state.sessionID, failedAgent: agent, nextAgent: state.agents[state.currentAgentIndex], round: state.currentRound + 1 },\n },\n })\n } catch { /* best-effort */ }\n await sendToAgent(ctx, state)\n } else if (state.currentRound + 1 < state.totalRounds) {\n state.currentRound++\n state.currentAgentIndex = 0\n try {\n await ctx.client.app.log({\n body: {\n service: \"roundtable\",\n level: \"debug\",\n message: \"Agent skipped due to error — moving to next round\",\n extra: { sessionID: state.sessionID, failedAgent: agent, round: state.currentRound + 1 },\n },\n })\n } catch { /* best-effort */ }\n await sendToAgent(ctx, state)\n } else {\n state.phase = \"aborted\"\n try {\n await ctx.client.tui.showToast({\n body: { message: \"All agents failed — roundtable aborted\", variant: \"error\" },\n })\n } catch { /* best-effort */ }\n await finalizeRoundtable(ctx, state)\n }\n}\n\n// ============================================================\n// handleSessionDeleted\n// ============================================================\n\nexport async function handleSessionDeleted(\n ctx: PluginInput,\n state: RoundtableState,\n deletedSessionID: string,\n): Promise<void> {\n const handle = timeoutHandles.get(state.sessionID)\n if (handle) { clearTimeout(handle); timeoutHandles.delete(state.sessionID) }\n\n if (deletedSessionID === state.sessionID) {\n state.phase = \"aborted\"\n const partialSummary = buildConsolidatedSummary(state)\n const output = [\n \"[Roundtable interrupted — session closed]\",\n \"Partial history up to interruption:\",\n \"\",\n partialSummary,\n ].join(\"\\n\")\n\n const pending = pendingResults.get(state.sessionID)\n if (pending) {\n pending.resolve(output)\n pendingResults.delete(state.sessionID)\n }\n\n try {\n await ctx.client.tui.showToast({\n body: { message: \"Roundtable interrupted\", variant: \"warning\" },\n })\n } catch { /* best-effort */ }\n try {\n await ctx.client.app.log({\n body: {\n service: \"roundtable\",\n level: \"debug\",\n message: \"S2 deleted — pending promise resolved with partial result\",\n extra: { sessionID: deletedSessionID, parentSessionID: state.parentSessionID },\n },\n })\n } catch { /* best-effort */ }\n } else if (deletedSessionID === state.parentSessionID) {\n state.phase = \"aborted\"\n try {\n await ctx.client.session.abort({ path: { id: state.sessionID } })\n } catch { /* S2 may already be gone */ }\n try {\n await ctx.client.app.log({\n body: {\n service: \"roundtable\",\n level: \"debug\",\n message: \"S1 deleted — S2 aborted\",\n extra: { sessionID: state.sessionID, parentSessionID: deletedSessionID },\n },\n })\n } catch { /* best-effort */ }\n }\n\n states.delete(state.sessionID)\n}\n\n// ============================================================\n// extendRoundtable\n// ============================================================\n\nexport async function extendRoundtable(\n ctx: PluginInput,\n args: RoundtableArgs,\n _toolCtx: { sessionID: string },\n): Promise<string> {\n const sessionID = args.sessionID!\n\n try {\n await ctx.client.session.get({ path: { id: sessionID } })\n } catch {\n return `Error: Session #${sessionID} not found or inaccessible. Cannot extend.`\n }\n\n let messagesData\n try {\n messagesData = await ctx.client.session.messages({ path: { id: sessionID } })\n } catch {\n return `Error: Could not read messages from session #${sessionID}`\n }\n\n const serializedRaw = findSerializedState(messagesData.data)\n if (!serializedRaw) {\n return [\n `Error: No roundtable state found in session #${sessionID}.`,\n \"This session is not a roundtable or the state was lost during compaction.\",\n ].join(\"\\n\")\n }\n\n const originalState = deserializeState(serializedRaw)\n if (!originalState) {\n return `Error: Corrupt roundtable state in session #${sessionID}. Cannot extend.`\n }\n\n if (originalState.phase === \"done\") {\n // proceed\n } else if (originalState.phase === \"active\") {\n const assistantCount = messagesData.data.filter(\n (m: { info: { role: string } }) => m.info.role === \"assistant\",\n ).length\n const expectedAssistantCount = originalState.totalRounds * originalState.agents.length + 1\n if (assistantCount >= expectedAssistantCount) {\n originalState.phase = \"done\"\n try {\n await ctx.client.app.log({\n body: {\n service: \"roundtable\",\n level: \"info\",\n message: `Recovered stuck session #${sessionID}: phase was active but ${assistantCount} assistant msgs suggest debate completed.`,\n extra: { sessionID, assistantCount, expectedAssistantCount },\n },\n })\n } catch { /* best-effort */ }\n } else {\n return [\n `Error: Roundtable #${sessionID} is still active (phase: ${originalState.phase}).`,\n \"Cannot extend until the roundtable concludes.\",\n ].join(\"\\n\")\n }\n } else {\n return [\n `Error: Roundtable #${sessionID} is in state \"${originalState.phase}\" and cannot be extended.`,\n ].join(\"\\n\")\n }\n\n if (args.agents && !arraysEqual(args.agents, originalState.agents)) {\n return [\n \"Error: Agent mismatch.\",\n `Original: ${originalState.agents.join(\", \")}`,\n `Provided: ${args.agents.join(\", \")}`,\n \"Extend must use the same agents as the original roundtable.\",\n ].join(\"\\n\")\n }\n\n try {\n const storedValidation = await validateAgents(ctx, originalState.agents)\n if (!storedValidation.valid) {\n return [\n \"Error: One or more agents from the original roundtable no longer exist.\",\n ...storedValidation.errors.map((e) => ` - ${e}`),\n ].join(\"\\n\")\n }\n } catch {\n return \"Error: Failed to validate agents. Cannot extend.\"\n }\n\n const extendedPrompt = buildExtendedPrompt(originalState.prompt, args.prompt)\n\n const newState: RoundtableState = {\n sessionID: originalState.sessionID,\n parentSessionID: originalState.parentSessionID,\n agents: originalState.agents,\n totalRounds: originalState.totalRounds + args.rounds,\n observer: originalState.observer,\n prompt: extendedPrompt,\n currentRound: originalState.currentRound,\n currentAgentIndex: 0,\n phase: \"active\",\n history: [...originalState.history],\n errors: [...originalState.errors],\n createdAt: Date.now(),\n currentGeneration: 0,\n userInterjections: [...(originalState.userInterjections ?? [])],\n }\n\n states.set(sessionID, newState)\n\n try {\n await ctx.client.session.prompt({\n path: { id: sessionID },\n body: { noReply: true, parts: [{ type: \"text\", text: serializeState(newState) }] },\n })\n\n const agentList = originalState.agents.join(\" vs \")\n await ctx.client.session.update({\n path: { id: sessionID },\n body: { title: `Roundtable: ${agentList} (R${newState.currentRound + 1}/${newState.totalRounds})` },\n })\n\n await ctx.client.session.prompt({\n path: { id: originalState.parentSessionID },\n body: {\n noReply: true,\n parts: [{\n type: \"text\",\n text: `The roundtable has been extended (${args.rounds} more round(s)). To extend again, use the tool roundtable({sessionID: \"${sessionID}\", rounds: N, prompt: \"...\"})`,\n }],\n },\n })\n\n await sendToAgent(ctx, newState)\n\n await ctx.client.tui.showToast({\n body: {\n message: `Roundtable #${sessionID} extended — ${args.rounds} more round(s) (${originalState.agents.join(\" → \")})`,\n variant: \"info\",\n },\n })\n\n return sessionID\n } catch (err) {\n states.delete(sessionID)\n throw err\n }\n}\n"
7
+ "import { readFile, writeFile, unlink, readdir, mkdir } from \"fs/promises\"\nimport { join } from \"path\"\nimport os from \"os\"\nimport type { RoundtableState } from \"./types\"\n\nconst statesDir = (() => {\n const xdgConfigHome = process.env.XDG_CONFIG_HOME\n const base = xdgConfigHome ? join(xdgConfigHome, \"opencode\") : join(os.homedir(), \".config\", \"opencode\")\n return join(base, \"roundtable-states\")\n})()\n\nexport const states = new Map<string, RoundtableState>()\nexport const timeoutHandles = new Map<string, ReturnType<typeof setTimeout>>()\nexport const pendingResults = new Map<string, {\n resolve: (output: string) => void\n}>()\n\nfunction stateFilePath(sessionID: string): string {\n return join(statesDir, `${sessionID}.json`)\n}\n\nexport async function saveStateFile(state: RoundtableState): Promise<void> {\n try {\n await mkdir(statesDir, { recursive: true })\n } catch { /* already exists */ }\n const filePath = stateFilePath(state.sessionID)\n await writeFile(filePath, JSON.stringify(state, null, 2), \"utf-8\")\n}\n\nexport async function loadStateFile(sessionID: string): Promise<RoundtableState | null> {\n try {\n const content = await readFile(stateFilePath(sessionID), \"utf-8\")\n const parsed = JSON.parse(content)\n if (typeof parsed !== \"object\" || !parsed) return null\n if (typeof parsed.sessionID !== \"string\") return null\n if (typeof parsed.parentSessionID !== \"string\") return null\n if (!Array.isArray(parsed.agents)) return null\n if (typeof parsed.totalRounds !== \"number\") return null\n if (typeof parsed.prompt !== \"string\") return null\n return {\n sessionID: parsed.sessionID,\n parentSessionID: parsed.parentSessionID,\n agents: parsed.agents,\n totalRounds: parsed.totalRounds,\n observer: parsed.observer ?? \"built-in\",\n prompt: parsed.prompt,\n currentRound: parsed.currentRound ?? 0,\n currentAgentIndex: parsed.currentAgentIndex ?? 0,\n phase: parsed.phase ?? \"done\",\n history: parsed.history ?? [],\n errors: parsed.errors ?? [],\n createdAt: parsed.createdAt ?? 0,\n currentGeneration: parsed.currentGeneration ?? 0,\n userInterjections: parsed.userInterjections ?? [],\n lastProcessedMsgId: parsed.lastProcessedMsgId ?? undefined,\n }\n } catch {\n return null\n }\n}\n\nexport async function deleteStateFile(sessionID: string): Promise<void> {\n try {\n await unlink(stateFilePath(sessionID))\n } catch { /* best-effort */ }\n}\n\nexport async function listStateFiles(): Promise<string[]> {\n try {\n const entries = await readdir(statesDir)\n return entries\n .filter((e) => e.endsWith(\".json\"))\n .map((e) => e.replace(/\\.json$/, \"\"))\n } catch {\n return []\n }\n}\n",
8
+ "import type { Part, HistoryEntry, ToolCallSummary, RoundtableState, RoundtableArgs } from \"./types\"\nimport { getConfig } from \"./config\"\nimport type { PluginInput } from \"@opencode-ai/plugin\"\nimport { pendingResults, listStateFiles, loadStateFile, states } from \"./state\"\n\nexport function generateDefaultTitle(args: RoundtableArgs & { agents: string[] }): string {\n if (args.title) return args.title\n const summary = args.prompt.length > 60 ? args.prompt.slice(0, 57) + \"...\" : args.prompt\n return `(Roundtable) - ${summary}`\n}\n\nexport function getSessionIdFromEvent(event: { type: string; properties: Record<string, unknown> }): string | undefined {\n if (!(\"properties\" in event)) return undefined\n const props = event.properties as Record<string, unknown>\n if (typeof props.sessionID === \"string\") return props.sessionID\n if (props.info && typeof props.info === \"object\") {\n const info = props.info as { id?: string }\n if (info.id) return info.id\n }\n return undefined\n}\n\nexport async function validateAgents(\n ctx: PluginInput,\n agentNames: string[],\n): Promise<{ valid: boolean; available: { name: string; description?: string }[]; errors: string[] }> {\n const errors: string[] = []\n if (agentNames.length < 2) {\n errors.push(\"At least 2 agents are required\")\n return { valid: false, available: [], errors }\n }\n\n let available: { name: string; description?: string }[] = []\n try {\n const result = await ctx.client.app.agents()\n available = result.data.map((a: { name: string; description?: string }) => ({\n name: a.name,\n description: a.description,\n }))\n } catch {\n errors.push(\"Failed to fetch available agents from server\")\n return { valid: false, available: [], errors }\n }\n\n const availableNames = new Set(available.map((a) => a.name))\n for (const name of agentNames) {\n if (!availableNames.has(name)) errors.push(`Agent \"${name}\" not found`)\n }\n\n return { valid: errors.length === 0, available, errors }\n}\n\nexport function arraysEqual(a: string[], b: string[]): boolean {\n if (a.length !== b.length) return false\n for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false\n return true\n}\n\nexport function detectLoop(history: HistoryEntry[]): boolean {\n if (history.length < 2) return false\n const last = history[history.length - 1].response\n const prev = history[history.length - 2].response\n\n const bigrams = (s: string): Set<string> => {\n const set = new Set<string>()\n const cleaned = s.replace(/[\\s\\n\\r]+/g, \" \")\n for (let i = 0; i < cleaned.length - 1; i++) set.add(cleaned.slice(i, i + 2))\n return set\n }\n\n const lastBigrams = bigrams(last)\n const prevBigrams = bigrams(prev)\n let intersection = 0\n for (const b of lastBigrams) if (prevBigrams.has(b)) intersection++\n\n const union = new Set([...lastBigrams, ...prevBigrams])\n if (union.size === 0) return false\n return intersection / union.size > getConfig().loopSimilarityThreshold\n}\n\nexport function extractResponse(parts: Part[]): string | null {\n for (const part of parts) if (part.type === \"text\") return part.text\n return null\n}\n\nexport function buildToolSummary(part: Part): ToolCallSummary | null {\n if (part.type !== \"tool\") return null\n const toolName = (part as unknown as { tool: string }).tool\n const state = (part as unknown as { state: { status: string; output?: string } }).state\n let outputPreview: string\n switch (state.status) {\n case \"completed\":\n outputPreview = state.output!.slice(0, getConfig().toolOutputPreviewMax)\n break\n case \"error\":\n outputPreview = (state.output ?? \"(unknown error)\").slice(0, getConfig().toolOutputPreviewMax)\n break\n case \"running\":\n case \"pending\":\n outputPreview = `(${state.status})`\n break\n default:\n outputPreview = \"(unknown)\"\n }\n return { toolName, outputPreview }\n}\n\nexport function buildToolSummaries(parts: Part[]): ToolCallSummary[] {\n const summaries: ToolCallSummary[] = []\n for (const part of parts) {\n const summary = buildToolSummary(part)\n if (summary) summaries.push(summary)\n }\n return summaries\n}\n\nexport function buildConsolidatedSummary(state: RoundtableState): string {\n const lines: string[] = []\n lines.push(\"━━━ Roundtable Concluded ━━━\")\n lines.push(`Topic: ${state.prompt}`)\n lines.push(`Participants: ${state.agents.join(\", \")}`)\n if (state.errors.length > 0) lines.push(`Errors: ${state.errors.join(\"; \")}`)\n lines.push(\"\")\n\n for (const entry of state.history) {\n const label = entry.agent === \"observer\" ? \"Observer\" : `${entry.agent} (Round ${entry.round + 1})`\n lines.push(`── ${label} ──`)\n lines.push(entry.response)\n if (entry.toolCalls.length > 0) {\n lines.push(...entry.toolCalls.map((tc) => ` \\u2022 ${tc.toolName} \\u2192 ${tc.outputPreview.slice(0, 80)}`))\n }\n if (entry.hasError) lines.push(\" \\u26A0 This response had errors\")\n lines.push(\"\")\n }\n return lines.join(\"\\n\")\n}\n\nexport async function injectRoundtableDelimiter(\n ctx: PluginInput,\n sessionID: string,\n): Promise<void> {\n const delimiter = [\n \"━━━ Roundtable Concluded ━━━\",\n \"Messages below this line are not part of the original debate.\",\n \"The result was consolidated in the main session.\",\n ].join(\"\\n\")\n\n await ctx.client.session.prompt({\n path: { id: sessionID },\n body: { noReply: true, parts: [{ type: \"text\", text: delimiter }] },\n })\n}\n\nexport function buildExtendedPrompt(originalPrompt: string, extendPrompt: string): string {\n const continuationTriggers = [\n \"debate more\", \"continue\", \"dive deeper\", \"go deeper\",\n \"expand on\", \"elaborate\", \"further discuss\", \"keep debating\",\n ]\n const lower = extendPrompt.toLowerCase().trim()\n const isContinuation = continuationTriggers.some((trigger) => lower.startsWith(trigger))\n\n if (isContinuation) {\n return `Original topic: ${originalPrompt}\\n\\nContinuation: ${extendPrompt}`\n }\n\n return [\n \"Previous discussion history preserved. Original topic was:\",\n ` ${originalPrompt}`,\n \"\",\n `New challenge: ${extendPrompt}`,\n ].join(\"\\n\")\n}\n\nexport async function scanOrphanRoundtables(ctx: PluginInput): Promise<void> {\n const sessionIDs = await listStateFiles()\n let loaded = 0\n let errors = 0\n for (const sid of sessionIDs) {\n try {\n const state = await loadStateFile(sid)\n if (state) {\n states.set(sid, state)\n loaded++\n }\n } catch {\n errors++\n }\n }\n await ctx.client.app.log({\n body: {\n service: \"roundtable\",\n level: \"debug\",\n message: `scanOrphanRoundtables: ${loaded} state(s) loaded, ${errors} error(s)`,\n extra: { loaded, errors, total: sessionIDs.length },\n },\n })\n}\n",
9
+ "import type { RoundtableState } from \"./types\"\nimport { getConfig } from \"./config\"\n\nexport function buildAgentPrompt(state: RoundtableState, agent: string): string {\n const lines: string[] = []\n const agentList = state.agents.join(\" → \")\n const roundInfo = `Round ${state.currentRound + 1}/${state.totalRounds} | Current agent: ${agent}`\n\n if (state.currentRound === 0 && state.currentAgentIndex === 0) {\n lines.push(`[System] You are participating in a roundtable debate. Agents (${agentList}) will discuss the topic below in ${state.totalRounds} round(s).`)\n lines.push(`[Topic] ${state.prompt}`)\n lines.push(\"\")\n }\n\n lines.push(roundInfo)\n\n const isLastAgent = state.currentAgentIndex === state.agents.length - 1\n const isLastRound = state.currentRound === state.totalRounds - 1\n if (isLastAgent && isLastRound) {\n lines.push(\"[System] This is the last prompt — finalize your thoughts\")\n }\n\n return lines.join(\"\\n\")\n}\n\nexport function buildObserverPrompt(state: RoundtableState, observer: \"built-in\" | string): string {\n const observerPrompt = getConfig().defaultObserverPrompt\n\n if (observer === \"built-in\") return observerPrompt\n\n return (\n `You are an impartial roundtable observer.\\n` +\n `Your role: ${observer}. Provide an executive summary of the debate.\\n\\n` +\n observerPrompt\n )\n}\n",
10
+ "import type { PluginInput } from \"@opencode-ai/plugin\"\nimport type { RoundtableArgs, RoundtableState, HistoryEntry, Event as RoundtableEvent } from \"./types\"\nimport { states, timeoutHandles, pendingResults, saveStateFile, loadStateFile, deleteStateFile } from \"./state\"\nimport { getConfig } from \"./config\"\nimport { buildAgentPrompt, buildObserverPrompt } from \"./prompts\"\nimport {\n validateAgents, arraysEqual, buildExtendedPrompt, detectLoop,\n extractResponse, buildToolSummaries, buildConsolidatedSummary,\n generateDefaultTitle, injectRoundtableDelimiter, scanOrphanRoundtables,\n} from \"./utils\"\n\n// ============================================================\n// startNewRoundtable\n// ============================================================\n\nexport async function startNewRoundtable(\n ctx: PluginInput,\n args: RoundtableArgs,\n toolCtx: { sessionID: string },\n): Promise<string> {\n const agents = args.agents!\n const newSession = await ctx.client.session.create({\n body: { title: generateDefaultTitle({ ...args, agents }) },\n })\n\n const sessionID = newSession.data.id\n const parentSessionID = toolCtx.sessionID\n\n const state: RoundtableState = {\n sessionID,\n parentSessionID,\n agents,\n totalRounds: args.rounds,\n observer: args.observer ?? \"built-in\",\n prompt: args.prompt,\n currentRound: 0,\n currentAgentIndex: 0,\n phase: \"active\",\n history: [],\n errors: [],\n createdAt: Date.now(),\n currentGeneration: 0,\n userInterjections: [],\n }\n\n states.set(sessionID, state)\n\n try {\n await saveStateFile(state)\n await sendToAgent(ctx, state)\n\n await ctx.client.session.prompt({\n path: { id: parentSessionID },\n body: {\n noReply: true,\n parts: [{\n type: \"text\",\n text: `The roundtable has started (agents: ${agents.join(\", \")}, ${args.rounds} round(s)). To extend it later, use the tool roundtable({sessionID: \"${sessionID}\", rounds: N, prompt: \"...\"})`,\n }],\n },\n })\n\n await ctx.client.tui.showToast({\n body: {\n message: `Roundtable started in #${sessionID} (${agents.join(\" → \")} · ${args.rounds} round(s))`,\n variant: \"info\",\n },\n })\n\n return sessionID\n } catch (err) {\n states.delete(sessionID)\n throw err\n }\n}\n\n// ============================================================\n// sendToAgent\n// ============================================================\n\nexport async function sendToAgent(\n ctx: PluginInput,\n state: RoundtableState,\n): Promise<void> {\n try {\n const agent = state.agents[state.currentAgentIndex]\n const prompt = buildAgentPrompt(state, agent)\n\n await ctx.client.session.prompt({\n path: { id: state.sessionID },\n body: { agent, parts: [{ type: \"text\", text: prompt }] },\n })\n\n state.currentGeneration++\n const capturedGeneration = state.currentGeneration\n\n const handle = setTimeout(async () => {\n timeoutHandles.delete(state.sessionID)\n if (state.currentGeneration !== capturedGeneration) return\n\n try {\n await ctx.client.session.abort({ path: { id: state.sessionID } })\n state.errors.push(`Agent \"${agent}\" timed out after ${getConfig().defaultTimeoutMs / 1000}s`)\n } catch { /* session may already be done */ }\n }, getConfig().defaultTimeoutMs)\n\n timeoutHandles.set(state.sessionID, handle)\n await updateSessionTitle(ctx, state)\n\n await ctx.client.app.log({\n body: {\n service: \"roundtable\",\n level: \"debug\",\n message: `Turn started: ${agent} (R${state.currentRound + 1}/${state.totalRounds})`,\n extra: {\n sessionID: state.sessionID, agent,\n round: state.currentRound + 1,\n totalRounds: state.totalRounds,\n generation: state.currentGeneration,\n },\n },\n })\n } catch (err) {\n state.errors.push(\n `Failed to send to agent \"${state.agents[state.currentAgentIndex]}\": ${err instanceof Error ? err.message : String(err)}`,\n )\n const handle = timeoutHandles.get(state.sessionID)\n if (handle) { clearTimeout(handle); timeoutHandles.delete(state.sessionID) }\n }\n}\n\n// ============================================================\n// updateSessionTitle\n// ============================================================\n\nexport async function updateSessionTitle(\n ctx: PluginInput,\n state: RoundtableState,\n): Promise<void> {\n const summary = state.prompt.length > 60 ? state.prompt.slice(0, 57) + \"...\" : state.prompt\n await ctx.client.session.update({\n path: { id: state.sessionID },\n body: { title: `(Roundtable) - ${summary}` },\n })\n}\n\n// ============================================================\n// sendObserverPrompt\n// ============================================================\n\nasync function sendObserverPrompt(\n ctx: PluginInput,\n state: RoundtableState,\n): Promise<void> {\n try {\n const prompt = buildObserverPrompt(state, state.observer)\n\n if (state.observer === \"built-in\") {\n await ctx.client.session.prompt({\n path: { id: state.sessionID },\n body: { noReply: false, parts: [{ type: \"text\", text: prompt }] },\n })\n } else {\n await ctx.client.session.prompt({\n path: { id: state.sessionID },\n body: { agent: state.observer, parts: [{ type: \"text\", text: prompt }] },\n })\n }\n\n await ctx.client.app.log({\n body: {\n service: \"roundtable\",\n level: \"debug\",\n message: `Observer prompt sent: ${state.observer}`,\n extra: { sessionID: state.sessionID, observer: state.observer },\n },\n })\n } catch (err) {\n state.errors.push(`Failed to send observer prompt: ${err instanceof Error ? err.message : String(err)}`)\n state.phase = \"aborted\"\n await finalizeRoundtable(ctx, state)\n }\n}\n\n// ============================================================\n// finalizeRoundtable\n// ============================================================\n\nexport async function finalizeRoundtable(\n ctx: PluginInput,\n state: RoundtableState,\n): Promise<void> {\n const sessionID = state.sessionID\n\n const timeoutHandle = timeoutHandles.get(sessionID)\n if (timeoutHandle) { clearTimeout(timeoutHandle); timeoutHandles.delete(sessionID) }\n\n try {\n const summary = buildConsolidatedSummary(state)\n\n const pending = pendingResults.get(sessionID)\n if (pending) {\n pending.resolve(summary)\n pendingResults.delete(sessionID)\n }\n\n await injectRoundtableDelimiter(ctx, sessionID)\n\n const shortPrompt = state.prompt.length > 50 ? state.prompt.slice(0, 47) + \"...\" : state.prompt\n await ctx.client.session.update({\n path: { id: sessionID },\n body: { title: `(Roundtable) - ${shortPrompt} · CONCLUDED` },\n })\n\n try {\n await saveStateFile(state)\n } catch { /* best-effort */ }\n\n await ctx.client.tui.showToast({\n body: { message: \"Roundtable concluded\", variant: \"success\" },\n })\n } catch (err) {\n try {\n await ctx.client.app.log({\n body: {\n service: \"roundtable\",\n level: \"error\",\n message: `Failed to finalize roundtable #${sessionID}: ${err instanceof Error ? err.message : String(err)}`,\n extra: { sessionID, phase: state.phase },\n },\n })\n } catch { /* best-effort */ }\n } finally {\n states.delete(sessionID)\n try {\n await ctx.client.app.log({\n body: {\n service: \"roundtable\",\n level: \"debug\",\n message: `State cleaned up for session #${sessionID}`,\n extra: { sessionID, phase: state.phase },\n },\n })\n } catch { /* best-effort */ }\n }\n}\n\n// ============================================================\n// processNextTurn\n// ============================================================\n\nexport async function processNextTurn(\n ctx: PluginInput,\n state: RoundtableState,\n): Promise<void> {\n if (state.phase === \"done\" || state.phase === \"aborted\") return\n\n const result = await ctx.client.session.messages({ path: { id: state.sessionID } })\n const messages = result.data\n\n const userMsgs = messages.filter((m: { info: { role: string } }) => m.info.role === \"user\")\n for (const msg of userMsgs) {\n for (const part of msg.parts) {\n if (part.type === \"text\") {\n if (!state.userInterjections.includes(part.text)) {\n state.userInterjections.push(part.text)\n }\n }\n }\n }\n\n const assistantMsgs = messages.filter(\n (m: { info: { role: string } }) => m.info.role === \"assistant\",\n )\n if (assistantMsgs.length === 0) return\n\n const latestMsg = assistantMsgs[assistantMsgs.length - 1]\n if (state.lastProcessedMsgId === latestMsg.info.id) return\n state.lastProcessedMsgId = latestMsg.info.id\n\n if (state.phase === \"active\") {\n const response = extractResponse(latestMsg.parts)\n if (!response) {\n state.errors.push(\n `Agent ${state.agents[state.currentAgentIndex]} returned no text in round ${state.currentRound + 1}`,\n )\n }\n\n const toolCalls = buildToolSummaries(latestMsg.parts)\n const entry: HistoryEntry = {\n agent: state.agents[state.currentAgentIndex],\n round: state.currentRound,\n response: response ?? \"(no text response)\",\n toolCalls,\n hasError: response === null,\n }\n state.history.push(entry)\n await saveStateFile(state)\n\n await ctx.client.app.log({\n body: {\n service: \"roundtable\",\n level: \"debug\",\n message: `Turn complete: ${entry.agent} (R${state.currentRound + 1})`,\n extra: {\n sessionID: state.sessionID, agent: entry.agent,\n round: state.currentRound + 1,\n responseLength: entry.response.length,\n toolCallCount: entry.toolCalls.length,\n hasError: entry.hasError,\n },\n },\n })\n\n if (detectLoop(state.history)) {\n state.errors.push(\"Loop detected — agents reached an impasse\")\n state.phase = \"done\"\n await ctx.client.app.log({\n body: {\n service: \"roundtable\",\n level: \"debug\",\n message: \"Loop detected — finalizing early\",\n extra: { sessionID: state.sessionID, similarity: getConfig().loopSimilarityThreshold },\n },\n })\n await finalizeRoundtable(ctx, state)\n return\n }\n\n const nextIndex = state.currentAgentIndex + 1\n if (nextIndex < state.agents.length) {\n state.currentAgentIndex = nextIndex\n await sendToAgent(ctx, state)\n } else if (state.currentRound + 1 < state.totalRounds) {\n state.currentRound++\n state.currentAgentIndex = 0\n await sendToAgent(ctx, state)\n } else {\n state.phase = \"observing\"\n await ctx.client.app.log({\n body: {\n service: \"roundtable\",\n level: \"debug\",\n message: \"All rounds complete — transitioning to observer\",\n extra: { sessionID: state.sessionID, totalRounds: state.totalRounds },\n },\n })\n await sendObserverPrompt(ctx, state)\n }\n return\n }\n\n if (state.phase === \"observing\") {\n const summary = extractResponse(latestMsg.parts)\n state.history.push({\n agent: \"observer\",\n round: state.currentRound,\n response: summary ?? \"(no summary)\",\n toolCalls: [],\n hasError: summary === null,\n })\n await saveStateFile(state)\n\n state.phase = \"done\"\n await finalizeRoundtable(ctx, state)\n }\n}\n\n// ============================================================\n// handleAgentError\n// ============================================================\n\nexport async function handleAgentError(\n ctx: PluginInput,\n state: RoundtableState,\n event: RoundtableEvent,\n): Promise<void> {\n if (state.phase === \"observing\" || state.phase === \"done\") {\n state.phase = \"aborted\"\n await saveStateFile(state)\n await finalizeRoundtable(ctx, state)\n return\n }\n\n const agent = state.agents[state.currentAgentIndex]\n const errorMsg =\n event.type === \"session.error\" && event.properties.error\n ? typeof event.properties.error === \"object\"\n ? (event.properties.error as { message?: string }).message ?? JSON.stringify(event.properties.error)\n : String(event.properties.error)\n : \"Unknown error\"\n\n state.errors.push(`Agent \"${agent}\" failed on round ${state.currentRound + 1}: ${errorMsg}`)\n\n const handle = timeoutHandles.get(state.sessionID)\n if (handle) { clearTimeout(handle); timeoutHandles.delete(state.sessionID) }\n\n await ctx.client.tui.showToast({\n body: {\n message: `\"${agent}\" failed on Round ${state.currentRound + 1}. Skipping to next.`,\n variant: \"warning\",\n },\n })\n\n const nextIndex = state.currentAgentIndex + 1\n if (nextIndex < state.agents.length) {\n state.currentAgentIndex = nextIndex\n try {\n await ctx.client.app.log({\n body: {\n service: \"roundtable\",\n level: \"debug\",\n message: \"Agent skipped due to error\",\n extra: { sessionID: state.sessionID, failedAgent: agent, nextAgent: state.agents[state.currentAgentIndex], round: state.currentRound + 1 },\n },\n })\n } catch { /* best-effort */ }\n await saveStateFile(state)\n await sendToAgent(ctx, state)\n } else if (state.currentRound + 1 < state.totalRounds) {\n state.currentRound++\n state.currentAgentIndex = 0\n try {\n await ctx.client.app.log({\n body: {\n service: \"roundtable\",\n level: \"debug\",\n message: \"Agent skipped due to error — moving to next round\",\n extra: { sessionID: state.sessionID, failedAgent: agent, round: state.currentRound + 1 },\n },\n })\n } catch { /* best-effort */ }\n await saveStateFile(state)\n await sendToAgent(ctx, state)\n } else {\n state.phase = \"aborted\"\n try {\n await ctx.client.tui.showToast({\n body: { message: \"All agents failed — roundtable aborted\", variant: \"error\" },\n })\n } catch { /* best-effort */ }\n await saveStateFile(state)\n await finalizeRoundtable(ctx, state)\n }\n}\n\n// ============================================================\n// handleSessionDeleted\n// ============================================================\n\nexport async function handleSessionDeleted(\n ctx: PluginInput,\n state: RoundtableState,\n deletedSessionID: string,\n): Promise<void> {\n const handle = timeoutHandles.get(state.sessionID)\n if (handle) { clearTimeout(handle); timeoutHandles.delete(state.sessionID) }\n\n await deleteStateFile(state.sessionID)\n\n if (deletedSessionID === state.sessionID) {\n state.phase = \"aborted\"\n const partialSummary = buildConsolidatedSummary(state)\n const output = [\n \"[Roundtable interrupted — session closed]\",\n \"Partial history up to interruption:\",\n \"\",\n partialSummary,\n ].join(\"\\n\")\n\n const pending = pendingResults.get(state.sessionID)\n if (pending) {\n pending.resolve(output)\n pendingResults.delete(state.sessionID)\n }\n\n try {\n await ctx.client.tui.showToast({\n body: { message: \"Roundtable interrupted\", variant: \"warning\" },\n })\n } catch { /* best-effort */ }\n try {\n await ctx.client.app.log({\n body: {\n service: \"roundtable\",\n level: \"debug\",\n message: \"S2 deleted — pending promise resolved with partial result\",\n extra: { sessionID: deletedSessionID, parentSessionID: state.parentSessionID },\n },\n })\n } catch { /* best-effort */ }\n } else if (deletedSessionID === state.parentSessionID) {\n state.phase = \"aborted\"\n try {\n await ctx.client.session.abort({ path: { id: state.sessionID } })\n } catch { /* S2 may already be gone */ }\n try {\n await ctx.client.app.log({\n body: {\n service: \"roundtable\",\n level: \"debug\",\n message: \"S1 deleted — S2 aborted\",\n extra: { sessionID: state.sessionID, parentSessionID: deletedSessionID },\n },\n })\n } catch { /* best-effort */ }\n }\n\n states.delete(state.sessionID)\n}\n\n// ============================================================\n// extendRoundtable\n// ============================================================\n\nexport async function extendRoundtable(\n ctx: PluginInput,\n args: RoundtableArgs,\n _toolCtx: { sessionID: string },\n): Promise<string> {\n const sessionID = args.sessionID!\n\n try {\n await ctx.client.session.get({ path: { id: sessionID } })\n } catch {\n return `Error: Session #${sessionID} not found or inaccessible. Cannot extend.`\n }\n\n const originalState = await loadStateFile(sessionID)\n if (!originalState) {\n return [\n `Error: No roundtable state found for session #${sessionID}.`,\n \"This session is not a roundtable or the state file was deleted.\",\n ].join(\"\\n\")\n }\n\n if (originalState.phase !== \"done\") {\n return [\n `Error: Roundtable #${sessionID} is in state \"${originalState.phase}\" and cannot be extended.`,\n ].join(\"\\n\")\n }\n\n if (args.agents && !arraysEqual(args.agents, originalState.agents)) {\n return [\n \"Error: Agent mismatch.\",\n `Original: ${originalState.agents.join(\", \")}`,\n `Provided: ${args.agents.join(\", \")}`,\n \"Extend must use the same agents as the original roundtable.\",\n ].join(\"\\n\")\n }\n\n try {\n const storedValidation = await validateAgents(ctx, originalState.agents)\n if (!storedValidation.valid) {\n return [\n \"Error: One or more agents from the original roundtable no longer exist.\",\n ...storedValidation.errors.map((e) => ` - ${e}`),\n ].join(\"\\n\")\n }\n } catch {\n return \"Error: Failed to validate agents. Cannot extend.\"\n }\n\n const extendedPrompt = buildExtendedPrompt(originalState.prompt, args.prompt)\n\n const newState: RoundtableState = {\n sessionID: originalState.sessionID,\n parentSessionID: originalState.parentSessionID,\n agents: originalState.agents,\n totalRounds: originalState.totalRounds + args.rounds,\n observer: originalState.observer,\n prompt: extendedPrompt,\n currentRound: originalState.currentRound,\n currentAgentIndex: 0,\n phase: \"active\",\n history: [...originalState.history],\n errors: [...originalState.errors],\n createdAt: Date.now(),\n currentGeneration: 0,\n userInterjections: [...(originalState.userInterjections ?? [])],\n }\n\n states.set(sessionID, newState)\n\n try {\n await saveStateFile(newState)\n\n const agentList = originalState.agents.join(\" vs \")\n await ctx.client.session.update({\n path: { id: sessionID },\n body: { title: `Roundtable: ${agentList} (R${newState.currentRound + 1}/${newState.totalRounds})` },\n })\n\n await ctx.client.session.prompt({\n path: { id: originalState.parentSessionID },\n body: {\n noReply: true,\n parts: [{\n type: \"text\",\n text: `The roundtable has been extended (${args.rounds} more round(s)). To extend again, use the tool roundtable({sessionID: \"${sessionID}\", rounds: N, prompt: \"...\"})`,\n }],\n },\n })\n\n await sendToAgent(ctx, newState)\n\n await ctx.client.tui.showToast({\n body: {\n message: `Roundtable #${sessionID} extended — ${args.rounds} more round(s) (${originalState.agents.join(\" → \")})`,\n variant: \"info\",\n },\n })\n\n return sessionID\n } catch (err) {\n states.delete(sessionID)\n throw err\n }\n}\n"
11
11
  ],
12
- "mappings": "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",
13
- "debugId": "3293C14B588953DF64756E2164756E21",
12
+ "mappings": "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",
13
+ "debugId": "BEEF18A38922C86164756E2164756E21",
14
14
  "names": []
15
15
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rrr2010/opencode-roundtable",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Multi-agent round-robin debate plugin for OpenCode",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -11,10 +11,15 @@
11
11
  "import": "./dist/index.js",
12
12
  "require": "./dist/index.js",
13
13
  "types": "./dist/index.d.ts"
14
+ },
15
+ "./tui": {
16
+ "import": "./src/tui/tui.tsx",
17
+ "types": "./src/tui/tui.tsx"
14
18
  }
15
19
  },
16
20
  "files": [
17
21
  "dist",
22
+ "src/tui/",
18
23
  "README.md",
19
24
  "docs/SPEC.md",
20
25
  "docs/roundtable.schema.json",
@@ -24,7 +29,7 @@
24
29
  "build": "bun build index.ts --outdir dist --target node --format esm --sourcemap --external @opencode-ai/plugin --external @opencode-ai/sdk",
25
30
  "typecheck": "tsc --noEmit",
26
31
  "prepublishOnly": "bun run build",
27
- "dev:copy": "cp src/roundtable.ts ~/.config/opencode/plugins/roundtable.ts"
32
+ "dev:install": "bun run build && npm link"
28
33
  },
29
34
  "keywords": [
30
35
  "opencode",
@@ -43,7 +48,10 @@
43
48
  "url": "https://github.com/opencode-ai/roundtable/issues"
44
49
  },
45
50
  "peerDependencies": {
46
- "@opencode-ai/plugin": "latest"
51
+ "@opencode-ai/plugin": "latest",
52
+ "@opentui/core": "^0.4.2",
53
+ "@opentui/solid": "^0.4.2",
54
+ "solid-js": "^1.9.12"
47
55
  },
48
56
  "devDependencies": {
49
57
  "@opencode-ai/plugin": "latest",
@@ -0,0 +1,99 @@
1
+ /** @jsxImportSource @opentui/solid */
2
+
3
+ import type { TuiPluginModule, TuiPluginApi } from "@opencode-ai/plugin/tui"
4
+ import { createResource } from "solid-js"
5
+
6
+ let api: TuiPluginApi
7
+
8
+ function Badge(props: { title: string }) {
9
+ const match = () => props.title.match(/^\(Roundtable\) - (.+?)(?: · CONCLUDED)?$/)
10
+ if (!match()) return null
11
+ const label = match()![1]
12
+ const isConcluded = props.title.includes("· CONCLUDED")
13
+ return (
14
+ <span>
15
+ {" "}
16
+ <span
17
+ style={{
18
+ color: isConcluded ? "var(--text-muted)" : "var(--accent)",
19
+ fontWeight: "bold",
20
+ }}
21
+ >
22
+ RT
23
+ </span>
24
+ <span style={{ color: "var(--text-muted)", fontSize: "0.9em" }}>
25
+ {" "}{label.length > 30 ? label.slice(0, 27) + "..." : label}
26
+ </span>
27
+ </span>
28
+ )
29
+ }
30
+
31
+ function LinkPanel(props: { sessionId: string }) {
32
+ const [session] = createResource(
33
+ () => props.sessionId,
34
+ async (id: string) => {
35
+ try {
36
+ return await api.client.session.get({ path: { id } })
37
+ } catch {
38
+ return null
39
+ }
40
+ },
41
+ )
42
+
43
+ const isRoundtable = () => {
44
+ const s = session()
45
+ return s?.data?.title?.startsWith("(Roundtable)")
46
+ }
47
+
48
+ const parentId = () => {
49
+ const s = session()
50
+ return s?.data?.parent_session_id
51
+ }
52
+
53
+ return (
54
+ <div style={{ padding: "0 8px" }}>
55
+ {isRoundtable() && parentId() && (
56
+ <div
57
+ style={{
58
+ cursor: "pointer",
59
+ color: "var(--accent)",
60
+ textDecoration: "underline",
61
+ fontSize: "0.9em",
62
+ }}
63
+ onClick={() => api.route.navigate("session", { sessionID: parentId()! })}
64
+ >
65
+ ← Parent session
66
+ </div>
67
+ )}
68
+ {!isRoundtable() && (
69
+ <div
70
+ style={{
71
+ cursor: "pointer",
72
+ color: "var(--accent)",
73
+ textDecoration: "underline",
74
+ fontSize: "0.9em",
75
+ }}
76
+ onClick={() => api.route.navigate("sessions")}
77
+ >
78
+ View sessions →
79
+ </div>
80
+ )}
81
+ </div>
82
+ )
83
+ }
84
+
85
+ const tui: TuiPluginModule["tui"] = async (a) => {
86
+ api = a
87
+
88
+ api.slots.register({
89
+ sidebar_title: (props) => <Badge title={props.title} />,
90
+ sidebar_content: (props) => <LinkPanel sessionId={props.session_id} />,
91
+ })
92
+
93
+ api.lifecycle.onDispose(() => {})
94
+ }
95
+
96
+ export default {
97
+ id: "opencode-roundtable",
98
+ tui,
99
+ } satisfies TuiPluginModule