borgmcp 1.0.6 → 1.0.7

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 (157) hide show
  1. package/dist/assimilate-cmd.js +39 -511
  2. package/dist/assimilate-deps.js +3 -177
  3. package/dist/assimilate-welcome.js +2 -24
  4. package/dist/auth-env.js +1 -107
  5. package/dist/auth.js +23 -612
  6. package/dist/claude.js +11 -281
  7. package/dist/cli-help.js +29 -50
  8. package/dist/cli-platform.js +4 -94
  9. package/dist/codex-app-server.js +4 -228
  10. package/dist/codex-app-wake.js +2 -122
  11. package/dist/codex-launch.js +1 -81
  12. package/dist/codex-remote.js +1 -250
  13. package/dist/config-utils.js +3 -385
  14. package/dist/config.js +1 -190
  15. package/dist/console-prefix.js +1 -86
  16. package/dist/cube-name.js +1 -65
  17. package/dist/cubes.js +4 -269
  18. package/dist/debug.js +1 -71
  19. package/dist/device-auth.js +1 -167
  20. package/dist/direct-log.js +1 -11
  21. package/dist/health-beat.js +1 -168
  22. package/dist/inbox-monitor.js +1 -129
  23. package/dist/index.js +26 -1378
  24. package/dist/lifecycle-log-guard.js +2 -93
  25. package/dist/list-roles-render.js +6 -39
  26. package/dist/log-audit.js +3 -186
  27. package/dist/log-stream.js +9 -848
  28. package/dist/name-validator.js +1 -22
  29. package/dist/parse-assimilate-args.js +1 -82
  30. package/dist/postinstall.js +8 -22
  31. package/dist/regen-format.js +11 -337
  32. package/dist/regen.js +5 -83
  33. package/dist/remote-client.js +1 -695
  34. package/dist/role-resolver.js +1 -36
  35. package/dist/role-section.js +8 -208
  36. package/dist/roster-render.js +3 -96
  37. package/dist/setup.js +36 -251
  38. package/dist/shell-escape.js +1 -22
  39. package/dist/spawn.js +10 -29
  40. package/dist/stale-version-check.js +1 -102
  41. package/dist/stream-owner.js +2 -202
  42. package/dist/stream-status.js +3 -211
  43. package/dist/subscription-retry.js +1 -23
  44. package/dist/sync-roles-render.js +3 -118
  45. package/dist/sync.js +22 -286
  46. package/dist/templates.js +120 -626
  47. package/dist/terminal-title.js +1 -68
  48. package/dist/token-crypto.js +1 -91
  49. package/dist/token-store.js +1 -222
  50. package/dist/types.js +0 -5
  51. package/dist/version.js +2 -78
  52. package/dist/worktree-lifecycle.js +2 -173
  53. package/package.json +11 -2
  54. package/dist/assimilate-cmd.d.ts.map +0 -1
  55. package/dist/assimilate-cmd.js.map +0 -1
  56. package/dist/assimilate-deps.d.ts.map +0 -1
  57. package/dist/assimilate-deps.js.map +0 -1
  58. package/dist/assimilate-welcome.d.ts.map +0 -1
  59. package/dist/assimilate-welcome.js.map +0 -1
  60. package/dist/auth-env.d.ts.map +0 -1
  61. package/dist/auth-env.js.map +0 -1
  62. package/dist/auth.d.ts.map +0 -1
  63. package/dist/auth.js.map +0 -1
  64. package/dist/claude.d.ts.map +0 -1
  65. package/dist/claude.js.map +0 -1
  66. package/dist/cli-help.d.ts.map +0 -1
  67. package/dist/cli-help.js.map +0 -1
  68. package/dist/cli-platform.d.ts.map +0 -1
  69. package/dist/cli-platform.js.map +0 -1
  70. package/dist/codex-app-server.d.ts.map +0 -1
  71. package/dist/codex-app-server.js.map +0 -1
  72. package/dist/codex-app-wake.d.ts.map +0 -1
  73. package/dist/codex-app-wake.js.map +0 -1
  74. package/dist/codex-launch.d.ts.map +0 -1
  75. package/dist/codex-launch.js.map +0 -1
  76. package/dist/codex-remote.d.ts.map +0 -1
  77. package/dist/codex-remote.js.map +0 -1
  78. package/dist/config-utils.d.ts.map +0 -1
  79. package/dist/config-utils.js.map +0 -1
  80. package/dist/config.d.ts.map +0 -1
  81. package/dist/config.js.map +0 -1
  82. package/dist/console-prefix.d.ts.map +0 -1
  83. package/dist/console-prefix.js.map +0 -1
  84. package/dist/cube-name.d.ts.map +0 -1
  85. package/dist/cube-name.js.map +0 -1
  86. package/dist/cubes.d.ts.map +0 -1
  87. package/dist/cubes.js.map +0 -1
  88. package/dist/debug.d.ts.map +0 -1
  89. package/dist/debug.js.map +0 -1
  90. package/dist/device-auth.d.ts.map +0 -1
  91. package/dist/device-auth.js.map +0 -1
  92. package/dist/direct-log.d.ts.map +0 -1
  93. package/dist/direct-log.js.map +0 -1
  94. package/dist/health-beat.d.ts.map +0 -1
  95. package/dist/health-beat.js.map +0 -1
  96. package/dist/inbox-monitor.d.ts.map +0 -1
  97. package/dist/inbox-monitor.js.map +0 -1
  98. package/dist/index.d.ts.map +0 -1
  99. package/dist/index.js.map +0 -1
  100. package/dist/lifecycle-log-guard.d.ts.map +0 -1
  101. package/dist/lifecycle-log-guard.js.map +0 -1
  102. package/dist/list-roles-render.d.ts.map +0 -1
  103. package/dist/list-roles-render.js.map +0 -1
  104. package/dist/log-audit.d.ts.map +0 -1
  105. package/dist/log-audit.js.map +0 -1
  106. package/dist/log-stream.d.ts.map +0 -1
  107. package/dist/log-stream.js.map +0 -1
  108. package/dist/name-validator.d.ts.map +0 -1
  109. package/dist/name-validator.js.map +0 -1
  110. package/dist/parse-assimilate-args.d.ts.map +0 -1
  111. package/dist/parse-assimilate-args.js.map +0 -1
  112. package/dist/postinstall.d.ts.map +0 -1
  113. package/dist/postinstall.js.map +0 -1
  114. package/dist/regen-format.d.ts.map +0 -1
  115. package/dist/regen-format.js.map +0 -1
  116. package/dist/regen.d.ts.map +0 -1
  117. package/dist/regen.js.map +0 -1
  118. package/dist/remote-client.d.ts.map +0 -1
  119. package/dist/remote-client.js.map +0 -1
  120. package/dist/role-resolver.d.ts.map +0 -1
  121. package/dist/role-resolver.js.map +0 -1
  122. package/dist/role-section.d.ts.map +0 -1
  123. package/dist/role-section.js.map +0 -1
  124. package/dist/roster-render.d.ts.map +0 -1
  125. package/dist/roster-render.js.map +0 -1
  126. package/dist/setup.d.ts.map +0 -1
  127. package/dist/setup.js.map +0 -1
  128. package/dist/shell-escape.d.ts.map +0 -1
  129. package/dist/shell-escape.js.map +0 -1
  130. package/dist/spawn.d.ts.map +0 -1
  131. package/dist/spawn.js.map +0 -1
  132. package/dist/stale-version-check.d.ts.map +0 -1
  133. package/dist/stale-version-check.js.map +0 -1
  134. package/dist/stream-owner.d.ts.map +0 -1
  135. package/dist/stream-owner.js.map +0 -1
  136. package/dist/stream-status.d.ts.map +0 -1
  137. package/dist/stream-status.js.map +0 -1
  138. package/dist/subscription-retry.d.ts.map +0 -1
  139. package/dist/subscription-retry.js.map +0 -1
  140. package/dist/sync-roles-render.d.ts.map +0 -1
  141. package/dist/sync-roles-render.js.map +0 -1
  142. package/dist/sync.d.ts.map +0 -1
  143. package/dist/sync.js.map +0 -1
  144. package/dist/templates.d.ts.map +0 -1
  145. package/dist/templates.js.map +0 -1
  146. package/dist/terminal-title.d.ts.map +0 -1
  147. package/dist/terminal-title.js.map +0 -1
  148. package/dist/token-crypto.d.ts.map +0 -1
  149. package/dist/token-crypto.js.map +0 -1
  150. package/dist/token-store.d.ts.map +0 -1
  151. package/dist/token-store.js.map +0 -1
  152. package/dist/types.d.ts.map +0 -1
  153. package/dist/types.js.map +0 -1
  154. package/dist/version.d.ts.map +0 -1
  155. package/dist/version.js.map +0 -1
  156. package/dist/worktree-lifecycle.d.ts.map +0 -1
  157. package/dist/worktree-lifecycle.js.map +0 -1
