@stackbilt/cli 0.3.2 → 0.4.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 (36) hide show
  1. package/README.md +18 -5
  2. package/dist/commands/adf-bundle.d.ts +8 -0
  3. package/dist/commands/adf-bundle.d.ts.map +1 -0
  4. package/dist/commands/adf-bundle.js +169 -0
  5. package/dist/commands/adf-bundle.js.map +1 -0
  6. package/dist/commands/adf-evidence.d.ts +8 -0
  7. package/dist/commands/adf-evidence.d.ts.map +1 -0
  8. package/dist/commands/adf-evidence.js +273 -0
  9. package/dist/commands/adf-evidence.js.map +1 -0
  10. package/dist/commands/adf-migrate.d.ts +10 -0
  11. package/dist/commands/adf-migrate.d.ts.map +1 -0
  12. package/dist/commands/adf-migrate.js +383 -0
  13. package/dist/commands/adf-migrate.js.map +1 -0
  14. package/dist/commands/adf-sync.d.ts +10 -0
  15. package/dist/commands/adf-sync.d.ts.map +1 -0
  16. package/dist/commands/adf-sync.js +213 -0
  17. package/dist/commands/adf-sync.js.map +1 -0
  18. package/dist/commands/adf.d.ts +7 -1
  19. package/dist/commands/adf.d.ts.map +1 -1
  20. package/dist/commands/adf.js +109 -472
  21. package/dist/commands/adf.js.map +1 -1
  22. package/dist/commands/bootstrap.d.ts +9 -0
  23. package/dist/commands/bootstrap.d.ts.map +1 -0
  24. package/dist/commands/bootstrap.js +660 -0
  25. package/dist/commands/bootstrap.js.map +1 -0
  26. package/dist/commands/hook.d.ts.map +1 -1
  27. package/dist/commands/hook.js +69 -10
  28. package/dist/commands/hook.js.map +1 -1
  29. package/dist/commands/setup.d.ts +103 -0
  30. package/dist/commands/setup.d.ts.map +1 -1
  31. package/dist/commands/setup.js +7 -0
  32. package/dist/commands/setup.js.map +1 -1
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +9 -2
  35. package/dist/index.js.map +1 -1
  36. package/package.json +8 -8
