@stackbilt/cli 0.9.2 → 0.10.0

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.
Files changed (55) hide show
  1. package/LICENSE +17 -1
  2. package/README.md +42 -0
  3. package/dist/__tests__/bootstrap.test.d.ts +2 -0
  4. package/dist/__tests__/bootstrap.test.d.ts.map +1 -0
  5. package/dist/__tests__/bootstrap.test.js +134 -0
  6. package/dist/__tests__/bootstrap.test.js.map +1 -0
  7. package/dist/__tests__/integration/precommit-hook.test.js +4 -4
  8. package/dist/__tests__/score.test.d.ts +2 -0
  9. package/dist/__tests__/score.test.d.ts.map +1 -0
  10. package/dist/__tests__/score.test.js +234 -0
  11. package/dist/__tests__/score.test.js.map +1 -0
  12. package/dist/commands/adf-tidy.d.ts.map +1 -1
  13. package/dist/commands/adf-tidy.js +6 -3
  14. package/dist/commands/adf-tidy.js.map +1 -1
  15. package/dist/commands/adf.js +20 -13
  16. package/dist/commands/adf.js.map +1 -1
  17. package/dist/commands/audit.js +24 -7
  18. package/dist/commands/audit.js.map +1 -1
  19. package/dist/commands/blast.d.ts +12 -0
  20. package/dist/commands/blast.d.ts.map +1 -0
  21. package/dist/commands/blast.js +208 -0
  22. package/dist/commands/blast.js.map +1 -0
  23. package/dist/commands/bootstrap.d.ts.map +1 -1
  24. package/dist/commands/bootstrap.js +245 -101
  25. package/dist/commands/bootstrap.js.map +1 -1
  26. package/dist/commands/doctor.d.ts.map +1 -1
  27. package/dist/commands/doctor.js +9 -2
  28. package/dist/commands/doctor.js.map +1 -1
  29. package/dist/commands/init.d.ts.map +1 -1
  30. package/dist/commands/init.js +127 -8
  31. package/dist/commands/init.js.map +1 -1
  32. package/dist/commands/run.js +1 -1
  33. package/dist/commands/run.js.map +1 -1
  34. package/dist/commands/score.d.ts +9 -0
  35. package/dist/commands/score.d.ts.map +1 -0
  36. package/dist/commands/score.js +1273 -0
  37. package/dist/commands/score.js.map +1 -0
  38. package/dist/commands/setup.js +2 -2
  39. package/dist/commands/setup.js.map +1 -1
  40. package/dist/commands/surface.d.ts +15 -0
  41. package/dist/commands/surface.d.ts.map +1 -0
  42. package/dist/commands/surface.js +112 -0
  43. package/dist/commands/surface.js.map +1 -0
  44. package/dist/http-client.d.ts +13 -4
  45. package/dist/http-client.d.ts.map +1 -1
  46. package/dist/http-client.js +1 -1
  47. package/dist/http-client.js.map +1 -1
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +22 -3
  50. package/dist/index.js.map +1 -1
  51. package/dist/types/scaffold-contract-types.d.ts +90 -0
  52. package/dist/types/scaffold-contract-types.d.ts.map +1 -0
  53. package/dist/types/scaffold-contract-types.js +22 -0
  54. package/dist/types/scaffold-contract-types.js.map +1 -0
  55. package/package.json +12 -9
package/LICENSE CHANGED
@@ -1,3 +1,19 @@
1
+ Copyright 2026 Stackbilt LLC
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
14
+
15
+ ---
16
+
1
17
  Apache License
2
18
  Version 2.0, January 2004
3
19
  http://www.apache.org/licenses/
@@ -175,7 +191,7 @@
175
191
 
176
192
  END OF TERMS AND CONDITIONS
177
193
 
178
- Copyright 2026 StackBilt, Smart Brand Strategies LLC
194
+ Copyright 2026 Stackbilt LLC
179
195
 
180
196
  Licensed under the Apache License, Version 2.0 (the "License");
