@chorus-aidlc/chorus 0.18.0 → 0.19.0
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 +341 -339
- package/.next/standalone/.next/app-path-routes-manifest.json +41 -41
- 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.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 +1 -1
- 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 +1 -1
- 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_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/agents/[uuid]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/agents/[uuid]/sessions/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/agents/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/api-keys/[uuid]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/api-keys/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/auth/callback/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/auth/check-default/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/auth/company-oidc/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/auth/default-login/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/auth/identify/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/auth/me/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/auth/sync-token/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/comments/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon/connection-heartbeat/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon/control/route.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_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon/execution-state/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon/executions/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon/pending-turns/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon/report-interrupt/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon/resume/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon/transcript/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon/turn-advance/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon-directory-requests/[uuid]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon-directory-requests/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon-sessions/[sessionUuid]/instruction/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon-sessions/[sessionUuid]/repoint/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon-sessions/[sessionUuid]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon-sessions/ad-hoc/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/daemon-sessions/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/documents/[uuid]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/entities/[type]/[uuid]/root-idea/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/events/notifications/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/events/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/health/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/ideas/[uuid]/claim/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/ideas/[uuid]/move/preview/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/ideas/[uuid]/move/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/ideas/[uuid]/parent/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/ideas/[uuid]/release/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/ideas/[uuid]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/ideas/[uuid]/wake-preview/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/ideas/conversational/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/mcp/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/me/assignments/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/mentionables/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/notifications/[uuid]/archive/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/notifications/[uuid]/read/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/notifications/preferences/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/notifications/read-all/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/notifications/unread-count/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/project-groups/[uuid]/dashboard/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/project-groups/[uuid]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/project-groups/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/project-visits/pin/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/project-visits/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/project-visits/visit/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[uuid]/activity/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[uuid]/agent-cwds/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[uuid]/available/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[uuid]/documents/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[uuid]/group/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[uuid]/ideas/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[uuid]/ideas/tracker/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[uuid]/proposals/[proposalUuid]/validate/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[uuid]/proposals/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[uuid]/proposals/summary/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[uuid]/resource-graph/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[uuid]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[uuid]/stats/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[uuid]/tasks/dependencies/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/[uuid]/tasks/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/agent-cwd-options/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/proposals/[uuid]/approve/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/proposals/[uuid]/close/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/proposals/[uuid]/reject/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/proposals/[uuid]/revoke/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/proposals/[uuid]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/references/[uuid]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/references/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/search/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/session/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/sessions/[uuid]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/tasks/[uuid]/claim/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/tasks/[uuid]/dependencies/[dependsOnUuid]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/tasks/[uuid]/dependencies/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/tasks/[uuid]/release/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/tasks/[uuid]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/tasks/[uuid]/sessions/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/index.html +2 -2
- package/.next/standalone/.next/server/app/index.rsc +2 -2
- package/.next/standalone/.next/server/app/login/admin/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/login/admin.html +2 -2
- package/.next/standalone/.next/server/app/login/admin.rsc +2 -2
- package/.next/standalone/.next/server/app/login/callback/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/login/callback.html +2 -2
- package/.next/standalone/.next/server/app/login/callback.rsc +2 -2
- package/.next/standalone/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/login/pick-workspace/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/login/pick-workspace.html +2 -2
- package/.next/standalone/.next/server/app/login/pick-workspace.rsc +2 -2
- package/.next/standalone/.next/server/app/login.html +2 -2
- package/.next/standalone/.next/server/app/login.rsc +2 -2
- package/.next/standalone/.next/server/app/onboarding/page.js +2 -2
- package/.next/standalone/.next/server/app/onboarding/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/onboarding/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/onboarding.html +2 -2
- package/.next/standalone/.next/server/app/onboarding.rsc +3 -3
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/projects.html +2 -2
- package/.next/standalone/.next/server/app/projects.rsc +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 +41 -41
- 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/{4810.js → 1683.js} +1 -1
- package/.next/standalone/.next/server/chunks/2572.js +2 -2
- package/.next/standalone/.next/server/chunks/2961.js +1 -1
- package/.next/standalone/.next/server/chunks/3112.js +1 -1
- package/.next/standalone/.next/server/chunks/3341.js +1 -0
- package/.next/standalone/.next/server/chunks/3419.js +1 -1
- package/.next/standalone/.next/server/chunks/5245.js +1 -1
- package/.next/standalone/.next/server/chunks/6113.js +1 -1
- package/.next/standalone/.next/server/chunks/6506.js +1 -1
- package/.next/standalone/.next/server/chunks/6607.js +1 -0
- package/.next/standalone/.next/server/chunks/6737.js +1 -1
- package/.next/standalone/.next/server/chunks/6753.js +3 -3
- 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/7400.js +1 -0
- 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/7789.js +1 -0
- package/.next/standalone/.next/server/chunks/8185.js +1 -0
- 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/{3619.js → 9848.js} +2 -2
- 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/{29305-f587e7e81bc0b200.js → 17562-56f932146e9e6c94.js} +4 -4
- package/.next/standalone/.next/static/chunks/18751-3616e33050e9611e.js +1 -0
- package/.next/standalone/.next/static/chunks/26020-7b4756ba0aa906cf.js +1 -0
- package/.next/standalone/.next/static/chunks/33456.20313bd67a5c41cc.js +1 -0
- package/.next/standalone/.next/static/chunks/44437-d13183f50281116f.js +1 -0
- package/.next/standalone/.next/static/chunks/4860.3b555a398cdffb19.js +1 -0
- package/.next/standalone/.next/static/chunks/59713-426f81b6576173d8.js +1 -0
- package/.next/standalone/.next/static/chunks/60351-bdef539874e5027e.js +1 -0
- package/.next/standalone/.next/static/chunks/79919-1e7e294a06f2c4a0.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/99733-5a2e39f57fbda32d.js +1 -0
- package/.next/standalone/.next/static/chunks/app/(dashboard)/layout-072a6b8f0a48b1b6.js +1 -0
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/dashboard/page-198a3ff89ae871b9.js +1 -0
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/documents/[documentUuid]/page-a506de82e8997714.js +1 -0
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/documents/{page-800a979f12b73f27.js → page-dc54fafa22d21863.js} +1 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/graph/{page-34de35f75aa71f6d.js → page-6eb5d3cb036a78e0.js} +1 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/proposals/[proposalUuid]/page-69c6f0190623e19b.js +1 -0
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/proposals/new/page-2a52f747e6fac5a7.js +1 -0
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/proposals/page-22cce567a85ea291.js +1 -0
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/tasks/[taskUuid]/{page-349b0977f3c6209a.js → page-301f21a3ae52e318.js} +1 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/tasks/{page-be43cb06112fce12.js → page-dd123990c14e9768.js} +1 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/settings/page-548231f8c9856489.js +1 -0
- package/.next/standalone/.next/static/chunks/app/onboarding/{page-c0090caae202eae5.js → page-5914ff3d878a3c34.js} +1 -1
- package/.next/standalone/.next/static/chunks/{webpack-cfb63dd1b416c92e.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 +1 -1
- package/.next/standalone/public/chorus-plugin/agents/code-reviewer.md +63 -6
- package/.next/standalone/public/chorus-plugin/agents/proposal-reviewer.md +60 -6
- package/.next/standalone/public/chorus-plugin/agents/task-reviewer.md +75 -8
- package/.next/standalone/public/chorus-plugin/bin/chorus-api.sh +1 -1
- package/.next/standalone/public/chorus-plugin/bin/on-pre-spawn-agent.sh +22 -9
- 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/test-syntax.sh +6 -2
- 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 +1 -1
- package/.next/standalone/public/chorus-plugin/skills/chorus-cli/SKILL.md +1 -1
- package/.next/standalone/public/chorus-plugin/skills/develop/SKILL.md +1 -1
- 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 +1 -1
- package/.next/standalone/public/chorus-plugin/skills/orchestrate/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/spec-lite/SKILL.md +1 -1
- package/.next/standalone/public/chorus-plugin/skills/yolo/SKILL.md +1 -1
- package/.next/standalone/public/kiro-plugin/.kiro/agents/chorus-code-reviewer.json +56 -1
- package/.next/standalone/public/kiro-plugin/.kiro/agents/chorus-proposal-reviewer.json +79 -1
- package/.next/standalone/public/kiro-plugin/.kiro/agents/chorus-task-reviewer.json +56 -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 +1 -1
- 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 +1 -1
- package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-orchestrate/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-spec-lite/SKILL.md +1 -1
- package/.next/standalone/public/kiro-plugin/.kiro/skills/chorus-yolo/SKILL.md +1 -1
- package/.next/standalone/public/kiro-plugin/bin/chorus-api.sh +1 -1
- package/.next/standalone/public/skill/code-reviewer-chorus/SKILL.md +60 -4
- package/.next/standalone/public/skill/proposal-reviewer-chorus/SKILL.md +58 -5
- package/.next/standalone/public/skill/task-reviewer-chorus/SKILL.md +72 -6
- package/README.ja.md +3 -1
- package/README.ko.md +3 -1
- package/README.md +3 -1
- package/README.zh.md +3 -1
- package/chorus.mjs +30 -2
- package/cli/child-exit.mjs +77 -0
- package/cli/claude-spawner.mjs +4 -1
- package/cli/codex-spawner.mjs +4 -1
- package/cli/control-handler.mjs +104 -6
- package/cli/daemon-rest-client.mjs +98 -29
- package/cli/daemon.mjs +5 -1
- package/cli/dsh-spawner.mjs +4 -1
- package/cli/kiro-spawner.mjs +4 -1
- package/cli/pi-spawner.mjs +4 -1
- package/package.json +1 -1
- package/.next/standalone/.next/server/chunks/109.js +0 -1
- package/.next/standalone/.next/server/chunks/1496.js +0 -1
- package/.next/standalone/.next/server/chunks/731.js +0 -1
- package/.next/standalone/.next/server/chunks/7857.js +0 -1
- package/.next/standalone/.next/static/chunks/11595.0afa1a540f681fb4.js +0 -1
- package/.next/standalone/.next/static/chunks/22705-324a191727ae45b7.js +0 -1
- package/.next/standalone/.next/static/chunks/33456.4a5f4712a7e78d8f.js +0 -1
- package/.next/standalone/.next/static/chunks/44216-3876e84f5b02d355.js +0 -1
- package/.next/standalone/.next/static/chunks/4860.5719e32b95be2d93.js +0 -1
- package/.next/standalone/.next/static/chunks/6528-a8a562ef7d26bb43.js +0 -1
- package/.next/standalone/.next/static/chunks/67439-7b339b28ed0ecfc6.js +0 -1
- package/.next/standalone/.next/static/chunks/79919-ae8bd8d8ec1e38ce.js +0 -1
- package/.next/standalone/.next/static/chunks/82203-4ce5926624df7ed0.js +0 -1
- package/.next/standalone/.next/static/chunks/94643-37ac7b8ef8ea5e75.js +0 -1
- package/.next/standalone/.next/static/chunks/99373.6c1509bfaf599741.js +0 -1
- package/.next/standalone/.next/static/chunks/99775-697e82ee04eac6b1.js +0 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/layout-2fda722cdace8147.js +0 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/dashboard/page-b45c42c536eff64b.js +0 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/documents/[documentUuid]/page-792aba7fd6b6daa3.js +0 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/proposals/[proposalUuid]/page-a16002aa2a911619.js +0 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/proposals/new/page-e8030824994edf35.js +0 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/projects/[uuid]/proposals/page-4f7f1ddbaf79be8f.js +0 -1
- package/.next/standalone/.next/static/chunks/app/(dashboard)/settings/page-6916e1abab42a6e6.js +0 -1
- package/.next/standalone/.next/static/css/75c761a5428611fa.css +0 -1
- /package/.next/standalone/.next/static/{IxKVu5zkFPTjSKAUR99yH → Pmji9kEq8T2lM6AKQkZji}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{IxKVu5zkFPTjSKAUR99yH → Pmji9kEq8T2lM6AKQkZji}/_ssgManifest.js +0 -0
|
@@ -114,14 +114,62 @@ Classify **every** finding as exactly one of:
|
|
|
114
114
|
|
|
115
115
|
**Rules:** Pseudocode inconsistencies → **always NOTE**. Cross-document wording differences → **always NOTE**. Only semantic contradictions → BLOCKER.
|
|
116
116
|
|
|
117
|
+
Give every finding a stable ID: BLOCKER titles are `B<round>-<slug>`, NOTE entries are `N<round>-<slug>`, where <round> is the round that FIRST reported it — never renamed or renumbered in later rounds.
|
|
118
|
+
Round 2+ MUST also acknowledge every prior BLOCKER and every prior NOTE by ID with exactly one of three states — `fixed` / `still-open` / `not-verifiable` — plus what you actually re-ran or re-read. Silence is not a fix: only an explicit `fixed` closes a finding. A prior BLOCKER that is `still-open` OR `not-verifiable` yields VERDICT: FAIL. An unresolved NOTE never yields worse than PASS WITH NOTES.
|
|
119
|
+
|
|
117
120
|
---
|
|
118
121
|
|
|
122
|
+
## What to report / what NOT to report
|
|
123
|
+
|
|
124
|
+
This list is specific to the proposal gate. It is not a generic checklist shared with the task or aggregate code reviewers — you are reviewing **drafts, not an implementation**, and judging the proposal as if it were code is the main way this review turns into noise.
|
|
125
|
+
|
|
126
|
+
**DO report:**
|
|
127
|
+
- Requirements that are not traceable to human-authored intent, and human-stated intent that no requirement carries.
|
|
128
|
+
- Acceptance criteria that are not machine-verifiable by a different agent.
|
|
129
|
+
- Task granularity problems and an unsound dependency DAG (wrong edges, cycles, a task that cannot start when its dependencies are done).
|
|
130
|
+
- A missing integration checkpoint once the DAG has 4+ tasks.
|
|
131
|
+
- Hallucination-risk specifics in the drafts (SDK versions, API paths, CLI flags, model IDs) → NOTE.
|
|
132
|
+
|
|
133
|
+
**DO NOT report:**
|
|
134
|
+
- **Never report something as missing without first confirming its absence with read-only Bash** (`ls` / `grep` / `rg` / `find` / `git ls-files`), and cite what you checked. An unverified "X is missing" is the single most common false BLOCKER.
|
|
135
|
+
- **Do not report document wording or formatting.** Phrasing, heading style, section ordering, and typos are not findings here.
|
|
136
|
+
- **Do not report that "the implementation detail isn't specific enough."** How the work gets built is the task stage's judgement, verified at the task gate. A proposal is not required to pre-specify implementation.
|
|
137
|
+
- **Do not propose alternative architectures.** Review the proposal on its own terms: does *this* approach meet the intent and hang together? A different design you would have preferred is not a finding.
|
|
138
|
+
- **Do not report future extensibility.** "This won't scale to a use case nobody asked for" is out of scope.
|
|
139
|
+
|
|
119
140
|
## Round 2+ Awareness
|
|
120
141
|
|
|
121
142
|
You may receive the current review round number in your context.
|
|
122
143
|
|
|
123
144
|
- **Round 1** — Full review at normal strictness.
|
|
124
|
-
- **Round 2+** — Focus ONLY on whether the previous BLOCKERs were fixed. Do NOT introduce new NOTEs on areas not flagged in earlier rounds. Round 1 already did the full-depth draft review. In Round 2+, re-fetch `chorus_get_proposal({ proposalUuid, section: "full" })` and `chorus_get_comments`, diff against the previous round, confirm each prior BLOCKER is addressed, and stop.
|
|
145
|
+
- **Round 2+** — Focus ONLY on whether the previous BLOCKERs were fixed. Do NOT introduce new NOTEs on areas not flagged in earlier rounds. Round 1 already did the full-depth draft review. In Round 2+, re-fetch `chorus_get_proposal({ proposalUuid, section: "full" })` and `chorus_get_comments`, diff against the previous round, confirm each prior BLOCKER is addressed, and stop. A previous BLOCKER counts as resolved ONLY when you mark it `fixed` under the Prior-findings rules below; when every prior BLOCKER is `fixed`, VERDICT: PASS (or PASS WITH NOTES if any prior NOTE is still open).
|
|
146
|
+
|
|
147
|
+
## Prior findings: stable IDs and cross-round acknowledgement
|
|
148
|
+
|
|
149
|
+
**Stable IDs.** Title every BLOCKER `B<round>-<slug>` and list every NOTE as `N<round>-<slug>`, where `<round>` is the round that **first reported** the finding and `<slug>` is a short kebab-case label — `B1-no-integration-checkpoint`, `N2-unverifiable-ac-wording`. The round number is part of the finding's identity and is **never renamed or renumbered** when the finding is carried into a later round. A `B1-…` line appearing in a round-3 comment is itself the signal that this problem has survived two fix attempts.
|
|
150
|
+
|
|
151
|
+
**Acknowledgement.** In round 2 and later, list **every** prior BLOCKER and **every** prior NOTE by ID under a `**Prior findings:**` block, each with exactly one of these three states and with what you actually re-read or re-ran this round:
|
|
152
|
+
|
|
153
|
+
- `fixed` — re-verified this round; cite the draft section (or read-only command) and what it now says.
|
|
154
|
+
- `still-open` — re-checked, and the problem is still there.
|
|
155
|
+
- `not-verifiable` — could not check it this round; say why (the relevant draft was not returned, no shell for the check the finding needs). Never counts as fixed.
|
|
156
|
+
|
|
157
|
+
Those three states are the whole vocabulary — there is no fourth state, and the same three words apply to BLOCKERs and NOTEs alike.
|
|
158
|
+
|
|
159
|
+
Three rules govern what the states mean for the verdict:
|
|
160
|
+
|
|
161
|
+
- **Silence is not a fix.** Not re-reporting a finding does not close it. Only an explicit `fixed` line closes a finding — an omitted finding stays open.
|
|
162
|
+
- **A prior BLOCKER whose state is `still-open` or `not-verifiable` yields `VERDICT: FAIL`.** Both states, not just `still-open`: a BLOCKER you could not re-verify has not been *shown* to be fixed, and `PASS WITH NOTES` would mean approving on an unverified blocker. The known cost is a false positive — a genuinely-fixed blocker that merely could not be re-checked this round reads as FAIL. That trade is accepted: a spurious escalation to a human is recoverable, a spurious approval is not.
|
|
163
|
+
- **NOTEs never escalate.** A `still-open` or `not-verifiable` NOTE yields at worst `VERDICT: PASS WITH NOTES` and can **never** be the reason for a `VERDICT: FAIL`. Only BLOCKERs block.
|
|
164
|
+
|
|
165
|
+
**How the NOTE limit composes with the round-2+ rule above.** These are two separate rules and they never apply to the same NOTEs:
|
|
166
|
+
|
|
167
|
+
| | Newly-raised NOTEs | Carried-forward acknowledgement lines |
|
|
168
|
+
|---|---|---|
|
|
169
|
+
| Round 1 | at most 5 — past 5, drop the least relevant | none exist yet |
|
|
170
|
+
| Round 2+ | **zero** — Round awareness above already forbids new NOTEs | **all of them, written in full, never limited** |
|
|
171
|
+
|
|
172
|
+
So the limit of 5 governs newly-raised NOTEs **only**. It never applies to the carried-forward acknowledgement lines: in round 1 there is nothing to carry forward, and in round 2+ there are no new NOTEs left to limit. Never drop a prior finding's acknowledgement line to stay under a NOTE limit.
|
|
125
173
|
|
|
126
174
|
---
|
|
127
175
|
|
|
@@ -157,19 +205,24 @@ Do NOT invent other verdicts like "APPROVE" or "OK" — automation greps for the
|
|
|
157
205
|
|
|
158
206
|
## Output Format (Required)
|
|
159
207
|
|
|
160
|
-
|
|
208
|
+
BLOCKER evidence is unbounded, so never truncate it to shorten the comment; report at most 5 newly-raised NOTEs and drop the least relevant beyond that. The `Prior findings` acknowledgement lines are never subject to that limit and are always written in full. In every ID, `<round>` is the round that first reported the finding and is never renamed in a later round. No preamble, no trailing summary paragraph. PASS items: names only. NOTE items: one-line descriptions. BLOCKER items: full evidence.
|
|
161
209
|
|
|
162
210
|
```
|
|
163
211
|
### Review Summary
|
|
164
212
|
|
|
213
|
+
**Prior findings:** (round 2+ only — omit this block in round 1)
|
|
214
|
+
- B1-<slug>: fixed — `<what you re-ran or re-read>` → <result observed>
|
|
215
|
+
- B1-<other-slug>: still-open — `<what you re-ran or re-read>` → <problem still present>
|
|
216
|
+
- B2-<slug>: not-verifiable — <why you could not check it this round>
|
|
217
|
+
- N1-<slug>: still-open
|
|
165
218
|
**PASS (N):** Check-1 name, Check-2 name, ...
|
|
166
219
|
|
|
167
220
|
**NOTE (M):**
|
|
168
|
-
-
|
|
169
|
-
-
|
|
221
|
+
- N<round>-<slug>: [one-line description]
|
|
222
|
+
- N<round>-<slug>: [one-line description]
|
|
170
223
|
|
|
171
224
|
**BLOCKER (K):**
|
|
172
|
-
###
|
|
225
|
+
### B<round>-<slug>
|
|
173
226
|
**Evidence:** [specific finding]
|
|
174
227
|
**Expected:** [what should be there]
|
|
175
228
|
**Actual:** [what is there or what is missing]
|
|
@@ -107,6 +107,19 @@ Pick 2-3 probes that fit the specific task — boundary values, missing fields,
|
|
|
107
107
|
|
|
108
108
|
**Hallucination check:** Flag anything that looks LLM-fabricated as a **NOTE** — API signatures, CLI flags, config keys, model IDs, endpoint URLs, package names, or any external detail the developer likely wrote from memory rather than referencing docs.
|
|
109
109
|
|
|
110
|
+
**Code quality and correctness beyond the AC — checked by default**
|
|
111
|
+
|
|
112
|
+
The AC were written before the code existed: they describe what to build, never how well it was built. Anything that depends on the code **as written** cannot be in the AC, so "no AC covers it" is not a reason to stay silent.
|
|
113
|
+
|
|
114
|
+
- **Correctness without an AC.** Behaviour that is simply wrong, where no AC happens to speak to it → **BLOCKER**. You do not need an acceptance criterion to report a bug.
|
|
115
|
+
- **Reimplementation.** Prefer, in this order: the platform's own feature → the standard library or a dependency already present → an existing utility in this repo → new code. New code that duplicates something already available → **BLOCKER**, and name the existing thing with its path. "This could be shorter" with nothing named is not a finding.
|
|
116
|
+
- **Security in this task's own code.** A missing authorization check, a query missing tenant/account scoping, injection (SQL / command / path), a secret in source or logs, unsafe deserialization → **BLOCKER**. Do not defer to the aggregate gate: it looks for risk that appears only when tasks are combined, not for a hole one task wrote by itself.
|
|
117
|
+
- **Tests that cannot fail.** Ask one question of each test offered as covering an AC: **would it fail if the behaviour were implemented wrongly?** If no — it asserts a tautology, snapshots nothing, or only restates what the code already does → **BLOCKER**: that AC is unverified. Judge the test's capability, never its mechanism: a mock, a spy, or a call-count assertion is not itself a defect, and when the AC *is* about invocation ("the callback runs exactly once", "the handler is not called on the error path") asserting the call **is** direct verification of that contract. Thin-but-real tests → NOTE.
|
|
118
|
+
- **Silent failure.** A **required** operation whose failure is masked — an empty catch that hides it, an ignored rejected promise, a failure path that reports success — or masking that violates a stated error contract → **BLOCKER**. Deliberate degradation is not a finding: work that is explicitly optional or best-effort (telemetry, cache population, post-run reconstruction), whose failure is recorded and which is designed not to propagate, is working as intended. Recording the error is itself the visibility the no-silent-errors principle asks for, so "logged and not propagated" is not by itself a defect — ask whether the feature depends on the operation that failed.
|
|
119
|
+
- **Maintainability, leftovers, diff hygiene → NOTE:** a function doing several unrelated things, deep nesting, copy-pasted blocks inside this diff, unnamed magic values; unused imports/exports, commented-out code, debug logging, TODOs this task introduced; changes unrelated to this task bundled into the same diff; `any` or unchecked nullables on the interface this task owns; a query inside a loop or an unbounded fetch. Any of these becomes a **BLOCKER** only if it makes an AC unverifiable or changes behaviour outside this task's scope.
|
|
120
|
+
|
|
121
|
+
**Severity rule.** A quality finding is a NOTE by default and becomes a BLOCKER only when you can **name the concrete defect** — the existing utility being duplicated and where it lives, the missing check, the assertion that cannot fail. Taste never blocks: if you cannot point at it, it is a NOTE or it is nothing. Report the cheapest concrete change, never a redesign.
|
|
122
|
+
|
|
110
123
|
### Step 6: Intent Alignment
|
|
111
124
|
|
|
112
125
|
Resolve the originating Idea (this task's proposal → `inputUuids[0]`) and read its body + human-answered elaboration + human-authored comments (`answeredBy.type` / `author.type == "user"`; agent-authored entries are audit context, not intent). Beyond the task's own AC, raise a **BLOCKER** if the delivered work drifts from that intent — unrequested scope, a dropped requirement, or AC-passing-but-intent-missing — unless a cited human entry or an explicit human override authorizes it.
|
|
@@ -140,16 +153,64 @@ Classify **every** finding as exactly one of:
|
|
|
140
153
|
- Style / naming suggestions.
|
|
141
154
|
- Hallucination-risk specifics (SDK versions, API paths, CLI flags, model IDs).
|
|
142
155
|
|
|
143
|
-
**Rules:**
|
|
156
|
+
**Rules:** Style, naming, and pseudocode inconsistencies → **always NOTE**. Functional, security, and verification-integrity issues → BLOCKER. A quality finding blocks only when you can name the concrete defect.
|
|
157
|
+
|
|
158
|
+
Give every finding a stable ID: BLOCKER titles are `B<round>-<slug>`, NOTE entries are `N<round>-<slug>`, where <round> is the round that FIRST reported it — never renamed or renumbered in later rounds.
|
|
159
|
+
Round 2+ MUST also acknowledge every prior BLOCKER and every prior NOTE by ID with exactly one of three states — `fixed` / `still-open` / `not-verifiable` — plus what you actually re-ran or re-read. Silence is not a fix: only an explicit `fixed` closes a finding. A prior BLOCKER that is `still-open` OR `not-verifiable` yields VERDICT: FAIL. An unresolved NOTE never yields worse than PASS WITH NOTES.
|
|
144
160
|
|
|
145
161
|
---
|
|
146
162
|
|
|
163
|
+
## What to report / what NOT to report
|
|
164
|
+
|
|
165
|
+
This list is specific to the task gate. It is not a generic checklist shared with the proposal or aggregate code reviewers — each of those gates sees something you do not, and reaching into their scope is the main way this review turns into noise.
|
|
166
|
+
|
|
167
|
+
**DO report:**
|
|
168
|
+
- The result of running this task's tests/build, quoting the real output — exact command, exit code, the relevant lines.
|
|
169
|
+
- **Match your evidence to the KIND of claim; never lower a finding's severity just because you could not run something.** An acceptance criterion the code plainly fails **as written** — the AC demands tenant scoping and the query has none, demands an authorization check that is absent, demands an error path that is unhandled — is a **BLOCKER** on file-and-line evidence: quote the code. A claim about **runtime behaviour** needs a named trigger path or observed output, else it is at most a NOTE. Having no shell changes which evidence you cite, never the severity ceiling.
|
|
170
|
+
- Judgements made against **this task's AC and this task's diff**, and nothing wider — with one explicit exception: the intent-alignment step above. Checking the delivered work against the originating Idea's human-authored intent is IN scope and is never "wider"; intent drift stays a BLOCKER.
|
|
171
|
+
- An acceptance criterion that is not actually covered by the implementation → BLOCKER.
|
|
172
|
+
- Behaviour that contradicts the approved proposal documents the task was built from.
|
|
173
|
+
|
|
174
|
+
**DO NOT report:**
|
|
175
|
+
- **Never report something as missing without first confirming its absence with read-only Bash** (`ls` / `grep` / `rg` / `find` / `git ls-files`), and cite the command you ran. An unverified "X is missing" is the single most common false BLOCKER.
|
|
176
|
+
- **Do not re-litigate decisions inside an already-approved proposal.** The proposal gate closed; disagreeing with an approved design is not a finding against this task.
|
|
177
|
+
- **Do not report pre-existing problems this task never touched** — unless this task's change makes one reachable, worse, or newly load-bearing, which makes it this change's problem and in scope. If the task's diff did not introduce it, it is not this review's finding.
|
|
178
|
+
- **Do not report gaps that belong to a different task** — the aggregate code reviewer owns inter-task gaps and will see it at the feature level. Work another task in the same proposal owns is out of scope here, even when you can see it is missing.
|
|
179
|
+
- **Never raise a BLOCKER for absent end-to-end integration tests.** Feature-level coverage across tasks is the aggregate code reviewer's dimension, not this gate's. This task's own AC is the standard here.
|
|
180
|
+
|
|
147
181
|
## Round 2+ Awareness
|
|
148
182
|
|
|
149
183
|
You may receive the current review round number in your context.
|
|
150
184
|
|
|
151
185
|
- **Round 1** — Full review at normal strictness.
|
|
152
|
-
- **Round 2+** — Focus ONLY on whether the previous BLOCKERs were fixed. Do NOT introduce new NOTEs on areas not flagged in earlier rounds. Round 1 already did the full-depth review. In Round 2+, re-read only the specific files and re-run only the specific tests/commands tied to
|
|
186
|
+
- **Round 2+** — Focus ONLY on whether the previous BLOCKERs were fixed. Do NOT introduce new NOTEs on areas not flagged in earlier rounds. Round 1 already did the full-depth review. In Round 2+, re-read only the specific files and re-run only the specific tests/commands tied to prior findings (BLOCKERs and NOTEs alike — a prior NOTE you may not re-read is a NOTE you can never close) — do not re-scan unrelated code, do not rerun the full suite, and do not probe new areas. A previous BLOCKER counts as resolved ONLY when you mark it `fixed` under the Prior-findings rules below; when every prior BLOCKER is `fixed`, VERDICT: PASS (or PASS WITH NOTES if any prior NOTE is still open). Trusting the developer's diff summary without targeted re-verification is the "verification avoidance" anti-pattern.
|
|
187
|
+
|
|
188
|
+
## Prior findings: stable IDs and cross-round acknowledgement
|
|
189
|
+
|
|
190
|
+
**Stable IDs.** Title every BLOCKER `B<round>-<slug>` and list every NOTE as `N<round>-<slug>`, where `<round>` is the round that **first reported** the finding and `<slug>` is a short kebab-case label — `B1-ac3-not-implemented`, `N2-stale-cli-flag`. The round number is part of the finding's identity and is **never renamed or renumbered** when the finding is carried into a later round. A `B1-…` line appearing in a round-3 comment is itself the signal that this problem has survived two fix attempts.
|
|
191
|
+
|
|
192
|
+
**Acknowledgement.** In round 2 and later, list **every** prior BLOCKER and **every** prior NOTE by ID under a `**Prior findings:**` block, each with exactly one of these three states and with the command you actually re-ran this round:
|
|
193
|
+
|
|
194
|
+
- `fixed` — re-verified this round; cite the command and its result.
|
|
195
|
+
- `still-open` — re-checked, and the problem is still there.
|
|
196
|
+
- `not-verifiable` — could not check it this round; say why (missing dependency, no database, environment read-only). Never counts as fixed.
|
|
197
|
+
|
|
198
|
+
Those three states are the whole vocabulary — there is no fourth state, and the same three words apply to BLOCKERs and NOTEs alike.
|
|
199
|
+
|
|
200
|
+
Three rules govern what the states mean for the verdict:
|
|
201
|
+
|
|
202
|
+
- **Silence is not a fix.** Not re-reporting a finding does not close it. Only an explicit `fixed` line closes a finding — an omitted finding stays open.
|
|
203
|
+
- **A prior BLOCKER whose state is `still-open` or `not-verifiable` yields `VERDICT: FAIL`.** Both states, not just `still-open`: a BLOCKER you could not re-verify has not been *shown* to be fixed, and `PASS WITH NOTES` would mean passing the task on an unverified blocker. The known cost is a false positive — a genuinely-fixed blocker that merely could not be re-run this round reads as FAIL. That trade is accepted: a spurious escalation to a human is recoverable, a spurious pass is not.
|
|
204
|
+
- **NOTEs never escalate.** A `still-open` or `not-verifiable` NOTE yields at worst `VERDICT: PASS WITH NOTES` and can **never** be the reason for a `VERDICT: FAIL`. Only BLOCKERs block.
|
|
205
|
+
|
|
206
|
+
**How the NOTE limit composes with the round-2+ rule above.** These are two separate rules and they never apply to the same NOTEs:
|
|
207
|
+
|
|
208
|
+
| | Newly-raised NOTEs | Carried-forward acknowledgement lines |
|
|
209
|
+
|---|---|---|
|
|
210
|
+
| Round 1 | at most 5 — past 5, drop the least relevant | none exist yet |
|
|
211
|
+
| Round 2+ | **zero** — Round awareness above already forbids new NOTEs | **all of them, written in full, never limited** |
|
|
212
|
+
|
|
213
|
+
So the limit of 5 governs newly-raised NOTEs **only**. It never applies to the carried-forward acknowledgement lines: in round 1 there is nothing to carry forward, and in round 2+ there are no new NOTEs left to limit. Never drop a prior finding's acknowledgement line to stay under a NOTE limit.
|
|
153
214
|
|
|
154
215
|
---
|
|
155
216
|
|
|
@@ -177,19 +238,24 @@ Do NOT invent other verdicts like "APPROVE" or "OK" — automation greps for the
|
|
|
177
238
|
|
|
178
239
|
## Output Format (Required)
|
|
179
240
|
|
|
180
|
-
|
|
241
|
+
BLOCKER evidence is unbounded, so never truncate it to shorten the comment; report at most 5 newly-raised NOTEs and drop the least relevant beyond that. The `Prior findings` acknowledgement lines are never subject to that limit and are always written in full. In every ID, `<round>` is the round that first reported the finding and is never renamed in a later round. No preamble, no trailing summary paragraph. PASS items: names only. NOTE items: one-line descriptions. BLOCKER items: full evidence (command + output + expected vs actual).
|
|
181
242
|
|
|
182
243
|
```
|
|
183
244
|
### Review Summary
|
|
184
245
|
|
|
246
|
+
**Prior findings:** (round 2+ only — omit this block in round 1)
|
|
247
|
+
- B1-<slug>: fixed — `<what you re-ran or re-read>` → <result observed>
|
|
248
|
+
- B1-<other-slug>: still-open — `<what you re-ran or re-read>` → <problem still present>
|
|
249
|
+
- B2-<slug>: not-verifiable — <why you could not check it this round>
|
|
250
|
+
- N1-<slug>: still-open
|
|
185
251
|
**PASS (N):** AC-1 name, AC-2 name, ...
|
|
186
252
|
|
|
187
253
|
**NOTE (M):**
|
|
188
|
-
-
|
|
189
|
-
-
|
|
254
|
+
- N<round>-<slug>: [one-line description]
|
|
255
|
+
- N<round>-<slug>: [one-line description]
|
|
190
256
|
|
|
191
257
|
**BLOCKER (K):**
|
|
192
|
-
###
|
|
258
|
+
### B<round>-<slug>
|
|
193
259
|
**Command run:** [exact command executed]
|
|
194
260
|
**Output observed:** [actual output — copy-paste, not paraphrased]
|
|
195
261
|
**Evidence:** [specific finding with file paths, line numbers]
|
package/README.ja.md
CHANGED
|
@@ -38,6 +38,8 @@ Idea ──> Proposal ──> [Document + Task DAG] ──> Execute ──> Veri
|
|
|
38
38
|
|
|
39
39
|
## 最近の更新
|
|
40
40
|
|
|
41
|
+
**[v0.19.0](https://chorus-ai.dev/blog/chorus-v0.19.0-release/)** — Cloudflare を参考にレビューの範囲を明確化し、問題の根拠を省略せず、固定 ID で再レビュー時も追跡。タスクレビューでは受け入れ基準に加え、コード品質も標準で確認します。
|
|
42
|
+
|
|
41
43
|
**[v0.18.0](https://chorus-ai.dev/blog/chorus-v0.18.0-release/)** — OpenSpec を補う、軽量で Git ネイティブなローカル Spec 管理として `spec-lite` を内蔵しました。live session anchor により、デーモンエージェントからの返信が、起点となったエージェントの既存 Idea セッションへ戻ります。
|
|
42
44
|
|
|
43
45
|
**[v0.17.2](https://chorus-ai.dev/blog/chorus-v0.17.2-release/)** — Pi が正式配布とデーモンウェイクに対応し、`chorus agents run` でローカルのエージェントプロファイルをすぐ切り替えられます。
|
|
@@ -63,7 +65,7 @@ Idea ──> Proposal ──> [Document + Task DAG] ──> Execute ──> Veri
|
|
|
63
65
|
2 つのコマンドだけです — データベースも Docker も設定ファイルも不要です。
|
|
64
66
|
|
|
65
67
|
```bash
|
|
66
|
-
npm install -g @chorus-aidlc/chorus@0.
|
|
68
|
+
npm install -g @chorus-aidlc/chorus@0.19.0
|
|
67
69
|
chorus
|
|
68
70
|
```
|
|
69
71
|
|
package/README.ko.md
CHANGED
|
@@ -38,6 +38,8 @@ Idea ──> Proposal ──> [Document + Task DAG] ──> Execute ──> Veri
|
|
|
38
38
|
|
|
39
39
|
## 최근 업데이트
|
|
40
40
|
|
|
41
|
+
**[v0.19.0](https://chorus-ai.dev/blog/chorus-v0.19.0-release/)** — Cloudflare를 참고해 리뷰 범위를 명확히 하고, 문제의 근거를 온전히 남기며, 고정 ID로 재검토까지 추적합니다. 태스크 리뷰는 인수 기준 외의 코드 품질도 기본으로 검사합니다.
|
|
42
|
+
|
|
41
43
|
**[v0.18.0](https://chorus-ai.dev/blog/chorus-v0.18.0-release/)** — OpenSpec을 보완하는 가볍고 Git 친화적인 로컬 Spec 관리 방식으로 `spec-lite`를 내장했습니다. live session anchor를 통해 데몬 에이전트의 응답이 작업을 시작한 에이전트의 기존 Idea 세션으로 돌아갑니다.
|
|
42
44
|
|
|
43
45
|
**[v0.17.2](https://chorus-ai.dev/blog/chorus-v0.17.2-release/)** — Pi를 정식 패키지와 데몬 웨이크로 사용할 수 있으며, `chorus agents run`으로 로컬 에이전트 프로파일을 빠르게 전환할 수 있습니다.
|
|
@@ -63,7 +65,7 @@ Idea ──> Proposal ──> [Document + Task DAG] ──> Execute ──> Veri
|
|
|
63
65
|
두 개의 명령이면 됩니다. 데이터베이스도, Docker도, 설정 파일도 필요 없습니다.
|
|
64
66
|
|
|
65
67
|
```bash
|
|
66
|
-
npm install -g @chorus-aidlc/chorus@0.
|
|
68
|
+
npm install -g @chorus-aidlc/chorus@0.19.0
|
|
67
69
|
chorus
|
|
68
70
|
```
|
|
69
71
|
|
package/README.md
CHANGED
|
@@ -38,6 +38,8 @@ The labels under each stage are the **permissions** an actor needs there — gra
|
|
|
38
38
|
|
|
39
39
|
## What's New
|
|
40
40
|
|
|
41
|
+
**[v0.19.0](https://chorus-ai.dev/blog/chorus-v0.19.0-release/)** — Cloudflare-inspired reviewer rules: clearer scope, complete blocker evidence, and stable finding IDs across rounds. Task reviews now check code quality beyond acceptance criteria.
|
|
42
|
+
|
|
41
43
|
**[v0.18.0](https://chorus-ai.dev/blog/chorus-v0.18.0-release/)** — Built-in `spec-lite` adds a lightweight, Git-native local spec workflow alongside OpenSpec. Live session anchors let daemon agents return replies to the initiating agent's existing Idea session.
|
|
42
44
|
|
|
43
45
|
**[v0.17.2](https://chorus-ai.dev/blog/chorus-v0.17.2-release/)** — Pi is now a published, wakeable Chorus agent, and `chorus agents run` switches local agent profiles with one command.
|
|
@@ -63,7 +65,7 @@ The labels under each stage are the **permissions** an actor needs there — gra
|
|
|
63
65
|
Two commands. No database, no Docker, no config files.
|
|
64
66
|
|
|
65
67
|
```bash
|
|
66
|
-
npm install -g @chorus-aidlc/chorus@0.
|
|
68
|
+
npm install -g @chorus-aidlc/chorus@0.19.0
|
|
67
69
|
chorus
|
|
68
70
|
```
|
|
69
71
|
|
package/README.zh.md
CHANGED
|
@@ -29,6 +29,8 @@ Idea ──> Proposal ──> [Document + Task DAG] ──> Execute ──> Veri
|
|
|
29
29
|
|
|
30
30
|
## 最近更新
|
|
31
31
|
|
|
32
|
+
**[v0.19.0](https://chorus-ai.dev/zh/blog/chorus-v0.19.0-release/)**:借鉴 Cloudflare,明确 reviewer 职责、保留完整证据,用稳定 ID 逐轮追踪问题。任务审查默认检查验收标准之外的代码质量。
|
|
33
|
+
|
|
32
34
|
**[v0.18.0](https://chorus-ai.dev/zh/blog/chorus-v0.18.0-release/)** — 内置 `spec-lite`,作为 OpenSpec 之外更轻量、可直接进 Git 的本地 Spec 管理方案。live session anchor 让 daemon Agent 的回复回到发起者已有的 Idea 会话。
|
|
33
35
|
|
|
34
36
|
**[v0.17.2](https://chorus-ai.dev/zh/blog/chorus-v0.17.2-release/)** — Pi 现在可以正式安装并由 daemon 唤醒,`chorus agents run` 还能一条命令切换本地 Agent profile。
|
|
@@ -54,7 +56,7 @@ Idea ──> Proposal ──> [Document + Task DAG] ──> Execute ──> Veri
|
|
|
54
56
|
两条命令即可,无需数据库、无需 Docker、无需配置文件。
|
|
55
57
|
|
|
56
58
|
```bash
|
|
57
|
-
npm install -g @chorus-aidlc/chorus@0.
|
|
59
|
+
npm install -g @chorus-aidlc/chorus@0.19.0
|
|
58
60
|
chorus
|
|
59
61
|
```
|
|
60
62
|
|
package/chorus.mjs
CHANGED
|
@@ -315,11 +315,39 @@ function isPortOccupied(host, tcpPort, timeoutMs = 1000) {
|
|
|
315
315
|
});
|
|
316
316
|
}
|
|
317
317
|
|
|
318
|
+
// Publicly known placeholder secrets (GitHub #559). Must stay identical to
|
|
319
|
+
// KNOWN_INSECURE_SECRETS in src/lib/secret-check.ts and
|
|
320
|
+
// CHORUS_KNOWN_INSECURE_SECRETS in docker/ensure-secret.sh (parity-tested).
|
|
321
|
+
const KNOWN_INSECURE_SECRETS = [
|
|
322
|
+
"chorus-docker-secret-change-in-production",
|
|
323
|
+
"chorus-local-secret",
|
|
324
|
+
"your-secret-key-change-in-production",
|
|
325
|
+
"change-me-to-a-random-secret",
|
|
326
|
+
];
|
|
327
|
+
|
|
318
328
|
function ensureSecret() {
|
|
319
329
|
const secretPath = join(dataDir, ".secret");
|
|
320
|
-
|
|
330
|
+
const fromEnv = process.env.NEXTAUTH_SECRET;
|
|
331
|
+
if (fromEnv) {
|
|
332
|
+
if (!KNOWN_INSECURE_SECRETS.includes(fromEnv.trim())) return;
|
|
333
|
+
// A pasted placeholder is treated exactly like "unset": fall through to the
|
|
334
|
+
// persisted / generated secret instead of signing JWTs with a public value.
|
|
335
|
+
console.error(
|
|
336
|
+
"WARNING: NEXTAUTH_SECRET is set to a publicly known placeholder (GitHub #559); ignoring it and using the persisted secret in " +
|
|
337
|
+
secretPath
|
|
338
|
+
);
|
|
339
|
+
}
|
|
321
340
|
if (existsSync(secretPath)) {
|
|
322
|
-
|
|
341
|
+
// Fail closed, matching docker/ensure-secret.sh: a persisted file that is
|
|
342
|
+
// empty or holds a publicly known placeholder must never be exported.
|
|
343
|
+
const persisted = readFileSync(secretPath, "utf8").trim();
|
|
344
|
+
if (!persisted || KNOWN_INSECURE_SECRETS.includes(persisted)) {
|
|
345
|
+
console.error(
|
|
346
|
+
`ERROR: the secret persisted at ${secretPath} is ${persisted ? "a publicly known placeholder" : "empty"} (GitHub #559); refusing to start — delete the file to regenerate, or set NEXTAUTH_SECRET explicitly.`
|
|
347
|
+
);
|
|
348
|
+
process.exit(1);
|
|
349
|
+
}
|
|
350
|
+
process.env.NEXTAUTH_SECRET = persisted;
|
|
323
351
|
return;
|
|
324
352
|
}
|
|
325
353
|
const secret = createHash("sha256")
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// cli/child-exit.mjs
|
|
2
|
+
// One shared settlement path for every spawner's child process, so the five
|
|
3
|
+
// backends (pi / claude / codex / kiro / dsh) cannot drift on "when is the wake
|
|
4
|
+
// over?".
|
|
5
|
+
//
|
|
6
|
+
// WHY THIS EXISTS — `close` is not the same event as "the agent finished".
|
|
7
|
+
// Node emits `exit` when the child process itself is reaped, but `close` only
|
|
8
|
+
// once every stdio stream the child was given has been closed. A child that
|
|
9
|
+
// leaves a DETACHED DESCENDANT behind (a backgrounded server, a `nohup`'d
|
|
10
|
+
// helper) hands that descendant the SAME inherited pipes, so the pipes stay
|
|
11
|
+
// open after the child is long gone and `close` may never fire. A spawner that
|
|
12
|
+
// waits only for `close` therefore keeps reporting a finished wake as still
|
|
13
|
+
// `running` — the phantom `running` turn. Settling on `exit` fixes that.
|
|
14
|
+
//
|
|
15
|
+
// !!! THE GRACE IS NOT A WAKE TIMEOUT AND NOT A WATCHDOG !!!
|
|
16
|
+
// `stdioGraceMs` only starts counting AFTER the child process has ALREADY
|
|
17
|
+
// EXITED, and it bounds one thing only: how long we wait for that dead
|
|
18
|
+
// process's pipes to drain so a final stdout chunk is still parsed. It places
|
|
19
|
+
// no limit whatsoever on how long an agent may run — a wake that runs for
|
|
20
|
+
// hours is never interrupted, cancelled or "timed out" by this module. No
|
|
21
|
+
// wake-duration limit is introduced anywhere here; do not repurpose this timer
|
|
22
|
+
// into one.
|
|
23
|
+
|
|
24
|
+
/** Grace for an already-exited process's pipes to drain. NOT a wake timeout. */
|
|
25
|
+
export const DEFAULT_STDIO_GRACE_MS = 2000;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Resolve once with the child's exit code as soon as the process is KNOWN to be gone.
|
|
29
|
+
*
|
|
30
|
+
* • `close` first → resolve immediately (today's behaviour, zero regression).
|
|
31
|
+
* • `exit` first → wait up to `stdioGraceMs` for `close` (so a last stdout chunk
|
|
32
|
+
* is still parsed), then resolve with the exit code anyway.
|
|
33
|
+
*
|
|
34
|
+
* Settles exactly once and NEVER rejects. The grace timer is `unref`'d so it can
|
|
35
|
+
* never hold the daemon's event loop open.
|
|
36
|
+
*
|
|
37
|
+
* @param {import("node:child_process").ChildProcess} child
|
|
38
|
+
* @param {{ stdioGraceMs?: number, logger?: { warn?: (msg: string) => void }, label?: string }} [options]
|
|
39
|
+
* @returns {Promise<number | null>} the exit code (`null` when the child was signalled)
|
|
40
|
+
*/
|
|
41
|
+
export function awaitChildSettled(child, options = {}) {
|
|
42
|
+
const { stdioGraceMs = DEFAULT_STDIO_GRACE_MS, logger, label = "child" } = options;
|
|
43
|
+
|
|
44
|
+
return new Promise((resolve) => {
|
|
45
|
+
let settled = false;
|
|
46
|
+
let timer = null;
|
|
47
|
+
|
|
48
|
+
const settle = (code) => {
|
|
49
|
+
if (settled) return;
|
|
50
|
+
settled = true;
|
|
51
|
+
if (timer) {
|
|
52
|
+
clearTimeout(timer);
|
|
53
|
+
timer = null;
|
|
54
|
+
}
|
|
55
|
+
resolve(code ?? null);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
child.on?.("close", (code) => settle(code));
|
|
59
|
+
|
|
60
|
+
child.on?.("exit", (code) => {
|
|
61
|
+
if (settled || timer) return;
|
|
62
|
+
// The process is gone; give its (possibly descendant-held) pipes a bounded
|
|
63
|
+
// moment to drain, then settle regardless. See the header: not a timeout.
|
|
64
|
+
timer = setTimeout(() => {
|
|
65
|
+
timer = null;
|
|
66
|
+
if (settled) return;
|
|
67
|
+
logger?.warn?.(
|
|
68
|
+
`[Chorus] ${label} exited (code ${code ?? null}) but stdio stayed open for ` +
|
|
69
|
+
`${stdioGraceMs}ms; settling on exit`
|
|
70
|
+
);
|
|
71
|
+
settle(code);
|
|
72
|
+
}, stdioGraceMs);
|
|
73
|
+
// Never keep the daemon's event loop alive for a dead process's pipes.
|
|
74
|
+
timer?.unref?.();
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
}
|
package/cli/claude-spawner.mjs
CHANGED
|
@@ -28,6 +28,7 @@ import { validateAgentCliConfig, overlayAgentEnv, getAgentEnv, assertConfiguredS
|
|
|
28
28
|
import { existsSync, statSync } from "node:fs";
|
|
29
29
|
import { homedir } from "node:os";
|
|
30
30
|
import { win32 as pathWin32, posix as pathPosix, join as pathJoin } from "node:path";
|
|
31
|
+
import { awaitChildSettled } from "./child-exit.mjs";
|
|
31
32
|
|
|
32
33
|
const NOOP_LOGGER = { info() {}, warn() {}, error() {} };
|
|
33
34
|
|
|
@@ -447,7 +448,9 @@ export class ClaudeSpawner {
|
|
|
447
448
|
resolve({ sessionId: observedSessionId, backendSessionId: id, exitCode: null, isNew });
|
|
448
449
|
});
|
|
449
450
|
|
|
450
|
-
|
|
451
|
+
// Settle on process exit, not only on stdio close: a detached descendant can
|
|
452
|
+
// inherit the pipes and keep `close` from ever firing (see cli/child-exit.mjs).
|
|
453
|
+
awaitChildSettled(child, { logger: this.logger, label: "claude" }).then((code) => {
|
|
451
454
|
if (code !== 0) {
|
|
452
455
|
this.logger.warn(`[Chorus] claude exited with code ${code}`);
|
|
453
456
|
}
|
package/cli/codex-spawner.mjs
CHANGED
|
@@ -33,6 +33,7 @@ import { readFileSync, statSync } from "node:fs";
|
|
|
33
33
|
import { homedir } from "node:os";
|
|
34
34
|
import { join, win32 as pathWin32, posix as pathPosix } from "node:path";
|
|
35
35
|
import { parseNdjsonChunk } from "./claude-spawner.mjs";
|
|
36
|
+
import { awaitChildSettled } from "./child-exit.mjs";
|
|
36
37
|
import { getThreadId as defaultGetThreadId, setThreadId as defaultSetThreadId } from "./codex-session-map.mjs";
|
|
37
38
|
import {
|
|
38
39
|
getCodexUsageSnapshot as defaultGetUsageSnapshot,
|
|
@@ -370,7 +371,9 @@ export class CodexSpawner {
|
|
|
370
371
|
resolve({ sessionId: anchor, backendSessionId: observedThreadId, exitCode: null, isNew });
|
|
371
372
|
});
|
|
372
373
|
|
|
373
|
-
|
|
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) => {
|
|
374
377
|
if (code !== 0) {
|
|
375
378
|
this.logger.warn(`[Chorus] codex exited with code ${code}`);
|
|
376
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.
|