@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.
- package/Dockerfile +10 -8
- package/README.md +146 -164
- package/dist/full/csp.txt +1 -0
- package/dist/full/fonts/JetBrains_Mono/JetBrainsMono-subset.woff2 +0 -0
- package/dist/full/fonts/JetBrains_Mono/README.txt +5 -0
- package/dist/full/fonts/Mona_Sans/MonaSans-subset.woff2 +0 -0
- package/{public/fonts/Open_Sans → dist/full/fonts/Mona_Sans}/OFL.txt +93 -93
- package/dist/full/fonts/Mona_Sans/README.txt +10 -0
- package/{public/fonts/JetBrains_Mono → dist/full/fonts/Newsreader}/OFL.txt +93 -93
- package/dist/full/fonts/Newsreader/README.txt +8 -0
- package/dist/full/fonts/Newsreader/newsreader.woff2 +0 -0
- package/dist/full/index.html +36 -653
- package/dist/full/js/app.BmuponPJ.js +32 -0
- package/dist/full/js/app.BmuponPJ.js.map +1 -0
- package/dist/full/js/chunk.1fJGQGbW.js +2 -0
- package/dist/full/js/chunk.1fJGQGbW.js.map +1 -0
- package/dist/full/js/chunk.5D7JO2zp.js +2 -0
- package/dist/full/js/chunk.5D7JO2zp.js.map +1 -0
- package/dist/full/js/chunk.BrNn_D79.js +2 -0
- package/dist/full/js/chunk.BrNn_D79.js.map +1 -0
- package/dist/full/js/chunk.CokJXIqM.js +2 -0
- package/dist/full/js/chunk.CokJXIqM.js.map +1 -0
- package/dist/full/js/chunk.D_Haqy6R.js +2 -0
- package/dist/full/js/chunk.D_Haqy6R.js.map +1 -0
- package/dist/full/js/chunk.RO0jsH6I.js +15 -0
- package/dist/full/js/chunk.RO0jsH6I.js.map +1 -0
- package/dist/full/js/chunk.dqWOEtBM.js +2 -0
- package/dist/full/js/chunk.dqWOEtBM.js.map +1 -0
- package/dist/full/js/warm.f260bbbc.js +15 -0
- package/dist/full/orbits-favicon.png +0 -0
- package/dist/full/orbits-logo-bg-wide.png +0 -0
- package/dist/full/orbits-logo-bg.png +0 -0
- package/dist/full/orbits-logo.png +0 -0
- package/dist/full/styles.2b154ffe.css +1 -0
- package/dist/full/vendor/starlove-ui/theme-init.js +66 -0
- package/dist/full/version.json +2 -2
- package/docs/AGENT_GUIDE.md +114 -0
- package/docs/UPDATING.md +249 -64
- package/lib/adapters/indexeddb/blobs.d.ts +3 -0
- package/lib/adapters/indexeddb/blobs.js +54 -0
- package/lib/adapters/indexeddb/database.d.ts +60 -0
- package/lib/adapters/indexeddb/database.js +126 -0
- package/lib/adapters/indexeddb/index.d.ts +5 -0
- package/lib/adapters/indexeddb/index.js +3 -0
- package/lib/adapters/indexeddb/locks.d.ts +14 -0
- package/lib/adapters/indexeddb/locks.js +40 -0
- package/lib/adapters/indexeddb/store.d.ts +40 -0
- package/lib/adapters/indexeddb/store.js +424 -0
- package/lib/adapters/indexeddb/tables.d.ts +43 -0
- package/lib/adapters/indexeddb/tables.js +127 -0
- package/lib/adapters/memory/blobs.d.ts +3 -0
- package/lib/adapters/memory/blobs.js +44 -0
- package/lib/adapters/memory/board.d.ts +41 -0
- package/lib/adapters/memory/board.js +521 -0
- package/lib/adapters/memory/index.d.ts +2 -0
- package/lib/adapters/memory/index.js +2 -0
- package/lib/adapters/memory/search.d.ts +6 -0
- package/lib/adapters/memory/search.js +30 -0
- package/lib/adapters/memory/store.d.ts +34 -0
- package/lib/adapters/memory/store.js +266 -0
- package/lib/adapters/sqlite/backups.d.ts +53 -0
- package/lib/adapters/sqlite/backups.js +232 -0
- package/lib/adapters/sqlite/blobs.d.ts +14 -0
- package/lib/adapters/sqlite/blobs.js +109 -0
- package/lib/adapters/sqlite/board.d.ts +77 -0
- package/lib/adapters/sqlite/board.js +328 -0
- package/lib/adapters/sqlite/database.d.ts +67 -0
- package/lib/adapters/sqlite/database.js +285 -0
- package/lib/adapters/sqlite/index.d.ts +3 -0
- package/lib/adapters/sqlite/index.js +2 -0
- package/lib/adapters/sqlite/lock.d.ts +11 -0
- package/lib/adapters/sqlite/lock.js +34 -0
- package/lib/adapters/sqlite/records.d.ts +54 -0
- package/lib/adapters/sqlite/records.js +546 -0
- package/lib/adapters/sqlite/schema.d.ts +54 -0
- package/lib/adapters/sqlite/schema.js +276 -0
- package/lib/adapters/sqlite/store.d.ts +39 -0
- package/lib/adapters/sqlite/store.js +385 -0
- package/lib/browser/in-page.d.ts +31 -0
- package/lib/browser/in-page.js +46 -0
- package/lib/browser/old-preview.d.ts +13 -0
- package/lib/browser/old-preview.js +80 -0
- package/lib/browser/preview-board.d.ts +8 -0
- package/lib/browser/preview-board.js +69 -0
- package/lib/cli/main.d.ts +7 -0
- package/lib/cli/main.js +343 -0
- package/lib/cli/orbit.d.ts +8 -0
- package/lib/cli/orbit.js +25 -0
- package/lib/client/http.d.ts +38 -0
- package/lib/client/http.js +334 -0
- package/lib/client/local.d.ts +26 -0
- package/lib/client/local.js +190 -0
- package/lib/client/object-url.d.ts +8 -0
- package/lib/client/object-url.js +21 -0
- package/lib/client/types.d.ts +268 -0
- package/lib/client/types.js +8 -0
- package/lib/commands/agent-tools.d.ts +31 -0
- package/lib/commands/agent-tools.js +100 -0
- package/lib/commands/index.d.ts +56 -0
- package/lib/commands/index.js +298 -0
- package/lib/commands/parse.d.ts +73 -0
- package/lib/commands/parse.js +231 -0
- package/lib/commands/present.d.ts +134 -0
- package/lib/commands/present.js +198 -0
- package/lib/commands/session.d.ts +85 -0
- package/lib/commands/session.js +138 -0
- package/lib/commands/verbs.d.ts +35 -0
- package/lib/commands/verbs.js +842 -0
- package/lib/core/actors.d.ts +18 -0
- package/lib/core/actors.js +45 -0
- package/lib/core/agent.d.ts +128 -0
- package/lib/core/agent.js +323 -0
- package/lib/core/boards.d.ts +113 -0
- package/lib/core/boards.js +288 -0
- package/lib/core/bootstrap.d.ts +47 -0
- package/lib/core/bootstrap.js +100 -0
- package/lib/core/bytes.d.ts +10 -0
- package/lib/core/bytes.js +52 -0
- package/lib/core/card-paths.d.ts +25 -0
- package/lib/core/card-paths.js +44 -0
- package/lib/core/context.d.ts +60 -0
- package/lib/core/context.js +42 -0
- package/lib/core/cross-board.d.ts +81 -0
- package/lib/core/cross-board.js +228 -0
- package/lib/core/describe.d.ts +21 -0
- package/lib/core/describe.js +81 -0
- package/lib/core/errors.d.ts +159 -0
- package/lib/core/errors.js +160 -0
- package/lib/core/files.d.ts +79 -0
- package/lib/core/files.js +262 -0
- package/lib/core/history.d.ts +20 -0
- package/lib/core/history.js +53 -0
- package/lib/core/image-types.d.ts +16 -0
- package/lib/core/image-types.js +36 -0
- package/lib/core/model.d.ts +263 -0
- package/lib/core/model.js +34 -0
- package/lib/core/nebula-link.d.ts +14 -0
- package/lib/core/nebula-link.js +39 -0
- package/lib/core/relations.d.ts +58 -0
- package/lib/core/relations.js +112 -0
- package/lib/core/search.d.ts +38 -0
- package/lib/core/search.js +92 -0
- package/lib/core/sessions.d.ts +44 -0
- package/lib/core/sessions.js +158 -0
- package/lib/core/snapshot-schema.d.ts +295 -0
- package/lib/core/snapshot-schema.js +82 -0
- package/lib/core/snapshots.d.ts +75 -0
- package/lib/core/snapshots.js +409 -0
- package/lib/core/states.d.ts +25 -0
- package/lib/core/states.js +126 -0
- package/lib/core/text.d.ts +40 -0
- package/lib/core/text.js +113 -0
- package/lib/core/tickets.d.ts +69 -0
- package/lib/core/tickets.js +311 -0
- package/lib/core/trello.d.ts +17 -0
- package/lib/core/trello.js +269 -0
- package/lib/core/verdicts.d.ts +28 -0
- package/lib/core/verdicts.js +92 -0
- package/lib/core/views.d.ts +95 -0
- package/lib/core/views.js +186 -0
- package/lib/http/app.d.ts +46 -0
- package/lib/http/app.js +491 -0
- package/lib/mcp-server.d.ts +10 -0
- package/lib/mcp-server.js +120 -0
- package/lib/node/assets.d.ts +7 -0
- package/lib/node/assets.js +68 -0
- package/lib/node/data-folder.d.ts +21 -0
- package/lib/node/data-folder.js +34 -0
- package/lib/node/env.d.ts +38 -0
- package/lib/node/env.js +49 -0
- package/lib/node/host-check.d.ts +24 -0
- package/lib/node/host-check.js +53 -0
- package/lib/node/host-services.d.ts +9 -0
- package/lib/node/host-services.js +150 -0
- package/lib/node/local.d.ts +22 -0
- package/lib/node/local.js +61 -0
- package/lib/node/migrate.d.ts +53 -0
- package/lib/node/migrate.js +635 -0
- package/lib/node/package.d.ts +7 -0
- package/lib/node/package.js +14 -0
- package/lib/node/repo-board.d.ts +49 -0
- package/lib/node/repo-board.js +245 -0
- package/lib/node/serve.d.ts +8 -0
- package/lib/node/serve.js +106 -0
- package/lib/orbit.d.ts +47 -0
- package/lib/orbit.js +44 -0
- package/lib/quiet-sqlite-warning.d.ts +1 -0
- package/lib/quiet-sqlite-warning.js +18 -0
- package/lib/store/blob-path.d.ts +6 -0
- package/lib/store/blob-path.js +12 -0
- package/lib/store/conformance.d.ts +52 -0
- package/lib/store/conformance.js +1449 -0
- package/lib/store/search-words.d.ts +10 -0
- package/lib/store/search-words.js +19 -0
- package/lib/store/types.d.ts +452 -0
- package/lib/store/types.js +34 -0
- package/llms.txt +63 -0
- package/package.json +109 -25
- package/src/cli/orbit.js +11 -658
- package/src/mcp-server.js +16 -876
- package/SKILL-ORBIT.md +0 -151
- package/build.mjs +0 -210
- package/dist/full/js/app.62905fcb.js +0 -952
- package/dist/full/js/app.62905fcb.js.map +0 -7
- package/dist/full/styles.4e60d824.css +0 -1
- package/docs/AGENT_PROTOCOL.md +0 -424
- package/docs/MCP_SETUP.md +0 -54
- package/docs/ORBIT_DISPATCH.md +0 -280
- package/docs/SS-Orbit-Dark.png +0 -0
- package/docs/SS-Orbit-Light.png +0 -0
- package/docs/mcp-client.example.json +0 -13
- package/docs/setup/orbit-init-wizard.md +0 -174
- package/public/apple-touch-icon.png +0 -0
- package/public/cursors/live_arrow.cur +0 -0
- package/public/cursors/live_link.cur +0 -0
- package/public/cursors/live_move.cur +0 -0
- package/public/cursors/live_select.cur +0 -0
- package/public/cursors/live_unavail.cur +0 -0
- package/public/favicon-32x32.png +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-Bold.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-BoldItalic.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-Italic.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-Light.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-LightItalic.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-Medium.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-MediumItalic.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-Regular.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-SemiBold.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-SemiBoldItalic.ttf +0 -0
- package/public/fonts/Chakra_Petch/OFL.txt +0 -93
- package/public/fonts/Inter/Inter-Italic-VariableFont_opsz,wght.ttf +0 -0
- package/public/fonts/Inter/Inter-VariableFont_opsz,wght.ttf +0 -0
- package/public/fonts/Inter/OFL.txt +0 -93
- package/public/fonts/Inter/README.txt +0 -118
- package/public/fonts/JetBrains_Mono/JetBrainsMono-Italic-VariableFont_wght.ttf +0 -0
- package/public/fonts/JetBrains_Mono/JetBrainsMono-VariableFont_wght.ttf +0 -0
- package/public/fonts/JetBrains_Mono/README.txt +0 -79
- package/public/fonts/OpenRing-Regular.ttf +0 -0
- package/public/fonts/Open_Sans/OpenSans-Italic-VariableFont_wdth,wght.ttf +0 -0
- package/public/fonts/Open_Sans/OpenSans-VariableFont_wdth,wght.ttf +0 -0
- package/public/fonts/Open_Sans/README.txt +0 -100
- package/public/fonts/Orbitron/OFL.txt +0 -93
- package/public/fonts/Orbitron/Orbitron-VariableFont_wght.ttf +0 -0
- package/public/fonts/Orbitron/README.txt +0 -68
- package/public/fonts/Rajdhani/OFL.txt +0 -93
- package/public/fonts/Rajdhani/Rajdhani-Bold.ttf +0 -0
- package/public/fonts/Rajdhani/Rajdhani-Light.ttf +0 -0
- package/public/fonts/Rajdhani/Rajdhani-Medium.ttf +0 -0
- package/public/fonts/Rajdhani/Rajdhani-Regular.ttf +0 -0
- package/public/fonts/Rajdhani/Rajdhani-SemiBold.ttf +0 -0
- package/public/fonts/runescape-uf.ttf +0 -0
- package/public/index.html +0 -769
- package/public/js/actor-labels.js +0 -65
- package/public/js/api.js +0 -39
- package/public/js/app.js +0 -45
- package/public/js/artifact-drawer.js +0 -79
- package/public/js/board-export.js +0 -161
- package/public/js/board-menu.js +0 -374
- package/public/js/card-actions.js +0 -545
- package/public/js/config.js +0 -20
- package/public/js/create-card.js +0 -190
- package/public/js/dom.js +0 -19
- package/public/js/drawer.js +0 -273
- package/public/js/font-preference.js +0 -229
- package/public/js/format.js +0 -433
- package/public/js/help-menu.js +0 -31
- package/public/js/icons.js +0 -16
- package/public/js/kanban.js +0 -694
- package/public/js/local-backend.js +0 -1015
- package/public/js/main.js +0 -161
- package/public/js/modal.js +0 -33
- package/public/js/motion-preference.js +0 -64
- package/public/js/panel.js +0 -58
- package/public/js/router.js +0 -134
- package/public/js/search.js +0 -56
- package/public/js/settings-tabs.js +0 -7
- package/public/js/settings.js +0 -1634
- package/public/js/sse.js +0 -159
- package/public/js/starscape.js +0 -332
- package/public/js/state.js +0 -129
- package/public/js/text-editing.js +0 -128
- package/public/js/theme-preference.js +0 -95
- package/public/js/ticket-detail.js +0 -1516
- package/public/js/ticket-typeahead.js +0 -49
- package/public/js/toast.js +0 -89
- package/public/js/topbar-notes.js +0 -155
- package/public/js/transport.js +0 -22
- package/public/js/typeahead.js +0 -206
- package/public/js/unread.js +0 -121
- package/public/js/update-check.js +0 -58
- package/public/js/url-routes.js +0 -94
- package/public/orbits-favicon.png +0 -0
- package/public/orbits-logo-bg-wide.png +0 -0
- package/public/orbits-logo-bg.png +0 -0
- package/public/orbits-logo.png +0 -0
- package/public/styles.css +0 -7709
- package/src/core/agent.js +0 -387
- package/src/core/agents-md.js +0 -109
- package/src/core/artifacts.js +0 -149
- package/src/core/attachments.js +0 -238
- package/src/core/auth.js +0 -85
- package/src/core/backups.js +0 -142
- package/src/core/board.js +0 -148
- package/src/core/boards.js +0 -409
- package/src/core/bootstrap.js +0 -170
- package/src/core/css-bundle.js +0 -30
- package/src/core/db.js +0 -315
- package/src/core/delete-board.js +0 -163
- package/src/core/dispatch.js +0 -1007
- package/src/core/events.js +0 -314
- package/src/core/http.js +0 -115
- package/src/core/migrate.js +0 -198
- package/src/core/paths.js +0 -55
- package/src/core/provision-repo-board.js +0 -119
- package/src/core/queries.js +0 -246
- package/src/core/registry.js +0 -211
- package/src/core/relations.js +0 -163
- package/src/core/review-verdicts.js +0 -138
- package/src/core/router.js +0 -556
- package/src/core/search.js +0 -183
- package/src/core/seed.js +0 -234
- package/src/core/snapshots.js +0 -692
- package/src/core/states.js +0 -167
- package/src/core/system-picker.js +0 -109
- package/src/core/tickets.js +0 -400
- package/src/core/util.js +0 -106
- package/src/core/version-check.js +0 -154
- package/src/mcp/orbit-client.js +0 -287
- package/src/server.js +0 -115
package/src/cli/orbit.js
CHANGED
|
@@ -1,662 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
// Orbit 1.x's bin lived here, and 1.x's `orbit init` registered MCP servers as
|
|
3
|
+
// `node <this file> mcp --cwd <repo>`. Orbit 2.0 installs over 1.x in place, so
|
|
4
|
+
// this file keeps those registrations starting: it runs 2.0's own bin with the
|
|
5
|
+
// same arguments. It says so on stderr only, because stdout is the MCP
|
|
6
|
+
// protocol. It stays until 3.0. Plain JavaScript, outside tsc and lint: npm
|
|
7
|
+
// ships it as it is.
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
import { fileURLToPath } from "node:url";
|
|
12
|
-
import { removeOrbitAgentsSection, syncAgentsMd, syncSkillOrbitMd } from "../core/agents-md.js";
|
|
13
|
-
|
|
14
|
-
const PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
15
|
-
|
|
16
|
-
function printUsage() {
|
|
17
|
-
console.log(`Usage:
|
|
18
|
-
orbit -v, --version Print the Orbit CLI version
|
|
19
|
-
orbit init [options] Provision .orbit/board.db + SKILL-ORBIT.md + AGENTS.md
|
|
20
|
-
orbit reset [options] Delete .orbit/ + SKILL-ORBIT.md + registry row
|
|
21
|
-
orbit run [options] Start the Orbit web app + HTTP API
|
|
22
|
-
orbit docker [options] Build/run Orbit's web app in Docker
|
|
23
|
-
orbit mcp [options] Start the stdio MCP server (for agent clients)
|
|
24
|
-
orbit dispatch [options] Dispatch a Hermes profile on a ticket
|
|
25
|
-
|
|
26
|
-
Options (init / reset / run / docker / mcp / dispatch):
|
|
27
|
-
--cwd <dir> Project root (default: process.cwd())
|
|
28
|
-
|
|
29
|
-
Options (init only):
|
|
30
|
-
--no-ai Create the board with AI collaboration disabled
|
|
31
|
-
--example Create example onboarding tickets
|
|
32
|
-
|
|
33
|
-
Options (run / docker):
|
|
34
|
-
--port <n> HTTP port (run auto-starts at 13701; --port/$PORT is exact)
|
|
35
|
-
|
|
36
|
-
Options (run):
|
|
37
|
-
-d, --detach Run in the background and print the child PID/log path
|
|
38
|
-
|
|
39
|
-
Options (dispatch):
|
|
40
|
-
--board <slug-or-id> Local board to dispatch against (default: board for --cwd)
|
|
41
|
-
--ticket <number-id> Ticket number or id to dispatch
|
|
42
|
-
--profile <name> Hermes profile to run (default: agent)
|
|
43
|
-
--policy <name> Autonomous policy wrappers to apply (default: agent-safe; use none to disable)
|
|
44
|
-
--server-url <url> Hosted Orbit base URL for remote dispatch
|
|
45
|
-
--remote Force hosted/remote dispatch mode
|
|
46
|
-
--worktree Create and preserve a git worktree for review/testing
|
|
47
|
-
--worktree-path <dir> Worktree path when --worktree is used
|
|
48
|
-
--branch <name> Branch name for the preserved worktree
|
|
49
|
-
--hermes-bin <cmd> Hermes executable (default: hermes)
|
|
50
|
-
--verify-command <cmd> Declare an expected verification command (repeatable)
|
|
51
|
-
--no-spawn Prepare card/worktree/run record but do not start Hermes or move In Progress
|
|
52
|
-
--no-yolo Do not pass --yolo to Hermes (default dispatch passes --yolo)
|
|
53
|
-
--foreground Attach spawned Hermes process to this terminal
|
|
54
|
-
--keep-handoff-file Keep duplicate handoff file under DATA_DIR/dispatch-runs/<board>
|
|
55
|
-
--force Dispatch even when blockers exist
|
|
56
|
-
--dry-run Preview only; no files, worktrees, ticket fields, comments, or agents change
|
|
57
|
-
|
|
58
|
-
Options (docker only):
|
|
59
|
-
--image <name> Docker image tag (default: starscape-orbit:local)
|
|
60
|
-
--data-dir <dir> Docker registry/export data dir (default: <cwd>/.orbit/docker-data)
|
|
61
|
-
--name <name> Optional Docker container name
|
|
62
|
-
-d, --detach Run the container in the background (default)
|
|
63
|
-
--foreground Run attached in the foreground
|
|
64
|
-
--no-build Skip docker build and run an existing image
|
|
65
|
-
--dry-run Print docker commands without running them`);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function printVersion() {
|
|
69
|
-
const packageJson = JSON.parse(readFileSync(resolve(PACKAGE_ROOT, "package.json"), "utf8"));
|
|
70
|
-
console.log(packageJson.version);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function shellQuote(value) {
|
|
74
|
-
return `"${String(value || "").replace(/"/g, '\\"')}"`;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function commandQuote(value) {
|
|
78
|
-
const text = String(value);
|
|
79
|
-
if (/^[A-Za-z0-9_./:@%+=,-]+$/.test(text)) return text;
|
|
80
|
-
return `'${text.replace(/'/g, "'\\''")}'`;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function formatCommand(executable, args) {
|
|
84
|
-
return [executable, ...args].map(commandQuote).join(" ");
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
async function loadCliCore() {
|
|
88
|
-
const [
|
|
89
|
-
{ disableAiCollaboration, enableAiCollaboration },
|
|
90
|
-
{ backupBoardDatabase, backupRegistry },
|
|
91
|
-
{ closeConnection, createRegistrySchema, openConnection },
|
|
92
|
-
{ DATA_DIR, ROOT_DIR },
|
|
93
|
-
{ provisionRepoBoard },
|
|
94
|
-
{ deleteBoard, getBoardByRepoPath },
|
|
95
|
-
{ normalizePath }
|
|
96
|
-
] = await Promise.all([
|
|
97
|
-
import("../core/boards.js"),
|
|
98
|
-
import("../core/backups.js"),
|
|
99
|
-
import("../core/db.js"),
|
|
100
|
-
import("../core/paths.js"),
|
|
101
|
-
import("../core/provision-repo-board.js"),
|
|
102
|
-
import("../core/registry.js"),
|
|
103
|
-
import("../core/util.js")
|
|
104
|
-
]);
|
|
105
|
-
|
|
106
|
-
return {
|
|
107
|
-
DATA_DIR,
|
|
108
|
-
ROOT_DIR,
|
|
109
|
-
backupBoardDatabase,
|
|
110
|
-
backupRegistry,
|
|
111
|
-
closeConnection,
|
|
112
|
-
createRegistrySchema,
|
|
113
|
-
deleteBoard,
|
|
114
|
-
disableAiCollaboration,
|
|
115
|
-
enableAiCollaboration,
|
|
116
|
-
getBoardByRepoPath,
|
|
117
|
-
normalizePath,
|
|
118
|
-
openConnection,
|
|
119
|
-
provisionRepoBoard
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function enableAiIfEnabled(options, registryRow, core) {
|
|
124
|
-
if (!options.ai || !registryRow) return;
|
|
125
|
-
const { enableAiCollaboration, openConnection } = core;
|
|
126
|
-
const db = openConnection(registryRow.db_path);
|
|
127
|
-
enableAiCollaboration(db, registryRow.id, { stageOnboardingTicket: options.example, actor: "orbit init" });
|
|
128
|
-
const suffix = options.example ? "; example ticket #12 is staged in AI Ready." : ".";
|
|
129
|
-
console.log(`AI collaboration enabled — AI Ready, In Progress, and Review lanes are present${suffix}`);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
function disableAiIfRequested(options, registryRow, core) {
|
|
133
|
-
if (options.ai || !registryRow) return;
|
|
134
|
-
const { disableAiCollaboration, openConnection } = core;
|
|
135
|
-
const db = openConnection(registryRow.db_path);
|
|
136
|
-
disableAiCollaboration(db, registryRow.id, { actor: "orbit init" });
|
|
137
|
-
console.log("AI collaboration disabled for this board.");
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
function isBusyFilesystemError(error) {
|
|
141
|
-
const message = String(error?.message || "").toLowerCase();
|
|
142
|
-
return (
|
|
143
|
-
["EBUSY", "EPERM", "ENOTEMPTY"].includes(error?.code) ||
|
|
144
|
-
(error?.code === "ERR_SQLITE_ERROR" && (message.includes("locked") || message.includes("busy")))
|
|
145
|
-
);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
function resetBusyError(error, projectRoot) {
|
|
149
|
-
if (!isBusyFilesystemError(error)) return error;
|
|
150
|
-
const message = [
|
|
151
|
-
`Orbit could not remove local board files under ${projectRoot}.`,
|
|
152
|
-
"",
|
|
153
|
-
"On Windows this usually means an Orbit web server, MCP helper, editor, or terminal still has .orbit/board.db open.",
|
|
154
|
-
"Close Orbit server terminals and restart any AI client with Orbit MCP enabled, then rerun:",
|
|
155
|
-
` orbit reset --cwd ${shellQuote(projectRoot)}`,
|
|
156
|
-
"",
|
|
157
|
-
`Original error: ${error.message}`
|
|
158
|
-
].join("\n");
|
|
159
|
-
const wrapped = new Error(message);
|
|
160
|
-
wrapped.code = error.code;
|
|
161
|
-
wrapped.cause = error;
|
|
162
|
-
return wrapped;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
function invalidArgs(args, message) {
|
|
166
|
-
console.error(message);
|
|
167
|
-
args.command = "help";
|
|
168
|
-
args.invalid = true;
|
|
169
|
-
return args;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
function parseArgs(argv) {
|
|
173
|
-
const args = {
|
|
174
|
-
command: null,
|
|
175
|
-
cwd: process.env.PROJECT_ROOT ? resolve(process.env.PROJECT_ROOT) : process.cwd(),
|
|
176
|
-
cwdProvided: false,
|
|
177
|
-
ai: true,
|
|
178
|
-
example: false,
|
|
179
|
-
port: null,
|
|
180
|
-
detachRequested: false,
|
|
181
|
-
image: "starscape-orbit:local",
|
|
182
|
-
dataDir: null,
|
|
183
|
-
containerName: null,
|
|
184
|
-
buildImage: true,
|
|
185
|
-
detach: true,
|
|
186
|
-
dryRun: false,
|
|
187
|
-
board: null,
|
|
188
|
-
ticket: null,
|
|
189
|
-
ticketUrl: null,
|
|
190
|
-
profile: "agent",
|
|
191
|
-
policy: "agent-safe",
|
|
192
|
-
serverUrl: null,
|
|
193
|
-
worktree: false,
|
|
194
|
-
worktreePath: null,
|
|
195
|
-
branch: null,
|
|
196
|
-
hermesBin: "hermes",
|
|
197
|
-
verifyCommands: [],
|
|
198
|
-
noSpawn: false,
|
|
199
|
-
yolo: true,
|
|
200
|
-
keepHandoffFile: false,
|
|
201
|
-
force: false,
|
|
202
|
-
foreground: false,
|
|
203
|
-
remote: false,
|
|
204
|
-
help: false,
|
|
205
|
-
invalid: false
|
|
206
|
-
};
|
|
207
|
-
const rest = argv.slice(2);
|
|
208
|
-
if (rest.length === 0 || rest[0] === "-h" || rest[0] === "--help") {
|
|
209
|
-
args.command = "help";
|
|
210
|
-
return args;
|
|
211
|
-
}
|
|
212
|
-
if (rest[0] === "-v" || rest[0] === "--version") {
|
|
213
|
-
args.command = "version";
|
|
214
|
-
return args;
|
|
215
|
-
}
|
|
216
|
-
if (rest[0] === "dispatch" && (rest[1] === "-h" || rest[1] === "--help")) {
|
|
217
|
-
args.command = "dispatch";
|
|
218
|
-
args.help = true;
|
|
219
|
-
return args;
|
|
220
|
-
}
|
|
221
|
-
args.command = rest[0];
|
|
222
|
-
for (let i = 1; i < rest.length; i++) {
|
|
223
|
-
const a = rest[i];
|
|
224
|
-
if (a === "--no-ai") args.ai = false;
|
|
225
|
-
else if (a === "--example") args.example = true;
|
|
226
|
-
else if (a === "--cwd" && rest[i + 1]) {
|
|
227
|
-
args.cwdProvided = true;
|
|
228
|
-
args.cwd = resolve(rest[++i]);
|
|
229
|
-
} else if (a.startsWith("--cwd=")) {
|
|
230
|
-
args.cwdProvided = true;
|
|
231
|
-
args.cwd = resolve(a.slice("--cwd=".length));
|
|
232
|
-
} else if (a === "--port" && rest[i + 1]) {
|
|
233
|
-
args.port = rest[++i];
|
|
234
|
-
} else if (a.startsWith("--port=")) {
|
|
235
|
-
args.port = a.slice("--port=".length);
|
|
236
|
-
} else if (a === "--board" && rest[i + 1]) {
|
|
237
|
-
args.board = rest[++i];
|
|
238
|
-
} else if (a.startsWith("--board=")) {
|
|
239
|
-
args.board = a.slice("--board=".length);
|
|
240
|
-
} else if (a === "--ticket" && rest[i + 1]) {
|
|
241
|
-
args.ticket = rest[++i];
|
|
242
|
-
} else if (a.startsWith("--ticket=")) {
|
|
243
|
-
args.ticket = a.slice("--ticket=".length);
|
|
244
|
-
} else if (a === "--profile" && rest[i + 1]) {
|
|
245
|
-
args.profile = rest[++i];
|
|
246
|
-
} else if (a.startsWith("--profile=")) {
|
|
247
|
-
args.profile = a.slice("--profile=".length);
|
|
248
|
-
} else if (a === "--policy" && rest[i + 1]) {
|
|
249
|
-
args.policy = rest[++i];
|
|
250
|
-
} else if (a.startsWith("--policy=")) {
|
|
251
|
-
args.policy = a.slice("--policy=".length);
|
|
252
|
-
} else if (a === "--server-url" && rest[i + 1]) {
|
|
253
|
-
args.serverUrl = rest[++i];
|
|
254
|
-
} else if (a.startsWith("--server-url=")) {
|
|
255
|
-
args.serverUrl = a.slice("--server-url=".length);
|
|
256
|
-
} else if (a === "--remote") {
|
|
257
|
-
args.remote = true;
|
|
258
|
-
} else if (a === "--worktree") {
|
|
259
|
-
args.worktree = true;
|
|
260
|
-
} else if (a === "--worktree-path" && rest[i + 1]) {
|
|
261
|
-
args.worktreePath = resolve(rest[++i]);
|
|
262
|
-
} else if (a.startsWith("--worktree-path=")) {
|
|
263
|
-
args.worktreePath = resolve(a.slice("--worktree-path=".length));
|
|
264
|
-
} else if (a === "--branch" && rest[i + 1]) {
|
|
265
|
-
args.branch = rest[++i];
|
|
266
|
-
} else if (a.startsWith("--branch=")) {
|
|
267
|
-
args.branch = a.slice("--branch=".length);
|
|
268
|
-
} else if (a === "--hermes-bin" && rest[i + 1]) {
|
|
269
|
-
args.hermesBin = rest[++i];
|
|
270
|
-
} else if (a.startsWith("--hermes-bin=")) {
|
|
271
|
-
args.hermesBin = a.slice("--hermes-bin=".length);
|
|
272
|
-
} else if (a === "--verify-command") {
|
|
273
|
-
const value = rest[i + 1];
|
|
274
|
-
if (!value || value.startsWith("--")) {
|
|
275
|
-
return invalidArgs(args, "--verify-command requires a non-empty value. Use --verify-command=<cmd> for values that start with --.");
|
|
276
|
-
}
|
|
277
|
-
args.verifyCommands.push(rest[++i]);
|
|
278
|
-
} else if (a.startsWith("--verify-command=")) {
|
|
279
|
-
const value = a.slice("--verify-command=".length);
|
|
280
|
-
if (!value) {
|
|
281
|
-
return invalidArgs(args, "--verify-command requires a non-empty value.");
|
|
282
|
-
}
|
|
283
|
-
args.verifyCommands.push(value);
|
|
284
|
-
} else if (a === "--no-spawn") {
|
|
285
|
-
args.noSpawn = true;
|
|
286
|
-
} else if (a === "--no-yolo") {
|
|
287
|
-
args.yolo = false;
|
|
288
|
-
} else if (a === "--yolo") {
|
|
289
|
-
args.yolo = true;
|
|
290
|
-
} else if (a === "--keep-handoff-file") {
|
|
291
|
-
args.keepHandoffFile = true;
|
|
292
|
-
} else if (a === "--force") {
|
|
293
|
-
args.force = true;
|
|
294
|
-
} else if (a === "--image" && rest[i + 1]) {
|
|
295
|
-
args.image = rest[++i];
|
|
296
|
-
} else if (a.startsWith("--image=")) {
|
|
297
|
-
args.image = a.slice("--image=".length);
|
|
298
|
-
} else if (a === "--data-dir" && rest[i + 1]) {
|
|
299
|
-
args.dataDir = resolve(rest[++i]);
|
|
300
|
-
} else if (a.startsWith("--data-dir=")) {
|
|
301
|
-
args.dataDir = resolve(a.slice("--data-dir=".length));
|
|
302
|
-
} else if (a === "--name" && rest[i + 1]) {
|
|
303
|
-
args.containerName = rest[++i];
|
|
304
|
-
} else if (a.startsWith("--name=")) {
|
|
305
|
-
args.containerName = a.slice("--name=".length);
|
|
306
|
-
} else if (a === "--no-build") {
|
|
307
|
-
args.buildImage = false;
|
|
308
|
-
} else if (a === "-d" || a === "--detach") {
|
|
309
|
-
args.detach = true;
|
|
310
|
-
args.detachRequested = true;
|
|
311
|
-
} else if (a === "--foreground") {
|
|
312
|
-
args.detach = false;
|
|
313
|
-
args.foreground = true;
|
|
314
|
-
} else if (a === "--dry-run") {
|
|
315
|
-
args.dryRun = true;
|
|
316
|
-
} else if (args.command === "dispatch" && /^https?:\/\//i.test(a) && !args.ticketUrl) {
|
|
317
|
-
args.ticketUrl = a;
|
|
318
|
-
args.remote = true;
|
|
319
|
-
} else {
|
|
320
|
-
console.error(`Unknown argument: ${a}`);
|
|
321
|
-
args.command = "help";
|
|
322
|
-
args.invalid = true;
|
|
323
|
-
return args;
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
return args;
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
async function runInit(options) {
|
|
330
|
-
const core = await loadCliCore();
|
|
331
|
-
const { DATA_DIR, ROOT_DIR, createRegistrySchema, normalizePath, provisionRepoBoard } = core;
|
|
332
|
-
const projectRoot = normalizePath(resolve(options.cwd));
|
|
333
|
-
mkdirSync(DATA_DIR, { recursive: true });
|
|
334
|
-
createRegistrySchema();
|
|
335
|
-
|
|
336
|
-
const result = provisionRepoBoard(projectRoot, { enableAi: options.ai, includeExamples: options.example });
|
|
337
|
-
const skillSrc = resolve(ROOT_DIR, "SKILL-ORBIT.md");
|
|
338
|
-
const skillDest = resolve(projectRoot, "SKILL-ORBIT.md");
|
|
339
|
-
|
|
340
|
-
if (!existsSync(skillSrc)) {
|
|
341
|
-
console.warn(`Warning: missing ${skillSrc} — skipped copying SKILL-ORBIT.md and AGENTS.md Orbit section.`);
|
|
342
|
-
} else {
|
|
343
|
-
const skillSync = syncSkillOrbitMd(projectRoot, skillSrc);
|
|
344
|
-
if (skillSync.status === "same_file") {
|
|
345
|
-
console.log("SKILL-ORBIT.md source is already the project copy — left unchanged.");
|
|
346
|
-
} else {
|
|
347
|
-
console.log(`Wrote ${skillDest}`);
|
|
348
|
-
}
|
|
349
|
-
syncAgentsMd(projectRoot);
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
enableAiIfEnabled(options, result.registryRow, core);
|
|
353
|
-
disableAiIfRequested(options, result.registryRow, core);
|
|
354
|
-
|
|
355
|
-
if (result.message && result.status === "skipped") {
|
|
356
|
-
console.log(result.message);
|
|
357
|
-
} else if (result.status === "created") {
|
|
358
|
-
console.log(`Initialized Orbit board at ${result.registryRow?.db_path ?? "(unknown path)"}`);
|
|
359
|
-
} else if (result.status === "repaired") {
|
|
360
|
-
console.log(result.message || "Linked existing board database to the registry.");
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
const cliPath = resolve(ROOT_DIR, "src", "cli", "orbit.js");
|
|
364
|
-
const mcpLine = ["claude mcp add starscape-orbit", "--", "node", shellQuote(cliPath), "mcp", "--cwd", shellQuote(projectRoot)].join(" ");
|
|
365
|
-
console.log(`
|
|
366
|
-
--- Next: MCP (run once per Claude Code install) ---
|
|
367
|
-
${mcpLine}
|
|
368
|
-
|
|
369
|
-
--- Next: agent prompt (from this repo) ---
|
|
370
|
-
Read AGENTS.md in this repository, then use the Orbit MCP tools. Use board_list, board_set_active, and ticket context tools per docs/AGENT_PROTOCOL.md before claiming or updating work.
|
|
371
|
-
|
|
372
|
-
${options.example ? (options.ai ? "Example ticket #12 is \"Try Orbit MCP on this ticket\" in AI Ready — good first exercise after MCP is connected." : "Example tickets were created. AI collaboration was disabled with `--no-ai`, so ticket #12 remains in Backlog.") : "No example tickets were created. Rerun on a fresh board with `orbit init --example` if you want the onboarding examples."}
|
|
373
|
-
`);
|
|
374
|
-
|
|
375
|
-
if (result.registryRow) {
|
|
376
|
-
console.log(`Board: ${result.registryRow.name} (${result.registryRow.slug}) registry id: ${result.registryRow.id}`);
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
async function runReset(options) {
|
|
381
|
-
const {
|
|
382
|
-
DATA_DIR,
|
|
383
|
-
backupBoardDatabase,
|
|
384
|
-
backupRegistry,
|
|
385
|
-
closeConnection,
|
|
386
|
-
createRegistrySchema,
|
|
387
|
-
deleteBoard,
|
|
388
|
-
getBoardByRepoPath,
|
|
389
|
-
normalizePath,
|
|
390
|
-
openConnection
|
|
391
|
-
} = await loadCliCore();
|
|
392
|
-
const projectRoot = normalizePath(resolve(options.cwd));
|
|
393
|
-
mkdirSync(DATA_DIR, { recursive: true });
|
|
394
|
-
createRegistrySchema();
|
|
395
|
-
|
|
396
|
-
const orbitDir = resolve(projectRoot, ".orbit");
|
|
397
|
-
const skillMd = resolve(projectRoot, "SKILL-ORBIT.md");
|
|
398
|
-
const removed = [];
|
|
399
|
-
const registryRow = getBoardByRepoPath(projectRoot);
|
|
400
|
-
|
|
401
|
-
if (registryRow && existsSync(registryRow.db_path)) {
|
|
402
|
-
const db = openConnection(registryRow.db_path);
|
|
403
|
-
try {
|
|
404
|
-
backupBoardDatabase(registryRow, db, "pre-cli-reset");
|
|
405
|
-
} catch (error) {
|
|
406
|
-
throw resetBusyError(error, projectRoot);
|
|
407
|
-
} finally {
|
|
408
|
-
closeConnection(registryRow.db_path);
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
if (registryRow) backupRegistry("pre-cli-reset");
|
|
412
|
-
|
|
413
|
-
try {
|
|
414
|
-
// Remove the board database. With central storage the db lives outside the
|
|
415
|
-
// project directory; with legacy in-repo storage it is inside orbitDir below.
|
|
416
|
-
const isCentralDb = registryRow && !registryRow.db_path.startsWith(projectRoot + "/");
|
|
417
|
-
if (isCentralDb && existsSync(registryRow.db_path)) {
|
|
418
|
-
const boardDir = dirname(registryRow.db_path);
|
|
419
|
-
rmSync(boardDir, { recursive: true, force: true });
|
|
420
|
-
removed.push(boardDir);
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
// Remove central dispatch-runs for this board.
|
|
424
|
-
if (registryRow) {
|
|
425
|
-
const dispatchRunsDir = join(DATA_DIR, "dispatch-runs", registryRow.slug);
|
|
426
|
-
if (existsSync(dispatchRunsDir)) {
|
|
427
|
-
rmSync(dispatchRunsDir, { recursive: true, force: true });
|
|
428
|
-
removed.push(dispatchRunsDir);
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
// Remove the in-repo .orbit/ directory (covers legacy db, residual dispatch-runs, etc.).
|
|
433
|
-
if (existsSync(orbitDir)) {
|
|
434
|
-
rmSync(orbitDir, { recursive: true, force: true });
|
|
435
|
-
removed.push(orbitDir);
|
|
436
|
-
}
|
|
437
|
-
if (existsSync(skillMd)) {
|
|
438
|
-
unlinkSync(skillMd);
|
|
439
|
-
removed.push(skillMd);
|
|
440
|
-
}
|
|
441
|
-
const agentsCleanup = removeOrbitAgentsSection(projectRoot);
|
|
442
|
-
if (agentsCleanup.removed) {
|
|
443
|
-
removed.push(`${agentsCleanup.path} Orbit section`);
|
|
444
|
-
} else if (!agentsCleanup.ok) {
|
|
445
|
-
console.warn(`Warning: skipped AGENTS.md cleanup (${agentsCleanup.reason}) in ${agentsCleanup.path}`);
|
|
446
|
-
}
|
|
447
|
-
} catch (error) {
|
|
448
|
-
throw resetBusyError(error, projectRoot);
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
if (registryRow) {
|
|
452
|
-
deleteBoard(registryRow.id);
|
|
453
|
-
removed.push(`registry row "${registryRow.slug}"`);
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
if (removed.length === 0) {
|
|
457
|
-
console.log(`Nothing to reset under ${projectRoot}.`);
|
|
458
|
-
} else {
|
|
459
|
-
for (const item of removed) console.log(`Removed ${item}`);
|
|
460
|
-
console.log(`\nRun \`orbit init\` from ${projectRoot} to provision a fresh board.`);
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
async function runServe(options) {
|
|
465
|
-
// PROJECT_ROOT must be set BEFORE importing the server, because src/core/paths.js
|
|
466
|
-
// captures it at module load. cwd defaults are equivalent for most users, but
|
|
467
|
-
// an explicit --cwd lets a global install target a board outside cwd.
|
|
468
|
-
process.env.PROJECT_ROOT = resolve(options.cwd);
|
|
469
|
-
process.env.ORBIT_SYNC_MANAGED_SKILL_ORBIT = "1";
|
|
470
|
-
if (options.port) process.env.PORT = String(options.port);
|
|
471
|
-
await import("../server.js");
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
function orbitDataDir() {
|
|
475
|
-
return process.env.DATA_DIR || join(homedir(), ".orbit");
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
function startDetachedRun(options) {
|
|
479
|
-
const dataDir = orbitDataDir();
|
|
480
|
-
mkdirSync(dataDir, { recursive: true });
|
|
481
|
-
const logPath = join(dataDir, "orbit-run.log");
|
|
482
|
-
const logFd = openSync(logPath, "a");
|
|
483
|
-
const cliPath = fileURLToPath(import.meta.url);
|
|
484
|
-
const childArgs = [cliPath, "run", "--cwd", resolve(options.cwd)];
|
|
485
|
-
if (options.port) childArgs.push("--port", String(options.port));
|
|
486
|
-
const child = spawn(process.execPath, childArgs, {
|
|
487
|
-
cwd: process.cwd(),
|
|
488
|
-
detached: true,
|
|
489
|
-
env: { ...process.env },
|
|
490
|
-
stdio: ["ignore", logFd, logFd]
|
|
491
|
-
});
|
|
492
|
-
child.unref();
|
|
493
|
-
closeSync(logFd);
|
|
494
|
-
const port = options.port || process.env.PORT || 13701;
|
|
495
|
-
console.log("Started Orbit in detached mode.");
|
|
496
|
-
console.log(`PID: ${child.pid}`);
|
|
497
|
-
console.log(`Log: ${logPath}`);
|
|
498
|
-
console.log(
|
|
499
|
-
options.port || process.env.PORT
|
|
500
|
-
? `URL: http://localhost:${port}`
|
|
501
|
-
: `URL: starts at http://localhost:${port} (auto-increments if busy; see log)`
|
|
502
|
-
);
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
function containerPathFor(hostPath, fallbackPath) {
|
|
506
|
-
// Linux/macOS Docker can mount the same absolute path into the container,
|
|
507
|
-
// which keeps existing Orbit board metadata meaningful. Windows paths are
|
|
508
|
-
// not valid Linux container paths, so use stable in-container fallbacks.
|
|
509
|
-
return process.platform === "win32" ? fallbackPath : hostPath;
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
function buildDockerPlan(options) {
|
|
513
|
-
const projectRoot = resolve(options.cwd);
|
|
514
|
-
const dataDir = resolve(options.dataDir || resolve(projectRoot, ".orbit", "docker-data"));
|
|
515
|
-
const containerProjectRoot = containerPathFor(projectRoot, "/workspace");
|
|
516
|
-
const containerDataDir = containerPathFor(dataDir, "/data");
|
|
517
|
-
const port = String(options.port || process.env.PORT || 13701);
|
|
518
|
-
|
|
519
|
-
if (!existsSync(projectRoot)) {
|
|
520
|
-
throw new Error(`Project root does not exist: ${projectRoot}`);
|
|
521
|
-
}
|
|
522
|
-
if (!existsSync(resolve(PACKAGE_ROOT, "Dockerfile"))) {
|
|
523
|
-
throw new Error(`Dockerfile not found in Orbit package root: ${PACKAGE_ROOT}`);
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
const buildArgs = ["build", "-t", options.image, PACKAGE_ROOT];
|
|
527
|
-
const runArgs = ["run", "--rm"];
|
|
528
|
-
if (options.detach) {
|
|
529
|
-
runArgs.push("--detach");
|
|
530
|
-
} else if (process.stdin.isTTY && process.stdout.isTTY) {
|
|
531
|
-
runArgs.push("-it");
|
|
532
|
-
}
|
|
533
|
-
if (options.containerName) runArgs.push("--name", options.containerName);
|
|
534
|
-
runArgs.push(
|
|
535
|
-
"-p",
|
|
536
|
-
`${port}:${port}`,
|
|
537
|
-
"-e",
|
|
538
|
-
`PORT=${port}`,
|
|
539
|
-
"-e",
|
|
540
|
-
`PROJECT_ROOT=${containerProjectRoot}`,
|
|
541
|
-
"-e",
|
|
542
|
-
`DATA_DIR=${containerDataDir}`,
|
|
543
|
-
"-e",
|
|
544
|
-
`SYSTEM_PATH=${projectRoot}`,
|
|
545
|
-
"-v",
|
|
546
|
-
`${projectRoot}:${containerProjectRoot}`,
|
|
547
|
-
"-v",
|
|
548
|
-
`${dataDir}:${containerDataDir}`,
|
|
549
|
-
"-w",
|
|
550
|
-
containerProjectRoot,
|
|
551
|
-
options.image,
|
|
552
|
-
"run",
|
|
553
|
-
"--cwd",
|
|
554
|
-
containerProjectRoot,
|
|
555
|
-
"--port",
|
|
556
|
-
port
|
|
557
|
-
);
|
|
558
|
-
|
|
559
|
-
return { buildArgs, containerDataDir, containerProjectRoot, dataDir, port, projectRoot, runArgs };
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
function runDockerCommand(args) {
|
|
563
|
-
const result = spawnSync("docker", args, { stdio: "inherit" });
|
|
564
|
-
if (result.error) {
|
|
565
|
-
throw new Error(`Failed to run docker: ${result.error.message}`);
|
|
566
|
-
}
|
|
567
|
-
if (result.signal) {
|
|
568
|
-
process.exitCode = 1;
|
|
569
|
-
return false;
|
|
570
|
-
}
|
|
571
|
-
if (result.status !== 0) {
|
|
572
|
-
process.exitCode = result.status ?? 1;
|
|
573
|
-
return false;
|
|
574
|
-
}
|
|
575
|
-
return true;
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
async function runDocker(options) {
|
|
579
|
-
const plan = buildDockerPlan(options);
|
|
580
|
-
const dryRun = options.dryRun || process.env.ORBIT_DOCKER_DRY_RUN === "1";
|
|
581
|
-
|
|
582
|
-
if (dryRun) {
|
|
583
|
-
console.log(`Project root: ${plan.projectRoot}`);
|
|
584
|
-
console.log(`Docker data: ${plan.dataDir}`);
|
|
585
|
-
if (options.buildImage) {
|
|
586
|
-
console.log(`Docker build:\n ${formatCommand("docker", plan.buildArgs)}`);
|
|
587
|
-
}
|
|
588
|
-
console.log(`Docker run:\n ${formatCommand("docker", plan.runArgs)}`);
|
|
589
|
-
return;
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
mkdirSync(plan.dataDir, { recursive: true });
|
|
593
|
-
if (options.buildImage && !runDockerCommand(plan.buildArgs)) return;
|
|
594
|
-
runDockerCommand(plan.runArgs);
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
async function runMcp(options) {
|
|
598
|
-
process.env.PROJECT_ROOT = resolve(options.cwd);
|
|
599
|
-
await import("../mcp-server.js");
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
async function runDispatch(options) {
|
|
603
|
-
if (options.help) {
|
|
604
|
-
printUsage();
|
|
605
|
-
return;
|
|
606
|
-
}
|
|
607
|
-
process.env.PROJECT_ROOT = resolve(options.cwd);
|
|
608
|
-
const { dispatchTicketAsync } = await import("../core/dispatch.js");
|
|
609
|
-
const result = await dispatchTicketAsync(options);
|
|
610
|
-
if (result.dry_run) {
|
|
611
|
-
console.log(`Dry run: would dispatch ticket #${result.ticket.number} ${result.ticket.title}`);
|
|
612
|
-
console.log(`Board: ${result.board.slug}`);
|
|
613
|
-
console.log(`Profile: ${result.profile}`);
|
|
614
|
-
console.log(`Mode: ${result.no_spawn ? "prepare-only" : "spawn"}`);
|
|
615
|
-
console.log("No files, worktrees, ticket fields, comments, or agents were changed.");
|
|
616
|
-
return;
|
|
617
|
-
}
|
|
618
|
-
console.log(`Dispatch ${result.spawned ? "started" : "prepared"}: ${result.run_id}`);
|
|
619
|
-
console.log(`Board: ${result.board.slug}`);
|
|
620
|
-
console.log(`Ticket: #${result.ticket.number} ${result.ticket.title}`);
|
|
621
|
-
console.log(`Profile: ${result.profile}`);
|
|
622
|
-
console.log(`Policy: ${result.policy}`);
|
|
623
|
-
console.log(`Worktree: ${result.worktree_path}`);
|
|
624
|
-
if (result.branch) console.log(`Branch: ${result.branch}`);
|
|
625
|
-
if (result.run_record_path) console.log(`Run record: ${result.run_record_path}`);
|
|
626
|
-
if (result.pid) console.log(`PID: ${result.pid}`);
|
|
627
|
-
console.log("AI Plan updated with a terse summary and linked handoff artifact.");
|
|
628
|
-
console.log("Run record comment added to the ticket.");
|
|
629
|
-
if (result.no_spawn) console.log("No agent spawned; ticket state left unchanged.");
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
async function main() {
|
|
633
|
-
const args = parseArgs(process.argv);
|
|
634
|
-
try {
|
|
635
|
-
if (args.command === "init") {
|
|
636
|
-
await runInit(args);
|
|
637
|
-
} else if (args.command === "reset") {
|
|
638
|
-
await runReset(args);
|
|
639
|
-
} else if (args.command === "run" || args.command === "serve") {
|
|
640
|
-
if (args.detachRequested && args.detach) startDetachedRun(args);
|
|
641
|
-
else await runServe(args);
|
|
642
|
-
} else if (args.command === "docker") {
|
|
643
|
-
await runDocker(args);
|
|
644
|
-
} else if (args.command === "mcp") {
|
|
645
|
-
await runMcp(args);
|
|
646
|
-
} else if (args.command === "dispatch") {
|
|
647
|
-
await runDispatch(args);
|
|
648
|
-
} else if (args.command === "version") {
|
|
649
|
-
printVersion();
|
|
650
|
-
} else {
|
|
651
|
-
printUsage();
|
|
652
|
-
process.exitCode = args.command === "help" && !args.invalid ? 0 : 1;
|
|
653
|
-
}
|
|
654
|
-
} catch (err) {
|
|
655
|
-
console.error(err?.message || err);
|
|
656
|
-
process.exitCode = 1;
|
|
657
|
-
}
|
|
9
|
+
if (process.argv[2] === "mcp") {
|
|
10
|
+
process.stderr.write("Orbit 2.0 starts as `orbit mcp`: this server was added the 1.x way, so re-add it as `orbit mcp` when convenient.\n");
|
|
11
|
+
} else {
|
|
12
|
+
process.stderr.write("Orbit 2.0's command is `orbit`: this path is 1.x's, so call `orbit` instead when convenient.\n");
|
|
658
13
|
}
|
|
659
14
|
|
|
660
|
-
await
|
|
661
|
-
await new Promise((resolvePromise) => process.stdout.write("", resolvePromise));
|
|
662
|
-
await new Promise((resolvePromise) => process.stderr.write("", resolvePromise));
|
|
15
|
+
await import("../../lib/cli/orbit.js");
|