crewly 1.6.4 → 1.6.5
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/config/roles/architect/prompt.md +68 -2
- package/config/roles/auditor/prompt.md +68 -0
- package/config/roles/backend-developer/prompt.md +68 -2
- package/config/roles/content-strategist/prompt.md +73 -5
- package/config/roles/designer/prompt.md +69 -4
- package/config/roles/developer/prompt.md +231 -4
- package/config/roles/frontend-developer/prompt.md +68 -2
- package/config/roles/fullstack-dev/prompt.md +68 -2
- package/config/roles/generalist/prompt.md +68 -2
- package/config/roles/ops/prompt.md +69 -3
- package/config/roles/orchestrator/fragments/communication.md +27 -0
- package/config/roles/orchestrator/fragments/role-boundary.md +1 -1
- package/config/roles/orchestrator/prompt.md +215 -72
- package/config/roles/product-manager/prompt.md +140 -7
- package/config/roles/qa/prompt.md +70 -5
- package/config/roles/qa-engineer/prompt.md +70 -5
- package/config/roles/researcher/prompt.md +68 -2
- package/config/roles/sales/prompt.md +70 -5
- package/config/roles/support/prompt.md +69 -4
- package/config/roles/team-leader/prompt.md +87 -6
- package/config/roles/team-leader/role-boundaries.md +26 -0
- package/config/roles/team-leader/tl-addon.md +153 -1
- package/config/roles/tpm/prompt.md +68 -2
- package/config/roles/ux-designer/prompt.md +70 -5
- package/config/skills/_common/complete-body-shape.test.sh +249 -0
- package/config/skills/agent/core/accept-task/execute.sh +18 -15
- package/config/skills/agent/core/block-task/execute.sh +27 -9
- package/config/skills/agent/core/cancel-followup/SKILL.md +18 -0
- package/config/skills/agent/core/complete-task/execute.sh +45 -7
- package/config/skills/agent/core/create-task/execute.sh +40 -12
- package/config/skills/agent/core/get-my-active-work/SKILL.md +3 -1
- package/config/skills/agent/core/get-my-tasks/execute.sh +7 -5
- package/config/skills/agent/core/handoff-task/execute.sh +34 -48
- package/config/skills/agent/core/list-my-followups/SKILL.md +18 -0
- package/config/skills/agent/core/read-task/execute.sh +21 -8
- package/config/skills/agent/core/recall/SKILL.md +7 -0
- package/config/skills/agent/core/remember/SKILL.md +17 -1
- package/config/skills/agent/core/remember/execute.sh +5 -1
- package/config/skills/agent/core/reply-channel/SKILL.md +19 -0
- package/config/skills/agent/core/report-progress/execute.sh +39 -16
- package/config/skills/agent/core/report-status/execute.sh +36 -12
- package/config/skills/agent/core/save-working-state/execute.sh +17 -6
- package/config/skills/agent/core/schedule-followup/SKILL.md +19 -0
- package/config/skills/agent/core/send-message/SKILL.md +6 -0
- package/config/skills/agent/core/supersede-memory/SKILL.md +76 -0
- package/config/skills/agent/core/supersede-memory/execute.sh +108 -0
- package/config/skills/agent/core/watch-for-event/SKILL.md +19 -0
- package/config/skills/agent/onboarding/materialize-team/SKILL.md +94 -0
- package/config/skills/agent/onboarding/materialize-team/execute.sh +98 -0
- package/config/skills/agent/onboarding/recommend-team/SKILL.md +90 -0
- package/config/skills/agent/onboarding/recommend-team/execute.sh +96 -0
- package/config/skills/agent/xhs-article-to-image/SKILL.md +20 -0
- package/config/skills/auditor/score-task/SKILL.md +15 -0
- package/config/skills/orchestrator/assign-task/execute.sh +28 -4
- package/config/skills/orchestrator/cancel-all-schedules/SKILL.md +15 -1
- package/config/skills/orchestrator/complete-task/execute.sh +45 -4
- package/config/skills/orchestrator/delegate-task/SKILL.md +1 -0
- package/config/skills/orchestrator/delegate-task/execute.sh +41 -2
- package/config/skills/orchestrator/get-tasks/execute.sh +22 -18
- package/config/skills/orchestrator/list-schedules/SKILL.md +15 -1
- package/config/skills/orchestrator/update-team-member/SKILL.md +20 -0
- package/config/skills/team-leader/decompose-goal/execute.sh +51 -20
- package/config/skills/team-leader/delegate-task/execute.sh +67 -26
- package/config/skills/team-leader/delegate-task/execute.test.sh +117 -0
- package/config/skills/team-leader/verify-output/execute.sh +19 -20
- package/config/slack-app-manifest.json +2 -1
- package/config/sops/common/dev-process-tiers.md +181 -0
- package/config/sops/common/owner-facing-communication.md +131 -0
- package/config/souls/orchestrator.md +8 -0
- package/config/souls/team-leader.md +77 -0
- package/dist/backend/backend/src/controllers/active-work/active-work.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/active-work/active-work.controller.js +4 -1
- package/dist/backend/backend/src/controllers/active-work/active-work.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/agent-stream/agent-stream.controller.d.ts +8 -1
- package/dist/backend/backend/src/controllers/agent-stream/agent-stream.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/agent-stream/agent-stream.controller.js +30 -26
- package/dist/backend/backend/src/controllers/agent-stream/agent-stream.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/api.controller.d.ts +0 -9
- package/dist/backend/backend/src/controllers/api.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/api.controller.js +4 -32
- package/dist/backend/backend/src/controllers/api.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/chat/chat.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/chat/chat.controller.js +5 -2
- package/dist/backend/backend/src/controllers/chat/chat.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.js +5 -2
- package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/checklist/checklist.controller.d.ts +45 -0
- package/dist/backend/backend/src/controllers/checklist/checklist.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/checklist/checklist.controller.js +122 -0
- package/dist/backend/backend/src/controllers/checklist/checklist.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/memory/memory.controller.d.ts +24 -0
- package/dist/backend/backend/src/controllers/memory/memory.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/memory/memory.controller.js +69 -1
- package/dist/backend/backend/src/controllers/memory/memory.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/memory/memory.routes.d.ts +1 -0
- package/dist/backend/backend/src/controllers/memory/memory.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/memory/memory.routes.js +3 -1
- package/dist/backend/backend/src/controllers/memory/memory.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/monitoring/terminal.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/monitoring/terminal.controller.js +80 -5
- package/dist/backend/backend/src/controllers/monitoring/terminal.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/onboarding/onboarding.routes.d.ts +1 -0
- package/dist/backend/backend/src/controllers/onboarding/onboarding.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/onboarding/onboarding.routes.js +30 -0
- package/dist/backend/backend/src/controllers/onboarding/onboarding.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/orchestrator-onboarding/orchestrator-onboarding.controller.d.ts +41 -0
- package/dist/backend/backend/src/controllers/orchestrator-onboarding/orchestrator-onboarding.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/orchestrator-onboarding/orchestrator-onboarding.controller.js +213 -0
- package/dist/backend/backend/src/controllers/orchestrator-onboarding/orchestrator-onboarding.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/orchestrator-onboarding/orchestrator-onboarding.routes.d.ts +21 -0
- package/dist/backend/backend/src/controllers/orchestrator-onboarding/orchestrator-onboarding.routes.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/orchestrator-onboarding/orchestrator-onboarding.routes.js +27 -0
- package/dist/backend/backend/src/controllers/orchestrator-onboarding/orchestrator-onboarding.routes.js.map +1 -0
- package/dist/backend/backend/src/controllers/slack/slack.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/slack/slack.controller.js +97 -0
- package/dist/backend/backend/src/controllers/slack/slack.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/task-management/in-progress-tasks.controller.d.ts +13 -3
- package/dist/backend/backend/src/controllers/task-management/in-progress-tasks.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/task-management/in-progress-tasks.controller.js +29 -24
- package/dist/backend/backend/src/controllers/task-management/in-progress-tasks.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/task-management/tasks.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/task-management/tasks.controller.js +61 -13
- package/dist/backend/backend/src/controllers/task-management/tasks.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.d.ts +159 -7
- package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.js +421 -37
- package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/task-pool/task-pool.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/task-pool/task-pool.routes.js +15 -1
- package/dist/backend/backend/src/controllers/task-pool/task-pool.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/team/team.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/team/team.controller.js +221 -10
- package/dist/backend/backend/src/controllers/team/team.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/teams-backup/teams-backup.controller.d.ts +22 -0
- package/dist/backend/backend/src/controllers/teams-backup/teams-backup.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/teams-backup/teams-backup.controller.js +92 -0
- package/dist/backend/backend/src/controllers/teams-backup/teams-backup.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/teams-backup/teams-backup.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/teams-backup/teams-backup.routes.js +6 -2
- package/dist/backend/backend/src/controllers/teams-backup/teams-backup.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/types.d.ts +1 -2
- package/dist/backend/backend/src/controllers/types.d.ts.map +1 -1
- package/dist/backend/backend/src/index.d.ts +4 -1
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +291 -64
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/models/Project.d.ts +2 -0
- package/dist/backend/backend/src/models/Project.d.ts.map +1 -1
- package/dist/backend/backend/src/models/Project.js +10 -1
- package/dist/backend/backend/src/models/Project.js.map +1 -1
- package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/routes/api.routes.js +4 -1
- package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
- package/dist/backend/backend/src/routes/modules/task-management.routes.d.ts +15 -0
- package/dist/backend/backend/src/routes/modules/task-management.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/routes/modules/task-management.routes.js +23 -43
- package/dist/backend/backend/src/routes/modules/task-management.routes.js.map +1 -1
- package/dist/backend/backend/src/scripts/cleanup-stale-pool.lib.d.ts +87 -0
- package/dist/backend/backend/src/scripts/cleanup-stale-pool.lib.d.ts.map +1 -0
- package/dist/backend/backend/src/scripts/cleanup-stale-pool.lib.js +116 -0
- package/dist/backend/backend/src/scripts/cleanup-stale-pool.lib.js.map +1 -0
- package/dist/backend/backend/src/services/agent/active-work-briefing.service.d.ts +46 -6
- package/dist/backend/backend/src/services/agent/active-work-briefing.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/active-work-briefing.service.js +56 -13
- package/dist/backend/backend/src/services/agent/active-work-briefing.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts +9 -0
- package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.js +28 -3
- package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/context-window-monitor.service.d.ts +31 -5
- package/dist/backend/backend/src/services/agent/context-window-monitor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/context-window-monitor.service.js +69 -29
- package/dist/backend/backend/src/services/agent/context-window-monitor.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.js +113 -75
- package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/auditor-tools.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/auditor-tools.js +5 -3
- package/dist/backend/backend/src/services/agent/crewly-agent/auditor-tools.js.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-runtime.service.d.ts +35 -0
- package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-runtime.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-runtime.service.js +127 -3
- package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-runtime.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/deepseek-sse-transform.d.ts +79 -0
- package/dist/backend/backend/src/services/agent/crewly-agent/deepseek-sse-transform.d.ts.map +1 -0
- package/dist/backend/backend/src/services/agent/crewly-agent/deepseek-sse-transform.js +145 -0
- package/dist/backend/backend/src/services/agent/crewly-agent/deepseek-sse-transform.js.map +1 -0
- package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.d.ts +64 -9
- package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.js +125 -15
- package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.js.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/tool-registry.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/tool-registry.js +101 -33
- package/dist/backend/backend/src/services/agent/crewly-agent/tool-registry.js.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/types.d.ts +76 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/types.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/types.js +73 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/types.js.map +1 -1
- package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.d.ts +5 -5
- package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.js +22 -8
- package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-builder.service.d.ts +10 -0
- package/dist/backend/backend/src/services/ai/prompt-builder.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-builder.service.js +160 -4
- package/dist/backend/backend/src/services/ai/prompt-builder.service.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/communication.module.d.ts +37 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/communication.module.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/communication.module.js +77 -3
- package/dist/backend/backend/src/services/ai/prompt-modules/communication.module.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/decision-rights.module.d.ts +59 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/decision-rights.module.d.ts.map +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/decision-rights.module.js +87 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/decision-rights.module.js.map +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/default-execution-loop.module.d.ts +67 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/default-execution-loop.module.d.ts.map +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/default-execution-loop.module.js +84 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/default-execution-loop.module.js.map +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/index.d.ts +4 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/index.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/index.js +4 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/index.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/lazy-anti-patterns.module.d.ts +65 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/lazy-anti-patterns.module.d.ts.map +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/lazy-anti-patterns.module.js +79 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/lazy-anti-patterns.module.js.map +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/mission-context.module.d.ts +60 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/mission-context.module.d.ts.map +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/mission-context.module.js +104 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/mission-context.module.js.map +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/prompt-assembly.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/prompt-assembly.service.js +45 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/prompt-assembly.service.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/prompt-module.interface.d.ts +16 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/prompt-module.interface.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/prompt-module.interface.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/request-contract.module.d.ts +106 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/request-contract.module.d.ts.map +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/request-contract.module.js +167 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/request-contract.module.js.map +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/role-boundary.module.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/role-boundary.module.js +28 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/role-boundary.module.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/soul.module.d.ts +38 -6
- package/dist/backend/backend/src/services/ai/prompt-modules/soul.module.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/soul.module.js +73 -10
- package/dist/backend/backend/src/services/ai/prompt-modules/soul.module.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/working-memory.module.d.ts +91 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/working-memory.module.d.ts.map +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/working-memory.module.js +136 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/working-memory.module.js.map +1 -0
- package/dist/backend/backend/src/services/autonomous/index.d.ts +7 -3
- package/dist/backend/backend/src/services/autonomous/index.d.ts.map +1 -1
- package/dist/backend/backend/src/services/autonomous/index.js +7 -3
- package/dist/backend/backend/src/services/autonomous/index.js.map +1 -1
- package/dist/backend/backend/src/services/browser/browser-bridge.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/browser/browser-bridge.service.js +16 -22
- package/dist/backend/backend/src/services/browser/browser-bridge.service.js.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/chat-v2.service.d.ts +13 -0
- package/dist/backend/backend/src/services/chat-v2/chat-v2.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/chat-v2.service.js +15 -0
- package/dist/backend/backend/src/services/chat-v2/chat-v2.service.js.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/sqlite/chat-db.d.ts +11 -0
- package/dist/backend/backend/src/services/chat-v2/sqlite/chat-db.d.ts.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/sqlite/chat-db.js +51 -19
- package/dist/backend/backend/src/services/chat-v2/sqlite/chat-db.js.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.d.ts +18 -0
- package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.d.ts.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.js +23 -0
- package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.js.map +1 -1
- package/dist/backend/backend/src/services/core/config.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/core/config.service.js +8 -1
- package/dist/backend/backend/src/services/core/config.service.js.map +1 -1
- package/dist/backend/backend/src/services/core/crewly-home.utils.d.ts +51 -0
- package/dist/backend/backend/src/services/core/crewly-home.utils.d.ts.map +1 -0
- package/dist/backend/backend/src/services/core/crewly-home.utils.js +59 -0
- package/dist/backend/backend/src/services/core/crewly-home.utils.js.map +1 -0
- package/dist/backend/backend/src/services/core/state-invariant.types.d.ts +53 -0
- package/dist/backend/backend/src/services/core/state-invariant.types.d.ts.map +1 -0
- package/dist/backend/backend/src/services/core/state-invariant.types.js +61 -0
- package/dist/backend/backend/src/services/core/state-invariant.types.js.map +1 -0
- package/dist/backend/backend/src/services/core/storage.service.d.ts +20 -0
- package/dist/backend/backend/src/services/core/storage.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/core/storage.service.js +96 -8
- package/dist/backend/backend/src/services/core/storage.service.js.map +1 -1
- package/dist/backend/backend/src/services/core/teams-backup.service.d.ts +94 -4
- package/dist/backend/backend/src/services/core/teams-backup.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/core/teams-backup.service.js +172 -10
- package/dist/backend/backend/src/services/core/teams-backup.service.js.map +1 -1
- package/dist/backend/backend/src/services/index.d.ts +0 -2
- package/dist/backend/backend/src/services/index.d.ts.map +1 -1
- package/dist/backend/backend/src/services/index.js +0 -2
- package/dist/backend/backend/src/services/index.js.map +1 -1
- package/dist/backend/backend/src/services/intent-task/intent-classifier.fixture.d.ts +78 -0
- package/dist/backend/backend/src/services/intent-task/intent-classifier.fixture.d.ts.map +1 -0
- package/dist/backend/backend/src/services/intent-task/intent-classifier.fixture.js +209 -0
- package/dist/backend/backend/src/services/intent-task/intent-classifier.fixture.js.map +1 -0
- package/dist/backend/backend/src/services/intent-task/intent-classifier.rules.d.ts +331 -0
- package/dist/backend/backend/src/services/intent-task/intent-classifier.rules.d.ts.map +1 -0
- package/dist/backend/backend/src/services/intent-task/intent-classifier.rules.js +413 -0
- package/dist/backend/backend/src/services/intent-task/intent-classifier.rules.js.map +1 -0
- package/dist/backend/backend/src/services/intent-task/intent-task.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/intent-task/intent-task.service.js +13 -4
- package/dist/backend/backend/src/services/intent-task/intent-task.service.js.map +1 -1
- package/dist/backend/backend/src/services/knowledge/fts5-index.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/knowledge/fts5-index.service.js +18 -13
- package/dist/backend/backend/src/services/knowledge/fts5-index.service.js.map +1 -1
- package/dist/backend/backend/src/services/knowledge/fts5-query-sanitizer.d.ts +102 -0
- package/dist/backend/backend/src/services/knowledge/fts5-query-sanitizer.d.ts.map +1 -0
- package/dist/backend/backend/src/services/knowledge/fts5-query-sanitizer.js +118 -0
- package/dist/backend/backend/src/services/knowledge/fts5-query-sanitizer.js.map +1 -0
- package/dist/backend/backend/src/services/knowledge/vector-store.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/knowledge/vector-store.service.js +11 -15
- package/dist/backend/backend/src/services/knowledge/vector-store.service.js.map +1 -1
- package/dist/backend/backend/src/services/memory/agent-memory.service.d.ts +20 -0
- package/dist/backend/backend/src/services/memory/agent-memory.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/memory/agent-memory.service.js +27 -2
- package/dist/backend/backend/src/services/memory/agent-memory.service.js.map +1 -1
- package/dist/backend/backend/src/services/memory/memory-supersession.service.d.ts +104 -0
- package/dist/backend/backend/src/services/memory/memory-supersession.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/memory/memory-supersession.service.js +127 -0
- package/dist/backend/backend/src/services/memory/memory-supersession.service.js.map +1 -0
- package/dist/backend/backend/src/services/memory/memory.service.d.ts +48 -17
- package/dist/backend/backend/src/services/memory/memory.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/memory/memory.service.js +65 -35
- package/dist/backend/backend/src/services/memory/memory.service.js.map +1 -1
- package/dist/backend/backend/src/services/memory/mission-context.service.d.ts +168 -0
- package/dist/backend/backend/src/services/memory/mission-context.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/memory/mission-context.service.js +365 -0
- package/dist/backend/backend/src/services/memory/mission-context.service.js.map +1 -0
- package/dist/backend/backend/src/services/memory/role-knowledge-eligibility.d.ts +138 -0
- package/dist/backend/backend/src/services/memory/role-knowledge-eligibility.d.ts.map +1 -0
- package/dist/backend/backend/src/services/memory/role-knowledge-eligibility.js +183 -0
- package/dist/backend/backend/src/services/memory/role-knowledge-eligibility.js.map +1 -0
- package/dist/backend/backend/src/services/memory/vector-store.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/memory/vector-store.service.js +7 -11
- package/dist/backend/backend/src/services/memory/vector-store.service.js.map +1 -1
- package/dist/backend/backend/src/services/memory/working-memory.service.d.ts +232 -0
- package/dist/backend/backend/src/services/memory/working-memory.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/memory/working-memory.service.js +417 -0
- package/dist/backend/backend/src/services/memory/working-memory.service.js.map +1 -0
- package/dist/backend/backend/src/services/messaging/queue-processor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/messaging/queue-processor.service.js +23 -2
- package/dist/backend/backend/src/services/messaging/queue-processor.service.js.map +1 -1
- package/dist/backend/backend/src/services/monitoring/activity-monitor.service.js +2 -2
- package/dist/backend/backend/src/services/monitoring/activity-monitor.service.js.map +1 -1
- package/dist/backend/backend/src/services/monitoring/team-activity-websocket.service.d.ts +27 -7
- package/dist/backend/backend/src/services/monitoring/team-activity-websocket.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/monitoring/team-activity-websocket.service.js +66 -27
- package/dist/backend/backend/src/services/monitoring/team-activity-websocket.service.js.map +1 -1
- package/dist/backend/backend/src/services/monitoring/teams-json-watcher.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/monitoring/teams-json-watcher.service.js +2 -2
- package/dist/backend/backend/src/services/monitoring/teams-json-watcher.service.js.map +1 -1
- package/dist/backend/backend/src/services/observability/agent-behavior-log.service.d.ts +132 -0
- package/dist/backend/backend/src/services/observability/agent-behavior-log.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/observability/agent-behavior-log.service.js +284 -0
- package/dist/backend/backend/src/services/observability/agent-behavior-log.service.js.map +1 -0
- package/dist/backend/backend/src/services/observability/agent-behavior-log.singleton.d.ts +70 -0
- package/dist/backend/backend/src/services/observability/agent-behavior-log.singleton.d.ts.map +1 -0
- package/dist/backend/backend/src/services/observability/agent-behavior-log.singleton.js +121 -0
- package/dist/backend/backend/src/services/observability/agent-behavior-log.singleton.js.map +1 -0
- package/dist/backend/backend/src/services/observability/agent-behavior-log.types.d.ts +130 -0
- package/dist/backend/backend/src/services/observability/agent-behavior-log.types.d.ts.map +1 -0
- package/dist/backend/backend/src/services/observability/agent-behavior-log.types.js +48 -0
- package/dist/backend/backend/src/services/observability/agent-behavior-log.types.js.map +1 -0
- package/dist/backend/backend/src/services/observability/observability-db.d.ts +84 -0
- package/dist/backend/backend/src/services/observability/observability-db.d.ts.map +1 -0
- package/dist/backend/backend/src/services/observability/observability-db.js +165 -0
- package/dist/backend/backend/src/services/observability/observability-db.js.map +1 -0
- package/dist/backend/backend/src/services/onboarding/onboarding.service.d.ts +22 -0
- package/dist/backend/backend/src/services/onboarding/onboarding.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/onboarding/onboarding.service.js +36 -0
- package/dist/backend/backend/src/services/onboarding/onboarding.service.js.map +1 -1
- package/dist/backend/backend/src/services/onboarding/onboarding.types.d.ts +21 -2
- package/dist/backend/backend/src/services/onboarding/onboarding.types.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/improvement-marker.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/improvement-marker.service.js +12 -3
- package/dist/backend/backend/src/services/orchestrator/improvement-marker.service.js.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/onboarding/materialize-team.d.ts +108 -0
- package/dist/backend/backend/src/services/orchestrator/onboarding/materialize-team.d.ts.map +1 -0
- package/dist/backend/backend/src/services/orchestrator/onboarding/materialize-team.js +165 -0
- package/dist/backend/backend/src/services/orchestrator/onboarding/materialize-team.js.map +1 -0
- package/dist/backend/backend/src/services/orchestrator/onboarding/recommend-team.d.ts +114 -0
- package/dist/backend/backend/src/services/orchestrator/onboarding/recommend-team.d.ts.map +1 -0
- package/dist/backend/backend/src/services/orchestrator/onboarding/recommend-team.js +299 -0
- package/dist/backend/backend/src/services/orchestrator/onboarding/recommend-team.js.map +1 -0
- package/dist/backend/backend/src/services/orchestrator/onboarding-bootstrap.service.d.ts +128 -0
- package/dist/backend/backend/src/services/orchestrator/onboarding-bootstrap.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/orchestrator/onboarding-bootstrap.service.js +195 -0
- package/dist/backend/backend/src/services/orchestrator/onboarding-bootstrap.service.js.map +1 -0
- package/dist/backend/backend/src/services/orchestrator/onboarding-mode-loader.d.ts +66 -0
- package/dist/backend/backend/src/services/orchestrator/onboarding-mode-loader.d.ts.map +1 -0
- package/dist/backend/backend/src/services/orchestrator/onboarding-mode-loader.js +145 -0
- package/dist/backend/backend/src/services/orchestrator/onboarding-mode-loader.js.map +1 -0
- package/dist/backend/backend/src/services/orchestrator/onboarding-mode.skill-allowlist.d.ts +59 -0
- package/dist/backend/backend/src/services/orchestrator/onboarding-mode.skill-allowlist.d.ts.map +1 -0
- package/dist/backend/backend/src/services/orchestrator/onboarding-mode.skill-allowlist.js +68 -0
- package/dist/backend/backend/src/services/orchestrator/onboarding-mode.skill-allowlist.js.map +1 -0
- package/dist/backend/backend/src/services/orchestrator/prompts/onboarding-mode.prompt.d.ts +67 -0
- package/dist/backend/backend/src/services/orchestrator/prompts/onboarding-mode.prompt.d.ts.map +1 -0
- package/dist/backend/backend/src/services/orchestrator/prompts/onboarding-mode.prompt.js +290 -0
- package/dist/backend/backend/src/services/orchestrator/prompts/onboarding-mode.prompt.js.map +1 -0
- package/dist/backend/backend/src/services/orchestrator/state-persistence.service.d.ts +23 -1
- package/dist/backend/backend/src/services/orchestrator/state-persistence.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/state-persistence.service.js +64 -1
- package/dist/backend/backend/src/services/orchestrator/state-persistence.service.js.map +1 -1
- package/dist/backend/backend/src/services/project/active-projects.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/project/active-projects.service.js +2 -2
- package/dist/backend/backend/src/services/project/active-projects.service.js.map +1 -1
- package/dist/backend/backend/src/services/project/task-tracking.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/project/task-tracking.service.js +2 -2
- package/dist/backend/backend/src/services/project/task-tracking.service.js.map +1 -1
- package/dist/backend/backend/src/services/prompt/prompt-generator.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/prompt/prompt-generator.service.js +2 -2
- package/dist/backend/backend/src/services/prompt/prompt-generator.service.js.map +1 -1
- package/dist/backend/backend/src/services/reconciler/reconcile-rules.d.ts +51 -5
- package/dist/backend/backend/src/services/reconciler/reconcile-rules.d.ts.map +1 -1
- package/dist/backend/backend/src/services/reconciler/reconcile-rules.js +162 -15
- package/dist/backend/backend/src/services/reconciler/reconcile-rules.js.map +1 -1
- package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.d.ts +15 -2
- package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.d.ts.map +1 -1
- package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.js +153 -11
- package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.js.map +1 -1
- package/dist/backend/backend/src/services/session/session-handoff.service.d.ts +31 -18
- package/dist/backend/backend/src/services/session/session-handoff.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/session/session-handoff.service.js +73 -80
- package/dist/backend/backend/src/services/session/session-handoff.service.js.map +1 -1
- package/dist/backend/backend/src/services/session/session-state-persistence.d.ts.map +1 -1
- package/dist/backend/backend/src/services/session/session-state-persistence.js +15 -4
- package/dist/backend/backend/src/services/session/session-state-persistence.js.map +1 -1
- package/dist/backend/backend/src/services/settings/settings.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/settings/settings.service.js +25 -0
- package/dist/backend/backend/src/services/settings/settings.service.js.map +1 -1
- package/dist/backend/backend/src/services/skill/skill-catalog.service.d.ts +14 -3
- package/dist/backend/backend/src/services/skill/skill-catalog.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/skill/skill-catalog.service.js +28 -3
- package/dist/backend/backend/src/services/skill/skill-catalog.service.js.map +1 -1
- package/dist/backend/backend/src/services/slack/cross-machine-message.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/cross-machine-message.service.js +13 -18
- package/dist/backend/backend/src/services/slack/cross-machine-message.service.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts +45 -0
- package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js +202 -19
- package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack.service.js +21 -0
- package/dist/backend/backend/src/services/slack/slack.service.js.map +1 -1
- package/dist/backend/backend/src/services/task-pool/pool-storage.d.ts +15 -1
- package/dist/backend/backend/src/services/task-pool/pool-storage.d.ts.map +1 -1
- package/dist/backend/backend/src/services/task-pool/pool-storage.js +31 -8
- package/dist/backend/backend/src/services/task-pool/pool-storage.js.map +1 -1
- package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts +183 -0
- package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/task-pool/task-pool.service.js +404 -8
- package/dist/backend/backend/src/services/task-pool/task-pool.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/agent-auto-claim.service.d.ts +14 -1
- package/dist/backend/backend/src/services/v3/agent-auto-claim.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/agent-auto-claim.service.js +128 -17
- package/dist/backend/backend/src/services/v3/agent-auto-claim.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/cascade-request-status.d.ts +95 -0
- package/dist/backend/backend/src/services/v3/cascade-request-status.d.ts.map +1 -0
- package/dist/backend/backend/src/services/v3/cascade-request-status.js +147 -0
- package/dist/backend/backend/src/services/v3/cascade-request-status.js.map +1 -0
- package/dist/backend/backend/src/services/v3/escalation-router.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/escalation-router.service.js +42 -0
- package/dist/backend/backend/src/services/v3/escalation-router.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/mission-executor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/mission-executor.service.js +16 -4
- package/dist/backend/backend/src/services/v3/mission-executor.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/request-cascade.subscriber.d.ts +87 -0
- package/dist/backend/backend/src/services/v3/request-cascade.subscriber.d.ts.map +1 -0
- package/dist/backend/backend/src/services/v3/request-cascade.subscriber.js +152 -0
- package/dist/backend/backend/src/services/v3/request-cascade.subscriber.js.map +1 -0
- package/dist/backend/backend/src/services/v3/request-decompose.subscriber.d.ts +253 -0
- package/dist/backend/backend/src/services/v3/request-decompose.subscriber.d.ts.map +1 -0
- package/dist/backend/backend/src/services/v3/request-decompose.subscriber.js +476 -0
- package/dist/backend/backend/src/services/v3/request-decompose.subscriber.js.map +1 -0
- package/dist/backend/backend/src/services/v3/request-sla.subscriber.d.ts +55 -0
- package/dist/backend/backend/src/services/v3/request-sla.subscriber.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/request-sla.subscriber.js +257 -20
- package/dist/backend/backend/src/services/v3/request-sla.subscriber.js.map +1 -1
- package/dist/backend/backend/src/services/v3/request-status-update.subscriber.d.ts +204 -0
- package/dist/backend/backend/src/services/v3/request-status-update.subscriber.d.ts.map +1 -0
- package/dist/backend/backend/src/services/v3/request-status-update.subscriber.js +575 -0
- package/dist/backend/backend/src/services/v3/request-status-update.subscriber.js.map +1 -0
- package/dist/backend/backend/src/services/v3/request.service.d.ts +107 -0
- package/dist/backend/backend/src/services/v3/request.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/request.service.js +155 -2
- package/dist/backend/backend/src/services/v3/request.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/trigger-engine.service.d.ts +69 -1
- package/dist/backend/backend/src/services/v3/trigger-engine.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/trigger-engine.service.js +157 -4
- package/dist/backend/backend/src/services/v3/trigger-engine.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/v3-data.service.d.ts +50 -26
- package/dist/backend/backend/src/services/v3/v3-data.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/v3-data.service.js +126 -161
- package/dist/backend/backend/src/services/v3/v3-data.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/work-item-projection.d.ts +40 -0
- package/dist/backend/backend/src/services/v3/work-item-projection.d.ts.map +1 -0
- package/dist/backend/backend/src/services/v3/work-item-projection.js +115 -0
- package/dist/backend/backend/src/services/v3/work-item-projection.js.map +1 -0
- package/dist/backend/backend/src/services/v3/workitem-dispatch.subscriber.d.ts +121 -0
- package/dist/backend/backend/src/services/v3/workitem-dispatch.subscriber.d.ts.map +1 -0
- package/dist/backend/backend/src/services/v3/workitem-dispatch.subscriber.js +268 -0
- package/dist/backend/backend/src/services/v3/workitem-dispatch.subscriber.js.map +1 -0
- package/dist/backend/backend/src/services/whatsapp/whatsapp.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/whatsapp/whatsapp.service.js +11 -2
- package/dist/backend/backend/src/services/whatsapp/whatsapp.service.js.map +1 -1
- package/dist/backend/backend/src/services/workflow/scheduler.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/workflow/scheduler.service.js +68 -14
- package/dist/backend/backend/src/services/workflow/scheduler.service.js.map +1 -1
- package/dist/backend/backend/src/types/event-bus.types.d.ts +1 -1
- package/dist/backend/backend/src/types/event-bus.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/event-bus.types.js +12 -0
- package/dist/backend/backend/src/types/event-bus.types.js.map +1 -1
- package/dist/backend/backend/src/types/index.d.ts +11 -1
- package/dist/backend/backend/src/types/index.d.ts.map +1 -1
- package/dist/backend/backend/src/types/index.js +0 -2
- package/dist/backend/backend/src/types/index.js.map +1 -1
- package/dist/backend/backend/src/types/intent-task.types.d.ts +22 -3
- package/dist/backend/backend/src/types/intent-task.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/intent-task.types.js +201 -40
- package/dist/backend/backend/src/types/intent-task.types.js.map +1 -1
- package/dist/backend/backend/src/types/memory.types.d.ts +53 -0
- package/dist/backend/backend/src/types/memory.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/memory.types.js.map +1 -1
- package/dist/backend/backend/src/types/orchestrator-state.types.d.ts +49 -0
- package/dist/backend/backend/src/types/orchestrator-state.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/orchestrator-state.types.js +27 -0
- package/dist/backend/backend/src/types/orchestrator-state.types.js.map +1 -1
- package/dist/backend/backend/src/types/settings.types.d.ts +38 -2
- package/dist/backend/backend/src/types/settings.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/settings.types.js +16 -2
- package/dist/backend/backend/src/types/settings.types.js.map +1 -1
- package/dist/backend/backend/src/types/v2/request.types.d.ts +5 -1
- package/dist/backend/backend/src/types/v2/request.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/v2/request.types.js +2 -2
- package/dist/backend/backend/src/types/v2/request.types.js.map +1 -1
- package/dist/backend/backend/src/types/v2/work-item.types.d.ts +40 -1
- package/dist/backend/backend/src/types/v2/work-item.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/v2/work-item.types.js +20 -0
- package/dist/backend/backend/src/types/v2/work-item.types.js.map +1 -1
- package/dist/backend/backend/src/utils/esm-require.utils.d.ts +111 -0
- package/dist/backend/backend/src/utils/esm-require.utils.d.ts.map +1 -0
- package/dist/backend/backend/src/utils/esm-require.utils.js +124 -0
- package/dist/backend/backend/src/utils/esm-require.utils.js.map +1 -0
- package/dist/backend/backend/src/utils/integrity-guarded-write.utils.d.ts +119 -0
- package/dist/backend/backend/src/utils/integrity-guarded-write.utils.d.ts.map +1 -0
- package/dist/backend/backend/src/utils/integrity-guarded-write.utils.js +212 -0
- package/dist/backend/backend/src/utils/integrity-guarded-write.utils.js.map +1 -0
- package/dist/backend/backend/src/utils/native-binding.utils.d.ts +128 -0
- package/dist/backend/backend/src/utils/native-binding.utils.d.ts.map +1 -0
- package/dist/backend/backend/src/utils/native-binding.utils.js +206 -0
- package/dist/backend/backend/src/utils/native-binding.utils.js.map +1 -0
- package/dist/backend/backend/src/utils/node-require.utils.d.ts +104 -0
- package/dist/backend/backend/src/utils/node-require.utils.d.ts.map +1 -0
- package/dist/backend/backend/src/utils/node-require.utils.js +111 -0
- package/dist/backend/backend/src/utils/node-require.utils.js.map +1 -0
- package/dist/cli/backend/src/models/Project.d.ts +2 -0
- package/dist/cli/backend/src/models/Project.d.ts.map +1 -1
- package/dist/cli/backend/src/models/Project.js +10 -1
- package/dist/cli/backend/src/models/Project.js.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/prompt-module.interface.d.ts +16 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/prompt-module.interface.d.ts.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/prompt-module.interface.js.map +1 -1
- package/dist/cli/backend/src/services/core/config.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/core/config.service.js +8 -1
- package/dist/cli/backend/src/services/core/config.service.js.map +1 -1
- package/dist/cli/backend/src/services/core/crewly-home.utils.d.ts +51 -0
- package/dist/cli/backend/src/services/core/crewly-home.utils.d.ts.map +1 -0
- package/dist/cli/backend/src/services/core/crewly-home.utils.js +59 -0
- package/dist/cli/backend/src/services/core/crewly-home.utils.js.map +1 -0
- package/dist/cli/backend/src/services/core/state-invariant.types.d.ts +53 -0
- package/dist/cli/backend/src/services/core/state-invariant.types.d.ts.map +1 -0
- package/dist/cli/backend/src/services/core/state-invariant.types.js +61 -0
- package/dist/cli/backend/src/services/core/state-invariant.types.js.map +1 -0
- package/dist/cli/backend/src/services/core/storage.service.d.ts +20 -0
- package/dist/cli/backend/src/services/core/storage.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/core/storage.service.js +96 -8
- package/dist/cli/backend/src/services/core/storage.service.js.map +1 -1
- package/dist/cli/backend/src/services/core/teams-backup.service.d.ts +94 -4
- package/dist/cli/backend/src/services/core/teams-backup.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/core/teams-backup.service.js +172 -10
- package/dist/cli/backend/src/services/core/teams-backup.service.js.map +1 -1
- package/dist/cli/backend/src/services/event-bus/event-bus.service.d.ts +245 -0
- package/dist/cli/backend/src/services/event-bus/event-bus.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/event-bus/event-bus.service.js +639 -0
- package/dist/cli/backend/src/services/event-bus/event-bus.service.js.map +1 -0
- package/dist/cli/backend/src/services/knowledge/fts5-index.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/knowledge/fts5-index.service.js +18 -13
- package/dist/cli/backend/src/services/knowledge/fts5-index.service.js.map +1 -1
- package/dist/cli/backend/src/services/knowledge/fts5-query-sanitizer.d.ts +102 -0
- package/dist/cli/backend/src/services/knowledge/fts5-query-sanitizer.d.ts.map +1 -0
- package/dist/cli/backend/src/services/knowledge/fts5-query-sanitizer.js +118 -0
- package/dist/cli/backend/src/services/knowledge/fts5-query-sanitizer.js.map +1 -0
- package/dist/cli/backend/src/services/knowledge/vector-store.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/knowledge/vector-store.service.js +11 -15
- package/dist/cli/backend/src/services/knowledge/vector-store.service.js.map +1 -1
- package/dist/cli/backend/src/services/memory/agent-memory.service.d.ts +20 -0
- package/dist/cli/backend/src/services/memory/agent-memory.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/memory/agent-memory.service.js +27 -2
- package/dist/cli/backend/src/services/memory/agent-memory.service.js.map +1 -1
- package/dist/cli/backend/src/services/memory/memory.service.d.ts +48 -17
- package/dist/cli/backend/src/services/memory/memory.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/memory/memory.service.js +65 -35
- package/dist/cli/backend/src/services/memory/memory.service.js.map +1 -1
- package/dist/cli/backend/src/services/memory/role-knowledge-eligibility.d.ts +138 -0
- package/dist/cli/backend/src/services/memory/role-knowledge-eligibility.d.ts.map +1 -0
- package/dist/cli/backend/src/services/memory/role-knowledge-eligibility.js +183 -0
- package/dist/cli/backend/src/services/memory/role-knowledge-eligibility.js.map +1 -0
- package/dist/cli/backend/src/services/messaging/message-queue.service.d.ts +236 -0
- package/dist/cli/backend/src/services/messaging/message-queue.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/messaging/message-queue.service.js +581 -0
- package/dist/cli/backend/src/services/messaging/message-queue.service.js.map +1 -0
- package/dist/cli/backend/src/services/project/task-tracking.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/project/task-tracking.service.js +2 -2
- package/dist/cli/backend/src/services/project/task-tracking.service.js.map +1 -1
- package/dist/cli/backend/src/services/settings/settings.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/settings/settings.service.js +25 -0
- package/dist/cli/backend/src/services/settings/settings.service.js.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-thread-store.service.d.ts +147 -0
- package/dist/cli/backend/src/services/slack/slack-thread-store.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/slack/slack-thread-store.service.js +258 -0
- package/dist/cli/backend/src/services/slack/slack-thread-store.service.js.map +1 -0
- package/dist/cli/backend/src/services/task-pool/pool-storage.d.ts +15 -1
- package/dist/cli/backend/src/services/task-pool/pool-storage.d.ts.map +1 -1
- package/dist/cli/backend/src/services/task-pool/pool-storage.js +31 -8
- package/dist/cli/backend/src/services/task-pool/pool-storage.js.map +1 -1
- package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts +459 -9
- package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/task-pool/task-pool.service.js +1050 -126
- package/dist/cli/backend/src/services/task-pool/task-pool.service.js.map +1 -1
- package/dist/cli/backend/src/services/v3/work-item-projection.d.ts +40 -0
- package/dist/cli/backend/src/services/v3/work-item-projection.d.ts.map +1 -0
- package/dist/cli/backend/src/services/v3/work-item-projection.js +115 -0
- package/dist/cli/backend/src/services/v3/work-item-projection.js.map +1 -0
- package/dist/cli/backend/src/types/event-bus.types.d.ts +173 -0
- package/dist/cli/backend/src/types/event-bus.types.d.ts.map +1 -0
- package/dist/cli/backend/src/types/event-bus.types.js +218 -0
- package/dist/cli/backend/src/types/event-bus.types.js.map +1 -0
- package/dist/cli/backend/src/types/index.d.ts +11 -1
- package/dist/cli/backend/src/types/index.d.ts.map +1 -1
- package/dist/cli/backend/src/types/index.js +0 -2
- package/dist/cli/backend/src/types/index.js.map +1 -1
- package/dist/cli/backend/src/types/memory.types.d.ts +53 -0
- package/dist/cli/backend/src/types/memory.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/memory.types.js.map +1 -1
- package/dist/cli/backend/src/types/messaging.types.d.ts +223 -0
- package/dist/cli/backend/src/types/messaging.types.d.ts.map +1 -0
- package/dist/cli/backend/src/types/messaging.types.js +231 -0
- package/dist/cli/backend/src/types/messaging.types.js.map +1 -0
- package/dist/cli/backend/src/types/settings.types.d.ts +38 -2
- package/dist/cli/backend/src/types/settings.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/settings.types.js +16 -2
- package/dist/cli/backend/src/types/settings.types.js.map +1 -1
- package/dist/cli/backend/src/types/slack.types.d.ts +356 -0
- package/dist/cli/backend/src/types/slack.types.d.ts.map +1 -0
- package/dist/cli/backend/src/types/slack.types.js +66 -0
- package/dist/cli/backend/src/types/slack.types.js.map +1 -0
- package/dist/cli/backend/src/types/v2/claim.types.d.ts +2 -5
- package/dist/cli/backend/src/types/v2/claim.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/v2/claim.types.js +2 -5
- package/dist/cli/backend/src/types/v2/claim.types.js.map +1 -1
- package/dist/cli/backend/src/types/v2/work-item.types.d.ts +40 -1
- package/dist/cli/backend/src/types/v2/work-item.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/v2/work-item.types.js +20 -0
- package/dist/cli/backend/src/types/v2/work-item.types.js.map +1 -1
- package/dist/cli/backend/src/utils/format-error.d.ts +8 -0
- package/dist/cli/backend/src/utils/format-error.d.ts.map +1 -0
- package/dist/cli/backend/src/utils/format-error.js +10 -0
- package/dist/cli/backend/src/utils/format-error.js.map +1 -0
- package/dist/cli/backend/src/utils/integrity-guarded-write.utils.d.ts +119 -0
- package/dist/cli/backend/src/utils/integrity-guarded-write.utils.d.ts.map +1 -0
- package/dist/cli/backend/src/utils/integrity-guarded-write.utils.js +212 -0
- package/dist/cli/backend/src/utils/integrity-guarded-write.utils.js.map +1 -0
- package/dist/cli/backend/src/utils/node-require.utils.d.ts +104 -0
- package/dist/cli/backend/src/utils/node-require.utils.d.ts.map +1 -0
- package/dist/cli/backend/src/utils/node-require.utils.js +111 -0
- package/dist/cli/backend/src/utils/node-require.utils.js.map +1 -0
- package/frontend/dist/assets/{index-7a4e7df5.js → index-698305f3.js} +337 -337
- package/frontend/dist/index.html +1 -1
- package/package.json +6 -2
- package/dist/backend/backend/src/controllers/eval/eval.controller.d.ts +0 -63
- package/dist/backend/backend/src/controllers/eval/eval.controller.d.ts.map +0 -1
- package/dist/backend/backend/src/controllers/eval/eval.controller.js +0 -228
- package/dist/backend/backend/src/controllers/eval/eval.controller.js.map +0 -1
- package/dist/backend/backend/src/controllers/eval/eval.routes.d.ts +0 -23
- package/dist/backend/backend/src/controllers/eval/eval.routes.d.ts.map +0 -1
- package/dist/backend/backend/src/controllers/eval/eval.routes.js +0 -37
- package/dist/backend/backend/src/controllers/eval/eval.routes.js.map +0 -1
- package/dist/backend/backend/src/controllers/knowledge-v3/index.d.ts +0 -8
- package/dist/backend/backend/src/controllers/knowledge-v3/index.d.ts.map +0 -1
- package/dist/backend/backend/src/controllers/knowledge-v3/index.js +0 -8
- package/dist/backend/backend/src/controllers/knowledge-v3/index.js.map +0 -1
- package/dist/backend/backend/src/controllers/knowledge-v3/knowledge-v3.controller.d.ts +0 -63
- package/dist/backend/backend/src/controllers/knowledge-v3/knowledge-v3.controller.d.ts.map +0 -1
- package/dist/backend/backend/src/controllers/knowledge-v3/knowledge-v3.controller.js +0 -179
- package/dist/backend/backend/src/controllers/knowledge-v3/knowledge-v3.controller.js.map +0 -1
- package/dist/backend/backend/src/controllers/knowledge-v3/knowledge-v3.routes.d.ts +0 -22
- package/dist/backend/backend/src/controllers/knowledge-v3/knowledge-v3.routes.d.ts.map +0 -1
- package/dist/backend/backend/src/controllers/knowledge-v3/knowledge-v3.routes.js +0 -34
- package/dist/backend/backend/src/controllers/knowledge-v3/knowledge-v3.routes.js.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/adapters/cli-adapter.d.ts +0 -130
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/adapters/cli-adapter.d.ts.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/adapters/cli-adapter.js +0 -406
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/adapters/cli-adapter.js.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/adapters/crewly-agent-adapter.d.ts +0 -68
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/adapters/crewly-agent-adapter.d.ts.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/adapters/crewly-agent-adapter.js +0 -206
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/adapters/crewly-agent-adapter.js.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/adapters/index.d.ts +0 -32
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/adapters/index.d.ts.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/adapters/index.js +0 -46
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/adapters/index.js.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/context-generator.d.ts +0 -87
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/context-generator.d.ts.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/context-generator.js +0 -299
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/context-generator.js.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/eval-runner.d.ts +0 -59
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/eval-runner.d.ts.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/eval-runner.js +0 -218
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/eval-runner.js.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/eval-scorer.d.ts +0 -203
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/eval-scorer.d.ts.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/eval-scorer.js +0 -467
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/eval-scorer.js.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/eval-types.d.ts +0 -313
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/eval-types.d.ts.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/eval-types.js +0 -45
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/eval-types.js.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/index.d.ts +0 -21
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/index.d.ts.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/index.js +0 -21
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/index.js.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/run-eval-cli.d.ts +0 -15
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/run-eval-cli.d.ts.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/run-eval-cli.js +0 -349
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/run-eval-cli.js.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/run-eval-l4.d.ts +0 -97
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/run-eval-l4.d.ts.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/run-eval-l4.js +0 -414
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/run-eval-l4.js.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/run-eval-standalone.d.ts +0 -42
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/run-eval-standalone.d.ts.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/run-eval-standalone.js +0 -403
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/run-eval-standalone.js.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/tasks/index.d.ts +0 -41
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/tasks/index.d.ts.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/tasks/index.js +0 -58
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/tasks/index.js.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/tasks/l1-tasks.d.ts +0 -15
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/tasks/l1-tasks.d.ts.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/tasks/l1-tasks.js +0 -396
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/tasks/l1-tasks.js.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/tasks/l2-tasks.d.ts +0 -14
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/tasks/l2-tasks.d.ts.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/tasks/l2-tasks.js +0 -564
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/tasks/l2-tasks.js.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/tasks/l3-tasks.d.ts +0 -13
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/tasks/l3-tasks.d.ts.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/tasks/l3-tasks.js +0 -634
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/tasks/l3-tasks.js.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/tasks/l4-tasks.d.ts +0 -21
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/tasks/l4-tasks.d.ts.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/tasks/l4-tasks.js +0 -1036
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/tasks/l4-tasks.js.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/tool-log-parser.d.ts +0 -100
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/tool-log-parser.d.ts.map +0 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/tool-log-parser.js +0 -187
- package/dist/backend/backend/src/services/agent/crewly-agent/eval/tool-log-parser.js.map +0 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.d.ts +0 -79
- package/dist/backend/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.d.ts.map +0 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.js +0 -118
- package/dist/backend/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.js.map +0 -1
- package/dist/backend/backend/src/services/cloud/cloud-event-bridge.service.d.ts +0 -113
- package/dist/backend/backend/src/services/cloud/cloud-event-bridge.service.d.ts.map +0 -1
- package/dist/backend/backend/src/services/cloud/cloud-event-bridge.service.js +0 -179
- package/dist/backend/backend/src/services/cloud/cloud-event-bridge.service.js.map +0 -1
- package/dist/backend/backend/src/services/cloud/cloud-event-forwarder.service.d.ts +0 -131
- package/dist/backend/backend/src/services/cloud/cloud-event-forwarder.service.d.ts.map +0 -1
- package/dist/backend/backend/src/services/cloud/cloud-event-forwarder.service.js +0 -227
- package/dist/backend/backend/src/services/cloud/cloud-event-forwarder.service.js.map +0 -1
- package/dist/backend/backend/src/services/knowledge/fts5-search-strategy.d.ts +0 -56
- package/dist/backend/backend/src/services/knowledge/fts5-search-strategy.d.ts.map +0 -1
- package/dist/backend/backend/src/services/knowledge/fts5-search-strategy.js +0 -91
- package/dist/backend/backend/src/services/knowledge/fts5-search-strategy.js.map +0 -1
- package/dist/backend/backend/src/services/memory/learning-format.validator.d.ts +0 -97
- package/dist/backend/backend/src/services/memory/learning-format.validator.d.ts.map +0 -1
- package/dist/backend/backend/src/services/memory/learning-format.validator.js +0 -209
- package/dist/backend/backend/src/services/memory/learning-format.validator.js.map +0 -1
- /package/dist/{backend → cli}/backend/src/services/knowledge/learnings-index.service.d.ts +0 -0
- /package/dist/{backend → cli}/backend/src/services/knowledge/learnings-index.service.d.ts.map +0 -0
- /package/dist/{backend → cli}/backend/src/services/knowledge/learnings-index.service.js +0 -0
- /package/dist/{backend → cli}/backend/src/services/knowledge/learnings-index.service.js.map +0 -0
|
@@ -11,8 +11,28 @@
|
|
|
11
11
|
import { PoolStorage } from './pool-storage.js';
|
|
12
12
|
import { ClaimService } from './claim.service.js';
|
|
13
13
|
import { LoggerService } from '../core/logger.service.js';
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
14
|
+
import { formatError } from '../../utils/format-error.js';
|
|
15
|
+
import { isWorkItem, isValidWorkItemTransition, isTransitionPermitted } from '../../types/v2/work-item.types.js';
|
|
16
|
+
import { createTaskClaim, } from '../../types/v2/claim.types.js';
|
|
17
|
+
/**
|
|
18
|
+
* Structured error thrown by {@link TaskPoolService.removeFromPool}
|
|
19
|
+
* when an active claim exists and `force: true` was not passed.
|
|
20
|
+
*/
|
|
21
|
+
export class WorkItemClaimedError extends Error {
|
|
22
|
+
workItemId;
|
|
23
|
+
claimId;
|
|
24
|
+
claimedBy;
|
|
25
|
+
constructor(args) {
|
|
26
|
+
super(`WorkItem '${args.workItemId}' has an active claim ` +
|
|
27
|
+
`(claimId='${args.claimId}', claimedBy='${args.claimedBy}'). ` +
|
|
28
|
+
`Pass { force: true } to delete anyway (will revoke the claim).`);
|
|
29
|
+
this.name = 'WorkItemClaimedError';
|
|
30
|
+
this.workItemId = args.workItemId;
|
|
31
|
+
this.claimId = args.claimId;
|
|
32
|
+
this.claimedBy = args.claimedBy;
|
|
33
|
+
Object.setPrototypeOf(this, WorkItemClaimedError.prototype);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
16
36
|
// ---------------------------------------------------------------------------
|
|
17
37
|
// Service
|
|
18
38
|
// ---------------------------------------------------------------------------
|
|
@@ -42,11 +62,87 @@ export class TaskPoolService {
|
|
|
42
62
|
storage;
|
|
43
63
|
claimService;
|
|
44
64
|
logger;
|
|
65
|
+
/**
|
|
66
|
+
* Optional EventBus reference — wired via {@link setEventBusService} from
|
|
67
|
+
* the boot path. When set, {@link addToPool} publishes a `workitem:queued`
|
|
68
|
+
* event so subscribers (notably {@link RequestSlaSubscriber}) can react to
|
|
69
|
+
* queue mutations. Optional because singleton callers (tests, CLI) bring
|
|
70
|
+
* up the pool before the bus exists; missing bus is treated as a no-op
|
|
71
|
+
* publish at warn level.
|
|
72
|
+
*/
|
|
73
|
+
eventBus = null;
|
|
74
|
+
/**
|
|
75
|
+
* Optional Request-linker reference — wired via {@link setRequestService}
|
|
76
|
+
* from the boot path. When set, {@link addToPool} pushes the new WI's id
|
|
77
|
+
* into the parent `Request.workItemIds[]` immediately after the storage
|
|
78
|
+
* flush, independent of any downstream subscriber.
|
|
79
|
+
*
|
|
80
|
+
* P1 Bug B (Pool umbrella WI 72ca743a) intrinsic-link contract:
|
|
81
|
+
* - The pre-fix path relied on `workitem:queued` / `task:delegated`
|
|
82
|
+
* subscribers (request-sla.subscriber, V3DataService) to backfill
|
|
83
|
+
* `Request.workItemIds[]`. Manual / programmatic / cron callers that
|
|
84
|
+
* bypass the standard event chain left Requests with
|
|
85
|
+
* `workItemIds=[]` even though their WIs were in the pool.
|
|
86
|
+
* - The intrinsic path here is the source-of-truth link and runs on
|
|
87
|
+
* every `addToPool`. Subscriber-driven linking remains as
|
|
88
|
+
* belt-and-suspenders (idempotent — see request.service.ts:328
|
|
89
|
+
* short-circuit on duplicate id).
|
|
90
|
+
* - Optional because singleton callers (tests, CLI) bring up the pool
|
|
91
|
+
* before RequestService exists; missing linker is a no-op debug log.
|
|
92
|
+
*/
|
|
93
|
+
requestService = null;
|
|
94
|
+
/**
|
|
95
|
+
* Serializes claim operations to prevent the race where two concurrent
|
|
96
|
+
* claimFromPool / claimSpecificItem calls both select the same queued
|
|
97
|
+
* WorkItem between their read and write phases. In-process only — does
|
|
98
|
+
* not protect against cross-process races, but the backend runs as a
|
|
99
|
+
* single process today.
|
|
100
|
+
*/
|
|
101
|
+
claimMutex = Promise.resolve();
|
|
45
102
|
constructor(storage) {
|
|
46
103
|
this.storage = storage ?? new PoolStorage();
|
|
47
104
|
this.claimService = new ClaimService(this.storage);
|
|
48
105
|
this.logger = LoggerService.getInstance().createComponentLogger('TaskPoolService');
|
|
49
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* Wire the EventBus reference used by {@link addToPool} to publish
|
|
109
|
+
* `workitem:queued` events (INBOUND-1.f1). Called from the backend boot
|
|
110
|
+
* path after both services have been constructed. Idempotent and may be
|
|
111
|
+
* called with `null` to disable publishing (testing).
|
|
112
|
+
*
|
|
113
|
+
* @param bus - The EventBus instance, or null to clear
|
|
114
|
+
*/
|
|
115
|
+
setEventBusService(bus) {
|
|
116
|
+
this.eventBus = bus;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Wire the Request-linker reference used by {@link addToPool} to
|
|
120
|
+
* intrinsically link the new WI into its parent `Request.workItemIds[]`
|
|
121
|
+
* (P1 Bug B — Pool umbrella WI 72ca743a).
|
|
122
|
+
*
|
|
123
|
+
* Called from the backend boot path after both services exist.
|
|
124
|
+
* Idempotent and may be called with `null` to disable intrinsic
|
|
125
|
+
* linking (testing). Mirrors the {@link setEventBusService} setter
|
|
126
|
+
* pattern so the dependency wiring stays uniform and grep-able.
|
|
127
|
+
*
|
|
128
|
+
* @param svc - The RequestService instance (or any object satisfying
|
|
129
|
+
* {@link IRequestWorkItemLinker}), or null to clear.
|
|
130
|
+
*/
|
|
131
|
+
setRequestService(svc) {
|
|
132
|
+
this.requestService = svc;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Chains the given critical section after any in-flight claim operation.
|
|
136
|
+
* Guarantees FIFO ordering even under concurrent invocation.
|
|
137
|
+
*/
|
|
138
|
+
withClaimLock(fn) {
|
|
139
|
+
const prev = this.claimMutex;
|
|
140
|
+
let release;
|
|
141
|
+
this.claimMutex = new Promise((r) => {
|
|
142
|
+
release = r;
|
|
143
|
+
});
|
|
144
|
+
return prev.then(fn).finally(() => release());
|
|
145
|
+
}
|
|
50
146
|
/**
|
|
51
147
|
* Get singleton instance of TaskPoolService.
|
|
52
148
|
*
|
|
@@ -70,18 +166,20 @@ export class TaskPoolService {
|
|
|
70
166
|
/**
|
|
71
167
|
* Adds an execution-ready WorkItem to the pool.
|
|
72
168
|
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
169
|
+
* Accepted statuses:
|
|
170
|
+
* - `queued` — ready to run
|
|
171
|
+
* - `blocked` — waiting on unresolved dependsOn; the resolver will promote
|
|
172
|
+
* it to `queued` when every upstream dep reaches terminal success.
|
|
75
173
|
*
|
|
76
174
|
* @param workItem - The work item to add
|
|
77
|
-
* @throws Error if workItem is
|
|
175
|
+
* @throws Error if workItem is invalid or in an ineligible status
|
|
78
176
|
*/
|
|
79
177
|
async addToPool(workItem) {
|
|
80
178
|
if (!isWorkItem(workItem)) {
|
|
81
179
|
throw new Error('Invalid WorkItem: does not conform to WorkItem interface');
|
|
82
180
|
}
|
|
83
|
-
if (workItem.status !== 'queued') {
|
|
84
|
-
throw new Error(`Cannot add WorkItem to pool: status must be 'queued', got '${workItem.status}'`);
|
|
181
|
+
if (workItem.status !== 'queued' && workItem.status !== 'blocked') {
|
|
182
|
+
throw new Error(`Cannot add WorkItem to pool: status must be 'queued' or 'blocked', got '${workItem.status}'`);
|
|
85
183
|
}
|
|
86
184
|
// Check for duplicates
|
|
87
185
|
const existing = await this.storage.findWorkItem(workItem.id);
|
|
@@ -96,6 +194,287 @@ export class TaskPoolService {
|
|
|
96
194
|
type: workItem.type,
|
|
97
195
|
title: workItem.title,
|
|
98
196
|
});
|
|
197
|
+
// P1 Bug B (Pool umbrella WI 72ca743a): intrinsically link the new
|
|
198
|
+
// WI into its parent `Request.workItemIds[]` if a linker is wired
|
|
199
|
+
// and the WI carries a requestId. This is the SOURCE-OF-TRUTH link
|
|
200
|
+
// and runs unconditionally on every successful addToPool, fixing
|
|
201
|
+
// the bug where manual / programmatic / cron / orchestrator-script
|
|
202
|
+
// callers that bypass the standard event chain left Requests with
|
|
203
|
+
// empty `workItemIds[]`.
|
|
204
|
+
//
|
|
205
|
+
// Subscriber-driven linking (request-sla.subscriber.ts on
|
|
206
|
+
// workitem:queued, V3DataService.onTaskDelegated on task:delegated)
|
|
207
|
+
// continues to run as belt-and-suspenders — `linkWorkItem` is
|
|
208
|
+
// idempotent (request.service.ts:328 short-circuits on duplicate id),
|
|
209
|
+
// so double-link is safe.
|
|
210
|
+
//
|
|
211
|
+
// Failure isolation: pool mutation is the source of truth. Link
|
|
212
|
+
// failures are warn-logged and swallowed; subscriber path remains
|
|
213
|
+
// as a backup, and a future addToPool of the same WI is a no-op
|
|
214
|
+
// (storage dedup) so retry comes via natural traffic.
|
|
215
|
+
await this.linkWorkItemToRequest(workItem);
|
|
216
|
+
// INBOUND-1.f1: announce the queue mutation so subscribers (notably the
|
|
217
|
+
// RequestSlaSubscriber) can react. We publish AFTER the storage flush
|
|
218
|
+
// so any subscriber that re-reads via taskPool.findWorkItem sees the
|
|
219
|
+
// committed item. Publish failures are logged-but-isolated — the pool
|
|
220
|
+
// mutation is the source of truth, the event is informational.
|
|
221
|
+
this.publishWorkItemQueued(workItem);
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* P1 Bug B helper: intrinsically link a freshly-added WI into its
|
|
225
|
+
* parent `Request.workItemIds[]`.
|
|
226
|
+
*
|
|
227
|
+
* Stays a separate method (vs inlining) so:
|
|
228
|
+
* 1. The dependency on RequestService stays explicit and grep-able,
|
|
229
|
+
* mirroring {@link publishWorkItemQueued}.
|
|
230
|
+
* 2. Future enqueue paths (e.g. a batch addAll) can route through
|
|
231
|
+
* the same linker for consistent behaviour.
|
|
232
|
+
* 3. Error handling stays in one place — a thrown linker must NOT
|
|
233
|
+
* back out the pool mutation (the storage write already committed).
|
|
234
|
+
*
|
|
235
|
+
* @param workItem - The WI just persisted into the pool.
|
|
236
|
+
*/
|
|
237
|
+
async linkWorkItemToRequest(workItem) {
|
|
238
|
+
if (!workItem.requestId) {
|
|
239
|
+
// No parent Request — nothing to link.
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
if (!this.requestService) {
|
|
243
|
+
this.logger.debug('No RequestService wired — skipping intrinsic Request link', { workItemId: workItem.id, requestId: workItem.requestId });
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
try {
|
|
247
|
+
await this.requestService.linkWorkItem(workItem.requestId, workItem.id);
|
|
248
|
+
}
|
|
249
|
+
catch (linkError) {
|
|
250
|
+
this.logger.warn('Bug B intrinsic link failed (subscriber path remains as fallback)', {
|
|
251
|
+
requestId: workItem.requestId,
|
|
252
|
+
workItemId: workItem.id,
|
|
253
|
+
error: formatError(linkError),
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* INBOUND-1.f1 helper: publish a `workitem:queued` event with correlation
|
|
259
|
+
* ids the SLA subscriber needs (`requestId`, `missionId`, plus the new
|
|
260
|
+
* `workItemId`). Called by {@link addToPool} after the storage flush.
|
|
261
|
+
*
|
|
262
|
+
* Stays a separate method (vs inlining) so:
|
|
263
|
+
* 1. The dependency on EventBus stays explicit and grep-able.
|
|
264
|
+
* 2. A future caller adding an alternate enqueue path (e.g. a batch
|
|
265
|
+
* addAll) can route through the same publisher for consistent
|
|
266
|
+
* observability.
|
|
267
|
+
* 3. Error handling stays in one place — a thrown publisher must NOT
|
|
268
|
+
* back out the pool mutation (the storage write already committed).
|
|
269
|
+
*/
|
|
270
|
+
publishWorkItemQueued(workItem) {
|
|
271
|
+
if (!this.eventBus) {
|
|
272
|
+
this.logger.debug('No EventBus wired — skipping workitem:queued publish', {
|
|
273
|
+
workItemId: workItem.id,
|
|
274
|
+
});
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
try {
|
|
278
|
+
this.eventBus.publish({
|
|
279
|
+
// Deterministic event id keyed on the WI id so a redelivered storage
|
|
280
|
+
// path (theoretical) collapses through the bus's per-(type,session)
|
|
281
|
+
// debounce window without firing the SLA handler twice.
|
|
282
|
+
id: `workitem:queued:${workItem.id}`,
|
|
283
|
+
type: 'workitem:queued',
|
|
284
|
+
timestamp: new Date().toISOString(),
|
|
285
|
+
teamId: '',
|
|
286
|
+
teamName: '',
|
|
287
|
+
memberId: '',
|
|
288
|
+
memberName: '',
|
|
289
|
+
// sessionName is empty — `workitem:queued` is a system-level event
|
|
290
|
+
// not attributable to a specific agent session. The bus's dedup key
|
|
291
|
+
// is `${type}:${sessionName}` so a unique sessionName per WI would
|
|
292
|
+
// defeat the dedup; an empty sessionName scoped per-id is fine since
|
|
293
|
+
// the event id already encodes the WI uniquely.
|
|
294
|
+
sessionName: '',
|
|
295
|
+
previousValue: '',
|
|
296
|
+
newValue: workItem.status,
|
|
297
|
+
changedField: 'taskStatus',
|
|
298
|
+
// INBOUND-1.f1 correlation fields. Mandatory: workItemId. Optional:
|
|
299
|
+
// requestId, missionId — populated when the WI carries them. The SLA
|
|
300
|
+
// subscriber no-ops when requestId is undefined (per spec), so we
|
|
301
|
+
// don't need a fallback chain here.
|
|
302
|
+
workItemId: workItem.id,
|
|
303
|
+
requestId: workItem.requestId,
|
|
304
|
+
missionId: workItem.missionId,
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
catch (err) {
|
|
308
|
+
this.logger.warn('workitem:queued publish threw', {
|
|
309
|
+
workItemId: workItem.id,
|
|
310
|
+
error: formatError(err),
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* F1-BRIDGE-1 helper: publish `task:done_by_worker` after a successful
|
|
316
|
+
* `submitForVerification` transition. The {@link EventToWorkItemBridge}
|
|
317
|
+
* subscribes to this event and creates a verification WorkItem for the
|
|
318
|
+
* resolved team-lead session.
|
|
319
|
+
*
|
|
320
|
+
* Stays a separate method (mirrors {@link publishWorkItemQueued}) so:
|
|
321
|
+
* 1. The dependency on EventBus stays explicit and grep-able — Arch's
|
|
322
|
+
* grep guard checks both the type declaration AND a publish call
|
|
323
|
+
* site for `task:done_by_worker`.
|
|
324
|
+
* 2. Error handling is uniform with the other publishers — a thrown
|
|
325
|
+
* bus must NOT back out the verified state transition; the storage
|
|
326
|
+
* flush has already committed.
|
|
327
|
+
* 3. A future caller adding an alternate verification-submission path
|
|
328
|
+
* (e.g. an admin endpoint or a CLI) routes through the same publisher.
|
|
329
|
+
*
|
|
330
|
+
* The deterministic event id (`task:done_by_worker:${workItemId}`) keys
|
|
331
|
+
* dedup so a redelivered submitForVerification (theoretical) collapses
|
|
332
|
+
* through the bus without firing the bridge handler twice.
|
|
333
|
+
*/
|
|
334
|
+
publishTaskDoneByWorker(workItem) {
|
|
335
|
+
if (!this.eventBus) {
|
|
336
|
+
this.logger.debug('No EventBus wired — skipping task:done_by_worker publish', {
|
|
337
|
+
workItemId: workItem.id,
|
|
338
|
+
});
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
try {
|
|
342
|
+
this.eventBus.publish({
|
|
343
|
+
id: `task:done_by_worker:${workItem.id}`,
|
|
344
|
+
type: 'task:done_by_worker',
|
|
345
|
+
timestamp: new Date().toISOString(),
|
|
346
|
+
teamId: '',
|
|
347
|
+
teamName: '',
|
|
348
|
+
memberId: '',
|
|
349
|
+
memberName: '',
|
|
350
|
+
// sessionName is empty — `task:done_by_worker` is published from the
|
|
351
|
+
// pool layer which doesn't carry the worker's PTY session. The bridge
|
|
352
|
+
// uses `workItemId` (and falls back to `taskId`) to resolve the
|
|
353
|
+
// source WI; sessionName is informational. Empty matches the
|
|
354
|
+
// workitem:queued publish convention.
|
|
355
|
+
sessionName: '',
|
|
356
|
+
// The state machine just landed at done_by_worker. Carry both ends
|
|
357
|
+
// so any subscriber filtering on (previousValue, newValue) sees
|
|
358
|
+
// the canonical transition.
|
|
359
|
+
previousValue: 'running',
|
|
360
|
+
newValue: 'done_by_worker',
|
|
361
|
+
changedField: 'taskStatus',
|
|
362
|
+
// BRIDGE-1.1 hybrid extension. `workItemId` is mandatory for the
|
|
363
|
+
// bridge handler; the `taskId` fallback path is unused here because
|
|
364
|
+
// WorkItem itself does not carry a taskId (the bridge resolves the
|
|
365
|
+
// source WI by id alone via taskPool.findWorkItem).
|
|
366
|
+
workItemId: workItem.id,
|
|
367
|
+
missionId: workItem.missionId,
|
|
368
|
+
requestId: workItem.requestId,
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
catch (err) {
|
|
372
|
+
this.logger.warn('task:done_by_worker publish threw', {
|
|
373
|
+
workItemId: workItem.id,
|
|
374
|
+
error: formatError(err),
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* F1-BRIDGE-1 helper: publish `task:rejected` after a successful
|
|
380
|
+
* `verifyItem` transition with verdict='rejected'. The
|
|
381
|
+
* {@link EventToWorkItemBridge} subscribes and either creates a retry
|
|
382
|
+
* WI (`retryCount < maxRetries`) or escalates to a TL review WI with
|
|
383
|
+
* `reviewReason='max_retries_exceeded'` at the cap.
|
|
384
|
+
*
|
|
385
|
+
* Mirrors {@link publishTaskDoneByWorker} for symmetry. Only the
|
|
386
|
+
* verdict='rejected' branch reaches this publisher — `verdict='verified'`
|
|
387
|
+
* does NOT publish (terminal-success path goes through
|
|
388
|
+
* {@link resolveBlockedDependents}, which is not a bridge trigger).
|
|
389
|
+
*/
|
|
390
|
+
publishTaskRejected(workItem) {
|
|
391
|
+
if (!this.eventBus) {
|
|
392
|
+
this.logger.debug('No EventBus wired — skipping task:rejected publish', {
|
|
393
|
+
workItemId: workItem.id,
|
|
394
|
+
});
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
try {
|
|
398
|
+
this.eventBus.publish({
|
|
399
|
+
id: `task:rejected:${workItem.id}`,
|
|
400
|
+
type: 'task:rejected',
|
|
401
|
+
timestamp: new Date().toISOString(),
|
|
402
|
+
teamId: '',
|
|
403
|
+
teamName: '',
|
|
404
|
+
memberId: '',
|
|
405
|
+
memberName: '',
|
|
406
|
+
sessionName: '',
|
|
407
|
+
previousValue: 'done_by_worker',
|
|
408
|
+
newValue: 'rejected',
|
|
409
|
+
changedField: 'taskStatus',
|
|
410
|
+
workItemId: workItem.id,
|
|
411
|
+
missionId: workItem.missionId,
|
|
412
|
+
requestId: workItem.requestId,
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
catch (err) {
|
|
416
|
+
this.logger.warn('task:rejected publish threw', {
|
|
417
|
+
workItemId: workItem.id,
|
|
418
|
+
error: formatError(err),
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Publish `task:cancelled` whenever a WorkItem transitions to the
|
|
424
|
+
* cancelled status via {@link updateItemStatus} or {@link transitionStatus}.
|
|
425
|
+
*
|
|
426
|
+
* **Why this exists.** 2026-05-09 dogfood: 4 child WIs of a Slack-
|
|
427
|
+
* originated Request all landed in `cancelled` (orc-not-in-health-map
|
|
428
|
+
* loop, fixed in #531) but the Request stayed in `ready` for hours.
|
|
429
|
+
* `cascadeRequestStatus` only fires from V3DataService's task
|
|
430
|
+
* handlers, which are wired to the retired `v3:task_*` events
|
|
431
|
+
* (`mission-executor.service.ts:152` v1-cleanup comment) — so out-of-
|
|
432
|
+
* band cancellations never reached cascade. The heartbeat sweep
|
|
433
|
+
* eventually caught it (#533), but with up-to-30-min latency that
|
|
434
|
+
* showed up as a misleading "0/4 in every bucket" ping in the user's
|
|
435
|
+
* Slack thread.
|
|
436
|
+
*
|
|
437
|
+
* Publishing `task:cancelled` lets `RequestCascadeSubscriber` close
|
|
438
|
+
* the Request within seconds of the last child cancelling, instead
|
|
439
|
+
* of waiting for the heartbeat catch.
|
|
440
|
+
*
|
|
441
|
+
* Mirrors {@link publishTaskDoneByWorker} / {@link publishTaskRejected}
|
|
442
|
+
* so the EventBus surface stays uniform.
|
|
443
|
+
*
|
|
444
|
+
* @param workItem - The WI snapshot AFTER the cancelled transition committed
|
|
445
|
+
* @param previousStatus - The status it transitioned from (for the event payload)
|
|
446
|
+
*/
|
|
447
|
+
publishTaskCancelled(workItem, previousStatus) {
|
|
448
|
+
if (!this.eventBus) {
|
|
449
|
+
this.logger.debug('No EventBus wired — skipping task:cancelled publish', {
|
|
450
|
+
workItemId: workItem.id,
|
|
451
|
+
});
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
try {
|
|
455
|
+
this.eventBus.publish({
|
|
456
|
+
id: `task:cancelled:${workItem.id}`,
|
|
457
|
+
type: 'task:cancelled',
|
|
458
|
+
timestamp: new Date().toISOString(),
|
|
459
|
+
teamId: '',
|
|
460
|
+
teamName: '',
|
|
461
|
+
memberId: '',
|
|
462
|
+
memberName: '',
|
|
463
|
+
sessionName: '',
|
|
464
|
+
previousValue: previousStatus,
|
|
465
|
+
newValue: 'cancelled',
|
|
466
|
+
changedField: 'taskStatus',
|
|
467
|
+
workItemId: workItem.id,
|
|
468
|
+
missionId: workItem.missionId,
|
|
469
|
+
requestId: workItem.requestId,
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
catch (err) {
|
|
473
|
+
this.logger.warn('task:cancelled publish threw', {
|
|
474
|
+
workItemId: workItem.id,
|
|
475
|
+
error: formatError(err),
|
|
476
|
+
});
|
|
477
|
+
}
|
|
99
478
|
}
|
|
100
479
|
/**
|
|
101
480
|
* Claims the next available WorkItem from the pool for an agent.
|
|
@@ -111,62 +490,87 @@ export class TaskPoolService {
|
|
|
111
490
|
if (!agentId || typeof agentId !== 'string') {
|
|
112
491
|
throw new Error('agentId is required and must be a non-empty string');
|
|
113
492
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
493
|
+
return this.withClaimLock(async () => {
|
|
494
|
+
// Check if agent already has an active claim
|
|
495
|
+
const existingClaim = await this.storage.findActiveClaimByAgent(agentId);
|
|
496
|
+
if (existingClaim) {
|
|
497
|
+
this.logger.warn('Agent already has an active claim', {
|
|
498
|
+
agentId,
|
|
499
|
+
existingClaimId: existingClaim.id,
|
|
500
|
+
existingWorkItemId: existingClaim.workItemId,
|
|
501
|
+
});
|
|
502
|
+
return null;
|
|
503
|
+
}
|
|
504
|
+
const workItems = await this.storage.getWorkItems();
|
|
505
|
+
const claims = await this.storage.getClaims();
|
|
506
|
+
// Set of work item IDs that have active claims
|
|
507
|
+
const claimedIds = new Set(claims
|
|
508
|
+
.filter((c) => c.status === 'active')
|
|
509
|
+
.map((c) => c.workItemId));
|
|
510
|
+
// Hygiene #3 — target-respect gate. Before this filter, claimFromPool
|
|
511
|
+
// would FIFO-pick the oldest queued+unclaimed item regardless of
|
|
512
|
+
// its existing `target` field, then unconditionally rewrite
|
|
513
|
+
// `wi.target = agentId` in the transitionStatus mutator. That
|
|
514
|
+
// produced the target-rotation bug observed in the 5/9 wave (WIs
|
|
515
|
+
// rotating through Quinn → Sam, Leo → Quinn, etc.).
|
|
516
|
+
//
|
|
517
|
+
// After this filter:
|
|
518
|
+
// - WIs with an explicit target are claimable ONLY by that target.
|
|
519
|
+
// - WIs with no target (broadcast pool) remain claimable by any agent.
|
|
520
|
+
// The defensive identity check in the transitionStatus mutator
|
|
521
|
+
// below ensures we never accidentally overwrite an existing target
|
|
522
|
+
// even if a future code path bypasses this filter.
|
|
523
|
+
const targetRespectingCandidates = workItems
|
|
524
|
+
.filter((wi) => wi.status === 'queued' && !claimedIds.has(wi.id))
|
|
525
|
+
.filter((wi) => !wi.target || wi.target === agentId);
|
|
526
|
+
// Find first matching unclaimed queued item (FIFO by createdAt)
|
|
527
|
+
const candidates = targetRespectingCandidates
|
|
528
|
+
.filter((wi) => matchesFilters(wi, filters))
|
|
529
|
+
.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
|
|
530
|
+
if (candidates.length === 0) {
|
|
531
|
+
return null;
|
|
532
|
+
}
|
|
533
|
+
const selected = candidates[0];
|
|
534
|
+
// TRANS-2: route the queued → running flip through the guarded
|
|
535
|
+
// transitionStatus helper so internal callers are subject to the
|
|
536
|
+
// same V3 actor-role + state-machine gates as external callers.
|
|
537
|
+
// `startedAt` is set automatically by transitionStatus when
|
|
538
|
+
// newStatus === 'running'; the mutator carries the agent target.
|
|
539
|
+
//
|
|
540
|
+
// Hygiene #3 — target-respect (defensive). The candidate filter
|
|
541
|
+
// above already excludes WIs whose target ≠ agentId, so the only
|
|
542
|
+
// remaining cases here are (a) wi.target === agentId (no-op assign)
|
|
543
|
+
// and (b) wi.target === undefined (broadcast claim). Either way we
|
|
544
|
+
// refuse to overwrite a non-matching existing target.
|
|
545
|
+
const claimedItem = await this.transitionStatus(selected.id, 'running', 'system', (wi) => {
|
|
546
|
+
if (!wi.target) {
|
|
547
|
+
wi.target = agentId;
|
|
548
|
+
}
|
|
549
|
+
// else: target already === agentId per the filter; leave as-is.
|
|
550
|
+
});
|
|
551
|
+
if (!claimedItem) {
|
|
552
|
+
this.logger.warn('Failed to update WorkItem during claim', { workItemId: selected.id });
|
|
553
|
+
return null;
|
|
554
|
+
}
|
|
555
|
+
// Create the claim
|
|
556
|
+
const claimInput = {
|
|
557
|
+
workItemId: selected.id,
|
|
558
|
+
agentId,
|
|
559
|
+
};
|
|
560
|
+
const claim = createTaskClaim(claimInput);
|
|
561
|
+
await this.storage.addClaim(claim);
|
|
562
|
+
await this.storage.flush();
|
|
563
|
+
this.logger.info('WorkItem claimed', {
|
|
564
|
+
workItemId: selected.id,
|
|
118
565
|
agentId,
|
|
119
|
-
|
|
120
|
-
|
|
566
|
+
claimId: claim.id,
|
|
567
|
+
title: selected.title,
|
|
121
568
|
});
|
|
122
|
-
return
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
// Set of work item IDs that have active claims
|
|
127
|
-
const claimedIds = new Set(claims
|
|
128
|
-
.filter((c) => c.status === 'active')
|
|
129
|
-
.map((c) => c.workItemId));
|
|
130
|
-
// Find first matching unclaimed queued item (FIFO by createdAt)
|
|
131
|
-
const candidates = workItems
|
|
132
|
-
.filter((wi) => wi.status === 'queued' && !claimedIds.has(wi.id))
|
|
133
|
-
.filter((wi) => matchesFilters(wi, filters))
|
|
134
|
-
.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
|
|
135
|
-
if (candidates.length === 0) {
|
|
136
|
-
return null;
|
|
137
|
-
}
|
|
138
|
-
const selected = candidates[0];
|
|
139
|
-
// Transition item to 'running'
|
|
140
|
-
const updated = await this.storage.updateWorkItem(selected.id, (wi) => {
|
|
141
|
-
wi.status = 'running';
|
|
142
|
-
wi.startedAt = new Date().toISOString();
|
|
143
|
-
wi.target = agentId;
|
|
144
|
-
});
|
|
145
|
-
if (!updated) {
|
|
146
|
-
this.logger.warn('Failed to update WorkItem during claim', { workItemId: selected.id });
|
|
147
|
-
return null;
|
|
148
|
-
}
|
|
149
|
-
// Create the claim (project_task gets extended lease to avoid premature revocation)
|
|
150
|
-
const claimInput = {
|
|
151
|
-
workItemId: selected.id,
|
|
152
|
-
agentId,
|
|
153
|
-
...(selected.type === 'project_task' ? { leaseDurationMs: PROJECT_TASK_LEASE_DURATION_MS } : {}),
|
|
154
|
-
};
|
|
155
|
-
const claim = createTaskClaim(claimInput);
|
|
156
|
-
await this.storage.addClaim(claim);
|
|
157
|
-
await this.storage.flush();
|
|
158
|
-
this.logger.info('WorkItem claimed', {
|
|
159
|
-
workItemId: selected.id,
|
|
160
|
-
agentId,
|
|
161
|
-
claimId: claim.id,
|
|
162
|
-
title: selected.title,
|
|
569
|
+
return {
|
|
570
|
+
workItem: claimedItem,
|
|
571
|
+
claim,
|
|
572
|
+
};
|
|
163
573
|
});
|
|
164
|
-
// Return the updated item
|
|
165
|
-
const claimedItem = await this.storage.findWorkItem(selected.id);
|
|
166
|
-
return {
|
|
167
|
-
workItem: claimedItem,
|
|
168
|
-
claim,
|
|
169
|
-
};
|
|
170
574
|
}
|
|
171
575
|
/**
|
|
172
576
|
* Claims a specific WorkItem by ID for an agent.
|
|
@@ -181,33 +585,49 @@ export class TaskPoolService {
|
|
|
181
585
|
if (!agentId || typeof agentId !== 'string') {
|
|
182
586
|
throw new Error('agentId is required and must be a non-empty string');
|
|
183
587
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
588
|
+
return this.withClaimLock(async () => {
|
|
589
|
+
const existingClaim = await this.storage.findActiveClaimByAgent(agentId);
|
|
590
|
+
if (existingClaim)
|
|
591
|
+
return null;
|
|
592
|
+
const workItem = await this.storage.findWorkItem(workItemId);
|
|
593
|
+
if (!workItem || workItem.status !== 'queued')
|
|
594
|
+
return null;
|
|
595
|
+
// Hygiene #3 — target-respect gate. Refuse to claim a WI whose
|
|
596
|
+
// existing target is set to a different agent. This prevents the
|
|
597
|
+
// claimSpecificItem path (used by AgentAutoClaimService for
|
|
598
|
+
// score-based selection) from rotating target onto an idle agent
|
|
599
|
+
// when another agent is the actual target. Same rule as
|
|
600
|
+
// claimFromPool: target=undefined (broadcast) is claimable by any
|
|
601
|
+
// agent; target=agentId is claimable only by that agent.
|
|
602
|
+
if (workItem.target && workItem.target !== agentId) {
|
|
603
|
+
this.logger.debug('claimSpecificItem refused — target mismatch', {
|
|
604
|
+
workItemId,
|
|
605
|
+
existingTarget: workItem.target,
|
|
606
|
+
requestingAgent: agentId,
|
|
607
|
+
});
|
|
608
|
+
return null;
|
|
609
|
+
}
|
|
610
|
+
const claims = await this.storage.getClaims();
|
|
611
|
+
if (claims.some((c) => c.workItemId === workItemId && c.status === 'active'))
|
|
612
|
+
return null;
|
|
613
|
+
// TRANS-2: route the queued → running flip through transitionStatus
|
|
614
|
+
// (mirrors claimFromPool — same V3 + state-machine gates).
|
|
615
|
+
// Hygiene #3 defensive: only assign target when it's currently
|
|
616
|
+
// undefined; never overwrite an existing target.
|
|
617
|
+
const claimedItem = await this.transitionStatus(workItemId, 'running', 'system', (wi) => {
|
|
618
|
+
if (!wi.target) {
|
|
619
|
+
wi.target = agentId;
|
|
620
|
+
}
|
|
621
|
+
});
|
|
622
|
+
if (!claimedItem)
|
|
623
|
+
return null;
|
|
624
|
+
const claimInput = { workItemId, agentId };
|
|
625
|
+
const claim = createTaskClaim(claimInput);
|
|
626
|
+
await this.storage.addClaim(claim);
|
|
627
|
+
await this.storage.flush();
|
|
628
|
+
this.logger.info('WorkItem claimed (specific)', { workItemId, agentId, claimId: claim.id });
|
|
629
|
+
return { workItem: claimedItem, claim };
|
|
197
630
|
});
|
|
198
|
-
if (!updated)
|
|
199
|
-
return null;
|
|
200
|
-
const claimInput = {
|
|
201
|
-
workItemId,
|
|
202
|
-
agentId,
|
|
203
|
-
...(workItem.type === 'project_task' ? { leaseDurationMs: PROJECT_TASK_LEASE_DURATION_MS } : {}),
|
|
204
|
-
};
|
|
205
|
-
const claim = createTaskClaim(claimInput);
|
|
206
|
-
await this.storage.addClaim(claim);
|
|
207
|
-
await this.storage.flush();
|
|
208
|
-
this.logger.info('WorkItem claimed (specific)', { workItemId, agentId, claimId: claim.id });
|
|
209
|
-
const claimedItem = await this.storage.findWorkItem(workItemId);
|
|
210
|
-
return claimedItem ? { workItem: claimedItem, claim } : null;
|
|
211
631
|
}
|
|
212
632
|
/**
|
|
213
633
|
* Releases a claimed WorkItem back to the pool.
|
|
@@ -235,11 +655,14 @@ export class TaskPoolService {
|
|
|
235
655
|
c.endReason = reason;
|
|
236
656
|
});
|
|
237
657
|
}
|
|
238
|
-
//
|
|
239
|
-
//
|
|
658
|
+
// TRANS-2: route the (running|blocked) → queued flip through the
|
|
659
|
+
// guarded transitionStatus helper. The state-machine entry for
|
|
660
|
+
// `running → queued` is a TRANS-2 addition, gated to system/TL/orc;
|
|
661
|
+
// `blocked → queued` was already TL/orc/system-gated by TRANS-1.
|
|
662
|
+
// Side-effect mutations (startedAt clear, target preservation when
|
|
663
|
+
// unblocking, retryCount bump) move into the atomic mutator.
|
|
240
664
|
const wasBlocked = workItem.status === 'blocked';
|
|
241
|
-
await this.
|
|
242
|
-
wi.status = 'queued';
|
|
665
|
+
await this.transitionStatus(workItemId, 'queued', 'system', (wi) => {
|
|
243
666
|
wi.startedAt = undefined;
|
|
244
667
|
if (!wasBlocked) {
|
|
245
668
|
wi.target = undefined;
|
|
@@ -254,38 +677,239 @@ export class TaskPoolService {
|
|
|
254
677
|
});
|
|
255
678
|
}
|
|
256
679
|
/**
|
|
257
|
-
*
|
|
680
|
+
* Decide whether a WorkItem requires TL verification before reaching a
|
|
681
|
+
* terminal-success status.
|
|
258
682
|
*
|
|
259
|
-
*
|
|
260
|
-
*
|
|
261
|
-
*
|
|
683
|
+
* Default policy (VERIF-1):
|
|
684
|
+
* - `delegate` items default to *requires verification* — a worker
|
|
685
|
+
* marking their own delegated work as "done" should produce
|
|
686
|
+
* `done_by_worker` and wake the TL for sign-off.
|
|
687
|
+
* - All other types (`cron_run`, `notify`, `reconcile`, `check`,
|
|
688
|
+
* `confirm`, `review`, ...) default to simple completion (`done`).
|
|
689
|
+
*
|
|
690
|
+
* The default is overridable via `wi.metadata.requiresVerification`:
|
|
691
|
+
* - `true` — force verification path even for non-delegate types
|
|
692
|
+
* - `false` — skip verification even for delegate types (this is the
|
|
693
|
+
* F-H affordance REVIEW-1 needs: review WIs are themselves the
|
|
694
|
+
* verification step, so they must NOT loop back to TL self-verify)
|
|
695
|
+
*
|
|
696
|
+
* @param wi - The WorkItem under inspection
|
|
697
|
+
* @returns true when the verification path should fire
|
|
698
|
+
*/
|
|
699
|
+
requiresVerification(wi) {
|
|
700
|
+
const metaFlag = wi.metadata?.requiresVerification;
|
|
701
|
+
if (metaFlag === true)
|
|
702
|
+
return true;
|
|
703
|
+
if (metaFlag === false)
|
|
704
|
+
return false;
|
|
705
|
+
return wi.type === 'delegate';
|
|
706
|
+
}
|
|
707
|
+
/**
|
|
708
|
+
* Internal: release the active claim on a WorkItem (if any). Shared by
|
|
709
|
+
* `completeSimpleItem` and `submitForVerification` because both
|
|
710
|
+
* represent the worker handing the item back to the system.
|
|
711
|
+
*
|
|
712
|
+
* @param workItemId - WorkItem whose claim should be released
|
|
713
|
+
* @param endReason - Reason recorded on the claim (`completed` /
|
|
714
|
+
* `submitted_for_verification`) for auditability
|
|
715
|
+
*/
|
|
716
|
+
async releaseClaim(workItemId, endReason) {
|
|
717
|
+
const claim = await this.storage.findActiveClaimByWorkItem(workItemId);
|
|
718
|
+
if (!claim)
|
|
719
|
+
return;
|
|
720
|
+
await this.storage.updateClaim(claim.id, (c) => {
|
|
721
|
+
c.status = 'released';
|
|
722
|
+
c.endedAt = new Date().toISOString();
|
|
723
|
+
c.endReason = endReason;
|
|
724
|
+
});
|
|
725
|
+
}
|
|
726
|
+
/**
|
|
727
|
+
* Worker reports a delegated WorkItem as done and submits it for TL
|
|
728
|
+
* verification.
|
|
729
|
+
*
|
|
730
|
+
* Transitions `running → done_by_worker` via {@link transitionStatus},
|
|
731
|
+
* which enforces the V3 actor-role gate (`'agent'` is allowed; any
|
|
732
|
+
* other role throws). The active claim is released as
|
|
733
|
+
* `submitted_for_verification` so the TL queue is the only thing
|
|
734
|
+
* blocking forward progress.
|
|
735
|
+
*
|
|
736
|
+
* Used by the `completeItem` facade for `delegate`-type items and any
|
|
737
|
+
* item whose `metadata.requiresVerification === true`.
|
|
738
|
+
*
|
|
739
|
+
* @param workItemId - WorkItem id
|
|
740
|
+
* @param actorRole - Role of the caller (`'agent'` for normal worker
|
|
741
|
+
* submissions; passed through to `isTransitionPermitted`)
|
|
742
|
+
* @param result - Optional result payload to attach to the WorkItem
|
|
743
|
+
* @returns The updated WorkItem, or `null` if the WI was deleted
|
|
744
|
+
* between the find and the update (race window)
|
|
745
|
+
* @throws When the WorkItem is missing, the transition is invalid, or
|
|
746
|
+
* the actor is not permitted to perform `running → done_by_worker`.
|
|
747
|
+
*/
|
|
748
|
+
async submitForVerification(workItemId, actorRole, result) {
|
|
749
|
+
await this.releaseClaim(workItemId, 'submitted_for_verification');
|
|
750
|
+
const updated = await this.transitionStatus(workItemId, 'done_by_worker', actorRole, (wi) => {
|
|
751
|
+
if (result)
|
|
752
|
+
wi.result = result;
|
|
753
|
+
});
|
|
754
|
+
await this.storage.flush();
|
|
755
|
+
this.logger.info('WorkItem submitted for verification', {
|
|
756
|
+
workItemId,
|
|
757
|
+
actorRole,
|
|
758
|
+
// BRIDGE-1 turns this into a real `task:done_by_worker` event below
|
|
759
|
+
// (F1-BRIDGE-1). The log line is preserved as a wake signal for any
|
|
760
|
+
// tail-based TL-watching subscriber that still greps it.
|
|
761
|
+
tlWakeRequested: true,
|
|
762
|
+
});
|
|
763
|
+
// F1-BRIDGE-1: publish AFTER the storage flush so any subscriber that
|
|
764
|
+
// re-reads via taskPool.findWorkItem sees the committed `done_by_worker`
|
|
765
|
+
// status. `updated` is null only on race-window deletion — skip the
|
|
766
|
+
// publish in that case (no source WI for the bridge to resolve).
|
|
767
|
+
if (updated) {
|
|
768
|
+
this.publishTaskDoneByWorker(updated);
|
|
769
|
+
}
|
|
770
|
+
return updated;
|
|
771
|
+
}
|
|
772
|
+
/**
|
|
773
|
+
* Worker (or system) marks a non-delegated WorkItem as fully done.
|
|
774
|
+
*
|
|
775
|
+
* Transitions `running → done` via {@link transitionStatus}. Used by
|
|
776
|
+
* the `completeItem` facade for `cron_run`, `notify`, `reconcile`,
|
|
777
|
+
* `check`, `confirm`, `review` types — anything whose lifecycle does
|
|
778
|
+
* NOT include a TL verification step.
|
|
779
|
+
*
|
|
780
|
+
* The Reconciler service is the only system-actor caller and uses
|
|
781
|
+
* `actorRole='system'`, which bypasses the actor check while still
|
|
782
|
+
* respecting the state-machine legality check.
|
|
783
|
+
*
|
|
784
|
+
* @param workItemId - WorkItem id
|
|
785
|
+
* @param actorRole - Role of the caller (`'agent'`, `'system'`, etc.)
|
|
786
|
+
* @param result - Optional result payload to attach
|
|
787
|
+
* @returns The updated WorkItem, or `null` if the WI was deleted
|
|
788
|
+
* between the find and the update (race window)
|
|
789
|
+
* @throws When the WorkItem is missing, the transition is invalid, or
|
|
790
|
+
* the actor is not permitted to perform `running → done`.
|
|
791
|
+
*/
|
|
792
|
+
async completeSimpleItem(workItemId, actorRole, result) {
|
|
793
|
+
await this.releaseClaim(workItemId, 'completed');
|
|
794
|
+
const updated = await this.transitionStatus(workItemId, 'done', actorRole, (wi) => {
|
|
795
|
+
if (result)
|
|
796
|
+
wi.result = result;
|
|
797
|
+
});
|
|
798
|
+
// Promote any blocked dependents whose deps are now all satisfied.
|
|
799
|
+
await this.resolveBlockedDependents(workItemId);
|
|
800
|
+
await this.storage.flush();
|
|
801
|
+
this.logger.info('WorkItem completed', { workItemId, actorRole });
|
|
802
|
+
return updated;
|
|
803
|
+
}
|
|
804
|
+
/**
|
|
805
|
+
* TL records a verdict on a WorkItem in `done_by_worker` status.
|
|
806
|
+
*
|
|
807
|
+
* `verified` advances to terminal success and unblocks dependents;
|
|
808
|
+
* `rejected` parks the item until the TL re-queues it (which TRANS-1
|
|
809
|
+
* gates to TL/orchestrator/system actors). Worker-actor calls throw
|
|
810
|
+
* automatically via {@link transitionStatus}'s permission gate — we
|
|
811
|
+
* do NOT need to add an explicit role check here, the matrix in
|
|
812
|
+
* `TRANSITION_PERMISSIONS` handles it.
|
|
813
|
+
*
|
|
814
|
+
* @param workItemId - WorkItem id (must currently be `done_by_worker`)
|
|
815
|
+
* @param actorRole - Role of the caller (`'team_lead'` or `'orchestrator'`
|
|
816
|
+
* for verify/reject; worker calls throw)
|
|
817
|
+
* @param verdict - `'verified'` or `'rejected'`
|
|
818
|
+
* @param comment - Optional reviewer comment recorded in `wi.error`
|
|
819
|
+
* (the field is reused — the WorkItem schema does not yet have a
|
|
820
|
+
* dedicated `verifierComment` slot; keeping this on `error` lets
|
|
821
|
+
* downstream UIs render TL feedback alongside failure causes)
|
|
822
|
+
* @returns The updated WorkItem, or `null` on race-window deletion
|
|
823
|
+
* @throws When the WorkItem is missing, the verdict is invalid, the
|
|
824
|
+
* transition is illegal, or the actor is not permitted to verify.
|
|
825
|
+
*/
|
|
826
|
+
async verifyItem(workItemId, actorRole, verdict, comment) {
|
|
827
|
+
if (verdict !== 'verified' && verdict !== 'rejected') {
|
|
828
|
+
throw new Error(`Invalid verdict: "${verdict}". Must be "verified" or "rejected".`);
|
|
829
|
+
}
|
|
830
|
+
const updated = await this.transitionStatus(workItemId, verdict, actorRole, (wi) => {
|
|
831
|
+
if (comment)
|
|
832
|
+
wi.error = comment;
|
|
833
|
+
});
|
|
834
|
+
if (verdict === 'verified') {
|
|
835
|
+
await this.resolveBlockedDependents(workItemId);
|
|
836
|
+
}
|
|
837
|
+
await this.storage.flush();
|
|
838
|
+
this.logger.info('WorkItem verdict recorded', { workItemId, verdict, actorRole });
|
|
839
|
+
// F1-BRIDGE-1: only the `rejected` branch publishes. The bridge's
|
|
840
|
+
// task:rejected handler creates the retry-or-escalate WI; the `verified`
|
|
841
|
+
// branch is terminal-success and unblocks dependents above without any
|
|
842
|
+
// bridge involvement. Skip the publish on race-window deletion.
|
|
843
|
+
if (verdict === 'rejected' && updated) {
|
|
844
|
+
this.publishTaskRejected(updated);
|
|
845
|
+
}
|
|
846
|
+
return updated;
|
|
847
|
+
}
|
|
848
|
+
/**
|
|
849
|
+
* Legacy facade — picks the verification path for the caller.
|
|
850
|
+
*
|
|
851
|
+
* Existing call sites (REST controller, task-management controllers,
|
|
852
|
+
* V3 data service) invoke `completeItem(id, result)` without an
|
|
853
|
+
* explicit actor role. The facade reads the WorkItem, applies the
|
|
854
|
+
* {@link requiresVerification} policy, and dispatches to either
|
|
855
|
+
* {@link submitForVerification} (delegate items / explicit opt-in)
|
|
856
|
+
* or {@link completeSimpleItem} (everything else).
|
|
857
|
+
*
|
|
858
|
+
* The legacy actor role for these implicit callers is `'agent'`.
|
|
859
|
+
* Migrations to explicit-actor calls can land in follow-up tickets
|
|
860
|
+
* without touching the five call sites in this PR.
|
|
861
|
+
*
|
|
862
|
+
* @param workItemId - WorkItem id
|
|
863
|
+
* @param result - Optional result payload
|
|
864
|
+
* @throws When the WorkItem is missing or the underlying transition
|
|
865
|
+
* is rejected (invalid state, forbidden actor).
|
|
262
866
|
*/
|
|
263
867
|
async completeItem(workItemId, result) {
|
|
264
868
|
const workItem = await this.storage.findWorkItem(workItemId);
|
|
265
869
|
if (!workItem) {
|
|
266
870
|
throw new Error(`WorkItem not found: ${workItemId}`);
|
|
267
871
|
}
|
|
268
|
-
if (workItem
|
|
269
|
-
|
|
872
|
+
if (this.requiresVerification(workItem)) {
|
|
873
|
+
await this.submitForVerification(workItemId, 'agent', result);
|
|
270
874
|
}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
if (claim) {
|
|
274
|
-
await this.storage.updateClaim(claim.id, (c) => {
|
|
275
|
-
c.status = 'released';
|
|
276
|
-
c.endedAt = new Date().toISOString();
|
|
277
|
-
c.endReason = 'completed';
|
|
278
|
-
});
|
|
875
|
+
else {
|
|
876
|
+
await this.completeSimpleItem(workItemId, 'agent', result);
|
|
279
877
|
}
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
878
|
+
}
|
|
879
|
+
/**
|
|
880
|
+
* Scans blocked WorkItems that list `completedId` in their `dependsOn` and
|
|
881
|
+
* promotes each to `queued` if every one of their deps has reached terminal
|
|
882
|
+
* success (`done` or `verified`). Idempotent and safe to call on any terminal
|
|
883
|
+
* success transition.
|
|
884
|
+
*
|
|
885
|
+
* Serialized via the claim mutex — a concurrent claimFromPool call must not
|
|
886
|
+
* observe a half-promoted item.
|
|
887
|
+
*/
|
|
888
|
+
async resolveBlockedDependents(completedId) {
|
|
889
|
+
await this.withClaimLock(async () => {
|
|
890
|
+
const items = await this.storage.getWorkItems();
|
|
891
|
+
const terminalSuccess = new Set(items
|
|
892
|
+
.filter((wi) => wi.status === 'done' || wi.status === 'verified')
|
|
893
|
+
.map((wi) => wi.id));
|
|
894
|
+
const candidates = items.filter((wi) => wi.status === 'blocked' &&
|
|
895
|
+
Array.isArray(wi.dependsOn) &&
|
|
896
|
+
wi.dependsOn.includes(completedId));
|
|
897
|
+
for (const candidate of candidates) {
|
|
898
|
+
const allSatisfied = (candidate.dependsOn ?? []).every((depId) => terminalSuccess.has(depId));
|
|
899
|
+
if (!allSatisfied)
|
|
900
|
+
continue;
|
|
901
|
+
// TRANS-2: route the blocked → queued promotion through
|
|
902
|
+
// transitionStatus. The 'system' actor matches both the V3
|
|
903
|
+
// permission gate (blocked→queued requires TL/orc/system) and
|
|
904
|
+
// the existing intent — dependency resolution is server-side
|
|
905
|
+
// bookkeeping, not a user-initiated action.
|
|
906
|
+
await this.transitionStatus(candidate.id, 'queued', 'system');
|
|
907
|
+
this.logger.info('WorkItem unblocked — all deps satisfied', {
|
|
908
|
+
workItemId: candidate.id,
|
|
909
|
+
via: completedId,
|
|
910
|
+
});
|
|
911
|
+
}
|
|
286
912
|
});
|
|
287
|
-
await this.storage.flush();
|
|
288
|
-
this.logger.info('WorkItem completed', { workItemId });
|
|
289
913
|
}
|
|
290
914
|
/**
|
|
291
915
|
* Marks a work item as failed.
|
|
@@ -311,10 +935,10 @@ export class TaskPoolService {
|
|
|
311
935
|
c.endReason = `failed: ${error}`;
|
|
312
936
|
});
|
|
313
937
|
}
|
|
314
|
-
//
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
938
|
+
// TRANS-2: route the running → failed flip through transitionStatus.
|
|
939
|
+
// `completedAt` is set automatically when newStatus === 'failed'; the
|
|
940
|
+
// mutator only needs to attach the error description.
|
|
941
|
+
await this.transitionStatus(workItemId, 'failed', 'system', (wi) => {
|
|
318
942
|
wi.error = error;
|
|
319
943
|
});
|
|
320
944
|
await this.storage.flush();
|
|
@@ -459,6 +1083,104 @@ export class TaskPoolService {
|
|
|
459
1083
|
async getAllItems() {
|
|
460
1084
|
return this.storage.getWorkItems();
|
|
461
1085
|
}
|
|
1086
|
+
/**
|
|
1087
|
+
* Find a WorkItem by id without mutating it.
|
|
1088
|
+
*
|
|
1089
|
+
* Public read accessor used by callers that need to inspect a
|
|
1090
|
+
* specific item — for example REVIEW-1's reentrancy lock checks the
|
|
1091
|
+
* status of a Mission's `pendingReviewWorkItemId` to decide whether
|
|
1092
|
+
* to clear the lock. Returns `null` (not `undefined`) so callers can
|
|
1093
|
+
* use a uniform null-fallthrough idiom shared with
|
|
1094
|
+
* `getWorkItemSnapshot` and `transitionStatus`.
|
|
1095
|
+
*
|
|
1096
|
+
* @param workItemId - WorkItem id to look up
|
|
1097
|
+
* @returns The WorkItem, or `null` if no item has that id
|
|
1098
|
+
*/
|
|
1099
|
+
async findWorkItem(workItemId) {
|
|
1100
|
+
return (await this.storage.findWorkItem(workItemId)) ?? null;
|
|
1101
|
+
}
|
|
1102
|
+
/**
|
|
1103
|
+
* Stores worker-supplied structured output on a WorkItem.
|
|
1104
|
+
*
|
|
1105
|
+
* Replaces the v1 `<taskId>.output.json` filesystem store with an
|
|
1106
|
+
* in-pool field (see {@link WorkItem.output}). Used by the worker
|
|
1107
|
+
* `complete-task` flow and read back by the TL `verify-output` skill.
|
|
1108
|
+
*
|
|
1109
|
+
* @param workItemId - WorkItem id to attach output to
|
|
1110
|
+
* @param output - Arbitrary task-specific output object
|
|
1111
|
+
* @returns The updated WorkItem, or null if not found
|
|
1112
|
+
*/
|
|
1113
|
+
async setOutput(workItemId, output) {
|
|
1114
|
+
const ok = await this.storage.updateWorkItem(workItemId, (wi) => {
|
|
1115
|
+
wi.output = output;
|
|
1116
|
+
});
|
|
1117
|
+
if (!ok)
|
|
1118
|
+
return null;
|
|
1119
|
+
return (await this.storage.findWorkItem(workItemId)) ?? null;
|
|
1120
|
+
}
|
|
1121
|
+
/**
|
|
1122
|
+
* Reassigns a WorkItem to a different target agent.
|
|
1123
|
+
*
|
|
1124
|
+
* Replaces the v1 `/task-management/handoff` filesystem reassign with a
|
|
1125
|
+
* direct `target` field update on the WorkItem.
|
|
1126
|
+
*
|
|
1127
|
+
* Allowed transitions:
|
|
1128
|
+
* - `target` must be a non-empty string
|
|
1129
|
+
* - WI must not be in a terminal state (done/cancelled/failed-final)
|
|
1130
|
+
*
|
|
1131
|
+
* @param workItemId - WorkItem to reassign
|
|
1132
|
+
* @param newTarget - Session name of the new target agent
|
|
1133
|
+
* @param fromAgent - Session name of the agent handing off (for audit)
|
|
1134
|
+
* @param reason - Human-readable reason recorded as a working-note
|
|
1135
|
+
* @returns The updated WorkItem, or null if not found
|
|
1136
|
+
*/
|
|
1137
|
+
async handoff(workItemId, newTarget, fromAgent, reason) {
|
|
1138
|
+
if (!newTarget || newTarget.trim() === '') {
|
|
1139
|
+
throw new Error('handoff: newTarget is required');
|
|
1140
|
+
}
|
|
1141
|
+
const wi = await this.storage.findWorkItem(workItemId);
|
|
1142
|
+
if (!wi)
|
|
1143
|
+
return null;
|
|
1144
|
+
if (wi.status === 'done' || wi.status === 'cancelled') {
|
|
1145
|
+
throw new Error(`handoff refused: WorkItem ${workItemId} is in terminal state '${wi.status}'`);
|
|
1146
|
+
}
|
|
1147
|
+
const handoffNote = `[HANDOFF] ${fromAgent} → ${newTarget}: ${reason || '(no reason)'}`;
|
|
1148
|
+
await this.storage.updateWorkItem(workItemId, (item) => {
|
|
1149
|
+
item.target = newTarget;
|
|
1150
|
+
const existing = (item.metadata && typeof item.metadata === 'object' ? item.metadata : {});
|
|
1151
|
+
const notes = Array.isArray(existing.notes) ? existing.notes : [];
|
|
1152
|
+
notes.push(`${new Date().toISOString()} ${handoffNote}`);
|
|
1153
|
+
item.metadata = { ...existing, notes };
|
|
1154
|
+
});
|
|
1155
|
+
this.logger.info('WorkItem handoff', { workItemId, fromAgent, newTarget });
|
|
1156
|
+
return (await this.storage.findWorkItem(workItemId)) ?? null;
|
|
1157
|
+
}
|
|
1158
|
+
/**
|
|
1159
|
+
* Appends a working-state note to a WorkItem's metadata.notes array.
|
|
1160
|
+
*
|
|
1161
|
+
* Replaces v1 `/task-management/sync` and `/task-management/save-working-notes`,
|
|
1162
|
+
* both of which appended progress notes to the `.md` task body. With v1
|
|
1163
|
+
* retired, notes live on the WorkItem itself under `metadata.notes[]`.
|
|
1164
|
+
*
|
|
1165
|
+
* @param workItemId - WorkItem id
|
|
1166
|
+
* @param author - Session name of note author
|
|
1167
|
+
* @param note - Note content (free-form)
|
|
1168
|
+
* @returns The updated WorkItem, or null if not found
|
|
1169
|
+
*/
|
|
1170
|
+
async appendNote(workItemId, author, note) {
|
|
1171
|
+
if (!note || note.trim() === '') {
|
|
1172
|
+
throw new Error('appendNote: note is required');
|
|
1173
|
+
}
|
|
1174
|
+
const ok = await this.storage.updateWorkItem(workItemId, (wi) => {
|
|
1175
|
+
const existing = (wi.metadata && typeof wi.metadata === 'object' ? wi.metadata : {});
|
|
1176
|
+
const notes = Array.isArray(existing.notes) ? existing.notes : [];
|
|
1177
|
+
notes.push(`${new Date().toISOString()} [${author}] ${note}`);
|
|
1178
|
+
wi.metadata = { ...existing, notes };
|
|
1179
|
+
});
|
|
1180
|
+
if (!ok)
|
|
1181
|
+
return null;
|
|
1182
|
+
return (await this.storage.findWorkItem(workItemId)) ?? null;
|
|
1183
|
+
}
|
|
462
1184
|
/**
|
|
463
1185
|
* Removes a WorkItem from the pool entirely.
|
|
464
1186
|
* Used for purging old completed/cancelled items.
|
|
@@ -468,6 +1190,63 @@ export class TaskPoolService {
|
|
|
468
1190
|
async removeItem(workItemId) {
|
|
469
1191
|
await this.storage.removeWorkItem(workItemId);
|
|
470
1192
|
}
|
|
1193
|
+
// -------------------------------------------------------------------------
|
|
1194
|
+
// P1 1ffffb84(a) — Bulk-DELETE stale WorkItems
|
|
1195
|
+
// -------------------------------------------------------------------------
|
|
1196
|
+
/**
|
|
1197
|
+
* Public delete API used by the bulk-cleanup script and the new
|
|
1198
|
+
* `DELETE /api/task-pool/:id` HTTP endpoint (P1 umbrella WI 1ffffb84
|
|
1199
|
+
* component a, Steve directive 2026-05-06: just-DELETE-not-backfill).
|
|
1200
|
+
*
|
|
1201
|
+
* Three guarantees over {@link removeItem}:
|
|
1202
|
+
* 1. Idempotent — `not_found` is a no-op return, not a throw.
|
|
1203
|
+
* 2. Claim-safety — refuses claimed delete unless `opts.force`.
|
|
1204
|
+
* 3. Audit log — single info-level log per removal.
|
|
1205
|
+
*
|
|
1206
|
+
* Force path also revokes the orphaned claim (status='revoked',
|
|
1207
|
+
* endedAt, endReason).
|
|
1208
|
+
*/
|
|
1209
|
+
async removeFromPool(workItemId, opts = {}) {
|
|
1210
|
+
const wi = await this.storage.findWorkItem(workItemId);
|
|
1211
|
+
if (!wi) {
|
|
1212
|
+
this.logger.debug('removeFromPool: item not found (idempotent)', { workItemId });
|
|
1213
|
+
return { removed: false, reason: 'not_found' };
|
|
1214
|
+
}
|
|
1215
|
+
const activeClaim = await this.storage.findActiveClaimByWorkItem(workItemId);
|
|
1216
|
+
const hadActiveClaim = !!activeClaim;
|
|
1217
|
+
if (hadActiveClaim && activeClaim && !opts.force) {
|
|
1218
|
+
this.logger.warn('removeFromPool refused: active claim exists', {
|
|
1219
|
+
workItemId,
|
|
1220
|
+
claimId: activeClaim.id,
|
|
1221
|
+
claimedBy: activeClaim.agentId,
|
|
1222
|
+
});
|
|
1223
|
+
throw new WorkItemClaimedError({
|
|
1224
|
+
workItemId,
|
|
1225
|
+
claimId: activeClaim.id,
|
|
1226
|
+
claimedBy: activeClaim.agentId,
|
|
1227
|
+
});
|
|
1228
|
+
}
|
|
1229
|
+
const removed = await this.storage.removeWorkItem(workItemId);
|
|
1230
|
+
if (hadActiveClaim && activeClaim) {
|
|
1231
|
+
await this.storage.updateClaim(activeClaim.id, (c) => {
|
|
1232
|
+
c.status = 'revoked';
|
|
1233
|
+
c.endedAt = new Date().toISOString();
|
|
1234
|
+
c.endReason = `WorkItem deleted via removeFromPool (force=${opts.force === true})`;
|
|
1235
|
+
});
|
|
1236
|
+
}
|
|
1237
|
+
this.logger.info('removeFromPool: WorkItem removed', {
|
|
1238
|
+
workItemId,
|
|
1239
|
+
status: wi.status,
|
|
1240
|
+
target: wi.target,
|
|
1241
|
+
force: opts.force === true,
|
|
1242
|
+
hadActiveClaim,
|
|
1243
|
+
});
|
|
1244
|
+
return {
|
|
1245
|
+
removed: removed === true,
|
|
1246
|
+
workItem: wi,
|
|
1247
|
+
hadActiveClaim,
|
|
1248
|
+
};
|
|
1249
|
+
}
|
|
471
1250
|
/**
|
|
472
1251
|
* Forces an immediate flush of pool data to disk.
|
|
473
1252
|
* Called during graceful shutdown to prevent data loss.
|
|
@@ -488,41 +1267,186 @@ export class TaskPoolService {
|
|
|
488
1267
|
* Updates a work item's status directly.
|
|
489
1268
|
* Used by the Reconciler for corrections (e.g., stuck → blocked).
|
|
490
1269
|
*
|
|
1270
|
+
* Reconciler invocations pass through `actorRole='system'` (default) which
|
|
1271
|
+
* bypasses the per-role gate at {@link isTransitionPermitted} but still
|
|
1272
|
+
* enforces the state-machine via {@link isValidWorkItemTransition}. Other
|
|
1273
|
+
* callers MUST supply the actor's role so TRANS-1 V3 enforcement applies.
|
|
1274
|
+
*
|
|
491
1275
|
* @param workItemId - The work item ID
|
|
492
1276
|
* @param newStatus - The target status
|
|
493
|
-
* @
|
|
1277
|
+
* @param actorRole - Role of the caller (defaults to `'system'` for Reconciler)
|
|
1278
|
+
* @throws Error if work item not found
|
|
1279
|
+
* @throws Error if transition is invalid (state machine — see WORK_ITEM_TRANSITIONS)
|
|
1280
|
+
* @throws Error if actor is not permitted (role check — see TRANSITION_PERMISSIONS)
|
|
494
1281
|
*/
|
|
495
|
-
async updateItemStatus(workItemId, newStatus) {
|
|
1282
|
+
async updateItemStatus(workItemId, newStatus, actorRole = 'system') {
|
|
496
1283
|
const items = await this.storage.getWorkItems();
|
|
497
1284
|
const item = items.find((wi) => wi.id === workItemId);
|
|
498
1285
|
if (!item) {
|
|
499
1286
|
throw new Error(`WorkItem not found: ${workItemId}`);
|
|
500
1287
|
}
|
|
501
|
-
if (item.status === newStatus) {
|
|
502
|
-
this.logger.debug('Work item status update is a no-op, skipping', {
|
|
503
|
-
workItemId,
|
|
504
|
-
status: newStatus,
|
|
505
|
-
});
|
|
506
|
-
return;
|
|
507
|
-
}
|
|
508
1288
|
if (!isValidWorkItemTransition(item.status, newStatus)) {
|
|
509
1289
|
throw new Error(`Invalid status transition for WorkItem ${workItemId}: ${item.status} → ${newStatus}`);
|
|
510
1290
|
}
|
|
1291
|
+
// TRANS-1 V3: enforce per-role permissions. system role always passes.
|
|
1292
|
+
if (!isTransitionPermitted(item.status, newStatus, actorRole)) {
|
|
1293
|
+
throw new Error(`Forbidden transition for WorkItem ${workItemId}: actor='${actorRole}' ` +
|
|
1294
|
+
`not permitted to perform ${item.status} → ${newStatus}.`);
|
|
1295
|
+
}
|
|
511
1296
|
await this.storage.updateWorkItem(workItemId, (wi) => {
|
|
512
1297
|
wi.status = newStatus;
|
|
513
|
-
//
|
|
1298
|
+
// P1 1ffffb84 component (b): mirror the transitionStatus
|
|
1299
|
+
// atomic-timestamp contract so the older updateItemStatus path
|
|
1300
|
+
// never produces a status↔completedAt mismatch either. See
|
|
1301
|
+
// transitionStatus below for the full root-cause writeup
|
|
1302
|
+
// (b7840fe8 partial-write bug).
|
|
514
1303
|
if (newStatus === 'running') {
|
|
515
1304
|
wi.startedAt = new Date().toISOString();
|
|
1305
|
+
wi.completedAt = undefined;
|
|
516
1306
|
}
|
|
517
1307
|
else if (newStatus === 'done' || newStatus === 'failed') {
|
|
518
1308
|
wi.completedAt = new Date().toISOString();
|
|
519
1309
|
}
|
|
1310
|
+
else {
|
|
1311
|
+
wi.completedAt = undefined;
|
|
1312
|
+
}
|
|
520
1313
|
});
|
|
521
1314
|
this.logger.info('Work item status updated', {
|
|
522
1315
|
workItemId,
|
|
523
1316
|
from: item.status,
|
|
524
1317
|
to: newStatus,
|
|
1318
|
+
actorRole,
|
|
525
1319
|
});
|
|
1320
|
+
// Cascade signal — let RequestCascadeSubscriber close the parent
|
|
1321
|
+
// Request without waiting for the heartbeat catch. See
|
|
1322
|
+
// {@link publishTaskCancelled} for the full bug writeup.
|
|
1323
|
+
if (newStatus === 'cancelled') {
|
|
1324
|
+
const post = await this.storage.findWorkItem(workItemId);
|
|
1325
|
+
if (post)
|
|
1326
|
+
this.publishTaskCancelled(post, item.status);
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
/**
|
|
1330
|
+
* Public guarded transition helper — TRANS-1's canonical entrypoint.
|
|
1331
|
+
*
|
|
1332
|
+
* Routes any externally-initiated WorkItem status change through the
|
|
1333
|
+
* combined state-machine + actor-role gates. Designed as the public API
|
|
1334
|
+
* VERIF-1 will call from `submitForVerification` / `verifyItem`, and as
|
|
1335
|
+
* the recommended path for any future caller that previously reached
|
|
1336
|
+
* for `storage.updateWorkItem` to flip status.
|
|
1337
|
+
*
|
|
1338
|
+
* Differences vs {@link updateItemStatus}:
|
|
1339
|
+
* - Requires `actorRole` explicitly (no default) — forces the caller to
|
|
1340
|
+
* decide the trust posture rather than silently inheriting `'system'`.
|
|
1341
|
+
* - Accepts an optional `mutator` so callers can carry additional field
|
|
1342
|
+
* updates (e.g. `result`, `error`, `completedAt`) atomically with the
|
|
1343
|
+
* status flip — preventing races between status update and metadata
|
|
1344
|
+
* attachment that direct `storage.updateWorkItem` callers risked.
|
|
1345
|
+
*
|
|
1346
|
+
* @param workItemId - The work item ID
|
|
1347
|
+
* @param newStatus - The target status
|
|
1348
|
+
* @param actorRole - Role of the caller (REQUIRED; pass `'system'` for trusted server-internal paths)
|
|
1349
|
+
* @param mutator - Optional additional WorkItem field updates applied atomically with the status change
|
|
1350
|
+
* @returns The updated WorkItem after the transition
|
|
1351
|
+
* @throws Error if work item not found
|
|
1352
|
+
* @throws Error if transition is invalid (state machine)
|
|
1353
|
+
* @throws Error if actor is not permitted (role check)
|
|
1354
|
+
*
|
|
1355
|
+
* @example
|
|
1356
|
+
* ```typescript
|
|
1357
|
+
* // VERIF-1 worker submitting for verification
|
|
1358
|
+
* await pool.transitionStatus(wiId, 'done_by_worker', 'agent', (wi) => {
|
|
1359
|
+
* wi.result = output;
|
|
1360
|
+
* });
|
|
1361
|
+
*
|
|
1362
|
+
* // VERIF-1 TL verifying
|
|
1363
|
+
* await pool.transitionStatus(wiId, 'verified', 'team_lead');
|
|
1364
|
+
*
|
|
1365
|
+
* // VERIF-1 TL rejecting (allowed for TL only)
|
|
1366
|
+
* await pool.transitionStatus(wiId, 'rejected', 'team_lead', (wi) => {
|
|
1367
|
+
* wi.error = 'Did not meet acceptance criteria';
|
|
1368
|
+
* });
|
|
1369
|
+
* ```
|
|
1370
|
+
*/
|
|
1371
|
+
async transitionStatus(workItemId, newStatus, actorRole, mutator) {
|
|
1372
|
+
const item = await this.storage.findWorkItem(workItemId);
|
|
1373
|
+
if (!item) {
|
|
1374
|
+
throw new Error(`WorkItem not found: ${workItemId}`);
|
|
1375
|
+
}
|
|
1376
|
+
if (!isValidWorkItemTransition(item.status, newStatus)) {
|
|
1377
|
+
throw new Error(`Invalid status transition for WorkItem ${workItemId}: ${item.status} → ${newStatus}`);
|
|
1378
|
+
}
|
|
1379
|
+
if (!isTransitionPermitted(item.status, newStatus, actorRole)) {
|
|
1380
|
+
throw new Error(`Forbidden transition for WorkItem ${workItemId}: actor='${actorRole}' ` +
|
|
1381
|
+
`not permitted to perform ${item.status} → ${newStatus}.`);
|
|
1382
|
+
}
|
|
1383
|
+
const ok = await this.storage.updateWorkItem(workItemId, (wi) => {
|
|
1384
|
+
wi.status = newStatus;
|
|
1385
|
+
// Atomic timestamp side-effects enforce the invariant
|
|
1386
|
+
// `completedAt is set IFF status ∈ {done, failed, verified,
|
|
1387
|
+
// done_by_worker, rejected}`.
|
|
1388
|
+
//
|
|
1389
|
+
// P1 1ffffb84 component (b): the prior code only SET completedAt
|
|
1390
|
+
// on terminal transitions; non-terminal landings (queued, running,
|
|
1391
|
+
// blocked, scheduled, proposed, accepted, escalated, cancelled)
|
|
1392
|
+
// inherited a stale completedAt from a prior terminal trip via
|
|
1393
|
+
// - `rejected → queued` (TL re-queue)
|
|
1394
|
+
// - `failed → queued` (BRIDGE-1 retry)
|
|
1395
|
+
// - `running → queued` (releaseBack abandon path)
|
|
1396
|
+
// WorkItem b7840fe8 reproduced the bug — status=queued AND
|
|
1397
|
+
// completedAt=2026-05-06T00:47:59Z AND retryCount=1 AND no
|
|
1398
|
+
// startedAt/target, which is the exact fingerprint of a
|
|
1399
|
+
// `failed → queued` retry leaving stale completedAt. The else
|
|
1400
|
+
// branch below closes the gap atomically with the status flip.
|
|
1401
|
+
if (newStatus === 'running') {
|
|
1402
|
+
wi.startedAt = new Date().toISOString();
|
|
1403
|
+
// Resuming work — clear stale completedAt from a prior failed/
|
|
1404
|
+
// rejected attempt so a re-claim never carries forward a
|
|
1405
|
+
// completion timestamp from an earlier terminal trip.
|
|
1406
|
+
wi.completedAt = undefined;
|
|
1407
|
+
}
|
|
1408
|
+
else if (newStatus === 'done' ||
|
|
1409
|
+
newStatus === 'failed' ||
|
|
1410
|
+
newStatus === 'verified' ||
|
|
1411
|
+
newStatus === 'done_by_worker' ||
|
|
1412
|
+
newStatus === 'rejected') {
|
|
1413
|
+
wi.completedAt = new Date().toISOString();
|
|
1414
|
+
}
|
|
1415
|
+
else {
|
|
1416
|
+
// Non-terminal-with-result landings: clear completedAt so the
|
|
1417
|
+
// invariant holds. (`cancelled` is technically terminal but
|
|
1418
|
+
// historically never carried completedAt — preserving that
|
|
1419
|
+
// shape here to keep the change minimal; the `cancelled`
|
|
1420
|
+
// semantics are out of scope.)
|
|
1421
|
+
wi.completedAt = undefined;
|
|
1422
|
+
}
|
|
1423
|
+
if (mutator)
|
|
1424
|
+
mutator(wi);
|
|
1425
|
+
});
|
|
1426
|
+
if (!ok) {
|
|
1427
|
+
// Race window: someone else removed the WorkItem between findWorkItem
|
|
1428
|
+
// and updateWorkItem. Surface as null so callers can distinguish from
|
|
1429
|
+
// a thrown invalid-transition / forbidden-transition error.
|
|
1430
|
+
return null;
|
|
1431
|
+
}
|
|
1432
|
+
this.logger.info('WorkItem transitioned', {
|
|
1433
|
+
workItemId,
|
|
1434
|
+
from: item.status,
|
|
1435
|
+
to: newStatus,
|
|
1436
|
+
actorRole,
|
|
1437
|
+
});
|
|
1438
|
+
// Return the post-update WorkItem snapshot so callers can chain on the
|
|
1439
|
+
// resolved value rather than re-fetching. Coerce `undefined` (item
|
|
1440
|
+
// removed during the race window) to `null` to match the declared
|
|
1441
|
+
// return type.
|
|
1442
|
+
const post = (await this.storage.findWorkItem(workItemId)) ?? null;
|
|
1443
|
+
// Cascade signal — let RequestCascadeSubscriber close the parent
|
|
1444
|
+
// Request without waiting for the heartbeat catch. See
|
|
1445
|
+
// {@link publishTaskCancelled} for the full bug writeup.
|
|
1446
|
+
if (newStatus === 'cancelled' && post) {
|
|
1447
|
+
this.publishTaskCancelled(post, item.status);
|
|
1448
|
+
}
|
|
1449
|
+
return post;
|
|
526
1450
|
}
|
|
527
1451
|
/**
|
|
528
1452
|
* Update token usage and cost on a WorkItem.
|