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,384 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.runReviewerHeadless = runReviewerHeadless;
|
|
37
|
+
/**
|
|
38
|
+
* Reviewer streaming execution.
|
|
39
|
+
*
|
|
40
|
+
* Mirrors runDoerHeadless but returns a boolean | null verdict instead of
|
|
41
|
+
* the {content, full} shape — caller (the per-chat reviewer pool) only
|
|
42
|
+
* needs to know agreed / disagreed / failed.
|
|
43
|
+
*
|
|
44
|
+
* Tested by tests/runner-reviewer.test.ts.
|
|
45
|
+
*/
|
|
46
|
+
const fs = __importStar(require("fs"));
|
|
47
|
+
const path = __importStar(require("path"));
|
|
48
|
+
const template_schema_js_1 = require("../../lib/template-schema.js");
|
|
49
|
+
const permissions_js_1 = require("../../lib/settings/permissions.js");
|
|
50
|
+
const cli_health_js_1 = require("../../lib/cli-health.js");
|
|
51
|
+
const stream_file_writer_js_1 = require("./stream-file-writer.js");
|
|
52
|
+
const verdict_js_1 = require("./verdict.js");
|
|
53
|
+
async function runReviewerHeadless(args) {
|
|
54
|
+
const { shim, chatId, phase, round, reviewerIdx, candidateLineage, candidateModel, agentName, askContent, answerFile, reviewerDir, abortSignal, onEvent, } = args;
|
|
55
|
+
if (!shim.runHeadless)
|
|
56
|
+
return null;
|
|
57
|
+
const perms = await (0, permissions_js_1.getPermissions)();
|
|
58
|
+
const startedAt = Date.now();
|
|
59
|
+
let accumulated = '';
|
|
60
|
+
let finalText;
|
|
61
|
+
let errored = false;
|
|
62
|
+
let capturedUsage;
|
|
63
|
+
// Captured from the first error event so we can write it to
|
|
64
|
+
// answer.md when the subprocess dies before producing any content.
|
|
65
|
+
// Without this, callers reading ~/.chorus/chats/<id>/round-N/
|
|
66
|
+
// reviewer-<agent>/answer.md see a 0-byte file with no clue what
|
|
67
|
+
// went wrong (opencode lock contention, codex quota, etc.).
|
|
68
|
+
let errorSummary;
|
|
69
|
+
fs.writeFileSync(answerFile, '');
|
|
70
|
+
const writer = new stream_file_writer_js_1.StreamFileWriter(answerFile);
|
|
71
|
+
const stream = shim.runHeadless({
|
|
72
|
+
cwd: reviewerDir,
|
|
73
|
+
promptText: askContent,
|
|
74
|
+
model: candidateModel,
|
|
75
|
+
sandbox: perms.sandboxProfile,
|
|
76
|
+
autoApprove: perms.autoApprovePrompts,
|
|
77
|
+
networkAccess: perms.networkAccess,
|
|
78
|
+
abortSignal,
|
|
79
|
+
timeoutMs: phase.timeoutMs ?? template_schema_js_1.DEFAULT_PHASE_TIMEOUT_MS,
|
|
80
|
+
});
|
|
81
|
+
// Safety net: if the stream closes without emitting ANY event (no text,
|
|
82
|
+
// no error, no message_done), the reviewer subprocess silently produced
|
|
83
|
+
// nothing — most often a CLI that wrote model output to /dev/tty instead
|
|
84
|
+
// of the pipe, or one that exited 0 with empty stdout. Without this
|
|
85
|
+
// counter the finally block has no signal to write a failure summary
|
|
86
|
+
// (errorSummary stays undefined), and answer.md ends up 0 bytes — the
|
|
87
|
+
// exact silent failure that hid opencode-cli for two days.
|
|
88
|
+
let eventCount = 0;
|
|
89
|
+
try {
|
|
90
|
+
for await (const event of stream) {
|
|
91
|
+
eventCount += 1;
|
|
92
|
+
if (event.type === 'text_delta') {
|
|
93
|
+
accumulated += event.text;
|
|
94
|
+
writer.write(event.text);
|
|
95
|
+
onEvent({
|
|
96
|
+
chatId,
|
|
97
|
+
type: 'phase_progress',
|
|
98
|
+
payload: {
|
|
99
|
+
phaseId: phase.id,
|
|
100
|
+
round,
|
|
101
|
+
role: 'reviewer',
|
|
102
|
+
agent: `${agentName}-${reviewerIdx}`,
|
|
103
|
+
output: accumulated.slice(-500),
|
|
104
|
+
},
|
|
105
|
+
ts: Date.now(),
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
else if (event.type === 'tool_call_start') {
|
|
109
|
+
onEvent({
|
|
110
|
+
chatId,
|
|
111
|
+
type: 'phase_progress',
|
|
112
|
+
payload: {
|
|
113
|
+
phaseId: phase.id,
|
|
114
|
+
round,
|
|
115
|
+
role: 'reviewer',
|
|
116
|
+
agent: `${agentName}-${reviewerIdx}`,
|
|
117
|
+
tool: event.tool,
|
|
118
|
+
},
|
|
119
|
+
ts: Date.now(),
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
else if (event.type === 'progress') {
|
|
123
|
+
onEvent({
|
|
124
|
+
chatId,
|
|
125
|
+
type: 'phase_progress',
|
|
126
|
+
payload: {
|
|
127
|
+
phaseId: phase.id,
|
|
128
|
+
round,
|
|
129
|
+
role: 'reviewer',
|
|
130
|
+
agent: `${agentName}-${reviewerIdx}`,
|
|
131
|
+
elapsedMs: event.elapsedMs,
|
|
132
|
+
},
|
|
133
|
+
ts: Date.now(),
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
else if (event.type === 'message_done') {
|
|
137
|
+
finalText = event.finalText;
|
|
138
|
+
if (event.usage)
|
|
139
|
+
capturedUsage = event.usage;
|
|
140
|
+
// Same guard as the doer side: don't truncate accumulated deltas
|
|
141
|
+
// when the CLI emits an empty `result` event (Gemini's text-then-
|
|
142
|
+
// disappears bug). Only overwrite when there's real authoritative
|
|
143
|
+
// text; otherwise just append the sentinel to what's already there.
|
|
144
|
+
writer.flushNow();
|
|
145
|
+
if (event.finalText.trim().length === 0) {
|
|
146
|
+
const existing = fs.existsSync(answerFile)
|
|
147
|
+
? fs.readFileSync(answerFile, 'utf-8')
|
|
148
|
+
: '';
|
|
149
|
+
if (!/\n##\s*DONE\s*\n?$/i.test(existing.trimEnd())) {
|
|
150
|
+
fs.appendFileSync(answerFile, existing.endsWith('\n') ? '\n## DONE\n' : '\n\n## DONE\n');
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
// Don't double-stamp the sentinel. Codex (and any CLI that
|
|
155
|
+
// ends its own output with "## DONE") would otherwise ship
|
|
156
|
+
// an answer with `... ## DONE\n\n\n## DONE\n` — the verdict
|
|
157
|
+
// heuristic doesn't care, but it looks unprofessional in the
|
|
158
|
+
// cockpit and breaks tools that grep for a single sentinel.
|
|
159
|
+
const trimmedTail = event.finalText.replace(/\s+$/, '');
|
|
160
|
+
const alreadyHasSentinel = /\n##\s*DONE\s*$/i.test(trimmedTail);
|
|
161
|
+
const body = alreadyHasSentinel
|
|
162
|
+
? `${trimmedTail}\n`
|
|
163
|
+
: `${trimmedTail}\n\n## DONE\n`;
|
|
164
|
+
fs.writeFileSync(answerFile, body);
|
|
165
|
+
}
|
|
166
|
+
// Persist runtime stats next to the answer so the cockpit run-
|
|
167
|
+
// artifacts route can surface "12.4s · 3.4k tok" on the card even
|
|
168
|
+
// after a daemon restart or browser reload. Sidecar mirrors the
|
|
169
|
+
// existing _meta.json (transport metadata) shape — write best-
|
|
170
|
+
// effort, ignore errors.
|
|
171
|
+
try {
|
|
172
|
+
fs.writeFileSync(path.join(reviewerDir, '_stats.json'), JSON.stringify({
|
|
173
|
+
durationMs: Date.now() - startedAt,
|
|
174
|
+
...(capturedUsage ? { usage: capturedUsage } : {}),
|
|
175
|
+
}), 'utf-8');
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
/* sidecar is informational; ignore write errors */
|
|
179
|
+
}
|
|
180
|
+
// participant_done payload carries identity only. The cockpit
|
|
181
|
+
// refetches /api/run-artifacts on this event to pick up the
|
|
182
|
+
// sidecar-backed stats — see retroactive PR #16 review for why
|
|
183
|
+
// duplicating durationMs/usage in the SSE payload was dead bytes.
|
|
184
|
+
onEvent({
|
|
185
|
+
chatId,
|
|
186
|
+
type: 'participant_done',
|
|
187
|
+
payload: {
|
|
188
|
+
phaseId: phase.id,
|
|
189
|
+
round,
|
|
190
|
+
role: 'reviewer',
|
|
191
|
+
agent: `${agentName}-${reviewerIdx}`,
|
|
192
|
+
},
|
|
193
|
+
ts: Date.now(),
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
else if (event.type === 'error') {
|
|
197
|
+
errored = true;
|
|
198
|
+
// Surface OpenRouter HTTP failures (insufficient credits, bad key,
|
|
199
|
+
// rate-limit, upstream outage) as health state so the home-page
|
|
200
|
+
// OpenRouter card flips to a quota/auth/rate-limit badge — same
|
|
201
|
+
// surfacing tmux CLIs already get via error-detector. Best-effort:
|
|
202
|
+
// health write doesn't block the run-page error event.
|
|
203
|
+
const classified = (0, cli_health_js_1.classifyOpenRouterError)(event.kind, event.message);
|
|
204
|
+
if (classified) {
|
|
205
|
+
(0, cli_health_js_1.recordHealth)({
|
|
206
|
+
lineage: 'openrouter',
|
|
207
|
+
status: classified.status,
|
|
208
|
+
message: classified.message,
|
|
209
|
+
}).catch((healthErr) => {
|
|
210
|
+
console.error('[chorus] recordHealth failed for openrouter:', healthErr);
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
// First error wins by default — but a more-specific later
|
|
214
|
+
// kind can supersede a vague earlier one. The gemini parser
|
|
215
|
+
// emits a generic `gemini_result_error` from the JSON result
|
|
216
|
+
// line; the on-exit handler then emits a precise
|
|
217
|
+
// `quota_exhausted` from stderr with the reset window. Without
|
|
218
|
+
// this upgrade rule the cockpit shows the vague first message
|
|
219
|
+
// and the user has no idea when their quota resets.
|
|
220
|
+
const VAGUE_KINDS = new Set(['gemini_result_error']);
|
|
221
|
+
const SPECIFIC_KINDS = new Set([
|
|
222
|
+
'quota_exhausted',
|
|
223
|
+
'rate_limit',
|
|
224
|
+
'auth_error',
|
|
225
|
+
'sandbox_unsupported',
|
|
226
|
+
'cli_not_in_path',
|
|
227
|
+
]);
|
|
228
|
+
const isUpgrade = errorSummary &&
|
|
229
|
+
VAGUE_KINDS.has(errorSummary.kind) &&
|
|
230
|
+
SPECIFIC_KINDS.has(event.kind);
|
|
231
|
+
if (!errorSummary || isUpgrade) {
|
|
232
|
+
errorSummary = {
|
|
233
|
+
kind: event.kind,
|
|
234
|
+
message: classified?.message ?? event.message,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
onEvent({
|
|
238
|
+
chatId,
|
|
239
|
+
type: 'cli_error',
|
|
240
|
+
payload: {
|
|
241
|
+
phaseId: phase.id,
|
|
242
|
+
phaseKind: phase.kind,
|
|
243
|
+
phaseIdx: 0,
|
|
244
|
+
round,
|
|
245
|
+
role: 'reviewer',
|
|
246
|
+
agent: `${agentName}-${reviewerIdx}`,
|
|
247
|
+
error: {
|
|
248
|
+
kind: event.kind,
|
|
249
|
+
message: classified?.message ?? event.message,
|
|
250
|
+
...(classified?.cta ? { cta: classified.cta } : {}),
|
|
251
|
+
lineage: candidateLineage,
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
ts: Date.now(),
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
catch (err) {
|
|
260
|
+
errored = true;
|
|
261
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
262
|
+
if (!errorSummary) {
|
|
263
|
+
errorSummary = { kind: 'stream_failure', message };
|
|
264
|
+
}
|
|
265
|
+
onEvent({
|
|
266
|
+
chatId,
|
|
267
|
+
type: 'cli_error',
|
|
268
|
+
payload: {
|
|
269
|
+
phaseId: phase.id,
|
|
270
|
+
phaseKind: phase.kind,
|
|
271
|
+
phaseIdx: 0,
|
|
272
|
+
round,
|
|
273
|
+
role: 'reviewer',
|
|
274
|
+
agent: `${agentName}-${reviewerIdx}`,
|
|
275
|
+
error: {
|
|
276
|
+
kind: 'stream_failure',
|
|
277
|
+
message,
|
|
278
|
+
lineage: candidateLineage,
|
|
279
|
+
},
|
|
280
|
+
},
|
|
281
|
+
ts: Date.now(),
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
finally {
|
|
285
|
+
writer.flushNow();
|
|
286
|
+
// Stream closed with zero events — the CLI ran but produced nothing
|
|
287
|
+
// we could parse (e.g. opencode 1.14.x writing to /dev/tty instead of
|
|
288
|
+
// the pipe, or any future CLI that exits 0 with empty stdout).
|
|
289
|
+
// Synthesise a no_output failure so:
|
|
290
|
+
// 1. The reviewer card renders the kind+lineage instead of the
|
|
291
|
+
// generic "didn't produce any output" stub.
|
|
292
|
+
// 2. answer.md carries a `## REVIEWER FAILED` block, matching the
|
|
293
|
+
// contract every other failure mode writes.
|
|
294
|
+
// 3. The runner's verdict parser sees a definite "request changes"
|
|
295
|
+
// shape, not an empty string the verdict logic is undefined on.
|
|
296
|
+
if (eventCount === 0 && !errorSummary) {
|
|
297
|
+
errored = true;
|
|
298
|
+
errorSummary = {
|
|
299
|
+
kind: 'no_output',
|
|
300
|
+
message: `${candidateLineage} CLI closed without emitting any output. ` +
|
|
301
|
+
`Likely a transport bug (e.g. opencode 1.14.x writes JSON only to a TTY) ` +
|
|
302
|
+
`or a silent abort. Check the CLI's own log for details.`,
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
// When the subprocess died without producing any content, write the
|
|
306
|
+
// error summary to answer.md so the chat dir is self-explanatory.
|
|
307
|
+
// Otherwise post-mortem inspection sees an empty file with no
|
|
308
|
+
// signal — exactly the silent-failure that hid opencode-cli-2's
|
|
309
|
+
// failure on the PR #10 review chat.
|
|
310
|
+
if (errored && accumulated.length === 0 && (!finalText || finalText.length === 0) && errorSummary) {
|
|
311
|
+
try {
|
|
312
|
+
// For quota / rate-limit failures, the error-detector (tmux path)
|
|
313
|
+
// or recordHealth call (HTTP shim path) has already stamped the
|
|
314
|
+
// lineage's cli-health row with `resetAt` if it's known. Pull
|
|
315
|
+
// that here so the cockpit's failure card can render a "Resets
|
|
316
|
+
// at HH:MM" countdown without a second round-trip. Best-effort:
|
|
317
|
+
// resolves to undefined for unknown lineages or cleared health.
|
|
318
|
+
let resetAt;
|
|
319
|
+
try {
|
|
320
|
+
const h = await (0, cli_health_js_1.getHealth)(candidateLineage);
|
|
321
|
+
if (typeof h.resetAt === 'number' && h.resetAt > Date.now()) {
|
|
322
|
+
resetAt = h.resetAt;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
catch {
|
|
326
|
+
/* health lookup is informational */
|
|
327
|
+
}
|
|
328
|
+
fs.writeFileSync(answerFile, `## REVIEWER FAILED\n\n` +
|
|
329
|
+
`**Kind:** ${errorSummary.kind}\n` +
|
|
330
|
+
`**Lineage:** ${candidateLineage}\n` +
|
|
331
|
+
`**Model:** ${candidateModel ?? '(default)'}\n` +
|
|
332
|
+
(resetAt ? `**Resets:** ${new Date(resetAt).toISOString()}\n` : '') +
|
|
333
|
+
`\n${errorSummary.message}\n`);
|
|
334
|
+
}
|
|
335
|
+
catch {
|
|
336
|
+
/* best-effort — don't fail the runner because of a write error */
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
// Mirror runDoerHeadless: surface answer.md write failures as a
|
|
340
|
+
// cli_warning so the user sees "stream stopped writing" instead of
|
|
341
|
+
// a quietly truncated reviewer transcript that the verdict parser
|
|
342
|
+
// then chokes on.
|
|
343
|
+
if (writer.isDead()) {
|
|
344
|
+
const err = writer.lastError();
|
|
345
|
+
onEvent({
|
|
346
|
+
chatId,
|
|
347
|
+
type: 'cli_warning',
|
|
348
|
+
payload: {
|
|
349
|
+
phaseId: phase.id,
|
|
350
|
+
round,
|
|
351
|
+
role: 'reviewer',
|
|
352
|
+
agent: `${agentName}-${reviewerIdx}`,
|
|
353
|
+
reason: 'stream_writer_dead',
|
|
354
|
+
message: `answer.md write failed; subsequent deltas dropped: ${err ? err.message : 'unknown'}`,
|
|
355
|
+
cta: 'Check disk space + permissions on ~/.chorus/chats. Re-run when fixed.',
|
|
356
|
+
},
|
|
357
|
+
ts: Date.now(),
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
// Prefer answer.md on disk over streamed text. Tool-using CLIs (gemini)
|
|
362
|
+
// put the actual review into the file via a Write tool call and only
|
|
363
|
+
// stream a confirmation message ("Changes have been requested...") that
|
|
364
|
+
// the verdict heuristic can't classify. Reading the file picks up both
|
|
365
|
+
// the tool-written verdict AND any text_delta-appended assistant text,
|
|
366
|
+
// matching what the cockpit and CLI both display to the user.
|
|
367
|
+
let onDisk = '';
|
|
368
|
+
try {
|
|
369
|
+
if (fs.existsSync(answerFile)) {
|
|
370
|
+
onDisk = fs.readFileSync(answerFile, 'utf-8');
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
catch {
|
|
374
|
+
/* best-effort — fall through to streamed content */
|
|
375
|
+
}
|
|
376
|
+
const streamed = finalText && finalText.length > 0 ? finalText : accumulated;
|
|
377
|
+
const content = onDisk.trim().length > 0 ? onDisk : streamed;
|
|
378
|
+
if (errored && content.trim().length === 0)
|
|
379
|
+
return null;
|
|
380
|
+
if (content.trim().length === 0)
|
|
381
|
+
return null;
|
|
382
|
+
return (0, verdict_js_1.verdictFromReviewerText)(content);
|
|
383
|
+
}
|
|
384
|
+
//# sourceMappingURL=reviewer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reviewer.js","sourceRoot":"","sources":["../../../src/daemon/runner/reviewer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runWithModelFallback = runWithModelFallback;
|
|
4
|
+
exports.runWithChainFallback = runWithChainFallback;
|
|
5
|
+
/**
|
|
6
|
+
* Per-slot model fallback chain.
|
|
7
|
+
*
|
|
8
|
+
* A reviewer or doer slot can list multiple models in `models[]`. When the
|
|
9
|
+
* primary returns null (subprocess produced no answer — quota, rate-limit,
|
|
10
|
+
* crash, empty-stream), this helper falls through to the next model in the
|
|
11
|
+
* list and retries. Auth and lineage selection are stable across the
|
|
12
|
+
* fallback because all models in a slot share the same lineage; only the
|
|
13
|
+
* `--model X` argv changes.
|
|
14
|
+
*
|
|
15
|
+
* Returning `null` from `attempt` is the agreed-upon "this model didn't
|
|
16
|
+
* produce an answer, please try the next one" signal. Throwing is
|
|
17
|
+
* propagated unchanged — a throw means something went wrong outside the
|
|
18
|
+
* model run (e.g. the chat dir disappeared) and falling through wouldn't
|
|
19
|
+
* help. Callers that want exceptions to engage the fallback should catch
|
|
20
|
+
* them inside `attempt` and return null instead.
|
|
21
|
+
*
|
|
22
|
+
* `onFallback(fromModel, toModel, fromIdx)` fires once per transition so
|
|
23
|
+
* the runner can emit a `cli_warning` event with `reason: 'model_fallback'`
|
|
24
|
+
* and the cockpit can show "claude-opus-4-7 → claude-sonnet-4-6" on the
|
|
25
|
+
* card. The index tells the cockpit how deep into the chain we are.
|
|
26
|
+
*
|
|
27
|
+
* If `models` is empty or undefined, exactly one attempt is made with
|
|
28
|
+
* `undefined` as the model — this matches the existing "no model = lineage
|
|
29
|
+
* default" semantics in the shim layer.
|
|
30
|
+
*/
|
|
31
|
+
async function runWithModelFallback(models, attempt, onFallback) {
|
|
32
|
+
const list = models && models.length > 0 ? [...models] : [undefined];
|
|
33
|
+
for (let i = 0; i < list.length; i++) {
|
|
34
|
+
const result = await attempt(list[i]);
|
|
35
|
+
if (result !== null)
|
|
36
|
+
return result;
|
|
37
|
+
if (i < list.length - 1) {
|
|
38
|
+
onFallback(list[i], list[i + 1], i);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
async function runWithChainFallback(chain, attempt, onFallback) {
|
|
44
|
+
if (chain.length === 0)
|
|
45
|
+
return null;
|
|
46
|
+
for (let i = 0; i < chain.length; i++) {
|
|
47
|
+
const result = await attempt(chain[i]);
|
|
48
|
+
if (result !== null)
|
|
49
|
+
return result;
|
|
50
|
+
if (i < chain.length - 1) {
|
|
51
|
+
onFallback(chain[i], chain[i + 1], i);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=run-with-fallback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-with-fallback.js","sourceRoot":"","sources":["../../../src/daemon/runner/run-with-fallback.ts"],"names":[],"mappings":";;AA0BA,oDAoBC;AAgBD,oDAcC;AA5ED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACI,KAAK,UAAU,oBAAoB,CACxC,MAA4B,EAC5B,OAAyD,EACzD,UAIS;IAET,MAAM,IAAI,GACR,MAAM,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAE1D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACtC,IAAI,MAAM,KAAK,IAAI;YAAE,OAAO,MAAM,CAAC;QACnC,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAgBM,KAAK,UAAU,oBAAoB,CACxC,KAA4B,EAC5B,OAAiD,EACjD,UAAuE;IAEvE,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACpC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACvC,IAAI,MAAM,KAAK,IAAI;YAAE,OAAO,MAAM,CAAC;QACnC,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzB,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACxC,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sanitizeName = sanitizeName;
|
|
4
|
+
/** tmux session names accept [a-zA-Z0-9_-]; drop everything else and clamp length. */
|
|
5
|
+
function sanitizeName(name) {
|
|
6
|
+
return name.replace(/[^a-zA-Z0-9_-]+/g, '_').slice(0, 80);
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=sanitize-name.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitize-name.js","sourceRoot":"","sources":["../../../src/daemon/runner/sanitize-name.ts"],"names":[],"mappings":";;AACA,oCAEC;AAHD,sFAAsF;AACtF,SAAgB,YAAY,CAAC,IAAY;IACvC,OAAO,IAAI,CAAC,OAAO,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC5D,CAAC"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.StreamFileWriter = void 0;
|
|
37
|
+
/**
|
|
38
|
+
* Buffered append-writer for live LLM streaming.
|
|
39
|
+
*
|
|
40
|
+
* Why this exists: the previous implementation called fs.appendFileSync on
|
|
41
|
+
* every text_delta event from the CLI shim. A typical Opus run emits ~5
|
|
42
|
+
* deltas/sec for ~5 minutes = ~1500 sync disk writes per doer, each one
|
|
43
|
+
* blocking the daemon event loop. Worse, the cockpit polls answer.md every
|
|
44
|
+
* 8s — it doesn't benefit from per-delta granularity.
|
|
45
|
+
*
|
|
46
|
+
* Now we flush whenever the buffer crosses 4KB OR a 750ms quiet timer
|
|
47
|
+
* fires, whichever comes first. Cockpit poll cadence is unchanged but
|
|
48
|
+
* the daemon does ~50 writes per run instead of ~1500.
|
|
49
|
+
*
|
|
50
|
+
* Caller MUST call flushNow() before any direct read of `path` or before
|
|
51
|
+
* fs.writeFileSync overwrites it — the buffer is otherwise lost.
|
|
52
|
+
*
|
|
53
|
+
* Failure semantics: if the underlying appendFileSync ever throws (FS
|
|
54
|
+
* ENOSPC, EACCES, etc.) the writer flips to a "dead" state and surfaces
|
|
55
|
+
* the cause via lastError(). Subsequent write() calls become no-ops; the
|
|
56
|
+
* buffered chunk that failed is dropped (re-trying would just fail again
|
|
57
|
+
* synchronously and leak more memory). The runner inspects isDead() /
|
|
58
|
+
* lastError() in its finally block to surface a cli_error event so the
|
|
59
|
+
* user knows their answer.md is partial — silent loss was the previous
|
|
60
|
+
* behavior and round-2 review flagged it.
|
|
61
|
+
*/
|
|
62
|
+
const fs = __importStar(require("fs"));
|
|
63
|
+
class StreamFileWriter {
|
|
64
|
+
filePath;
|
|
65
|
+
flushBytes;
|
|
66
|
+
flushMs;
|
|
67
|
+
buf = '';
|
|
68
|
+
flushTimer = null;
|
|
69
|
+
dead = false;
|
|
70
|
+
lastErr = null;
|
|
71
|
+
constructor(filePath, flushBytes = 4096, flushMs = 750) {
|
|
72
|
+
this.filePath = filePath;
|
|
73
|
+
this.flushBytes = flushBytes;
|
|
74
|
+
this.flushMs = flushMs;
|
|
75
|
+
}
|
|
76
|
+
write(chunk) {
|
|
77
|
+
if (!chunk || this.dead)
|
|
78
|
+
return;
|
|
79
|
+
this.buf += chunk;
|
|
80
|
+
if (this.buf.length >= this.flushBytes) {
|
|
81
|
+
this.flushNow();
|
|
82
|
+
}
|
|
83
|
+
else if (this.flushTimer === null) {
|
|
84
|
+
this.flushTimer = setTimeout(() => this.flushNow(), this.flushMs);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
flushNow() {
|
|
88
|
+
if (this.flushTimer !== null) {
|
|
89
|
+
clearTimeout(this.flushTimer);
|
|
90
|
+
this.flushTimer = null;
|
|
91
|
+
}
|
|
92
|
+
if (this.buf.length === 0 || this.dead)
|
|
93
|
+
return;
|
|
94
|
+
try {
|
|
95
|
+
fs.appendFileSync(this.filePath, this.buf);
|
|
96
|
+
this.buf = '';
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
// Permanent failure — flip dead, drop the in-flight buffer to free
|
|
100
|
+
// memory, surface via lastError() for the runner to forward as a
|
|
101
|
+
// cli_error so the user sees something instead of a quietly stale
|
|
102
|
+
// answer.md.
|
|
103
|
+
this.dead = true;
|
|
104
|
+
this.lastErr = err instanceof Error ? err : new Error(String(err));
|
|
105
|
+
this.buf = '';
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
isDead() {
|
|
109
|
+
return this.dead;
|
|
110
|
+
}
|
|
111
|
+
lastError() {
|
|
112
|
+
return this.lastErr;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
exports.StreamFileWriter = StreamFileWriter;
|
|
116
|
+
//# sourceMappingURL=stream-file-writer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream-file-writer.js","sourceRoot":"","sources":["../../../src/daemon/runner/stream-file-writer.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,uCAAyB;AAEzB,MAAa,gBAAgB;IAOR;IACA;IACA;IARX,GAAG,GAAG,EAAE,CAAC;IACT,UAAU,GAA0B,IAAI,CAAC;IACzC,IAAI,GAAG,KAAK,CAAC;IACb,OAAO,GAAiB,IAAI,CAAC;IAErC,YACmB,QAAgB,EAChB,aAAa,IAAI,EACjB,UAAU,GAAG;QAFb,aAAQ,GAAR,QAAQ,CAAQ;QAChB,eAAU,GAAV,UAAU,CAAO;QACjB,YAAO,GAAP,OAAO,CAAM;IAC7B,CAAC;IAEJ,KAAK,CAAC,KAAa;QACjB,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI;YAAE,OAAO;QAChC,IAAI,CAAC,GAAG,IAAI,KAAK,CAAC;QAClB,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACvC,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClB,CAAC;aAAM,IAAI,IAAI,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;YACpC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QACpE,CAAC;IACH,CAAC;IAED,QAAQ;QACN,IAAI,IAAI,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;YAC7B,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC9B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACzB,CAAC;QACD,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,IAAI;YAAE,OAAO;QAC/C,IAAI,CAAC;YACH,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;YAC3C,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC;QAChB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,mEAAmE;YACnE,iEAAiE;YACjE,kEAAkE;YAClE,aAAa;YACb,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;YACjB,IAAI,CAAC,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YACnE,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC;QAChB,CAAC;IACH,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED,SAAS;QACP,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;CACF;AAjDD,4CAiDC"}
|