@stackbilt/cli 0.3.3 → 0.4.1

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.
@@ -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;AAO3C,eAAO,MAAM,iBAAiB,0VAc7B,CAAC;AAEF,eAAO,MAAM,aAAa,moDAuCzB,CAAC;AAEF,eAAO,MAAM,cAAc,mJAI1B,CAAC;AAMF,wBAAsB,UAAU,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAyBrF;AAeD,eAAO,MAAM,iBAAiB,2bAU7B,CAAC;AAEF,eAAO,MAAM,mBAAmB,oSAO/B,CAAC;AAEF,eAAO,MAAM,iBAAiB,8UAU7B,CAAC"}
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;
@@ -42,9 +42,12 @@ exports.POINTER_AGENTS_MD = exports.POINTER_CURSORRULES = exports.POINTER_CLAUDE
42
42
  exports.adfCommand = adfCommand;
43
43
  const fs = __importStar(require("node:fs"));
44
44
  const path = __importStar(require("node:path"));
45
- const crypto = __importStar(require("node:crypto"));
46
45
  const adf_1 = require("@stackbilt/adf");
47
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");
48
51
  // ============================================================================
49
52
  // Scaffold Content
50
53
  // ============================================================================
@@ -65,35 +68,15 @@ exports.MANIFEST_SCAFFOLD = `ADF: 0.1
65
68
  `;
66
69
  exports.CORE_SCAFFOLD = `ADF: 0.1
67
70
 
68
- # Rule Routing Guide (remove after initial setup)
69
- # \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
70
- # Where does each rule belong?
71
- #
72
- # Pure runtime/environment? (OS, line endings, shell)
73
- # \u2192 CLAUDE.md (not ADF)
74
- #
75
- # Universal architecture constraint? (platform choice, tenant isolation)
76
- # \u2192 core.adf CONSTRAINTS [load-bearing]
77
- #
78
- # Stack-specific operational rule? (wrangler flags, D1 batching)
79
- # \u2192 domain-specific .adf module (backend.adf, frontend.adf)
80
- #
81
- # Agent identity/behavior? ("You ARE the X agent", bias toward action)
82
- # \u2192 core.adf CONTEXT
83
- #
84
- # Language/tooling discipline? (type checks, enum safety)
85
- # \u2192 core.adf CONSTRAINTS or dedicated section
86
- #
87
- # Section weight guide:
88
- # [load-bearing] = violation causes incorrect output
89
- # [advisory] = best practice, not enforced
90
- # (no tag) = informational context
91
- #
92
- # Section types (open taxonomy, custom sections allowed):
93
- # CONTEXT \u2014 factual project/agent identity
94
- # CONSTRAINTS \u2014 must/never rules
95
- # ADVISORY \u2014 should/prefer guidance
96
- # METRICS \u2014 quantitative ceilings (key: value / ceiling [unit])
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
97
80
 
98
81
  \u26A0\uFE0F CONSTRAINTS [load-bearing]:
99
82
  - Use Conventional Commits (feat, fix, docs, chore)
@@ -126,16 +109,18 @@ async function adfCommand(options, args) {
126
109
  case 'patch':
127
110
  return adfPatch(options, restArgs);
128
111
  case 'bundle':
129
- return adfBundle(options, restArgs);
112
+ return (0, adf_bundle_1.adfBundle)(options, restArgs);
130
113
  case 'sync':
131
- return adfSync(options, restArgs);
114
+ return (0, adf_sync_1.adfSync)(options, restArgs);
132
115
  case 'evidence':
133
- 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);
134
119
  default:
135
- 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`);
136
121
  }
137
122
  }
