@aion0/forge 0.5.26 → 0.5.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (255) hide show
  1. package/.forge/worktrees/pipeline-4dd8dc2d/CLAUDE.md +86 -0
  2. package/.forge/worktrees/pipeline-4dd8dc2d/README.md +136 -0
  3. package/.forge/worktrees/pipeline-4dd8dc2d/RELEASE_NOTES.md +36 -0
  4. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/agents/route.ts +17 -0
  5. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/auth/[...nextauth]/route.ts +3 -0
  6. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/auth/verify/route.ts +46 -0
  7. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/claude/[id]/route.ts +31 -0
  8. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/claude/[id]/stream/route.ts +63 -0
  9. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/claude/route.ts +28 -0
  10. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/claude-sessions/[projectName]/entries/route.ts +23 -0
  11. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/claude-sessions/[projectName]/live/route.ts +72 -0
  12. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/claude-sessions/[projectName]/route.ts +37 -0
  13. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/claude-sessions/sync/route.ts +17 -0
  14. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/claude-templates/route.ts +145 -0
  15. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/code/route.ts +299 -0
  16. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/delivery/[id]/route.ts +62 -0
  17. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/delivery/route.ts +40 -0
  18. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/detect-cli/route.ts +46 -0
  19. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/docs/route.ts +176 -0
  20. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/docs/sessions/route.ts +54 -0
  21. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/favorites/route.ts +26 -0
  22. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/flows/route.ts +6 -0
  23. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/flows/run/route.ts +19 -0
  24. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/git/route.ts +149 -0
  25. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/help/route.ts +84 -0
  26. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/issue-scanner/route.ts +116 -0
  27. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/logs/route.ts +100 -0
  28. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/mobile-chat/route.ts +115 -0
  29. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/monitor/route.ts +74 -0
  30. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/notifications/route.ts +42 -0
  31. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/notify/test/route.ts +33 -0
  32. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/online/route.ts +40 -0
  33. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/pipelines/[id]/route.ts +41 -0
  34. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/pipelines/route.ts +90 -0
  35. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/plugins/route.ts +75 -0
  36. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/preview/[...path]/route.ts +64 -0
  37. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/preview/route.ts +156 -0
  38. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/project-pipelines/route.ts +91 -0
  39. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/project-sessions/route.ts +61 -0
  40. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/projects/route.ts +26 -0
  41. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/sessions/[id]/chat/route.ts +64 -0
  42. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/sessions/[id]/messages/route.ts +9 -0
  43. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/sessions/[id]/route.ts +17 -0
  44. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/sessions/route.ts +20 -0
  45. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/settings/route.ts +64 -0
  46. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/skills/local/route.ts +228 -0
  47. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/skills/route.ts +182 -0
  48. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/smith-templates/route.ts +81 -0
  49. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/status/route.ts +12 -0
  50. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/tabs/route.ts +25 -0
  51. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/tasks/[id]/route.ts +51 -0
  52. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/tasks/[id]/stream/route.ts +77 -0
  53. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/tasks/link/route.ts +37 -0
  54. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/tasks/route.ts +44 -0
  55. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/tasks/session/route.ts +14 -0
  56. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/telegram/route.ts +23 -0
  57. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/templates/route.ts +6 -0
  58. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/terminal-bell/route.ts +39 -0
  59. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/terminal-cwd/route.ts +19 -0
  60. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/terminal-state/route.ts +15 -0
  61. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/tunnel/route.ts +26 -0
  62. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/upgrade/route.ts +43 -0
  63. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/usage/route.ts +20 -0
  64. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/version/route.ts +78 -0
  65. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/watchers/route.ts +33 -0
  66. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/workspace/[id]/agents/route.ts +35 -0
  67. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/workspace/[id]/memory/route.ts +23 -0
  68. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/workspace/[id]/smith/route.ts +22 -0
  69. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/workspace/[id]/stream/route.ts +31 -0
  70. package/.forge/worktrees/pipeline-4dd8dc2d/app/api/workspace/route.ts +79 -0
  71. package/.forge/worktrees/pipeline-4dd8dc2d/app/global-error.tsx +21 -0
  72. package/.forge/worktrees/pipeline-4dd8dc2d/app/globals.css +52 -0
  73. package/.forge/worktrees/pipeline-4dd8dc2d/app/icon.ico +0 -0
  74. package/.forge/worktrees/pipeline-4dd8dc2d/app/icon.png +0 -0
  75. package/.forge/worktrees/pipeline-4dd8dc2d/app/icon.svg +106 -0
  76. package/.forge/worktrees/pipeline-4dd8dc2d/app/layout.tsx +17 -0
  77. package/.forge/worktrees/pipeline-4dd8dc2d/app/login/LoginForm.tsx +96 -0
  78. package/.forge/worktrees/pipeline-4dd8dc2d/app/login/page.tsx +10 -0
  79. package/.forge/worktrees/pipeline-4dd8dc2d/app/mobile/page.tsx +10 -0
  80. package/.forge/worktrees/pipeline-4dd8dc2d/app/page.tsx +22 -0
  81. package/.forge/worktrees/pipeline-4dd8dc2d/bin/forge-server.mjs +484 -0
  82. package/.forge/worktrees/pipeline-4dd8dc2d/check-forge-status.sh +71 -0
  83. package/.forge/worktrees/pipeline-4dd8dc2d/cli/mw.ts +579 -0
  84. package/.forge/worktrees/pipeline-4dd8dc2d/components/BrowserPanel.tsx +175 -0
  85. package/.forge/worktrees/pipeline-4dd8dc2d/components/ChatPanel.tsx +191 -0
  86. package/.forge/worktrees/pipeline-4dd8dc2d/components/ClaudeTerminal.tsx +267 -0
  87. package/.forge/worktrees/pipeline-4dd8dc2d/components/CodeViewer.tsx +787 -0
  88. package/.forge/worktrees/pipeline-4dd8dc2d/components/ConversationEditor.tsx +411 -0
  89. package/.forge/worktrees/pipeline-4dd8dc2d/components/ConversationGraphView.tsx +347 -0
  90. package/.forge/worktrees/pipeline-4dd8dc2d/components/ConversationTerminalView.tsx +303 -0
  91. package/.forge/worktrees/pipeline-4dd8dc2d/components/Dashboard.tsx +807 -0
  92. package/.forge/worktrees/pipeline-4dd8dc2d/components/DashboardWrapper.tsx +9 -0
  93. package/.forge/worktrees/pipeline-4dd8dc2d/components/DeliveryFlowEditor.tsx +491 -0
  94. package/.forge/worktrees/pipeline-4dd8dc2d/components/DeliveryList.tsx +230 -0
  95. package/.forge/worktrees/pipeline-4dd8dc2d/components/DeliveryWorkspace.tsx +589 -0
  96. package/.forge/worktrees/pipeline-4dd8dc2d/components/DocTerminal.tsx +187 -0
  97. package/.forge/worktrees/pipeline-4dd8dc2d/components/DocsViewer.tsx +574 -0
  98. package/.forge/worktrees/pipeline-4dd8dc2d/components/HelpDialog.tsx +169 -0
  99. package/.forge/worktrees/pipeline-4dd8dc2d/components/HelpTerminal.tsx +141 -0
  100. package/.forge/worktrees/pipeline-4dd8dc2d/components/InlinePipelineView.tsx +111 -0
  101. package/.forge/worktrees/pipeline-4dd8dc2d/components/LogViewer.tsx +194 -0
  102. package/.forge/worktrees/pipeline-4dd8dc2d/components/MarkdownContent.tsx +73 -0
  103. package/.forge/worktrees/pipeline-4dd8dc2d/components/MobileView.tsx +385 -0
  104. package/.forge/worktrees/pipeline-4dd8dc2d/components/MonitorPanel.tsx +122 -0
  105. package/.forge/worktrees/pipeline-4dd8dc2d/components/NewSessionModal.tsx +93 -0
  106. package/.forge/worktrees/pipeline-4dd8dc2d/components/NewTaskModal.tsx +492 -0
  107. package/.forge/worktrees/pipeline-4dd8dc2d/components/PipelineEditor.tsx +570 -0
  108. package/.forge/worktrees/pipeline-4dd8dc2d/components/PipelineView.tsx +1018 -0
  109. package/.forge/worktrees/pipeline-4dd8dc2d/components/PluginsPanel.tsx +472 -0
  110. package/.forge/worktrees/pipeline-4dd8dc2d/components/ProjectDetail.tsx +1618 -0
  111. package/.forge/worktrees/pipeline-4dd8dc2d/components/ProjectList.tsx +108 -0
  112. package/.forge/worktrees/pipeline-4dd8dc2d/components/ProjectManager.tsx +401 -0
  113. package/.forge/worktrees/pipeline-4dd8dc2d/components/SessionList.tsx +74 -0
  114. package/.forge/worktrees/pipeline-4dd8dc2d/components/SessionView.tsx +726 -0
  115. package/.forge/worktrees/pipeline-4dd8dc2d/components/SettingsModal.tsx +1647 -0
  116. package/.forge/worktrees/pipeline-4dd8dc2d/components/SkillsPanel.tsx +969 -0
  117. package/.forge/worktrees/pipeline-4dd8dc2d/components/StatusBar.tsx +99 -0
  118. package/.forge/worktrees/pipeline-4dd8dc2d/components/TabBar.tsx +46 -0
  119. package/.forge/worktrees/pipeline-4dd8dc2d/components/TaskBoard.tsx +113 -0
  120. package/.forge/worktrees/pipeline-4dd8dc2d/components/TaskDetail.tsx +372 -0
  121. package/.forge/worktrees/pipeline-4dd8dc2d/components/TerminalLauncher.tsx +398 -0
  122. package/.forge/worktrees/pipeline-4dd8dc2d/components/TunnelToggle.tsx +206 -0
  123. package/.forge/worktrees/pipeline-4dd8dc2d/components/UsagePanel.tsx +207 -0
  124. package/.forge/worktrees/pipeline-4dd8dc2d/components/WebTerminal.tsx +1743 -0
  125. package/.forge/worktrees/pipeline-4dd8dc2d/components/WorkspaceTree.tsx +221 -0
  126. package/.forge/worktrees/pipeline-4dd8dc2d/components/WorkspaceView.tsx +4048 -0
  127. package/.forge/worktrees/pipeline-4dd8dc2d/dev-test.sh +5 -0
  128. package/.forge/worktrees/pipeline-4dd8dc2d/docs/Forge_Memory_Layer_Design.docx +0 -0
  129. package/.forge/worktrees/pipeline-4dd8dc2d/docs/Forge_Strategy_Research_2026.docx +0 -0
  130. package/.forge/worktrees/pipeline-4dd8dc2d/docs/LOCAL-DEPLOY.md +144 -0
  131. package/.forge/worktrees/pipeline-4dd8dc2d/docs/roadmap-multi-agent-workflow.md +330 -0
  132. package/.forge/worktrees/pipeline-4dd8dc2d/forge-logo.png +0 -0
  133. package/.forge/worktrees/pipeline-4dd8dc2d/forge-logo.svg +106 -0
  134. package/.forge/worktrees/pipeline-4dd8dc2d/hooks/useSidebarResize.ts +52 -0
  135. package/.forge/worktrees/pipeline-4dd8dc2d/install.sh +29 -0
  136. package/.forge/worktrees/pipeline-4dd8dc2d/instrumentation.ts +35 -0
  137. package/.forge/worktrees/pipeline-4dd8dc2d/lib/agents/claude-adapter.ts +104 -0
  138. package/.forge/worktrees/pipeline-4dd8dc2d/lib/agents/generic-adapter.ts +64 -0
  139. package/.forge/worktrees/pipeline-4dd8dc2d/lib/agents/index.ts +245 -0
  140. package/.forge/worktrees/pipeline-4dd8dc2d/lib/agents/types.ts +70 -0
  141. package/.forge/worktrees/pipeline-4dd8dc2d/lib/artifacts.ts +106 -0
  142. package/.forge/worktrees/pipeline-4dd8dc2d/lib/auth.ts +62 -0
  143. package/.forge/worktrees/pipeline-4dd8dc2d/lib/builtin-plugins/docker.yaml +70 -0
  144. package/.forge/worktrees/pipeline-4dd8dc2d/lib/builtin-plugins/http.yaml +66 -0
  145. package/.forge/worktrees/pipeline-4dd8dc2d/lib/builtin-plugins/jenkins.yaml +92 -0
  146. package/.forge/worktrees/pipeline-4dd8dc2d/lib/builtin-plugins/llm-vision.yaml +85 -0
  147. package/.forge/worktrees/pipeline-4dd8dc2d/lib/builtin-plugins/playwright.yaml +111 -0
  148. package/.forge/worktrees/pipeline-4dd8dc2d/lib/builtin-plugins/shell-command.yaml +60 -0
  149. package/.forge/worktrees/pipeline-4dd8dc2d/lib/builtin-plugins/slack.yaml +48 -0
  150. package/.forge/worktrees/pipeline-4dd8dc2d/lib/builtin-plugins/webhook.yaml +56 -0
  151. package/.forge/worktrees/pipeline-4dd8dc2d/lib/claude-process.ts +361 -0
  152. package/.forge/worktrees/pipeline-4dd8dc2d/lib/claude-sessions.ts +266 -0
  153. package/.forge/worktrees/pipeline-4dd8dc2d/lib/claude-templates.ts +227 -0
  154. package/.forge/worktrees/pipeline-4dd8dc2d/lib/cloudflared.ts +424 -0
  155. package/.forge/worktrees/pipeline-4dd8dc2d/lib/crypto.ts +67 -0
  156. package/.forge/worktrees/pipeline-4dd8dc2d/lib/delivery.ts +787 -0
  157. package/.forge/worktrees/pipeline-4dd8dc2d/lib/dirs.ts +99 -0
  158. package/.forge/worktrees/pipeline-4dd8dc2d/lib/flows.ts +86 -0
  159. package/.forge/worktrees/pipeline-4dd8dc2d/lib/forge-mcp-server.ts +732 -0
  160. package/.forge/worktrees/pipeline-4dd8dc2d/lib/forge-skills/forge-inbox.md +38 -0
  161. package/.forge/worktrees/pipeline-4dd8dc2d/lib/forge-skills/forge-send.md +47 -0
  162. package/.forge/worktrees/pipeline-4dd8dc2d/lib/forge-skills/forge-status.md +32 -0
  163. package/.forge/worktrees/pipeline-4dd8dc2d/lib/forge-skills/forge-workspace-sync.md +37 -0
  164. package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/00-overview.md +40 -0
  165. package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/01-settings.md +194 -0
  166. package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/02-telegram.md +41 -0
  167. package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/03-tunnel.md +31 -0
  168. package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/04-tasks.md +52 -0
  169. package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/05-pipelines.md +460 -0
  170. package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/06-skills.md +43 -0
  171. package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/07-projects.md +73 -0
  172. package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/08-rules.md +53 -0
  173. package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/09-issue-autofix.md +55 -0
  174. package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/10-troubleshooting.md +89 -0
  175. package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/11-workspace.md +810 -0
  176. package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/CLAUDE.md +62 -0
  177. package/.forge/worktrees/pipeline-4dd8dc2d/lib/init.ts +266 -0
  178. package/.forge/worktrees/pipeline-4dd8dc2d/lib/issue-scanner.ts +298 -0
  179. package/.forge/worktrees/pipeline-4dd8dc2d/lib/logger.ts +79 -0
  180. package/.forge/worktrees/pipeline-4dd8dc2d/lib/notifications.ts +75 -0
  181. package/.forge/worktrees/pipeline-4dd8dc2d/lib/notify.ts +108 -0
  182. package/.forge/worktrees/pipeline-4dd8dc2d/lib/password.ts +97 -0
  183. package/.forge/worktrees/pipeline-4dd8dc2d/lib/pipeline-scheduler.ts +373 -0
  184. package/.forge/worktrees/pipeline-4dd8dc2d/lib/pipeline.ts +1565 -0
  185. package/.forge/worktrees/pipeline-4dd8dc2d/lib/plugins/executor.ts +347 -0
  186. package/.forge/worktrees/pipeline-4dd8dc2d/lib/plugins/registry.ts +228 -0
  187. package/.forge/worktrees/pipeline-4dd8dc2d/lib/plugins/types.ts +103 -0
  188. package/.forge/worktrees/pipeline-4dd8dc2d/lib/project-sessions.ts +53 -0
  189. package/.forge/worktrees/pipeline-4dd8dc2d/lib/projects.ts +86 -0
  190. package/.forge/worktrees/pipeline-4dd8dc2d/lib/session-manager.ts +156 -0
  191. package/.forge/worktrees/pipeline-4dd8dc2d/lib/session-utils.ts +53 -0
  192. package/.forge/worktrees/pipeline-4dd8dc2d/lib/session-watcher.ts +345 -0
  193. package/.forge/worktrees/pipeline-4dd8dc2d/lib/settings.ts +195 -0
  194. package/.forge/worktrees/pipeline-4dd8dc2d/lib/skills.ts +458 -0
  195. package/.forge/worktrees/pipeline-4dd8dc2d/lib/task-manager.ts +951 -0
  196. package/.forge/worktrees/pipeline-4dd8dc2d/lib/telegram-bot.ts +1477 -0
  197. package/.forge/worktrees/pipeline-4dd8dc2d/lib/telegram-standalone.ts +83 -0
  198. package/.forge/worktrees/pipeline-4dd8dc2d/lib/terminal-server.ts +70 -0
  199. package/.forge/worktrees/pipeline-4dd8dc2d/lib/terminal-standalone.ts +438 -0
  200. package/.forge/worktrees/pipeline-4dd8dc2d/lib/usage-scanner.ts +249 -0
  201. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/__tests__/state-machine.test.ts +388 -0
  202. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/__tests__/workspace.test.ts +311 -0
  203. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/agent-bus.ts +416 -0
  204. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/agent-worker.ts +655 -0
  205. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/backends/api-backend.ts +262 -0
  206. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/backends/cli-backend.ts +491 -0
  207. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/index.ts +84 -0
  208. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/manager.ts +136 -0
  209. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/orchestrator.ts +3415 -0
  210. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/persistence.ts +309 -0
  211. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/presets.ts +649 -0
  212. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/requests.ts +287 -0
  213. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/session-monitor.ts +240 -0
  214. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/skill-installer.ts +275 -0
  215. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/smith-memory.ts +498 -0
  216. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/types.ts +241 -0
  217. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/watch-manager.ts +560 -0
  218. package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace-standalone.ts +978 -0
  219. package/.forge/worktrees/pipeline-4dd8dc2d/middleware.ts +51 -0
  220. package/.forge/worktrees/pipeline-4dd8dc2d/next.config.ts +26 -0
  221. package/.forge/worktrees/pipeline-4dd8dc2d/package.json +74 -0
  222. package/.forge/worktrees/pipeline-4dd8dc2d/pnpm-lock.yaml +3719 -0
  223. package/.forge/worktrees/pipeline-4dd8dc2d/pnpm-workspace.yaml +1 -0
  224. package/.forge/worktrees/pipeline-4dd8dc2d/postcss.config.mjs +7 -0
  225. package/.forge/worktrees/pipeline-4dd8dc2d/publish.sh +133 -0
  226. package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/README.md +66 -0
  227. package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/results/.gitignore +2 -0
  228. package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/run.ts +635 -0
  229. package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/tasks/01-text-utils/task.md +26 -0
  230. package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/tasks/01-text-utils/validator.sh +46 -0
  231. package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/tasks/02-pagination/setup.sh +19 -0
  232. package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/tasks/02-pagination/task.md +48 -0
  233. package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/tasks/02-pagination/validator.sh +69 -0
  234. package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/tasks/03-bug-fix/setup.sh +82 -0
  235. package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/tasks/03-bug-fix/task.md +30 -0
  236. package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/tasks/03-bug-fix/validator.sh +29 -0
  237. package/.forge/worktrees/pipeline-4dd8dc2d/scripts/verify-usage.ts +178 -0
  238. package/.forge/worktrees/pipeline-4dd8dc2d/src/config/index.ts +129 -0
  239. package/.forge/worktrees/pipeline-4dd8dc2d/src/core/db/database.ts +259 -0
  240. package/.forge/worktrees/pipeline-4dd8dc2d/src/core/memory/strategy.ts +32 -0
  241. package/.forge/worktrees/pipeline-4dd8dc2d/src/core/providers/chat.ts +65 -0
  242. package/.forge/worktrees/pipeline-4dd8dc2d/src/core/providers/registry.ts +60 -0
  243. package/.forge/worktrees/pipeline-4dd8dc2d/src/core/session/manager.ts +190 -0
  244. package/.forge/worktrees/pipeline-4dd8dc2d/src/types/index.ts +129 -0
  245. package/.forge/worktrees/pipeline-4dd8dc2d/start.sh +32 -0
  246. package/.forge/worktrees/pipeline-4dd8dc2d/templates/smith-lead.json +45 -0
  247. package/.forge/worktrees/pipeline-4dd8dc2d/tsconfig.json +42 -0
  248. package/RELEASE_NOTES.md +10 -29
  249. package/app/api/terminal-bell/route.ts +6 -2
  250. package/app/api/terminal-cwd/route.ts +7 -4
  251. package/components/CodeViewer.tsx +3 -31
  252. package/components/Dashboard.tsx +34 -20
  253. package/components/WebTerminal.tsx +36 -2
  254. package/lib/terminal-standalone.ts +19 -2
  255. package/package.json +1 -1
