borgmcp 1.0.6 → 1.0.8
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/README.md +5 -3
- 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.d.ts +4 -7
- 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 +41 -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.d.ts +0 -5
- package/dist/types.js +0 -5
- package/dist/version.js +2 -78
- package/dist/worktree-lifecycle.js +2 -173
- package/package.json +12 -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/setup.js
CHANGED
|
@@ -1,252 +1,42 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
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
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
// Optional: Borg can also run with Codex.
|
|
44
|
-
}
|
|
45
|
-
try {
|
|
46
|
-
codexCliPath = which.sync('codex');
|
|
47
|
-
}
|
|
48
|
-
catch (error) {
|
|
49
|
-
// Optional: Borg can also run with Claude Code.
|
|
50
|
-
}
|
|
51
|
-
if (claudeCliPath)
|
|
52
|
-
console.log(chalk.gray(`Found Claude CLI: ${claudeCliPath}`));
|
|
53
|
-
if (codexCliPath)
|
|
54
|
-
console.log(chalk.gray(`Found Codex CLI: ${codexCliPath}`));
|
|
55
|
-
if (claudeCliPath || codexCliPath)
|
|
56
|
-
console.log('');
|
|
57
|
-
if (!claudeCliPath && !codexCliPath) {
|
|
58
|
-
console.error(chalk.red('◼ No supported agent CLI found\n'));
|
|
59
|
-
console.error(chalk.yellow('Please install Claude Code or Codex first:'));
|
|
60
|
-
console.error(chalk.gray(' Claude Code: https://claude.ai/download'));
|
|
61
|
-
console.error(chalk.gray(' Codex: https://developers.openai.com/codex\n'));
|
|
62
|
-
process.exit(1);
|
|
63
|
-
}
|
|
64
|
-
// Step 1: Configure every detected agent CLI. Idempotent; re-running
|
|
65
|
-
// setup is the normal path for OAuth refresh and CLI self-healing.
|
|
66
|
-
console.log(chalk.blue('◼ Agent CLI Integration'));
|
|
67
|
-
if (claudeCliPath) {
|
|
68
|
-
try {
|
|
69
|
-
if (!isMcpServerConfigured())
|
|
70
|
-
addMcpServer();
|
|
71
|
-
addSessionStartHook();
|
|
72
|
-
addUserPromptSubmitHook();
|
|
73
|
-
console.log(chalk.green('◼ borg configured for Claude Code'));
|
|
74
|
-
}
|
|
75
|
-
catch (error) {
|
|
76
|
-
console.error(chalk.red(`\n◼ Failed to configure Claude Code: ${error.message}\n`));
|
|
77
|
-
process.exit(1);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
if (codexCliPath) {
|
|
81
|
-
try {
|
|
82
|
-
if (!isCodexMcpServerConfigured())
|
|
83
|
-
addCodexMcpServer();
|
|
84
|
-
addCodexSessionStartHook();
|
|
85
|
-
addCodexUserPromptSubmitHook();
|
|
86
|
-
console.log(chalk.green('◼ borg configured for Codex'));
|
|
87
|
-
}
|
|
88
|
-
catch (error) {
|
|
89
|
-
console.error(chalk.red(`\n◼ Failed to configure Codex: ${error.message}\n`));
|
|
90
|
-
process.exit(1);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
console.log('');
|
|
94
|
-
// Step 2: Authentication
|
|
95
|
-
console.log(chalk.blue('◼ Google Authentication'));
|
|
96
|
-
const authed = await isAuthenticated();
|
|
97
|
-
if (!authed) {
|
|
98
|
-
try {
|
|
99
|
-
await authenticateWithGoogle(noBrowser ? { noBrowser: true } : undefined);
|
|
100
|
-
}
|
|
101
|
-
catch (error) {
|
|
102
|
-
console.error(chalk.red(`\n◼ Authentication failed: ${error.message}\n`));
|
|
103
|
-
// gh#557 NOTE-2: device-flow errors (access_denied / expired_token) and
|
|
104
|
-
// any other auth failure exit here — give the remote user a recovery
|
|
105
|
-
// path instead of a bare exit.
|
|
106
|
-
console.error(chalk.yellow('Re-run `borg setup` to try again.\n'));
|
|
107
|
-
process.exit(1);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
else {
|
|
111
|
-
console.log(chalk.green('◼ Already authenticated\n'));
|
|
112
|
-
}
|
|
113
|
-
// Step 3: Subscription
|
|
114
|
-
console.log(chalk.blue('◼ Subscription Check'));
|
|
115
|
-
let status;
|
|
116
|
-
try {
|
|
117
|
-
status = await checkSubscriptionStatus();
|
|
118
|
-
}
|
|
119
|
-
catch (error) {
|
|
120
|
-
console.error(chalk.red(`\n◼ Failed to check subscription: ${error.message}\n`));
|
|
121
|
-
process.exit(1);
|
|
122
|
-
}
|
|
123
|
-
// gh#521: a user who just subscribed via web hits propagation lag — retry a
|
|
124
|
-
// few times (non-alarmingly) before declaring no subscription, instead of
|
|
125
|
-
// flashing a scary "not found" immediately after payment.
|
|
126
|
-
status = await retrySubscriptionCheck(status, {
|
|
127
|
-
check: checkSubscriptionStatus,
|
|
128
|
-
sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
|
|
129
|
-
onRetry: (attempt, total) => console.log(chalk.gray(`◼ Checking subscription... (attempt ${attempt}/${total})`)),
|
|
130
|
-
});
|
|
131
|
-
if (!status.hasAccess) {
|
|
132
|
-
// gh#687: a fresh user has no subscription BY DESIGN — the Free tier is the
|
|
133
|
-
// permanent entry point (no trial). Lead with that as a WIN, not a
|
|
134
|
-
// "not found" failure, and present upgrading as an OFFER (Continue on Free
|
|
135
|
-
// is the default). The gh#521 just-subscribed propagation-lag retry already
|
|
136
|
-
// ran above; the "I already subscribed — re-check" choice covers the tail.
|
|
137
|
-
console.log(chalk.green("◼ You're on the Free tier — permanent, no card needed: 1 cube + 3 drones + 100 req/hr."));
|
|
138
|
-
console.log(chalk.gray('◼ Start using borgmcp right now. Upgrade any time for unlimited cubes + drones ($1/cube/month).\n'));
|
|
139
|
-
const { subscribeMethod } = await prompts({
|
|
140
|
-
type: 'select',
|
|
141
|
-
name: 'subscribeMethod',
|
|
142
|
-
message: "You're ready on the Free tier. Want to do more?",
|
|
143
|
-
choices: [
|
|
144
|
-
{
|
|
145
|
-
title: '◼ Continue on the Free tier (recommended)',
|
|
146
|
-
value: 'skip',
|
|
147
|
-
description: 'Start now — 1 cube, 3 drones, 100 req/hr. No payment required.'
|
|
148
|
-
},
|
|
149
|
-
{
|
|
150
|
-
title: '◼ Upgrade to Cube tier — $1/cube/month',
|
|
151
|
-
value: 'web',
|
|
152
|
-
description: 'Unlimited cubes + drones + 1000 req/hr. Opens the subscribe page in your browser.'
|
|
153
|
-
},
|
|
154
|
-
{
|
|
155
|
-
title: '◼ Quick Stripe checkout',
|
|
156
|
-
value: 'stripe',
|
|
157
|
-
description: 'Fast upgrade checkout in the browser'
|
|
158
|
-
},
|
|
159
|
-
{
|
|
160
|
-
title: '◼ I already subscribed — re-check',
|
|
161
|
-
value: 'recheck',
|
|
162
|
-
description: 'Re-check now — a just-completed subscription can take a moment to activate'
|
|
163
|
-
}
|
|
164
|
-
]
|
|
165
|
-
});
|
|
166
|
-
switch (subscribeMethod) {
|
|
167
|
-
case 'web':
|
|
168
|
-
console.log(chalk.blue('\n◼ Opening: https://borgmcp.ai/subscribe'));
|
|
169
|
-
try {
|
|
170
|
-
await open('https://borgmcp.ai/subscribe');
|
|
171
|
-
console.log(chalk.gray('◼ Waiting for subscription (checking every 5s for 2 min)...\n'));
|
|
172
|
-
await pollForSubscription();
|
|
173
|
-
}
|
|
174
|
-
catch (error) {
|
|
175
|
-
console.error(chalk.yellow(`\n◼ ${error.message}`));
|
|
176
|
-
}
|
|
177
|
-
break;
|
|
178
|
-
case 'stripe':
|
|
179
|
-
try {
|
|
180
|
-
const checkoutUrl = await createSubscription();
|
|
181
|
-
console.log(chalk.blue(`\n◼ Opening Stripe: ${checkoutUrl}`));
|
|
182
|
-
await open(checkoutUrl);
|
|
183
|
-
console.log(chalk.gray('◼ Waiting for subscription...\n'));
|
|
184
|
-
await pollForSubscription();
|
|
185
|
-
}
|
|
186
|
-
catch (error) {
|
|
187
|
-
console.error(chalk.red(`\n◼ Failed to create checkout: ${error.message}\n`));
|
|
188
|
-
}
|
|
189
|
-
break;
|
|
190
|
-
case 'recheck':
|
|
191
|
-
try {
|
|
192
|
-
const recheckStatus = await checkSubscriptionStatus();
|
|
193
|
-
if (recheckStatus.hasAccess) {
|
|
194
|
-
console.log(chalk.green('\n◼ Subscription found!\n'));
|
|
195
|
-
}
|
|
196
|
-
else {
|
|
197
|
-
console.log(chalk.yellow('\n◼ No subscription found\n'));
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
catch (error) {
|
|
201
|
-
console.error(chalk.red(`\n◼ Failed to recheck: ${error.message}\n`));
|
|
202
|
-
}
|
|
203
|
-
break;
|
|
204
|
-
case 'skip':
|
|
205
|
-
console.log(chalk.green("\n◼ You're all set on the Free tier: 1 cube, 3 drones, 100 req/hr.\n"));
|
|
206
|
-
break;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
else {
|
|
210
|
-
console.log(chalk.green('◼ Active subscription found'));
|
|
211
|
-
if (status.expiresAt) {
|
|
212
|
-
const expiresAt = new Date(status.expiresAt);
|
|
213
|
-
console.log(chalk.gray(` Expires: ${expiresAt.toLocaleDateString()}\n`));
|
|
214
|
-
}
|
|
215
|
-
else {
|
|
216
|
-
console.log('');
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
// Success message
|
|
220
|
-
console.log(chalk.green.bold('Setup complete!\n'));
|
|
221
|
-
console.log(chalk.yellow('🔄 Restart Claude Code/Codex (or open a new session) for the changes to take effect.\n'));
|
|
222
|
-
console.log(chalk.gray('◼ Next steps:'));
|
|
223
|
-
console.log(chalk.gray('1. Run "borg" to start Claude Code or Codex with your cube'));
|
|
224
|
-
console.log(chalk.gray('2. Manage cubes and subscription at https://borgmcp.ai/dashboard\n'));
|
|
225
|
-
}
|
|
226
|
-
/**
|
|
227
|
-
* Poll for subscription activation
|
|
228
|
-
* Checks every 5 seconds for 2 minutes (24 attempts)
|
|
229
|
-
*/
|
|
230
|
-
async function pollForSubscription() {
|
|
231
|
-
const maxAttempts = 24;
|
|
232
|
-
for (let i = 0; i < maxAttempts; i++) {
|
|
233
|
-
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
234
|
-
try {
|
|
235
|
-
const status = await checkSubscriptionStatus();
|
|
236
|
-
if (status.hasAccess) {
|
|
237
|
-
console.log(chalk.green('◼ Subscription activated!\n'));
|
|
238
|
-
return;
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
catch (error) {
|
|
242
|
-
// Continue polling even on errors
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
throw new Error('Timeout - Run setup again after subscribing');
|
|
246
|
-
}
|
|
247
|
-
// Run wizard
|
|
248
|
-
main().catch((error) => {
|
|
249
|
-
console.error(chalk.red(`\n◼ Setup failed: ${error.message}\n`));
|
|
250
|
-
process.exit(1);
|
|
251
|
-
});
|
|
252
|
-
//# sourceMappingURL=setup.js.map
|
|
2
|
+
import h from"prompts";import e from"chalk";import g from"open";import u from"which";import{authenticateWithGoogle as b}from"./auth.js";import{checkSubscriptionStatus as c,createSubscription as m}from"./remote-client.js";import{retrySubscriptionCheck as d}from"./subscription-retry.js";import{addMcpServer as f,addSessionStartHook as y,addUserPromptSubmitHook as w,addCodexMcpServer as C,addCodexSessionStartHook as k,addCodexUserPromptSubmitHook as S,isMcpServerConfigured as x,isCodexMcpServerConfigured as F}from"./config-utils.js";import{isAuthenticated as v}from"./config.js";import{handleVersionFlag as $}from"./version.js";import{initDebugFromArgv as A}from"./debug.js";async function P(){A(process.argv),$(),console.log(e.blue.bold(`
|
|
3
|
+
\u25FC Borg MCP Setup Wizard \u25FC`));const i=process.argv.includes("--no-browser")||process.argv.includes("--device");let n=null,t=null;try{n=u.sync("claude")}catch{}try{t=u.sync("codex")}catch{}if(n&&console.log(e.gray(`Found Claude CLI: ${n}`)),t&&console.log(e.gray(`Found Codex CLI: ${t}`)),(n||t)&&console.log(""),!n&&!t&&(console.error(e.red(`\u25FC No supported agent CLI found
|
|
4
|
+
`)),console.error(e.yellow("Please install Claude Code or Codex first:")),console.error(e.gray(" Claude Code: https://claude.ai/download")),console.error(e.gray(` Codex: https://developers.openai.com/codex
|
|
5
|
+
`)),process.exit(1)),console.log(e.blue("\u25FC Agent CLI Integration")),n)try{x()||f(),y(),w(),console.log(e.green("\u25FC borg configured for Claude Code"))}catch(o){console.error(e.red(`
|
|
6
|
+
\u25FC Failed to configure Claude Code: ${o.message}
|
|
7
|
+
`)),process.exit(1)}if(t)try{F()||C(),k(),S(),console.log(e.green("\u25FC borg configured for Codex"))}catch(o){console.error(e.red(`
|
|
8
|
+
\u25FC Failed to configure Codex: ${o.message}
|
|
9
|
+
`)),process.exit(1)}if(console.log(""),console.log(e.blue("\u25FC Google Authentication")),await v())console.log(e.green(`\u25FC Already authenticated
|
|
10
|
+
`));else try{await b(i?{noBrowser:!0}:void 0)}catch(o){console.error(e.red(`
|
|
11
|
+
\u25FC Authentication failed: ${o.message}
|
|
12
|
+
`)),console.error(e.yellow("Re-run `borg setup` to try again.\n")),process.exit(1)}console.log(e.blue("\u25FC Subscription Check"));let s;try{s=await c()}catch(o){console.error(e.yellow(`
|
|
13
|
+
\u25FC Subscription check failed: ${o.message}`)),console.error(e.gray(`\u25FC Retrying before falling back to the Free tier...
|
|
14
|
+
`)),s={hasAccess:!1}}if(s=await d(s,{check:c,sleep:o=>new Promise(r=>setTimeout(r,o)),onRetry:(o,r)=>console.log(e.gray(`\u25FC Checking subscription... (attempt ${o}/${r})`))}),s.hasAccess)if(console.log(e.green("\u25FC Active subscription found")),s.expiresAt){const o=new Date(s.expiresAt);console.log(e.gray(` Expires: ${o.toLocaleDateString()}
|
|
15
|
+
`))}else console.log("");else{console.log(e.green("\u25FC You're on the Free tier \u2014 permanent, no card needed: 1 cube + 3 agent sessions + 100 req/hr.")),console.log(e.gray(`\u25FC Start using borgmcp right now. Upgrade any time: $1/month per cube, each cube adds 8 pooled agent sessions + 1000 req/hr.
|
|
16
|
+
`));const{subscribeMethod:o}=await h({type:"select",name:"subscribeMethod",message:"You're ready on the Free tier. Want to do more?",choices:[{title:"\u25FC Continue on the Free tier (recommended)",value:"skip",description:"Start now \u2014 1 cube, 3 agent sessions, 100 req/hr. No payment required."},{title:"\u25FC Upgrade to Cube tier \u2014 $1/month per cube",value:"web",description:"Each cube adds 8 pooled agent sessions + 1000 req/hr. Opens the subscribe page in your browser."},{title:"\u25FC Quick Stripe checkout",value:"stripe",description:"Fast upgrade checkout in the browser"},{title:"\u25FC I already subscribed \u2014 re-check",value:"recheck",description:"Re-check now \u2014 a just-completed subscription can take a moment to activate"}]});switch(o===void 0&&console.log(e.yellow(`
|
|
17
|
+
\u25FC No subscription option selected \u2014 continuing on the Free tier.
|
|
18
|
+
`)),o){case"web":console.log(e.blue(`
|
|
19
|
+
\u25FC Opening: https://borgmcp.ai/subscribe`));try{await g("https://borgmcp.ai/subscribe"),console.log(e.gray(`\u25FC Waiting for subscription (checking every 5s for 2 min)...
|
|
20
|
+
`)),await p()}catch(r){console.error(e.yellow(`
|
|
21
|
+
\u25FC ${r.message}`)),console.log(e.green(`\u25FC Continuing on the Free tier. Upgrade any time from https://borgmcp.ai/subscribe.
|
|
22
|
+
`))}break;case"stripe":try{const r=await m();console.log(e.blue(`
|
|
23
|
+
\u25FC Opening Stripe: ${r}`)),await g(r),console.log(e.gray(`\u25FC Waiting for subscription...
|
|
24
|
+
`)),await p()}catch(r){console.error(e.red(`
|
|
25
|
+
\u25FC Failed to create checkout: ${r.message}
|
|
26
|
+
`)),console.log(e.green(`\u25FC Continuing on the Free tier. Upgrade any time from https://borgmcp.ai/subscribe.
|
|
27
|
+
`))}break;case"recheck":try{let r;try{r=await c()}catch{r={hasAccess:!1}}r=await d(r,{check:c,sleep:a=>new Promise(l=>setTimeout(l,a)),onRetry:(a,l)=>console.log(e.gray(`\u25FC Re-checking subscription... (attempt ${a}/${l})`))}),r.hasAccess?console.log(e.green(`
|
|
28
|
+
\u25FC Subscription found!
|
|
29
|
+
`)):console.log(e.yellow(`
|
|
30
|
+
\u25FC No subscription found \u2014 continuing on the Free tier.
|
|
31
|
+
`))}catch(r){console.error(e.red(`
|
|
32
|
+
\u25FC Failed to recheck: ${r.message}
|
|
33
|
+
`)),console.log(e.green(`\u25FC Continuing on the Free tier.
|
|
34
|
+
`))}break;case"skip":console.log(e.green(`
|
|
35
|
+
\u25FC You're all set on the Free tier: 1 cube, 3 agent sessions, 100 req/hr.
|
|
36
|
+
`));break}}console.log(e.green.bold(`Setup complete!
|
|
37
|
+
`)),console.log(e.yellow(`\u{1F504} Restart Claude Code/Codex (or open a new session) for the changes to take effect.
|
|
38
|
+
`)),console.log(e.gray("\u25FC Next steps:")),console.log(e.gray('1. Run "borg" to start Claude Code or Codex with your cube')),console.log(e.gray(`2. Manage cubes and subscription at https://borgmcp.ai/dashboard
|
|
39
|
+
`))}async function p(){for(let n=0;n<24;n++){await new Promise(t=>setTimeout(t,5e3));try{if((await c()).hasAccess){console.log(e.green(`\u25FC Subscription activated!
|
|
40
|
+
`));return}}catch{}}throw new Error("Timeout - Run setup again after subscribing")}P().catch(i=>{console.error(e.red(`
|
|
41
|
+
\u25FC Setup failed: ${i.message}
|
|
42
|
+
`)),process.exit(1)});
|
package/dist/shell-escape.js
CHANGED
|
@@ -1,22 +1 @@
|
|
|
1
|
-
|
|
2
|
-
//
|
|
3
|
-
// Sprint 18 (gh-tracked via dispatch 10:41:47Z): when the CLI emits a
|
|
4
|
-
// `cd <path>` line for the user to copy-paste into their shell, the path is
|
|
5
|
-
// a filesystem-controlled string with no character constraints (unlike
|
|
6
|
-
// DB-CHECK-constrained role/cube names). Paths can legally contain spaces,
|
|
7
|
-
// `$VAR`, backticks, `$(cmd)`, embedded single-quotes, and other shell
|
|
8
|
-
// metacharacters that would execute on paste under naive emission.
|
|
9
|
-
//
|
|
10
|
-
// drone-11 SR-LANE (cube entry 2026-05-19T10:44:35Z) escalation: double-
|
|
11
|
-
// quoting handles spaces but `$VAR` / backtick / `$(cmd)` still expand
|
|
12
|
-
// inside double-quotes. Single-quotes with internal-quote escape (`'\''`
|
|
13
|
-
// = close-quote / escaped-quote / re-open-quote) defang every shell
|
|
14
|
-
// metachar including embedded `'`. POSIX-defined, copy-paste-runnable
|
|
15
|
-
// across bash / zsh / dash / sh.
|
|
16
|
-
//
|
|
17
|
-
// Behavior: returns the input wrapped in single-quotes with any internal
|
|
18
|
-
// `'` rewritten as `'\''`. Empty string returns `''`.
|
|
19
|
-
export function shellEscape(s) {
|
|
20
|
-
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
21
|
-
}
|
|
22
|
-
//# sourceMappingURL=shell-escape.js.map
|
|
1
|
+
function r(e){return`'${e.replace(/'/g,"'\\''")}'`}export{r as shellEscape};
|
package/dist/spawn.js
CHANGED
|
@@ -1,29 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
* `validateName` continues to be re-exported from here for callers
|
|
12
|
-
* that still depend on the symbol (it lives in `name-validator.ts`
|
|
13
|
-
* now — single source of truth).
|
|
14
|
-
*/
|
|
15
|
-
export { validateName } from './name-validator.js';
|
|
16
|
-
export async function runSpawn() {
|
|
17
|
-
const msg = 'borg spawn is removed. Use:\n' +
|
|
18
|
-
' borg assimilate [role] --worktree <name>\n' +
|
|
19
|
-
'\n' +
|
|
20
|
-
'Example: if you previously ran `borg spawn drone-2`, the equivalent is\n' +
|
|
21
|
-
' borg assimilate --worktree drone-2\n' +
|
|
22
|
-
'(role is optional; defaults per first-drone rules)\n' +
|
|
23
|
-
'\n' +
|
|
24
|
-
'If you want a specific role:\n' +
|
|
25
|
-
' borg assimilate builder --worktree drone-2\n';
|
|
26
|
-
process.stderr.write(msg);
|
|
27
|
-
return 2;
|
|
28
|
-
}
|
|
29
|
-
//# sourceMappingURL=spawn.js.map
|
|
1
|
+
import{validateName as s}from"./name-validator.js";async function r(){return process.stderr.write(`borg spawn is removed. Use:
|
|
2
|
+
borg assimilate [role] --worktree <name>
|
|
3
|
+
|
|
4
|
+
Example: if you previously ran \`borg spawn drone-2\`, the equivalent is
|
|
5
|
+
borg assimilate --worktree drone-2
|
|
6
|
+
(role is optional; defaults per first-drone rules)
|
|
7
|
+
|
|
8
|
+
If you want a specific role:
|
|
9
|
+
borg assimilate builder --worktree drone-2
|
|
10
|
+
`),2}export{r as runSpawn,s as validateName};
|
|
@@ -1,102 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* Sprint 7 (b) — stale-binary defensive hardening (gh#148 close-out).
|
|
3
|
-
*
|
|
4
|
-
* drone-3's v0.8.0 case (cube log 2026-05-18T10:35Z) ran for months
|
|
5
|
-
* without warning that v0.8.10 had shipped the gh#71 carve-out for
|
|
6
|
-
* own-drone heartbeat-pings. The silent-stale-binary failure mode
|
|
7
|
-
* costs cube collective time to diagnose because the gap between
|
|
8
|
-
* "installed version" and "latest published" is invisible to the
|
|
9
|
-
* operator.
|
|
10
|
-
*
|
|
11
|
-
* This module surfaces that gap at borg launch time via a stderr
|
|
12
|
-
* warning. Network check against npmjs.org registry is async +
|
|
13
|
-
* timeout-gated so a slow registry doesn't block the operator. Fails
|
|
14
|
-
* silently on any error (network failure, registry change,
|
|
15
|
-
* prerelease version, etc.) — defense-in-depth, never a blocker.
|
|
16
|
-
*/
|
|
17
|
-
const NPM_REGISTRY_LATEST_URL = 'https://registry.npmjs.org/borgmcp/latest';
|
|
18
|
-
const FETCH_TIMEOUT_MS = 2000;
|
|
19
|
-
const MINOR_VERSIONS_BEHIND_THRESHOLD = 1;
|
|
20
|
-
/**
|
|
21
|
-
* Pure compare: given an installed version string and a latest version
|
|
22
|
-
* string, decide whether to warn. Both strings are expected in semver
|
|
23
|
-
* `MAJOR.MINOR.PATCH` form (no prerelease, no build metadata).
|
|
24
|
-
*
|
|
25
|
-
* Returns `{stale: true, message}` when installed is at least
|
|
26
|
-
* MINOR_VERSIONS_BEHIND_THRESHOLD minor versions behind latest on the
|
|
27
|
-
* same major. Defaults conservatively — unparseable input, prerelease
|
|
28
|
-
* tags, or anything weird returns `stale: false` so we never
|
|
29
|
-
* false-positive on edge cases.
|
|
30
|
-
*/
|
|
31
|
-
export function compareVersionsForStaleness(installed, latest) {
|
|
32
|
-
const installedParts = parseSemver(installed);
|
|
33
|
-
const latestParts = parseSemver(latest);
|
|
34
|
-
if (!installedParts || !latestParts) {
|
|
35
|
-
return { stale: false, message: null };
|
|
36
|
-
}
|
|
37
|
-
// Don't warn across major-version transitions — those are
|
|
38
|
-
// explicit migrations the operator is aware of (or should be); the
|
|
39
|
-
// warning shape isn't the right surface for them.
|
|
40
|
-
if (installedParts.major !== latestParts.major) {
|
|
41
|
-
return { stale: false, message: null };
|
|
42
|
-
}
|
|
43
|
-
const minorDelta = latestParts.minor - installedParts.minor;
|
|
44
|
-
if (minorDelta < MINOR_VERSIONS_BEHIND_THRESHOLD) {
|
|
45
|
-
return { stale: false, message: null };
|
|
46
|
-
}
|
|
47
|
-
// Lead-with-warning shape per drone-7 UX-FOLLOWUP 2026-05-18T13:49:54Z:
|
|
48
|
-
// both versions explicit (no "N versions behind" count ambiguity that
|
|
49
|
-
// flattens severity perception), single actionable command, no
|
|
50
|
-
// backticks (terminal renders them as literal characters). Fits the
|
|
51
|
-
// Coordinator-discipline 80-char preview rule. drone-1 ratified the
|
|
52
|
-
// (X) network-check approach + this copy shape at 13:49:59Z.
|
|
53
|
-
// minorDelta is informational; intentionally not surfaced.
|
|
54
|
-
void minorDelta;
|
|
55
|
-
const message = `⚠ borgmcp ${installed} is behind latest ${latest} — npm install -g borgmcp@latest`;
|
|
56
|
-
return { stale: true, message };
|
|
57
|
-
}
|
|
58
|
-
function parseSemver(s) {
|
|
59
|
-
// Strict MAJOR.MINOR.PATCH; rejects prerelease tags, build metadata,
|
|
60
|
-
// empty / 'unknown' / malformed strings. Conservative on purpose:
|
|
61
|
-
// ambiguous version strings should not trigger a warning.
|
|
62
|
-
if (typeof s !== 'string' || s.length === 0)
|
|
63
|
-
return null;
|
|
64
|
-
const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(s);
|
|
65
|
-
if (!match)
|
|
66
|
-
return null;
|
|
67
|
-
return {
|
|
68
|
-
major: parseInt(match[1], 10),
|
|
69
|
-
minor: parseInt(match[2], 10),
|
|
70
|
-
patch: parseInt(match[3], 10),
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Fetch the latest published borgmcp version from the npm registry.
|
|
75
|
-
* Returns the version string on success, `null` on any failure
|
|
76
|
-
* (timeout, network error, registry change, malformed response).
|
|
77
|
-
* Never throws — caller treats null as "skip the warning."
|
|
78
|
-
*/
|
|
79
|
-
export async function fetchLatestBorgmcpVersion() {
|
|
80
|
-
const controller = new AbortController();
|
|
81
|
-
const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
82
|
-
try {
|
|
83
|
-
const response = await fetch(NPM_REGISTRY_LATEST_URL, {
|
|
84
|
-
signal: controller.signal,
|
|
85
|
-
headers: { Accept: 'application/json' },
|
|
86
|
-
});
|
|
87
|
-
if (!response.ok)
|
|
88
|
-
return null;
|
|
89
|
-
const body = (await response.json());
|
|
90
|
-
if (typeof body.version !== 'string' || body.version.length === 0)
|
|
91
|
-
return null;
|
|
92
|
-
return body.version;
|
|
93
|
-
}
|
|
94
|
-
catch {
|
|
95
|
-
// AbortError, network error, parse error — all treated as "skip silently."
|
|
96
|
-
return null;
|
|
97
|
-
}
|
|
98
|
-
finally {
|
|
99
|
-
clearTimeout(timeout);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
//# sourceMappingURL=stale-version-check.js.map
|
|
1
|
+
const a="https://registry.npmjs.org/borgmcp/latest",i=2e3,c=1;function u(t,e){const r=o(t),n=o(e);if(!r||!n)return{stale:!1,message:null};if(r.major!==n.major)return{stale:!1,message:null};const s=n.minor-r.minor;return s<1?{stale:!1,message:null}:{stale:!0,message:`\u26A0 borgmcp ${t} is behind latest ${e} \u2014 npm install -g borgmcp@latest`}}function o(t){if(typeof t!="string"||t.length===0)return null;const e=/^(\d+)\.(\d+)\.(\d+)$/.exec(t);return e?{major:parseInt(e[1],10),minor:parseInt(e[2],10),patch:parseInt(e[3],10)}:null}async function m(){const t=new AbortController,e=setTimeout(()=>t.abort(),2e3);try{const r=await fetch(a,{signal:t.signal,headers:{Accept:"application/json"}});if(!r.ok)return null;const n=await r.json();return typeof n.version!="string"||n.version.length===0?null:n.version}catch{return null}finally{clearTimeout(e)}}export{u as compareVersionsForStaleness,m as fetchLatestBorgmcpVersion};
|