@bongos/core 1.19.131 → 1.19.132

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,22 +2,22 @@
2
2
  "artifact": "bongos-core",
3
3
  "manifest_schema": 1,
4
4
  "generator": "scripts/gds/package-core.js",
5
- "core_version": "1.19.131",
6
- "core_contract": "1.19.131",
7
- "source_commit": "7fc91a6722c91cd40c09ce632c2a765377952e49",
5
+ "core_version": "1.19.132",
6
+ "core_contract": "1.19.132",
7
+ "source_commit": "450f890ee24a473026548ea2cf82cf69ac1d6d9c",
8
8
  "source_ref": "HEAD",
9
- "built_at": "2026-08-15T03:23:58.787Z",
9
+ "built_at": "2026-08-15T03:38:15.933Z",
10
10
  "redaction": {
11
11
  "model": "docs-redacted+functional-verbatim",
12
12
  "docs_redacted": 303,
13
13
  "agent_docs_stubbed": 21,
14
- "functional_verbatim": 1247,
14
+ "functional_verbatim": 1248,
15
15
  "rules": 3,
16
16
  "gate_literals": 3,
17
17
  "gate": "passed"
18
18
  },
19
- "file_count": 1571,
20
- "tree_sha256": "81215c25cbaed99553dba15247df2e2f9daf37245d8144df0a5e32b507b4c0b9",
19
+ "file_count": 1572,
20
+ "tree_sha256": "d0e21da3aa85bb9e774ef6c921a2cc4be514b8dab592b7a1b3fa8bb07e8be485",
21
21
  "files": [
22
22
  {
23
23
  "path": ".claude/skills/blocker-review/SKILL.md",
@@ -4172,12 +4172,12 @@
4172
4172
  {
4173
4173
  "path": "package-lock.json",
4174
4174
  "mode": "0000644",
4175
- "sha256": "ad651e607ce3937ca8522552d21ecfbaa03108734f9c7987c79a2e8ef8a7c7f3"
4175
+ "sha256": "26a0143ba944f1edf0c163992ecd6f447fa911d16d7b8161578c7b1bc6725a48"
4176
4176
  },
4177
4177
  {
4178
4178
  "path": "package.json",
4179
4179
  "mode": "0000644",
4180
- "sha256": "178ddf3d5958c428d370e3381cdca505455abe6006b9f920245de0062bc2d5aa"
4180
+ "sha256": "763b31a597012a53b4f7b6c0c0ce9a30e10ba13206468820d16dcc5d04d972ec"
4181
4181
  },
4182
4182
  {
4183
4183
  "path": "public-docs/index.html",
@@ -4767,7 +4767,7 @@
4767
4767
  {
4768
4768
  "path": "scripts/gds/docs-entropy.js",
4769
4769
  "mode": "0000644",
4770
- "sha256": "afeea5e6c75a8cb7ac9bb8ee3eefc828102866dc3ae6836b0dc28946c56cb330"
4770
+ "sha256": "1a7cbe47158e4de63c1b788d6bb4f682584723a45c1824ab2ae3fbf92a54fbce"
4771
4771
  },
4772
4772
  {
4773
4773
  "path": "scripts/gds/doctor.js",
@@ -5762,7 +5762,7 @@
5762
5762
  {
5763
5763
  "path": "src/module-api.js",
5764
5764
  "mode": "0000644",
5765
- "sha256": "fd76c822f4e795248c2c010052dab9cce8cc237a5f501fbf90e66c413c58eac6"
5765
+ "sha256": "9754ad61248f7a9ccf1b4361bf7de1895318872a4994f74f53668151c60f8aeb"
5766
5766
  },
5767
5767
  {
5768
5768
  "path": "src/module-loader/catalog.js",
@@ -6242,7 +6242,7 @@
6242
6242
  {
6243
6243
  "path": "tests/cloud_bongos_pack.mjs",
6244
6244
  "mode": "0000644",
6245
- "sha256": "715fecde91ee9dff56dfca9b9da46a47b49322b0dd50aad1bd606491f551fe06"
6245
+ "sha256": "087d0379a559ebb858e8e42458754cfb93720a5222e5f85fb81995851ce811be"
6246
6246
  },
6247
6247
  {
6248
6248
  "path": "tests/conductor.mjs",
@@ -6484,6 +6484,11 @@
6484
6484
  "mode": "0000644",
6485
6485
  "sha256": "d9fd04cc3f2fcb3b4a9945c1e743c44445a216a10648fa619f74716b381468f3"
6486
6486
  },
6487
+ {
6488
+ "path": "tests/docs_entropy.mjs",
6489
+ "mode": "0000644",
6490
+ "sha256": "4d64164d45d6b81d706074b8394da4f3d0f7f8c5263a37a287a163d6a746a96b"
6491
+ },
6487
6492
  {
6488
6493
  "path": "tests/docs_openapi_route.mjs",
6489
6494
  "mode": "0000644",
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.19.131",
3
+ "version": "1.19.132",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.19.131",
9
+ "version": "1.19.132",
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.131",
3
+ "version": "1.19.132",
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",
@@ -16,37 +16,50 @@
16
16
  //
17
17
  // Exit codes:
18
18
  // 0 scan complete
19
- // 1 fatal error
19
+ // 1 fatal error (including a scan defect: zero markdown files enumerated)
20
20
 
21
21
  'use strict';
22
22
 
23
23
  const fs = require('node:fs');
24
24
  const path = require('node:path');
25
- const { execSync } = require('node:child_process');
26
- const { hasFlag, cliClient, requireSession } = require('./cli-lib');
25
+ const { execFileSync } = require('node:child_process');
26
+ const { hasFlag, cliClient, requireSession, cliExit } = require('./cli-lib');
27
27
 
28
28
  const REPO_ROOT = path.resolve(__dirname, '..', '..');
29
29
  const MIN_DUPE_CHARS = 120; // minimum paragraph length to flag as duplicate
30
30
  const MAX_DUPES_REPORTED = 20; // cap to avoid flooding the report
31
31
 
32
- // Shell helper — returns stdout or null on failure.
33
- function sh(cmd) {
32
+ // ---------- file collection ----------
33
+
34
+ // argv array, never a shell string: `git ls-files '*.md'` as a string runs
35
+ // through cmd.exe on Windows, where the quotes are literal, so git matched
36
+ // nothing and the whole scan reported on zero files (task 1002526).
37
+ function gitLsFiles(args) {
34
38
  try {
35
- return execSync(cmd, {
39
+ return execFileSync('git', args, {
36
40
  cwd: REPO_ROOT,
37
41
  encoding: 'utf8',
38
- stdio: ['ignore', 'pipe', 'ignore'],
39
- }).trim();
40
- } catch (_) {
41
- return null;
42
+ stdio: ['ignore', 'pipe', 'pipe'],
43
+ });
44
+ } catch (err) {
45
+ const detail = String(err.stderr || err.message || '').trim();
46
+ throw new Error(`docs-entropy: \`git ${args.join(' ')}\` failed in ${REPO_ROOT}: ${detail}`);
42
47
  }
43
48
  }
44
49
 
45
- // ---------- file collection ----------
46
-
47
- function collectMarkdownFiles() {
48
- const out = sh("git ls-files '*.md'");
49
- return out ? out.split('\n').map(f => f.trim()).filter(Boolean) : [];
50
+ // Throws rather than returning [] — an empty enumeration in a repo that tracks
51
+ // hundreds of .md files is a broken scan, and a lint that silently reports on
52
+ // nothing is worse than one that fails.
53
+ function collectMarkdownFiles({ run = gitLsFiles } = {}) {
54
+ const out = run(['ls-files', '*.md']);
55
+ const files = String(out || '').split('\n').map(f => f.trim()).filter(Boolean);
56
+ if (!files.length) {
57
+ throw new Error(
58
+ `docs-entropy: scan defect — enumerated 0 tracked markdown files under ${REPO_ROOT}. ` +
59
+ 'This repo tracks hundreds, so this is a broken scan (bad git invocation or wrong cwd), not a clean result.'
60
+ );
61
+ }
62
+ return files;
50
63
  }
51
64
 
52
65
  // ---------- parsing ----------
@@ -326,10 +339,12 @@ async function docsEntropyMain() {
326
339
  const fileIdeas = hasFlag('--file-ideas', args);
327
340
  const verbose = hasFlag('--verbose', args);
328
341
 
329
- const relFiles = collectMarkdownFiles();
330
- if (!relFiles.length) {
331
- console.error('docs-entropy: no tracked markdown files found');
332
- process.exit(1);
342
+ let relFiles;
343
+ try {
344
+ relFiles = collectMarkdownFiles();
345
+ } catch (err) {
346
+ console.error(err.message);
347
+ return cliExit(1);
333
348
  }
334
349
 
335
350
  const linkFindings = scanStaleLinks(relFiles);
@@ -350,9 +365,12 @@ async function docsEntropyMain() {
350
365
  };
351
366
 
352
367
  if (asJson) {
368
+ // cliExit, not process.exit: the JSON here can run well past the 64KB pipe
369
+ // buffer, and process.exit() drops unflushed stdout — CI saw the payload
370
+ // truncated mid-string (PR 148's flaky unit run). Natural exit flushes.
353
371
  console.log(JSON.stringify(result, null, 2));
354
372
  if (fileIdeas) await fileToInbox(staleLinks, brokenAnchors, dupes);
355
- process.exit(0);
373
+ return cliExit(0);
356
374
  }
357
375
 
358
376
  console.log('Docs entropy scan');
@@ -390,13 +408,13 @@ async function docsEntropyMain() {
390
408
  await fileToInbox(staleLinks, brokenAnchors, dupes);
391
409
  }
392
410
 
393
- process.exit(0);
411
+ cliExit(0);
394
412
  }
395
413
 
396
414
  if (require.main === module) {
397
415
  docsEntropyMain().catch((err) => {
398
416
  console.error('fatal:', err);
399
- process.exit(1);
417
+ cliExit(1);
400
418
  });
401
419
  }
402
420
 
package/src/module-api.js CHANGED
@@ -689,8 +689,10 @@ const { validateOrRespond, LIMITS, parseId, asyncHandler, corsPublicGet, parsePa
689
689
  // landed since 1.19.129 with no explicit bump. run 31861289412. (task 1002620)
690
690
  // 1.19.131 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
691
691
  // landed since 1.19.130 with no explicit bump. run 31861682626. (task 1002620)
692
+ // 1.19.132 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
693
+ // landed since 1.19.131 with no explicit bump. run 31862317758. (task 1002620)
692
694
  // ---------------------------------------------------------------------------
693
- const CORE_VERSION = '1.19.131'; // CI auto-patch carrier (ADR 0161); see changelog above
695
+ const CORE_VERSION = '1.19.132'; // CI auto-patch carrier (ADR 0161); see changelog above
694
696
 
695
697
  // A namespaced logger so a module's log lines are attributable + consistent.
696
698
  // Usage: const log = api.logger('dev-box'); log.info('mounted');
@@ -71,14 +71,16 @@ test('R74: themeMarkup paints the backdrop only when the pack supplies one', ()
71
71
  assert.match(themeMarkup(clientBranding(vanilla()).theme), /body\{background:.+\}/);
72
72
  });
73
73
 
74
- test('customer-0: GDS_BRANDING_FILE selects the cloudbongos.com instance pack (task 1374)', () => {
74
+ test('customer-0: GDS_BRANDING_FILE selects the cloudbongos.com instance pack (task 1374)', (t) => {
75
75
  // The live dogfood instance runs from the SAME checkout as OTB; the env knob
76
76
  // points this process at its own pack (deltas over neutral) instead of OTB's
77
77
  // config/branding.json. Proves the brand-switch + the cloudbongos pack content.
78
78
  // Both packs are INSTANCE content — the neutral core ships neither, so this
79
79
  // asserts one deployment's config (task 1002470). The selector MECHANISM is
80
80
  // proven unconditionally by the fixture test below.
81
- if (!existsSync(join(ROOT, 'config/branding.cloudbongos.json'))) return;
81
+ // Report the absence as a SKIP, not a silent pass — a case that asserts nothing
82
+ // must not read as green coverage (task 1002526).
83
+ if (!existsSync(join(ROOT, 'config/branding.cloudbongos.json'))) return t.skip('no config/branding.cloudbongos.json on this checkout');
82
84
  const b = loadBranding({ env: { GDS_BRANDING_FILE: 'config/branding.cloudbongos.json' } });
83
85
  assert.equal(b.identity.productName, 'Cloud Bongos'); // from neutral
84
86
  assert.equal(b.currency.label, 'credits'); // from neutral, not "drachmae"
@@ -91,11 +93,11 @@ test('customer-0: GDS_BRANDING_FILE selects the cloudbongos.com instance pack (t
91
93
  assert.equal(b.firstAdmin, 'lars589');
92
94
  });
93
95
 
94
- test('customer-0: no GDS_BRANDING_FILE still resolves the instance pack (default unchanged)', () => {
96
+ test('customer-0: no GDS_BRANDING_FILE still resolves the instance pack (default unchanged)', (t) => {
95
97
  // The OTB process (server.js) sets no GDS_BRANDING_FILE → config/branding.json.
96
98
  // Same instance-content caveat as above: with no instance pack the correct default
97
99
  // IS the neutral starter, which is what the vanilla tests in this file already pin.
98
- if (!existsSync(INSTANCE_PATH)) return;
100
+ if (!existsSync(INSTANCE_PATH)) return t.skip('no config/branding.json (instance pack) on this checkout');
99
101
  const b = loadBranding({ env: {} });
100
102
  assert.notDeepEqual(b.identity, vanilla().identity, 'the instance pack must win over neutral by default');
101
103
  });
@@ -0,0 +1,55 @@
1
+ // tests/docs_entropy.mjs — the markdown entropy lint actually scans (task 1002526).
2
+ //
3
+ // The bug this pins: collectMarkdownFiles() shelled out to the STRING
4
+ // `git ls-files '*.md'`. On Windows that runs through cmd.exe, where the single
5
+ // quotes are literal, so git matched nothing — docs-entropy reported on zero
6
+ // files on every Windows checkout, a lint that proved nothing. Two guarantees:
7
+ // 1. enumeration goes through an argv ARRAY (no shell quoting to get wrong),
8
+ // 2. zero tracked markdown files is treated as a SCAN DEFECT and errors
9
+ // loudly — this repo tracks hundreds, so an empty result is never real.
10
+ import assert from 'node:assert/strict';
11
+ import { test } from 'node:test';
12
+ import { execFileSync } from 'node:child_process';
13
+ import { createRequire } from 'node:module';
14
+ import { fileURLToPath } from 'node:url';
15
+ import path from 'node:path';
16
+
17
+ const require = createRequire(import.meta.url);
18
+ const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
19
+ const SCANNER = path.join(ROOT, 'scripts', 'gds', 'docs-entropy.js');
20
+ const { collectMarkdownFiles } = require(SCANNER); // require.main-guarded → no scan on import
21
+
22
+ test('collectMarkdownFiles passes the glob as an argv array, never a shell string', () => {
23
+ let seen = null;
24
+ const files = collectMarkdownFiles({ run: (args) => { seen = args; return 'a.md\nb.md\n'; } });
25
+ assert.ok(Array.isArray(seen), 'git args must be an array — a shell string is what broke Windows');
26
+ assert.deepEqual(seen, ['ls-files', '*.md'], 'the glob reaches git unquoted');
27
+ assert.deepEqual(files, ['a.md', 'b.md']);
28
+ });
29
+
30
+ test('zero tracked markdown files is a loud scan defect, not a clean empty result', () => {
31
+ assert.throws(
32
+ () => collectMarkdownFiles({ run: () => '' }),
33
+ /scan defect/i,
34
+ 'an empty enumeration must name itself a defect so the lint cannot silently prove nothing',
35
+ );
36
+ });
37
+
38
+ test('a failing git invocation propagates instead of collapsing to zero files', () => {
39
+ // The old sh() helper caught every failure and returned null → [] → a scan of
40
+ // nothing. The enumeration must never swallow its own failure.
41
+ assert.throws(
42
+ () => collectMarkdownFiles({ run: () => { throw new Error('not a git repository'); } }),
43
+ /not a git repository/,
44
+ );
45
+ });
46
+
47
+ test('the real scan enumerates the repo (the regression: it reported on 0 files)', () => {
48
+ const stdout = execFileSync(process.execPath, [SCANNER, '--json'], {
49
+ cwd: ROOT, encoding: 'utf8', maxBuffer: 64 * 1024 * 1024,
50
+ });
51
+ const result = JSON.parse(stdout);
52
+ assert.ok(result.scanned_files > 50, `expected hundreds of markdown files, scanned ${result.scanned_files}`);
53
+ assert.ok(Number.isFinite(result.stale_links));
54
+ assert.ok(Number.isFinite(result.broken_anchors));
55
+ });