@@ -1 +1 @@
1
- {"version":3,"file":"adf.d.ts","sourceRoot":"","sources":["../../src/commands/adf.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAeH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAiD3C,wBAAsB,UAAU,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAyBrF"}
1
+ {"version":3,"file":"adf.d.ts","sourceRoot":"","sources":["../../src/commands/adf.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAUH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAW3C,eAAO,MAAM,iBAAiB,0VAc7B,CAAC;AAEF,eAAO,MAAM,aAAa,k3BAmBzB,CAAC;AAEF,eAAO,MAAM,cAAc,mJAI1B,CAAC;AAMF,wBAAsB,UAAU,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA2BrF;AAeD,eAAO,MAAM,iBAAiB,2bAU7B,CAAC;AAEF,eAAO,MAAM,mBAAmB,oSAO/B,CAAC;AAEF,eAAO,MAAM,iBAAiB,8UAU7B,CAAC"}
@@ -2,7 +2,7 @@
2
2
  /**
3
3
  * charter adf
4
4
  *
5
- * ADF (Attention-Directed Format) subcommands: init, fmt, patch, bundle, sync.
5
+ * ADF (Attention-Directed Format) subcommands: init, fmt, patch, bundle, sync, evidence, migrate.
6
6
  */
7
7
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
8
  if (k2 === undefined) k2 = k;
@@ -38,16 +38,20 @@ var __importStar = (this && this.__importStar) || (function () {
38
38
  };
39
39
  })();
40
40
  Object.defineProperty(exports, "__esModule", { value: true });
41
+ exports.POINTER_AGENTS_MD = exports.POINTER_CURSORRULES = exports.POINTER_CLAUDE_MD = exports.STATE_SCAFFOLD = exports.CORE_SCAFFOLD = exports.MANIFEST_SCAFFOLD = void 0;
41
42
  exports.adfCommand = adfCommand;
42
43
  const fs = __importStar(require("node:fs"));
43
44
  const path = __importStar(require("node:path"));
44
- const crypto = __importStar(require("node:crypto"));
45
45
  const adf_1 = require("@stackbilt/adf");
46
46
  const index_1 = require("../index");
47
+ const adf_migrate_1 = require("./adf-migrate");
48
+ const adf_bundle_1 = require("./adf-bundle");
49
+ const adf_sync_1 = require("./adf-sync");
50
+ const adf_evidence_1 = require("./adf-evidence");
47
51
  // ============================================================================
48
52
  // Scaffold Content
49
53
  // ============================================================================
50
- const MANIFEST_SCAFFOLD = `ADF: 0.1
54
+ exports.MANIFEST_SCAFFOLD = `ADF: 0.1
51
55
  \u{1F3AF} ROLE: Repo context router
52
56
 
53
57
  \u{1F4E6} DEFAULT_LOAD:
@@ -62,22 +66,27 @@ const MANIFEST_SCAFFOLD = `ADF: 0.1
62
66
  - Prefer smallest relevant module set.
63
67
  - Never assume unseen modules were loaded.
64
68
  `;
65
- const CORE_SCAFFOLD = `ADF: 0.1
66
- \u{1F3AF} TASK: Define universal repository rules
69
+ exports.CORE_SCAFFOLD = `ADF: 0.1
67
70
 
68
- \u{2699}\u{FE0F} CONTEXT:
69
- - This file is loaded by default for every task.
70
- - Keep it lean add domain-specific rules to on-demand modules.
71
+ \u{1F4D6} GUIDE [advisory]:
72
+ - Pure runtime/environment? (OS, line endings) \u2192 CLAUDE.md, not ADF
73
+ - Universal architecture constraint? \u2192 core.adf CONSTRAINTS [load-bearing]
74
+ - Stack-specific operational rule? \u2192 domain .adf module (backend.adf, frontend.adf)
75
+ - Agent identity/behavior? \u2192 core.adf CONTEXT
76
+ - Language/tooling discipline? \u2192 core.adf CONSTRAINTS or dedicated section
77
+ - [load-bearing] = violation causes incorrect output
78
+ - [advisory] = best practice, not enforced
79
+ - Section types are open: CONTEXT, CONSTRAINTS, ADVISORY, METRICS, custom
71
80
 
72
- \u{26A0}\u{FE0F} CONSTRAINTS [load-bearing]:
73
- - Follow conventional commits.
74
- - No secrets in source code.
75
- - Prefer pure functions in library code.
81
+ \u26A0\uFE0F CONSTRAINTS [load-bearing]:
82
+ - Use Conventional Commits (feat, fix, docs, chore)
83
+ - Never commit secrets or credentials
84
+ - Pure functions in library code; side effects only in entry points
76
85
 
77
- \u{1F4CA} METRICS [load-bearing]:
86
+ \uD83D\uDCCA METRICS:
78
87
  entry_loc: 0 / 500 [lines]
79
88
  `;
80
- const STATE_SCAFFOLD = `ADF: 0.1
89
+ exports.STATE_SCAFFOLD = `ADF: 0.1
81
90
  \u{1F9E0} STATE:
82
91
  CURRENT: Repository initialized with ADF context system
83
92
  NEXT: Configure on-demand modules for your stack
@@ -100,15 +109,48 @@ async function adfCommand(options, args) {
100
109
  case 'patch':
101
110
  return adfPatch(options, restArgs);
102
111
  case 'bundle':
103
- return adfBundle(options, restArgs);
112
+ return (0, adf_bundle_1.adfBundle)(options, restArgs);
104
113
  case 'sync':
105
- return adfSync(options, restArgs);
114
+ return (0, adf_sync_1.adfSync)(options, restArgs);
106
115
  case 'evidence':
107
- return adfEvidence(options, restArgs);
116
+ return (0, adf_evidence_1.adfEvidence)(options, restArgs);
117
+ case 'migrate':
118
+ return (0, adf_migrate_1.adfMigrateCommand)(options, restArgs);
108
119
  default:
109
- throw new index_1.CLIError(`Unknown adf subcommand: ${subcommand}. Supported: init, fmt, patch, bundle, sync, evidence`);
120
+ throw new index_1.CLIError(`Unknown adf subcommand: ${subcommand}. Supported: init, fmt, patch, bundle, sync, evidence, migrate`);
110
121
  }
111
122
  }
123
+ // -- Thin pointer file content --
124
+ exports.POINTER_CLAUDE_MD = `# Project Context
125
+
126
+ > This project uses [ADF](https://github.com/Stackbilt-dev/charter) for AI agent context management.
127
+ > All stack rules, constraints, and architectural guidance live in \`.ai/\`.
128
+ > **Do not duplicate ADF rules here.** Only pre-ADF bootstrap content belongs in this file.
129
+
130
+ See \`.ai/manifest.adf\` for the module routing manifest.
131
+
132
+ ## Environment
133
+ <!-- Add runtime/OS/shell-specific notes here (not stack rules) -->
134
+ `;
135
+ exports.POINTER_CURSORRULES = `# Cursor Rules
136
+
137
+ This project uses ADF (Attention-Directed Format) for context management.
138
+ All rules and constraints are in .ai/ \u2014 see .ai/manifest.adf for routing.
139
+
140
+ Do not add stack rules here. This file exists only as a pointer.
141
+ See: .ai/core.adf for universal constraints.
142
+ `;
143
+ exports.POINTER_AGENTS_MD = `# Agent Guidelines
144
+
145
+ This project uses ADF for structured agent context.
146
+ All architectural rules, constraints, and guidance live in \`.ai/\`.
147
+
148
+ Module manifest: .ai/manifest.adf
149
+ Universal rules: .ai/core.adf
150
+ Current state: .ai/state.adf
151
+
152
+ Do not duplicate rules from .ai/ modules into this file or other agent config files.
153
+ `;
112
154
  function adfInit(options, args) {
113
155
  const force = options.yes || args.includes('--force');
114
156
  const aiDir = getFlag(args, '--ai-dir') || '.ai';
@@ -125,14 +167,45 @@ function adfInit(options, args) {
125
167
  return index_1.EXIT_CODE.SUCCESS;
126
168
  }
127
169
  fs.mkdirSync(aiDir, { recursive: true });
128
- fs.writeFileSync(path.join(aiDir, 'manifest.adf'), MANIFEST_SCAFFOLD);
129
- fs.writeFileSync(path.join(aiDir, 'core.adf'), CORE_SCAFFOLD);
130
- fs.writeFileSync(path.join(aiDir, 'state.adf'), STATE_SCAFFOLD);
170
+ fs.writeFileSync(path.join(aiDir, 'manifest.adf'), exports.MANIFEST_SCAFFOLD);
171
+ fs.writeFileSync(path.join(aiDir, 'core.adf'), exports.CORE_SCAFFOLD);
172
+ fs.writeFileSync(path.join(aiDir, 'state.adf'), exports.STATE_SCAFFOLD);
131
173
  const result = {
132
174
  created: true,
133
175
  aiDir,
134
176
  files: ['manifest.adf', 'core.adf', 'state.adf'],
135
177
  };
178
+ // --emit-pointers: generate thin pointer files that redirect to .ai/
179
+ const emitPointers = args.includes('--emit-pointers') || args.includes('--pointers');
180
+ if (emitPointers) {
181
+ const pointerSpecs = [
182
+ { file: 'CLAUDE.md', content: exports.POINTER_CLAUDE_MD, label: 'CLAUDE.md (thin pointer)' },
183
+ { file: '.cursorrules', content: exports.POINTER_CURSORRULES, label: '.cursorrules (thin pointer)' },
184
+ { file: 'agents.md', content: exports.POINTER_AGENTS_MD, label: 'agents.md (thin pointer)' },
185
+ ];
186
+ const createdPointers = [];
187
+ const skippedPointers = [];
188
+ for (const spec of pointerSpecs) {
189
+ if (fs.existsSync(spec.file)) {
190
+ skippedPointers.push(spec.file);
191
+ }
192
+ else {
193
+ fs.writeFileSync(spec.file, spec.content);
194
+ createdPointers.push(spec.file);
195
+ result.files.push(spec.file);
196
+ }
197
+ }
198
+ result.pointers = createdPointers;
199
+ if (options.format !== 'json') {
200
+ for (const p of createdPointers) {
201
+ const label = pointerSpecs.find(s => s.file === p)?.label ?? p;
202
+ console.log(` Generated ${label}`);
203
+ }
204
+ for (const p of skippedPointers) {
205
+ console.log(` Skipped ${p} (already exists)`);
206
+ }
207
+ }
208
+ }
136
209
  if (options.format === 'json') {
137
210
  console.log(JSON.stringify({
138
211
  ...result,
@@ -258,456 +331,6 @@ function adfPatch(options, args) {
258
331
  }
259
332
  }
260
333
  // ============================================================================
261
- // adf bundle
262
- // ============================================================================
263
- function adfBundle(options, args) {
264
- const task = getFlag(args, '--task');
265
- if (!task) {
266
- throw new index_1.CLIError('adf bundle requires --task "<prompt>". Usage: charter adf bundle --task "Fix React component"');
267
- }
268
- const aiDir = getFlag(args, '--ai-dir') || '.ai';
269
- const manifestPath = path.join(aiDir, 'manifest.adf');
270
- if (!fs.existsSync(manifestPath)) {
271
- throw new index_1.CLIError(`manifest.adf not found at ${manifestPath}. Run: charter adf init`);
272
- }
273
- const manifestContent = fs.readFileSync(manifestPath, 'utf-8');
274
- const manifestDoc = (0, adf_1.parseAdf)(manifestContent);
275
- const manifest = (0, adf_1.parseManifest)(manifestDoc);
276
- // Tokenize task into keywords (simple word split)
277
- const keywords = task
278
- .split(/[\s,;:()[\]{}]+/)
279
- .filter(w => w.length > 1)
280
- .map(w => w.replace(/[^a-zA-Z0-9]/g, ''));
281
- const modulePaths = (0, adf_1.resolveModules)(manifest, keywords);
282
- const readFile = (p) => fs.readFileSync(p, 'utf-8');
283
- try {
284
- const result = (0, adf_1.bundleModules)(aiDir, modulePaths, readFile, keywords);
285
- if (options.format === 'json') {
286
- const jsonOut = {
287
- task,
288
- keywords,
289
- resolvedModules: result.resolvedModules,
290
- tokenEstimate: result.tokenEstimate,
291
- tokenBudget: result.tokenBudget,
292
- tokenUtilization: result.tokenUtilization,
293
- perModuleTokens: result.perModuleTokens,
294
- triggerMatches: result.triggerMatches,
295
- };
296
- if (result.unmatchedModules.length > 0) {
297
- jsonOut.unmatchedModules = result.unmatchedModules;
298
- }
299
- if (result.moduleBudgetOverruns.length > 0) {
300
- jsonOut.moduleBudgetOverruns = result.moduleBudgetOverruns;
301
- }
302
- if (result.advisoryOnlyModules.length > 0) {
303
- jsonOut.advisoryOnlyModules = result.advisoryOnlyModules;
304
- }
305
- if (result.manifest.cadence.length > 0) {
306
- jsonOut.cadence = result.manifest.cadence;
307
- }
308
- console.log(JSON.stringify(jsonOut, null, 2));
309
- }
310
- else {
311
- console.log(` Task: "${task}"`);
312
- console.log(` Keywords: ${keywords.join(', ')}`);
313
- console.log(` Resolved modules: ${result.resolvedModules.join(', ')}`);
314
- console.log(` Token estimate: ~${result.tokenEstimate}`);
315
- if (result.tokenBudget !== null) {
316
- const pct = result.tokenUtilization !== null
317
- ? ` (${(result.tokenUtilization * 100).toFixed(0)}%)`
318
- : '';
319
- console.log(` Token budget: ${result.tokenBudget}${pct}`);
320
- }
321
- console.log('');
322
- if (result.moduleBudgetOverruns.length > 0) {
323
- console.log(' Module budget overruns:');
324
- for (const o of result.moduleBudgetOverruns) {
325
- console.log(` [!] ${o.module}: ~${o.tokens} tokens (budget: ${o.budget})`);
326
- }
327
- console.log('');
328
- }
329
- if (result.triggerMatches.length > 0) {
330
- console.log(' Trigger report:');
331
- for (const tm of result.triggerMatches) {
332
- const icon = tm.matched ? '+' : '-';
333
- const kw = tm.matchedKeywords.length > 0 ? ` [${tm.matchedKeywords.join(', ')}]` : '';
334
- console.log(` [${icon}] ${tm.module} (${tm.trigger})${kw}`);
335
- }
336
- console.log('');
337
- }
338
- if (result.unmatchedModules.length > 0) {
339
- console.log(' Unmatched modules (not loaded):');
340
- for (const m of result.unmatchedModules) {
341
- console.log(` [-] ${m}`);
342
- }
343
- console.log('');
344
- }
345
- if (result.advisoryOnlyModules.length > 0) {
346
- console.log(' Advisory-only modules:');
347
- for (const m of result.advisoryOnlyModules) {
348
- console.log(` [!] ${m}: no load-bearing sections`);
349
- }
350
- console.log('');
351
- }
352
- if (result.manifest.cadence.length > 0) {
353
- console.log(' Cadence schedule:');
354
- for (const c of result.manifest.cadence) {
355
- console.log(` ${c.check}: ${c.frequency}`);
356
- }
357
- console.log('');
358
- }
359
- // Output merged document
360
- const output = (0, adf_1.formatAdf)(result.mergedDocument);
361
- console.log(' --- Merged Context ---');
362
- console.log(output);
363
- }
364
- return index_1.EXIT_CODE.SUCCESS;
365
- }
366
- catch (e) {
367
- if (e instanceof Error && e.name === 'AdfBundleError') {
368
- if (options.format === 'json') {
369
- console.log(JSON.stringify({ error: e.message }, null, 2));
370
- }
371
- else {
372
- console.error(` [error] ${e.message}`);
373
- }
374
- return index_1.EXIT_CODE.RUNTIME_ERROR;
375
- }
376
- throw e;
377
- }
378
- }
379
- function adfSync(options, args) {
380
- const aiDir = getFlag(args, '--ai-dir') || '.ai';
381
- const checkMode = args.includes('--check');
382
- const writeMode = args.includes('--write');
383
- if (!checkMode && !writeMode) {
384
- throw new index_1.CLIError('adf sync requires --check or --write. Usage: charter adf sync --check');
385
- }
386
- const manifestPath = path.join(aiDir, 'manifest.adf');
387
- if (!fs.existsSync(manifestPath)) {
388
- throw new index_1.CLIError(`manifest.adf not found at ${manifestPath}. Run: charter adf init`);
389
- }
390
- const manifestContent = fs.readFileSync(manifestPath, 'utf-8');
391
- const manifestDoc = (0, adf_1.parseAdf)(manifestContent);
392
- const manifest = (0, adf_1.parseManifest)(manifestDoc);
393
- if (manifest.sync.length === 0) {
394
- const result = {
395
- aiDir,
396
- lockFile: path.join(aiDir, '.adf.lock'),
397
- entries: [],
398
- allInSync: true,
399
- written: false,
400
- };
401
- if (options.format === 'json') {
402
- console.log(JSON.stringify(result, null, 2));
403
- }
404
- else {
405
- console.log(' No SYNC entries in manifest. Nothing to check.');
406
- }
407
- return index_1.EXIT_CODE.SUCCESS;
408
- }
409
- const lockFile = path.join(aiDir, '.adf.lock');
410
- const locked = loadLockFile(lockFile);
411
- const entries = [];
412
- for (const entry of manifest.sync) {
413
- const sourcePath = path.join(aiDir, entry.source);
414
- if (!fs.existsSync(sourcePath)) {
415
- throw new index_1.CLIError(`Sync source not found: ${sourcePath}`);
416
- }
417
- const sourceContent = fs.readFileSync(sourcePath, 'utf-8');
418
- const sourceHash = hashContent(sourceContent);
419
- const lockedHash = locked[entry.source] ?? null;
420
- entries.push({
421
- source: entry.source,
422
- target: entry.target,
423
- sourceHash,
424
- lockedHash,
425
- inSync: lockedHash === sourceHash,
426
- });
427
- }
428
- const allInSync = entries.every(e => e.inSync);
429
- if (writeMode) {
430
- const newLock = {};
431
- for (const e of entries) {
432
- newLock[e.source] = e.sourceHash;
433
- }
434
- fs.writeFileSync(lockFile, JSON.stringify(newLock, null, 2) + '\n');
435
- const result = {
436
- aiDir,
437
- lockFile,
438
- entries,
439
- allInSync: true,
440
- written: true,
441
- };
442
- if (options.format === 'json') {
443
- console.log(JSON.stringify(result, null, 2));
444
- }
445
- else {
446
- console.log(` [ok] Updated ${lockFile} with ${entries.length} hash${entries.length === 1 ? '' : 'es'}.`);
447
- }
448
- return index_1.EXIT_CODE.SUCCESS;
449
- }
450
- // --check mode
451
- const result = {
452
- aiDir,
453
- lockFile,
454
- entries,
455
- allInSync,
456
- written: false,
457
- };
458
- if (options.format === 'json') {
459
- const syncOut = { ...result };
460
- if (!allInSync) {
461
- syncOut.nextActions = ['Regenerate targets from source .adf files', 'charter adf sync --write'];
462
- }
463
- console.log(JSON.stringify(syncOut, null, 2));
464
- }
465
- else {
466
- for (const e of entries) {
467
- if (e.inSync) {
468
- console.log(` [ok] ${e.source} -> ${e.target} (in sync)`);
469
- }
470
- else if (e.lockedHash === null) {
471
- console.log(` [warn] ${e.source} -> ${e.target} (no lock entry — run: charter adf sync --write)`);
472
- }
473
- else {
474
- console.log(` [fail] ${e.source} -> ${e.target} (source changed since last sync)`);
475
- }
476
- }
477
- if (!allInSync) {
478
- console.log('');
479
- console.log(' Source .adf files have changed. Regenerate targets and run: charter adf sync --write');
480
- }
481
- }
482
- return allInSync ? index_1.EXIT_CODE.SUCCESS : index_1.EXIT_CODE.POLICY_VIOLATION;
483
- }
484
- function hashContent(content) {
485
- return crypto.createHash('sha256').update(content).digest('hex').slice(0, 16);
486
- }
487
- function loadLockFile(lockFile) {
488
- if (!fs.existsSync(lockFile))
489
- return {};
490
- try {
491
- return JSON.parse(fs.readFileSync(lockFile, 'utf-8'));
492
- }
493
- catch {
494
- return {};
495
- }
496
- }
497
- function adfEvidence(options, args) {
498
- const task = getFlag(args, '--task');
499
- const aiDir = getFlag(args, '--ai-dir') || '.ai';
500
- const contextJson = getFlag(args, '--context');
501
- const contextFile = getFlag(args, '--context-file');
502
- const autoMeasure = args.includes('--auto-measure');
503
- const manifestPath = path.join(aiDir, 'manifest.adf');
504
- if (!fs.existsSync(manifestPath)) {
505
- throw new index_1.CLIError(`manifest.adf not found at ${manifestPath}. Run: charter adf init`);
506
- }
507
- const manifestContent = fs.readFileSync(manifestPath, 'utf-8');
508
- const manifestDoc = (0, adf_1.parseAdf)(manifestContent);
509
- const manifest = (0, adf_1.parseManifest)(manifestDoc);
510
- // Resolve modules
511
- let modulePaths;
512
- let keywords = [];
513
- if (task) {
514
- keywords = task
515
- .split(/[\s,;:()[\]{}]+/)
516
- .filter(w => w.length > 1)
517
- .map(w => w.replace(/[^a-zA-Z0-9]/g, ''));
518
- modulePaths = (0, adf_1.resolveModules)(manifest, keywords);
519
- }
520
- else {
521
- modulePaths = [...manifest.defaultLoad];
522
- }
523
- const readFile = (p) => fs.readFileSync(p, 'utf-8');
524
- let context;
525
- const rawContext = contextFile ? readJsonFlag(contextFile, '--context-file') : contextJson;
526
- if (rawContext) {
527
- try {
528
- const parsed = JSON.parse(rawContext);
529
- if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
530
- throw new Error('must be a JSON object');
531
- }
532
- context = parsed;
533
- }
534
- catch (e) {
535
- const msg = e instanceof Error ? e.message : String(e);
536
- throw new index_1.CLIError(`Invalid --context JSON: ${msg}`);
537
- }
538
- }
539
- // Auto-measure: count lines in files referenced by manifest METRICS
540
- // Manifest keys are UPPERCASE (parser map disambiguation), metric keys are lowercase.
541
- const autoMeasured = [];
542
- if (autoMeasure && manifest.metrics.length > 0) {
543
- const measured = {};
544
- for (const ms of manifest.metrics) {
545
- const metricKey = ms.key.toLowerCase();
546
- const filePath = path.resolve(ms.path);
547
- if (fs.existsSync(filePath)) {
548
- const content = fs.readFileSync(filePath, 'utf-8');
549
- const lines = content.split('\n').length;
550
- measured[metricKey] = lines;
551
- autoMeasured.push({ metric: metricKey, path: ms.path, lines });
552
- }
553
- else {
554
- autoMeasured.push({ metric: metricKey, path: ms.path, lines: null, error: 'file not found' });
555
- }
556
- }
557
- // Merge: explicit --context wins over auto-measured
558
- context = { ...measured, ...context };
559
- }
560
- try {
561
- const bundle = (0, adf_1.bundleModules)(aiDir, modulePaths, readFile, keywords);
562
- const evidence = (0, adf_1.validateConstraints)(bundle.mergedDocument, context);
563
- // Check sync status
564
- const lockFile = path.join(aiDir, '.adf.lock');
565
- const locked = loadLockFile(lockFile);
566
- const syncEntries = [];
567
- for (const entry of manifest.sync) {
568
- const sourcePath = path.join(aiDir, entry.source);
569
- if (fs.existsSync(sourcePath)) {
570
- const sourceContent = fs.readFileSync(sourcePath, 'utf-8');
571
- const sourceHash = hashContent(sourceContent);
572
- const lockedHash = locked[entry.source] ?? null;
573
- syncEntries.push({ source: entry.source, inSync: lockedHash === sourceHash });
574
- }
575
- }
576
- const allInSync = syncEntries.length === 0 || syncEntries.every(e => e.inSync);
577
- const staleCount = syncEntries.filter(e => !e.inSync).length;
578
- if (options.format === 'json') {
579
- const jsonOut = {
580
- aiDir,
581
- resolvedModules: bundle.resolvedModules,
582
- tokenEstimate: bundle.tokenEstimate,
583
- tokenBudget: bundle.tokenBudget,
584
- tokenUtilization: bundle.tokenUtilization,
585
- constraints: evidence.constraints,
586
- weightSummary: evidence.weightSummary,
587
- allPassing: evidence.allPassing,
588
- failCount: evidence.failCount,
589
- warnCount: evidence.warnCount,
590
- syncStatus: { allInSync, staleCount },
591
- };
592
- if (task) {
593
- jsonOut.task = task;
594
- jsonOut.keywords = keywords;
595
- }
596
- if (bundle.advisoryOnlyModules.length > 0) {
597
- jsonOut.advisoryOnlyModules = bundle.advisoryOnlyModules;
598
- }
599
- if (autoMeasured.length > 0) {
600
- jsonOut.autoMeasured = autoMeasured;
601
- }
602
- // Suggest logical next steps based on results
603
- const nextActions = [];
604
- if (!evidence.allPassing) {
605
- nextActions.push('Fix failing constraints before merging');
606
- }
607
- if (!allInSync) {
608
- nextActions.push('charter adf sync --write');
609
- }
610
- if (evidence.warnCount > 0) {
611
- nextActions.push('Review metrics at ceiling boundary');
612
- }
613
- if (nextActions.length > 0) {
614
- jsonOut.nextActions = nextActions;
615
- }
616
- console.log(JSON.stringify(jsonOut, null, 2));
617
- }
618
- else {
619
- console.log('');
620
- console.log(' ADF Evidence Report');
621
- console.log(' ===================');
622
- console.log(` Modules loaded: ${bundle.resolvedModules.join(', ')}`);
623
- console.log(` Token estimate: ~${bundle.tokenEstimate}`);
624
- if (bundle.tokenBudget !== null) {
625
- const pct = bundle.tokenUtilization !== null
626
- ? ` (${(bundle.tokenUtilization * 100).toFixed(0)}%)`
627
- : '';
628
- console.log(` Token budget: ${bundle.tokenBudget}${pct}`);
629
- }
630
- console.log('');
631
- // Auto-measured metrics
632
- if (autoMeasured.length > 0) {
633
- console.log(' Auto-measured:');
634
- for (const m of autoMeasured) {
635
- if (m.lines !== null) {
636
- console.log(` ${m.metric}: ${m.lines} lines (${m.path})`);
637
- }
638
- else {
639
- console.log(` ${m.metric}: [file not found] (${m.path})`);
640
- }
641
- }
642
- console.log('');
643
- }
644
- // Weight summary
645
- console.log(' Section weights:');
646
- console.log(` Load-bearing: ${evidence.weightSummary.loadBearing}`);
647
- console.log(` Advisory: ${evidence.weightSummary.advisory}`);
648
- console.log(` Unweighted: ${evidence.weightSummary.unweighted}`);
649
- console.log('');
650
- // Advisory-only module warnings
651
- if (bundle.advisoryOnlyModules.length > 0) {
652
- console.log(' Advisory-only modules:');
653
- for (const m of bundle.advisoryOnlyModules) {
654
- console.log(` [!] ${m}: no load-bearing sections`);
655
- }
656
- console.log('');
657
- }
658
- // Constraints
659
- if (evidence.constraints.length > 0) {
660
- console.log(' Constraints:');
661
- for (const c of evidence.constraints) {
662
- const icon = c.status === 'pass' ? 'ok' : c.status === 'warn' ? 'WARN' : 'FAIL';
663
- console.log(` [${icon}] ${c.message}`);
664
- }
665
- }
666
- else {
667
- console.log(' Constraints: (none)');
668
- }
669
- console.log('');
670
- // Sync status
671
- if (syncEntries.length > 0) {
672
- if (allInSync) {
673
- console.log(' Sync: all sources in sync');
674
- }
675
- else {
676
- console.log(` Sync: ${staleCount} source${staleCount === 1 ? '' : 's'} out of sync`);
677
- }
678
- }
679
- else {
680
- console.log(' Sync: no sync entries configured');
681
- }
682
- console.log('');
683
- // Verdict
684
- const verdict = evidence.allPassing ? 'PASS' : 'FAIL';
685
- console.log(` Verdict: ${verdict}`);
686
- if (evidence.warnCount > 0) {
687
- console.log(` (${evidence.warnCount} warning${evidence.warnCount === 1 ? '' : 's'} — at ceiling boundary)`);
688
- }
689
- console.log('');
690
- }
691
- // CI mode: exit 1 on constraint failures
692
- if (options.ciMode && !evidence.allPassing) {
693
- return index_1.EXIT_CODE.POLICY_VIOLATION;
694
- }
695
- return index_1.EXIT_CODE.SUCCESS;
696
- }
697
- catch (e) {
698
- if (e instanceof Error && e.name === 'AdfBundleError') {
699
- if (options.format === 'json') {
700
- console.log(JSON.stringify({ error: e.message }, null, 2));
701
- }
702
- else {
703
- console.error(` [error] ${e.message}`);
704
- }
705
- return index_1.EXIT_CODE.RUNTIME_ERROR;
706
- }
707
- throw e;
708
- }
709
- }
710
- // ============================================================================
711
334
  // Helpers
712
335
  // ============================================================================
713
336
  function getFlag(args, flag) {
@@ -728,8 +351,9 @@ function printHelp() {
728
351
  console.log(' charter adf — Attention-Directed Format tools');
729
352
  console.log('');
730
353
  console.log(' Usage:');
731
- console.log(' charter adf init [--ai-dir <dir>] [--force]');
354
+ console.log(' charter adf init [--ai-dir <dir>] [--force] [--emit-pointers]');
732
355
  console.log(' Scaffold .ai/ directory with manifest, core, and state modules.');
356
+ console.log(' --emit-pointers: also generate thin pointer files (CLAUDE.md, .cursorrules, agents.md)');
733
357
  console.log('');
734
358
  console.log(' charter adf fmt <file> [--check] [--write]');
735
359
  console.log(' Parse and reformat an ADF file to canonical form.');
@@ -750,6 +374,9 @@ function printHelp() {
750
374
  console.log(' charter adf sync --write [--ai-dir <dir>]');
751
375
  console.log(' Update .adf.lock with current source hashes.');
752
376
  console.log('');
377
+ console.log(' charter adf sync --explain');
378
+ console.log(' Show .adf.lock schema documentation.');
379
+ console.log('');
753
380
  console.log(' charter adf evidence [--task "<prompt>"] [--ai-dir <dir>] [--auto-measure]');
754
381
  console.log(' [--context \'{"key": value}\']');
755
382
  console.log(' Validate metric constraints and produce a structured evidence report.');
@@ -759,5 +386,15 @@ function printHelp() {
759
386
  console.log(' --context-file: read --context JSON from a file instead.');
760
387
  console.log(' In --ci mode, exit 1 if any constraint fails.');
761
388
  console.log('');
389
+ console.log(' charter adf migrate [--dry-run] [--source <file>] [--no-backup]');
390
+ console.log(' [--merge-strategy append|dedupe|replace] [--ai-dir <dir>]');
391
+ console.log(' Ingest existing agent config files (CLAUDE.md, .cursorrules, etc.) and');
392
+ console.log(' migrate their content into structured ADF modules. Replaces originals');
393
+ console.log(' with thin pointers that retain environment-specific rules.');
394
+ console.log(' --dry-run: preview migration plan without writing files');
395
+ console.log(' --source: migrate a single file instead of scanning all agent configs');
396
+ console.log(' --no-backup: skip creating .pre-adf-migrate.bak backups');
397
+ console.log(' --merge-strategy: append (always add), dedupe (skip duplicates, default), replace');
398
+ console.log('');
762
399
  }
763
400
  //# sourceMappingURL=adf.js.map