@bongos/core 1.19.1011 → 1.19.1012

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.1011",
6
- "core_contract": "1.19.1011",
7
- "source_commit": "24339084e27e496ab04322675456dc4d428df08a",
5
+ "core_version": "1.19.1012",
6
+ "core_contract": "1.19.1012",
7
+ "source_commit": "67c8c7ea6e9225abe84f04ee97d072e125b78671",
8
8
  "source_ref": "HEAD",
9
- "built_at": "2026-09-24T22:18:21.675Z",
9
+ "built_at": "2026-09-24T22:32:49.600Z",
10
10
  "redaction": {
11
11
  "model": "docs-redacted+functional-verbatim",
12
12
  "docs_redacted": 523,
@@ -17,7 +17,7 @@
17
17
  "gate": "passed"
18
18
  },
19
19
  "file_count": 2975,
20
- "tree_sha256": "ceac975ccace002c6914b47746ed15c8c76eb5f1919ebab13fafe0cf8b0c860d",
20
+ "tree_sha256": "43775a7c655de35e08a0b90ecee94c1ccad0cc2e460df21d0b3b5d463e6fb7e2",
21
21
  "files": [
22
22
  {
23
23
  "path": ".claude/skills/ask-for-help/SKILL.md",
@@ -2727,7 +2727,7 @@
2727
2727
  {
2728
2728
  "path": "docs/module-api-changelog.md",
2729
2729
  "mode": "0000644",
2730
- "sha256": "a6d72a65cf5f1ae3f4b317e0684b642b01ad8c3944b2d4db0feddbbd49e54974"
2730
+ "sha256": "6a78c943439f5d8b591f285c69db81d7a468e4e18656d04330685885ed2cbbd8"
2731
2731
  },
2732
2732
  {
2733
2733
  "path": "docs/modules-contract.md",
@@ -8242,12 +8242,12 @@
8242
8242
  {
8243
8243
  "path": "package-lock.json",
8244
8244
  "mode": "0000644",
8245
- "sha256": "2534d0c2e37f998d9e0ab7bb505469b9c10d4b22f0e65317a75a79769a344b98"
8245
+ "sha256": "b26e2dff351ba48f806de1851a00dc5657a52ceb0f6c2ec66bf0b407f074ca49"
8246
8246
  },
8247
8247
  {
8248
8248
  "path": "package.json",
8249
8249
  "mode": "0000644",
8250
- "sha256": "989026ca4569325ebd370b4e8b3956a199ecb50951f13539a362894ebcabc7e7"
8250
+ "sha256": "05dadaedb82b7aac68954714ab5dba673cc5e19adc0bea7109c2951bfe8692c3"
8251
8251
  },
8252
8252
  {
8253
8253
  "path": "public-docs/index.html",
@@ -8897,7 +8897,7 @@
8897
8897
  {
8898
8898
  "path": "scripts/gds/gen-file-map.js",
8899
8899
  "mode": "0000644",
8900
- "sha256": "ac2308077104c2ff899f4b12ff9da7baa965a9c0d3e4ef2f92e6bdf9d3613fb6"
8900
+ "sha256": "38505bcbacd92114abbbd06cbc41bc841e1269cb11ebaace395f3ad22104ba1a"
8901
8901
  },
8902
8902
  {
8903
8903
  "path": "scripts/gds/gen-freshness.js",
@@ -10292,7 +10292,7 @@
10292
10292
  {
10293
10293
  "path": "src/module-api.js",
10294
10294
  "mode": "0000644",
10295
- "sha256": "4f83439e8988caf0153a289fc10ba2c9aca89837322ac94158d70e21dad1aaf5"
10295
+ "sha256": "d575c9f71dfced09c23cf793d5e0d048d240621a588e65f375d47bf96cd6e006"
10296
10296
  },
10297
10297
  {
10298
10298
  "path": "src/module-loader/catalog.js",
@@ -11562,7 +11562,7 @@
11562
11562
  {
11563
11563
  "path": "tests/file_map.mjs",
11564
11564
  "mode": "0000644",
11565
- "sha256": "c6a7da467336246652fae6db5b5d7faa147e71ac1db89a66ec143dcf03bf8013"
11565
+ "sha256": "b4bdd09b0c11bb8d12677b48d1758603d3bc210511b090d7cc6de2f6d2b37cc0"
11566
11566
  },
11567
11567
  {
11568
11568
  "path": "tests/filing_abuse_matrix.mjs",
@@ -2496,5 +2496,7 @@ is load-bearing: the script throws rather than guess if it is missing, and
2496
2496
  landed since 1.19.1009 with no explicit bump. run 36064558803. (task 1002620)
2497
2497
  1.19.1011 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
2498
2498
  landed since 1.19.1010 with no explicit bump. run 36066617514. (task 1002620)
2499
+ 1.19.1012 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
2500
+ landed since 1.19.1011 with no explicit bump. run 36067980398. (task 1002620)
2499
2501
  ---------------------------------------------------------------------------
2500
2502
  ```
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.19.1011",
3
+ "version": "1.19.1012",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.19.1011",
9
+ "version": "1.19.1012",
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.1011",
3
+ "version": "1.19.1012",
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",
@@ -91,16 +91,31 @@ function materializedNames(absDir) { return new Set(Object.keys(readModuleSkills
91
91
  // The subdirs of `relDir` holding at least one TRACKED file (task 1004213). An untracked one is the
92
92
  // builder's own — a locally-installed plugin skill, or the empty husk a plugin extract leaves — and
93
93
  // listing it would publish one machine's tooling into a shared doc on every post-merge regen.
94
- // null when `root` is not the top of a git work tree (a packaged install, ADR 0108 §1): nothing to ask.
94
+ // tracked: null when `root` is not the top of a git work tree (a packaged install, ADR 0108 §1).
95
+ // gitError: git COULD not answer (task 1004222) — a safe.directory refusal, git off PATH, a broken
96
+ // GIT_DIR, ENOBUFS. That also falls back to the disk listing, but loudly: main() warns and fails --check.
97
+ const GIT_MAX_BUFFER = 64 * 1024 * 1024;
98
+ // Discovery's own refusal. A broken GIT_DIR also exits 128 "not a git repository: '<dir>'", without this tail.
99
+ const NOT_A_REPO = /not a git repository \(or any (of the )?parent/;
95
100
  function trackedSubdirs(root, relDir) {
96
- const git = (args) => execFileSync('git', args, { cwd: root, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
101
+ // LC_ALL=C: the refusal is matched by its text, which a translated git would not print.
102
+ const git = (args) => execFileSync('git', args, {
103
+ cwd: root, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], maxBuffer: GIT_MAX_BUFFER, env: { ...process.env, LC_ALL: 'C' },
104
+ });
97
105
  try {
98
- if (git(['rev-parse', '--show-prefix']).trim() !== '') return null;
99
- return new Set(git(['ls-files', '-z', '--', relDir]).split('\0')
100
- .map((p) => p.slice(relDir.length + 1).split('/'))
101
- .filter((segs) => segs.length > 1)
102
- .map((segs) => segs[0]));
103
- } catch { return null; }
106
+ if (git(['rev-parse', '--show-prefix']).trim() !== '') return { tracked: null, gitError: null };
107
+ return {
108
+ tracked: new Set(git(['ls-files', '-z', '--', relDir]).split('\0')
109
+ .map((p) => p.slice(relDir.length + 1).split('/'))
110
+ .filter((segs) => segs.length > 1)
111
+ .map((segs) => segs[0])),
112
+ gitError: null,
113
+ };
114
+ } catch (err) {
115
+ const stderr = String(err.stderr || '').trim();
116
+ if (err.status === 128 && NOT_A_REPO.test(stderr)) return { tracked: null, gitError: null };
117
+ return { tracked: null, gitError: stderr.split('\n')[0] || err.code || err.message };
118
+ }
104
119
  }
105
120
 
106
121
  // Immediate subdirectories of an absolute dir, sorted by name (deterministic); materialised
@@ -120,7 +135,7 @@ function listSubdirs(absDir) {
120
135
  function buildSection(section, notes) {
121
136
  const absDir = path.join(REPO_ROOT, section.dir);
122
137
  const present = listSubdirs(absDir);
123
- const tracked = trackedSubdirs(REPO_ROOT, section.dir);
138
+ const { tracked, gitError } = trackedSubdirs(REPO_ROOT, section.dir);
124
139
  const names = tracked ? present.filter((n) => tracked.has(n)) : present;
125
140
  const sectionNotes = (notes && notes[section.notesKey]) || {};
126
141
  const entries = names.map((name) => {
@@ -135,7 +150,7 @@ function buildSection(section, notes) {
135
150
  // A note is a ghost only when its dir is gone from disk — one not yet `git add`ed is not.
136
151
  const onDisk = new Set(present);
137
152
  const stale = Object.keys(sectionNotes).filter((k) => !onDisk.has(k)).map((k) => `${section.notesKey}.${k}`);
138
- return { ...section, absDir, entries, missing, stale };
153
+ return { ...section, absDir, entries, missing, stale, gitError };
139
154
  }
140
155
 
141
156
  function buildModel() {
@@ -244,6 +259,7 @@ function computeWrites() {
244
259
  const model = buildModel();
245
260
  const missing = model.flatMap((m) => m.missing);
246
261
  const stale = model.flatMap((m) => m.stale);
262
+ const gitErrors = [...new Set(model.map((m) => m.gitError).filter(Boolean))];
247
263
  const writes = [];
248
264
  let markersMissing = [];
249
265
  let mapText = '';
@@ -258,7 +274,7 @@ function computeWrites() {
258
274
  mapText = next; // coverage reads the POST-generation text, so a regen never changes the verdict
259
275
  }
260
276
  const modules = moduleCoverage(mapText);
261
- return { model, writes, missing, stale, markersMissing, modules };
277
+ return { model, writes, missing, stale, gitErrors, markersMissing, modules };
262
278
  }
263
279
 
264
280
  function main() {
@@ -267,7 +283,7 @@ function main() {
267
283
  process.stdout.write(JSON.stringify(buildModel(), null, 2) + '\n');
268
284
  return;
269
285
  }
270
- const { writes, missing, stale, markersMissing, modules } = computeWrites();
286
+ const { writes, missing, stale, gitErrors, markersMissing, modules } = computeWrites();
271
287
 
272
288
  // A missing note (dir without a note) or a stale note (note without a dir) is a hard failure in
273
289
  // BOTH modes: in --check it fails CI; in write mode we still report it (and render a visible
@@ -275,6 +291,7 @@ function main() {
275
291
  const problems = [];
276
292
  if (missing.length) problems.push(`notes MISSING for: ${missing.join(', ')} — add a one-line note to docs/file-map.notes.json`);
277
293
  if (stale.length) problems.push(`notes are STALE (no such dir) — remove from docs/file-map.notes.json: ${stale.join(', ')}`);
294
+ for (const e of gitErrors) problems.push(`git could not list tracked files (${e}) — every dir on disk was listed, untracked plugin installs included; fix git (PATH, safe.directory) and re-run (task 1004222)`);
278
295
  if (markersMissing.length) problems.push(`docs/file-map.md is missing generated markers for: ${markersMissing.join(', ')}`);
279
296
  if (modules.undocumented.length) problems.push(`modules with NO docs/file-map.md entry: ${modules.undocumented.map((k) => `${MODULES_DIR}/${k}`).join(', ')} — add an entry to the modules/ block of docs/file-map.md (task 1004066)`);
280
297
  for (const d of modules.defects) problems.push(`module-coverage SCAN DEFECT — ${d}`);
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.1011'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
74
+ const CORE_VERSION = '1.19.1012'; // 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');
@@ -2,7 +2,7 @@
2
2
  // (task 1276 / ADR 0066). Mirrors tests/session_index.mjs + tests/repo_map.mjs.
3
3
  import assert from 'node:assert/strict';
4
4
  import { test } from 'node:test';
5
- import { execFileSync } from 'node:child_process';
5
+ import { execFileSync, spawnSync } from 'node:child_process';
6
6
  import { readFileSync, existsSync, readdirSync, mkdirSync, writeFileSync, rmSync, mkdtempSync } from 'node:fs';
7
7
  import { tmpdir } from 'node:os';
8
8
  import { createRequire } from 'node:module';
@@ -90,10 +90,19 @@ function fixtureRoot({ git }) {
90
90
  }
91
91
  return root;
92
92
  }
93
- const skillsSectionAt = (cwd) => JSON.parse(execFileSync(process.execPath,
93
+ const skillsSectionAt = (cwd, env) => JSON.parse(execFileSync(process.execPath,
94
94
  ['-e', `process.stdout.write(JSON.stringify(require(${JSON.stringify(GEN)}).buildModel()))`],
95
- { cwd, encoding: 'utf8' })).find((s) => s.id === 'skills');
95
+ { cwd, encoding: 'utf8', env })).find((s) => s.id === 'skills');
96
96
  const skillNamesAt = (cwd) => skillsSectionAt(cwd).entries.map((e) => e.name);
97
+ function genAt(cwd, args, env) {
98
+ const r = spawnSync(process.execPath, [GEN, ...args], { cwd, encoding: 'utf8', env });
99
+ return { code: r.status, stderr: r.stderr };
100
+ }
101
+ // Two ways git fails to answer inside a real work tree (task 1004222): no git on PATH (ENOENT), and a
102
+ // GIT_DIR naming nothing — exit 128 like "not a repository", but not discovery's own refusal.
103
+ // PATH is dropped under every casing: Windows spells it `Path`, and a copy of both keys is ambiguous.
104
+ const withoutGit = (root) => ({ ...Object.fromEntries(Object.entries(process.env).filter(([k]) => k.toUpperCase() !== 'PATH')), PATH: path.join(root, 'no-bin') });
105
+ const brokenGitDir = (root) => ({ ...process.env, GIT_DIR: path.join(root, 'no-such-git-dir') });
97
106
 
98
107
  test('--check FAILS (exit 2) when a new tracked skill has no note — a skill can no longer land undescribed', () => {
99
108
  const root = fixtureRoot({ git: true });
@@ -128,15 +137,38 @@ test('outside a git work tree (a packaged install) every dir on disk is still li
128
137
  const nested = path.join(parent, 'instance');
129
138
  try {
130
139
  assert.deepEqual(skillNamesAt(root), ['empty-husk', 'local-plugin', 'new-skill']);
140
+ // Silently: not being in a repository is the packaged install's normal state, not a git failure.
141
+ assert.equal(skillsSectionAt(root).gitError, null);
142
+ assert.doesNotMatch(genAt(root, ['--check']).stderr, /git could not/);
131
143
  // A root that is a SUBDIR of some repo is not that repo's top: its files are not the repo's to judge.
132
144
  mkdirSync(path.join(nested, '.claude', 'skills', 'inner'), { recursive: true });
133
145
  assert.deepEqual(skillNamesAt(nested), ['inner']);
146
+ assert.equal(skillsSectionAt(nested).gitError, null);
134
147
  } finally {
135
148
  rmSync(root, { recursive: true, force: true });
136
149
  rmSync(parent, { recursive: true, force: true });
137
150
  }
138
151
  });
139
152
 
153
+ test('a git failure inside a work tree is NOT "not a repository" — it warns in write mode and fails --check', () => {
154
+ const root = fixtureRoot({ git: true });
155
+ try {
156
+ for (const [shape, env, named] of [['git missing from PATH', withoutGit(root), /ENOENT/], ['GIT_DIR naming nothing', brokenGitDir(root), /not a git repository: /]]) {
157
+ assert.match(skillsSectionAt(root, env).gitError || '', named, `${shape}: the model names the git error`);
158
+ const check = genAt(root, ['--check'], env);
159
+ assert.equal(check.code, 2, `${shape}: --check must fail rather than pass on an unfiltered listing`);
160
+ assert.match(check.stderr, /gen-file-map --check: git could not list tracked files/, shape);
161
+ const write = genAt(root, [], env);
162
+ assert.equal(write.code, 2, `${shape}: write mode exits non-zero`);
163
+ assert.match(write.stderr, /gen-file-map: WARN git could not list tracked files/, shape);
164
+ }
165
+ // The same root with git answering carries no git error: the failure above is the env, not the fixture.
166
+ assert.equal(skillsSectionAt(root).gitError, null);
167
+ } finally {
168
+ rmSync(root, { recursive: true, force: true });
169
+ }
170
+ });
171
+
140
172
  test('generation is deterministic + idempotent (a second run is a no-op)', () => {
141
173
  const r1 = run([]);
142
174
  assert.equal(r1.code, 0);