@swarmclawai/swarmclaw 0.2.0

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 (319) hide show
  1. package/README.md +577 -0
  2. package/bin/server-cmd.js +359 -0
  3. package/bin/swarmclaw.js +29 -0
  4. package/bin/swarmclaw.mjs +1504 -0
  5. package/next.config.ts +33 -0
  6. package/package.json +112 -0
  7. package/postcss.config.mjs +7 -0
  8. package/public/branding/swarmclaw-org-avatar.png +0 -0
  9. package/public/branding/swarmclaw-org-avatar.svg +58 -0
  10. package/public/file.svg +1 -0
  11. package/public/globe.svg +1 -0
  12. package/public/next.svg +1 -0
  13. package/public/screenshots/agents.png +0 -0
  14. package/public/screenshots/connectors.png +0 -0
  15. package/public/screenshots/dashboard.png +0 -0
  16. package/public/screenshots/new-session-openclaw.png +0 -0
  17. package/public/screenshots/providers.png +0 -0
  18. package/public/screenshots/schedules.png +0 -0
  19. package/public/screenshots/tasks.png +0 -0
  20. package/public/vercel.svg +1 -0
  21. package/public/window.svg +1 -0
  22. package/src/app/api/agents/[id]/route.ts +30 -0
  23. package/src/app/api/agents/[id]/thread/route.ts +66 -0
  24. package/src/app/api/agents/generate/route.ts +42 -0
  25. package/src/app/api/agents/route.ts +33 -0
  26. package/src/app/api/auth/route.ts +25 -0
  27. package/src/app/api/claude-skills/route.ts +42 -0
  28. package/src/app/api/clawhub/install/route.ts +39 -0
  29. package/src/app/api/clawhub/search/route.ts +11 -0
  30. package/src/app/api/connectors/[id]/route.ts +79 -0
  31. package/src/app/api/connectors/route.ts +60 -0
  32. package/src/app/api/credentials/[id]/route.ts +14 -0
  33. package/src/app/api/credentials/route.ts +31 -0
  34. package/src/app/api/daemon/health-check/route.ts +11 -0
  35. package/src/app/api/daemon/route.ts +22 -0
  36. package/src/app/api/dirs/pick/route.ts +60 -0
  37. package/src/app/api/dirs/route.ts +29 -0
  38. package/src/app/api/documents/[id]/route.ts +47 -0
  39. package/src/app/api/documents/route.ts +93 -0
  40. package/src/app/api/files/serve/route.ts +69 -0
  41. package/src/app/api/generate/info/route.ts +12 -0
  42. package/src/app/api/generate/route.ts +106 -0
  43. package/src/app/api/ip/route.ts +6 -0
  44. package/src/app/api/knowledge/[id]/route.ts +61 -0
  45. package/src/app/api/knowledge/route.ts +48 -0
  46. package/src/app/api/knowledge/upload/route.ts +86 -0
  47. package/src/app/api/logs/route.ts +65 -0
  48. package/src/app/api/mcp-servers/[id]/route.ts +32 -0
  49. package/src/app/api/mcp-servers/[id]/test/route.ts +23 -0
  50. package/src/app/api/mcp-servers/[id]/tools/route.ts +32 -0
  51. package/src/app/api/mcp-servers/route.ts +27 -0
  52. package/src/app/api/memory/[id]/route.ts +126 -0
  53. package/src/app/api/memory/maintenance/route.ts +63 -0
  54. package/src/app/api/memory/route.ts +111 -0
  55. package/src/app/api/memory-images/[filename]/route.ts +36 -0
  56. package/src/app/api/orchestrator/run/route.ts +43 -0
  57. package/src/app/api/plugins/install/route.ts +58 -0
  58. package/src/app/api/plugins/marketplace/route.ts +33 -0
  59. package/src/app/api/plugins/route.ts +21 -0
  60. package/src/app/api/preview-server/route.ts +339 -0
  61. package/src/app/api/providers/[id]/models/route.ts +29 -0
  62. package/src/app/api/providers/[id]/route.ts +34 -0
  63. package/src/app/api/providers/configs/route.ts +7 -0
  64. package/src/app/api/providers/ollama/route.ts +30 -0
  65. package/src/app/api/providers/openclaw/health/route.ts +23 -0
  66. package/src/app/api/providers/route.ts +28 -0
  67. package/src/app/api/runs/[id]/route.ts +9 -0
  68. package/src/app/api/runs/route.ts +13 -0
  69. package/src/app/api/schedules/[id]/route.ts +28 -0
  70. package/src/app/api/schedules/[id]/run/route.ts +104 -0
  71. package/src/app/api/schedules/route.ts +78 -0
  72. package/src/app/api/secrets/[id]/route.ts +29 -0
  73. package/src/app/api/secrets/route.ts +42 -0
  74. package/src/app/api/sessions/[id]/browser/route.ts +13 -0
  75. package/src/app/api/sessions/[id]/chat/route.ts +96 -0
  76. package/src/app/api/sessions/[id]/clear/route.ts +19 -0
  77. package/src/app/api/sessions/[id]/deploy/route.ts +34 -0
  78. package/src/app/api/sessions/[id]/devserver/route.ts +69 -0
  79. package/src/app/api/sessions/[id]/mailbox/route.ts +70 -0
  80. package/src/app/api/sessions/[id]/main-loop/route.ts +94 -0
  81. package/src/app/api/sessions/[id]/messages/route.ts +9 -0
  82. package/src/app/api/sessions/[id]/retry/route.ts +28 -0
  83. package/src/app/api/sessions/[id]/route.ts +103 -0
  84. package/src/app/api/sessions/[id]/stop/route.ts +13 -0
  85. package/src/app/api/sessions/heartbeat/route.ts +26 -0
  86. package/src/app/api/sessions/route.ts +85 -0
  87. package/src/app/api/settings/route.ts +58 -0
  88. package/src/app/api/setup/check-provider/route.ts +326 -0
  89. package/src/app/api/setup/doctor/route.ts +250 -0
  90. package/src/app/api/skills/[id]/route.ts +40 -0
  91. package/src/app/api/skills/import/route.ts +69 -0
  92. package/src/app/api/skills/route.ts +28 -0
  93. package/src/app/api/tasks/[id]/route.ts +102 -0
  94. package/src/app/api/tasks/route.ts +115 -0
  95. package/src/app/api/tts/route.ts +40 -0
  96. package/src/app/api/upload/route.ts +18 -0
  97. package/src/app/api/uploads/[filename]/route.ts +59 -0
  98. package/src/app/api/usage/route.ts +35 -0
  99. package/src/app/api/version/route.ts +81 -0
  100. package/src/app/api/version/update/route.ts +95 -0
  101. package/src/app/api/webhooks/[id]/history/route.ts +13 -0
  102. package/src/app/api/webhooks/[id]/route.ts +204 -0
  103. package/src/app/api/webhooks/route.ts +37 -0
  104. package/src/app/favicon.ico +0 -0
  105. package/src/app/globals.css +370 -0
  106. package/src/app/layout.tsx +52 -0
  107. package/src/app/page.tsx +172 -0
  108. package/src/cli/index.js +1232 -0
  109. package/src/cli/index.test.js +281 -0
  110. package/src/cli/index.ts +1158 -0
  111. package/src/cli/spec.js +284 -0
  112. package/src/components/agents/agent-card.tsx +219 -0
  113. package/src/components/agents/agent-chat-list.tsx +165 -0
  114. package/src/components/agents/agent-list.tsx +110 -0
  115. package/src/components/agents/agent-sheet.tsx +1220 -0
  116. package/src/components/auth/access-key-gate.tsx +248 -0
  117. package/src/components/auth/setup-wizard.tsx +940 -0
  118. package/src/components/auth/user-picker.tsx +88 -0
  119. package/src/components/chat/chat-area.tsx +406 -0
  120. package/src/components/chat/chat-header.tsx +491 -0
  121. package/src/components/chat/chat-tool-toggles.tsx +161 -0
  122. package/src/components/chat/code-block.tsx +146 -0
  123. package/src/components/chat/dev-server-bar.tsx +39 -0
  124. package/src/components/chat/message-bubble.tsx +486 -0
  125. package/src/components/chat/message-list.tsx +299 -0
  126. package/src/components/chat/session-debug-panel.tsx +196 -0
  127. package/src/components/chat/streaming-bubble.tsx +85 -0
  128. package/src/components/chat/thinking-indicator.tsx +26 -0
  129. package/src/components/chat/tool-call-bubble.tsx +438 -0
  130. package/src/components/chat/tool-request-banner.tsx +103 -0
  131. package/src/components/connectors/connector-list.tsx +196 -0
  132. package/src/components/connectors/connector-sheet.tsx +804 -0
  133. package/src/components/input/chat-input.tsx +235 -0
  134. package/src/components/knowledge/knowledge-list.tsx +206 -0
  135. package/src/components/knowledge/knowledge-sheet.tsx +316 -0
  136. package/src/components/layout/app-layout.tsx +1016 -0
  137. package/src/components/layout/daemon-indicator.tsx +56 -0
  138. package/src/components/layout/mobile-header.tsx +31 -0
  139. package/src/components/layout/network-banner.tsx +17 -0
  140. package/src/components/layout/update-banner.tsx +130 -0
  141. package/src/components/logs/log-list.tsx +358 -0
  142. package/src/components/mcp-servers/mcp-server-list.tsx +122 -0
  143. package/src/components/mcp-servers/mcp-server-sheet.tsx +243 -0
  144. package/src/components/memory/memory-card.tsx +63 -0
  145. package/src/components/memory/memory-detail.tsx +339 -0
  146. package/src/components/memory/memory-list.tsx +198 -0
  147. package/src/components/memory/memory-sheet.tsx +70 -0
  148. package/src/components/plugins/plugin-list.tsx +60 -0
  149. package/src/components/plugins/plugin-sheet.tsx +311 -0
  150. package/src/components/providers/provider-list.tsx +96 -0
  151. package/src/components/providers/provider-sheet.tsx +542 -0
  152. package/src/components/runs/run-list.tsx +231 -0
  153. package/src/components/schedules/schedule-card.tsx +63 -0
  154. package/src/components/schedules/schedule-list.tsx +76 -0
  155. package/src/components/schedules/schedule-sheet.tsx +336 -0
  156. package/src/components/secrets/secret-sheet.tsx +180 -0
  157. package/src/components/secrets/secrets-list.tsx +91 -0
  158. package/src/components/sessions/new-session-sheet.tsx +478 -0
  159. package/src/components/sessions/session-card.tsx +144 -0
  160. package/src/components/sessions/session-list.tsx +202 -0
  161. package/src/components/shared/ai-gen-block.tsx +77 -0
  162. package/src/components/shared/avatar.tsx +48 -0
  163. package/src/components/shared/bottom-sheet.tsx +30 -0
  164. package/src/components/shared/confirm-dialog.tsx +47 -0
  165. package/src/components/shared/connector-platform-icon.tsx +113 -0
  166. package/src/components/shared/dir-browser.tsx +285 -0
  167. package/src/components/shared/dropdown.tsx +55 -0
  168. package/src/components/shared/icon-button.tsx +25 -0
  169. package/src/components/shared/settings/plugin-manager.tsx +207 -0
  170. package/src/components/shared/settings/section-capability-policy.tsx +93 -0
  171. package/src/components/shared/settings/section-embedding.tsx +99 -0
  172. package/src/components/shared/settings/section-heartbeat.tsx +168 -0
  173. package/src/components/shared/settings/section-memory.tsx +77 -0
  174. package/src/components/shared/settings/section-orchestrator.tsx +108 -0
  175. package/src/components/shared/settings/section-providers.tsx +181 -0
  176. package/src/components/shared/settings/section-runtime-loop.tsx +183 -0
  177. package/src/components/shared/settings/section-secrets.tsx +132 -0
  178. package/src/components/shared/settings/section-user-preferences.tsx +24 -0
  179. package/src/components/shared/settings/section-voice.tsx +53 -0
  180. package/src/components/shared/settings/settings-sheet.tsx +88 -0
  181. package/src/components/shared/settings/types.ts +7 -0
  182. package/src/components/shared/settings/utils.ts +13 -0
  183. package/src/components/shared/settings-sheet.tsx +1 -0
  184. package/src/components/shared/skeleton.tsx +19 -0
  185. package/src/components/shared/usage-badge.tsx +28 -0
  186. package/src/components/skills/clawhub-browser.tsx +225 -0
  187. package/src/components/skills/skill-list.tsx +70 -0
  188. package/src/components/skills/skill-sheet.tsx +254 -0
  189. package/src/components/tasks/task-board.tsx +96 -0
  190. package/src/components/tasks/task-card.tsx +179 -0
  191. package/src/components/tasks/task-column.tsx +73 -0
  192. package/src/components/tasks/task-list.tsx +118 -0
  193. package/src/components/tasks/task-sheet.tsx +415 -0
  194. package/src/components/ui/avatar.tsx +109 -0
  195. package/src/components/ui/badge.tsx +48 -0
  196. package/src/components/ui/button.tsx +64 -0
  197. package/src/components/ui/card.tsx +92 -0
  198. package/src/components/ui/dialog.tsx +158 -0
  199. package/src/components/ui/dropdown-menu.tsx +257 -0
  200. package/src/components/ui/input.tsx +21 -0
  201. package/src/components/ui/scroll-area.tsx +58 -0
  202. package/src/components/ui/select.tsx +190 -0
  203. package/src/components/ui/separator.tsx +28 -0
  204. package/src/components/ui/sheet.tsx +143 -0
  205. package/src/components/ui/sonner.tsx +22 -0
  206. package/src/components/ui/textarea.tsx +18 -0
  207. package/src/components/ui/tooltip.tsx +56 -0
  208. package/src/components/usage/usage-list.tsx +105 -0
  209. package/src/components/webhooks/webhook-list.tsx +166 -0
  210. package/src/components/webhooks/webhook-sheet.tsx +402 -0
  211. package/src/hooks/use-auto-resize.ts +20 -0
  212. package/src/hooks/use-media-query.ts +21 -0
  213. package/src/hooks/use-speech-recognition.ts +83 -0
  214. package/src/instrumentation.ts +8 -0
  215. package/src/lib/agents.ts +13 -0
  216. package/src/lib/api-client.ts +100 -0
  217. package/src/lib/chat.ts +60 -0
  218. package/src/lib/memory.ts +42 -0
  219. package/src/lib/openclaw-endpoint.test.ts +48 -0
  220. package/src/lib/openclaw-endpoint.ts +67 -0
  221. package/src/lib/provider-config.ts +13 -0
  222. package/src/lib/providers/anthropic.ts +135 -0
  223. package/src/lib/providers/claude-cli.ts +202 -0
  224. package/src/lib/providers/codex-cli.ts +260 -0
  225. package/src/lib/providers/index.ts +351 -0
  226. package/src/lib/providers/ollama.ts +131 -0
  227. package/src/lib/providers/openai.ts +164 -0
  228. package/src/lib/providers/openclaw.ts +330 -0
  229. package/src/lib/providers/opencode-cli.ts +164 -0
  230. package/src/lib/runtime-loop.ts +15 -0
  231. package/src/lib/schedule-dedupe.test.ts +84 -0
  232. package/src/lib/schedule-dedupe.ts +174 -0
  233. package/src/lib/schedule-name.ts +62 -0
  234. package/src/lib/schedules.ts +16 -0
  235. package/src/lib/server/agent-registry.ts +70 -0
  236. package/src/lib/server/api-routes.test.ts +362 -0
  237. package/src/lib/server/autonomy-contract.ts +200 -0
  238. package/src/lib/server/build-llm.ts +155 -0
  239. package/src/lib/server/capability-router.test.ts +21 -0
  240. package/src/lib/server/capability-router.ts +172 -0
  241. package/src/lib/server/chat-execution.ts +894 -0
  242. package/src/lib/server/clawhub-client.test.ts +161 -0
  243. package/src/lib/server/clawhub-client.ts +26 -0
  244. package/src/lib/server/connectors/connector-routing.test.ts +243 -0
  245. package/src/lib/server/connectors/discord.ts +116 -0
  246. package/src/lib/server/connectors/googlechat.ts +66 -0
  247. package/src/lib/server/connectors/manager.ts +559 -0
  248. package/src/lib/server/connectors/matrix.ts +78 -0
  249. package/src/lib/server/connectors/media.ts +149 -0
  250. package/src/lib/server/connectors/openclaw.test.ts +375 -0
  251. package/src/lib/server/connectors/openclaw.ts +1132 -0
  252. package/src/lib/server/connectors/signal.ts +183 -0
  253. package/src/lib/server/connectors/slack.ts +258 -0
  254. package/src/lib/server/connectors/teams.ts +94 -0
  255. package/src/lib/server/connectors/telegram.ts +221 -0
  256. package/src/lib/server/connectors/types.ts +62 -0
  257. package/src/lib/server/connectors/whatsapp.ts +349 -0
  258. package/src/lib/server/context-manager.ts +232 -0
  259. package/src/lib/server/cost.ts +31 -0
  260. package/src/lib/server/daemon-state.ts +354 -0
  261. package/src/lib/server/data-dir.ts +3 -0
  262. package/src/lib/server/embeddings.ts +111 -0
  263. package/src/lib/server/execution-log.ts +257 -0
  264. package/src/lib/server/gateway/protocol.test.ts +54 -0
  265. package/src/lib/server/gateway/protocol.ts +114 -0
  266. package/src/lib/server/heartbeat-service.ts +366 -0
  267. package/src/lib/server/knowledge-db.test.ts +441 -0
  268. package/src/lib/server/logger.ts +47 -0
  269. package/src/lib/server/main-agent-loop.ts +1017 -0
  270. package/src/lib/server/mcp-client.test.ts +342 -0
  271. package/src/lib/server/mcp-client.ts +130 -0
  272. package/src/lib/server/memory-db.ts +1078 -0
  273. package/src/lib/server/memory-graph.test.ts +153 -0
  274. package/src/lib/server/memory-graph.ts +138 -0
  275. package/src/lib/server/openclaw-health.ts +245 -0
  276. package/src/lib/server/orchestrator-lg.ts +431 -0
  277. package/src/lib/server/orchestrator.ts +364 -0
  278. package/src/lib/server/playwright-proxy.mjs +70 -0
  279. package/src/lib/server/plugins.ts +229 -0
  280. package/src/lib/server/process-manager.ts +327 -0
  281. package/src/lib/server/provider-health.ts +113 -0
  282. package/src/lib/server/queue.ts +859 -0
  283. package/src/lib/server/runtime-settings.ts +119 -0
  284. package/src/lib/server/scheduler.ts +196 -0
  285. package/src/lib/server/session-mailbox.ts +129 -0
  286. package/src/lib/server/session-run-manager.ts +512 -0
  287. package/src/lib/server/session-tools/connector.ts +124 -0
  288. package/src/lib/server/session-tools/context-mgmt.ts +103 -0
  289. package/src/lib/server/session-tools/context.ts +114 -0
  290. package/src/lib/server/session-tools/crud.ts +673 -0
  291. package/src/lib/server/session-tools/delegate.ts +708 -0
  292. package/src/lib/server/session-tools/file.ts +264 -0
  293. package/src/lib/server/session-tools/index.ts +164 -0
  294. package/src/lib/server/session-tools/memory.ts +230 -0
  295. package/src/lib/server/session-tools/session-info.ts +422 -0
  296. package/src/lib/server/session-tools/session-tools-wiring.test.ts +166 -0
  297. package/src/lib/server/session-tools/shell.ts +171 -0
  298. package/src/lib/server/session-tools/web.ts +408 -0
  299. package/src/lib/server/session-tools.ts +9 -0
  300. package/src/lib/server/skills-normalize.ts +130 -0
  301. package/src/lib/server/storage-mcp.test.ts +161 -0
  302. package/src/lib/server/storage.ts +670 -0
  303. package/src/lib/server/stream-agent-chat.ts +571 -0
  304. package/src/lib/server/task-reports.ts +122 -0
  305. package/src/lib/server/task-result.ts +161 -0
  306. package/src/lib/server/task-validation.test.ts +27 -0
  307. package/src/lib/server/task-validation.ts +90 -0
  308. package/src/lib/server/tool-capability-policy.test.ts +58 -0
  309. package/src/lib/server/tool-capability-policy.ts +262 -0
  310. package/src/lib/sessions.ts +68 -0
  311. package/src/lib/tasks.ts +20 -0
  312. package/src/lib/tts.ts +42 -0
  313. package/src/lib/upload.ts +10 -0
  314. package/src/lib/utils.ts +6 -0
  315. package/src/proxy.ts +43 -0
  316. package/src/stores/use-app-store.ts +468 -0
  317. package/src/stores/use-chat-store.ts +323 -0
  318. package/src/types/index.ts +621 -0
  319. package/tsconfig.json +34 -0
