@bongos/core 1.19.683 → 1.19.685

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 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.683",
6
- "core_contract": "1.19.683",
7
- "source_commit": "40eeb484085efb69d5aaa3645233d23854e2bbc1",
5
+ "core_version": "1.19.685",
6
+ "core_contract": "1.19.685",
7
+ "source_commit": "b1f9d9ab3a9892d6ccca5a2624ffbe732f23b98b",
8
8
  "source_ref": "HEAD",
9
- "built_at": "2026-09-12T17:02:13.044Z",
9
+ "built_at": "2026-09-12T21:13:17.682Z",
10
10
  "redaction": {
11
11
  "model": "docs-redacted+functional-verbatim",
12
12
  "docs_redacted": 477,
@@ -17,7 +17,7 @@
17
17
  "gate": "passed"
18
18
  },
19
19
  "file_count": 2626,
20
- "tree_sha256": "aa8a467c8dcd7322882229d5b60da130eb5b67e726e38a0dde2b34d2ce6bfa4a",
20
+ "tree_sha256": "39b75c53e1b9736b4820105974401f9c9a67a3b5ed629b7434c0272f0a64d5eb",
21
21
  "files": [
22
22
  {
23
23
  "path": ".claude/skills/ask-for-help/SKILL.md",
@@ -2802,7 +2802,7 @@
2802
2802
  {
2803
2803
  "path": "docs/module-api-changelog.md",
2804
2804
  "mode": "0000644",
2805
- "sha256": "abe1e67ec7bd2d5d4bf27a2b5d8b4337fc1d4b7374c1edab6c5392016a83fde3"
2805
+ "sha256": "aa474c62aed632c8ff75731a38bf22b286866cb6aa30953a64f2ea46e3c83ee2"
2806
2806
  },
2807
2807
  {
2808
2808
  "path": "docs/modules-contract.md",
@@ -7782,12 +7782,12 @@
7782
7782
  {
7783
7783
  "path": "package-lock.json",
7784
7784
  "mode": "0000644",
7785
- "sha256": "81888175ae0227d30c633c8f51a25936418cfdbf1d36c77bdd7c329d41d0c429"
7785
+ "sha256": "e1896f085954a25abf57b98c3e16dc53825a88f657cb70f0839e65cf45960cdc"
7786
7786
  },
7787
7787
  {
7788
7788
  "path": "package.json",
7789
7789
  "mode": "0000644",
7790
- "sha256": "b5cd5f5c6b24980f4b85986be1919f4cb2697c3ba219277d51b1ef07de72343b"
7790
+ "sha256": "4f32692ff1a262f499c156645e05890e5814346a1ddbe081846bfbebaf3c6f20"
7791
7791
  },
7792
7792
  {
7793
7793
  "path": "public-docs/index.html",
@@ -8287,7 +8287,7 @@
8287
8287
  {
8288
8288
  "path": "scripts/gds/gen-api-client.js",
8289
8289
  "mode": "0000644",
8290
- "sha256": "2d8b35709e19b339bc55c57237f2add36fa6bdeb83a9b036faa902b0c4b8e3f9"
8290
+ "sha256": "a023a19001d63b671409efe1afeae400dae96ea50debd6e3a49a7d10dffb55b0"
8291
8291
  },
8292
8292
  {
8293
8293
  "path": "scripts/gds/gen-api-docs.js",
@@ -9547,7 +9547,7 @@
9547
9547
  {
9548
9548
  "path": "src/module-api.js",
9549
9549
  "mode": "0000644",
9550
- "sha256": "2adaf10cbc0a2e65aeaa820f95b2b789c8e66c398c5f56299e9d1f52e82b86a1"
9550
+ "sha256": "50802a77ae69160c8c739f40a02cae66c61bfd200e3d9a6d6be4024baa382793"
9551
9551
  },
9552
9552
  {
9553
9553
  "path": "src/module-loader/catalog.js",
@@ -9667,7 +9667,7 @@
9667
9667
  {
9668
9668
  "path": "tests/api_client.mjs",
9669
9669
  "mode": "0000644",
9670
- "sha256": "fa360a42fa5d11b225afe1b13622f2a27fe43f2b7d0a47c2fef158bc8a11ecb6"
9670
+ "sha256": "c1563c043f34e84aa6c0eec722244b24c51dc1254750fe1a27d3664c327bacd1"
9671
9671
  },
9672
9672
  {
9673
9673
  "path": "tests/api_docs.mjs",
@@ -9972,7 +9972,7 @@
9972
9972
  {
9973
9973
  "path": "tests/box_infra_resolve.mjs",
9974
9974
  "mode": "0000644",
9975
- "sha256": "99209d0e407333bdd00236f0efe9ea63a94678bc206e1c5ae2995f76381f87fd"
9975
+ "sha256": "cf261fa549f36d47ee42343bac2a297b132638aedf03beb8f521370b0c45c0e3"
9976
9976
  },
9977
9977
  {
9978
9978
  "path": "tests/box_onboard.mjs",
@@ -1825,5 +1825,9 @@ is load-bearing: the script throws rather than guess if it is missing, and
1825
1825
  landed since 1.19.681 with no explicit bump. run 34704993368. (task 1002620)
1826
1826
  1.19.683 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
1827
1827
  landed since 1.19.682 with no explicit bump. run 34706984747. (task 1002620)
1828
+ 1.19.684 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
1829
+ landed since 1.19.683 with no explicit bump. run 34718471740. (task 1002620)
1830
+ 1.19.685 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
1831
+ landed since 1.19.684 with no explicit bump. run 34719298791. (task 1002620)
1828
1832
  ---------------------------------------------------------------------------
1829
1833
  ```
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.19.683",
3
+ "version": "1.19.685",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.19.683",
9
+ "version": "1.19.685",
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.683",
3
+ "version": "1.19.685",
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",
@@ -21,6 +21,7 @@
21
21
  const fs = require('node:fs');
22
22
  const path = require('node:path');
23
23
  const { resolveDocsRoot } = require('../../src/instance-config');
24
+ const { sameContent } = require('./gen-freshness'); // eol-insensitive freshness (CRLF checkouts)
24
25
 
25
26
  // The client is generated FROM the spec and lives beside it as a per-instance
26
27
  // artifact: both resolve to the DOCS root — the instance repo when a consumer
@@ -516,7 +517,15 @@ function main() {
516
517
  for (const [name, content] of Object.entries(files)) {
517
518
  const dest = path.join(OUT_DIR, name);
518
519
  const existing = fs.existsSync(dest) ? fs.readFileSync(dest, 'utf8') : null;
519
- if (existing !== content) {
520
+ // Freshness is a question about CONTENT, so compare content (task 1003844 — the
521
+ // same defect as 1003619). We render with join('\n') = LF, but a core.autocrlf
522
+ // checkout hands readFileSync back CRLF, so a byte-wise `!==` called the already
523
+ // -correct client STALE on every Windows clone, forever: regenerating writes LF,
524
+ // git restores CRLF, gate red again. Comparing via sameContent cures it for every
525
+ // file here at once, so a seventh generated file can't reintroduce it by missing
526
+ // an eol pin. A missing file reads as null, which never matches a non-empty
527
+ // render — still stale, as before.
528
+ if (!sameContent(existing, content)) {
520
529
  stale = true;
521
530
  if (!check) { fs.mkdirSync(OUT_DIR, { recursive: true }); fs.writeFileSync(dest, content); }
522
531
  }
package/src/module-api.js CHANGED
@@ -71,7 +71,7 @@ const { responsibilityFor, ROLE_RESPONSIBILITIES } = require('./role-responsibil
71
71
  // there. scripts/gds/bump-version.js still rewrites the literal below; it appends
72
72
  // the entry to that file. Look for a version's history there, not here.
73
73
  // ---------------------------------------------------------------------------
74
- const CORE_VERSION = '1.19.683'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
74
+ const CORE_VERSION = '1.19.685'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
75
75
 
76
76
  // A namespaced logger so a module's log lines are attributable + consistent.
77
77
  // Usage: const log = api.logger('dev-box'); log.info('mounted');
@@ -11,12 +11,15 @@ import { strict as assert } from 'node:assert';
11
11
  import { test } from 'node:test';
12
12
  import { createRequire } from 'node:module';
13
13
  import fs from 'node:fs';
14
+ import os from 'node:os';
14
15
  import path from 'node:path';
16
+ import { spawnSync } from 'node:child_process';
15
17
  import { fileURLToPath } from 'node:url';
16
18
  import { createClient, ApiError, API_VERSION, DEFAULT_BASE_URL } from '../clients/bongos-client/index.mjs';
17
19
 
18
20
  const require = createRequire(import.meta.url);
19
21
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
22
+ const { sameContent } = require(path.join(ROOT, 'scripts', 'gds', 'gen-freshness.js'));
20
23
 
21
24
  function fakeFetch(recorder, response = { ok: true, status: 200, body: { ok: true } }) {
22
25
  return async (url, init) => {
@@ -149,12 +152,21 @@ test('baseUrl:"" is honored (absolute-path passthrough for the hall fetch wrappe
149
152
  assert.deepEqual(res, { status: 200, ok: true, data: { x: 1 } });
150
153
  });
151
154
 
155
+ // The CI-gate twin of `gen-api-client.js --check`, and it carried the SAME defect
156
+ // (task 1003844): a byte-wise assert.equal against a CRLF working copy failed on
157
+ // every Windows checkout, forever — index.d.ts and README.md have no eol pin, so
158
+ // core.autocrlf hands them back CRLF while the generator renders LF. Compare with
159
+ // sameContent for the same reason gen-freshness.js exists; a real content change
160
+ // still fails, which tests/gen_freshness.mjs pins.
152
161
  test('committed client is fresh (regenerate with gen-api-client.js if this fails)', () => {
153
162
  const gen = require('../scripts/gds/gen-api-client.js');
154
163
  const { files } = gen.build();
155
164
  for (const [name, content] of Object.entries(files)) {
156
165
  const onDisk = fs.readFileSync(path.join(ROOT, 'clients/bongos-client', name), 'utf8');
157
- assert.equal(onDisk, content, `clients/bongos-client/${name} is STALE — run node scripts/gds/gen-api-client.js`);
166
+ assert.ok(
167
+ sameContent(onDisk, content),
168
+ `clients/bongos-client/${name} is STALE — run node scripts/gds/gen-api-client.js`,
169
+ );
158
170
  }
159
171
  });
160
172
 
@@ -245,3 +257,49 @@ test('browser-global build exposes window.BongosClient and shapes requests ident
245
257
  assert.equal(rec.init.headers.Authorization, 'Bearer tok');
246
258
  assert.equal(rec.init.body, JSON.stringify({ a: 1 }));
247
259
  });
260
+
261
+ // --- the --check gate itself (task 1003844) ---------------------------------
262
+ //
263
+ // The assertions above compare the client this checkout HAS, so they can only ever
264
+ // see the eol convention this checkout happens to use. The bug lived in the other
265
+ // direction: a Windows clone whose committed client is already correct was told it
266
+ // was STALE, forever. So drive the real CLI against a throwaway docs root where we
267
+ // control the line endings, and pin BOTH halves — the eol-only case must pass, and
268
+ // a genuine edit must still fail, which is what stops an over-broad "fix" (the same
269
+ // pairing tests/gen_freshness.mjs makes for the helper).
270
+ function runGen(root, args = []) {
271
+ return spawnSync(process.execPath, [path.join(ROOT, 'scripts/gds/gen-api-client.js'), ...args], {
272
+ encoding: 'utf8',
273
+ env: { ...process.env, BONGOS_INSTANCE_ROOT: root },
274
+ });
275
+ }
276
+
277
+ test('--check reads a CRLF working copy as fresh, and a real edit as stale (task 1003844)', () => {
278
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), 'gen-api-client-'));
279
+ try {
280
+ fs.mkdirSync(path.join(root, 'docs', 'api'), { recursive: true });
281
+ fs.copyFileSync(path.join(ROOT, 'docs/api/openapi.json'), path.join(root, 'docs/api/openapi.json'));
282
+
283
+ const wrote = runGen(root);
284
+ assert.equal(wrote.status, 0, `generator failed: ${wrote.stderr}`);
285
+
286
+ // What a core.autocrlf=true checkout hands back for the two files with no eol
287
+ // pin. Nothing about the CONTENT changed, so --check must stay quiet.
288
+ for (const name of ['index.d.ts', 'README.md']) {
289
+ const f = path.join(root, 'clients/bongos-client', name);
290
+ fs.writeFileSync(f, fs.readFileSync(f, 'utf8').replace(/\n/g, '\r\n'));
291
+ }
292
+ const fresh = runGen(root, ['--check']);
293
+ assert.equal(fresh.status, 0, `CRLF must not read as STALE — this is the bug: ${fresh.stderr}`);
294
+ assert.match(fresh.stdout, /is fresh/);
295
+
296
+ // ...and the gate is still a gate.
297
+ const target = path.join(root, 'clients/bongos-client/index.mjs');
298
+ fs.writeFileSync(target, `${fs.readFileSync(target, 'utf8')}\nexport const SMUGGLED = 1;\n`);
299
+ const stale = runGen(root, ['--check']);
300
+ assert.equal(stale.status, 2, 'a real content change must still exit 2');
301
+ assert.match(stale.stderr, /STALE/);
302
+ } finally {
303
+ fs.rmSync(root, { recursive: true, force: true });
304
+ }
305
+ });
@@ -69,22 +69,30 @@ function makeInfra({ template = true, inlined = INLINED } = {}) {
69
69
  // ===========================================================================
70
70
  // boxInfraCandidates — ordering (pure, injected; ADR 0150 prong A)
71
71
  // ===========================================================================
72
+ // Expected candidates are built with path.join/path.resolve — the same calls
73
+ // boxInfraCandidates makes — never as literal POSIX strings (task 1003821). A
74
+ // hardcoded '/inst/infra' is 'C:\inst\infra' once the code has run it through
75
+ // path.resolve, so these two tests were permanently red for every Windows builder
76
+ // while ubuntu CI stayed green. A known-noise entry in a local baseline is the
77
+ // thing that teaches a reader to skim the fail list instead of diffing it by name.
78
+ const VENDORED_ROOT = '/srv/app/node_modules/@bongos/core';
79
+
72
80
  await test('candidate order: override → explicit instance root → repoRoot → node_modules walk-up', () => {
73
- const env = { CLOUDBONGOS_BOX_INFRA_DIR: '/ovr', CLOUDBONGOS_INSTANCE_ROOT: '/inst' };
74
- const c = box.boxInfraCandidates({ env, repoRoot: '/srv/app/node_modules/@bongos/core' });
81
+ const env = { BONGOS_BOX_INFRA_DIR: '/ovr', BONGOS_INSTANCE_ROOT: '/inst' };
82
+ const c = box.boxInfraCandidates({ env, repoRoot: VENDORED_ROOT });
75
83
  assert.equal(c[0], path.resolve('/ovr'), 'explicit override is first');
76
- assert.equal(c[1], path.join('/inst', 'infra'), 'then the explicit instance root');
77
- assert.equal(c[2], '/srv/app/node_modules/@bongos/core/infra', 'then REPO_ROOT/infra');
84
+ assert.equal(c[1], path.join(path.resolve('/inst'), 'infra'), 'then the explicit instance root');
85
+ assert.equal(c[2], path.join(VENDORED_ROOT, 'infra'), 'then REPO_ROOT/infra');
78
86
  // the load-bearing case: a vendored core walks UP out of node_modules to its host
79
87
  // instance root, so infra/ is found with no pointer at all.
80
- assert.ok(c.includes('/srv/app/infra'), 'walk-up recovers the host instance root infra/');
88
+ assert.ok(c.includes(path.join('/srv/app', 'infra')), 'walk-up recovers the host instance root infra/');
81
89
  });
82
90
 
83
91
  await test('repoRoot/infra precedes its ancestors in the walk-up (robust to any cwd pointer)', () => {
84
92
  const c = box.boxInfraCandidates({ env: {}, repoRoot: '/x/y/z' });
85
- const i0 = c.indexOf('/x/y/z/infra');
86
- const i1 = c.indexOf('/x/y/infra');
87
- const i2 = c.indexOf('/x/infra');
93
+ const i0 = c.indexOf(path.join('/x/y/z', 'infra'));
94
+ const i1 = c.indexOf(path.join('/x/y', 'infra'));
95
+ const i2 = c.indexOf(path.join('/x', 'infra'));
88
96
  assert.ok(i0 >= 0 && i1 > i0 && i2 > i1, 'repoRoot/infra, then /x/y/infra, then /x/infra — in order');
89
97
  });
90
98
 
@@ -93,7 +101,7 @@ await test('repoRoot/infra precedes its ancestors in the walk-up (robust to any
93
101
  // ===========================================================================
94
102
  await test('resolveBoxInfraDir picks the override dir when it holds the template', () => {
95
103
  const { infra } = makeInfra();
96
- const got = box.resolveBoxInfraDir({ env: { CLOUDBONGOS_BOX_INFRA_DIR: infra }, repoRoot: '/nope/does/not/exist' });
104
+ const got = box.resolveBoxInfraDir({ env: { BONGOS_BOX_INFRA_DIR: infra }, repoRoot: '/nope/does/not/exist' });
97
105
  assert.equal(got, infra);
98
106
  });
99
107
 
@@ -103,7 +111,7 @@ await test('resolveBoxInfraDir falls THROUGH a template-less override to the ins
103
111
  const { infra } = makeInfra(); // a real infra/ to fall through to
104
112
  const instRoot = path.dirname(infra); // <root>, so <root>/infra === the real one
105
113
  const got = box.resolveBoxInfraDir({
106
- env: { CLOUDBONGOS_BOX_INFRA_DIR: emptyOverride, CLOUDBONGOS_INSTANCE_ROOT: instRoot },
114
+ env: { BONGOS_BOX_INFRA_DIR: emptyOverride, BONGOS_INSTANCE_ROOT: instRoot },
107
115
  repoRoot: '/nope',
108
116
  });
109
117
  assert.equal(got, infra, 'skips the template-less override, takes the instance-root infra/');