@@ -0,0 +1,579 @@
1
+ #!/usr/bin/env npx tsx
2
+ /**
3
+ * forge — Forge CLI
4
+ *
5
+ * Local CLI that talks to the same backend as Telegram.
6
+ * Usage:
7
+ * mw task <project> "prompt" — submit a task
8
+ * mw run <flow-name> — run a YAML workflow
9
+ * mw tasks [status] — list tasks
10
+ * mw log <id> — show task execution log
11
+ * mw status <id> — task details
12
+ * mw cancel <id> — cancel a task
13
+ * mw retry <id> — retry a failed task
14
+ * mw flows — list available workflows
15
+ * mw projects — list projects
16
+ * mw watch <id> — live stream task output
17
+ */
18
+
19
+ const _cliPort = process.argv.find((a, i) => i > 0 && process.argv[i - 1] === '--port');
20
+ const BASE = process.env.MW_URL || `http://localhost:${_cliPort || '3000'}`;
21
+
22
+ const [, , cmd, ...args] = process.argv;
23
+
24
+ /** Check npm for newer version, print reminder if available */
25
+ async function checkForUpdate() {
26
+ try {
27
+ const { readFileSync } = await import('node:fs');
28
+ const { join, dirname } = await import('node:path');
29
+ const { fileURLToPath } = await import('node:url');
30
+ const pkg = JSON.parse(readFileSync(join(dirname(fileURLToPath(import.meta.url)), '..', 'package.json'), 'utf-8'));
31
+ const current = pkg.version;
32
+
33
+ const controller = new AbortController();
34
+ const timeout = setTimeout(() => controller.abort(), 3000);
35
+ const res = await fetch('https://registry.npmjs.org/@aion0/forge/latest', {
36
+ signal: controller.signal,
37
+ headers: { 'Accept': 'application/json' },
38
+ });
39
+ clearTimeout(timeout);
40
+ if (!res.ok) return;
41
+ const data = await res.json();
42
+ const latest = data.version;
43
+
44
+ const [ca, cb, cc] = current.split('.').map(Number);
45
+ const [la, lb, lc] = latest.split('.').map(Number);
46
+ if (la > ca || (la === ca && lb > cb) || (la === ca && lb === cb && lc > cc)) {
47
+ console.log(`\n Update available: v${current} → v${latest}`);
48
+ console.log(` Run: forge upgrade\n`);
49
+ }
50
+ } catch {}
51
+ }
52
+
53
+ async function api(path: string, opts?: RequestInit) {
54
+ const res = await fetch(`${BASE}${path}`, opts);
55
+ if (!res.ok) {
56
+ const text = await res.text();
57
+ console.error(`Error ${res.status}: ${text}`);
58
+ process.exit(1);
59
+ }
60
+ return res.json();
61
+ }
62
+
63
+ async function main() {
64
+ if (cmd === '--version' || cmd === '-v') {
65
+ const { readFileSync } = await import('node:fs');
66
+ const { join, dirname } = await import('node:path');
67
+ const { fileURLToPath } = await import('node:url');
68
+ try {
69
+ const pkg = JSON.parse(readFileSync(join(dirname(fileURLToPath(import.meta.url)), '..', 'package.json'), 'utf-8'));
70
+ console.log(`@aion0/forge v${pkg.version}`);
71
+ } catch {
72
+ console.log('forge (version unknown)');
73
+ }
74
+ process.exit(0);
75
+ }
76
+
77
+ if (cmd === '--reset-password') {
78
+ // Shortcut: delegate to forge-server.mjs --reset-password
79
+ const { execSync } = await import('node:child_process');
80
+ const { join, dirname } = await import('node:path');
81
+ const { fileURLToPath } = await import('node:url');
82
+ const serverScript = join(dirname(fileURLToPath(import.meta.url)), '..', 'bin', 'forge-server.mjs');
83
+ try {
84
+ execSync(`node ${serverScript} --reset-password`, { stdio: 'inherit' });
85
+ } catch {}
86
+ process.exit(0);
87
+ }
88
+
89
+ switch (cmd) {
90
+ case 'task':
91
+ case 't': {
92
+ // Parse --new flag to force a fresh session
93
+ const newSession = args.includes('--new');
94
+ const filtered = args.filter(a => a !== '--new');
95
+ const project = filtered[0];
96
+ const prompt = filtered.slice(1).join(' ');
97
+ if (!project || !prompt) {
98
+ console.log('Usage: mw task <project> <prompt> [--new]');
99
+ console.log(' --new Start a fresh session (ignore previous context)');
100
+ console.log('Example: mw task my-app "Fix the login bug"');
101
+ process.exit(1);
102
+ }
103
+ const task = await api('/api/tasks', {
104
+ method: 'POST',
105
+ headers: { 'Content-Type': 'application/json' },
106
+ body: JSON.stringify({ projectName: project, prompt, newSession }),
107
+ });
108
+ const session = task.conversationId ? '(continuing session)' : '(new session)';
109
+ console.log(`✓ Task ${task.id} created ${session}`);
110
+ console.log(` Project: ${task.projectName}`);
111
+ console.log(` ${prompt}`);
112
+ console.log(`\n Watch: mw watch ${task.id}`);
113
+ console.log(` Status: mw status ${task.id}`);
114
+ break;
115
+ }
116
+
117
+ case 'run':
118
+ case 'r': {
119
+ const flowName = args[0];
120
+ if (!flowName) {
121
+ console.log('Usage: mw run <flow-name>');
122
+ console.log('List flows: mw flows');
123
+ process.exit(1);
124
+ }
125
+ const result = await api('/api/flows/run', {
126
+ method: 'POST',
127
+ headers: { 'Content-Type': 'application/json' },
128
+ body: JSON.stringify({ name: flowName }),
129
+ });
130
+ console.log(`✓ Flow "${flowName}" started`);
131
+ for (const t of result.tasks) {
132
+ console.log(` Task ${t.id}: ${t.projectName} — ${t.prompt.slice(0, 60)}`);
133
+ }
134
+ break;
135
+ }
136
+
137
+ case 'tasks':
138
+ case 'ls': {
139
+ const status = args[0] || '';
140
+ const query = status ? `?status=${status}` : '';
141
+ const tasks = await api(`/api/tasks${query}`);
142
+ if (tasks.length === 0) {
143
+ console.log('No tasks.');
144
+ break;
145
+ }
146
+ const icons: Record<string, string> = {
147
+ queued: '⏳', running: '🔄', done: '✅', failed: '❌', cancelled: '⚪',
148
+ };
149
+ for (const t of tasks) {
150
+ const icon = icons[t.status] || '?';
151
+ const cost = t.costUSD != null ? ` $${t.costUSD.toFixed(3)}` : '';
152
+ console.log(`${icon} ${t.id} ${t.status.padEnd(9)} ${t.projectName.padEnd(20)} ${t.prompt.slice(0, 50)}${cost}`);
153
+ }
154
+ break;
155
+ }
156
+
157
+ case 's': {
158
+ const id = args[0];
159
+ if (!id) { console.log('Usage: forge status <id>'); process.exit(1); }
160
+ const task = await api(`/api/tasks/${id}`);
161
+ console.log(`Task: ${task.id}`);
162
+ console.log(`Project: ${task.projectName} (${task.projectPath})`);
163
+ console.log(`Status: ${task.status}`);
164
+ console.log(`Prompt: ${task.prompt}`);
165
+ if (task.startedAt) console.log(`Started: ${task.startedAt}`);
166
+ if (task.completedAt) console.log(`Completed: ${task.completedAt}`);
167
+ if (task.costUSD != null) console.log(`Cost: $${task.costUSD.toFixed(4)}`);
168
+ if (task.error) console.log(`Error: ${task.error}`);
169
+ if (task.resultSummary) {
170
+ console.log(`\nResult:\n${task.resultSummary}`);
171
+ }
172
+ if (task.gitDiff) {
173
+ console.log(`\nGit Diff:\n${task.gitDiff.slice(0, 2000)}`);
174
+ }
175
+ break;
176
+ }
177
+
178
+ case 'log':
179
+ case 'l': {
180
+ const id = args[0];
181
+ if (!id) { console.log('Usage: mw log <id>'); process.exit(1); }
182
+ const task = await api(`/api/tasks/${id}`);
183
+ if (task.log.length === 0) {
184
+ console.log('No log entries.');
185
+ break;
186
+ }
187
+ for (const entry of task.log) {
188
+ const prefix = entry.subtype === 'tool_use' ? `🔧 [${entry.tool}]`
189
+ : entry.subtype === 'error' ? '❗'
190
+ : entry.type === 'result' ? '✅'
191
+ : entry.subtype === 'tool_result' ? ' ↳'
192
+ : ' ';
193
+ console.log(`${prefix} ${entry.content.slice(0, 300)}`);
194
+ }
195
+ break;
196
+ }
197
+
198
+ case 'watch':
199
+ case 'w': {
200
+ const id = args[0];
201
+ if (!id) { console.log('Usage: mw watch <id>'); process.exit(1); }
202
+ console.log(`Watching task ${id}... (Ctrl+C to stop)\n`);
203
+
204
+ const res = await fetch(`${BASE}/api/tasks/${id}/stream`);
205
+ if (!res.ok || !res.body) {
206
+ console.error('Failed to connect to stream');
207
+ process.exit(1);
208
+ }
209
+
210
+ const reader = res.body.getReader();
211
+ const decoder = new TextDecoder();
212
+ let buffer = '';
213
+
214
+ while (true) {
215
+ const { done, value } = await reader.read();
216
+ if (done) break;
217
+
218
+ buffer += decoder.decode(value, { stream: true });
219
+ const lines = buffer.split('\n');
220
+ buffer = lines.pop() || '';
221
+
222
+ for (const line of lines) {
223
+ if (!line.startsWith('data: ')) continue;
224
+ try {
225
+ const data = JSON.parse(line.slice(6));
226
+ if (data.type === 'log') {
227
+ const e = data.entry;
228
+ if (e.subtype === 'tool_use') {
229
+ console.log(`🔧 [${e.tool}] ${e.content.slice(0, 200)}`);
230
+ } else if (e.subtype === 'text') {
231
+ process.stdout.write(e.content);
232
+ } else if (e.type === 'result') {
233
+ console.log(`\n✅ ${e.content}`);
234
+ } else if (e.subtype === 'error') {
235
+ console.log(`❗ ${e.content}`);
236
+ }
237
+ } else if (data.type === 'status') {
238
+ if (data.status === 'done') {
239
+ console.log('\n✅ Task completed');
240
+ } else if (data.status === 'failed') {
241
+ console.log('\n❌ Task failed');
242
+ } else if (data.status === 'running') {
243
+ console.log('🚀 Started...\n');
244
+ }
245
+ } else if (data.type === 'complete') {
246
+ if (data.task?.costUSD != null) {
247
+ console.log(`Cost: $${data.task.costUSD.toFixed(4)}`);
248
+ }
249
+ process.exit(0);
250
+ }
251
+ } catch {}
252
+ }
253
+ }
254
+ break;
255
+ }
256
+
257
+ case 'cancel': {
258
+ const id = args[0];
259
+ if (!id) { console.log('Usage: mw cancel <id>'); process.exit(1); }
260
+ await api(`/api/tasks/${id}`, {
261
+ method: 'POST',
262
+ headers: { 'Content-Type': 'application/json' },
263
+ body: JSON.stringify({ action: 'cancel' }),
264
+ });
265
+ console.log(`✓ Task ${id} cancelled`);
266
+ break;
267
+ }
268
+
269
+ case 'retry': {
270
+ const id = args[0];
271
+ if (!id) { console.log('Usage: mw retry <id>'); process.exit(1); }
272
+ const task = await api(`/api/tasks/${id}`, {
273
+ method: 'POST',
274
+ headers: { 'Content-Type': 'application/json' },
275
+ body: JSON.stringify({ action: 'retry' }),
276
+ });
277
+ console.log(`✓ Retrying as task ${task.id}`);
278
+ break;
279
+ }
280
+
281
+ case 'flows':
282
+ case 'f': {
283
+ const flows = await api('/api/flows');
284
+ if (flows.length === 0) {
285
+ console.log('No flows defined.');
286
+ console.log(`Create flows in ~/.forge/flows/*.yaml`);
287
+ break;
288
+ }
289
+ for (const f of flows) {
290
+ const schedule = f.schedule ? ` (${f.schedule})` : '';
291
+ console.log(` ${f.name}${schedule} — ${f.steps.length} steps`);
292
+ }
293
+ break;
294
+ }
295
+
296
+ case 'session': {
297
+ const subCmd = args[0];
298
+
299
+ // mw session link <project> <session-id> — register a local CLI session
300
+ if (subCmd === 'link') {
301
+ const project = args[1];
302
+ const sessionId = args[2];
303
+ if (!project || !sessionId) {
304
+ console.log('Usage: mw session link <project> <session-id>');
305
+ console.log('\nFind your session ID:');
306
+ console.log(' In Claude Code CLI, look for the session ID in the output');
307
+ console.log(' Or check: ls ~/.claude/projects/');
308
+ process.exit(1);
309
+ }
310
+ const result = await api('/api/tasks/link', {
311
+ method: 'POST',
312
+ headers: { 'Content-Type': 'application/json' },
313
+ body: JSON.stringify({ projectName: project, conversationId: sessionId }),
314
+ });
315
+ console.log(`✓ Linked session ${sessionId} to project ${result.projectName}`);
316
+ console.log(` Future "mw task ${result.projectName} ..." will continue this session`);
317
+ break;
318
+ }
319
+
320
+ // mw session (no args) — list all project sessions
321
+ if (!subCmd) {
322
+ const tasks = await api('/api/tasks?status=done');
323
+ const sessions = new Map<string, { id: string; project: string; path: string; lastUsed: string }>();
324
+ for (const t of tasks) {
325
+ if (t.conversationId && !sessions.has(t.projectName)) {
326
+ sessions.set(t.projectName, {
327
+ id: t.conversationId,
328
+ project: t.projectName,
329
+ path: t.projectPath,
330
+ lastUsed: t.completedAt,
331
+ });
332
+ }
333
+ }
334
+ if (sessions.size === 0) {
335
+ console.log('No active sessions. Submit a task first, or link a local session:');
336
+ console.log(' mw session link <project> <session-id>');
337
+ break;
338
+ }
339
+ console.log('Project sessions:\n');
340
+ for (const [name, s] of sessions) {
341
+ console.log(` ${name.padEnd(25)} ${s.id}`);
342
+ console.log(` ${''.padEnd(25)} cd ${s.path} && claude --resume ${s.id}`);
343
+ console.log();
344
+ }
345
+ break;
346
+ }
347
+
348
+ // mw session <project> — get session for specific project
349
+ const project = subCmd;
350
+ const tasks = await api('/api/tasks?status=done');
351
+ const match = tasks.find((t: any) => t.projectName === project && t.conversationId);
352
+ if (!match) {
353
+ console.log(`No session found for project: ${project}`);
354
+ console.log(`\nLink a local session: mw session link ${project} <session-id>`);
355
+ break;
356
+ }
357
+ console.log(`Project: ${match.projectName}`);
358
+ console.log(`Session: ${match.conversationId}`);
359
+ console.log(`Path: ${match.projectPath}`);
360
+ console.log(`\nResume in CLI:`);
361
+ console.log(` cd ${match.projectPath} && claude --resume ${match.conversationId}`);
362
+ break;
363
+ }
364
+
365
+ case 'tunnel_code':
366
+ case 'tcode': {
367
+ const { readFileSync, existsSync } = await import('node:fs');
368
+ const { join } = await import('node:path');
369
+ const { getDataDir: _gdd } = await import('../lib/dirs');
370
+ const dataDir = _gdd();
371
+ const codeFile = join(dataDir, 'session-code.json');
372
+ try {
373
+ if (existsSync(codeFile)) {
374
+ const data = JSON.parse(readFileSync(codeFile, 'utf-8'));
375
+ if (data.code) {
376
+ console.log(`Session code: ${data.code}`);
377
+ } else {
378
+ console.log('No session code. Start tunnel first.');
379
+ }
380
+ } else {
381
+ console.log('No session code. Start tunnel first.');
382
+ }
383
+ } catch {}
384
+ // Also show tunnel URL if running
385
+ try {
386
+ const tunnelState = JSON.parse(readFileSync(join(dataDir, 'tunnel-state.json'), 'utf-8'));
387
+ if (tunnelState.url) console.log(`Tunnel URL: ${tunnelState.url}`);
388
+ } catch {}
389
+ break;
390
+ }
391
+
392
+ case 'projects':
393
+ case 'p': {
394
+ const projects = await api('/api/projects');
395
+ for (const p of projects) {
396
+ const lang = p.language ? `[${p.language}]` : '';
397
+ console.log(` ${p.name.padEnd(25)} ${lang.padEnd(6)} ${p.path}`);
398
+ }
399
+ console.log(`\n${projects.length} projects`);
400
+ break;
401
+ }
402
+
403
+ case 'server': {
404
+ // Delegate to forge-server.mjs
405
+ const { execSync } = await import('node:child_process');
406
+ const { join, dirname } = await import('node:path');
407
+ const { fileURLToPath } = await import('node:url');
408
+ const serverScript = join(dirname(fileURLToPath(import.meta.url)), '..', 'bin', 'forge-server.mjs');
409
+ const sub = args[0] || 'start';
410
+ const serverArgs = args.slice(1);
411
+
412
+ const flagMap: Record<string, string[]> = {
413
+ 'start': [],
414
+ 'stop': ['--stop'],
415
+ 'restart': ['--restart'],
416
+ 'rebuild': ['--rebuild'],
417
+ 'dev': ['--dev'],
418
+ };
419
+
420
+ const flags = flagMap[sub] || [];
421
+ const allArgs = [...flags, ...serverArgs];
422
+
423
+ try {
424
+ execSync(`node ${serverScript} ${allArgs.join(' ')}`, { stdio: 'inherit' });
425
+ } catch {}
426
+ break;
427
+ }
428
+
429
+ case 'status': {
430
+ // If arg provided, show task details
431
+ if (args[0]) {
432
+ const task = await api(`/api/tasks/${args[0]}`);
433
+ console.log(`Task: ${task.id}`);
434
+ console.log(`Project: ${task.projectName} (${task.projectPath})`);
435
+ console.log(`Status: ${task.status}`);
436
+ console.log(`Prompt: ${task.prompt}`);
437
+ if (task.startedAt) console.log(`Started: ${task.startedAt}`);
438
+ if (task.completedAt) console.log(`Completed: ${task.completedAt}`);
439
+ if (task.costUSD != null) console.log(`Cost: $${task.costUSD.toFixed(4)}`);
440
+ if (task.error) console.log(`Error: ${task.error}`);
441
+ if (task.resultSummary) console.log(`\nResult:\n${task.resultSummary}`);
442
+ if (task.gitDiff) console.log(`\nGit Diff:\n${task.gitDiff.slice(0, 2000)}`);
443
+ break;
444
+ }
445
+
446
+ // No arg — show process status
447
+ const { execSync } = await import('node:child_process');
448
+
449
+ const check = (pattern: string) => {
450
+ try {
451
+ const out = execSync(`ps aux | grep '${pattern}' | grep -v grep | head -1`, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
452
+ return out ? out.split(/\s+/)[1] : null;
453
+ } catch { return null; }
454
+ };
455
+
456
+ const nextPid = check('next-server');
457
+ const termPid = check('terminal-standalone');
458
+ const telePid = check('telegram-standalone');
459
+ const tunnPid = check('cloudflared tunnel');
460
+
461
+ console.log('');
462
+ console.log(` ${nextPid ? '●' : '○'} Next.js ${nextPid ? `running (pid: ${nextPid})` : 'stopped'}`);
463
+ console.log(` ${termPid ? '●' : '○'} Terminal ${termPid ? `running (pid: ${termPid})` : 'stopped'}`);
464
+ console.log(` ${telePid ? '●' : '○'} Telegram ${telePid ? `running (pid: ${telePid})` : 'stopped'}`);
465
+ console.log(` ${tunnPid ? '●' : '○'} Tunnel ${tunnPid ? `running (pid: ${tunnPid})` : 'stopped'}`);
466
+
467
+ try {
468
+ const { execSync: ex } = await import('node:child_process');
469
+ const sessions = ex("tmux list-sessions -F '#{session_name} #{session_attached}' 2>/dev/null", { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] })
470
+ .trim().split('\n').filter(l => l.startsWith('mw-'));
471
+ console.log(`\n Sessions: ${sessions.length}`);
472
+ for (const s of sessions) {
473
+ const [name, att] = s.split(' ');
474
+ console.log(` ${att !== '0' ? '●' : '○'} ${name}`);
475
+ }
476
+ } catch {
477
+ console.log('\n Sessions: 0');
478
+ }
479
+ console.log('');
480
+ break;
481
+ }
482
+
483
+ case 'upgrade': {
484
+ const { execSync } = await import('node:child_process');
485
+ const { lstatSync } = await import('node:fs');
486
+ const { join, dirname } = await import('node:path');
487
+ const { fileURLToPath } = await import('node:url');
488
+
489
+ // Check if installed via npm link (symlink)
490
+ const cliDir = dirname(fileURLToPath(import.meta.url));
491
+ let isLinked = false;
492
+ try { isLinked = lstatSync(join(cliDir, '..')).isSymbolicLink(); } catch {}
493
+
494
+ if (isLinked) {
495
+ console.log('[forge] Installed via npm link (local source)');
496
+ console.log('[forge] Pull latest and rebuild:');
497
+ console.log(' cd ' + join(cliDir, '..'));
498
+ console.log(' git pull && pnpm install && pnpm build');
499
+ } else {
500
+ console.log('[forge] Upgrading from npm...');
501
+ try {
502
+ const { homedir } = await import('node:os');
503
+ execSync('npm install -g @aion0/forge@latest --prefer-online', {
504
+ stdio: 'inherit',
505
+ cwd: homedir(),
506
+ });
507
+ // Show installed version
508
+ try {
509
+ const { readFileSync } = await import('node:fs');
510
+ const globalRoot = execSync('npm root -g', { encoding: 'utf-8', cwd: homedir() }).trim();
511
+ const pkg = JSON.parse(readFileSync(join(globalRoot, '@aion0', 'forge', 'package.json'), 'utf-8'));
512
+ console.log(`[forge] Upgraded to v${pkg.version}. Run: forge server restart`);
513
+ } catch {
514
+ console.log('[forge] Upgraded. Run: forge server restart');
515
+ }
516
+ } catch {
517
+ console.log('[forge] Upgrade failed');
518
+ }
519
+ }
520
+ break;
521
+ }
522
+
523
+ case 'uninstall': {
524
+ const { execSync } = await import('node:child_process');
525
+ console.log('[forge] Stopping server...');
526
+ try { execSync('forge server stop', { stdio: 'inherit' }); } catch {}
527
+ console.log('[forge] Uninstalling...');
528
+ try {
529
+ execSync('npm uninstall -g @aion0/forge', { stdio: 'inherit' });
530
+ console.log('[forge] Uninstalled. Data remains in ~/.forge/');
531
+ } catch {
532
+ console.log('[forge] Uninstall failed');
533
+ }
534
+ break;
535
+ }
536
+
537
+ default:
538
+ console.log(`forge — Forge CLI (@aion0/forge)
539
+
540
+ Usage:
541
+ forge server start [options] Start server (default: foreground)
542
+ forge server stop Stop server
543
+ forge server restart Restart server (safe for remote)
544
+ forge server dev Start in dev mode
545
+ forge server rebuild Force rebuild
546
+
547
+ forge task <project> <prompt> Submit a task
548
+ forge tasks [status] List tasks
549
+ forge watch <id> Live stream output
550
+ forge status [<id>] Process status / task details
551
+ forge log <id> Show execution log
552
+ forge cancel <id> Cancel a task
553
+ forge retry <id> Retry a failed task
554
+
555
+ forge run <flow> Run a workflow
556
+ forge flows List workflows
557
+ forge projects List projects
558
+ forge session [project] Show session info
559
+ forge password Show login password
560
+
561
+ forge upgrade Update to latest version
562
+ forge uninstall Remove forge
563
+
564
+ Options for 'forge server start':
565
+ --port 4000 Custom web port (default: 8403)
566
+ --terminal-port 4001 Custom terminal port (default: 8404)
567
+ --dir ~/.forge-staging Custom data directory
568
+ --background Run in background
569
+ --reset-terminal Kill terminal server on start
570
+
571
+ Shortcuts: t=task, ls=tasks, w=watch, s=status, l=log, f=flows, p=projects, pw=password`);
572
+ }
573
+ }
574
+
575
+ const skipUpdateCheck = ['upgrade', 'uninstall', '--version', '-v', '--reset-password'];
576
+ main().then(() => { if (!skipUpdateCheck.includes(cmd)) return checkForUpdate(); }).catch(err => {
577
+ console.error(err.message);
578
+ process.exit(1);
579
+ });