borgmcp 4.1.0 → 4.2.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/dist/direct-log.d.ts +1 -1
- package/dist/direct-log.d.ts.map +1 -1
- package/dist/direct-log.js +18 -2
- package/dist/direct-log.js.map +1 -1
- package/dist/drone-management.d.ts +19 -2
- package/dist/drone-management.d.ts.map +1 -1
- package/dist/drone-management.js +17 -7
- package/dist/drone-management.js.map +1 -1
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +235 -42
- package/dist/index.js.map +1 -1
- package/dist/tool-manifest.d.ts +14 -0
- package/dist/tool-manifest.d.ts.map +1 -1
- package/dist/tool-manifest.js +520 -1
- package/dist/tool-manifest.js.map +1 -1
- package/package.json +1 -1
- package/src/direct-log.ts +17 -2
- package/src/drone-management.ts +35 -9
- package/src/index.ts +240 -42
- package/src/tool-manifest.ts +546 -1
package/src/drone-management.ts
CHANGED
|
@@ -63,10 +63,26 @@ async function requireActiveCube(deps: DroneManagementDeps): Promise<ActiveCube>
|
|
|
63
63
|
return active;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
// gh#492: tool helpers return the mutation receipt data alongside the rendered
|
|
67
|
+
// text so the MCP handler can emit structuredContent from the same source.
|
|
68
|
+
export interface ReassignDroneToolResult {
|
|
69
|
+
text: string;
|
|
70
|
+
drone: { id: string; cube_id: string; role_id: string; label: string };
|
|
71
|
+
roleName: string;
|
|
72
|
+
cubeName: string;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface EvictDroneToolResult {
|
|
76
|
+
text: string;
|
|
77
|
+
droneId: string;
|
|
78
|
+
label: string;
|
|
79
|
+
cubeName: string;
|
|
80
|
+
}
|
|
81
|
+
|
|
66
82
|
export async function runReassignDroneTool(
|
|
67
83
|
input: { droneId: unknown; roleId: unknown },
|
|
68
84
|
deps: DroneManagementDeps = defaultDeps,
|
|
69
|
-
): Promise<
|
|
85
|
+
): Promise<ReassignDroneToolResult> {
|
|
70
86
|
if (typeof input.droneId !== 'string' || input.droneId.length === 0) {
|
|
71
87
|
throw new Error('drone_id is required');
|
|
72
88
|
}
|
|
@@ -113,19 +129,24 @@ export async function runReassignDroneTool(
|
|
|
113
129
|
}
|
|
114
130
|
}
|
|
115
131
|
|
|
116
|
-
return
|
|
117
|
-
|
|
118
|
-
|
|
132
|
+
return {
|
|
133
|
+
text: formatReassignDroneSuccess({
|
|
134
|
+
droneLabel: drone.label,
|
|
135
|
+
cubeName: cube.name,
|
|
136
|
+
roleName: role.name,
|
|
137
|
+
droneId: drone.id,
|
|
138
|
+
roleId: drone.role_id,
|
|
139
|
+
}) + warning,
|
|
140
|
+
drone: { id: drone.id, cube_id: drone.cube_id, role_id: drone.role_id, label: drone.label },
|
|
119
141
|
roleName: role.name,
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
}) + warning;
|
|
142
|
+
cubeName: cube.name,
|
|
143
|
+
};
|
|
123
144
|
}
|
|
124
145
|
|
|
125
146
|
export async function runEvictDroneTool(
|
|
126
147
|
args: Record<string, unknown> | undefined,
|
|
127
148
|
deps: DroneManagementDeps = defaultDeps,
|
|
128
|
-
): Promise<
|
|
149
|
+
): Promise<EvictDroneToolResult> {
|
|
129
150
|
const droneIdInput = typeof args?.drone_id === 'string' ? args.drone_id : undefined;
|
|
130
151
|
const labelInput = typeof args?.label === 'string' ? args.label.trim() : undefined;
|
|
131
152
|
const cubeIdInput = typeof args?.cube_id === 'string' ? args.cube_id : undefined;
|
|
@@ -164,5 +185,10 @@ export async function runEvictDroneTool(
|
|
|
164
185
|
'[LOCAL-MANAGE-COMMIT-UNCONFIRMED] The server returned a successful eviction response for an unexpected drone. The eviction may already be committed. Do not retry blindly; inspect the cube roster first.',
|
|
165
186
|
);
|
|
166
187
|
}
|
|
167
|
-
return
|
|
188
|
+
return {
|
|
189
|
+
text: formatEvictDroneSuccess(priorDrone.label, cube.name),
|
|
190
|
+
droneId: priorDrone.id,
|
|
191
|
+
label: priorDrone.label,
|
|
192
|
+
cubeName: cube.name,
|
|
193
|
+
};
|
|
168
194
|
}
|
package/src/index.ts
CHANGED
|
@@ -253,6 +253,22 @@ export function formatUpdatedRoleResult(role: { name: string; id: string; role_c
|
|
|
253
253
|
return appendServerAdvisory(`Updated role **${role.name}**${tag} (id: ${role.id}).`, advisory);
|
|
254
254
|
}
|
|
255
255
|
|
|
256
|
+
// gh#496: the unread drain runs on every wake, so its structured payload must
|
|
257
|
+
// stay proportional to the entries it returns. Rosters are deliberately NOT
|
|
258
|
+
// included — entries already carry drone_label/role_name, and borg_roster
|
|
259
|
+
// serves identity mapping when a consumer needs it.
|
|
260
|
+
export function buildReadLogStructuredContent(input: {
|
|
261
|
+
entries: unknown[];
|
|
262
|
+
behind_by: unknown;
|
|
263
|
+
has_more: unknown;
|
|
264
|
+
}): { entries: unknown[]; behind_by: number | null; has_more: boolean } {
|
|
265
|
+
return {
|
|
266
|
+
entries: input.entries,
|
|
267
|
+
behind_by: typeof input.behind_by === 'number' ? input.behind_by : null,
|
|
268
|
+
has_more: input.has_more === true,
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
|
|
256
272
|
export function formatPatchedRoleSectionResult(action: 'replace' | 'insert' | 'delete', heading: string, role: { name: string; id: string }, advisory?: unknown): string {
|
|
257
273
|
const verb = action === 'replace' ? 'Replaced' : action === 'insert' ? 'Inserted' : 'Deleted';
|
|
258
274
|
return appendServerAdvisory(`${verb} section **${heading}** in role **${role.name}** (id: ${role.id}).`, advisory);
|
|
@@ -419,8 +435,15 @@ export async function main() {
|
|
|
419
435
|
isError: true,
|
|
420
436
|
};
|
|
421
437
|
}
|
|
438
|
+
const described = {
|
|
439
|
+
name: def.name,
|
|
440
|
+
description: def.description,
|
|
441
|
+
inputSchema: def.inputSchema,
|
|
442
|
+
outputSchema: def.outputSchema ?? null,
|
|
443
|
+
};
|
|
422
444
|
return {
|
|
423
|
-
content: [{ type: 'text', text: JSON.stringify(
|
|
445
|
+
content: [{ type: 'text', text: JSON.stringify(described, null, 2) }],
|
|
446
|
+
structuredContent: described,
|
|
424
447
|
};
|
|
425
448
|
}
|
|
426
449
|
|
|
@@ -471,6 +494,7 @@ export async function main() {
|
|
|
471
494
|
text: 'Not connected to a cube. Use `borg_assimilate cube_name="<name>"` to join one.',
|
|
472
495
|
},
|
|
473
496
|
],
|
|
497
|
+
structuredContent: { connected: false },
|
|
474
498
|
};
|
|
475
499
|
}
|
|
476
500
|
seedDisplayIdentity(active);
|
|
@@ -524,10 +548,12 @@ export async function main() {
|
|
|
524
548
|
|
|
525
549
|
// gh#285: version-mismatch nudge when on-disk package is newer.
|
|
526
550
|
let versionHeader = '';
|
|
551
|
+
let onDiskVersion: string | null = null;
|
|
527
552
|
try {
|
|
528
553
|
const running = getPackageVersion();
|
|
529
554
|
const onDisk = getOnDiskVersion();
|
|
530
555
|
if (running !== 'unknown' && onDisk !== 'unknown' && onDisk !== running) {
|
|
556
|
+
onDiskVersion = onDisk;
|
|
531
557
|
const [rMaj, rMin, rPat] = running.split('.').map(Number);
|
|
532
558
|
const [dMaj, dMin, dPat] = onDisk.split('.').map(Number);
|
|
533
559
|
const onDiskNewer = dMaj > rMaj || (dMaj === rMaj && dMin > rMin) || (dMaj === rMaj && dMin === rMin && dPat > rPat);
|
|
@@ -537,7 +563,21 @@ export async function main() {
|
|
|
537
563
|
}
|
|
538
564
|
} catch { /* never break regen */ }
|
|
539
565
|
|
|
540
|
-
return {
|
|
566
|
+
return {
|
|
567
|
+
content: [{ type: 'text', text: versionHeader + prefix + formatRegenMarkdown(displayedResult, { mode }) }],
|
|
568
|
+
structuredContent: {
|
|
569
|
+
connected: true,
|
|
570
|
+
mode,
|
|
571
|
+
cube: displayedResult.cube,
|
|
572
|
+
drone: displayedResult.drone,
|
|
573
|
+
role: displayedResult.role,
|
|
574
|
+
behind_by: typeof displayedResult.behind_by === 'number' ? displayedResult.behind_by : null,
|
|
575
|
+
decision_topics: (displayedResult.decisions ?? []).map((d: any) => d.topic),
|
|
576
|
+
running_version: getPackageVersion(),
|
|
577
|
+
on_disk_version: onDiskVersion,
|
|
578
|
+
wake_path_healthy: inboxMonitorHealthy,
|
|
579
|
+
},
|
|
580
|
+
};
|
|
541
581
|
}
|
|
542
582
|
|
|
543
583
|
case 'borg_assimilate': {
|
|
@@ -583,6 +623,11 @@ export async function main() {
|
|
|
583
623
|
].join('\n');
|
|
584
624
|
return {
|
|
585
625
|
content: [{ type: 'text', text: header + formatRegenMarkdown(displayedResult, { mode: 'full' }) }],
|
|
626
|
+
structuredContent: {
|
|
627
|
+
reattached: true,
|
|
628
|
+
cube_name: displayIdentity.cubeName,
|
|
629
|
+
drone_label: displayIdentity.droneLabel,
|
|
630
|
+
},
|
|
586
631
|
};
|
|
587
632
|
} catch (err: any) {
|
|
588
633
|
markDisplayIdentityReadFailed(active!);
|
|
@@ -592,7 +637,10 @@ export async function main() {
|
|
|
592
637
|
}
|
|
593
638
|
|
|
594
639
|
case 'borg_version': {
|
|
595
|
-
return {
|
|
640
|
+
return {
|
|
641
|
+
content: [{ type: 'text', text: `borgmcp ${getPackageVersion()}` }],
|
|
642
|
+
structuredContent: { version: getPackageVersion() },
|
|
643
|
+
};
|
|
596
644
|
}
|
|
597
645
|
|
|
598
646
|
case 'borg_playbook': {
|
|
@@ -615,7 +663,14 @@ export async function main() {
|
|
|
615
663
|
: topic
|
|
616
664
|
? `No exact match for "${topic}". Full Borg MCP docs index — WebFetch the URL you need:`
|
|
617
665
|
: `Borg MCP docs index — WebFetch the URL of the section you need:`;
|
|
618
|
-
return {
|
|
666
|
+
return {
|
|
667
|
+
content: [{ type: 'text', text: `${header}\n\n${formatDocsIndex(sections)}` }],
|
|
668
|
+
structuredContent: {
|
|
669
|
+
topic: topic || null,
|
|
670
|
+
matched: matched.length > 0,
|
|
671
|
+
sections: sections.map((s) => ({ slug: s.slug, title: s.title, url: s.url, summary: s.summary })),
|
|
672
|
+
},
|
|
673
|
+
};
|
|
619
674
|
}
|
|
620
675
|
|
|
621
676
|
case 'borg_whoami': {
|
|
@@ -644,7 +699,10 @@ export async function main() {
|
|
|
644
699
|
// The invocation-local server truth remains authoritative even if
|
|
645
700
|
// the display-only persistence refresh cannot be written.
|
|
646
701
|
}
|
|
647
|
-
return {
|
|
702
|
+
return {
|
|
703
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
704
|
+
structuredContent: { ...result },
|
|
705
|
+
};
|
|
648
706
|
}
|
|
649
707
|
|
|
650
708
|
case 'borg_cube': {
|
|
@@ -697,7 +755,10 @@ export async function main() {
|
|
|
697
755
|
}
|
|
698
756
|
lines.push('');
|
|
699
757
|
lines.push(getDronePlaybook());
|
|
700
|
-
return {
|
|
758
|
+
return {
|
|
759
|
+
content: [{ type: 'text', text: lines.join('\n') }],
|
|
760
|
+
structuredContent: { cube, roles },
|
|
761
|
+
};
|
|
701
762
|
}
|
|
702
763
|
|
|
703
764
|
case 'borg_role': {
|
|
@@ -718,7 +779,7 @@ export async function main() {
|
|
|
718
779
|
``,
|
|
719
780
|
role.detailed_description || '_(no detailed description set)_',
|
|
720
781
|
].join('\n');
|
|
721
|
-
return { content: [{ type: 'text', text }] };
|
|
782
|
+
return { content: [{ type: 'text', text }], structuredContent: { role } };
|
|
722
783
|
}
|
|
723
784
|
const { role } = await getRoleInfo(
|
|
724
785
|
active.sessionToken,
|
|
@@ -730,7 +791,7 @@ export async function main() {
|
|
|
730
791
|
``,
|
|
731
792
|
role.detailed_description || '_(no detailed description set)_',
|
|
732
793
|
].join('\n');
|
|
733
|
-
return { content: [{ type: 'text', text }] };
|
|
794
|
+
return { content: [{ type: 'text', text }], structuredContent: { role } };
|
|
734
795
|
}
|
|
735
796
|
|
|
736
797
|
case 'borg_role-rationale': {
|
|
@@ -749,7 +810,10 @@ export async function main() {
|
|
|
749
810
|
'',
|
|
750
811
|
result.body || '_(empty)_',
|
|
751
812
|
].join('\n');
|
|
752
|
-
return {
|
|
813
|
+
return {
|
|
814
|
+
content: [{ type: 'text', text }],
|
|
815
|
+
structuredContent: { role: result.role, section: result.section, body: result.body },
|
|
816
|
+
};
|
|
753
817
|
}
|
|
754
818
|
|
|
755
819
|
case 'borg_roster': {
|
|
@@ -763,7 +827,10 @@ export async function main() {
|
|
|
763
827
|
resolvedSince: resolvedSince ?? null,
|
|
764
828
|
humanAgo,
|
|
765
829
|
});
|
|
766
|
-
return {
|
|
830
|
+
return {
|
|
831
|
+
content: [{ type: 'text', text }],
|
|
832
|
+
structuredContent: { cube_name: active.name, drones, roles, since: resolvedSince ?? null },
|
|
833
|
+
};
|
|
767
834
|
}
|
|
768
835
|
|
|
769
836
|
case 'borg_stream-status': {
|
|
@@ -803,7 +870,18 @@ export async function main() {
|
|
|
803
870
|
cubeName: active?.name ?? null,
|
|
804
871
|
humanAgo,
|
|
805
872
|
});
|
|
806
|
-
return {
|
|
873
|
+
return {
|
|
874
|
+
content: [{ type: 'text', text: silentInertWarning + text }],
|
|
875
|
+
structuredContent: {
|
|
876
|
+
status,
|
|
877
|
+
wake_path: wakePath,
|
|
878
|
+
inbox_monitor_healthy: inboxMonitorHealthy,
|
|
879
|
+
inbox_path: inboxPath,
|
|
880
|
+
monitor_state_root: monitorStateRoot,
|
|
881
|
+
drone_label: active?.droneLabel ?? null,
|
|
882
|
+
cube_name: active?.name ?? null,
|
|
883
|
+
},
|
|
884
|
+
};
|
|
807
885
|
}
|
|
808
886
|
|
|
809
887
|
case 'borg_read-log': {
|
|
@@ -849,7 +927,10 @@ export async function main() {
|
|
|
849
927
|
`⚠ behind_by: ${behind_by} more unread ${behind_by === 1 ? 'entry' : 'entries'} addressed to you — call \`borg_read-log unread_only=true\` again until behind_by=0 so you don't skip messages.`
|
|
850
928
|
);
|
|
851
929
|
}
|
|
852
|
-
return {
|
|
930
|
+
return {
|
|
931
|
+
content: [{ type: 'text', text: lines.join('\n') }],
|
|
932
|
+
structuredContent: buildReadLogStructuredContent({ entries, behind_by, has_more }),
|
|
933
|
+
};
|
|
853
934
|
}
|
|
854
935
|
|
|
855
936
|
case 'borg_read-entry': {
|
|
@@ -867,19 +948,28 @@ export async function main() {
|
|
|
867
948
|
'',
|
|
868
949
|
formatLogEntryMarkdown(entry, droneById, roleById),
|
|
869
950
|
].join('\n');
|
|
870
|
-
return {
|
|
951
|
+
return {
|
|
952
|
+
content: [{ type: 'text', text }],
|
|
953
|
+
structuredContent: { entry, drones, roles },
|
|
954
|
+
};
|
|
871
955
|
}
|
|
872
956
|
|
|
873
957
|
case 'borg_put-document': {
|
|
874
958
|
const active = await requireActiveCube();
|
|
875
959
|
const result = await putDocument(active.sessionToken, active.apiUrl, args ?? {}, active.serverTrustIdentity);
|
|
876
|
-
return {
|
|
960
|
+
return {
|
|
961
|
+
content: [{ type: 'text', text: `Created cube document.\n\n${formatDocument(result.document)}` }],
|
|
962
|
+
structuredContent: { document: result.document },
|
|
963
|
+
};
|
|
877
964
|
}
|
|
878
965
|
|
|
879
966
|
case 'borg_get-document': {
|
|
880
967
|
const active = await requireActiveCube();
|
|
881
968
|
const result = await getDocument(active.sessionToken, active.apiUrl, args ?? {}, active.serverTrustIdentity);
|
|
882
|
-
return {
|
|
969
|
+
return {
|
|
970
|
+
content: [{ type: 'text', text: formatDocument(result.document) }],
|
|
971
|
+
structuredContent: { document: result.document },
|
|
972
|
+
};
|
|
883
973
|
}
|
|
884
974
|
|
|
885
975
|
case 'borg_list-documents': {
|
|
@@ -888,13 +978,19 @@ export async function main() {
|
|
|
888
978
|
const text = result.documents.length === 0
|
|
889
979
|
? `No active or superseded documents in cube "${active.name}".`
|
|
890
980
|
: result.documents.map(formatDocumentMetadata).join('\n\n');
|
|
891
|
-
return {
|
|
981
|
+
return {
|
|
982
|
+
content: [{ type: 'text', text }],
|
|
983
|
+
structuredContent: { documents: result.documents },
|
|
984
|
+
};
|
|
892
985
|
}
|
|
893
986
|
|
|
894
987
|
case 'borg_remove-document': {
|
|
895
988
|
const active = await requireActiveCube();
|
|
896
989
|
const result = await removeDocument(active.sessionToken, active.apiUrl, args ?? {}, active.serverTrustIdentity);
|
|
897
|
-
return {
|
|
990
|
+
return {
|
|
991
|
+
content: [{ type: 'text', text: `Removed cube document.\n\n${formatDocumentMetadata(result.document)}` }],
|
|
992
|
+
structuredContent: { document: result.document },
|
|
993
|
+
};
|
|
898
994
|
}
|
|
899
995
|
|
|
900
996
|
case 'borg_log': {
|
|
@@ -918,6 +1014,13 @@ export async function main() {
|
|
|
918
1014
|
text: `Suppressed duplicate ${decision.signal?.toUpperCase()} lifecycle log for ${displayIdentity.droneLabel}; recent cube log already contains this signal.`,
|
|
919
1015
|
},
|
|
920
1016
|
],
|
|
1017
|
+
structuredContent: {
|
|
1018
|
+
suppressed: true,
|
|
1019
|
+
entry: null,
|
|
1020
|
+
recipients: [],
|
|
1021
|
+
unreachable_recipients: [],
|
|
1022
|
+
advisory: null,
|
|
1023
|
+
},
|
|
921
1024
|
};
|
|
922
1025
|
}
|
|
923
1026
|
}
|
|
@@ -962,7 +1065,16 @@ export async function main() {
|
|
|
962
1065
|
? `\nAdvisory: this message exceeded ${result.advisory.threshold_bytes} UTF-8 bytes. Store durable detail with borg_put-document, then cite its full id in borg_log.documents with an explicit borg_log.to audience.`
|
|
963
1066
|
: '';
|
|
964
1067
|
const text = `Logged to cube "${displayIdentity.cubeName}" as ${displayIdentity.droneLabel}. (entry id: ${result.entry.id})${routed}${unreachable}${citations}${advisory}`;
|
|
965
|
-
return {
|
|
1068
|
+
return {
|
|
1069
|
+
content: [{ type: 'text', text }],
|
|
1070
|
+
structuredContent: {
|
|
1071
|
+
suppressed: false,
|
|
1072
|
+
entry: result.entry,
|
|
1073
|
+
recipients: routedRecipients,
|
|
1074
|
+
unreachable_recipients: result.unreachableRecipients ?? [],
|
|
1075
|
+
advisory: result.advisory ?? null,
|
|
1076
|
+
},
|
|
1077
|
+
};
|
|
966
1078
|
}
|
|
967
1079
|
|
|
968
1080
|
case 'borg_ack': {
|
|
@@ -992,6 +1104,7 @@ export async function main() {
|
|
|
992
1104
|
: `Acked entry ${entryId} in cube "${active.name}".`,
|
|
993
1105
|
},
|
|
994
1106
|
],
|
|
1107
|
+
structuredContent: { entry_id: entryId, kind, cube_name: active.name },
|
|
995
1108
|
};
|
|
996
1109
|
}
|
|
997
1110
|
|
|
@@ -1003,7 +1116,10 @@ export async function main() {
|
|
|
1003
1116
|
args ?? {},
|
|
1004
1117
|
active.serverTrustIdentity,
|
|
1005
1118
|
);
|
|
1006
|
-
return {
|
|
1119
|
+
return {
|
|
1120
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
1121
|
+
structuredContent: { ...result },
|
|
1122
|
+
};
|
|
1007
1123
|
}
|
|
1008
1124
|
|
|
1009
1125
|
case 'borg_decide': {
|
|
@@ -1031,6 +1147,7 @@ export async function main() {
|
|
|
1031
1147
|
text: `Recorded ratified decision on "${topic}" in cube "${active.name}"${superseded}. Cite it via borg_decisions; it surfaces in borg_regen.`,
|
|
1032
1148
|
},
|
|
1033
1149
|
],
|
|
1150
|
+
structuredContent: { decision: row, superseded: Boolean(row?.supersedes), cube_name: active.name },
|
|
1034
1151
|
};
|
|
1035
1152
|
}
|
|
1036
1153
|
|
|
@@ -1051,7 +1168,10 @@ export async function main() {
|
|
|
1051
1168
|
: decisions
|
|
1052
1169
|
.map((d: any) => `**${d.topic}:** ${d.decision}${d.rationale ? ` — ${d.rationale}` : ''}`)
|
|
1053
1170
|
.join('\n');
|
|
1054
|
-
return {
|
|
1171
|
+
return {
|
|
1172
|
+
content: [{ type: 'text', text }],
|
|
1173
|
+
structuredContent: { decisions },
|
|
1174
|
+
};
|
|
1055
1175
|
}
|
|
1056
1176
|
|
|
1057
1177
|
case 'borg_remove-decision': {
|
|
@@ -1073,18 +1193,25 @@ export async function main() {
|
|
|
1073
1193
|
type: 'text',
|
|
1074
1194
|
text: `Removed the active ratified decision on "${decision.topic}" from cube "${active.name}".`,
|
|
1075
1195
|
}],
|
|
1196
|
+
structuredContent: { decision, cube_name: active.name },
|
|
1076
1197
|
};
|
|
1077
1198
|
}
|
|
1078
1199
|
|
|
1079
1200
|
case 'borg_list-cubes': {
|
|
1080
1201
|
const { cubes } = await listCubes();
|
|
1081
1202
|
if (!cubes.length) {
|
|
1082
|
-
return {
|
|
1203
|
+
return {
|
|
1204
|
+
content: [{ type: 'text', text: 'No cubes yet. Use borg_create-cube to make your first one.' }],
|
|
1205
|
+
structuredContent: { cubes: [] },
|
|
1206
|
+
};
|
|
1083
1207
|
}
|
|
1084
1208
|
const lines = cubes.map((c: any) =>
|
|
1085
1209
|
`- **${c.name}** (id: ${c.id})\n ${(c.cube_directive || '_(no directive set)_').split('\n')[0].slice(0, 120)}`
|
|
1086
1210
|
);
|
|
1087
|
-
return {
|
|
1211
|
+
return {
|
|
1212
|
+
content: [{ type: 'text', text: `Your cubes (${cubes.length}):\n\n${lines.join('\n\n')}` }],
|
|
1213
|
+
structuredContent: { cubes },
|
|
1214
|
+
};
|
|
1088
1215
|
}
|
|
1089
1216
|
|
|
1090
1217
|
case 'borg_create-cube': {
|
|
@@ -1126,10 +1253,21 @@ export async function main() {
|
|
|
1126
1253
|
? ' Template cube directive applied (operator passed empty).'
|
|
1127
1254
|
: '';
|
|
1128
1255
|
const text = `Created cube **${cube.name}** (id: ${cube.id}) with template **${templateName}** applied — ${summary.created} role(s) created, ${summary.updated} updated.${cubeDirectiveNote} Use borg_assimilate ${cube.name} to join as a drone.`;
|
|
1129
|
-
return {
|
|
1256
|
+
return {
|
|
1257
|
+
content: [{ type: 'text', text }],
|
|
1258
|
+
structuredContent: {
|
|
1259
|
+
cube,
|
|
1260
|
+
template: templateName,
|
|
1261
|
+
roles_created: summary.created,
|
|
1262
|
+
roles_updated: summary.updated,
|
|
1263
|
+
},
|
|
1264
|
+
};
|
|
1130
1265
|
}
|
|
1131
1266
|
const text = `Created cube **${cube.name}** (id: ${cube.id}). A default "Drone" role was seeded — rename or replace it via borg_update-role / borg_create-role / borg_delete-role. Use borg_assimilate ${cube.name} to join as a drone.`;
|
|
1132
|
-
return {
|
|
1267
|
+
return {
|
|
1268
|
+
content: [{ type: 'text', text }],
|
|
1269
|
+
structuredContent: { cube, template: null, roles_created: null, roles_updated: null },
|
|
1270
|
+
};
|
|
1133
1271
|
}
|
|
1134
1272
|
|
|
1135
1273
|
case 'borg_update-cube': {
|
|
@@ -1141,7 +1279,10 @@ export async function main() {
|
|
|
1141
1279
|
if (Array.isArray(args?.message_taxonomy)) updates.message_taxonomy = args.message_taxonomy as MessageTaxonomy;
|
|
1142
1280
|
if (Object.keys(updates).length === 0) throw new Error('Pass at least one of: cube_directive, message_taxonomy.');
|
|
1143
1281
|
const { cube, advisory } = await updateCube(cubeId, updates);
|
|
1144
|
-
return {
|
|
1282
|
+
return {
|
|
1283
|
+
content: [{ type: 'text', text: formatUpdatedCubeResult(cube, advisory) }],
|
|
1284
|
+
structuredContent: { cube, advisory: advisory ?? null },
|
|
1285
|
+
};
|
|
1145
1286
|
}
|
|
1146
1287
|
|
|
1147
1288
|
case 'borg_patch-taxonomy-class': {
|
|
@@ -1167,7 +1308,10 @@ export async function main() {
|
|
|
1167
1308
|
label = String(classDef.class ?? '');
|
|
1168
1309
|
}
|
|
1169
1310
|
const verb = action === 'add' ? 'Added' : action === 'replace' ? 'Replaced' : 'Removed';
|
|
1170
|
-
return {
|
|
1311
|
+
return {
|
|
1312
|
+
content: [{ type: 'text', text: `${verb} taxonomy class **${label}** in cube **${cube.name}** (id: ${cube.id}).` }],
|
|
1313
|
+
structuredContent: { action, class: label, cube },
|
|
1314
|
+
};
|
|
1171
1315
|
}
|
|
1172
1316
|
|
|
1173
1317
|
case 'borg_delete-cube': {
|
|
@@ -1178,7 +1322,10 @@ export async function main() {
|
|
|
1178
1322
|
throw new CubeDeletionConfirmationError(cubeId, confirmCubeId);
|
|
1179
1323
|
}
|
|
1180
1324
|
await deleteCube(cubeId, confirmCubeId);
|
|
1181
|
-
return {
|
|
1325
|
+
return {
|
|
1326
|
+
content: [{ type: 'text', text: `Deleted cube ${cubeId} (and all its roles, drones, log entries).` }],
|
|
1327
|
+
structuredContent: { cube_id: cubeId, deleted: true },
|
|
1328
|
+
};
|
|
1182
1329
|
}
|
|
1183
1330
|
|
|
1184
1331
|
case 'borg_create-role': {
|
|
@@ -1213,7 +1360,10 @@ export async function main() {
|
|
|
1213
1360
|
role.is_mandatory ? 'mandatory' : null,
|
|
1214
1361
|
].filter(Boolean).join(', ');
|
|
1215
1362
|
const tag = tags ? ` (${tags})` : '';
|
|
1216
|
-
return {
|
|
1363
|
+
return {
|
|
1364
|
+
content: [{ type: 'text', text: `Created role **${role.name}**${tag} (id: ${role.id}) in cube ${cubeId}.` }],
|
|
1365
|
+
structuredContent: { role, cube_id: cubeId },
|
|
1366
|
+
};
|
|
1217
1367
|
}
|
|
1218
1368
|
|
|
1219
1369
|
case 'borg_update-role': {
|
|
@@ -1231,7 +1381,10 @@ export async function main() {
|
|
|
1231
1381
|
if (typeof args?.default_model === 'string') updates.default_model = args.default_model as string;
|
|
1232
1382
|
if (Object.keys(updates).length === 0) throw new Error('Pass at least one of: name, short_description, detailed_description, is_default, is_mandatory, is_human_seat, can_broadcast, receives_all_direct.');
|
|
1233
1383
|
const { role, advisory } = await updateRole(roleId, updates);
|
|
1234
|
-
return {
|
|
1384
|
+
return {
|
|
1385
|
+
content: [{ type: 'text', text: formatUpdatedRoleResult(role, advisory) }],
|
|
1386
|
+
structuredContent: { role, advisory: advisory ?? null },
|
|
1387
|
+
};
|
|
1235
1388
|
}
|
|
1236
1389
|
|
|
1237
1390
|
case 'borg_patch-role-section': {
|
|
@@ -1259,28 +1412,47 @@ export async function main() {
|
|
|
1259
1412
|
({ role, advisory } = await patchRoleSection(roleId, { action, heading, body }));
|
|
1260
1413
|
}
|
|
1261
1414
|
}
|
|
1262
|
-
return {
|
|
1415
|
+
return {
|
|
1416
|
+
content: [{ type: 'text', text: formatPatchedRoleSectionResult(action, heading, role, advisory) }],
|
|
1417
|
+
structuredContent: { action, heading, role, advisory: advisory ?? null },
|
|
1418
|
+
};
|
|
1263
1419
|
}
|
|
1264
1420
|
|
|
1265
1421
|
case 'borg_delete-role': {
|
|
1266
1422
|
const roleId = args?.role_id as string;
|
|
1267
1423
|
if (!roleId) throw new Error('role_id is required');
|
|
1268
1424
|
await deleteRole(roleId);
|
|
1269
|
-
return {
|
|
1425
|
+
return {
|
|
1426
|
+
content: [{ type: 'text', text: `Deleted role ${roleId}.` }],
|
|
1427
|
+
structuredContent: { role_id: roleId, deleted: true },
|
|
1428
|
+
};
|
|
1270
1429
|
}
|
|
1271
1430
|
|
|
1272
1431
|
case 'borg_reassign-drone': {
|
|
1432
|
+
const reassigned = await runReassignDroneTool({
|
|
1433
|
+
droneId: args?.drone_id,
|
|
1434
|
+
roleId: args?.role_id,
|
|
1435
|
+
});
|
|
1273
1436
|
return {
|
|
1274
|
-
content: [{ type: 'text', text:
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1437
|
+
content: [{ type: 'text', text: reassigned.text }],
|
|
1438
|
+
structuredContent: {
|
|
1439
|
+
drone: reassigned.drone,
|
|
1440
|
+
role_name: reassigned.roleName,
|
|
1441
|
+
cube_name: reassigned.cubeName,
|
|
1442
|
+
},
|
|
1278
1443
|
};
|
|
1279
1444
|
}
|
|
1280
1445
|
|
|
1281
1446
|
case 'borg_evict-drone': {
|
|
1447
|
+
const evicted = await runEvictDroneTool(args);
|
|
1282
1448
|
return {
|
|
1283
|
-
content: [{ type: 'text', text:
|
|
1449
|
+
content: [{ type: 'text', text: evicted.text }],
|
|
1450
|
+
structuredContent: {
|
|
1451
|
+
drone_id: evicted.droneId,
|
|
1452
|
+
label: evicted.label,
|
|
1453
|
+
cube_name: evicted.cubeName,
|
|
1454
|
+
evicted: true,
|
|
1455
|
+
},
|
|
1284
1456
|
};
|
|
1285
1457
|
}
|
|
1286
1458
|
|
|
@@ -1289,7 +1461,10 @@ export async function main() {
|
|
|
1289
1461
|
if (!cubeId) throw new Error('cube_id is required');
|
|
1290
1462
|
const { drones, roles } = await getCube(cubeId);
|
|
1291
1463
|
if (!drones.length) {
|
|
1292
|
-
return {
|
|
1464
|
+
return {
|
|
1465
|
+
content: [{ type: 'text', text: 'No drones in this cube yet.' }],
|
|
1466
|
+
structuredContent: { cube_id: cubeId, drones: [], roles },
|
|
1467
|
+
};
|
|
1293
1468
|
}
|
|
1294
1469
|
const rolesById = new Map(roles.map((r: any) => [r.id, r]));
|
|
1295
1470
|
const lines = drones.map((d: any) => {
|
|
@@ -1303,7 +1478,10 @@ export async function main() {
|
|
|
1303
1478
|
...renderRuntimeMetadataLines(d),
|
|
1304
1479
|
].join('\n');
|
|
1305
1480
|
});
|
|
1306
|
-
return {
|
|
1481
|
+
return {
|
|
1482
|
+
content: [{ type: 'text', text: `Drones in cube ${cubeId} (${drones.length}):\n\n_${RUNTIME_METADATA_ADVISORY}_\n\n${lines.join('\n')}` }],
|
|
1483
|
+
structuredContent: { cube_id: cubeId, drones, roles },
|
|
1484
|
+
};
|
|
1307
1485
|
}
|
|
1308
1486
|
|
|
1309
1487
|
case 'borg_list-roles': {
|
|
@@ -1318,7 +1496,10 @@ export async function main() {
|
|
|
1318
1496
|
const cubeId = args?.cube_id as string;
|
|
1319
1497
|
if (!cubeId) throw new Error('cube_id is required');
|
|
1320
1498
|
const roles = await listRoles(cubeId);
|
|
1321
|
-
return {
|
|
1499
|
+
return {
|
|
1500
|
+
content: [{ type: 'text', text: renderRoleList(roles, cubeId) }],
|
|
1501
|
+
structuredContent: { cube_id: cubeId, roles },
|
|
1502
|
+
};
|
|
1322
1503
|
}
|
|
1323
1504
|
|
|
1324
1505
|
case 'borg_list-templates': {
|
|
@@ -1327,7 +1508,12 @@ export async function main() {
|
|
|
1327
1508
|
const t = getTemplate(n)!;
|
|
1328
1509
|
return `- **${n}**: ${t.description}`;
|
|
1329
1510
|
});
|
|
1330
|
-
return {
|
|
1511
|
+
return {
|
|
1512
|
+
content: [{ type: 'text', text: `Available templates:\n\n${lines.join('\n')}` }],
|
|
1513
|
+
structuredContent: {
|
|
1514
|
+
templates: names.map((n) => ({ name: n, description: getTemplate(n)!.description })),
|
|
1515
|
+
},
|
|
1516
|
+
};
|
|
1331
1517
|
}
|
|
1332
1518
|
|
|
1333
1519
|
case 'borg_sync-roles': {
|
|
@@ -1344,7 +1530,10 @@ export async function main() {
|
|
|
1344
1530
|
: undefined;
|
|
1345
1531
|
if (!cubeId) throw new Error('cube_id is required');
|
|
1346
1532
|
const result = await syncRoles(cubeId, templateName, apply, decisions);
|
|
1347
|
-
return {
|
|
1533
|
+
return {
|
|
1534
|
+
content: [{ type: 'text', text: renderSyncRolesResult(result, templateName) }],
|
|
1535
|
+
structuredContent: { cube_id: cubeId, template: templateName, apply, result },
|
|
1536
|
+
};
|
|
1348
1537
|
}
|
|
1349
1538
|
|
|
1350
1539
|
case 'borg_apply-template': {
|
|
@@ -1364,7 +1553,16 @@ export async function main() {
|
|
|
1364
1553
|
});
|
|
1365
1554
|
const { summary, cubeDirectiveNote } = await runApplyTemplateTool(cubeId, template, authority);
|
|
1366
1555
|
|
|
1367
|
-
return {
|
|
1556
|
+
return {
|
|
1557
|
+
content: [{ type: 'text', text: `Applied template **${templateName}** to cube ${cubeId} — ${summary.created} role(s) created, ${summary.updated} updated.${cubeDirectiveNote}` }],
|
|
1558
|
+
structuredContent: {
|
|
1559
|
+
cube_id: cubeId,
|
|
1560
|
+
template: templateName,
|
|
1561
|
+
roles_created: summary.created,
|
|
1562
|
+
roles_updated: summary.updated,
|
|
1563
|
+
cube_directive_applied: cubeDirectiveNote !== '',
|
|
1564
|
+
},
|
|
1565
|
+
};
|
|
1368
1566
|
}
|
|
1369
1567
|
|
|
1370
1568
|
default:
|