@chorus-aidlc/chorus 0.17.3 → 0.18.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 +345 -341
- package/.next/standalone/.next/app-path-routes-manifest.json +35 -35
- package/.next/standalone/.next/build-manifest.json +5 -5
- package/.next/standalone/.next/prerender-manifest.json +27 -27
- 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.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_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_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.js.nft.json +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.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 +1 -1
- 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 +35 -35
- package/.next/standalone/.next/server/chunks/1318.js +1 -1
- package/.next/standalone/.next/server/chunks/{5201.js → 1416.js} +2 -2
- package/.next/standalone/.next/server/chunks/1559.js +2 -2
- package/.next/standalone/.next/server/chunks/{3630.js → 2195.js} +1 -1
- package/.next/standalone/.next/server/chunks/2460.js +1 -0
- package/.next/standalone/.next/server/chunks/2572.js +2 -2
- package/.next/standalone/.next/server/chunks/2758.js +1 -0
- package/.next/standalone/.next/server/chunks/2961.js +1 -1
- package/.next/standalone/.next/server/chunks/3419.js +1 -1
- package/.next/standalone/.next/server/chunks/4066.js +1 -0
- package/.next/standalone/.next/server/chunks/4827.js +1 -1
- package/.next/standalone/.next/server/chunks/5245.js +1 -1
- package/.next/standalone/.next/server/chunks/5453.js +1 -1
- package/.next/standalone/.next/server/chunks/5489.js +1 -1
- package/.next/standalone/.next/server/chunks/6113.js +1 -1
- package/.next/standalone/.next/server/chunks/6506.js +2 -2
- package/.next/standalone/.next/server/chunks/6737.js +1 -0
- package/.next/standalone/.next/server/chunks/679.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/7578.js +2 -2
- package/.next/standalone/.next/server/chunks/7675.js +1 -0
- package/.next/standalone/.next/server/chunks/7789.js +1 -0
- package/.next/standalone/.next/server/chunks/{1201.js → 8030.js} +2 -2
- 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/9931.js +1 -1
- package/.next/standalone/.next/server/instrumentation.js +1 -1
- 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.f080a1d100972212.js +1 -0
- package/.next/standalone/.next/static/chunks/14628-283d3983d1fb36c9.js +1 -0
- package/.next/standalone/.next/static/chunks/{29305-f587e7e81bc0b200.js → 17562-56f932146e9e6c94.js} +4 -4
- package/.next/standalone/.next/static/chunks/25080-25ad29e64c855338.js +1 -0
- package/.next/standalone/.next/static/chunks/28698-7fb271ffc6e63a26.js +1 -0
- package/.next/standalone/.next/static/chunks/{95225-96b44da3ebd6ddad.js → 32736-aeaaa1e4c4d5529b.js} +1 -1
- package/.next/standalone/.next/static/chunks/33456.20313bd67a5c41cc.js +1 -0
- package/.next/standalone/.next/static/chunks/4860.3b555a398cdffb19.js +1 -0
- package/.next/standalone/.next/static/chunks/75257-99c0ce24b436847b.js +1 -0
- package/.next/standalone/.next/static/chunks/79919-0c6dcda1dd8646f0.js +1 -0
- package/.next/standalone/.next/static/chunks/91328-f501e3c3ca519a92.js +1 -0
- package/.next/standalone/.next/static/chunks/94643-e54eff17e941a93b.js +1 -0
- package/.next/standalone/.next/static/chunks/99373.b8a95d1bec5ad4e7.js +1 -0
- package/.next/standalone/.next/static/chunks/app/(dashboard)/layout-f3c6431432d42c7c.js +1 -0
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/dashboard/{page-77b175e52a85f3cb.js → page-5d723f974bdad33b.js} +1 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/documents/[documentUuid]/page-8d3b1f4d8b76d66c.js +1 -0
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/documents/page-57c698dea2fa6e29.js +1 -0
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/graph/{page-69d3162667f85677.js → page-d2bb622855e746f1.js} +1 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/proposals/[proposalUuid]/page-fc255dc3612032b9.js +1 -0
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/proposals/new/{page-a3f83031dfbafc81.js → page-f032ee8a80d1f56a.js} +1 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/proposals/page-46a0ddfd0421b0a8.js +1 -0
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/tasks/[taskUuid]/{page-3c7ff3a40a4615ac.js → page-3a83748ce0ae1c4f.js} +1 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/tasks/{page-7b8e11fdc5b596d0.js → page-8af9bb9f96ab0258.js} +1 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/settings/page-b02939820affdae5.js +1 -0
- package/.next/standalone/.next/static/chunks/app/onboarding/page-d2c0c7951114e763.js +1 -0
- package/.next/standalone/.next/static/chunks/{webpack-dffb97a4feb8faba.js → webpack-de8a36d232a91d6b.js} +1 -1
- package/.next/standalone/.next/static/css/44f13b43a3de716d.css +1 -0
- package/.next/standalone/package.json +1 -1
- package/.next/standalone/public/chorus-plugin/.claude-plugin/plugin.json +2 -2
- package/.next/standalone/public/chorus-plugin/agents/code-reviewer.md +1 -0
- package/.next/standalone/public/chorus-plugin/agents/proposal-reviewer.md +12 -3
- package/.next/standalone/public/chorus-plugin/agents/task-reviewer.md +4 -0
- package/.next/standalone/public/chorus-plugin/bin/chorus-api.sh +1 -1
- package/.next/standalone/public/chorus-plugin/bin/on-post-submit-for-verify.sh +3 -3
- package/.next/standalone/public/chorus-plugin/bin/on-post-submit-proposal.sh +3 -3
- package/.next/standalone/public/chorus-plugin/bin/on-post-verify-task.sh +2 -2
- package/.next/standalone/public/chorus-plugin/bin/on-pre-spawn-agent.sh +22 -9
- package/.next/standalone/public/chorus-plugin/bin/on-session-start.sh +39 -64
- package/.next/standalone/public/chorus-plugin/bin/on-subagent-start.sh +44 -29
- package/.next/standalone/public/chorus-plugin/bin/on-subagent-stop.sh +100 -29
- package/.next/standalone/public/chorus-plugin/bin/resolve-spec-mode.sh +107 -0
- package/.next/standalone/public/chorus-plugin/bin/test-syntax.sh +6 -2
- package/.next/standalone/public/chorus-plugin/bin/tests/test-resolver-drift.sh +46 -0
- package/.next/standalone/public/chorus-plugin/bin/tests/test-skill-harness-fidelity-negative.sh +328 -0
- package/.next/standalone/public/chorus-plugin/bin/tests/test-skill-harness-fidelity.sh +372 -0
- package/.next/standalone/public/chorus-plugin/bin/tests/test-spec-mode-resolution.sh +83 -0
- package/.next/standalone/public/chorus-plugin/bin/tests/test-subagent-session-name.sh +599 -0
- package/.next/standalone/public/chorus-plugin/skills/brainstorm/SKILL.md +1 -1
- package/.next/standalone/public/chorus-plugin/skills/chorus/SKILL.md +11 -6
- package/.next/standalone/public/chorus-plugin/skills/chorus-cli/SKILL.md +1 -1
- package/.next/standalone/public/chorus-plugin/skills/develop/SKILL.md +14 -9
- package/.next/standalone/public/chorus-plugin/skills/docs/SKILL.md +1 -1
- package/.next/standalone/public/chorus-plugin/skills/idea/SKILL.md +1 -1
- package/.next/standalone/public/chorus-plugin/skills/openspec-aware/SKILL.md +27 -31
- package/.next/standalone/public/chorus-plugin/skills/orchestrate/SKILL.md +11 -1
- package/.next/standalone/public/chorus-plugin/skills/proposal/SKILL.md +14 -7
- package/.next/standalone/public/chorus-plugin/skills/quick-dev/SKILL.md +6 -4
- package/.next/standalone/public/chorus-plugin/skills/review/SKILL.md +10 -8
- package/.next/standalone/public/chorus-plugin/skills/spec-lite/SKILL.md +147 -0
- package/.next/standalone/public/chorus-plugin/skills/yolo/SKILL.md +49 -34
- 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 +2 -1
- package/.next/standalone/public/kiro-plugin/.kiro/agents/chorus-task-reviewer.json +1 -1
- package/.next/standalone/public/kiro-plugin/.kiro/agents/chorus.md +1 -1
- package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-brainstorm/SKILL.md +1 -1
- package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-cli/SKILL.md +1 -1
- package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-develop/SKILL.md +9 -7
- package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-docs/SKILL.md +1 -1
- 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 +35 -27
- package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-orchestrate/SKILL.md +9 -1
- package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-proposal/SKILL.md +14 -7
- package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-quick-dev/SKILL.md +2 -2
- package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-review/SKILL.md +8 -8
- package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-spec-lite/SKILL.md +147 -0
- package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-yolo/SKILL.md +39 -25
- package/.next/standalone/public/kiro-plugin/.kiro/steering/chorus.md +11 -6
- package/.next/standalone/public/kiro-plugin/bin/chorus-api.sh +1 -1
- package/.next/standalone/public/kiro-plugin/bin/on-agent-spawn.sh +41 -0
- package/.next/standalone/public/kiro-plugin/bin/on-post-submit-for-verify.sh +3 -3
- package/.next/standalone/public/kiro-plugin/bin/on-post-submit-proposal.sh +3 -3
- package/.next/standalone/public/kiro-plugin/bin/on-post-verify-task.sh +2 -2
- package/.next/standalone/public/kiro-plugin/bin/resolve-spec-mode.sh +107 -0
- package/.next/standalone/public/kiro-plugin/manifest.txt +2 -0
- package/.next/standalone/public/skill/chorus/SKILL.md +11 -1
- package/.next/standalone/public/skill/code-reviewer-chorus/SKILL.md +1 -0
- package/.next/standalone/public/skill/develop-chorus/SKILL.md +1 -1
- package/.next/standalone/public/skill/orchestrate-chorus/SKILL.md +11 -1
- package/.next/standalone/public/skill/proposal-reviewer-chorus/SKILL.md +5 -2
- package/.next/standalone/public/skill/quick-dev-chorus/SKILL.md +1 -1
- package/.next/standalone/public/skill/review-chorus/SKILL.md +5 -3
- package/.next/standalone/public/skill/task-reviewer-chorus/SKILL.md +4 -0
- package/.next/standalone/public/skill/yolo-chorus/SKILL.md +23 -7
- package/README.ja.md +3 -3
- package/README.ko.md +3 -3
- package/README.md +3 -3
- package/README.zh.md +3 -3
- package/chorus.mjs +30 -2
- package/cli/agent-cli-config.mjs +323 -0
- package/cli/agent-launcher.mjs +44 -16
- package/cli/child-exit.mjs +77 -0
- package/cli/claude-spawner.mjs +26 -14
- package/cli/codex-spawner.mjs +27 -16
- package/cli/control-handler.mjs +104 -6
- package/cli/credentials.mjs +7 -0
- package/cli/daemon-config.mjs +14 -0
- package/cli/daemon-rest-client.mjs +98 -29
- package/cli/daemon.mjs +37 -7
- package/cli/dsh-managed-config.mjs +26 -28
- package/cli/dsh-spawner.mjs +27 -16
- package/cli/init/steps/credential-seed.mjs +1 -1
- package/cli/kiro-spawner.mjs +26 -16
- package/cli/launch-diagnostics.mjs +67 -0
- package/cli/login.mjs +17 -1
- package/cli/pi-spawner.mjs +23 -13
- package/cli/prompts.mjs +52 -2
- package/cli/spawner-select.mjs +6 -11
- package/package.json +1 -1
- package/.next/standalone/.next/server/chunks/1114.js +0 -1
- package/.next/standalone/.next/server/chunks/1155.js +0 -1
- package/.next/standalone/.next/server/chunks/6465.js +0 -1
- package/.next/standalone/.next/server/chunks/8105.js +0 -1
- package/.next/standalone/.next/server/chunks/8232.js +0 -1
- package/.next/standalone/.next/static/chunks/11595.f7c3ef5cd7fc8feb.js +0 -1
- package/.next/standalone/.next/static/chunks/33456.c81079032acc2966.js +0 -1
- package/.next/standalone/.next/static/chunks/45262-38b332523f00a223.js +0 -1
- package/.next/standalone/.next/static/chunks/46021-f5d072b0cbcb7fac.js +0 -1
- package/.next/standalone/.next/static/chunks/4860.f0cfb1201191ae88.js +0 -1
- package/.next/standalone/.next/static/chunks/66609-64a01d5cb415465b.js +0 -1
- package/.next/standalone/.next/static/chunks/79919-c5a2a3fd8f5f9204.js +0 -1
- package/.next/standalone/.next/static/chunks/94394-38194b81b489275c.js +0 -1
- package/.next/standalone/.next/static/chunks/94643-f1bdf37fb3bb6adb.js +0 -1
- package/.next/standalone/.next/static/chunks/96482-2b3bdb2544d72e5a.js +0 -1
- package/.next/standalone/.next/static/chunks/99373.3c23ac2efbd4db02.js +0 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/layout-66328332f62c7371.js +0 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/documents/[documentUuid]/page-87ceae13c4950fc9.js +0 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/documents/page-45e95154e546460e.js +0 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/proposals/[proposalUuid]/page-b7b2017e5be69564.js +0 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/proposals/page-8b06834ca0f663bb.js +0 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/settings/page-efe5326c47aca9ca.js +0 -1
- package/.next/standalone/.next/static/chunks/app/onboarding/page-0ce33b9327fe3d8c.js +0 -1
- package/.next/standalone/.next/static/css/1d9cf83f50b6db00.css +0 -1
- /package/.next/standalone/.next/static/{wuqYN129vOIGymh_NEdZe → dot63ILT878Tloqi7Czj_}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{wuqYN129vOIGymh_NEdZe → dot63ILT878Tloqi7Czj_}/_ssgManifest.js +0 -0
package/cli/codex-spawner.mjs
CHANGED
|
@@ -27,10 +27,13 @@
|
|
|
27
27
|
// stream parse) and the PATH-walk shape of resolveClaudePath.
|
|
28
28
|
|
|
29
29
|
import { spawn } from "node:child_process";
|
|
30
|
+
import { safeSpawnError } from "./launch-diagnostics.mjs";
|
|
31
|
+
import { validateAgentCliConfig, overlayAgentEnv, getAgentEnv, assertConfiguredShimArgs } from "./agent-cli-config.mjs";
|
|
30
32
|
import { readFileSync, statSync } from "node:fs";
|
|
31
33
|
import { homedir } from "node:os";
|
|
32
34
|
import { join, win32 as pathWin32, posix as pathPosix } from "node:path";
|
|
33
35
|
import { parseNdjsonChunk } from "./claude-spawner.mjs";
|
|
36
|
+
import { awaitChildSettled } from "./child-exit.mjs";
|
|
34
37
|
import { getThreadId as defaultGetThreadId, setThreadId as defaultSetThreadId } from "./codex-session-map.mjs";
|
|
35
38
|
import {
|
|
36
39
|
getCodexUsageSnapshot as defaultGetUsageSnapshot,
|
|
@@ -49,8 +52,9 @@ const NOOP_LOGGER = { info() {}, warn() {}, error() {} };
|
|
|
49
52
|
export function hasChorusMcpServer(deps = {}) {
|
|
50
53
|
const env = deps.env ?? process.env;
|
|
51
54
|
const readFile = deps.readFile ?? readFileSync;
|
|
52
|
-
const
|
|
53
|
-
const
|
|
55
|
+
const platform = deps.platform ?? process.platform;
|
|
56
|
+
const home = deps.home ?? getAgentEnv(env, "HOME", platform) ?? getAgentEnv(env, "USERPROFILE", platform) ?? homedir();
|
|
57
|
+
const configPath = join(getAgentEnv(env, "CODEX_HOME", platform) || join(home, ".codex"), "config.toml");
|
|
54
58
|
try {
|
|
55
59
|
const config = readFile(configPath, "utf8");
|
|
56
60
|
return /^\s*\[mcp_servers\.chorus\]\s*(?:#.*)?$/m.test(config);
|
|
@@ -148,14 +152,15 @@ export function resolveCodexPath(deps = {}) {
|
|
|
148
152
|
}
|
|
149
153
|
});
|
|
150
154
|
|
|
151
|
-
|
|
152
|
-
|
|
155
|
+
const override = getAgentEnv(env, "CHORUS_CODEX_PATH", platform);
|
|
156
|
+
if (override && isFile(override)) {
|
|
157
|
+
return override;
|
|
153
158
|
}
|
|
154
159
|
|
|
155
160
|
const isWin = platform === "win32";
|
|
156
161
|
const p = isWin ? pathWin32 : pathPosix;
|
|
157
162
|
const names = isWin ? ["codex.cmd", "codex.exe", "codex"] : ["codex"];
|
|
158
|
-
const pathVar = env
|
|
163
|
+
const pathVar = getAgentEnv(env, "PATH", platform) || env.Path || "";
|
|
159
164
|
const dirs = pathVar.split(p.delimiter).filter(Boolean);
|
|
160
165
|
for (const dir of dirs) {
|
|
161
166
|
for (const name of names) {
|
|
@@ -178,7 +183,7 @@ export function resolveSpawnCommand(codexPath, args, platform = process.platform
|
|
|
178
183
|
const isWin = platform === "win32";
|
|
179
184
|
const lower = codexPath.toLowerCase();
|
|
180
185
|
if (isWin && (lower.endsWith(".cmd") || lower.endsWith(".bat"))) {
|
|
181
|
-
const comspec = env
|
|
186
|
+
const comspec = getAgentEnv(env, "COMSPEC", platform) || "cmd.exe";
|
|
182
187
|
return { command: comspec, argv: ["/d", "/s", "/c", codexPath, ...args] };
|
|
183
188
|
}
|
|
184
189
|
return { command: codexPath, argv: args };
|
|
@@ -210,6 +215,8 @@ export class CodexSpawner {
|
|
|
210
215
|
this.permissionMode = opts.permissionMode ?? "chorus";
|
|
211
216
|
this.creds = opts.creds ?? null;
|
|
212
217
|
this.platform = opts.platform ?? process.platform;
|
|
218
|
+
this.cliConfig = validateAgentCliConfig(opts.cliConfig, "codex", opts.label);
|
|
219
|
+
this.env = overlayAgentEnv(opts.env ?? process.env, this.cliConfig.env, this.platform);
|
|
213
220
|
this.getThreadIdFn = opts.getThreadIdFn ?? defaultGetThreadId;
|
|
214
221
|
this.setThreadIdFn = opts.setThreadIdFn ?? defaultSetThreadId;
|
|
215
222
|
this.getUsageSnapshotFn = opts.getUsageSnapshotFn ?? defaultGetUsageSnapshot;
|
|
@@ -246,7 +253,7 @@ export class CodexSpawner {
|
|
|
246
253
|
// instead of publishing the entire historical cumulative total.
|
|
247
254
|
let needsUsageSeed = Boolean(knownThreadId && !previousUsage);
|
|
248
255
|
|
|
249
|
-
const codexPath = this.codexPath ?? this.resolveCodexPathFn();
|
|
256
|
+
const codexPath = this.codexPath ?? this.resolveCodexPathFn({ env: this.env, platform: this.platform });
|
|
250
257
|
if (!codexPath) {
|
|
251
258
|
// No crash — surface visibly and resolve with a failure result.
|
|
252
259
|
this.logger.error("[Chorus] cannot locate the `codex` executable on PATH; skipping wake");
|
|
@@ -255,15 +262,17 @@ export class CodexSpawner {
|
|
|
255
262
|
|
|
256
263
|
if (!this.mcpConfigChecked) {
|
|
257
264
|
this.mcpConfigChecked = true;
|
|
258
|
-
if (!this.hasChorusMcpServerFn()) {
|
|
265
|
+
if (!this.hasChorusMcpServerFn({ env: this.env, platform: this.platform })) {
|
|
259
266
|
this.logger.warn(
|
|
260
267
|
"[Chorus] Codex config has no [mcp_servers.chorus] entry; wake will continue without Chorus MCP tools",
|
|
261
268
|
);
|
|
262
269
|
}
|
|
263
270
|
}
|
|
264
271
|
|
|
265
|
-
|
|
266
|
-
const {
|
|
272
|
+
assertConfiguredShimArgs(codexPath, this.cliConfig.args, this.platform);
|
|
273
|
+
const args = [...buildCodexArgs({ isNew, threadId: knownThreadId, permissionMode: this.permissionMode }), ...this.cliConfig.args,
|
|
274
|
+
...(this.cliConfig.args.length ? ["-"] : [])];
|
|
275
|
+
const { command, argv } = resolveSpawnCommand(codexPath, args, this.platform, this.env);
|
|
267
276
|
|
|
268
277
|
// POSIX: detached process group so the interrupt path can group-kill the tree
|
|
269
278
|
// (codex exec forks child shells for tools). Windows uses taskkill /T. stdio
|
|
@@ -273,7 +282,7 @@ export class CodexSpawner {
|
|
|
273
282
|
// Export the daemon's resolved connection pair for both Codex MCP auth and
|
|
274
283
|
// SessionStart hooks. Explicitly overwrite inherited values so the hook and
|
|
275
284
|
// daemon cannot disagree about which Chorus instance this wake belongs to.
|
|
276
|
-
const childEnv = { ...
|
|
285
|
+
const childEnv = { ...this.env, CHORUS_DAEMON_HEADLESS: "1" };
|
|
277
286
|
if (this.creds) {
|
|
278
287
|
if (this.creds.url) childEnv.CHORUS_URL = this.creds.url;
|
|
279
288
|
if (this.creds.apiKey) childEnv.CHORUS_API_KEY = this.creds.apiKey;
|
|
@@ -294,8 +303,8 @@ export class CodexSpawner {
|
|
|
294
303
|
detached,
|
|
295
304
|
windowsHide: true,
|
|
296
305
|
});
|
|
297
|
-
} catch (
|
|
298
|
-
this.logger.error(`[Chorus] failed to spawn codex: ${
|
|
306
|
+
} catch (error) {
|
|
307
|
+
this.logger.error(`[Chorus] failed to spawn codex: ${safeSpawnError(error)}`);
|
|
299
308
|
resolve({ sessionId: anchor, backendSessionId: knownThreadId, exitCode: null, isNew });
|
|
300
309
|
return;
|
|
301
310
|
}
|
|
@@ -357,12 +366,14 @@ export class CodexSpawner {
|
|
|
357
366
|
if (text) this.logger.warn(`[Chorus] codex stderr: ${text}`);
|
|
358
367
|
});
|
|
359
368
|
|
|
360
|
-
child.on("error", (
|
|
361
|
-
this.logger.error(`[Chorus] codex process error: ${
|
|
369
|
+
child.on("error", (error) => {
|
|
370
|
+
this.logger.error(`[Chorus] codex process error: ${safeSpawnError(error)}`);
|
|
362
371
|
resolve({ sessionId: anchor, backendSessionId: observedThreadId, exitCode: null, isNew });
|
|
363
372
|
});
|
|
364
373
|
|
|
365
|
-
|
|
374
|
+
// Settle on process exit, not only on stdio close: a detached descendant can
|
|
375
|
+
// inherit the pipes and keep `close` from ever firing (see cli/child-exit.mjs).
|
|
376
|
+
awaitChildSettled(child, { logger: this.logger, label: "codex" }).then((code) => {
|
|
366
377
|
if (code !== 0) {
|
|
367
378
|
this.logger.warn(`[Chorus] codex exited with code ${code}`);
|
|
368
379
|
}
|
package/cli/control-handler.mjs
CHANGED
|
@@ -12,6 +12,17 @@
|
|
|
12
12
|
// so a stale / recycled connection uuid can never make the daemon kill the wrong
|
|
13
13
|
// subprocess (Tech Design "Risks": mis-kill after a reconnect).
|
|
14
14
|
//
|
|
15
|
+
// When Check-2 fails for an `interrupt` (no live child here) the command is NOT
|
|
16
|
+
// silently dropped (fix-phantom-running-turn, Tech Design "D — a no-child interrupt
|
|
17
|
+
// reports the truth"): the handler logs the miss AND fire-and-forgets one
|
|
18
|
+
// `advanceTurn({ status: "interrupted", interruptedReason: "user" })` so a server-side
|
|
19
|
+
// `running` turn with no daemon child behind it converges instead of hanging forever.
|
|
20
|
+
// The session business key is derived without any lookup, and therefore only for the
|
|
21
|
+
// two control entity types where the derivation is an identity (`idea`,
|
|
22
|
+
// `daemon_session` → sessionId === entityUuid). `task` / `proposal` / `document` keep
|
|
23
|
+
// the pure-log behaviour: their session is anchored on the resource's DIRECT idea,
|
|
24
|
+
// which the daemon cannot resolve locally, and guessing would converge the wrong turn.
|
|
25
|
+
//
|
|
15
26
|
// On a verified match it (a) sets a per-entity "interrupting" flag on the waker so
|
|
16
27
|
// the waker reports the resulting exit as interrupted(reason="user") rather than a
|
|
17
28
|
// crash, then (b) invokes the injected killer (process-killer.killProcessTree) on
|
|
@@ -25,6 +36,16 @@ import { killProcessTree } from "./process-killer.mjs";
|
|
|
25
36
|
|
|
26
37
|
const NOOP_LOGGER = { info() {}, warn() {}, error() {} };
|
|
27
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Control entity types whose session business key is the entityUuid itself, so a
|
|
41
|
+
* no-child interrupt can report the turn terminal WITHOUT any REST lookup:
|
|
42
|
+
* • `idea` — the session anchor IS the direct idea uuid.
|
|
43
|
+
* • `daemon_session` — the ad-hoc session's own business id.
|
|
44
|
+
* Every other member of CONTROL_ENTITY_TYPES (`task`, `proposal`, `document`) is
|
|
45
|
+
* anchored on that resource's DIRECT idea, which is not derivable locally.
|
|
46
|
+
*/
|
|
47
|
+
const SELF_ANCHORED_ENTITY_TYPES = new Set(["idea", "daemon_session"]);
|
|
48
|
+
|
|
28
49
|
/**
|
|
29
50
|
* Build the `onControl(event)` callback the SseListener invokes for a
|
|
30
51
|
* `type:"control"` event.
|
|
@@ -56,6 +77,15 @@ const NOOP_LOGGER = { info() {}, warn() {}, error() {} };
|
|
|
56
77
|
* other still-pending turn along. Injected by the
|
|
57
78
|
* daemon (`backfill.pendingTurnsOnly`); the
|
|
58
79
|
* arg-less form (reconnect) still sweeps all.
|
|
80
|
+
* advanceTurn?: (params: { sessionId: string, status: string, interruptedReason?: string,
|
|
81
|
+
* entityType?: string|null, entityUuid?: string|null }) => any,
|
|
82
|
+
* The SAME `createTurnReporter(...)` instance the
|
|
83
|
+
* waker uses (injected by `cli/daemon.mjs`; no
|
|
84
|
+
* second transport, no new endpoint). Invoked
|
|
85
|
+
* fire-and-forget ONLY when an `interrupt` finds no
|
|
86
|
+
* live child for a self-anchored entity type, to
|
|
87
|
+
* close a server-side `running` turn that nothing
|
|
88
|
+
* else would ever close.
|
|
59
89
|
* logger?: { info(m:string):void, warn(m:string):void, error(m:string):void },
|
|
60
90
|
* }} deps
|
|
61
91
|
* @returns {(event: any) => void} The onControl callback (synchronous, non-throwing).
|
|
@@ -67,6 +97,7 @@ export function createControlHandler(deps) {
|
|
|
67
97
|
const sigintTimeoutMs = deps.sigintTimeoutMs;
|
|
68
98
|
const redispatchResume = deps.redispatchResume;
|
|
69
99
|
const deliverTurn = deps.deliverTurn;
|
|
100
|
+
const advanceTurn = deps.advanceTurn;
|
|
70
101
|
const handleDirectoryRequest = deps.handleDirectoryRequest;
|
|
71
102
|
const reportDirectoryRequest = deps.reportDirectoryRequest;
|
|
72
103
|
const logger = deps.logger ?? NOOP_LOGGER;
|
|
@@ -202,11 +233,76 @@ export function createControlHandler(deps) {
|
|
|
202
233
|
}
|
|
203
234
|
|
|
204
235
|
// --- interrupt path: Check 2 — in-memory entity ownership (running child) ---
|
|
236
|
+
//
|
|
237
|
+
// The registry is keyed by the WAKE's own resource (`task:T`), while a
|
|
238
|
+
// conversation's control key is its session anchor (`idea:A`). A wake on a CHILD
|
|
239
|
+
// resource of idea A runs on session A (waker: `sessionId = directIdeaUuid`), so an
|
|
240
|
+
// `idea:A` interrupt must also find a running `task:T` / `proposal:P` / `document:D`
|
|
241
|
+
// entry whose `directIdeaUuid` is A — the same rule the UI's `executionMatchesSession`
|
|
242
|
+
// applies. Without this the exact-key lookup misses, we report a turn miss, the
|
|
243
|
+
// server's FIFO resolution grabs the SIBLING wake's `running` turn, and NOTHING is
|
|
244
|
+
// killed: the UI would say interrupted while the agent keeps working.
|
|
205
245
|
const key = execKey(entityType, entityUuid);
|
|
206
|
-
|
|
246
|
+
let entry = waker?.executions?.get(key);
|
|
247
|
+
// The entity the kill actually targets — normally the command's own, but a sibling
|
|
248
|
+
// wake when the match below re-points it.
|
|
249
|
+
let killEntityType = entityType;
|
|
250
|
+
let killEntityUuid = entityUuid;
|
|
251
|
+
let killKey = key;
|
|
252
|
+
if ((!entry || entry.status !== "running" || !entry.child) && entityType === "idea") {
|
|
253
|
+
for (const candidate of waker?.executions?.values() ?? []) {
|
|
254
|
+
if (
|
|
255
|
+
candidate.status === "running" &&
|
|
256
|
+
candidate.child &&
|
|
257
|
+
candidate.directIdeaUuid === entityUuid
|
|
258
|
+
) {
|
|
259
|
+
killEntityType = candidate.entityType;
|
|
260
|
+
killEntityUuid = candidate.entityUuid;
|
|
261
|
+
killKey = execKey(killEntityType, killEntityUuid);
|
|
262
|
+
logger.info(
|
|
263
|
+
`[Chorus] control: no direct child for ${key}, but sibling wake ${killKey} ` +
|
|
264
|
+
`runs on this session; interrupting that instead`
|
|
265
|
+
);
|
|
266
|
+
entry = candidate;
|
|
267
|
+
break;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
207
271
|
if (!entry || entry.status !== "running" || !entry.child) {
|
|
208
272
|
// Either we never ran this entity, it's only queued (no child yet), or the
|
|
209
|
-
// wake already finished (race: interrupt arrived after exit).
|
|
273
|
+
// wake already finished (race: interrupt arrived after exit). There is nothing
|
|
274
|
+
// to kill — but the SERVER may still hold a `running` turn for this session
|
|
275
|
+
// that nothing else will ever close (the phantom-running-turn bug). Report it
|
|
276
|
+
// terminal so the UI converges. Only for the self-anchored entity types; for
|
|
277
|
+
// the rest we cannot know the session locally, so keep the old pure log.
|
|
278
|
+
if (SELF_ANCHORED_ENTITY_TYPES.has(entityType)) {
|
|
279
|
+
logger.info(
|
|
280
|
+
`[Chorus] control: no running subprocess for ${key} on this daemon; ` +
|
|
281
|
+
`reporting the turn as interrupted(user)`
|
|
282
|
+
);
|
|
283
|
+
// Fire-and-forget: createTurnReporter never throws and logs its own
|
|
284
|
+
// failures, but guard both the synchronous throw and the rejection so
|
|
285
|
+
// nothing escapes into the SSE loop. A server with no `running` turn
|
|
286
|
+
// answers not_found — a harmless no-op (losing race).
|
|
287
|
+
try {
|
|
288
|
+
Promise.resolve(
|
|
289
|
+
advanceTurn?.({
|
|
290
|
+
sessionId: entityUuid,
|
|
291
|
+
status: "interrupted",
|
|
292
|
+
interruptedReason: "user",
|
|
293
|
+
entityType,
|
|
294
|
+
entityUuid,
|
|
295
|
+
})
|
|
296
|
+
).catch((err) => {
|
|
297
|
+
logger.warn(
|
|
298
|
+
`[Chorus] control: interrupted-turn report rejected for ${key}: ${err}`
|
|
299
|
+
);
|
|
300
|
+
});
|
|
301
|
+
} catch (err) {
|
|
302
|
+
logger.warn(`[Chorus] control: interrupted-turn report failed for ${key}: ${err}`);
|
|
303
|
+
}
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
210
306
|
logger.info(
|
|
211
307
|
`[Chorus] control: no running subprocess for ${key} on this daemon; ignoring interrupt`
|
|
212
308
|
);
|
|
@@ -215,18 +311,20 @@ export function createControlHandler(deps) {
|
|
|
215
311
|
|
|
216
312
|
// --- Both checks passed: mark interrupting (so the waker reports reason=user),
|
|
217
313
|
// then kill the tree. ---
|
|
218
|
-
logger.info(`[Chorus] control: interrupting running subprocess for ${
|
|
314
|
+
logger.info(`[Chorus] control: interrupting running subprocess for ${killKey} (pid=${entry.child.pid})`);
|
|
219
315
|
try {
|
|
220
|
-
|
|
316
|
+
// Flag the entity whose wake we are actually killing — a sibling re-point must
|
|
317
|
+
// mark THAT wake interrupting, or its exit would be reported as a crash.
|
|
318
|
+
waker.markInterrupting?.(killEntityType, killEntityUuid);
|
|
221
319
|
} catch (err) {
|
|
222
|
-
logger.warn(`[Chorus] control: markInterrupting failed for ${
|
|
320
|
+
logger.warn(`[Chorus] control: markInterrupting failed for ${killKey}: ${err}`);
|
|
223
321
|
}
|
|
224
322
|
|
|
225
323
|
// Fire-and-forget the kill: the waker observes the child's exit and reports
|
|
226
324
|
// the interrupted state. The killer never throws, but guard the promise
|
|
227
325
|
// anyway so a rejection can't surface as an unhandled rejection.
|
|
228
326
|
Promise.resolve(killer(entry.child, { sigintTimeoutMs, logger })).catch((err) => {
|
|
229
|
-
logger.warn(`[Chorus] control: killProcessTree rejected for ${
|
|
327
|
+
logger.warn(`[Chorus] control: killProcessTree rejected for ${killKey}: ${err}`);
|
|
230
328
|
});
|
|
231
329
|
} catch (err) {
|
|
232
330
|
// Absolute backstop — a control event must never crash the SSE loop.
|
package/cli/credentials.mjs
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
import { readFileSync } from "node:fs";
|
|
20
20
|
import { homedir } from "node:os";
|
|
21
21
|
import { join, resolve } from "node:path";
|
|
22
|
+
import { rejectSharedCliConfig } from "./agent-cli-config.mjs";
|
|
22
23
|
|
|
23
24
|
/** Absolute path to the login file written by `chorus login`. */
|
|
24
25
|
export function loginFilePath() {
|
|
@@ -425,6 +426,7 @@ export function resolveLaunchAgent(flags = {}, deps = {}) {
|
|
|
425
426
|
const wanted = nonEmpty(flags.name) ?? nonEmpty(flags.agent) ?? nonEmpty(env.CHORUS_AGENT_PROFILE);
|
|
426
427
|
|
|
427
428
|
const file = readJson(loginPath);
|
|
429
|
+
rejectSharedCliConfig(file);
|
|
428
430
|
const agentEntries =
|
|
429
431
|
file && Array.isArray(file.agents)
|
|
430
432
|
? file.agents.filter((a) => a && typeof a === "object")
|
|
@@ -448,6 +450,8 @@ export function resolveLaunchAgent(flags = {}, deps = {}) {
|
|
|
448
450
|
agentUuid: nonEmpty(entry.agentUuid),
|
|
449
451
|
agentName: nonEmpty(entry.agentName) ?? nonEmpty(entry.name),
|
|
450
452
|
agentType: nonEmpty(entry.agentType),
|
|
453
|
+
args: entry.args,
|
|
454
|
+
env: entry.env,
|
|
451
455
|
}));
|
|
452
456
|
const labels = resolved.map((a) => a.label).join(", ");
|
|
453
457
|
|
|
@@ -479,6 +483,9 @@ export function resolveLaunchAgent(flags = {}, deps = {}) {
|
|
|
479
483
|
agentUuid: selected.agentUuid,
|
|
480
484
|
agentName: selected.agentName,
|
|
481
485
|
agentType: selected.agentType,
|
|
486
|
+
// Validation uses the launcher's effective --type, not the stored classification.
|
|
487
|
+
args: selected.args,
|
|
488
|
+
env: selected.env,
|
|
482
489
|
label: selected.label,
|
|
483
490
|
};
|
|
484
491
|
}
|
package/cli/daemon-config.mjs
CHANGED
|
@@ -18,6 +18,14 @@ import { isAbsolute, resolve as resolvePath } from "node:path";
|
|
|
18
18
|
import { loginFilePath, resolveCredentials, resolveCredentialDefaults } from "./credentials.mjs";
|
|
19
19
|
import { resolveAgentType, KNOWN_AGENTS } from "./daemon-agent.mjs";
|
|
20
20
|
import { resolvePermissionMode } from "./daemon-permission-mode.mjs";
|
|
21
|
+
import { rejectSharedCliConfig, validateAgentCliConfig } from "./agent-cli-config.mjs";
|
|
22
|
+
|
|
23
|
+
/** Read only the flat profile customization; also used by the legacy startup path. */
|
|
24
|
+
export function resolveFlatAgentCliConfig(type, deps = {}) {
|
|
25
|
+
const file = (deps.readJson ?? readJsonSafe)(deps.loginPath ?? loginFilePath());
|
|
26
|
+
rejectSharedCliConfig(file);
|
|
27
|
+
return validateAgentCliConfig(file ?? {}, type, "agent");
|
|
28
|
+
}
|
|
21
29
|
|
|
22
30
|
/** Built-in default escalation window (ms) — matches the spec's 10 seconds. */
|
|
23
31
|
export const DEFAULT_SIGINT_TIMEOUT_MS = 10_000;
|
|
@@ -307,6 +315,8 @@ function positiveInt(value) {
|
|
|
307
315
|
* @property {string} url Chorus server URL for this agent.
|
|
308
316
|
* @property {string} apiKey This agent's `cho_` API key.
|
|
309
317
|
* @property {string} agentType Backend: claude-code | codex | kiro | dsh | offline.
|
|
318
|
+
* @property {string[]} args Literal extra backend arguments (per-agent only).
|
|
319
|
+
* @property {Record<string,string>} env Literal child environment overrides (per-agent only).
|
|
310
320
|
* @property {boolean} [daemonWake] Wake opt-in for a wakeable backend; only
|
|
311
321
|
* `false` disables (absent/true ⇒ woken).
|
|
312
322
|
* @property {Array<string|undefined>} cwds Served paths (`undefined` ⇒ process cwd).
|
|
@@ -344,6 +354,8 @@ export function resolveAgentConfigs(flags = {}, deps = {}) {
|
|
|
344
354
|
const home = deps.home ?? homedir();
|
|
345
355
|
const file = readJson(loginPath);
|
|
346
356
|
|
|
357
|
+
rejectSharedCliConfig(file);
|
|
358
|
+
|
|
347
359
|
// Global default permission posture; a per-agent `permissionMode` overrides it.
|
|
348
360
|
// needConfirm/hasAck is vestigial, so isTTY/hasAck do not affect the resolved mode.
|
|
349
361
|
const defaultPermissionMode =
|
|
@@ -365,6 +377,7 @@ export function resolveAgentConfigs(flags = {}, deps = {}) {
|
|
|
365
377
|
url: creds.url,
|
|
366
378
|
apiKey: creds.apiKey,
|
|
367
379
|
agentType: at.agent,
|
|
380
|
+
...validateAgentCliConfig(file ?? {}, at.agent, "agent"),
|
|
368
381
|
cwds: resolveDaemonCwds(flags, deps),
|
|
369
382
|
permissionMode: defaultPermissionMode,
|
|
370
383
|
maxConcurrency: positiveInt(file?.maxConcurrency) ?? DEFAULT_MAX_CONCURRENCY,
|
|
@@ -449,6 +462,7 @@ export function resolveAgentConfigs(flags = {}, deps = {}) {
|
|
|
449
462
|
url,
|
|
450
463
|
apiKey,
|
|
451
464
|
agentType,
|
|
465
|
+
...validateAgentCliConfig(entry, agentType, label),
|
|
452
466
|
cwds,
|
|
453
467
|
permissionMode,
|
|
454
468
|
maxConcurrency,
|
|
@@ -40,6 +40,26 @@
|
|
|
40
40
|
|
|
41
41
|
const NOOP_LOGGER = { info() {}, warn() {}, error() {} };
|
|
42
42
|
|
|
43
|
+
// Bounded retry policy for the TERMINAL turn-advance edge only (fix-phantom-running-turn).
|
|
44
|
+
// A lost terminal report is the one failure that leaves a permanently phantom `running`
|
|
45
|
+
// turn, so it — and only it — is worth retrying. Fixed constants on purpose: one more
|
|
46
|
+
// configuration knob buys nothing here.
|
|
47
|
+
const TERMINAL_TURN_ADVANCE_ATTEMPTS = 3;
|
|
48
|
+
const TERMINAL_TURN_ADVANCE_DELAYS_MS = [500, 2000];
|
|
49
|
+
|
|
50
|
+
/** Real-time delay; tests inject their own so they never sleep for real. */
|
|
51
|
+
const realSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* A failure is retryable when repeating it can plausibly succeed: a network-level failure
|
|
55
|
+
* (no HTTP response at all), a `429`, or any `5xx`. Every `4xx` is a server VERDICT
|
|
56
|
+
* (invalid_transition, not_found, auth) — repeating it cannot make it true.
|
|
57
|
+
* @param {number|null} status
|
|
58
|
+
*/
|
|
59
|
+
function isRetryableFailure(status) {
|
|
60
|
+
return status === null || status === 429 || status >= 500;
|
|
61
|
+
}
|
|
62
|
+
|
|
43
63
|
/**
|
|
44
64
|
* @typedef {Object} DaemonRestResult
|
|
45
65
|
* @property {boolean} ok True only on a 2xx response (and, for reads, a
|
|
@@ -70,6 +90,8 @@ const NOOP_LOGGER = { info() {}, warn() {}, error() {} };
|
|
|
70
90
|
* executionState, reportInterrupt, readPendingTurns)
|
|
71
91
|
* require it; a null value skips the call (logged).
|
|
72
92
|
* fetchImpl?: typeof fetch, Injectable for tests (defaults to global fetch).
|
|
93
|
+
* sleep?: (ms: number) => Promise<void>, Injectable retry delay (defaults to setTimeout).
|
|
94
|
+
* Only the terminal turn-advance edge retries.
|
|
73
95
|
* logger?: { info(m:string):void, warn(m:string):void, error(m:string):void },
|
|
74
96
|
* }} opts
|
|
75
97
|
* @returns {{
|
|
@@ -88,6 +110,8 @@ export function createDaemonRestClient(opts) {
|
|
|
88
110
|
const getConnectionUuid = opts.getConnectionUuid ?? (() => null);
|
|
89
111
|
const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
90
112
|
const logger = opts.logger ?? NOOP_LOGGER;
|
|
113
|
+
// Injectable retry delay so tests assert the schedule without spending real seconds.
|
|
114
|
+
const sleepImpl = opts.sleep ?? realSleep;
|
|
91
115
|
|
|
92
116
|
const jsonHeaders = {
|
|
93
117
|
Authorization: `Bearer ${apiKey}`,
|
|
@@ -111,41 +135,71 @@ export function createDaemonRestClient(opts) {
|
|
|
111
135
|
* `<op> request failed` / `<op> returned <status>` core, so the
|
|
112
136
|
* failing entity stays visible in the log without disturbing the
|
|
113
137
|
* established op-prefixed message.
|
|
138
|
+
* @param {boolean} [readData] Parse the response envelope's `data` on success.
|
|
139
|
+
* @param {{ attempts: number, delaysMs: number[], sleep?: (ms: number) => Promise<void> }|null} [retry]
|
|
140
|
+
* Optional bounded retry policy. Absent/null = today's exact
|
|
141
|
+
* single-shot behaviour (used by every op but the terminal
|
|
142
|
+
* turn-advance edge).
|
|
114
143
|
* @returns {Promise<DaemonRestResult>}
|
|
115
144
|
*/
|
|
116
|
-
async function post(op, path, body, successLog, context = "", readData = false) {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
logger.warn(`[Chorus] ${error}`);
|
|
128
|
-
return { ok: false, status: null, error };
|
|
129
|
-
}
|
|
130
|
-
if (!response.ok) {
|
|
131
|
-
// Non-2xx. Surface WITH the status so a 4xx/5xx is debuggable.
|
|
132
|
-
const error = `${op} returned ${response.status}${context}`;
|
|
133
|
-
logger.warn(`[Chorus] ${error}`);
|
|
134
|
-
return { ok: false, status: response.status, error };
|
|
135
|
-
}
|
|
136
|
-
let data;
|
|
137
|
-
if (readData) {
|
|
145
|
+
async function post(op, path, body, successLog, context = "", readData = false, retry = null) {
|
|
146
|
+
const attempts = retry ? retry.attempts : 1;
|
|
147
|
+
const delaysMs = retry?.delaysMs ?? [];
|
|
148
|
+
// Named distinctly from the module-closure `sleepImpl` so this local never reads as a
|
|
149
|
+
// shadow: callers with a retry policy pass their own sleep explicitly.
|
|
150
|
+
const retrySleep = retry?.sleep ?? realSleep;
|
|
151
|
+
|
|
152
|
+
let failure;
|
|
153
|
+
for (let attempt = 1; attempt <= attempts; attempt += 1) {
|
|
154
|
+
failure = undefined;
|
|
155
|
+
let response;
|
|
138
156
|
try {
|
|
139
|
-
|
|
140
|
-
|
|
157
|
+
response = await fetchImpl(`${url}${path}`, {
|
|
158
|
+
method: "POST",
|
|
159
|
+
headers: jsonHeaders,
|
|
160
|
+
body: JSON.stringify(body),
|
|
161
|
+
});
|
|
141
162
|
} catch (err) {
|
|
142
|
-
//
|
|
143
|
-
//
|
|
144
|
-
|
|
163
|
+
// Network-level failure (DNS, connection refused, abort, …). Surface WITH cause.
|
|
164
|
+
// `head`/`tail` are split so the attempt ordinal can be injected before the cause.
|
|
165
|
+
failure = { status: null, head: `${op} request failed${context}`, tail: `: ${err}` };
|
|
166
|
+
}
|
|
167
|
+
if (!failure && !response.ok) {
|
|
168
|
+
// Non-2xx. Surface WITH the status so a 4xx/5xx is debuggable.
|
|
169
|
+
failure = { status: response.status, head: `${op} returned ${response.status}${context}`, tail: "" };
|
|
145
170
|
}
|
|
171
|
+
if (!failure) {
|
|
172
|
+
let data;
|
|
173
|
+
if (readData) {
|
|
174
|
+
try {
|
|
175
|
+
const parsed = await response.json();
|
|
176
|
+
data = parsed && typeof parsed === "object" ? parsed.data : undefined;
|
|
177
|
+
} catch (err) {
|
|
178
|
+
// Mixed-version fallback: older servers may return an empty successful body.
|
|
179
|
+
// Keep the lifecycle report successful, but make the missing correlation visible.
|
|
180
|
+
logger.warn(`[Chorus] ${op} response correlation unavailable: ${err}`);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (successLog) logger.info(`[Chorus] ${successLog}`);
|
|
184
|
+
return { ok: true, status: response.status, ...(data !== undefined ? { data } : {}) };
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const canRetry = attempt < attempts && isRetryableFailure(failure.status);
|
|
188
|
+
// Per-attempt visibility, but ONLY when another attempt actually follows: the ordinal
|
|
189
|
+
// exists to explain a retry. A single-shot op, or a terminal failure that will be
|
|
190
|
+
// re-logged verbatim two lines below, must not emit a redundant ordinal line.
|
|
191
|
+
if (canRetry) {
|
|
192
|
+
logger.warn(`[Chorus] ${failure.head} (attempt ${attempt}/${attempts})${failure.tail}`);
|
|
193
|
+
}
|
|
194
|
+
if (!canRetry) break;
|
|
195
|
+
await retrySleep(delaysMs[attempt - 1] ?? delaysMs[delaysMs.length - 1] ?? 0);
|
|
146
196
|
}
|
|
147
|
-
|
|
148
|
-
|
|
197
|
+
|
|
198
|
+
// Final failure: the message and the structured result are EXACTLY what they were
|
|
199
|
+
// before retries existed, so existing log-grep expectations still match.
|
|
200
|
+
const error = `${failure.head}${failure.tail}`;
|
|
201
|
+
logger.warn(`[Chorus] ${error}`);
|
|
202
|
+
return { ok: false, status: failure.status, error };
|
|
149
203
|
}
|
|
150
204
|
|
|
151
205
|
return {
|
|
@@ -203,6 +257,21 @@ export function createDaemonRestClient(opts) {
|
|
|
203
257
|
`advanced turn for session ${sessionId} → ${status}`,
|
|
204
258
|
"",
|
|
205
259
|
status === "running",
|
|
260
|
+
// Bounded retry on the TERMINAL edge only. A lost `→ ended`/`→ interrupted` report
|
|
261
|
+
// is what strands a turn as phantom `running` forever; the `→ running` edge is not
|
|
262
|
+
// retried because the wake is about to run anyway and a stale retry could race the
|
|
263
|
+
// terminal edge. The repeat is safe: the daemon sends the `turnUuid` it learned
|
|
264
|
+
// from its own → running report, and advanceTurnForWake returns the existing
|
|
265
|
+
// projection for a same-turn same-terminal-status replay (no second usage rollup,
|
|
266
|
+
// timestamp write or SSE publish). Without a turnUuid, the FIFO lookup finds no
|
|
267
|
+
// `running` turn and answers not_found, changing nothing.
|
|
268
|
+
isTerminal
|
|
269
|
+
? {
|
|
270
|
+
attempts: TERMINAL_TURN_ADVANCE_ATTEMPTS,
|
|
271
|
+
delaysMs: TERMINAL_TURN_ADVANCE_DELAYS_MS,
|
|
272
|
+
sleep: sleepImpl,
|
|
273
|
+
}
|
|
274
|
+
: null,
|
|
206
275
|
);
|
|
207
276
|
const resolvedTurnUuid =
|
|
208
277
|
typeof result.data?.turn?.uuid === "string" ? result.data.turn.uuid : null;
|