chorus-codes 0.7.0 → 0.7.2
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/.next/BUILD_ID +1 -1
- package/.next/build-manifest.json +3 -3
- package/.next/cache/.previewinfo +1 -1
- package/.next/cache/.rscinfo +1 -1
- package/.next/cache/.tsbuildinfo +1 -1
- package/.next/fallback-build-manifest.json +3 -3
- package/.next/prerender-manifest.json +3 -3
- package/.next/server/app/_global-error.html +1 -1
- package/.next/server/app/_global-error.rsc +1 -1
- package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/_not-found.html +1 -1
- package/.next/server/app/_not-found.rsc +1 -1
- package/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/new.html +1 -1
- package/.next/server/app/new.rsc +1 -1
- package/.next/server/app/new.segments/_full.segment.rsc +1 -1
- package/.next/server/app/new.segments/_head.segment.rsc +1 -1
- package/.next/server/app/new.segments/_index.segment.rsc +1 -1
- package/.next/server/app/new.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/new.segments/new/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/new.segments/new.segment.rsc +1 -1
- package/.next/server/app/onboarding.html +1 -1
- package/.next/server/app/onboarding.rsc +1 -1
- package/.next/server/app/onboarding.segments/_full.segment.rsc +1 -1
- package/.next/server/app/onboarding.segments/_head.segment.rsc +1 -1
- package/.next/server/app/onboarding.segments/_index.segment.rsc +1 -1
- package/.next/server/app/onboarding.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/onboarding.segments/onboarding/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/onboarding.segments/onboarding.segment.rsc +1 -1
- package/.next/server/app/personas.html +1 -1
- package/.next/server/app/personas.rsc +1 -1
- package/.next/server/app/personas.segments/_full.segment.rsc +1 -1
- package/.next/server/app/personas.segments/_head.segment.rsc +1 -1
- package/.next/server/app/personas.segments/_index.segment.rsc +1 -1
- package/.next/server/app/personas.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/personas.segments/personas/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/personas.segments/personas.segment.rsc +1 -1
- package/.next/server/app/settings.html +1 -1
- package/.next/server/app/settings.rsc +1 -1
- package/.next/server/app/settings.segments/_full.segment.rsc +1 -1
- package/.next/server/app/settings.segments/_head.segment.rsc +1 -1
- package/.next/server/app/settings.segments/_index.segment.rsc +1 -1
- package/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/settings.segments/settings.segment.rsc +1 -1
- package/.next/server/app/templates.html +1 -1
- package/.next/server/app/templates.rsc +1 -1
- package/.next/server/app/templates.segments/_full.segment.rsc +1 -1
- package/.next/server/app/templates.segments/_head.segment.rsc +1 -1
- package/.next/server/app/templates.segments/_index.segment.rsc +1 -1
- package/.next/server/app/templates.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/templates.segments/templates/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/templates.segments/templates.segment.rsc +1 -1
- package/.next/server/middleware-build-manifest.js +3 -3
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.js +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/trace +1 -1
- package/.next/trace-build +1 -1
- package/README.md +38 -15
- package/dist/cli/commands/doctor.js +116 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/init.js +211 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/start.js +298 -0
- package/dist/cli/commands/start.js.map +1 -0
- package/dist/cli/commands/status.js +54 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/commands/stop.js +97 -0
- package/dist/cli/commands/stop.js.map +1 -0
- package/dist/cli/connect.js +108 -0
- package/dist/cli/connect.js.map +1 -0
- package/dist/cli/index.js +99 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/port-utils.js +260 -0
- package/dist/cli/port-utils.js.map +1 -0
- package/dist/cli/runtime-env.js +60 -0
- package/dist/cli/runtime-env.js.map +1 -0
- package/dist/cli/shared.js +54 -0
- package/dist/cli/shared.js.map +1 -0
- package/dist/cli/ui.js +60 -0
- package/dist/cli/ui.js.map +1 -0
- package/dist/daemon/agents/claude.js +98 -0
- package/dist/daemon/agents/claude.js.map +1 -0
- package/dist/daemon/agents/codex.js +160 -0
- package/dist/daemon/agents/codex.js.map +1 -0
- package/dist/daemon/agents/gemini.js +111 -0
- package/dist/daemon/agents/gemini.js.map +1 -0
- package/dist/daemon/agents/index.js +59 -0
- package/dist/daemon/agents/index.js.map +1 -0
- package/dist/daemon/agents/kimi.js +206 -0
- package/dist/daemon/agents/kimi.js.map +1 -0
- package/dist/daemon/agents/opencode.js +228 -0
- package/dist/daemon/agents/opencode.js.map +1 -0
- package/dist/daemon/agents/openrouter.js +274 -0
- package/dist/daemon/agents/openrouter.js.map +1 -0
- package/dist/daemon/agents/parsers/claude.js +63 -0
- package/dist/daemon/agents/parsers/claude.js.map +1 -0
- package/dist/daemon/agents/parsers/codex.js +51 -0
- package/dist/daemon/agents/parsers/codex.js.map +1 -0
- package/dist/daemon/agents/parsers/gemini.js +144 -0
- package/dist/daemon/agents/parsers/gemini.js.map +1 -0
- package/dist/daemon/agents/parsers/index.js +31 -0
- package/dist/daemon/agents/parsers/index.js.map +1 -0
- package/dist/daemon/agents/parsers/kimi.js +8 -0
- package/dist/daemon/agents/parsers/kimi.js.map +1 -0
- package/dist/daemon/agents/parsers/opencode.js +105 -0
- package/dist/daemon/agents/parsers/opencode.js.map +1 -0
- package/dist/daemon/agents/parsers/openrouter.js +69 -0
- package/dist/daemon/agents/parsers/openrouter.js.map +1 -0
- package/dist/daemon/agents/parsers/shared.js +17 -0
- package/dist/daemon/agents/parsers/shared.js.map +1 -0
- package/dist/daemon/agents/preflight.js +83 -0
- package/dist/daemon/agents/preflight.js.map +1 -0
- package/dist/daemon/agents/quote.js +45 -0
- package/dist/daemon/agents/quote.js.map +1 -0
- package/dist/daemon/agents/sandbox-guard.js +69 -0
- package/dist/daemon/agents/sandbox-guard.js.map +1 -0
- package/dist/daemon/agents/types.js +6 -0
- package/dist/daemon/agents/types.js.map +1 -0
- package/dist/daemon/api-response.js +65 -0
- package/dist/daemon/api-response.js.map +1 -0
- package/dist/daemon/error-detector.js +329 -0
- package/dist/daemon/error-detector.js.map +1 -0
- package/dist/daemon/headless.js +533 -0
- package/dist/daemon/headless.js.map +1 -0
- package/dist/daemon/index.js +333 -0
- package/dist/daemon/index.js.map +1 -0
- package/dist/daemon/openrouter.js +192 -0
- package/dist/daemon/openrouter.js.map +1 -0
- package/dist/daemon/orchestrators/claude.js +163 -0
- package/dist/daemon/orchestrators/claude.js.map +1 -0
- package/dist/daemon/orchestrators/codex.js +101 -0
- package/dist/daemon/orchestrators/codex.js.map +1 -0
- package/dist/daemon/orchestrators/cursor-windsurf.js +118 -0
- package/dist/daemon/orchestrators/cursor-windsurf.js.map +1 -0
- package/dist/daemon/orchestrators/gemini.js +108 -0
- package/dist/daemon/orchestrators/gemini.js.map +1 -0
- package/dist/daemon/orchestrators/index.js +90 -0
- package/dist/daemon/orchestrators/index.js.map +1 -0
- package/dist/daemon/orchestrators/kimi.js +108 -0
- package/dist/daemon/orchestrators/kimi.js.map +1 -0
- package/dist/daemon/orchestrators/opencode.js +152 -0
- package/dist/daemon/orchestrators/opencode.js.map +1 -0
- package/dist/daemon/orchestrators/shared.js +60 -0
- package/dist/daemon/orchestrators/shared.js.map +1 -0
- package/dist/daemon/output-watcher.js +131 -0
- package/dist/daemon/output-watcher.js.map +1 -0
- package/dist/daemon/participant-aborts.js +123 -0
- package/dist/daemon/participant-aborts.js.map +1 -0
- package/dist/daemon/reaper.js +46 -0
- package/dist/daemon/reaper.js.map +1 -0
- package/dist/daemon/routes/chats-events.js +62 -0
- package/dist/daemon/routes/chats-events.js.map +1 -0
- package/dist/daemon/routes/chats-stream.js +241 -0
- package/dist/daemon/routes/chats-stream.js.map +1 -0
- package/dist/daemon/routes/chats-validation.js +13 -0
- package/dist/daemon/routes/chats-validation.js.map +1 -0
- package/dist/daemon/routes/chats.js +545 -0
- package/dist/daemon/routes/chats.js.map +1 -0
- package/dist/daemon/routes/openrouter.js +103 -0
- package/dist/daemon/routes/openrouter.js.map +1 -0
- package/dist/daemon/routes/settings.js +199 -0
- package/dist/daemon/routes/settings.js.map +1 -0
- package/dist/daemon/routes/stats.js +155 -0
- package/dist/daemon/routes/stats.js.map +1 -0
- package/dist/daemon/routes/system.js +208 -0
- package/dist/daemon/routes/system.js.map +1 -0
- package/dist/daemon/routes/templates-personas.js +254 -0
- package/dist/daemon/routes/templates-personas.js.map +1 -0
- package/dist/daemon/routes/voices.js +139 -0
- package/dist/daemon/routes/voices.js.map +1 -0
- package/dist/daemon/runner/doer-driver.js +346 -0
- package/dist/daemon/runner/doer-driver.js.map +1 -0
- package/dist/daemon/runner/doer.js +336 -0
- package/dist/daemon/runner/doer.js.map +1 -0
- package/dist/daemon/runner/prior-round.js +140 -0
- package/dist/daemon/runner/prior-round.js.map +1 -0
- package/dist/daemon/runner/prompt-builder.js +292 -0
- package/dist/daemon/runner/prompt-builder.js.map +1 -0
- package/dist/daemon/runner/review-only-phase.js +103 -0
- package/dist/daemon/runner/review-only-phase.js.map +1 -0
- package/dist/daemon/runner/reviewer-driver.js +410 -0
- package/dist/daemon/runner/reviewer-driver.js.map +1 -0
- package/dist/daemon/runner/reviewer.js +384 -0
- package/dist/daemon/runner/reviewer.js.map +1 -0
- package/dist/daemon/runner/run-with-fallback.js +56 -0
- package/dist/daemon/runner/run-with-fallback.js.map +1 -0
- package/dist/daemon/runner/sanitize-name.js +8 -0
- package/dist/daemon/runner/sanitize-name.js.map +1 -0
- package/dist/daemon/runner/stream-file-writer.js +116 -0
- package/dist/daemon/runner/stream-file-writer.js.map +1 -0
- package/dist/daemon/runner/swap-sidecar.js +102 -0
- package/dist/daemon/runner/swap-sidecar.js.map +1 -0
- package/dist/daemon/runner/template-fallback.js +119 -0
- package/dist/daemon/runner/template-fallback.js.map +1 -0
- package/dist/daemon/runner/types.js +3 -0
- package/dist/daemon/runner/types.js.map +1 -0
- package/dist/daemon/runner/verdict.js +51 -0
- package/dist/daemon/runner/verdict.js.map +1 -0
- package/dist/daemon/runner-multiplex.js +364 -0
- package/dist/daemon/runner-multiplex.js.map +1 -0
- package/dist/daemon/runner.js +427 -0
- package/dist/daemon/runner.js.map +1 -0
- package/dist/daemon/ship.js +340 -0
- package/dist/daemon/ship.js.map +1 -0
- package/dist/daemon/template-cache.js +37 -0
- package/dist/daemon/template-cache.js.map +1 -0
- package/dist/daemon/tmux-types.js +9 -0
- package/dist/daemon/tmux-types.js.map +1 -0
- package/dist/daemon/tmux.js +341 -0
- package/dist/daemon/tmux.js.map +1 -0
- package/dist/lib/atomic-write.js +55 -0
- package/dist/lib/atomic-write.js.map +1 -0
- package/dist/lib/chat-events-bus.js +27 -0
- package/dist/lib/chat-events-bus.js.map +1 -0
- package/dist/lib/chat-slug.js +105 -0
- package/dist/lib/chat-slug.js.map +1 -0
- package/dist/lib/cli-detect.js +388 -0
- package/dist/lib/cli-detect.js.map +1 -0
- package/dist/lib/cli-health.js +156 -0
- package/dist/lib/cli-health.js.map +1 -0
- package/dist/lib/cli-paths.js +113 -0
- package/dist/lib/cli-paths.js.map +1 -0
- package/dist/lib/cli-precheck.js +141 -0
- package/dist/lib/cli-precheck.js.map +1 -0
- package/dist/lib/db/chats.js +244 -0
- package/dist/lib/db/chats.js.map +1 -0
- package/dist/lib/db/connection.js +254 -0
- package/dist/lib/db/connection.js.map +1 -0
- package/dist/lib/db/index.js +34 -0
- package/dist/lib/db/index.js.map +1 -0
- package/dist/lib/db/personas.js +65 -0
- package/dist/lib/db/personas.js.map +1 -0
- package/dist/lib/db/phase-events.js +172 -0
- package/dist/lib/db/phase-events.js.map +1 -0
- package/dist/lib/db/secrets.js +53 -0
- package/dist/lib/db/secrets.js.map +1 -0
- package/dist/lib/db/settings.js +47 -0
- package/dist/lib/db/settings.js.map +1 -0
- package/dist/lib/db/templates.js +75 -0
- package/dist/lib/db/templates.js.map +1 -0
- package/dist/lib/db/voices.js +184 -0
- package/dist/lib/db/voices.js.map +1 -0
- package/dist/lib/lineage-maps.js +200 -0
- package/dist/lib/lineage-maps.js.map +1 -0
- package/dist/lib/logger.js +186 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/personas.js +117 -0
- package/dist/lib/personas.js.map +1 -0
- package/dist/lib/runtime-path.js +222 -0
- package/dist/lib/runtime-path.js.map +1 -0
- package/dist/lib/settings/billing.js +58 -0
- package/dist/lib/settings/billing.js.map +1 -0
- package/dist/lib/settings/permissions.js +81 -0
- package/dist/lib/settings/permissions.js.map +1 -0
- package/dist/lib/settings/transport.js +113 -0
- package/dist/lib/settings/transport.js.map +1 -0
- package/dist/lib/telemetry.js +290 -0
- package/dist/lib/telemetry.js.map +1 -0
- package/dist/lib/template-schema.js +319 -0
- package/dist/lib/template-schema.js.map +1 -0
- package/dist/lib/template-validation.js +82 -0
- package/dist/lib/template-validation.js.map +1 -0
- package/dist/lib/voices.js +533 -0
- package/dist/lib/voices.js.map +1 -0
- package/dist/mcp/client.js +138 -0
- package/dist/mcp/client.js.map +1 -0
- package/dist/mcp/index.js +178 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/tools.js +355 -0
- package/dist/mcp/tools.js.map +1 -0
- package/package.json +2 -1
- package/.next/dev/static/chunks/05w9_next_dist_shared_lib_0beh7rg._.js +0 -6077
- package/.next/dev/static/chunks/05w9_next_dist_shared_lib_0beh7rg._.js.map +0 -69
- package/.next/dev/static/chunks/05w9_next_dist_shared_lib_0pjsj.j._.js +0 -6318
- package/.next/dev/static/chunks/05w9_next_dist_shared_lib_0pjsj.j._.js.map +0 -71
- package/.next/dev/types/cache-life.d.ts +0 -145
- package/.next/dev/types/routes.d.ts +0 -84
- package/.next/dev/types/validator.ts +0 -178
- /package/.next/static/{dJlbRLlhISA0JGtHKVqgQ → 9cD3yIOGe_Aqr17uJHTQS}/_buildManifest.js +0 -0
- /package/.next/static/{dJlbRLlhISA0JGtHKVqgQ → 9cD3yIOGe_Aqr17uJHTQS}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{dJlbRLlhISA0JGtHKVqgQ → 9cD3yIOGe_Aqr17uJHTQS}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.kimiOrchestrator = void 0;
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const shared_js_1 = require("./shared.js");
|
|
11
|
+
const KIMI_CONFIG_DIR = node_path_1.default.join(node_os_1.default.homedir(), '.kimi');
|
|
12
|
+
const KIMI_MCP_PATH = node_path_1.default.join(KIMI_CONFIG_DIR, 'mcp.json');
|
|
13
|
+
function getKimiStatus() {
|
|
14
|
+
const detected = node_fs_1.default.existsSync(KIMI_CONFIG_DIR);
|
|
15
|
+
const connected = detected && hasKimiMcpServer();
|
|
16
|
+
return {
|
|
17
|
+
name: 'kimi',
|
|
18
|
+
label: 'Kimi CLI',
|
|
19
|
+
connected,
|
|
20
|
+
approvedTools: connected ? 1 : 0,
|
|
21
|
+
totalTools: 1,
|
|
22
|
+
note: 'Registers Chorus as an MCP server in ~/.kimi/mcp.json. Kimi may show a one-time prompt before the first tool call — click Always allow.',
|
|
23
|
+
supported: detected,
|
|
24
|
+
firstCallBehavior: 'prompts_once',
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function hasKimiMcpServer(expectedBinPath) {
|
|
28
|
+
if (!node_fs_1.default.existsSync(KIMI_MCP_PATH))
|
|
29
|
+
return false;
|
|
30
|
+
try {
|
|
31
|
+
const body = JSON.parse(node_fs_1.default.readFileSync(KIMI_MCP_PATH, 'utf-8'));
|
|
32
|
+
const servers = body.mcpServers;
|
|
33
|
+
const chorus = servers?.chorus;
|
|
34
|
+
if (!chorus)
|
|
35
|
+
return false;
|
|
36
|
+
if (!expectedBinPath)
|
|
37
|
+
return true;
|
|
38
|
+
return Array.isArray(chorus.args) && chorus.args.includes(expectedBinPath);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Register Chorus with Kimi CLI via `kimi mcp add`. Same JSON shape as
|
|
46
|
+
* Gemini (mcpServers.<name>) but stored in ~/.kimi/mcp.json. Idempotent
|
|
47
|
+
* + path-aware: re-registers if binPath drifted.
|
|
48
|
+
*/
|
|
49
|
+
async function connectKimi(opts) {
|
|
50
|
+
if (hasKimiMcpServer(opts.binPath)) {
|
|
51
|
+
return {
|
|
52
|
+
added: [],
|
|
53
|
+
alreadyPresent: ['mcpServers.chorus'],
|
|
54
|
+
configPath: KIMI_MCP_PATH,
|
|
55
|
+
slashCommand: 'skipped',
|
|
56
|
+
slashCommandPath: '',
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
if (hasKimiMcpServer()) {
|
|
60
|
+
try {
|
|
61
|
+
await (0, shared_js_1.execFileAsync)('kimi', ['mcp', 'remove', 'chorus'], {
|
|
62
|
+
timeout: 30_000,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
/* best-effort */
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const daemonUrl = opts.daemonUrl ?? shared_js_1.DEFAULT_DAEMON_URL;
|
|
70
|
+
try {
|
|
71
|
+
await (0, shared_js_1.execFileAsync)('kimi', [
|
|
72
|
+
'mcp',
|
|
73
|
+
'add',
|
|
74
|
+
'--transport',
|
|
75
|
+
'stdio',
|
|
76
|
+
'chorus',
|
|
77
|
+
'-e',
|
|
78
|
+
`CHORUS_DAEMON_URL=${daemonUrl}`,
|
|
79
|
+
'--',
|
|
80
|
+
'node',
|
|
81
|
+
opts.binPath,
|
|
82
|
+
'mcp',
|
|
83
|
+
], { timeout: 30_000 });
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
87
|
+
throw new Error(`kimi mcp add failed: ${msg}`);
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
added: ['mcpServers.chorus'],
|
|
91
|
+
alreadyPresent: [],
|
|
92
|
+
configPath: KIMI_MCP_PATH,
|
|
93
|
+
slashCommand: 'skipped',
|
|
94
|
+
slashCommandPath: '',
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
exports.kimiOrchestrator = {
|
|
98
|
+
name: 'kimi',
|
|
99
|
+
label: 'Kimi CLI',
|
|
100
|
+
getStatus: getKimiStatus,
|
|
101
|
+
detect: () => node_fs_1.default.existsSync(KIMI_CONFIG_DIR),
|
|
102
|
+
connect: async (opts) => {
|
|
103
|
+
const before = hasKimiMcpServer(opts.binPath);
|
|
104
|
+
const full = await connectKimi(opts);
|
|
105
|
+
return { registered: !before, toolsAdded: 0, full };
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
//# sourceMappingURL=kimi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kimi.js","sourceRoot":"","sources":["../../../src/daemon/orchestrators/kimi.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.opencodeOrchestrator = void 0;
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const shared_js_1 = require("./shared.js");
|
|
11
|
+
const OPENCODE_USER_CONFIG_PATH = node_path_1.default.join(node_os_1.default.homedir(), '.config', 'opencode', 'opencode.json');
|
|
12
|
+
/**
|
|
13
|
+
* Safe-bash allowlist for OpenCode reviewers. Read-only ops that
|
|
14
|
+
* reviewers legitimately need to inspect a diff (git diff, ls, cat,
|
|
15
|
+
* grep, find) — these shouldn't prompt every spawn. Destructive ops
|
|
16
|
+
* (rm, git push, git reset) fall through to `*: ask` which preserves
|
|
17
|
+
* the safety gate.
|
|
18
|
+
*
|
|
19
|
+
* Layer 1 of the three-layer permission model: prevent the dialog from
|
|
20
|
+
* appearing in the first place. Layer 2 (shim.recoverKeys) catches
|
|
21
|
+
* anything this misses.
|
|
22
|
+
*/
|
|
23
|
+
const OPENCODE_SAFE_BASH = {
|
|
24
|
+
'git diff': 'allow',
|
|
25
|
+
'git diff *': 'allow',
|
|
26
|
+
'git status': 'allow',
|
|
27
|
+
'git log': 'allow',
|
|
28
|
+
'git log *': 'allow',
|
|
29
|
+
'git show *': 'allow',
|
|
30
|
+
'git blame *': 'allow',
|
|
31
|
+
cat: 'allow',
|
|
32
|
+
'cat *': 'allow',
|
|
33
|
+
ls: 'allow',
|
|
34
|
+
'ls *': 'allow',
|
|
35
|
+
'find *': 'allow',
|
|
36
|
+
'rg *': 'allow',
|
|
37
|
+
'grep *': 'allow',
|
|
38
|
+
'head *': 'allow',
|
|
39
|
+
'tail *': 'allow',
|
|
40
|
+
'wc *': 'allow',
|
|
41
|
+
pwd: 'allow',
|
|
42
|
+
'echo *': 'allow',
|
|
43
|
+
'*': 'ask',
|
|
44
|
+
};
|
|
45
|
+
function readOpencodeConfig() {
|
|
46
|
+
if (!node_fs_1.default.existsSync(OPENCODE_USER_CONFIG_PATH)) {
|
|
47
|
+
return { config: {}, existed: false };
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
return {
|
|
51
|
+
config: JSON.parse(node_fs_1.default.readFileSync(OPENCODE_USER_CONFIG_PATH, 'utf-8')),
|
|
52
|
+
existed: true,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return { config: {}, existed: true };
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function getOpencodeStatus() {
|
|
60
|
+
const detected = node_fs_1.default.existsSync(node_path_1.default.dirname(OPENCODE_USER_CONFIG_PATH));
|
|
61
|
+
const { config } = readOpencodeConfig();
|
|
62
|
+
const connected = detected &&
|
|
63
|
+
Boolean(config.mcp && config.mcp.chorus);
|
|
64
|
+
return {
|
|
65
|
+
name: 'opencode',
|
|
66
|
+
label: 'OpenCode',
|
|
67
|
+
connected,
|
|
68
|
+
approvedTools: connected ? 1 : 0,
|
|
69
|
+
totalTools: 1,
|
|
70
|
+
note: 'Registers Chorus as a local MCP server in ~/.config/opencode/opencode.json with `enabled: true` so the agent can call its tools.',
|
|
71
|
+
supported: detected,
|
|
72
|
+
firstCallBehavior: 'auto',
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Register Chorus with OpenCode. `opencode mcp add` is interactive (no
|
|
77
|
+
* flags for non-tty use), so we patch the user-scope config directly.
|
|
78
|
+
* Idempotent.
|
|
79
|
+
*/
|
|
80
|
+
async function connectOpencode(opts) {
|
|
81
|
+
const { config } = readOpencodeConfig();
|
|
82
|
+
const mcp = (config.mcp ?? {});
|
|
83
|
+
const existing = mcp.chorus;
|
|
84
|
+
const existingBinMatches = existing &&
|
|
85
|
+
Array.isArray(existing.command) &&
|
|
86
|
+
existing.command.includes(opts.binPath);
|
|
87
|
+
// Bash pre-approval is independent of the MCP block — pre-approve
|
|
88
|
+
// even if the MCP block is already correct, in case the user's
|
|
89
|
+
// existing config doesn't have it. Idempotent merge: never overwrite
|
|
90
|
+
// a user's explicit setting, only fill gaps.
|
|
91
|
+
const existingPermission = (config.permission ?? {});
|
|
92
|
+
const existingBash = (existingPermission.bash ?? {});
|
|
93
|
+
const mergedBash = {
|
|
94
|
+
...OPENCODE_SAFE_BASH,
|
|
95
|
+
};
|
|
96
|
+
// User's settings win over our defaults — preserves explicit deny rules.
|
|
97
|
+
for (const [pattern, mode] of Object.entries(existingBash)) {
|
|
98
|
+
mergedBash[pattern] = mode;
|
|
99
|
+
}
|
|
100
|
+
const bashChanged = JSON.stringify(existingBash) !== JSON.stringify(mergedBash);
|
|
101
|
+
if (existingBinMatches && !bashChanged) {
|
|
102
|
+
return {
|
|
103
|
+
added: [],
|
|
104
|
+
alreadyPresent: ['mcp.chorus', 'permission.bash'],
|
|
105
|
+
configPath: OPENCODE_USER_CONFIG_PATH,
|
|
106
|
+
slashCommand: 'skipped',
|
|
107
|
+
slashCommandPath: '',
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
const daemonUrl = opts.daemonUrl ?? shared_js_1.DEFAULT_DAEMON_URL;
|
|
111
|
+
mcp.chorus = {
|
|
112
|
+
type: 'local',
|
|
113
|
+
command: ['node', opts.binPath, 'mcp'],
|
|
114
|
+
environment: { CHORUS_DAEMON_URL: daemonUrl },
|
|
115
|
+
enabled: true,
|
|
116
|
+
};
|
|
117
|
+
const next = {
|
|
118
|
+
$schema: 'https://opencode.ai/config.json',
|
|
119
|
+
...config,
|
|
120
|
+
mcp,
|
|
121
|
+
permission: {
|
|
122
|
+
...existingPermission,
|
|
123
|
+
bash: mergedBash,
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
node_fs_1.default.mkdirSync(node_path_1.default.dirname(OPENCODE_USER_CONFIG_PATH), { recursive: true });
|
|
127
|
+
node_fs_1.default.writeFileSync(OPENCODE_USER_CONFIG_PATH, JSON.stringify(next, null, 2) + '\n', 'utf-8');
|
|
128
|
+
const added = [];
|
|
129
|
+
if (!existingBinMatches)
|
|
130
|
+
added.push('mcp.chorus');
|
|
131
|
+
if (bashChanged)
|
|
132
|
+
added.push('permission.bash');
|
|
133
|
+
return {
|
|
134
|
+
added,
|
|
135
|
+
alreadyPresent: [],
|
|
136
|
+
configPath: OPENCODE_USER_CONFIG_PATH,
|
|
137
|
+
slashCommand: 'skipped',
|
|
138
|
+
slashCommandPath: '',
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
exports.opencodeOrchestrator = {
|
|
142
|
+
name: 'opencode',
|
|
143
|
+
label: 'OpenCode',
|
|
144
|
+
getStatus: getOpencodeStatus,
|
|
145
|
+
detect: () => node_fs_1.default.existsSync(node_path_1.default.dirname(OPENCODE_USER_CONFIG_PATH)) ||
|
|
146
|
+
node_fs_1.default.existsSync(node_path_1.default.join(node_os_1.default.homedir(), '.opencode')),
|
|
147
|
+
connect: async (opts) => {
|
|
148
|
+
const full = await connectOpencode(opts);
|
|
149
|
+
return { registered: full.added.length > 0, toolsAdded: 0, full };
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
//# sourceMappingURL=opencode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opencode.js","sourceRoot":"","sources":["../../../src/daemon/orchestrators/opencode.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Cross-orchestrator constants, types, and small JSON helpers reused by
|
|
4
|
+
* Cursor + Windsurf (they share the `{ mcpServers: ... }` JSON shape).
|
|
5
|
+
*/
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.DEFAULT_DAEMON_URL = exports.CHORUS_TOOLS = exports.execFileAsync = void 0;
|
|
11
|
+
exports.hasMcpEntry = hasMcpEntry;
|
|
12
|
+
exports.writeMcpEntry = writeMcpEntry;
|
|
13
|
+
const node_child_process_1 = require("node:child_process");
|
|
14
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
15
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
16
|
+
const node_util_1 = require("node:util");
|
|
17
|
+
exports.execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
|
|
18
|
+
exports.CHORUS_TOOLS = [
|
|
19
|
+
'mcp__chorus__create_chat',
|
|
20
|
+
'mcp__chorus__wait_for_chat',
|
|
21
|
+
'mcp__chorus__get_chat_status',
|
|
22
|
+
'mcp__chorus__list_blocked',
|
|
23
|
+
'mcp__chorus__resume_chat',
|
|
24
|
+
'mcp__chorus__cancel_chat',
|
|
25
|
+
'mcp__chorus__list_templates',
|
|
26
|
+
];
|
|
27
|
+
exports.DEFAULT_DAEMON_URL = 'http://127.0.0.1:7707';
|
|
28
|
+
function readJsonOrEmpty(filePath) {
|
|
29
|
+
if (!node_fs_1.default.existsSync(filePath))
|
|
30
|
+
return {};
|
|
31
|
+
try {
|
|
32
|
+
return JSON.parse(node_fs_1.default.readFileSync(filePath, 'utf-8'));
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return {};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function hasMcpEntry(filePath, expectedBinPath) {
|
|
39
|
+
const cfg = readJsonOrEmpty(filePath);
|
|
40
|
+
const chorus = cfg.mcpServers
|
|
41
|
+
?.chorus;
|
|
42
|
+
if (!chorus)
|
|
43
|
+
return false;
|
|
44
|
+
if (!expectedBinPath)
|
|
45
|
+
return true;
|
|
46
|
+
return Array.isArray(chorus.args) && chorus.args.includes(expectedBinPath);
|
|
47
|
+
}
|
|
48
|
+
function writeMcpEntry(opts) {
|
|
49
|
+
const cfg = readJsonOrEmpty(opts.filePath);
|
|
50
|
+
const servers = (cfg.mcpServers ?? {});
|
|
51
|
+
servers.chorus = {
|
|
52
|
+
command: 'node',
|
|
53
|
+
args: [opts.binPath, 'mcp'],
|
|
54
|
+
env: { CHORUS_DAEMON_URL: opts.daemonUrl },
|
|
55
|
+
};
|
|
56
|
+
const next = { ...cfg, mcpServers: servers };
|
|
57
|
+
node_fs_1.default.mkdirSync(node_path_1.default.dirname(opts.filePath), { recursive: true });
|
|
58
|
+
node_fs_1.default.writeFileSync(opts.filePath, JSON.stringify(next, null, 2) + '\n', 'utf-8');
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../../src/daemon/orchestrators/shared.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;AA6IH,kCAOC;AAED,sCAeC;AAnKD,2DAA8C;AAC9C,sDAAyB;AACzB,0DAA6B;AAC7B,yCAAsC;AAEzB,QAAA,aAAa,GAAG,IAAA,qBAAS,EAAC,6BAAQ,CAAC,CAAC;AAEpC,QAAA,YAAY,GAAG;IAC1B,0BAA0B;IAC1B,4BAA4B;IAC5B,8BAA8B;IAC9B,2BAA2B;IAC3B,0BAA0B;IAC1B,0BAA0B;IAC1B,6BAA6B;CAC9B,CAAC;AAWW,QAAA,kBAAkB,GAAG,uBAAuB,CAAC;AAwG1D,SAAS,eAAe,CAAC,QAAgB;IACvC,IAAI,CAAC,iBAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,CAAC;IACxC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,iBAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAiB,CAAC;IACxE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,SAAgB,WAAW,CAAC,QAAgB,EAAE,eAAwB;IACpE,MAAM,GAAG,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;IACtC,MAAM,MAAM,GAAI,GAAG,CAAC,UAA8D;QAChF,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC1B,IAAI,CAAC,eAAe;QAAE,OAAO,IAAI,CAAC;IAClC,OAAO,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;AAC7E,CAAC;AAED,SAAgB,aAAa,CAAC,IAI7B;IACC,MAAM,GAAG,GAAG,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC3C,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,UAAU,IAAI,EAAE,CAA4B,CAAC;IAClE,OAAO,CAAC,MAAM,GAAG;QACf,OAAO,EAAE,MAAM;QACf,IAAI,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC;QAC3B,GAAG,EAAE,EAAE,iBAAiB,EAAE,IAAI,CAAC,SAAS,EAAE;KAC3C,CAAC;IACF,MAAM,IAAI,GAAiB,EAAE,GAAG,GAAG,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC;IAC3D,iBAAE,CAAC,SAAS,CAAC,mBAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/D,iBAAE,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;AACjF,CAAC"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* File system watcher for phase output completion.
|
|
4
|
+
* Ported from openbridge folder transport pattern.
|
|
5
|
+
* Watches for answer.md completion via:
|
|
6
|
+
* - done sentinel file appearance (preferred)
|
|
7
|
+
* - answer.md ending with sentinel string (default: ## DONE)
|
|
8
|
+
* - 90s silence after first write (matches openbridge timeout)
|
|
9
|
+
*/
|
|
10
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
11
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
12
|
+
};
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.waitForAnswer = waitForAnswer;
|
|
15
|
+
const chokidar_1 = __importDefault(require("chokidar"));
|
|
16
|
+
const fs_1 = __importDefault(require("fs"));
|
|
17
|
+
const path_1 = __importDefault(require("path"));
|
|
18
|
+
/**
|
|
19
|
+
* Wait for an answer file to be written and completed.
|
|
20
|
+
* Resolves when:
|
|
21
|
+
* - done sentinel file appears (preferred), OR
|
|
22
|
+
* - answer.md ends with the configured sentinel string (default ## DONE), OR
|
|
23
|
+
* - 90s silence after first write (matches openbridge timeout)
|
|
24
|
+
*
|
|
25
|
+
* Rejects on timeoutMs reached.
|
|
26
|
+
*/
|
|
27
|
+
function waitForAnswer(answerFile, opts) {
|
|
28
|
+
const sentinel = opts.doneSentinel || '## DONE';
|
|
29
|
+
const silenceTimeoutMs = 90_000;
|
|
30
|
+
const answerDir = path_1.default.dirname(answerFile);
|
|
31
|
+
const answerBasename = path_1.default.basename(answerFile);
|
|
32
|
+
return new Promise((resolve, reject) => {
|
|
33
|
+
let resolved = false;
|
|
34
|
+
let lastWriteTime = 0;
|
|
35
|
+
let firstWriteTime = 0;
|
|
36
|
+
// Main timeout
|
|
37
|
+
const mainTimeout = setTimeout(() => {
|
|
38
|
+
if (!resolved) {
|
|
39
|
+
resolved = true;
|
|
40
|
+
watcher.close();
|
|
41
|
+
if (silenceCheckInterval)
|
|
42
|
+
clearInterval(silenceCheckInterval);
|
|
43
|
+
reject(new Error(`Timeout waiting for answer after ${opts.timeoutMs}ms`));
|
|
44
|
+
}
|
|
45
|
+
}, opts.timeoutMs);
|
|
46
|
+
// Silence checker: if 90s pass without a write, assume complete
|
|
47
|
+
const checkSilence = () => {
|
|
48
|
+
if (!resolved && firstWriteTime > 0 && Date.now() - lastWriteTime > silenceTimeoutMs) {
|
|
49
|
+
resolved = true;
|
|
50
|
+
watcher.close();
|
|
51
|
+
if (silenceCheckInterval)
|
|
52
|
+
clearInterval(silenceCheckInterval);
|
|
53
|
+
clearTimeout(mainTimeout);
|
|
54
|
+
try {
|
|
55
|
+
const content = fs_1.default.readFileSync(answerFile, 'utf-8');
|
|
56
|
+
resolve({ content, full: content.includes(sentinel) });
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
reject(new Error(`Failed to read answer file: ${error instanceof Error ? error.message : String(error)}`));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
const silenceCheckInterval = setInterval(checkSilence, 5000);
|
|
64
|
+
// Watch the directory for changes
|
|
65
|
+
const watcher = chokidar_1.default.watch(answerDir, {
|
|
66
|
+
ignored: /node_modules/,
|
|
67
|
+
awaitWriteFinish: { stabilityThreshold: 100, pollInterval: 100 },
|
|
68
|
+
persistent: true,
|
|
69
|
+
});
|
|
70
|
+
// Shared handler — chokidar fires 'add' on first creation and 'change'
|
|
71
|
+
// on subsequent writes. CLIs that write the whole answer in one shot
|
|
72
|
+
// (Claude, Gemini) only trigger 'add'; CLIs that stream (Codex) trigger
|
|
73
|
+
// 'change'. We need both.
|
|
74
|
+
const onAnswerWrite = (filePath) => {
|
|
75
|
+
if (path_1.default.basename(filePath) !== answerBasename)
|
|
76
|
+
return;
|
|
77
|
+
lastWriteTime = Date.now();
|
|
78
|
+
if (firstWriteTime === 0)
|
|
79
|
+
firstWriteTime = lastWriteTime;
|
|
80
|
+
try {
|
|
81
|
+
const content = fs_1.default.readFileSync(answerFile, 'utf-8');
|
|
82
|
+
if (content.includes(sentinel)) {
|
|
83
|
+
if (!resolved) {
|
|
84
|
+
resolved = true;
|
|
85
|
+
watcher.close();
|
|
86
|
+
if (silenceCheckInterval)
|
|
87
|
+
clearInterval(silenceCheckInterval);
|
|
88
|
+
clearTimeout(mainTimeout);
|
|
89
|
+
resolve({ content, full: true });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// File not yet readable on this snapshot, retry on next write event.
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
watcher.on('add', onAnswerWrite);
|
|
98
|
+
watcher.on('change', onAnswerWrite);
|
|
99
|
+
// Optional explicit `done` sentinel file — kept as an opt-in escape hatch
|
|
100
|
+
// for shims that prefer marker-file completion over content sentinel.
|
|
101
|
+
watcher.on('add', (filePath) => {
|
|
102
|
+
if (path_1.default.basename(filePath) !== 'done')
|
|
103
|
+
return;
|
|
104
|
+
if (!resolved) {
|
|
105
|
+
resolved = true;
|
|
106
|
+
watcher.close();
|
|
107
|
+
if (silenceCheckInterval)
|
|
108
|
+
clearInterval(silenceCheckInterval);
|
|
109
|
+
clearTimeout(mainTimeout);
|
|
110
|
+
try {
|
|
111
|
+
const content = fs_1.default.readFileSync(answerFile, 'utf-8');
|
|
112
|
+
resolve({ content, full: true });
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
reject(new Error(`Failed to read answer file: ${error instanceof Error ? error.message : String(error)}`));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
watcher.on('error', (error) => {
|
|
120
|
+
if (!resolved) {
|
|
121
|
+
resolved = true;
|
|
122
|
+
watcher.close();
|
|
123
|
+
if (silenceCheckInterval)
|
|
124
|
+
clearInterval(silenceCheckInterval);
|
|
125
|
+
clearTimeout(mainTimeout);
|
|
126
|
+
reject(error);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=output-watcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output-watcher.js","sourceRoot":"","sources":["../../src/daemon/output-watcher.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;;;AAsBH,sCA4GC;AAhID,wDAAgC;AAChC,4CAAoB;AACpB,gDAAwB;AASxB;;;;;;;;GAQG;AACH,SAAgB,aAAa,CAC3B,UAAkB,EAClB,IAAkD;IAElD,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,IAAI,SAAS,CAAC;IAChD,MAAM,gBAAgB,GAAG,MAAM,CAAC;IAChC,MAAM,SAAS,GAAG,cAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAC3C,MAAM,cAAc,GAAG,cAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IAEjD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,IAAI,QAAQ,GAAG,KAAK,CAAC;QACrB,IAAI,aAAa,GAAG,CAAC,CAAC;QACtB,IAAI,cAAc,GAAG,CAAC,CAAC;QAEvB,eAAe;QACf,MAAM,WAAW,GAAG,UAAU,CAAC,GAAG,EAAE;YAClC,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,QAAQ,GAAG,IAAI,CAAC;gBAChB,OAAO,CAAC,KAAK,EAAE,CAAC;gBAChB,IAAI,oBAAoB;oBAAE,aAAa,CAAC,oBAAoB,CAAC,CAAC;gBAC9D,MAAM,CAAC,IAAI,KAAK,CAAC,oCAAoC,IAAI,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC;YAC5E,CAAC;QACH,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QAEnB,gEAAgE;QAChE,MAAM,YAAY,GAAG,GAAG,EAAE;YACxB,IAAI,CAAC,QAAQ,IAAI,cAAc,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,aAAa,GAAG,gBAAgB,EAAE,CAAC;gBACrF,QAAQ,GAAG,IAAI,CAAC;gBAChB,OAAO,CAAC,KAAK,EAAE,CAAC;gBAChB,IAAI,oBAAoB;oBAAE,aAAa,CAAC,oBAAoB,CAAC,CAAC;gBAC9D,YAAY,CAAC,WAAW,CAAC,CAAC;gBAE1B,IAAI,CAAC;oBACH,MAAM,OAAO,GAAG,YAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;oBACrD,OAAO,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;gBACzD,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,MAAM,CAAC,IAAI,KAAK,CAAC,+BAA+B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;gBAC7G,CAAC;YACH,CAAC;QACH,CAAC,CAAC;QACF,MAAM,oBAAoB,GAAG,WAAW,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;QAE7D,kCAAkC;QAClC,MAAM,OAAO,GAAG,kBAAQ,CAAC,KAAK,CAAC,SAAS,EAAE;YACxC,OAAO,EAAE,cAAc;YACvB,gBAAgB,EAAE,EAAE,kBAAkB,EAAE,GAAG,EAAE,YAAY,EAAE,GAAG,EAAE;YAChE,UAAU,EAAE,IAAI;SACjB,CAAC,CAAC;QAEH,uEAAuE;QACvE,qEAAqE;QACrE,wEAAwE;QACxE,0BAA0B;QAC1B,MAAM,aAAa,GAAG,CAAC,QAAgB,EAAE,EAAE;YACzC,IAAI,cAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,cAAc;gBAAE,OAAO;YAEvD,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC3B,IAAI,cAAc,KAAK,CAAC;gBAAE,cAAc,GAAG,aAAa,CAAC;YAEzD,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,YAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;gBACrD,IAAI,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;oBAC/B,IAAI,CAAC,QAAQ,EAAE,CAAC;wBACd,QAAQ,GAAG,IAAI,CAAC;wBAChB,OAAO,CAAC,KAAK,EAAE,CAAC;wBAChB,IAAI,oBAAoB;4BAAE,aAAa,CAAC,oBAAoB,CAAC,CAAC;wBAC9D,YAAY,CAAC,WAAW,CAAC,CAAC;wBAC1B,OAAO,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;oBACnC,CAAC;gBACH,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,qEAAqE;YACvE,CAAC;QACH,CAAC,CAAC;QAEF,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;QACjC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;QAEpC,0EAA0E;QAC1E,sEAAsE;QACtE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,EAAE;YAC7B,IAAI,cAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,MAAM;gBAAE,OAAO;YAE/C,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,QAAQ,GAAG,IAAI,CAAC;gBAChB,OAAO,CAAC,KAAK,EAAE,CAAC;gBAChB,IAAI,oBAAoB;oBAAE,aAAa,CAAC,oBAAoB,CAAC,CAAC;gBAC9D,YAAY,CAAC,WAAW,CAAC,CAAC;gBAE1B,IAAI,CAAC;oBACH,MAAM,OAAO,GAAG,YAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;oBACrD,OAAO,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;gBACnC,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,MAAM,CAAC,IAAI,KAAK,CAAC,+BAA+B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;gBAC7G,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;YAC5B,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,QAAQ,GAAG,IAAI,CAAC;gBAChB,OAAO,CAAC,KAAK,EAAE,CAAC;gBAChB,IAAI,oBAAoB;oBAAE,aAAa,CAAC,oBAAoB,CAAC,CAAC;gBAC9D,YAAY,CAAC,WAAW,CAAC,CAAC;gBAC1B,MAAM,CAAC,KAAK,CAAC,CAAC;YAChB,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Per-participant abort registry.
|
|
4
|
+
*
|
|
5
|
+
* Chat-level cancel goes through the chat-wide `AbortController` in
|
|
6
|
+
* `runWithMultiplex` and tears down every runner. This module covers the
|
|
7
|
+
* narrower case: cancelling a single reviewer (or doer) without
|
|
8
|
+
* collapsing the whole chat. The runner registers a child controller
|
|
9
|
+
* here when a participant subprocess starts; the cockpit hits a
|
|
10
|
+
* dedicated route to fire it.
|
|
11
|
+
*
|
|
12
|
+
* Why a Map keyed by chatId → participantKey:
|
|
13
|
+
* - O(1) lookup from the route handler
|
|
14
|
+
* - Lets `cleanupChat(chatId)` wipe stale entries when a chat ends
|
|
15
|
+
* - Naturally scopes participant keys (a reviewer-1 in chat A doesn't
|
|
16
|
+
* collide with reviewer-1 in chat B)
|
|
17
|
+
*
|
|
18
|
+
* Combining with the parent signal: each `register` returns a
|
|
19
|
+
* `combinedSignal` that fires when EITHER the parent (chat-level) signal
|
|
20
|
+
* fires OR `abortParticipant` is called for this key. We use
|
|
21
|
+
* AbortSignal.any (Node 20+) to compose. This way chat-cancel still
|
|
22
|
+
* propagates to every runner without duplicating wiring at every call
|
|
23
|
+
* site.
|
|
24
|
+
*/
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.participantKey = participantKey;
|
|
27
|
+
exports.register = register;
|
|
28
|
+
exports.abortParticipant = abortParticipant;
|
|
29
|
+
exports.cleanupChat = cleanupChat;
|
|
30
|
+
exports._activeKeys = _activeKeys;
|
|
31
|
+
const registry = new Map();
|
|
32
|
+
/**
|
|
33
|
+
* Build the participant key. Doers carry `agentName`; reviewers carry
|
|
34
|
+
* `agentName` + index. Format kept stable so the route handler can
|
|
35
|
+
* accept the same shape from the URL path.
|
|
36
|
+
*/
|
|
37
|
+
function participantKey(role, agentName, reviewerIdx) {
|
|
38
|
+
return role === 'reviewer'
|
|
39
|
+
? `reviewer-${agentName}-${reviewerIdx ?? 0}`
|
|
40
|
+
: `doer-${agentName}`;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Register a runner for per-participant cancellation.
|
|
44
|
+
*
|
|
45
|
+
* @param chatId Chat the runner belongs to.
|
|
46
|
+
* @param key Output of `participantKey(...)`.
|
|
47
|
+
* @param parent The chat-wide signal — its abort fires the combined signal too.
|
|
48
|
+
*/
|
|
49
|
+
function register(chatId, key, parent) {
|
|
50
|
+
let chatMap = registry.get(chatId);
|
|
51
|
+
if (!chatMap) {
|
|
52
|
+
chatMap = new Map();
|
|
53
|
+
registry.set(chatId, chatMap);
|
|
54
|
+
}
|
|
55
|
+
// Dedup: if a previous runner with the same key didn't release (crash,
|
|
56
|
+
// race), aborting it now is harmless and avoids leaking the prior
|
|
57
|
+
// controller. The new runner gets a fresh controller below.
|
|
58
|
+
const previous = chatMap.get(key);
|
|
59
|
+
if (previous) {
|
|
60
|
+
try {
|
|
61
|
+
previous.abort();
|
|
62
|
+
}
|
|
63
|
+
catch { /* ignore */ }
|
|
64
|
+
}
|
|
65
|
+
const child = new AbortController();
|
|
66
|
+
chatMap.set(key, child);
|
|
67
|
+
// AbortSignal.any composes — fires when either parent or child aborts.
|
|
68
|
+
// Standardised in Node 20.x; engines pin in package.json gates lower.
|
|
69
|
+
const signal = AbortSignal.any([parent, child.signal]);
|
|
70
|
+
return {
|
|
71
|
+
signal,
|
|
72
|
+
release: () => {
|
|
73
|
+
const cur = registry.get(chatId);
|
|
74
|
+
if (!cur)
|
|
75
|
+
return;
|
|
76
|
+
// Only remove if the entry still points at THIS controller — a
|
|
77
|
+
// re-registered key from a retried run shouldn't be wiped here.
|
|
78
|
+
if (cur.get(key) === child) {
|
|
79
|
+
cur.delete(key);
|
|
80
|
+
if (cur.size === 0)
|
|
81
|
+
registry.delete(chatId);
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Fire the controller for a single participant. Returns true if a
|
|
88
|
+
* controller was found and aborted, false if the participant isn't
|
|
89
|
+
* tracked (already finished, never started, wrong key).
|
|
90
|
+
*/
|
|
91
|
+
function abortParticipant(chatId, key) {
|
|
92
|
+
const chatMap = registry.get(chatId);
|
|
93
|
+
if (!chatMap)
|
|
94
|
+
return false;
|
|
95
|
+
const controller = chatMap.get(key);
|
|
96
|
+
if (!controller)
|
|
97
|
+
return false;
|
|
98
|
+
try {
|
|
99
|
+
controller.abort();
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Drop all controllers for a chat — called when the chat ends so the
|
|
108
|
+
* registry doesn't accrete stale entries across long daemon uptime.
|
|
109
|
+
* Doesn't fire any controllers: the chat is already terminating, the
|
|
110
|
+
* underlying processes are exiting through their own signals.
|
|
111
|
+
*/
|
|
112
|
+
function cleanupChat(chatId) {
|
|
113
|
+
registry.delete(chatId);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Test/debug: peek at the keys for a chat. Production code never reads
|
|
117
|
+
* this; exported so vitest can assert registry hygiene.
|
|
118
|
+
*/
|
|
119
|
+
function _activeKeys(chatId) {
|
|
120
|
+
const chatMap = registry.get(chatId);
|
|
121
|
+
return chatMap ? Array.from(chatMap.keys()) : [];
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=participant-aborts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"participant-aborts.js","sourceRoot":"","sources":["../../src/daemon/participant-aborts.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;;AAgBH,wCAQC;AASD,4BAsCC;AAOD,4CAWC;AAQD,kCAEC;AAMD,kCAGC;AA1GD,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAwC,CAAC;AASjE;;;;GAIG;AACH,SAAgB,cAAc,CAC5B,IAAyB,EACzB,SAAiB,EACjB,WAAoB;IAEpB,OAAO,IAAI,KAAK,UAAU;QACxB,CAAC,CAAC,YAAY,SAAS,IAAI,WAAW,IAAI,CAAC,EAAE;QAC7C,CAAC,CAAC,QAAQ,SAAS,EAAE,CAAC;AAC1B,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,QAAQ,CACtB,MAAc,EACd,GAAW,EACX,MAAmB;IAEnB,IAAI,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACnC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,GAAG,IAAI,GAAG,EAAE,CAAC;QACpB,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,CAAC;IACD,uEAAuE;IACvE,kEAAkE;IAClE,4DAA4D;IAC5D,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,QAAQ,EAAE,CAAC;QACb,IAAI,CAAC;YAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IAClD,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,eAAe,EAAE,CAAC;IACpC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAExB,uEAAuE;IACvE,sEAAsE;IACtE,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IAEvD,OAAO;QACL,MAAM;QACN,OAAO,EAAE,GAAG,EAAE;YACZ,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACjC,IAAI,CAAC,GAAG;gBAAE,OAAO;YACjB,+DAA+D;YAC/D,gEAAgE;YAChE,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,KAAK,EAAE,CAAC;gBAC3B,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBAChB,IAAI,GAAG,CAAC,IAAI,KAAK,CAAC;oBAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAC9C,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,SAAgB,gBAAgB,CAAC,MAAc,EAAE,GAAW;IAC1D,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACrC,IAAI,CAAC,OAAO;QAAE,OAAO,KAAK,CAAC;IAC3B,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,CAAC,UAAU;QAAE,OAAO,KAAK,CAAC;IAC9B,IAAI,CAAC;QACH,UAAU,CAAC,KAAK,EAAE,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAgB,WAAW,CAAC,MAAc;IACxC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AAC1B,CAAC;AAED;;;GAGG;AACH,SAAgB,WAAW,CAAC,MAAc;IACxC,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACrC,OAAO,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACnD,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.startReaper = startReaper;
|
|
4
|
+
const cli_health_js_1 = require("../lib/cli-health.js");
|
|
5
|
+
/**
|
|
6
|
+
* Start the reaper service. Returns a stop() function for graceful shutdown.
|
|
7
|
+
*
|
|
8
|
+
* The reaper runs every `intervalMs` and kills:
|
|
9
|
+
* 1. Orphaned sessions (chatId not in activeChats)
|
|
10
|
+
* 2. Sessions whose chat is in a terminal state
|
|
11
|
+
* 3. Sessions in terminal state
|
|
12
|
+
* 4. Sessions in awaiting_user state idle > idleDestroyMinutes
|
|
13
|
+
*
|
|
14
|
+
* Logs one-liner summaries of killed sessions.
|
|
15
|
+
*/
|
|
16
|
+
function startReaper(mgr, getActiveChats, cfg) {
|
|
17
|
+
const interval = setInterval(() => {
|
|
18
|
+
void (async () => {
|
|
19
|
+
try {
|
|
20
|
+
const activeChats = await getActiveChats();
|
|
21
|
+
const result = mgr.reapOnce({
|
|
22
|
+
activeChats,
|
|
23
|
+
idleDestroyMinutes: cfg.idleDestroyMinutes,
|
|
24
|
+
});
|
|
25
|
+
if (result.killed.length > 0) {
|
|
26
|
+
console.log(`[reaper] Killed ${result.killed.length} session(s): ${result.killed.join(', ')}`);
|
|
27
|
+
}
|
|
28
|
+
// Auto-clear stale quota / rate-limit state. Without this, the
|
|
29
|
+
// home-page fleet card stays red after the upstream window passes
|
|
30
|
+
// until the next failed call would otherwise overwrite health.
|
|
31
|
+
const cleared = await (0, cli_health_js_1.clearStaleHealth)();
|
|
32
|
+
if (cleared.length > 0) {
|
|
33
|
+
console.log(`[reaper] Cleared stale health: ${cleared.join(', ')}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
console.error('[reaper] Error during sweep:', error);
|
|
38
|
+
}
|
|
39
|
+
})();
|
|
40
|
+
}, cfg.intervalMs);
|
|
41
|
+
// Return stop function
|
|
42
|
+
return () => {
|
|
43
|
+
clearInterval(interval);
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=reaper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reaper.js","sourceRoot":"","sources":["../../src/daemon/reaper.ts"],"names":[],"mappings":";;AAwBA,kCAmCC;AA1DD,wDAAwD;AAYxD;;;;;;;;;;GAUG;AACH,SAAgB,WAAW,CACzB,GAAgB,EAChB,cAAkD,EAClD,GAAiB;IAEjB,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE;QAChC,KAAK,CAAC,KAAK,IAAI,EAAE;YACf,IAAI,CAAC;gBACH,MAAM,WAAW,GAAG,MAAM,cAAc,EAAE,CAAC;gBAC3C,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,CAAC;oBAC1B,WAAW;oBACX,kBAAkB,EAAE,GAAG,CAAC,kBAAkB;iBAC3C,CAAC,CAAC;gBAEH,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC7B,OAAO,CAAC,GAAG,CAAC,mBAAmB,MAAM,CAAC,MAAM,CAAC,MAAM,gBAAgB,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBACjG,CAAC;gBAED,+DAA+D;gBAC/D,kEAAkE;gBAClE,+DAA+D;gBAC/D,MAAM,OAAO,GAAG,MAAM,IAAA,gCAAgB,GAAE,CAAC;gBACzC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACvB,OAAO,CAAC,GAAG,CAAC,kCAAkC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBACtE,CAAC;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,KAAK,CAAC,CAAC;YACvD,CAAC;QACH,CAAC,CAAC,EAAE,CAAC;IACP,CAAC,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC;IAEnB,uBAAuB;IACvB,OAAO,GAAG,EAAE;QACV,aAAa,CAAC,QAAQ,CAAC,CAAC;IAC1B,CAAC,CAAC;AACJ,CAAC"}
|