@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.
- package/.forge/worktrees/pipeline-4dd8dc2d/CLAUDE.md +86 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/README.md +136 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/RELEASE_NOTES.md +36 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/agents/route.ts +17 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/auth/[...nextauth]/route.ts +3 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/auth/verify/route.ts +46 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/claude/[id]/route.ts +31 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/claude/[id]/stream/route.ts +63 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/claude/route.ts +28 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/claude-sessions/[projectName]/entries/route.ts +23 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/claude-sessions/[projectName]/live/route.ts +72 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/claude-sessions/[projectName]/route.ts +37 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/claude-sessions/sync/route.ts +17 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/claude-templates/route.ts +145 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/code/route.ts +299 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/delivery/[id]/route.ts +62 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/delivery/route.ts +40 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/detect-cli/route.ts +46 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/docs/route.ts +176 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/docs/sessions/route.ts +54 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/favorites/route.ts +26 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/flows/route.ts +6 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/flows/run/route.ts +19 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/git/route.ts +149 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/help/route.ts +84 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/issue-scanner/route.ts +116 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/logs/route.ts +100 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/mobile-chat/route.ts +115 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/monitor/route.ts +74 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/notifications/route.ts +42 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/notify/test/route.ts +33 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/online/route.ts +40 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/pipelines/[id]/route.ts +41 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/pipelines/route.ts +90 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/plugins/route.ts +75 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/preview/[...path]/route.ts +64 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/preview/route.ts +156 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/project-pipelines/route.ts +91 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/project-sessions/route.ts +61 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/projects/route.ts +26 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/sessions/[id]/chat/route.ts +64 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/sessions/[id]/messages/route.ts +9 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/sessions/[id]/route.ts +17 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/sessions/route.ts +20 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/settings/route.ts +64 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/skills/local/route.ts +228 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/skills/route.ts +182 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/smith-templates/route.ts +81 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/status/route.ts +12 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/tabs/route.ts +25 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/tasks/[id]/route.ts +51 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/tasks/[id]/stream/route.ts +77 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/tasks/link/route.ts +37 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/tasks/route.ts +44 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/tasks/session/route.ts +14 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/telegram/route.ts +23 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/templates/route.ts +6 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/terminal-bell/route.ts +39 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/terminal-cwd/route.ts +19 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/terminal-state/route.ts +15 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/tunnel/route.ts +26 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/upgrade/route.ts +43 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/usage/route.ts +20 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/version/route.ts +78 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/watchers/route.ts +33 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/workspace/[id]/agents/route.ts +35 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/workspace/[id]/memory/route.ts +23 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/workspace/[id]/smith/route.ts +22 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/workspace/[id]/stream/route.ts +31 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/workspace/route.ts +79 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/global-error.tsx +21 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/globals.css +52 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/icon.ico +0 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/icon.png +0 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/icon.svg +106 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/layout.tsx +17 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/login/LoginForm.tsx +96 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/login/page.tsx +10 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/mobile/page.tsx +10 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/page.tsx +22 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/bin/forge-server.mjs +484 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/check-forge-status.sh +71 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/cli/mw.ts +579 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/BrowserPanel.tsx +175 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/ChatPanel.tsx +191 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/ClaudeTerminal.tsx +267 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/CodeViewer.tsx +787 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/ConversationEditor.tsx +411 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/ConversationGraphView.tsx +347 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/ConversationTerminalView.tsx +303 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/Dashboard.tsx +807 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/DashboardWrapper.tsx +9 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/DeliveryFlowEditor.tsx +491 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/DeliveryList.tsx +230 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/DeliveryWorkspace.tsx +589 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/DocTerminal.tsx +187 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/DocsViewer.tsx +574 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/HelpDialog.tsx +169 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/HelpTerminal.tsx +141 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/InlinePipelineView.tsx +111 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/LogViewer.tsx +194 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/MarkdownContent.tsx +73 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/MobileView.tsx +385 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/MonitorPanel.tsx +122 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/NewSessionModal.tsx +93 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/NewTaskModal.tsx +492 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/PipelineEditor.tsx +570 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/PipelineView.tsx +1018 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/PluginsPanel.tsx +472 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/ProjectDetail.tsx +1618 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/ProjectList.tsx +108 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/ProjectManager.tsx +401 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/SessionList.tsx +74 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/SessionView.tsx +726 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/SettingsModal.tsx +1647 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/SkillsPanel.tsx +969 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/StatusBar.tsx +99 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/TabBar.tsx +46 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/TaskBoard.tsx +113 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/TaskDetail.tsx +372 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/TerminalLauncher.tsx +398 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/TunnelToggle.tsx +206 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/UsagePanel.tsx +207 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/WebTerminal.tsx +1743 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/WorkspaceTree.tsx +221 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/WorkspaceView.tsx +4048 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/dev-test.sh +5 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/docs/Forge_Memory_Layer_Design.docx +0 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/docs/Forge_Strategy_Research_2026.docx +0 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/docs/LOCAL-DEPLOY.md +144 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/docs/roadmap-multi-agent-workflow.md +330 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/forge-logo.png +0 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/forge-logo.svg +106 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/hooks/useSidebarResize.ts +52 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/install.sh +29 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/instrumentation.ts +35 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/agents/claude-adapter.ts +104 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/agents/generic-adapter.ts +64 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/agents/index.ts +245 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/agents/types.ts +70 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/artifacts.ts +106 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/auth.ts +62 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/builtin-plugins/docker.yaml +70 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/builtin-plugins/http.yaml +66 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/builtin-plugins/jenkins.yaml +92 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/builtin-plugins/llm-vision.yaml +85 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/builtin-plugins/playwright.yaml +111 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/builtin-plugins/shell-command.yaml +60 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/builtin-plugins/slack.yaml +48 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/builtin-plugins/webhook.yaml +56 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/claude-process.ts +361 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/claude-sessions.ts +266 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/claude-templates.ts +227 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/cloudflared.ts +424 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/crypto.ts +67 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/delivery.ts +787 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/dirs.ts +99 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/flows.ts +86 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/forge-mcp-server.ts +732 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/forge-skills/forge-inbox.md +38 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/forge-skills/forge-send.md +47 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/forge-skills/forge-status.md +32 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/forge-skills/forge-workspace-sync.md +37 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/00-overview.md +40 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/01-settings.md +194 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/02-telegram.md +41 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/03-tunnel.md +31 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/04-tasks.md +52 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/05-pipelines.md +460 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/06-skills.md +43 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/07-projects.md +73 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/08-rules.md +53 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/09-issue-autofix.md +55 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/10-troubleshooting.md +89 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/11-workspace.md +810 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/CLAUDE.md +62 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/init.ts +266 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/issue-scanner.ts +298 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/logger.ts +79 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/notifications.ts +75 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/notify.ts +108 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/password.ts +97 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/pipeline-scheduler.ts +373 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/pipeline.ts +1565 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/plugins/executor.ts +347 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/plugins/registry.ts +228 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/plugins/types.ts +103 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/project-sessions.ts +53 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/projects.ts +86 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/session-manager.ts +156 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/session-utils.ts +53 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/session-watcher.ts +345 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/settings.ts +195 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/skills.ts +458 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/task-manager.ts +951 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/telegram-bot.ts +1477 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/telegram-standalone.ts +83 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/terminal-server.ts +70 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/terminal-standalone.ts +438 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/usage-scanner.ts +249 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/__tests__/state-machine.test.ts +388 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/__tests__/workspace.test.ts +311 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/agent-bus.ts +416 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/agent-worker.ts +655 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/backends/api-backend.ts +262 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/backends/cli-backend.ts +491 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/index.ts +84 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/manager.ts +136 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/orchestrator.ts +3415 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/persistence.ts +309 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/presets.ts +649 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/requests.ts +287 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/session-monitor.ts +240 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/skill-installer.ts +275 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/smith-memory.ts +498 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/types.ts +241 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/watch-manager.ts +560 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace-standalone.ts +978 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/middleware.ts +51 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/next.config.ts +26 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/package.json +74 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/pnpm-lock.yaml +3719 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/pnpm-workspace.yaml +1 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/postcss.config.mjs +7 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/publish.sh +133 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/README.md +66 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/results/.gitignore +2 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/run.ts +635 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/tasks/01-text-utils/task.md +26 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/tasks/01-text-utils/validator.sh +46 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/tasks/02-pagination/setup.sh +19 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/tasks/02-pagination/task.md +48 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/tasks/02-pagination/validator.sh +69 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/tasks/03-bug-fix/setup.sh +82 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/tasks/03-bug-fix/task.md +30 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/tasks/03-bug-fix/validator.sh +29 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/scripts/verify-usage.ts +178 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/src/config/index.ts +129 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/src/core/db/database.ts +259 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/src/core/memory/strategy.ts +32 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/src/core/providers/chat.ts +65 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/src/core/providers/registry.ts +60 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/src/core/session/manager.ts +190 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/src/types/index.ts +129 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/start.sh +32 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/templates/smith-lead.json +45 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/tsconfig.json +42 -0
- package/RELEASE_NOTES.md +11 -28
- package/app/api/terminal-bell/route.ts +6 -2
- package/components/WebTerminal.tsx +36 -2
- package/lib/terminal-standalone.ts +19 -2
- package/next-env.d.ts +1 -1
- 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);
|