@starlove/orbit 1.4.0 → 2.0.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 (329) hide show
  1. package/Dockerfile +10 -8
  2. package/README.md +146 -164
  3. package/dist/full/csp.txt +1 -0
  4. package/dist/full/fonts/JetBrains_Mono/JetBrainsMono-subset.woff2 +0 -0
  5. package/dist/full/fonts/JetBrains_Mono/README.txt +5 -0
  6. package/dist/full/fonts/Mona_Sans/MonaSans-subset.woff2 +0 -0
  7. package/{public/fonts/Open_Sans → dist/full/fonts/Mona_Sans}/OFL.txt +93 -93
  8. package/dist/full/fonts/Mona_Sans/README.txt +10 -0
  9. package/{public/fonts/JetBrains_Mono → dist/full/fonts/Newsreader}/OFL.txt +93 -93
  10. package/dist/full/fonts/Newsreader/README.txt +8 -0
  11. package/dist/full/fonts/Newsreader/newsreader.woff2 +0 -0
  12. package/dist/full/index.html +36 -653
  13. package/dist/full/js/app.BmuponPJ.js +32 -0
  14. package/dist/full/js/app.BmuponPJ.js.map +1 -0
  15. package/dist/full/js/chunk.1fJGQGbW.js +2 -0
  16. package/dist/full/js/chunk.1fJGQGbW.js.map +1 -0
  17. package/dist/full/js/chunk.5D7JO2zp.js +2 -0
  18. package/dist/full/js/chunk.5D7JO2zp.js.map +1 -0
  19. package/dist/full/js/chunk.BrNn_D79.js +2 -0
  20. package/dist/full/js/chunk.BrNn_D79.js.map +1 -0
  21. package/dist/full/js/chunk.CokJXIqM.js +2 -0
  22. package/dist/full/js/chunk.CokJXIqM.js.map +1 -0
  23. package/dist/full/js/chunk.D_Haqy6R.js +2 -0
  24. package/dist/full/js/chunk.D_Haqy6R.js.map +1 -0
  25. package/dist/full/js/chunk.RO0jsH6I.js +15 -0
  26. package/dist/full/js/chunk.RO0jsH6I.js.map +1 -0
  27. package/dist/full/js/chunk.dqWOEtBM.js +2 -0
  28. package/dist/full/js/chunk.dqWOEtBM.js.map +1 -0
  29. package/dist/full/js/warm.f260bbbc.js +15 -0
  30. package/dist/full/orbits-favicon.png +0 -0
  31. package/dist/full/orbits-logo-bg-wide.png +0 -0
  32. package/dist/full/orbits-logo-bg.png +0 -0
  33. package/dist/full/orbits-logo.png +0 -0
  34. package/dist/full/styles.2b154ffe.css +1 -0
  35. package/dist/full/vendor/starlove-ui/theme-init.js +66 -0
  36. package/dist/full/version.json +2 -2
  37. package/docs/AGENT_GUIDE.md +114 -0
  38. package/docs/UPDATING.md +249 -64
  39. package/lib/adapters/indexeddb/blobs.d.ts +3 -0
  40. package/lib/adapters/indexeddb/blobs.js +54 -0
  41. package/lib/adapters/indexeddb/database.d.ts +60 -0
  42. package/lib/adapters/indexeddb/database.js +126 -0
  43. package/lib/adapters/indexeddb/index.d.ts +5 -0
  44. package/lib/adapters/indexeddb/index.js +3 -0
  45. package/lib/adapters/indexeddb/locks.d.ts +14 -0
  46. package/lib/adapters/indexeddb/locks.js +40 -0
  47. package/lib/adapters/indexeddb/store.d.ts +40 -0
  48. package/lib/adapters/indexeddb/store.js +424 -0
  49. package/lib/adapters/indexeddb/tables.d.ts +43 -0
  50. package/lib/adapters/indexeddb/tables.js +127 -0
  51. package/lib/adapters/memory/blobs.d.ts +3 -0
  52. package/lib/adapters/memory/blobs.js +44 -0
  53. package/lib/adapters/memory/board.d.ts +41 -0
  54. package/lib/adapters/memory/board.js +521 -0
  55. package/lib/adapters/memory/index.d.ts +2 -0
  56. package/lib/adapters/memory/index.js +2 -0
  57. package/lib/adapters/memory/search.d.ts +6 -0
  58. package/lib/adapters/memory/search.js +30 -0
  59. package/lib/adapters/memory/store.d.ts +34 -0
  60. package/lib/adapters/memory/store.js +266 -0
  61. package/lib/adapters/sqlite/backups.d.ts +53 -0
  62. package/lib/adapters/sqlite/backups.js +232 -0
  63. package/lib/adapters/sqlite/blobs.d.ts +14 -0
  64. package/lib/adapters/sqlite/blobs.js +109 -0
  65. package/lib/adapters/sqlite/board.d.ts +77 -0
  66. package/lib/adapters/sqlite/board.js +328 -0
  67. package/lib/adapters/sqlite/database.d.ts +67 -0
  68. package/lib/adapters/sqlite/database.js +285 -0
  69. package/lib/adapters/sqlite/index.d.ts +3 -0
  70. package/lib/adapters/sqlite/index.js +2 -0
  71. package/lib/adapters/sqlite/lock.d.ts +11 -0
  72. package/lib/adapters/sqlite/lock.js +34 -0
  73. package/lib/adapters/sqlite/records.d.ts +54 -0
  74. package/lib/adapters/sqlite/records.js +546 -0
  75. package/lib/adapters/sqlite/schema.d.ts +54 -0
  76. package/lib/adapters/sqlite/schema.js +276 -0
  77. package/lib/adapters/sqlite/store.d.ts +39 -0
  78. package/lib/adapters/sqlite/store.js +385 -0
  79. package/lib/browser/in-page.d.ts +31 -0
  80. package/lib/browser/in-page.js +46 -0
  81. package/lib/browser/old-preview.d.ts +13 -0
  82. package/lib/browser/old-preview.js +80 -0
  83. package/lib/browser/preview-board.d.ts +8 -0
  84. package/lib/browser/preview-board.js +69 -0
  85. package/lib/cli/main.d.ts +7 -0
  86. package/lib/cli/main.js +343 -0
  87. package/lib/cli/orbit.d.ts +8 -0
  88. package/lib/cli/orbit.js +25 -0
  89. package/lib/client/http.d.ts +38 -0
  90. package/lib/client/http.js +334 -0
  91. package/lib/client/local.d.ts +26 -0
  92. package/lib/client/local.js +190 -0
  93. package/lib/client/object-url.d.ts +8 -0
  94. package/lib/client/object-url.js +21 -0
  95. package/lib/client/types.d.ts +268 -0
  96. package/lib/client/types.js +8 -0
  97. package/lib/commands/agent-tools.d.ts +31 -0
  98. package/lib/commands/agent-tools.js +100 -0
  99. package/lib/commands/index.d.ts +56 -0
  100. package/lib/commands/index.js +298 -0
  101. package/lib/commands/parse.d.ts +73 -0
  102. package/lib/commands/parse.js +231 -0
  103. package/lib/commands/present.d.ts +134 -0
  104. package/lib/commands/present.js +198 -0
  105. package/lib/commands/session.d.ts +85 -0
  106. package/lib/commands/session.js +138 -0
  107. package/lib/commands/verbs.d.ts +35 -0
  108. package/lib/commands/verbs.js +842 -0
  109. package/lib/core/actors.d.ts +18 -0
  110. package/lib/core/actors.js +45 -0
  111. package/lib/core/agent.d.ts +128 -0
  112. package/lib/core/agent.js +323 -0
  113. package/lib/core/boards.d.ts +113 -0
  114. package/lib/core/boards.js +288 -0
  115. package/lib/core/bootstrap.d.ts +47 -0
  116. package/lib/core/bootstrap.js +100 -0
  117. package/lib/core/bytes.d.ts +10 -0
  118. package/lib/core/bytes.js +52 -0
  119. package/lib/core/card-paths.d.ts +25 -0
  120. package/lib/core/card-paths.js +44 -0
  121. package/lib/core/context.d.ts +60 -0
  122. package/lib/core/context.js +42 -0
  123. package/lib/core/cross-board.d.ts +81 -0
  124. package/lib/core/cross-board.js +228 -0
  125. package/lib/core/describe.d.ts +21 -0
  126. package/lib/core/describe.js +81 -0
  127. package/lib/core/errors.d.ts +159 -0
  128. package/lib/core/errors.js +160 -0
  129. package/lib/core/files.d.ts +79 -0
  130. package/lib/core/files.js +262 -0
  131. package/lib/core/history.d.ts +20 -0
  132. package/lib/core/history.js +53 -0
  133. package/lib/core/image-types.d.ts +16 -0
  134. package/lib/core/image-types.js +36 -0
  135. package/lib/core/model.d.ts +263 -0
  136. package/lib/core/model.js +34 -0
  137. package/lib/core/nebula-link.d.ts +14 -0
  138. package/lib/core/nebula-link.js +39 -0
  139. package/lib/core/relations.d.ts +58 -0
  140. package/lib/core/relations.js +112 -0
  141. package/lib/core/search.d.ts +38 -0
  142. package/lib/core/search.js +92 -0
  143. package/lib/core/sessions.d.ts +44 -0
  144. package/lib/core/sessions.js +158 -0
  145. package/lib/core/snapshot-schema.d.ts +295 -0
  146. package/lib/core/snapshot-schema.js +82 -0
  147. package/lib/core/snapshots.d.ts +75 -0
  148. package/lib/core/snapshots.js +409 -0
  149. package/lib/core/states.d.ts +25 -0
  150. package/lib/core/states.js +126 -0
  151. package/lib/core/text.d.ts +40 -0
  152. package/lib/core/text.js +113 -0
  153. package/lib/core/tickets.d.ts +69 -0
  154. package/lib/core/tickets.js +311 -0
  155. package/lib/core/trello.d.ts +17 -0
  156. package/lib/core/trello.js +269 -0
  157. package/lib/core/verdicts.d.ts +28 -0
  158. package/lib/core/verdicts.js +92 -0
  159. package/lib/core/views.d.ts +95 -0
  160. package/lib/core/views.js +186 -0
  161. package/lib/http/app.d.ts +46 -0
  162. package/lib/http/app.js +491 -0
  163. package/lib/mcp-server.d.ts +10 -0
  164. package/lib/mcp-server.js +120 -0
  165. package/lib/node/assets.d.ts +7 -0
  166. package/lib/node/assets.js +68 -0
  167. package/lib/node/data-folder.d.ts +21 -0
  168. package/lib/node/data-folder.js +34 -0
  169. package/lib/node/env.d.ts +38 -0
  170. package/lib/node/env.js +49 -0
  171. package/lib/node/host-check.d.ts +24 -0
  172. package/lib/node/host-check.js +53 -0
  173. package/lib/node/host-services.d.ts +9 -0
  174. package/lib/node/host-services.js +150 -0
  175. package/lib/node/local.d.ts +22 -0
  176. package/lib/node/local.js +61 -0
  177. package/lib/node/migrate.d.ts +53 -0
  178. package/lib/node/migrate.js +635 -0
  179. package/lib/node/package.d.ts +7 -0
  180. package/lib/node/package.js +14 -0
  181. package/lib/node/repo-board.d.ts +49 -0
  182. package/lib/node/repo-board.js +245 -0
  183. package/lib/node/serve.d.ts +8 -0
  184. package/lib/node/serve.js +106 -0
  185. package/lib/orbit.d.ts +47 -0
  186. package/lib/orbit.js +44 -0
  187. package/lib/quiet-sqlite-warning.d.ts +1 -0
  188. package/lib/quiet-sqlite-warning.js +18 -0
  189. package/lib/store/blob-path.d.ts +6 -0
  190. package/lib/store/blob-path.js +12 -0
  191. package/lib/store/conformance.d.ts +52 -0
  192. package/lib/store/conformance.js +1449 -0
  193. package/lib/store/search-words.d.ts +10 -0
  194. package/lib/store/search-words.js +19 -0
  195. package/lib/store/types.d.ts +452 -0
  196. package/lib/store/types.js +34 -0
  197. package/llms.txt +63 -0
  198. package/package.json +109 -25
  199. package/src/cli/orbit.js +11 -658
  200. package/src/mcp-server.js +16 -876
  201. package/SKILL-ORBIT.md +0 -151
  202. package/build.mjs +0 -210
  203. package/dist/full/js/app.62905fcb.js +0 -952
  204. package/dist/full/js/app.62905fcb.js.map +0 -7
  205. package/dist/full/styles.4e60d824.css +0 -1
  206. package/docs/AGENT_PROTOCOL.md +0 -424
  207. package/docs/MCP_SETUP.md +0 -54
  208. package/docs/ORBIT_DISPATCH.md +0 -280
  209. package/docs/SS-Orbit-Dark.png +0 -0
  210. package/docs/SS-Orbit-Light.png +0 -0
  211. package/docs/mcp-client.example.json +0 -13
  212. package/docs/setup/orbit-init-wizard.md +0 -174
  213. package/public/apple-touch-icon.png +0 -0
  214. package/public/cursors/live_arrow.cur +0 -0
  215. package/public/cursors/live_link.cur +0 -0
  216. package/public/cursors/live_move.cur +0 -0
  217. package/public/cursors/live_select.cur +0 -0
  218. package/public/cursors/live_unavail.cur +0 -0
  219. package/public/favicon-32x32.png +0 -0
  220. package/public/fonts/Chakra_Petch/ChakraPetch-Bold.ttf +0 -0
  221. package/public/fonts/Chakra_Petch/ChakraPetch-BoldItalic.ttf +0 -0
  222. package/public/fonts/Chakra_Petch/ChakraPetch-Italic.ttf +0 -0
  223. package/public/fonts/Chakra_Petch/ChakraPetch-Light.ttf +0 -0
  224. package/public/fonts/Chakra_Petch/ChakraPetch-LightItalic.ttf +0 -0
  225. package/public/fonts/Chakra_Petch/ChakraPetch-Medium.ttf +0 -0
  226. package/public/fonts/Chakra_Petch/ChakraPetch-MediumItalic.ttf +0 -0
  227. package/public/fonts/Chakra_Petch/ChakraPetch-Regular.ttf +0 -0
  228. package/public/fonts/Chakra_Petch/ChakraPetch-SemiBold.ttf +0 -0
  229. package/public/fonts/Chakra_Petch/ChakraPetch-SemiBoldItalic.ttf +0 -0
  230. package/public/fonts/Chakra_Petch/OFL.txt +0 -93
  231. package/public/fonts/Inter/Inter-Italic-VariableFont_opsz,wght.ttf +0 -0
  232. package/public/fonts/Inter/Inter-VariableFont_opsz,wght.ttf +0 -0
  233. package/public/fonts/Inter/OFL.txt +0 -93
  234. package/public/fonts/Inter/README.txt +0 -118
  235. package/public/fonts/JetBrains_Mono/JetBrainsMono-Italic-VariableFont_wght.ttf +0 -0
  236. package/public/fonts/JetBrains_Mono/JetBrainsMono-VariableFont_wght.ttf +0 -0
  237. package/public/fonts/JetBrains_Mono/README.txt +0 -79
  238. package/public/fonts/OpenRing-Regular.ttf +0 -0
  239. package/public/fonts/Open_Sans/OpenSans-Italic-VariableFont_wdth,wght.ttf +0 -0
  240. package/public/fonts/Open_Sans/OpenSans-VariableFont_wdth,wght.ttf +0 -0
  241. package/public/fonts/Open_Sans/README.txt +0 -100
  242. package/public/fonts/Orbitron/OFL.txt +0 -93
  243. package/public/fonts/Orbitron/Orbitron-VariableFont_wght.ttf +0 -0
  244. package/public/fonts/Orbitron/README.txt +0 -68
  245. package/public/fonts/Rajdhani/OFL.txt +0 -93
  246. package/public/fonts/Rajdhani/Rajdhani-Bold.ttf +0 -0
  247. package/public/fonts/Rajdhani/Rajdhani-Light.ttf +0 -0
  248. package/public/fonts/Rajdhani/Rajdhani-Medium.ttf +0 -0
  249. package/public/fonts/Rajdhani/Rajdhani-Regular.ttf +0 -0
  250. package/public/fonts/Rajdhani/Rajdhani-SemiBold.ttf +0 -0
  251. package/public/fonts/runescape-uf.ttf +0 -0
  252. package/public/index.html +0 -769
  253. package/public/js/actor-labels.js +0 -65
  254. package/public/js/api.js +0 -39
  255. package/public/js/app.js +0 -45
  256. package/public/js/artifact-drawer.js +0 -79
  257. package/public/js/board-export.js +0 -161
  258. package/public/js/board-menu.js +0 -374
  259. package/public/js/card-actions.js +0 -545
  260. package/public/js/config.js +0 -20
  261. package/public/js/create-card.js +0 -190
  262. package/public/js/dom.js +0 -19
  263. package/public/js/drawer.js +0 -273
  264. package/public/js/font-preference.js +0 -229
  265. package/public/js/format.js +0 -433
  266. package/public/js/help-menu.js +0 -31
  267. package/public/js/icons.js +0 -16
  268. package/public/js/kanban.js +0 -694
  269. package/public/js/local-backend.js +0 -1015
  270. package/public/js/main.js +0 -161
  271. package/public/js/modal.js +0 -33
  272. package/public/js/motion-preference.js +0 -64
  273. package/public/js/panel.js +0 -58
  274. package/public/js/router.js +0 -134
  275. package/public/js/search.js +0 -56
  276. package/public/js/settings-tabs.js +0 -7
  277. package/public/js/settings.js +0 -1634
  278. package/public/js/sse.js +0 -159
  279. package/public/js/starscape.js +0 -332
  280. package/public/js/state.js +0 -129
  281. package/public/js/text-editing.js +0 -128
  282. package/public/js/theme-preference.js +0 -95
  283. package/public/js/ticket-detail.js +0 -1516
  284. package/public/js/ticket-typeahead.js +0 -49
  285. package/public/js/toast.js +0 -89
  286. package/public/js/topbar-notes.js +0 -155
  287. package/public/js/transport.js +0 -22
  288. package/public/js/typeahead.js +0 -206
  289. package/public/js/unread.js +0 -121
  290. package/public/js/update-check.js +0 -58
  291. package/public/js/url-routes.js +0 -94
  292. package/public/orbits-favicon.png +0 -0
  293. package/public/orbits-logo-bg-wide.png +0 -0
  294. package/public/orbits-logo-bg.png +0 -0
  295. package/public/orbits-logo.png +0 -0
  296. package/public/styles.css +0 -7709
  297. package/src/core/agent.js +0 -387
  298. package/src/core/agents-md.js +0 -109
  299. package/src/core/artifacts.js +0 -149
  300. package/src/core/attachments.js +0 -238
  301. package/src/core/auth.js +0 -85
  302. package/src/core/backups.js +0 -142
  303. package/src/core/board.js +0 -148
  304. package/src/core/boards.js +0 -409
  305. package/src/core/bootstrap.js +0 -170
  306. package/src/core/css-bundle.js +0 -30
  307. package/src/core/db.js +0 -315
  308. package/src/core/delete-board.js +0 -163
  309. package/src/core/dispatch.js +0 -1007
  310. package/src/core/events.js +0 -314
  311. package/src/core/http.js +0 -115
  312. package/src/core/migrate.js +0 -198
  313. package/src/core/paths.js +0 -55
  314. package/src/core/provision-repo-board.js +0 -119
  315. package/src/core/queries.js +0 -246
  316. package/src/core/registry.js +0 -211
  317. package/src/core/relations.js +0 -163
  318. package/src/core/review-verdicts.js +0 -138
  319. package/src/core/router.js +0 -556
  320. package/src/core/search.js +0 -183
  321. package/src/core/seed.js +0 -234
  322. package/src/core/snapshots.js +0 -692
  323. package/src/core/states.js +0 -167
  324. package/src/core/system-picker.js +0 -109
  325. package/src/core/tickets.js +0 -400
  326. package/src/core/util.js +0 -106
  327. package/src/core/version-check.js +0 -154
  328. package/src/mcp/orbit-client.js +0 -287
  329. package/src/server.js +0 -115
