crewly 1.20.153 → 1.20.155
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/README.md +21 -3
- package/config/constants.ts +78 -0
- package/config/hooks/agent-status/report.sh +78 -0
- package/config/hooks/control-plane-guard/pretooluse-bash.sh +241 -0
- package/config/orchestrator_tasks/prompts/assign-task-orchestrator-prompt-template.md +19 -49
- package/config/orchestrator_tasks/prompts/checkin-orchestrator-prompt-template.md +25 -125
- package/config/orchestrator_tasks/prompts/project-start-orchestrator-prompt-template.md +29 -100
- package/config/roles/orchestrator/prompt.md +18 -2
- package/config/roles/team-leader/prompt.md +13 -3
- package/config/roles/team-leader/role.json +1 -1
- package/config/roles/team-leader/tl-addon.md +12 -3
- package/config/skills/agent/core/complete-task/SKILL.md +1 -1
- package/config/skills/agent/core/project-tickets/SKILL.md +127 -0
- package/config/skills/agent/core/project-tickets/execute.sh +182 -0
- package/config/skills/agent/core/project-tickets/execute.test.sh +116 -0
- package/config/skills/agent/core/recall/SKILL.md +1 -1
- package/config/skills/agent/core/recall/execute.sh +7 -0
- package/config/skills/agent/core/report-status/SKILL.md +3 -2
- package/config/skills/agent/core/report-status/execute.sh +37 -15
- package/config/skills/agent/core/split-ticket/SKILL.md +62 -0
- package/config/skills/agent/core/split-ticket/execute.sh +87 -0
- package/config/skills/agent/core/split-ticket/execute.test.sh +77 -0
- package/config/skills/agent/core/standing-update/SKILL.md +96 -0
- package/config/skills/agent/core/standing-update/execute.sh +107 -0
- package/config/skills/agent/onboarding/materialize-team/SKILL.md +1 -1
- package/config/skills/agent/onboarding/recommend-team/SKILL.md +1 -1
- package/config/skills/orchestrator/delegate-task/SKILL.md +4 -3
- package/config/skills/orchestrator/render-verdict/SKILL.md +62 -0
- package/config/skills/orchestrator/render-verdict/execute.sh +47 -0
- package/config/skills/orchestrator/render-verdict/execute.test.sh +121 -0
- package/config/skills/orchestrator/wiki-migrate/SKILL.md +0 -1
- package/config/skills/team-leader/aggregate-results/SKILL.md +1 -1
- package/config/skills/team-leader/assign-ticket/SKILL.md +47 -0
- package/config/skills/team-leader/assign-ticket/execute.sh +59 -0
- package/config/skills/team-leader/assign-ticket/execute.test.sh +64 -0
- package/config/skills/team-leader/decompose-goal/SKILL.md +4 -4
- package/config/skills/team-leader/delegate-task/SKILL.md +1 -1
- package/config/skills/team-leader/delegate-task/execute.sh +17 -4
- package/config/skills/team-leader/verify-output/SKILL.md +2 -2
- package/config/sops/developer/git-workflow.md +1 -1
- package/dist/backend/backend/src/constants.d.ts +397 -1
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +388 -2
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/agent-hooks/agent-hooks.controller.d.ts +27 -0
- package/dist/backend/backend/src/controllers/agent-hooks/agent-hooks.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/agent-hooks/agent-hooks.controller.js +55 -0
- package/dist/backend/backend/src/controllers/agent-hooks/agent-hooks.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/agent-hooks/agent-hooks.routes.d.ts +13 -0
- package/dist/backend/backend/src/controllers/agent-hooks/agent-hooks.routes.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/agent-hooks/agent-hooks.routes.js +19 -0
- package/dist/backend/backend/src/controllers/agent-hooks/agent-hooks.routes.js.map +1 -0
- package/dist/backend/backend/src/controllers/api.controller.d.ts +0 -12
- package/dist/backend/backend/src/controllers/api.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/api.controller.js +0 -44
- package/dist/backend/backend/src/controllers/api.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/approvals/approvals.controller.d.ts +27 -5
- package/dist/backend/backend/src/controllers/approvals/approvals.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/approvals/approvals.controller.js +55 -15
- package/dist/backend/backend/src/controllers/approvals/approvals.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/approvals/approvals.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/approvals/approvals.routes.js +2 -0
- package/dist/backend/backend/src/controllers/approvals/approvals.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/expert/expert.controller.d.ts +13 -0
- package/dist/backend/backend/src/controllers/expert/expert.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/expert/expert.controller.js +67 -9
- package/dist/backend/backend/src/controllers/expert/expert.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/monitoring/terminal.controller.d.ts +32 -0
- package/dist/backend/backend/src/controllers/monitoring/terminal.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/monitoring/terminal.controller.js +122 -8
- package/dist/backend/backend/src/controllers/monitoring/terminal.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/owner-receipt/owner-receipt.controller.d.ts +41 -0
- package/dist/backend/backend/src/controllers/owner-receipt/owner-receipt.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/owner-receipt/owner-receipt.controller.js +146 -0
- package/dist/backend/backend/src/controllers/owner-receipt/owner-receipt.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/owner-receipt/owner-receipt.routes.d.ts +20 -0
- package/dist/backend/backend/src/controllers/owner-receipt/owner-receipt.routes.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/owner-receipt/owner-receipt.routes.js +29 -0
- package/dist/backend/backend/src/controllers/owner-receipt/owner-receipt.routes.js.map +1 -0
- package/dist/backend/backend/src/controllers/project/project.controller.d.ts +2 -2
- package/dist/backend/backend/src/controllers/project/project.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/project/project.controller.js +24 -7
- package/dist/backend/backend/src/controllers/project/project.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/project/project.routes.d.ts +2 -2
- package/dist/backend/backend/src/controllers/project/project.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/project/project.routes.js +3 -36
- package/dist/backend/backend/src/controllers/project/project.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.d.ts +93 -0
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.js +252 -0
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.routes.d.ts +34 -0
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.routes.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.routes.js +51 -0
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.routes.js.map +1 -0
- package/dist/backend/backend/src/controllers/request-types.d.ts +13 -0
- package/dist/backend/backend/src/controllers/request-types.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/standing/standing.controller.d.ts +49 -0
- package/dist/backend/backend/src/controllers/standing/standing.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/standing/standing.controller.js +100 -0
- package/dist/backend/backend/src/controllers/standing/standing.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.d.ts +38 -0
- 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 +143 -8
- 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 +6 -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 +2 -0
- package/dist/backend/backend/src/controllers/team/team.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/team/team.controller.js +26 -6
- package/dist/backend/backend/src/controllers/team/team.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/tickets/tickets.controller.d.ts +18 -0
- package/dist/backend/backend/src/controllers/tickets/tickets.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/tickets/tickets.controller.js +56 -0
- package/dist/backend/backend/src/controllers/tickets/tickets.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/tickets/tickets.routes.d.ts +1 -0
- package/dist/backend/backend/src/controllers/tickets/tickets.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/tickets/tickets.routes.js +3 -1
- package/dist/backend/backend/src/controllers/tickets/tickets.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/controllers/wiki/wiki.controller.d.ts +2 -3
- package/dist/backend/backend/src/controllers/wiki/wiki.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/wiki/wiki.controller.js +2 -3
- package/dist/backend/backend/src/controllers/wiki/wiki.controller.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +113 -7
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/middleware/api-token.middleware.d.ts +29 -0
- package/dist/backend/backend/src/middleware/api-token.middleware.d.ts.map +1 -1
- package/dist/backend/backend/src/middleware/api-token.middleware.js +38 -0
- package/dist/backend/backend/src/middleware/api-token.middleware.js.map +1 -1
- package/dist/backend/backend/src/models/index.d.ts +0 -1
- package/dist/backend/backend/src/models/index.d.ts.map +1 -1
- package/dist/backend/backend/src/models/index.js +0 -1
- package/dist/backend/backend/src/models/index.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 +24 -3
- package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
- package/dist/backend/backend/src/scripts/leaked-stub-teams.lib.d.ts +6 -2
- package/dist/backend/backend/src/scripts/leaked-stub-teams.lib.d.ts.map +1 -1
- package/dist/backend/backend/src/scripts/leaked-stub-teams.lib.js +6 -2
- package/dist/backend/backend/src/scripts/leaked-stub-teams.lib.js.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts +43 -1
- 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 +129 -34
- package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/control-plane-guard.service.d.ts +169 -0
- package/dist/backend/backend/src/services/agent/control-plane-guard.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/agent/control-plane-guard.service.js +231 -0
- package/dist/backend/backend/src/services/agent/control-plane-guard.service.js.map +1 -0
- package/dist/backend/backend/src/services/agent/fresh-task-conversation.service.d.ts +154 -2
- package/dist/backend/backend/src/services/agent/fresh-task-conversation.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/fresh-task-conversation.service.js +380 -22
- package/dist/backend/backend/src/services/agent/fresh-task-conversation.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.d.ts +16 -0
- package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.js +50 -0
- package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.js.map +1 -1
- package/dist/backend/backend/src/services/agent/tmux-command.service.d.ts +9 -1
- package/dist/backend/backend/src/services/agent/tmux-command.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/tmux-command.service.js +12 -2
- package/dist/backend/backend/src/services/agent/tmux-command.service.js.map +1 -1
- 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 +9 -8
- package/dist/backend/backend/src/services/ai/prompt-builder.service.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/active-work.module.d.ts +75 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/active-work.module.d.ts.map +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/active-work.module.js +89 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/active-work.module.js.map +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/index.d.ts +3 -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 +3 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/index.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/project-reference.module.js +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/project-reference.module.js.map +1 -1
- 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 +12 -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 +14 -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/recovery.module.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/recovery.module.js +11 -7
- package/dist/backend/backend/src/services/ai/prompt-modules/recovery.module.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/session-briefing.module.d.ts +41 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/session-briefing.module.d.ts.map +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/session-briefing.module.js +44 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/session-briefing.module.js.map +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/standing-answers.module.d.ts +67 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/standing-answers.module.d.ts.map +1 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/standing-answers.module.js +146 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/standing-answers.module.js.map +1 -0
- package/dist/backend/backend/src/services/ai/prompt-template.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-template.service.js +9 -7
- package/dist/backend/backend/src/services/ai/prompt-template.service.js.map +1 -1
- package/dist/backend/backend/src/services/cloud/mobile-api-relay.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/cloud/mobile-api-relay.service.js +7 -0
- package/dist/backend/backend/src/services/cloud/mobile-api-relay.service.js.map +1 -1
- package/dist/backend/backend/src/services/continuation/patterns/waiting-patterns.d.ts +7 -0
- package/dist/backend/backend/src/services/continuation/patterns/waiting-patterns.d.ts.map +1 -1
- package/dist/backend/backend/src/services/continuation/patterns/waiting-patterns.js +9 -1
- package/dist/backend/backend/src/services/continuation/patterns/waiting-patterns.js.map +1 -1
- package/dist/backend/backend/src/services/core/logger.service.d.ts +21 -0
- package/dist/backend/backend/src/services/core/logger.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/core/logger.service.js +42 -4
- package/dist/backend/backend/src/services/core/logger.service.js.map +1 -1
- package/dist/backend/backend/src/services/core/storage.service.d.ts +1 -5
- package/dist/backend/backend/src/services/core/storage.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/core/storage.service.js +5 -162
- package/dist/backend/backend/src/services/core/storage.service.js.map +1 -1
- package/dist/backend/backend/src/services/event-bus/event-bus.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/event-bus/event-bus.service.js +6 -0
- package/dist/backend/backend/src/services/event-bus/event-bus.service.js.map +1 -1
- package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.js +15 -9
- package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.js.map +1 -1
- package/dist/backend/backend/src/services/index.d.ts +0 -4
- package/dist/backend/backend/src/services/index.d.ts.map +1 -1
- package/dist/backend/backend/src/services/index.js +0 -4
- package/dist/backend/backend/src/services/index.js.map +1 -1
- package/dist/backend/backend/src/services/intent-task/intent-task.service.d.ts +1 -1
- package/dist/backend/backend/src/services/intent-task/intent-task.service.js +1 -1
- package/dist/backend/backend/src/services/mcp-server.d.ts +19 -6
- package/dist/backend/backend/src/services/mcp-server.d.ts.map +1 -1
- package/dist/backend/backend/src/services/mcp-server.js +46 -16
- package/dist/backend/backend/src/services/mcp-server.js.map +1 -1
- package/dist/backend/backend/src/services/mcp-tool-definitions.d.ts.map +1 -1
- package/dist/backend/backend/src/services/mcp-tool-definitions.js +3 -2
- package/dist/backend/backend/src/services/mcp-tool-definitions.js.map +1 -1
- package/dist/backend/backend/src/services/memory/standing-answers.service.d.ts +247 -0
- package/dist/backend/backend/src/services/memory/standing-answers.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/memory/standing-answers.service.js +534 -0
- package/dist/backend/backend/src/services/memory/standing-answers.service.js.map +1 -0
- package/dist/backend/backend/src/services/memory/standing-refresh.service.d.ts +104 -0
- package/dist/backend/backend/src/services/memory/standing-refresh.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/memory/standing-refresh.service.js +218 -0
- package/dist/backend/backend/src/services/memory/standing-refresh.service.js.map +1 -0
- package/dist/backend/backend/src/services/monitoring/activity-monitor.service.d.ts +35 -0
- package/dist/backend/backend/src/services/monitoring/activity-monitor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/monitoring/activity-monitor.service.js +99 -1
- package/dist/backend/backend/src/services/monitoring/activity-monitor.service.js.map +1 -1
- package/dist/backend/backend/src/services/monitoring/agent-attention-registry.d.ts +75 -0
- package/dist/backend/backend/src/services/monitoring/agent-attention-registry.d.ts.map +1 -0
- package/dist/backend/backend/src/services/monitoring/agent-attention-registry.js +80 -0
- package/dist/backend/backend/src/services/monitoring/agent-attention-registry.js.map +1 -0
- package/dist/backend/backend/src/services/monitoring/agent-attention.d.ts +114 -0
- package/dist/backend/backend/src/services/monitoring/agent-attention.d.ts.map +1 -0
- package/dist/backend/backend/src/services/monitoring/agent-attention.js +165 -0
- package/dist/backend/backend/src/services/monitoring/agent-attention.js.map +1 -0
- package/dist/backend/backend/src/services/monitoring/agent-hook-state.d.ts +76 -0
- package/dist/backend/backend/src/services/monitoring/agent-hook-state.d.ts.map +1 -0
- package/dist/backend/backend/src/services/monitoring/agent-hook-state.js +96 -0
- package/dist/backend/backend/src/services/monitoring/agent-hook-state.js.map +1 -0
- package/dist/backend/backend/src/services/orchestrator/onboarding/materialize-team.js +1 -1
- package/dist/backend/backend/src/services/orchestrator/onboarding/recommend-team.d.ts +1 -1
- package/dist/backend/backend/src/services/orchestrator/onboarding/recommend-team.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/onboarding/recommend-team.js +13 -3
- package/dist/backend/backend/src/services/orchestrator/onboarding/recommend-team.js.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/prompts/onboarding-mode.prompt.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/prompts/onboarding-mode.prompt.js +0 -4
- package/dist/backend/backend/src/services/orchestrator/prompts/onboarding-mode.prompt.js.map +1 -1
- package/dist/backend/backend/src/services/project/project-search.service.d.ts +22 -16
- package/dist/backend/backend/src/services/project/project-search.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/project/project-search.service.js +30 -53
- package/dist/backend/backend/src/services/project/project-search.service.js.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/project-ticket-workflow.service.d.ts +381 -0
- package/dist/backend/backend/src/services/project-tickets/project-ticket-workflow.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/project-tickets/project-ticket-workflow.service.js +839 -0
- package/dist/backend/backend/src/services/project-tickets/project-ticket-workflow.service.js.map +1 -0
- package/dist/backend/backend/src/services/project-tickets/project-ticket.service.d.ts +214 -0
- package/dist/backend/backend/src/services/project-tickets/project-ticket.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/project-tickets/project-ticket.service.js +466 -0
- package/dist/backend/backend/src/services/project-tickets/project-ticket.service.js.map +1 -0
- package/dist/backend/backend/src/services/project-tickets/ticket-file.d.ts +121 -0
- package/dist/backend/backend/src/services/project-tickets/ticket-file.d.ts.map +1 -0
- package/dist/backend/backend/src/services/project-tickets/ticket-file.js +468 -0
- package/dist/backend/backend/src/services/project-tickets/ticket-file.js.map +1 -0
- package/dist/backend/backend/src/services/project-tickets/ticket-folder-lock.d.ts +69 -0
- package/dist/backend/backend/src/services/project-tickets/ticket-folder-lock.d.ts.map +1 -0
- package/dist/backend/backend/src/services/project-tickets/ticket-folder-lock.js +194 -0
- package/dist/backend/backend/src/services/project-tickets/ticket-folder-lock.js.map +1 -0
- package/dist/backend/backend/src/services/project-tickets/ticket-tracking.d.ts +47 -0
- package/dist/backend/backend/src/services/project-tickets/ticket-tracking.d.ts.map +1 -0
- package/dist/backend/backend/src/services/project-tickets/ticket-tracking.js +83 -0
- package/dist/backend/backend/src/services/project-tickets/ticket-tracking.js.map +1 -0
- package/dist/backend/backend/src/services/project-tickets/v1-task-migration.d.ts +97 -0
- package/dist/backend/backend/src/services/project-tickets/v1-task-migration.d.ts.map +1 -0
- package/dist/backend/backend/src/services/project-tickets/v1-task-migration.js +201 -0
- package/dist/backend/backend/src/services/project-tickets/v1-task-migration.js.map +1 -0
- package/dist/backend/backend/src/services/reconciler/reconcile-rules.d.ts +86 -22
- package/dist/backend/backend/src/services/reconciler/reconcile-rules.d.ts.map +1 -1
- package/dist/backend/backend/src/services/reconciler/reconcile-rules.js +173 -28
- 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 +19 -1
- 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 +33 -4
- package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.js.map +1 -1
- package/dist/backend/backend/src/services/reconciler/reconciler.service.d.ts +24 -12
- package/dist/backend/backend/src/services/reconciler/reconciler.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/reconciler/reconciler.service.js +87 -19
- package/dist/backend/backend/src/services/reconciler/reconciler.service.js.map +1 -1
- package/dist/backend/backend/src/services/runtime-adapter.d.ts +1 -1
- package/dist/backend/backend/src/services/runtime-adapter.d.ts.map +1 -1
- package/dist/backend/backend/src/services/runtime-adapter.js +5 -9
- package/dist/backend/backend/src/services/runtime-adapter.js.map +1 -1
- package/dist/backend/backend/src/services/session/pty/pty-session-backend.d.ts +26 -1
- package/dist/backend/backend/src/services/session/pty/pty-session-backend.d.ts.map +1 -1
- package/dist/backend/backend/src/services/session/pty/pty-session-backend.js +33 -2
- package/dist/backend/backend/src/services/session/pty/pty-session-backend.js.map +1 -1
- package/dist/backend/backend/src/services/session/pty/pty-session.d.ts +5 -0
- package/dist/backend/backend/src/services/session/pty/pty-session.d.ts.map +1 -1
- package/dist/backend/backend/src/services/session/pty/pty-session.js +8 -1
- package/dist/backend/backend/src/services/session/pty/pty-session.js.map +1 -1
- package/dist/backend/backend/src/services/session/pty/pty-terminal-buffer.d.ts +18 -0
- package/dist/backend/backend/src/services/session/pty/pty-terminal-buffer.d.ts.map +1 -1
- package/dist/backend/backend/src/services/session/pty/pty-terminal-buffer.js +23 -0
- package/dist/backend/backend/src/services/session/pty/pty-terminal-buffer.js.map +1 -1
- package/dist/backend/backend/src/services/session/session-backend.interface.d.ts +8 -0
- package/dist/backend/backend/src/services/session/session-backend.interface.d.ts.map +1 -1
- package/dist/backend/backend/src/services/session/session-backend.interface.js.map +1 -1
- package/dist/backend/backend/src/services/session/session-command-helper.d.ts +12 -2
- package/dist/backend/backend/src/services/session/session-command-helper.d.ts.map +1 -1
- package/dist/backend/backend/src/services/session/session-command-helper.js +14 -2
- package/dist/backend/backend/src/services/session/session-command-helper.js.map +1 -1
- package/dist/backend/backend/src/services/task-pool/give-up/give-up-recovery.service.d.ts +239 -0
- package/dist/backend/backend/src/services/task-pool/give-up/give-up-recovery.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/task-pool/give-up/give-up-recovery.service.js +395 -0
- package/dist/backend/backend/src/services/task-pool/give-up/give-up-recovery.service.js.map +1 -0
- package/dist/backend/backend/src/services/task-pool/give-up/give-up-stats.d.ts +53 -0
- package/dist/backend/backend/src/services/task-pool/give-up/give-up-stats.d.ts.map +1 -0
- package/dist/backend/backend/src/services/task-pool/give-up/give-up-stats.js +83 -0
- package/dist/backend/backend/src/services/task-pool/give-up/give-up-stats.js.map +1 -0
- package/dist/backend/backend/src/services/task-pool/give-up/stop-classifier.d.ts +93 -0
- package/dist/backend/backend/src/services/task-pool/give-up/stop-classifier.d.ts.map +1 -0
- package/dist/backend/backend/src/services/task-pool/give-up/stop-classifier.js +244 -0
- package/dist/backend/backend/src/services/task-pool/give-up/stop-classifier.js.map +1 -0
- package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts +145 -19
- 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 +323 -53
- package/dist/backend/backend/src/services/task-pool/task-pool.service.js.map +1 -1
- package/dist/backend/backend/src/services/template/template.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/template/template.service.js +11 -6
- package/dist/backend/backend/src/services/template/template.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/agent-auto-claim.service.d.ts +21 -4
- 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 +53 -3
- package/dist/backend/backend/src/services/v3/agent-auto-claim.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/escalation-router.service.d.ts +85 -6
- 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 +188 -9
- package/dist/backend/backend/src/services/v3/escalation-router.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/escalation.service.js +1 -1
- package/dist/backend/backend/src/services/v3/escalation.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/mission-executor.service.js +2 -2
- package/dist/backend/backend/src/services/v3/mission-executor.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/owner-receipt/owner-receipt-data.d.ts +184 -0
- package/dist/backend/backend/src/services/v3/owner-receipt/owner-receipt-data.d.ts.map +1 -0
- package/dist/backend/backend/src/services/v3/owner-receipt/owner-receipt-data.js +420 -0
- package/dist/backend/backend/src/services/v3/owner-receipt/owner-receipt-data.js.map +1 -0
- package/dist/backend/backend/src/services/v3/owner-receipt/owner-receipt.boot.d.ts +61 -0
- package/dist/backend/backend/src/services/v3/owner-receipt/owner-receipt.boot.d.ts.map +1 -0
- package/dist/backend/backend/src/services/v3/owner-receipt/owner-receipt.boot.js +100 -0
- package/dist/backend/backend/src/services/v3/owner-receipt/owner-receipt.boot.js.map +1 -0
- package/dist/backend/backend/src/services/v3/owner-receipt/owner-receipt.renderer.d.ts +36 -0
- package/dist/backend/backend/src/services/v3/owner-receipt/owner-receipt.renderer.d.ts.map +1 -0
- package/dist/backend/backend/src/services/v3/owner-receipt/owner-receipt.renderer.js +239 -0
- package/dist/backend/backend/src/services/v3/owner-receipt/owner-receipt.renderer.js.map +1 -0
- package/dist/backend/backend/src/services/v3/owner-receipt/owner-receipt.service.d.ts +152 -0
- package/dist/backend/backend/src/services/v3/owner-receipt/owner-receipt.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/v3/owner-receipt/owner-receipt.service.js +209 -0
- package/dist/backend/backend/src/services/v3/owner-receipt/owner-receipt.service.js.map +1 -0
- package/dist/backend/backend/src/services/v3/owner-receipt/owner-receipt.types.d.ts +194 -0
- package/dist/backend/backend/src/services/v3/owner-receipt/owner-receipt.types.d.ts.map +1 -0
- package/dist/backend/backend/src/services/v3/owner-receipt/owner-receipt.types.js +85 -0
- package/dist/backend/backend/src/services/v3/owner-receipt/owner-receipt.types.js.map +1 -0
- package/dist/backend/backend/src/services/v3/request-sla.subscriber.d.ts +6 -4
- 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 +15 -6
- 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.map +1 -1
- package/dist/backend/backend/src/services/v3/request-status-update.subscriber.js +14 -5
- package/dist/backend/backend/src/services/v3/request-status-update.subscriber.js.map +1 -1
- package/dist/backend/backend/src/services/v3/request.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/request.service.js +2 -0
- package/dist/backend/backend/src/services/v3/request.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/ticket-ask-classifier.d.ts +82 -0
- package/dist/backend/backend/src/services/v3/ticket-ask-classifier.d.ts.map +1 -0
- package/dist/backend/backend/src/services/v3/ticket-ask-classifier.js +172 -0
- package/dist/backend/backend/src/services/v3/ticket-ask-classifier.js.map +1 -0
- package/dist/backend/backend/src/services/v3/ticket-channel-hooks.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/ticket-channel-hooks.js +2 -0
- package/dist/backend/backend/src/services/v3/ticket-channel-hooks.js.map +1 -1
- package/dist/backend/backend/src/services/v3/ticket-intake-log.d.ts +87 -0
- package/dist/backend/backend/src/services/v3/ticket-intake-log.d.ts.map +1 -0
- package/dist/backend/backend/src/services/v3/ticket-intake-log.js +116 -0
- package/dist/backend/backend/src/services/v3/ticket-intake-log.js.map +1 -0
- package/dist/backend/backend/src/services/v3/ticket-intake.service.d.ts +133 -15
- package/dist/backend/backend/src/services/v3/ticket-intake.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/ticket-intake.service.js +263 -45
- package/dist/backend/backend/src/services/v3/ticket-intake.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/ticket-review.service.d.ts +3 -1
- package/dist/backend/backend/src/services/v3/ticket-review.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/ticket-review.service.js +6 -2
- package/dist/backend/backend/src/services/v3/ticket-review.service.js.map +1 -1
- 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 +9 -3
- package/dist/backend/backend/src/services/v3/v3-data.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/workitem-dispatch.subscriber.d.ts +88 -1
- package/dist/backend/backend/src/services/v3/workitem-dispatch.subscriber.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/workitem-dispatch.subscriber.js +169 -5
- package/dist/backend/backend/src/services/v3/workitem-dispatch.subscriber.js.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-migrate.service.d.ts +13 -5
- package/dist/backend/backend/src/services/wiki/wiki-migrate.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-migrate.service.js +10 -9
- package/dist/backend/backend/src/services/wiki/wiki-migrate.service.js.map +1 -1
- package/dist/backend/backend/src/services/worktree/workitem-worktree.service.d.ts +241 -0
- package/dist/backend/backend/src/services/worktree/workitem-worktree.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/worktree/workitem-worktree.service.js +511 -0
- package/dist/backend/backend/src/services/worktree/workitem-worktree.service.js.map +1 -0
- package/dist/backend/backend/src/services/worktree/workitem-worktree.subscriber.d.ts +70 -0
- package/dist/backend/backend/src/services/worktree/workitem-worktree.subscriber.d.ts.map +1 -0
- package/dist/backend/backend/src/services/worktree/workitem-worktree.subscriber.js +121 -0
- package/dist/backend/backend/src/services/worktree/workitem-worktree.subscriber.js.map +1 -0
- package/dist/backend/backend/src/services/worktree/worktree-git.d.ts +260 -0
- package/dist/backend/backend/src/services/worktree/worktree-git.d.ts.map +1 -0
- package/dist/backend/backend/src/services/worktree/worktree-git.js +569 -0
- package/dist/backend/backend/src/services/worktree/worktree-git.js.map +1 -0
- package/dist/backend/backend/src/types/event-bus.types.d.ts +6 -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 +8 -0
- package/dist/backend/backend/src/types/event-bus.types.js.map +1 -1
- package/dist/backend/backend/src/types/index.d.ts +23 -18
- package/dist/backend/backend/src/types/index.d.ts.map +1 -1
- package/dist/backend/backend/src/types/index.js.map +1 -1
- package/dist/backend/backend/src/types/intent-task.types.d.ts +1 -1
- package/dist/backend/backend/src/types/intent-task.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/project-ticket.types.d.ts +132 -0
- package/dist/backend/backend/src/types/project-ticket.types.d.ts.map +1 -0
- package/dist/backend/backend/src/types/project-ticket.types.js +120 -0
- package/dist/backend/backend/src/types/project-ticket.types.js.map +1 -0
- package/dist/backend/backend/src/types/review-reason.types.d.ts +3 -1
- package/dist/backend/backend/src/types/review-reason.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/review-reason.types.js +1 -0
- package/dist/backend/backend/src/types/review-reason.types.js.map +1 -1
- package/dist/backend/backend/src/types/v2/index.d.ts +2 -2
- package/dist/backend/backend/src/types/v2/index.d.ts.map +1 -1
- package/dist/backend/backend/src/types/v2/index.js +1 -1
- package/dist/backend/backend/src/types/v2/index.js.map +1 -1
- package/dist/backend/backend/src/types/v2/reconcile.types.d.ts +7 -0
- package/dist/backend/backend/src/types/v2/reconcile.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/v2/reconcile.types.js.map +1 -1
- package/dist/backend/backend/src/types/v2/request.types.d.ts +18 -0
- package/dist/backend/backend/src/types/v2/request.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/v2/request.types.js +1 -0
- package/dist/backend/backend/src/types/v2/request.types.js.map +1 -1
- package/dist/backend/backend/src/types/v2/ticket.types.d.ts +6 -2
- package/dist/backend/backend/src/types/v2/ticket.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/v2/ticket.types.js +1 -1
- package/dist/backend/backend/src/types/v2/ticket.types.js.map +1 -1
- package/dist/backend/backend/src/types/v2/work-item.types.d.ts +169 -14
- 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 +263 -44
- package/dist/backend/backend/src/types/v2/work-item.types.js.map +1 -1
- package/dist/backend/backend/src/utils/agent-caller.utils.d.ts +33 -0
- package/dist/backend/backend/src/utils/agent-caller.utils.d.ts.map +1 -1
- package/dist/backend/backend/src/utils/agent-caller.utils.js +37 -0
- package/dist/backend/backend/src/utils/agent-caller.utils.js.map +1 -1
- package/dist/backend/backend/src/utils/secret-env.d.ts +61 -0
- package/dist/backend/backend/src/utils/secret-env.d.ts.map +1 -0
- package/dist/backend/backend/src/utils/secret-env.js +89 -0
- package/dist/backend/backend/src/utils/secret-env.js.map +1 -0
- package/dist/backend/build-info.json +2 -2
- package/dist/backend/config/constants.d.ts +71 -0
- package/dist/backend/config/constants.d.ts.map +1 -1
- package/dist/backend/config/constants.js +77 -0
- package/dist/backend/config/constants.js.map +1 -1
- package/dist/cli/backend/src/constants.d.ts +397 -1
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +388 -2
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/models/index.d.ts +0 -1
- package/dist/cli/backend/src/models/index.d.ts.map +1 -1
- package/dist/cli/backend/src/models/index.js +0 -1
- package/dist/cli/backend/src/models/index.js.map +1 -1
- package/dist/cli/backend/src/services/agent/agent-registration.service.d.ts +43 -1
- package/dist/cli/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/agent/agent-registration.service.js +129 -34
- package/dist/cli/backend/src/services/agent/agent-registration.service.js.map +1 -1
- package/dist/cli/backend/src/services/agent/control-plane-guard.service.d.ts +169 -0
- package/dist/cli/backend/src/services/agent/control-plane-guard.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/agent/control-plane-guard.service.js +231 -0
- package/dist/cli/backend/src/services/agent/control-plane-guard.service.js.map +1 -0
- package/dist/cli/backend/src/services/agent/fresh-task-conversation.service.d.ts +409 -0
- package/dist/cli/backend/src/services/agent/fresh-task-conversation.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/agent/fresh-task-conversation.service.js +961 -0
- package/dist/cli/backend/src/services/agent/fresh-task-conversation.service.js.map +1 -0
- package/dist/cli/backend/src/services/agent/runtime-agent.service.abstract.d.ts +16 -0
- package/dist/cli/backend/src/services/agent/runtime-agent.service.abstract.d.ts.map +1 -1
- package/dist/cli/backend/src/services/agent/runtime-agent.service.abstract.js +50 -0
- package/dist/cli/backend/src/services/agent/runtime-agent.service.abstract.js.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-builder.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-builder.service.js +9 -8
- package/dist/cli/backend/src/services/ai/prompt-builder.service.js.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/active-work.module.d.ts +75 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/active-work.module.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/active-work.module.js +89 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/active-work.module.js.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/project-reference.module.js +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/project-reference.module.js.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/prompt-assembly.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/prompt-assembly.service.js +12 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/prompt-assembly.service.js.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/prompt-module.interface.d.ts +14 -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/ai/prompt-modules/recovery.module.d.ts.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/recovery.module.js +11 -7
- package/dist/cli/backend/src/services/ai/prompt-modules/recovery.module.js.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/session-briefing.module.d.ts +41 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/session-briefing.module.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/session-briefing.module.js +44 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/session-briefing.module.js.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/standing-answers.module.d.ts +67 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/standing-answers.module.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/standing-answers.module.js +146 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/standing-answers.module.js.map +1 -0
- package/dist/cli/backend/src/services/continuation/patterns/waiting-patterns.d.ts +7 -0
- package/dist/cli/backend/src/services/continuation/patterns/waiting-patterns.d.ts.map +1 -1
- package/dist/cli/backend/src/services/continuation/patterns/waiting-patterns.js +9 -1
- package/dist/cli/backend/src/services/continuation/patterns/waiting-patterns.js.map +1 -1
- package/dist/cli/backend/src/services/core/logger.service.d.ts +21 -0
- package/dist/cli/backend/src/services/core/logger.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/core/logger.service.js +42 -4
- package/dist/cli/backend/src/services/core/logger.service.js.map +1 -1
- package/dist/cli/backend/src/services/core/storage.service.d.ts +1 -5
- package/dist/cli/backend/src/services/core/storage.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/core/storage.service.js +5 -162
- package/dist/cli/backend/src/services/core/storage.service.js.map +1 -1
- package/dist/cli/backend/src/services/event-bus/event-bus.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/event-bus/event-bus.service.js +6 -0
- package/dist/cli/backend/src/services/event-bus/event-bus.service.js.map +1 -1
- package/dist/cli/backend/src/services/mcp-server.d.ts +19 -6
- package/dist/cli/backend/src/services/mcp-server.d.ts.map +1 -1
- package/dist/cli/backend/src/services/mcp-server.js +46 -16
- package/dist/cli/backend/src/services/mcp-server.js.map +1 -1
- package/dist/cli/backend/src/services/mcp-tool-definitions.d.ts.map +1 -1
- package/dist/cli/backend/src/services/mcp-tool-definitions.js +3 -2
- package/dist/cli/backend/src/services/mcp-tool-definitions.js.map +1 -1
- package/dist/cli/backend/src/services/memory/standing-answers.service.d.ts +247 -0
- package/dist/cli/backend/src/services/memory/standing-answers.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/memory/standing-answers.service.js +534 -0
- package/dist/cli/backend/src/services/memory/standing-answers.service.js.map +1 -0
- package/dist/cli/backend/src/services/monitoring/activity-monitor.service.d.ts +35 -0
- package/dist/cli/backend/src/services/monitoring/activity-monitor.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/monitoring/activity-monitor.service.js +99 -1
- package/dist/cli/backend/src/services/monitoring/activity-monitor.service.js.map +1 -1
- package/dist/cli/backend/src/services/monitoring/agent-attention-registry.d.ts +75 -0
- package/dist/cli/backend/src/services/monitoring/agent-attention-registry.d.ts.map +1 -0
- package/dist/cli/backend/src/services/monitoring/agent-attention-registry.js +80 -0
- package/dist/cli/backend/src/services/monitoring/agent-attention-registry.js.map +1 -0
- package/dist/cli/backend/src/services/monitoring/agent-attention.d.ts +114 -0
- package/dist/cli/backend/src/services/monitoring/agent-attention.d.ts.map +1 -0
- package/dist/cli/backend/src/services/monitoring/agent-attention.js +165 -0
- package/dist/cli/backend/src/services/monitoring/agent-attention.js.map +1 -0
- package/dist/cli/backend/src/services/project-tickets/project-ticket.service.d.ts +214 -0
- package/dist/cli/backend/src/services/project-tickets/project-ticket.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/project-tickets/project-ticket.service.js +466 -0
- package/dist/cli/backend/src/services/project-tickets/project-ticket.service.js.map +1 -0
- package/dist/cli/backend/src/services/project-tickets/ticket-file.d.ts +121 -0
- package/dist/cli/backend/src/services/project-tickets/ticket-file.d.ts.map +1 -0
- package/dist/cli/backend/src/services/project-tickets/ticket-file.js +468 -0
- package/dist/cli/backend/src/services/project-tickets/ticket-file.js.map +1 -0
- package/dist/cli/backend/src/services/project-tickets/ticket-folder-lock.d.ts +69 -0
- package/dist/cli/backend/src/services/project-tickets/ticket-folder-lock.d.ts.map +1 -0
- package/dist/cli/backend/src/services/project-tickets/ticket-folder-lock.js +194 -0
- package/dist/cli/backend/src/services/project-tickets/ticket-folder-lock.js.map +1 -0
- package/dist/cli/backend/src/services/project-tickets/ticket-tracking.d.ts +47 -0
- package/dist/cli/backend/src/services/project-tickets/ticket-tracking.d.ts.map +1 -0
- package/dist/cli/backend/src/services/project-tickets/ticket-tracking.js +83 -0
- package/dist/cli/backend/src/services/project-tickets/ticket-tracking.js.map +1 -0
- package/dist/cli/backend/src/services/project-tickets/v1-task-migration.d.ts +97 -0
- package/dist/cli/backend/src/services/project-tickets/v1-task-migration.d.ts.map +1 -0
- package/dist/cli/backend/src/services/project-tickets/v1-task-migration.js +201 -0
- package/dist/cli/backend/src/services/project-tickets/v1-task-migration.js.map +1 -0
- package/dist/cli/backend/src/services/session/pty/pty-session-backend.d.ts +26 -1
- package/dist/cli/backend/src/services/session/pty/pty-session-backend.d.ts.map +1 -1
- package/dist/cli/backend/src/services/session/pty/pty-session-backend.js +33 -2
- package/dist/cli/backend/src/services/session/pty/pty-session-backend.js.map +1 -1
- package/dist/cli/backend/src/services/session/pty/pty-session.d.ts +5 -0
- package/dist/cli/backend/src/services/session/pty/pty-session.d.ts.map +1 -1
- package/dist/cli/backend/src/services/session/pty/pty-session.js +8 -1
- package/dist/cli/backend/src/services/session/pty/pty-session.js.map +1 -1
- package/dist/cli/backend/src/services/session/pty/pty-terminal-buffer.d.ts +18 -0
- package/dist/cli/backend/src/services/session/pty/pty-terminal-buffer.d.ts.map +1 -1
- package/dist/cli/backend/src/services/session/pty/pty-terminal-buffer.js +23 -0
- package/dist/cli/backend/src/services/session/pty/pty-terminal-buffer.js.map +1 -1
- package/dist/cli/backend/src/services/session/session-backend.interface.d.ts +8 -0
- package/dist/cli/backend/src/services/session/session-backend.interface.d.ts.map +1 -1
- package/dist/cli/backend/src/services/session/session-backend.interface.js.map +1 -1
- package/dist/cli/backend/src/services/session/session-command-helper.d.ts +12 -2
- package/dist/cli/backend/src/services/session/session-command-helper.d.ts.map +1 -1
- package/dist/cli/backend/src/services/session/session-command-helper.js +14 -2
- package/dist/cli/backend/src/services/session/session-command-helper.js.map +1 -1
- package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts +145 -19
- 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 +323 -53
- package/dist/cli/backend/src/services/task-pool/task-pool.service.js.map +1 -1
- package/dist/cli/backend/src/services/template/template.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/template/template.service.js +11 -6
- package/dist/cli/backend/src/services/template/template.service.js.map +1 -1
- package/dist/cli/backend/src/services/v3/escalation-router.service.d.ts +85 -6
- package/dist/cli/backend/src/services/v3/escalation-router.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/v3/escalation-router.service.js +188 -9
- package/dist/cli/backend/src/services/v3/escalation-router.service.js.map +1 -1
- package/dist/cli/backend/src/services/v3/mission-executor.service.js +2 -2
- package/dist/cli/backend/src/services/v3/mission-executor.service.js.map +1 -1
- package/dist/cli/backend/src/services/v3/request-sla.subscriber.d.ts +6 -4
- package/dist/cli/backend/src/services/v3/request-sla.subscriber.d.ts.map +1 -1
- package/dist/cli/backend/src/services/v3/request-sla.subscriber.js +15 -6
- package/dist/cli/backend/src/services/v3/request-sla.subscriber.js.map +1 -1
- package/dist/cli/backend/src/services/v3/request.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/v3/request.service.js +2 -0
- package/dist/cli/backend/src/services/v3/request.service.js.map +1 -1
- package/dist/cli/backend/src/services/v3/ticket-ask-classifier.d.ts +82 -0
- package/dist/cli/backend/src/services/v3/ticket-ask-classifier.d.ts.map +1 -0
- package/dist/cli/backend/src/services/v3/ticket-ask-classifier.js +172 -0
- package/dist/cli/backend/src/services/v3/ticket-ask-classifier.js.map +1 -0
- package/dist/cli/backend/src/services/v3/ticket-channel-hooks.d.ts.map +1 -1
- package/dist/cli/backend/src/services/v3/ticket-channel-hooks.js +2 -0
- package/dist/cli/backend/src/services/v3/ticket-channel-hooks.js.map +1 -1
- package/dist/cli/backend/src/services/v3/ticket-intake-log.d.ts +87 -0
- package/dist/cli/backend/src/services/v3/ticket-intake-log.d.ts.map +1 -0
- package/dist/cli/backend/src/services/v3/ticket-intake-log.js +116 -0
- package/dist/cli/backend/src/services/v3/ticket-intake-log.js.map +1 -0
- package/dist/cli/backend/src/services/v3/ticket-intake.service.d.ts +133 -15
- package/dist/cli/backend/src/services/v3/ticket-intake.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/v3/ticket-intake.service.js +263 -45
- package/dist/cli/backend/src/services/v3/ticket-intake.service.js.map +1 -1
- package/dist/cli/backend/src/services/v3/ticket-review.service.d.ts +3 -1
- package/dist/cli/backend/src/services/v3/ticket-review.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/v3/ticket-review.service.js +6 -2
- package/dist/cli/backend/src/services/v3/ticket-review.service.js.map +1 -1
- package/dist/cli/backend/src/services/v3/v3-data.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/v3/v3-data.service.js +9 -3
- package/dist/cli/backend/src/services/v3/v3-data.service.js.map +1 -1
- package/dist/cli/backend/src/services/worktree/worktree-git.d.ts +260 -0
- package/dist/cli/backend/src/services/worktree/worktree-git.d.ts.map +1 -0
- package/dist/cli/backend/src/services/worktree/worktree-git.js +569 -0
- package/dist/cli/backend/src/services/worktree/worktree-git.js.map +1 -0
- package/dist/cli/backend/src/types/event-bus.types.d.ts +6 -1
- package/dist/cli/backend/src/types/event-bus.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/event-bus.types.js +8 -0
- package/dist/cli/backend/src/types/event-bus.types.js.map +1 -1
- package/dist/cli/backend/src/types/index.d.ts +23 -18
- package/dist/cli/backend/src/types/index.d.ts.map +1 -1
- package/dist/cli/backend/src/types/index.js.map +1 -1
- package/dist/cli/backend/src/types/intent-task.types.d.ts +1 -1
- package/dist/cli/backend/src/types/intent-task.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/project-ticket.types.d.ts +132 -0
- package/dist/cli/backend/src/types/project-ticket.types.d.ts.map +1 -0
- package/dist/cli/backend/src/types/project-ticket.types.js +120 -0
- package/dist/cli/backend/src/types/project-ticket.types.js.map +1 -0
- package/dist/cli/backend/src/types/v2/index.d.ts +2 -2
- package/dist/cli/backend/src/types/v2/index.d.ts.map +1 -1
- package/dist/cli/backend/src/types/v2/index.js +1 -1
- package/dist/cli/backend/src/types/v2/index.js.map +1 -1
- package/dist/cli/backend/src/types/v2/reconcile.types.d.ts +7 -0
- package/dist/cli/backend/src/types/v2/reconcile.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/v2/reconcile.types.js.map +1 -1
- package/dist/cli/backend/src/types/v2/request.types.d.ts +18 -0
- package/dist/cli/backend/src/types/v2/request.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/v2/request.types.js +1 -0
- package/dist/cli/backend/src/types/v2/request.types.js.map +1 -1
- package/dist/cli/backend/src/types/v2/ticket.types.d.ts +6 -2
- package/dist/cli/backend/src/types/v2/ticket.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/v2/ticket.types.js +1 -1
- package/dist/cli/backend/src/types/v2/ticket.types.js.map +1 -1
- package/dist/cli/backend/src/types/v2/work-item.types.d.ts +169 -14
- 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 +263 -44
- package/dist/cli/backend/src/types/v2/work-item.types.js.map +1 -1
- package/dist/cli/backend/src/utils/secret-env.d.ts +61 -0
- package/dist/cli/backend/src/utils/secret-env.d.ts.map +1 -0
- package/dist/cli/backend/src/utils/secret-env.js +89 -0
- package/dist/cli/backend/src/utils/secret-env.js.map +1 -0
- package/dist/cli/cli/src/commands/onboard.d.ts +1 -1
- package/dist/cli/cli/src/commands/onboard.js +3 -3
- package/dist/cli/cli/src/commands/onboard.js.map +1 -1
- package/dist/cli/cli/src/commands/publish.d.ts.map +1 -1
- package/dist/cli/cli/src/commands/publish.js +4 -5
- package/dist/cli/cli/src/commands/publish.js.map +1 -1
- package/dist/cli/cli/src/commands/service.d.ts.map +1 -1
- package/dist/cli/cli/src/commands/service.js +5 -2
- package/dist/cli/cli/src/commands/service.js.map +1 -1
- package/dist/cli/cli/src/commands/tickets.d.ts +60 -0
- package/dist/cli/cli/src/commands/tickets.d.ts.map +1 -0
- package/dist/cli/cli/src/commands/tickets.js +111 -0
- package/dist/cli/cli/src/commands/tickets.js.map +1 -0
- package/dist/cli/cli/src/index.js +12 -0
- package/dist/cli/cli/src/index.js.map +1 -1
- package/dist/cli/cli/src/utils/archive-creator.d.ts +7 -3
- package/dist/cli/cli/src/utils/archive-creator.d.ts.map +1 -1
- package/dist/cli/cli/src/utils/archive-creator.js +17 -5
- package/dist/cli/cli/src/utils/archive-creator.js.map +1 -1
- package/dist/cli/cli/src/utils/cloud-submit.d.ts +1 -1
- package/dist/cli/cli/src/utils/cloud-submit.js +1 -1
- package/dist/cli/cli/src/utils/gh-submit.d.ts +10 -1
- package/dist/cli/cli/src/utils/gh-submit.d.ts.map +1 -1
- package/dist/cli/cli/src/utils/gh-submit.js +20 -4
- package/dist/cli/cli/src/utils/gh-submit.js.map +1 -1
- package/dist/cli/cli/src/utils/package-validator.d.ts +29 -6
- package/dist/cli/cli/src/utils/package-validator.d.ts.map +1 -1
- package/dist/cli/cli/src/utils/package-validator.js +88 -36
- package/dist/cli/cli/src/utils/package-validator.js.map +1 -1
- package/dist/cli/config/constants.d.ts +71 -0
- package/dist/cli/config/constants.d.ts.map +1 -1
- package/dist/cli/config/constants.js +77 -0
- package/dist/cli/config/constants.js.map +1 -1
- package/dist/cli/config/skills/marketplace-registry.d.ts +143 -0
- package/dist/cli/config/skills/marketplace-registry.d.ts.map +1 -0
- package/dist/cli/config/skills/marketplace-registry.js +192 -0
- package/dist/cli/config/skills/marketplace-registry.js.map +1 -0
- package/frontend/dist/assets/index-8d4b3ad2.js +4951 -0
- package/frontend/dist/assets/index-b6aded4c.css +42 -0
- package/frontend/dist/index.html +2 -2
- package/package.json +1 -1
- package/config/task_starters/build_e2e_test_plan_prompt.json +0 -51
- package/config/task_starters/build_tasks_prompt.json +0 -55
- package/config/task_starters/prompts/build_tasks_step1_milestone_structure.md +0 -274
- package/config/task_starters/prompts/e2e_test_plan_step1_build_tests.md +0 -391
- package/config/task_starters/prompts/e2e_test_plan_step2_run_tests.md +0 -240
- package/config/templates/customer-loyalty-team.json +0 -44
- package/config/templates/dtc-viral-content-team.json +0 -58
- package/config/templates/expert-innovation-team.json +0 -60
- package/config/templates/pragmatic-mvp-dev-team.json +0 -58
- package/config/templates/pro-sops/norms/content-production-pipeline.md +0 -39
- package/config/templates/pro-sops/norms/customer-onboarding-sop.md +0 -40
- package/dist/backend/backend/src/controllers/task-management/tickets.controller.d.ts +0 -13
- package/dist/backend/backend/src/controllers/task-management/tickets.controller.d.ts.map +0 -1
- package/dist/backend/backend/src/controllers/task-management/tickets.controller.js +0 -214
- package/dist/backend/backend/src/controllers/task-management/tickets.controller.js.map +0 -1
- package/dist/backend/backend/src/models/Ticket.d.ts +0 -24
- package/dist/backend/backend/src/models/Ticket.d.ts.map +0 -1
- package/dist/backend/backend/src/models/Ticket.js +0 -102
- package/dist/backend/backend/src/models/Ticket.js.map +0 -1
- package/dist/backend/backend/src/services/agent/task-planning.service.d.ts +0 -134
- package/dist/backend/backend/src/services/agent/task-planning.service.d.ts.map +0 -1
- package/dist/backend/backend/src/services/agent/task-planning.service.js +0 -291
- package/dist/backend/backend/src/services/agent/task-planning.service.js.map +0 -1
- package/dist/backend/backend/src/services/monitoring/task-assignment-monitor.service.d.ts +0 -71
- package/dist/backend/backend/src/services/monitoring/task-assignment-monitor.service.d.ts.map +0 -1
- package/dist/backend/backend/src/services/monitoring/task-assignment-monitor.service.js +0 -304
- package/dist/backend/backend/src/services/monitoring/task-assignment-monitor.service.js.map +0 -1
- package/dist/backend/backend/src/services/project/task-folder.service.d.ts +0 -48
- package/dist/backend/backend/src/services/project/task-folder.service.d.ts.map +0 -1
- package/dist/backend/backend/src/services/project/task-folder.service.js +0 -193
- package/dist/backend/backend/src/services/project/task-folder.service.js.map +0 -1
- package/dist/backend/backend/src/services/project/task.service.d.ts +0 -47
- package/dist/backend/backend/src/services/project/task.service.d.ts.map +0 -1
- package/dist/backend/backend/src/services/project/task.service.js +0 -253
- package/dist/backend/backend/src/services/project/task.service.js.map +0 -1
- package/dist/backend/backend/src/services/project/ticket-editor.service.d.ts +0 -130
- package/dist/backend/backend/src/services/project/ticket-editor.service.d.ts.map +0 -1
- package/dist/backend/backend/src/services/project/ticket-editor.service.js +0 -406
- package/dist/backend/backend/src/services/project/ticket-editor.service.js.map +0 -1
- package/dist/cli/backend/src/models/Ticket.d.ts +0 -24
- package/dist/cli/backend/src/models/Ticket.d.ts.map +0 -1
- package/dist/cli/backend/src/models/Ticket.js +0 -102
- package/dist/cli/backend/src/models/Ticket.js.map +0 -1
- package/frontend/dist/assets/index-2bdb57b9.css +0 -42
- package/frontend/dist/assets/index-54f1061c.js +0 -4963
|
@@ -0,0 +1,839 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project ticket workflow — who may do what, claiming / assigning a ticket
|
|
3
|
+
* through a linked WorkItem, and syncing the WorkItem's outcome back into the
|
|
4
|
+
* ticket (specs/2026-09-28-project-tickets.md §4–§5).
|
|
5
|
+
*
|
|
6
|
+
* Layering: {@link ProjectTicketService} owns the files; the task pool owns
|
|
7
|
+
* WorkItems; this service is the only place that connects the two. The link
|
|
8
|
+
* is one metadata key on the WorkItem (`metadata.projectTicket`) plus the
|
|
9
|
+
* ticket's `workItemId`. Invariant: one ticket = at most one live WorkItem,
|
|
10
|
+
* enforced under the ticket folder lock at claim time.
|
|
11
|
+
*
|
|
12
|
+
* @module services/project-tickets/project-ticket-workflow.service
|
|
13
|
+
*/
|
|
14
|
+
import * as path from 'path';
|
|
15
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
16
|
+
import { ORCHESTRATOR_SESSION_NAME, PROJECT_TICKET_CONSTANTS } from '../../constants.js';
|
|
17
|
+
import { LoggerService } from '../core/logger.service.js';
|
|
18
|
+
import { MAX_BRIEF_MARKDOWN_BYTES, getWorkItemDisposition, } from '../../types/v2/work-item.types.js';
|
|
19
|
+
import { projectTicketPriorityRank, readProjectTicketLink, } from '../../types/project-ticket.types.js';
|
|
20
|
+
import { ProjectTicketError, } from './project-ticket.service.js';
|
|
21
|
+
import { SUPERSEDED_BY_METADATA_KEY } from '../v3/request-completion.js';
|
|
22
|
+
/** WorkItem statuses that still carry the ticket's work. */
|
|
23
|
+
const LIVE_STATUSES = new Set([
|
|
24
|
+
'queued',
|
|
25
|
+
'scheduled',
|
|
26
|
+
'proposed',
|
|
27
|
+
'accepted',
|
|
28
|
+
'running',
|
|
29
|
+
'blocked',
|
|
30
|
+
'escalated',
|
|
31
|
+
'done_by_worker',
|
|
32
|
+
]);
|
|
33
|
+
/** Statuses of an agent's own WorkItems that keep it from picking up a ticket. */
|
|
34
|
+
const BUSY_STATUSES = new Set(['queued', 'proposed', 'accepted', 'running']);
|
|
35
|
+
/** Pool events that can change a linked ticket. */
|
|
36
|
+
export const PROJECT_TICKET_SYNC_EVENTS = ['task:verified', 'task:done', 'task:rejected', 'task:cancelled', 'task:failed'];
|
|
37
|
+
/** Max ticket claims tried per idle agent (another agent may win a race). */
|
|
38
|
+
const MAX_AUTO_CLAIM_ATTEMPTS = 3;
|
|
39
|
+
/** WorkItem description cap (callers cap `description` at 500 chars). */
|
|
40
|
+
const WORK_ITEM_DESCRIPTION_MAX = 500;
|
|
41
|
+
/**
|
|
42
|
+
* Whether a member leads a team.
|
|
43
|
+
*
|
|
44
|
+
* @param team - Team
|
|
45
|
+
* @param member - Member of that team
|
|
46
|
+
* @returns True for a team lead
|
|
47
|
+
*/
|
|
48
|
+
export function isTeamLead(team, member) {
|
|
49
|
+
return ((team.leaderIds ?? []).includes(member.id) ||
|
|
50
|
+
team.leaderId === member.id ||
|
|
51
|
+
member.canDelegate === true ||
|
|
52
|
+
member.role === 'team-leader');
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Whether a member runs as the given session.
|
|
56
|
+
*
|
|
57
|
+
* @param member - Team member
|
|
58
|
+
* @param session - Session name / agent id
|
|
59
|
+
* @returns True on a match
|
|
60
|
+
*/
|
|
61
|
+
function isSession(member, session) {
|
|
62
|
+
return member.sessionName === session || member.agentId === session;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Cut a string to a byte budget (UTF-8), keeping whole characters.
|
|
66
|
+
*
|
|
67
|
+
* @param text - Text
|
|
68
|
+
* @param maxBytes - Budget
|
|
69
|
+
* @returns Text within the budget
|
|
70
|
+
*/
|
|
71
|
+
function capBytes(text, maxBytes) {
|
|
72
|
+
if (Buffer.byteLength(text, 'utf8') <= maxBytes)
|
|
73
|
+
return text;
|
|
74
|
+
let out = text.slice(0, maxBytes);
|
|
75
|
+
while (Buffer.byteLength(out, 'utf8') > maxBytes - 32)
|
|
76
|
+
out = out.slice(0, -64);
|
|
77
|
+
return `${out}\n\n…(truncated — read the ticket file)`;
|
|
78
|
+
}
|
|
79
|
+
export class ProjectTicketWorkflowService {
|
|
80
|
+
static instance = null;
|
|
81
|
+
tickets;
|
|
82
|
+
pool;
|
|
83
|
+
directory;
|
|
84
|
+
logger;
|
|
85
|
+
now;
|
|
86
|
+
sweepTimer = null;
|
|
87
|
+
unsubscribe = null;
|
|
88
|
+
sweeping = false;
|
|
89
|
+
/**
|
|
90
|
+
* @param deps - Ticket store, task pool, team/project directory
|
|
91
|
+
*/
|
|
92
|
+
constructor(deps) {
|
|
93
|
+
this.tickets = deps.tickets;
|
|
94
|
+
this.pool = deps.pool;
|
|
95
|
+
this.directory = deps.directory;
|
|
96
|
+
this.logger = deps.logger ?? LoggerService.getInstance().createComponentLogger('ProjectTicketWorkflow');
|
|
97
|
+
this.now = deps.now ?? (() => new Date().toISOString());
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* The wired process-wide instance, or null before boot wired it.
|
|
101
|
+
*
|
|
102
|
+
* @returns Instance or null
|
|
103
|
+
*/
|
|
104
|
+
static getInstance() {
|
|
105
|
+
return ProjectTicketWorkflowService.instance;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Install the process-wide instance (boot path).
|
|
109
|
+
*
|
|
110
|
+
* @param service - Instance, or null to clear (tests)
|
|
111
|
+
*/
|
|
112
|
+
static setInstance(service) {
|
|
113
|
+
ProjectTicketWorkflowService.instance = service;
|
|
114
|
+
}
|
|
115
|
+
// ---------------------------------------------------------------------------
|
|
116
|
+
// Lifecycle
|
|
117
|
+
// ---------------------------------------------------------------------------
|
|
118
|
+
/**
|
|
119
|
+
* Subscribe to WorkItem lifecycle events and start the periodic sweep.
|
|
120
|
+
*
|
|
121
|
+
* @param events - Event bus with `onInProcess` (optional in tests)
|
|
122
|
+
* @param intervalMs - Sweep interval (0 disables the timer)
|
|
123
|
+
*/
|
|
124
|
+
start(events, intervalMs = PROJECT_TICKET_CONSTANTS.SYNC_SWEEP_INTERVAL_MS) {
|
|
125
|
+
if (events) {
|
|
126
|
+
this.unsubscribe = events.onInProcess([...PROJECT_TICKET_SYNC_EVENTS], async (event) => {
|
|
127
|
+
if (event?.workItemId)
|
|
128
|
+
await this.onWorkItemEvent(event.workItemId);
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
if (intervalMs > 0) {
|
|
132
|
+
this.sweepTimer = setInterval(() => {
|
|
133
|
+
void this.syncAll().catch((err) => this.logger.debug('Project ticket sweep failed (non-fatal)', { error: err instanceof Error ? err.message : String(err) }));
|
|
134
|
+
}, intervalMs);
|
|
135
|
+
this.sweepTimer.unref?.();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/** Stop the sweep and the event subscription. */
|
|
139
|
+
stop() {
|
|
140
|
+
if (this.sweepTimer)
|
|
141
|
+
clearInterval(this.sweepTimer);
|
|
142
|
+
this.sweepTimer = null;
|
|
143
|
+
this.unsubscribe?.();
|
|
144
|
+
this.unsubscribe = null;
|
|
145
|
+
}
|
|
146
|
+
// ---------------------------------------------------------------------------
|
|
147
|
+
// Directory helpers
|
|
148
|
+
// ---------------------------------------------------------------------------
|
|
149
|
+
/**
|
|
150
|
+
* Find a project by id, name (case-insensitive) or absolute path.
|
|
151
|
+
*
|
|
152
|
+
* @param ref - Project reference
|
|
153
|
+
* @returns The project
|
|
154
|
+
* @throws ProjectTicketError(404) when no project matches
|
|
155
|
+
*/
|
|
156
|
+
async resolveProject(ref) {
|
|
157
|
+
const projects = await this.directory.getProjects();
|
|
158
|
+
const wanted = String(ref ?? '').trim();
|
|
159
|
+
const asPath = wanted.startsWith('/') ? path.resolve(wanted) : null;
|
|
160
|
+
const hit = projects.find((p) => p.id === wanted) ??
|
|
161
|
+
(asPath ? projects.find((p) => path.resolve(p.path) === asPath) : undefined) ??
|
|
162
|
+
projects.find((p) => p.name.toLowerCase() === wanted.toLowerCase());
|
|
163
|
+
if (!hit)
|
|
164
|
+
throw new ProjectTicketError(404, `Project not found: ${ref}`);
|
|
165
|
+
return hit;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Teams working on a project (not archived).
|
|
169
|
+
*
|
|
170
|
+
* @param project - Project
|
|
171
|
+
* @param teams - All teams
|
|
172
|
+
* @returns Teams whose `projectIds` contain the project
|
|
173
|
+
*/
|
|
174
|
+
projectTeams(project, teams) {
|
|
175
|
+
return teams.filter((t) => !t.archived && (t.projectIds ?? []).includes(project.id));
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* The caller's standing on a project.
|
|
179
|
+
*
|
|
180
|
+
* @param caller - Caller
|
|
181
|
+
* @param project - Project
|
|
182
|
+
* @returns Access level and the caller's memberships in the project's teams
|
|
183
|
+
*/
|
|
184
|
+
async accessOf(caller, project) {
|
|
185
|
+
if (!caller.session)
|
|
186
|
+
return { access: 'owner', memberships: [] };
|
|
187
|
+
if (caller.session === ORCHESTRATOR_SESSION_NAME)
|
|
188
|
+
return { access: 'orchestrator', memberships: [] };
|
|
189
|
+
const teams = this.projectTeams(project, await this.directory.getTeams());
|
|
190
|
+
const memberships = [];
|
|
191
|
+
for (const team of teams) {
|
|
192
|
+
for (const member of team.members ?? []) {
|
|
193
|
+
if (isSession(member, caller.session))
|
|
194
|
+
memberships.push({ team, member });
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
if (memberships.length === 0)
|
|
198
|
+
return { access: 'outsider', memberships };
|
|
199
|
+
return { access: memberships.some((m) => isTeamLead(m.team, m.member)) ? 'lead' : 'member', memberships };
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Name recorded in Log lines for a caller.
|
|
203
|
+
*
|
|
204
|
+
* @param caller - Caller
|
|
205
|
+
* @returns `owner` or the session name
|
|
206
|
+
*/
|
|
207
|
+
actorName(caller) {
|
|
208
|
+
return caller.session ?? 'owner';
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Refuse unless the caller has one of the given access levels.
|
|
212
|
+
*
|
|
213
|
+
* @param access - Caller's access
|
|
214
|
+
* @param allowed - Allowed levels
|
|
215
|
+
* @param what - Action (for the message)
|
|
216
|
+
* @throws ProjectTicketError(403)
|
|
217
|
+
*/
|
|
218
|
+
requireAccess(access, allowed, what) {
|
|
219
|
+
if (!allowed.includes(access)) {
|
|
220
|
+
throw new ProjectTicketError(403, `Not allowed to ${what}: only ${allowed.join(', ')} of this project may`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
// ---------------------------------------------------------------------------
|
|
224
|
+
// Reads
|
|
225
|
+
// ---------------------------------------------------------------------------
|
|
226
|
+
/**
|
|
227
|
+
* List a project's tickets, optionally filtered.
|
|
228
|
+
*
|
|
229
|
+
* @param ref - Project reference
|
|
230
|
+
* @param filter - `status`, `assignee`, `label`
|
|
231
|
+
* @returns Project and tickets
|
|
232
|
+
*/
|
|
233
|
+
async list(ref, filter = {}) {
|
|
234
|
+
const project = await this.resolveProject(ref);
|
|
235
|
+
const result = await this.tickets.list(project.path);
|
|
236
|
+
const statuses = filter.status ? filter.status.split(',').map((s) => s.trim()) : null;
|
|
237
|
+
const tickets = result.tickets.filter((t) => (!statuses || statuses.includes(t.status)) &&
|
|
238
|
+
(!filter.assignee || t.assignee === filter.assignee) &&
|
|
239
|
+
(!filter.label || t.labels.includes(filter.label)));
|
|
240
|
+
return { project, tickets, invalid: result.invalid };
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* One ticket.
|
|
244
|
+
*
|
|
245
|
+
* @param ref - Project reference
|
|
246
|
+
* @param id - Ticket id
|
|
247
|
+
* @returns The ticket
|
|
248
|
+
* @throws ProjectTicketError(404)
|
|
249
|
+
*/
|
|
250
|
+
async get(ref, id) {
|
|
251
|
+
const project = await this.resolveProject(ref);
|
|
252
|
+
const ticket = await this.tickets.get(project.path, id);
|
|
253
|
+
if (!ticket)
|
|
254
|
+
throw new ProjectTicketError(404, `Ticket not found: ${id}`);
|
|
255
|
+
return ticket;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Tickets of every project a session's teams work on.
|
|
259
|
+
*
|
|
260
|
+
* @param session - Agent session
|
|
261
|
+
* @param filter - Optional status filter
|
|
262
|
+
* @returns Per-project tickets
|
|
263
|
+
*/
|
|
264
|
+
async listForSession(session, filter = {}) {
|
|
265
|
+
const teams = (await this.directory.getTeams()).filter((t) => !t.archived && (t.members ?? []).some((m) => isSession(m, session)));
|
|
266
|
+
const projectIds = new Set(teams.flatMap((t) => t.projectIds ?? []));
|
|
267
|
+
const projects = (await this.directory.getProjects()).filter((p) => projectIds.has(p.id));
|
|
268
|
+
const out = [];
|
|
269
|
+
for (const project of projects) {
|
|
270
|
+
const { tickets } = await this.list(project.id, filter);
|
|
271
|
+
out.push({ project: { id: project.id, name: project.name, path: project.path }, tickets });
|
|
272
|
+
}
|
|
273
|
+
return out;
|
|
274
|
+
}
|
|
275
|
+
// ---------------------------------------------------------------------------
|
|
276
|
+
// Writes
|
|
277
|
+
// ---------------------------------------------------------------------------
|
|
278
|
+
/**
|
|
279
|
+
* Create a ticket. Workers' tickets always start in `backlog`.
|
|
280
|
+
*
|
|
281
|
+
* @param ref - Project reference
|
|
282
|
+
* @param input - Content
|
|
283
|
+
* @param caller - Caller
|
|
284
|
+
* @returns New ticket
|
|
285
|
+
* @throws ProjectTicketError(403) for outsiders, (400) for a team not on the project
|
|
286
|
+
*/
|
|
287
|
+
async create(ref, input, caller) {
|
|
288
|
+
const project = await this.resolveProject(ref);
|
|
289
|
+
const { access } = await this.accessOf(caller, project);
|
|
290
|
+
this.requireAccess(access, ['owner', 'orchestrator', 'lead', 'member'], 'create tickets');
|
|
291
|
+
await this.assertTeamOnProject(project, input.team);
|
|
292
|
+
const status = access === 'member' ? 'backlog' : input.status ?? 'backlog';
|
|
293
|
+
if (status === 'in_progress' || status === 'review' || status === 'done') {
|
|
294
|
+
throw new ProjectTicketError(400, 'A new ticket starts in backlog or ready; claim or assign it to start work');
|
|
295
|
+
}
|
|
296
|
+
const source = input.source ?? (caller.session ? `agent:${caller.session}` : 'owner');
|
|
297
|
+
return this.tickets.create(project.path, project.name, { ...input, status, source, assignee: input.assignee ?? null }, this.actorName(caller));
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Change fields / sections, optionally followed by a status transition.
|
|
301
|
+
*
|
|
302
|
+
* @param ref - Project reference
|
|
303
|
+
* @param id - Ticket id
|
|
304
|
+
* @param input - Changes (+ optional `status`)
|
|
305
|
+
* @param caller - Caller
|
|
306
|
+
* @param note - Optional Log note
|
|
307
|
+
* @returns Updated ticket
|
|
308
|
+
*/
|
|
309
|
+
async update(ref, id, input, caller, note) {
|
|
310
|
+
const project = await this.resolveProject(ref);
|
|
311
|
+
const { access } = await this.accessOf(caller, project);
|
|
312
|
+
this.requireAccess(access, ['owner', 'orchestrator', 'lead', 'member'], 'edit tickets');
|
|
313
|
+
if (input.team !== undefined)
|
|
314
|
+
await this.assertTeamOnProject(project, input.team);
|
|
315
|
+
const { status, ...fields } = input;
|
|
316
|
+
let ticket = await this.tickets.update(project.path, id, fields, this.actorName(caller), status ? undefined : note);
|
|
317
|
+
if (status && status !== ticket.status)
|
|
318
|
+
ticket = await this.transition(project.id, id, status, caller, note);
|
|
319
|
+
return ticket;
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Move a ticket to another status (spec §3–§4). Starting work goes through
|
|
323
|
+
* {@link claim} / {@link assign}, not here. Moving a ticket out of
|
|
324
|
+
* `in_progress` by hand cancels its live WorkItem; ready / backlog /
|
|
325
|
+
* cancelled also clear the assignee and the WorkItem link.
|
|
326
|
+
*
|
|
327
|
+
* @param ref - Project reference
|
|
328
|
+
* @param id - Ticket id
|
|
329
|
+
* @param to - New status
|
|
330
|
+
* @param caller - Caller
|
|
331
|
+
* @param note - Optional reason
|
|
332
|
+
* @returns Updated ticket
|
|
333
|
+
* @throws ProjectTicketError(400/403/404)
|
|
334
|
+
*/
|
|
335
|
+
async transition(ref, id, to, caller, note) {
|
|
336
|
+
const project = await this.resolveProject(ref);
|
|
337
|
+
const { access } = await this.accessOf(caller, project);
|
|
338
|
+
if (to === 'in_progress')
|
|
339
|
+
throw new ProjectTicketError(400, 'Use claim or assign to start work on a ticket');
|
|
340
|
+
const current = await this.tickets.get(project.path, id);
|
|
341
|
+
if (!current)
|
|
342
|
+
throw new ProjectTicketError(404, `Ticket not found: ${id}`);
|
|
343
|
+
const isRelease = current.status === 'in_progress' && (to === 'ready' || to === 'backlog');
|
|
344
|
+
const ownRelease = isRelease && !!caller.session && current.assignee === caller.session;
|
|
345
|
+
if (!(ownRelease && access === 'member')) {
|
|
346
|
+
this.requireAccess(access, ['owner', 'orchestrator', 'lead'], `move tickets to ${to}`);
|
|
347
|
+
}
|
|
348
|
+
const clearsWork = to === 'ready' || to === 'backlog' || to === 'cancelled';
|
|
349
|
+
const extra = clearsWork ? { assignee: null, workItemId: null } : {};
|
|
350
|
+
const updated = await this.tickets.transition(project.path, id, to, this.actorName(caller), note, extra);
|
|
351
|
+
// A person moving the ticket out of in_progress stops the work: a live
|
|
352
|
+
// WorkItem is cancelled (one already submitted for review is left to
|
|
353
|
+
// its reviewer — done_by_worker cannot be cancelled).
|
|
354
|
+
if (current.status === 'in_progress' && current.workItemId) {
|
|
355
|
+
await this.cancelLiveWorkItem(current.workItemId, `project ticket ${id} moved to ${to} by ${this.actorName(caller)}`);
|
|
356
|
+
}
|
|
357
|
+
return updated;
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Append a note to a ticket's Log.
|
|
361
|
+
*
|
|
362
|
+
* @param ref - Project reference
|
|
363
|
+
* @param id - Ticket id
|
|
364
|
+
* @param caller - Caller
|
|
365
|
+
* @param note - The note
|
|
366
|
+
* @returns Updated ticket
|
|
367
|
+
*/
|
|
368
|
+
async log(ref, id, caller, note) {
|
|
369
|
+
const project = await this.resolveProject(ref);
|
|
370
|
+
const { access } = await this.accessOf(caller, project);
|
|
371
|
+
this.requireAccess(access, ['owner', 'orchestrator', 'lead', 'member'], 'write to ticket logs');
|
|
372
|
+
return this.tickets.appendLog(project.path, id, this.actorName(caller), note);
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* The calling agent claims a `ready` ticket: it becomes `in_progress`,
|
|
376
|
+
* assigned to the caller, with a new linked WorkItem claimed for it.
|
|
377
|
+
*
|
|
378
|
+
* @param ref - Project reference
|
|
379
|
+
* @param id - Ticket id
|
|
380
|
+
* @param caller - Must be an agent on one of the project's (eligible) teams
|
|
381
|
+
* @returns Ticket, WorkItem, whether the WorkItem is claimed
|
|
382
|
+
* @throws ProjectTicketError(403) for non-members, (409) when not claimable
|
|
383
|
+
*/
|
|
384
|
+
async claim(ref, id, caller) {
|
|
385
|
+
const project = await this.resolveProject(ref);
|
|
386
|
+
if (!caller.session)
|
|
387
|
+
throw new ProjectTicketError(400, 'Claiming needs an agent session (X-Agent-Session); the owner assigns instead');
|
|
388
|
+
const ticket = await this.tickets.get(project.path, id);
|
|
389
|
+
if (!ticket)
|
|
390
|
+
throw new ProjectTicketError(404, `Ticket not found: ${id}`);
|
|
391
|
+
const teamId = await this.eligibleTeamOf(project, ticket, caller.session);
|
|
392
|
+
if (!teamId)
|
|
393
|
+
throw new ProjectTicketError(403, `${caller.session} is not on a team that works on ${ticket.id}`);
|
|
394
|
+
return this.startWork(project, id, caller.session, caller.session, teamId, { self: true, allowed: ['ready'] });
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Assign a ticket (owner, orchestrator or a lead of a project team). An
|
|
398
|
+
* agent assignee on an eligible team gets a linked WorkItem (queued for it,
|
|
399
|
+
* dispatched by the normal path) unless `start` is false; any other
|
|
400
|
+
* assignee (a human) is only recorded.
|
|
401
|
+
*
|
|
402
|
+
* @param ref - Project reference
|
|
403
|
+
* @param id - Ticket id
|
|
404
|
+
* @param assignee - Session name or a human's name
|
|
405
|
+
* @param caller - Caller
|
|
406
|
+
* @param options - `start` (default true)
|
|
407
|
+
* @returns The ticket, plus the WorkItem when work started
|
|
408
|
+
*/
|
|
409
|
+
async assign(ref, id, assignee, caller, options = {}) {
|
|
410
|
+
const project = await this.resolveProject(ref);
|
|
411
|
+
const { access } = await this.accessOf(caller, project);
|
|
412
|
+
this.requireAccess(access, ['owner', 'orchestrator', 'lead'], 'assign tickets');
|
|
413
|
+
const who = String(assignee ?? '').trim();
|
|
414
|
+
if (!who)
|
|
415
|
+
throw new ProjectTicketError(400, 'assignee is required');
|
|
416
|
+
const ticket = await this.tickets.get(project.path, id);
|
|
417
|
+
if (!ticket)
|
|
418
|
+
throw new ProjectTicketError(404, `Ticket not found: ${id}`);
|
|
419
|
+
const teamId = await this.eligibleTeamOf(project, ticket, who);
|
|
420
|
+
const isAgent = await this.isKnownAgent(who);
|
|
421
|
+
if (isAgent && !teamId)
|
|
422
|
+
throw new ProjectTicketError(403, `${who} is not on a team that works on ${ticket.id}`);
|
|
423
|
+
if (teamId && options.start !== false) {
|
|
424
|
+
const started = await this.startWork(project, id, who, this.actorName(caller), teamId, { self: false, allowed: ['backlog', 'ready'] });
|
|
425
|
+
return { ticket: started.ticket, workItem: started.workItem };
|
|
426
|
+
}
|
|
427
|
+
if (ticket.status === 'in_progress')
|
|
428
|
+
throw new ProjectTicketError(409, `${ticket.id} is in progress; release it before reassigning`);
|
|
429
|
+
const updated = await this.tickets.mutate(project.path, id, this.actorName(caller), (t) => t.assignee === who ? null : { fields: { assignee: who }, log: [`assigned to ${who}`] });
|
|
430
|
+
return { ticket: updated };
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* Claim the best `ready` ticket for an idle agent (AutoClaim fallback, spec
|
|
434
|
+
* §5): highest priority, then oldest, across its teams' projects. Skipped
|
|
435
|
+
* when the agent already works a ticket or still has WorkItems of its own.
|
|
436
|
+
*
|
|
437
|
+
* A team lead is not fed tickets automatically in a team that has other
|
|
438
|
+
* members — leads delegate (they can still claim or assign explicitly). A
|
|
439
|
+
* lead who is the only member of its team is treated like any member.
|
|
440
|
+
*
|
|
441
|
+
* @param session - Idle agent
|
|
442
|
+
* @returns The started work, or null
|
|
443
|
+
*/
|
|
444
|
+
async claimNextForAgent(session) {
|
|
445
|
+
if (!session || session === ORCHESTRATOR_SESSION_NAME)
|
|
446
|
+
return null;
|
|
447
|
+
const teams = (await this.directory.getTeams()).filter((t) => {
|
|
448
|
+
if (t.archived)
|
|
449
|
+
return false;
|
|
450
|
+
const me = (t.members ?? []).find((m) => isSession(m, session));
|
|
451
|
+
if (!me)
|
|
452
|
+
return false;
|
|
453
|
+
return !isTeamLead(t, me) || (t.members ?? []).length === 1;
|
|
454
|
+
});
|
|
455
|
+
if (teams.length === 0)
|
|
456
|
+
return null;
|
|
457
|
+
const pool = await this.pool.getAllItems();
|
|
458
|
+
if (pool.some((wi) => wi.target === session && BUSY_STATUSES.has(wi.status)))
|
|
459
|
+
return null;
|
|
460
|
+
const projectIds = new Set(teams.flatMap((t) => t.projectIds ?? []));
|
|
461
|
+
const projects = (await this.directory.getProjects()).filter((p) => projectIds.has(p.id));
|
|
462
|
+
const candidates = [];
|
|
463
|
+
for (const project of projects) {
|
|
464
|
+
const { tickets } = await this.tickets.list(project.path);
|
|
465
|
+
if (tickets.some((t) => t.status === 'in_progress' && t.assignee === session))
|
|
466
|
+
return null;
|
|
467
|
+
for (const ticket of tickets) {
|
|
468
|
+
if (ticket.status !== 'ready')
|
|
469
|
+
continue;
|
|
470
|
+
const team = teams.find((t) => (t.projectIds ?? []).includes(project.id) && (!ticket.team || ticket.team === t.id));
|
|
471
|
+
if (team)
|
|
472
|
+
candidates.push({ project, ticket, teamId: team.id });
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
candidates.sort((a, b) => projectTicketPriorityRank(a.ticket.priority) - projectTicketPriorityRank(b.ticket.priority) ||
|
|
476
|
+
(Date.parse(a.ticket.createdAt) || 0) - (Date.parse(b.ticket.createdAt) || 0) ||
|
|
477
|
+
Number(a.ticket.id.split('-').pop()) - Number(b.ticket.id.split('-').pop()));
|
|
478
|
+
for (const c of candidates.slice(0, MAX_AUTO_CLAIM_ATTEMPTS)) {
|
|
479
|
+
try {
|
|
480
|
+
return await this.startWork(c.project, c.ticket.id, session, session, c.teamId, { self: true, allowed: ['ready'] });
|
|
481
|
+
}
|
|
482
|
+
catch (err) {
|
|
483
|
+
// Lost a race (someone claimed it, a human moved it) — try the next.
|
|
484
|
+
this.logger.debug('Ticket auto-claim attempt skipped', {
|
|
485
|
+
ticketId: c.ticket.id,
|
|
486
|
+
session,
|
|
487
|
+
error: err instanceof Error ? err.message : String(err),
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
return null;
|
|
492
|
+
}
|
|
493
|
+
// ---------------------------------------------------------------------------
|
|
494
|
+
// Sync (WorkItem → ticket)
|
|
495
|
+
// ---------------------------------------------------------------------------
|
|
496
|
+
/**
|
|
497
|
+
* React to a pool lifecycle event: find the ticket the WorkItem (or one of
|
|
498
|
+
* its ancestors — a reviewer's retry or review item) belongs to and sync it.
|
|
499
|
+
*
|
|
500
|
+
* @param workItemId - WorkItem from the event
|
|
501
|
+
*/
|
|
502
|
+
async onWorkItemEvent(workItemId) {
|
|
503
|
+
try {
|
|
504
|
+
let wi = await this.pool.findWorkItem(workItemId);
|
|
505
|
+
for (let hop = 0; wi && hop < PROJECT_TICKET_CONSTANTS.MAX_SUCCESSOR_HOPS; hop++) {
|
|
506
|
+
const link = readProjectTicketLink(wi.metadata);
|
|
507
|
+
if (link) {
|
|
508
|
+
await this.syncTicket(link.projectPath, link.id);
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
const parentId = wi.parentWorkItemId ?? (typeof wi.metadata?.verifyOf === 'string' ? wi.metadata.verifyOf : undefined);
|
|
512
|
+
wi = parentId ? await this.pool.findWorkItem(parentId) : null;
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
catch (err) {
|
|
516
|
+
this.logger.warn('Project ticket sync on WorkItem event failed (sweep will retry)', {
|
|
517
|
+
workItemId,
|
|
518
|
+
error: err instanceof Error ? err.message : String(err),
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Reconcile every `in_progress` ticket of every project with its WorkItem.
|
|
524
|
+
*
|
|
525
|
+
* @returns Number of tickets changed
|
|
526
|
+
*/
|
|
527
|
+
async syncAll() {
|
|
528
|
+
if (this.sweeping)
|
|
529
|
+
return 0;
|
|
530
|
+
this.sweeping = true;
|
|
531
|
+
let changed = 0;
|
|
532
|
+
try {
|
|
533
|
+
for (const project of await this.directory.getProjects()) {
|
|
534
|
+
let tickets = [];
|
|
535
|
+
try {
|
|
536
|
+
tickets = (await this.tickets.list(project.path)).tickets;
|
|
537
|
+
}
|
|
538
|
+
catch {
|
|
539
|
+
continue;
|
|
540
|
+
}
|
|
541
|
+
for (const t of tickets) {
|
|
542
|
+
if (t.status !== 'in_progress' || !t.workItemId)
|
|
543
|
+
continue;
|
|
544
|
+
const outcome = await this.syncTicket(project.path, t.id).catch(() => 'unchanged');
|
|
545
|
+
if (outcome !== 'unchanged')
|
|
546
|
+
changed += 1;
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
finally {
|
|
551
|
+
this.sweeping = false;
|
|
552
|
+
}
|
|
553
|
+
return changed;
|
|
554
|
+
}
|
|
555
|
+
/**
|
|
556
|
+
* Bring one ticket in line with its WorkItem chain (spec §5 table).
|
|
557
|
+
* Only an `in_progress` ticket is ever changed, so human moves are never
|
|
558
|
+
* fought.
|
|
559
|
+
*
|
|
560
|
+
* @param projectPath - Project root
|
|
561
|
+
* @param id - Ticket id
|
|
562
|
+
* @returns What changed
|
|
563
|
+
*/
|
|
564
|
+
async syncTicket(projectPath, id) {
|
|
565
|
+
const ticket = await this.tickets.get(projectPath, id);
|
|
566
|
+
if (!ticket || ticket.status !== 'in_progress' || !ticket.workItemId)
|
|
567
|
+
return 'unchanged';
|
|
568
|
+
const end = await this.followChain(ticket.workItemId);
|
|
569
|
+
let outcome = 'unchanged';
|
|
570
|
+
await this.tickets.mutate(projectPath, id, 'crewly', (t) => {
|
|
571
|
+
// Re-checked under the lock: a human or another sync may have moved it.
|
|
572
|
+
if (t.status !== 'in_progress' || t.workItemId !== ticket.workItemId)
|
|
573
|
+
return null;
|
|
574
|
+
switch (end.kind) {
|
|
575
|
+
case 'success': {
|
|
576
|
+
const to = t.ownerReview ? 'review' : 'done';
|
|
577
|
+
outcome = to;
|
|
578
|
+
return {
|
|
579
|
+
fields: { status: to, workItemId: end.wi.id },
|
|
580
|
+
log: [`WorkItem ${end.wi.id} ${end.wi.status} → ${to}${to === 'review' ? ' (waiting for the owner)' : ''}`],
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
case 'live':
|
|
584
|
+
if (end.wi.id === t.workItemId)
|
|
585
|
+
return null;
|
|
586
|
+
outcome = 'relinked';
|
|
587
|
+
return {
|
|
588
|
+
fields: { workItemId: end.wi.id, ...(end.wi.target ? { assignee: end.wi.target } : {}) },
|
|
589
|
+
log: [`work continues in WorkItem ${end.wi.id}`],
|
|
590
|
+
};
|
|
591
|
+
case 'returned':
|
|
592
|
+
outcome = 'returned';
|
|
593
|
+
return {
|
|
594
|
+
fields: { status: 'ready', assignee: null, workItemId: null },
|
|
595
|
+
log: [`WorkItem ${end.id} ${end.why} — back to ready`],
|
|
596
|
+
};
|
|
597
|
+
default:
|
|
598
|
+
return null;
|
|
599
|
+
}
|
|
600
|
+
});
|
|
601
|
+
if (outcome !== 'unchanged')
|
|
602
|
+
this.logger.info('Project ticket synced from its WorkItem', { projectPath, id, outcome });
|
|
603
|
+
return outcome;
|
|
604
|
+
}
|
|
605
|
+
// ---------------------------------------------------------------------------
|
|
606
|
+
// Internals
|
|
607
|
+
// ---------------------------------------------------------------------------
|
|
608
|
+
/**
|
|
609
|
+
* Start work on a ticket under the folder lock: refuse when a live WorkItem
|
|
610
|
+
* already carries it, create the WorkItem, write the ticket, roll the
|
|
611
|
+
* WorkItem back if the write fails; then claim it for a self-claim.
|
|
612
|
+
*
|
|
613
|
+
* @param project - Project
|
|
614
|
+
* @param id - Ticket id
|
|
615
|
+
* @param assignee - Agent that will do the work
|
|
616
|
+
* @param actor - Who started it (Log)
|
|
617
|
+
* @param teamId - Team the assignee works on it for
|
|
618
|
+
* @param options - `self`: claim the WorkItem for the assignee; `allowed`: statuses work may start from
|
|
619
|
+
* @returns Started work
|
|
620
|
+
*/
|
|
621
|
+
async startWork(project, id, assignee, actor, teamId, options) {
|
|
622
|
+
let created = null;
|
|
623
|
+
let ticket;
|
|
624
|
+
try {
|
|
625
|
+
ticket = await this.tickets.mutate(project.path, id, actor, async (t) => {
|
|
626
|
+
if (!options.allowed.includes(t.status)) {
|
|
627
|
+
throw new ProjectTicketError(409, `${t.id} is ${t.status}; only ${options.allowed.join(' or ')} tickets can be ${options.self ? 'claimed' : 'assigned'}`);
|
|
628
|
+
}
|
|
629
|
+
if (t.team && t.team !== teamId)
|
|
630
|
+
throw new ProjectTicketError(403, `${t.id} belongs to team ${t.team}`);
|
|
631
|
+
const live = await this.findLiveLinkedWorkItem(project.path, t);
|
|
632
|
+
if (live)
|
|
633
|
+
throw new ProjectTicketError(409, `${t.id} is already being worked in WorkItem ${live.id}`);
|
|
634
|
+
created = this.buildWorkItem(project, t, assignee, teamId);
|
|
635
|
+
await this.pool.addToPool(created);
|
|
636
|
+
return {
|
|
637
|
+
fields: { status: 'in_progress', assignee, workItemId: created.id },
|
|
638
|
+
log: [options.self ? `claimed by ${assignee} — WorkItem ${created.id}` : `assigned to ${assignee} — WorkItem ${created.id}`],
|
|
639
|
+
};
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
catch (err) {
|
|
643
|
+
const orphan = created;
|
|
644
|
+
if (orphan) {
|
|
645
|
+
await this.pool.cancelQueued(orphan.id, `project ticket ${id} could not be updated`).catch(() => undefined);
|
|
646
|
+
}
|
|
647
|
+
throw err;
|
|
648
|
+
}
|
|
649
|
+
let workItem = created;
|
|
650
|
+
let claimed = false;
|
|
651
|
+
if (options.self) {
|
|
652
|
+
const result = await this.pool.claimSpecificItem(assignee, workItem.id).catch(() => null);
|
|
653
|
+
if (result) {
|
|
654
|
+
workItem = result.workItem;
|
|
655
|
+
claimed = true;
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
this.logger.info('Project ticket work started', { projectPath: project.path, id, assignee, workItemId: workItem.id, claimed });
|
|
659
|
+
return { ticket, workItem, claimed };
|
|
660
|
+
}
|
|
661
|
+
/**
|
|
662
|
+
* Build the WorkItem that carries a ticket's work.
|
|
663
|
+
*
|
|
664
|
+
* @param project - Project
|
|
665
|
+
* @param t - Ticket
|
|
666
|
+
* @param assignee - Target agent
|
|
667
|
+
* @param teamId - Team
|
|
668
|
+
* @returns WorkItem (queued)
|
|
669
|
+
*/
|
|
670
|
+
buildWorkItem(project, t, assignee, teamId) {
|
|
671
|
+
const criteria = t.acceptance.map((c) => `- [${c.done ? 'x' : ' '}] ${c.text}`).join('\n');
|
|
672
|
+
const brief = [
|
|
673
|
+
`# ${t.id}: ${t.title}`,
|
|
674
|
+
'',
|
|
675
|
+
`Project ticket file: \`${t.filePath}\` (project ${project.name}). Priority ${t.priority}.`,
|
|
676
|
+
'When you finish, complete this WorkItem as usual (complete-task / report-status with this WorkItem id);',
|
|
677
|
+
'your lead reviews it and the ticket moves to done by itself. Use `project-tickets log` for progress notes.',
|
|
678
|
+
'',
|
|
679
|
+
'## Description',
|
|
680
|
+
'',
|
|
681
|
+
t.description || '_No description._',
|
|
682
|
+
'',
|
|
683
|
+
'## Acceptance criteria',
|
|
684
|
+
'',
|
|
685
|
+
criteria || '_None listed._',
|
|
686
|
+
].join('\n');
|
|
687
|
+
const priorityMeta = t.priority.toLowerCase();
|
|
688
|
+
return {
|
|
689
|
+
id: uuidv4(),
|
|
690
|
+
type: 'project_task',
|
|
691
|
+
owner: 'agent',
|
|
692
|
+
target: assignee,
|
|
693
|
+
targetSource: 'assigned',
|
|
694
|
+
title: `${t.id}: ${t.title}`,
|
|
695
|
+
description: (t.description || t.title).slice(0, WORK_ITEM_DESCRIPTION_MAX),
|
|
696
|
+
briefMarkdown: capBytes(brief, MAX_BRIEF_MARKDOWN_BYTES),
|
|
697
|
+
status: 'queued',
|
|
698
|
+
createdAt: this.now(),
|
|
699
|
+
retryCount: 0,
|
|
700
|
+
maxRetries: 3,
|
|
701
|
+
projectTaskId: t.id,
|
|
702
|
+
...(t.requestId ? { requestId: t.requestId } : {}),
|
|
703
|
+
inputTokens: 0,
|
|
704
|
+
outputTokens: 0,
|
|
705
|
+
cost: 0,
|
|
706
|
+
metadata: {
|
|
707
|
+
[PROJECT_TICKET_CONSTANTS.WORK_ITEM_METADATA_KEY]: { projectPath: project.path, id: t.id },
|
|
708
|
+
projectId: project.id,
|
|
709
|
+
projectPath: project.path,
|
|
710
|
+
teamId,
|
|
711
|
+
priority: priorityMeta,
|
|
712
|
+
requiresVerification: true,
|
|
713
|
+
},
|
|
714
|
+
};
|
|
715
|
+
}
|
|
716
|
+
/**
|
|
717
|
+
* A live WorkItem already carrying this ticket: the ticket's own
|
|
718
|
+
* `workItemId` chain, or any pool item whose metadata links the ticket.
|
|
719
|
+
*
|
|
720
|
+
* @param projectPath - Project root
|
|
721
|
+
* @param t - Ticket
|
|
722
|
+
* @returns The live item, or null
|
|
723
|
+
*/
|
|
724
|
+
async findLiveLinkedWorkItem(projectPath, t) {
|
|
725
|
+
if (t.workItemId) {
|
|
726
|
+
const end = await this.followChain(t.workItemId);
|
|
727
|
+
if (end.kind === 'live')
|
|
728
|
+
return end.wi;
|
|
729
|
+
}
|
|
730
|
+
const root = path.resolve(projectPath);
|
|
731
|
+
const items = await this.pool.getAllItems();
|
|
732
|
+
return (items.find((wi) => {
|
|
733
|
+
if (!LIVE_STATUSES.has(wi.status))
|
|
734
|
+
return false;
|
|
735
|
+
const link = readProjectTicketLink(wi.metadata);
|
|
736
|
+
return !!link && link.id === t.id && path.resolve(link.projectPath) === root;
|
|
737
|
+
}) ?? null);
|
|
738
|
+
}
|
|
739
|
+
/**
|
|
740
|
+
* Follow a WorkItem through its successors to where the work stands now.
|
|
741
|
+
*
|
|
742
|
+
* @param startId - The ticket's WorkItem
|
|
743
|
+
* @returns Where the chain ends
|
|
744
|
+
*/
|
|
745
|
+
async followChain(startId) {
|
|
746
|
+
let current = startId;
|
|
747
|
+
for (let hop = 0; hop < PROJECT_TICKET_CONSTANTS.MAX_SUCCESSOR_HOPS; hop++) {
|
|
748
|
+
const wi = await this.pool.findWorkItem(current);
|
|
749
|
+
if (!wi)
|
|
750
|
+
return { kind: 'returned', id: current, why: 'no longer exists' };
|
|
751
|
+
if (wi.status === 'verified' || wi.status === 'done')
|
|
752
|
+
return { kind: 'success', wi };
|
|
753
|
+
if (LIVE_STATUSES.has(wi.status))
|
|
754
|
+
return { kind: 'live', wi };
|
|
755
|
+
const superseded = wi.metadata?.[SUPERSEDED_BY_METADATA_KEY];
|
|
756
|
+
const supersededBy = Array.isArray(superseded) && typeof superseded[0] === 'string' ? superseded[0] : undefined;
|
|
757
|
+
const disposition = getWorkItemDisposition(wi);
|
|
758
|
+
const successor = supersededBy ?? (disposition?.kind === 'succeeded_by' ? disposition.successorWorkItemId : undefined);
|
|
759
|
+
if (successor && successor !== current) {
|
|
760
|
+
current = successor;
|
|
761
|
+
continue;
|
|
762
|
+
}
|
|
763
|
+
if (wi.status === 'cancelled')
|
|
764
|
+
return { kind: 'returned', id: wi.id, why: `cancelled${wi.cancelReason ? `: ${wi.cancelReason}` : ''}` };
|
|
765
|
+
if (disposition?.kind === 'terminal')
|
|
766
|
+
return { kind: 'returned', id: wi.id, why: `${wi.status}${wi.error ? `: ${wi.error}` : ''}` };
|
|
767
|
+
// failed / rejected with no decision yet: the harness is still choosing
|
|
768
|
+
// between a retry in place and a successor — wait.
|
|
769
|
+
return { kind: 'pending' };
|
|
770
|
+
}
|
|
771
|
+
return { kind: 'pending' };
|
|
772
|
+
}
|
|
773
|
+
/**
|
|
774
|
+
* Cancel a WorkItem if it is still live (best-effort).
|
|
775
|
+
*
|
|
776
|
+
* @param workItemId - Item
|
|
777
|
+
* @param reason - Cancel reason
|
|
778
|
+
*/
|
|
779
|
+
async cancelLiveWorkItem(workItemId, reason) {
|
|
780
|
+
try {
|
|
781
|
+
const end = await this.followChain(workItemId);
|
|
782
|
+
if (end.kind !== 'live')
|
|
783
|
+
return;
|
|
784
|
+
const wi = end.wi;
|
|
785
|
+
if (wi.status === 'queued' || wi.status === 'blocked' || wi.status === 'scheduled') {
|
|
786
|
+
await this.pool.cancelQueued(wi.id, reason);
|
|
787
|
+
}
|
|
788
|
+
else if (wi.status === 'running') {
|
|
789
|
+
await this.pool.releaseClaim(wi.id, reason);
|
|
790
|
+
await this.pool.transitionStatus(wi.id, 'cancelled', 'system', undefined, reason);
|
|
791
|
+
}
|
|
792
|
+
else {
|
|
793
|
+
this.logger.info('Linked WorkItem left as is (not cancellable from its status)', { workItemId: wi.id, status: wi.status });
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
catch (err) {
|
|
797
|
+
this.logger.warn('Could not cancel the linked WorkItem', { workItemId, error: err instanceof Error ? err.message : String(err) });
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
/**
|
|
801
|
+
* The team an agent would work a ticket for, or null when it may not.
|
|
802
|
+
*
|
|
803
|
+
* @param project - Project
|
|
804
|
+
* @param ticket - Ticket (its `team` narrows the choice)
|
|
805
|
+
* @param session - Agent session
|
|
806
|
+
* @returns Team id or null
|
|
807
|
+
*/
|
|
808
|
+
async eligibleTeamOf(project, ticket, session) {
|
|
809
|
+
const teams = this.projectTeams(project, await this.directory.getTeams());
|
|
810
|
+
const team = teams.find((t) => (!ticket.team || ticket.team === t.id) && (t.members ?? []).some((m) => isSession(m, session)));
|
|
811
|
+
return team?.id ?? null;
|
|
812
|
+
}
|
|
813
|
+
/**
|
|
814
|
+
* Whether a name is an agent session on any team.
|
|
815
|
+
*
|
|
816
|
+
* @param name - Candidate
|
|
817
|
+
* @returns True for a known agent
|
|
818
|
+
*/
|
|
819
|
+
async isKnownAgent(name) {
|
|
820
|
+
if (name === ORCHESTRATOR_SESSION_NAME)
|
|
821
|
+
return true;
|
|
822
|
+
return (await this.directory.getTeams()).some((t) => (t.members ?? []).some((m) => isSession(m, name)));
|
|
823
|
+
}
|
|
824
|
+
/**
|
|
825
|
+
* Refuse a `team` value that is not one of the project's teams.
|
|
826
|
+
*
|
|
827
|
+
* @param project - Project
|
|
828
|
+
* @param team - Team id (null/empty = any)
|
|
829
|
+
* @throws ProjectTicketError(400)
|
|
830
|
+
*/
|
|
831
|
+
async assertTeamOnProject(project, team) {
|
|
832
|
+
if (!team)
|
|
833
|
+
return;
|
|
834
|
+
const teams = this.projectTeams(project, await this.directory.getTeams());
|
|
835
|
+
if (!teams.some((t) => t.id === team))
|
|
836
|
+
throw new ProjectTicketError(400, `Team ${team} does not work on project ${project.name}`);
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
//# sourceMappingURL=project-ticket-workflow.service.js.map
|