@chorus-aidlc/chorus 0.14.3 → 0.14.4
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/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/app-build-manifest.json +161 -161
- package/.next/standalone/.next/app-path-routes-manifest.json +34 -34
- package/.next/standalone/.next/build-manifest.json +2 -2
- package/.next/standalone/.next/prerender-manifest.json +42 -42
- package/.next/standalone/.next/server/app/(dashboard)/project-groups/[uuid]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/activity/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/dashboard/[ideaUuid]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/dashboard/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/documents/[documentUuid]/page.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/documents/[documentUuid]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/documents/page.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/documents/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/graph/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/proposals/[proposalUuid]/page.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/proposals/[proposalUuid]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/proposals/new/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/proposals/page.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/proposals/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/tasks/[taskUuid]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/tasks/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/projects/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/settings/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +2 -2
- package/.next/standalone/.next/server/app/_not-found.rsc +1 -1
- package/.next/standalone/.next/server/app/admin/companies/[uuid]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/admin/companies/new/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/admin/companies/new.html +2 -2
- package/.next/standalone/.next/server/app/admin/companies/new.rsc +1 -1
- package/.next/standalone/.next/server/app/admin/companies/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/admin/companies.html +2 -2
- package/.next/standalone/.next/server/app/admin/companies.rsc +1 -1
- package/.next/standalone/.next/server/app/admin/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/admin.html +2 -2
- package/.next/standalone/.next/server/app/admin.rsc +1 -1
- package/.next/standalone/.next/server/app/api/admin/companies/[uuid]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/admin/companies/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/admin/login/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/admin/session/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/agent-connections/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/agents/[uuid]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/agents/[uuid]/sessions/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/agents/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/api-keys/[uuid]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/api-keys/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/auth/callback/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/auth/check-default/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/auth/company-oidc/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/auth/default-login/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/auth/identify/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/auth/me/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/auth/sync-token/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/comments/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon/connection-heartbeat/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon/control/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon/execution-state/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon/executions/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon/pending-turns/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon/report-interrupt/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon/resume/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon/transcript/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon/turn-advance/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon-sessions/[sessionUuid]/instruction/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon-sessions/[sessionUuid]/repoint/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon-sessions/[sessionUuid]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon-sessions/ad-hoc/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon-sessions/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/documents/[uuid]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/entities/[type]/[uuid]/root-idea/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/events/notifications/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/events/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/health/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/ideas/[uuid]/claim/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/ideas/[uuid]/move/preview/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/ideas/[uuid]/move/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/ideas/[uuid]/parent/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/ideas/[uuid]/release/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/ideas/[uuid]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/ideas/[uuid]/wake-preview/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/ideas/conversational/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/mcp/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/me/assignments/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/mentionables/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/notifications/[uuid]/archive/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/notifications/[uuid]/read/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/notifications/preferences/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/notifications/read-all/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/notifications/unread-count/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/project-groups/[uuid]/dashboard/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/project-groups/[uuid]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/project-groups/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/project-visits/pin/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/project-visits/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/project-visits/visit/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[uuid]/activity/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[uuid]/available/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[uuid]/documents/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[uuid]/group/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[uuid]/ideas/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[uuid]/ideas/tracker/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[uuid]/proposals/[proposalUuid]/validate/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[uuid]/proposals/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[uuid]/proposals/summary/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[uuid]/resource-graph/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[uuid]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[uuid]/stats/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[uuid]/tasks/dependencies/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[uuid]/tasks/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/proposals/[uuid]/approve/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/proposals/[uuid]/close/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/proposals/[uuid]/reject/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/proposals/[uuid]/revoke/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/proposals/[uuid]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/references/[uuid]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/references/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/search/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/session/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/sessions/[uuid]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/tasks/[uuid]/claim/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/tasks/[uuid]/dependencies/[dependsOnUuid]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/tasks/[uuid]/dependencies/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/tasks/[uuid]/release/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/tasks/[uuid]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/tasks/[uuid]/sessions/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/index.html +2 -2
- package/.next/standalone/.next/server/app/index.rsc +1 -1
- package/.next/standalone/.next/server/app/login/admin/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/login/admin.html +2 -2
- package/.next/standalone/.next/server/app/login/admin.rsc +1 -1
- package/.next/standalone/.next/server/app/login/callback/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/login/callback.html +2 -2
- package/.next/standalone/.next/server/app/login/callback.rsc +1 -1
- package/.next/standalone/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/login/pick-workspace/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/login/pick-workspace.html +2 -2
- package/.next/standalone/.next/server/app/login/pick-workspace.rsc +1 -1
- package/.next/standalone/.next/server/app/login.html +2 -2
- package/.next/standalone/.next/server/app/login.rsc +1 -1
- package/.next/standalone/.next/server/app/onboarding/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/onboarding.html +2 -2
- package/.next/standalone/.next/server/app/onboarding.rsc +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/projects.html +2 -2
- package/.next/standalone/.next/server/app/projects.rsc +1 -1
- package/.next/standalone/.next/server/app/settings.html +2 -2
- package/.next/standalone/.next/server/app/settings.rsc +1 -1
- package/.next/standalone/.next/server/app-paths-manifest.json +34 -34
- package/.next/standalone/.next/server/chunks/6515.js +2 -2
- package/.next/standalone/.next/server/chunks/8454.js +1 -1
- package/.next/standalone/.next/server/middleware-manifest.json +1 -1
- package/.next/standalone/.next/server/pages/404.html +2 -2
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
- package/.next/standalone/package.json +1 -1
- package/README.md +2 -0
- package/cli/client-args.mjs +15 -8
- package/cli/daemon-agent.mjs +56 -6
- package/cli/daemon-install-config.mjs +129 -0
- package/cli/daemon.mjs +23 -1
- package/package.json +1 -1
- /package/.next/standalone/.next/static/{3R5zOQKwCZOVs9-BjIVqk → WVmgQzimrMNvGtHx6Cqm1}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{3R5zOQKwCZOVs9-BjIVqk → WVmgQzimrMNvGtHx6Cqm1}/_ssgManifest.js +0 -0
package/cli/daemon-agent.mjs
CHANGED
|
@@ -3,7 +3,18 @@
|
|
|
3
3
|
// `claude-code` (the default), `codex`, and `kiro` are all implemented backends
|
|
4
4
|
// (add-daemon-codex-backend cashed in the reserved `codex` slot;
|
|
5
5
|
// add-daemon-kiro-backend adds `kiro`). Resolving an unknown value is a hard
|
|
6
|
-
// error (no silent fallback).
|
|
6
|
+
// error (no silent fallback).
|
|
7
|
+
//
|
|
8
|
+
// Resolution is layered like resolveSigintTimeoutMs / resolveDaemonCwds in
|
|
9
|
+
// daemon-config.mjs — first defined source wins:
|
|
10
|
+
// --agent flag > CHORUS_AGENT env > ~/.chorus/daemon.json `agent` > claude-code.
|
|
11
|
+
// The config-file layer lets an operator persist a default backend (e.g.
|
|
12
|
+
// `"agent": "codex"`) once instead of re-passing --agent / re-exporting the env
|
|
13
|
+
// on every start. IO (file read) is injectable so this stays unit-testable
|
|
14
|
+
// without real disk.
|
|
15
|
+
|
|
16
|
+
import { readFileSync } from "node:fs";
|
|
17
|
+
import { loginFilePath } from "./credentials.mjs";
|
|
7
18
|
|
|
8
19
|
/** The agent backends the daemon recognizes. All are implemented (claude-code
|
|
9
20
|
* via ClaudeSpawner, codex via CodexSpawner, kiro via KiroSpawner — see
|
|
@@ -42,19 +53,58 @@ export function backendClientType(agentType) {
|
|
|
42
53
|
}
|
|
43
54
|
|
|
44
55
|
/**
|
|
45
|
-
*
|
|
46
|
-
*
|
|
56
|
+
* Read a JSON file, returning `null` on any error (missing / unreadable /
|
|
57
|
+
* malformed). Never throws — mirrors daemon-config.mjs readJsonSafe.
|
|
58
|
+
* @param {string} path
|
|
59
|
+
* @returns {Record<string, unknown> | null}
|
|
60
|
+
*/
|
|
61
|
+
function readJsonSafe(path) {
|
|
62
|
+
try {
|
|
63
|
+
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
64
|
+
return parsed && typeof parsed === "object" ? parsed : null;
|
|
65
|
+
} catch {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** A non-empty trimmed string, or undefined. */
|
|
71
|
+
function nonEmpty(value) {
|
|
72
|
+
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Resolve the agent type from flag → env → config file → default, and validate it.
|
|
77
|
+
* Precedence (first defined source wins, mirroring resolveSigintTimeoutMs /
|
|
78
|
+
* resolveDaemonCwds): explicit `--agent` flag > CHORUS_AGENT env >
|
|
79
|
+
* ~/.chorus/daemon.json `agent` > DEFAULT_AGENT.
|
|
80
|
+
*
|
|
81
|
+
* An unknown value from ANY source (flag, env, or file) is a hard error — no
|
|
82
|
+
* silent fallback. The config file lets an operator persist a default backend
|
|
83
|
+
* without re-passing --agent on every start.
|
|
47
84
|
*
|
|
48
85
|
* @param {{ agent?: string }} flags
|
|
49
86
|
* @param {Record<string, string|undefined>} env
|
|
87
|
+
* @param {{
|
|
88
|
+
* readJson?: (path: string) => (Record<string, unknown>|null),
|
|
89
|
+
* loginPath?: string,
|
|
90
|
+
* }} [deps]
|
|
50
91
|
* @returns {{ ok: true, agent: string } | { ok: false, value: string, error: string }}
|
|
51
92
|
* `ok:false` carries the offending value and a human-actionable error naming
|
|
52
93
|
* the accepted types — the caller exits non-zero and prints `error`.
|
|
53
94
|
*/
|
|
54
|
-
export function resolveAgentType(flags, env) {
|
|
95
|
+
export function resolveAgentType(flags, env, deps = {}) {
|
|
96
|
+
const readJson = deps.readJson ?? readJsonSafe;
|
|
97
|
+
const loginPath = deps.loginPath ?? loginFilePath();
|
|
98
|
+
|
|
99
|
+
const fromFile = () => {
|
|
100
|
+
const file = readJson(loginPath);
|
|
101
|
+
return file ? nonEmpty(file.agent) : undefined;
|
|
102
|
+
};
|
|
103
|
+
|
|
55
104
|
const raw =
|
|
56
|
-
(
|
|
57
|
-
(
|
|
105
|
+
nonEmpty(flags.agent) ||
|
|
106
|
+
nonEmpty(env.CHORUS_AGENT) ||
|
|
107
|
+
fromFile() ||
|
|
58
108
|
DEFAULT_AGENT;
|
|
59
109
|
if (!KNOWN_AGENTS.includes(raw)) {
|
|
60
110
|
return {
|
|
@@ -26,6 +26,11 @@ import { resolveCredentials, loginFilePath } from "./credentials.mjs";
|
|
|
26
26
|
import { updateDaemonConfig, prompt as defaultPrompt } from "./login.mjs";
|
|
27
27
|
import { validateAndFetchIdentity } from "./chorus-client.mjs";
|
|
28
28
|
import { normalizeCwd, cleanCwdList } from "./daemon-config.mjs";
|
|
29
|
+
import { KNOWN_AGENTS, DEFAULT_AGENT } from "./daemon-agent.mjs";
|
|
30
|
+
import { agentNotFoundWarningLine } from "./daemon-banner.mjs";
|
|
31
|
+
import { resolveClaudePath } from "./claude-spawner.mjs";
|
|
32
|
+
import { resolveCodexPath } from "./codex-spawner.mjs";
|
|
33
|
+
import { resolveKiroPath } from "./kiro-spawner.mjs";
|
|
29
34
|
import { readFileSync } from "node:fs";
|
|
30
35
|
|
|
31
36
|
/** A non-empty trimmed string, or undefined. */
|
|
@@ -211,3 +216,127 @@ export async function resolveInstallCwds(flags = {}, opts = {}) {
|
|
|
211
216
|
if (finalCwds.length > 0) writeConfig({ cwds: finalCwds });
|
|
212
217
|
return { cwds: finalCwds };
|
|
213
218
|
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* The interactive agent-backend menu. Order mirrors KNOWN_AGENTS with claude-code
|
|
222
|
+
* first (it is the default). Kept beside the resolver so the numbered prompt and
|
|
223
|
+
* the accepted values never drift.
|
|
224
|
+
*/
|
|
225
|
+
const AGENT_MENU = [
|
|
226
|
+
{ value: "claude-code", label: "Claude Code (default)" },
|
|
227
|
+
{ value: "codex", label: "Codex CLI" },
|
|
228
|
+
{ value: "kiro", label: "Kiro CLI" },
|
|
229
|
+
];
|
|
230
|
+
|
|
231
|
+
/** Probe the selected backend's CLI on PATH. Returns the resolved path or null.
|
|
232
|
+
* Injectable per backend so the check is testable without a real PATH. */
|
|
233
|
+
function probeAgentCli(agent, probes = {}) {
|
|
234
|
+
const findClaude = probes.resolveClaudePath ?? resolveClaudePath;
|
|
235
|
+
const findCodex = probes.resolveCodexPath ?? resolveCodexPath;
|
|
236
|
+
const findKiro = probes.resolveKiroPath ?? resolveKiroPath;
|
|
237
|
+
if (agent === "codex") return findCodex();
|
|
238
|
+
if (agent === "kiro") return findKiro();
|
|
239
|
+
return findClaude();
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Determine which local agent backend the installed daemon wakes and persist it
|
|
244
|
+
* to ~/.chorus/daemon.json `agent` (the single source of truth — the unit carries
|
|
245
|
+
* no --agent, exactly like `cwds`). AFTER resolving, probe the selected backend's
|
|
246
|
+
* CLI on PATH and warn (non-fatal) when it is missing, so the operator learns at
|
|
247
|
+
* install time rather than when the first wake fails.
|
|
248
|
+
*
|
|
249
|
+
* Resolution (first defined source wins):
|
|
250
|
+
* 1. --agent flag — the operator's explicit choice.
|
|
251
|
+
* 2. CHORUS_AGENT env — matches the daemon's own resolution precedence.
|
|
252
|
+
* 3. existing daemon.json `agent` — a prior valid choice is kept (re-install is
|
|
253
|
+
* idempotent and does not re-prompt); an invalid stored value is ignored.
|
|
254
|
+
* 4. TTY + !skip — interactive numbered menu (Enter = claude-code default).
|
|
255
|
+
* 5. non-TTY / skip — DEFAULT_AGENT (claude-code), persisted so the config
|
|
256
|
+
* is explicit about the backend the boot service runs.
|
|
257
|
+
*
|
|
258
|
+
* Never fails: --agent / CHORUS_AGENT are already validated upstream by
|
|
259
|
+
* resolveAgentType (runDaemon rejects an unknown value before dispatch), the menu
|
|
260
|
+
* is constrained to KNOWN_AGENTS, and default/stored-invalid fall back to
|
|
261
|
+
* claude-code. Returns the resolved `{ agent, cliPath, cliFound }`. Never throws.
|
|
262
|
+
*
|
|
263
|
+
* @param {{ agent?: string }} flags
|
|
264
|
+
* @param {Record<string, string|undefined>} [env]
|
|
265
|
+
* @param {{
|
|
266
|
+
* isTTY?: boolean, skip?: boolean,
|
|
267
|
+
* readJson?: (path: string) => (Record<string, unknown>|null),
|
|
268
|
+
* loginPath?: string,
|
|
269
|
+
* writeConfig?: (partial: Record<string, unknown>) => string,
|
|
270
|
+
* prompt?: typeof defaultPrompt,
|
|
271
|
+
* probes?: { resolveClaudePath?: Function, resolveCodexPath?: Function, resolveKiroPath?: Function },
|
|
272
|
+
* log?: (m: string) => void,
|
|
273
|
+
* errLog?: (m: string) => void,
|
|
274
|
+
* }} [opts]
|
|
275
|
+
* @returns {Promise<{ agent: string, cliPath: string|null, cliFound: boolean }>}
|
|
276
|
+
*/
|
|
277
|
+
export async function resolveInstallAgent(flags = {}, env = {}, opts = {}) {
|
|
278
|
+
const isTTY = opts.isTTY ?? false;
|
|
279
|
+
const skip = opts.skip ?? false;
|
|
280
|
+
const readJson = opts.readJson ?? readJsonSafe;
|
|
281
|
+
const loginPath = opts.loginPath ?? loginFilePath();
|
|
282
|
+
const writeConfig = opts.writeConfig ?? updateDaemonConfig;
|
|
283
|
+
const ask = opts.prompt ?? defaultPrompt;
|
|
284
|
+
const log = opts.log ?? (() => {});
|
|
285
|
+
const errLog = opts.errLog ?? (() => {});
|
|
286
|
+
|
|
287
|
+
// Only a KNOWN backend is ever accepted; anything else is treated as absent.
|
|
288
|
+
const known = (v) => (v && KNOWN_AGENTS.includes(v) ? v : undefined);
|
|
289
|
+
|
|
290
|
+
let agent;
|
|
291
|
+
let persist = true; // write unless we reuse an already-stored value (no-op)
|
|
292
|
+
|
|
293
|
+
// 1/2. Explicit --agent flag or CHORUS_AGENT env (both pre-validated upstream).
|
|
294
|
+
agent = known(nonEmpty(flags.agent)) ?? known(nonEmpty(env.CHORUS_AGENT));
|
|
295
|
+
|
|
296
|
+
// 3. Existing daemon.json `agent` — a prior valid choice is authoritative; keep
|
|
297
|
+
// it and do not re-prompt (re-install stays idempotent). Skip the re-write.
|
|
298
|
+
if (!agent) {
|
|
299
|
+
const file = readJson(loginPath);
|
|
300
|
+
const stored = known(file ? nonEmpty(file.agent) : undefined);
|
|
301
|
+
if (stored) {
|
|
302
|
+
agent = stored;
|
|
303
|
+
persist = false; // already on disk — no-op write avoided
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// 4. Interactive numbered menu on a TTY (Enter accepts the claude-code default).
|
|
308
|
+
if (!agent && isTTY && !skip) {
|
|
309
|
+
log("[Chorus] Which local agent backend should this daemon wake?");
|
|
310
|
+
for (let i = 0; i < AGENT_MENU.length; i += 1) {
|
|
311
|
+
log(`[Chorus] ${i + 1}) ${AGENT_MENU[i].label}`);
|
|
312
|
+
}
|
|
313
|
+
const answer = nonEmpty(await ask(`Select [1-${AGENT_MENU.length}] (Enter for 1): `));
|
|
314
|
+
if (!answer) {
|
|
315
|
+
agent = DEFAULT_AGENT;
|
|
316
|
+
} else {
|
|
317
|
+
const n = Number(answer);
|
|
318
|
+
const byNumber = Number.isInteger(n) && n >= 1 && n <= AGENT_MENU.length ? AGENT_MENU[n - 1].value : undefined;
|
|
319
|
+
// Also accept the value typed by name (e.g. "codex") for muscle memory.
|
|
320
|
+
agent = byNumber ?? known(answer) ?? DEFAULT_AGENT;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// 5. Non-TTY / skip with nothing configured → the default, persisted so the boot
|
|
325
|
+
// service config is explicit about the backend it runs.
|
|
326
|
+
if (!agent) agent = DEFAULT_AGENT;
|
|
327
|
+
|
|
328
|
+
if (persist) writeConfig({ agent });
|
|
329
|
+
|
|
330
|
+
// Probe the selected backend's CLI (non-fatal). A missing binary warns loudly so
|
|
331
|
+
// the operator fixes PATH before the first wake, but never blocks the install.
|
|
332
|
+
const cliPath = probeAgentCli(agent, opts.probes);
|
|
333
|
+
const cliFound = cliPath !== null;
|
|
334
|
+
if (cliFound) {
|
|
335
|
+
log(`[Chorus] agent backend: ${agent} (found CLI at ${cliPath}).`);
|
|
336
|
+
} else {
|
|
337
|
+
log(`[Chorus] agent backend: ${agent}.`);
|
|
338
|
+
errLog(`[Chorus] ${agentNotFoundWarningLine(agent)}`);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
return { agent, cliPath, cliFound };
|
|
342
|
+
}
|
package/cli/daemon.mjs
CHANGED
|
@@ -17,6 +17,7 @@ import { prompt, writeLoginFile, updateDaemonConfig } from "./login.mjs";
|
|
|
17
17
|
import {
|
|
18
18
|
resolveInstallCredentials,
|
|
19
19
|
resolveInstallCwds,
|
|
20
|
+
resolveInstallAgent,
|
|
20
21
|
} from "./daemon-install-config.mjs";
|
|
21
22
|
import {
|
|
22
23
|
resolvePermissionMode,
|
|
@@ -777,6 +778,7 @@ export async function handleLifecycleAction(action, { log, errLog, lifecycle, se
|
|
|
777
778
|
const installCfg = svc.installConfig ?? {
|
|
778
779
|
resolveInstallCredentials,
|
|
779
780
|
resolveInstallCwds,
|
|
781
|
+
resolveInstallAgent,
|
|
780
782
|
};
|
|
781
783
|
|
|
782
784
|
const credResult = await installCfg.resolveInstallCredentials(flags, env, {
|
|
@@ -810,10 +812,30 @@ export async function handleLifecycleAction(action, { log, errLog, lifecycle, se
|
|
|
810
812
|
log,
|
|
811
813
|
});
|
|
812
814
|
|
|
815
|
+
// Configure + persist the agent backend to daemon.json `agent` (single source
|
|
816
|
+
// of truth; the unit carries no --agent, exactly like --cwd). Prompts an
|
|
817
|
+
// interactive menu on a TTY (Enter = claude-code); reuses a --agent flag /
|
|
818
|
+
// CHORUS_AGENT env / a prior stored choice; probes the selected CLI and warns
|
|
819
|
+
// (non-fatal) when it is missing. An unknown --agent was already rejected by
|
|
820
|
+
// resolveAgentType above, so this phase never fails.
|
|
821
|
+
await installCfg.resolveInstallAgent(flags, env, {
|
|
822
|
+
isTTY,
|
|
823
|
+
skip,
|
|
824
|
+
writeConfig: pfDeps?.writeConfig ?? updateDaemonConfig,
|
|
825
|
+
readJson: pfDeps?.readJson,
|
|
826
|
+
loginPath: pfDeps?.loginPath,
|
|
827
|
+
prompt: pfDeps?.askPrompt,
|
|
828
|
+
log,
|
|
829
|
+
errLog,
|
|
830
|
+
});
|
|
831
|
+
|
|
813
832
|
const spec = {
|
|
814
833
|
...svc.resolveServicePaths(),
|
|
815
834
|
cwds: flags.cwd ?? [],
|
|
816
|
-
|
|
835
|
+
// NOTE: agent is deliberately NOT passed into the unit. The selected backend
|
|
836
|
+
// is persisted to daemon.json `agent` (single source of truth) and read back
|
|
837
|
+
// by the daemon via resolveAgentType — mirroring how --cwd is handled. Baking
|
|
838
|
+
// --agent into ExecStart too would let the two sources drift.
|
|
817
839
|
chorusOnly: flags.chorusOnly === true,
|
|
818
840
|
workingDir: process.cwd(),
|
|
819
841
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chorus-aidlc/chorus",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.4",
|
|
4
4
|
"description": "The Agent Harness for AI-Human Collaboration — session lifecycle, task state, sub-agent orchestration, observability, and failure recovery",
|
|
5
5
|
"homepage": "https://github.com/Chorus-AIDLC/Chorus",
|
|
6
6
|
"repository": {
|
|
File without changes
|
|
File without changes
|