181
197
  you may not use this file except in compliance with the License.
package/README.md CHANGED
@@ -69,6 +69,8 @@ charter adf migrate --dry-run # preview agent config → ADF migration
69
69
  charter adf sync --check # verify .adf files match locked hashes
70
70
  charter adf evidence --auto-measure --format json # validate metric ceilings
71
71
  charter telemetry report --period 24h --format json # passive local usage summary
72
+ charter blast src/foo.ts --depth 3 # reverse dep graph → files affected by changing this seed
73
+ charter surface --markdown # extract routes (Hono/Express) + D1 schema as markdown
72
74
  ```
73
75
 
74
76
  ## Human Onboarding (Copy/Paste)
@@ -299,6 +301,44 @@ charter adf migrate [--dry-run] [--source <file>] [--no-backup]
299
301
  - `metrics recalibrate`: Re-measure current LOC from manifest metric sources, propose and apply new ceilings using configurable headroom, and append rationale records to `BUDGET_RATIONALES`. Requires explicit rationale (`--reason`) unless `--auto-rationale` is used.
300
302
  - `migrate`: Scan existing agent config files (CLAUDE.md, .cursorrules, agents.md, GEMINI.md, copilot-instructions.md), classify content using the ADX-002 decision tree, and migrate into ADF modules. `--dry-run` previews the migration plan without writing files. `--source <file>` targets a single file. `--no-backup` skips `.pre-adf-migrate.bak` creation. `--merge-strategy` controls deduplication: `dedupe` (default, skip items already in ADF), `append` (always add), or `replace`. Environment-specific rules (WSL, PATH, credential helpers) are retained in the thin pointer.
301
303
 
304
+ ### `charter blast`
305
+
306
+ Compute the blast radius of a change: which files transitively depend on the given seed files? Builds a reverse dependency graph (TS/JS imports — handles ESM `.js → .ts`, tsconfig path aliases including `extends` chains, `src/index.*` fallback, cycles, comments) and BFS-traverses up to a configurable depth.
307
+
308
+ ```bash
309
+ charter blast src/kernel/dispatch.ts # default depth 3
310
+ charter blast src/a.ts src/b.ts --depth 4 # multi-seed
311
+ charter blast src/foo.ts --format json # structured output
312
+ charter blast src/foo.ts --root ./packages/x # scan a subdirectory
313
+ ```
314
+
315
+ Reports:
316
+ - `affected` — relative paths of transitively dependent files
317
+ - `hotFiles` — top 20 most-imported files in the graph (architectural hubs)
318
+ - `summary.totalAffected`, `summary.depthHistogram`
319
+
320
+ Blast radius ≥20 files triggers a `CROSS_CUTTING` warning — a signal for governance gates to escalate the change. Pure heuristic, no LLM calls, zero runtime dependencies. Backed by `@stackbilt/blast`.
321
+
322
+ ### `charter surface`
323
+
324
+ Extract the API surface of a project: HTTP routes and database schema. Designed for Cloudflare Worker projects but works on any Node.js HTTP backend.
325
+
326
+ ```bash
327
+ charter surface # text summary
328
+ charter surface --format json # machine-readable
329
+ charter surface --markdown # for .ai/surface.adf injection
330
+ charter surface --root ./packages/worker # scan a subdirectory
331
+ charter surface --schema db/schema.sql # explicit schema path
332
+ ```
333
+
334
+ Detects:
335
+ - **Routes** — Hono, Express, itty-router via regex (requires `/` path prefix; strips comments before scanning)
336
+ - **Schema** — D1/SQLite `CREATE TABLE` statements with column flags (pk, unique, nullable, default)
337
+
338
+ Ignores `__tests__/`, `*.test.*`, `*.spec.*` to avoid false positives from test fixtures.
339
+
340
+ Use cases: breaking change detection (diff surfaces before/after a PR), auto-generated AI context maps, deploy pipeline gates, mission brief fingerprinting for autonomous task runners. Backed by `@stackbilt/surface`.
341
+
302
342
  ### `charter telemetry`
303
343
 
304
344
  Passive local observability for Charter/ADF usage. Every CLI run appends command metadata (timestamp, command path, flags, duration, exit code) to `.charter/telemetry/events.ndjson`.
@@ -372,6 +412,8 @@ Setup-only options:
372
412
  - `@stackbilt/drift` -- blessed-stack pattern drift detection
373
413
  - `@stackbilt/validate` -- citation validation and intent classification
374
414
  - `@stackbilt/adf` -- ADF parser, formatter, patcher, and bundler
415
+ - `@stackbilt/blast` -- reverse dependency graph + blast radius analysis
416
+ - `@stackbilt/surface` -- API surface extraction (routes + D1 schema)
375
417
  - `@stackbilt/ci` -- GitHub Actions integration helpers
376
418
 
377
419
  ## License
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=bootstrap.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/bootstrap.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const fs = __importStar(require("node:fs"));
37
+ const os = __importStar(require("node:os"));
38
+ const path = __importStar(require("node:path"));
39
+ const vitest_1 = require("vitest");
40
+ const bootstrap_1 = require("../commands/bootstrap");
41
+ const baseOptions = {
42
+ configPath: '.charter',
43
+ format: 'text',
44
+ ciMode: false,
45
+ yes: false,
46
+ };
47
+ (0, vitest_1.describe)('bootstrapCommand', () => {
48
+ let originalCwd;
49
+ let tempDir;
50
+ let logs;
51
+ (0, vitest_1.beforeEach)(() => {
52
+ originalCwd = process.cwd();
53
+ tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'charter-bootstrap-test-'));
54
+ process.chdir(tempDir);
55
+ logs = [];
56
+ vitest_1.vi.spyOn(console, 'log').mockImplementation((...args) => {
57
+ logs.push(args.map(String).join(' '));
58
+ });
59
+ });
60
+ (0, vitest_1.afterEach)(() => {
61
+ process.chdir(originalCwd);
62
+ fs.rmSync(tempDir, { recursive: true, force: true });
63
+ vitest_1.vi.restoreAllMocks();
64
+ });
65
+ (0, vitest_1.it)('keeps custom ADF files when run with --yes but without --force', async () => {
66
+ fs.mkdirSync('.ai', { recursive: true });
67
+ const customCore = `ADF: 0.1
68
+
69
+ CONTEXT:
70
+ - Custom core instructions
71
+ `;
72
+ fs.writeFileSync(path.join('.ai', 'core.adf'), customCore);
73
+ const exitCode = await (0, bootstrap_1.bootstrapCommand)({ ...baseOptions, yes: true }, ['--yes', '--preset', 'worker', '--skip-install', '--skip-doctor']);
74
+ (0, vitest_1.expect)(exitCode).toBe(0);
75
+ (0, vitest_1.expect)(fs.readFileSync(path.join('.ai', 'core.adf'), 'utf-8')).toBe(customCore);
76
+ (0, vitest_1.expect)(fs.existsSync(path.join('.ai', '.backup'))).toBe(false);
77
+ (0, vitest_1.expect)(fs.existsSync(path.join('.ai', 'manifest.adf'))).toBe(true);
78
+ (0, vitest_1.expect)(fs.existsSync(path.join('.ai', 'state.adf'))).toBe(true);
79
+ const skipWarning = logs.find(l => l.includes('.ai/core.adf has custom content') && l.includes('skipping scaffold overwrite'));
80
+ (0, vitest_1.expect)(skipWarning).toBeDefined();
81
+ (0, vitest_1.expect)(skipWarning).toMatch(/\d+ bytes/);
82
+ });
83
+ (0, vitest_1.it)('backs up and overwrites custom ADF files when run with --force', async () => {
84
+ fs.mkdirSync('.ai', { recursive: true });
85
+ const customCore = `ADF: 0.1
86
+
87
+ CONTEXT:
88
+ - Preserve me in backup
89
+ `;
90
+ const customState = `ADF: 0.1
91
+ STATE:
92
+ CURRENT: Custom state
93
+ `;
94
+ fs.writeFileSync(path.join('.ai', 'core.adf'), customCore);
95
+ fs.writeFileSync(path.join('.ai', 'state.adf'), customState);
96
+ const exitCode = await (0, bootstrap_1.bootstrapCommand)(baseOptions, ['--force', '--preset', 'worker', '--skip-install', '--skip-doctor']);
97
+ (0, vitest_1.expect)(exitCode).toBe(0);
98
+ // Backup files should exist with timestamp suffix
99
+ const backupDir = path.join('.ai', '.backup');
100
+ (0, vitest_1.expect)(fs.existsSync(backupDir)).toBe(true);
101
+ const backupFiles = fs.readdirSync(backupDir);
102
+ const coreBackup = backupFiles.find(f => f.startsWith('core.adf.'));
103
+ const stateBackup = backupFiles.find(f => f.startsWith('state.adf.'));
104
+ (0, vitest_1.expect)(coreBackup).toBeDefined();
105
+ (0, vitest_1.expect)(stateBackup).toBeDefined();
106
+ (0, vitest_1.expect)(fs.readFileSync(path.join(backupDir, coreBackup), 'utf-8')).toBe(customCore);
107
+ (0, vitest_1.expect)(fs.readFileSync(path.join(backupDir, stateBackup), 'utf-8')).toBe(customState);
108
+ // Originals should be overwritten with scaffold content
109
+ (0, vitest_1.expect)(fs.readFileSync(path.join('.ai', 'core.adf'), 'utf-8')).not.toBe(customCore);
110
+ (0, vitest_1.expect)(fs.readFileSync(path.join('.ai', 'state.adf'), 'utf-8')).not.toBe(customState);
111
+ (0, vitest_1.expect)(logs).toContain(' Backed up 2 files to .ai/.backup/');
112
+ });
113
+ (0, vitest_1.it)('detects orphaned .adf modules and auto-registers them in --yes mode', async () => {
114
+ // Pre-create .ai/ with extra modules that won't be in the scaffold manifest
115
+ fs.mkdirSync('.ai', { recursive: true });
116
+ fs.writeFileSync(path.join('.ai', 'agent.adf'), 'ADF: 0.1\n\nCONTEXT:\n - Agent rules\n');
117
+ fs.writeFileSync(path.join('.ai', 'persona.adf'), 'ADF: 0.1\n\nCONTEXT:\n - Persona rules\n');
118
+ const exitCode = await (0, bootstrap_1.bootstrapCommand)({ ...baseOptions, yes: true }, ['--yes', '--preset', 'worker', '--skip-install', '--skip-doctor']);
119
+ (0, vitest_1.expect)(exitCode).toBe(0);
120
+ // Should warn about the two unregistered modules
121
+ const orphanWarning = logs.find(l => l.includes('unregistered .adf module'));
122
+ (0, vitest_1.expect)(orphanWarning).toBeDefined();
123
+ (0, vitest_1.expect)(orphanWarning).toContain('agent.adf');
124
+ (0, vitest_1.expect)(orphanWarning).toContain('persona.adf');
125
+ // In --yes mode, orphans should be auto-registered in manifest
126
+ const registerLog = logs.find(l => l.includes('Registered 2 module(s) as ON_DEMAND'));
127
+ (0, vitest_1.expect)(registerLog).toBeDefined();
128
+ // Verify manifest contains the orphan entries
129
+ const manifest = fs.readFileSync(path.join('.ai', 'manifest.adf'), 'utf-8');
130
+ (0, vitest_1.expect)(manifest).toContain('agent.adf');
131
+ (0, vitest_1.expect)(manifest).toContain('persona.adf');
132
+ });
133
+ });
134
+ //# sourceMappingURL=bootstrap.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.test.js","sourceRoot":"","sources":["../../src/__tests__/bootstrap.test.ts"],"names":[],"mappings":"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"}
@@ -170,7 +170,7 @@ function writeHookFixtureRepo(tmp) {
170
170
  // v3 Pre-commit Hook Simulation
171
171
  // ============================================================================
172
172
  (0, vitest_1.describe)('pre-commit hook auto-tidy (integration)', () => {
173
- (0, vitest_1.it)('auto-tidies bloated CLAUDE.md during git commit', { timeout: 30000 }, () => {
173
+ (0, vitest_1.it)('auto-tidies bloated CLAUDE.md during git commit', { timeout: 60000 }, () => {
174
174
  const tmp = makeTempDir('hook-tidy');
175
175
  writeHookFixtureRepo(tmp);
176
176
  // Inject bloat into CLAUDE.md
@@ -197,7 +197,7 @@ function writeHookFixtureRepo(tmp) {
197
197
  (0, vitest_1.expect)(finalContent).not.toContain('## Database Rules');
198
198
  (0, vitest_1.expect)(finalContent).toContain('## Environment');
199
199
  });
200
- (0, vitest_1.it)('passes through cleanly when CLAUDE.md has no bloat', { timeout: 30000 }, () => {
200
+ (0, vitest_1.it)('passes through cleanly when CLAUDE.md has no bloat', { timeout: 60000 }, () => {
201
201
  const tmp = makeTempDir('hook-clean');
202
202
  writeHookFixtureRepo(tmp);
203
203
  // Make a trivial change to CLAUDE.md (add env item, not bloat)
@@ -210,7 +210,7 @@ function writeHookFixtureRepo(tmp) {
210
210
  const finalContent = fs.readFileSync(path.join(tmp, 'CLAUDE.md'), 'utf-8');
211
211
  (0, vitest_1.expect)(finalContent).toContain('DO NOT add rules');
212
212
  });
213
- (0, vitest_1.it)('skips tidy when CHARTER_SKIP_TIDY=1 is set', { timeout: 30000 }, () => {
213
+ (0, vitest_1.it)('skips tidy when CHARTER_SKIP_TIDY=1 is set', { timeout: 60000 }, () => {
214
214
  const tmp = makeTempDir('hook-skip');
215
215
  writeHookFixtureRepo(tmp);
216
216
  // Inject bloat
@@ -237,7 +237,7 @@ function writeHookFixtureRepo(tmp) {
237
237
  const finalContent = fs.readFileSync(path.join(tmp, 'CLAUDE.md'), 'utf-8');
238
238
  (0, vitest_1.expect)(finalContent).toContain('## Architecture');
239
239
  });
240
- (0, vitest_1.it)('re-stages modified .adf modules after tidy', { timeout: 30000 }, () => {
240
+ (0, vitest_1.it)('re-stages modified .adf modules after tidy', { timeout: 60000 }, () => {
241
241
  const tmp = makeTempDir('hook-restage');
242
242
  writeHookFixtureRepo(tmp);
243
243
  // Inject bloat with trigger keywords that route to backend.adf
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=score.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"score.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/score.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,234 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const fs = __importStar(require("node:fs"));
37
+ const os = __importStar(require("node:os"));
38
+ const path = __importStar(require("node:path"));
39
+ const vitest_1 = require("vitest");
40
+ const index_1 = require("../index");
41
+ const score_1 = require("../commands/score");
42
+ const baseOptions = {
43
+ configPath: '.charter',
44
+ format: 'json',
45
+ ciMode: false,
46
+ yes: false,
47
+ };
48
+ const originalCwd = process.cwd();
49
+ const tempDirs = [];
50
+ (0, vitest_1.afterEach)(() => {
51
+ process.chdir(originalCwd);
52
+ while (tempDirs.length > 0) {
53
+ const dir = tempDirs.pop();
54
+ if (dir) {
55
+ fs.rmSync(dir, { recursive: true, force: true });
56
+ }
57
+ }
58
+ vitest_1.vi.restoreAllMocks();
59
+ });
60
+ (0, vitest_1.describe)('scoreCommand', () => {
61
+ (0, vitest_1.it)('gives a strong score to a well-grounded Charter-style repo', async () => {
62
+ const tmp = createTempRepo();
63
+ process.chdir(tmp);
64
+ fs.mkdirSync(path.join(tmp, '.ai'), { recursive: true });
65
+ fs.mkdirSync(path.join(tmp, '.github', 'workflows'), { recursive: true });
66
+ fs.mkdirSync(path.join(tmp, '.githooks'), { recursive: true });
67
+ fs.mkdirSync(path.join(tmp, '.codex', 'skills', 'review'), { recursive: true });
68
+ fs.mkdirSync(path.join(tmp, '.claude'), { recursive: true });
69
+ fs.mkdirSync(path.join(tmp, 'src'), { recursive: true });
70
+ fs.writeFileSync(path.join(tmp, 'package.json'), JSON.stringify({
71
+ name: 'ready-repo',
72
+ version: '1.0.0',
73
+ scripts: {
74
+ test: 'vitest run',
75
+ 'test:unit': 'vitest run src/index.ts',
76
+ },
77
+ }, null, 2));
78
+ fs.writeFileSync(path.join(tmp, 'README.md'), `# Ready Repo
79
+
80
+ See \`src/index.ts\` and \`.ai/manifest.adf\`.
81
+
82
+ \`\`\`sh
83
+ npm test
84
+ npm run test:unit
85
+ \`\`\`
86
+ `);
87
+ fs.writeFileSync(path.join(tmp, 'CLAUDE.md'), `# Working Rules
88
+
89
+ Use \`src/index.ts\` as the main entrypoint.
90
+ Review \`.ai/manifest.adf\` before changing architecture.
91
+
92
+ \`\`\`sh
93
+ charter adf evidence --auto-measure
94
+ \`\`\`
95
+ `);
96
+ fs.writeFileSync(path.join(tmp, '.cursorrules'), `Keep edits small.
97
+ Check \`.ai/core.adf\` and \`.ai/state.adf\` before large changes.
98
+ `);
99
+ fs.writeFileSync(path.join(tmp, 'AGENTS.md'), `# Agents
100
+
101
+ Coordinate ownership before parallel changes.
102
+ Use \`npm test\` before handing work back.
103
+ `);
104
+ fs.writeFileSync(path.join(tmp, '.ai', 'manifest.adf'), `ADF: 0.1
105
+ ROLE: Repo context router
106
+
107
+ DEFAULT_LOAD:
108
+ - core.adf
109
+ - state.adf
110
+
111
+ ON_DEMAND:
112
+ - backend.adf (Triggers on: API, Node, DB)
113
+ `);
114
+ fs.writeFileSync(path.join(tmp, '.ai', 'core.adf'), `ADF: 0.1
115
+
116
+ CONTEXT:
117
+ - Service entrypoint: src/index.ts
118
+
119
+ CONSTRAINTS [load-bearing]:
120
+ - Run npm test before merge
121
+ - Keep API handlers pure at the edge
122
+
123
+ METRICS:
124
+ entry_loc: 12 / 200 [lines]
125
+ `);
126
+ fs.writeFileSync(path.join(tmp, '.ai', 'state.adf'), `ADF: 0.1
127
+ STATE:
128
+ CURRENT: scoring implementation is active
129
+ NEXT: keep docs synchronized
130
+ `);
131
+ fs.writeFileSync(path.join(tmp, '.ai', 'backend.adf'), `ADF: 0.1
132
+ CONTEXT:
133
+ - API routes live in src/index.ts
134
+ `);
135
+ fs.writeFileSync(path.join(tmp, 'src', 'index.ts'), 'export const ready = true;\n');
136
+ fs.writeFileSync(path.join(tmp, '.github', 'workflows', 'ci.yml'), 'name: CI\non: [push]\n');
137
+ fs.writeFileSync(path.join(tmp, '.githooks', 'pre-commit'), '#!/usr/bin/env sh\nnpm test\n');
138
+ fs.writeFileSync(path.join(tmp, '.codex', 'skills', 'review', 'SKILL.md'), '# Review Skill\n');
139
+ fs.writeFileSync(path.join(tmp, '.claude', 'settings.json'), JSON.stringify({
140
+ permissions: {
141
+ allow: ['Bash(npm test)'],
142
+ },
143
+ }, null, 2));
144
+ const { exitCode, report } = await captureJson(() => (0, score_1.scoreCommand)(baseOptions, []));
145
+ (0, vitest_1.expect)(exitCode).toBe(0);
146
+ (0, vitest_1.expect)(report.score.grade).toBe('A');
147
+ (0, vitest_1.expect)(report.score.total).toBeGreaterThanOrEqual(95);
148
+ (0, vitest_1.expect)(findCategory(report, 'agent-config')?.score).toBe(25);
149
+ (0, vitest_1.expect)(findCategory(report, 'architecture')?.score).toBe(20);
150
+ (0, vitest_1.expect)(findCategory(report, 'governance')?.score).toBe(10);
151
+ (0, vitest_1.expect)(report.recommendations).not.toContainEqual(vitest_1.expect.stringContaining('charter bootstrap --yes'));
152
+ });
153
+ (0, vitest_1.it)('is registered in the top-level CLI and scores non-Charter repos without crashing', async () => {
154
+ const tmp = createTempRepo();
155
+ process.chdir(tmp);
156
+ fs.mkdirSync(path.join(tmp, 'src'), { recursive: true });
157
+ fs.mkdirSync(path.join(tmp, '.github', 'workflows'), { recursive: true });
158
+ fs.writeFileSync(path.join(tmp, 'package.json'), JSON.stringify({
159
+ name: 'plain-repo',
160
+ version: '1.0.0',
161
+ scripts: {
162
+ test: 'node --test',
163
+ },
164
+ }, null, 2));
165
+ fs.writeFileSync(path.join(tmp, 'README.md'), `# Plain Repo
166
+
167
+ Main module: \`src/app.ts\`
168
+
169
+ \`\`\`sh
170
+ npm test
171
+ \`\`\`
172
+ `);
173
+ fs.writeFileSync(path.join(tmp, 'src', 'app.ts'), 'export const app = 1;\n');
174
+ fs.writeFileSync(path.join(tmp, '.github', 'workflows', 'ci.yml'), 'name: CI\non: [push]\n');
175
+ const { exitCode, report } = await captureJson(() => (0, index_1.run)(['score', '--format', 'json']));
176
+ (0, vitest_1.expect)(exitCode).toBe(0);
177
+ (0, vitest_1.expect)(report.score.total).toBeGreaterThan(0);
178
+ (0, vitest_1.expect)(report.recommendations.some((item) => item.includes('charter bootstrap --yes'))).toBe(true);
179
+ (0, vitest_1.expect)(report.recommendations.some((item) => item.includes('CLAUDE.md'))).toBe(true);
180
+ });
181
+ (0, vitest_1.it)('falls back to mtime freshness and flags stale config relative to code', async () => {
182
+ const tmp = createTempRepo();
183
+ process.chdir(tmp);
184
+ fs.mkdirSync(path.join(tmp, 'src'), { recursive: true });
185
+ fs.writeFileSync(path.join(tmp, 'package.json'), JSON.stringify({
186
+ name: 'stale-repo',
187
+ version: '1.0.0',
188
+ scripts: {
189
+ test: 'node --test',
190
+ },
191
+ }, null, 2));
192
+ fs.writeFileSync(path.join(tmp, 'README.md'), `# Stale Repo
193
+
194
+ \`\`\`sh
195
+ npm test
196
+ \`\`\`
197
+ `);
198
+ fs.writeFileSync(path.join(tmp, 'CLAUDE.md'), '# Repo Rules\n\nRun `npm test` before merge.\n');
199
+ fs.writeFileSync(path.join(tmp, '.cursorrules'), 'Keep changes localized.\n');
200
+ fs.writeFileSync(path.join(tmp, 'AGENTS.md'), '# Agents\n\nCoordinate work.\n');
201
+ fs.writeFileSync(path.join(tmp, 'src', 'app.ts'), 'export const stale = true;\n');
202
+ const oldDate = new Date(Date.now() - (160 * 24 * 60 * 60 * 1000));
203
+ const newDate = new Date(Date.now() - (2 * 24 * 60 * 60 * 1000));
204
+ for (const file of ['CLAUDE.md', '.cursorrules', 'AGENTS.md']) {
205
+ fs.utimesSync(path.join(tmp, file), oldDate, oldDate);
206
+ }
207
+ fs.utimesSync(path.join(tmp, 'src', 'app.ts'), newDate, newDate);
208
+ const { report } = await captureJson(() => (0, score_1.scoreCommand)(baseOptions, []));
209
+ (0, vitest_1.expect)(report.signals.freshness.strategy).toBe('mtime');
210
+ (0, vitest_1.expect)((report.signals.freshness.deltaDays || 0)).toBeGreaterThan(100);
211
+ (0, vitest_1.expect)(findCategory(report, 'freshness')?.score).toBeLessThanOrEqual(2);
212
+ (0, vitest_1.expect)(report.recommendations.some((item) => item.includes('Refresh agent config after recent code changes'))).toBe(true);
213
+ });
214
+ });
215
+ function createTempRepo() {
216
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'charter-score-test-'));
217
+ tempDirs.push(tmp);
218
+ return tmp;
219
+ }
220
+ async function captureJson(runCommand) {
221
+ const logs = [];
222
+ vitest_1.vi.spyOn(console, 'log').mockImplementation((message) => {
223
+ logs.push(String(message ?? ''));
224
+ });
225
+ const exitCode = await runCommand();
226
+ return {
227
+ exitCode,
228
+ report: JSON.parse(logs[0]),
229
+ };
230
+ }
231
+ function findCategory(report, id) {
232
+ return report.categories.find((category) => category.id === id);
233
+ }
234
+ //# sourceMappingURL=score.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"score.test.js","sourceRoot":"","sources":["../../src/__tests__/score.test.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"adf-tidy.d.ts","sourceRoot":"","sources":["../../src/commands/adf-tidy.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAcH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAwE3C,wBAAsB,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAwHzF"}
1
+ {"version":3,"file":"adf-tidy.d.ts","sourceRoot":"","sources":["../../src/commands/adf-tidy.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAeH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAwE3C,wBAAsB,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAwHzF"}
@@ -220,7 +220,9 @@ function extractBeyondPointer(content, fileName) {
220
220
  const template = getPointerTemplates()[baseName];
221
221
  if (!template)
222
222
  return '';
223
- const lines = content.split('\n');
223
+ // Strip charter-managed sentinel blocks before scanning for bloat.
224
+ // Without this, tidy treats the module index table as user-authored content.
225
+ const lines = (0, adf_1.stripCharterSentinels)(content).split('\n');
224
226
  const bloatLines = [];
225
227
  let inEnvironmentSection = false;
226
228
  let inPointerHeader = true; // Start true — skip the pointer preamble
@@ -254,13 +256,14 @@ function extractBeyondPointer(content, fileName) {
254
256
  }
255
257
  // Section detection
256
258
  if (trimmed.startsWith('## ')) {
257
- if (trimmed === '## Environment') {
259
+ // Environment and Module Index are charter-managed retained sections — not bloat (#71)
260
+ if (trimmed === '## Environment' || trimmed === '## Module Index') {
258
261
  inEnvironmentSection = true;
259
262
  continue;
260
263
  }
261
264
  else {
262
265
  inEnvironmentSection = false;
263
- // Non-Environment H2 section = bloat
266
+ // Non-retained H2 section = bloat
264
267
  bloatLines.push(line);
265
268
  continue;
266
269
  }