@bongos/core 1.19.271 → 1.19.272
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/.bongos-core.json +10 -10
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/scripts/gds/context-pack.js +62 -4
- package/src/module-api.js +3 -1
- package/tests/context_pack.mjs +105 -2
package/.bongos-core.json
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"artifact": "bongos-core",
|
|
3
3
|
"manifest_schema": 1,
|
|
4
4
|
"generator": "scripts/gds/package-core.js",
|
|
5
|
-
"core_version": "1.19.
|
|
6
|
-
"core_contract": "1.19.
|
|
7
|
-
"source_commit": "
|
|
5
|
+
"core_version": "1.19.272",
|
|
6
|
+
"core_contract": "1.19.272",
|
|
7
|
+
"source_commit": "1ddcabf5f0c390df6bf2db273da05131d7c5555d",
|
|
8
8
|
"source_ref": "HEAD",
|
|
9
|
-
"built_at": "2026-08-21T01:
|
|
9
|
+
"built_at": "2026-08-21T01:58:30.188Z",
|
|
10
10
|
"redaction": {
|
|
11
11
|
"model": "docs-redacted+functional-verbatim",
|
|
12
12
|
"docs_redacted": 318,
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"gate": "passed"
|
|
18
18
|
},
|
|
19
19
|
"file_count": 1709,
|
|
20
|
-
"tree_sha256": "
|
|
20
|
+
"tree_sha256": "7e96896dddb704ffea439416bad0d7ba6ad81ead9d79ed34212de45a2df50f71",
|
|
21
21
|
"files": [
|
|
22
22
|
{
|
|
23
23
|
"path": ".claude/skills/blocker-review/SKILL.md",
|
|
@@ -4472,12 +4472,12 @@
|
|
|
4472
4472
|
{
|
|
4473
4473
|
"path": "package-lock.json",
|
|
4474
4474
|
"mode": "0000644",
|
|
4475
|
-
"sha256": "
|
|
4475
|
+
"sha256": "b77fc259ddf810fa62ea5e745751449a5dc49847311ddf4199a997df9dcd06ed"
|
|
4476
4476
|
},
|
|
4477
4477
|
{
|
|
4478
4478
|
"path": "package.json",
|
|
4479
4479
|
"mode": "0000644",
|
|
4480
|
-
"sha256": "
|
|
4480
|
+
"sha256": "725dd9f78abd547ef32e6d9a9b886ecf447fa1bd62a747df49943e2a1e047949"
|
|
4481
4481
|
},
|
|
4482
4482
|
{
|
|
4483
4483
|
"path": "public-docs/index.html",
|
|
@@ -4997,7 +4997,7 @@
|
|
|
4997
4997
|
{
|
|
4998
4998
|
"path": "scripts/gds/context-pack.js",
|
|
4999
4999
|
"mode": "0000644",
|
|
5000
|
-
"sha256": "
|
|
5000
|
+
"sha256": "caa5dd1628b00569a5593964f1831641ac12c9a85b8ec132964a1baf67c77350"
|
|
5001
5001
|
},
|
|
5002
5002
|
{
|
|
5003
5003
|
"path": "scripts/gds/control-manifest.js",
|
|
@@ -6122,7 +6122,7 @@
|
|
|
6122
6122
|
{
|
|
6123
6123
|
"path": "src/module-api.js",
|
|
6124
6124
|
"mode": "0000644",
|
|
6125
|
-
"sha256": "
|
|
6125
|
+
"sha256": "67c1067ae657f640493d8bfa3f7001ce64f416d0176afd6e84be387349a9578e"
|
|
6126
6126
|
},
|
|
6127
6127
|
{
|
|
6128
6128
|
"path": "src/module-loader/catalog.js",
|
|
@@ -6652,7 +6652,7 @@
|
|
|
6652
6652
|
{
|
|
6653
6653
|
"path": "tests/context_pack.mjs",
|
|
6654
6654
|
"mode": "0000644",
|
|
6655
|
-
"sha256": "
|
|
6655
|
+
"sha256": "09f956c01f169ab7384204a5d43deefa3e57a7d57924072dfa8215f0942c2513"
|
|
6656
6656
|
},
|
|
6657
6657
|
{
|
|
6658
6658
|
"path": "tests/control_manifest.mjs",
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.272",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@bongos/core",
|
|
9
|
-
"version": "1.19.
|
|
9
|
+
"version": "1.19.272",
|
|
10
10
|
"license": "AGPL-3.0-or-later",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"express": "^4.21.2",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.272",
|
|
4
4
|
"description": "Cloud Bongos — the AI-first build platform core (GDS + platform surfaces + module system), installed as a versioned dependency (ADR 0108).",
|
|
5
5
|
"license": "AGPL-3.0-or-later",
|
|
6
6
|
"main": "src/platform-server.js",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
// and must NEVER throw or block a claim.
|
|
26
26
|
|
|
27
27
|
const { execFileSync } = require('node:child_process');
|
|
28
|
+
const path = require('node:path');
|
|
28
29
|
|
|
29
30
|
// The live validators. task-classifier is a pure module (no DB, no network),
|
|
30
31
|
// so importing it from a CLI is safe — same precedent as next-number.js reading
|
|
@@ -61,14 +62,70 @@ function apiContract() {
|
|
|
61
62
|
|
|
62
63
|
// Resolve the absolute worktree root. runGit throws → fall back to cwd (which is
|
|
63
64
|
// still better than nothing; the builder at least sees the directory they're in).
|
|
65
|
+
//
|
|
66
|
+
// task 1002573: also resolve WHICH KIND of tree this is. The pack used to print
|
|
67
|
+
// the root and then assert "this is the session's tree, not the main checkout"
|
|
68
|
+
// unconditionally — so claiming from the main checkout produced a sentence that
|
|
69
|
+
// was flatly false, and the tooling told the builder to do the one thing that
|
|
70
|
+
// makes the ship unmergeable (ship.js's local auto-merge has nowhere to merge
|
|
71
|
+
// INTO when the receiving tree is the one holding the branch — task 1002572).
|
|
72
|
+
//
|
|
73
|
+
// The signal is the same one claim.js detectWorktreeName() already uses: in the
|
|
74
|
+
// main checkout `--git-dir` and `--git-common-dir` resolve to the same path; in a
|
|
75
|
+
// linked worktree they diverge. isMainCheckout is TRI-STATE — null means "could
|
|
76
|
+
// not tell", and the guidance hedges rather than guessing, because this is a UX
|
|
77
|
+
// surface that must never block a claim.
|
|
64
78
|
function resolveWorktreeRoot({ runGit, cwd }) {
|
|
79
|
+
let root = null;
|
|
80
|
+
let degraded = false;
|
|
65
81
|
try {
|
|
66
|
-
|
|
67
|
-
if (root) return { root, degraded: false };
|
|
82
|
+
root = runGit(['rev-parse', '--show-toplevel']).trim() || null;
|
|
68
83
|
} catch {
|
|
69
84
|
/* fall through */
|
|
70
85
|
}
|
|
71
|
-
|
|
86
|
+
if (!root) {
|
|
87
|
+
root = cwd;
|
|
88
|
+
degraded = true;
|
|
89
|
+
}
|
|
90
|
+
let isMainCheckout = null;
|
|
91
|
+
try {
|
|
92
|
+
const gitDir = runGit(['rev-parse', '--git-dir']).trim();
|
|
93
|
+
const commonDir = runGit(['rev-parse', '--git-common-dir']).trim();
|
|
94
|
+
if (gitDir && commonDir) {
|
|
95
|
+
// Both can come back RELATIVE ('.git' in the main checkout), so resolve
|
|
96
|
+
// against the tree we are describing rather than the process cwd.
|
|
97
|
+
const base = degraded ? cwd : root;
|
|
98
|
+
isMainCheckout = path.resolve(base, gitDir) === path.resolve(base, commonDir);
|
|
99
|
+
}
|
|
100
|
+
} catch {
|
|
101
|
+
/* unknown — the guidance hedges */
|
|
102
|
+
}
|
|
103
|
+
return { root, degraded, isMainCheckout };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// task 1002573: the guidance line(s) for the resolved tree. Pure, and exported so
|
|
107
|
+
// the "these two must not read the same" property is unit-tested rather than
|
|
108
|
+
// eyeballed. Returns an array of lines (the warning needs more than one).
|
|
109
|
+
function worktreeGuidance(worktree) {
|
|
110
|
+
const isMain = worktree ? worktree.isMainCheckout : null;
|
|
111
|
+
if (isMain === true) {
|
|
112
|
+
return [
|
|
113
|
+
' ⚠ THIS IS THE MAIN CHECKOUT — not a per-claim worktree.',
|
|
114
|
+
' Working the claim here parks the main checkout off `main`, and the local',
|
|
115
|
+
' auto-merge then has nowhere to merge INTO: the ship strands at `confirmed`',
|
|
116
|
+
' until the server reconciler (or /merge-mode) catches it. Automation that',
|
|
117
|
+
' resets this tree mid-session can also take your uncommitted work with it.',
|
|
118
|
+
' Prefer a worktree: git worktree add .claude/worktrees/<name> -b <branch>',
|
|
119
|
+
];
|
|
120
|
+
}
|
|
121
|
+
if (isMain === false) {
|
|
122
|
+
return [' → edit files + run git HERE. This is the session\'s tree, not the main checkout (the #1 wrong-path footgun).'];
|
|
123
|
+
}
|
|
124
|
+
return [
|
|
125
|
+
' → edit files + run git HERE.',
|
|
126
|
+
' ⚠ Could not tell whether this is the main checkout or a linked worktree. If it is',
|
|
127
|
+
' the main checkout, prefer a per-claim worktree — see the warning in /builder-claim.',
|
|
128
|
+
];
|
|
72
129
|
}
|
|
73
130
|
|
|
74
131
|
// OS toolchain facts the corpus showed sessions tripping over. `which` returns a
|
|
@@ -148,7 +205,7 @@ function formatContextPack(pack) {
|
|
|
148
205
|
const lines = [];
|
|
149
206
|
lines.push('🧭 Context pack (so this session starts knowing, not hunting):');
|
|
150
207
|
lines.push(` Worktree root: ${worktree.root}`);
|
|
151
|
-
lines.push(
|
|
208
|
+
lines.push(...worktreeGuidance(worktree)); // task 1002573 — tells the TRUTH about which tree this is
|
|
152
209
|
if (worktree.degraded) {
|
|
153
210
|
lines.push(' ⚠ git toplevel unreadable — showing cwd; double-check before writing.');
|
|
154
211
|
}
|
|
@@ -217,6 +274,7 @@ module.exports = {
|
|
|
217
274
|
API_PREFIX,
|
|
218
275
|
apiContract,
|
|
219
276
|
resolveWorktreeRoot,
|
|
277
|
+
worktreeGuidance, // task 1002573
|
|
220
278
|
osFacts,
|
|
221
279
|
normalizeClaims,
|
|
222
280
|
buildContextPack,
|
package/src/module-api.js
CHANGED
|
@@ -969,8 +969,10 @@ const { validateOrRespond, LIMITS, parseId, asyncHandler, corsPublicGet, parsePa
|
|
|
969
969
|
// landed since 1.19.269 with no explicit bump. run 32428659648. (task 1002620)
|
|
970
970
|
// 1.19.271 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
971
971
|
// landed since 1.19.270 with no explicit bump. run 32437463473. (task 1002620)
|
|
972
|
+
// 1.19.272 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
973
|
+
// landed since 1.19.271 with no explicit bump. run 32438140524. (task 1002620)
|
|
972
974
|
// ---------------------------------------------------------------------------
|
|
973
|
-
const CORE_VERSION = '1.19.
|
|
975
|
+
const CORE_VERSION = '1.19.272'; // CI auto-patch carrier (ADR 0161); see changelog above
|
|
974
976
|
|
|
975
977
|
// A namespaced logger so a module's log lines are attributable + consistent.
|
|
976
978
|
// Usage: const log = api.logger('dev-box'); log.info('mounted');
|
package/tests/context_pack.mjs
CHANGED
|
@@ -17,6 +17,7 @@ const require = createRequire(import.meta.url);
|
|
|
17
17
|
const {
|
|
18
18
|
apiContract,
|
|
19
19
|
resolveWorktreeRoot,
|
|
20
|
+
worktreeGuidance,
|
|
20
21
|
osFacts,
|
|
21
22
|
normalizeClaims,
|
|
22
23
|
buildContextPack,
|
|
@@ -177,6 +178,104 @@ t('buildContextPack: composes worktree + claims + api + os from injected runners
|
|
|
177
178
|
assert.equal(pack.os.platform, 'linux');
|
|
178
179
|
});
|
|
179
180
|
|
|
181
|
+
// ---- task 1002573: which tree is this, and does the guidance tell the truth ----
|
|
182
|
+
//
|
|
183
|
+
// The pack used to print the root and then assert "this is the session's tree,
|
|
184
|
+
// not the main checkout" UNCONDITIONALLY. Claiming from the main checkout
|
|
185
|
+
// therefore produced a flatly false sentence, and the tooling told the builder to
|
|
186
|
+
// do the one thing that makes the ship unmergeable (the receiving tree is the one
|
|
187
|
+
// holding the branch — task 1002572). The signal was already computed elsewhere
|
|
188
|
+
// (claim.js detectWorktreeName) and simply never surfaced.
|
|
189
|
+
//
|
|
190
|
+
// Stubs mirror real git: in the MAIN checkout `--git-dir` and `--git-common-dir`
|
|
191
|
+
// both answer '.git'; in a LINKED worktree they diverge.
|
|
192
|
+
const gitMain = (args) => {
|
|
193
|
+
const a = args.join(' ');
|
|
194
|
+
if (a.includes('--show-toplevel')) return '/repo\n';
|
|
195
|
+
if (a.includes('--git-common-dir')) return '.git\n';
|
|
196
|
+
if (a.includes('--git-dir')) return '.git\n';
|
|
197
|
+
throw new Error(`unexpected git call: ${a}`);
|
|
198
|
+
};
|
|
199
|
+
const gitLinked = (args) => {
|
|
200
|
+
const a = args.join(' ');
|
|
201
|
+
if (a.includes('--show-toplevel')) return '/repo/.claude/worktrees/task-1\n';
|
|
202
|
+
if (a.includes('--git-common-dir')) return '/repo/.git\n';
|
|
203
|
+
if (a.includes('--git-dir')) return '/repo/.git/worktrees/task-1\n';
|
|
204
|
+
throw new Error(`unexpected git call: ${a}`);
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
t('resolveWorktreeRoot: identical git-dir and common-dir ⇒ the MAIN checkout', () => {
|
|
208
|
+
const r = resolveWorktreeRoot({ runGit: gitMain, cwd: '/elsewhere' });
|
|
209
|
+
assert.equal(r.root, '/repo');
|
|
210
|
+
assert.equal(r.degraded, false);
|
|
211
|
+
assert.equal(r.isMainCheckout, true);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
t('resolveWorktreeRoot: diverging git-dir ⇒ a LINKED worktree', () => {
|
|
215
|
+
const r = resolveWorktreeRoot({ runGit: gitLinked, cwd: '/elsewhere' });
|
|
216
|
+
assert.equal(r.root, '/repo/.claude/worktrees/task-1');
|
|
217
|
+
assert.equal(r.isMainCheckout, false);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
t('resolveWorktreeRoot: unresolvable tree kind is UNKNOWN (null), never a guess', () => {
|
|
221
|
+
// toplevel works, but the dir probes fail — the kind must not default to either.
|
|
222
|
+
const partial = (args) => {
|
|
223
|
+
if (args.join(' ').includes('--show-toplevel')) return '/repo\n';
|
|
224
|
+
throw new Error('no');
|
|
225
|
+
};
|
|
226
|
+
assert.equal(resolveWorktreeRoot({ runGit: partial, cwd: '/c' }).isMainCheckout, null);
|
|
227
|
+
// And a total git failure still degrades to cwd without throwing.
|
|
228
|
+
const dead = resolveWorktreeRoot({ runGit: () => { throw new Error('no git'); }, cwd: '/here' });
|
|
229
|
+
assert.equal(dead.root, '/here');
|
|
230
|
+
assert.equal(dead.degraded, true);
|
|
231
|
+
assert.equal(dead.isMainCheckout, null);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
t('worktreeGuidance: the main-checkout text DIFFERS from the worktree text', () => {
|
|
235
|
+
// The task's own verify criterion: the guidance must not read the same in both
|
|
236
|
+
// trees. Anything else means the builder is being told the same thing whether
|
|
237
|
+
// it is true or not.
|
|
238
|
+
const mainText = worktreeGuidance({ isMainCheckout: true }).join('\n');
|
|
239
|
+
const wtText = worktreeGuidance({ isMainCheckout: false }).join('\n');
|
|
240
|
+
assert.notEqual(mainText, wtText);
|
|
241
|
+
// The old, wrong sentence must NOT appear in the main checkout.
|
|
242
|
+
assert.doesNotMatch(mainText, /not the main checkout/i,
|
|
243
|
+
'the main checkout must never be told it is not the main checkout');
|
|
244
|
+
assert.match(wtText, /not the main checkout/i, 'a real worktree keeps the original line');
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
t('worktreeGuidance: the main-checkout warning names the CONSEQUENCE, not just the fact', () => {
|
|
248
|
+
const text = worktreeGuidance({ isMainCheckout: true }).join('\n');
|
|
249
|
+
assert.match(text, /MAIN CHECKOUT/);
|
|
250
|
+
assert.match(text, /auto-merge/i, 'says what breaks');
|
|
251
|
+
assert.match(text, /confirmed/, 'and where the ship strands');
|
|
252
|
+
assert.match(text, /git worktree add/, 'and gives the command that avoids it');
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
t('worktreeGuidance: unknown tree kind hedges instead of asserting either', () => {
|
|
256
|
+
for (const w of [{ isMainCheckout: null }, {}, null, undefined]) {
|
|
257
|
+
const text = worktreeGuidance(w).join('\n');
|
|
258
|
+
assert.match(text, /Could not tell/i, `hedged for ${JSON.stringify(w)}`);
|
|
259
|
+
assert.doesNotMatch(text, /THIS IS THE MAIN CHECKOUT/, 'never assert main');
|
|
260
|
+
assert.doesNotMatch(text, /This is the session's tree/, 'never assert worktree');
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
t('formatContextPack: renders the main-checkout WARNING when that is the truth', () => {
|
|
265
|
+
const pack = buildContextPack({
|
|
266
|
+
activeClaims: [{ task_id: 942, title: 'x' }],
|
|
267
|
+
currentTaskId: 942,
|
|
268
|
+
cwd: '/fallback',
|
|
269
|
+
platform: 'linux',
|
|
270
|
+
runGit: gitMain,
|
|
271
|
+
runWhich: fakeWhich({ timeout: '/usr/bin/timeout', psql: '/usr/bin/psql' }),
|
|
272
|
+
});
|
|
273
|
+
const out = formatContextPack(pack);
|
|
274
|
+
assert.match(out, /THIS IS THE MAIN CHECKOUT/);
|
|
275
|
+
assert.doesNotMatch(out, /not the main checkout/i);
|
|
276
|
+
assert.ok(!/undefined/.test(out), 'no undefined leaked into the rendered pack');
|
|
277
|
+
});
|
|
278
|
+
|
|
180
279
|
// ---- formatting ------------------------------------------------------------
|
|
181
280
|
t('formatClaims: empty vs held, with the (this one) marker', () => {
|
|
182
281
|
assert.equal(formatClaims([]), '(none held)');
|
|
@@ -194,16 +293,20 @@ t('formatOs: names the macOS no-timeout case in prose', () => {
|
|
|
194
293
|
});
|
|
195
294
|
|
|
196
295
|
t('formatContextPack: includes worktree root, prefix, a real kind, and warns the wrong-tree footgun', () => {
|
|
296
|
+
// task 1002573: uses a LINKED-worktree stub. It previously passed an
|
|
297
|
+
// args-ignoring stub, which returned the same path for every probe — i.e. the
|
|
298
|
+
// main checkout — while asserting the "not the main checkout" line. The test
|
|
299
|
+
// was encoding the bug.
|
|
197
300
|
const pack = buildContextPack({
|
|
198
301
|
activeClaims: [{ task_id: 942, title: 'x' }],
|
|
199
302
|
currentTaskId: 942,
|
|
200
303
|
cwd: '/fallback',
|
|
201
304
|
platform: 'linux',
|
|
202
|
-
runGit:
|
|
305
|
+
runGit: gitLinked,
|
|
203
306
|
runWhich: fakeWhich({ timeout: '/usr/bin/timeout', psql: '/usr/bin/psql' }),
|
|
204
307
|
});
|
|
205
308
|
const out = formatContextPack(pack);
|
|
206
|
-
assert.match(out,
|
|
309
|
+
assert.match(out, /task-1/);
|
|
207
310
|
assert.match(out, /\/api\/bongos/);
|
|
208
311
|
assert.match(out, /feature/); // a real kind from VALID_KINDS
|
|
209
312
|
assert.match(out, /not the main checkout/i);
|