borgmcp 2.7.2 → 2.8.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 +96 -230
- package/dist/assimilate-cmd.d.ts.map +1 -1
- package/dist/assimilate-cmd.js +11 -2
- package/dist/assimilate-cmd.js.map +1 -1
- package/dist/claude.js +6 -16
- package/dist/claude.js.map +1 -1
- package/dist/cli-help.d.ts +5 -0
- package/dist/cli-help.d.ts.map +1 -1
- package/dist/cli-help.js +49 -1
- package/dist/cli-help.js.map +1 -1
- package/dist/drone-lifecycle.d.ts +8 -0
- package/dist/drone-lifecycle.d.ts.map +1 -1
- package/dist/drone-lifecycle.js +19 -0
- package/dist/drone-lifecycle.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -2
- package/dist/index.js.map +1 -1
- package/dist/log-stream.d.ts +4 -0
- package/dist/log-stream.d.ts.map +1 -1
- package/dist/log-stream.js +28 -4
- package/dist/log-stream.js.map +1 -1
- package/dist/remote-client.d.ts +1 -1
- package/dist/remote-client.d.ts.map +1 -1
- package/dist/remote-client.js +42 -7
- package/dist/remote-client.js.map +1 -1
- package/dist/server-errors.d.ts +8 -0
- package/dist/server-errors.d.ts.map +1 -1
- package/dist/server-errors.js +19 -0
- package/dist/server-errors.js.map +1 -1
- package/dist/server-facade.d.ts +4 -0
- package/dist/server-facade.d.ts.map +1 -1
- package/dist/server-facade.js +11 -0
- package/dist/server-facade.js.map +1 -1
- package/dist/server-handshake.d.ts +1 -1
- package/dist/server-trust.d.ts.map +1 -1
- package/dist/server-trust.js +10 -0
- package/dist/server-trust.js.map +1 -1
- package/dist/setup.js +2 -4
- package/dist/setup.js.map +1 -1
- package/dist/tool-manifest.d.ts.map +1 -1
- package/dist/tool-manifest.js +14 -13
- package/dist/tool-manifest.js.map +1 -1
- package/dist/update-cmd.d.ts.map +1 -1
- package/dist/update-cmd.js +122 -16
- package/dist/update-cmd.js.map +1 -1
- package/docs/EXTRACTION_PROVENANCE.md +7 -7
- package/docs/LOCAL_SERVER.md +3 -3
- package/docs/RELEASING.md +16 -6
- package/package.json +2 -2
- package/src/assimilate-cmd.ts +13 -2
- package/src/claude.ts +11 -16
- package/src/cli-help.ts +65 -1
- package/src/drone-lifecycle.ts +25 -0
- package/src/index.ts +15 -1
- package/src/log-stream.ts +26 -5
- package/src/remote-client.ts +56 -5
- package/src/server-errors.ts +24 -0
- package/src/server-facade.ts +15 -0
- package/src/server-handshake.ts +1 -1
- package/src/server-trust.ts +11 -0
- package/src/setup.ts +2 -4
- package/src/tool-manifest.ts +14 -13
- package/src/update-cmd.ts +145 -16
package/src/remote-client.ts
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
import { randomUUID } from 'node:crypto';
|
|
17
17
|
import {
|
|
18
18
|
createProtocolEnvelope,
|
|
19
|
+
decodeDeleteCubeResponse,
|
|
19
20
|
decodeDroneRuntimeMetadataState,
|
|
20
21
|
decodeEvictDroneResult,
|
|
21
22
|
decodeProtocolEnvelope,
|
|
@@ -23,6 +24,7 @@ import {
|
|
|
23
24
|
decodeReassignDroneResult,
|
|
24
25
|
decodeUpdateDroneRuntimeMetadataResponse,
|
|
25
26
|
ErrorCode,
|
|
27
|
+
ProtocolContractError,
|
|
26
28
|
type AgentKind,
|
|
27
29
|
type EvictDroneResult,
|
|
28
30
|
type ReassignDroneResult,
|
|
@@ -30,7 +32,12 @@ import {
|
|
|
30
32
|
import { consolePrefix } from './console-prefix.js';
|
|
31
33
|
import { debugLog } from './debug.js';
|
|
32
34
|
import { assertUuidShape } from './evict-drone.js';
|
|
33
|
-
import {
|
|
35
|
+
import {
|
|
36
|
+
CubeDeletedError,
|
|
37
|
+
CUBE_DELETED_CODE,
|
|
38
|
+
DroneEvictedError,
|
|
39
|
+
DRONE_EVICTED_CODE,
|
|
40
|
+
} from './drone-lifecycle.js';
|
|
34
41
|
import type { MessageTaxonomy, MessageTaxonomyClass } from 'borgmcp-shared/templates';
|
|
35
42
|
import { getTemplate, type Template, type TemplateRole } from 'borgmcp-shared/templates';
|
|
36
43
|
import { parseRoleSections } from 'borgmcp-shared/role-section';
|
|
@@ -41,8 +48,10 @@ import { loadBorgServerTrust, type ServerFetch } from './server-trust.js';
|
|
|
41
48
|
import {
|
|
42
49
|
BorgServerError,
|
|
43
50
|
BorgServerHttpError,
|
|
51
|
+
BorgProtocolMismatchError,
|
|
44
52
|
BorgServerTrustError,
|
|
45
53
|
BorgServerUnreachableError,
|
|
54
|
+
CubeDeletionConfirmationError,
|
|
46
55
|
LocalManageCredentialUnavailableError,
|
|
47
56
|
LocalManageRequiredError,
|
|
48
57
|
} from './server-errors.js';
|
|
@@ -226,6 +235,12 @@ async function decodeLocalProtocolResponse<T>(
|
|
|
226
235
|
// CR5: a TYPED transport-timeout verdict (message kept for call-site parity).
|
|
227
236
|
throw new BorgServerUnreachableError('Local Borg server request timed out');
|
|
228
237
|
}
|
|
238
|
+
if (
|
|
239
|
+
error instanceof ProtocolContractError &&
|
|
240
|
+
error.code === ErrorCode.UNSUPPORTED_PROTOCOL_VERSION
|
|
241
|
+
) {
|
|
242
|
+
throw new BorgProtocolMismatchError();
|
|
243
|
+
}
|
|
229
244
|
throw error;
|
|
230
245
|
} finally {
|
|
231
246
|
clearTimeout(timeout);
|
|
@@ -329,6 +344,9 @@ async function localManageRequest<T>(
|
|
|
329
344
|
}),
|
|
330
345
|
}), true, decodePayload);
|
|
331
346
|
} catch (error) {
|
|
347
|
+
if (error instanceof CubeDeletedError) {
|
|
348
|
+
throw new CubeDeletedError(operation.cubeName);
|
|
349
|
+
}
|
|
332
350
|
if (
|
|
333
351
|
error instanceof BorgServerHttpError &&
|
|
334
352
|
error.status === 403 &&
|
|
@@ -704,6 +722,7 @@ async function authedFetch(
|
|
|
704
722
|
// terminal controls. Decode only the bounded protocol error code for typed
|
|
705
723
|
// branching; never surface the server-provided message or details.
|
|
706
724
|
let code: ErrorCode | undefined;
|
|
725
|
+
let protocolMismatch = false;
|
|
707
726
|
try {
|
|
708
727
|
const body = await readBoundedResponseBody(
|
|
709
728
|
response,
|
|
@@ -713,7 +732,13 @@ async function authedFetch(
|
|
|
713
732
|
const parsed = JSON.parse(body);
|
|
714
733
|
try {
|
|
715
734
|
code = decodeProtocolErrorEnvelope(parsed).error.code;
|
|
716
|
-
} catch {
|
|
735
|
+
} catch (error) {
|
|
736
|
+
if (
|
|
737
|
+
error instanceof ProtocolContractError &&
|
|
738
|
+
error.code === ErrorCode.UNSUPPORTED_PROTOCOL_VERSION
|
|
739
|
+
) {
|
|
740
|
+
protocolMismatch = true;
|
|
741
|
+
}
|
|
717
742
|
if (
|
|
718
743
|
parsed !== null && typeof parsed === 'object' &&
|
|
719
744
|
parsed.error !== null && typeof parsed.error === 'object' &&
|
|
@@ -738,10 +763,15 @@ async function authedFetch(
|
|
|
738
763
|
code = undefined;
|
|
739
764
|
}
|
|
740
765
|
debugLog(`✗ ${response.status} ${method} ${path}`);
|
|
766
|
+
if (protocolMismatch) throw new BorgProtocolMismatchError();
|
|
741
767
|
if (droneSession !== undefined && response.status === 410 && code === DRONE_EVICTED_CODE) {
|
|
742
768
|
if (localSessionCredentialRef !== undefined) markSeatRejected(localSessionCredentialRef);
|
|
743
769
|
throw new DroneEvictedError();
|
|
744
770
|
}
|
|
771
|
+
if (response.status === 410 && code === CUBE_DELETED_CODE) {
|
|
772
|
+
if (localSessionCredentialRef !== undefined) markSeatRejected(localSessionCredentialRef);
|
|
773
|
+
throw new CubeDeletedError();
|
|
774
|
+
}
|
|
745
775
|
throw new BorgServerHttpError(
|
|
746
776
|
response.status,
|
|
747
777
|
`Borg server request failed (HTTP ${response.status})`,
|
|
@@ -1316,9 +1346,30 @@ export async function patchTaxonomyClass(
|
|
|
1316
1346
|
* Delete a cube. Cascade-deletes all roles, drones, and log entries.
|
|
1317
1347
|
* Requires a live cube-manage grant on the selected local client.
|
|
1318
1348
|
*/
|
|
1319
|
-
export async function deleteCube(cubeId: string): Promise<void> {
|
|
1320
|
-
|
|
1321
|
-
|
|
1349
|
+
export async function deleteCube(cubeId: string, confirmCubeId: string): Promise<void> {
|
|
1350
|
+
if (confirmCubeId !== cubeId) {
|
|
1351
|
+
throw new CubeDeletionConfirmationError(cubeId, confirmCubeId);
|
|
1352
|
+
}
|
|
1353
|
+
assertUuidShape(cubeId, 'cube_id');
|
|
1354
|
+
const active = await getActiveCube();
|
|
1355
|
+
if (!active?.serverTrustIdentity) throw new Error('Selected Borg server authority state is missing or unreadable');
|
|
1356
|
+
const cubeName = cubeId === active.cubeId ? active.name : cubeId;
|
|
1357
|
+
const result = await localManageRequest(
|
|
1358
|
+
active,
|
|
1359
|
+
`/api/cubes/${cubeId}`,
|
|
1360
|
+
'DELETE',
|
|
1361
|
+
{
|
|
1362
|
+
operation: `delete cube ${manageCopyValue(cubeName)}`,
|
|
1363
|
+
cubeName,
|
|
1364
|
+
noMutation: 'The cube was not deleted.',
|
|
1365
|
+
},
|
|
1366
|
+
{},
|
|
1367
|
+
decodeDeleteCubeResponse,
|
|
1368
|
+
);
|
|
1369
|
+
if (!result) throw new Error('Local Borg server returned an empty cube deletion response');
|
|
1370
|
+
if (result.cube_id !== cubeId) {
|
|
1371
|
+
throw new Error('Local Borg server returned a deletion response for an unexpected cube');
|
|
1372
|
+
}
|
|
1322
1373
|
}
|
|
1323
1374
|
|
|
1324
1375
|
/**
|
package/src/server-errors.ts
CHANGED
|
@@ -35,6 +35,16 @@ export class BorgServerHttpError extends Error {
|
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
export class BorgProtocolMismatchError extends Error {
|
|
39
|
+
constructor() {
|
|
40
|
+
super(
|
|
41
|
+
'This client and the selected Borg server use different protocol versions. ' +
|
|
42
|
+
'Update `borgmcp-server` and `borgmcp` to matching releases, server first and then client.',
|
|
43
|
+
);
|
|
44
|
+
this.name = 'BorgProtocolMismatchError';
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
38
48
|
export class LocalManageRequiredError extends Error {
|
|
39
49
|
constructor(
|
|
40
50
|
public readonly operation: string,
|
|
@@ -106,6 +116,20 @@ export class CubeCreationConfirmationError extends Error {
|
|
|
106
116
|
}
|
|
107
117
|
}
|
|
108
118
|
|
|
119
|
+
export class CubeDeletionConfirmationError extends Error {
|
|
120
|
+
constructor(
|
|
121
|
+
public readonly cubeId: string,
|
|
122
|
+
public readonly confirmCubeId: string | undefined,
|
|
123
|
+
) {
|
|
124
|
+
const supplied = confirmCubeId === undefined ? '(missing)' : `"${confirmCubeId}"`;
|
|
125
|
+
super(
|
|
126
|
+
`Cube deletion is irreversible. The confirmation cube ID ${supplied} must exactly match ` +
|
|
127
|
+
`the requested cube ID "${cubeId}". No cube was deleted.`,
|
|
128
|
+
);
|
|
129
|
+
this.name = 'CubeDeletionConfirmationError';
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
109
133
|
export type RepositoryAssociationFailure =
|
|
110
134
|
| 'repository-already-associated'
|
|
111
135
|
| 'cube-already-associated'
|
package/src/server-facade.ts
CHANGED
|
@@ -12,6 +12,7 @@ export type ParsedServerFacadeArgs =
|
|
|
12
12
|
| { kind: 'help' }
|
|
13
13
|
| { kind: 'cube-init-help' }
|
|
14
14
|
| { kind: 'cube-init'; args: string[] }
|
|
15
|
+
| { kind: 'command-help'; command: ServerLifecycleCommand }
|
|
15
16
|
| { kind: 'command'; command: ServerLifecycleCommand; args: string[] }
|
|
16
17
|
| { kind: 'error'; reason: 'unknown-command'; command: string };
|
|
17
18
|
|
|
@@ -33,6 +34,9 @@ export function parseServerFacadeArgs(args: readonly string[]): ParsedServerFaca
|
|
|
33
34
|
if (!(SERVER_LIFECYCLE_COMMANDS as readonly string[]).includes(command)) {
|
|
34
35
|
return { kind: 'error', reason: 'unknown-command', command };
|
|
35
36
|
}
|
|
37
|
+
if (rest.some(isHelpFlag)) {
|
|
38
|
+
return { kind: 'command-help', command: command as ServerLifecycleCommand };
|
|
39
|
+
}
|
|
36
40
|
return {
|
|
37
41
|
kind: 'command',
|
|
38
42
|
command: command as ServerLifecycleCommand,
|
|
@@ -163,6 +167,13 @@ export function unknownServerCommandText(command: string): string {
|
|
|
163
167
|
);
|
|
164
168
|
}
|
|
165
169
|
|
|
170
|
+
export function serverLifecycleHelpText(command: ServerLifecycleCommand): string {
|
|
171
|
+
return (
|
|
172
|
+
`Usage: borg server ${command} [arguments]\n\n` +
|
|
173
|
+
`Command arguments are server-owned and pass to the verified borg-mcp-server executable when run.\n`
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
166
177
|
export function missingServerExecutableText(command: ServerLifecycleCommand): string {
|
|
167
178
|
return (
|
|
168
179
|
`Local server command is unavailable: borg-mcp-server was not found.\n` +
|
|
@@ -256,6 +267,10 @@ export async function runEarlyServerFacade(
|
|
|
256
267
|
output.writeStdout(cubeInitHelpText(getPackageVersion()));
|
|
257
268
|
return 0;
|
|
258
269
|
}
|
|
270
|
+
if (parsed.kind === 'command-help') {
|
|
271
|
+
output.writeStdout(serverLifecycleHelpText(parsed.command));
|
|
272
|
+
return 0;
|
|
273
|
+
}
|
|
259
274
|
if (parsed.kind === 'error') {
|
|
260
275
|
output.writeStderr(unknownServerCommandText(parsed.command));
|
|
261
276
|
return 1;
|
package/src/server-handshake.ts
CHANGED
|
@@ -196,7 +196,7 @@ export interface ServerAttachResult {
|
|
|
196
196
|
}
|
|
197
197
|
|
|
198
198
|
/**
|
|
199
|
-
* Attach an enrolled client principal to one granted cube/role over protocol
|
|
199
|
+
* Attach an enrolled client principal to one granted cube/role over protocol v7.
|
|
200
200
|
* The client CSPRNG-generates the session bearer and persists it PENDING in the
|
|
201
201
|
* OS keychain (keyed by the stable per-seat identity) BEFORE this request, so an
|
|
202
202
|
* interrupted/lost response is recovered by re-sending the exact same bearer —
|
package/src/server-trust.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Buffer } from 'node:buffer';
|
|
1
2
|
import { createHash, timingSafeEqual, X509Certificate } from 'node:crypto';
|
|
2
3
|
import { constants } from 'node:fs';
|
|
3
4
|
import { open } from 'node:fs/promises';
|
|
@@ -157,6 +158,16 @@ export function createPinnedServerFetch(origin: string, caCertificate: string):
|
|
|
157
158
|
|
|
158
159
|
const body = requestBody(init.body);
|
|
159
160
|
const headers = new Headers(init.headers);
|
|
161
|
+
if (body !== undefined) {
|
|
162
|
+
const contentLength = String(
|
|
163
|
+
typeof body === 'string' ? Buffer.byteLength(body, 'utf8') : body.byteLength,
|
|
164
|
+
);
|
|
165
|
+
const declaredLength = headers.get('Content-Length');
|
|
166
|
+
if (declaredLength !== null && declaredLength !== contentLength) {
|
|
167
|
+
throw new Error('Borg server transport refused an inconsistent Content-Length');
|
|
168
|
+
}
|
|
169
|
+
if (declaredLength === null) headers.set('Content-Length', contentLength);
|
|
170
|
+
}
|
|
160
171
|
return await new Promise<Response>((resolvePromise, rejectPromise) => {
|
|
161
172
|
const request = httpsRequest({
|
|
162
173
|
protocol: 'https:',
|
package/src/setup.ts
CHANGED
|
@@ -38,6 +38,7 @@ import { handleVersionFlag } from './version.js';
|
|
|
38
38
|
import { initDebugFromArgv } from './debug.js';
|
|
39
39
|
import { defaultApprovalIo, setupApprovalWarnings } from './cli-tool-approval.js';
|
|
40
40
|
import { offerFirstRunServerInstall } from './first-run-server.js';
|
|
41
|
+
import { setupNextStepsText } from './cli-help.js';
|
|
41
42
|
|
|
42
43
|
/**
|
|
43
44
|
* Main setup wizard
|
|
@@ -184,10 +185,7 @@ async function main() {
|
|
|
184
185
|
// Success message
|
|
185
186
|
console.log(chalk.green.bold('\nSetup complete!\n'));
|
|
186
187
|
console.log(chalk.yellow('🔄 Restart Claude Code / Codex / OpenCode (or open a new session) for the changes to take effect.\n'));
|
|
187
|
-
console.log(chalk.gray(
|
|
188
|
-
console.log(chalk.gray('1. cd into your project, then run "borg assimilate --host <host>" to join a cube'));
|
|
189
|
-
console.log(chalk.gray(' (this connects to your local server and launches your agent)'));
|
|
190
|
-
console.log(chalk.gray('2. Use `borg assimilate --host <host> --enroll` from the operator terminal to enroll a new client\n'));
|
|
188
|
+
console.log(chalk.gray(setupNextStepsText()));
|
|
191
189
|
}
|
|
192
190
|
|
|
193
191
|
// Run wizard
|
package/src/tool-manifest.ts
CHANGED
|
@@ -58,10 +58,10 @@ export const TOOL_MANIFEST: ToolManifestEntry[] = [
|
|
|
58
58
|
{
|
|
59
59
|
name: 'borg_assimilate',
|
|
60
60
|
description:
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
'
|
|
61
|
+
"Reconnect this session to the existing drone saved for this worktree. This tool " +
|
|
62
|
+
"never creates drones. Provide the cube's name; on a match it returns the cube " +
|
|
63
|
+
"directive, your role's instructions, and recent activity for that drone. To create " +
|
|
64
|
+
'a drone or switch cubes, run `borg assimilate` in a terminal instead.',
|
|
65
65
|
inputSchema: {
|
|
66
66
|
type: 'object',
|
|
67
67
|
properties: {
|
|
@@ -116,7 +116,7 @@ export const TOOL_MANIFEST: ToolManifestEntry[] = [
|
|
|
116
116
|
{
|
|
117
117
|
name: 'borg_playbook',
|
|
118
118
|
description:
|
|
119
|
-
'Load the full operating-playbook chapter — the detailed disciplines, rationale, and examples behind the
|
|
119
|
+
'Load the full operating-playbook chapter — the detailed disciplines, rationale, and examples behind the abbreviated session instructions (verification discipline v1/v2/v3, concrete source-of-truth surfaces, four-surface propagation). This detail is omitted from the initial context to keep it light; fetch it ONCE per session when doing review/verify-class work. Static text — do NOT re-fetch on every wake.',
|
|
120
120
|
inputSchema: {
|
|
121
121
|
type: 'object',
|
|
122
122
|
properties: {},
|
|
@@ -153,7 +153,7 @@ export const TOOL_MANIFEST: ToolManifestEntry[] = [
|
|
|
153
153
|
name: 'borg_role-rationale',
|
|
154
154
|
description:
|
|
155
155
|
"Fetch an on-demand rationale/case-study section for a role playbook. " +
|
|
156
|
-
"Pass a role name/id and a plain-label section key to read the rationale without expanding every
|
|
156
|
+
"Pass a role name/id and a plain-label section key to read the rationale without expanding every context refresh.",
|
|
157
157
|
inputSchema: {
|
|
158
158
|
type: 'object',
|
|
159
159
|
properties: {
|
|
@@ -249,7 +249,7 @@ export const TOOL_MANIFEST: ToolManifestEntry[] = [
|
|
|
249
249
|
{
|
|
250
250
|
name: 'borg_decide',
|
|
251
251
|
description:
|
|
252
|
-
'Record a RATIFIED cube decision in the durable decision registry
|
|
252
|
+
'Record a RATIFIED cube decision in the durable decision registry so drones cite it by topic instead of restating from memory. Coordinator and Queen roles are workflow-eligible to ratify, but role labels grant no server permission; the selected local client must have a live cube-manage grant. Recording IS the ratification act; a decision is not ratified until it is in the registry. Topic-keyed: recording a new decision on an existing topic supersedes the prior (one active per topic). The decision appears in borg_regen and borg_decisions.',
|
|
253
253
|
inputSchema: {
|
|
254
254
|
type: 'object',
|
|
255
255
|
required: ['topic', 'decision'],
|
|
@@ -272,7 +272,7 @@ export const TOOL_MANIFEST: ToolManifestEntry[] = [
|
|
|
272
272
|
{
|
|
273
273
|
name: 'borg_decisions',
|
|
274
274
|
description:
|
|
275
|
-
'List the active ratified decisions for the cube
|
|
275
|
+
'List the active ratified decisions for the cube — the source of truth to CITE instead of restating a decision from memory. Any member may read. Pass `topic` to fetch one topic\'s active decision; omit for all active decisions.',
|
|
276
276
|
inputSchema: {
|
|
277
277
|
type: 'object',
|
|
278
278
|
properties: {
|
|
@@ -350,7 +350,7 @@ export const TOOL_MANIFEST: ToolManifestEntry[] = [
|
|
|
350
350
|
pattern: '^[a-z0-9-]+$',
|
|
351
351
|
maxLength: 64,
|
|
352
352
|
},
|
|
353
|
-
cube_directive: { type: 'string', description: 'Markdown
|
|
353
|
+
cube_directive: { type: 'string', description: 'Project-specific Markdown shown to every drone when it refreshes cube context.' },
|
|
354
354
|
template: {
|
|
355
355
|
type: 'string',
|
|
356
356
|
description: 'Optional template name to apply after cube creation (e.g. "software-dev"). Roles are merged by name; the default Drone role gets overwritten by the template if a same-named role is in the template.',
|
|
@@ -419,13 +419,14 @@ export const TOOL_MANIFEST: ToolManifestEntry[] = [
|
|
|
419
419
|
},
|
|
420
420
|
{
|
|
421
421
|
name: 'borg_delete-cube',
|
|
422
|
-
description: 'Delete a cube and all its roles, drones, and log entries. Irreversible
|
|
422
|
+
description: 'Delete a cube and all its roles, drones, and log entries. Irreversible; requires the exact cube UUID again after explicit user confirmation.',
|
|
423
423
|
inputSchema: {
|
|
424
424
|
type: 'object',
|
|
425
425
|
properties: {
|
|
426
426
|
cube_id: { type: 'string', description: 'UUID of the cube to delete.' },
|
|
427
|
+
confirm_cube_id: { type: 'string', description: 'Explicit user confirmation: repeat the exact cube UUID to confirm this irreversible deletion.' },
|
|
427
428
|
},
|
|
428
|
-
required: ['cube_id'],
|
|
429
|
+
required: ['cube_id', 'confirm_cube_id'],
|
|
429
430
|
},
|
|
430
431
|
},
|
|
431
432
|
{
|
|
@@ -439,7 +440,7 @@ export const TOOL_MANIFEST: ToolManifestEntry[] = [
|
|
|
439
440
|
short_description: { type: 'string', description: 'One-line summary, shown to every drone in the cube.' },
|
|
440
441
|
detailed_description: { type: 'string', description: 'Full playbook for drones in this role — workflow, conventions, log signals to post.' },
|
|
441
442
|
is_default: { type: 'boolean', description: 'If true, new drones assimilating into this cube are assigned this role. Demotes the previous default.' },
|
|
442
|
-
is_mandatory: { type: 'boolean', description: 'If true, role-less
|
|
443
|
+
is_mandatory: { type: 'boolean', description: 'If true, role-less assimilation prioritizes this unoccupied role before ordinary worker roles. Platform-wide management roles are never auto-assigned; a mandatory human-operator role is selected first until occupied.' },
|
|
443
444
|
is_human_seat: { type: 'boolean', description: 'If true, this role represents the cube\'s human-occupied seat (where the human Queen sits directly). The class-hierarchy guard in reassign-drone allows promotion FROM a human-seat role TO the platform Queen role; promotion from non-human-seat roles is rejected.' },
|
|
444
445
|
can_broadcast: { type: 'boolean', description: 'If true, drones in this role may post broadcast log entries when strict broadcast gating is enabled.' },
|
|
445
446
|
receives_all_direct: { type: 'boolean', description: 'If true, drones in this role can see direct log entries as observer/audit recipients.' },
|
|
@@ -458,7 +459,7 @@ export const TOOL_MANIFEST: ToolManifestEntry[] = [
|
|
|
458
459
|
short_description: { type: 'string', description: 'New short description (optional).' },
|
|
459
460
|
detailed_description: { type: 'string', description: 'New detailed playbook (optional).' },
|
|
460
461
|
is_default: { type: 'boolean', description: 'Set true to make this the cube\'s default role (optional).' },
|
|
461
|
-
is_mandatory: { type: 'boolean', description: 'Set true/false to prioritize this unoccupied
|
|
462
|
+
is_mandatory: { type: 'boolean', description: 'Set true/false to prioritize this unoccupied role during role-less assimilation. Platform-wide management roles are never auto-assigned.' },
|
|
462
463
|
is_human_seat: { type: 'boolean', description: 'Set true/false to mark/unmark this as the cube\'s human-occupied seat (the elevation source for the platform Queen role).' },
|
|
463
464
|
can_broadcast: { type: 'boolean', description: 'Set true/false to allow or deny broadcast log entries when strict broadcast gating is enabled.' },
|
|
464
465
|
receives_all_direct: { type: 'boolean', description: 'Set true/false to grant or remove observer visibility into direct log entries.' },
|