@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,37 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { createTask } from '@/lib/task-manager';
|
|
3
|
+
import { getProjectInfo } from '@/lib/projects';
|
|
4
|
+
import { getDb } from '@/src/core/db/database';
|
|
5
|
+
import { getDbPath } from '@/src/config';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Link an existing local Claude Code session to a project.
|
|
9
|
+
* Creates a placeholder task with the conversation_id so future tasks
|
|
10
|
+
* for this project automatically continue that session.
|
|
11
|
+
*/
|
|
12
|
+
export async function POST(req: Request) {
|
|
13
|
+
const { projectName, conversationId } = await req.json();
|
|
14
|
+
|
|
15
|
+
if (!projectName || !conversationId) {
|
|
16
|
+
return NextResponse.json({ error: 'projectName and conversationId required' }, { status: 400 });
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const project = getProjectInfo(projectName);
|
|
20
|
+
if (!project) {
|
|
21
|
+
return NextResponse.json({ error: `Project not found: ${projectName}` }, { status: 404 });
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Create a placeholder "done" task that carries the conversation_id
|
|
25
|
+
const db = getDb(getDbPath());
|
|
26
|
+
const id = `link-${Date.now().toString(36)}`;
|
|
27
|
+
db.prepare(`
|
|
28
|
+
INSERT INTO tasks (id, project_name, project_path, prompt, status, priority, conversation_id, log, result_summary, completed_at)
|
|
29
|
+
VALUES (?, ?, ?, ?, 'done', 0, ?, '[]', ?, datetime('now'))
|
|
30
|
+
`).run(id, project.name, project.path, '(linked from local CLI)', conversationId, `Session ${conversationId} linked from local CLI`);
|
|
31
|
+
|
|
32
|
+
return NextResponse.json({
|
|
33
|
+
id,
|
|
34
|
+
projectName: project.name,
|
|
35
|
+
conversationId,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { createTask, listTasks } from '@/lib/task-manager';
|
|
3
|
+
import { ensureInitialized } from '@/lib/init';
|
|
4
|
+
import { getProjectInfo } from '@/lib/projects';
|
|
5
|
+
import type { TaskStatus } from '@/src/types';
|
|
6
|
+
|
|
7
|
+
// List tasks — optionally filter by status
|
|
8
|
+
export async function GET(req: Request) {
|
|
9
|
+
ensureInitialized();
|
|
10
|
+
const url = new URL(req.url);
|
|
11
|
+
const status = url.searchParams.get('status') as TaskStatus | null;
|
|
12
|
+
return NextResponse.json(listTasks(status || undefined));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Create a new task
|
|
16
|
+
export async function POST(req: Request) {
|
|
17
|
+
const { projectName, prompt, priority, newSession, conversationId, scheduledAt, mode, watchConfig, agent } = await req.json();
|
|
18
|
+
|
|
19
|
+
if (!projectName || !prompt) {
|
|
20
|
+
return NextResponse.json({ error: 'projectName and prompt are required' }, { status: 400 });
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const project = getProjectInfo(projectName);
|
|
24
|
+
if (!project) {
|
|
25
|
+
return NextResponse.json({ error: `Project not found: ${projectName}` }, { status: 404 });
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// conversationId: explicit value → use it; newSession → empty string (force new); otherwise → auto-inherit
|
|
29
|
+
const convId = conversationId || (newSession ? '' : undefined);
|
|
30
|
+
|
|
31
|
+
const task = createTask({
|
|
32
|
+
projectName: project.name,
|
|
33
|
+
projectPath: project.path,
|
|
34
|
+
prompt,
|
|
35
|
+
priority: priority || 0,
|
|
36
|
+
conversationId: convId,
|
|
37
|
+
scheduledAt: scheduledAt || undefined,
|
|
38
|
+
mode: mode || 'prompt',
|
|
39
|
+
watchConfig: watchConfig || undefined,
|
|
40
|
+
agent: agent || undefined,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
return NextResponse.json(task);
|
|
44
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { getProjectConversationId } from '@/lib/task-manager';
|
|
3
|
+
|
|
4
|
+
export async function GET(req: Request) {
|
|
5
|
+
const url = new URL(req.url);
|
|
6
|
+
const project = url.searchParams.get('project');
|
|
7
|
+
|
|
8
|
+
if (!project) {
|
|
9
|
+
return NextResponse.json({ error: 'project parameter required' }, { status: 400 });
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const conversationId = getProjectConversationId(project);
|
|
13
|
+
return NextResponse.json({ conversationId });
|
|
14
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { NextResponse, type NextRequest } from 'next/server';
|
|
2
|
+
import { loadSettings } from '@/lib/settings';
|
|
3
|
+
import { handleTelegramMessage } from '@/lib/telegram-bot';
|
|
4
|
+
|
|
5
|
+
// POST /api/telegram — receives messages from telegram-standalone process
|
|
6
|
+
export async function POST(req: NextRequest) {
|
|
7
|
+
const settings = loadSettings();
|
|
8
|
+
|
|
9
|
+
// Verify the request comes from our standalone process
|
|
10
|
+
const secret = req.headers.get('x-telegram-secret');
|
|
11
|
+
if (!secret || secret !== settings.telegramBotToken) {
|
|
12
|
+
return NextResponse.json({ error: 'unauthorized' }, { status: 401 });
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const message = await req.json();
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
await handleTelegramMessage(message);
|
|
19
|
+
return NextResponse.json({ ok: true });
|
|
20
|
+
} catch (e: any) {
|
|
21
|
+
return NextResponse.json({ error: e.message }, { status: 500 });
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { loadSettings } from '@/lib/settings';
|
|
3
|
+
import { addNotification } from '@/lib/notifications';
|
|
4
|
+
|
|
5
|
+
export async function POST(req: Request) {
|
|
6
|
+
const { tabLabel } = await req.json();
|
|
7
|
+
const label = tabLabel || 'Terminal';
|
|
8
|
+
|
|
9
|
+
// Check settings — terminal bell notifications can be disabled
|
|
10
|
+
const settings = loadSettings();
|
|
11
|
+
if ((settings as any).terminalBellEnabled === false) {
|
|
12
|
+
return NextResponse.json({ ok: true, skipped: true });
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// In-app notification
|
|
16
|
+
try {
|
|
17
|
+
addNotification('terminal_bell', `Terminal idle: ${label}`, `Claude appears to have finished in "${label}".`);
|
|
18
|
+
} catch {}
|
|
19
|
+
|
|
20
|
+
// Telegram notification
|
|
21
|
+
const { telegramBotToken, telegramChatId } = settings;
|
|
22
|
+
if (telegramBotToken && telegramChatId) {
|
|
23
|
+
try {
|
|
24
|
+
const chatIds = String(telegramChatId).split(',').map(s => s.trim()).filter(Boolean);
|
|
25
|
+
for (const chatId of chatIds) {
|
|
26
|
+
await fetch(`https://api.telegram.org/bot${telegramBotToken}/sendMessage`, {
|
|
27
|
+
method: 'POST',
|
|
28
|
+
headers: { 'Content-Type': 'application/json' },
|
|
29
|
+
body: JSON.stringify({
|
|
30
|
+
chat_id: chatId,
|
|
31
|
+
text: `🔔 Forge — Terminal idle\n\n"${label}" appears to have finished.`,
|
|
32
|
+
}),
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
} catch {}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return NextResponse.json({ ok: true });
|
|
39
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { execSync } from 'node:child_process';
|
|
3
|
+
|
|
4
|
+
export async function GET(req: Request) {
|
|
5
|
+
const { searchParams } = new URL(req.url);
|
|
6
|
+
const session = searchParams.get('session');
|
|
7
|
+
if (!session || !session.startsWith('mw-')) {
|
|
8
|
+
return NextResponse.json({ path: null });
|
|
9
|
+
}
|
|
10
|
+
try {
|
|
11
|
+
const cwd = execSync(`tmux display-message -p -t ${session} '#{pane_current_path}'`, {
|
|
12
|
+
encoding: 'utf-8',
|
|
13
|
+
timeout: 3000,
|
|
14
|
+
}).trim();
|
|
15
|
+
return NextResponse.json({ path: cwd || null });
|
|
16
|
+
} catch {
|
|
17
|
+
return NextResponse.json({ path: null });
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { NextResponse } from 'next/server';
|
|
4
|
+
import { getDataDir } from '@/lib/dirs';
|
|
5
|
+
|
|
6
|
+
const STATE_FILE = join(getDataDir(), 'terminal-state.json');
|
|
7
|
+
|
|
8
|
+
export async function GET() {
|
|
9
|
+
try {
|
|
10
|
+
const data = JSON.parse(readFileSync(STATE_FILE, 'utf-8'));
|
|
11
|
+
return NextResponse.json(data);
|
|
12
|
+
} catch {
|
|
13
|
+
return NextResponse.json(null);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { startTunnel, stopTunnel, getTunnelStatus } from '@/lib/cloudflared';
|
|
3
|
+
import { verifyAdmin } from '@/lib/password';
|
|
4
|
+
|
|
5
|
+
export async function GET() {
|
|
6
|
+
return NextResponse.json(getTunnelStatus());
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export async function POST(req: Request) {
|
|
10
|
+
const body = await req.json() as { action: 'start' | 'stop'; password?: string };
|
|
11
|
+
|
|
12
|
+
if (body.action === 'start') {
|
|
13
|
+
if (!body.password || !verifyAdmin(body.password)) {
|
|
14
|
+
return NextResponse.json({ ok: false, error: 'Wrong password' }, { status: 403 });
|
|
15
|
+
}
|
|
16
|
+
const result = await startTunnel();
|
|
17
|
+
return NextResponse.json({ ok: !result.error, ...getTunnelStatus() });
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (body.action === 'stop') {
|
|
21
|
+
stopTunnel();
|
|
22
|
+
return NextResponse.json({ ok: true, ...getTunnelStatus() });
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return NextResponse.json({ ok: false, error: 'Invalid action' }, { status: 400 });
|
|
26
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { execSync } from 'node:child_process';
|
|
4
|
+
import { readFileSync } from 'node:fs';
|
|
5
|
+
import { homedir } from 'node:os';
|
|
6
|
+
|
|
7
|
+
export async function POST() {
|
|
8
|
+
try {
|
|
9
|
+
// Get global npm root first (before any cwd changes)
|
|
10
|
+
const pkgRoot = execSync('npm root -g', { encoding: 'utf-8', timeout: 5000, cwd: homedir() }).trim();
|
|
11
|
+
const forgeRoot = join(pkgRoot, '@aion0', 'forge');
|
|
12
|
+
|
|
13
|
+
// Upgrade from npm — use cwd instead of cd
|
|
14
|
+
execSync('npm install -g @aion0/forge@latest --prefer-online 2>&1', {
|
|
15
|
+
encoding: 'utf-8',
|
|
16
|
+
timeout: 120000,
|
|
17
|
+
cwd: homedir(),
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// Install devDependencies for build
|
|
21
|
+
try {
|
|
22
|
+
execSync('npm install --include=dev 2>&1', { cwd: forgeRoot, timeout: 120000 });
|
|
23
|
+
} catch {}
|
|
24
|
+
|
|
25
|
+
// Read installed version
|
|
26
|
+
let installedVersion = '';
|
|
27
|
+
try {
|
|
28
|
+
const pkg = JSON.parse(readFileSync(join(forgeRoot, 'package.json'), 'utf-8'));
|
|
29
|
+
installedVersion = pkg.version;
|
|
30
|
+
} catch {}
|
|
31
|
+
|
|
32
|
+
return NextResponse.json({
|
|
33
|
+
ok: true,
|
|
34
|
+
message: `Upgraded to v${installedVersion}. Restart server to apply.`,
|
|
35
|
+
});
|
|
36
|
+
} catch (e) {
|
|
37
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
38
|
+
return NextResponse.json({
|
|
39
|
+
ok: false,
|
|
40
|
+
error: `Upgrade failed: ${msg.slice(0, 300)}`,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { scanUsage, queryUsage } from '@/lib/usage-scanner';
|
|
3
|
+
|
|
4
|
+
// GET /api/usage?days=7&project=forge&source=task&model=claude-opus-4
|
|
5
|
+
export async function GET(req: Request) {
|
|
6
|
+
const { searchParams } = new URL(req.url);
|
|
7
|
+
const days = searchParams.get('days') ? parseInt(searchParams.get('days')!) : undefined;
|
|
8
|
+
const projectName = searchParams.get('project') || undefined;
|
|
9
|
+
const source = searchParams.get('source') || undefined;
|
|
10
|
+
const model = searchParams.get('model') || undefined;
|
|
11
|
+
|
|
12
|
+
const data = queryUsage({ days, projectName, source, model });
|
|
13
|
+
return NextResponse.json(data);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// POST /api/usage — trigger scan
|
|
17
|
+
export async function POST() {
|
|
18
|
+
const result = scanUsage();
|
|
19
|
+
return NextResponse.json(result);
|
|
20
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
|
|
5
|
+
// Read version once at module load (= server start), not on every request
|
|
6
|
+
const CURRENT_VERSION = (() => {
|
|
7
|
+
try {
|
|
8
|
+
const pkg = JSON.parse(readFileSync(join(process.cwd(), 'package.json'), 'utf-8'));
|
|
9
|
+
return pkg.version as string;
|
|
10
|
+
} catch {
|
|
11
|
+
return '0.0.0';
|
|
12
|
+
}
|
|
13
|
+
})();
|
|
14
|
+
|
|
15
|
+
// Cache npm version check for 10 minutes
|
|
16
|
+
let cachedLatest: { version: string; checkedAt: number } | null = null;
|
|
17
|
+
const CACHE_TTL = 10 * 60 * 1000;
|
|
18
|
+
|
|
19
|
+
// Track which versions we already notified about (avoid duplicates)
|
|
20
|
+
let notifiedVersion = '';
|
|
21
|
+
|
|
22
|
+
async function getLatestVersion(force = false): Promise<string> {
|
|
23
|
+
if (!force && cachedLatest && Date.now() - cachedLatest.checkedAt < CACHE_TTL) {
|
|
24
|
+
return cachedLatest.version;
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
const controller = new AbortController();
|
|
28
|
+
const timeout = setTimeout(() => controller.abort(), 5000);
|
|
29
|
+
const res = await fetch('https://registry.npmjs.org/@aion0/forge/latest', {
|
|
30
|
+
signal: controller.signal,
|
|
31
|
+
headers: { 'Accept': 'application/json' },
|
|
32
|
+
});
|
|
33
|
+
clearTimeout(timeout);
|
|
34
|
+
if (!res.ok) return cachedLatest?.version || '';
|
|
35
|
+
const data = await res.json();
|
|
36
|
+
cachedLatest = { version: data.version, checkedAt: Date.now() };
|
|
37
|
+
return data.version;
|
|
38
|
+
} catch {
|
|
39
|
+
return cachedLatest?.version || '';
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function compareVersions(a: string, b: string): number {
|
|
44
|
+
const pa = a.split('.').map(Number);
|
|
45
|
+
const pb = b.split('.').map(Number);
|
|
46
|
+
for (let i = 0; i < 3; i++) {
|
|
47
|
+
if ((pa[i] || 0) < (pb[i] || 0)) return -1;
|
|
48
|
+
if ((pa[i] || 0) > (pb[i] || 0)) return 1;
|
|
49
|
+
}
|
|
50
|
+
return 0;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export async function GET(req: Request) {
|
|
54
|
+
const { searchParams } = new URL(req.url);
|
|
55
|
+
const force = searchParams.has('force');
|
|
56
|
+
const current = CURRENT_VERSION;
|
|
57
|
+
const latest = await getLatestVersion(force);
|
|
58
|
+
const hasUpdate = !!(latest && compareVersions(current, latest) < 0);
|
|
59
|
+
|
|
60
|
+
// Create a notification when new version is detected (once per version)
|
|
61
|
+
if (hasUpdate && latest !== notifiedVersion) {
|
|
62
|
+
notifiedVersion = latest;
|
|
63
|
+
try {
|
|
64
|
+
const { addNotification } = require('@/lib/notifications');
|
|
65
|
+
addNotification(
|
|
66
|
+
'system',
|
|
67
|
+
`Update available: v${latest}`,
|
|
68
|
+
`Current: v${current}\nforge upgrade\nnpm install -g @aion0/forge@latest`,
|
|
69
|
+
);
|
|
70
|
+
} catch {}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return NextResponse.json({
|
|
74
|
+
current,
|
|
75
|
+
latest: latest || current,
|
|
76
|
+
hasUpdate,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { ensureInitialized } from '@/lib/init';
|
|
3
|
+
import { listWatchers, createWatcher, deleteWatcher, toggleWatcher } from '@/lib/session-watcher';
|
|
4
|
+
|
|
5
|
+
export async function GET() {
|
|
6
|
+
ensureInitialized();
|
|
7
|
+
return NextResponse.json(listWatchers());
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export async function POST(req: Request) {
|
|
11
|
+
ensureInitialized();
|
|
12
|
+
const body = await req.json();
|
|
13
|
+
|
|
14
|
+
if (body.action === 'delete') {
|
|
15
|
+
deleteWatcher(body.id);
|
|
16
|
+
return NextResponse.json({ ok: true });
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (body.action === 'toggle') {
|
|
20
|
+
toggleWatcher(body.id, body.active);
|
|
21
|
+
return NextResponse.json({ ok: true });
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Create new watcher
|
|
25
|
+
const watcher = createWatcher({
|
|
26
|
+
projectName: body.projectName,
|
|
27
|
+
sessionId: body.sessionId,
|
|
28
|
+
label: body.label,
|
|
29
|
+
checkInterval: body.checkInterval || 60,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
return NextResponse.json(watcher);
|
|
33
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
|
|
3
|
+
const WORKSPACE_PORT = Number(process.env.WORKSPACE_PORT) || 8405;
|
|
4
|
+
const DAEMON_URL = `http://localhost:${WORKSPACE_PORT}`;
|
|
5
|
+
|
|
6
|
+
// Proxy to workspace daemon — Agent operations
|
|
7
|
+
export async function POST(req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
8
|
+
const { id } = await params;
|
|
9
|
+
const body = await req.json();
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
const res = await fetch(`${DAEMON_URL}/workspace/${id}/agents`, {
|
|
13
|
+
method: 'POST',
|
|
14
|
+
headers: { 'Content-Type': 'application/json' },
|
|
15
|
+
body: JSON.stringify(body),
|
|
16
|
+
});
|
|
17
|
+
const data = await res.json();
|
|
18
|
+
return NextResponse.json(data, { status: res.status });
|
|
19
|
+
} catch (err: any) {
|
|
20
|
+
return NextResponse.json({ error: 'Workspace daemon not available' }, { status: 503 });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Proxy to workspace daemon — Get agent states
|
|
25
|
+
export async function GET(_req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
26
|
+
const { id } = await params;
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const res = await fetch(`${DAEMON_URL}/workspace/${id}/agents`);
|
|
30
|
+
const data = await res.json();
|
|
31
|
+
return NextResponse.json(data, { status: res.status });
|
|
32
|
+
} catch (err: any) {
|
|
33
|
+
return NextResponse.json({ error: 'Workspace daemon not available' }, { status: 503 });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
|
|
3
|
+
const WORKSPACE_PORT = Number(process.env.WORKSPACE_PORT) || 8405;
|
|
4
|
+
const DAEMON_URL = `http://localhost:${WORKSPACE_PORT}`;
|
|
5
|
+
|
|
6
|
+
// Proxy to workspace daemon — Memory query
|
|
7
|
+
export async function GET(req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
8
|
+
const { id: workspaceId } = await params;
|
|
9
|
+
const url = new URL(req.url);
|
|
10
|
+
const agentId = url.searchParams.get('agentId');
|
|
11
|
+
|
|
12
|
+
if (!agentId) {
|
|
13
|
+
return NextResponse.json({ error: 'agentId required' }, { status: 400 });
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
const res = await fetch(`${DAEMON_URL}/workspace/${workspaceId}/memory?agentId=${encodeURIComponent(agentId)}`);
|
|
18
|
+
const data = await res.json();
|
|
19
|
+
return NextResponse.json(data, { status: res.status });
|
|
20
|
+
} catch (err: any) {
|
|
21
|
+
return NextResponse.json({ error: 'Workspace daemon not available' }, { status: 503 });
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
|
|
3
|
+
const WORKSPACE_PORT = Number(process.env.WORKSPACE_PORT) || 8405;
|
|
4
|
+
const DAEMON_URL = `http://localhost:${WORKSPACE_PORT}`;
|
|
5
|
+
|
|
6
|
+
// Proxy to workspace daemon — Smith API (called by forge skills in terminal)
|
|
7
|
+
export async function POST(req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
8
|
+
const { id } = await params;
|
|
9
|
+
const body = await req.json();
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
const res = await fetch(`${DAEMON_URL}/workspace/${id}/smith`, {
|
|
13
|
+
method: 'POST',
|
|
14
|
+
headers: { 'Content-Type': 'application/json' },
|
|
15
|
+
body: JSON.stringify(body),
|
|
16
|
+
});
|
|
17
|
+
const data = await res.json();
|
|
18
|
+
return NextResponse.json(data, { status: res.status });
|
|
19
|
+
} catch (err: any) {
|
|
20
|
+
return NextResponse.json({ error: 'Workspace daemon not available' }, { status: 503 });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export const dynamic = 'force-dynamic';
|
|
2
|
+
export const runtime = 'nodejs';
|
|
3
|
+
|
|
4
|
+
const WORKSPACE_PORT = Number(process.env.WORKSPACE_PORT) || 8405;
|
|
5
|
+
const DAEMON_URL = `http://localhost:${WORKSPACE_PORT}`;
|
|
6
|
+
|
|
7
|
+
// SSE relay — proxy daemon's SSE stream to browser
|
|
8
|
+
export async function GET(req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
9
|
+
const { id } = await params;
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
const daemonRes = await fetch(`${DAEMON_URL}/workspace/${id}/stream`, {
|
|
13
|
+
signal: req.signal,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
if (!daemonRes.ok || !daemonRes.body) {
|
|
17
|
+
return new Response(daemonRes.statusText || 'Daemon error', { status: daemonRes.status });
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Pipe daemon SSE stream directly to browser
|
|
21
|
+
return new Response(daemonRes.body, {
|
|
22
|
+
headers: {
|
|
23
|
+
'Content-Type': 'text/event-stream',
|
|
24
|
+
'Cache-Control': 'no-cache, no-transform',
|
|
25
|
+
'Connection': 'keep-alive',
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
} catch (err: any) {
|
|
29
|
+
return new Response('Workspace daemon not available', { status: 503 });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { listWorkspaces, findWorkspaceByProject, loadWorkspace, deleteWorkspace } from '@/lib/workspace';
|
|
3
|
+
import { randomUUID } from 'node:crypto';
|
|
4
|
+
|
|
5
|
+
// List workspaces, find by projectPath, or export template
|
|
6
|
+
export async function GET(req: Request) {
|
|
7
|
+
const url = new URL(req.url);
|
|
8
|
+
const projectPath = url.searchParams.get('projectPath');
|
|
9
|
+
const exportId = url.searchParams.get('export');
|
|
10
|
+
|
|
11
|
+
if (exportId) {
|
|
12
|
+
// Export workspace as template (agents + positions, no state/logs)
|
|
13
|
+
const ws = loadWorkspace(exportId);
|
|
14
|
+
if (!ws) return NextResponse.json({ error: 'not found' }, { status: 404 });
|
|
15
|
+
const template = {
|
|
16
|
+
name: ws.projectName + ' template',
|
|
17
|
+
agents: ws.agents.map(a => ({ ...a, entries: undefined })), // strip Input entries
|
|
18
|
+
nodePositions: ws.nodePositions,
|
|
19
|
+
exportedAt: Date.now(),
|
|
20
|
+
};
|
|
21
|
+
return NextResponse.json(template);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (projectPath) {
|
|
25
|
+
const ws = findWorkspaceByProject(projectPath);
|
|
26
|
+
return NextResponse.json(ws || null);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return NextResponse.json(listWorkspaces());
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Create workspace or import template — proxied through the workspace daemon
|
|
33
|
+
// so the daemon remains the exclusive writer of state.json (prevents race conditions).
|
|
34
|
+
export async function POST(req: Request) {
|
|
35
|
+
const body = await req.json();
|
|
36
|
+
const { projectPath, projectName, template } = body;
|
|
37
|
+
|
|
38
|
+
if (!projectPath || !projectName) {
|
|
39
|
+
return NextResponse.json({ error: 'projectPath and projectName are required' }, { status: 400 });
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const existing = findWorkspaceByProject(projectPath);
|
|
43
|
+
if (existing && !template) {
|
|
44
|
+
return NextResponse.json(existing);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const daemonUrl = `http://localhost:${Number(process.env.WORKSPACE_PORT) || 8405}`;
|
|
48
|
+
try {
|
|
49
|
+
const daemonRes = await fetch(`${daemonUrl}/workspace/create`, {
|
|
50
|
+
method: 'POST',
|
|
51
|
+
headers: { 'Content-Type': 'application/json' },
|
|
52
|
+
body: JSON.stringify({
|
|
53
|
+
id: existing?.id || randomUUID(),
|
|
54
|
+
projectPath,
|
|
55
|
+
projectName,
|
|
56
|
+
template,
|
|
57
|
+
createdAt: existing?.createdAt,
|
|
58
|
+
}),
|
|
59
|
+
});
|
|
60
|
+
const data = await daemonRes.json();
|
|
61
|
+
return NextResponse.json(data, { status: daemonRes.status });
|
|
62
|
+
} catch (err: any) {
|
|
63
|
+
return NextResponse.json({ error: `Workspace daemon unreachable: ${err.message}` }, { status: 503 });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Delete a workspace
|
|
68
|
+
export async function DELETE(req: Request) {
|
|
69
|
+
const url = new URL(req.url);
|
|
70
|
+
const id = url.searchParams.get('id');
|
|
71
|
+
if (!id) return NextResponse.json({ error: 'id required' }, { status: 400 });
|
|
72
|
+
|
|
73
|
+
// Unload from daemon if active
|
|
74
|
+
const daemonUrl = `http://localhost:${Number(process.env.WORKSPACE_PORT) || 8405}`;
|
|
75
|
+
try { await fetch(`${daemonUrl}/workspace/${id}/unload`, { method: 'POST' }); } catch {}
|
|
76
|
+
|
|
77
|
+
deleteWorkspace(id);
|
|
78
|
+
return NextResponse.json({ ok: true });
|
|
79
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
export default function GlobalError({ error, reset }: { error: Error & { digest?: string }; reset: () => void }) {
|
|
4
|
+
return (
|
|
5
|
+
<html lang="en">
|
|
6
|
+
<head>
|
|
7
|
+
<meta charSet="utf-8" />
|
|
8
|
+
</head>
|
|
9
|
+
<body style={{ background: '#0a0a0a', color: '#e5e5e5', fontFamily: 'monospace', padding: '2rem' }}>
|
|
10
|
+
<h2>Something went wrong</h2>
|
|
11
|
+
<p style={{ color: '#999' }}>{error?.message || 'Unknown error'}</p>
|
|
12
|
+
<button
|
|
13
|
+
onClick={() => reset()}
|
|
14
|
+
style={{ marginTop: '1rem', padding: '0.5rem 1rem', background: '#3b82f6', color: '#fff', border: 'none', borderRadius: '4px', cursor: 'pointer' }}
|
|
15
|
+
>
|
|
16
|
+
Try again
|
|
17
|
+
</button>
|
|
18
|
+
</body>
|
|
19
|
+
</html>
|
|
20
|
+
);
|
|
21
|
+
}
|