borgmcp 2.0.8 → 2.0.10
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 +2 -2
- package/dist/agent-runtime.d.ts +2 -0
- package/dist/agent-runtime.d.ts.map +1 -1
- package/dist/agent-runtime.js +5 -1
- package/dist/agent-runtime.js.map +1 -1
- package/dist/assimilate-cmd.d.ts +2 -0
- package/dist/assimilate-cmd.d.ts.map +1 -1
- package/dist/assimilate-cmd.js +2 -0
- package/dist/assimilate-cmd.js.map +1 -1
- package/dist/assimilate-deps.d.ts.map +1 -1
- package/dist/assimilate-deps.js +6 -0
- package/dist/assimilate-deps.js.map +1 -1
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +38 -23
- package/dist/index.js.map +1 -1
- package/dist/regen-format.d.ts.map +1 -1
- package/dist/regen-format.js +6 -4
- package/dist/regen-format.js.map +1 -1
- package/dist/regen.js +2 -0
- package/dist/regen.js.map +1 -1
- package/dist/remote-client.d.ts +24 -9
- package/dist/remote-client.d.ts.map +1 -1
- package/dist/remote-client.js +329 -49
- package/dist/remote-client.js.map +1 -1
- package/dist/roster-render.d.ts +11 -0
- package/dist/roster-render.d.ts.map +1 -1
- package/dist/roster-render.js +41 -8
- package/dist/roster-render.js.map +1 -1
- package/dist/runtime-metadata.d.ts +13 -0
- package/dist/runtime-metadata.d.ts.map +1 -0
- package/dist/runtime-metadata.js +52 -0
- package/dist/runtime-metadata.js.map +1 -0
- package/dist/server-handshake.d.ts +2 -1
- package/dist/server-handshake.d.ts.map +1 -1
- package/dist/server-handshake.js +3 -0
- package/dist/server-handshake.js.map +1 -1
- package/dist/sync-roles-render.d.ts +2 -0
- package/dist/sync-roles-render.d.ts.map +1 -1
- package/dist/sync-roles-render.js +26 -7
- package/dist/sync-roles-render.js.map +1 -1
- package/dist/working-repo.d.ts +5 -7
- package/dist/working-repo.d.ts.map +1 -1
- package/dist/working-repo.js +30 -40
- package/dist/working-repo.js.map +1 -1
- package/docs/EXTRACTION_PROVENANCE.md +8 -7
- package/docs/LOCAL_SERVER.md +1 -1
- package/docs/RELEASING.md +19 -1
- package/package.json +2 -2
- package/src/agent-runtime.ts +8 -1
- package/src/assimilate-cmd.ts +3 -1
- package/src/assimilate-deps.ts +10 -4
- package/src/index.ts +58 -27
- package/src/regen-format.ts +12 -5
- package/src/regen.ts +2 -0
- package/src/remote-client.ts +382 -43
- package/src/roster-render.ts +58 -8
- package/src/runtime-metadata.ts +67 -0
- package/src/server-handshake.ts +7 -2
- package/src/sync-roles-render.ts +24 -7
- package/src/working-repo.ts +30 -41
|
@@ -9,11 +9,30 @@
|
|
|
9
9
|
*
|
|
10
10
|
* The shape mirrors the worker's `NonClobberSyncResult`.
|
|
11
11
|
*/
|
|
12
|
+
const BIDI_CONTROL_RE = /\p{Bidi_Control}/u;
|
|
13
|
+
/** Escape cube-controlled text before it reaches Markdown or a terminal. */
|
|
14
|
+
export function escapeSyncDisplay(value) {
|
|
15
|
+
return [...value].map((char) => {
|
|
16
|
+
const code = char.codePointAt(0);
|
|
17
|
+
if (code === 0x0a)
|
|
18
|
+
return '⏎';
|
|
19
|
+
if (code < 0x20 || (code >= 0x7f && code <= 0x9f))
|
|
20
|
+
return `\\u{${code.toString(16)}}`;
|
|
21
|
+
if (BIDI_CONTROL_RE.test(char) || code === 0x2028 || code === 0x2029) {
|
|
22
|
+
return `\\u{${code.toString(16)}}`;
|
|
23
|
+
}
|
|
24
|
+
if (char === '`')
|
|
25
|
+
return '\\u{60}';
|
|
26
|
+
if ('\\*_[]()<>&#|~'.includes(char))
|
|
27
|
+
return `\\${char}`;
|
|
28
|
+
return char;
|
|
29
|
+
}).join('');
|
|
30
|
+
}
|
|
12
31
|
/** Truncate long fragment bodies for at-a-glance diffs. */
|
|
13
32
|
function trunc(s, n = 200) {
|
|
14
33
|
if (s == null)
|
|
15
34
|
return '(absent)';
|
|
16
|
-
const flat = s
|
|
35
|
+
const flat = escapeSyncDisplay(s);
|
|
17
36
|
return flat.length > n ? flat.slice(0, n) + '…' : flat;
|
|
18
37
|
}
|
|
19
38
|
/**
|
|
@@ -45,7 +64,7 @@ export function renderSyncRolesResult(result, templateName) {
|
|
|
45
64
|
const mode = result.dryRun
|
|
46
65
|
? '**DRY RUN** (review conflicts below; re-run with `apply: true` + a `decisions` map to commit)'
|
|
47
66
|
: '**APPLIED**';
|
|
48
|
-
const lines = [`## borg_sync-roles — ${mode}`, `Template: ${templateName}`, ''];
|
|
67
|
+
const lines = [`## borg_sync-roles — ${mode}`, `Template: ${escapeSyncDisplay(templateName)}`, ''];
|
|
49
68
|
// Gather all fragments across roles + taxonomy for tallying.
|
|
50
69
|
const allFragments = [
|
|
51
70
|
...result.roles.flatMap((r) => r.fragments),
|
|
@@ -74,7 +93,7 @@ export function renderSyncRolesResult(result, templateName) {
|
|
|
74
93
|
: applied
|
|
75
94
|
? '✓ accepted — template version applied'
|
|
76
95
|
: '↩ kept your version';
|
|
77
|
-
lines.push(`- **${f.label}** \`${f.key}\` ${status}`);
|
|
96
|
+
lines.push(`- **${escapeSyncDisplay(f.label)}** \`${escapeSyncDisplay(f.key)}\` ${status}`);
|
|
78
97
|
lines.push(` - cube (current): "${trunc(f.cubeValue)}"`);
|
|
79
98
|
lines.push(` - template (new): "${trunc(f.templateValue)}"`);
|
|
80
99
|
}
|
|
@@ -87,7 +106,7 @@ export function renderSyncRolesResult(result, templateName) {
|
|
|
87
106
|
lines.push('These keys in your `decisions` map did not correspond to any classified conflict this run ' +
|
|
88
107
|
'(typo or stale key) — their intended accept had NO effect. Check the exact keys against the conflicts above:');
|
|
89
108
|
for (const k of unmatched) {
|
|
90
|
-
lines.push(`- \`${k}\``);
|
|
109
|
+
lines.push(`- \`${escapeSyncDisplay(k)}\``);
|
|
91
110
|
}
|
|
92
111
|
lines.push('');
|
|
93
112
|
}
|
|
@@ -96,17 +115,17 @@ export function renderSyncRolesResult(result, templateName) {
|
|
|
96
115
|
lines.push(`### Additions (safe — auto-applied, zero clobber risk)`);
|
|
97
116
|
for (const r of newRoles) {
|
|
98
117
|
const note = result.dryRun ? '(new role — would be created)' : '✓ created';
|
|
99
|
-
lines.push(`- new role **${r.name}** ${note}`);
|
|
118
|
+
lines.push(`- new role **${escapeSyncDisplay(r.name)}** ${note}`);
|
|
100
119
|
}
|
|
101
120
|
for (const f of adds) {
|
|
102
121
|
const note = result.dryRun ? '(would be added)' : '✓ added';
|
|
103
|
-
lines.push(`- **${f.label}** \`${f.key}\` ${note}`);
|
|
122
|
+
lines.push(`- **${escapeSyncDisplay(f.label)}** \`${escapeSyncDisplay(f.key)}\` ${note}`);
|
|
104
123
|
}
|
|
105
124
|
lines.push('');
|
|
106
125
|
}
|
|
107
126
|
// ── Custom roles (never touched) ──
|
|
108
127
|
if (customRoles.length > 0) {
|
|
109
|
-
lines.push(`### Custom roles (untouched): ${customRoles.map((r) => r.name).join(', ')}`);
|
|
128
|
+
lines.push(`### Custom roles (untouched): ${customRoles.map((r) => escapeSyncDisplay(r.name)).join(', ')}`);
|
|
110
129
|
lines.push('');
|
|
111
130
|
}
|
|
112
131
|
// ── Clean no-op ──
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-roles-render.js","sourceRoot":"","sources":["../src/sync-roles-render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;
|
|
1
|
+
{"version":3,"file":"sync-roles-render.js","sourceRoot":"","sources":["../src/sync-roles-render.ts"],"names":[],"mappings":"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"}
|
package/dist/working-repo.d.ts
CHANGED
|
@@ -7,8 +7,9 @@
|
|
|
7
7
|
*/
|
|
8
8
|
export interface WorkingRepo {
|
|
9
9
|
name: string | null;
|
|
10
|
-
/** Canonical
|
|
10
|
+
/** Canonical public HTTPS identity, never a raw Git remote URL. */
|
|
11
11
|
origin: string | null;
|
|
12
|
+
state?: 'known' | 'unknown' | 'unavailable' | 'rejected';
|
|
12
13
|
}
|
|
13
14
|
export interface WorkingRepoDeps {
|
|
14
15
|
runGit?: (cwd: string, args: string[]) => {
|
|
@@ -17,13 +18,10 @@ export interface WorkingRepoDeps {
|
|
|
17
18
|
};
|
|
18
19
|
}
|
|
19
20
|
/**
|
|
20
|
-
* Convert a Git remote to
|
|
21
|
-
*
|
|
22
|
-
* URL userinfo, query strings, fragments, scheme, and SCP-style user prefixes
|
|
23
|
-
* are deliberately discarded. Inputs that cannot identify a host and path are
|
|
24
|
-
* treated as unreportable rather than forwarded verbatim.
|
|
21
|
+
* Convert a Git remote to the shared canonical public repository identity.
|
|
22
|
+
* Hostile or credential-bearing inputs are rejected rather than sanitized.
|
|
25
23
|
*/
|
|
26
|
-
export declare function canonicalizeWorkingRepoIdentity(origin: string):
|
|
24
|
+
export declare function canonicalizeWorkingRepoIdentity(origin: string): WorkingRepo | null;
|
|
27
25
|
/**
|
|
28
26
|
* Return a reportable identity for the caller's current directory.
|
|
29
27
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"working-repo.d.ts","sourceRoot":"","sources":["../src/working-repo.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"working-repo.d.ts","sourceRoot":"","sources":["../src/working-repo.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,mEAAmE;IACnE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,aAAa,GAAG,UAAU,CAAC;CAC1D;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,CACP,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EAAE,KACX;QAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;CACxD;AAYD;;;GAGG;AACH,wBAAgB,+BAA+B,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAWlF;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,GAAE,MAAsB,EAC3B,IAAI,GAAE,eAAoB,GACzB,WAAW,CA0Bb"}
|
package/dist/working-repo.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* included in lifecycle metadata.
|
|
7
7
|
*/
|
|
8
8
|
import { spawnSync } from 'node:child_process';
|
|
9
|
+
import { canonicalizeRepositoryIdentity } from 'borgmcp-shared/runtime-metadata';
|
|
9
10
|
function defaultRunGit(cwd, args) {
|
|
10
11
|
const result = spawnSync('git', args, { cwd, encoding: 'utf-8' });
|
|
11
12
|
return { status: result.status, stdout: result.stdout };
|
|
@@ -14,45 +15,20 @@ function trimmed(value) {
|
|
|
14
15
|
const normalized = value?.trim();
|
|
15
16
|
return normalized ? normalized : null;
|
|
16
17
|
}
|
|
17
|
-
function nameFromIdentity(identity) {
|
|
18
|
-
const lastPathSegment = identity.replace(/\/$/, '').split('/').pop();
|
|
19
|
-
const name = lastPathSegment?.replace(/\.git$/i, '').trim();
|
|
20
|
-
return name || null;
|
|
21
|
-
}
|
|
22
18
|
/**
|
|
23
|
-
* Convert a Git remote to
|
|
24
|
-
*
|
|
25
|
-
* URL userinfo, query strings, fragments, scheme, and SCP-style user prefixes
|
|
26
|
-
* are deliberately discarded. Inputs that cannot identify a host and path are
|
|
27
|
-
* treated as unreportable rather than forwarded verbatim.
|
|
19
|
+
* Convert a Git remote to the shared canonical public repository identity.
|
|
20
|
+
* Hostile or credential-bearing inputs are rejected rather than sanitized.
|
|
28
21
|
*/
|
|
29
22
|
export function canonicalizeWorkingRepoIdentity(origin) {
|
|
30
|
-
const raw = origin.trim();
|
|
31
|
-
if (!raw)
|
|
32
|
-
return null;
|
|
33
|
-
// Remote clients send this canonical form on subsequent lifecycle calls.
|
|
34
|
-
const canonical = raw.match(/^([A-Za-z0-9.-]+)\/([^?#\s]+)$/);
|
|
35
|
-
if (canonical) {
|
|
36
|
-
const host = canonical[1].toLowerCase();
|
|
37
|
-
const path = canonical[2].replace(/^\/+|\/+$/g, '').replace(/\.git$/i, '');
|
|
38
|
-
return host && path ? `${host}/${path}` : null;
|
|
39
|
-
}
|
|
40
23
|
try {
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
24
|
+
const canonical = canonicalizeRepositoryIdentity(origin.trim());
|
|
25
|
+
return {
|
|
26
|
+
name: canonical.working_repo_name,
|
|
27
|
+
origin: canonical.working_repo_origin,
|
|
28
|
+
state: 'known',
|
|
29
|
+
};
|
|
46
30
|
}
|
|
47
31
|
catch {
|
|
48
|
-
// SCP-style SSH remote: discard its optional user prefix and URL-like
|
|
49
|
-
// query/fragment suffix before accepting only host + repository path.
|
|
50
|
-
const match = raw.match(/^(?:[^@\s/:]+@)?([A-Za-z0-9.-]+):\/?([^?#\s]+)(?:[?#].*)?$/);
|
|
51
|
-
if (match) {
|
|
52
|
-
const host = match[1].toLowerCase();
|
|
53
|
-
const path = match[2].replace(/^\/+|\/+$/g, '').replace(/\.git$/i, '');
|
|
54
|
-
return host && path ? `${host}/${path}` : null;
|
|
55
|
-
}
|
|
56
32
|
return null;
|
|
57
33
|
}
|
|
58
34
|
}
|
|
@@ -65,17 +41,31 @@ export function canonicalizeWorkingRepoIdentity(origin) {
|
|
|
65
41
|
*/
|
|
66
42
|
export function resolveWorkingRepo(cwd = process.cwd(), deps = {}) {
|
|
67
43
|
const runGit = deps.runGit ?? defaultRunGit;
|
|
68
|
-
|
|
44
|
+
let rootResult;
|
|
45
|
+
try {
|
|
46
|
+
rootResult = runGit(cwd, ['rev-parse', '--show-toplevel']);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return { name: null, origin: null, state: 'unavailable' };
|
|
50
|
+
}
|
|
69
51
|
const root = rootResult.status === 0 ? trimmed(rootResult.stdout) : null;
|
|
70
52
|
if (!root) {
|
|
71
|
-
return { name: null, origin: null };
|
|
53
|
+
return { name: null, origin: null, state: 'unknown' };
|
|
54
|
+
}
|
|
55
|
+
let originResult;
|
|
56
|
+
try {
|
|
57
|
+
originResult = runGit(cwd, ['config', '--get', 'remote.origin.url']);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return { name: null, origin: null, state: 'unavailable' };
|
|
72
61
|
}
|
|
73
|
-
const originResult = runGit(cwd, ['config', '--get', 'remote.origin.url']);
|
|
74
62
|
const originRaw = originResult.status === 0 ? trimmed(originResult.stdout) : null;
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
63
|
+
if (!originRaw)
|
|
64
|
+
return { name: null, origin: null, state: 'unknown' };
|
|
65
|
+
return canonicalizeWorkingRepoIdentity(originRaw) ?? {
|
|
66
|
+
name: null,
|
|
67
|
+
origin: null,
|
|
68
|
+
state: 'rejected',
|
|
79
69
|
};
|
|
80
70
|
}
|
|
81
71
|
//# sourceMappingURL=working-repo.js.map
|
package/dist/working-repo.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"working-repo.js","sourceRoot":"","sources":["../src/working-repo.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"working-repo.js","sourceRoot":"","sources":["../src/working-repo.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,8BAA8B,EAAE,MAAM,iCAAiC,CAAC;AAejF,SAAS,aAAa,CAAC,GAAW,EAAE,IAAc;IAChD,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IAClE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;AAC1D,CAAC;AAED,SAAS,OAAO,CAAC,KAAgC;IAC/C,MAAM,UAAU,GAAG,KAAK,EAAE,IAAI,EAAE,CAAC;IACjC,OAAO,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AACxC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,+BAA+B,CAAC,MAAc;IAC5D,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,8BAA8B,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;QAChE,OAAO;YACL,IAAI,EAAE,SAAS,CAAC,iBAAiB;YACjC,MAAM,EAAE,SAAS,CAAC,mBAAmB;YACrC,KAAK,EAAE,OAAO;SACf,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAChC,MAAc,OAAO,CAAC,GAAG,EAAE,EAC3B,OAAwB,EAAE;IAE1B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,aAAa,CAAC;IAC5C,IAAI,UAAU,CAAC;IACf,IAAI,CAAC;QACH,UAAU,GAAG,MAAM,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAC7D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;IAC5D,CAAC;IACD,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACzE,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;IACxD,CAAC;IAED,IAAI,YAAY,CAAC;IACjB,IAAI,CAAC;QACH,YAAY,GAAG,MAAM,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,mBAAmB,CAAC,CAAC,CAAC;IACvE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;IAC5D,CAAC;IACD,MAAM,SAAS,GAAG,YAAY,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAClF,IAAI,CAAC,SAAS;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;IACtE,OAAO,+BAA+B,CAAC,SAAS,CAAC,IAAI;QACnD,IAAI,EAAE,IAAI;QACV,MAAM,EAAE,IAAI;QACZ,KAAK,EAAE,UAAU;KAClB,CAAC;AACJ,CAAC"}
|
|
@@ -8,7 +8,7 @@ The extraction copied the monorepo's `client/src/` production boundary and top-l
|
|
|
8
8
|
|
|
9
9
|
## Deliberate Transformations
|
|
10
10
|
|
|
11
|
-
- Replaced the monorepo dependency on `borgmcp-shared` with the exact audited registry release `borgmcp-shared@0.
|
|
11
|
+
- Replaced the monorepo dependency on `borgmcp-shared` with the exact audited registry release `borgmcp-shared@0.6.1` and a fresh standalone lockfile.
|
|
12
12
|
- Replaced local template, role-section, drone-address, and log high-water-mark implementations with `borgmcp-shared` exports.
|
|
13
13
|
- Removed monorepo-only website anti-drift tests and re-anchored remaining filesystem tests to this repository.
|
|
14
14
|
- Removed consumer lifecycle hooks, parent-directory deployment scripts, minification, and private integration-environment configuration.
|
|
@@ -21,8 +21,9 @@ The extraction copied the monorepo's `client/src/` production boundary and top-l
|
|
|
21
21
|
lightweight release tag failed before packaging. The reviewed `2.0.1`
|
|
22
22
|
recovery, `2.0.2`, `2.0.3`, `2.0.4`, `2.0.5`, and `2.0.6` successors were
|
|
23
23
|
published and registry-verified. The immutable `2.0.7` workflow failed before
|
|
24
|
-
package creation or npm publication
|
|
25
|
-
|
|
24
|
+
package creation or npm publication. The `2.0.8` and `2.0.9` successors were
|
|
25
|
+
published and registry-verified, so the next candidate identity is `2.0.10`. Extraction and
|
|
26
|
+
versioning do not authorize publication.
|
|
26
27
|
|
|
27
28
|
## Review Holds
|
|
28
29
|
|
|
@@ -37,9 +38,9 @@ artifact reaches no hosted authority.
|
|
|
37
38
|
Local enrollment now uses the reviewed client-generated credential/retry
|
|
38
39
|
contract, with a pre-request `PENDING` record in the local 0600-permission seat
|
|
39
40
|
store, exact-tuple ambiguous retry, and verified activation. The contract now
|
|
40
|
-
resolves to the audited registry `borgmcp-shared@0.
|
|
41
|
-
`borgmcp-server@0.1.
|
|
42
|
-
`borgmcp@2.0.
|
|
41
|
+
resolves to the audited registry `borgmcp-shared@0.6.1`. The matching
|
|
42
|
+
`borgmcp-server@0.1.17` release is published and registry-verified. Client
|
|
43
|
+
`borgmcp@2.0.9` is published and registry-verified. The immutable `v2.0.7`
|
|
43
44
|
attempt failed before publication and remains preserved. Publication of the next
|
|
44
|
-
candidate remains gated by reviewed `v2.0.
|
|
45
|
+
candidate remains gated by reviewed `v2.0.10` source, a fresh annotated tag, and
|
|
45
46
|
exact registry integrity and signature verification.
|
package/docs/LOCAL_SERVER.md
CHANGED
|
@@ -139,7 +139,7 @@ The default discovery endpoint is `https://127.0.0.1:7091`. Explicit `--host` va
|
|
|
139
139
|
|
|
140
140
|
## Release status
|
|
141
141
|
|
|
142
|
-
This self-hosted path consumes the published `borgmcp-shared@0.
|
|
142
|
+
This self-hosted path consumes the published `borgmcp-shared@0.6.1` v3 registry
|
|
143
143
|
release. The matching server owner-enrollment, cube-create, attach, restart, log,
|
|
144
144
|
and SSE implementation must also pass the full process-level local dogfood gate.
|
|
145
145
|
Until that gate opens the self-hosted path remains preview-only, and the client
|
package/docs/RELEASING.md
CHANGED
|
@@ -76,6 +76,24 @@ rerun that tag, version, or workflow. The next candidate uses the unused
|
|
|
76
76
|
`v2.0.8` identity from a fresh reviewed protected-main commit and requires the
|
|
77
77
|
complete release gate again.
|
|
78
78
|
|
|
79
|
+
The annotated `v2.0.8` tag object
|
|
80
|
+
`7b5a4929534abfa97a65e278df230adfdb842d8f` peels to protected-main commit
|
|
81
|
+
`8bc796d8fc4e307dca593138fb080984662c7d62`. Workflow run `30012098601`, attempt 1,
|
|
82
|
+
successfully published that exact source as `borgmcp@2.0.8`; the registry records integrity
|
|
83
|
+
`sha512-az1IKG4VNwAF/8PKEVK88gdRoFFBqgtl6ObXX+CcJadavNqkwJ9UFeP8LOJ2js911mIiXEm8c4xDf6MnO0GOng==`.
|
|
84
|
+
Never move, replace, reuse, or rerun that tag or workflow. Its successor used
|
|
85
|
+
the fresh `v2.0.9` identity from a reviewed protected-main commit and passed the
|
|
86
|
+
complete release gate.
|
|
87
|
+
|
|
88
|
+
The annotated `v2.0.9` tag object
|
|
89
|
+
`3a88bb4f46143789803a4e57f52b94d762f1ca9b` peels to protected-main commit
|
|
90
|
+
`18084fc486a041f3438f584a97d218c01a5e0399`. Workflow run `30047299013`, attempt 1,
|
|
91
|
+
successfully published that exact source as `borgmcp@2.0.9`; the registry records integrity
|
|
92
|
+
`sha512-lf0TZ8ZcpHv/Nt3LkY/IGxkUFkg3weavF+rLv6xLImDDhLIaZly1y8jUdo3UuheQVhrLnLcxoz37Myr4mPx9lg==`.
|
|
93
|
+
Never move, replace, reuse, or rerun that tag or workflow. The next candidate
|
|
94
|
+
uses the unused `v2.0.10` identity from a fresh reviewed protected-main commit
|
|
95
|
+
and requires the complete release gate again.
|
|
96
|
+
|
|
79
97
|
## Release Prerequisites
|
|
80
98
|
|
|
81
99
|
The standalone client was extracted from private-monorepo commit
|
|
@@ -85,7 +103,7 @@ Before creating the release tag, independently verify all of these conditions:
|
|
|
85
103
|
- the extraction review confirms no private backend secrets, deployment
|
|
86
104
|
configuration, customer data, local state, or duplicated shared contracts
|
|
87
105
|
entered the public package;
|
|
88
|
-
- the exact audited registry dependency `borgmcp-shared@0.
|
|
106
|
+
- the exact audited registry dependency `borgmcp-shared@0.6.1` remains locked to
|
|
89
107
|
its canonical tarball and integrity;
|
|
90
108
|
- the client and matching server pass the complete local dogfood gate;
|
|
91
109
|
- the selected stable client version is unused and the exact release commit is
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "borgmcp",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.10",
|
|
4
4
|
"description": "Coordinate AI coding agents in shared cubes. Works with Claude Code, Codex, and OpenCode.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
},
|
|
69
69
|
"dependencies": {
|
|
70
70
|
"@modelcontextprotocol/sdk": "^1.0.4",
|
|
71
|
-
"borgmcp-shared": "0.
|
|
71
|
+
"borgmcp-shared": "0.6.1",
|
|
72
72
|
"chalk": "^5.3.0",
|
|
73
73
|
"prompts": "^2.4.2",
|
|
74
74
|
"which": "^4.0.0"
|
package/src/agent-runtime.ts
CHANGED
|
@@ -24,10 +24,17 @@ function isAgentKind(value: string | undefined): value is AgentKind {
|
|
|
24
24
|
* already-installed clients.
|
|
25
25
|
*/
|
|
26
26
|
export function resolveSessionAgentKind(env: NodeJS.ProcessEnv = process.env): AgentKind {
|
|
27
|
+
return resolveReportableSessionAgentKind(env) ?? 'claude';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Resolve only positively identified CLI state for advisory server reporting. */
|
|
31
|
+
export function resolveReportableSessionAgentKind(
|
|
32
|
+
env: NodeJS.ProcessEnv = process.env
|
|
33
|
+
): AgentKind | null {
|
|
27
34
|
if (isAgentKind(env[BORG_AGENT_KIND_ENV])) return env[BORG_AGENT_KIND_ENV];
|
|
28
35
|
if (env[BORG_OPENCODE_ENV] === '1') return 'opencode';
|
|
29
36
|
if (env[BORG_CODEX_REMOTE_WAKE_ENV] === '1') return 'codex';
|
|
30
|
-
return
|
|
37
|
+
return null;
|
|
31
38
|
}
|
|
32
39
|
|
|
33
40
|
/**
|
package/src/assimilate-cmd.ts
CHANGED
|
@@ -49,6 +49,7 @@ import type { ExpectedBinding, FinalizeServerSeatOutcome, PersistedLocalSeat } f
|
|
|
49
49
|
import type { SeatBinding, BindPendingSeatOutcome } from './seats.js';
|
|
50
50
|
import { createHash } from 'node:crypto';
|
|
51
51
|
import { buildOpenCodeLaunchArgs, type LaunchApprovalDecision } from './cli-tool-approval.js';
|
|
52
|
+
import { resolveWorkingRepo, type WorkingRepo } from './working-repo.js';
|
|
52
53
|
|
|
53
54
|
const PRIVATE_STATE_UNAVAILABLE_COPY = [
|
|
54
55
|
'Borg could not safely prepare its private local state.',
|
|
@@ -259,7 +260,7 @@ export interface AssimilateDeps {
|
|
|
259
260
|
assimilate: (
|
|
260
261
|
apiUrl: string,
|
|
261
262
|
token: string,
|
|
262
|
-
params: { cube_id: string; role_id: string; hostname?: string | null; prior_drone_id?: string; remint_invalid_prior?: boolean; model?: string | null; agent_kind?: 'claude' | 'codex' | 'opencode' | null; session_operation?: ServerSessionOperation; session_expected?: ExpectedBinding; revalidate_at_prepare?: boolean },
|
|
263
|
+
params: { cube_id: string; role_id: string; hostname?: string | null; prior_drone_id?: string; remint_invalid_prior?: boolean; model?: string | null; agent_kind?: 'claude' | 'codex' | 'opencode' | null; working_repo?: WorkingRepo; session_operation?: ServerSessionOperation; session_expected?: ExpectedBinding; revalidate_at_prepare?: boolean },
|
|
263
264
|
serverTrustIdentity?: string,
|
|
264
265
|
) => Promise<AssimilateResult>;
|
|
265
266
|
|
|
@@ -1183,6 +1184,7 @@ export async function runAssimilate(
|
|
|
1183
1184
|
hostname: deps.getHostname(),
|
|
1184
1185
|
agent_kind: cli,
|
|
1185
1186
|
model: effectiveModel,
|
|
1187
|
+
working_repo: resolveWorkingRepo(projectRoot),
|
|
1186
1188
|
...(reattachPriorId ? { prior_drone_id: reattachPriorId } : {}),
|
|
1187
1189
|
...(remintInvalidPrior ? { remint_invalid_prior: true } : {}),
|
|
1188
1190
|
session_operation: sessionOperation,
|
package/src/assimilate-deps.ts
CHANGED
|
@@ -16,6 +16,7 @@ import { createInterface } from 'node:readline/promises';
|
|
|
16
16
|
import prompts from 'prompts';
|
|
17
17
|
import { readinessProbeEnv } from './readiness-probe.js';
|
|
18
18
|
import { resolveMcpBinaryPath } from './self-path.js';
|
|
19
|
+
import { buildRuntimeMetadataReport } from './runtime-metadata.js';
|
|
19
20
|
|
|
20
21
|
import type { AssimilateDeps } from './assimilate-cmd.js';
|
|
21
22
|
import {
|
|
@@ -322,10 +323,15 @@ export function buildDefaultAssimilateDeps(): AssimilateDeps {
|
|
|
322
323
|
cubeId: params.cube_id,
|
|
323
324
|
roleId: params.role_id,
|
|
324
325
|
operation,
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
326
|
+
...(params.prior_drone_id === undefined
|
|
327
|
+
? {}
|
|
328
|
+
: { priorDroneId: params.prior_drone_id }),
|
|
329
|
+
runtimeMetadata: buildRuntimeMetadataReport({
|
|
330
|
+
agentKind: params.agent_kind,
|
|
331
|
+
reportedModel: params.model,
|
|
332
|
+
workingRepo: params.working_repo,
|
|
333
|
+
}),
|
|
334
|
+
},
|
|
329
335
|
pending.credential,
|
|
330
336
|
{ fetchImpl: trust.fetchImpl },
|
|
331
337
|
);
|
package/src/index.ts
CHANGED
|
@@ -43,11 +43,14 @@ import {
|
|
|
43
43
|
patchTaxonomyClass,
|
|
44
44
|
deleteRole,
|
|
45
45
|
getCube,
|
|
46
|
+
getCubeForManagement,
|
|
47
|
+
resolveLocalManageAuthority,
|
|
46
48
|
listRoles,
|
|
47
49
|
syncRoles,
|
|
48
50
|
applyTemplate,
|
|
49
51
|
whoami,
|
|
50
52
|
roleRationale,
|
|
53
|
+
type LocalManageAuthority,
|
|
51
54
|
} from './remote-client.js';
|
|
52
55
|
import {
|
|
53
56
|
getTemplate,
|
|
@@ -90,7 +93,11 @@ import {
|
|
|
90
93
|
formatWakePathPrefix,
|
|
91
94
|
shouldShowWakePathWarning,
|
|
92
95
|
} from './stream-status.js';
|
|
93
|
-
import {
|
|
96
|
+
import {
|
|
97
|
+
RUNTIME_METADATA_ADVISORY,
|
|
98
|
+
renderRoster,
|
|
99
|
+
renderRuntimeMetadataLines,
|
|
100
|
+
} from './roster-render.js';
|
|
94
101
|
import { resolveWorkingRepo } from './working-repo.js';
|
|
95
102
|
import {
|
|
96
103
|
DroneEvictedError,
|
|
@@ -107,6 +114,7 @@ import { initConsolePrefix, consolePrefix } from './console-prefix.js';
|
|
|
107
114
|
import {
|
|
108
115
|
resolveSessionAgentKind,
|
|
109
116
|
} from './codex-app-wake.js';
|
|
117
|
+
import { resolveReportableSessionAgentKind } from './agent-runtime.js';
|
|
110
118
|
import {
|
|
111
119
|
connectOpenCodeDrone,
|
|
112
120
|
injectOpenCodeEntry,
|
|
@@ -142,9 +150,38 @@ import {
|
|
|
142
150
|
*/
|
|
143
151
|
async function applyTemplateToCube(
|
|
144
152
|
cubeId: string,
|
|
145
|
-
template: Template
|
|
153
|
+
template: Template,
|
|
154
|
+
authority?: LocalManageAuthority,
|
|
146
155
|
): Promise<{ created: number; updated: number }> {
|
|
147
|
-
return await applyTemplate(cubeId, template.name);
|
|
156
|
+
return await applyTemplate(cubeId, template.name, authority);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export async function runApplyTemplateTool(
|
|
160
|
+
cubeId: string,
|
|
161
|
+
template: Template,
|
|
162
|
+
authority: LocalManageAuthority,
|
|
163
|
+
deps: {
|
|
164
|
+
applyTemplate?: typeof applyTemplate;
|
|
165
|
+
getCubeForManagement?: typeof getCubeForManagement;
|
|
166
|
+
updateCube?: typeof updateCube;
|
|
167
|
+
} = {},
|
|
168
|
+
): Promise<{ summary: { created: number; updated: number }; cubeDirectiveNote: string }> {
|
|
169
|
+
const apply = deps.applyTemplate ?? applyTemplate;
|
|
170
|
+
const read = deps.getCubeForManagement ?? getCubeForManagement;
|
|
171
|
+
const update = deps.updateCube ?? updateCube;
|
|
172
|
+
const summary = await apply(cubeId, template.name, authority);
|
|
173
|
+
const cubeForRules = await read(cubeId, {
|
|
174
|
+
operation: `read template target ${JSON.stringify(template.name)}`,
|
|
175
|
+
cubeName: cubeId === authority.active.cubeId ? authority.active.name : cubeId,
|
|
176
|
+
noMutation: 'No template fragments were changed.',
|
|
177
|
+
}, authority.active, authority.connection);
|
|
178
|
+
const newCubeDirective = resolveCubeDirectiveForApply(cubeForRules.cube_directive, template);
|
|
179
|
+
if (newCubeDirective === null) return { summary, cubeDirectiveNote: '' };
|
|
180
|
+
await update(cubeId, { cube_directive: newCubeDirective }, authority.active, authority.connection);
|
|
181
|
+
return {
|
|
182
|
+
summary,
|
|
183
|
+
cubeDirectiveNote: ' Template cube directive applied (cube directive was empty).',
|
|
184
|
+
};
|
|
148
185
|
}
|
|
149
186
|
|
|
150
187
|
/**
|
|
@@ -336,6 +373,7 @@ export async function main() {
|
|
|
336
373
|
const result = await regen(active.sessionToken, active.apiUrl, {
|
|
337
374
|
since,
|
|
338
375
|
reportedModel,
|
|
376
|
+
agentKind: resolveReportableSessionAgentKind(),
|
|
339
377
|
workingRepo: resolveWorkingRepo(),
|
|
340
378
|
serverTrustIdentity: active.serverTrustIdentity,
|
|
341
379
|
});
|
|
@@ -412,6 +450,7 @@ export async function main() {
|
|
|
412
450
|
// — an evicted/revoked seat FAILS server-side and is surfaced).
|
|
413
451
|
try {
|
|
414
452
|
const result = await regen(active!.sessionToken, active!.apiUrl, {
|
|
453
|
+
agentKind: resolveReportableSessionAgentKind(),
|
|
415
454
|
workingRepo: resolveWorkingRepo(),
|
|
416
455
|
serverTrustIdentity: active!.serverTrustIdentity,
|
|
417
456
|
});
|
|
@@ -1052,21 +1091,18 @@ export async function main() {
|
|
|
1052
1091
|
return { content: [{ type: 'text', text: 'No drones in this cube yet.' }] };
|
|
1053
1092
|
}
|
|
1054
1093
|
const rolesById = new Map(roles.map((r: any) => [r.id, r]));
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
const wakeClass =
|
|
1094
|
+
const lines = drones.map((d: any) => {
|
|
1095
|
+
const r = rolesById.get(d.role_id) as any;
|
|
1096
|
+
const wakeClass =
|
|
1059
1097
|
d.wake_path_alert_class && d.wake_path_alert_class !== 'independent'
|
|
1060
1098
|
? ` — wake-path-class: ${d.wake_path_alert_class}`
|
|
1061
1099
|
: '';
|
|
1062
|
-
|
|
1063
|
-
?
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
});
|
|
1069
|
-
return { content: [{ type: 'text', text: `Drones in cube ${cubeId} (${drones.length}):\n\n${lines.join('\n')}` }] };
|
|
1100
|
+
return [
|
|
1101
|
+
`- **${d.label}** (id: ${d.id}) — Role: ${r?.name ?? '?'} (${d.role_id}) — last seen ${d.last_seen}${wakeClass}`,
|
|
1102
|
+
...renderRuntimeMetadataLines(d),
|
|
1103
|
+
].join('\n');
|
|
1104
|
+
});
|
|
1105
|
+
return { content: [{ type: 'text', text: `Drones in cube ${cubeId} (${drones.length}):\n\n_${RUNTIME_METADATA_ADVISORY}_\n\n${lines.join('\n')}` }] };
|
|
1070
1106
|
}
|
|
1071
1107
|
|
|
1072
1108
|
case 'borg_list-roles': {
|
|
@@ -1119,18 +1155,13 @@ export async function main() {
|
|
|
1119
1155
|
if (!template) {
|
|
1120
1156
|
throw new Error(`Unknown template "${templateName}". Available: ${listTemplateNames().join(', ')}`);
|
|
1121
1157
|
}
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
const newCubeDirective = resolveCubeDirectiveForApply(cubeForRules.cube_directive, template);
|
|
1130
|
-
if (newCubeDirective !== null) {
|
|
1131
|
-
await updateCube(cubeId, { cube_directive: newCubeDirective });
|
|
1132
|
-
cubeDirectiveNote = ' Template cube directive applied (cube directive was empty).';
|
|
1133
|
-
}
|
|
1158
|
+
const active = await requireActiveCube();
|
|
1159
|
+
const authority = await resolveLocalManageAuthority(active, {
|
|
1160
|
+
operation: `apply template ${JSON.stringify(templateName)}`,
|
|
1161
|
+
cubeName: cubeId === active.cubeId ? active.name : cubeId,
|
|
1162
|
+
noMutation: 'No template fragments were changed.',
|
|
1163
|
+
});
|
|
1164
|
+
const { summary, cubeDirectiveNote } = await runApplyTemplateTool(cubeId, template, authority);
|
|
1134
1165
|
|
|
1135
1166
|
return { content: [{ type: 'text', text: `Applied template **${templateName}** to cube ${cubeId} — ${summary.created} role(s) created, ${summary.updated} updated.${cubeDirectiveNote}` }] };
|
|
1136
1167
|
}
|
package/src/regen-format.ts
CHANGED
|
@@ -12,7 +12,10 @@ import {
|
|
|
12
12
|
} from 'borgmcp-shared/templates';
|
|
13
13
|
import { parseRoleSections } from 'borgmcp-shared/role-section';
|
|
14
14
|
import { formatDroneAddressToken } from 'borgmcp-shared/drone-address';
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
RUNTIME_METADATA_ADVISORY,
|
|
17
|
+
renderRuntimeMetadataLines,
|
|
18
|
+
} from './roster-render.js';
|
|
16
19
|
import { shellEscape } from './shell-escape.js';
|
|
17
20
|
import { resolveInboxMonitorPath } from './self-path.js';
|
|
18
21
|
|
|
@@ -488,10 +491,12 @@ export function formatRegenMarkdown(
|
|
|
488
491
|
|
|
489
492
|
const droneOverview =
|
|
490
493
|
result.drones
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
494
|
+
.map((d: any) => {
|
|
495
|
+
const role = result.roles.find((r: any) => r.id === d.role_id);
|
|
496
|
+
return [
|
|
497
|
+
`- **${d.label}** (Role: ${role?.name ?? '?'}) — last seen ${humanAgo(new Date(d.last_seen))}`,
|
|
498
|
+
...renderRuntimeMetadataLines(d),
|
|
499
|
+
].join('\n');
|
|
495
500
|
})
|
|
496
501
|
.join('\n') || '_(no drones connected)_';
|
|
497
502
|
|
|
@@ -611,6 +616,8 @@ export function formatRegenMarkdown(
|
|
|
611
616
|
roleOverview,
|
|
612
617
|
'',
|
|
613
618
|
`## Connected drones`,
|
|
619
|
+
`_${RUNTIME_METADATA_ADVISORY}_`,
|
|
620
|
+
'',
|
|
614
621
|
droneOverview,
|
|
615
622
|
'',
|
|
616
623
|
`## Cube log`,
|
package/src/regen.ts
CHANGED
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
type AgentKind,
|
|
27
27
|
} from './regen-format.js';
|
|
28
28
|
import { resolveSessionAgentKind } from './codex-app-wake.js';
|
|
29
|
+
import { resolveReportableSessionAgentKind } from './agent-runtime.js';
|
|
29
30
|
import { handleVersionFlag } from './version.js';
|
|
30
31
|
import { gateAllowsActivation } from './launch-gate.js';
|
|
31
32
|
import { resolveWorkingRepo } from './working-repo.js';
|
|
@@ -85,6 +86,7 @@ async function main(): Promise<void> {
|
|
|
85
86
|
let result: Awaited<ReturnType<typeof regen>> | null = null;
|
|
86
87
|
try {
|
|
87
88
|
result = await regen(active.sessionToken, active.apiUrl, {
|
|
89
|
+
agentKind: resolveReportableSessionAgentKind(),
|
|
88
90
|
workingRepo: resolveWorkingRepo(),
|
|
89
91
|
serverTrustIdentity: active.serverTrustIdentity,
|
|
90
92
|
});
|