@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 +15 -10
- package/dist/index.js +68 -86
- package/dist/index.js.map +7 -7
- package/package.json +11 -3
- package/src/tui/tui.tsx +99 -0
package/README.md
CHANGED
|
@@ -9,20 +9,26 @@ executive summary.
|
|
|
9
9
|
|
|
10
10
|
## Installation
|
|
11
11
|
|
|
12
|
-
###
|
|
12
|
+
### npm (recommended)
|
|
13
13
|
|
|
14
|
-
```
|
|
15
|
-
|
|
14
|
+
```json
|
|
15
|
+
{
|
|
16
|
+
"plugin": ["@rrr2010/opencode-roundtable@latest"]
|
|
17
|
+
}
|
|
16
18
|
```
|
|
17
19
|
|
|
18
|
-
|
|
20
|
+
OpenCode auto-installs npm plugins on startup. No manual copy needed.
|
|
21
|
+
|
|
22
|
+
### Local (dev)
|
|
19
23
|
|
|
20
|
-
|
|
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
|
-
|
|
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
|
|
98
|
-
|
|
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
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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
|
|
115
|
+
async function loadStateFile(sessionID) {
|
|
115
116
|
try {
|
|
116
|
-
const
|
|
117
|
-
const
|
|
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:
|
|
343
|
-
extra: {
|
|
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
|
|
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
|
|
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"
|
|
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
|
-
|
|
784
|
-
|
|
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
|
|
793
|
-
"This session is not a roundtable or the state was
|
|
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
|
-
|
|
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
|
|
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
|
|
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=
|
|
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).
|
|
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
|
|
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
|
|
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(`[
|
|
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": "
|
|
12
|
+
"mappings": ";AAAA;;;ACAA;AACA;AACA;AAIA,IAAM,aAAa,MAAM;AAAA,EACvB,MAAM,gBAAgB,QAAQ,IAAI;AAAA,EAClC,IAAI;AAAA,IAAe,OAAO,KAAK,eAAe,UAAU;AAAA,EACxD,OAAO,KAAK,GAAG,QAAQ,GAAG,WAAW,UAAU;AAAA,GAC9C;AAEH,IAAM,aAAa,KAAK,WAAW,iBAAiB;AAEpD,IAAM,kBACJ;AAEF,IAAM,iBAA+B;AAAA,EACnC,kBAAkB;AAAA,EAClB,yBAAyB;AAAA,EACzB,sBAAsB;AAAA,EACtB,uBAAuB;AAAA,IACrB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK;AAAA,CAAI;AAAA,EACX,WAAW;AACb;AAEA,IAAI,SAAuB,KAAK,eAAe;AAExC,SAAS,SAAS,GAAiB;AAAA,EACxC,OAAO;AAAA;AAGT,SAAS,cAAc,CAAC,KAA4C;AAAA,EAClE,OAAO;AAAA,IACL,kBACE,OAAO,IAAI,qBAAqB,YAAY,IAAI,oBAAoB,QAChE,IAAI,mBACJ,eAAe;AAAA,IACrB,yBACE,OAAO,IAAI,4BAA4B,YACvC,IAAI,2BAA2B,KAC/B,IAAI,2BAA2B,IAC3B,IAAI,0BACJ,eAAe;AAAA,IACrB,sBACE,OAAO,IAAI,yBAAyB,YAAY,IAAI,wBAAwB,MACxE,IAAI,uBACJ,eAAe;AAAA,IACrB,uBACE,OAAO,IAAI,0BAA0B,YAAY,IAAI,sBAAsB,SAAS,IAChF,IAAI,wBACJ,eAAe;AAAA,IACrB,WACE,OAAO,IAAI,cAAc,YAAY,IAAI,aAAa,IAClD,IAAI,YACJ,eAAe;AAAA,EACvB;AAAA;AAGF,eAAsB,UAAU,CAAC,KAAiC;AAAA,EAChE,IAAI;AAAA,IACF,MAAM,UAAU,MAAM,SAAS,YAAY,OAAO;AAAA,IAClD,MAAM,MAAM,KAAK,MAAM,OAAO;AAAA,IAC9B,IAAI,OAAO,QAAQ,YAAY,CAAC;AAAA,MAAK,MAAM,IAAI,MAAM,uBAAuB;AAAA,IAC5E,SAAS,eAAe,GAA8B;AAAA,IACtD,MAAM,IAAI,OAAO,IAAI,IAAI;AAAA,MACvB,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,OAAO;AAAA,QACP,SAAS;AAAA,QACT,OAAO,EAAE,WAAW;AAAA,MACtB;AAAA,IACF,CAAC;AAAA,IACD,OAAO,KAAK;AAAA,IACZ,IACE,OAAO,QAAQ,YACf,QAAQ,QACR,UAAU,OACT,IAAyB,SAAS,UACnC;AAAA,MACA,IAAI;AAAA,QACF,MAAM,UACJ,YACA,KAAK,UAAU,EAAE,SAAS,oBAAoB,eAAe,GAAG,MAAM,CAAC,GACvE,OACF;AAAA,QACA,SAAS,KAAK,eAAe;AAAA,QAC7B,MAAM,IAAI,OAAO,IAAI,IAAI;AAAA,UACvB,MAAM;AAAA,YACJ,SAAS;AAAA,YACT,OAAO;AAAA,YACP,SAAS;AAAA,YACT,OAAO,EAAE,WAAW;AAAA,UACtB;AAAA,QACF,CAAC;AAAA,QACD,MAAM;AAAA,QACN,SAAS,KAAK,eAAe;AAAA;AAAA,IAEjC,EAAO;AAAA,MACL,IAAI;AAAA,QACF,MAAM,IAAI,OAAO,IAAI,IAAI;AAAA,UACvB,MAAM;AAAA,YACJ,SAAS;AAAA,YACT,OAAO;AAAA,YACP,SAAS,mCAAmC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,YAC3F,OAAO,EAAE,WAAW;AAAA,UACtB;AAAA,QACF,CAAC;AAAA,QACD,MAAM;AAAA,MACR,SAAS,KAAK,eAAe;AAAA;AAAA;AAAA;;;ACrHnC,qBAAS,wBAAU;AACnB,iBAAS;AACT;AAGA,IAAM,aAAa,MAAM;AAAA,EACvB,MAAM,gBAAgB,QAAQ,IAAI;AAAA,EAClC,MAAM,OAAO,gBAAgB,MAAK,eAAe,UAAU,IAAI,MAAK,IAAG,QAAQ,GAAG,WAAW,UAAU;AAAA,EACvG,OAAO,MAAK,MAAM,mBAAmB;AAAA,GACpC;AAEI,IAAM,SAAS,IAAI;AACnB,IAAM,iBAAiB,IAAI;AAC3B,IAAM,iBAAiB,IAAI;AAIlC,SAAS,aAAa,CAAC,WAA2B;AAAA,EAChD,OAAO,MAAK,WAAW,GAAG,gBAAgB;AAAA;AAG5C,eAAsB,aAAa,CAAC,OAAuC;AAAA,EACzE,IAAI;AAAA,IACF,MAAM,MAAM,WAAW,EAAE,WAAW,KAAK,CAAC;AAAA,IAC1C,MAAM;AAAA,EACR,MAAM,WAAW,cAAc,MAAM,SAAS;AAAA,EAC9C,MAAM,WAAU,UAAU,KAAK,UAAU,OAAO,MAAM,CAAC,GAAG,OAAO;AAAA;AAGnE,eAAsB,aAAa,CAAC,WAAoD;AAAA,EACtF,IAAI;AAAA,IACF,MAAM,UAAU,MAAM,UAAS,cAAc,SAAS,GAAG,OAAO;AAAA,IAChE,MAAM,SAAS,KAAK,MAAM,OAAO;AAAA,IACjC,IAAI,OAAO,WAAW,YAAY,CAAC;AAAA,MAAQ,OAAO;AAAA,IAClD,IAAI,OAAO,OAAO,cAAc;AAAA,MAAU,OAAO;AAAA,IACjD,IAAI,OAAO,OAAO,oBAAoB;AAAA,MAAU,OAAO;AAAA,IACvD,IAAI,CAAC,MAAM,QAAQ,OAAO,MAAM;AAAA,MAAG,OAAO;AAAA,IAC1C,IAAI,OAAO,OAAO,gBAAgB;AAAA,MAAU,OAAO;AAAA,IACnD,IAAI,OAAO,OAAO,WAAW;AAAA,MAAU,OAAO;AAAA,IAC9C,OAAO;AAAA,MACL,WAAW,OAAO;AAAA,MAClB,iBAAiB,OAAO;AAAA,MACxB,QAAQ,OAAO;AAAA,MACf,aAAa,OAAO;AAAA,MACpB,UAAU,OAAO,YAAY;AAAA,MAC7B,QAAQ,OAAO;AAAA,MACf,cAAc,OAAO,gBAAgB;AAAA,MACrC,mBAAmB,OAAO,qBAAqB;AAAA,MAC/C,OAAO,OAAO,SAAS;AAAA,MACvB,SAAS,OAAO,WAAW,CAAC;AAAA,MAC5B,QAAQ,OAAO,UAAU,CAAC;AAAA,MAC1B,WAAW,OAAO,aAAa;AAAA,MAC/B,mBAAmB,OAAO,qBAAqB;AAAA,MAC/C,mBAAmB,OAAO,qBAAqB,CAAC;AAAA,MAChD,oBAAoB,OAAO,sBAAsB;AAAA,IACnD;AAAA,IACA,MAAM;AAAA,IACN,OAAO;AAAA;AAAA;AAIX,eAAsB,eAAe,CAAC,WAAkC;AAAA,EACtE,IAAI;AAAA,IACF,MAAM,OAAO,cAAc,SAAS,CAAC;AAAA,IACrC,MAAM;AAAA;AAGV,eAAsB,cAAc,GAAsB;AAAA,EACxD,IAAI;AAAA,IACF,MAAM,UAAU,MAAM,QAAQ,SAAS;AAAA,IACvC,OAAO,QACJ,OAAO,CAAC,MAAM,EAAE,SAAS,OAAO,CAAC,EACjC,IAAI,CAAC,MAAM,EAAE,QAAQ,WAAW,EAAE,CAAC;AAAA,IACtC,MAAM;AAAA,IACN,OAAO,CAAC;AAAA;AAAA;;;ACrEL,SAAS,oBAAoB,CAAC,MAAqD;AAAA,EACxF,IAAI,KAAK;AAAA,IAAO,OAAO,KAAK;AAAA,EAC5B,MAAM,UAAU,KAAK,OAAO,SAAS,KAAK,KAAK,OAAO,MAAM,GAAG,EAAE,IAAI,QAAQ,KAAK;AAAA,EAClF,OAAO,kBAAkB;AAAA;AAGpB,SAAS,qBAAqB,CAAC,OAAkF;AAAA,EACtH,IAAI,EAAE,gBAAgB;AAAA,IAAQ;AAAA,EAC9B,MAAM,QAAQ,MAAM;AAAA,EACpB,IAAI,OAAO,MAAM,cAAc;AAAA,IAAU,OAAO,MAAM;AAAA,EACtD,IAAI,MAAM,QAAQ,OAAO,MAAM,SAAS,UAAU;AAAA,IAChD,MAAM,OAAO,MAAM;AAAA,IACnB,IAAI,KAAK;AAAA,MAAI,OAAO,KAAK;AAAA,EAC3B;AAAA,EACA;AAAA;AAGF,eAAsB,cAAc,CAClC,KACA,YACoG;AAAA,EACpG,MAAM,SAAmB,CAAC;AAAA,EAC1B,IAAI,WAAW,SAAS,GAAG;AAAA,IACzB,OAAO,KAAK,gCAAgC;AAAA,IAC5C,OAAO,EAAE,OAAO,OAAO,WAAW,CAAC,GAAG,OAAO;AAAA,EAC/C;AAAA,EAEA,IAAI,YAAsD,CAAC;AAAA,EAC3D,IAAI;AAAA,IACF,MAAM,SAAS,MAAM,IAAI,OAAO,IAAI,OAAO;AAAA,IAC3C,YAAY,OAAO,KAAK,IAAI,CAAC,OAA+C;AAAA,MAC1E,MAAM,EAAE;AAAA,MACR,aAAa,EAAE;AAAA,IACjB,EAAE;AAAA,IACF,MAAM;AAAA,IACN,OAAO,KAAK,8CAA8C;AAAA,IAC1D,OAAO,EAAE,OAAO,OAAO,WAAW,CAAC,GAAG,OAAO;AAAA;AAAA,EAG/C,MAAM,iBAAiB,IAAI,IAAI,UAAU,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;AAAA,EAC3D,WAAW,QAAQ,YAAY;AAAA,IAC7B,IAAI,CAAC,eAAe,IAAI,IAAI;AAAA,MAAG,OAAO,KAAK,UAAU,iBAAiB;AAAA,EACxE;AAAA,EAEA,OAAO,EAAE,OAAO,OAAO,WAAW,GAAG,WAAW,OAAO;AAAA;AAGlD,SAAS,WAAW,CAAC,GAAa,GAAsB;AAAA,EAC7D,IAAI,EAAE,WAAW,EAAE;AAAA,IAAQ,OAAO;AAAA,EAClC,SAAS,IAAI,EAAG,IAAI,EAAE,QAAQ;AAAA,IAAK,IAAI,EAAE,OAAO,EAAE;AAAA,MAAI,OAAO;AAAA,EAC7D,OAAO;AAAA;AAGF,SAAS,UAAU,CAAC,SAAkC;AAAA,EAC3D,IAAI,QAAQ,SAAS;AAAA,IAAG,OAAO;AAAA,EAC/B,MAAM,OAAO,QAAQ,QAAQ,SAAS,GAAG;AAAA,EACzC,MAAM,OAAO,QAAQ,QAAQ,SAAS,GAAG;AAAA,EAEzC,MAAM,UAAU,CAAC,MAA2B;AAAA,IAC1C,MAAM,MAAM,IAAI;AAAA,IAChB,MAAM,UAAU,EAAE,QAAQ,cAAc,GAAG;AAAA,IAC3C,SAAS,IAAI,EAAG,IAAI,QAAQ,SAAS,GAAG;AAAA,MAAK,IAAI,IAAI,QAAQ,MAAM,GAAG,IAAI,CAAC,CAAC;AAAA,IAC5E,OAAO;AAAA;AAAA,EAGT,MAAM,cAAc,QAAQ,IAAI;AAAA,EAChC,MAAM,cAAc,QAAQ,IAAI;AAAA,EAChC,IAAI,eAAe;AAAA,EACnB,WAAW,KAAK;AAAA,IAAa,IAAI,YAAY,IAAI,CAAC;AAAA,MAAG;AAAA,EAErD,MAAM,QAAQ,IAAI,IAAI,CAAC,GAAG,aAAa,GAAG,WAAW,CAAC;AAAA,EACtD,IAAI,MAAM,SAAS;AAAA,IAAG,OAAO;AAAA,EAC7B,OAAO,eAAe,MAAM,OAAO,UAAU,EAAE;AAAA;AAG1C,SAAS,eAAe,CAAC,OAA8B;AAAA,EAC5D,WAAW,QAAQ;AAAA,IAAO,IAAI,KAAK,SAAS;AAAA,MAAQ,OAAO,KAAK;AAAA,EAChE,OAAO;AAAA;AAGF,SAAS,gBAAgB,CAAC,MAAoC;AAAA,EACnE,IAAI,KAAK,SAAS;AAAA,IAAQ,OAAO;AAAA,EACjC,MAAM,WAAY,KAAqC;AAAA,EACvD,MAAM,QAAS,KAAmE;AAAA,EAClF,IAAI;AAAA,EACJ,QAAQ,MAAM;AAAA,SACP;AAAA,MACH,gBAAgB,MAAM,OAAQ,MAAM,GAAG,UAAU,EAAE,oBAAoB;AAAA,MACvE;AAAA,SACG;AAAA,MACH,iBAAiB,MAAM,UAAU,mBAAmB,MAAM,GAAG,UAAU,EAAE,oBAAoB;AAAA,MAC7F;AAAA,SACG;AAAA,SACA;AAAA,MACH,gBAAgB,IAAI,MAAM;AAAA,MAC1B;AAAA;AAAA,MAEA,gBAAgB;AAAA;AAAA,EAEpB,OAAO,EAAE,UAAU,cAAc;AAAA;AAG5B,SAAS,kBAAkB,CAAC,OAAkC;AAAA,EACnE,MAAM,YAA+B,CAAC;AAAA,EACtC,WAAW,QAAQ,OAAO;AAAA,IACxB,MAAM,UAAU,iBAAiB,IAAI;AAAA,IACrC,IAAI;AAAA,MAAS,UAAU,KAAK,OAAO;AAAA,EACrC;AAAA,EACA,OAAO;AAAA;AAGF,SAAS,wBAAwB,CAAC,OAAgC;AAAA,EACvE,MAAM,QAAkB,CAAC;AAAA,EACzB,MAAM,KAAK,8BAA6B;AAAA,EACxC,MAAM,KAAK,UAAU,MAAM,QAAQ;AAAA,EACnC,MAAM,KAAK,iBAAiB,MAAM,OAAO,KAAK,IAAI,GAAG;AAAA,EACrD,IAAI,MAAM,OAAO,SAAS;AAAA,IAAG,MAAM,KAAK,WAAW,MAAM,OAAO,KAAK,IAAI,GAAG;AAAA,EAC5E,MAAM,KAAK,EAAE;AAAA,EAEb,WAAW,SAAS,MAAM,SAAS;AAAA,IACjC,MAAM,QAAQ,MAAM,UAAU,aAAa,aAAa,GAAG,MAAM,gBAAgB,MAAM,QAAQ;AAAA,IAC/F,MAAM,KAAK,MAAK,UAAU;AAAA,IAC1B,MAAM,KAAK,MAAM,QAAQ;AAAA,IACzB,IAAI,MAAM,UAAU,SAAS,GAAG;AAAA,MAC9B,MAAM,KAAK,GAAG,MAAM,UAAU,IAAI,CAAC,OAAO,OAAY,GAAG,cAAmB,GAAG,cAAc,MAAM,GAAG,EAAE,GAAG,CAAC;AAAA,IAC9G;AAAA,IACA,IAAI,MAAM;AAAA,MAAU,MAAM,KAAK,8BAAmC;AAAA,IAClE,MAAM,KAAK,EAAE;AAAA,EACf;AAAA,EACA,OAAO,MAAM,KAAK;AAAA,CAAI;AAAA;AAGxB,eAAsB,yBAAyB,CAC7C,KACA,WACe;AAAA,EACf,MAAM,YAAY;AAAA,IAChB;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK;AAAA,CAAI;AAAA,EAEX,MAAM,IAAI,OAAO,QAAQ,OAAO;AAAA,IAC9B,MAAM,EAAE,IAAI,UAAU;AAAA,IACtB,MAAM,EAAE,SAAS,MAAM,OAAO,CAAC,EAAE,MAAM,QAAQ,MAAM,UAAU,CAAC,EAAE;AAAA,EACpE,CAAC;AAAA;AAGI,SAAS,mBAAmB,CAAC,gBAAwB,cAA8B;AAAA,EACxF,MAAM,uBAAuB;AAAA,IAC3B;AAAA,IAAe;AAAA,IAAY;AAAA,IAAe;AAAA,IAC1C;AAAA,IAAa;AAAA,IAAa;AAAA,IAAmB;AAAA,EAC/C;AAAA,EACA,MAAM,QAAQ,aAAa,YAAY,EAAE,KAAK;AAAA,EAC9C,MAAM,iBAAiB,qBAAqB,KAAK,CAAC,YAAY,MAAM,WAAW,OAAO,CAAC;AAAA,EAEvF,IAAI,gBAAgB;AAAA,IAClB,OAAO,mBAAmB;AAAA;AAAA,gBAAmC;AAAA,EAC/D;AAAA,EAEA,OAAO;AAAA,IACL;AAAA,IACA,KAAK;AAAA,IACL;AAAA,IACA,kBAAkB;AAAA,EACpB,EAAE,KAAK;AAAA,CAAI;AAAA;AAGb,eAAsB,qBAAqB,CAAC,KAAiC;AAAA,EAC3E,MAAM,aAAa,MAAM,eAAe;AAAA,EACxC,IAAI,SAAS;AAAA,EACb,IAAI,SAAS;AAAA,EACb,WAAW,OAAO,YAAY;AAAA,IAC5B,IAAI;AAAA,MACF,MAAM,QAAQ,MAAM,cAAc,GAAG;AAAA,MACrC,IAAI,OAAO;AAAA,QACT,OAAO,IAAI,KAAK,KAAK;AAAA,QACrB;AAAA,MACF;AAAA,MACA,MAAM;AAAA,MACN;AAAA;AAAA,EAEJ;AAAA,EACA,MAAM,IAAI,OAAO,IAAI,IAAI;AAAA,IACvB,MAAM;AAAA,MACJ,SAAS;AAAA,MACT,OAAO;AAAA,MACP,SAAS,0BAA0B,2BAA2B;AAAA,MAC9D,OAAO,EAAE,QAAQ,QAAQ,OAAO,WAAW,OAAO;AAAA,IACpD;AAAA,EACF,CAAC;AAAA;;;AChMI,SAAS,gBAAgB,CAAC,OAAwB,OAAuB;AAAA,EAC9E,MAAM,QAAkB,CAAC;AAAA,EACzB,MAAM,YAAY,MAAM,OAAO,KAAK,KAAI;AAAA,EACxC,MAAM,YAAY,SAAS,MAAM,eAAe,KAAK,MAAM,gCAAgC;AAAA,EAE3F,IAAI,MAAM,iBAAiB,KAAK,MAAM,sBAAsB,GAAG;AAAA,IAC7D,MAAM,KAAK,kEAAkE,8CAA8C,MAAM,uBAAuB;AAAA,IACxJ,MAAM,KAAK,WAAW,MAAM,QAAQ;AAAA,IACpC,MAAM,KAAK,EAAE;AAAA,EACf;AAAA,EAEA,MAAM,KAAK,SAAS;AAAA,EAEpB,MAAM,cAAc,MAAM,sBAAsB,MAAM,OAAO,SAAS;AAAA,EACtE,MAAM,cAAc,MAAM,iBAAiB,MAAM,cAAc;AAAA,EAC/D,IAAI,eAAe,aAAa;AAAA,IAC9B,MAAM,KAAK,2DAA0D;AAAA,EACvE;AAAA,EAEA,OAAO,MAAM,KAAK;AAAA,CAAI;AAAA;AAGjB,SAAS,mBAAmB,CAAC,OAAwB,UAAuC;AAAA,EACjG,MAAM,iBAAiB,UAAU,EAAE;AAAA,EAEnC,IAAI,aAAa;AAAA,IAAY,OAAO;AAAA,EAEpC,OACE;AAAA,IACA,cAAc;AAAA;AAAA,IACd;AAAA;;;AClBJ,eAAsB,kBAAkB,CACtC,KACA,MACA,SACiB;AAAA,EACjB,MAAM,SAAS,KAAK;AAAA,EACpB,MAAM,aAAa,MAAM,IAAI,OAAO,QAAQ,OAAO;AAAA,IACjD,MAAM,EAAE,OAAO,qBAAqB,KAAK,MAAM,OAAO,CAAC,EAAE;AAAA,EAC3D,CAAC;AAAA,EAED,MAAM,YAAY,WAAW,KAAK;AAAA,EAClC,MAAM,kBAAkB,QAAQ;AAAA,EAEhC,MAAM,QAAyB;AAAA,IAC7B;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,KAAK;AAAA,IAClB,UAAU,KAAK,YAAY;AAAA,IAC3B,QAAQ,KAAK;AAAA,IACb,cAAc;AAAA,IACd,mBAAmB;AAAA,IACnB,OAAO;AAAA,IACP,SAAS,CAAC;AAAA,IACV,QAAQ,CAAC;AAAA,IACT,WAAW,KAAK,IAAI;AAAA,IACpB,mBAAmB;AAAA,IACnB,mBAAmB,CAAC;AAAA,EACtB;AAAA,EAEA,OAAO,IAAI,WAAW,KAAK;AAAA,EAE3B,IAAI;AAAA,IACF,MAAM,cAAc,KAAK;AAAA,IACzB,MAAM,YAAY,KAAK,KAAK;AAAA,IAE5B,MAAM,IAAI,OAAO,QAAQ,OAAO;AAAA,MAC9B,MAAM,EAAE,IAAI,gBAAgB;AAAA,MAC5B,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,OAAO,CAAC;AAAA,UACN,MAAM;AAAA,UACN,MAAM,uCAAuC,OAAO,KAAK,IAAI,MAAM,KAAK,8EAA8E;AAAA,QACxJ,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAAA,IAED,MAAM,IAAI,OAAO,IAAI,UAAU;AAAA,MAC7B,MAAM;AAAA,QACJ,SAAS,0BAA0B,cAAc,OAAO,KAAK,KAAI,OAAO,KAAK;AAAA,QAC7E,SAAS;AAAA,MACX;AAAA,IACF,CAAC;AAAA,IAED,OAAO;AAAA,IACP,OAAO,KAAK;AAAA,IACZ,OAAO,OAAO,SAAS;AAAA,IACvB,MAAM;AAAA;AAAA;AAQV,eAAsB,WAAW,CAC/B,KACA,OACe;AAAA,EACf,IAAI;AAAA,IACF,MAAM,QAAQ,MAAM,OAAO,MAAM;AAAA,IACjC,MAAM,SAAS,iBAAiB,OAAO,KAAK;AAAA,IAE5C,MAAM,IAAI,OAAO,QAAQ,OAAO;AAAA,MAC9B,MAAM,EAAE,IAAI,MAAM,UAAU;AAAA,MAC5B,MAAM,EAAE,OAAO,OAAO,CAAC,EAAE,MAAM,QAAQ,MAAM,OAAO,CAAC,EAAE;AAAA,IACzD,CAAC;AAAA,IAED,MAAM;AAAA,IACN,MAAM,qBAAqB,MAAM;AAAA,IAEjC,MAAM,SAAS,WAAW,YAAY;AAAA,MACpC,eAAe,OAAO,MAAM,SAAS;AAAA,MACrC,IAAI,MAAM,sBAAsB;AAAA,QAAoB;AAAA,MAEpD,IAAI;AAAA,QACF,MAAM,IAAI,OAAO,QAAQ,MAAM,EAAE,MAAM,EAAE,IAAI,MAAM,UAAU,EAAE,CAAC;AAAA,QAChE,MAAM,OAAO,KAAK,UAAU,0BAA0B,UAAU,EAAE,mBAAmB,OAAO;AAAA,QAC5F,MAAM;AAAA,OACP,UAAU,EAAE,gBAAgB;AAAA,IAE/B,eAAe,IAAI,MAAM,WAAW,MAAM;AAAA,IAC1C,MAAM,mBAAmB,KAAK,KAAK;AAAA,IAEnC,MAAM,IAAI,OAAO,IAAI,IAAI;AAAA,MACvB,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,OAAO;AAAA,QACP,SAAS,iBAAiB,WAAW,MAAM,eAAe,KAAK,MAAM;AAAA,QACrE,OAAO;AAAA,UACL,WAAW,MAAM;AAAA,UAAW;AAAA,UAC5B,OAAO,MAAM,eAAe;AAAA,UAC5B,aAAa,MAAM;AAAA,UACnB,YAAY,MAAM;AAAA,QACpB;AAAA,MACF;AAAA,IACF,CAAC;AAAA,IACD,OAAO,KAAK;AAAA,IACZ,MAAM,OAAO,KACX,4BAA4B,MAAM,OAAO,MAAM,wBAAwB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,GACxH;AAAA,IACA,MAAM,SAAS,eAAe,IAAI,MAAM,SAAS;AAAA,IACjD,IAAI,QAAQ;AAAA,MAAE,aAAa,MAAM;AAAA,MAAG,eAAe,OAAO,MAAM,SAAS;AAAA,IAAE;AAAA;AAAA;AAQ/E,eAAsB,kBAAkB,CACtC,KACA,OACe;AAAA,EACf,MAAM,UAAU,MAAM,OAAO,SAAS,KAAK,MAAM,OAAO,MAAM,GAAG,EAAE,IAAI,QAAQ,MAAM;AAAA,EACrF,MAAM,IAAI,OAAO,QAAQ,OAAO;AAAA,IAC9B,MAAM,EAAE,IAAI,MAAM,UAAU;AAAA,IAC5B,MAAM,EAAE,OAAO,kBAAkB,UAAU;AAAA,EAC7C,CAAC;AAAA;AAOH,eAAe,kBAAkB,CAC/B,KACA,OACe;AAAA,EACf,IAAI;AAAA,IACF,MAAM,SAAS,oBAAoB,OAAO,MAAM,QAAQ;AAAA,IAExD,IAAI,MAAM,aAAa,YAAY;AAAA,MACjC,MAAM,IAAI,OAAO,QAAQ,OAAO;AAAA,QAC9B,MAAM,EAAE,IAAI,MAAM,UAAU;AAAA,QAC5B,MAAM,EAAE,SAAS,OAAO,OAAO,CAAC,EAAE,MAAM,QAAQ,MAAM,OAAO,CAAC,EAAE;AAAA,MAClE,CAAC;AAAA,IACH,EAAO;AAAA,MACL,MAAM,IAAI,OAAO,QAAQ,OAAO;AAAA,QAC9B,MAAM,EAAE,IAAI,MAAM,UAAU;AAAA,QAC5B,MAAM,EAAE,OAAO,MAAM,UAAU,OAAO,CAAC,EAAE,MAAM,QAAQ,MAAM,OAAO,CAAC,EAAE;AAAA,MACzE,CAAC;AAAA;AAAA,IAGH,MAAM,IAAI,OAAO,IAAI,IAAI;AAAA,MACvB,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,OAAO;AAAA,QACP,SAAS,yBAAyB,MAAM;AAAA,QACxC,OAAO,EAAE,WAAW,MAAM,WAAW,UAAU,MAAM,SAAS;AAAA,MAChE;AAAA,IACF,CAAC;AAAA,IACD,OAAO,KAAK;AAAA,IACZ,MAAM,OAAO,KAAK,mCAAmC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,GAAG;AAAA,IACvG,MAAM,QAAQ;AAAA,IACd,MAAM,mBAAmB,KAAK,KAAK;AAAA;AAAA;AAQvC,eAAsB,kBAAkB,CACtC,KACA,OACe;AAAA,EACf,MAAM,YAAY,MAAM;AAAA,EAExB,MAAM,gBAAgB,eAAe,IAAI,SAAS;AAAA,EAClD,IAAI,eAAe;AAAA,IAAE,aAAa,aAAa;AAAA,IAAG,eAAe,OAAO,SAAS;AAAA,EAAE;AAAA,EAEnF,IAAI;AAAA,IACF,MAAM,UAAU,yBAAyB,KAAK;AAAA,IAE9C,MAAM,UAAU,eAAe,IAAI,SAAS;AAAA,IAC5C,IAAI,SAAS;AAAA,MACX,QAAQ,QAAQ,OAAO;AAAA,MACvB,eAAe,OAAO,SAAS;AAAA,IACjC;AAAA,IAEA,MAAM,0BAA0B,KAAK,SAAS;AAAA,IAE9C,MAAM,cAAc,MAAM,OAAO,SAAS,KAAK,MAAM,OAAO,MAAM,GAAG,EAAE,IAAI,QAAQ,MAAM;AAAA,IACzF,MAAM,IAAI,OAAO,QAAQ,OAAO;AAAA,MAC9B,MAAM,EAAE,IAAI,UAAU;AAAA,MACtB,MAAM,EAAE,OAAO,kBAAkB,0BAAyB;AAAA,IAC5D,CAAC;AAAA,IAED,IAAI;AAAA,MACF,MAAM,cAAc,KAAK;AAAA,MACzB,MAAM;AAAA,IAER,MAAM,IAAI,OAAO,IAAI,UAAU;AAAA,MAC7B,MAAM,EAAE,SAAS,wBAAwB,SAAS,UAAU;AAAA,IAC9D,CAAC;AAAA,IACD,OAAO,KAAK;AAAA,IACZ,IAAI;AAAA,MACF,MAAM,IAAI,OAAO,IAAI,IAAI;AAAA,QACvB,MAAM;AAAA,UACJ,SAAS;AAAA,UACT,OAAO;AAAA,UACP,SAAS,kCAAkC,cAAc,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,UACxG,OAAO,EAAE,WAAW,OAAO,MAAM,MAAM;AAAA,QACzC;AAAA,MACF,CAAC;AAAA,MACD,MAAM;AAAA,YACR;AAAA,IACA,OAAO,OAAO,SAAS;AAAA,IACvB,IAAI;AAAA,MACF,MAAM,IAAI,OAAO,IAAI,IAAI;AAAA,QACvB,MAAM;AAAA,UACJ,SAAS;AAAA,UACT,OAAO;AAAA,UACP,SAAS,iCAAiC;AAAA,UAC1C,OAAO,EAAE,WAAW,OAAO,MAAM,MAAM;AAAA,QACzC;AAAA,MACF,CAAC;AAAA,MACD,MAAM;AAAA;AAAA;AAQZ,eAAsB,eAAe,CACnC,KACA,OACe;AAAA,EACf,IAAI,MAAM,UAAU,UAAU,MAAM,UAAU;AAAA,IAAW;AAAA,EAEzD,MAAM,SAAS,MAAM,IAAI,OAAO,QAAQ,SAAS,EAAE,MAAM,EAAE,IAAI,MAAM,UAAU,EAAE,CAAC;AAAA,EAClF,MAAM,WAAW,OAAO;AAAA,EAExB,MAAM,WAAW,SAAS,OAAO,CAAC,MAAkC,EAAE,KAAK,SAAS,MAAM;AAAA,EAC1F,WAAW,OAAO,UAAU;AAAA,IAC1B,WAAW,QAAQ,IAAI,OAAO;AAAA,MAC5B,IAAI,KAAK,SAAS,QAAQ;AAAA,QACxB,IAAI,CAAC,MAAM,kBAAkB,SAAS,KAAK,IAAI,GAAG;AAAA,UAChD,MAAM,kBAAkB,KAAK,KAAK,IAAI;AAAA,QACxC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,gBAAgB,SAAS,OAC7B,CAAC,MAAkC,EAAE,KAAK,SAAS,WACrD;AAAA,EACA,IAAI,cAAc,WAAW;AAAA,IAAG;AAAA,EAEhC,MAAM,YAAY,cAAc,cAAc,SAAS;AAAA,EACvD,IAAI,MAAM,uBAAuB,UAAU,KAAK;AAAA,IAAI;AAAA,EACpD,MAAM,qBAAqB,UAAU,KAAK;AAAA,EAE1C,IAAI,MAAM,UAAU,UAAU;AAAA,IAC5B,MAAM,WAAW,gBAAgB,UAAU,KAAK;AAAA,IAChD,IAAI,CAAC,UAAU;AAAA,MACb,MAAM,OAAO,KACX,SAAS,MAAM,OAAO,MAAM,gDAAgD,MAAM,eAAe,GACnG;AAAA,IACF;AAAA,IAEA,MAAM,YAAY,mBAAmB,UAAU,KAAK;AAAA,IACpD,MAAM,QAAsB;AAAA,MAC1B,OAAO,MAAM,OAAO,MAAM;AAAA,MAC1B,OAAO,MAAM;AAAA,MACb,UAAU,YAAY;AAAA,MACtB;AAAA,MACA,UAAU,aAAa;AAAA,IACzB;AAAA,IACA,MAAM,QAAQ,KAAK,KAAK;AAAA,IACxB,MAAM,cAAc,KAAK;AAAA,IAEzB,MAAM,IAAI,OAAO,IAAI,IAAI;AAAA,MACvB,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,OAAO;AAAA,QACP,SAAS,kBAAkB,MAAM,WAAW,MAAM,eAAe;AAAA,QACjE,OAAO;AAAA,UACL,WAAW,MAAM;AAAA,UAAW,OAAO,MAAM;AAAA,UACzC,OAAO,MAAM,eAAe;AAAA,UAC5B,gBAAgB,MAAM,SAAS;AAAA,UAC/B,eAAe,MAAM,UAAU;AAAA,UAC/B,UAAU,MAAM;AAAA,QAClB;AAAA,MACF;AAAA,IACF,CAAC;AAAA,IAED,IAAI,WAAW,MAAM,OAAO,GAAG;AAAA,MAC7B,MAAM,OAAO,KAAK,2CAA0C;AAAA,MAC5D,MAAM,QAAQ;AAAA,MACd,MAAM,IAAI,OAAO,IAAI,IAAI;AAAA,QACvB,MAAM;AAAA,UACJ,SAAS;AAAA,UACT,OAAO;AAAA,UACP,SAAS;AAAA,UACT,OAAO,EAAE,WAAW,MAAM,WAAW,YAAY,UAAU,EAAE,wBAAwB;AAAA,QACvF;AAAA,MACF,CAAC;AAAA,MACD,MAAM,mBAAmB,KAAK,KAAK;AAAA,MACnC;AAAA,IACF;AAAA,IAEA,MAAM,YAAY,MAAM,oBAAoB;AAAA,IAC5C,IAAI,YAAY,MAAM,OAAO,QAAQ;AAAA,MACnC,MAAM,oBAAoB;AAAA,MAC1B,MAAM,YAAY,KAAK,KAAK;AAAA,IAC9B,EAAO,SAAI,MAAM,eAAe,IAAI,MAAM,aAAa;AAAA,MACrD,MAAM;AAAA,MACN,MAAM,oBAAoB;AAAA,MAC1B,MAAM,YAAY,KAAK,KAAK;AAAA,IAC9B,EAAO;AAAA,MACL,MAAM,QAAQ;AAAA,MACd,MAAM,IAAI,OAAO,IAAI,IAAI;AAAA,QACvB,MAAM;AAAA,UACJ,SAAS;AAAA,UACT,OAAO;AAAA,UACP,SAAS;AAAA,UACT,OAAO,EAAE,WAAW,MAAM,WAAW,aAAa,MAAM,YAAY;AAAA,QACtE;AAAA,MACF,CAAC;AAAA,MACD,MAAM,mBAAmB,KAAK,KAAK;AAAA;AAAA,IAErC;AAAA,EACF;AAAA,EAEA,IAAI,MAAM,UAAU,aAAa;AAAA,IAC/B,MAAM,UAAU,gBAAgB,UAAU,KAAK;AAAA,IAC/C,MAAM,QAAQ,KAAK;AAAA,MACjB,OAAO;AAAA,MACP,OAAO,MAAM;AAAA,MACb,UAAU,WAAW;AAAA,MACrB,WAAW,CAAC;AAAA,MACZ,UAAU,YAAY;AAAA,IACxB,CAAC;AAAA,IACD,MAAM,cAAc,KAAK;AAAA,IAEzB,MAAM,QAAQ;AAAA,IACd,MAAM,mBAAmB,KAAK,KAAK;AAAA,EACrC;AAAA;AAOF,eAAsB,gBAAgB,CACpC,KACA,OACA,OACe;AAAA,EACf,IAAI,MAAM,UAAU,eAAe,MAAM,UAAU,QAAQ;AAAA,IACzD,MAAM,QAAQ;AAAA,IACd,MAAM,cAAc,KAAK;AAAA,IACzB,MAAM,mBAAmB,KAAK,KAAK;AAAA,IACnC;AAAA,EACF;AAAA,EAEA,MAAM,QAAQ,MAAM,OAAO,MAAM;AAAA,EACjC,MAAM,WACJ,MAAM,SAAS,mBAAmB,MAAM,WAAW,QAC/C,OAAO,MAAM,WAAW,UAAU,WAC/B,MAAM,WAAW,MAA+B,WAAW,KAAK,UAAU,MAAM,WAAW,KAAK,IACjG,OAAO,MAAM,WAAW,KAAK,IAC/B;AAAA,EAEN,MAAM,OAAO,KAAK,UAAU,0BAA0B,MAAM,eAAe,MAAM,UAAU;AAAA,EAE3F,MAAM,SAAS,eAAe,IAAI,MAAM,SAAS;AAAA,EACjD,IAAI,QAAQ;AAAA,IAAE,aAAa,MAAM;AAAA,IAAG,eAAe,OAAO,MAAM,SAAS;AAAA,EAAE;AAAA,EAE3E,MAAM,IAAI,OAAO,IAAI,UAAU;AAAA,IAC7B,MAAM;AAAA,MACJ,SAAS,IAAI,0BAA0B,MAAM,eAAe;AAAA,MAC5D,SAAS;AAAA,IACX;AAAA,EACF,CAAC;AAAA,EAED,MAAM,YAAY,MAAM,oBAAoB;AAAA,EAC5C,IAAI,YAAY,MAAM,OAAO,QAAQ;AAAA,IACnC,MAAM,oBAAoB;AAAA,IAC1B,IAAI;AAAA,MACF,MAAM,IAAI,OAAO,IAAI,IAAI;AAAA,QACvB,MAAM;AAAA,UACJ,SAAS;AAAA,UACT,OAAO;AAAA,UACP,SAAS;AAAA,UACT,OAAO,EAAE,WAAW,MAAM,WAAW,aAAa,OAAO,WAAW,MAAM,OAAO,MAAM,oBAAoB,OAAO,MAAM,eAAe,EAAE;AAAA,QAC3I;AAAA,MACF,CAAC;AAAA,MACD,MAAM;AAAA,IACR,MAAM,cAAc,KAAK;AAAA,IACzB,MAAM,YAAY,KAAK,KAAK;AAAA,EAC9B,EAAO,SAAI,MAAM,eAAe,IAAI,MAAM,aAAa;AAAA,IACrD,MAAM;AAAA,IACN,MAAM,oBAAoB;AAAA,IAC1B,IAAI;AAAA,MACF,MAAM,IAAI,OAAO,IAAI,IAAI;AAAA,QACvB,MAAM;AAAA,UACJ,SAAS;AAAA,UACT,OAAO;AAAA,UACP,SAAS;AAAA,UACT,OAAO,EAAE,WAAW,MAAM,WAAW,aAAa,OAAO,OAAO,MAAM,eAAe,EAAE;AAAA,QACzF;AAAA,MACF,CAAC;AAAA,MACD,MAAM;AAAA,IACR,MAAM,cAAc,KAAK;AAAA,IACzB,MAAM,YAAY,KAAK,KAAK;AAAA,EAC9B,EAAO;AAAA,IACL,MAAM,QAAQ;AAAA,IACd,IAAI;AAAA,MACF,MAAM,IAAI,OAAO,IAAI,UAAU;AAAA,QAC7B,MAAM,EAAE,SAAS,0CAAyC,SAAS,QAAQ;AAAA,MAC7E,CAAC;AAAA,MACD,MAAM;AAAA,IACR,MAAM,cAAc,KAAK;AAAA,IACzB,MAAM,mBAAmB,KAAK,KAAK;AAAA;AAAA;AAQvC,eAAsB,oBAAoB,CACxC,KACA,OACA,kBACe;AAAA,EACf,MAAM,SAAS,eAAe,IAAI,MAAM,SAAS;AAAA,EACjD,IAAI,QAAQ;AAAA,IAAE,aAAa,MAAM;AAAA,IAAG,eAAe,OAAO,MAAM,SAAS;AAAA,EAAE;AAAA,EAE3E,MAAM,gBAAgB,MAAM,SAAS;AAAA,EAErC,IAAI,qBAAqB,MAAM,WAAW;AAAA,IACxC,MAAM,QAAQ;AAAA,IACd,MAAM,iBAAiB,yBAAyB,KAAK;AAAA,IACrD,MAAM,SAAS;AAAA,MACb;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK;AAAA,CAAI;AAAA,IAEX,MAAM,UAAU,eAAe,IAAI,MAAM,SAAS;AAAA,IAClD,IAAI,SAAS;AAAA,MACX,QAAQ,QAAQ,MAAM;AAAA,MACtB,eAAe,OAAO,MAAM,SAAS;AAAA,IACvC;AAAA,IAEA,IAAI;AAAA,MACF,MAAM,IAAI,OAAO,IAAI,UAAU;AAAA,QAC7B,MAAM,EAAE,SAAS,0BAA0B,SAAS,UAAU;AAAA,MAChE,CAAC;AAAA,MACD,MAAM;AAAA,IACR,IAAI;AAAA,MACF,MAAM,IAAI,OAAO,IAAI,IAAI;AAAA,QACvB,MAAM;AAAA,UACJ,SAAS;AAAA,UACT,OAAO;AAAA,UACP,SAAS;AAAA,UACT,OAAO,EAAE,WAAW,kBAAkB,iBAAiB,MAAM,gBAAgB;AAAA,QAC/E;AAAA,MACF,CAAC;AAAA,MACD,MAAM;AAAA,EACV,EAAO,SAAI,qBAAqB,MAAM,iBAAiB;AAAA,IACrD,MAAM,QAAQ;AAAA,IACd,IAAI;AAAA,MACF,MAAM,IAAI,OAAO,QAAQ,MAAM,EAAE,MAAM,EAAE,IAAI,MAAM,UAAU,EAAE,CAAC;AAAA,MAChE,MAAM;AAAA,IACR,IAAI;AAAA,MACF,MAAM,IAAI,OAAO,IAAI,IAAI;AAAA,QACvB,MAAM;AAAA,UACJ,SAAS;AAAA,UACT,OAAO;AAAA,UACP,SAAS;AAAA,UACT,OAAO,EAAE,WAAW,MAAM,WAAW,iBAAiB,iBAAiB;AAAA,QACzE;AAAA,MACF,CAAC;AAAA,MACD,MAAM;AAAA,EACV;AAAA,EAEA,OAAO,OAAO,MAAM,SAAS;AAAA;AAO/B,eAAsB,gBAAgB,CACpC,KACA,MACA,UACiB;AAAA,EACjB,MAAM,YAAY,KAAK;AAAA,EAEvB,IAAI;AAAA,IACF,MAAM,IAAI,OAAO,QAAQ,IAAI,EAAE,MAAM,EAAE,IAAI,UAAU,EAAE,CAAC;AAAA,IACxD,MAAM;AAAA,IACN,OAAO,mBAAmB;AAAA;AAAA,EAG5B,MAAM,gBAAgB,MAAM,cAAc,SAAS;AAAA,EACnD,IAAI,CAAC,eAAe;AAAA,IAClB,OAAO;AAAA,MACL,iDAAiD;AAAA,MACjD;AAAA,IACF,EAAE,KAAK;AAAA,CAAI;AAAA,EACb;AAAA,EAEA,IAAI,cAAc,UAAU,QAAQ;AAAA,IAClC,OAAO;AAAA,MACL,sBAAsB,0BAA0B,cAAc;AAAA,IAChE,EAAE,KAAK;AAAA,CAAI;AAAA,EACb;AAAA,EAEA,IAAI,KAAK,UAAU,CAAC,YAAY,KAAK,QAAQ,cAAc,MAAM,GAAG;AAAA,IAClE,OAAO;AAAA,MACL;AAAA,MACA,aAAa,cAAc,OAAO,KAAK,IAAI;AAAA,MAC3C,aAAa,KAAK,OAAO,KAAK,IAAI;AAAA,MAClC;AAAA,IACF,EAAE,KAAK;AAAA,CAAI;AAAA,EACb;AAAA,EAEA,IAAI;AAAA,IACF,MAAM,mBAAmB,MAAM,eAAe,KAAK,cAAc,MAAM;AAAA,IACvE,IAAI,CAAC,iBAAiB,OAAO;AAAA,MAC3B,OAAO;AAAA,QACL;AAAA,QACA,GAAG,iBAAiB,OAAO,IAAI,CAAC,MAAM,OAAO,GAAG;AAAA,MAClD,EAAE,KAAK;AAAA,CAAI;AAAA,IACb;AAAA,IACA,MAAM;AAAA,IACN,OAAO;AAAA;AAAA,EAGT,MAAM,iBAAiB,oBAAoB,cAAc,QAAQ,KAAK,MAAM;AAAA,EAE5E,MAAM,WAA4B;AAAA,IAChC,WAAW,cAAc;AAAA,IACzB,iBAAiB,cAAc;AAAA,IAC/B,QAAQ,cAAc;AAAA,IACtB,aAAa,cAAc,cAAc,KAAK;AAAA,IAC9C,UAAU,cAAc;AAAA,IACxB,QAAQ;AAAA,IACR,cAAc,cAAc;AAAA,IAC5B,mBAAmB;AAAA,IACnB,OAAO;AAAA,IACP,SAAS,CAAC,GAAG,cAAc,OAAO;AAAA,IAClC,QAAQ,CAAC,GAAG,cAAc,MAAM;AAAA,IAChC,WAAW,KAAK,IAAI;AAAA,IACpB,mBAAmB;AAAA,IACnB,mBAAmB,CAAC,GAAI,cAAc,qBAAqB,CAAC,CAAE;AAAA,EAChE;AAAA,EAEA,OAAO,IAAI,WAAW,QAAQ;AAAA,EAE9B,IAAI;AAAA,IACF,MAAM,cAAc,QAAQ;AAAA,IAE5B,MAAM,YAAY,cAAc,OAAO,KAAK,MAAM;AAAA,IAClD,MAAM,IAAI,OAAO,QAAQ,OAAO;AAAA,MAC9B,MAAM,EAAE,IAAI,UAAU;AAAA,MACtB,MAAM,EAAE,OAAO,eAAe,eAAe,SAAS,eAAe,KAAK,SAAS,eAAe;AAAA,IACpG,CAAC;AAAA,IAED,MAAM,IAAI,OAAO,QAAQ,OAAO;AAAA,MAC9B,MAAM,EAAE,IAAI,cAAc,gBAAgB;AAAA,MAC1C,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,OAAO,CAAC;AAAA,UACN,MAAM;AAAA,UACN,MAAM,qCAAqC,KAAK,gFAAgF;AAAA,QAClI,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAAA,IAED,MAAM,YAAY,KAAK,QAAQ;AAAA,IAE/B,MAAM,IAAI,OAAO,IAAI,UAAU;AAAA,MAC7B,MAAM;AAAA,QACJ,SAAS,eAAe,wBAAuB,KAAK,yBAAyB,cAAc,OAAO,KAAK,KAAK;AAAA,QAC5G,SAAS;AAAA,MACX;AAAA,IACF,CAAC;AAAA,IAED,OAAO;AAAA,IACP,OAAO,KAAK;AAAA,IACZ,OAAO,OAAO,SAAS;AAAA,IACvB,MAAM;AAAA;AAAA;;;ALjmBH,IAAM,mBAA2B,OAAO,QAAQ;AAAA,EACrD,IAAI;AAAA,IACF,MAAM,WAAW,GAAG;AAAA,IACpB,MAAM;AAAA,EAER,IAAI;AAAA,IACF,MAAM,sBAAsB,GAAG;AAAA,IAC/B,OAAO,KAAK;AAAA,IACZ,IAAI;AAAA,MACF,MAAM,IAAI,OAAO,IAAI,IAAI;AAAA,QACvB,MAAM;AAAA,UACJ,SAAS;AAAA,UACT,OAAO;AAAA,UACP,SAAS,iCAAiC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,QAC3F;AAAA,MACF,CAAC;AAAA,MACD,MAAM;AAAA;AAAA,EAGV,OAAO;AAAA,IACL,OAAO,SAAS,YAA8E;AAAA,MAC5F,MAAM,YAAY,sBAAsB,KAAK;AAAA,MAC7C,IAAI,CAAC,aAAa,CAAC,OAAO,IAAI,SAAS;AAAA,QAAG;AAAA,MAE1C,MAAM,QAAQ,OAAO,IAAI,SAAS;AAAA,MAElC,QAAQ,MAAM;AAAA,aACP,gBAAgB;AAAA,UACnB,MAAM,SAAS,eAAe,IAAI,SAAS;AAAA,UAC3C,IAAI,QAAQ;AAAA,YAAE,aAAa,MAAM;AAAA,YAAG,eAAe,OAAO,SAAS;AAAA,UAAE;AAAA,UACrE,MAAM,gBAAgB,KAAK,KAAK;AAAA,UAChC;AAAA,QACF;AAAA,aACK,iBAAiB;AAAA,UACpB,MAAM,iBAAiB,KAAK,OAAO,KAAwB;AAAA,UAC3D;AAAA,QACF;AAAA,aACK,mBAAmB;AAAA,UACtB,MAAM,YAAa,MAAM,WAAW,MAA0B;AAAA,UAC9D,IAAI;AAAA,YAAW,MAAM,qBAAqB,KAAK,OAAO,SAAS;AAAA,UAC/D;AAAA,QACF;AAAA;AAAA;AAAA,IAIJ,mCAAmC,OACjC,QACA,YACG;AAAA,IAIL,MAAM;AAAA,MACJ,YAAY,KAAK;AAAA,QACf,aACE,uFACA;AAAA;AAAA,IACA;AAAA;AAAA,IACA,mFACA;AAAA;AAAA,IACA,oFACA;AAAA;AAAA,IACA,8FACA,2FACA;AAAA;AAAA,IACA,oFACA,oFACA,mFACA;AAAA,QAEF,MAAM;AAAA,UACJ,QAAQ,KAAK,OACV,MAAM,KAAK,OAAO,OAAO,CAAC,EAC1B,IAAI,CAAC,EACL,SACC,sFACA,+EACA,mEACF;AAAA,UACF,QAAQ,KAAK,OACV,OAAO,EACP,SACC,2EACA,+EACA,4EACF;AAAA,UACF,QAAQ,KAAK,OACV,OAAO,EACP,IAAI,CAAC,EACL,IAAI,EAAE,EACN,SACC,qEACA,qFACA,oEACF;AAAA,UACF,UAAU,KAAK,OACZ,OAAO,EACP,SAAS,EACT,SACC,2EACA,iEACF;AAAA,UACF,WAAW,KAAK,OACb,OAAO,EACP,SAAS,EACT,SACC,sEACA,wEACA,iCACF;AAAA,UACF,OAAO,KAAK,OACT,OAAO,EACP,SAAS,EACT,SACC,8EACA,6EACF;AAAA,QACJ;AAAA,aAEM,QAAO,CAAC,MAA+B,SAAgC;AAAA,UAC3E,IAAI;AAAA,YACF,MAAM,SAAU,KAAK,UAAqB;AAAA,YAE1C,IAAI,KAAK,WAAW;AAAA,cAClB,IAAI,OAAO,KAAK,cAAc,YAAY,CAAC,KAAK,UAAU,KAAK,GAAG;AAAA,gBAChE,OAAO;AAAA,cACT;AAAA,cACA,IAAI,KAAK,QAAQ;AAAA,gBACf,OAAO;AAAA,cACT;AAAA,cACA,MAAM,OAAM,MAAM,iBAAiB,KAAK,MAAmC,OAAO;AAAA,cAClF,IAAI,KAAI,WAAW,QAAQ,KAAK,KAAI,WAAW,SAAS;AAAA,gBAAG,OAAO;AAAA,cAClE,MAAM,UAAS,MAAM,IAAI,QAAgB,CAAC,YAAY,eAAe,IAAI,MAAK,EAAE,QAAQ,CAAC,CAAC;AAAA,cAC1F,OAAO;AAAA,YACT;AAAA,YAEA,IAAI,CAAC,KAAK,UAAU,CAAC,MAAM,QAAQ,KAAK,MAAM,KAAK,KAAK,OAAO,SAAS,GAAG;AAAA,cACzE,OAAO;AAAA,YACT;AAAA,YACA,MAAM,aAAa,MAAM,eAAe,KAAK,KAAK,MAAkB;AAAA,YACpE,IAAI,CAAC,WAAW,OAAO;AAAA,cACrB,MAAM,YAAY,WAAW,UAAU,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,IAAI;AAAA,cACnE,OAAO,CAAC,gCAAgC,GAAG,WAAW,OAAO,IAAI,CAAC,MAAM,OAAO,GAAG,GAAG,qBAAqB,WAAW,EAAE,KAAK;AAAA,CAAI;AAAA,YAClI;AAAA,YACA,IAAI,SAAS,IAAI;AAAA,cACf,OAAO;AAAA,YACT;AAAA,YAEA,MAAM,MAAM,MAAM,mBAAmB,KAAK,KAAK,MAAM,OAAO,GAAqB,OAAO;AAAA,YACxF,MAAM,SAAS,MAAM,IAAI,QAAgB,CAAC,YAAY,eAAe,IAAI,KAAK,EAAE,QAAQ,CAAC,CAAC;AAAA,YAC1F,OAAO;AAAA,YACP,OAAO,KAAK;AAAA,YACZ,MAAM,IAAI,OAAO,IAAI,IAAI;AAAA,cACvB,MAAM;AAAA,gBACJ,SAAS;AAAA,gBACT,OAAO;AAAA,gBACP,SAAS,6BAA6B,eAAe,QAAQ,IAAI,SAAS,IAAI,UAAU,OAAO,GAAG;AAAA,cACpG;AAAA,YACF,CAAC;AAAA,YACD,OAAO,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA;AAAA;AAAA,MAGtE,CAAC;AAAA,MAED,kBAAkB,KAAK;AAAA,QACrB,aACE,kDACA,sFACA,wEACA;AAAA,QAEF,MAAM,CAAC;AAAA,aAED,QAAO,GAAG;AAAA,UACd,IAAI;AAAA,YACF,MAAM,SAAS,MAAM,IAAI,OAAO,IAAI,OAAO;AAAA,YAC3C,MAAM,QAAQ,OAAO,KAAK,IAAI,CAAC,MAAwB,EAAE,IAAI;AAAA,YAC7D,OAAO,qBAAqB,MAAM,KAAK,IAAI;AAAA,YAC3C,MAAM;AAAA,YACN,OAAO;AAAA;AAAA;AAAA,MAGb,CAAC;AAAA,IACH;AAAA,EACF;AAAA;",
|
|
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.
|
|
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:
|
|
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",
|
package/src/tui/tui.tsx
ADDED
|
@@ -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
|