@chorus-aidlc/chorus 0.15.1 → 0.16.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/app-build-manifest.json +394 -393
- package/.next/standalone/.next/app-path-routes-manifest.json +46 -46
- package/.next/standalone/.next/build-manifest.json +5 -5
- package/.next/standalone/.next/prerender-manifest.json +21 -21
- 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 +2 -2
- package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/activity/page.js.nft.json +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 +2 -2
- package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/dashboard/[ideaUuid]/page.js.nft.json +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.js.nft.json +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 +2 -2
- package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/documents/page.js.nft.json +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.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.js.nft.json +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 +2 -2
- package/.next/standalone/.next/server/app/(dashboard)/projects/[uuid]/proposals/page.js.nft.json +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.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.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/agents/[uuid]/sessions/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/comments/route.js.nft.json +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.js.nft.json +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.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.js.nft.json +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.js.nft.json +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.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon/pending-turns/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon/report-interrupt/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon/resume/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon/transcript/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon/turn-advance/route.js.nft.json +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.js.nft.json +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.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon-sessions/[sessionUuid]/instruction/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon-sessions/[sessionUuid]/repoint/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon-sessions/[sessionUuid]/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon-sessions/ad-hoc/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon-sessions/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/entities/[type]/[uuid]/root-idea/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/events/notifications/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/events/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/ideas/[uuid]/claim/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/ideas/[uuid]/move/preview/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/ideas/[uuid]/move/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/ideas/[uuid]/parent/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/ideas/[uuid]/release/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/ideas/[uuid]/route.js.nft.json +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.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/ideas/conversational/route.js.nft.json +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.js +2 -2
- package/.next/standalone/.next/server/app/api/mcp/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/me/assignments/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/mentionables/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/notifications/[uuid]/archive/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/notifications/[uuid]/read/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/notifications/preferences/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/notifications/read-all/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/notifications/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/notifications/unread-count/route.js.nft.json +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.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[uuid]/available/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[uuid]/ideas/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[uuid]/ideas/tracker/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[uuid]/resource-graph/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[uuid]/tasks/dependencies/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[uuid]/tasks/route.js.nft.json +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.js.nft.json +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.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/sessions/[uuid]/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/tasks/[uuid]/claim/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/tasks/[uuid]/dependencies/[dependsOnUuid]/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/tasks/[uuid]/dependencies/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/tasks/[uuid]/release/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/tasks/[uuid]/route.js.nft.json +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.js +1 -1
- package/.next/standalone/.next/server/app/api/tasks/[uuid]/sessions/route.js.nft.json +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 +3 -3
- 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 +46 -46
- 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/2570.js +2 -2
- package/.next/standalone/.next/server/chunks/2572.js +1 -1
- package/.next/standalone/.next/server/chunks/2618.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/{2547.js → 4011.js} +3 -3
- package/.next/standalone/.next/server/chunks/4394.js +1 -0
- package/.next/standalone/.next/server/chunks/4827.js +1 -1
- package/.next/standalone/.next/server/chunks/5205.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 +3 -3
- 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/7364.js +1 -1
- 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/pages-manifest.json +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.b6f8ad33572b32fe.js +1 -0
- package/.next/standalone/.next/static/chunks/19887-9f459ee9e8d0855f.js +1 -0
- package/.next/standalone/.next/static/chunks/29108-b9b232255811ffa8.js +1 -0
- package/.next/standalone/.next/static/chunks/{31308-bb4a97b3f39c22dd.js → 31308-fda6febfb2882a28.js} +1 -1
- package/.next/standalone/.next/static/chunks/33456.e8550ad410031e29.js +1 -0
- package/.next/standalone/.next/static/chunks/35432-ee83da56c49ef6f8.js +1 -0
- package/.next/standalone/.next/static/chunks/4860.b405fc235b36271b.js +1 -0
- package/.next/standalone/.next/static/chunks/53073-5fd399cb25a11740.js +1 -0
- package/.next/standalone/.next/static/chunks/6603-07faab08560f7ecd.js +1 -0
- package/.next/standalone/.next/static/chunks/66980-652990fcf3212c94.js +10 -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-6d31df78aa3074b5.js +1 -0
- package/.next/standalone/.next/static/chunks/96170-75da13decdb6f73f.js +1 -0
- package/.next/standalone/.next/static/chunks/99366-425e9ef22e60e3e2.js +1 -0
- package/.next/standalone/.next/static/chunks/99373.9dce8f30802824fc.js +1 -0
- package/.next/standalone/.next/static/chunks/app/(dashboard)/layout-cea0bb3e3a295bea.js +1 -0
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/dashboard/page-007278623926490f.js +1 -0
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/documents/[documentUuid]/page-b6ecaf52f6b81ec7.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-f5a351c544ed23d7.js +1 -0
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/proposals/[proposalUuid]/page-3cd46bec9383b191.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-7f87113e5d8bcf6e.js} +1 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/tasks/{page-715b000c156a080c.js → page-30ab1573c4bd466f.js} +1 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/settings/page-b21d4184d9ca0b25.js +1 -0
- package/.next/standalone/.next/static/chunks/app/onboarding/page-3b6c54f887108635.js +1 -0
- package/.next/standalone/.next/static/chunks/{webpack-e181cbbb1e041891.js → webpack-b54e0c78eded76be.js} +1 -1
- package/.next/standalone/.next/static/css/893d99a21153c9b0.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/agents/code-reviewer.md +1 -1
- package/.next/standalone/public/chorus-plugin/agents/proposal-reviewer.md +1 -0
- package/.next/standalone/public/chorus-plugin/agents/task-reviewer.md +2 -0
- package/.next/standalone/public/chorus-plugin/skills/brainstorm/SKILL.md +1 -1
- package/.next/standalone/public/chorus-plugin/skills/chorus/SKILL.md +4 -3
- 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-code-reviewer.json +1 -1
- package/.next/standalone/public/kiro-plugin/.kiro/agents/chorus-proposal-reviewer.json +1 -1
- package/.next/standalone/public/kiro-plugin/.kiro/agents/chorus-task-reviewer.json +1 -1
- 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 +3 -2
- 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 +4 -3
- package/.next/standalone/public/skill/code-reviewer-chorus/SKILL.md +2 -2
- 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 +2 -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 +2 -1
- package/.next/standalone/public/skill/yolo-chorus/SKILL.md +1 -1
- package/README.ja.md +31 -359
- package/README.ko.md +33 -360
- package/README.md +39 -367
- package/README.zh.md +36 -341
- package/cli/claude-spawner.mjs +15 -6
- package/cli/client-args.mjs +8 -0
- package/cli/codex-spawner.mjs +7 -3
- package/cli/control-handler.mjs +13 -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-rest-client.mjs +11 -3
- package/cli/daemon.mjs +274 -11
- package/cli/event-router.mjs +17 -5
- package/cli/login.mjs +90 -2
- package/cli/prompts.mjs +116 -1
- package/cli/turn-reporter.mjs +5 -1
- package/cli/wake-queue.mjs +57 -35
- package/cli/waker.mjs +125 -36
- package/package.json +1 -1
- package/prisma/migrations/20260814101500_add_typed_assignment_provenance/migration.sql +2 -0
- package/prisma/schema.prisma +4 -2
- package/.next/standalone/.next/server/chunks/1114.js +0 -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.69e774e65ffda45f.js +0 -1
- package/.next/standalone/.next/static/chunks/18351-12dc856208d79e10.js +0 -1
- package/.next/standalone/.next/static/chunks/33456.48112aa459fd9c68.js +0 -1
- package/.next/standalone/.next/static/chunks/37938-0b9a2b891c04b166.js +0 -1
- package/.next/standalone/.next/static/chunks/4340-a33120fb742af57e.js +0 -1
- package/.next/standalone/.next/static/chunks/4860.496d21fc6db9e153.js +0 -1
- package/.next/standalone/.next/static/chunks/68326-61feeb2f6cddd338.js +0 -1
- package/.next/standalone/.next/static/chunks/72974-7e63b565a9ef443b.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/94426-39b6da238425f9b7.js +0 -10
- package/.next/standalone/.next/static/chunks/94470-cae3b3ad4e51d2ff.js +0 -1
- package/.next/standalone/.next/static/chunks/94643-ba1ebff5769d2b50.js +0 -1
- package/.next/standalone/.next/static/chunks/99373.5ac319a55a8f99a1.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-ae7c9d32fa1c2532.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-dd5a0d1e50226c78.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/{8kqUZqMF8xgdDXm_I4XdF → YTZwWTfE0BsJnjCDYCEHi}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{8kqUZqMF8xgdDXm_I4XdF → YTZwWTfE0BsJnjCDYCEHi}/_ssgManifest.js +0 -0
package/cli/daemon.mjs
CHANGED
|
@@ -8,6 +8,12 @@
|
|
|
8
8
|
// so a human can `claude --resume <idea-uuid>`); new-vs-resume is decided by
|
|
9
9
|
// probing the on-disk transcript — there is no persisted session-id map.
|
|
10
10
|
//
|
|
11
|
+
// Wake coalescing (add-daemon-wake-coalescing): the WakeQueue is PER-CONNECTION
|
|
12
|
+
// and serializes per DIRECT idea (= per session). Wakes that pile up on the same
|
|
13
|
+
// key while a turn runs are drained together and delivered as ONE batch — a
|
|
14
|
+
// single runBatch → waker.wakeBatch → one `claude --resume` turn — so N
|
|
15
|
+
// same-session queued wakes coalesce into one turn, never N sequential turns.
|
|
16
|
+
//
|
|
11
17
|
// Connection / session / transcript reporting to the server is intentionally
|
|
12
18
|
// NOT done here — the no-op UploadHooks reserve those seams for the derived
|
|
13
19
|
// observability idea.
|
|
@@ -47,7 +53,13 @@ import { createInterruptReporter } from "./interrupt-reporter.mjs";
|
|
|
47
53
|
import { createTurnReporter } from "./turn-reporter.mjs";
|
|
48
54
|
import { createDaemonRestClient } from "./daemon-rest-client.mjs";
|
|
49
55
|
import { createControlHandler } from "./control-handler.mjs";
|
|
50
|
-
import {
|
|
56
|
+
import {
|
|
57
|
+
resolveSigintTimeoutMs,
|
|
58
|
+
resolveDaemonCwds,
|
|
59
|
+
resolveBrowseRoots,
|
|
60
|
+
resolveAgentConfigs,
|
|
61
|
+
hasConfiguredAgents,
|
|
62
|
+
} from "./daemon-config.mjs";
|
|
51
63
|
import { discoverDirectories, validateDirectory } from "./directory-discovery.mjs";
|
|
52
64
|
import {
|
|
53
65
|
startBackground,
|
|
@@ -141,10 +153,7 @@ export function buildDaemon(creds, deps = {}) {
|
|
|
141
153
|
// passed through so the Codex backend can export the daemon key into the woken
|
|
142
154
|
// process env (the Claude backend ignores creds — it gets its key via --mcp-config).
|
|
143
155
|
const spawner = deps.spawner ?? selectSpawner(agentType, { logger, permissionMode, creds });
|
|
144
|
-
|
|
145
|
-
// path-connections: serialization-per-idea still holds, and maxConcurrency caps the
|
|
146
|
-
// whole process's in-flight wakes rather than per-cwd — the right global budget.
|
|
147
|
-
const queue = new WakeQueue({ maxConcurrency: deps.maxConcurrency ?? 4, logger });
|
|
156
|
+
const maxConcurrency = deps.maxConcurrency ?? 4;
|
|
148
157
|
|
|
149
158
|
// ===== Multi-path: the SET of cwds this daemon serves (T3 — FR-5) =====
|
|
150
159
|
// Each declared path becomes one INDEPENDENT connection (own SSE self-report + own
|
|
@@ -332,6 +341,11 @@ export function buildDaemon(creds, deps = {}) {
|
|
|
332
341
|
selectWaker(notification).markQueued(notification, key, attribution),
|
|
333
342
|
wake: (notification, key, attribution) =>
|
|
334
343
|
selectWaker(notification).wake(notification, key, attribution),
|
|
344
|
+
// Coalesced batch (add-daemon-wake-coalescing): every item shares the key → the same
|
|
345
|
+
// session → the same cwd (a session's cwd is pinned), so route the whole batch to the
|
|
346
|
+
// waker selected by the first item's runtimeCwd.
|
|
347
|
+
wakeBatch: (notifications, key, attribution) =>
|
|
348
|
+
selectWaker(notifications[0]).wakeBatch(notifications, key, attribution),
|
|
335
349
|
markInterrupting(entityType, entityUuid) {
|
|
336
350
|
for (const candidate of runtimeWakers.values()) {
|
|
337
351
|
if (candidate.executions.has(`${entityType}:${entityUuid}`)) {
|
|
@@ -345,6 +359,19 @@ export function buildDaemon(creds, deps = {}) {
|
|
|
345
359
|
buildExecutionSnapshot: () =>
|
|
346
360
|
[...runtimeWakers.values()].flatMap((candidate) => candidate.buildExecutionSnapshot()),
|
|
347
361
|
};
|
|
362
|
+
// The WakeQueue serializes per DIRECT idea (keyFor's key) and coalesces same-key pending
|
|
363
|
+
// wakes into one batch (add-daemon-wake-coalescing §C1/§C4). It is PER-CONNECTION so the
|
|
364
|
+
// batch runs on THIS connection's own waker facade — the runBatch drains the per-key data
|
|
365
|
+
// items { notification, attribution } and hands the whole batch to waker.wakeBatch (all
|
|
366
|
+
// items on one key share the session anchor, so items[0].attribution is the batch
|
|
367
|
+
// attribution). maxConcurrency caps this connection's in-flight batches.
|
|
368
|
+
const queue = new WakeQueue({
|
|
369
|
+
maxConcurrency,
|
|
370
|
+
logger,
|
|
371
|
+
runBatch: (key, items) =>
|
|
372
|
+
waker.wakeBatch(items.map((i) => i.notification), key, items[0].attribution),
|
|
373
|
+
});
|
|
374
|
+
|
|
348
375
|
// The router reads THIS connection's own uuid lazily (same source the control handler
|
|
349
376
|
// uses) to suppress a DIRECTED (pinned) wake stamped for a different connection
|
|
350
377
|
// (fix-pinned-wake-directed-delivery, T2). Null until the SSE handshake assigns it — a
|
|
@@ -364,8 +391,20 @@ export function buildDaemon(creds, deps = {}) {
|
|
|
364
391
|
// all scoped to THIS connection's uuid/router/backfill (see the original wiring
|
|
365
392
|
// comments retained on the shared helpers). The control handler verifies a control
|
|
366
393
|
// event against this connection's own connectionUuid before acting.
|
|
367
|
-
const redispatchResume = (
|
|
368
|
-
|
|
394
|
+
const redispatchResume = (
|
|
395
|
+
entityType,
|
|
396
|
+
entityUuid,
|
|
397
|
+
resumeReason,
|
|
398
|
+
runtimeCwd,
|
|
399
|
+
orchestrator,
|
|
400
|
+
) => {
|
|
401
|
+
router.dispatchResume?.({
|
|
402
|
+
entityType,
|
|
403
|
+
entityUuid,
|
|
404
|
+
resumeReason,
|
|
405
|
+
runtimeCwd,
|
|
406
|
+
orchestrator,
|
|
407
|
+
});
|
|
369
408
|
};
|
|
370
409
|
const deliverTurn = (turnUuid) => backfill?.pendingTurnsOnly?.(turnUuid);
|
|
371
410
|
const onControl = createControlHandler({
|
|
@@ -477,6 +516,7 @@ export function buildDaemon(creds, deps = {}) {
|
|
|
477
516
|
connectionState,
|
|
478
517
|
waker,
|
|
479
518
|
runtimeWakers,
|
|
519
|
+
queue,
|
|
480
520
|
router,
|
|
481
521
|
backfill,
|
|
482
522
|
sseListener,
|
|
@@ -495,9 +535,11 @@ export function buildDaemon(creds, deps = {}) {
|
|
|
495
535
|
mcpClient,
|
|
496
536
|
lineage,
|
|
497
537
|
spawner,
|
|
498
|
-
queue,
|
|
499
538
|
// Back-compat single-connection aliases (the common single-path case). The full
|
|
500
|
-
// set is exposed as `connections` for multi-path inspection/tests.
|
|
539
|
+
// set is exposed as `connections` for multi-path inspection/tests. The WakeQueue is
|
|
540
|
+
// now per-connection (add-daemon-wake-coalescing) so its runBatch can run on the right
|
|
541
|
+
// connection's waker facade; the primary connection's queue is aliased here.
|
|
542
|
+
queue: primary.queue,
|
|
501
543
|
waker: primary.waker,
|
|
502
544
|
router: primary.router,
|
|
503
545
|
sseListener: primary.sseListener,
|
|
@@ -520,8 +562,10 @@ export function buildDaemon(creds, deps = {}) {
|
|
|
520
562
|
// and latch the queue (queued-but-unstarted wakes never spawn).
|
|
521
563
|
for (const c of connections) {
|
|
522
564
|
c.sseListener.disconnect?.();
|
|
565
|
+
// Latch each connection's OWN queue (queues are per-connection now — add-daemon-
|
|
566
|
+
// wake-coalescing) so queued-but-unstarted wakes never spawn.
|
|
567
|
+
c.queue?.stop?.();
|
|
523
568
|
}
|
|
524
|
-
queue.stop();
|
|
525
569
|
// 2. Interrupt every in-flight wake subprocess via the shared kill escalation.
|
|
526
570
|
// Each wake's exit path — seeing shuttingDown — reports its turn
|
|
527
571
|
// interrupted(shutdown) and suppresses the execution crash report.
|
|
@@ -532,7 +576,11 @@ export function buildDaemon(creds, deps = {}) {
|
|
|
532
576
|
// the kill escalation window plus a hard 5s cap for the exit path's REST
|
|
533
577
|
// reports. A wake that outlives this does NOT hang the shutdown — its
|
|
534
578
|
// orphaned turn is the server-side offline reconcile's job (the backstop).
|
|
535
|
-
|
|
579
|
+
// Drain every connection's queue in parallel; `drained` is true only if all did.
|
|
580
|
+
const drainResults = await Promise.all(
|
|
581
|
+
connections.map((c) => c.queue?.drain?.(sigintTimeoutMs + 5_000) ?? true),
|
|
582
|
+
);
|
|
583
|
+
const drained = drainResults.every(Boolean);
|
|
536
584
|
if (!drained) {
|
|
537
585
|
logger.warn(
|
|
538
586
|
"[Chorus] shutdown: in-flight wake(s) did not finish within the bound — exiting anyway (server reconcile will finalize their turns)",
|
|
@@ -544,6 +592,122 @@ export function buildDaemon(creds, deps = {}) {
|
|
|
544
592
|
};
|
|
545
593
|
}
|
|
546
594
|
|
|
595
|
+
/**
|
|
596
|
+
* Fan-out builder: compose ONE `buildDaemon` runtime per agent config, so a single
|
|
597
|
+
* daemon process serves N fully-independent agents — each with its own creds,
|
|
598
|
+
* ChorusClient, LineageResolver, spawner (by its `agentType`), WakeQueue (its own
|
|
599
|
+
* `maxConcurrency`), and connections over its OWN cwds. For N=1 this is behaviorally
|
|
600
|
+
* identical to `buildDaemon({url,apiKey}, deps)`.
|
|
601
|
+
*
|
|
602
|
+
* Each agent's runtime is isolated: a build/start failure in one agent is logged and
|
|
603
|
+
* skipped, and the others keep serving. The aggregate `allConflict` settles only when
|
|
604
|
+
* EVERY agent's paths are all already served (nothing left to do at all).
|
|
605
|
+
*
|
|
606
|
+
* Injectable seams mirror `buildDaemon`; array-valued deps (`spawner`, `mcpClient`,
|
|
607
|
+
* `lineage`, `sseListener`, `makeSseListener`) are indexed PER agent for tests.
|
|
608
|
+
*
|
|
609
|
+
* @param {import("./daemon-config.mjs").AgentConfig[]} agentConfigs
|
|
610
|
+
* @param {object} [deps]
|
|
611
|
+
* @returns {{ agents: Array<{cfg: any, daemon: any}>, connections: any[],
|
|
612
|
+
* waker: any, router: any, sseListener: any, allConflict: Promise<void>,
|
|
613
|
+
* start: () => Promise<void>, stop: () => Promise<void> }}
|
|
614
|
+
*/
|
|
615
|
+
export function buildMultiAgentDaemon(agentConfigs, deps = {}) {
|
|
616
|
+
const logger = deps.logger ?? defaultLogger();
|
|
617
|
+
if (!Array.isArray(agentConfigs) || agentConfigs.length === 0) {
|
|
618
|
+
throw new Error("buildMultiAgentDaemon: at least one agent config is required");
|
|
619
|
+
}
|
|
620
|
+
const build = deps.build ?? buildDaemon;
|
|
621
|
+
const perAgent = (key, i) => {
|
|
622
|
+
const v = deps[key];
|
|
623
|
+
return Array.isArray(v) ? v[i] : i === 0 ? v : undefined;
|
|
624
|
+
};
|
|
625
|
+
|
|
626
|
+
const agents = agentConfigs
|
|
627
|
+
.map((cfg, i) => {
|
|
628
|
+
// Per-agent deps: cfg fields drive the per-agent runtime; injectable fakes are
|
|
629
|
+
// indexed per agent. `cwd` (singular) is cleared so a caller's single value can
|
|
630
|
+
// never leak across agents — each agent's `cwds` is authoritative.
|
|
631
|
+
const agentDeps = {
|
|
632
|
+
...deps,
|
|
633
|
+
logger,
|
|
634
|
+
permissionMode: cfg.permissionMode,
|
|
635
|
+
agentType: cfg.agentType,
|
|
636
|
+
cwds: cfg.cwds,
|
|
637
|
+
cwd: undefined,
|
|
638
|
+
maxConcurrency: cfg.maxConcurrency,
|
|
639
|
+
sigintTimeoutMs: cfg.sigintTimeoutMs,
|
|
640
|
+
browseRoots: cfg.browseRoots,
|
|
641
|
+
mcpClient: perAgent("mcpClient", i),
|
|
642
|
+
lineage: perAgent("lineage", i),
|
|
643
|
+
spawner: perAgent("spawner", i),
|
|
644
|
+
sseListener: perAgent("sseListener", i),
|
|
645
|
+
makeSseListener: Array.isArray(deps.makeSseListener)
|
|
646
|
+
? deps.makeSseListener[i]
|
|
647
|
+
: deps.makeSseListener,
|
|
648
|
+
};
|
|
649
|
+
try {
|
|
650
|
+
return { cfg, daemon: build({ url: cfg.url, apiKey: cfg.apiKey }, agentDeps) };
|
|
651
|
+
} catch (err) {
|
|
652
|
+
logger.error?.(
|
|
653
|
+
`[Chorus] agent ${cfg.label}: failed to build runtime — skipping ` +
|
|
654
|
+
`(${err instanceof Error ? err.message : String(err)})`,
|
|
655
|
+
);
|
|
656
|
+
return null;
|
|
657
|
+
}
|
|
658
|
+
})
|
|
659
|
+
.filter(Boolean);
|
|
660
|
+
|
|
661
|
+
if (agents.length === 0) {
|
|
662
|
+
throw new Error("buildMultiAgentDaemon: all agent runtimes failed to build");
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
const connections = agents.flatMap((a) => a.daemon.connections ?? []);
|
|
666
|
+
const primary = agents[0].daemon;
|
|
667
|
+
// Aggregate all-conflict: settles only when EVERY agent's paths are all already
|
|
668
|
+
// served by a live daemon (each agent's allConflict settles only in that case, and
|
|
669
|
+
// never otherwise). A single serving agent keeps the whole daemon alive.
|
|
670
|
+
const allConflict = Promise.all(
|
|
671
|
+
agents.map((a) => a.daemon.allConflict ?? new Promise(() => {})),
|
|
672
|
+
).then(() => {});
|
|
673
|
+
|
|
674
|
+
return {
|
|
675
|
+
agents,
|
|
676
|
+
connections,
|
|
677
|
+
// Back-compat single aliases (first agent's primary connection) for inspection.
|
|
678
|
+
waker: primary.waker,
|
|
679
|
+
router: primary.router,
|
|
680
|
+
sseListener: primary.sseListener,
|
|
681
|
+
allConflict,
|
|
682
|
+
async start() {
|
|
683
|
+
// Start each agent independently; one agent's start failure is logged and
|
|
684
|
+
// isolated so the others still serve.
|
|
685
|
+
for (const a of agents) {
|
|
686
|
+
try {
|
|
687
|
+
await a.daemon.start();
|
|
688
|
+
} catch (err) {
|
|
689
|
+
logger.error?.(
|
|
690
|
+
`[Chorus] agent ${a.cfg.label}: start failed — ` +
|
|
691
|
+
`${err instanceof Error ? err.message : String(err)} (other agents continue)`,
|
|
692
|
+
);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
},
|
|
696
|
+
async stop() {
|
|
697
|
+
for (const a of agents) {
|
|
698
|
+
try {
|
|
699
|
+
await a.daemon.stop();
|
|
700
|
+
} catch (err) {
|
|
701
|
+
logger.warn?.(
|
|
702
|
+
`[Chorus] agent ${a.cfg.label}: stop error — ` +
|
|
703
|
+
`${err instanceof Error ? err.message : String(err)}`,
|
|
704
|
+
);
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
},
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
|
|
547
711
|
/**
|
|
548
712
|
* Entry point for `chorus daemon`. Resolves credentials, validates them
|
|
549
713
|
* (echoing the agent identity), and runs the daemon until terminated.
|
|
@@ -650,6 +814,105 @@ export async function runDaemon(flags = {}, deps = {}) {
|
|
|
650
814
|
const cwds = resolveDaemonCwds({ cwd: flags.cwd }, { env });
|
|
651
815
|
const browseRoots = resolveBrowseRoots({ browseRoot: flags.browseRoot }, { env });
|
|
652
816
|
|
|
817
|
+
// ===== Multi-agent mode (daemon-multi-agent) =====
|
|
818
|
+
// When daemon.json declares a non-empty agents[], run N fully-independent agents in
|
|
819
|
+
// one process. Each agent carries its OWN creds, so this bypasses the flat single-
|
|
820
|
+
// credential preflight (interactive credential completion is a single-agent
|
|
821
|
+
// affordance). Each agent authenticates on its own key; a failure is isolated
|
|
822
|
+
// (logged + that agent skipped) so the rest still serve.
|
|
823
|
+
if (hasConfiguredAgents({ readJson: deps.readJson, loginPath: deps.loginPath })) {
|
|
824
|
+
const buildMulti = deps.buildMulti ?? buildMultiAgentDaemon;
|
|
825
|
+
let agentConfigs;
|
|
826
|
+
try {
|
|
827
|
+
agentConfigs = resolveAgentConfigs(
|
|
828
|
+
{
|
|
829
|
+
url: flags.url,
|
|
830
|
+
apiKey: flags.apiKey,
|
|
831
|
+
agent: flags.agent,
|
|
832
|
+
cwd: flags.cwd,
|
|
833
|
+
browseRoot: flags.browseRoot,
|
|
834
|
+
sigintTimeout: flags.sigintTimeout,
|
|
835
|
+
chorusOnly: flags.chorusOnly,
|
|
836
|
+
yolo: flags.yolo,
|
|
837
|
+
},
|
|
838
|
+
{ env, readJson: deps.readJson, loginPath: deps.loginPath },
|
|
839
|
+
);
|
|
840
|
+
} catch (err) {
|
|
841
|
+
errLog(`[Chorus] ${err instanceof Error ? err.message : String(err)}`);
|
|
842
|
+
return 1;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
// Validate each agent independently. A validation failure logs + skips that agent
|
|
846
|
+
// (isolation) — the daemon still serves the agents that authenticated.
|
|
847
|
+
const okConfigs = [];
|
|
848
|
+
for (const cfg of agentConfigs) {
|
|
849
|
+
try {
|
|
850
|
+
const id = await validate({ url: cfg.url, apiKey: cfg.apiKey });
|
|
851
|
+
okConfigs.push(cfg);
|
|
852
|
+
log(
|
|
853
|
+
`[Chorus] agent ${cfg.label}: ${id.name} (${id.uuid}) — ${cfg.agentType}, ` +
|
|
854
|
+
`${cfg.permissionMode}, ${cfg.cwds.length} path(s), maxConcurrency=${cfg.maxConcurrency}`,
|
|
855
|
+
);
|
|
856
|
+
if (cfg.permissionMode === "yolo") errLog(`[Chorus] agent ${cfg.label}: ${yoloWarningLine()}`);
|
|
857
|
+
} catch (err) {
|
|
858
|
+
errLog(
|
|
859
|
+
`[Chorus] agent ${cfg.label}: credential validation failed — ` +
|
|
860
|
+
`${err instanceof Error ? err.message : String(err)} (skipping this agent)`,
|
|
861
|
+
);
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
if (okConfigs.length === 0) {
|
|
865
|
+
errLog(
|
|
866
|
+
`[Chorus] no agents authenticated — nothing to serve. Check the apiKeys in ${loginFilePath()}.`,
|
|
867
|
+
);
|
|
868
|
+
return 1;
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
const totalPaths = okConfigs.reduce((n, c) => n + c.cwds.length, 0);
|
|
872
|
+
log(
|
|
873
|
+
`[Chorus] multi-agent daemon starting — ${okConfigs.length} agent(s), ` +
|
|
874
|
+
`${totalPaths} connection(s), subscribing to ${okConfigs[0].url}/api/events/notifications`,
|
|
875
|
+
);
|
|
876
|
+
const multiDaemon = buildMulti(okConfigs, {
|
|
877
|
+
logger: { info: log, warn: errLog, error: errLog },
|
|
878
|
+
verbose,
|
|
879
|
+
fetchImpl: deps.fetchImpl,
|
|
880
|
+
killer: deps.killer,
|
|
881
|
+
sseListener: deps.sseListener,
|
|
882
|
+
makeSseListener: deps.makeSseListener,
|
|
883
|
+
spawner: deps.spawner,
|
|
884
|
+
mcpClient: deps.mcpClient,
|
|
885
|
+
lineage: deps.lineage,
|
|
886
|
+
build: deps.build,
|
|
887
|
+
});
|
|
888
|
+
|
|
889
|
+
const shutdownMulti = () => {
|
|
890
|
+
log("[Chorus] shutting down daemon...");
|
|
891
|
+
Promise.resolve(multiDaemon.stop()).finally(() => process.exit(0));
|
|
892
|
+
};
|
|
893
|
+
process.on("SIGINT", shutdownMulti);
|
|
894
|
+
process.on("SIGTERM", shutdownMulti);
|
|
895
|
+
await multiDaemon.start();
|
|
896
|
+
log("[Chorus] multi-agent daemon running. Waiting for task dispatches (Ctrl+C to stop).");
|
|
897
|
+
|
|
898
|
+
const ALL_CONFLICT_M = Symbol("all-conflict");
|
|
899
|
+
const waitForeverM = deps.waitForever ?? (() => new Promise(() => {}));
|
|
900
|
+
const allConflictSignalM = multiDaemon.allConflict ?? new Promise(() => {});
|
|
901
|
+
const outcomeM = await Promise.race([
|
|
902
|
+
waitForeverM().then(() => 0),
|
|
903
|
+
allConflictSignalM.then(() => ALL_CONFLICT_M),
|
|
904
|
+
]);
|
|
905
|
+
if (outcomeM === ALL_CONFLICT_M) {
|
|
906
|
+
errLog(
|
|
907
|
+
`[Chorus] every declared path for every agent is already served by a live daemon — ` +
|
|
908
|
+
`nothing to do. Stop the other daemon(s) or remove the conflicting path(s), then restart.`,
|
|
909
|
+
);
|
|
910
|
+
await multiDaemon.stop();
|
|
911
|
+
return 1;
|
|
912
|
+
}
|
|
913
|
+
return 0;
|
|
914
|
+
}
|
|
915
|
+
|
|
653
916
|
// Foreground preflight: resolve/complete credentials + resolve the permission
|
|
654
917
|
// posture (confirming yolo on a TTY). Reuses the same pfDeps bundle the detach
|
|
655
918
|
// path uses. Returns a numeric exit code on failure, or
|
package/cli/event-router.mjs
CHANGED
|
@@ -37,8 +37,8 @@ export class EventRouter {
|
|
|
37
37
|
/**
|
|
38
38
|
* @param {{
|
|
39
39
|
* mcpClient: { callTool: (name: string, args?: Record<string, unknown>) => Promise<any> },
|
|
40
|
-
* waker: { keyFor: (n: any) => Promise<{ key: string, rootIdeaUuid: string|null, directIdeaUuid: string|null }>,
|
|
41
|
-
* queue: { enqueue: (key: string,
|
|
40
|
+
* waker: { keyFor: (n: any) => Promise<{ key: string, rootIdeaUuid: string|null, directIdeaUuid: string|null }>, wakeBatch: (ns: any[], key: string, attribution?: any) => Promise<void>, markQueued?: (n: any, key: string, attribution?: any) => void },
|
|
41
|
+
* queue: { enqueue: (key: string, item: { notification: any, attribution: any }) => void },
|
|
42
42
|
* wakeActions: Set<string>,
|
|
43
43
|
* getConnectionUuid?: () => (string|null), This daemon's registered connection uuid
|
|
44
44
|
* (null until the SSE handshake reports it).
|
|
@@ -228,7 +228,8 @@ export class EventRouter {
|
|
|
228
228
|
* reason ("user" | "crash") threaded from the control event; it is stamped on the
|
|
229
229
|
* synthetic notification as `resumedFrom` so the prompt builder can state a crash
|
|
230
230
|
* explicitly. Absent/unknown → not stamped → the user-resume prompt.
|
|
231
|
-
* @param {{ entityType?: string, entityUuid?: string, resumeReason?: string
|
|
231
|
+
* @param {{ entityType?: string, entityUuid?: string, resumeReason?: string,
|
|
232
|
+
* orchestrator?: { type?: string, uuid?: string, name?: string } | null }} target
|
|
232
233
|
*/
|
|
233
234
|
dispatchResume(target) {
|
|
234
235
|
const entityType = target?.entityType;
|
|
@@ -247,6 +248,11 @@ export class EventRouter {
|
|
|
247
248
|
entityUuid,
|
|
248
249
|
...(resumedFrom ? { resumedFrom } : {}),
|
|
249
250
|
...(typeof target?.runtimeCwd === "string" ? { runtimeCwd: target.runtimeCwd } : {}),
|
|
251
|
+
...(target?.orchestrator?.type === "agent" &&
|
|
252
|
+
typeof target.orchestrator.uuid === "string" &&
|
|
253
|
+
typeof target.orchestrator.name === "string"
|
|
254
|
+
? { orchestrator: target.orchestrator }
|
|
255
|
+
: {}),
|
|
250
256
|
};
|
|
251
257
|
this.#resolveAndEnqueue(n, `resume:${entityType}:${entityUuid}`).catch((err) => {
|
|
252
258
|
this.logger.error(`[Chorus] failed to dispatch resume for ${entityType}:${entityUuid}: ${err}`);
|
|
@@ -383,7 +389,10 @@ export class EventRouter {
|
|
|
383
389
|
} catch (err) {
|
|
384
390
|
this.logger.warn(`[Chorus] markQueued failed for pending turn ${turnUuid}: ${err}`);
|
|
385
391
|
}
|
|
386
|
-
|
|
392
|
+
// Enqueue an opaque DATA payload (add-daemon-wake-coalescing §C4), NOT a thunk: the
|
|
393
|
+
// queue coalesces all same-key pending items and hands the whole batch to its runBatch
|
|
394
|
+
// (wired to waker.wakeBatch in daemon.mjs). markQueued was already called per-item above.
|
|
395
|
+
this.queue.enqueue(key, { notification: n, attribution });
|
|
387
396
|
}
|
|
388
397
|
|
|
389
398
|
/**
|
|
@@ -531,6 +540,9 @@ export class EventRouter {
|
|
|
531
540
|
} catch (err) {
|
|
532
541
|
this.logger.warn(`[Chorus] markQueued failed for ${label}: ${err}`);
|
|
533
542
|
}
|
|
534
|
-
|
|
543
|
+
// Enqueue an opaque DATA payload (add-daemon-wake-coalescing §C4), NOT a thunk: the
|
|
544
|
+
// queue coalesces all same-key pending items and hands the whole batch to its runBatch
|
|
545
|
+
// (wired to waker.wakeBatch in daemon.mjs). markQueued was already called per-item above.
|
|
546
|
+
this.queue.enqueue(key, { notification: n, attribution });
|
|
535
547
|
}
|
|
536
548
|
}
|
package/cli/login.mjs
CHANGED
|
@@ -144,15 +144,86 @@ export function recordYoloAck(yoloAckAt, deps = {}) {
|
|
|
144
144
|
return updateDaemonConfig({ yoloAckAt }, deps);
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
+
/** A non-empty trimmed string, or undefined. */
|
|
148
|
+
function nonEmpty(value) {
|
|
149
|
+
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Append a new agent to `~/.chorus/daemon.json`'s `agents[]` (daemon-multi-agent),
|
|
154
|
+
* via the same field-merge writer, WITHOUT overwriting any existing agent.
|
|
155
|
+
*
|
|
156
|
+
* Migration rule: if the file is still a flat single-agent config (top-level
|
|
157
|
+
* `apiKey`, no `agents[]`), the flat fields are first folded into `agents[0]` so
|
|
158
|
+
* the newly added key becomes `agents[1]` — the result is unambiguous (once
|
|
159
|
+
* `agents[]` exists, the flat top-level fields serve only as defaults, never as a
|
|
160
|
+
* standalone agent). Duplicate protection: if the new `apiKey` already matches an
|
|
161
|
+
* existing agent (or the pre-migration flat key), nothing is written.
|
|
162
|
+
*
|
|
163
|
+
* @param {{ url?: string, apiKey: string, agentType?: string, agentUuid?: string, agentName?: string }} agentObj
|
|
164
|
+
* @param {{ path?: string, read?: (p: string) => string, write?: (p: string, c: string, o: object) => void, mkdir?: (p: string, o: object) => void, rename?: (from: string, to: string) => void }} [deps]
|
|
165
|
+
* @returns {{ ok: true, path: string, agents: object[], index: number } | { ok: false, reason: "duplicate" }}
|
|
166
|
+
*/
|
|
167
|
+
export function appendAgentConfig(agentObj, deps = {}) {
|
|
168
|
+
const path = deps.path ?? loginFilePath();
|
|
169
|
+
const read = deps.read ?? ((p) => readFileSync(p, "utf8"));
|
|
170
|
+
|
|
171
|
+
let current = {};
|
|
172
|
+
try {
|
|
173
|
+
const parsed = JSON.parse(read(path));
|
|
174
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) current = parsed;
|
|
175
|
+
} catch {
|
|
176
|
+
// treat as empty
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const existingAgents =
|
|
180
|
+
Array.isArray(current.agents) ? current.agents.filter((a) => a && typeof a === "object") : [];
|
|
181
|
+
|
|
182
|
+
/** @type {object[]} */
|
|
183
|
+
let agents;
|
|
184
|
+
if (existingAgents.length > 0) {
|
|
185
|
+
agents = existingAgents.slice();
|
|
186
|
+
} else if (nonEmpty(current.apiKey)) {
|
|
187
|
+
// Migrate the flat single-agent config into agents[0] so the new key is agents[1].
|
|
188
|
+
const flat = { apiKey: current.apiKey };
|
|
189
|
+
if (nonEmpty(current.url)) flat.url = current.url;
|
|
190
|
+
if (nonEmpty(current.agent)) flat.agentType = current.agent;
|
|
191
|
+
if (Array.isArray(current.cwds)) flat.cwds = current.cwds;
|
|
192
|
+
if (nonEmpty(current.agentName)) flat.agentName = current.agentName;
|
|
193
|
+
if (nonEmpty(current.agentUuid)) flat.agentUuid = current.agentUuid;
|
|
194
|
+
agents = [flat];
|
|
195
|
+
} else {
|
|
196
|
+
agents = [];
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Never add a duplicate: refuse if this apiKey already backs an agent (checking
|
|
200
|
+
// both the agents[] entries and any pre-migration flat top-level key).
|
|
201
|
+
const existingKeys = new Set(agents.map((a) => a.apiKey).filter(Boolean));
|
|
202
|
+
if (nonEmpty(current.apiKey)) existingKeys.add(current.apiKey);
|
|
203
|
+
if (existingKeys.has(agentObj.apiKey)) {
|
|
204
|
+
return { ok: false, reason: "duplicate" };
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
agents.push(agentObj);
|
|
208
|
+
const writtenPath = updateDaemonConfig({ agents }, deps);
|
|
209
|
+
return { ok: true, path: writtenPath, agents, index: agents.length - 1 };
|
|
210
|
+
}
|
|
211
|
+
|
|
147
212
|
/**
|
|
148
213
|
* Run the login flow: collect url + key (flags or interactive), validate
|
|
149
214
|
* against the server, and on success persist + echo identity. Returns an exit
|
|
150
215
|
* code (0 success, non-zero failure). Never throws.
|
|
151
216
|
*
|
|
152
|
-
*
|
|
217
|
+
* With `flags.add`, the validated key is APPENDED as an additional agent
|
|
218
|
+
* (daemon-multi-agent) via {@link appendAgentConfig} instead of overwriting the
|
|
219
|
+
* single flat credential — so one daemon can serve several agents. On an invalid
|
|
220
|
+
* key, or a duplicate, nothing is written.
|
|
221
|
+
*
|
|
222
|
+
* @param {{ url?: string, apiKey?: string, agent?: string, add?: boolean }} flags
|
|
153
223
|
* @param {{
|
|
154
224
|
* validate?: typeof validateAndFetchIdentity,
|
|
155
225
|
* write?: typeof writeLoginFile,
|
|
226
|
+
* appendAgent?: typeof appendAgentConfig,
|
|
156
227
|
* prompt?: typeof prompt,
|
|
157
228
|
* log?: (m: string) => void,
|
|
158
229
|
* errLog?: (m: string) => void,
|
|
@@ -162,6 +233,7 @@ export function recordYoloAck(yoloAckAt, deps = {}) {
|
|
|
162
233
|
export async function runLogin(flags = {}, deps = {}) {
|
|
163
234
|
const validate = deps.validate ?? validateAndFetchIdentity;
|
|
164
235
|
const write = deps.write ?? writeLoginFile;
|
|
236
|
+
const appendAgent = deps.appendAgent ?? appendAgentConfig;
|
|
165
237
|
const ask = deps.prompt ?? prompt;
|
|
166
238
|
const log = deps.log ?? ((m) => process.stdout.write(m + "\n"));
|
|
167
239
|
const errLog = deps.errLog ?? ((m) => process.stderr.write(m + "\n"));
|
|
@@ -183,10 +255,26 @@ export async function runLogin(flags = {}, deps = {}) {
|
|
|
183
255
|
} catch (err) {
|
|
184
256
|
const msg = err instanceof Error ? err.message : String(err);
|
|
185
257
|
errLog(`Login failed: ${msg}`);
|
|
186
|
-
errLog("Credentials were NOT saved.");
|
|
258
|
+
errLog(flags.add ? "No agent was added." : "Credentials were NOT saved.");
|
|
187
259
|
return 1;
|
|
188
260
|
}
|
|
189
261
|
|
|
262
|
+
// --add: append as an additional agent (multi-agent) instead of overwriting.
|
|
263
|
+
if (flags.add) {
|
|
264
|
+
const agentObj = { url, apiKey, agentUuid: identity.uuid, agentName: identity.name };
|
|
265
|
+
if (nonEmpty(flags.agent)) agentObj.agentType = nonEmpty(flags.agent);
|
|
266
|
+
const res = appendAgent(agentObj);
|
|
267
|
+
if (!res.ok) {
|
|
268
|
+
errLog(
|
|
269
|
+
`Agent ${identity.name} (${identity.uuid}) is already configured (same API key) — nothing changed.`,
|
|
270
|
+
);
|
|
271
|
+
return 1;
|
|
272
|
+
}
|
|
273
|
+
log(`Added agent ${identity.name} (${identity.uuid}) as agents[${res.index}] in ${res.path}.`);
|
|
274
|
+
log(`This daemon now serves ${res.agents.length} agent(s).`);
|
|
275
|
+
return 0;
|
|
276
|
+
}
|
|
277
|
+
|
|
190
278
|
const path = write({ url, apiKey, agentUuid: identity.uuid, agentName: identity.name });
|
|
191
279
|
log(`Logged in as ${identity.name} (${identity.uuid}).`);
|
|
192
280
|
log(`Credentials saved to ${path}.`);
|