borgmcp 2.0.11 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -3
- package/dist/assimilate-cmd.d.ts +13 -4
- package/dist/assimilate-cmd.d.ts.map +1 -1
- package/dist/assimilate-cmd.js +134 -110
- package/dist/assimilate-cmd.js.map +1 -1
- package/dist/assimilate-deps.d.ts +7 -1
- package/dist/assimilate-deps.d.ts.map +1 -1
- package/dist/assimilate-deps.js +44 -18
- package/dist/assimilate-deps.js.map +1 -1
- package/dist/claude.d.ts +3 -1
- package/dist/claude.d.ts.map +1 -1
- package/dist/claude.js +26 -12
- package/dist/claude.js.map +1 -1
- package/dist/cli-help.d.ts +2 -0
- package/dist/cli-help.d.ts.map +1 -1
- package/dist/cli-help.js +22 -5
- package/dist/cli-help.js.map +1 -1
- package/dist/config.d.ts +7 -4
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +21 -4
- package/dist/config.js.map +1 -1
- package/dist/remote-client.js +1 -1
- package/dist/repository-cube-init.d.ts +57 -0
- package/dist/repository-cube-init.d.ts.map +1 -0
- package/dist/repository-cube-init.js +196 -0
- package/dist/repository-cube-init.js.map +1 -0
- package/dist/repository-identity.d.ts +29 -0
- package/dist/repository-identity.d.ts.map +1 -0
- package/dist/repository-identity.js +143 -0
- package/dist/repository-identity.js.map +1 -0
- package/dist/server-errors.d.ts +6 -0
- package/dist/server-errors.d.ts.map +1 -1
- package/dist/server-errors.js +12 -0
- package/dist/server-errors.js.map +1 -1
- package/dist/server-facade.d.ts +11 -1
- package/dist/server-facade.d.ts.map +1 -1
- package/dist/server-facade.js +33 -3
- package/dist/server-facade.js.map +1 -1
- package/dist/server-handshake.d.ts +8 -4
- package/dist/server-handshake.d.ts.map +1 -1
- package/dist/server-handshake.js +15 -6
- package/dist/server-handshake.js.map +1 -1
- package/docs/EXTRACTION_PROVENANCE.md +7 -7
- package/docs/LOCAL_SERVER.md +35 -6
- package/docs/RELEASING.md +11 -3
- package/package.json +2 -2
- package/src/assimilate-cmd.ts +166 -140
- package/src/assimilate-deps.ts +59 -17
- package/src/claude.ts +34 -14
- package/src/cli-help.ts +25 -5
- package/src/config.ts +30 -8
- package/src/remote-client.ts +1 -1
- package/src/repository-cube-init.ts +273 -0
- package/src/repository-identity.ts +199 -0
- package/src/server-errors.ts +14 -0
- package/src/server-facade.ts +47 -2
- package/src/server-handshake.ts +33 -7
package/README.md
CHANGED
|
@@ -60,8 +60,16 @@ From inside your project repo:
|
|
|
60
60
|
borg assimilate
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
-
You will be prompted for the self-hosted server to connect to. Borg
|
|
64
|
-
Cube names
|
|
63
|
+
You will be prompted for the self-hosted server to connect to. Borg shows the repository context, lets you edit the proposed cube name, offers the Software Development and Starter templates, and asks for one confirmation. It then creates or resolves that repository's cube, registers the current session as a drone, and launches the selected agent CLI with cube context.
|
|
64
|
+
Cube names allow letters, digits, spaces, dots, underscores, and hyphens, start with a letter or digit, and are at most 120 UTF-8 bytes. Use `--cube-name <name>` to supply one directly. Pass `--yes` to accept the repository name and Software Development template non-interactively.
|
|
65
|
+
|
|
66
|
+
To initialize the repository cube without creating a drone or launching an agent:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
borg server cube init
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Both commands use the same idempotent repository association. Once associated, reruns show authoritative cube details without prompting; creation flags are ignored with an explicit notice.
|
|
65
73
|
|
|
66
74
|
To connect directly to a local server (non-interactive):
|
|
67
75
|
|
|
@@ -91,7 +99,7 @@ borg assimilate
|
|
|
91
99
|
|
|
92
100
|
Setup provisions the first same-machine owner credential in the owner-only
|
|
93
101
|
`~/.borg/credentials` file. Bare assimilation uses that credential without an
|
|
94
|
-
invitation prompt, creates or joins the repository cube, attaches a drone to a
|
|
102
|
+
invitation prompt, creates or joins the Software Development repository cube, attaches a drone to a
|
|
95
103
|
role seat, and launches the selected agent. For another client or device, run
|
|
96
104
|
`borg server invite`, then use `borg assimilate --host <server> --enroll` on the
|
|
97
105
|
intended recipient and enter the invitation at its hidden prompt.
|
package/dist/assimilate-cmd.d.ts
CHANGED
|
@@ -7,6 +7,9 @@ import type { ExpectedBinding, FinalizeServerSeatOutcome, PersistedLocalSeat } f
|
|
|
7
7
|
import type { SeatBinding } from './seats.js';
|
|
8
8
|
import { type LaunchApprovalDecision } from './cli-tool-approval.js';
|
|
9
9
|
import { type WorkingRepo } from './working-repo.js';
|
|
10
|
+
import type { CreateCubeRepository, CubeTemplate } from 'borgmcp-shared/protocol';
|
|
11
|
+
import { type RepositoryCubeCreation } from './repository-cube-init.js';
|
|
12
|
+
import type { GitRepositoryContext, RepositoryAssociation } from './repository-identity.js';
|
|
10
13
|
export interface AssimilateFlags {
|
|
11
14
|
worktree?: string;
|
|
12
15
|
template?: string;
|
|
@@ -22,6 +25,7 @@ export interface AssimilateFlags {
|
|
|
22
25
|
export interface AssimilateArgs {
|
|
23
26
|
role: string | undefined;
|
|
24
27
|
flags: AssimilateFlags;
|
|
28
|
+
mode?: 'assimilate' | 'cube-init';
|
|
25
29
|
}
|
|
26
30
|
export interface CubeSummary {
|
|
27
31
|
id: string;
|
|
@@ -130,6 +134,10 @@ export interface AssimilateDeps {
|
|
|
130
134
|
scrubPending: () => Promise<unknown>;
|
|
131
135
|
}) => Promise<FinalizeServerSeatOutcome>;
|
|
132
136
|
findProjectRoot: (cwd: string) => string;
|
|
137
|
+
resolveRepositoryContext: (cwd: string) => Promise<GitRepositoryContext | null>;
|
|
138
|
+
getRepositoryIdentity: (context: GitRepositoryContext) => Promise<CreateCubeRepository>;
|
|
139
|
+
getRepositoryAssociation: (trustIdentity: string, repository: CreateCubeRepository) => Promise<RepositoryAssociation | null>;
|
|
140
|
+
saveRepositoryAssociation: (trustIdentity: string, repository: CreateCubeRepository, association: RepositoryAssociation) => Promise<void>;
|
|
133
141
|
installProjectSessionHook: (projectRoot: string) => void;
|
|
134
142
|
/** gh#27: optional test seam — when set, selectAssimilationAuthority uses
|
|
135
143
|
* this instead of prompting/failing. Not wired in production. */
|
|
@@ -150,10 +158,11 @@ export interface AssimilateDeps {
|
|
|
150
158
|
listCubes: (apiUrl: string, token: string, serverTrustIdentity?: string) => Promise<CubeSummary[]>;
|
|
151
159
|
getCube: (apiUrl: string, token: string, cubeId: string, serverTrustIdentity?: string) => Promise<CubeDetail>;
|
|
152
160
|
createCube: (apiUrl: string, token: string, params: {
|
|
153
|
-
name
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
161
|
+
name: string;
|
|
162
|
+
workingRepoName: string;
|
|
163
|
+
repository: CreateCubeRepository;
|
|
164
|
+
template: Exclude<CubeTemplate, 'default'>;
|
|
165
|
+
}, serverTrustIdentity?: string) => Promise<RepositoryCubeCreation>;
|
|
157
166
|
assimilate: (apiUrl: string, token: string, params: {
|
|
158
167
|
cube_id: string;
|
|
159
168
|
role_id: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assimilate-cmd.d.ts","sourceRoot":"","sources":["../src/assimilate-cmd.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"assimilate-cmd.d.ts","sourceRoot":"","sources":["../src/assimilate-cmd.ts"],"names":[],"mappings":"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"}
|
package/dist/assimilate-cmd.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { dirname, basename } from 'node:path';
|
|
2
2
|
import { randomUUID } from 'node:crypto';
|
|
3
3
|
import { roleSlug, matchRoleByName, occupiedRoleIdsForAutoRole, pickDefaultRole, } from './role-resolver.js';
|
|
4
|
-
import { deriveCubeName, parseGitRemote, sanitizeRemoteUrl } from './cube-name.js';
|
|
5
4
|
import { validateName } from './name-validator.js';
|
|
6
5
|
import { renderAssimilationWelcome } from './assimilate-welcome.js';
|
|
7
6
|
import { shellEscape } from './shell-escape.js';
|
|
@@ -20,10 +19,11 @@ import { installBorgPlugin } from './opencode-plugin.js';
|
|
|
20
19
|
import { computeOpenCodePort, connectOpenCodeDrone, createOpenCodeLaunchKickoff, injectInitialKickoff } from './opencode-drone.js';
|
|
21
20
|
import { ensureCliMcpConfigured } from './ensure-mcp-config.js';
|
|
22
21
|
import { normalizeServerEndpoint } from './server-endpoint.js';
|
|
23
|
-
import { BorgServerError, LegacySessionCredentialCollisionError } from './server-errors.js';
|
|
22
|
+
import { BorgServerError, CubeCreationConfirmationError, CubeCreationOutcomeUnknownError, LegacySessionCredentialCollisionError, } from './server-errors.js';
|
|
24
23
|
import { createHash } from 'node:crypto';
|
|
25
24
|
import { buildOpenCodeLaunchArgs } from './cli-tool-approval.js';
|
|
26
25
|
import { resolveWorkingRepo } from './working-repo.js';
|
|
26
|
+
import { initializeRepositoryCube, RepositoryAssociationSaveError, validRepositoryCubeName, } from './repository-cube-init.js';
|
|
27
27
|
const PRIVATE_STATE_UNAVAILABLE_COPY = [
|
|
28
28
|
'Borg could not safely prepare its private local state.',
|
|
29
29
|
'No Borg server or cube change was made.',
|
|
@@ -33,10 +33,6 @@ function affirmative(answer) {
|
|
|
33
33
|
const normalized = answer.trim().toLowerCase();
|
|
34
34
|
return normalized === '' || normalized === 'y' || normalized === 'yes';
|
|
35
35
|
}
|
|
36
|
-
function isLocalCubePresentationName(name) {
|
|
37
|
-
return name.length >= 1 && name.length <= 120 &&
|
|
38
|
-
/^[A-Za-z0-9][A-Za-z0-9 ._-]*$/.test(name);
|
|
39
|
-
}
|
|
40
36
|
async function selectAssimilationAuthority(flags, deps) {
|
|
41
37
|
if (flags.server !== undefined) {
|
|
42
38
|
try {
|
|
@@ -191,6 +187,7 @@ function diagnoseSessionTermination(deps, apiUrl, outcome) {
|
|
|
191
187
|
return 1;
|
|
192
188
|
}
|
|
193
189
|
export async function runAssimilate(args, deps) {
|
|
190
|
+
const mode = args.mode ?? 'assimilate';
|
|
194
191
|
// ----- Input validation (before any subprocess work) -----
|
|
195
192
|
if (args.role !== undefined) {
|
|
196
193
|
const v = validateName(args.role);
|
|
@@ -206,6 +203,27 @@ export async function runAssimilate(args, deps) {
|
|
|
206
203
|
return 1;
|
|
207
204
|
}
|
|
208
205
|
}
|
|
206
|
+
if (args.flags.cubeName !== undefined && !validRepositoryCubeName(args.flags.cubeName.trim())) {
|
|
207
|
+
deps.stderr('Invalid cube name. Use 1-120 letters, digits, spaces, dots, underscores, or hyphens, starting with a letter or digit.\n');
|
|
208
|
+
return 1;
|
|
209
|
+
}
|
|
210
|
+
let repositoryContext;
|
|
211
|
+
try {
|
|
212
|
+
repositoryContext = await deps.resolveRepositoryContext(deps.cwd());
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
if (error instanceof Error && error.message === 'BARE_REPOSITORY') {
|
|
216
|
+
deps.stderr('borg assimilate requires a non-bare repository worktree. Clone or check out the repository, then retry.\n');
|
|
217
|
+
return 1;
|
|
218
|
+
}
|
|
219
|
+
repositoryContext = null;
|
|
220
|
+
}
|
|
221
|
+
if (!repositoryContext) {
|
|
222
|
+
deps.stderr('No Git repository was found for this directory.\n' +
|
|
223
|
+
'Nothing was changed.\n' +
|
|
224
|
+
'Run this command inside a Git repository.\n');
|
|
225
|
+
return 1;
|
|
226
|
+
}
|
|
209
227
|
try {
|
|
210
228
|
await deps.preparePrivateRoot();
|
|
211
229
|
}
|
|
@@ -236,67 +254,7 @@ export async function runAssimilate(args, deps) {
|
|
|
236
254
|
if (localSeatReadError !== undefined) {
|
|
237
255
|
return reportServerFailure(deps, authority.apiUrl, localSeatReadError);
|
|
238
256
|
}
|
|
239
|
-
|
|
240
|
-
// Resolve and, where necessary, confirm local presentation data before an
|
|
241
|
-
// owner invitation can be consumed. A declined/underivable basename must
|
|
242
|
-
// not leave a successfully enrolled client behind.
|
|
243
|
-
const projectRoot = deps.findProjectRoot(deps.cwd());
|
|
244
|
-
let cubeName;
|
|
245
|
-
if (args.flags.cubeName) {
|
|
246
|
-
cubeName = args.flags.cubeName;
|
|
247
|
-
}
|
|
248
|
-
else {
|
|
249
|
-
const remoteResult = deps.runSync('git', ['remote', 'get-url', 'origin'], projectRoot);
|
|
250
|
-
const remoteUrl = remoteResult.status === 0 ? remoteResult.stdout : null;
|
|
251
|
-
const sanitizedRemote = remoteUrl ? sanitizeRemoteUrl(remoteUrl) : null;
|
|
252
|
-
const parsedRepo = sanitizedRemote ? parseGitRemote(sanitizedRemote) : null;
|
|
253
|
-
if (!parsedRepo) {
|
|
254
|
-
const bareResult = deps.runSync('git', ['rev-parse', '--is-bare-repository'], projectRoot);
|
|
255
|
-
if (bareResult.status === 0 && bareResult.stdout.trim() === 'true') {
|
|
256
|
-
deps.stderr('borg assimilate requires a non-bare repository worktree. ' +
|
|
257
|
-
(authority.kind === 'server'
|
|
258
|
-
? `Clone or check out the repository, then rerun ${localAssimilateCommand(authority.apiUrl)}.\n`
|
|
259
|
-
: 'Clone or check out the repository, then retry.\n'));
|
|
260
|
-
return 1;
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
cubeName = deriveCubeName(projectRoot, remoteUrl);
|
|
264
|
-
if (!cubeName) {
|
|
265
|
-
deps.stderr('Could not derive a cube name from this repository. ' +
|
|
266
|
-
(authority.kind === 'server'
|
|
267
|
-
? `Rerun ${localAssimilateCommand(authority.apiUrl)} with \`--cube-name <name>\`.\n`
|
|
268
|
-
: 'Pass --cube-name <name> and retry.\n'));
|
|
269
|
-
return 1;
|
|
270
|
-
}
|
|
271
|
-
if (!parsedRepo) {
|
|
272
|
-
if (sanitizedRemote) {
|
|
273
|
-
deps.stderr(`Could not parse the origin remote; using directory name '${cubeName}' as the cube name.\n`);
|
|
274
|
-
}
|
|
275
|
-
if (!args.flags.yes) {
|
|
276
|
-
if (!deps.isTTY()) {
|
|
277
|
-
deps.stderr(`Using directory name '${cubeName}' as the cube name requires confirmation. ` +
|
|
278
|
-
(authority.kind === 'server'
|
|
279
|
-
? `Rerun ${localAssimilateCommand(authority.apiUrl)} with \`--cube-name <name>\` or \`--yes\`.\n`
|
|
280
|
-
: 'Re-run with --cube-name <name> or --yes.\n'));
|
|
281
|
-
return 1;
|
|
282
|
-
}
|
|
283
|
-
const confirmed = await deps.prompt(`No usable origin remote was found. Use directory name '${cubeName}' as the cube name? [Y/n]: `);
|
|
284
|
-
if (!affirmative(confirmed)) {
|
|
285
|
-
deps.stderr(authority.kind === 'server'
|
|
286
|
-
? `Cube creation for ${authority.apiUrl} was cancelled. Rerun ` +
|
|
287
|
-
`${localAssimilateCommand(authority.apiUrl)} with \`--cube-name <name>\`.\n`
|
|
288
|
-
: 'Cube creation cancelled. Re-run with --cube-name <name> to choose a name.\n');
|
|
289
|
-
return 1;
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
if (authority.kind === 'server' && !isLocalCubePresentationName(cubeName)) {
|
|
295
|
-
deps.stderr(`Invalid cube name for ${authority.apiUrl}. Use 1–120 letters, digits, spaces, dots, ` +
|
|
296
|
-
'underscores, or hyphens, starting with a letter or digit. Rerun ' +
|
|
297
|
-
`${localAssimilateCommand(authority.apiUrl)} with \`--cube-name <name>\`.\n`);
|
|
298
|
-
return 1;
|
|
299
|
-
}
|
|
257
|
+
const projectRoot = repositoryContext.root;
|
|
300
258
|
let auth;
|
|
301
259
|
{
|
|
302
260
|
try {
|
|
@@ -347,6 +305,7 @@ export async function runAssimilate(args, deps) {
|
|
|
347
305
|
token: serverAuth.token,
|
|
348
306
|
apiUrl: authority.apiUrl,
|
|
349
307
|
serverTrustIdentity: serverAuth.trustIdentity,
|
|
308
|
+
serverCapabilities: serverAuth.serverCapabilities ?? [],
|
|
350
309
|
};
|
|
351
310
|
}
|
|
352
311
|
catch (error) {
|
|
@@ -366,57 +325,122 @@ export async function runAssimilate(args, deps) {
|
|
|
366
325
|
// Sprint 18: capture pre-chdir cwd for the post-exit shell-cd hint
|
|
367
326
|
// (no chdir has happened yet; this is a stable starting point).
|
|
368
327
|
const originalCwd = deps.cwd();
|
|
369
|
-
|
|
370
|
-
// gh#653 B4: announce each network step. These calls take 2–5s and were
|
|
371
|
-
// previously silent, so a user read the wait as a hang and Ctrl-C'd mid-run.
|
|
372
|
-
deps.stderr('Checking your cubes…\n');
|
|
373
|
-
let allCubes;
|
|
328
|
+
let initialized;
|
|
374
329
|
try {
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
330
|
+
if (!auth.serverCapabilities.includes('create_cube') && !existing) {
|
|
331
|
+
const repository = await deps.getRepositoryIdentity(repositoryContext);
|
|
332
|
+
const association = await deps.getRepositoryAssociation(auth.serverTrustIdentity, repository);
|
|
333
|
+
if (association) {
|
|
334
|
+
initialized = await initializeRepositoryCube({
|
|
335
|
+
mode, context: repositoryContext, serverOrigin: auth.apiUrl, flags: args.flags,
|
|
336
|
+
}, {
|
|
337
|
+
isTTY: deps.isTTY,
|
|
338
|
+
prompt: deps.prompt,
|
|
339
|
+
write: deps.stderr,
|
|
340
|
+
getIdentity: async () => repository,
|
|
341
|
+
getAssociation: async () => association,
|
|
342
|
+
saveAssociation: (identity, saved) => deps.saveRepositoryAssociation(auth.serverTrustIdentity, identity, saved),
|
|
343
|
+
getCube: (cubeId) => deps.getCube(auth.apiUrl, auth.token, cubeId, auth.serverTrustIdentity),
|
|
344
|
+
createCube: (params) => deps.createCube(auth.apiUrl, auth.token, params, auth.serverTrustIdentity),
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
const candidateName = args.flags.cubeName ?? repositoryContext.derivedName;
|
|
349
|
+
const accessible = await deps.listCubes(auth.apiUrl, auth.token, auth.serverTrustIdentity);
|
|
350
|
+
const matches = accessible.filter((cube) => cube.name === candidateName);
|
|
351
|
+
if (matches.length !== 1) {
|
|
352
|
+
deps.stderr(matches.length === 0
|
|
353
|
+
? `This enrolled client cannot create a cube on ${auth.apiUrl}. Ask the server operator to grant access to a cube, then rerun ${localAssimilateCommand(auth.apiUrl)}.\n`
|
|
354
|
+
: `More than one accessible cube is named '${candidateName}'. Nothing was changed. Ask the server operator for an unambiguous repository cube grant.\n`);
|
|
355
|
+
return 1;
|
|
356
|
+
}
|
|
357
|
+
const cube = await deps.getCube(auth.apiUrl, auth.token, matches[0].id, auth.serverTrustIdentity);
|
|
358
|
+
const association = {
|
|
359
|
+
cubeId: cube.id,
|
|
360
|
+
name: cube.name,
|
|
361
|
+
workingRepoName: repositoryContext.derivedName,
|
|
362
|
+
template: 'default',
|
|
363
|
+
};
|
|
364
|
+
try {
|
|
365
|
+
await deps.saveRepositoryAssociation(auth.serverTrustIdentity, repository, association);
|
|
366
|
+
}
|
|
367
|
+
catch {
|
|
368
|
+
throw new RepositoryAssociationSaveError();
|
|
369
|
+
}
|
|
370
|
+
const response = {
|
|
371
|
+
result: 'resolved',
|
|
372
|
+
cube_id: cube.id,
|
|
373
|
+
name: cube.name,
|
|
374
|
+
working_repo_name: repositoryContext.derivedName,
|
|
375
|
+
repository,
|
|
376
|
+
template: 'default',
|
|
377
|
+
human_seat_role_id: cube.roles.find((role) => role.is_human_seat)?.id ?? '',
|
|
378
|
+
default_worker_role_id: cube.roles.find((role) => role.is_default)?.id ?? '',
|
|
379
|
+
access: 'manage',
|
|
380
|
+
};
|
|
381
|
+
deps.stderr(`Cube already initialized.\n Name: ${cube.name}\n Template: Default (legacy)\n` +
|
|
382
|
+
` Repository: ${repositoryContext.root}\n Server: ${auth.apiUrl}\n` +
|
|
383
|
+
(mode === 'cube-init'
|
|
384
|
+
? `No drone was created.\nNext: borg assimilate --host ${shellEscape(auth.apiUrl)}\n`
|
|
385
|
+
: 'Continuing with role and seat setup...\n'));
|
|
386
|
+
initialized = { kind: 'success', creation: { response, cube }, existing: true };
|
|
387
|
+
}
|
|
387
388
|
}
|
|
388
|
-
|
|
389
|
-
|
|
389
|
+
else {
|
|
390
|
+
initialized = await initializeRepositoryCube({
|
|
391
|
+
mode,
|
|
392
|
+
context: repositoryContext,
|
|
393
|
+
serverOrigin: auth.apiUrl,
|
|
394
|
+
flags: args.flags,
|
|
395
|
+
}, {
|
|
396
|
+
isTTY: deps.isTTY,
|
|
397
|
+
prompt: deps.prompt,
|
|
398
|
+
write: deps.stderr,
|
|
399
|
+
getIdentity: deps.getRepositoryIdentity,
|
|
400
|
+
getAssociation: (repository) => deps.getRepositoryAssociation(auth.serverTrustIdentity, repository),
|
|
401
|
+
saveAssociation: (repository, association) => deps.saveRepositoryAssociation(auth.serverTrustIdentity, repository, association),
|
|
402
|
+
getCube: (cubeId) => deps.getCube(auth.apiUrl, auth.token, cubeId, auth.serverTrustIdentity),
|
|
403
|
+
createCube: (params) => deps.createCube(auth.apiUrl, auth.token, params, auth.serverTrustIdentity),
|
|
404
|
+
});
|
|
390
405
|
}
|
|
391
|
-
isFirstDrone = (cubeDetail.drones?.length ?? 0) === 0;
|
|
392
406
|
}
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
deps.stderr(`Borg server ${authority.apiUrl} supports its default cube template only. ` +
|
|
399
|
-
`Rerun ${localAssimilateCommand(authority.apiUrl)} without \`--template\` or \`--no-template\`.\n`);
|
|
407
|
+
catch (error) {
|
|
408
|
+
if (error instanceof RepositoryAssociationSaveError) {
|
|
409
|
+
deps.stderr('The repository cube was confirmed, but Borg could not save its local repository association.\n' +
|
|
410
|
+
'No drone was created.\n' +
|
|
411
|
+
'Run the same command again; the server will resolve the existing cube and restore the local association.\n');
|
|
400
412
|
return 1;
|
|
401
413
|
}
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
? {
|
|
408
|
-
name: cubeName ?? undefined,
|
|
409
|
-
template: chosenTemplate,
|
|
410
|
-
projectRoot,
|
|
411
|
-
}
|
|
412
|
-
: { name: cubeName ?? undefined };
|
|
413
|
-
cubeDetail = await deps.createCube(auth.apiUrl, auth.token, createParams, auth.serverTrustIdentity);
|
|
414
|
+
if (error instanceof CubeCreationOutcomeUnknownError) {
|
|
415
|
+
deps.stderr('Cube creation outcome is unknown.\n' +
|
|
416
|
+
'No local repository association was saved.\n' +
|
|
417
|
+
'Run the same command again; the server will resolve the original request or return a conflict.\n');
|
|
418
|
+
return 1;
|
|
414
419
|
}
|
|
415
|
-
|
|
416
|
-
|
|
420
|
+
if (error instanceof CubeCreationConfirmationError) {
|
|
421
|
+
deps.stderr('Cube creation could not be confirmed.\n' +
|
|
422
|
+
`${error.message}\n` +
|
|
423
|
+
'No local repository association was saved.\n' +
|
|
424
|
+
'Resolve the conflict, then run the same command again.\n');
|
|
425
|
+
return 1;
|
|
426
|
+
}
|
|
427
|
+
if (error instanceof BorgServerError && error.code === 'CREATE_CUBE_DENIED') {
|
|
428
|
+
deps.stderr(`This enrolled client cannot create a cube on ${auth.apiUrl}. ` +
|
|
429
|
+
`Ask the server operator to grant access to a cube, then rerun ${localAssimilateCommand(auth.apiUrl)}.\n`);
|
|
430
|
+
return 1;
|
|
417
431
|
}
|
|
418
|
-
|
|
432
|
+
if (error instanceof BorgServerError) {
|
|
433
|
+
return reportServerFailure(deps, auth.apiUrl, error);
|
|
434
|
+
}
|
|
435
|
+
deps.stderr('Could not create cube.\nThe selected Borg server rejected the request.\nNothing was changed.\n');
|
|
436
|
+
return 1;
|
|
419
437
|
}
|
|
438
|
+
if (initialized.kind === 'stop')
|
|
439
|
+
return initialized.code;
|
|
440
|
+
const cubeDetail = initialized.creation.cube;
|
|
441
|
+
const isFirstDrone = (cubeDetail.drones?.length ?? 0) === 0;
|
|
442
|
+
if (mode === 'cube-init')
|
|
443
|
+
return 0;
|
|
420
444
|
// Read the worktree identity before role selection. A live local seat must
|
|
421
445
|
// retain its original role so the attach request reuses the exact durable
|
|
422
446
|
// retry binding instead of selecting another unoccupied role and minting a
|
|
@@ -1298,7 +1322,7 @@ export async function runAssimilate(args, deps) {
|
|
|
1298
1322
|
serverUrl,
|
|
1299
1323
|
directory: agentCwd,
|
|
1300
1324
|
droneLabel: result.drone_label,
|
|
1301
|
-
cubeName:
|
|
1325
|
+
cubeName: cubeDetail.name,
|
|
1302
1326
|
})
|
|
1303
1327
|
.then(() => injectInitialKickoff(launchKickoff))
|
|
1304
1328
|
.catch(() => { });
|