@aion0/forge 0.5.26 → 0.5.27

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.
Files changed (253) hide show
  1. package/.forge/worktrees/pipeline-4dd8dc2d/CLAUDE.md +86 -0
  2. package/.forge/worktrees/pipeline-4dd8dc2d/README.md +136 -0
  3. package/.forge/worktrees/pipeline-4dd8dc2d/RELEASE_NOTES.md +36 -0
  4. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/agents/route.ts +17 -0
  5. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/auth/[...nextauth]/route.ts +3 -0
  6. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/auth/verify/route.ts +46 -0
  7. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/claude/[id]/route.ts +31 -0
  8. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/claude/[id]/stream/route.ts +63 -0
  9. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/claude/route.ts +28 -0
  10. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/claude-sessions/[projectName]/entries/route.ts +23 -0
  11. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/claude-sessions/[projectName]/live/route.ts +72 -0
  12. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/claude-sessions/[projectName]/route.ts +37 -0
  13. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/claude-sessions/sync/route.ts +17 -0
  14. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/claude-templates/route.ts +145 -0
  15. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/code/route.ts +299 -0
  16. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/delivery/[id]/route.ts +62 -0
  17. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/delivery/route.ts +40 -0
  18. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/detect-cli/route.ts +46 -0
  19. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/docs/route.ts +176 -0
  20. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/docs/sessions/route.ts +54 -0
  21. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/favorites/route.ts +26 -0
  22. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/flows/route.ts +6 -0
  23. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/flows/run/route.ts +19 -0
  24. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/git/route.ts +149 -0
  25. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/help/route.ts +84 -0
  26. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/issue-scanner/route.ts +116 -0
  27. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/logs/route.ts +100 -0
  28. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/mobile-chat/route.ts +115 -0
  29. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/monitor/route.ts +74 -0
  30. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/notifications/route.ts +42 -0
  31. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/notify/test/route.ts +33 -0
  32. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/online/route.ts +40 -0
  33. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/pipelines/[id]/route.ts +41 -0
  34. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/pipelines/route.ts +90 -0
  35. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/plugins/route.ts +75 -0
  36. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/preview/[...path]/route.ts +64 -0
  37. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/preview/route.ts +156 -0
  38. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/project-pipelines/route.ts +91 -0
  39. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/project-sessions/route.ts +61 -0
  40. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/projects/route.ts +26 -0
  41. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/sessions/[id]/chat/route.ts +64 -0
  42. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/sessions/[id]/messages/route.ts +9 -0
  43. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/sessions/[id]/route.ts +17 -0
  44. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/sessions/route.ts +20 -0
  45. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/settings/route.ts +64 -0
  46. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/skills/local/route.ts +228 -0
  47. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/skills/route.ts +182 -0
  48. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/smith-templates/route.ts +81 -0
  49. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/status/route.ts +12 -0
  50. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/tabs/route.ts +25 -0
  51. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/tasks/[id]/route.ts +51 -0
  52. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/tasks/[id]/stream/route.ts +77 -0
  53. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/tasks/link/route.ts +37 -0
  54. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/tasks/route.ts +44 -0
  55. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/tasks/session/route.ts +14 -0
  56. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/telegram/route.ts +23 -0
  57. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/templates/route.ts +6 -0
  58. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/terminal-bell/route.ts +39 -0
  59. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/terminal-cwd/route.ts +19 -0
  60. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/terminal-state/route.ts +15 -0
  61. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/tunnel/route.ts +26 -0
  62. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/upgrade/route.ts +43 -0
  63. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/usage/route.ts +20 -0
  64. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/version/route.ts +78 -0
  65. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/watchers/route.ts +33 -0
  66. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/workspace/[id]/agents/route.ts +35 -0
  67. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/workspace/[id]/memory/route.ts +23 -0
  68. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/workspace/[id]/smith/route.ts +22 -0
  69. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/workspace/[id]/stream/route.ts +31 -0
  70. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/workspace/route.ts +79 -0
  71. package/.forge/worktrees/pipeline-4dd8dc2d/app/global-error.tsx +21 -0
  72. package/.forge/worktrees/pipeline-4dd8dc2d/app/globals.css +52 -0
  73. package/.forge/worktrees/pipeline-4dd8dc2d/app/icon.ico +0 -0
  74. package/.forge/worktrees/pipeline-4dd8dc2d/app/icon.png +0 -0
  75. package/.forge/worktrees/pipeline-4dd8dc2d/app/icon.svg +106 -0
  76. package/.forge/worktrees/pipeline-4dd8dc2d/app/layout.tsx +17 -0
  77. package/.forge/worktrees/pipeline-4dd8dc2d/app/login/LoginForm.tsx +96 -0
  78. package/.forge/worktrees/pipeline-4dd8dc2d/app/login/page.tsx +10 -0
  79. package/.forge/worktrees/pipeline-4dd8dc2d/app/mobile/page.tsx +10 -0
  80. package/.forge/worktrees/pipeline-4dd8dc2d/app/page.tsx +22 -0
  81. package/.forge/worktrees/pipeline-4dd8dc2d/bin/forge-server.mjs +484 -0
  82. package/.forge/worktrees/pipeline-4dd8dc2d/check-forge-status.sh +71 -0
  83. package/.forge/worktrees/pipeline-4dd8dc2d/cli/mw.ts +579 -0
  84. package/.forge/worktrees/pipeline-4dd8dc2d/components/BrowserPanel.tsx +175 -0
  85. package/.forge/worktrees/pipeline-4dd8dc2d/components/ChatPanel.tsx +191 -0
  86. package/.forge/worktrees/pipeline-4dd8dc2d/components/ClaudeTerminal.tsx +267 -0
  87. package/.forge/worktrees/pipeline-4dd8dc2d/components/CodeViewer.tsx +787 -0
  88. package/.forge/worktrees/pipeline-4dd8dc2d/components/ConversationEditor.tsx +411 -0
  89. package/.forge/worktrees/pipeline-4dd8dc2d/components/ConversationGraphView.tsx +347 -0
  90. package/.forge/worktrees/pipeline-4dd8dc2d/components/ConversationTerminalView.tsx +303 -0
  91. package/.forge/worktrees/pipeline-4dd8dc2d/components/Dashboard.tsx +807 -0
  92. package/.forge/worktrees/pipeline-4dd8dc2d/components/DashboardWrapper.tsx +9 -0
  93. package/.forge/worktrees/pipeline-4dd8dc2d/components/DeliveryFlowEditor.tsx +491 -0
  94. package/.forge/worktrees/pipeline-4dd8dc2d/components/DeliveryList.tsx +230 -0
  95. package/.forge/worktrees/pipeline-4dd8dc2d/components/DeliveryWorkspace.tsx +589 -0
  96. package/.forge/worktrees/pipeline-4dd8dc2d/components/DocTerminal.tsx +187 -0
  97. package/.forge/worktrees/pipeline-4dd8dc2d/components/DocsViewer.tsx +574 -0
  98. package/.forge/worktrees/pipeline-4dd8dc2d/components/HelpDialog.tsx +169 -0
  99. package/.forge/worktrees/pipeline-4dd8dc2d/components/HelpTerminal.tsx +141 -0
  100. package/.forge/worktrees/pipeline-4dd8dc2d/components/InlinePipelineView.tsx +111 -0
  101. package/.forge/worktrees/pipeline-4dd8dc2d/components/LogViewer.tsx +194 -0
  102. package/.forge/worktrees/pipeline-4dd8dc2d/components/MarkdownContent.tsx +73 -0
  103. package/.forge/worktrees/pipeline-4dd8dc2d/components/MobileView.tsx +385 -0
  104. package/.forge/worktrees/pipeline-4dd8dc2d/components/MonitorPanel.tsx +122 -0
  105. package/.forge/worktrees/pipeline-4dd8dc2d/components/NewSessionModal.tsx +93 -0
  106. package/.forge/worktrees/pipeline-4dd8dc2d/components/NewTaskModal.tsx +492 -0
  107. package/.forge/worktrees/pipeline-4dd8dc2d/components/PipelineEditor.tsx +570 -0
  108. package/.forge/worktrees/pipeline-4dd8dc2d/components/PipelineView.tsx +1018 -0
  109. package/.forge/worktrees/pipeline-4dd8dc2d/components/PluginsPanel.tsx +472 -0
  110. package/.forge/worktrees/pipeline-4dd8dc2d/components/ProjectDetail.tsx +1618 -0
  111. package/.forge/worktrees/pipeline-4dd8dc2d/components/ProjectList.tsx +108 -0
  112. package/.forge/worktrees/pipeline-4dd8dc2d/components/ProjectManager.tsx +401 -0
  113. package/.forge/worktrees/pipeline-4dd8dc2d/components/SessionList.tsx +74 -0
  114. package/.forge/worktrees/pipeline-4dd8dc2d/components/SessionView.tsx +726 -0
  115. package/.forge/worktrees/pipeline-4dd8dc2d/components/SettingsModal.tsx +1647 -0
  116. package/.forge/worktrees/pipeline-4dd8dc2d/components/SkillsPanel.tsx +969 -0
  117. package/.forge/worktrees/pipeline-4dd8dc2d/components/StatusBar.tsx +99 -0
  118. package/.forge/worktrees/pipeline-4dd8dc2d/components/TabBar.tsx +46 -0
  119. package/.forge/worktrees/pipeline-4dd8dc2d/components/TaskBoard.tsx +113 -0
  120. package/.forge/worktrees/pipeline-4dd8dc2d/components/TaskDetail.tsx +372 -0
  121. package/.forge/worktrees/pipeline-4dd8dc2d/components/TerminalLauncher.tsx +398 -0
  122. package/.forge/worktrees/pipeline-4dd8dc2d/components/TunnelToggle.tsx +206 -0
  123. package/.forge/worktrees/pipeline-4dd8dc2d/components/UsagePanel.tsx +207 -0
  124. package/.forge/worktrees/pipeline-4dd8dc2d/components/WebTerminal.tsx +1743 -0
  125. package/.forge/worktrees/pipeline-4dd8dc2d/components/WorkspaceTree.tsx +221 -0
  126. package/.forge/worktrees/pipeline-4dd8dc2d/components/WorkspaceView.tsx +4048 -0
  127. package/.forge/worktrees/pipeline-4dd8dc2d/dev-test.sh +5 -0
  128. package/.forge/worktrees/pipeline-4dd8dc2d/docs/Forge_Memory_Layer_Design.docx +0 -0
  129. package/.forge/worktrees/pipeline-4dd8dc2d/docs/Forge_Strategy_Research_2026.docx +0 -0
  130. package/.forge/worktrees/pipeline-4dd8dc2d/docs/LOCAL-DEPLOY.md +144 -0
  131. package/.forge/worktrees/pipeline-4dd8dc2d/docs/roadmap-multi-agent-workflow.md +330 -0
  132. package/.forge/worktrees/pipeline-4dd8dc2d/forge-logo.png +0 -0
  133. package/.forge/worktrees/pipeline-4dd8dc2d/forge-logo.svg +106 -0
  134. package/.forge/worktrees/pipeline-4dd8dc2d/hooks/useSidebarResize.ts +52 -0
  135. package/.forge/worktrees/pipeline-4dd8dc2d/install.sh +29 -0
  136. package/.forge/worktrees/pipeline-4dd8dc2d/instrumentation.ts +35 -0
  137. package/.forge/worktrees/pipeline-4dd8dc2d/lib/agents/claude-adapter.ts +104 -0
  138. package/.forge/worktrees/pipeline-4dd8dc2d/lib/agents/generic-adapter.ts +64 -0
  139. package/.forge/worktrees/pipeline-4dd8dc2d/lib/agents/index.ts +245 -0
  140. package/.forge/worktrees/pipeline-4dd8dc2d/lib/agents/types.ts +70 -0
  141. package/.forge/worktrees/pipeline-4dd8dc2d/lib/artifacts.ts +106 -0
  142. package/.forge/worktrees/pipeline-4dd8dc2d/lib/auth.ts +62 -0
  143. package/.forge/worktrees/pipeline-4dd8dc2d/lib/builtin-plugins/docker.yaml +70 -0
  144. package/.forge/worktrees/pipeline-4dd8dc2d/lib/builtin-plugins/http.yaml +66 -0
  145. package/.forge/worktrees/pipeline-4dd8dc2d/lib/builtin-plugins/jenkins.yaml +92 -0
  146. package/.forge/worktrees/pipeline-4dd8dc2d/lib/builtin-plugins/llm-vision.yaml +85 -0
  147. package/.forge/worktrees/pipeline-4dd8dc2d/lib/builtin-plugins/playwright.yaml +111 -0
  148. package/.forge/worktrees/pipeline-4dd8dc2d/lib/builtin-plugins/shell-command.yaml +60 -0
  149. package/.forge/worktrees/pipeline-4dd8dc2d/lib/builtin-plugins/slack.yaml +48 -0
  150. package/.forge/worktrees/pipeline-4dd8dc2d/lib/builtin-plugins/webhook.yaml +56 -0
  151. package/.forge/worktrees/pipeline-4dd8dc2d/lib/claude-process.ts +361 -0
  152. package/.forge/worktrees/pipeline-4dd8dc2d/lib/claude-sessions.ts +266 -0
  153. package/.forge/worktrees/pipeline-4dd8dc2d/lib/claude-templates.ts +227 -0
  154. package/.forge/worktrees/pipeline-4dd8dc2d/lib/cloudflared.ts +424 -0
  155. package/.forge/worktrees/pipeline-4dd8dc2d/lib/crypto.ts +67 -0
  156. package/.forge/worktrees/pipeline-4dd8dc2d/lib/delivery.ts +787 -0
  157. package/.forge/worktrees/pipeline-4dd8dc2d/lib/dirs.ts +99 -0
  158. package/.forge/worktrees/pipeline-4dd8dc2d/lib/flows.ts +86 -0
  159. package/.forge/worktrees/pipeline-4dd8dc2d/lib/forge-mcp-server.ts +732 -0
  160. package/.forge/worktrees/pipeline-4dd8dc2d/lib/forge-skills/forge-inbox.md +38 -0
  161. package/.forge/worktrees/pipeline-4dd8dc2d/lib/forge-skills/forge-send.md +47 -0
  162. package/.forge/worktrees/pipeline-4dd8dc2d/lib/forge-skills/forge-status.md +32 -0
  163. package/.forge/worktrees/pipeline-4dd8dc2d/lib/forge-skills/forge-workspace-sync.md +37 -0
  164. package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/00-overview.md +40 -0
  165. package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/01-settings.md +194 -0
  166. package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/02-telegram.md +41 -0
  167. package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/03-tunnel.md +31 -0
  168. package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/04-tasks.md +52 -0
  169. package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/05-pipelines.md +460 -0
  170. package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/06-skills.md +43 -0
  171. package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/07-projects.md +73 -0
  172. package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/08-rules.md +53 -0
  173. package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/09-issue-autofix.md +55 -0
  174. package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/10-troubleshooting.md +89 -0
  175. package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/11-workspace.md +810 -0
  176. package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/CLAUDE.md +62 -0
  177. package/.forge/worktrees/pipeline-4dd8dc2d/lib/init.ts +266 -0
  178. package/.forge/worktrees/pipeline-4dd8dc2d/lib/issue-scanner.ts +298 -0
  179. package/.forge/worktrees/pipeline-4dd8dc2d/lib/logger.ts +79 -0
  180. package/.forge/worktrees/pipeline-4dd8dc2d/lib/notifications.ts +75 -0
  181. package/.forge/worktrees/pipeline-4dd8dc2d/lib/notify.ts +108 -0
  182. package/.forge/worktrees/pipeline-4dd8dc2d/lib/password.ts +97 -0
  183. package/.forge/worktrees/pipeline-4dd8dc2d/lib/pipeline-scheduler.ts +373 -0
  184. package/.forge/worktrees/pipeline-4dd8dc2d/lib/pipeline.ts +1565 -0
  185. package/.forge/worktrees/pipeline-4dd8dc2d/lib/plugins/executor.ts +347 -0
  186. package/.forge/worktrees/pipeline-4dd8dc2d/lib/plugins/registry.ts +228 -0
  187. package/.forge/worktrees/pipeline-4dd8dc2d/lib/plugins/types.ts +103 -0
  188. package/.forge/worktrees/pipeline-4dd8dc2d/lib/project-sessions.ts +53 -0
  189. package/.forge/worktrees/pipeline-4dd8dc2d/lib/projects.ts +86 -0
  190. package/.forge/worktrees/pipeline-4dd8dc2d/lib/session-manager.ts +156 -0
  191. package/.forge/worktrees/pipeline-4dd8dc2d/lib/session-utils.ts +53 -0
  192. package/.forge/worktrees/pipeline-4dd8dc2d/lib/session-watcher.ts +345 -0
  193. package/.forge/worktrees/pipeline-4dd8dc2d/lib/settings.ts +195 -0
  194. package/.forge/worktrees/pipeline-4dd8dc2d/lib/skills.ts +458 -0
  195. package/.forge/worktrees/pipeline-4dd8dc2d/lib/task-manager.ts +951 -0
  196. package/.forge/worktrees/pipeline-4dd8dc2d/lib/telegram-bot.ts +1477 -0
  197. package/.forge/worktrees/pipeline-4dd8dc2d/lib/telegram-standalone.ts +83 -0
  198. package/.forge/worktrees/pipeline-4dd8dc2d/lib/terminal-server.ts +70 -0
  199. package/.forge/worktrees/pipeline-4dd8dc2d/lib/terminal-standalone.ts +438 -0
  200. package/.forge/worktrees/pipeline-4dd8dc2d/lib/usage-scanner.ts +249 -0
  201. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/__tests__/state-machine.test.ts +388 -0
  202. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/__tests__/workspace.test.ts +311 -0
  203. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/agent-bus.ts +416 -0
  204. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/agent-worker.ts +655 -0
  205. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/backends/api-backend.ts +262 -0
  206. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/backends/cli-backend.ts +491 -0
  207. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/index.ts +84 -0
  208. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/manager.ts +136 -0
  209. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/orchestrator.ts +3415 -0
  210. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/persistence.ts +309 -0
  211. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/presets.ts +649 -0
  212. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/requests.ts +287 -0
  213. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/session-monitor.ts +240 -0
  214. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/skill-installer.ts +275 -0
  215. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/smith-memory.ts +498 -0
  216. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/types.ts +241 -0
  217. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/watch-manager.ts +560 -0
  218. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace-standalone.ts +978 -0
  219. package/.forge/worktrees/pipeline-4dd8dc2d/middleware.ts +51 -0
  220. package/.forge/worktrees/pipeline-4dd8dc2d/next.config.ts +26 -0
  221. package/.forge/worktrees/pipeline-4dd8dc2d/package.json +74 -0
  222. package/.forge/worktrees/pipeline-4dd8dc2d/pnpm-lock.yaml +3719 -0
  223. package/.forge/worktrees/pipeline-4dd8dc2d/pnpm-workspace.yaml +1 -0
  224. package/.forge/worktrees/pipeline-4dd8dc2d/postcss.config.mjs +7 -0
  225. package/.forge/worktrees/pipeline-4dd8dc2d/publish.sh +133 -0
  226. package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/README.md +66 -0
  227. package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/results/.gitignore +2 -0
  228. package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/run.ts +635 -0
  229. package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/tasks/01-text-utils/task.md +26 -0
  230. package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/tasks/01-text-utils/validator.sh +46 -0
  231. package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/tasks/02-pagination/setup.sh +19 -0
  232. package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/tasks/02-pagination/task.md +48 -0
  233. package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/tasks/02-pagination/validator.sh +69 -0
  234. package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/tasks/03-bug-fix/setup.sh +82 -0
  235. package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/tasks/03-bug-fix/task.md +30 -0
  236. package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/tasks/03-bug-fix/validator.sh +29 -0
  237. package/.forge/worktrees/pipeline-4dd8dc2d/scripts/verify-usage.ts +178 -0
  238. package/.forge/worktrees/pipeline-4dd8dc2d/src/config/index.ts +129 -0
  239. package/.forge/worktrees/pipeline-4dd8dc2d/src/core/db/database.ts +259 -0
  240. package/.forge/worktrees/pipeline-4dd8dc2d/src/core/memory/strategy.ts +32 -0
  241. package/.forge/worktrees/pipeline-4dd8dc2d/src/core/providers/chat.ts +65 -0
  242. package/.forge/worktrees/pipeline-4dd8dc2d/src/core/providers/registry.ts +60 -0
  243. package/.forge/worktrees/pipeline-4dd8dc2d/src/core/session/manager.ts +190 -0
  244. package/.forge/worktrees/pipeline-4dd8dc2d/src/types/index.ts +129 -0
  245. package/.forge/worktrees/pipeline-4dd8dc2d/start.sh +32 -0
  246. package/.forge/worktrees/pipeline-4dd8dc2d/templates/smith-lead.json +45 -0
  247. package/.forge/worktrees/pipeline-4dd8dc2d/tsconfig.json +42 -0
  248. package/RELEASE_NOTES.md +11 -28
  249. package/app/api/terminal-bell/route.ts +6 -2
  250. package/components/WebTerminal.tsx +36 -2
  251. package/lib/terminal-standalone.ts +19 -2
  252. package/next-env.d.ts +1 -1
  253. package/package.json +1 -1
