@bongos/core 1.19.1001 → 1.19.1003
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 +11 -11
- package/docs/module-api-changelog.md +4 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/scripts/gds/gen-file-map.js +22 -3
- package/src/module-api.js +1 -1
- package/tests/file_map.mjs +64 -12
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.1003",
|
|
6
|
+
"core_contract": "1.19.1003",
|
|
7
|
+
"source_commit": "145db63a197eedb2b567473f622e1b208dc0fe00",
|
|
8
8
|
"source_ref": "HEAD",
|
|
9
|
-
"built_at": "2026-09-
|
|
9
|
+
"built_at": "2026-09-24T15:36:25.098Z",
|
|
10
10
|
"redaction": {
|
|
11
11
|
"model": "docs-redacted+functional-verbatim",
|
|
12
12
|
"docs_redacted": 521,
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"gate": "passed"
|
|
18
18
|
},
|
|
19
19
|
"file_count": 2957,
|
|
20
|
-
"tree_sha256": "
|
|
20
|
+
"tree_sha256": "30960b9b7c273ac36ba63d380f5b2c8f31e832f5f702f57215ca4e9c27f50db2",
|
|
21
21
|
"files": [
|
|
22
22
|
{
|
|
23
23
|
"path": ".claude/skills/ask-for-help/SKILL.md",
|
|
@@ -2722,7 +2722,7 @@
|
|
|
2722
2722
|
{
|
|
2723
2723
|
"path": "docs/module-api-changelog.md",
|
|
2724
2724
|
"mode": "0000644",
|
|
2725
|
-
"sha256": "
|
|
2725
|
+
"sha256": "bfcc1b1653c36c240cd5793aa5d483f7bd740c5681f2ed0600f01217c5d8937d"
|
|
2726
2726
|
},
|
|
2727
2727
|
{
|
|
2728
2728
|
"path": "docs/modules-contract.md",
|
|
@@ -8207,12 +8207,12 @@
|
|
|
8207
8207
|
{
|
|
8208
8208
|
"path": "package-lock.json",
|
|
8209
8209
|
"mode": "0000644",
|
|
8210
|
-
"sha256": "
|
|
8210
|
+
"sha256": "f509ecfaca00e821fa21984c54d36121ff0cf2d40057b0bf98c2442edc6b74ab"
|
|
8211
8211
|
},
|
|
8212
8212
|
{
|
|
8213
8213
|
"path": "package.json",
|
|
8214
8214
|
"mode": "0000644",
|
|
8215
|
-
"sha256": "
|
|
8215
|
+
"sha256": "f2e41698e557ef6542dcc15b564de5cee94bfa8736097add3523fa5d665c60a6"
|
|
8216
8216
|
},
|
|
8217
8217
|
{
|
|
8218
8218
|
"path": "public-docs/index.html",
|
|
@@ -8862,7 +8862,7 @@
|
|
|
8862
8862
|
{
|
|
8863
8863
|
"path": "scripts/gds/gen-file-map.js",
|
|
8864
8864
|
"mode": "0000644",
|
|
8865
|
-
"sha256": "
|
|
8865
|
+
"sha256": "ac2308077104c2ff899f4b12ff9da7baa965a9c0d3e4ef2f92e6bdf9d3613fb6"
|
|
8866
8866
|
},
|
|
8867
8867
|
{
|
|
8868
8868
|
"path": "scripts/gds/gen-freshness.js",
|
|
@@ -10257,7 +10257,7 @@
|
|
|
10257
10257
|
{
|
|
10258
10258
|
"path": "src/module-api.js",
|
|
10259
10259
|
"mode": "0000644",
|
|
10260
|
-
"sha256": "
|
|
10260
|
+
"sha256": "edd1b0444e04d5511e536f5991e87c8fc271b7a18f2ee3f3f6d2dc6d1fd88486"
|
|
10261
10261
|
},
|
|
10262
10262
|
{
|
|
10263
10263
|
"path": "src/module-loader/catalog.js",
|
|
@@ -11522,7 +11522,7 @@
|
|
|
11522
11522
|
{
|
|
11523
11523
|
"path": "tests/file_map.mjs",
|
|
11524
11524
|
"mode": "0000644",
|
|
11525
|
-
"sha256": "
|
|
11525
|
+
"sha256": "c6a7da467336246652fae6db5b5d7faa147e71ac1db89a66ec143dcf03bf8013"
|
|
11526
11526
|
},
|
|
11527
11527
|
{
|
|
11528
11528
|
"path": "tests/filing_abuse_matrix.mjs",
|
|
@@ -2476,5 +2476,9 @@ is load-bearing: the script throws rather than guess if it is missing, and
|
|
|
2476
2476
|
landed since 1.19.999 with no explicit bump. run 35943151697. (task 1002620)
|
|
2477
2477
|
1.19.1001 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2478
2478
|
landed since 1.19.1000 with no explicit bump. run 36016738965. (task 1002620)
|
|
2479
|
+
1.19.1002 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2480
|
+
landed since 1.19.1001 with no explicit bump. run 36019839845. (task 1002620)
|
|
2481
|
+
1.19.1003 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2482
|
+
landed since 1.19.1002 with no explicit bump. run 36021332931. (task 1002620)
|
|
2479
2483
|
---------------------------------------------------------------------------
|
|
2480
2484
|
```
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.1003",
|
|
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.1003",
|
|
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.1003",
|
|
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",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
// and .claude/scheduled-tasks/ — are now GENERATED from what is on disk. The per-entry one-line
|
|
14
14
|
// notes (the prose after the ←, which no directory walk can know) live in a sidecar,
|
|
15
15
|
// docs/file-map.notes.json, the ONE place a human writes them. The contract enforced by --check:
|
|
16
|
-
// • every skill/routine dir
|
|
16
|
+
// • every TRACKED skill/routine dir MUST have a note → a new skill can't land undescribed;
|
|
17
17
|
// • every note MUST map to a dir that exists → the map can't carry ghosts;
|
|
18
18
|
// • the rendered block MUST match what's committed → no stale tree.
|
|
19
19
|
// MODULE COVERAGE (task 1004066). The same honor system that let a skill land unmapped let a whole
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
|
|
42
42
|
const fs = require('node:fs');
|
|
43
43
|
const path = require('node:path');
|
|
44
|
+
const { execFileSync } = require('node:child_process');
|
|
44
45
|
const { resolveInstanceRoot } = require('../../src/instance-config'); // ADR 0108 §1: configurable-root
|
|
45
46
|
const { sameContent } = require('./gen-freshness'); // eol-insensitive freshness (CRLF checkouts)
|
|
46
47
|
|
|
@@ -87,6 +88,21 @@ function loadNotes() {
|
|
|
87
88
|
const { readModuleSkillsManifest } = require('./claude-materialize.js');
|
|
88
89
|
function materializedNames(absDir) { return new Set(Object.keys(readModuleSkillsManifest(absDir).skills)); }
|
|
89
90
|
|
|
91
|
+
// The subdirs of `relDir` holding at least one TRACKED file (task 1004213). An untracked one is the
|
|
92
|
+
// builder's own — a locally-installed plugin skill, or the empty husk a plugin extract leaves — and
|
|
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.
|
|
95
|
+
function trackedSubdirs(root, relDir) {
|
|
96
|
+
const git = (args) => execFileSync('git', args, { cwd: root, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
|
|
97
|
+
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; }
|
|
104
|
+
}
|
|
105
|
+
|
|
90
106
|
// Immediate subdirectories of an absolute dir, sorted by name (deterministic); materialised
|
|
91
107
|
// module copies excluded.
|
|
92
108
|
function listSubdirs(absDir) {
|
|
@@ -103,7 +119,9 @@ function listSubdirs(absDir) {
|
|
|
103
119
|
// classes the freshness contract enforces (a dir with no note; a note with no dir).
|
|
104
120
|
function buildSection(section, notes) {
|
|
105
121
|
const absDir = path.join(REPO_ROOT, section.dir);
|
|
106
|
-
const
|
|
122
|
+
const present = listSubdirs(absDir);
|
|
123
|
+
const tracked = trackedSubdirs(REPO_ROOT, section.dir);
|
|
124
|
+
const names = tracked ? present.filter((n) => tracked.has(n)) : present;
|
|
107
125
|
const sectionNotes = (notes && notes[section.notesKey]) || {};
|
|
108
126
|
const entries = names.map((name) => {
|
|
109
127
|
// Skills + scheduled-tasks each carry a SKILL.md; label it explicitly when present (matches the
|
|
@@ -114,7 +132,8 @@ function buildSection(section, notes) {
|
|
|
114
132
|
return { name, label, note };
|
|
115
133
|
});
|
|
116
134
|
const missing = entries.filter((e) => e.note == null).map((e) => `${section.dir}/${e.name}`);
|
|
117
|
-
|
|
135
|
+
// A note is a ghost only when its dir is gone from disk — one not yet `git add`ed is not.
|
|
136
|
+
const onDisk = new Set(present);
|
|
118
137
|
const stale = Object.keys(sectionNotes).filter((k) => !onDisk.has(k)).map((k) => `${section.notesKey}.${k}`);
|
|
119
138
|
return { ...section, absDir, entries, missing, stale };
|
|
120
139
|
}
|
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.
|
|
74
|
+
const CORE_VERSION = '1.19.1003'; // 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');
|
package/tests/file_map.mjs
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
import assert from 'node:assert/strict';
|
|
4
4
|
import { test } from 'node:test';
|
|
5
5
|
import { execFileSync } from 'node:child_process';
|
|
6
|
-
import { readFileSync, existsSync, readdirSync, mkdirSync, writeFileSync, rmSync } from 'node:fs';
|
|
6
|
+
import { readFileSync, existsSync, readdirSync, mkdirSync, writeFileSync, rmSync, mkdtempSync } from 'node:fs';
|
|
7
|
+
import { tmpdir } from 'node:os';
|
|
7
8
|
import { createRequire } from 'node:module';
|
|
8
9
|
import { fileURLToPath } from 'node:url';
|
|
9
10
|
import path from 'node:path';
|
|
@@ -40,8 +41,11 @@ test('EVERY skill + scheduled-task dir on disk is listed AND has a note — no s
|
|
|
40
41
|
// A module skill materialised into this checkout (task 1003330) is an untracked copy the
|
|
41
42
|
// module documents; the generator skips it by the manifest beside it, and so does this.
|
|
42
43
|
const materialised = gen.materializedNames(path.join(ROOT, section.dir));
|
|
44
|
+
// An untracked dir is the builder's own (a plugin install, an empty husk — task 1004213).
|
|
45
|
+
const tracked = new Set(execFileSync('git', ['ls-files', '-z', '--', section.dir], { cwd: ROOT, encoding: 'utf8' })
|
|
46
|
+
.split('\0').map((p) => p.slice(section.dir.length + 1).split('/')).filter((s) => s.length > 1).map((s) => s[0]));
|
|
43
47
|
const onDisk = readdirSync(path.join(ROOT, section.dir), { withFileTypes: true })
|
|
44
|
-
.filter((e) => e.isDirectory() && !e.name.startsWith('.') && !materialised.has(e.name))
|
|
48
|
+
.filter((e) => e.isDirectory() && !e.name.startsWith('.') && !materialised.has(e.name) && tracked.has(e.name))
|
|
45
49
|
.map((e) => e.name)
|
|
46
50
|
.sort();
|
|
47
51
|
const listed = section.entries.map((e) => e.name).sort();
|
|
@@ -69,20 +73,68 @@ test('the generated blocks live between markers and carry one ← note per entry
|
|
|
69
73
|
}
|
|
70
74
|
});
|
|
71
75
|
|
|
72
|
-
|
|
73
|
-
|
|
76
|
+
// A throwaway instance root (task 1004213). `new-skill` is staged, so git tracks it; `local-plugin`
|
|
77
|
+
// is untracked with a SKILL.md, as a real plugin install is; `empty-husk` is the bare dir a plugin
|
|
78
|
+
// extract leaves behind. The generator falls back to cwd for its root, so no env is needed.
|
|
79
|
+
function fixtureRoot({ git }) {
|
|
80
|
+
const root = mkdtempSync(path.join(tmpdir(), 'file-map-'));
|
|
81
|
+
const skills = path.join(root, '.claude', 'skills');
|
|
82
|
+
for (const n of ['new-skill', 'local-plugin']) {
|
|
83
|
+
mkdirSync(path.join(skills, n), { recursive: true });
|
|
84
|
+
writeFileSync(path.join(skills, n, 'SKILL.md'), `---\nname: ${n}\n---\n`);
|
|
85
|
+
}
|
|
86
|
+
mkdirSync(path.join(skills, 'empty-husk'));
|
|
87
|
+
if (git) {
|
|
88
|
+
execFileSync('git', ['init', '-q'], { cwd: root, stdio: 'ignore' });
|
|
89
|
+
execFileSync('git', ['add', '.claude/skills/new-skill'], { cwd: root, stdio: 'ignore' });
|
|
90
|
+
}
|
|
91
|
+
return root;
|
|
92
|
+
}
|
|
93
|
+
const skillsSectionAt = (cwd) => JSON.parse(execFileSync(process.execPath,
|
|
94
|
+
['-e', `process.stdout.write(JSON.stringify(require(${JSON.stringify(GEN)}).buildModel()))`],
|
|
95
|
+
{ cwd, encoding: 'utf8' })).find((s) => s.id === 'skills');
|
|
96
|
+
const skillNamesAt = (cwd) => skillsSectionAt(cwd).entries.map((e) => e.name);
|
|
97
|
+
|
|
98
|
+
test('--check FAILS (exit 2) when a new tracked skill has no note — a skill can no longer land undescribed', () => {
|
|
99
|
+
const root = fixtureRoot({ git: true });
|
|
74
100
|
try {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
101
|
+
let r;
|
|
102
|
+
try { execFileSync(process.execPath, [GEN, '--check'], { cwd: root, encoding: 'utf8', stdio: 'pipe' }); r = { code: 0, stderr: '' }; }
|
|
103
|
+
catch (e) { r = { code: e.status, stderr: String(e.stderr) }; }
|
|
78
104
|
assert.equal(r.code, 2, 'an undescribed skill must fail the gate');
|
|
79
|
-
assert.match(r.stderr, /notes MISSING
|
|
80
|
-
assert.
|
|
105
|
+
assert.match(r.stderr, /notes MISSING for: \.claude\/skills\/new-skill(?! *,)/, 'the tracked skill, and only it, is missing a note');
|
|
106
|
+
assert.doesNotMatch(r.stderr, /local-plugin|empty-husk/);
|
|
81
107
|
} finally {
|
|
82
|
-
rmSync(
|
|
108
|
+
rmSync(root, { recursive: true, force: true });
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test('an untracked skill dir is the builder\'s own — a plugin install and an empty husk never reach the map', () => {
|
|
113
|
+
const root = fixtureRoot({ git: true });
|
|
114
|
+
try {
|
|
115
|
+
assert.deepEqual(skillNamesAt(root), ['new-skill']);
|
|
116
|
+
// A note written before `git add` is not a ghost: its dir is on disk.
|
|
117
|
+
mkdirSync(path.join(root, 'docs'));
|
|
118
|
+
writeFileSync(path.join(root, 'docs', 'file-map.notes.json'), JSON.stringify({ skills: { 'local-plugin': 'x', gone: 'y' } }));
|
|
119
|
+
assert.deepEqual(skillsSectionAt(root).stale, ['skills.gone']);
|
|
120
|
+
} finally {
|
|
121
|
+
rmSync(root, { recursive: true, force: true });
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test('outside a git work tree (a packaged install) every dir on disk is still listed', () => {
|
|
126
|
+
const root = fixtureRoot({ git: false });
|
|
127
|
+
const parent = fixtureRoot({ git: true });
|
|
128
|
+
const nested = path.join(parent, 'instance');
|
|
129
|
+
try {
|
|
130
|
+
assert.deepEqual(skillNamesAt(root), ['empty-husk', 'local-plugin', 'new-skill']);
|
|
131
|
+
// 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
|
+
mkdirSync(path.join(nested, '.claude', 'skills', 'inner'), { recursive: true });
|
|
133
|
+
assert.deepEqual(skillNamesAt(nested), ['inner']);
|
|
134
|
+
} finally {
|
|
135
|
+
rmSync(root, { recursive: true, force: true });
|
|
136
|
+
rmSync(parent, { recursive: true, force: true });
|
|
83
137
|
}
|
|
84
|
-
// and clean again once removed
|
|
85
|
-
assert.equal(run(['--check']).code, 0, 'gate is clean after the probe dir is removed');
|
|
86
138
|
});
|
|
87
139
|
|
|
88
140
|
test('generation is deterministic + idempotent (a second run is a no-op)', () => {
|