package/dist/claude.js CHANGED
@@ -1,282 +1,12 @@
1
1
  #!/usr/bin/env node
2
- /**
3
- * Borg CLI launcher
4
- *
5
- * Spawns Claude Code with a minimal kickoff prompt so the SessionStart
6
- * hook's injected drone playbook actually fires on the first turn.
7
- * Without this, Claude sits waiting for user input and the autonomous
8
- * "look at the log and act" directive never executes.
9
- *
10
- * Commands:
11
- * borg → Launch Claude with kickoff prompt
12
- * borg setup → Re-route to the setup wizard
13
- * borg spawn <name> → Create a sibling git worktree + launch a
14
- * fresh drone inside it (see spawn.ts)
15
- * borg sync → Advance the current worktree across the 5
16
- * lifecycle states (see sync.ts, gh#33)
17
- */
18
- import { spawn } from 'child_process';
19
- import { randomUUID } from 'node:crypto';
20
- import { basename } from 'node:path';
21
- import { createInterface } from 'node:readline/promises';
22
- import chalk from 'chalk';
23
- import { getActiveCube, inboxPathForDrone, setCodexWakeTarget } from './cubes.js';
24
- import { handleVersionFlag, getPackageVersion } from './version.js';
25
- import { isHelpFlag, setupHelpText, topLevelHelpText } from './cli-help.js';
26
- import { runSpawn } from './spawn.js';
27
- import { parseSyncArgs, runSync } from './sync.js';
28
- import { parseAssimilateArgs } from './parse-assimilate-args.js';
29
- import { runAssimilate } from './assimilate-cmd.js';
30
- import { buildDefaultAssimilateDeps } from './assimilate-deps.js';
31
- import { setTerminalTitle } from './terminal-title.js';
32
- import { initConsolePrefix, consolePrefix } from './console-prefix.js';
33
- import { initDebugFromArgv } from './debug.js';
34
- import { fetchLatestBorgmcpVersion, compareVersionsForStaleness } from './stale-version-check.js';
35
- import { defaultCliChoiceDeps, detectCliAvailability, parseCliFlag, resolveCliChoice } from './cli-platform.js';
36
- import { prepareCodexRemoteLaunch, withCodexCwdArg, defaultCodexRemoteDeps } from './codex-remote.js';
37
- import { findLoadedCodexThread } from './codex-app-server.js';
38
- import { buildAgentKickoffPrompt, recordCodexWakeTarget, socketPathFromRemoteArgs, } from './codex-launch.js';
39
- import { addCodexMcpServer, addCodexSessionStartHook, addCodexUserPromptSubmitHook, addMcpServer, addSessionStartHook, addUserPromptSubmitHook, isCodexMcpServerConfigured, isMcpServerConfigured, } from './config-utils.js';
40
- async function main() {
41
- // `--debug` / BORG_DEBUG: enable HTTP request/response logging to stderr
42
- // (observability for failures like the cross-account assimilate 404).
43
- // Done first so debug covers everything below; strips `--debug` from argv
44
- // so subcommand parsers (which reject unknown flags) never see it. Covers
45
- // the top-level dispatcher + `borg setup` + `borg assimilate` — all route
46
- // through this main.
47
- initDebugFromArgv(process.argv);
48
- // Honor `--version` / `-v` before any other work.
49
- handleVersionFlag();
50
- // Resolve drone self-identification prefix (gh#25) before any error
51
- // emission so messages carry `[drone-X · cube]` from launch onward.
52
- await initConsolePrefix();
53
- // Sprint 7 (b) — silent-stale-binary defensive hardening (gh#148).
54
- // Async + non-blocking: fire the npm registry check in the
55
- // background; if it returns within ~2s with a stale verdict, emit a
56
- // stderr warning before Claude Code launches. Never blocks startup;
57
- // fails silent on any error. The warning fires only when the user is
58
- // launching `borg` interactively (TTY) — scripted invocations stay
59
- // quiet to avoid CI-log noise.
60
- const staleCheckPromise = (async () => {
61
- if (!process.stderr.isTTY)
62
- return;
63
- const installed = getPackageVersion();
64
- const latest = await fetchLatestBorgmcpVersion();
65
- if (!latest)
66
- return;
67
- const result = compareVersionsForStaleness(installed, latest);
68
- if (result.stale && result.message) {
69
- process.stderr.write(`${consolePrefix()}${result.message}\n`);
70
- }
71
- })();
72
- // Intercept --help / -h before handing off to Claude.
73
- if (process.argv[2] === '--help' || process.argv[2] === '-h') {
74
- process.stdout.write(topLevelHelpText(getPackageVersion()));
75
- process.exit(0);
76
- }
77
- // Re-route subcommands.
78
- if (process.argv[2] === 'setup') {
79
- // gh#520: `borg setup --help` must show help, not run the wizard.
80
- if (isHelpFlag(process.argv[3])) {
81
- process.stdout.write(setupHelpText(getPackageVersion()));
82
- process.exit(0);
83
- }
84
- await import('./setup.js');
85
- return;
86
- }
87
- if (process.argv[2] === 'assimilate') {
88
- const parsed = parseAssimilateArgs(process.argv.slice(3));
89
- if (!parsed.ok) {
90
- process.stderr.write(chalk.red(`${consolePrefix()}◼ borg assimilate: ${parsed.error}\n`));
91
- process.exit(1);
92
- }
93
- const deps = buildDefaultAssimilateDeps();
94
- const code = await runAssimilate({ role: parsed.role, flags: parsed.flags }, deps);
95
- process.exit(code);
96
- }
97
- if (process.argv[2] === 'spawn') {
98
- // Deprecated; the stub prints a redirect message and exits 2.
99
- const code = await runSpawn();
100
- process.exit(code);
101
- }
102
- if (process.argv[2] === 'sync') {
103
- const parsed = parseSyncArgs(process.argv.slice(3));
104
- if (!parsed.ok) {
105
- process.stderr.write(chalk.red(`${consolePrefix()}◼ borg sync: ${parsed.error}\n`));
106
- process.exit(1);
107
- }
108
- const code = await runSync({}, parsed.options);
109
- process.exit(code);
110
- }
111
- const parsedCli = parseCliFlag(process.argv.slice(2));
112
- if (parsedCli.error) {
113
- process.stderr.write(chalk.red(`${consolePrefix()}◼ ${parsedCli.error}\n`));
114
- process.exit(1);
115
- }
116
- const prompt = async (message) => {
117
- const rl = createInterface({ input: process.stdin, output: process.stdout });
118
- try {
119
- return await rl.question(message);
120
- }
121
- finally {
122
- rl.close();
123
- }
124
- };
125
- const cli = await resolveCliChoice(parsedCli.cli, defaultCliChoiceDeps(prompt, () => process.stdin.isTTY === true));
126
- ensureDetectedCliConfigured();
127
- // Forward any user-supplied flags (e.g. --resume <id>, --cwd, etc.) to
128
- // the selected agent CLI unchanged.
129
- //
130
- // The kickoff prompt goes at the end as the positional user-message
131
- // argument so the SessionStart hook + drone playbook get a turn to
132
- // execute on session start. Works for fresh sessions and resumed ones.
133
- //
134
- // The /loop wrapper (dynamic mode — no fixed interval) lets Claude
135
- // self-pace iterations. We instruct it to arm a persistent Monitor on
136
- // the inbox file so it wakes the moment another drone posts to the
137
- // cube (the MCP client appends a line to that file in real time via
138
- // the long-poll poller). A 30-min ScheduleWakeup heartbeat acts as a
139
- // safety net so the loop never goes silent.
140
- const passthroughArgs = parsedCli.rest;
141
- // Only include the Monitor instruction if this project is already
142
- // assimilated to a cube — without one we don't know which inbox file
143
- // to watch, and arming a Monitor on a not-yet-relevant path produces
144
- // no signal. The user can assimilate and relaunch to engage real-time
145
- // wake; the /loop heartbeat alone covers the meantime.
146
- const active = await getActiveCube();
147
- // Set the terminal title so sibling drone sessions are
148
- // distinguishable in Cmd-Tab / tab bars / Mission Control. No-op
149
- // when stdout isn't a TTY (piped invocation, CI). Claude Code does
150
- // not set its own title, so this persists for the session.
151
- setTerminalTitle(active ? { label: active.droneLabel, cubeName: active.name } : null, basename(process.cwd()));
152
- const monitorClause = active && cli === 'claude'
153
- ? `If you haven't yet, arm a persistent Monitor running the command ` +
154
- `\`borg-inbox-monitor ${inboxPathForDrone(active.cubeId, active.droneId)}\` ` +
155
- `so each event's task-notification title summarizes the new cube log entry ` +
156
- `(drone label, role, and first ~80 chars of the message body) — letting you ` +
157
- `triage events without reading the full body. `
158
- : '';
159
- // Surface the stale-version warning before launching Claude Code so
160
- // the operator sees it inline rather than buried in MCP-server stderr.
161
- // 2s ceiling: if the registry check hasn't returned by now, skip
162
- // silently — Claude Code launch shouldn't wait on a network check.
163
- await Promise.race([staleCheckPromise, new Promise((r) => setTimeout(r, 2000))]);
164
- const codexWakeNonce = cli === 'codex' ? `borg-wake-${randomUUID()}` : null;
165
- let codexWakePathClause;
166
- let remoteArgs = [];
167
- let launchEnv = process.env;
168
- let codexSocketPath = null;
169
- let codexServerCleanup = null;
170
- if (cli === 'codex' && !passthroughArgs.includes('--remote')) {
171
- console.error(`${consolePrefix()}${chalk.gray('◼ Starting Codex remote-wake app-server…')}`);
172
- const remote = await prepareCodexRemoteLaunch(defaultCodexRemoteDeps());
173
- if (remote.warning) {
174
- console.error(`${consolePrefix()}${chalk.yellow(`warning: ${remote.warning}`)}`);
175
- codexWakePathClause =
176
- `⚠ Codex wake-path capability check failed: remote-control is unavailable for this session. Run borg:regen manually whenever you return, and expect only fallback wakeups until relaunch.`;
177
- }
178
- else {
179
- codexWakePathClause =
180
- `Codex wake-path capability check passed: remote-control socket established for this session.`;
181
- }
182
- remoteArgs = remote.args;
183
- launchEnv = { ...process.env, ...remote.env };
184
- codexSocketPath = socketPathFromRemoteArgs(remote.args);
185
- codexServerCleanup = remote.server?.cleanup ?? null;
186
- }
187
- else if (cli === 'codex' && passthroughArgs.includes('--remote')) {
188
- codexWakePathClause =
189
- `Codex wake-path capability check: using caller-provided --remote socket; if no wake arrives, run borg:regen manually when returning to the session.`;
190
- codexSocketPath = socketPathFromRemoteArgs(passthroughArgs);
191
- if (codexSocketPath) {
192
- launchEnv = { ...process.env, BORG_CODEX_REMOTE_WAKE: '1' };
193
- }
194
- }
195
- const kickoff = buildAgentKickoffPrompt({
196
- cli,
197
- codexWakeNonce,
198
- monitorClause,
199
- codexWakePathClause,
200
- });
201
- let launchArgs = [...passthroughArgs, kickoff];
202
- if (cli === 'codex') {
203
- launchArgs = [...remoteArgs, ...withCodexCwdArg(launchArgs, process.cwd())];
204
- }
205
- console.error(`${consolePrefix()}${chalk.blue(`◼ Launching ${cli === 'claude' ? 'Claude Code' : 'Codex'}…`)}`);
206
- const agentProcess = spawn(cli, launchArgs, {
207
- stdio: 'inherit',
208
- shell: false,
209
- env: launchEnv,
210
- });
211
- if (cli === 'codex' && active && codexSocketPath) {
212
- void recordCodexWakeTarget({
213
- deps: { setCodexWakeTarget, findLoadedCodexThread },
214
- cubeId: active.cubeId,
215
- droneId: active.droneId,
216
- socketPath: codexSocketPath,
217
- passthroughArgs,
218
- previewNeedle: codexWakeNonce ?? kickoff.slice(0, 120),
219
- cwd: process.cwd(),
220
- launchedAtSeconds: Math.floor(Date.now() / 1000),
221
- });
222
- }
223
- agentProcess.on('error', (err) => {
224
- if (codexServerCleanup) {
225
- try {
226
- codexServerCleanup();
227
- }
228
- catch {
229
- // best-effort
230
- }
231
- }
232
- if (err.code === 'ENOENT') {
233
- console.error(`${consolePrefix()}${chalk.red(`\n◼ Failed to launch ${cli}`)}`);
234
- console.error(`${consolePrefix()}${chalk.gray(`Make sure ${cli} is installed.\n`)}`);
235
- }
236
- else {
237
- console.error(`${consolePrefix()}${chalk.red(`\n◼ Failed to launch ${cli}: ${err.message}\n`)}`);
238
- }
239
- process.exit(1);
240
- });
241
- agentProcess.on('exit', (code) => {
242
- if (codexServerCleanup) {
243
- try {
244
- codexServerCleanup();
245
- }
246
- catch {
247
- // best-effort
248
- }
249
- }
250
- process.exit(code ?? 0);
251
- });
252
- }
253
- function ensureDetectedCliConfigured() {
254
- const found = detectCliAvailability();
255
- if (found.claude) {
256
- try {
257
- if (!isMcpServerConfigured())
258
- addMcpServer();
259
- addSessionStartHook();
260
- addUserPromptSubmitHook();
261
- }
262
- catch (err) {
263
- console.error(`${consolePrefix()}${chalk.yellow(`warning: Claude Code integration check failed: ${err?.message ?? err}`)}`);
264
- }
265
- }
266
- if (found.codex) {
267
- try {
268
- if (!isCodexMcpServerConfigured())
269
- addCodexMcpServer();
270
- addCodexSessionStartHook();
271
- addCodexUserPromptSubmitHook();
272
- }
273
- catch (err) {
274
- console.error(`${consolePrefix()}${chalk.yellow(`warning: Codex integration check failed: ${err?.message ?? err}`)}`);
275
- }
276
- }
277
- }
278
- main().catch((error) => {
279
- console.error(`${consolePrefix()}${chalk.red(`\n◼ Error: ${error.message}\n`)}`);
280
- process.exit(1);
281
- });
282
- //# sourceMappingURL=claude.js.map
2
+ import{spawn as b}from"child_process";import{randomUUID as y}from"node:crypto";import{basename as S}from"node:path";import{createInterface as A}from"node:readline/promises";import s from"chalk";import{getActiveCube as P,inboxPathForDrone as T,setCodexWakeTarget as D}from"./cubes.js";import{handleVersionFlag as F,getPackageVersion as g}from"./version.js";import{isHelpFlag as I,setupHelpText as E,topLevelHelpText as M}from"./cli-help.js";import{runSpawn as H}from"./spawn.js";import{parseSyncArgs as L,runSync as R}from"./sync.js";import{parseAssimilateArgs as N}from"./parse-assimilate-args.js";import{runAssimilate as W}from"./assimilate-cmd.js";import{buildDefaultAssimilateDeps as O}from"./assimilate-deps.js";import{setTerminalTitle as U}from"./terminal-title.js";import{initConsolePrefix as V,consolePrefix as r}from"./console-prefix.js";import{initDebugFromArgv as _}from"./debug.js";import{fetchLatestBorgmcpVersion as B,compareVersionsForStaleness as K}from"./stale-version-check.js";import{defaultCliChoiceDeps as Y,detectCliAvailability as q,parseCliFlag as z,resolveCliChoice as G}from"./cli-platform.js";import{prepareCodexRemoteLaunch as X,withCodexCwdArg as j,defaultCodexRemoteDeps as J}from"./codex-remote.js";import{findLoadedCodexThread as Q}from"./codex-app-server.js";import{buildAgentKickoffPrompt as Z,recordCodexWakeTarget as ee,socketPathFromRemoteArgs as C}from"./codex-launch.js";import{addCodexMcpServer as re,addCodexSessionStartHook as oe,addCodexUserPromptSubmitHook as se,addMcpServer as te,addSessionStartHook as ie,addUserPromptSubmitHook as ae,isCodexMcpServerConfigured as ne,isMcpServerConfigured as ce}from"./config-utils.js";async function le(){_(process.argv),F(),await V();const n=(async()=>{if(!process.stderr.isTTY)return;const e=g(),a=await B();if(!a)return;const p=K(e,a);p.stale&&p.message&&process.stderr.write(`${r()}${p.message}
3
+ `)})();if((process.argv[2]==="--help"||process.argv[2]==="-h")&&(process.stdout.write(M(g())),process.exit(0)),process.argv[2]==="setup"){I(process.argv[3])&&(process.stdout.write(E(g())),process.exit(0)),await import("./setup.js");return}if(process.argv[2]==="assimilate"){const e=N(process.argv.slice(3));e.ok||(process.stderr.write(s.red(`${r()}\u25FC borg assimilate: ${e.error}
4
+ `)),process.exit(1));const a=O(),p=await W({role:e.role,flags:e.flags},a);process.exit(p)}if(process.argv[2]==="spawn"){const e=await H();process.exit(e)}if(process.argv[2]==="sync"){const e=L(process.argv.slice(3));e.ok||(process.stderr.write(s.red(`${r()}\u25FC borg sync: ${e.error}
5
+ `)),process.exit(1));const a=await R({},e.options);process.exit(a)}const t=z(process.argv.slice(2));t.error&&(process.stderr.write(s.red(`${r()}\u25FC ${t.error}
6
+ `)),process.exit(1));const $=async e=>{const a=A({input:process.stdin,output:process.stdout});try{return await a.question(e)}finally{a.close()}},o=await G(t.cli,Y($,()=>process.stdin.isTTY===!0));de();const c=t.rest,i=await P();U(i?{label:i.droneLabel,cubeName:i.name}:null,S(process.cwd()));const k=i&&o==="claude"?`If you haven't yet, arm a persistent Monitor running the command \`borg-inbox-monitor ${T(i.cubeId,i.droneId)}\` so each event's task-notification title summarizes the new cube log entry (drone label, role, and first ~80 chars of the message body) \u2014 letting you triage events without reading the full body. `:"";await Promise.race([n,new Promise(e=>setTimeout(e,2e3))]);const h=o==="codex"?`borg-wake-${y()}`:null;let m,w=[],u=process.env,l=null,d=null;if(o==="codex"&&!c.includes("--remote")){console.error(`${r()}${s.gray("\u25FC Starting Codex remote-wake app-server\u2026")}`);const e=await X(J());e.warning?(console.error(`${r()}${s.yellow(`warning: ${e.warning}`)}`),m="\u26A0 Codex wake-path capability check failed: remote-control is unavailable for this session. Run borg:regen manually whenever you return, and expect only fallback wakeups until relaunch."):m="Codex wake-path capability check passed: remote-control socket established for this session.",w=e.args,u={...process.env,...e.env},l=C(e.args),d=e.server?.cleanup??null}else o==="codex"&&c.includes("--remote")&&(m="Codex wake-path capability check: using caller-provided --remote socket; if no wake arrives, run borg:regen manually when returning to the session.",l=C(c),l&&(u={...process.env,BORG_CODEX_REMOTE_WAKE:"1"}));const x=Z({cli:o,codexWakeNonce:h,monitorClause:k,codexWakePathClause:m});let f=[...c,x];o==="codex"&&(f=[...w,...j(f,process.cwd())]),console.error(`${r()}${s.blue(`\u25FC Launching ${o==="claude"?"Claude Code":"Codex"}\u2026`)}`);const v=b(o,f,{stdio:"inherit",shell:!1,env:u});o==="codex"&&i&&l&&ee({deps:{setCodexWakeTarget:D,findLoadedCodexThread:Q},cubeId:i.cubeId,droneId:i.droneId,socketPath:l,passthroughArgs:c,previewNeedle:h??x.slice(0,120),cwd:process.cwd(),launchedAtSeconds:Math.floor(Date.now()/1e3)}),v.on("error",e=>{if(d)try{d()}catch{}e.code==="ENOENT"?(console.error(`${r()}${s.red(`
7
+ \u25FC Failed to launch ${o}`)}`),console.error(`${r()}${s.gray(`Make sure ${o} is installed.
8
+ `)}`)):console.error(`${r()}${s.red(`
9
+ \u25FC Failed to launch ${o}: ${e.message}
10
+ `)}`),process.exit(1)}),v.on("exit",e=>{if(d)try{d()}catch{}process.exit(e??0)})}function de(){const n=q();if(n.claude)try{ce()||te(),ie(),ae()}catch(t){console.error(`${r()}${s.yellow(`warning: Claude Code integration check failed: ${t?.message??t}`)}`)}if(n.codex)try{ne()||re(),oe(),se()}catch(t){console.error(`${r()}${s.yellow(`warning: Codex integration check failed: ${t?.message??t}`)}`)}}le().catch(n=>{console.error(`${r()}${s.red(`
11
+ \u25FC Error: ${n.message}
12
+ `)}`),process.exit(1)});
package/dist/cli-help.js CHANGED
@@ -1,50 +1,29 @@
1
- /**
2
- * Pure CLI help-text + flag helpers.
3
- *
4
- * Kept in its own module (not in claude.ts) so importing them in tests does NOT
5
- * run claude.ts's `main()` side effects — the same pattern as parse-assimilate-args.ts
6
- * and cli-platform.ts.
7
- */
8
- /** True for the standard help flags `--help` / `-h`. */
9
- export function isHelpFlag(arg) {
10
- return arg === '--help' || arg === '-h';
11
- }
12
- /**
13
- * Help text for top-level `borg --help`.
14
- *
15
- * Kept pure so tests can pin user-facing discoverability without importing
16
- * claude.ts, which launches agent CLIs as a side effect.
17
- */
18
- export function topLevelHelpText(version) {
19
- return (`borgmcp ${version} — coordinate AI coding agents in shared cubes\n` +
20
- ` MCP server for Claude Code and Codex\n\n` +
21
- `Install Claude Code or Codex first. Type borg ... in your terminal;\n` +
22
- `type borg:... inside your agent session after assimilation.\n\n` +
23
- `Usage:\n` +
24
- ` borg Launch your agent CLI with cube context\n` +
25
- ` borg setup Set up OAuth + register MCP server\n` +
26
- ` borg setup --no-browser Set up from SSH/headless terminals\n` +
27
- ` borg assimilate [role] Join a cube (creates one if needed)\n` +
28
- ` borg assimilate --worktree <name> Spawn a sibling worktree drone\n` +
29
- ` borg sync [--prune] Sync this worktree's branch to origin/main\n` +
30
- ` borg --cli claude|codex Choose agent CLI for this project\n` +
31
- ` borg --version Show installed version\n\n` +
32
- `All other arguments are passed through to the selected agent CLI.\n`);
33
- }
34
- /**
35
- * Help text for `borg setup --help` (gh#520 — previously this ran the setup
36
- * wizard instead of showing help). Mirrors the `borg setup` description in the
37
- * top-level `borg --help`.
38
- */
39
- export function setupHelpText(version) {
40
- return (`borg setup (borgmcp ${version}) — set up OAuth + register the borg MCP server\n\n` +
41
- `Borg MCP needs Claude Code or Codex installed first.\n\n` +
42
- `Usage:\n` +
43
- ` borg setup Run the interactive setup wizard (OAuth sign-in +\n` +
44
- ` register the borg MCP server with your agent CLI)\n` +
45
- ` borg setup --no-browser Sign in without a local browser (device-code flow)\n` +
46
- ` for SSH / headless / container terminals. Alias: --device.\n` +
47
- ` Auto-detected on SSH/headless; this forces it.\n` +
48
- ` borg setup --help Show this help\n`);
49
- }
50
- //# sourceMappingURL=cli-help.js.map
1
+ function r(e){return e==="--help"||e==="-h"}function n(e){return`borgmcp ${e} \u2014 coordinate AI coding agents in shared cubes
2
+ MCP server for Claude Code and Codex
3
+
4
+ Install Claude Code or Codex first. Type borg ... in your terminal;
5
+ type borg:... inside your agent session after assimilation.
6
+
7
+ Usage:
8
+ borg Launch your agent CLI with cube context
9
+ borg setup Set up OAuth + register MCP server
10
+ borg setup --no-browser Set up from SSH/headless terminals
11
+ borg assimilate [role] Join a cube (creates one if needed)
12
+ borg assimilate --worktree <name> Spawn a sibling worktree drone
13
+ borg sync [--prune] Sync this worktree's branch to origin/main
14
+ borg --cli claude|codex Choose agent CLI for this project
15
+ borg --version Show installed version
16
+
17
+ All other arguments are passed through to the selected agent CLI.
18
+ `}function o(e){return`borg setup (borgmcp ${e}) \u2014 set up OAuth + register the borg MCP server
19
+
20
+ Borg MCP needs Claude Code or Codex installed first.
21
+
22
+ Usage:
23
+ borg setup Run the interactive setup wizard (OAuth sign-in +
24
+ register the borg MCP server with your agent CLI)
25
+ borg setup --no-browser Sign in without a local browser (device-code flow)
26
+ for SSH / headless / container terminals. Alias: --device.
27
+ Auto-detected on SSH/headless; this forces it.
28
+ borg setup --help Show this help
29
+ `}export{r as isHelpFlag,o as setupHelpText,n as topLevelHelpText};
@@ -1,94 +1,4 @@
1
- import which from 'which';
2
- import { getProjectCliPreference, setProjectCliPreference } from './cubes.js';
3
- export function detectCliAvailability() {
4
- return {
5
- claude: findCommand('claude'),
6
- codex: findCommand('codex'),
7
- };
8
- }
9
- function findCommand(name) {
10
- try {
11
- return which.sync(name);
12
- }
13
- catch {
14
- return null;
15
- }
16
- }
17
- export function installedCliNames(availability) {
18
- const out = [];
19
- if (availability.claude)
20
- out.push('claude');
21
- if (availability.codex)
22
- out.push('codex');
23
- return out;
24
- }
25
- export async function resolveCliChoice(explicit, deps) {
26
- const availability = deps.detectCli();
27
- const installed = installedCliNames(availability);
28
- if (installed.length === 0) {
29
- throw new Error('Neither Claude Code nor Codex is installed. Install one of them, then run borg again.');
30
- }
31
- if (explicit) {
32
- if (!installed.includes(explicit)) {
33
- throw new Error(`${explicit} CLI is not installed.`);
34
- }
35
- await deps.setPreference(explicit);
36
- return explicit;
37
- }
38
- const stored = await deps.getPreference();
39
- if (stored && installed.includes(stored))
40
- return stored;
41
- if (installed.length === 1) {
42
- await deps.setPreference(installed[0]);
43
- return installed[0];
44
- }
45
- if (!deps.isTTY()) {
46
- throw new Error('Multiple agent CLIs detected. Pass --cli claude or --cli codex to choose.');
47
- }
48
- const answer = (await deps.prompt('Use which CLI for this project?\n 1) claude\n 2) codex\n[1]: ')).trim();
49
- const choice = answer === '' || answer === '1' || answer.toLowerCase() === 'claude'
50
- ? 'claude'
51
- : answer === '2' || answer.toLowerCase() === 'codex'
52
- ? 'codex'
53
- : null;
54
- if (!choice)
55
- throw new Error(`invalid CLI choice "${answer}"`);
56
- await deps.setPreference(choice);
57
- return choice;
58
- }
59
- export function defaultCliChoiceDeps(prompt, isTTY) {
60
- return {
61
- detectCli: detectCliAvailability,
62
- getPreference: getProjectCliPreference,
63
- setPreference: setProjectCliPreference,
64
- prompt,
65
- isTTY,
66
- };
67
- }
68
- export function parseCliFlag(args) {
69
- const rest = [];
70
- let cli;
71
- for (let i = 0; i < args.length; i++) {
72
- const arg = args[i];
73
- if (arg === '--cli') {
74
- const next = args[i + 1];
75
- if (next !== 'claude' && next !== 'codex') {
76
- return { rest, error: '--cli requires claude or codex' };
77
- }
78
- cli = next;
79
- i += 1;
80
- }
81
- else if (arg.startsWith('--cli=')) {
82
- const value = arg.slice('--cli='.length);
83
- if (value !== 'claude' && value !== 'codex') {
84
- return { rest, error: '--cli requires claude or codex' };
85
- }
86
- cli = value;
87
- }
88
- else {
89
- rest.push(arg);
90
- }
91
- }
92
- return { cli, rest };
93
- }
94
- //# sourceMappingURL=cli-platform.js.map
1
+ import a from"which";import{getProjectCliPreference as u,setProjectCliPreference as s}from"./cubes.js";function d(){return{claude:l("claude"),codex:l("codex")}}function l(r){try{return a.sync(r)}catch{return null}}function f(r){const e=[];return r.claude&&e.push("claude"),r.codex&&e.push("codex"),e}async function w(r,e){const c=e.detectCli(),o=f(c);if(o.length===0)throw new Error("Neither Claude Code nor Codex is installed. Install one of them, then run borg again.");if(r){if(!o.includes(r))throw new Error(`${r} CLI is not installed.`);return await e.setPreference(r),r}const n=await e.getPreference();if(n&&o.includes(n))return n;if(o.length===1)return await e.setPreference(o[0]),o[0];if(!e.isTTY())throw new Error("Multiple agent CLIs detected. Pass --cli claude or --cli codex to choose.");const t=(await e.prompt(`Use which CLI for this project?
2
+ 1) claude
3
+ 2) codex
4
+ [1]: `)).trim(),i=t===""||t==="1"||t.toLowerCase()==="claude"?"claude":t==="2"||t.toLowerCase()==="codex"?"codex":null;if(!i)throw new Error(`invalid CLI choice "${t}"`);return await e.setPreference(i),i}function x(r,e){return{detectCli:d,getPreference:u,setPreference:s,prompt:r,isTTY:e}}function P(r){const e=[];let c;for(let o=0;o<r.length;o++){const n=r[o];if(n==="--cli"){const t=r[o+1];if(t!=="claude"&&t!=="codex")return{rest:e,error:"--cli requires claude or codex"};c=t,o+=1}else if(n.startsWith("--cli=")){const t=n.slice(6);if(t!=="claude"&&t!=="codex")return{rest:e,error:"--cli requires claude or codex"};c=t}else e.push(n)}return{cli:c,rest:e}}export{x as defaultCliChoiceDeps,d as detectCliAvailability,f as installedCliNames,P as parseCliFlag,w as resolveCliChoice};