borgmcp 2.0.11 → 2.1.1
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 +22 -4
- package/dist/assimilate-cmd.d.ts.map +1 -1
- package/dist/assimilate-cmd.js +109 -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 +69 -25
- 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 +25 -7
- 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/remote-client.js.map +1 -1
- package/dist/repository-cube-init.d.ts +72 -0
- package/dist/repository-cube-init.d.ts.map +1 -0
- package/dist/repository-cube-init.js +341 -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 +17 -0
- package/dist/server-errors.d.ts.map +1 -1
- package/dist/server-errors.js +32 -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 +38 -4
- package/dist/server-handshake.d.ts.map +1 -1
- package/dist/server-handshake.js +175 -13
- package/dist/server-handshake.js.map +1 -1
- package/docs/EXTRACTION_PROVENANCE.md +9 -7
- package/docs/LOCAL_SERVER.md +44 -9
- package/docs/RELEASING.md +21 -4
- package/package.json +2 -2
- package/src/assimilate-cmd.ts +179 -137
- package/src/assimilate-deps.ts +96 -24
- package/src/claude.ts +34 -14
- package/src/cli-help.ts +28 -7
- package/src/config.ts +30 -8
- package/src/remote-client.ts +1 -1
- package/src/repository-cube-init.ts +452 -0
- package/src/repository-identity.ts +199 -0
- package/src/server-errors.ts +41 -0
- package/src/server-facade.ts +47 -2
- package/src/server-handshake.ts +258 -14
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 first resolves an existing repository association. Without one, an exact-name accessible cube requires explicit interactive confirmation before Borg associates it with this repository; otherwise Borg shows the repository context, lets you edit the proposed cube name, offers the Software Development and Starter templates, and asks for creation confirmation. It then 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 only when creating a new cube; it never adopts an existing cube by name.
|
|
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 { AssociateRepositoryCubeResponse, CreateCubeRepository, CubeTemplate } from 'borgmcp-shared/protocol';
|
|
11
|
+
import { type RepositoryCubeCreation, type RepositoryCubeResolution } 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. */
|
|
@@ -147,13 +155,23 @@ export interface AssimilateDeps {
|
|
|
147
155
|
trustIdentity: string;
|
|
148
156
|
serverCapabilities?: readonly string[];
|
|
149
157
|
} | null>;
|
|
158
|
+
resolveRepositoryCube: (apiUrl: string, token: string, input: {
|
|
159
|
+
workingRepoName: string;
|
|
160
|
+
repository: CreateCubeRepository;
|
|
161
|
+
}, serverTrustIdentity?: string) => Promise<RepositoryCubeResolution>;
|
|
162
|
+
associateRepositoryCube: (apiUrl: string, token: string, input: {
|
|
163
|
+
cubeId: string;
|
|
164
|
+
workingRepoName: string;
|
|
165
|
+
repository: CreateCubeRepository;
|
|
166
|
+
}, serverTrustIdentity?: string) => Promise<AssociateRepositoryCubeResponse>;
|
|
150
167
|
listCubes: (apiUrl: string, token: string, serverTrustIdentity?: string) => Promise<CubeSummary[]>;
|
|
151
168
|
getCube: (apiUrl: string, token: string, cubeId: string, serverTrustIdentity?: string) => Promise<CubeDetail>;
|
|
152
169
|
createCube: (apiUrl: string, token: string, params: {
|
|
153
|
-
name
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
170
|
+
name: string;
|
|
171
|
+
workingRepoName: string;
|
|
172
|
+
repository: CreateCubeRepository;
|
|
173
|
+
template: Exclude<CubeTemplate, 'default'>;
|
|
174
|
+
}, serverTrustIdentity?: string) => Promise<RepositoryCubeCreation>;
|
|
157
175
|
assimilate: (apiUrl: string, token: string, params: {
|
|
158
176
|
cube_id: string;
|
|
159
177
|
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, RepositoryAssociationOperationError, RepositoryAssociationOutcomeUnknownError, RepositoryAssociationResolutionError, } 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, RepositoryAssociationConfirmationError, 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,97 @@ 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
|
-
|
|
330
|
+
initialized = await initializeRepositoryCube({
|
|
331
|
+
mode,
|
|
332
|
+
context: repositoryContext,
|
|
333
|
+
serverOrigin: auth.apiUrl,
|
|
334
|
+
flags: args.flags,
|
|
335
|
+
canCreate: auth.serverCapabilities.includes('create_cube'),
|
|
336
|
+
}, {
|
|
337
|
+
isTTY: deps.isTTY,
|
|
338
|
+
prompt: deps.prompt,
|
|
339
|
+
write: deps.stderr,
|
|
340
|
+
getIdentity: deps.getRepositoryIdentity,
|
|
341
|
+
getAssociation: (repository) => deps.getRepositoryAssociation(auth.serverTrustIdentity, repository),
|
|
342
|
+
saveAssociation: (repository, association) => deps.saveRepositoryAssociation(auth.serverTrustIdentity, repository, association),
|
|
343
|
+
resolveAssociation: (repository, workingRepoName) => deps.resolveRepositoryCube(auth.apiUrl, auth.token, { repository, workingRepoName }, auth.serverTrustIdentity),
|
|
344
|
+
listCubes: () => deps.listCubes(auth.apiUrl, auth.token, auth.serverTrustIdentity),
|
|
345
|
+
associateCube: (params) => deps.associateRepositoryCube(auth.apiUrl, auth.token, params, auth.serverTrustIdentity),
|
|
346
|
+
getCube: (cubeId) => deps.getCube(auth.apiUrl, auth.token, cubeId, auth.serverTrustIdentity),
|
|
347
|
+
createCube: (params) => deps.createCube(auth.apiUrl, auth.token, params, auth.serverTrustIdentity),
|
|
348
|
+
});
|
|
379
349
|
}
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
cubeDetail = await deps.getCube(auth.apiUrl, auth.token, existingCube.id, auth.serverTrustIdentity);
|
|
350
|
+
catch (error) {
|
|
351
|
+
if (error instanceof RepositoryAssociationOutcomeUnknownError) {
|
|
352
|
+
deps.stderr('Repository cube association outcome is unknown.\n' +
|
|
353
|
+
'The server may have created the repository binding; no local repository association was saved and no drone was created.\n' +
|
|
354
|
+
'Run the same command again; Borg will first resolve the authoritative server association without creating a cube.\n');
|
|
355
|
+
return 1;
|
|
387
356
|
}
|
|
388
|
-
|
|
389
|
-
|
|
357
|
+
if (error instanceof RepositoryAssociationResolutionError) {
|
|
358
|
+
deps.stderr('Repository cube association could not be resolved.\n' +
|
|
359
|
+
'Verify that the server is reachable and the client and server versions match, then run the same command again.\n' +
|
|
360
|
+
'No cube, repository binding, or drone was created.\n');
|
|
361
|
+
return 1;
|
|
390
362
|
}
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
363
|
+
if (error instanceof RepositoryAssociationOperationError) {
|
|
364
|
+
const recovery = error.failure === 'repository-already-associated'
|
|
365
|
+
? 'This repository is already associated with another cube. Run the same command again to use the existing managed association, or ask the server operator to correct the repository binding.'
|
|
366
|
+
: error.failure === 'cube-already-associated'
|
|
367
|
+
? 'The selected cube is already associated with another repository. Choose a different cube, or run the command from the repository already linked to that cube.'
|
|
368
|
+
: error.failure === 'access-denied'
|
|
369
|
+
? 'This enrolled client does not have permission to manage the selected cube. Ask the server operator to grant this client management access, then run the same command again.'
|
|
370
|
+
: 'The selected cube does not have valid authoritative roles. Ask the server operator to repair its role configuration, or choose another cube.';
|
|
371
|
+
deps.stderr('Repository cube association could not be completed.\n' +
|
|
372
|
+
`${recovery}\n` +
|
|
373
|
+
'No cube, repository binding, or drone was created.\n');
|
|
400
374
|
return 1;
|
|
401
375
|
}
|
|
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);
|
|
376
|
+
if (error instanceof RepositoryAssociationConfirmationError) {
|
|
377
|
+
deps.stderr('Repository cube association could not be confirmed.\n' +
|
|
378
|
+
'The server may have created the repository binding; no local repository association was saved and no drone was created.\n' +
|
|
379
|
+
'Run the same command again; Borg will resolve authoritative server state before creating or associating a cube.\n');
|
|
380
|
+
return 1;
|
|
414
381
|
}
|
|
415
|
-
|
|
416
|
-
|
|
382
|
+
if (error instanceof RepositoryAssociationSaveError) {
|
|
383
|
+
deps.stderr('The repository cube was confirmed, but Borg could not save its local repository association.\n' +
|
|
384
|
+
'No drone was created.\n' +
|
|
385
|
+
'Run the same command again; the server will resolve the existing cube and restore the local association.\n');
|
|
386
|
+
return 1;
|
|
417
387
|
}
|
|
418
|
-
|
|
388
|
+
if (error instanceof CubeCreationOutcomeUnknownError) {
|
|
389
|
+
deps.stderr('Cube creation outcome is unconfirmed.\n' +
|
|
390
|
+
'The server may have created the cube and repository binding; no local repository association was saved and no drone was created.\n' +
|
|
391
|
+
'Run the same command again; Borg will resolve authoritative server state before creating a cube.\n');
|
|
392
|
+
return 1;
|
|
393
|
+
}
|
|
394
|
+
if (error instanceof CubeCreationConfirmationError) {
|
|
395
|
+
deps.stderr('Cube creation could not be confirmed.\n' +
|
|
396
|
+
'The server may have created the cube and repository binding; no local repository association was saved and no drone was created.\n' +
|
|
397
|
+
'Run the same command again; Borg will resolve authoritative server state before creating a cube.\n');
|
|
398
|
+
return 1;
|
|
399
|
+
}
|
|
400
|
+
if (error instanceof BorgServerError && error.code === 'CREATE_CUBE_DENIED') {
|
|
401
|
+
deps.stderr(`This enrolled client cannot create a cube on ${auth.apiUrl}. ` +
|
|
402
|
+
`Ask the server operator to grant access to a cube, then rerun ${localAssimilateCommand(auth.apiUrl)}.\n`);
|
|
403
|
+
return 1;
|
|
404
|
+
}
|
|
405
|
+
if (error instanceof BorgServerError) {
|
|
406
|
+
return reportServerFailure(deps, auth.apiUrl, error);
|
|
407
|
+
}
|
|
408
|
+
deps.stderr('Repository cube initialization failed.\n' +
|
|
409
|
+
'The server may have created or associated a cube; local repository state may be incomplete and no drone was created.\n' +
|
|
410
|
+
'Run the same command again; Borg will resolve authoritative server state before creating or associating a cube.\n');
|
|
411
|
+
return 1;
|
|
419
412
|
}
|
|
413
|
+
if (initialized.kind === 'stop')
|
|
414
|
+
return initialized.code;
|
|
415
|
+
const cubeDetail = initialized.creation.cube;
|
|
416
|
+
const isFirstDrone = (cubeDetail.drones?.length ?? 0) === 0;
|
|
417
|
+
if (mode === 'cube-init')
|
|
418
|
+
return 0;
|
|
420
419
|
// Read the worktree identity before role selection. A live local seat must
|
|
421
420
|
// retain its original role so the attach request reuses the exact durable
|
|
422
421
|
// retry binding instead of selecting another unoccupied role and minting a
|
|
@@ -1298,7 +1297,7 @@ export async function runAssimilate(args, deps) {
|
|
|
1298
1297
|
serverUrl,
|
|
1299
1298
|
directory: agentCwd,
|
|
1300
1299
|
droneLabel: result.drone_label,
|
|
1301
|
-
cubeName:
|
|
1300
|
+
cubeName: cubeDetail.name,
|
|
1302
1301
|
})
|
|
1303
1302
|
.then(() => injectInitialKickoff(launchKickoff))
|
|
1304
1303
|
.catch(() => { });
|