chorus-codes 0.7.0 → 0.7.1
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/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/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 +240 -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 → 8H2I8TTPlrKuWCV-SxY5f}/_buildManifest.js +0 -0
- /package/.next/static/{dJlbRLlhISA0JGtHKVqgQ → 8H2I8TTPlrKuWCV-SxY5f}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{dJlbRLlhISA0JGtHKVqgQ → 8H2I8TTPlrKuWCV-SxY5f}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerStatusCommand = registerStatusCommand;
|
|
4
|
+
const shared_js_1 = require("../shared.js");
|
|
5
|
+
const ui_js_1 = require("../ui.js");
|
|
6
|
+
function registerStatusCommand(program) {
|
|
7
|
+
program
|
|
8
|
+
.command('status')
|
|
9
|
+
.description('Check daemon health')
|
|
10
|
+
.action(async () => {
|
|
11
|
+
try {
|
|
12
|
+
const response = await fetch(`${shared_js_1.DAEMON_URL}/api/v1/health`);
|
|
13
|
+
if (!response.ok) {
|
|
14
|
+
console.log('');
|
|
15
|
+
console.log((0, ui_js_1.header)(ui_js_1.sym.err, 'Daemon is not running', 'start with `chorus start`'));
|
|
16
|
+
console.log('');
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
const envelope = (await response.json());
|
|
20
|
+
const data = envelope.data;
|
|
21
|
+
if (envelope.ok && data) {
|
|
22
|
+
const uptime = Math.floor(data.uptime / 1000);
|
|
23
|
+
const human = uptime < 60
|
|
24
|
+
? `${uptime}s`
|
|
25
|
+
: uptime < 3600
|
|
26
|
+
? `${Math.floor(uptime / 60)}m`
|
|
27
|
+
: `${Math.floor(uptime / 3600)}h ${Math.floor((uptime % 3600) / 60)}m`;
|
|
28
|
+
console.log('');
|
|
29
|
+
console.log((0, ui_js_1.header)(ui_js_1.sym.ok, 'Chorus is running'));
|
|
30
|
+
console.log('');
|
|
31
|
+
console.log((0, ui_js_1.kv)([
|
|
32
|
+
['Version', ui_js_1.c.cyan(data.version)],
|
|
33
|
+
['Uptime', ui_js_1.c.dim(human)],
|
|
34
|
+
['Cockpit', ui_js_1.c.cyan(shared_js_1.COCKPIT_URL)],
|
|
35
|
+
['Daemon', ui_js_1.c.dim(shared_js_1.DAEMON_URL)],
|
|
36
|
+
]));
|
|
37
|
+
console.log('');
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
console.log('');
|
|
41
|
+
console.log((0, ui_js_1.header)(ui_js_1.sym.err, 'Daemon is not responding correctly'));
|
|
42
|
+
console.log('');
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
console.log('');
|
|
48
|
+
console.log((0, ui_js_1.header)(ui_js_1.sym.err, 'Daemon is not running', 'start with `chorus start`'));
|
|
49
|
+
console.log('');
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/cli/commands/status.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,97 @@
|
|
|
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.registerStopCommand = registerStopCommand;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const os_1 = __importDefault(require("os"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const port_utils_js_1 = require("../port-utils.js");
|
|
11
|
+
const ui_js_1 = require("../ui.js");
|
|
12
|
+
/**
|
|
13
|
+
* Two-stage shutdown per managed process: SIGTERM, wait up to 1.5s,
|
|
14
|
+
* escalate to SIGKILL if still alive. Don't unlink the pidfile until
|
|
15
|
+
* the process is confirmed dead — otherwise an orphan that ignores
|
|
16
|
+
* SIGTERM keeps running while we forget about it (the bug behind the
|
|
17
|
+
* "stale next-server serving 500s" incident on 2026-05-03).
|
|
18
|
+
*
|
|
19
|
+
* Belt-and-braces: after pidfile-based shutdown, also sweep ports
|
|
20
|
+
* :7707 (daemon) and :5050 (cockpit). Catches the case where the
|
|
21
|
+
* pidfile was lost or pointed at a recycled PID but a real chorus
|
|
22
|
+
* process still owns the port.
|
|
23
|
+
*/
|
|
24
|
+
function registerStopCommand(program) {
|
|
25
|
+
program
|
|
26
|
+
.command('stop')
|
|
27
|
+
.description('Stop the Chorus daemon and cockpit')
|
|
28
|
+
.action(async () => {
|
|
29
|
+
try {
|
|
30
|
+
const chorusDir = path_1.default.join(os_1.default.homedir(), '.chorus');
|
|
31
|
+
const daemonPidFile = path_1.default.join(chorusDir, 'daemon.pid');
|
|
32
|
+
const webPidFile = path_1.default.join(chorusDir, 'web.pid');
|
|
33
|
+
const daemonPidfileExists = fs_1.default.existsSync(daemonPidFile);
|
|
34
|
+
const webPidfileExists = fs_1.default.existsSync(webPidFile);
|
|
35
|
+
const daemonPortInUse = await (0, port_utils_js_1.isPortInUse)(7707);
|
|
36
|
+
const cockpitPortInUse = await (0, port_utils_js_1.isPortInUse)(5050);
|
|
37
|
+
if (!daemonPidfileExists &&
|
|
38
|
+
!webPidfileExists &&
|
|
39
|
+
!daemonPortInUse &&
|
|
40
|
+
!cockpitPortInUse) {
|
|
41
|
+
console.log('');
|
|
42
|
+
console.log((0, ui_js_1.header)(ui_js_1.sym.info, 'Chorus is not running', 'nothing to stop'));
|
|
43
|
+
console.log('');
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
console.log('');
|
|
47
|
+
console.log((0, ui_js_1.header)(ui_js_1.sym.pointer, 'Stopping Chorus...'));
|
|
48
|
+
console.log('');
|
|
49
|
+
await stopProcess('Daemon', daemonPidFile);
|
|
50
|
+
await stopProcess('Cockpit', webPidFile);
|
|
51
|
+
// Port-based sweep — kills any chorus-owned listener that
|
|
52
|
+
// escaped the pidfile path. Errs on the side of cleanup;
|
|
53
|
+
// running a non-chorus service on these ports while invoking
|
|
54
|
+
// `chorus stop` is unsupported.
|
|
55
|
+
await sweepPort(7707, 'Daemon');
|
|
56
|
+
await sweepPort(5050, 'Cockpit');
|
|
57
|
+
console.log('');
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
console.error(`${ui_js_1.sym.err} ${ui_js_1.c.red('Error stopping chorus:')}`, error);
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
async function stopProcess(label, pidFile) {
|
|
66
|
+
if (!fs_1.default.existsSync(pidFile))
|
|
67
|
+
return;
|
|
68
|
+
const pid = parseInt(fs_1.default.readFileSync(pidFile, 'utf-8'), 10);
|
|
69
|
+
if (!Number.isFinite(pid) || pid <= 0) {
|
|
70
|
+
fs_1.default.unlinkSync(pidFile);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const dead = await (0, port_utils_js_1.killAndVerify)(pid, label);
|
|
74
|
+
if (dead) {
|
|
75
|
+
console.log(` ${ui_js_1.sym.ok} ${label.padEnd(7)} ${ui_js_1.c.dim(`(PID ${pid})`)}`);
|
|
76
|
+
// Only unlink once we've confirmed the process is gone. Earlier
|
|
77
|
+
// code unconditionally unlinked, which orphaned any process that
|
|
78
|
+
// ignored SIGTERM — its successor `chorus start` couldn't see
|
|
79
|
+
// the ghost owner of the port.
|
|
80
|
+
try {
|
|
81
|
+
fs_1.default.unlinkSync(pidFile);
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
/* already gone */
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
async function sweepPort(port, label) {
|
|
89
|
+
const pids = (0, port_utils_js_1.findPidsOnPort)(port);
|
|
90
|
+
for (const pid of pids) {
|
|
91
|
+
const dead = await (0, port_utils_js_1.killAndVerify)(pid, `${label} orphan`);
|
|
92
|
+
if (dead) {
|
|
93
|
+
console.log(` ${ui_js_1.sym.ok} ${label.padEnd(7)} ${ui_js_1.c.dim(`(orphan PID ${pid} on :${port})`)}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=stop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stop.js","sourceRoot":"","sources":["../../../src/cli/commands/stop.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* `chorus connect [orchestrator]` — wire Chorus into a CLI's MCP config so
|
|
4
|
+
* the user can call chorus.* tools from inside it. Removes the per-tool
|
|
5
|
+
* "Yes, allow for this project?" friction (Claude) or registers the MCP
|
|
6
|
+
* server (Codex/Gemini/OpenCode) which they don't have until we add it.
|
|
7
|
+
*
|
|
8
|
+
* Idempotent. Same logic exposed at daemon `POST /orchestrators/:name/connect`
|
|
9
|
+
* so the cockpit's /connect page can run it with one click.
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* chorus connect # all detected CLIs
|
|
13
|
+
* chorus connect claude # just Claude Code
|
|
14
|
+
* chorus connect codex,gemini # comma-separated subset
|
|
15
|
+
*/
|
|
16
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
17
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
18
|
+
};
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.runConnect = runConnect;
|
|
21
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
22
|
+
const index_js_1 = require("../daemon/orchestrators/index.js");
|
|
23
|
+
const CHORUS_BIN_PATH = node_path_1.default.resolve(__dirname, '..', '..', 'bin', 'chorus.mjs');
|
|
24
|
+
const ALL_NAMES = ['claude', 'codex', 'gemini', 'opencode', 'kimi', 'cursor', 'windsurf'];
|
|
25
|
+
function parseTargets(arg) {
|
|
26
|
+
if (!arg)
|
|
27
|
+
return null; // null = "all detected"
|
|
28
|
+
const wanted = arg.split(',').map((s) => s.trim().toLowerCase());
|
|
29
|
+
const valid = [];
|
|
30
|
+
for (const w of wanted) {
|
|
31
|
+
if (ALL_NAMES.includes(w)) {
|
|
32
|
+
valid.push(w);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
console.error(`Unknown orchestrator: '${w}'. Valid: ${ALL_NAMES.join(', ')}`);
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return valid;
|
|
40
|
+
}
|
|
41
|
+
async function runConnect(orchestrator) {
|
|
42
|
+
const only = parseTargets(orchestrator);
|
|
43
|
+
const binPath = CHORUS_BIN_PATH;
|
|
44
|
+
console.log(`Connecting Chorus${only ? ` to: ${only.join(', ')}` : ''}...`);
|
|
45
|
+
console.log('');
|
|
46
|
+
try {
|
|
47
|
+
const result = await (0, index_js_1.autoConnectAll)({
|
|
48
|
+
binPath,
|
|
49
|
+
...(only && only.length > 0 ? { only } : {}),
|
|
50
|
+
});
|
|
51
|
+
const statuses = (0, index_js_1.listOrchestrators)();
|
|
52
|
+
const promptsOnce = [];
|
|
53
|
+
const inheritsGlobal = [];
|
|
54
|
+
for (const step of result.steps) {
|
|
55
|
+
if (!step.detected) {
|
|
56
|
+
console.log(` ✗ ${step.label}: not detected on this machine`);
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (step.error) {
|
|
60
|
+
console.log(` ! ${step.label}: ${step.error}`);
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
const parts = [];
|
|
64
|
+
if (step.registered)
|
|
65
|
+
parts.push('MCP server registered');
|
|
66
|
+
else
|
|
67
|
+
parts.push('MCP already registered');
|
|
68
|
+
if (step.toolsAdded > 0)
|
|
69
|
+
parts.push(`${step.toolsAdded} tool(s) approved`);
|
|
70
|
+
else if (step.name === 'claude')
|
|
71
|
+
parts.push(`all ${index_js_1.CHORUS_TOOLS.length} tools already approved`);
|
|
72
|
+
if (step.slashCommand === 'installed')
|
|
73
|
+
parts.push('/chorus command installed');
|
|
74
|
+
else if (step.slashCommand === 'updated')
|
|
75
|
+
parts.push('/chorus command updated');
|
|
76
|
+
console.log(` ✓ ${step.label}: ${parts.join(' · ')}`);
|
|
77
|
+
const status = statuses.find((s) => s.name === step.name);
|
|
78
|
+
if (status?.firstCallBehavior === 'prompts_once')
|
|
79
|
+
promptsOnce.push(step.label);
|
|
80
|
+
if (status?.firstCallBehavior === 'inherits_global')
|
|
81
|
+
inheritsGlobal.push(step.label);
|
|
82
|
+
}
|
|
83
|
+
if (!result.anyConnected) {
|
|
84
|
+
console.log('');
|
|
85
|
+
console.log('No supported CLIs detected. Install Claude Code, Codex, Gemini, OpenCode, Kimi, Cursor, or Windsurf then retry.');
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
console.log('');
|
|
89
|
+
console.log('Restart any CLI you just connected so it picks up the new MCP server.');
|
|
90
|
+
console.log('Inside the CLI: try `/chorus bug-diagnose <paste a snippet>` (Claude) or');
|
|
91
|
+
console.log('say `chorus, run bug-diagnose on <snippet>` (any other CLI).');
|
|
92
|
+
if (promptsOnce.length > 0) {
|
|
93
|
+
console.log('');
|
|
94
|
+
console.log(`Heads up: ${promptsOnce.join(', ')} will show a one-time permission prompt`);
|
|
95
|
+
console.log('on your first chorus.* tool call. Click "Always allow" to make it stick.');
|
|
96
|
+
}
|
|
97
|
+
if (inheritsGlobal.length > 0) {
|
|
98
|
+
console.log('');
|
|
99
|
+
console.log(`${inheritsGlobal.join(', ')} use a global approval policy — whether tool calls`);
|
|
100
|
+
console.log('prompt depends on your existing config (we don\'t override it).');
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
console.error(`\nFailed: ${err instanceof Error ? err.message : String(err)}`);
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=connect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connect.js","sourceRoot":"","sources":["../../src/cli/connect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,99 @@
|
|
|
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
|
+
const commander_1 = require("commander");
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const open_1 = __importDefault(require("open"));
|
|
9
|
+
const os_1 = __importDefault(require("os"));
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
11
|
+
const doctor_js_1 = require("./commands/doctor.js");
|
|
12
|
+
const init_js_1 = require("./commands/init.js");
|
|
13
|
+
const start_js_1 = require("./commands/start.js");
|
|
14
|
+
const status_js_1 = require("./commands/status.js");
|
|
15
|
+
const stop_js_1 = require("./commands/stop.js");
|
|
16
|
+
const runtime_env_js_1 = require("./runtime-env.js");
|
|
17
|
+
const shared_js_1 = require("./shared.js");
|
|
18
|
+
const ui_js_1 = require("./ui.js");
|
|
19
|
+
const program = new commander_1.Command();
|
|
20
|
+
program
|
|
21
|
+
.name('chorus')
|
|
22
|
+
.description('Driver-agnostic multi-LLM peer review for code decisions')
|
|
23
|
+
.version(shared_js_1.pkg.version);
|
|
24
|
+
// Show a quick-start banner before the standard help so first-time
|
|
25
|
+
// users see the setup sequence even when npm's global install hides
|
|
26
|
+
// postinstall stdout. State-aware: chorus.db is the marker — dir alone
|
|
27
|
+
// is not enough, an empty ~/.chorus can exist from a prior aborted
|
|
28
|
+
// install.
|
|
29
|
+
program.addHelpText('beforeAll', () => {
|
|
30
|
+
const chorusDir = path_1.default.join(os_1.default.homedir(), '.chorus');
|
|
31
|
+
const dbFile = path_1.default.join(chorusDir, 'chorus.db');
|
|
32
|
+
const daemonPid = path_1.default.join(chorusDir, 'daemon.pid');
|
|
33
|
+
const initialised = fs_1.default.existsSync(dbFile);
|
|
34
|
+
const running = fs_1.default.existsSync(daemonPid);
|
|
35
|
+
if (!initialised) {
|
|
36
|
+
return [
|
|
37
|
+
'',
|
|
38
|
+
` ${ui_js_1.sym.rocket} ${ui_js_1.c.bold('Welcome to Chorus')} ${ui_js_1.c.dim('— two commands to get going:')}`,
|
|
39
|
+
'',
|
|
40
|
+
` ${ui_js_1.c.cyan('1.')} ${ui_js_1.c.bold('chorus init')} ${ui_js_1.c.dim('register MCP with your editors + seed templates + detect CLIs')}`,
|
|
41
|
+
` ${ui_js_1.c.cyan('2.')} ${ui_js_1.c.bold('chorus start')} ${ui_js_1.c.dim('bring up the daemon + cockpit at')} ${ui_js_1.c.cyan('http://127.0.0.1:5050')}`,
|
|
42
|
+
'',
|
|
43
|
+
].join('\n');
|
|
44
|
+
}
|
|
45
|
+
if (!running) {
|
|
46
|
+
return [
|
|
47
|
+
'',
|
|
48
|
+
` ${ui_js_1.sym.pointer} ${ui_js_1.c.bold('Daemon is stopped.')} ${ui_js_1.c.dim('Bring it back up:')}`,
|
|
49
|
+
'',
|
|
50
|
+
` ${ui_js_1.c.bold('chorus start')}`,
|
|
51
|
+
'',
|
|
52
|
+
].join('\n');
|
|
53
|
+
}
|
|
54
|
+
return '';
|
|
55
|
+
});
|
|
56
|
+
(0, init_js_1.registerInitCommand)(program);
|
|
57
|
+
(0, start_js_1.registerStartCommand)(program);
|
|
58
|
+
(0, stop_js_1.registerStopCommand)(program);
|
|
59
|
+
(0, status_js_1.registerStatusCommand)(program);
|
|
60
|
+
(0, doctor_js_1.registerDoctorCommand)(program);
|
|
61
|
+
program
|
|
62
|
+
.command('ui')
|
|
63
|
+
.description('Open the Chorus web UI in default browser')
|
|
64
|
+
.action(async () => {
|
|
65
|
+
try {
|
|
66
|
+
const env = (0, runtime_env_js_1.detectRuntimeEnv)();
|
|
67
|
+
(0, shared_js_1.printCockpitAccessHint)();
|
|
68
|
+
if ((0, runtime_env_js_1.shouldAutoOpenBrowser)(env)) {
|
|
69
|
+
await (0, open_1.default)(shared_js_1.COCKPIT_URL);
|
|
70
|
+
console.log(`\nOpening ${shared_js_1.COCKPIT_URL}...`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
console.error('Failed to open browser:', error);
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
program
|
|
79
|
+
.command('connect [orchestrator]')
|
|
80
|
+
.description('Pre-approve all Chorus MCP tools in your orchestrator (default: claude)')
|
|
81
|
+
.action(async (orchestrator) => {
|
|
82
|
+
const { runConnect } = await import('./connect.js');
|
|
83
|
+
runConnect(orchestrator);
|
|
84
|
+
});
|
|
85
|
+
program
|
|
86
|
+
.command('mcp')
|
|
87
|
+
.description('Run the MCP server on stdio (for orchestrators)')
|
|
88
|
+
.action(async () => {
|
|
89
|
+
// Hand off stdio to the MCP server. This call never returns under
|
|
90
|
+
// normal operation — the orchestrator (Claude Code, Codex, Cursor)
|
|
91
|
+
// holds the pipe open and pumps JSON-RPC messages until it shuts
|
|
92
|
+
// the child down.
|
|
93
|
+
await import('../mcp/index.js');
|
|
94
|
+
});
|
|
95
|
+
program.parse(process.argv);
|
|
96
|
+
if (!process.argv.slice(2).length) {
|
|
97
|
+
program.outputHelp();
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,260 @@
|
|
|
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.isPortInUse = isPortInUse;
|
|
7
|
+
exports.findPidsOnPort = findPidsOnPort;
|
|
8
|
+
exports.pidLooksLikeChorus = pidLooksLikeChorus;
|
|
9
|
+
exports.killAndVerify = killAndVerify;
|
|
10
|
+
const child_process_1 = require("child_process");
|
|
11
|
+
const fs_1 = __importDefault(require("fs"));
|
|
12
|
+
const net_1 = __importDefault(require("net"));
|
|
13
|
+
const ui_js_1 = require("./ui.js");
|
|
14
|
+
/**
|
|
15
|
+
* Probe whether anything is listening on a TCP port on 127.0.0.1.
|
|
16
|
+
*
|
|
17
|
+
* Used by the start-path orphan reaper: if a previous next-server from
|
|
18
|
+
* an earlier `chorus start` survived a `chorus stop` (because the
|
|
19
|
+
* pidfile was lost or the SIGTERM was ignored), the next start would
|
|
20
|
+
* silently race against it on :5050 and leave the user stuck on stale
|
|
21
|
+
* chunks after a rebuild.
|
|
22
|
+
*/
|
|
23
|
+
function isPortInUse(port, host = '127.0.0.1', timeoutMs = 500) {
|
|
24
|
+
return new Promise((resolve) => {
|
|
25
|
+
const sock = new net_1.default.Socket();
|
|
26
|
+
let settled = false;
|
|
27
|
+
const finish = (inUse) => {
|
|
28
|
+
if (settled)
|
|
29
|
+
return;
|
|
30
|
+
settled = true;
|
|
31
|
+
try {
|
|
32
|
+
sock.destroy();
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
/* ignore */
|
|
36
|
+
}
|
|
37
|
+
resolve(inUse);
|
|
38
|
+
};
|
|
39
|
+
sock.setTimeout(timeoutMs);
|
|
40
|
+
sock.once('connect', () => finish(true));
|
|
41
|
+
sock.once('timeout', () => finish(false));
|
|
42
|
+
sock.once('error', () => finish(false));
|
|
43
|
+
sock.connect(port, host);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Find any process holding a TCP listener on `port` on 127.0.0.1.
|
|
48
|
+
* Returns the PIDs found via `ss`/`lsof`. Best-effort — returns [] on
|
|
49
|
+
* platforms where neither tool is available.
|
|
50
|
+
*
|
|
51
|
+
* Why: pidfile-based tracking is fragile (file deleted on a partial
|
|
52
|
+
* stop, PID reused by an unrelated process). Port-based reaping is the
|
|
53
|
+
* source of truth — if something's bound to :5050, we want it gone
|
|
54
|
+
* before we spawn our own.
|
|
55
|
+
*/
|
|
56
|
+
function findPidsOnPort(port) {
|
|
57
|
+
const candidates = [
|
|
58
|
+
{
|
|
59
|
+
cmd: `ss -ltnp 'sport = :${port}' 2>/dev/null`,
|
|
60
|
+
parse: (out) => {
|
|
61
|
+
const pids = [];
|
|
62
|
+
for (const m of out.matchAll(/pid=(\d+)/g)) {
|
|
63
|
+
const pid = parseInt(m[1], 10);
|
|
64
|
+
if (Number.isFinite(pid) && pid > 0)
|
|
65
|
+
pids.push(pid);
|
|
66
|
+
}
|
|
67
|
+
return pids;
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
cmd: `lsof -nP -iTCP:${port} -sTCP:LISTEN -t 2>/dev/null`,
|
|
72
|
+
parse: (out) => out
|
|
73
|
+
.split(/\s+/)
|
|
74
|
+
.map((s) => parseInt(s, 10))
|
|
75
|
+
.filter((n) => Number.isFinite(n) && n > 0),
|
|
76
|
+
},
|
|
77
|
+
];
|
|
78
|
+
for (const { cmd, parse } of candidates) {
|
|
79
|
+
try {
|
|
80
|
+
const out = (0, child_process_1.execSync)(cmd, {
|
|
81
|
+
encoding: 'utf-8',
|
|
82
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
83
|
+
});
|
|
84
|
+
const pids = parse(out);
|
|
85
|
+
if (pids.length > 0)
|
|
86
|
+
return Array.from(new Set(pids));
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
/* tool not present or no match — try next */
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return [];
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Read the process's command line so we can decide whether it looks
|
|
96
|
+
* like a chorus orphan (safe to reap) vs a foreign process the user
|
|
97
|
+
* owns (refuse to kill — Grafana/another dev server happens to be on
|
|
98
|
+
* 5050 or 7707). Linux exposes /proc/<pid>/cmdline; macOS doesn't, so
|
|
99
|
+
* we fall back to `ps -p <pid> -o command=`.
|
|
100
|
+
*/
|
|
101
|
+
function readCmdline(pid) {
|
|
102
|
+
try {
|
|
103
|
+
const procPath = `/proc/${pid}/cmdline`;
|
|
104
|
+
if (fs_1.default.existsSync(procPath)) {
|
|
105
|
+
// /proc/<pid>/cmdline is NUL-separated argv. Replace with spaces
|
|
106
|
+
// so we can substring-match against the joined invocation.
|
|
107
|
+
return fs_1.default.readFileSync(procPath, 'utf-8').replace(/ /g, ' ').trim();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
/* race with process exit, fall through to ps */
|
|
112
|
+
}
|
|
113
|
+
try {
|
|
114
|
+
// execFileSync over execSync so a future loosening of `pid`'s
|
|
115
|
+
// numeric type can't slip into a shell command-injection. argv
|
|
116
|
+
// goes straight to ps without an intermediate sh -c.
|
|
117
|
+
const out = (0, child_process_1.execFileSync)('ps', ['-p', String(pid), '-o', 'command='], {
|
|
118
|
+
encoding: 'utf-8',
|
|
119
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
120
|
+
});
|
|
121
|
+
const trimmed = out.trim();
|
|
122
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Path-segment match for the chorus / chorus-codes directory names.
|
|
130
|
+
* Splitting on `/` so we accept `/dev/chorus/...` but not
|
|
131
|
+
* `/dev/chorus-experiments/...`. Used by the next-launcher fallback
|
|
132
|
+
* for both cmdline and cwd checks.
|
|
133
|
+
*/
|
|
134
|
+
function pathHasChorusSegment(somePath) {
|
|
135
|
+
const segs = somePath.split('/');
|
|
136
|
+
return segs.includes('chorus') || segs.includes('chorus-codes');
|
|
137
|
+
}
|
|
138
|
+
function cmdlineHasChorusSegment(cmdline) {
|
|
139
|
+
for (const tok of cmdline.split(/\s+/)) {
|
|
140
|
+
if (pathHasChorusSegment(tok))
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Does this process look like a chorus daemon or cockpit?
|
|
147
|
+
*
|
|
148
|
+
* The reap loop in `chorus start` kills whatever's bound to 5050/7707
|
|
149
|
+
* before respawning. Pre-fix, that loop would happily SIGKILL
|
|
150
|
+
* `grafana-server` or another user's `next dev` if either happened to
|
|
151
|
+
* be on the same port — silently murdering work and surprising the user.
|
|
152
|
+
*
|
|
153
|
+
* Accept anything whose argv mentions one of these markers, all of
|
|
154
|
+
* which are uniquely chorus-shaped:
|
|
155
|
+
* - `chorus/dist/daemon/index.js` — compiled daemon entrypoint
|
|
156
|
+
* - `src/daemon/index.ts` — dev (tsx) entrypoint
|
|
157
|
+
* - `chorus/bin/chorus.mjs` — CLI wrapper
|
|
158
|
+
* - `next-server` / `next start` running in a path that contains chorus
|
|
159
|
+
*
|
|
160
|
+
* Anything else returns false; the caller should refuse to reap and
|
|
161
|
+
* surface a clear "port is taken by <cmd>" error.
|
|
162
|
+
*/
|
|
163
|
+
function pidLooksLikeChorus(pid) {
|
|
164
|
+
const cmdline = readCmdline(pid);
|
|
165
|
+
if (!cmdline) {
|
|
166
|
+
// Couldn't read cmdline (race / permission). Fail-closed: treat as
|
|
167
|
+
// foreign, force the user to investigate.
|
|
168
|
+
return { match: false, cmdline: null };
|
|
169
|
+
}
|
|
170
|
+
// Path markers covering both dev (repo) and installed (node_modules)
|
|
171
|
+
// layouts. The unscoped npm name `chorus-codes` lands the package at
|
|
172
|
+
// node_modules/chorus-codes/* on global installs.
|
|
173
|
+
//
|
|
174
|
+
// Each marker is prefixed with `/` so substring search anchors on a
|
|
175
|
+
// path-segment boundary. Without the leading slash,
|
|
176
|
+
// `cmdline.includes('chorus/dist/...')` would match
|
|
177
|
+
// `/x/notchorus/dist/...` or `/x/mychorus-fork/dist/...`.
|
|
178
|
+
const markers = [
|
|
179
|
+
'/chorus/dist/daemon/index.js',
|
|
180
|
+
'/chorus/src/daemon/index.ts',
|
|
181
|
+
'/chorus/bin/chorus.mjs',
|
|
182
|
+
'/chorus/dist/cli/index.js',
|
|
183
|
+
'/chorus-codes/dist/daemon/index.js',
|
|
184
|
+
'/chorus-codes/src/daemon/index.ts',
|
|
185
|
+
'/chorus-codes/bin/chorus.mjs',
|
|
186
|
+
'/chorus-codes/dist/cli/index.js',
|
|
187
|
+
];
|
|
188
|
+
if (markers.some((m) => cmdline.includes(m)))
|
|
189
|
+
return { match: true, cmdline };
|
|
190
|
+
// next-server is the cockpit. The launcher may show up as either the
|
|
191
|
+
// literal `next-server (vXX.YY.ZZ)` worker title (Next overwrites
|
|
192
|
+
// process.title once running, wiping the original argv — chorus
|
|
193
|
+
// disappears from cmdline at that point) OR as the original `node
|
|
194
|
+
// node_modules/next/dist/bin/next start` argv. To stay safe in both
|
|
195
|
+
// states, accept either form when the cmdline carries a chorus path
|
|
196
|
+
// segment OR the process's cwd has one — chorus start always spawns
|
|
197
|
+
// Next with cwd: packageRoot. Path-segment matching (split + includes)
|
|
198
|
+
// so /home/user/chorus-experiments/marketing-site doesn't mistakenly
|
|
199
|
+
// match.
|
|
200
|
+
const nextLauncher = cmdline.includes('next-server') ||
|
|
201
|
+
/node_modules\/next\/dist\/bin\/next (start|dev)/.test(cmdline);
|
|
202
|
+
if (nextLauncher) {
|
|
203
|
+
if (cmdlineHasChorusSegment(cmdline))
|
|
204
|
+
return { match: true, cmdline };
|
|
205
|
+
let cwd = null;
|
|
206
|
+
try {
|
|
207
|
+
cwd = fs_1.default.readlinkSync(`/proc/${pid}/cwd`);
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
/* not Linux or process gone — fall through */
|
|
211
|
+
}
|
|
212
|
+
if (cwd && pathHasChorusSegment(cwd))
|
|
213
|
+
return { match: true, cmdline };
|
|
214
|
+
}
|
|
215
|
+
return { match: false, cmdline };
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Send SIGTERM to a PID and wait up to `gracefulMs` for it to die. If
|
|
219
|
+
* still alive, escalate to SIGKILL. Returns true if the process is
|
|
220
|
+
* gone by the time we return (or never existed in the first place),
|
|
221
|
+
* false if SIGKILL also failed.
|
|
222
|
+
*/
|
|
223
|
+
async function killAndVerify(pid, label, gracefulMs = 1500) {
|
|
224
|
+
const isAlive = () => {
|
|
225
|
+
try {
|
|
226
|
+
process.kill(pid, 0);
|
|
227
|
+
return true;
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
return false;
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
if (!isAlive())
|
|
234
|
+
return true;
|
|
235
|
+
try {
|
|
236
|
+
process.kill(pid, 'SIGTERM');
|
|
237
|
+
}
|
|
238
|
+
catch {
|
|
239
|
+
/* gone already */
|
|
240
|
+
}
|
|
241
|
+
const deadline = Date.now() + gracefulMs;
|
|
242
|
+
while (Date.now() < deadline) {
|
|
243
|
+
if (!isAlive())
|
|
244
|
+
return true;
|
|
245
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
246
|
+
}
|
|
247
|
+
// Stubborn — escalate.
|
|
248
|
+
try {
|
|
249
|
+
process.kill(pid, 'SIGKILL');
|
|
250
|
+
}
|
|
251
|
+
catch {
|
|
252
|
+
/* may already be dead */
|
|
253
|
+
}
|
|
254
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
255
|
+
if (!isAlive())
|
|
256
|
+
return true;
|
|
257
|
+
console.warn(` ${ui_js_1.sym.err} ${label} PID ${pid} survived SIGKILL — manual cleanup needed`);
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
//# sourceMappingURL=port-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"port-utils.js","sourceRoot":"","sources":["../../src/cli/port-utils.ts"],"names":[],"mappings":"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"}
|