@@ -0,0 +1,343 @@
1
+ /**
2
+ * Orbit CLI, loaded by the bin (./orbit.ts): `orbit run` serves the app and the API, `orbit mcp` serves agents
3
+ * over stdio, and any other first word is a board command (`orbit view`).
4
+ * Each command loads only what it runs: Hono for `orbit run`, the MCP SDK for
5
+ * `orbit mcp`, neither for a board command.
6
+ */
7
+ // First, so Node 22 never prints its SQLite warning.
8
+ import "../quiet-sqlite-warning.js";
9
+ import { spawn } from "node:child_process";
10
+ import { closeSync, existsSync, mkdirSync, openSync, readFileSync, readdirSync } from "node:fs";
11
+ import { homedir } from "node:os";
12
+ import { join, resolve, sep } from "node:path";
13
+ import { fileURLToPath } from "node:url";
14
+ import { namedAgentActor } from "../core/actors.js";
15
+ import { readEnv } from "../node/env.js";
16
+ // What `orbit help <word>` says for the commands this file runs itself.
17
+ const SERVER_HELP = {
18
+ run: `orbit run [--port <n>] [-d]
19
+ Start Orbit: it serves the app and the board commands, then prints the address to open.
20
+ --port <n> uses that port (without it Orbit starts at 13701 and moves up if it's busy);
21
+ -d keeps it running in the background and prints its PID and log.`,
22
+ mcp: `orbit mcp
23
+ Serve the board commands to an MCP app over stdio (the orbit_read and orbit_write tools).
24
+ Add it once for your user, for example in Claude Code:
25
+ claude mcp add --scope user orbit --env ORBIT_AGENT_NAME=claude -- orbit mcp`,
26
+ version: `orbit -v
27
+ Print Orbit's version (also orbit --version).`,
28
+ migrate: `orbit migrate [<old data folder or exports...>] [--to <new folder>] [--json]
29
+ Bring boards from an older Orbit (1.x, or 2.0 before its rebuild) into this Orbit's data folder
30
+ (~/.starscape/orbit, or DATA_DIR), or the folder --to names, which must be new, empty or hold no
31
+ boards. With no folder named it reads ~/.orbit, the older Orbit's own, and its boards may join
32
+ boards already here when none has the same name. The old files are only read, never changed. Each
33
+ board keeps its cards, numbers and ids, and is checked against the old one; the report says
34
+ anything that couldn't come. Running it again changes nothing.`
35
+ };
36
+ const SERVER_ALIASES = { serve: "run", v: "version" };
37
+ // The server-side commands; any other first word is a board command (orbit view, orbit take...).
38
+ const SERVER_COMMANDS = new Set(["run", "serve", "mcp", "migrate", "version", "help"]);
39
+ // Commands Orbit 2.0 removed: each says what replaced it, in one line, and exits non-zero.
40
+ const REMOVED_COMMANDS = {
41
+ init: "boards live in Orbit now, not in your repo. Run `orbit run` and make a board in the app, or `orbit boards new <name>`.",
42
+ reset: "Orbit no longer writes files into your repo. To delete a board, open the app with `orbit run`, then Settings, Data, Delete Board.",
43
+ dispatch: "your agent takes cards itself: have it run `orbit take`, or `orbit take 12` for one card.",
44
+ docker: "start Orbit with `orbit run`, or build the Dockerfile that ships with Orbit with docker build."
45
+ };
46
+ /** The one text for `orbit`, `orbit help` and `orbit --help`: start, the board commands, connect an agent. */
47
+ async function printHelp(env) {
48
+ const { agentLines, helpText } = await import("../commands/index.js");
49
+ const actor = namedAgentActor(env.agentName);
50
+ const boardHelp = (await helpText(actor, "cli")).text;
51
+ console.log(`Orbit: a kanban board for you and your AI agents.
52
+
53
+ For agents:
54
+ ${agentLines({ actor, transport: "cli" })
55
+ .map((line) => ` ${line}`)
56
+ .join("\n")}
57
+
58
+ Start:
59
+ orbit run: open Orbit in your browser at the address it prints, and make a board
60
+ orbit run --port 8080 -d: another port, kept running in the background
61
+ orbit migrate: boards from an older Orbit (in ~/.orbit), brought over
62
+
63
+ ${boardHelp}
64
+
65
+ Connect an agent:
66
+ An agent with a shell needs only the orbit command. Say this to it once, or put it
67
+ in the project's AGENTS.md or CLAUDE.md:
68
+ Use Orbit for this project's tasks, on the board <board>: run orbit help to learn it,
69
+ and name the board in commands (orbit view <board>, <board>#12) unless the repo's
70
+ orbit.json names it.
71
+ MCP apps get one server for your user, named orbit. In Claude Code:
72
+ claude mcp add --scope user orbit --env ORBIT_AGENT_NAME=claude -- orbit mcp
73
+ Name each agent so cards say which did what: in a shell, export ORBIT_AGENT_NAME=<name>;
74
+ an MCP app sets it in the server's env, as --env does above.
75
+
76
+ orbit help <command> explains one command; orbit -v prints the version.`);
77
+ }
78
+ /** `run`'s options, or the word it doesn't take. */
79
+ function runArgs(rest) {
80
+ const args = { port: null, detach: false };
81
+ for (let i = 0; i < rest.length; i += 1) {
82
+ const arg = rest[i] ?? "";
83
+ if (arg === "--port" && rest[i + 1])
84
+ args.port = rest[++i] ?? null;
85
+ else if (arg.startsWith("--port="))
86
+ args.port = arg.slice("--port=".length);
87
+ else if (arg === "-d" || arg === "--detach")
88
+ args.detach = true;
89
+ else
90
+ return { unknown: arg };
91
+ }
92
+ return args;
93
+ }
94
+ async function startDetached(env, args) {
95
+ const { makeDefaultDataDir, nextSteps, olderDataWaiting } = await import("../node/data-folder.js");
96
+ makeDefaultDataDir(env);
97
+ mkdirSync(env.dataDir, { recursive: true });
98
+ // The server says for sure in its log; here a folder of boards is enough to tell, without opening it.
99
+ const boardsDir = join(env.dataDir, "boards");
100
+ const older = olderDataWaiting(env) && !(existsSync(boardsDir) && readdirSync(boardsDir).length);
101
+ const logPath = join(env.dataDir, "orbit-run.log");
102
+ const logFd = openSync(logPath, "a");
103
+ const childArgs = [fileURLToPath(new URL("./orbit.js", import.meta.url)), "run", ...(args.port ? ["--port", args.port] : [])];
104
+ const child = spawn(process.execPath, childArgs, { cwd: process.cwd(), detached: true, env: { ...process.env }, stdio: ["ignore", logFd, logFd] });
105
+ child.unref();
106
+ closeSync(logFd);
107
+ const named = args.port ?? (env.port === null ? null : String(env.port));
108
+ const port = named ?? "13701";
109
+ console.log("Started Orbit in detached mode.");
110
+ console.log(`PID: ${child.pid ?? ""}`);
111
+ console.log(`Log: ${logPath}`);
112
+ console.log(named ? `URL: http://localhost:${port}` : `URL: starts at http://localhost:${port} (auto-increments if busy; see log)`);
113
+ // The same next steps the foreground start prints, then how to stop it.
114
+ console.log("");
115
+ console.log("Next:");
116
+ nextSteps(`http://localhost:${port}`, older ? "to see them" : "", older).forEach((line) => { console.log(line); });
117
+ console.log("");
118
+ console.log(`Stop it with: kill ${child.pid ?? ""}`);
119
+ }
120
+ /** A migration count's records in the app's words: "1 card", "3 journal entries". */
121
+ const COUNT_WORDS = {
122
+ states: ["lane", "lanes"],
123
+ labels: ["label", "labels"],
124
+ tickets: ["card", "cards"],
125
+ comments: ["comment", "comments"],
126
+ review_verdicts: ["review", "reviews"],
127
+ relations: ["link between cards", "links between cards"],
128
+ cross_board_relations: ["link to another board", "links to other boards"],
129
+ attachments: ["image", "images"],
130
+ board_entries: ["journal entry", "journal entries"],
131
+ events: ["history event", "history events"]
132
+ };
133
+ function countWords(kind, n) {
134
+ const words = COUNT_WORDS[kind];
135
+ return words ? words[n === 1 ? 0 : 1] : kind.replace(/_/g, " ");
136
+ }
137
+ /** `orbit migrate [<old folder or exports...>] [--to <folder>] [--json]`: an older Orbit's boards (~/.orbit when none is named) into a new folder. */
138
+ async function runMigrate(env, rest) {
139
+ const sources = [];
140
+ let to = env.dataDir;
141
+ let json = false;
142
+ for (let i = 0; i < rest.length; i += 1) {
143
+ const arg = rest[i] ?? "";
144
+ if (arg === "--to" && rest[i + 1])
145
+ to = rest[++i] ?? to;
146
+ else if (arg.startsWith("--to="))
147
+ to = arg.slice("--to=".length);
148
+ else if (arg === "--json")
149
+ json = true;
150
+ else if (arg.startsWith("-")) {
151
+ console.error(`Unknown argument: ${arg}`);
152
+ console.error(SERVER_HELP.migrate);
153
+ process.exitCode = 1;
154
+ return;
155
+ }
156
+ else
157
+ sources.push(arg);
158
+ }
159
+ const { makeDefaultDataDir } = await import("../node/data-folder.js");
160
+ // With no folder named, into Orbit's own folder: the old boards may join boards already there.
161
+ const fill = !sources.length && resolve(to) === env.dataDir;
162
+ if (!sources.length) {
163
+ // The older Orbit's default, read only when it holds a registry: it is never made or changed here.
164
+ if (!existsSync(join(env.olderDataDir, "registry.db"))) {
165
+ console.error(`Nothing to bring: ${env.olderDataDir} holds no boards from an older Orbit. Name the old data folder or exports: orbit migrate <folder or exports...>`);
166
+ process.exitCode = 1;
167
+ return;
168
+ }
169
+ sources.push(env.olderDataDir);
170
+ }
171
+ if (resolve(to) === env.dataDir)
172
+ makeDefaultDataDir(env);
173
+ const { migrate } = await import("../node/migrate.js");
174
+ const report = await migrate({ sources, to, fill });
175
+ if (json) {
176
+ console.log(JSON.stringify(report, null, 2));
177
+ return;
178
+ }
179
+ console.log(report.already ? `These boards are already in ${report.to}: nothing was changed.` : `Brought ${report.boards.length} board${report.boards.length === 1 ? "" : "s"} into ${report.to}. The old files weren't changed.`);
180
+ for (const board of report.boards) {
181
+ const counts = Object.entries(board.counts)
182
+ .filter(([, n]) => n > 0)
183
+ .map(([kind, n]) => `${n} ${countWords(kind, n)}`)
184
+ .join(", ");
185
+ console.log(`\n${board.slug}: ${counts || "empty"}.`);
186
+ console.log(` Checked against the old board: ${board.matched.length === Object.keys(board.counts).length ? "every record and file matches" : `matches for ${board.matched.map((kind) => countWords(kind, 2)).join(", ")}`}.`);
187
+ for (const note of board.notes)
188
+ console.log(` ${note}`);
189
+ }
190
+ for (const note of report.notes)
191
+ console.log(`\n${note}`);
192
+ // Where 1.x used each board, so its repo can name it again; nothing is written there. A folder
193
+ // can name one board, so boards 1.x kept for the same folder share a line.
194
+ const home = homedir();
195
+ const byFolder = new Map();
196
+ for (const board of report.boards)
197
+ if (board.folder_1x)
198
+ byFolder.set(board.folder_1x, [...(byFolder.get(board.folder_1x) ?? []), board.slug]);
199
+ if (byFolder.size)
200
+ console.log("");
201
+ for (const [folder, slugs] of byFolder) {
202
+ const shown = folder === home || folder.startsWith(home + sep) ? `~${folder.slice(home.length)}` : folder;
203
+ const link = slugs.length === 1 ? `${slugs[0] ?? ""}: 1.x used it for ${shown}. Run \`orbit boards link ${slugs[0] ?? ""}\` there.` : `${slugs.join(" and ")}: 1.x used them for ${shown}. A folder names one board: run \`orbit boards link <board>\` there with the one its agents should use.`;
204
+ console.log(`${link} That folder may still hold 1.x's SKILL-ORBIT.md and an Orbit block in AGENTS.md; you can remove them.`);
205
+ }
206
+ if (!report.already && resolve(report.to) !== env.dataDir)
207
+ console.log(`\nStart Orbit on it with DATA_DIR=${report.to} orbit run.`);
208
+ }
209
+ /** Pulls `-m -` (or --text -) out of the words: the text comes from stdin. */
210
+ function takeStdinText(words) {
211
+ const out = [];
212
+ let text;
213
+ for (let i = 0; i < words.length; i += 1) {
214
+ const word = words[i] ?? "";
215
+ if (["-m", "--message", "--text"].includes(word) && words[i + 1] === "-") {
216
+ text = readFileSync(0, "utf8").replace(/\n$/, "");
217
+ i += 1;
218
+ }
219
+ else if (["-m=-", "--message=-", "--text=-"].includes(word)) {
220
+ text = readFileSync(0, "utf8").replace(/\n$/, "");
221
+ }
222
+ else {
223
+ out.push(word);
224
+ }
225
+ }
226
+ return { words: out, text };
227
+ }
228
+ async function runBoardCommand(env, words) {
229
+ const { words: argv, text } = takeStdinText(words);
230
+ const input = { argv, transport: "cli", ...(text === undefined ? {} : { text }) };
231
+ const repo = await import("../node/repo-board.js");
232
+ if (env.mode === "remote") {
233
+ if (!env.apiUrl)
234
+ throw new Error("ORBIT_MODE=remote requires ORBIT_API_URL.");
235
+ const { createHttpClient } = await import("../client/http.js");
236
+ // The client reads this repo's orbit.json and sends the board with each command.
237
+ const client = createHttpClient({ baseUrl: env.apiUrl, headers: { "x-orbit-actor-type": "agent", "x-orbit-agent-name": env.agentName }, board: env.board, repo: () => repo.readRepoBoard(process.cwd()) });
238
+ const link = repo.repoLinkWords(argv);
239
+ if (!link)
240
+ return client.command(input);
241
+ // The server checks the words and the board; this shell writes the file.
242
+ const checked = await client.command({ ...input, json: true });
243
+ if (!checked.ok)
244
+ return checked;
245
+ const board = checked.data?.board ?? "";
246
+ const result = link === "link" ? repo.linkRepoBoard(process.cwd(), board) : repo.unlinkRepoBoard(process.cwd());
247
+ return result.ok && argv.includes("--json") ? { ...result, text: JSON.stringify(result.data) } : result;
248
+ }
249
+ const [{ openLocalOrbit }, { createSession, runCommand }] = await Promise.all([import("../node/local.js"), import("../commands/index.js")]);
250
+ const local = await openLocalOrbit(env);
251
+ try {
252
+ const session = createSession(local.orbit.context(namedAgentActor(env.agentName)), { transport: "cli", board: env.board, repo: repo.repoSourceAt(process.cwd(), { writes: true }) });
253
+ return await runCommand(input, session);
254
+ }
255
+ finally {
256
+ await local.close();
257
+ }
258
+ }
259
+ function removed(word) {
260
+ if (!Object.hasOwn(REMOVED_COMMANDS, word))
261
+ return false;
262
+ console.error(`orbit ${word} was removed in Orbit 2.0: ${REMOVED_COMMANDS[word] ?? ""}`);
263
+ process.exitCode = 1;
264
+ return true;
265
+ }
266
+ async function main() {
267
+ const argv = process.argv.slice(2);
268
+ const first = argv[0];
269
+ const env = readEnv();
270
+ if (first !== undefined && removed(first))
271
+ return;
272
+ if (first && !first.startsWith("-") && !SERVER_COMMANDS.has(first)) {
273
+ const result = await runBoardCommand(env, argv);
274
+ if (result.ok)
275
+ console.log(result.text);
276
+ else {
277
+ console.error(result.text);
278
+ process.exitCode = 1;
279
+ }
280
+ return;
281
+ }
282
+ if (first === "help" && argv[1]) {
283
+ const word = argv[1].replace(/^--?/, "");
284
+ if (removed(word))
285
+ return;
286
+ const server = SERVER_HELP[SERVER_ALIASES[word] ?? word];
287
+ if (server && !argv[2])
288
+ console.log(server);
289
+ else {
290
+ const { helpText } = await import("../commands/index.js");
291
+ const result = await helpText(namedAgentActor(env.agentName), "cli", argv.slice(1));
292
+ if (result.ok)
293
+ console.log(result.text);
294
+ else {
295
+ console.error(result.text);
296
+ process.exitCode = 1;
297
+ }
298
+ }
299
+ return;
300
+ }
301
+ if (first === undefined || first === "-h" || first === "--help" || first === "help") {
302
+ await printHelp(env);
303
+ return;
304
+ }
305
+ if (first === "run" || first === "serve") {
306
+ const args = runArgs(argv.slice(1));
307
+ if ("unknown" in args) {
308
+ console.error(`Unknown argument: ${args.unknown}`);
309
+ console.error("Run orbit help to see what Orbit takes.");
310
+ process.exitCode = 1;
311
+ return;
312
+ }
313
+ if (args.detach) {
314
+ await startDetached(env, args);
315
+ return;
316
+ }
317
+ const port = args.port === null ? env.port : /^\d{1,5}$/.test(args.port) ? Number(args.port) : env.port;
318
+ const { runServer } = await import("../node/serve.js");
319
+ await runServer({ ...env, port });
320
+ return;
321
+ }
322
+ if (first === "mcp") {
323
+ const { runMcpServer } = await import("../mcp-server.js");
324
+ await runMcpServer();
325
+ return;
326
+ }
327
+ if (first === "migrate") {
328
+ await runMigrate(env, argv.slice(1));
329
+ return;
330
+ }
331
+ console.error(`Unknown option ${first}.`);
332
+ await printHelp(env);
333
+ process.exitCode = 1;
334
+ }
335
+ try {
336
+ await main();
337
+ }
338
+ catch (error) {
339
+ console.error(error instanceof Error ? error.message : String(error));
340
+ process.exitCode = 1;
341
+ }
342
+ await new Promise((resolve) => process.stdout.write("", () => { resolve(); }));
343
+ await new Promise((resolve) => process.stderr.write("", () => { resolve(); }));
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * The `orbit` bin. Node's warning filter first; `orbit -v` answers here,
4
+ * loading nothing else; otherwise Node's compile cache goes on, so every later
5
+ * start skips compiling Orbit and its libraries again, and the CLI itself
6
+ * (./main.ts) runs.
7
+ */
8
+ import "../quiet-sqlite-warning.ts";
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * The `orbit` bin. Node's warning filter first; `orbit -v` answers here,
4
+ * loading nothing else; otherwise Node's compile cache goes on, so every later
5
+ * start skips compiling Orbit and its libraries again, and the CLI itself
6
+ * (./main.ts) runs.
7
+ */
8
+ import "../quiet-sqlite-warning.js";
9
+ import { enableCompileCache } from "node:module";
10
+ // Orbit's search is SQLite's FTS5, which Node's own SQLite has from 22.16 and
11
+ // 24.0 (not 23); on an older Node every new board would fail, so say so first.
12
+ const [major = 0, minor = 0] = process.versions.node.split(".").map(Number);
13
+ if (major < 22 || (major === 22 && minor < 16) || major === 23) {
14
+ console.error(`Orbit needs Node.js 22.16 or newer (24 is recommended); this is ${process.version}, whose SQLite has no full-text search.`);
15
+ process.exit(1);
16
+ }
17
+ const first = process.argv[2];
18
+ if (first === "-v" || first === "--version" || first === "version") {
19
+ const { packageVersion } = await import("../node/package.js");
20
+ console.log(packageVersion());
21
+ }
22
+ else {
23
+ enableCompileCache();
24
+ await import("./main.js");
25
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * The OrbitClient over HTTP: `createHttpClient({ baseUrl })` calls an Orbit's
3
+ * JSON API with any `fetch` (remote agents, the CLI in remote mode, the web
4
+ * app, the Suite). Each method is one route; a refusal comes back as the
5
+ * OrbitError the server answered with.
6
+ *
7
+ * A command session's board lives here, on the caller's side: the server
8
+ * forgets between requests, so each command sends the board this client
9
+ * chose last, and the caller's orbit.json as it reads it.
10
+ */
11
+ import type { RepoChoice } from "../commands/index.ts";
12
+ import type { OrbitClient } from "./types.ts";
13
+ export interface HttpClientOptions {
14
+ baseUrl: string;
15
+ /** Default: globalThis.fetch. The browser edition passes its in-page app's. */
16
+ fetch?: typeof fetch;
17
+ /** x-orbit-agent-name, or a host's own auth. */
18
+ headers?: Record<string, string>;
19
+ /** The board a command session starts on (ORBIT_BOARD). */
20
+ board?: string | null;
21
+ /** The caller's orbit.json, read where it runs, sent with each command. */
22
+ repo?: () => RepoChoice | null;
23
+ /**
24
+ * How `attachments.url()` gives an image: `route` (the default), the
25
+ * server's address for its bytes; `object`, the bytes fetched and given as
26
+ * an object URL, for a `fetch` no browser can reach by address (the
27
+ * browser edition's in-page app) or a server that needs headers.
28
+ */
29
+ images?: "route" | "object";
30
+ /** The live stream's reconnect delays, in ms: the first, and the most it doubles to. Default 1,000 and 30,000. */
31
+ reconnect?: {
32
+ firstMs?: number;
33
+ maxMs?: number;
34
+ };
35
+ /** With no byte from the stream for this long (heartbeats included), it reconnects. Default 75,000 (the server's heartbeat is 30,000). */
36
+ staleMs?: number;
37
+ }
38
+ export declare function createHttpClient(options: HttpClientOptions): OrbitClient;