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.
- package/dist/assimilate-cmd.js +39 -511
- package/dist/assimilate-deps.js +3 -177
- package/dist/assimilate-welcome.js +2 -24
- package/dist/auth-env.js +1 -107
- package/dist/auth.js +23 -612
- package/dist/claude.js +11 -281
- package/dist/cli-help.js +29 -50
- package/dist/cli-platform.js +4 -94
- package/dist/codex-app-server.js +4 -228
- package/dist/codex-app-wake.js +2 -122
- package/dist/codex-launch.js +1 -81
- package/dist/codex-remote.js +1 -250
- package/dist/config-utils.js +3 -385
- package/dist/config.js +1 -190
- package/dist/console-prefix.js +1 -86
- package/dist/cube-name.js +1 -65
- package/dist/cubes.js +4 -269
- package/dist/debug.js +1 -71
- package/dist/device-auth.js +1 -167
- package/dist/direct-log.js +1 -11
- package/dist/health-beat.js +1 -168
- package/dist/inbox-monitor.js +1 -129
- package/dist/index.js +26 -1378
- package/dist/lifecycle-log-guard.js +2 -93
- package/dist/list-roles-render.js +6 -39
- package/dist/log-audit.js +3 -186
- package/dist/log-stream.js +9 -848
- package/dist/name-validator.js +1 -22
- package/dist/parse-assimilate-args.js +1 -82
- package/dist/postinstall.js +8 -22
- package/dist/regen-format.js +11 -337
- package/dist/regen.js +5 -83
- package/dist/remote-client.js +1 -695
- package/dist/role-resolver.js +1 -36
- package/dist/role-section.js +8 -208
- package/dist/roster-render.js +3 -96
- package/dist/setup.js +36 -251
- package/dist/shell-escape.js +1 -22
- package/dist/spawn.js +10 -29
- package/dist/stale-version-check.js +1 -102
- package/dist/stream-owner.js +2 -202
- package/dist/stream-status.js +3 -211
- package/dist/subscription-retry.js +1 -23
- package/dist/sync-roles-render.js +3 -118
- package/dist/sync.js +22 -286
- package/dist/templates.js +120 -626
- package/dist/terminal-title.js +1 -68
- package/dist/token-crypto.js +1 -91
- package/dist/token-store.js +1 -222
- package/dist/types.js +0 -5
- package/dist/version.js +2 -78
- package/dist/worktree-lifecycle.js +2 -173
- package/package.json +11 -2
- package/dist/assimilate-cmd.d.ts.map +0 -1
- package/dist/assimilate-cmd.js.map +0 -1
- package/dist/assimilate-deps.d.ts.map +0 -1
- package/dist/assimilate-deps.js.map +0 -1
- package/dist/assimilate-welcome.d.ts.map +0 -1
- package/dist/assimilate-welcome.js.map +0 -1
- package/dist/auth-env.d.ts.map +0 -1
- package/dist/auth-env.js.map +0 -1
- package/dist/auth.d.ts.map +0 -1
- package/dist/auth.js.map +0 -1
- package/dist/claude.d.ts.map +0 -1
- package/dist/claude.js.map +0 -1
- package/dist/cli-help.d.ts.map +0 -1
- package/dist/cli-help.js.map +0 -1
- package/dist/cli-platform.d.ts.map +0 -1
- package/dist/cli-platform.js.map +0 -1
- package/dist/codex-app-server.d.ts.map +0 -1
- package/dist/codex-app-server.js.map +0 -1
- package/dist/codex-app-wake.d.ts.map +0 -1
- package/dist/codex-app-wake.js.map +0 -1
- package/dist/codex-launch.d.ts.map +0 -1
- package/dist/codex-launch.js.map +0 -1
- package/dist/codex-remote.d.ts.map +0 -1
- package/dist/codex-remote.js.map +0 -1
- package/dist/config-utils.d.ts.map +0 -1
- package/dist/config-utils.js.map +0 -1
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/console-prefix.d.ts.map +0 -1
- package/dist/console-prefix.js.map +0 -1
- package/dist/cube-name.d.ts.map +0 -1
- package/dist/cube-name.js.map +0 -1
- package/dist/cubes.d.ts.map +0 -1
- package/dist/cubes.js.map +0 -1
- package/dist/debug.d.ts.map +0 -1
- package/dist/debug.js.map +0 -1
- package/dist/device-auth.d.ts.map +0 -1
- package/dist/device-auth.js.map +0 -1
- package/dist/direct-log.d.ts.map +0 -1
- package/dist/direct-log.js.map +0 -1
- package/dist/health-beat.d.ts.map +0 -1
- package/dist/health-beat.js.map +0 -1
- package/dist/inbox-monitor.d.ts.map +0 -1
- package/dist/inbox-monitor.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/lifecycle-log-guard.d.ts.map +0 -1
- package/dist/lifecycle-log-guard.js.map +0 -1
- package/dist/list-roles-render.d.ts.map +0 -1
- package/dist/list-roles-render.js.map +0 -1
- package/dist/log-audit.d.ts.map +0 -1
- package/dist/log-audit.js.map +0 -1
- package/dist/log-stream.d.ts.map +0 -1
- package/dist/log-stream.js.map +0 -1
- package/dist/name-validator.d.ts.map +0 -1
- package/dist/name-validator.js.map +0 -1
- package/dist/parse-assimilate-args.d.ts.map +0 -1
- package/dist/parse-assimilate-args.js.map +0 -1
- package/dist/postinstall.d.ts.map +0 -1
- package/dist/postinstall.js.map +0 -1
- package/dist/regen-format.d.ts.map +0 -1
- package/dist/regen-format.js.map +0 -1
- package/dist/regen.d.ts.map +0 -1
- package/dist/regen.js.map +0 -1
- package/dist/remote-client.d.ts.map +0 -1
- package/dist/remote-client.js.map +0 -1
- package/dist/role-resolver.d.ts.map +0 -1
- package/dist/role-resolver.js.map +0 -1
- package/dist/role-section.d.ts.map +0 -1
- package/dist/role-section.js.map +0 -1
- package/dist/roster-render.d.ts.map +0 -1
- package/dist/roster-render.js.map +0 -1
- package/dist/setup.d.ts.map +0 -1
- package/dist/setup.js.map +0 -1
- package/dist/shell-escape.d.ts.map +0 -1
- package/dist/shell-escape.js.map +0 -1
- package/dist/spawn.d.ts.map +0 -1
- package/dist/spawn.js.map +0 -1
- package/dist/stale-version-check.d.ts.map +0 -1
- package/dist/stale-version-check.js.map +0 -1
- package/dist/stream-owner.d.ts.map +0 -1
- package/dist/stream-owner.js.map +0 -1
- package/dist/stream-status.d.ts.map +0 -1
- package/dist/stream-status.js.map +0 -1
- package/dist/subscription-retry.d.ts.map +0 -1
- package/dist/subscription-retry.js.map +0 -1
- package/dist/sync-roles-render.d.ts.map +0 -1
- package/dist/sync-roles-render.js.map +0 -1
- package/dist/sync.d.ts.map +0 -1
- package/dist/sync.js.map +0 -1
- package/dist/templates.d.ts.map +0 -1
- package/dist/templates.js.map +0 -1
- package/dist/terminal-title.d.ts.map +0 -1
- package/dist/terminal-title.js.map +0 -1
- package/dist/token-crypto.d.ts.map +0 -1
- package/dist/token-crypto.js.map +0 -1
- package/dist/token-store.d.ts.map +0 -1
- package/dist/token-store.js.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/version.d.ts.map +0 -1
- package/dist/version.js.map +0 -1
- package/dist/worktree-lifecycle.d.ts.map +0 -1
- 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
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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};
|
package/dist/cli-platform.js
CHANGED
|
@@ -1,94 +1,4 @@
|
|
|
1
|
-
import which from
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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};
|