@chorus-aidlc/chorus 0.15.0 → 0.16.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/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/app-build-manifest.json +411 -411
- package/.next/standalone/.next/app-path-routes-manifest.json +49 -49
- package/.next/standalone/.next/build-manifest.json +5 -5
- package/.next/standalone/.next/prerender-manifest.json +42 -42
- package/.next/standalone/.next/server/app/(dashboard)/project-groups/[uuid]/page.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/project-groups/[uuid]/page.js.nft.json +1 -1
- 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.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.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.js +2 -2
- package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/dashboard/page.js.nft.json +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 +2 -2
- 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 +2 -2
- 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.js +2 -2
- package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/graph/page.js.nft.json +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 +2 -2
- package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/proposals/[proposalUuid]/page.js.nft.json +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.js +2 -2
- 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 +2 -2
- 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.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/tasks/[taskUuid]/page.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/tasks/page.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/(dashboard)/projects/page.js.nft.json +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.js +2 -2
- package/.next/standalone/.next/server/app/(dashboard)/settings/page.js.nft.json +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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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/directory-request/report/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-directory-requests/[uuid]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon-directory-requests/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]/agent-cwds/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/agent-cwd-options/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/route.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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- package/.next/standalone/.next/server/app/login.html +2 -2
- package/.next/standalone/.next/server/app/login.rsc +2 -2
- package/.next/standalone/.next/server/app/onboarding/page.js +2 -2
- package/.next/standalone/.next/server/app/onboarding/page.js.nft.json +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 +3 -3
- 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 +4 -4
- package/.next/standalone/.next/server/app/settings.html +2 -2
- package/.next/standalone/.next/server/app/settings.rsc +4 -4
- package/.next/standalone/.next/server/app-paths-manifest.json +49 -49
- package/.next/standalone/.next/server/chunks/1114.js +1 -1
- package/.next/standalone/.next/server/chunks/1318.js +1 -1
- package/.next/standalone/.next/server/chunks/1559.js +2 -2
- package/.next/standalone/.next/server/chunks/1722.js +1 -1
- package/.next/standalone/.next/server/chunks/2570.js +2 -2
- package/.next/standalone/.next/server/chunks/2572.js +1 -1
- package/.next/standalone/.next/server/chunks/2961.js +1 -1
- package/.next/standalone/.next/server/chunks/3594.js +1 -0
- package/.next/standalone/.next/server/chunks/4394.js +1 -0
- package/.next/standalone/.next/server/chunks/5245.js +1 -1
- package/.next/standalone/.next/server/chunks/{2282.js → 5351.js} +3 -3
- package/.next/standalone/.next/server/chunks/6113.js +1 -1
- package/.next/standalone/.next/server/chunks/6207.js +1 -1
- package/.next/standalone/.next/server/chunks/6506.js +1 -1
- package/.next/standalone/.next/server/chunks/6667.js +1 -0
- package/.next/standalone/.next/server/chunks/679.js +1 -1
- package/.next/standalone/.next/server/chunks/6995.js +1 -0
- package/.next/standalone/.next/server/chunks/7368.js +1 -1
- package/.next/standalone/.next/server/chunks/7530.js +1 -1
- package/.next/standalone/.next/server/chunks/920.js +1 -1
- package/.next/standalone/.next/server/chunks/9213.js +1 -1
- package/.next/standalone/.next/server/chunks/9378.js +1 -1
- package/.next/standalone/.next/server/chunks/9793.js +1 -0
- package/.next/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/.next/standalone/.next/server/middleware-manifest.json +5 -5
- 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/.next/static/chunks/11595.1bcd2b65089007ae.js +1 -0
- package/.next/standalone/.next/static/chunks/19887-4d76db57a7ce4437.js +1 -0
- package/.next/standalone/.next/static/chunks/29108-e171d8b8c680cbb5.js +1 -0
- package/.next/standalone/.next/static/chunks/33456.c98d3e21528b61d8.js +1 -0
- package/.next/standalone/.next/static/chunks/4860.9122a86d33dc6b62.js +1 -0
- package/.next/standalone/.next/static/chunks/53073-5fd399cb25a11740.js +1 -0
- package/.next/standalone/.next/static/chunks/53402-a54163001f3d953a.js +1 -0
- package/.next/standalone/.next/static/chunks/6603-07faab08560f7ecd.js +1 -0
- package/.next/standalone/.next/static/chunks/7777-5dad34f6bdc13482.js +1 -0
- package/.next/standalone/.next/static/chunks/78155-db70d9684a1e77a2.js +1 -0
- package/.next/standalone/.next/static/chunks/78917-7354d3b6908da7d1.js +1 -0
- package/.next/standalone/.next/static/chunks/82751-de255af4418d53e4.js +1 -0
- package/.next/standalone/.next/static/chunks/94643-90a9ec7b9a9abaf0.js +1 -0
- package/.next/standalone/.next/static/chunks/99366-425e9ef22e60e3e2.js +1 -0
- package/.next/standalone/.next/static/chunks/99373.585230dcb315a068.js +1 -0
- package/.next/standalone/.next/static/chunks/app/(dashboard)/layout-3d3b3b9e16c03cda.js +1 -0
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/dashboard/page-69d746c98079024d.js +1 -0
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/documents/[documentUuid]/page-2af705f6c3789131.js +1 -0
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/documents/{page-2c9d3f4c6e0ff807.js → page-82404154708e48a9.js} +1 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/graph/page-8119df915138a9c3.js +1 -0
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/proposals/[proposalUuid]/page-f619bd65e1eed8c9.js +1 -0
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/proposals/new/page-d5b222f379b2e8ca.js +1 -0
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/proposals/{page-ed9415921188b4d3.js → page-6abc7d1785e2b999.js} +1 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/tasks/[taskUuid]/{page-c70af8cac7bdc483.js → page-0789c6589363154c.js} +1 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/tasks/{page-715b000c156a080c.js → page-a612f6fc5be0239d.js} +1 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/settings/page-5fb9fd3db155d5ca.js +1 -0
- package/.next/standalone/.next/static/chunks/app/onboarding/page-e85315278aafc300.js +1 -0
- package/.next/standalone/.next/static/chunks/{webpack-84e2db1b2418c974.js → webpack-dec1f54ebb9bf963.js} +1 -1
- package/.next/standalone/.next/static/css/67fba0943f494f0e.css +1 -0
- package/.next/standalone/package.json +1 -1
- package/.next/standalone/public/chorus-plugin/.claude-plugin/plugin.json +1 -1
- package/.next/standalone/public/chorus-plugin/skills/brainstorm/SKILL.md +1 -1
- package/.next/standalone/public/chorus-plugin/skills/chorus/SKILL.md +2 -1
- package/.next/standalone/public/chorus-plugin/skills/develop/SKILL.md +1 -1
- package/.next/standalone/public/chorus-plugin/skills/docs/SKILL.md +68 -0
- package/.next/standalone/public/chorus-plugin/skills/idea/SKILL.md +1 -1
- package/.next/standalone/public/chorus-plugin/skills/openspec-aware/SKILL.md +1 -1
- package/.next/standalone/public/chorus-plugin/skills/proposal/SKILL.md +1 -1
- package/.next/standalone/public/chorus-plugin/skills/quick-dev/SKILL.md +1 -1
- package/.next/standalone/public/chorus-plugin/skills/review/SKILL.md +1 -1
- package/.next/standalone/public/chorus-plugin/skills/yolo/SKILL.md +1 -1
- package/.next/standalone/public/install-kiro.sh +10 -7
- package/.next/standalone/public/kiro-plugin/.kiro/agents/chorus.json +1 -0
- package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-brainstorm/SKILL.md +1 -1
- package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-develop/SKILL.md +1 -1
- package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-docs/SKILL.md +68 -0
- package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-idea/SKILL.md +1 -1
- package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-openspec-aware/SKILL.md +1 -1
- package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-proposal/SKILL.md +1 -1
- package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-quick-dev/SKILL.md +1 -1
- package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-review/SKILL.md +1 -1
- package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-yolo/SKILL.md +1 -1
- package/.next/standalone/public/kiro-plugin/.kiro/steering/chorus.md +1 -0
- package/.next/standalone/public/kiro-plugin/bin/chorus-api.sh +1 -1
- package/.next/standalone/public/skill/brainstorm-chorus/SKILL.md +1 -1
- package/.next/standalone/public/skill/chorus/SKILL.md +2 -1
- package/.next/standalone/public/skill/code-reviewer-chorus/SKILL.md +1 -1
- package/.next/standalone/public/skill/develop-chorus/SKILL.md +1 -1
- package/.next/standalone/public/skill/docs-chorus/SKILL.md +70 -0
- package/.next/standalone/public/skill/idea-chorus/SKILL.md +1 -1
- package/.next/standalone/public/skill/package.json +9 -5
- package/.next/standalone/public/skill/proposal-chorus/SKILL.md +1 -1
- package/.next/standalone/public/skill/proposal-reviewer-chorus/SKILL.md +1 -1
- package/.next/standalone/public/skill/quick-dev-chorus/SKILL.md +1 -1
- package/.next/standalone/public/skill/review-chorus/SKILL.md +1 -1
- package/.next/standalone/public/skill/task-reviewer-chorus/SKILL.md +1 -1
- package/.next/standalone/public/skill/yolo-chorus/SKILL.md +1 -1
- package/README.ja.md +6 -14
- package/README.ko.md +6 -14
- package/README.md +6 -14
- package/README.zh.md +6 -14
- package/cli/claude-spawner.mjs +15 -6
- package/cli/client-args.mjs +8 -0
- package/cli/codex-spawner.mjs +7 -3
- package/cli/credentials.mjs +41 -0
- package/cli/daemon-config.mjs +202 -1
- package/cli/daemon-install-config.mjs +38 -1
- package/cli/daemon.mjs +222 -1
- package/cli/login.mjs +90 -2
- package/package.json +1 -1
- package/.next/standalone/.next/server/chunks/1524.js +0 -1
- package/.next/standalone/.next/server/chunks/330.js +0 -1
- package/.next/standalone/.next/server/chunks/3525.js +0 -1
- package/.next/standalone/.next/server/chunks/4070.js +0 -1
- package/.next/standalone/.next/server/chunks/8540.js +0 -1
- package/.next/standalone/.next/static/chunks/11595.f1e55e827d67f2bc.js +0 -1
- package/.next/standalone/.next/static/chunks/18351-12dc856208d79e10.js +0 -1
- package/.next/standalone/.next/static/chunks/33456.4817cdce41593c7e.js +0 -1
- package/.next/standalone/.next/static/chunks/37938-0b9a2b891c04b166.js +0 -1
- package/.next/standalone/.next/static/chunks/4860.bb2749ebaf8eb15f.js +0 -1
- package/.next/standalone/.next/static/chunks/53402-be6989c3f3968e7b.js +0 -1
- package/.next/standalone/.next/static/chunks/68326-61feeb2f6cddd338.js +0 -1
- package/.next/standalone/.next/static/chunks/72974-714dcca796895c40.js +0 -1
- package/.next/standalone/.next/static/chunks/7777-13466138aa42bd5f.js +0 -1
- package/.next/standalone/.next/static/chunks/78917-f91904c6c2d12dab.js +0 -1
- package/.next/standalone/.next/static/chunks/80748-e971c5a5d6ef967d.js +0 -1
- package/.next/standalone/.next/static/chunks/80904-973284d1fe916c38.js +0 -1
- package/.next/standalone/.next/static/chunks/94470-0c74a933d5a2902f.js +0 -1
- package/.next/standalone/.next/static/chunks/94643-ba1ebff5769d2b50.js +0 -1
- package/.next/standalone/.next/static/chunks/99373.ae03246bdf49c700.js +0 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/layout-177a3fa88be94b4a.js +0 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/dashboard/page-03b8510273520572.js +0 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/documents/[documentUuid]/page-4a8ac49308a4e23b.js +0 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/graph/page-03408be00dc4822b.js +0 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/proposals/[proposalUuid]/page-be353989e67e7b55.js +0 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/proposals/new/page-596d97796dd55e2f.js +0 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/settings/page-e786a59c24eb5bda.js +0 -1
- package/.next/standalone/.next/static/chunks/app/onboarding/page-df7c97cefb508201.js +0 -1
- package/.next/standalone/.next/static/css/ef995b001437e3ef.css +0 -1
- /package/.next/standalone/.next/static/{oHZy43Le4b2I7pg7_cQ0Z → H92ZuhpmDWcL3WOfYRc--}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{oHZy43Le4b2I7pg7_cQ0Z → H92ZuhpmDWcL3WOfYRc--}/_ssgManifest.js +0 -0
package/cli/claude-spawner.mjs
CHANGED
|
@@ -284,7 +284,11 @@ export class ClaudeSpawner {
|
|
|
284
284
|
* so the waker can store the handle in its execution registry for the interrupt
|
|
285
285
|
* path BEFORE this promise resolves. It is invoked once, synchronously, only on a
|
|
286
286
|
* successful spawn; a spawn failure never calls it.
|
|
287
|
-
* @returns {Promise<{ sessionId: string, exitCode: number|null, isNew: boolean }>}
|
|
287
|
+
* @returns {Promise<{ sessionId: string, backendSessionId: string|null, exitCode: number|null, isNew: boolean }>}
|
|
288
|
+
* `backendSessionId` is the Claude `--resume` anchor (the input `sessionId`) on a
|
|
289
|
+
* terminal resolution after a spawn, so the conversation UI can offer a resumable
|
|
290
|
+
* id — mirrors codex-spawner's shape. `null` on the pre-spawn failure paths (no
|
|
291
|
+
* turn ran, nothing to resume).
|
|
288
292
|
*/
|
|
289
293
|
async wake({ prompt, sessionId, isNew, mcpConfigPath, cwd, onMessage, onChild }) {
|
|
290
294
|
const id = sessionId;
|
|
@@ -295,14 +299,14 @@ export class ClaudeSpawner {
|
|
|
295
299
|
this.logger.error(
|
|
296
300
|
`[Chorus] refusing to spawn: session id is not a valid lowercase UUID: ${id}`
|
|
297
301
|
);
|
|
298
|
-
return { sessionId: typeof id === "string" ? id : "", exitCode: null, isNew: Boolean(isNew) };
|
|
302
|
+
return { sessionId: typeof id === "string" ? id : "", backendSessionId: null, exitCode: null, isNew: Boolean(isNew) };
|
|
299
303
|
}
|
|
300
304
|
|
|
301
305
|
const claudePath = this.claudePath ?? resolveClaudePath();
|
|
302
306
|
if (!claudePath) {
|
|
303
307
|
// No crash — surface visibly and resolve with a failure result.
|
|
304
308
|
this.logger.error("[Chorus] cannot locate the `claude` executable on PATH; skipping wake");
|
|
305
|
-
return { sessionId: id, exitCode: null, isNew };
|
|
309
|
+
return { sessionId: id, backendSessionId: null, exitCode: null, isNew };
|
|
306
310
|
}
|
|
307
311
|
|
|
308
312
|
const args = buildArgs({ sessionId: id, isNew, mcpConfigPath, permissionMode: this.permissionMode });
|
|
@@ -345,7 +349,7 @@ export class ClaudeSpawner {
|
|
|
345
349
|
});
|
|
346
350
|
} catch (err) {
|
|
347
351
|
this.logger.error(`[Chorus] failed to spawn claude: ${err}`);
|
|
348
|
-
resolve({ sessionId: id, exitCode: null, isNew });
|
|
352
|
+
resolve({ sessionId: id, backendSessionId: null, exitCode: null, isNew });
|
|
349
353
|
return;
|
|
350
354
|
}
|
|
351
355
|
|
|
@@ -391,14 +395,19 @@ export class ClaudeSpawner {
|
|
|
391
395
|
child.on("error", (err) => {
|
|
392
396
|
// e.g. ENOENT if the resolved path vanished — log, don't throw.
|
|
393
397
|
this.logger.error(`[Chorus] claude process error: ${err}`);
|
|
394
|
-
|
|
398
|
+
// backendSessionId is the `--resume` anchor (`id`), NOT observedSessionId:
|
|
399
|
+
// a fork-on-resume claude can emit a new stream session_id, but the daemon
|
|
400
|
+
// resumes and files the transcript under `id`, so `id` is the resumable value.
|
|
401
|
+
resolve({ sessionId: observedSessionId, backendSessionId: id, exitCode: null, isNew });
|
|
395
402
|
});
|
|
396
403
|
|
|
397
404
|
child.on("close", (code) => {
|
|
398
405
|
if (code !== 0) {
|
|
399
406
|
this.logger.warn(`[Chorus] claude exited with code ${code}`);
|
|
400
407
|
}
|
|
401
|
-
|
|
408
|
+
// backendSessionId is the `--resume` anchor (`id`), NOT observedSessionId (see
|
|
409
|
+
// the process-error handler above for why the anchor is the resumable value).
|
|
410
|
+
resolve({ sessionId: observedSessionId, backendSessionId: id, exitCode: code, isNew });
|
|
402
411
|
});
|
|
403
412
|
|
|
404
413
|
// Guard against an ASYNC stdin error (EPIPE): if claude exits/closes
|
package/cli/client-args.mjs
CHANGED
|
@@ -69,6 +69,7 @@ export function parseClientFlags(argv) {
|
|
|
69
69
|
else if (a === "-d" || a === "--detach") out.detach = true;
|
|
70
70
|
else if (a === "--force") out.force = true;
|
|
71
71
|
else if (a === "--yes" || a === "-y") out.yes = true;
|
|
72
|
+
else if (a === "--add") out.add = true;
|
|
72
73
|
else if (a === "--help" || a === "-h") out.help = true;
|
|
73
74
|
}
|
|
74
75
|
return out;
|
|
@@ -202,9 +203,16 @@ USAGE
|
|
|
202
203
|
OPTIONS
|
|
203
204
|
--url <url> Remote Chorus server URL (env: CHORUS_URL)
|
|
204
205
|
--api-key <cho_...> Agent API key (env: CHORUS_API_KEY)
|
|
206
|
+
--add Add this key as an ADDITIONAL agent (multi-agent daemon)
|
|
207
|
+
instead of overwriting the single credential
|
|
205
208
|
-h, --help Show this help message
|
|
206
209
|
|
|
207
210
|
With no flags, login prompts interactively for the URL and a masked API key,
|
|
208
211
|
validates them against the server, and on success saves the credentials.
|
|
212
|
+
|
|
213
|
+
With --add, the validated key is appended to the daemon.json 'agents[]' array
|
|
214
|
+
so one daemon can serve several independent agents (see docs/DAEMON.md). The
|
|
215
|
+
first --add migrates an existing flat credential into agents[0]; a duplicate
|
|
216
|
+
key is refused and existing agents are never overwritten.
|
|
209
217
|
`;
|
|
210
218
|
}
|
package/cli/codex-spawner.mjs
CHANGED
|
@@ -13,9 +13,13 @@
|
|
|
13
13
|
// it and persist anchor→thread_id (codex-session-map.mjs) so a later wake can
|
|
14
14
|
// `resume <thread_id>`. (serde: ThreadEvent tag="type", rename="thread.started";
|
|
15
15
|
// ThreadStartedEvent.thread_id: String — codex-rs/exec/src/exec_events.rs.)
|
|
16
|
-
// • No `--mcp-config`: MCP
|
|
17
|
-
//
|
|
18
|
-
//
|
|
16
|
+
// • No `--mcp-config`: Codex reads MCP servers from the user's ~/.codex/config.toml.
|
|
17
|
+
// The Chorus MCP key there is USER-MANAGED: the installer writes a LITERAL Bearer
|
|
18
|
+
// header and Codex does NOT expand ${VAR} inside http_headers, so the CHORUS_API_KEY
|
|
19
|
+
// the daemon exports does NOT reach Codex's MCP auth. The daemon still exports
|
|
20
|
+
// CHORUS_URL / CHORUS_API_KEY into the child env — but only for the plugin's shell
|
|
21
|
+
// tooling (chorus-api.sh / SessionStart hooks), never argv and never Codex MCP.
|
|
22
|
+
// (Multi-agent: two Codex agents with different keys each need their own CODEX_HOME.)
|
|
19
23
|
// • Permission is a SANDBOX mode, not a tool allowlist.
|
|
20
24
|
//
|
|
21
25
|
// Reuses claude-spawner's platform-neutral helpers: parseNdjsonChunk (NDJSON
|
package/cli/credentials.mjs
CHANGED
|
@@ -70,6 +70,47 @@ export function readYoloAck(deps = {}) {
|
|
|
70
70
|
return file ? nonEmpty(file.yoloAckAt) ?? null : null;
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
/**
|
|
74
|
+
* Resolve the DEFAULT url + apiKey layer (per-field, non-throwing) for the
|
|
75
|
+
* multi-agent config. Unlike `resolveCredentials` (which needs a COMPLETE pair
|
|
76
|
+
* and throws when none resolves), this resolves each field independently and
|
|
77
|
+
* returns `undefined` for any field no source supplies. It is the "top-level
|
|
78
|
+
* defaults" layer that each `agents[]` entry merges over: an agent that omits
|
|
79
|
+
* `url` inherits this default `url`, an agent that omits `apiKey` inherits this
|
|
80
|
+
* default `apiKey` (rarely useful, but symmetric with every other default).
|
|
81
|
+
*
|
|
82
|
+
* Same source order as `resolveCredentials`, applied per field:
|
|
83
|
+
* flag > env > login file (top-level) > plugin fallback.
|
|
84
|
+
*
|
|
85
|
+
* @param {{ url?: string, apiKey?: string }} flags
|
|
86
|
+
* @param {ResolveDeps} [deps]
|
|
87
|
+
* @returns {{ url: string | undefined, apiKey: string | undefined }}
|
|
88
|
+
*/
|
|
89
|
+
export function resolveCredentialDefaults(flags = {}, deps = {}) {
|
|
90
|
+
const env = deps.env ?? process.env;
|
|
91
|
+
const readJson = deps.readJson ?? readJsonSafe;
|
|
92
|
+
const loginPath = deps.loginPath ?? loginFilePath();
|
|
93
|
+
const settingsPath = deps.settingsPath ?? claudeSettingsPath();
|
|
94
|
+
|
|
95
|
+
const file = readJson(loginPath);
|
|
96
|
+
const settings = readJson(settingsPath);
|
|
97
|
+
const pluginEnv =
|
|
98
|
+
settings && typeof settings.env === "object" && settings.env !== null
|
|
99
|
+
? /** @type {Record<string, unknown>} */ (settings.env)
|
|
100
|
+
: null;
|
|
101
|
+
|
|
102
|
+
const pick = (flagVal, envKey, fileKey) =>
|
|
103
|
+
nonEmpty(flagVal) ??
|
|
104
|
+
nonEmpty(env[envKey]) ??
|
|
105
|
+
(file ? nonEmpty(file[fileKey]) : undefined) ??
|
|
106
|
+
(pluginEnv ? nonEmpty(pluginEnv[envKey]) : undefined);
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
url: pick(flags.url, "CHORUS_URL", "url"),
|
|
110
|
+
apiKey: pick(flags.apiKey, "CHORUS_API_KEY", "apiKey"),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
73
114
|
/**
|
|
74
115
|
* @typedef {Object} ResolvedCredentials
|
|
75
116
|
* @property {string} url
|
package/cli/daemon-config.mjs
CHANGED
|
@@ -15,11 +15,21 @@
|
|
|
15
15
|
import { readFileSync } from "node:fs";
|
|
16
16
|
import { homedir } from "node:os";
|
|
17
17
|
import { isAbsolute, resolve as resolvePath } from "node:path";
|
|
18
|
-
import { loginFilePath } from "./credentials.mjs";
|
|
18
|
+
import { loginFilePath, resolveCredentials, resolveCredentialDefaults } from "./credentials.mjs";
|
|
19
|
+
import { resolveAgentType, KNOWN_AGENTS } from "./daemon-agent.mjs";
|
|
20
|
+
import { resolvePermissionMode } from "./daemon-permission-mode.mjs";
|
|
19
21
|
|
|
20
22
|
/** Built-in default escalation window (ms) — matches the spec's 10 seconds. */
|
|
21
23
|
export const DEFAULT_SIGINT_TIMEOUT_MS = 10_000;
|
|
22
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Built-in default per-agent wake concurrency. This was the process-wide
|
|
27
|
+
* hardcoded WakeQueue cap (`maxConcurrency ?? 4` in daemon.mjs) before it became
|
|
28
|
+
* a per-agent, configurable value — kept at 4 so an agent that specifies no
|
|
29
|
+
* `maxConcurrency` behaves exactly as the daemon did before.
|
|
30
|
+
*/
|
|
31
|
+
export const DEFAULT_MAX_CONCURRENCY = 4;
|
|
32
|
+
|
|
23
33
|
/**
|
|
24
34
|
* Coerce a value to a positive finite integer of milliseconds, or undefined when it
|
|
25
35
|
* is absent / not a usable number. Accepts a number or a numeric string (env vars
|
|
@@ -235,3 +245,194 @@ export function resolveBrowseRoots(flags = {}, deps = {}) {
|
|
|
235
245
|
: [];
|
|
236
246
|
return fromFile.length ? fromFile : [normalizeCwd(home, home)];
|
|
237
247
|
}
|
|
248
|
+
|
|
249
|
+
// ===== Multi-agent config (daemon-multi-agent — N independent agents per daemon) =====
|
|
250
|
+
//
|
|
251
|
+
// One daemon process may serve a LIST of fully-independent agents, each with its
|
|
252
|
+
// own credentials + working directories + backend + permission mode + concurrency.
|
|
253
|
+
// `resolveAgentConfigs` returns that list as `AgentConfig[]`, every field already
|
|
254
|
+
// merged with its default. Two shapes are supported:
|
|
255
|
+
//
|
|
256
|
+
// 1. `~/.chorus/daemon.json` has a non-empty `agents: [ … ]` array → one
|
|
257
|
+
// AgentConfig per entry, each entry's fields merged OVER the top-level
|
|
258
|
+
// defaults (per-agent value wins; an omitted field inherits the default).
|
|
259
|
+
// 2. No `agents[]` (or empty) → exactly ONE AgentConfig synthesized from the
|
|
260
|
+
// existing flat resolution (resolveCredentials + resolveDaemonCwds +
|
|
261
|
+
// resolveAgentType + sigint + browseRoots). This is byte-for-byte the
|
|
262
|
+
// daemon's current single-agent behavior — old installs run unchanged, and
|
|
263
|
+
// flags / env still resolve this single agent's fields.
|
|
264
|
+
//
|
|
265
|
+
// Validation is strict and visible: a missing apiKey, an unresolvable url, an
|
|
266
|
+
// unknown agentType, or an invalid permissionMode THROWS an Error naming the
|
|
267
|
+
// offending agent. The daemon's top-level error handler turns that into a
|
|
268
|
+
// non-zero exit — the resolver never silently drops or falls back to a default
|
|
269
|
+
// agent (matching resolveCredentials' throw-on-nothing contract).
|
|
270
|
+
|
|
271
|
+
/** A non-empty trimmed string, or undefined. */
|
|
272
|
+
function nonEmptyStr(value) {
|
|
273
|
+
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* True iff `~/.chorus/daemon.json` declares a non-empty `agents[]` with at least
|
|
278
|
+
* one object entry — i.e. the daemon should run in multi-agent mode. Lets the
|
|
279
|
+
* daemon pick the multi-agent startup path (bypassing the flat single-credential
|
|
280
|
+
* preflight) without duplicating the file read. Never throws.
|
|
281
|
+
* @param {{ readJson?: (p: string) => (Record<string, unknown>|null), loginPath?: string }} [deps]
|
|
282
|
+
* @returns {boolean}
|
|
283
|
+
*/
|
|
284
|
+
export function hasConfiguredAgents(deps = {}) {
|
|
285
|
+
const readJson = deps.readJson ?? readJsonSafe;
|
|
286
|
+
const loginPath = deps.loginPath ?? loginFilePath();
|
|
287
|
+
const file = readJson(loginPath);
|
|
288
|
+
return Boolean(
|
|
289
|
+
file && Array.isArray(file.agents) && file.agents.some((a) => a && typeof a === "object"),
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Coerce to a positive finite integer (count), or undefined. Accepts number or
|
|
295
|
+
* numeric string; rejects 0, negatives, NaN, Infinity. Used for maxConcurrency.
|
|
296
|
+
* @param {unknown} value @returns {number | undefined}
|
|
297
|
+
*/
|
|
298
|
+
function positiveInt(value) {
|
|
299
|
+
if (value === undefined || value === null || value === "") return undefined;
|
|
300
|
+
const n = typeof value === "number" ? value : Number(String(value).trim());
|
|
301
|
+
if (!Number.isFinite(n) || n <= 0) return undefined;
|
|
302
|
+
return Math.floor(n);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* @typedef {Object} AgentConfig One fully-resolved agent runtime config.
|
|
307
|
+
* @property {string} url Chorus server URL for this agent.
|
|
308
|
+
* @property {string} apiKey This agent's `cho_` API key.
|
|
309
|
+
* @property {string} agentType Backend: claude-code | codex | kiro.
|
|
310
|
+
* @property {Array<string|undefined>} cwds Served paths (`undefined` ⇒ process cwd).
|
|
311
|
+
* @property {"yolo"|"chorus"} permissionMode Woken-agent permission posture.
|
|
312
|
+
* @property {number} maxConcurrency This agent's wake-queue cap.
|
|
313
|
+
* @property {number} sigintTimeoutMs Interrupt escalation window (ms).
|
|
314
|
+
* @property {string[]} browseRoots Directory-discovery allowlist.
|
|
315
|
+
* @property {string} label Diagnostic label ("agent" or "agents[i]").
|
|
316
|
+
*/
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Resolve the list of agents this daemon serves. See the block comment above.
|
|
320
|
+
*
|
|
321
|
+
* @param {{ url?: string, apiKey?: string, agent?: string, cwd?: string|string[],
|
|
322
|
+
* browseRoot?: string|string[], sigintTimeout?: number|string,
|
|
323
|
+
* chorusOnly?: boolean, yolo?: boolean }} [flags]
|
|
324
|
+
* @param {{
|
|
325
|
+
* env?: Record<string, string|undefined>,
|
|
326
|
+
* readJson?: (path: string) => (Record<string, unknown>|null),
|
|
327
|
+
* loginPath?: string,
|
|
328
|
+
* settingsPath?: string,
|
|
329
|
+
* home?: string,
|
|
330
|
+
* permissionMode?: "yolo"|"chorus", // pre-resolved global posture (else computed)
|
|
331
|
+
* }} [deps]
|
|
332
|
+
* @returns {AgentConfig[]} Non-empty list; throws on an invalid agent entry.
|
|
333
|
+
*/
|
|
334
|
+
export function resolveAgentConfigs(flags = {}, deps = {}) {
|
|
335
|
+
const env = deps.env ?? process.env;
|
|
336
|
+
const readJson = deps.readJson ?? readJsonSafe;
|
|
337
|
+
const loginPath = deps.loginPath ?? loginFilePath();
|
|
338
|
+
const home = deps.home ?? homedir();
|
|
339
|
+
const file = readJson(loginPath);
|
|
340
|
+
|
|
341
|
+
// Global default permission posture; a per-agent `permissionMode` overrides it.
|
|
342
|
+
// needConfirm/hasAck is vestigial, so isTTY/hasAck do not affect the resolved mode.
|
|
343
|
+
const defaultPermissionMode =
|
|
344
|
+
deps.permissionMode ??
|
|
345
|
+
resolvePermissionMode(flags, env, { isTTY: false, hasAck: false }).mode;
|
|
346
|
+
|
|
347
|
+
const agentEntries =
|
|
348
|
+
file && Array.isArray(file.agents)
|
|
349
|
+
? file.agents.filter((a) => a && typeof a === "object")
|
|
350
|
+
: [];
|
|
351
|
+
|
|
352
|
+
// ---- Back-compat: no agents[] → exactly one agent from flat resolution ----
|
|
353
|
+
if (agentEntries.length === 0) {
|
|
354
|
+
const creds = resolveCredentials(flags, deps); // throws if no complete pair (today's behavior)
|
|
355
|
+
const at = resolveAgentType(flags, env, deps);
|
|
356
|
+
if (!at.ok) throw new Error(at.error);
|
|
357
|
+
return [
|
|
358
|
+
{
|
|
359
|
+
url: creds.url,
|
|
360
|
+
apiKey: creds.apiKey,
|
|
361
|
+
agentType: at.agent,
|
|
362
|
+
cwds: resolveDaemonCwds(flags, deps),
|
|
363
|
+
permissionMode: defaultPermissionMode,
|
|
364
|
+
maxConcurrency: positiveInt(file?.maxConcurrency) ?? DEFAULT_MAX_CONCURRENCY,
|
|
365
|
+
sigintTimeoutMs: resolveSigintTimeoutMs(flags, deps),
|
|
366
|
+
browseRoots: resolveBrowseRoots(flags, deps),
|
|
367
|
+
label: "agent",
|
|
368
|
+
},
|
|
369
|
+
];
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// ---- Multi-agent: each entry merged over the top-level defaults ----
|
|
373
|
+
const credDefaults = resolveCredentialDefaults(flags, deps);
|
|
374
|
+
const defaultCwds = resolveDaemonCwds(flags, deps);
|
|
375
|
+
const defaultAgentType = resolveAgentType(flags, env, deps); // top-level default (may be {ok:false} if top-level `agent` is garbage)
|
|
376
|
+
const defaultSigint = resolveSigintTimeoutMs(flags, deps);
|
|
377
|
+
const defaultBrowseRoots = resolveBrowseRoots(flags, deps);
|
|
378
|
+
const defaultMaxConcurrency = positiveInt(file?.maxConcurrency) ?? DEFAULT_MAX_CONCURRENCY;
|
|
379
|
+
|
|
380
|
+
return agentEntries.map((entry, i) => {
|
|
381
|
+
const label = nonEmptyStr(entry.label) ?? nonEmptyStr(entry.name) ?? `agents[${i}]`;
|
|
382
|
+
|
|
383
|
+
const url = nonEmptyStr(entry.url) ?? credDefaults.url;
|
|
384
|
+
const apiKey = nonEmptyStr(entry.apiKey) ?? credDefaults.apiKey;
|
|
385
|
+
if (!apiKey) {
|
|
386
|
+
throw new Error(`Agent ${label}: missing apiKey (no per-agent apiKey and no top-level default).`);
|
|
387
|
+
}
|
|
388
|
+
if (!url) {
|
|
389
|
+
throw new Error(`Agent ${label}: missing/unresolvable url (no per-agent url and no top-level default).`);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// agentType: per-agent value, else the top-level default (which must itself be valid).
|
|
393
|
+
let agentType;
|
|
394
|
+
if (nonEmptyStr(entry.agentType)) {
|
|
395
|
+
agentType = nonEmptyStr(entry.agentType);
|
|
396
|
+
} else if (defaultAgentType.ok) {
|
|
397
|
+
agentType = defaultAgentType.agent;
|
|
398
|
+
} else {
|
|
399
|
+
throw new Error(
|
|
400
|
+
`Agent ${label}: no agentType and the top-level agent default is invalid (${defaultAgentType.error}).`,
|
|
401
|
+
);
|
|
402
|
+
}
|
|
403
|
+
if (!KNOWN_AGENTS.includes(agentType)) {
|
|
404
|
+
throw new Error(
|
|
405
|
+
`Agent ${label}: unknown agentType "${agentType}". Accepted: ${KNOWN_AGENTS.join(", ")}.`,
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// permissionMode: per-agent override (yolo|chorus only), else global posture.
|
|
410
|
+
let permissionMode = defaultPermissionMode;
|
|
411
|
+
if (entry.permissionMode !== undefined) {
|
|
412
|
+
const pm = nonEmptyStr(entry.permissionMode);
|
|
413
|
+
if (pm !== "yolo" && pm !== "chorus") {
|
|
414
|
+
throw new Error(
|
|
415
|
+
`Agent ${label}: invalid permissionMode "${entry.permissionMode}". Accepted: yolo, chorus.`,
|
|
416
|
+
);
|
|
417
|
+
}
|
|
418
|
+
permissionMode = pm;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// cwds: per-agent list (cleaned); an empty/blank list degrades to [undefined]
|
|
422
|
+
// (serve the process cwd). Omitted → inherit the top-level default set.
|
|
423
|
+
let cwds;
|
|
424
|
+
if (entry.cwds !== undefined) {
|
|
425
|
+
const cleaned = cleanCwdList(entry.cwds, home);
|
|
426
|
+
cwds = cleaned.length ? cleaned : [undefined];
|
|
427
|
+
} else {
|
|
428
|
+
cwds = defaultCwds;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
const maxConcurrency = positiveInt(entry.maxConcurrency) ?? defaultMaxConcurrency;
|
|
432
|
+
const sigintTimeoutMs = positiveIntMs(entry.sigintTimeoutMs) ?? defaultSigint;
|
|
433
|
+
const browseRoots =
|
|
434
|
+
entry.browseRoots !== undefined ? cleanCwdList(entry.browseRoots, home) : defaultBrowseRoots;
|
|
435
|
+
|
|
436
|
+
return { url, apiKey, agentType, cwds, permissionMode, maxConcurrency, sigintTimeoutMs, browseRoots, label };
|
|
437
|
+
});
|
|
438
|
+
}
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
|
|
24
24
|
import { homedir } from "node:os";
|
|
25
25
|
import { resolveCredentials, loginFilePath } from "./credentials.mjs";
|
|
26
|
-
import { updateDaemonConfig, prompt as defaultPrompt } from "./login.mjs";
|
|
26
|
+
import { updateDaemonConfig, appendAgentConfig, prompt as defaultPrompt } from "./login.mjs";
|
|
27
27
|
import { validateAndFetchIdentity } from "./chorus-client.mjs";
|
|
28
28
|
import { normalizeCwd, cleanCwdList } from "./daemon-config.mjs";
|
|
29
29
|
import { KNOWN_AGENTS, DEFAULT_AGENT } from "./daemon-agent.mjs";
|
|
@@ -132,6 +132,43 @@ export async function resolveInstallCredentials(flags = {}, env = {}, opts = {})
|
|
|
132
132
|
// field-merge writer preserves cwds / yoloAckAt / sigintTimeoutMs.
|
|
133
133
|
writeConfig({ url, apiKey, agentUuid: identity.uuid, agentName: identity.name });
|
|
134
134
|
log(`[Chorus] credentials saved for ${identity.name} (${identity.uuid}).`);
|
|
135
|
+
|
|
136
|
+
// Multi-agent (daemon-multi-agent): with `--add` on a TTY, offer to add more
|
|
137
|
+
// agents in the same run. Each additional key is validated then APPENDED to
|
|
138
|
+
// agents[] (the first agent above is folded into agents[0] on the first
|
|
139
|
+
// append). Opt-in via --add so a plain install prompts for nothing extra;
|
|
140
|
+
// never runs on a non-TTY / --yes / skip run. Hand-editing daemon.json remains
|
|
141
|
+
// fully supported regardless.
|
|
142
|
+
if (isTTY && !skip && flags.add === true) {
|
|
143
|
+
const appendAgent = opts.appendAgent ?? appendAgentConfig;
|
|
144
|
+
// Bound the loop so a stuck/looping prompt can never spin forever.
|
|
145
|
+
for (let added = 0; added < 32; added += 1) {
|
|
146
|
+
const more = nonEmpty(await ask("Add another agent? [y/N]: "));
|
|
147
|
+
if (!more || !/^y(es)?$/i.test(more)) break;
|
|
148
|
+
const u = nonEmpty(await ask(" Chorus URL: "));
|
|
149
|
+
const k = nonEmpty(await ask(" Chorus API key (cho_...): ", { mask: true }));
|
|
150
|
+
if (!u || !k) {
|
|
151
|
+
errLog("[Chorus] both a URL and an API key are required — skipping this agent.");
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
let id;
|
|
155
|
+
try {
|
|
156
|
+
id = await validate({ url: u, apiKey: k });
|
|
157
|
+
} catch (err) {
|
|
158
|
+
errLog(
|
|
159
|
+
`[Chorus] validation failed: ${err instanceof Error ? err.message : String(err)} — this agent was NOT added.`,
|
|
160
|
+
);
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
const res = appendAgent({ url: u, apiKey: k, agentUuid: id.uuid, agentName: id.name });
|
|
164
|
+
if (!res.ok) {
|
|
165
|
+
errLog(`[Chorus] agent ${id.name} (${id.uuid}) is already configured — skipping.`);
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
log(`[Chorus] added agent ${id.name} (${id.uuid}) — this daemon now serves ${res.agents.length} agents.`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
135
172
|
return { ok: true, creds: { url, apiKey }, identity };
|
|
136
173
|
}
|
|
137
174
|
|
package/cli/daemon.mjs
CHANGED
|
@@ -47,7 +47,13 @@ import { createInterruptReporter } from "./interrupt-reporter.mjs";
|
|
|
47
47
|
import { createTurnReporter } from "./turn-reporter.mjs";
|
|
48
48
|
import { createDaemonRestClient } from "./daemon-rest-client.mjs";
|
|
49
49
|
import { createControlHandler } from "./control-handler.mjs";
|
|
50
|
-
import {
|
|
50
|
+
import {
|
|
51
|
+
resolveSigintTimeoutMs,
|
|
52
|
+
resolveDaemonCwds,
|
|
53
|
+
resolveBrowseRoots,
|
|
54
|
+
resolveAgentConfigs,
|
|
55
|
+
hasConfiguredAgents,
|
|
56
|
+
} from "./daemon-config.mjs";
|
|
51
57
|
import { discoverDirectories, validateDirectory } from "./directory-discovery.mjs";
|
|
52
58
|
import {
|
|
53
59
|
startBackground,
|
|
@@ -544,6 +550,122 @@ export function buildDaemon(creds, deps = {}) {
|
|
|
544
550
|
};
|
|
545
551
|
}
|
|
546
552
|
|
|
553
|
+
/**
|
|
554
|
+
* Fan-out builder: compose ONE `buildDaemon` runtime per agent config, so a single
|
|
555
|
+
* daemon process serves N fully-independent agents — each with its own creds,
|
|
556
|
+
* ChorusClient, LineageResolver, spawner (by its `agentType`), WakeQueue (its own
|
|
557
|
+
* `maxConcurrency`), and connections over its OWN cwds. For N=1 this is behaviorally
|
|
558
|
+
* identical to `buildDaemon({url,apiKey}, deps)`.
|
|
559
|
+
*
|
|
560
|
+
* Each agent's runtime is isolated: a build/start failure in one agent is logged and
|
|
561
|
+
* skipped, and the others keep serving. The aggregate `allConflict` settles only when
|
|
562
|
+
* EVERY agent's paths are all already served (nothing left to do at all).
|
|
563
|
+
*
|
|
564
|
+
* Injectable seams mirror `buildDaemon`; array-valued deps (`spawner`, `mcpClient`,
|
|
565
|
+
* `lineage`, `sseListener`, `makeSseListener`) are indexed PER agent for tests.
|
|
566
|
+
*
|
|
567
|
+
* @param {import("./daemon-config.mjs").AgentConfig[]} agentConfigs
|
|
568
|
+
* @param {object} [deps]
|
|
569
|
+
* @returns {{ agents: Array<{cfg: any, daemon: any}>, connections: any[],
|
|
570
|
+
* waker: any, router: any, sseListener: any, allConflict: Promise<void>,
|
|
571
|
+
* start: () => Promise<void>, stop: () => Promise<void> }}
|
|
572
|
+
*/
|
|
573
|
+
export function buildMultiAgentDaemon(agentConfigs, deps = {}) {
|
|
574
|
+
const logger = deps.logger ?? defaultLogger();
|
|
575
|
+
if (!Array.isArray(agentConfigs) || agentConfigs.length === 0) {
|
|
576
|
+
throw new Error("buildMultiAgentDaemon: at least one agent config is required");
|
|
577
|
+
}
|
|
578
|
+
const build = deps.build ?? buildDaemon;
|
|
579
|
+
const perAgent = (key, i) => {
|
|
580
|
+
const v = deps[key];
|
|
581
|
+
return Array.isArray(v) ? v[i] : i === 0 ? v : undefined;
|
|
582
|
+
};
|
|
583
|
+
|
|
584
|
+
const agents = agentConfigs
|
|
585
|
+
.map((cfg, i) => {
|
|
586
|
+
// Per-agent deps: cfg fields drive the per-agent runtime; injectable fakes are
|
|
587
|
+
// indexed per agent. `cwd` (singular) is cleared so a caller's single value can
|
|
588
|
+
// never leak across agents — each agent's `cwds` is authoritative.
|
|
589
|
+
const agentDeps = {
|
|
590
|
+
...deps,
|
|
591
|
+
logger,
|
|
592
|
+
permissionMode: cfg.permissionMode,
|
|
593
|
+
agentType: cfg.agentType,
|
|
594
|
+
cwds: cfg.cwds,
|
|
595
|
+
cwd: undefined,
|
|
596
|
+
maxConcurrency: cfg.maxConcurrency,
|
|
597
|
+
sigintTimeoutMs: cfg.sigintTimeoutMs,
|
|
598
|
+
browseRoots: cfg.browseRoots,
|
|
599
|
+
mcpClient: perAgent("mcpClient", i),
|
|
600
|
+
lineage: perAgent("lineage", i),
|
|
601
|
+
spawner: perAgent("spawner", i),
|
|
602
|
+
sseListener: perAgent("sseListener", i),
|
|
603
|
+
makeSseListener: Array.isArray(deps.makeSseListener)
|
|
604
|
+
? deps.makeSseListener[i]
|
|
605
|
+
: deps.makeSseListener,
|
|
606
|
+
};
|
|
607
|
+
try {
|
|
608
|
+
return { cfg, daemon: build({ url: cfg.url, apiKey: cfg.apiKey }, agentDeps) };
|
|
609
|
+
} catch (err) {
|
|
610
|
+
logger.error?.(
|
|
611
|
+
`[Chorus] agent ${cfg.label}: failed to build runtime — skipping ` +
|
|
612
|
+
`(${err instanceof Error ? err.message : String(err)})`,
|
|
613
|
+
);
|
|
614
|
+
return null;
|
|
615
|
+
}
|
|
616
|
+
})
|
|
617
|
+
.filter(Boolean);
|
|
618
|
+
|
|
619
|
+
if (agents.length === 0) {
|
|
620
|
+
throw new Error("buildMultiAgentDaemon: all agent runtimes failed to build");
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
const connections = agents.flatMap((a) => a.daemon.connections ?? []);
|
|
624
|
+
const primary = agents[0].daemon;
|
|
625
|
+
// Aggregate all-conflict: settles only when EVERY agent's paths are all already
|
|
626
|
+
// served by a live daemon (each agent's allConflict settles only in that case, and
|
|
627
|
+
// never otherwise). A single serving agent keeps the whole daemon alive.
|
|
628
|
+
const allConflict = Promise.all(
|
|
629
|
+
agents.map((a) => a.daemon.allConflict ?? new Promise(() => {})),
|
|
630
|
+
).then(() => {});
|
|
631
|
+
|
|
632
|
+
return {
|
|
633
|
+
agents,
|
|
634
|
+
connections,
|
|
635
|
+
// Back-compat single aliases (first agent's primary connection) for inspection.
|
|
636
|
+
waker: primary.waker,
|
|
637
|
+
router: primary.router,
|
|
638
|
+
sseListener: primary.sseListener,
|
|
639
|
+
allConflict,
|
|
640
|
+
async start() {
|
|
641
|
+
// Start each agent independently; one agent's start failure is logged and
|
|
642
|
+
// isolated so the others still serve.
|
|
643
|
+
for (const a of agents) {
|
|
644
|
+
try {
|
|
645
|
+
await a.daemon.start();
|
|
646
|
+
} catch (err) {
|
|
647
|
+
logger.error?.(
|
|
648
|
+
`[Chorus] agent ${a.cfg.label}: start failed — ` +
|
|
649
|
+
`${err instanceof Error ? err.message : String(err)} (other agents continue)`,
|
|
650
|
+
);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
},
|
|
654
|
+
async stop() {
|
|
655
|
+
for (const a of agents) {
|
|
656
|
+
try {
|
|
657
|
+
await a.daemon.stop();
|
|
658
|
+
} catch (err) {
|
|
659
|
+
logger.warn?.(
|
|
660
|
+
`[Chorus] agent ${a.cfg.label}: stop error — ` +
|
|
661
|
+
`${err instanceof Error ? err.message : String(err)}`,
|
|
662
|
+
);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
},
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
|
|
547
669
|
/**
|
|
548
670
|
* Entry point for `chorus daemon`. Resolves credentials, validates them
|
|
549
671
|
* (echoing the agent identity), and runs the daemon until terminated.
|
|
@@ -650,6 +772,105 @@ export async function runDaemon(flags = {}, deps = {}) {
|
|
|
650
772
|
const cwds = resolveDaemonCwds({ cwd: flags.cwd }, { env });
|
|
651
773
|
const browseRoots = resolveBrowseRoots({ browseRoot: flags.browseRoot }, { env });
|
|
652
774
|
|
|
775
|
+
// ===== Multi-agent mode (daemon-multi-agent) =====
|
|
776
|
+
// When daemon.json declares a non-empty agents[], run N fully-independent agents in
|
|
777
|
+
// one process. Each agent carries its OWN creds, so this bypasses the flat single-
|
|
778
|
+
// credential preflight (interactive credential completion is a single-agent
|
|
779
|
+
// affordance). Each agent authenticates on its own key; a failure is isolated
|
|
780
|
+
// (logged + that agent skipped) so the rest still serve.
|
|
781
|
+
if (hasConfiguredAgents({ readJson: deps.readJson, loginPath: deps.loginPath })) {
|
|
782
|
+
const buildMulti = deps.buildMulti ?? buildMultiAgentDaemon;
|
|
783
|
+
let agentConfigs;
|
|
784
|
+
try {
|
|
785
|
+
agentConfigs = resolveAgentConfigs(
|
|
786
|
+
{
|
|
787
|
+
url: flags.url,
|
|
788
|
+
apiKey: flags.apiKey,
|
|
789
|
+
agent: flags.agent,
|
|
790
|
+
cwd: flags.cwd,
|
|
791
|
+
browseRoot: flags.browseRoot,
|
|
792
|
+
sigintTimeout: flags.sigintTimeout,
|
|
793
|
+
chorusOnly: flags.chorusOnly,
|
|
794
|
+
yolo: flags.yolo,
|
|
795
|
+
},
|
|
796
|
+
{ env, readJson: deps.readJson, loginPath: deps.loginPath },
|
|
797
|
+
);
|
|
798
|
+
} catch (err) {
|
|
799
|
+
errLog(`[Chorus] ${err instanceof Error ? err.message : String(err)}`);
|
|
800
|
+
return 1;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
// Validate each agent independently. A validation failure logs + skips that agent
|
|
804
|
+
// (isolation) — the daemon still serves the agents that authenticated.
|
|
805
|
+
const okConfigs = [];
|
|
806
|
+
for (const cfg of agentConfigs) {
|
|
807
|
+
try {
|
|
808
|
+
const id = await validate({ url: cfg.url, apiKey: cfg.apiKey });
|
|
809
|
+
okConfigs.push(cfg);
|
|
810
|
+
log(
|
|
811
|
+
`[Chorus] agent ${cfg.label}: ${id.name} (${id.uuid}) — ${cfg.agentType}, ` +
|
|
812
|
+
`${cfg.permissionMode}, ${cfg.cwds.length} path(s), maxConcurrency=${cfg.maxConcurrency}`,
|
|
813
|
+
);
|
|
814
|
+
if (cfg.permissionMode === "yolo") errLog(`[Chorus] agent ${cfg.label}: ${yoloWarningLine()}`);
|
|
815
|
+
} catch (err) {
|
|
816
|
+
errLog(
|
|
817
|
+
`[Chorus] agent ${cfg.label}: credential validation failed — ` +
|
|
818
|
+
`${err instanceof Error ? err.message : String(err)} (skipping this agent)`,
|
|
819
|
+
);
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
if (okConfigs.length === 0) {
|
|
823
|
+
errLog(
|
|
824
|
+
`[Chorus] no agents authenticated — nothing to serve. Check the apiKeys in ${loginFilePath()}.`,
|
|
825
|
+
);
|
|
826
|
+
return 1;
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
const totalPaths = okConfigs.reduce((n, c) => n + c.cwds.length, 0);
|
|
830
|
+
log(
|
|
831
|
+
`[Chorus] multi-agent daemon starting — ${okConfigs.length} agent(s), ` +
|
|
832
|
+
`${totalPaths} connection(s), subscribing to ${okConfigs[0].url}/api/events/notifications`,
|
|
833
|
+
);
|
|
834
|
+
const multiDaemon = buildMulti(okConfigs, {
|
|
835
|
+
logger: { info: log, warn: errLog, error: errLog },
|
|
836
|
+
verbose,
|
|
837
|
+
fetchImpl: deps.fetchImpl,
|
|
838
|
+
killer: deps.killer,
|
|
839
|
+
sseListener: deps.sseListener,
|
|
840
|
+
makeSseListener: deps.makeSseListener,
|
|
841
|
+
spawner: deps.spawner,
|
|
842
|
+
mcpClient: deps.mcpClient,
|
|
843
|
+
lineage: deps.lineage,
|
|
844
|
+
build: deps.build,
|
|
845
|
+
});
|
|
846
|
+
|
|
847
|
+
const shutdownMulti = () => {
|
|
848
|
+
log("[Chorus] shutting down daemon...");
|
|
849
|
+
Promise.resolve(multiDaemon.stop()).finally(() => process.exit(0));
|
|
850
|
+
};
|
|
851
|
+
process.on("SIGINT", shutdownMulti);
|
|
852
|
+
process.on("SIGTERM", shutdownMulti);
|
|
853
|
+
await multiDaemon.start();
|
|
854
|
+
log("[Chorus] multi-agent daemon running. Waiting for task dispatches (Ctrl+C to stop).");
|
|
855
|
+
|
|
856
|
+
const ALL_CONFLICT_M = Symbol("all-conflict");
|
|
857
|
+
const waitForeverM = deps.waitForever ?? (() => new Promise(() => {}));
|
|
858
|
+
const allConflictSignalM = multiDaemon.allConflict ?? new Promise(() => {});
|
|
859
|
+
const outcomeM = await Promise.race([
|
|
860
|
+
waitForeverM().then(() => 0),
|
|
861
|
+
allConflictSignalM.then(() => ALL_CONFLICT_M),
|
|
862
|
+
]);
|
|
863
|
+
if (outcomeM === ALL_CONFLICT_M) {
|
|
864
|
+
errLog(
|
|
865
|
+
`[Chorus] every declared path for every agent is already served by a live daemon — ` +
|
|
866
|
+
`nothing to do. Stop the other daemon(s) or remove the conflicting path(s), then restart.`,
|
|
867
|
+
);
|
|
868
|
+
await multiDaemon.stop();
|
|
869
|
+
return 1;
|
|
870
|
+
}
|
|
871
|
+
return 0;
|
|
872
|
+
}
|
|
873
|
+
|
|
653
874
|
// Foreground preflight: resolve/complete credentials + resolve the permission
|
|
654
875
|
// posture (confirming yolo on a TTY). Reuses the same pfDeps bundle the detach
|
|
655
876
|
// path uses. Returns a numeric exit code on failure, or
|