@@ -0,0 +1,359 @@
1
+ #!/usr/bin/env node
2
+ 'use strict'
3
+
4
+ const fs = require('node:fs')
5
+ const path = require('node:path')
6
+ const { spawn, execSync } = require('node:child_process')
7
+ const os = require('node:os')
8
+
9
+ // ---------------------------------------------------------------------------
10
+ // Paths
11
+ // ---------------------------------------------------------------------------
12
+
13
+ const SWARMCLAW_HOME = process.env.SWARMCLAW_HOME || path.join(os.homedir(), '.swarmclaw')
14
+ const PKG_ROOT = path.resolve(__dirname, '..')
15
+ const BUILT_MARKER = path.join(SWARMCLAW_HOME, '.built')
16
+ const PID_FILE = path.join(SWARMCLAW_HOME, 'server.pid')
17
+ const LOG_FILE = path.join(SWARMCLAW_HOME, 'server.log')
18
+ const DATA_DIR = path.join(SWARMCLAW_HOME, 'data')
19
+
20
+ // Files/directories to symlink from the npm package into SWARMCLAW_HOME
21
+ const SYMLINKS = [
22
+ 'src',
23
+ 'public',
24
+ 'next.config.ts',
25
+ 'tsconfig.json',
26
+ 'postcss.config.mjs',
27
+ 'package.json',
28
+ ]
29
+
30
+ // ---------------------------------------------------------------------------
31
+ // Helpers
32
+ // ---------------------------------------------------------------------------
33
+
34
+ function ensureDir(dir) {
35
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true })
36
+ }
37
+
38
+ function log(msg) {
39
+ process.stdout.write(`[swarmclaw] ${msg}\n`)
40
+ }
41
+
42
+ function logError(msg) {
43
+ process.stderr.write(`[swarmclaw] ${msg}\n`)
44
+ }
45
+
46
+ function readPid() {
47
+ try {
48
+ const pid = parseInt(fs.readFileSync(PID_FILE, 'utf8').trim(), 10)
49
+ return Number.isFinite(pid) ? pid : null
50
+ } catch {
51
+ return null
52
+ }
53
+ }
54
+
55
+ function isProcessRunning(pid) {
56
+ try {
57
+ process.kill(pid, 0)
58
+ return true
59
+ } catch {
60
+ return false
61
+ }
62
+ }
63
+
64
+ function symlink(src, dest) {
65
+ // Remove existing symlink/file if present
66
+ try {
67
+ const stat = fs.lstatSync(dest)
68
+ if (stat.isSymbolicLink() || stat.isFile()) {
69
+ fs.unlinkSync(dest)
70
+ }
71
+ } catch {
72
+ // doesn't exist
73
+ }
74
+ fs.symlinkSync(src, dest)
75
+ }
76
+
77
+ // ---------------------------------------------------------------------------
78
+ // Build
79
+ // ---------------------------------------------------------------------------
80
+
81
+ function needsBuild(forceBuild) {
82
+ if (forceBuild) return true
83
+ if (!fs.existsSync(BUILT_MARKER)) return true
84
+ return false
85
+ }
86
+
87
+ function runBuild() {
88
+ log('Preparing build environment...')
89
+ ensureDir(SWARMCLAW_HOME)
90
+ ensureDir(DATA_DIR)
91
+
92
+ // Create symlinks from PKG_ROOT into SWARMCLAW_HOME
93
+ for (const entry of SYMLINKS) {
94
+ const src = path.join(PKG_ROOT, entry)
95
+ const dest = path.join(SWARMCLAW_HOME, entry)
96
+
97
+ if (!fs.existsSync(src)) {
98
+ log(`Warning: ${entry} not found in package, skipping`)
99
+ continue
100
+ }
101
+
102
+ symlink(src, dest)
103
+ }
104
+
105
+ // Symlink node_modules
106
+ const nmSrc = path.join(PKG_ROOT, 'node_modules')
107
+ const nmDest = path.join(SWARMCLAW_HOME, 'node_modules')
108
+ if (fs.existsSync(nmSrc)) {
109
+ symlink(nmSrc, nmDest)
110
+ } else {
111
+ // If node_modules doesn't exist at PKG_ROOT, install
112
+ log('Installing dependencies...')
113
+ execSync('npm install --omit=dev', { cwd: SWARMCLAW_HOME, stdio: 'inherit' })
114
+ }
115
+
116
+ // Run Next.js build
117
+ log('Building Next.js application (this may take a minute)...')
118
+ execSync('npx next build', { cwd: SWARMCLAW_HOME, stdio: 'inherit' })
119
+
120
+ // Write built marker
121
+ fs.writeFileSync(BUILT_MARKER, JSON.stringify({ builtAt: new Date().toISOString(), version: getVersion() }))
122
+ log('Build complete.')
123
+ }
124
+
125
+ function getVersion() {
126
+ try {
127
+ const pkg = JSON.parse(fs.readFileSync(path.join(PKG_ROOT, 'package.json'), 'utf8'))
128
+ return pkg.version || 'unknown'
129
+ } catch {
130
+ return 'unknown'
131
+ }
132
+ }
133
+
134
+ // ---------------------------------------------------------------------------
135
+ // Find standalone server.js
136
+ // ---------------------------------------------------------------------------
137
+
138
+ function findStandaloneServer() {
139
+ // Next.js standalone output creates .next/standalone/ with server.js
140
+ // The path mirrors the build machine's directory structure
141
+ const standaloneBase = path.join(SWARMCLAW_HOME, '.next', 'standalone')
142
+
143
+ if (!fs.existsSync(standaloneBase)) {
144
+ return null
145
+ }
146
+
147
+ // Try direct server.js first
148
+ const direct = path.join(standaloneBase, 'server.js')
149
+ if (fs.existsSync(direct)) return direct
150
+
151
+ // Recursively search for server.js (handles nested paths from build machine)
152
+ function search(dir) {
153
+ const entries = fs.readdirSync(dir, { withFileTypes: true })
154
+ for (const entry of entries) {
155
+ const full = path.join(dir, entry.name)
156
+ if (entry.isFile() && entry.name === 'server.js') return full
157
+ if (entry.isDirectory() && entry.name !== 'node_modules') {
158
+ const found = search(full)
159
+ if (found) return found
160
+ }
161
+ }
162
+ return null
163
+ }
164
+
165
+ return search(standaloneBase)
166
+ }
167
+
168
+ // ---------------------------------------------------------------------------
169
+ // Start server
170
+ // ---------------------------------------------------------------------------
171
+
172
+ function startServer(opts) {
173
+ const serverJs = findStandaloneServer()
174
+ if (!serverJs) {
175
+ logError('Standalone server.js not found. Try running: swarmclaw server --build')
176
+ process.exit(1)
177
+ }
178
+
179
+ const port = opts.port || '3456'
180
+ const host = opts.host || '0.0.0.0'
181
+
182
+ const env = {
183
+ ...process.env,
184
+ PORT: port,
185
+ HOSTNAME: host,
186
+ DATA_DIR,
187
+ }
188
+
189
+ log(`Starting server on ${host}:${port}...`)
190
+ log(`Data directory: ${DATA_DIR}`)
191
+
192
+ if (opts.detach) {
193
+ // Detached mode — run in background
194
+ const logStream = fs.openSync(LOG_FILE, 'a')
195
+ const child = spawn(process.execPath, [serverJs], {
196
+ env,
197
+ detached: true,
198
+ stdio: ['ignore', logStream, logStream],
199
+ })
200
+
201
+ child.unref()
202
+ fs.writeFileSync(PID_FILE, String(child.pid))
203
+ log(`Server started in background (PID: ${child.pid})`)
204
+ log(`Logs: ${LOG_FILE}`)
205
+ process.exit(0)
206
+ } else {
207
+ // Foreground mode
208
+ const child = spawn(process.execPath, [serverJs], {
209
+ env,
210
+ stdio: 'inherit',
211
+ })
212
+
213
+ child.on('exit', (code) => {
214
+ process.exit(code || 0)
215
+ })
216
+
217
+ // Forward signals
218
+ for (const sig of ['SIGINT', 'SIGTERM']) {
219
+ process.on(sig, () => child.kill(sig))
220
+ }
221
+ }
222
+ }
223
+
224
+ // ---------------------------------------------------------------------------
225
+ // Stop server
226
+ // ---------------------------------------------------------------------------
227
+
228
+ function stopServer() {
229
+ const pid = readPid()
230
+ if (!pid) {
231
+ log('No PID file found. Server may not be running in detached mode.')
232
+ return
233
+ }
234
+
235
+ if (!isProcessRunning(pid)) {
236
+ log(`Process ${pid} is not running. Cleaning up PID file.`)
237
+ try { fs.unlinkSync(PID_FILE) } catch {}
238
+ return
239
+ }
240
+
241
+ log(`Stopping server (PID: ${pid})...`)
242
+ try {
243
+ process.kill(pid, 'SIGTERM')
244
+ log('Server stopped.')
245
+ } catch (err) {
246
+ logError(`Failed to stop server: ${err.message}`)
247
+ }
248
+ try { fs.unlinkSync(PID_FILE) } catch {}
249
+ }
250
+
251
+ // ---------------------------------------------------------------------------
252
+ // Status
253
+ // ---------------------------------------------------------------------------
254
+
255
+ function showStatus() {
256
+ const pid = readPid()
257
+ if (!pid) {
258
+ log('Server: not running (no PID file)')
259
+ return
260
+ }
261
+
262
+ if (isProcessRunning(pid)) {
263
+ log(`Server: running (PID: ${pid})`)
264
+ } else {
265
+ log(`Server: not running (stale PID: ${pid})`)
266
+ try { fs.unlinkSync(PID_FILE) } catch {}
267
+ }
268
+
269
+ log(`Home: ${SWARMCLAW_HOME}`)
270
+ log(`Data: ${DATA_DIR}`)
271
+
272
+ if (fs.existsSync(BUILT_MARKER)) {
273
+ try {
274
+ const info = JSON.parse(fs.readFileSync(BUILT_MARKER, 'utf8'))
275
+ log(`Built: ${info.builtAt || 'unknown'} (v${info.version || '?'})`)
276
+ } catch {
277
+ log('Built: yes')
278
+ }
279
+ } else {
280
+ log('Built: no')
281
+ }
282
+ }
283
+
284
+ // ---------------------------------------------------------------------------
285
+ // CLI parsing
286
+ // ---------------------------------------------------------------------------
287
+
288
+ function printHelp() {
289
+ const help = `
290
+ Usage: swarmclaw server [command] [options]
291
+
292
+ Commands:
293
+ start Start the server (default)
294
+ stop Stop a detached server
295
+ status Show server status
296
+
297
+ Options:
298
+ --build Force rebuild before starting
299
+ -d, --detach Start server in background
300
+ --port <port> Server port (default: 3456)
301
+ --host <host> Server host (default: 0.0.0.0)
302
+ -h, --help Show this help message
303
+ `.trim()
304
+ console.log(help)
305
+ }
306
+
307
+ function main() {
308
+ const args = process.argv.slice(3) // skip node, bin, 'server'
309
+ let command = 'start'
310
+ let forceBuild = false
311
+ let detach = false
312
+ let port = null
313
+ let host = null
314
+
315
+ for (let i = 0; i < args.length; i++) {
316
+ const arg = args[i]
317
+ if (arg === 'start') {
318
+ command = 'start'
319
+ } else if (arg === 'stop') {
320
+ command = 'stop'
321
+ } else if (arg === 'status') {
322
+ command = 'status'
323
+ } else if (arg === '--build') {
324
+ forceBuild = true
325
+ } else if (arg === '-d' || arg === '--detach') {
326
+ detach = true
327
+ } else if (arg === '--port' && i + 1 < args.length) {
328
+ port = args[++i]
329
+ } else if (arg === '--host' && i + 1 < args.length) {
330
+ host = args[++i]
331
+ } else if (arg === '-h' || arg === '--help') {
332
+ printHelp()
333
+ process.exit(0)
334
+ } else {
335
+ logError(`Unknown argument: ${arg}`)
336
+ printHelp()
337
+ process.exit(1)
338
+ }
339
+ }
340
+
341
+ if (command === 'stop') {
342
+ stopServer()
343
+ return
344
+ }
345
+
346
+ if (command === 'status') {
347
+ showStatus()
348
+ return
349
+ }
350
+
351
+ // command === 'start'
352
+ if (needsBuild(forceBuild)) {
353
+ runBuild()
354
+ }
355
+
356
+ startServer({ port, host, detach })
357
+ }
358
+
359
+ main()
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env node
2
+ 'use strict'
3
+
4
+ const path = require('node:path')
5
+ const { spawnSync } = require('node:child_process')
6
+
7
+ // Route 'server' subcommand to the CJS server script (no TS dependency)
8
+ if (process.argv[2] === 'server') {
9
+ require('./server-cmd.js')
10
+ } else {
11
+ const cliPath = path.join(__dirname, '..', 'src', 'cli', 'index.ts')
12
+
13
+ const child = spawnSync(
14
+ process.execPath,
15
+ ['--no-warnings', '--experimental-strip-types', cliPath, ...process.argv.slice(2)],
16
+ {
17
+ stdio: 'inherit',
18
+ },
19
+ )
20
+
21
+ if (child.error) {
22
+ process.stderr.write(`${child.error.message}\n`)
23
+ process.exitCode = 1
24
+ } else if (typeof child.status === 'number') {
25
+ process.exitCode = child.status
26
+ } else {
27
+ process.exitCode = 1
28
+ }
29
+ }