@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,484 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* forge-server — Start the Forge web platform.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* forge-server Start in foreground (production)
|
|
7
|
+
* forge-server --dev Start in foreground (development)
|
|
8
|
+
* forge-server --background Start in background
|
|
9
|
+
* forge-server --stop Stop background server
|
|
10
|
+
* forge-server --restart Stop + start (safe for remote)
|
|
11
|
+
* forge-server --rebuild Force rebuild
|
|
12
|
+
* forge-server --port 4000 Custom web port (default: 8403)
|
|
13
|
+
* forge-server --terminal-port 4001 Custom terminal port (default: 8404)
|
|
14
|
+
* forge-server --dir ~/.forge-test Custom data directory (default: ~/.forge)
|
|
15
|
+
* forge-server --reset-terminal Kill terminal server before start (loses tmux sessions)
|
|
16
|
+
*
|
|
17
|
+
* Examples:
|
|
18
|
+
* forge-server --background --port 4000 --terminal-port 4001 --dir ~/.forge-staging
|
|
19
|
+
* forge-server --restart
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { execSync, spawn } from 'node:child_process';
|
|
23
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync, openSync } from 'node:fs';
|
|
24
|
+
import { join, dirname } from 'node:path';
|
|
25
|
+
import { fileURLToPath } from 'node:url';
|
|
26
|
+
import { homedir } from 'node:os';
|
|
27
|
+
|
|
28
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
29
|
+
const ROOT = join(__dirname, '..');
|
|
30
|
+
|
|
31
|
+
/** Build Next.js — install devDependencies first if missing */
|
|
32
|
+
function buildNext() {
|
|
33
|
+
// Check if devDependencies are installed (e.g. @tailwindcss/postcss)
|
|
34
|
+
if (!existsSync(join(ROOT, 'node_modules', '@tailwindcss', 'postcss'))) {
|
|
35
|
+
console.log('[forge] Installing dependencies...');
|
|
36
|
+
execSync('npm install --include=dev', { cwd: ROOT, stdio: 'inherit' });
|
|
37
|
+
}
|
|
38
|
+
execSync('npx next build', { cwd: ROOT, stdio: 'inherit', env: { ...process.env } });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ── Parse arguments ──
|
|
42
|
+
|
|
43
|
+
function getArg(name) {
|
|
44
|
+
const idx = process.argv.indexOf(name);
|
|
45
|
+
if (idx === -1 || idx + 1 >= process.argv.length) return null;
|
|
46
|
+
return process.argv[idx + 1];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ── Version ──
|
|
50
|
+
if (process.argv.includes('--version') || process.argv.includes('-v')) {
|
|
51
|
+
const pkg = JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf-8'));
|
|
52
|
+
console.log(`@aion0/forge v${pkg.version}`);
|
|
53
|
+
process.exit(0);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const isDev = process.argv.includes('--dev');
|
|
57
|
+
const isForeground = process.argv.includes('--foreground');
|
|
58
|
+
const isBackground = !isForeground && !isDev; // default background unless --foreground or --dev
|
|
59
|
+
const isStop = process.argv.includes('--stop');
|
|
60
|
+
const isRestart = process.argv.includes('--restart');
|
|
61
|
+
const isRebuild = process.argv.includes('--rebuild');
|
|
62
|
+
const resetTerminal = process.argv.includes('--reset-terminal');
|
|
63
|
+
const resetPassword = process.argv.includes('--reset-password');
|
|
64
|
+
|
|
65
|
+
const webPort = parseInt(getArg('--port')) || 8403;
|
|
66
|
+
const terminalPort = parseInt(getArg('--terminal-port')) || (webPort + 1);
|
|
67
|
+
const workspacePort = parseInt(getArg('--workspace-port')) || (webPort + 2);
|
|
68
|
+
const DATA_DIR = getArg('--dir')?.replace(/^~/, homedir()) || join(homedir(), '.forge', 'data');
|
|
69
|
+
|
|
70
|
+
const PID_FILE = join(DATA_DIR, 'forge.pid');
|
|
71
|
+
const PIDS_FILE = join(DATA_DIR, 'forge.pids'); // all child process PIDs
|
|
72
|
+
const LOG_FILE = join(DATA_DIR, 'forge.log');
|
|
73
|
+
|
|
74
|
+
process.chdir(ROOT);
|
|
75
|
+
|
|
76
|
+
// ── Migrate old layout (~/.forge/*) to new (~/.forge/data/*) ──
|
|
77
|
+
if (!getArg('--dir')) {
|
|
78
|
+
const oldSettings = join(homedir(), '.forge', 'settings.yaml');
|
|
79
|
+
const newSettings = join(DATA_DIR, 'settings.yaml');
|
|
80
|
+
if (existsSync(oldSettings) && !existsSync(newSettings)) {
|
|
81
|
+
console.log('[forge] Migrating data from ~/.forge/ to ~/.forge/data/...');
|
|
82
|
+
mkdirSync(DATA_DIR, { recursive: true });
|
|
83
|
+
const migrateFiles = ['settings.yaml', '.encrypt-key', '.env.local', 'session-code.json', 'terminal-state.json', 'tunnel-state.json', 'preview.json', 'forge.pid', 'forge.log'];
|
|
84
|
+
for (const f of migrateFiles) {
|
|
85
|
+
const src = join(homedir(), '.forge', f);
|
|
86
|
+
const dest = join(DATA_DIR, f);
|
|
87
|
+
if (existsSync(src) && !existsSync(dest)) {
|
|
88
|
+
try { const { copyFileSync } = await import('node:fs'); copyFileSync(src, dest); console.log(` ${f}`); } catch {}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// data.db → workflow.db
|
|
92
|
+
const oldDb = join(homedir(), '.forge', 'data.db');
|
|
93
|
+
const newDb = join(DATA_DIR, 'workflow.db');
|
|
94
|
+
if (existsSync(oldDb) && !existsSync(newDb)) {
|
|
95
|
+
try { const { copyFileSync } = await import('node:fs'); copyFileSync(oldDb, newDb); console.log(' data.db → workflow.db'); } catch {}
|
|
96
|
+
}
|
|
97
|
+
// Migrate directories
|
|
98
|
+
for (const d of ['flows', 'pipelines']) {
|
|
99
|
+
const src = join(homedir(), '.forge', d);
|
|
100
|
+
const dest = join(DATA_DIR, d);
|
|
101
|
+
if (existsSync(src) && !existsSync(dest)) {
|
|
102
|
+
try { const { renameSync } = await import('node:fs'); renameSync(src, dest); console.log(` ${d}/`); } catch {}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
console.log('[forge] Migration complete.');
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
mkdirSync(DATA_DIR, { recursive: true });
|
|
110
|
+
|
|
111
|
+
// ── Load <data-dir>/.env.local ──
|
|
112
|
+
const envFile = join(DATA_DIR, '.env.local');
|
|
113
|
+
if (existsSync(envFile)) {
|
|
114
|
+
for (const line of readFileSync(envFile, 'utf-8').split('\n')) {
|
|
115
|
+
const trimmed = line.trim();
|
|
116
|
+
if (!trimmed || trimmed.startsWith('#')) continue;
|
|
117
|
+
const eq = trimmed.indexOf('=');
|
|
118
|
+
if (eq === -1) continue;
|
|
119
|
+
const key = trimmed.slice(0, eq).trim();
|
|
120
|
+
const val = trimmed.slice(eq + 1).trim();
|
|
121
|
+
if (!process.env[key]) process.env[key] = val;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Set env vars for Next.js and terminal server
|
|
126
|
+
process.env.PORT = String(webPort);
|
|
127
|
+
process.env.TERMINAL_PORT = String(terminalPort);
|
|
128
|
+
process.env.WORKSPACE_PORT = String(workspacePort);
|
|
129
|
+
process.env.FORGE_DATA_DIR = DATA_DIR;
|
|
130
|
+
|
|
131
|
+
// ── Password setup (first run or --reset-password) ──
|
|
132
|
+
if (!isStop) {
|
|
133
|
+
const YAML = await import('yaml');
|
|
134
|
+
const settingsFile = join(DATA_DIR, 'settings.yaml');
|
|
135
|
+
let settings = {};
|
|
136
|
+
try { settings = YAML.parse(readFileSync(settingsFile, 'utf-8')) || {}; } catch {}
|
|
137
|
+
|
|
138
|
+
const hasPassword = !!settings.telegramTunnelPassword;
|
|
139
|
+
|
|
140
|
+
if (resetPassword || !hasPassword) {
|
|
141
|
+
if (resetPassword) {
|
|
142
|
+
console.log('[forge] Password reset requested');
|
|
143
|
+
} else {
|
|
144
|
+
console.log('[forge] First run — please set an admin password');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const readline = await import('node:readline');
|
|
148
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
149
|
+
const ask = (q) => new Promise((resolve, reject) => {
|
|
150
|
+
rl.question(q, resolve);
|
|
151
|
+
rl.once('close', () => reject(new Error('cancelled')));
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
let pw = '';
|
|
155
|
+
try {
|
|
156
|
+
while (true) {
|
|
157
|
+
pw = await ask(' Enter admin password: ');
|
|
158
|
+
if (!pw || pw.length < 4) {
|
|
159
|
+
console.log(' Password must be at least 4 characters');
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
const confirm = await ask(' Confirm password: ');
|
|
163
|
+
if (pw !== confirm) {
|
|
164
|
+
console.log(' Passwords do not match, try again');
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
} catch {
|
|
170
|
+
console.log('\n[forge] Cancelled');
|
|
171
|
+
process.exit(0);
|
|
172
|
+
}
|
|
173
|
+
rl.close();
|
|
174
|
+
|
|
175
|
+
// Encrypt and save
|
|
176
|
+
const crypto = await import('node:crypto');
|
|
177
|
+
const KEY_FILE = join(DATA_DIR, '.encrypt-key');
|
|
178
|
+
let encKey;
|
|
179
|
+
if (existsSync(KEY_FILE)) {
|
|
180
|
+
encKey = Buffer.from(readFileSync(KEY_FILE, 'utf-8').trim(), 'hex');
|
|
181
|
+
} else {
|
|
182
|
+
encKey = crypto.randomBytes(32);
|
|
183
|
+
writeFileSync(KEY_FILE, encKey.toString('hex'), { mode: 0o600 });
|
|
184
|
+
}
|
|
185
|
+
const iv = crypto.randomBytes(12);
|
|
186
|
+
const cipher = crypto.createCipheriv('aes-256-gcm', encKey, iv);
|
|
187
|
+
const encrypted = Buffer.concat([cipher.update(pw, 'utf-8'), cipher.final()]);
|
|
188
|
+
const tag = cipher.getAuthTag();
|
|
189
|
+
settings.telegramTunnelPassword = `enc:${iv.toString('base64')}.${tag.toString('base64')}.${encrypted.toString('base64')}`;
|
|
190
|
+
if (!existsSync(dirname(settingsFile))) mkdirSync(dirname(settingsFile), { recursive: true });
|
|
191
|
+
writeFileSync(settingsFile, YAML.stringify(settings), 'utf-8');
|
|
192
|
+
console.log('[forge] Admin password saved');
|
|
193
|
+
|
|
194
|
+
if (resetPassword) {
|
|
195
|
+
process.exit(0);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// ── Reset terminal server (kill port + tmux sessions) ──
|
|
201
|
+
if (resetTerminal) {
|
|
202
|
+
console.log(`[forge] Resetting terminal server (port ${terminalPort})...`);
|
|
203
|
+
try {
|
|
204
|
+
const pids = execSync(`lsof -ti:${terminalPort}`, { encoding: 'utf-8' }).trim();
|
|
205
|
+
for (const pid of pids.split('\n').filter(Boolean)) {
|
|
206
|
+
try { execSync(`kill ${pid.trim()}`); } catch {}
|
|
207
|
+
}
|
|
208
|
+
console.log(`[forge] Killed terminal server on port ${terminalPort}`);
|
|
209
|
+
} catch {
|
|
210
|
+
console.log(`[forge] No process on port ${terminalPort}`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// ── PID tracking for clean shutdown ──
|
|
215
|
+
|
|
216
|
+
function savePids(pids) {
|
|
217
|
+
writeFileSync(PIDS_FILE, JSON.stringify(pids), 'utf-8');
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function loadPids() {
|
|
221
|
+
try { return JSON.parse(readFileSync(PIDS_FILE, 'utf-8')); } catch { return []; }
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function killTrackedPids() {
|
|
225
|
+
const pids = loadPids();
|
|
226
|
+
for (const pid of pids) {
|
|
227
|
+
try { process.kill(pid, 'SIGTERM'); } catch {}
|
|
228
|
+
}
|
|
229
|
+
// Give them a moment, then force kill
|
|
230
|
+
if (pids.length > 0) {
|
|
231
|
+
setTimeout(() => {
|
|
232
|
+
for (const pid of pids) {
|
|
233
|
+
try { process.kill(pid, 'SIGKILL'); } catch {}
|
|
234
|
+
}
|
|
235
|
+
}, 2000);
|
|
236
|
+
}
|
|
237
|
+
try { unlinkSync(PIDS_FILE); } catch {}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// ── Kill orphan standalone processes ──
|
|
241
|
+
const protectedPids = new Set();
|
|
242
|
+
|
|
243
|
+
function cleanupOrphans() {
|
|
244
|
+
const myPid = String(process.pid);
|
|
245
|
+
const instanceTag = `--forge-port=${webPort}`;
|
|
246
|
+
try {
|
|
247
|
+
// Kill processes on our ports
|
|
248
|
+
for (const port of [webPort, terminalPort]) {
|
|
249
|
+
try {
|
|
250
|
+
const pids = execSync(`lsof -ti:${port}`, { encoding: 'utf-8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'] }).trim();
|
|
251
|
+
for (const pid of pids.split('\n').filter(Boolean)) {
|
|
252
|
+
const p = pid.trim();
|
|
253
|
+
if (p === myPid || protectedPids.has(p)) continue;
|
|
254
|
+
try { process.kill(parseInt(p), 'SIGTERM'); } catch {}
|
|
255
|
+
}
|
|
256
|
+
} catch {}
|
|
257
|
+
}
|
|
258
|
+
// Kill standalone processes: our instance's + orphans without any tag
|
|
259
|
+
try {
|
|
260
|
+
const out = execSync(`ps aux | grep -E 'telegram-standalone|terminal-standalone|workspace-standalone' | grep -v grep`, {
|
|
261
|
+
encoding: 'utf-8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'],
|
|
262
|
+
}).trim();
|
|
263
|
+
for (const line of out.split('\n').filter(Boolean)) {
|
|
264
|
+
const isOurs = line.includes(instanceTag);
|
|
265
|
+
const isOrphan = !line.includes('--forge-port='); // no tag = legacy orphan
|
|
266
|
+
if (!isOurs && !isOrphan) continue; // belongs to another instance, skip
|
|
267
|
+
const pid = line.trim().split(/\s+/)[1];
|
|
268
|
+
if (pid === myPid || protectedPids.has(pid)) continue;
|
|
269
|
+
try { process.kill(parseInt(pid), 'SIGTERM'); } catch {}
|
|
270
|
+
}
|
|
271
|
+
} catch {}
|
|
272
|
+
} catch {}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// ── Start standalone services (single instance each) ──
|
|
276
|
+
const services = [];
|
|
277
|
+
|
|
278
|
+
function startServices() {
|
|
279
|
+
cleanupOrphans();
|
|
280
|
+
|
|
281
|
+
const instanceTag = `--forge-port=${webPort}`;
|
|
282
|
+
|
|
283
|
+
// Terminal server
|
|
284
|
+
const termScript = join(ROOT, 'lib', 'terminal-standalone.ts');
|
|
285
|
+
const termChild = spawn('npx', ['tsx', termScript, instanceTag], {
|
|
286
|
+
cwd: ROOT,
|
|
287
|
+
stdio: ['ignore', 'inherit', 'inherit'],
|
|
288
|
+
env: { ...process.env },
|
|
289
|
+
});
|
|
290
|
+
services.push(termChild);
|
|
291
|
+
console.log(`[forge] Terminal server started (pid: ${termChild.pid})`);
|
|
292
|
+
|
|
293
|
+
// Telegram bot
|
|
294
|
+
const telegramScript = join(ROOT, 'lib', 'telegram-standalone.ts');
|
|
295
|
+
const telegramChild = spawn('npx', ['tsx', telegramScript, instanceTag], {
|
|
296
|
+
cwd: ROOT,
|
|
297
|
+
stdio: ['ignore', 'inherit', 'inherit'],
|
|
298
|
+
env: { ...process.env },
|
|
299
|
+
});
|
|
300
|
+
services.push(telegramChild);
|
|
301
|
+
console.log(`[forge] Telegram bot started (pid: ${telegramChild.pid})`);
|
|
302
|
+
|
|
303
|
+
// Workspace daemon
|
|
304
|
+
const workspaceScript = join(ROOT, 'lib', 'workspace-standalone.ts');
|
|
305
|
+
const workspaceChild = spawn('npx', ['tsx', workspaceScript, instanceTag], {
|
|
306
|
+
cwd: ROOT,
|
|
307
|
+
stdio: ['ignore', 'inherit', 'inherit'],
|
|
308
|
+
env: { ...process.env },
|
|
309
|
+
});
|
|
310
|
+
services.push(workspaceChild);
|
|
311
|
+
console.log(`[forge] Workspace daemon started (pid: ${workspaceChild.pid})`);
|
|
312
|
+
|
|
313
|
+
// Track all child PIDs for clean shutdown
|
|
314
|
+
const childPids = services.map(c => c.pid).filter(Boolean);
|
|
315
|
+
savePids(childPids);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function stopServices() {
|
|
319
|
+
for (const child of services) {
|
|
320
|
+
try { child.kill('SIGTERM'); } catch {}
|
|
321
|
+
}
|
|
322
|
+
services.length = 0;
|
|
323
|
+
cleanupOrphans();
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// ── Helper: stop running instance ──
|
|
327
|
+
async function stopServer() {
|
|
328
|
+
stopServices();
|
|
329
|
+
try { unlinkSync(join(DATA_DIR, 'tunnel-state.json')); } catch {}
|
|
330
|
+
|
|
331
|
+
// Kill all tracked child PIDs first
|
|
332
|
+
killTrackedPids();
|
|
333
|
+
|
|
334
|
+
let stopped = false;
|
|
335
|
+
|
|
336
|
+
// Try PID file first
|
|
337
|
+
try {
|
|
338
|
+
const pid = parseInt(readFileSync(PID_FILE, 'utf-8').trim());
|
|
339
|
+
process.kill(pid, 'SIGTERM');
|
|
340
|
+
console.log(`[forge] Stopped (pid ${pid})`);
|
|
341
|
+
stopped = true;
|
|
342
|
+
} catch {}
|
|
343
|
+
try { unlinkSync(PID_FILE); } catch {}
|
|
344
|
+
|
|
345
|
+
// Also kill by port (in case PID file is stale)
|
|
346
|
+
const portPids = [];
|
|
347
|
+
try {
|
|
348
|
+
const pids = execSync(`lsof -ti:${webPort}`, { encoding: 'utf-8', timeout: 3000 }).trim();
|
|
349
|
+
for (const p of pids.split('\n').filter(Boolean)) {
|
|
350
|
+
const pid = parseInt(p.trim());
|
|
351
|
+
try { process.kill(pid, 'SIGTERM'); stopped = true; portPids.push(pid); } catch {}
|
|
352
|
+
}
|
|
353
|
+
if (pids) console.log(`[forge] Killed processes on port ${webPort}`);
|
|
354
|
+
} catch {}
|
|
355
|
+
|
|
356
|
+
// Force kill after 2 seconds if SIGTERM didn't work
|
|
357
|
+
if (portPids.length > 0) {
|
|
358
|
+
await new Promise(r => setTimeout(r, 2000));
|
|
359
|
+
for (const pid of portPids) {
|
|
360
|
+
try { process.kill(pid, 'SIGKILL'); } catch {}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
if (!stopped) {
|
|
365
|
+
console.log('[forge] No running server found');
|
|
366
|
+
}
|
|
367
|
+
return stopped;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// ── Helper: start background server ──
|
|
371
|
+
function startBackground() {
|
|
372
|
+
if (!existsSync(join(ROOT, '.next', 'BUILD_ID'))) {
|
|
373
|
+
console.log('[forge] Building...');
|
|
374
|
+
buildNext();
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
const logFd = openSync(LOG_FILE, 'a');
|
|
378
|
+
const nextBin = join(ROOT, 'node_modules', '.bin', 'next');
|
|
379
|
+
const child = spawn(nextBin, ['start', '-p', String(webPort)], {
|
|
380
|
+
cwd: ROOT,
|
|
381
|
+
stdio: ['ignore', logFd, logFd],
|
|
382
|
+
env: { ...process.env, FORGE_EXTERNAL_SERVICES: '1' },
|
|
383
|
+
detached: true,
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
writeFileSync(PID_FILE, String(child.pid));
|
|
387
|
+
protectedPids.add(String(child.pid));
|
|
388
|
+
child.unref();
|
|
389
|
+
|
|
390
|
+
// Start services in background too (cleanupOrphans will skip protectedPids)
|
|
391
|
+
startServices();
|
|
392
|
+
|
|
393
|
+
console.log(`[forge] Started in background (pid ${child.pid})`);
|
|
394
|
+
if (!getArg('--port')) {
|
|
395
|
+
console.log(`[forge] ⚠️ Default port changed: 3000 → ${webPort}`);
|
|
396
|
+
console.log(`[forge] ⚠️ Default port changed: 3000 → ${webPort}`);
|
|
397
|
+
console.log(`[forge] ⚠️ Default port changed: 3000 → ${webPort}`);
|
|
398
|
+
console.log(`[forge] ⚠️ Default port changed: 3000 → ${webPort}`);
|
|
399
|
+
console.log(`[forge] ⚠️ Default port changed: 3000 → ${webPort}`);
|
|
400
|
+
}
|
|
401
|
+
console.log(`[forge] Web: http://localhost:${webPort}`);
|
|
402
|
+
console.log(`[forge] Terminal: ws://localhost:${terminalPort}`);
|
|
403
|
+
console.log(`[forge] Data: ${DATA_DIR}`);
|
|
404
|
+
console.log(`[forge] Log: ${LOG_FILE}`);
|
|
405
|
+
console.log(`[forge] Stop: forge server stop`);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// ── Stop ──
|
|
409
|
+
if (isStop) {
|
|
410
|
+
await stopServer();
|
|
411
|
+
process.exit(0);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// ── Restart ──
|
|
415
|
+
if (isRestart) {
|
|
416
|
+
await stopServer();
|
|
417
|
+
// Wait for port to fully release
|
|
418
|
+
const net = await import('node:net');
|
|
419
|
+
for (let i = 0; i < 20; i++) {
|
|
420
|
+
await new Promise(r => setTimeout(r, 500));
|
|
421
|
+
const free = await new Promise(resolve => {
|
|
422
|
+
const s = net.createServer();
|
|
423
|
+
s.once('error', () => resolve(false));
|
|
424
|
+
s.once('listening', () => { s.close(); resolve(true); });
|
|
425
|
+
s.listen(webPort);
|
|
426
|
+
});
|
|
427
|
+
if (free) break;
|
|
428
|
+
}
|
|
429
|
+
startBackground();
|
|
430
|
+
process.exit(0);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// ── Rebuild ──
|
|
434
|
+
if (isRebuild || existsSync(join(ROOT, '.next', 'BUILD_ID'))) {
|
|
435
|
+
const pkgVersion = JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf-8')).version;
|
|
436
|
+
const versionFile = join(ROOT, '.next', '.forge-version');
|
|
437
|
+
const lastBuiltVersion = existsSync(versionFile) ? readFileSync(versionFile, 'utf-8').trim() : '';
|
|
438
|
+
if (isRebuild || lastBuiltVersion !== pkgVersion) {
|
|
439
|
+
console.log(`[forge] Rebuilding (v${pkgVersion})...`);
|
|
440
|
+
execSync('rm -rf .next', { cwd: ROOT });
|
|
441
|
+
buildNext();
|
|
442
|
+
writeFileSync(versionFile, pkgVersion);
|
|
443
|
+
if (isRebuild) {
|
|
444
|
+
console.log('[forge] Rebuild complete');
|
|
445
|
+
process.exit(0);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// ── Background ──
|
|
451
|
+
if (isBackground) {
|
|
452
|
+
startBackground();
|
|
453
|
+
process.exit(0);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// ── Foreground ──
|
|
457
|
+
|
|
458
|
+
// Clean up services on exit
|
|
459
|
+
process.on('SIGINT', () => { stopServices(); process.exit(0); });
|
|
460
|
+
process.on('SIGTERM', () => { stopServices(); process.exit(0); });
|
|
461
|
+
|
|
462
|
+
if (isDev) {
|
|
463
|
+
console.log(`[forge] Starting dev mode (port ${webPort}, terminal ${terminalPort}, data ${DATA_DIR})`);
|
|
464
|
+
startServices();
|
|
465
|
+
const child = spawn('npx', ['next', 'dev', '--turbopack', '-p', String(webPort)], {
|
|
466
|
+
cwd: ROOT,
|
|
467
|
+
stdio: 'inherit',
|
|
468
|
+
env: { ...process.env, FORGE_EXTERNAL_SERVICES: '1' },
|
|
469
|
+
});
|
|
470
|
+
child.on('exit', (code) => { stopServices(); process.exit(code || 0); });
|
|
471
|
+
} else {
|
|
472
|
+
if (!existsSync(join(ROOT, '.next', 'BUILD_ID'))) {
|
|
473
|
+
console.log('[forge] Building...');
|
|
474
|
+
buildNext();
|
|
475
|
+
}
|
|
476
|
+
console.log(`[forge] Starting server (port ${webPort}, terminal ${terminalPort}, data ${DATA_DIR})`);
|
|
477
|
+
startServices();
|
|
478
|
+
const child = spawn('npx', ['next', 'start', '-p', String(webPort)], {
|
|
479
|
+
cwd: ROOT,
|
|
480
|
+
stdio: 'inherit',
|
|
481
|
+
env: { ...process.env, FORGE_EXTERNAL_SERVICES: '1' },
|
|
482
|
+
});
|
|
483
|
+
child.on('exit', (code) => { stopServices(); process.exit(code || 0); });
|
|
484
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# check-forge-status.sh — Show Forge process status
|
|
3
|
+
|
|
4
|
+
echo "══════════════════════════════════"
|
|
5
|
+
echo " Forge Process Status"
|
|
6
|
+
echo "══════════════════════════════════"
|
|
7
|
+
|
|
8
|
+
# Next.js
|
|
9
|
+
count=$(ps aux | grep 'next-server' | grep -v grep | wc -l | tr -d ' ')
|
|
10
|
+
pid=$(ps aux | grep 'next-server' | grep -v grep | awk '{print $2}' | head -1)
|
|
11
|
+
if [ "$count" -gt 0 ]; then
|
|
12
|
+
echo " ● Next.js running (pid: $pid)"
|
|
13
|
+
else
|
|
14
|
+
echo " ○ Next.js stopped"
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
# Terminal
|
|
18
|
+
count=$(ps aux | grep 'terminal-standalone' | grep -v grep | grep -v 'npm exec' | grep -v 'cli.mjs' | wc -l | tr -d ' ')
|
|
19
|
+
pid=$(ps aux | grep 'terminal-standalone' | grep -v grep | grep -v 'npm exec' | grep -v 'cli.mjs' | awk '{print $2}' | head -1)
|
|
20
|
+
if [ "$count" -gt 0 ]; then
|
|
21
|
+
echo " ● Terminal running (pid: $pid)"
|
|
22
|
+
else
|
|
23
|
+
echo " ○ Terminal stopped"
|
|
24
|
+
fi
|
|
25
|
+
|
|
26
|
+
# Telegram
|
|
27
|
+
count=$(ps aux | grep 'telegram-standalone' | grep -v grep | grep -v 'npm exec' | grep -v 'cli.mjs' | wc -l | tr -d ' ')
|
|
28
|
+
pid=$(ps aux | grep 'telegram-standalone' | grep -v grep | grep -v 'npm exec' | grep -v 'cli.mjs' | awk '{print $2}' | head -1)
|
|
29
|
+
if [ "$count" -gt 0 ]; then
|
|
30
|
+
echo " ● Telegram running (pid: $pid)"
|
|
31
|
+
else
|
|
32
|
+
echo " ○ Telegram stopped"
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
# Workspace Daemon
|
|
36
|
+
count=$(ps aux | grep 'workspace-standalone' | grep -v grep | grep -v 'npm exec' | grep -v 'cli.mjs' | wc -l | tr -d ' ')
|
|
37
|
+
pid=$(ps aux | grep 'workspace-standalone' | grep -v grep | grep -v 'npm exec' | grep -v 'cli.mjs' | awk '{print $2}' | head -1)
|
|
38
|
+
if [ "$count" -gt 0 ]; then
|
|
39
|
+
echo " ● Workspace running (pid: $pid)"
|
|
40
|
+
else
|
|
41
|
+
echo " ○ Workspace stopped"
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
# MCP Server (runs inside workspace-standalone)
|
|
45
|
+
mcp_status=$(curl -s http://localhost:8406/health 2>/dev/null)
|
|
46
|
+
if echo "$mcp_status" | grep -q '"ok":true'; then
|
|
47
|
+
sessions=$(echo "$mcp_status" | python3 -c "import sys,json; print(json.load(sys.stdin).get('sessions',0))" 2>/dev/null)
|
|
48
|
+
echo " ● MCP Server running (port: 8406, sessions: $sessions)"
|
|
49
|
+
else
|
|
50
|
+
echo " ○ MCP Server stopped"
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
# Cloudflare Tunnel
|
|
54
|
+
count=$(ps aux | grep 'cloudflared tunnel' | grep -v grep | wc -l | tr -d ' ')
|
|
55
|
+
pid=$(ps aux | grep 'cloudflared tunnel' | grep -v grep | awk '{print $2}' | head -1)
|
|
56
|
+
url=$(cat ~/.forge/tunnel-state.json 2>/dev/null | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('url',''))" 2>/dev/null)
|
|
57
|
+
if [ "$count" -gt 0 ]; then
|
|
58
|
+
echo " ● Tunnel running (pid: $pid) ${url}"
|
|
59
|
+
else
|
|
60
|
+
echo " ○ Tunnel stopped"
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
# tmux sessions
|
|
64
|
+
tmux_count=$(tmux list-sessions 2>/dev/null | grep '^mw-' | wc -l | tr -d ' ')
|
|
65
|
+
echo ""
|
|
66
|
+
echo " Terminal sessions: $tmux_count"
|
|
67
|
+
tmux list-sessions 2>/dev/null | grep '^mw-' | while read line; do
|
|
68
|
+
echo " $line"
|
|
69
|
+
done
|
|
70
|
+
|
|
71
|
+
echo "══════════════════════════════════"
|