@@ -0,0 +1,787 @@
1
+ /**
2
+ * Delivery Engine — multi-agent orchestrated software delivery.
3
+ *
4
+ * Phases: Analyze → Implement → Test → Review
5
+ * Each phase runs as one or more Tasks via the existing task system.
6
+ * Artifacts (structured documents) pass between phases.
7
+ * Completely independent from the pipeline system.
8
+ */
9
+
10
+ import { randomUUID } from 'node:crypto';
11
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync, rmSync } from 'node:fs';
12
+ import { join } from 'node:path';
13
+ import { createTask, getTask, onTaskEvent } from './task-manager';
14
+ import { getProjectInfo } from './projects';
15
+ import { loadSettings } from './settings';
16
+ import { createArtifact, listArtifacts, extractArtifacts, writeArtifactToProject } from './artifacts';
17
+ import type { Artifact, ArtifactType } from './artifacts';
18
+ import { getDataDir } from './dirs';
19
+
20
+ const DELIVERIES_DIR = join(getDataDir(), 'deliveries');
21
+
22
+ function ensureDir() {
23
+ if (!existsSync(DELIVERIES_DIR)) mkdirSync(DELIVERIES_DIR, { recursive: true });
24
+ }
25
+
26
+ // ─── Types ────────────────────────────────────────────────
27
+
28
+ export type PhaseName = 'analyze' | 'implement' | 'test' | 'review';
29
+ export type PhaseStatus = 'pending' | 'waiting_human' | 'running' | 'done' | 'failed' | 'skipped';
30
+
31
+ export interface DeliveryPhase {
32
+ name: PhaseName;
33
+ status: PhaseStatus;
34
+ agentRole: string;
35
+ agentId: string; // agent registry ID
36
+ taskIds: string[];
37
+ inputArtifactTypes: ArtifactType[]; // which artifact types this phase consumes
38
+ outputArtifactIds: string[];
39
+ startedAt?: string;
40
+ completedAt?: string;
41
+ error?: string;
42
+ interactions: { from: string; message: string; taskId?: string; timestamp: string }[];
43
+ // Custom metadata (from user-defined phases)
44
+ _waitForHuman?: boolean;
45
+ _label?: string;
46
+ _icon?: string;
47
+ _outputArtifactName?: string;
48
+ _outputArtifactType?: ArtifactType;
49
+ // Requires-driven scheduling
50
+ _requires?: string[]; // artifact names needed before this phase can start
51
+ _produces?: string[]; // artifact names this phase outputs (including references)
52
+ }
53
+
54
+ export interface Delivery {
55
+ id: string;
56
+ title: string;
57
+ status: 'running' | 'paused' | 'done' | 'failed' | 'cancelled';
58
+ input: {
59
+ prUrl?: string;
60
+ description?: string;
61
+ project: string;
62
+ projectPath: string;
63
+ };
64
+ phases: DeliveryPhase[];
65
+ currentPhaseIndex: number;
66
+ createdAt: string;
67
+ completedAt?: string;
68
+ }
69
+
70
+ // ─── Persistence ──────────────────────────────────────────
71
+
72
+ function deliveryPath(id: string): string {
73
+ return join(DELIVERIES_DIR, id, 'delivery.json');
74
+ }
75
+
76
+ function saveDelivery(d: Delivery): void {
77
+ ensureDir();
78
+ const dir = join(DELIVERIES_DIR, d.id);
79
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
80
+ writeFileSync(deliveryPath(d.id), JSON.stringify(d, null, 2));
81
+ }
82
+
83
+ export function getDelivery(id: string): Delivery | null {
84
+ try {
85
+ return JSON.parse(readFileSync(deliveryPath(id), 'utf-8'));
86
+ } catch { return null; }
87
+ }
88
+
89
+ export function listDeliveries(): Delivery[] {
90
+ ensureDir();
91
+ const dirs = readdirSync(DELIVERIES_DIR, { withFileTypes: true })
92
+ .filter(d => d.isDirectory())
93
+ .map(d => d.name);
94
+
95
+ return dirs
96
+ .map(id => getDelivery(id))
97
+ .filter(Boolean)
98
+ .sort((a, b) => b!.createdAt.localeCompare(a!.createdAt)) as Delivery[];
99
+ }
100
+
101
+ export function deleteDelivery(id: string): boolean {
102
+ const dir = join(DELIVERIES_DIR, id);
103
+ if (!existsSync(dir)) return false;
104
+ try { rmSync(dir, { recursive: true }); return true; } catch { return false; }
105
+ }
106
+
107
+ // ─── Default Phase Configs ────────────────────────────────
108
+
109
+ const DEFAULT_PHASES: Omit<DeliveryPhase, 'agentId'>[] = [
110
+ {
111
+ name: 'analyze',
112
+ status: 'pending',
113
+ agentRole: `You are a Product Manager. Analyze the requirements and produce a structured requirements document.
114
+
115
+ Your tasks:
116
+ 1. Read the input (PR, description, or project code)
117
+ 2. Break down into clear functional requirements
118
+ 3. Identify edge cases and dependencies
119
+ 4. Output the requirements document
120
+
121
+ Output your analysis between artifact markers:
122
+ ===ARTIFACT:requirements.md===
123
+ # Requirements
124
+ ## Overview
125
+ ...
126
+ ## Functional Requirements
127
+ 1. ...
128
+ ## Edge Cases
129
+ ...
130
+ ===ARTIFACT:requirements.md===`,
131
+ taskIds: [],
132
+ inputArtifactTypes: [],
133
+ outputArtifactIds: [],
134
+ interactions: [],
135
+ },
136
+ {
137
+ name: 'implement',
138
+ status: 'pending',
139
+ agentRole: `You are a Senior Software Engineer. Based on the requirements, design the architecture and implement the solution.
140
+
141
+ Your tasks:
142
+ 1. Read the requirements document
143
+ 2. Design the architecture (modules, interfaces, data flow)
144
+ 3. Implement each module
145
+ 4. Commit your changes
146
+
147
+ Output your architecture document between artifact markers:
148
+ ===ARTIFACT:architecture.md===
149
+ # Architecture Design
150
+ ## Overview
151
+ ...
152
+ ## Modules
153
+ ...
154
+ ## Implementation Notes
155
+ ...
156
+ ===ARTIFACT:architecture.md===`,
157
+ taskIds: [],
158
+ inputArtifactTypes: ['requirements'],
159
+ outputArtifactIds: [],
160
+ interactions: [],
161
+ },
162
+ {
163
+ name: 'test',
164
+ status: 'pending',
165
+ agentRole: `You are a QA Engineer. Based on the requirements and architecture, design and run tests.
166
+
167
+ Your tasks:
168
+ 1. Read the requirements and architecture documents
169
+ 2. Design test cases covering all requirements
170
+ 3. Write and run the tests
171
+ 4. Report results
172
+
173
+ Output your test plan between artifact markers:
174
+ ===ARTIFACT:test-plan.md===
175
+ # Test Plan
176
+ ## Test Cases
177
+ 1. ...
178
+ ## Results
179
+ ...
180
+ ===ARTIFACT:test-plan.md===`,
181
+ taskIds: [],
182
+ inputArtifactTypes: ['requirements', 'architecture'],
183
+ outputArtifactIds: [],
184
+ interactions: [],
185
+ },
186
+ {
187
+ name: 'review',
188
+ status: 'pending',
189
+ agentRole: `You are a Code Reviewer. Review the entire delivery: requirements, architecture, implementation, and test results.
190
+
191
+ Your tasks:
192
+ 1. Read all artifacts from previous phases
193
+ 2. Review code changes (git diff)
194
+ 3. Check if requirements are met
195
+ 4. Check test coverage
196
+ 5. Approve or request changes
197
+
198
+ Output your review between artifact markers:
199
+ ===ARTIFACT:review-report.md===
200
+ # Review Report
201
+ ## Status: APPROVED / CHANGES_REQUESTED
202
+ ## Findings
203
+ ...
204
+ ## Verdict
205
+ ...
206
+ ===ARTIFACT:review-report.md===`,
207
+ taskIds: [],
208
+ inputArtifactTypes: ['requirements', 'architecture', 'test-plan', 'code-diff'],
209
+ outputArtifactIds: [],
210
+ interactions: [],
211
+ },
212
+ ];
213
+
214
+ // ─── Role Presets ─────────────────────────────────────────
215
+
216
+ export interface RolePreset {
217
+ id: string;
218
+ label: string;
219
+ icon: string;
220
+ role: string;
221
+ inputArtifactTypes: ArtifactType[];
222
+ outputArtifactName: string;
223
+ outputArtifactType: ArtifactType;
224
+ waitForHuman?: boolean; // pause after completion for approval
225
+ }
226
+
227
+ export const ROLE_PRESETS: RolePreset[] = [
228
+ {
229
+ id: 'pm', label: 'PM - Analyze', icon: '📋',
230
+ role: 'You are a Product Manager. Analyze the requirements, break down into modules, identify edge cases.',
231
+ inputArtifactTypes: [],
232
+ outputArtifactName: 'requirements.md', outputArtifactType: 'requirements',
233
+ waitForHuman: true,
234
+ },
235
+ {
236
+ id: 'engineer', label: 'Engineer - Implement', icon: '🔨',
237
+ role: 'You are a Senior Engineer. Design the architecture and implement the solution based on the requirements.',
238
+ inputArtifactTypes: ['requirements'],
239
+ outputArtifactName: 'architecture.md', outputArtifactType: 'architecture',
240
+ },
241
+ {
242
+ id: 'qa', label: 'QA - Test', icon: '🧪',
243
+ role: 'You are a QA Engineer. Design test cases from the requirements and architecture, then run them.',
244
+ inputArtifactTypes: ['requirements', 'architecture'],
245
+ outputArtifactName: 'test-plan.md', outputArtifactType: 'test-plan',
246
+ },
247
+ {
248
+ id: 'reviewer', label: 'Reviewer', icon: '🔍',
249
+ role: 'You are a Code Reviewer. Review all artifacts, check code quality, approve or request changes.',
250
+ inputArtifactTypes: ['requirements', 'architecture', 'test-plan', 'code-diff'],
251
+ outputArtifactName: 'review-report.md', outputArtifactType: 'review-report',
252
+ },
253
+ {
254
+ id: 'devops', label: 'DevOps - Deploy', icon: '🚀',
255
+ role: 'You are a DevOps engineer. Set up CI/CD, deployment configs, and infrastructure.',
256
+ inputArtifactTypes: ['architecture'],
257
+ outputArtifactName: 'deploy-plan.md', outputArtifactType: 'custom',
258
+ },
259
+ {
260
+ id: 'security', label: 'Security Audit', icon: '🔒',
261
+ role: 'You are a security auditor. Review code for vulnerabilities, check OWASP top 10, suggest fixes.',
262
+ inputArtifactTypes: ['architecture', 'code-diff'],
263
+ outputArtifactName: 'security-report.md', outputArtifactType: 'review-report',
264
+ },
265
+ {
266
+ id: 'docs', label: 'Tech Writer - Docs', icon: '📝',
267
+ role: 'You are a technical writer. Write API documentation, README updates, and user guides based on the implementation.',
268
+ inputArtifactTypes: ['requirements', 'architecture'],
269
+ outputArtifactName: 'documentation.md', outputArtifactType: 'custom',
270
+ },
271
+ ];
272
+
273
+ function buildPhasePrompt(p: PhaseInput): string {
274
+ let prompt = p.role;
275
+ prompt += `\n\nOutput your result between artifact markers:\n===ARTIFACT:${p.outputArtifactName}===\n(your output here)\n===ARTIFACT:${p.outputArtifactName}===`;
276
+ return prompt;
277
+ }
278
+
279
+ /** User-defined phase input for creating a delivery */
280
+ export interface PhaseInput {
281
+ name: string; // unique id within this delivery
282
+ label: string;
283
+ icon: string;
284
+ role: string;
285
+ agentId: string;
286
+ inputArtifactTypes: ArtifactType[];
287
+ outputArtifactName: string;
288
+ outputArtifactType: ArtifactType;
289
+ waitForHuman?: boolean;
290
+ requires?: string[]; // artifact names needed (auto-derived from edges)
291
+ produces?: string[]; // artifact names produced (derived from outputArtifactName + extras)
292
+ }
293
+
294
+ // ─── Create Delivery ──────────────────────────────────────
295
+
296
+ export function createDelivery(opts: {
297
+ title: string;
298
+ project: string;
299
+ projectPath: string;
300
+ prUrl?: string;
301
+ description?: string;
302
+ agentId?: string; // default agent for all phases
303
+ customPhases?: PhaseInput[]; // user-defined phases (overrides defaults)
304
+ }): Delivery {
305
+ const id = randomUUID().slice(0, 8);
306
+ const defaultAgentId = opts.agentId || loadSettings().defaultAgent || 'claude';
307
+
308
+ let phases: DeliveryPhase[];
309
+
310
+ if (opts.customPhases && opts.customPhases.length > 0) {
311
+ // Custom phases from user
312
+ phases = opts.customPhases.map(p => ({
313
+ name: p.name as PhaseName,
314
+ status: 'pending' as PhaseStatus,
315
+ agentRole: buildPhasePrompt(p),
316
+ agentId: p.agentId || defaultAgentId,
317
+ taskIds: [],
318
+ inputArtifactTypes: p.inputArtifactTypes,
319
+ outputArtifactIds: [],
320
+ interactions: [],
321
+ _waitForHuman: p.waitForHuman,
322
+ _label: p.label,
323
+ _icon: p.icon,
324
+ _outputArtifactName: p.outputArtifactName,
325
+ _outputArtifactType: p.outputArtifactType,
326
+ _requires: p.requires || [],
327
+ _produces: p.produces || [p.outputArtifactName],
328
+ }));
329
+ } else {
330
+ // Default 4-phase with requires derived from presets
331
+ phases = DEFAULT_PHASES.map((p, i) => {
332
+ const preset = ROLE_PRESETS.find(r => r.id === p.name) || ROLE_PRESETS[i];
333
+ // Derive requires from inputArtifactTypes → match other presets' outputArtifactName
334
+ const requires: string[] = [];
335
+ for (const needType of p.inputArtifactTypes) {
336
+ const provider = ROLE_PRESETS.find(r => r.outputArtifactType === needType);
337
+ if (provider) requires.push(provider.outputArtifactName);
338
+ }
339
+ return {
340
+ ...p,
341
+ agentId: defaultAgentId,
342
+ taskIds: [],
343
+ outputArtifactIds: [],
344
+ interactions: [],
345
+ _requires: requires,
346
+ _produces: [preset?.outputArtifactName || `${p.name}-output.md`],
347
+ _outputArtifactName: preset?.outputArtifactName || `${p.name}-output.md`,
348
+ _outputArtifactType: preset?.outputArtifactType,
349
+ _label: preset?.label,
350
+ _icon: preset?.icon,
351
+ };
352
+ });
353
+ }
354
+
355
+ const delivery: Delivery = {
356
+ id,
357
+ title: opts.title,
358
+ status: 'running',
359
+ input: {
360
+ project: opts.project,
361
+ projectPath: opts.projectPath,
362
+ prUrl: opts.prUrl,
363
+ description: opts.description,
364
+ },
365
+ phases,
366
+ currentPhaseIndex: 0,
367
+ createdAt: new Date().toISOString(),
368
+ };
369
+
370
+ saveDelivery(delivery);
371
+
372
+ // Start all phases whose requires are already met (typically the first one)
373
+ scheduleReadyPhases(delivery);
374
+
375
+ return delivery;
376
+ }
377
+
378
+ // ─── Standard Prompt Builder (Envelope Format) ───────────
379
+
380
+ function buildStandardPrompt(
381
+ delivery: Delivery,
382
+ phase: DeliveryPhase,
383
+ phaseIndex: number,
384
+ inputArtifacts: Artifact[],
385
+ ): string {
386
+ const sections: string[] = [];
387
+
388
+ // 1. Role
389
+ sections.push(`===ROLE===\n${phase.agentRole}\n===END===`);
390
+
391
+ // 2. Context — always present
392
+ sections.push(`===CONTEXT===
393
+ Project: ${delivery.input.project} (${delivery.input.projectPath})
394
+ Delivery: ${delivery.title}
395
+ Phase: ${phase._label || phase.name} (${phaseIndex + 1}/${delivery.phases.length})${delivery.input.prUrl ? `\nPR: ${delivery.input.prUrl}` : ''}${delivery.input.description ? `\nTask: ${delivery.input.description}` : ''}
396
+ ===END===`);
397
+
398
+ // 3. Input artifacts — from upstream agents
399
+ if (inputArtifacts.length > 0) {
400
+ for (const a of inputArtifacts) {
401
+ // Skip request/response audit records
402
+ if (a.name.includes('-request-') || a.name.includes('-response-')) continue;
403
+ sections.push(`===INPUT:${a.name} (from: ${a.producedBy})===\n${a.content}\n===END===`);
404
+ }
405
+ }
406
+
407
+ // 4. Feedback — from user or other agents
408
+ if (phase.interactions.length > 0) {
409
+ for (const inter of phase.interactions) {
410
+ sections.push(`===FEEDBACK:${inter.from}===\n${inter.message}\n===END===`);
411
+ }
412
+ }
413
+
414
+ // 5. Output instructions
415
+ const outputName = phase._outputArtifactName || `${phase.name}-output.md`;
416
+ sections.push(`===OUTPUT_FORMAT===
417
+ Produce your output between these markers:
418
+ ===ARTIFACT:${outputName}===
419
+ (your structured output here)
420
+ ===ARTIFACT:${outputName}===
421
+
422
+ You MUST include the artifact markers. The content between markers will be saved as "${outputName}" and passed to downstream agents.
423
+ ===END===`);
424
+
425
+ return sections.join('\n\n');
426
+ }
427
+
428
+ // ─── Phase Dispatch ───────────────────────────────────────
429
+
430
+ function dispatchPhase(delivery: Delivery, phaseIndex: number): void {
431
+ const phase = delivery.phases[phaseIndex];
432
+ if (!phase || phase.status === 'done') return;
433
+
434
+ const projectInfo = getProjectInfo(delivery.input.project);
435
+ if (!projectInfo) {
436
+ phase.status = 'failed';
437
+ phase.error = `Project not found: ${delivery.input.project}`;
438
+ saveDelivery(delivery);
439
+ return;
440
+ }
441
+
442
+ // Build standardized prompt with envelope format
443
+ const allArtifacts = listArtifacts(delivery.id);
444
+ const requires = phase._requires || [];
445
+
446
+ // Collect relevant artifacts: match by requires (artifact names from edges)
447
+ const relevantArtifacts: Artifact[] = [];
448
+ const seen = new Set<string>();
449
+
450
+ // First: artifacts matching requires by name
451
+ for (const reqName of requires) {
452
+ // Find the latest artifact with this name (not request/response audit records)
453
+ const matches = allArtifacts
454
+ .filter(a => a.name === reqName && !a.name.includes('-request-') && !a.name.includes('-response-'))
455
+ .sort((a, b) => b.createdAt.localeCompare(a.createdAt));
456
+ if (matches[0] && !seen.has(matches[0].id)) {
457
+ relevantArtifacts.push(matches[0]);
458
+ seen.add(matches[0].id);
459
+ }
460
+ }
461
+
462
+ // Fallback: also include by inputArtifactTypes (backward compat with presets)
463
+ for (const a of allArtifacts) {
464
+ if (seen.has(a.id)) continue;
465
+ if (a.name.includes('-request-') || a.name.includes('-response-')) continue;
466
+ if (phase.inputArtifactTypes.includes(a.type)) {
467
+ relevantArtifacts.push(a);
468
+ seen.add(a.id);
469
+ }
470
+ }
471
+
472
+ const prompt = buildStandardPrompt(delivery, phase, phaseIndex, relevantArtifacts);
473
+
474
+ // Record the request as an artifact for audit trail
475
+ createArtifact(delivery.id, {
476
+ type: 'custom',
477
+ name: `${phase.name}-request-${phase.taskIds.length + 1}.md`,
478
+ content: prompt,
479
+ producedBy: 'system',
480
+ });
481
+
482
+ // Create task
483
+ const task = createTask({
484
+ projectName: projectInfo.name,
485
+ projectPath: projectInfo.path,
486
+ prompt,
487
+ mode: 'prompt',
488
+ agent: phase.agentId || undefined,
489
+ conversationId: '', // fresh session
490
+ });
491
+
492
+ phase.status = 'running';
493
+ phase.taskIds.push(task.id);
494
+ phase.startedAt = phase.startedAt || new Date().toISOString();
495
+ delivery.currentPhaseIndex = phaseIndex;
496
+ saveDelivery(delivery);
497
+
498
+ // Listen for completion
499
+ setupDeliveryTaskListener(delivery.id, task.id, phaseIndex);
500
+ }
501
+
502
+ // ─── Task Completion Handler ──────────────────────────────
503
+
504
+ function setupDeliveryTaskListener(deliveryId: string, taskId: string, phaseIndex: number): void {
505
+ const cleanup = onTaskEvent((evtTaskId, event, data) => {
506
+ if (evtTaskId !== taskId) return;
507
+ if (event !== 'status') return;
508
+ if (data !== 'done' && data !== 'failed') return;
509
+
510
+ cleanup();
511
+
512
+ const delivery = getDelivery(deliveryId);
513
+ if (!delivery || delivery.status !== 'running') return;
514
+
515
+ const phase = delivery.phases[phaseIndex];
516
+ if (!phase) return;
517
+
518
+ const task = getTask(taskId);
519
+
520
+ if (data === 'failed' || !task) {
521
+ // Record failed response
522
+ createArtifact(deliveryId, {
523
+ type: 'custom',
524
+ name: `${phase.name}-response-${phase.taskIds.length}-failed.md`,
525
+ content: task?.error || 'Task failed',
526
+ producedBy: phase.name,
527
+ });
528
+ phase.status = 'failed';
529
+ phase.error = task?.error || 'Task failed';
530
+ phase.completedAt = new Date().toISOString();
531
+ delivery.status = 'failed';
532
+ delivery.completedAt = new Date().toISOString();
533
+ saveDelivery(delivery);
534
+ return;
535
+ }
536
+
537
+ // Record response as artifact for audit trail
538
+ const output = task.resultSummary || '';
539
+ createArtifact(deliveryId, {
540
+ type: 'custom',
541
+ name: `${phase.name}-response-${phase.taskIds.length}.md`,
542
+ content: output,
543
+ producedBy: phase.name,
544
+ });
545
+ const extracted = extractArtifacts(output, deliveryId, phase.name);
546
+
547
+ // If no structured artifacts found, create a fallback from the full output
548
+ if (extracted.length === 0 && output.trim()) {
549
+ const fallbackName = phase._outputArtifactName || `${phase.name}-output.md`;
550
+ const fallbackType: ArtifactType = phase._outputArtifactType ||
551
+ (phase.name === 'analyze' ? 'requirements' :
552
+ phase.name === 'implement' ? 'architecture' :
553
+ phase.name === 'test' ? 'test-plan' :
554
+ phase.name === 'review' ? 'review-report' : 'custom');
555
+
556
+ const fallback = createArtifact(deliveryId, {
557
+ type: fallbackType,
558
+ name: fallbackName,
559
+ content: output,
560
+ producedBy: phase.name,
561
+ });
562
+ extracted.push(fallback);
563
+ }
564
+
565
+ phase.outputArtifactIds.push(...extracted.map(a => a.id));
566
+
567
+ // Write artifacts to project directory
568
+ for (const a of extracted) {
569
+ try { writeArtifactToProject(a, delivery.input.projectPath); } catch {}
570
+ }
571
+
572
+ // Wait for human approval if configured (default: analyze phase)
573
+ const needsHumanApproval = phase._waitForHuman !== undefined ? phase._waitForHuman : phase.name === 'analyze';
574
+ if (needsHumanApproval) {
575
+ phase.status = 'waiting_human';
576
+ saveDelivery(delivery);
577
+ return;
578
+ }
579
+
580
+ // Other phases: mark done and advance
581
+ phase.status = 'done';
582
+ phase.completedAt = new Date().toISOString();
583
+ saveDelivery(delivery);
584
+
585
+ scheduleReadyPhases(delivery);
586
+ });
587
+ }
588
+
589
+ /**
590
+ * Requires-driven scheduling: check all pending phases,
591
+ * start any whose required artifacts are now available.
592
+ */
593
+ function scheduleReadyPhases(delivery: Delivery): void {
594
+ // Collect all produced artifact names so far
595
+ const allArtifacts = listArtifacts(delivery.id);
596
+ const producedNames = new Set(
597
+ allArtifacts
598
+ .filter(a => !a.name.includes('-request-') && !a.name.includes('-response-'))
599
+ .map(a => a.name)
600
+ );
601
+
602
+ let anyStarted = false;
603
+
604
+ for (let i = 0; i < delivery.phases.length; i++) {
605
+ const phase = delivery.phases[i];
606
+ if (phase.status !== 'pending') continue;
607
+
608
+ const requires = phase._requires || [];
609
+
610
+ // Check if all required artifacts exist
611
+ const satisfied = requires.length === 0 || requires.every(name => producedNames.has(name));
612
+
613
+ if (satisfied) {
614
+ dispatchPhase(delivery, i);
615
+ anyStarted = true;
616
+ }
617
+ }
618
+
619
+ // If nothing started and no phase is running/waiting, delivery is complete
620
+ if (!anyStarted) {
621
+ const allDone = delivery.phases.every(p =>
622
+ p.status === 'done' || p.status === 'failed' || p.status === 'skipped'
623
+ );
624
+ if (allDone) {
625
+ const anyFailed = delivery.phases.some(p => p.status === 'failed');
626
+ delivery.status = anyFailed ? 'failed' : 'done';
627
+ delivery.completedAt = new Date().toISOString();
628
+ saveDelivery(delivery);
629
+ }
630
+ }
631
+ }
632
+
633
+ // ─── Human Approval (Analyze phase) ──────────────────────
634
+
635
+ export function approveDeliveryPhase(deliveryId: string, feedback?: string): boolean {
636
+ const delivery = getDelivery(deliveryId);
637
+ if (!delivery) return false;
638
+
639
+ // Find any phase waiting for human approval
640
+ const waitingPhase = delivery.phases.find(p => p.status === 'waiting_human');
641
+ if (!waitingPhase) return false;
642
+
643
+ if (feedback) {
644
+ waitingPhase.interactions.push({
645
+ from: 'user',
646
+ message: feedback,
647
+ timestamp: new Date().toISOString(),
648
+ });
649
+ }
650
+
651
+ waitingPhase.status = 'done';
652
+ waitingPhase.completedAt = new Date().toISOString();
653
+ saveDelivery(delivery);
654
+
655
+ scheduleReadyPhases(delivery);
656
+ return true;
657
+ }
658
+
659
+ export function rejectDeliveryPhase(deliveryId: string, feedback: string): boolean {
660
+ const delivery = getDelivery(deliveryId);
661
+ if (!delivery) return false;
662
+
663
+ const waitingPhase = delivery.phases.find(p => p.status === 'waiting_human');
664
+ if (!waitingPhase) return false;
665
+
666
+ const phaseIndex = delivery.phases.indexOf(waitingPhase);
667
+ waitingPhase.interactions.push({
668
+ from: 'user',
669
+ message: `REJECTED: ${feedback}`,
670
+ timestamp: new Date().toISOString(),
671
+ });
672
+
673
+ // Re-run the phase with feedback
674
+ waitingPhase.status = 'pending';
675
+ saveDelivery(delivery);
676
+
677
+ dispatchPhase(delivery, phaseIndex);
678
+ return true;
679
+ }
680
+
681
+ // ─── Send Message to Agent ────────────────────────────────
682
+
683
+ export function sendToAgent(deliveryId: string, phaseName: PhaseName, message: string): boolean {
684
+ const delivery = getDelivery(deliveryId);
685
+ if (!delivery || delivery.status !== 'running') return false;
686
+
687
+ const phaseIndex = delivery.phases.findIndex(p => p.name === phaseName);
688
+ const phase = delivery.phases[phaseIndex];
689
+ if (!phase) return false;
690
+
691
+ phase.interactions.push({
692
+ from: 'user',
693
+ message,
694
+ timestamp: new Date().toISOString(),
695
+ });
696
+ saveDelivery(delivery);
697
+
698
+ // If the phase is idle (done or waiting), dispatch a new task with the message
699
+ if (phase.status === 'done' || phase.status === 'waiting_human') {
700
+ phase.status = 'pending';
701
+ saveDelivery(delivery);
702
+ dispatchPhase(delivery, phaseIndex);
703
+ return true;
704
+ }
705
+
706
+ // If running, the message will be visible in next interaction
707
+ return true;
708
+ }
709
+
710
+ // ─── Cancel ───────────────────────────────────────────────
711
+
712
+ export function cancelDelivery(id: string): boolean {
713
+ const delivery = getDelivery(id);
714
+ if (!delivery || delivery.status !== 'running') return false;
715
+
716
+ for (const phase of delivery.phases) {
717
+ if (phase.status === 'running') {
718
+ // Cancel running tasks
719
+ for (const taskId of phase.taskIds) {
720
+ try { const { cancelTask } = require('./task-manager'); cancelTask(taskId); } catch {}
721
+ }
722
+ phase.status = 'failed';
723
+ }
724
+ if (phase.status === 'pending' || phase.status === 'waiting_human') {
725
+ phase.status = 'skipped';
726
+ }
727
+ }
728
+
729
+ delivery.status = 'cancelled';
730
+ delivery.completedAt = new Date().toISOString();
731
+ saveDelivery(delivery);
732
+ return true;
733
+ }
734
+
735
+ // ─── Retry Phase ──────────────────────────────────────────
736
+
737
+ export function retryPhase(deliveryId: string, phaseName: PhaseName): boolean {
738
+ const delivery = getDelivery(deliveryId);
739
+ if (!delivery) return false;
740
+
741
+ const phaseIndex = delivery.phases.findIndex(p => p.name === phaseName);
742
+ const phase = delivery.phases[phaseIndex];
743
+ if (!phase || phase.status === 'running') return false;
744
+
745
+ phase.status = 'pending';
746
+ phase.error = undefined;
747
+ delivery.status = 'running';
748
+ delivery.completedAt = undefined;
749
+ saveDelivery(delivery);
750
+
751
+ dispatchPhase(delivery, phaseIndex);
752
+ return true;
753
+ }
754
+
755
+ // ─── Recovery ─────────────────────────────────────────────
756
+
757
+ function recoverStuckDeliveries(): void {
758
+ try {
759
+ const deliveries = listDeliveries().filter(d => d.status === 'running');
760
+ for (const delivery of deliveries) {
761
+ for (let i = 0; i < delivery.phases.length; i++) {
762
+ const phase = delivery.phases[i];
763
+ if (phase.status !== 'running') continue;
764
+
765
+ const lastTaskId = phase.taskIds[phase.taskIds.length - 1];
766
+ if (!lastTaskId) continue;
767
+
768
+ const task = getTask(lastTaskId);
769
+ if (!task) {
770
+ phase.status = 'failed';
771
+ phase.error = 'Task not found (cleaned up)';
772
+ phase.completedAt = new Date().toISOString();
773
+ saveDelivery(delivery);
774
+ } else if (task.status === 'done' || task.status === 'failed') {
775
+ // Task finished but we missed the event — re-process
776
+ setupDeliveryTaskListener(delivery.id, lastTaskId, i);
777
+ } else {
778
+ // Still running — re-attach listener
779
+ setupDeliveryTaskListener(delivery.id, lastTaskId, i);
780
+ }
781
+ }
782
+ }
783
+ } catch {}
784
+ }
785
+
786
+ setInterval(recoverStuckDeliveries, 30_000);
787
+ setTimeout(recoverStuckDeliveries, 5000);