138
- // ── Thin pointer file content ──
123
+ // -- Thin pointer file content --
139
124
  exports.POINTER_CLAUDE_MD = `# Project Context
140
125
 
141
126
  > This project uses [ADF](https://github.com/Stackbilt-dev/charter) for AI agent context management.
@@ -346,495 +331,6 @@ function adfPatch(options, args) {
346
331
  }
347
332
  }
348
333
  // ============================================================================
349
- // adf bundle
350
- // ============================================================================
351
- function adfBundle(options, args) {
352
- const task = getFlag(args, '--task');
353
- if (!task) {
354
- throw new index_1.CLIError('adf bundle requires --task "<prompt>". Usage: charter adf bundle --task "Fix React component"');
355
- }
356
- const aiDir = getFlag(args, '--ai-dir') || '.ai';
357
- const manifestPath = path.join(aiDir, 'manifest.adf');
358
- if (!fs.existsSync(manifestPath)) {
359
- throw new index_1.CLIError(`manifest.adf not found at ${manifestPath}. Run: charter adf init`);
360
- }
361
- const manifestContent = fs.readFileSync(manifestPath, 'utf-8');
362
- const manifestDoc = (0, adf_1.parseAdf)(manifestContent);
363
- const manifest = (0, adf_1.parseManifest)(manifestDoc);
364
- // Tokenize task into keywords (simple word split)
365
- const keywords = task
366
- .split(/[\s,;:()[\]{}]+/)
367
- .filter(w => w.length > 1)
368
- .map(w => w.replace(/[^a-zA-Z0-9]/g, ''));
369
- const modulePaths = (0, adf_1.resolveModules)(manifest, keywords);
370
- const readFile = (p) => fs.readFileSync(p, 'utf-8');
371
- try {
372
- const result = (0, adf_1.bundleModules)(aiDir, modulePaths, readFile, keywords);
373
- if (options.format === 'json') {
374
- const jsonOut = {
375
- task,
376
- keywords,
377
- resolvedModules: result.resolvedModules,
378
- tokenEstimate: result.tokenEstimate,
379
- tokenBudget: result.tokenBudget,
380
- tokenUtilization: result.tokenUtilization,
381
- perModuleTokens: result.perModuleTokens,
382
- triggerMatches: result.triggerMatches,
383
- };
384
- if (result.unmatchedModules.length > 0) {
385
- jsonOut.unmatchedModules = result.unmatchedModules;
386
- }
387
- if (result.moduleBudgetOverruns.length > 0) {
388
- jsonOut.moduleBudgetOverruns = result.moduleBudgetOverruns;
389
- }
390
- if (result.advisoryOnlyModules.length > 0) {
391
- jsonOut.advisoryOnlyModules = result.advisoryOnlyModules;
392
- }
393
- if (result.manifest.cadence.length > 0) {
394
- jsonOut.cadence = result.manifest.cadence;
395
- }
396
- console.log(JSON.stringify(jsonOut, null, 2));
397
- }
398
- else {
399
- console.log(` Task: "${task}"`);
400
- console.log(` Keywords: ${keywords.join(', ')}`);
401
- console.log(` Resolved modules: ${result.resolvedModules.join(', ')}`);
402
- console.log(` Token estimate: ~${result.tokenEstimate}`);
403
- if (result.tokenBudget !== null) {
404
- const pct = result.tokenUtilization !== null
405
- ? ` (${(result.tokenUtilization * 100).toFixed(0)}%)`
406
- : '';
407
- console.log(` Token budget: ${result.tokenBudget}${pct}`);
408
- }
409
- console.log('');
410
- if (result.moduleBudgetOverruns.length > 0) {
411
- console.log(' Module budget overruns:');
412
- for (const o of result.moduleBudgetOverruns) {
413
- console.log(` [!] ${o.module}: ~${o.tokens} tokens (budget: ${o.budget})`);
414
- }
415
- console.log('');
416
- }
417
- if (result.triggerMatches.length > 0) {
418
- console.log(' Trigger report:');
419
- for (const tm of result.triggerMatches) {
420
- const icon = tm.matched ? '+' : '-';
421
- const kw = tm.matchedKeywords.length > 0 ? ` [${tm.matchedKeywords.join(', ')}]` : '';
422
- console.log(` [${icon}] ${tm.module} (${tm.trigger})${kw}`);
423
- }
424
- console.log('');
425
- }
426
- if (result.unmatchedModules.length > 0) {
427
- console.log(' Unmatched modules (not loaded):');
428
- for (const m of result.unmatchedModules) {
429
- console.log(` [-] ${m}`);
430
- }
431
- console.log('');
432
- }
433
- if (result.advisoryOnlyModules.length > 0) {
434
- console.log(' Advisory-only modules:');
435
- for (const m of result.advisoryOnlyModules) {
436
- console.log(` [!] ${m}: no load-bearing sections`);
437
- }
438
- console.log('');
439
- }
440
- if (result.manifest.cadence.length > 0) {
441
- console.log(' Cadence schedule:');
442
- for (const c of result.manifest.cadence) {
443
- console.log(` ${c.check}: ${c.frequency}`);
444
- }
445
- console.log('');
446
- }
447
- // Output merged document
448
- const output = (0, adf_1.formatAdf)(result.mergedDocument);
449
- console.log(' --- Merged Context ---');
450
- console.log(output);
451
- }
452
- return index_1.EXIT_CODE.SUCCESS;
453
- }
454
- catch (e) {
455
- if (e instanceof Error && e.name === 'AdfBundleError') {
456
- if (options.format === 'json') {
457
- console.log(JSON.stringify({ error: e.message }, null, 2));
458
- }
459
- else {
460
- console.error(` [error] ${e.message}`);
461
- }
462
- return index_1.EXIT_CODE.RUNTIME_ERROR;
463
- }
464
- throw e;
465
- }
466
- }
467
- function adfSync(options, args) {
468
- // --explain: output lockfile schema documentation and exit
469
- if (args.includes('--explain')) {
470
- const explanation = {
471
- format: '.adf.lock',
472
- description: 'Flat JSON map of ADF source files to SHA-256 hash prefixes (16 hex chars)',
473
- schema: {
474
- type: 'object',
475
- pattern: '{ "<filename>.adf": "<sha256-prefix-16>" }',
476
- example: {
477
- 'core.adf': '54d5c9a146d6da3c',
478
- 'state.adf': 'a1b2c3d4e5f67890',
479
- },
480
- },
481
- hashAlgorithm: 'SHA-256, first 16 hex characters',
482
- commands: {
483
- check: 'charter adf sync --check \u2014 verify sources match locked hashes',
484
- write: 'charter adf sync --write \u2014 update lock with current hashes',
485
- },
486
- location: '.ai/.adf.lock (relative to AI directory)',
487
- purpose: 'Detect when ADF source files have changed since last sync. Used in CI to enforce governance drift checks.',
488
- };
489
- if (options.format === 'json') {
490
- console.log(JSON.stringify(explanation, null, 2));
491
- }
492
- else {
493
- console.log('ADF Sync Lock Format (.adf.lock)');
494
- console.log('================================\n');
495
- console.log('Format: Flat JSON map of source files to hash prefixes\n');
496
- console.log('Schema: { "<filename>.adf": "<sha256-prefix-16>" }\n');
497
- console.log('Hash: SHA-256, first 16 hex characters\n');
498
- console.log('Location: .ai/.adf.lock\n');
499
- console.log('Commands:');
500
- console.log(' sync --check Verify sources match locked hashes');
501
- console.log(' sync --write Update lock with current hashes');
502
- console.log(' sync --explain Show this schema documentation\n');
503
- console.log('Purpose: Detect ADF source drift. Used in CI governance checks.');
504
- }
505
- return index_1.EXIT_CODE.SUCCESS;
506
- }
507
- const aiDir = getFlag(args, '--ai-dir') || '.ai';
508
- const checkMode = args.includes('--check');
509
- const writeMode = args.includes('--write');
510
- if (!checkMode && !writeMode) {
511
- throw new index_1.CLIError('adf sync requires --check, --write, or --explain. Usage: charter adf sync --check');
512
- }
513
- const manifestPath = path.join(aiDir, 'manifest.adf');
514
- if (!fs.existsSync(manifestPath)) {
515
- throw new index_1.CLIError(`manifest.adf not found at ${manifestPath}. Run: charter adf init`);
516
- }
517
- const manifestContent = fs.readFileSync(manifestPath, 'utf-8');
518
- const manifestDoc = (0, adf_1.parseAdf)(manifestContent);
519
- const manifest = (0, adf_1.parseManifest)(manifestDoc);
520
- if (manifest.sync.length === 0) {
521
- const result = {
522
- aiDir,
523
- lockFile: path.join(aiDir, '.adf.lock'),
524
- entries: [],
525
- allInSync: true,
526
- written: false,
527
- };
528
- if (options.format === 'json') {
529
- console.log(JSON.stringify(result, null, 2));
530
- }
531
- else {
532
- console.log(' No SYNC entries in manifest. Nothing to check.');
533
- }
534
- return index_1.EXIT_CODE.SUCCESS;
535
- }
536
- const lockFile = path.join(aiDir, '.adf.lock');
537
- const locked = loadLockFile(lockFile);
538
- const entries = [];
539
- for (const entry of manifest.sync) {
540
- const sourcePath = path.join(aiDir, entry.source);
541
- if (!fs.existsSync(sourcePath)) {
542
- throw new index_1.CLIError(`Sync source not found: ${sourcePath}`);
543
- }
544
- const sourceContent = fs.readFileSync(sourcePath, 'utf-8');
545
- const sourceHash = hashContent(sourceContent);
546
- const lockedHash = locked[entry.source] ?? null;
547
- entries.push({
548
- source: entry.source,
549
- target: entry.target,
550
- sourceHash,
551
- lockedHash,
552
- inSync: lockedHash === sourceHash,
553
- });
554
- }
555
- const allInSync = entries.every(e => e.inSync);
556
- if (writeMode) {
557
- const newLock = {};
558
- for (const e of entries) {
559
- newLock[e.source] = e.sourceHash;
560
- }
561
- fs.writeFileSync(lockFile, JSON.stringify(newLock, null, 2) + '\n');
562
- const result = {
563
- aiDir,
564
- lockFile,
565
- entries,
566
- allInSync: true,
567
- written: true,
568
- };
569
- if (options.format === 'json') {
570
- console.log(JSON.stringify(result, null, 2));
571
- }
572
- else {
573
- console.log(` [ok] Updated ${lockFile} with ${entries.length} hash${entries.length === 1 ? '' : 'es'}.`);
574
- }
575
- return index_1.EXIT_CODE.SUCCESS;
576
- }
577
- // --check mode
578
- const result = {
579
- aiDir,
580
- lockFile,
581
- entries,
582
- allInSync,
583
- written: false,
584
- };
585
- if (options.format === 'json') {
586
- const syncOut = { ...result };
587
- if (!allInSync) {
588
- syncOut.nextActions = ['Regenerate targets from source .adf files', 'charter adf sync --write'];
589
- }
590
- console.log(JSON.stringify(syncOut, null, 2));
591
- }
592
- else {
593
- for (const e of entries) {
594
- if (e.inSync) {
595
- console.log(` [ok] ${e.source} -> ${e.target} (in sync)`);
596
- }
597
- else if (e.lockedHash === null) {
598
- console.log(` [warn] ${e.source} -> ${e.target} (no lock entry — run: charter adf sync --write)`);
599
- }
600
- else {
601
- console.log(` [fail] ${e.source} -> ${e.target} (source changed since last sync)`);
602
- }
603
- }
604
- if (!allInSync) {
605
- console.log('');
606
- console.log(' Source .adf files have changed. Regenerate targets and run: charter adf sync --write');
607
- }
608
- }
609
- return allInSync ? index_1.EXIT_CODE.SUCCESS : index_1.EXIT_CODE.POLICY_VIOLATION;
610
- }
611
- function hashContent(content) {
612
- return crypto.createHash('sha256').update(content).digest('hex').slice(0, 16);
613
- }
614
- function loadLockFile(lockFile) {
615
- if (!fs.existsSync(lockFile))
616
- return {};
617
- try {
618
- return JSON.parse(fs.readFileSync(lockFile, 'utf-8'));
619
- }
620
- catch {
621
- return {};
622
- }
623
- }
624
- function adfEvidence(options, args) {
625
- const task = getFlag(args, '--task');
626
- const aiDir = getFlag(args, '--ai-dir') || '.ai';
627
- const contextJson = getFlag(args, '--context');
628
- const contextFile = getFlag(args, '--context-file');
629
- const autoMeasure = args.includes('--auto-measure');
630
- const manifestPath = path.join(aiDir, 'manifest.adf');
631
- if (!fs.existsSync(manifestPath)) {
632
- throw new index_1.CLIError(`manifest.adf not found at ${manifestPath}. Run: charter adf init`);
633
- }
634
- const manifestContent = fs.readFileSync(manifestPath, 'utf-8');
635
- const manifestDoc = (0, adf_1.parseAdf)(manifestContent);
636
- const manifest = (0, adf_1.parseManifest)(manifestDoc);
637
- // Resolve modules
638
- let modulePaths;
639
- let keywords = [];
640
- if (task) {
641
- keywords = task
642
- .split(/[\s,;:()[\]{}]+/)
643
- .filter(w => w.length > 1)
644
- .map(w => w.replace(/[^a-zA-Z0-9]/g, ''));
645
- modulePaths = (0, adf_1.resolveModules)(manifest, keywords);
646
- }
647
- else {
648
- modulePaths = [...manifest.defaultLoad];
649
- }
650
- const readFile = (p) => fs.readFileSync(p, 'utf-8');
651
- let context;
652
- const rawContext = contextFile ? readJsonFlag(contextFile, '--context-file') : contextJson;
653
- if (rawContext) {
654
- try {
655
- const parsed = JSON.parse(rawContext);
656
- if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
657
- throw new Error('must be a JSON object');
658
- }
659
- context = parsed;
660
- }
661
- catch (e) {
662
- const msg = e instanceof Error ? e.message : String(e);
663
- throw new index_1.CLIError(`Invalid --context JSON: ${msg}`);
664
- }
665
- }
666
- // Auto-measure: count lines in files referenced by manifest METRICS
667
- // Manifest keys are UPPERCASE (parser map disambiguation), metric keys are lowercase.
668
- const autoMeasured = [];
669
- if (autoMeasure && manifest.metrics.length > 0) {
670
- const measured = {};
671
- for (const ms of manifest.metrics) {
672
- const metricKey = ms.key.toLowerCase();
673
- const filePath = path.resolve(ms.path);
674
- if (fs.existsSync(filePath)) {
675
- const content = fs.readFileSync(filePath, 'utf-8');
676
- const lines = content.split('\n').length;
677
- measured[metricKey] = lines;
678
- autoMeasured.push({ metric: metricKey, path: ms.path, lines });
679
- }
680
- else {
681
- autoMeasured.push({ metric: metricKey, path: ms.path, lines: null, error: 'file not found' });
682
- }
683
- }
684
- // Merge: explicit --context wins over auto-measured
685
- context = { ...measured, ...context };
686
- }
687
- try {
688
- const bundle = (0, adf_1.bundleModules)(aiDir, modulePaths, readFile, keywords);
689
- const evidence = (0, adf_1.validateConstraints)(bundle.mergedDocument, context);
690
- // Check sync status
691
- const lockFile = path.join(aiDir, '.adf.lock');
692
- const locked = loadLockFile(lockFile);
693
- const syncEntries = [];
694
- for (const entry of manifest.sync) {
695
- const sourcePath = path.join(aiDir, entry.source);
696
- if (fs.existsSync(sourcePath)) {
697
- const sourceContent = fs.readFileSync(sourcePath, 'utf-8');
698
- const sourceHash = hashContent(sourceContent);
699
- const lockedHash = locked[entry.source] ?? null;
700
- syncEntries.push({ source: entry.source, inSync: lockedHash === sourceHash });
701
- }
702
- }
703
- const allInSync = syncEntries.length === 0 || syncEntries.every(e => e.inSync);
704
- const staleCount = syncEntries.filter(e => !e.inSync).length;
705
- if (options.format === 'json') {
706
- const jsonOut = {
707
- aiDir,
708
- resolvedModules: bundle.resolvedModules,
709
- tokenEstimate: bundle.tokenEstimate,
710
- tokenBudget: bundle.tokenBudget,
711
- tokenUtilization: bundle.tokenUtilization,
712
- constraints: evidence.constraints,
713
- weightSummary: evidence.weightSummary,
714
- allPassing: evidence.allPassing,
715
- failCount: evidence.failCount,
716
- warnCount: evidence.warnCount,
717
- syncStatus: { allInSync, staleCount },
718
- };
719
- if (task) {
720
- jsonOut.task = task;
721
- jsonOut.keywords = keywords;
722
- }
723
- if (bundle.advisoryOnlyModules.length > 0) {
724
- jsonOut.advisoryOnlyModules = bundle.advisoryOnlyModules;
725
- }
726
- if (autoMeasured.length > 0) {
727
- jsonOut.autoMeasured = autoMeasured;
728
- }
729
- // Suggest logical next steps based on results
730
- const nextActions = [];
731
- if (!evidence.allPassing) {
732
- nextActions.push('Fix failing constraints before merging');
733
- }
734
- if (!allInSync) {
735
- nextActions.push('charter adf sync --write');
736
- }
737
- if (evidence.warnCount > 0) {
738
- nextActions.push('Review metrics at ceiling boundary');
739
- }
740
- if (nextActions.length > 0) {
741
- jsonOut.nextActions = nextActions;
742
- }
743
- console.log(JSON.stringify(jsonOut, null, 2));
744
- }
745
- else {
746
- console.log('');
747
- console.log(' ADF Evidence Report');
748
- console.log(' ===================');
749
- console.log(` Modules loaded: ${bundle.resolvedModules.join(', ')}`);
750
- console.log(` Token estimate: ~${bundle.tokenEstimate}`);
751
- if (bundle.tokenBudget !== null) {
752
- const pct = bundle.tokenUtilization !== null
753
- ? ` (${(bundle.tokenUtilization * 100).toFixed(0)}%)`
754
- : '';
755
- console.log(` Token budget: ${bundle.tokenBudget}${pct}`);
756
- }
757
- console.log('');
758
- // Auto-measured metrics
759
- if (autoMeasured.length > 0) {
760
- console.log(' Auto-measured:');
761
- for (const m of autoMeasured) {
762
- if (m.lines !== null) {
763
- console.log(` ${m.metric}: ${m.lines} lines (${m.path})`);
764
- }
765
- else {
766
- console.log(` ${m.metric}: [file not found] (${m.path})`);
767
- }
768
- }
769
- console.log('');
770
- }
771
- // Weight summary
772
- console.log(' Section weights:');
773
- console.log(` Load-bearing: ${evidence.weightSummary.loadBearing}`);
774
- console.log(` Advisory: ${evidence.weightSummary.advisory}`);
775
- console.log(` Unweighted: ${evidence.weightSummary.unweighted}`);
776
- console.log('');
777
- // Advisory-only module warnings
778
- if (bundle.advisoryOnlyModules.length > 0) {
779
- console.log(' Advisory-only modules:');
780
- for (const m of bundle.advisoryOnlyModules) {
781
- console.log(` [!] ${m}: no load-bearing sections`);
782
- }
783
- console.log('');
784
- }
785
- // Constraints
786
- if (evidence.constraints.length > 0) {
787
- console.log(' Constraints:');
788
- for (const c of evidence.constraints) {
789
- const icon = c.status === 'pass' ? 'ok' : c.status === 'warn' ? 'WARN' : 'FAIL';
790
- console.log(` [${icon}] ${c.message}`);
791
- }
792
- }
793
- else {
794
- console.log(' Constraints: (none)');
795
- }
796
- console.log('');
797
- // Sync status
798
- if (syncEntries.length > 0) {
799
- if (allInSync) {
800
- console.log(' Sync: all sources in sync');
801
- }
802
- else {
803
- console.log(` Sync: ${staleCount} source${staleCount === 1 ? '' : 's'} out of sync`);
804
- }
805
- }
806
- else {
807
- console.log(' Sync: no sync entries configured');
808
- }
809
- console.log('');
810
- // Verdict
811
- const verdict = evidence.allPassing ? 'PASS' : 'FAIL';
812
- console.log(` Verdict: ${verdict}`);
813
- if (evidence.warnCount > 0) {
814
- console.log(` (${evidence.warnCount} warning${evidence.warnCount === 1 ? '' : 's'} — at ceiling boundary)`);
815
- }
816
- console.log('');
817
- }
818
- // CI mode: exit 1 on constraint failures
819
- if (options.ciMode && !evidence.allPassing) {
820
- return index_1.EXIT_CODE.POLICY_VIOLATION;
821
- }
822
- return index_1.EXIT_CODE.SUCCESS;
823
- }
824
- catch (e) {
825
- if (e instanceof Error && e.name === 'AdfBundleError') {
826
- if (options.format === 'json') {
827
- console.log(JSON.stringify({ error: e.message }, null, 2));
828
- }
829
- else {
830
- console.error(` [error] ${e.message}`);
831
- }
832
- return index_1.EXIT_CODE.RUNTIME_ERROR;
833
- }
834
- throw e;
835
- }
836
- }
837
- // ============================================================================
838
334
  // Helpers
839
335
  // ============================================================================
840
336
  function getFlag(args, flag) {
@@ -890,5 +386,15 @@ function printHelp() {
890
386
  console.log(' --context-file: read --context JSON from a file instead.');
891
387
  console.log(' In --ci mode, exit 1 if any constraint fails.');
892
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('');
893
399
  }
894
400
  //# sourceMappingURL=adf.js.map