@bongos/core 1.21.100 → 1.21.101
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 +12 -12
- package/docs/module-api-changelog.md +2 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +6 -0
- package/scripts/gds/worktree.js +21 -2
- package/src/module-api.js +1 -1
- package/tests/worktree_helper.mjs +64 -5
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.21.
|
|
6
|
-
"core_contract": "1.21.
|
|
7
|
-
"source_commit": "
|
|
5
|
+
"core_version": "1.21.101",
|
|
6
|
+
"core_contract": "1.21.101",
|
|
7
|
+
"source_commit": "7858ffa1199248ca5c40837b5f21f0e8ef19d47f",
|
|
8
8
|
"source_ref": "HEAD",
|
|
9
|
-
"built_at": "2026-10-
|
|
9
|
+
"built_at": "2026-10-09T13:00:03.202Z",
|
|
10
10
|
"redaction": {
|
|
11
11
|
"model": "docs-redacted+functional-verbatim",
|
|
12
12
|
"docs_redacted": 592,
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"gate": "passed"
|
|
18
18
|
},
|
|
19
19
|
"file_count": 3640,
|
|
20
|
-
"tree_sha256": "
|
|
20
|
+
"tree_sha256": "02e0d13b4633dbacbe287ad2057cb25994404d346b87f7f87f013d0f367ee8c2",
|
|
21
21
|
"files": [
|
|
22
22
|
{
|
|
23
23
|
"path": ".claude/skills/ask-for-help/SKILL.md",
|
|
@@ -2872,7 +2872,7 @@
|
|
|
2872
2872
|
{
|
|
2873
2873
|
"path": "docs/module-api-changelog.md",
|
|
2874
2874
|
"mode": "0000644",
|
|
2875
|
-
"sha256": "
|
|
2875
|
+
"sha256": "cf3cee3fb9bea331857c69de667438a0c83137849f262712af3de7172e701e26"
|
|
2876
2876
|
},
|
|
2877
2877
|
{
|
|
2878
2878
|
"path": "docs/modules-contract.md",
|
|
@@ -10132,12 +10132,12 @@
|
|
|
10132
10132
|
{
|
|
10133
10133
|
"path": "package-lock.json",
|
|
10134
10134
|
"mode": "0000644",
|
|
10135
|
-
"sha256": "
|
|
10135
|
+
"sha256": "dd270ec93485ddb27786d87ba9eb34a588c39492310114df6c22efb4a99ee447"
|
|
10136
10136
|
},
|
|
10137
10137
|
{
|
|
10138
10138
|
"path": "package.json",
|
|
10139
10139
|
"mode": "0000644",
|
|
10140
|
-
"sha256": "
|
|
10140
|
+
"sha256": "888c5c97454286a61cc39bbe0c14547d92765fa057195303f3f3352410edcfa6"
|
|
10141
10141
|
},
|
|
10142
10142
|
{
|
|
10143
10143
|
"path": "public-docs/index.html",
|
|
@@ -10157,7 +10157,7 @@
|
|
|
10157
10157
|
{
|
|
10158
10158
|
"path": "release-notes.json",
|
|
10159
10159
|
"mode": "0000644",
|
|
10160
|
-
"sha256": "
|
|
10160
|
+
"sha256": "d1156f6a018933ff1c6f4f4481a4089ac754815318468fa5ce6bdd880105bbdb"
|
|
10161
10161
|
},
|
|
10162
10162
|
{
|
|
10163
10163
|
"path": "scripts/cron/style_guide_audit.sh",
|
|
@@ -11932,7 +11932,7 @@
|
|
|
11932
11932
|
{
|
|
11933
11933
|
"path": "scripts/gds/worktree.js",
|
|
11934
11934
|
"mode": "0000644",
|
|
11935
|
-
"sha256": "
|
|
11935
|
+
"sha256": "40aa204dd081022580bbd016b1f2741ebfc4eb9324d4f60a2ac7da9636d813f1"
|
|
11936
11936
|
},
|
|
11937
11937
|
{
|
|
11938
11938
|
"path": "scripts/hall-preview/README.md",
|
|
@@ -12432,7 +12432,7 @@
|
|
|
12432
12432
|
{
|
|
12433
12433
|
"path": "src/module-api.js",
|
|
12434
12434
|
"mode": "0000644",
|
|
12435
|
-
"sha256": "
|
|
12435
|
+
"sha256": "515c7e51fc93bf9b5fe62e46252650d733818c4e9fd6e7ab3e310fbd6593564a"
|
|
12436
12436
|
},
|
|
12437
12437
|
{
|
|
12438
12438
|
"path": "src/module-loader/catalog.js",
|
|
@@ -18207,7 +18207,7 @@
|
|
|
18207
18207
|
{
|
|
18208
18208
|
"path": "tests/worktree_helper.mjs",
|
|
18209
18209
|
"mode": "0000644",
|
|
18210
|
-
"sha256": "
|
|
18210
|
+
"sha256": "0dea42cbad0d17eb63e516a6812050b239c51b0f2f2d13c3a949eff27ec44657"
|
|
18211
18211
|
},
|
|
18212
18212
|
{
|
|
18213
18213
|
"path": "tests/world_tokens.mjs",
|
|
@@ -3037,5 +3037,7 @@ is load-bearing: the script throws rather than guess if it is missing, and
|
|
|
3037
3037
|
landed since 1.21.98 with no explicit bump. run 37927704012. (task 1002620)
|
|
3038
3038
|
1.21.100 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
3039
3039
|
landed since 1.21.99 with no explicit bump. run 37931583687. (task 1002620)
|
|
3040
|
+
1.21.101 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
3041
|
+
landed since 1.21.100 with no explicit bump. run 37933684016. (task 1002620)
|
|
3040
3042
|
---------------------------------------------------------------------------
|
|
3041
3043
|
```
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.21.
|
|
3
|
+
"version": "1.21.101",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@bongos/core",
|
|
9
|
-
"version": "1.21.
|
|
9
|
+
"version": "1.21.101",
|
|
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.21.
|
|
3
|
+
"version": "1.21.101",
|
|
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",
|
package/release-notes.json
CHANGED
|
@@ -9438,5 +9438,11 @@
|
|
|
9438
9438
|
"id": "1004659",
|
|
9439
9439
|
"text": "There is now a plain-language guide to how a project's government works: GOVERNMENT.md, linked from the README and the hall primer. It explains the four forms you can pick today, who votes and how many must agree, who decides"
|
|
9440
9440
|
}
|
|
9441
|
+
],
|
|
9442
|
+
"1.21.101": [
|
|
9443
|
+
{
|
|
9444
|
+
"id": "1004582",
|
|
9445
|
+
"text": "Cleaning up a finished worktree no longer crashes on Linux and Mac machines. It used to stop halfway and leave the old workspace registered; now it removes the shortcut to the shared packages safely and carries on."
|
|
9446
|
+
}
|
|
9441
9447
|
]
|
|
9442
9448
|
}
|
package/scripts/gds/worktree.js
CHANGED
|
@@ -173,6 +173,24 @@ function nodeModulesState(wtPath) {
|
|
|
173
173
|
return st.isSymbolicLink() ? 'junction' : 'real-dir';
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
+
// Remove a node_modules LINK without ever following it (task 1004582). rmdir is
|
|
177
|
+
// only right for a Windows junction: on Linux/macOS (cloud containers) the link
|
|
178
|
+
// is a plain symlink and rmdir throws ENOTDIR, leaving the worktree registered.
|
|
179
|
+
// unlink removes the link itself on every platform — libuv unlinks a junction
|
|
180
|
+
// too — and refuses a real directory outright, so it can never delete contents.
|
|
181
|
+
// The win32 rmdir fallback covers a reparse point unlink will not take.
|
|
182
|
+
function unlinkNodeModulesLink(linkPath, { platform = process.platform, fsImpl = fs } = {}) {
|
|
183
|
+
if (!fsImpl.lstatSync(linkPath).isSymbolicLink()) {
|
|
184
|
+
throw new Error(`${linkPath} is not a link — refusing to remove a real directory`);
|
|
185
|
+
}
|
|
186
|
+
try {
|
|
187
|
+
fsImpl.unlinkSync(linkPath);
|
|
188
|
+
} catch (e) {
|
|
189
|
+
if (platform !== 'win32' || (e.code !== 'EPERM' && e.code !== 'EISDIR')) throw e;
|
|
190
|
+
fsImpl.rmdirSync(linkPath); // on a junction, rmdir removes the LINK only
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
176
194
|
function resolveWorktreePath(root, nameOrPath) {
|
|
177
195
|
const all = listWorktrees(root);
|
|
178
196
|
const norm = (p) => path.resolve(p).replace(/\\/g, '/').toLowerCase();
|
|
@@ -296,8 +314,8 @@ function cmdRemove(root, argv) {
|
|
|
296
314
|
const state = nodeModulesState(wtPath);
|
|
297
315
|
for (const step of removalPlan({ nodeModulesState: state })) {
|
|
298
316
|
if (step === 'unlink-junction') {
|
|
299
|
-
//
|
|
300
|
-
|
|
317
|
+
// Removes the LINK only, never the target's contents — junction or symlink.
|
|
318
|
+
unlinkNodeModulesLink(path.join(wtPath, 'node_modules'));
|
|
301
319
|
console.log(' removed node_modules junction (link only — the shared node_modules is untouched)');
|
|
302
320
|
} else {
|
|
303
321
|
const args = ['worktree', 'remove', ...(hasFlag('--force', argv) ? ['--force'] : []), wtPath];
|
|
@@ -427,4 +445,5 @@ if (require.main === module) main();
|
|
|
427
445
|
|
|
428
446
|
module.exports = {
|
|
429
447
|
worktreeNameFor, needsJunction, removalPlan, nodeModulesState, shadowingNodeModules, huskDisposition,
|
|
448
|
+
unlinkNodeModulesLink,
|
|
430
449
|
};
|
package/src/module-api.js
CHANGED
|
@@ -75,7 +75,7 @@ const { responsibilityFor, ROLE_RESPONSIBILITIES } = require('./role-responsibil
|
|
|
75
75
|
// MAJOR (see allowBoxScope below): passes the request through untouched.
|
|
76
76
|
function deprecatedNoopMiddleware(_req, _res, next) { next(); }
|
|
77
77
|
|
|
78
|
-
const CORE_VERSION = '1.21.
|
|
78
|
+
const CORE_VERSION = '1.21.101'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
|
|
79
79
|
|
|
80
80
|
// A namespaced logger so a module's log lines are attributable + consistent.
|
|
81
81
|
// Usage: const log = api.logger('discord'); log.info('mounted');
|
|
@@ -27,7 +27,7 @@ import os from 'node:os';
|
|
|
27
27
|
import path from 'node:path';
|
|
28
28
|
|
|
29
29
|
const require = createRequire(import.meta.url);
|
|
30
|
-
const { worktreeNameFor, needsJunction, removalPlan, nodeModulesState, shadowingNodeModules, huskDisposition } = require('../scripts/gds/worktree.js');
|
|
30
|
+
const { worktreeNameFor, needsJunction, removalPlan, nodeModulesState, shadowingNodeModules, huskDisposition, unlinkNodeModulesLink } = require('../scripts/gds/worktree.js');
|
|
31
31
|
|
|
32
32
|
const HOUR = 60 * 60 * 1000;
|
|
33
33
|
|
|
@@ -118,16 +118,75 @@ test('nodeModulesState: absent / real-dir / junction classified from disk', () =
|
|
|
118
118
|
fs.symlinkSync(target, link, 'junction');
|
|
119
119
|
eq(nodeModulesState(wtJct), 'junction');
|
|
120
120
|
|
|
121
|
-
// Removing the link (the helper's unlink step) must not touch the target.
|
|
122
|
-
//
|
|
123
|
-
//
|
|
124
|
-
|
|
121
|
+
// Removing the link (the helper's own unlink step) must not touch the target.
|
|
122
|
+
// On Linux CI this is a plain dir-symlink — the case rmdir crashed on with
|
|
123
|
+
// ENOTDIR (task 1004582); on Windows it is a real junction.
|
|
124
|
+
unlinkNodeModulesLink(link);
|
|
125
|
+
eq(fs.existsSync(link), false, 'the link itself is gone');
|
|
125
126
|
eq(fs.existsSync(path.join(target, 'canary.txt')), true, 'target survives link removal');
|
|
126
127
|
} finally {
|
|
127
128
|
fs.rmSync(base, { recursive: true, force: true });
|
|
128
129
|
}
|
|
129
130
|
});
|
|
130
131
|
|
|
132
|
+
// The win32 rmdir fallback, driven through a fake fs so every platform runs it.
|
|
133
|
+
function fakeFs(unlinkCode) {
|
|
134
|
+
const calls = [];
|
|
135
|
+
return {
|
|
136
|
+
calls,
|
|
137
|
+
lstatSync: () => ({ isSymbolicLink: () => true }),
|
|
138
|
+
unlinkSync: (p) => {
|
|
139
|
+
calls.push(['unlink', p]);
|
|
140
|
+
if (unlinkCode) { const e = new Error(unlinkCode); e.code = unlinkCode; throw e; }
|
|
141
|
+
},
|
|
142
|
+
rmdirSync: (p) => { calls.push(['rmdir', p]); },
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
test('unlinkNodeModulesLink: unlink succeeds → rmdir is never called', () => {
|
|
147
|
+
const f = fakeFs(null);
|
|
148
|
+
unlinkNodeModulesLink('L', { platform: 'linux', fsImpl: f });
|
|
149
|
+
eqArr(f.calls, [['unlink', 'L']]);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
for (const code of ['EPERM', 'EISDIR']) {
|
|
153
|
+
test(`unlinkNodeModulesLink: win32 + ${code} falls back to rmdir`, () => {
|
|
154
|
+
const f = fakeFs(code);
|
|
155
|
+
unlinkNodeModulesLink('L', { platform: 'win32', fsImpl: f });
|
|
156
|
+
eqArr(f.calls, [['unlink', 'L'], ['rmdir', 'L']]);
|
|
157
|
+
});
|
|
158
|
+
test(`unlinkNodeModulesLink: non-win32 + ${code} rethrows, no rmdir`, () => {
|
|
159
|
+
const f = fakeFs(code);
|
|
160
|
+
let thrown = null;
|
|
161
|
+
try { unlinkNodeModulesLink('L', { platform: 'linux', fsImpl: f }); } catch (e) { thrown = e.code; }
|
|
162
|
+
eq(thrown, code);
|
|
163
|
+
eqArr(f.calls, [['unlink', 'L']]);
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
test('unlinkNodeModulesLink: win32 + any other code rethrows, no rmdir', () => {
|
|
168
|
+
const f = fakeFs('EBUSY');
|
|
169
|
+
let thrown = null;
|
|
170
|
+
try { unlinkNodeModulesLink('L', { platform: 'win32', fsImpl: f }); } catch (e) { thrown = e.code; }
|
|
171
|
+
eq(thrown, 'EBUSY');
|
|
172
|
+
eqArr(f.calls, [['unlink', 'L']]);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
test('unlinkNodeModulesLink refuses a REAL directory and leaves it intact', () => {
|
|
176
|
+
const base = fs.mkdtempSync(path.join(os.tmpdir(), 'wt-helper-test-'));
|
|
177
|
+
try {
|
|
178
|
+
const real = path.join(base, 'node_modules');
|
|
179
|
+
fs.mkdirSync(real);
|
|
180
|
+
fs.writeFileSync(path.join(real, 'canary.txt'), 'x');
|
|
181
|
+
let threw = false;
|
|
182
|
+
try { unlinkNodeModulesLink(real); } catch (_) { threw = true; }
|
|
183
|
+
eq(threw, true, 'a real dir is refused');
|
|
184
|
+
eq(fs.existsSync(path.join(real, 'canary.txt')), true, 'its contents survive');
|
|
185
|
+
} finally {
|
|
186
|
+
fs.rmSync(base, { recursive: true, force: true });
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
|
|
131
190
|
// ---- 3. removalPlan — junction-first ordering is the whole point ----
|
|
132
191
|
|
|
133
192
|
test('junction node_modules: unlink FIRST, then git worktree remove', () => {
|