@codeyam/codeyam-cli 0.1.22 → 0.1.24

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 (102) hide show
  1. package/analyzer-template/.build-info.json +7 -7
  2. package/analyzer-template/log.txt +3 -3
  3. package/analyzer-template/packages/ai/src/lib/astScopes/methodSemantics.ts +135 -0
  4. package/analyzer-template/packages/ai/src/lib/astScopes/nodeToSource.ts +19 -0
  5. package/analyzer-template/packages/ai/src/lib/astScopes/paths.ts +11 -4
  6. package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateDataStructure.ts +5 -1
  7. package/analyzer-template/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.ts +1632 -1554
  8. package/analyzer-template/packages/database/src/lib/loadAnalysis.ts +7 -1
  9. package/analyzer-template/packages/github/dist/database/src/lib/loadAnalysis.d.ts.map +1 -1
  10. package/analyzer-template/packages/github/dist/database/src/lib/loadAnalysis.js +7 -1
  11. package/analyzer-template/packages/github/dist/database/src/lib/loadAnalysis.js.map +1 -1
  12. package/analyzer-template/project/runMultiScenarioServer.ts +26 -3
  13. package/background/src/lib/virtualized/project/runMultiScenarioServer.js +23 -3
  14. package/background/src/lib/virtualized/project/runMultiScenarioServer.js.map +1 -1
  15. package/codeyam-cli/src/commands/__tests__/editor.analyzeImportsArgs.test.js +47 -0
  16. package/codeyam-cli/src/commands/__tests__/editor.analyzeImportsArgs.test.js.map +1 -0
  17. package/codeyam-cli/src/commands/__tests__/editor.auditNoAutoAnalysis.test.js +17 -9
  18. package/codeyam-cli/src/commands/__tests__/editor.auditNoAutoAnalysis.test.js.map +1 -1
  19. package/codeyam-cli/src/commands/__tests__/editor.designSystem.test.js +30 -0
  20. package/codeyam-cli/src/commands/__tests__/editor.designSystem.test.js.map +1 -0
  21. package/codeyam-cli/src/commands/editor.js +207 -41
  22. package/codeyam-cli/src/commands/editor.js.map +1 -1
  23. package/codeyam-cli/src/commands/editorAnalyzeImportsArgs.js +23 -0
  24. package/codeyam-cli/src/commands/editorAnalyzeImportsArgs.js.map +1 -0
  25. package/codeyam-cli/src/data/designSystems.js +27 -0
  26. package/codeyam-cli/src/data/designSystems.js.map +1 -0
  27. package/codeyam-cli/src/utils/__tests__/editorApi.test.js +44 -0
  28. package/codeyam-cli/src/utils/__tests__/editorApi.test.js.map +1 -1
  29. package/codeyam-cli/src/utils/__tests__/editorAudit.test.js +103 -1
  30. package/codeyam-cli/src/utils/__tests__/editorAudit.test.js.map +1 -1
  31. package/codeyam-cli/src/utils/__tests__/editorScenarios.test.js +140 -1
  32. package/codeyam-cli/src/utils/__tests__/editorScenarios.test.js.map +1 -1
  33. package/codeyam-cli/src/utils/__tests__/editorSeedAdapter.test.js +50 -1
  34. package/codeyam-cli/src/utils/__tests__/editorSeedAdapter.test.js.map +1 -1
  35. package/codeyam-cli/src/utils/editorApi.js +16 -0
  36. package/codeyam-cli/src/utils/editorApi.js.map +1 -1
  37. package/codeyam-cli/src/utils/editorAudit.js +38 -2
  38. package/codeyam-cli/src/utils/editorAudit.js.map +1 -1
  39. package/codeyam-cli/src/utils/editorScenarios.js +60 -0
  40. package/codeyam-cli/src/utils/editorScenarios.js.map +1 -1
  41. package/codeyam-cli/src/utils/editorSeedAdapter.js +42 -2
  42. package/codeyam-cli/src/utils/editorSeedAdapter.js.map +1 -1
  43. package/codeyam-cli/src/utils/queue/__tests__/job.interactiveStart.test.js +159 -0
  44. package/codeyam-cli/src/utils/queue/__tests__/job.interactiveStart.test.js.map +1 -0
  45. package/codeyam-cli/src/utils/queue/job.js +9 -1
  46. package/codeyam-cli/src/utils/queue/job.js.map +1 -1
  47. package/codeyam-cli/src/webserver/__tests__/api.interactive-switch-scenario.test.js +98 -0
  48. package/codeyam-cli/src/webserver/__tests__/api.interactive-switch-scenario.test.js.map +1 -0
  49. package/codeyam-cli/src/webserver/__tests__/editorProxy.test.js +30 -11
  50. package/codeyam-cli/src/webserver/__tests__/editorProxy.test.js.map +1 -1
  51. package/codeyam-cli/src/webserver/app/routes/api.interactive-switch-scenario.js +34 -0
  52. package/codeyam-cli/src/webserver/app/routes/api.interactive-switch-scenario.js.map +1 -0
  53. package/codeyam-cli/src/webserver/build/client/assets/{InteractivePreview-CKeQT5Ty.js → InteractivePreview-DtYTSPL2.js} +1 -1
  54. package/codeyam-cli/src/webserver/build/client/assets/{ScenarioViewer-DUMfcNVK.js → ScenarioViewer-CefgqbCr.js} +1 -1
  55. package/codeyam-cli/src/webserver/build/client/assets/Spinner-Bc8BG-Lw.js +34 -0
  56. package/codeyam-cli/src/webserver/build/client/assets/{_index-BAWd-Xjf.js → _index-C1YkzTAV.js} +1 -1
  57. package/codeyam-cli/src/webserver/build/client/assets/{activity.(_tab)-BOARiB-g.js → activity.(_tab)-yH46LLUz.js} +1 -1
  58. package/codeyam-cli/src/webserver/build/client/assets/api.editor-verify-routes-l0sNRNKZ.js +1 -0
  59. package/codeyam-cli/src/webserver/build/client/assets/api.interactive-switch-scenario-l0sNRNKZ.js +1 -0
  60. package/codeyam-cli/src/webserver/build/client/assets/{dev.empty-C8y4mmyv.js → dev.empty-CRepiabR.js} +1 -1
  61. package/codeyam-cli/src/webserver/build/client/assets/{editor.entity.(_sha)-aIHKLB-m.js → editor.entity.(_sha)-oBrbke_R.js} +19 -19
  62. package/codeyam-cli/src/webserver/build/client/assets/{entity._sha._-ByHz6rAQ.js → entity._sha._-DYJRGiDI.js} +1 -1
  63. package/codeyam-cli/src/webserver/build/client/assets/{entity._sha.scenarios._scenarioId.dev-CmLO432x.js → entity._sha.scenarios._scenarioId.dev-wdiwx5-Z.js} +1 -1
  64. package/codeyam-cli/src/webserver/build/client/assets/{entity._sha.scenarios._scenarioId.fullscreen-Bz9sCUF_.js → entity._sha.scenarios._scenarioId.fullscreen-BrkN-40Y.js} +1 -1
  65. package/codeyam-cli/src/webserver/build/client/assets/{entity._sha_.create-scenario-DQM8E7L4.js → entity._sha_.create-scenario-DxfhekTZ.js} +1 -1
  66. package/codeyam-cli/src/webserver/build/client/assets/{entity._sha_.edit._scenarioId-CAoXLsQr.js → entity._sha_.edit._scenarioId-CRXJWmpB.js} +1 -1
  67. package/codeyam-cli/src/webserver/build/client/assets/manifest-694b698a.js +1 -0
  68. package/codeyam-cli/src/webserver/build/client/assets/{root-D2_tktnk.js → root-DXjFYOxD.js} +1 -1
  69. package/codeyam-cli/src/webserver/build/client/assets/useLastLogLine-D9QZKaLJ.js +2 -0
  70. package/codeyam-cli/src/webserver/build/server/assets/{analysisRunner-DjF-soOH.js → analysisRunner-zEYtiv0T.js} +1 -1
  71. package/codeyam-cli/src/webserver/build/server/assets/{index-nAvHGWbz.js → index-CcHPEbhi.js} +1 -1
  72. package/codeyam-cli/src/webserver/build/server/assets/{init-XhpIt-OT.js → init-D68IyWbU.js} +1 -1
  73. package/codeyam-cli/src/webserver/build/server/assets/{server-build-DVwiibFu.js → server-build-Cxzo0Zp2.js} +192 -148
  74. package/codeyam-cli/src/webserver/build/server/index.js +1 -1
  75. package/codeyam-cli/src/webserver/build-info.json +5 -5
  76. package/codeyam-cli/src/webserver/editorProxy.js +55 -3
  77. package/codeyam-cli/src/webserver/editorProxy.js.map +1 -1
  78. package/codeyam-cli/src/webserver/terminalServer.js +1 -2
  79. package/codeyam-cli/src/webserver/terminalServer.js.map +1 -1
  80. package/codeyam-cli/templates/codeyam-editor-reference.md +8 -6
  81. package/codeyam-cli/templates/design-systems/clean-dashboard-design-system.md +255 -0
  82. package/codeyam-cli/templates/design-systems/editorial-design-system.md +267 -0
  83. package/codeyam-cli/templates/design-systems/mono-brutalist-design-system.md +256 -0
  84. package/codeyam-cli/templates/design-systems/neo-brutalist-design-system.md +294 -0
  85. package/codeyam-cli/templates/nextjs-prisma-sqlite/seed-adapter.ts +47 -34
  86. package/codeyam-cli/templates/seed-adapters/supabase.ts +14 -5
  87. package/package.json +1 -1
  88. package/packages/ai/src/lib/astScopes/methodSemantics.js +99 -0
  89. package/packages/ai/src/lib/astScopes/methodSemantics.js.map +1 -1
  90. package/packages/ai/src/lib/astScopes/nodeToSource.js +16 -0
  91. package/packages/ai/src/lib/astScopes/nodeToSource.js.map +1 -1
  92. package/packages/ai/src/lib/astScopes/paths.js +12 -3
  93. package/packages/ai/src/lib/astScopes/paths.js.map +1 -1
  94. package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js +5 -1
  95. package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js.map +1 -1
  96. package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js +1330 -1270
  97. package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js.map +1 -1
  98. package/packages/database/src/lib/loadAnalysis.js +7 -1
  99. package/packages/database/src/lib/loadAnalysis.js.map +1 -1
  100. package/codeyam-cli/src/webserver/build/client/assets/Spinner-D0LgAaSa.js +0 -34
  101. package/codeyam-cli/src/webserver/build/client/assets/manifest-bcbb3d49.js +0 -1
  102. package/codeyam-cli/src/webserver/build/client/assets/useLastLogLine-BNd5hYuW.js +0 -2
@@ -13,6 +13,7 @@ import { installClaudeCodeSkills } from "../utils/install-skills.js";
13
13
  import { setupClaudeCodeSettings } from "../utils/setupClaudeCodeSettings.js";
14
14
  import { ensureAnalyzerFinalized, } from "../utils/analyzerFinalization.js";
15
15
  import { APP_FORMATS, TECH_STACKS } from "../data/techStacks.js";
16
+ import { DESIGN_SYSTEMS } from "../data/designSystems.js";
16
17
  import { getProjectRoot as getStateProjectRoot } from "../state.js";
17
18
  import initCommand from "./init.js";
18
19
  import { scanScenarioFiles, syncScenarioFilesToDatabase, backfillScenarioMetadata, migrateScenarioFormats, } from "../utils/scenariosManifest.js";
@@ -714,11 +715,17 @@ function printSetup(root) {
714
715
  console.log();
715
716
  // ── Design System ────────────────────────────────────────────────
716
717
  console.log(chalk.bold('Design System (ask FIRST):'));
717
- console.log(chalk.dim(' Ask: "Do you have a design system, brand guidelines, or style preferences you\'d like me to follow?"'));
718
+ console.log(chalk.dim(' Ask: "What visual style do you want? Pick a built-in design system or bring your own."'));
718
719
  console.log(chalk.dim(' Use AskUserQuestion with these EXACT option labels:'));
719
- console.log(chalk.yellow(' Option 1 label: "Yes, I\'ll paste my design system"'));
720
+ console.log();
721
+ for (const ds of DESIGN_SYSTEMS) {
722
+ console.log(chalk.yellow(` Option label: "${ds.name}"`) +
723
+ chalk.dim(` — ${ds.description}`));
724
+ console.log(chalk.dim(` → Run: codeyam editor design-system ${ds.id}`));
725
+ }
726
+ console.log(chalk.yellow(' Option label: "I\'ll paste my own design system"'));
720
727
  console.log(chalk.dim(' → Wait for paste, save to .codeyam/design-system.md, confirm with brief summary'));
721
- console.log(chalk.yellow(' Option 2 label: "No, use sensible defaults"'));
728
+ console.log(chalk.yellow(' Option label: "Skip use sensible defaults"'));
722
729
  console.log(chalk.dim(' → Skip'));
723
730
  console.log();
724
731
  console.log(chalk.bold('Checklist:'));
@@ -1132,14 +1139,13 @@ function printStep4(root, feature) {
1132
1139
  console.log('Verify everything works before presenting the prototype.');
1133
1140
  console.log();
1134
1141
  console.log(chalk.bold('Verify the dev server:'));
1135
- console.log(chalk.dim(` # Get dev server URL: codeyam editor dev-server`));
1136
- console.log(chalk.dim(' # Check page loads: curl -s -o /dev/null -w "%{http_code}" http://localhost:<dev-port>'));
1137
- console.log(chalk.dim(' # Check API routes: curl -s http://localhost:<dev-port>/api/your-route'));
1142
+ console.log(chalk.dim(' # Verify pages and API routes load:'));
1143
+ console.log(chalk.dim(` codeyam editor verify-routes '{"paths":["/your-page"],"apiRoutes":["/api/your-route"]}'`));
1138
1144
  console.log();
1139
1145
  console.log(chalk.bold('Verify before proceeding:'));
1140
1146
  console.log(chalk.yellow(' Verify everything works before presenting the prototype to the user.'));
1141
- checkbox('Verify the page loads: curl the dev server URL and confirm HTTP 200 (not an error page)');
1142
- checkbox('Verify API routes return valid JSON: curl each route and confirm no error responses');
1147
+ checkbox('Verify page and API routes: `codeyam editor verify-routes \'{"paths":["/"],"apiRoutes":["/api/your-route"]}\'`');
1148
+ console.log(chalk.dim(' Include ALL page paths you built and ALL API routes they depend on.'));
1143
1149
  checkbox('Check for broken images: `codeyam editor verify-images \'{"paths":["/"], "imageUrls":["url1","url2"]}\'`');
1144
1150
  console.log(chalk.dim(' Pass ALL page paths and ALL image URLs you used in seed data / API responses.'));
1145
1151
  console.log(chalk.dim(' Client-rendered pages need imageUrls — the HTML shell has no images to scan.'));
@@ -1182,7 +1188,7 @@ function printStep5(root, feature) {
1182
1188
  console.log();
1183
1189
  console.log(chalk.bold('Before presenting — verify everything works:'));
1184
1190
  checkbox(`Refresh the preview: \`codeyam editor preview '{"dimension":"${dim}"}'\` — check the \`preview\` field for \`healthy: false\``);
1185
- checkbox('Verify API routes return valid data (curl each route)');
1191
+ checkbox('Verify routes: `codeyam editor verify-routes \'{"paths":["/"],"apiRoutes":["/api/your-route"]}\'`');
1186
1192
  console.log();
1187
1193
  console.log(chalk.bold.red(' Verify EVERY image loads (this is the #1 source of broken prototypes):'));
1188
1194
  checkbox('Run `codeyam editor verify-images \'{"paths":["/"], "imageUrls":["url1","url2"]}\'`');
@@ -1978,7 +1984,7 @@ function printMigrateStep8(root) {
1978
1984
  printComponentCaptureInstructions();
1979
1985
  console.log();
1980
1986
  console.log(chalk.bold('Verify:'));
1981
- checkbox('Run `codeyam editor analyze-imports` to populate import graph');
1987
+ checkbox('Run `codeyam editor analyze-imports` to populate import graph (or `codeyam editor analyze-imports path/to/file.tsx ...` for specific files)');
1982
1988
  checkbox('Run library function tests: `npx jest --testPathPattern="<relevant>" --maxWorkers=2`');
1983
1989
  checkbox('Run `codeyam editor audit` to check completeness');
1984
1990
  checkbox('Check for client errors: `codeyam editor client-errors`');
@@ -2356,10 +2362,14 @@ async function handleAnalyzeImports(options = {}) {
2356
2362
  glossaryEntries = sanitizeGlossaryEntries(parsed);
2357
2363
  }
2358
2364
  catch {
2365
+ if (options.silent)
2366
+ return;
2359
2367
  console.error(chalk.red('Error: Could not parse .codeyam/glossary.json.'));
2360
2368
  process.exit(1);
2361
2369
  }
2362
2370
  if (glossaryEntries.length === 0) {
2371
+ if (options.silent)
2372
+ return;
2363
2373
  console.error(chalk.red('Error: glossary.json is empty.'));
2364
2374
  process.exit(1);
2365
2375
  }
@@ -2428,6 +2438,15 @@ async function handleAnalyzeImports(options = {}) {
2428
2438
  catch {
2429
2439
  // Non-fatal — fall back to analyzing all files
2430
2440
  }
2441
+ // If specific file paths were requested, scope analysis to only those files.
2442
+ // The full filePaths set is still used for the import graph below.
2443
+ if (options.filePaths && options.filePaths.length > 0) {
2444
+ const requested = new Set(options.filePaths);
2445
+ targetFilePaths = targetFilePaths.filter((fp) => requested.has(fp));
2446
+ if (targetFilePaths.length === 0 && !options.silent) {
2447
+ console.log(chalk.dim('Requested file(s) already analyzed or not in glossary — skipping analysis.'));
2448
+ }
2449
+ }
2431
2450
  // Run data-structure-only analysis for entities that need it.
2432
2451
  // Don't pass entityNames — entities may not exist yet (fresh clone).
2433
2452
  // The analyzer will discover and create them from file paths.
@@ -2444,6 +2463,10 @@ async function handleAnalyzeImports(options = {}) {
2444
2463
  catch (err) {
2445
2464
  progress.fail('Analysis failed');
2446
2465
  const msg = err instanceof Error ? err.message : String(err);
2466
+ if (options.silent) {
2467
+ // Internal caller — don't kill the process, let the caller handle it
2468
+ return;
2469
+ }
2447
2470
  console.error(chalk.red(`Error: ${msg}`));
2448
2471
  process.exit(1);
2449
2472
  }
@@ -2499,18 +2522,10 @@ async function handleAnalyzeImports(options = {}) {
2499
2522
  }
2500
2523
  }
2501
2524
  }
2502
- else if (targetFilePaths.length > 0) {
2503
- // Couldn't parse specific entity names mark all target files
2504
- // that we attempted to analyze as potentially failed
2505
- for (const fp of targetFilePaths) {
2506
- const entry = glossary.find((e) => e.filePath === fp);
2507
- updatedFailures[fp] = {
2508
- entityName: entry?.name || path.basename(fp, path.extname(fp)),
2509
- error: `Automated analysis failed — see .codeyam/analysis-errors.txt`,
2510
- failedAt: now,
2511
- };
2512
- }
2513
- }
2525
+ // When we can't parse specific entity names from the error, DON'T mark
2526
+ // all target files as failed. The error may be non-fatal (e.g., a cache
2527
+ // miss logged as "CodeYam Error") and blanket-marking every file as
2528
+ // permanently failed blocks future audits from resolving them.
2514
2529
  writeAnalysisFailures(root, updatedFailures);
2515
2530
  }
2516
2531
  catch {
@@ -2709,6 +2724,24 @@ async function handleDelete(scenarioId) {
2709
2724
  * Creates isolation route directories and the layout guard file.
2710
2725
  * This avoids brace-expansion permission prompts in the embedded terminal.
2711
2726
  */
2727
+ function handleDesignSystem(designSystemId) {
2728
+ const root = process.cwd();
2729
+ const ds = DESIGN_SYSTEMS.find((d) => d.id === designSystemId);
2730
+ if (!ds) {
2731
+ console.error(chalk.red(`Error: Unknown design system "${designSystemId}". Valid options: ${DESIGN_SYSTEMS.map((d) => d.id).join(', ')}`));
2732
+ process.exit(1);
2733
+ }
2734
+ const srcPath = path.join(__dirname, '..', '..', 'templates', 'design-systems', ds.fileName);
2735
+ if (!fs.existsSync(srcPath)) {
2736
+ console.error(chalk.red(`Error: Design system file not found: ${srcPath}`));
2737
+ process.exit(1);
2738
+ }
2739
+ const destDir = path.join(root, '.codeyam');
2740
+ fs.mkdirSync(destDir, { recursive: true });
2741
+ const destPath = path.join(destDir, 'design-system.md');
2742
+ fs.copyFileSync(srcPath, destPath);
2743
+ console.log(chalk.green(`Installed "${ds.name}" design system → .codeyam/design-system.md`));
2744
+ }
2712
2745
  function handleIsolate(componentNames) {
2713
2746
  const root = process.cwd();
2714
2747
  if (componentNames.length === 0) {
@@ -2848,6 +2881,34 @@ function formatApiSubcommandResult(subcommand, data) {
2848
2881
  }
2849
2882
  return parts.join(' ');
2850
2883
  }
2884
+ case 'verify-routes': {
2885
+ const lines = [];
2886
+ lines.push(chalk.bold.yellow('━━━ Route Verification ━━━'));
2887
+ for (const [route, info] of Object.entries(data.routes || {})) {
2888
+ const r = info;
2889
+ if (r.ok) {
2890
+ lines.push(chalk.green(` ✓ ${route} — HTTP ${r.status}`));
2891
+ }
2892
+ else {
2893
+ lines.push(chalk.red(` ✗ ${route} — ${r.error || `HTTP ${r.status}`}`));
2894
+ }
2895
+ }
2896
+ for (const [route, info] of Object.entries(data.apiRoutes || {})) {
2897
+ const r = info;
2898
+ if (r.ok && r.isJSON) {
2899
+ lines.push(chalk.green(` ✓ ${route} — HTTP ${r.status}, valid JSON`));
2900
+ }
2901
+ else if (r.ok) {
2902
+ lines.push(chalk.yellow(` ⚠ ${route} — HTTP ${r.status}, not valid JSON`));
2903
+ }
2904
+ else {
2905
+ lines.push(chalk.red(` ✗ ${route} — ${r.error || `HTTP ${r.status}`}`));
2906
+ }
2907
+ }
2908
+ lines.push('');
2909
+ lines.push(data.ok ? chalk.green(data.summary) : chalk.red(data.summary));
2910
+ return lines.join('\n');
2911
+ }
2851
2912
  default:
2852
2913
  return null; // journal-list, show/hide-results: keep full JSON
2853
2914
  }
@@ -3454,7 +3515,15 @@ function printAuditGateFailures(data) {
3454
3515
  for (const m of missingGlossary) {
3455
3516
  issues.push(` → ${m.name} (${m.filePath})`);
3456
3517
  }
3457
- issues.push(` Fix: Run \`codeyam editor analyze-imports\` to add these files to the glossary`);
3518
+ const missingPaths = missingGlossary
3519
+ .map((m) => m.filePath)
3520
+ .filter(Boolean);
3521
+ if (missingPaths.length > 0) {
3522
+ issues.push(` Fix: Run \`codeyam editor analyze-imports ${missingPaths.join(' ')}\``);
3523
+ }
3524
+ else {
3525
+ issues.push(` Fix: Run \`codeyam editor analyze-imports\` to add these files to the glossary`);
3526
+ }
3458
3527
  }
3459
3528
  if (s.incompleteEntities > 0) {
3460
3529
  // Check for persistent analysis failures
@@ -3498,8 +3567,16 @@ function printAuditGateFailures(data) {
3498
3567
  }
3499
3568
  }
3500
3569
  if (s.unassociatedScenarios > 0) {
3501
- issues.push(`${s.unassociatedScenarios} component(s) have scenarios with no entity link — run \`codeyam editor analyze-imports\` then re-run audit`);
3502
3570
  const unassociated = data.unassociatedScenarios || [];
3571
+ const unassocPaths = unassociated
3572
+ .map((u) => u.filePath)
3573
+ .filter(Boolean);
3574
+ if (unassocPaths.length > 0) {
3575
+ issues.push(`${s.unassociatedScenarios} component(s) have scenarios with no entity link — run \`codeyam editor analyze-imports ${unassocPaths.join(' ')}\` then re-run audit`);
3576
+ }
3577
+ else {
3578
+ issues.push(`${s.unassociatedScenarios} component(s) have scenarios with no entity link — run \`codeyam editor analyze-imports\` then re-run audit`);
3579
+ }
3503
3580
  for (const u of unassociated) {
3504
3581
  issues.push(` → ${u.name} (${u.filePath}) — ${u.scenarioCount} scenario${u.scenarioCount !== 1 ? 's' : ''}`);
3505
3582
  }
@@ -3554,16 +3631,16 @@ function printAuditGateFailures(data) {
3554
3631
  * which glossary components have registered scenarios and which functions
3555
3632
  * have test files. Exits with code 1 if anything is missing.
3556
3633
  */
3557
- async function handleAudit() {
3634
+ async function handleAudit(options) {
3558
3635
  let data = await fetchAuditResult();
3559
3636
  if (!data) {
3560
3637
  console.error(chalk.red('Error: Could not reach the CodeYam server. Is it running?'));
3561
3638
  process.exit(1);
3562
3639
  }
3563
- // Lightweight auto-fix: backfill entity_sha on scenarios that were
3564
- // registered before entity records existed. This is fast (DB-only).
3565
- // Import analysis is NOT triggered here it scans all files and takes
3566
- // minutes on large projects. Users should run it separately if needed.
3640
+ // Two-phase auto-fix for entity associations:
3641
+ // Phase 1: DB-only backfill fast, matches existing entities to scenarios.
3642
+ // Phase 2: If backfill fails, targeted analyze-imports for only the
3643
+ // specific unresolved files (1-3 files, not the full glossary scan).
3567
3644
  const incompleteBeforeFix = data.incompleteEntities || [];
3568
3645
  const unassociatedBeforeFix = data.unassociatedScenarios || [];
3569
3646
  let autoRemediationFailed = false;
@@ -3595,14 +3672,58 @@ async function handleAudit() {
3595
3672
  console.error(chalk.red('Error: Could not reach the CodeYam server after backfill.'));
3596
3673
  process.exit(1);
3597
3674
  }
3598
- // If issues persist after backfill, flag it so we show clear guidance
3675
+ // If issues persist after DB-only backfill, run targeted analyze-imports
3676
+ // for ONLY the specific files that need entities. This is fast (1-3 files)
3677
+ // unlike full analyze-imports which scans all glossary entries.
3678
+ const incompleteAfterBackfill = data.incompleteEntities || [];
3679
+ const unassociatedAfterBackfill = data.unassociatedScenarios || [];
3680
+ if (incompleteAfterBackfill.length > 0 ||
3681
+ unassociatedAfterBackfill.length > 0) {
3682
+ const { determineTargetedAnalysisPaths } = await import('../utils/editorAudit.js');
3683
+ const targetPaths = determineTargetedAnalysisPaths({
3684
+ unassociatedScenarios: unassociatedAfterBackfill,
3685
+ incompleteEntities: incompleteAfterBackfill,
3686
+ });
3687
+ if (targetPaths.length > 0) {
3688
+ console.log(chalk.dim(`Running targeted analysis for ${targetPaths.length} file${targetPaths.length !== 1 ? 's' : ''}...`));
3689
+ try {
3690
+ await handleAnalyzeImports({
3691
+ silent: true,
3692
+ filePaths: targetPaths,
3693
+ });
3694
+ // Retry backfill after analysis created entities
3695
+ const entities = await loadEntities({});
3696
+ if (entities && entities.length > 0) {
3697
+ const { getDatabase: getDb } = await import('../../../packages/database/index.js');
3698
+ const freshDb = getDb();
3699
+ await backfillEntityShaOnScenarios(freshDb, entities.map((e) => ({
3700
+ sha: e.sha,
3701
+ name: e.name,
3702
+ filePath: e.filePath || '',
3703
+ isDefaultExport: e.metadata?.notExported === false &&
3704
+ e.metadata?.namedExport === false,
3705
+ })));
3706
+ }
3707
+ // Re-fetch audit results after targeted analysis
3708
+ data = await fetchAuditResult({ skipTests: true });
3709
+ if (!data) {
3710
+ console.error(chalk.red('Error: Could not reach the CodeYam server after analysis.'));
3711
+ process.exit(1);
3712
+ }
3713
+ }
3714
+ catch {
3715
+ // Targeted analysis failed — fall through to show remaining issues
3716
+ }
3717
+ }
3718
+ }
3719
+ // Check if issues persist after all remediation attempts
3599
3720
  const incompleteAfterFix = data.incompleteEntities || [];
3600
3721
  const unassociatedAfterFix = data.unassociatedScenarios || [];
3601
3722
  if (incompleteAfterFix.length > 0 || unassociatedAfterFix.length > 0) {
3602
3723
  autoRemediationFailed = true;
3603
3724
  }
3604
3725
  }
3605
- const { components, functions, summary } = data;
3726
+ let { components, functions, summary } = data;
3606
3727
  console.log();
3607
3728
  console.log(chalk.bold.cyan('━━━ Editor Audit ━━━'));
3608
3729
  console.log();
@@ -3701,7 +3822,15 @@ async function handleAudit() {
3701
3822
  for (const m of missingFromGlossary) {
3702
3823
  console.log(` ${chalk.red('✗')} ${m.name} ${chalk.dim(`(${m.filePath})`)} — ${m.scenarioCount} scenario${m.scenarioCount !== 1 ? 's' : ''} but not in glossary`);
3703
3824
  }
3704
- console.log(chalk.yellow(' Add these to .codeyam/glossary.json and run `codeyam editor analyze-imports`'));
3825
+ const mgPaths = missingFromGlossary
3826
+ .map((m) => m.filePath)
3827
+ .filter(Boolean);
3828
+ if (mgPaths.length > 0) {
3829
+ console.log(chalk.yellow(` Add these to .codeyam/glossary.json and run \`codeyam editor analyze-imports ${mgPaths.join(' ')}\``));
3830
+ }
3831
+ else {
3832
+ console.log(chalk.yellow(' Add these to .codeyam/glossary.json and run `codeyam editor analyze-imports`'));
3833
+ }
3705
3834
  console.log();
3706
3835
  }
3707
3836
  // Incomplete entities (scenarios without analyses) — report with guidance.
@@ -3756,12 +3885,18 @@ async function handleAudit() {
3756
3885
  console.log(chalk.dim(` … and ${u.scenarioNames.length - 3} more`));
3757
3886
  }
3758
3887
  }
3888
+ const uaPaths = unassociatedScenarios
3889
+ .map((u) => u.filePath)
3890
+ .filter(Boolean);
3891
+ const uaCmd = uaPaths.length > 0
3892
+ ? `codeyam editor analyze-imports ${uaPaths.join(' ')}`
3893
+ : 'codeyam editor analyze-imports';
3759
3894
  if (autoRemediationFailed) {
3760
3895
  console.log(chalk.yellow(' analyze-imports ran automatically but could not resolve these.'));
3761
- console.log(chalk.yellow(' Run `codeyam editor analyze-imports` to see the full error output.'));
3896
+ console.log(chalk.yellow(` Run \`${uaCmd}\` to see the full error output.`));
3762
3897
  }
3763
3898
  else {
3764
- console.log(chalk.yellow(' Run `codeyam editor analyze-imports` to create entity records, then re-run audit to backfill.'));
3899
+ console.log(chalk.yellow(` Run \`${uaCmd}\` to create entity records, then re-run audit to backfill.`));
3765
3900
  }
3766
3901
  const unassocErrorReportPath = path.join(getProjectRoot(), '.codeyam', 'analysis-errors.txt');
3767
3902
  if (fs.existsSync(unassocErrorReportPath)) {
@@ -3794,7 +3929,26 @@ async function handleAudit() {
3794
3929
  : `${s.status.status}`;
3795
3930
  console.log(` ${chalk.red('✗')} ${s.scenarioName} ${chalk.dim(`(${s.entityName} — ${reason})`)}`);
3796
3931
  }
3797
- console.log(chalk.yellow(' Run: codeyam editor recapture-stale'));
3932
+ if (options?.fix) {
3933
+ // --fix: auto-recapture stale scenarios instead of just reporting them
3934
+ const { shouldAutoRecapture } = await import('../utils/editorAudit.js');
3935
+ if (shouldAutoRecapture({ fix: true, scenariosNeedingRecapture })) {
3936
+ console.log(chalk.cyan(' --fix: auto-recapturing stale scenarios...'));
3937
+ console.log();
3938
+ await handleRecaptureStale();
3939
+ // Re-fetch audit results so the summary and exit code reflect
3940
+ // the post-fix state, not the pre-fix state.
3941
+ const refreshed = await fetchAuditResult({ skipTests: true });
3942
+ if (refreshed) {
3943
+ data = refreshed;
3944
+ ({ components, functions, summary } = data);
3945
+ }
3946
+ }
3947
+ }
3948
+ else {
3949
+ console.log(chalk.yellow(' Run: codeyam editor recapture-stale'));
3950
+ console.log(chalk.dim(' Or: codeyam editor audit --fix (to auto-recapture)'));
3951
+ }
3798
3952
  console.log();
3799
3953
  }
3800
3954
  // Duplicate glossary names (warning, not a failure)
@@ -4764,8 +4918,8 @@ const editorCommand = {
4764
4918
  describe: 'Editor mode guided workflow',
4765
4919
  builder: (yargs) => {
4766
4920
  const stepDescription = IS_INTERNAL_BUILD
4767
- ? 'Step number (1-18) or subcommand (template, register, isolate, analyze-imports, manual-entity, dependents, audit, scenarios, scenario-coverage, recapture-stale, change, sync, debug, preview, show-results, hide-results, commit, journal, journal-list, journal-update, dev-server, client-errors, task-ontrack)'
4768
- : 'Step number (1-18) or subcommand (template, register, isolate, analyze-imports, manual-entity, dependents, audit, scenarios, scenario-coverage, recapture-stale, change, sync, preview, show-results, hide-results, commit, journal, journal-list, journal-update, dev-server, client-errors, task-ontrack)';
4921
+ ? 'Step number (1-18) or subcommand (template, register, isolate, analyze-imports, manual-entity, dependents, audit, scenarios, scenario-coverage, recapture-stale, change, sync, debug, design-system, preview, show-results, hide-results, commit, journal, journal-list, journal-update, dev-server, client-errors, task-ontrack)'
4922
+ : 'Step number (1-18) or subcommand (template, register, isolate, analyze-imports, manual-entity, dependents, audit, scenarios, scenario-coverage, recapture-stale, change, sync, design-system, preview, show-results, hide-results, commit, journal, journal-list, journal-update, dev-server, client-errors, task-ontrack)';
4769
4923
  let builder = yargs
4770
4924
  .positional('step', {
4771
4925
  type: 'string',
@@ -4796,6 +4950,11 @@ const editorCommand = {
4796
4950
  alias: 'p',
4797
4951
  describe: 'Port to run the web server on',
4798
4952
  default: 3111,
4953
+ })
4954
+ .option('fix', {
4955
+ type: 'boolean',
4956
+ describe: 'For audit: also recapture stale scenarios after displaying results',
4957
+ default: false,
4799
4958
  });
4800
4959
  if (IS_INTERNAL_BUILD) {
4801
4960
  builder = builder
@@ -4923,9 +5082,11 @@ const editorCommand = {
4923
5082
  fs.writeFileSync(trackingPath, JSON.stringify({ step: state.step, taskCreated: true }, null, 2), 'utf8');
4924
5083
  return;
4925
5084
  }
4926
- // Subcommand: codeyam editor analyze-imports
5085
+ // Subcommand: codeyam editor analyze-imports [file1.tsx file2.tsx ...]
4927
5086
  if (argv.step === 'analyze-imports') {
4928
- await handleAnalyzeImports();
5087
+ const { parseAnalyzeImportsArgs } = await import('./editorAnalyzeImportsArgs.js');
5088
+ const requestedPaths = parseAnalyzeImportsArgs(argv.json, argv._);
5089
+ await handleAnalyzeImports(requestedPaths.length > 0 ? { filePaths: requestedPaths } : {});
4929
5090
  return;
4930
5091
  }
4931
5092
  // Subcommand: codeyam editor manual-entity <JSON|@file>
@@ -4938,9 +5099,9 @@ const editorCommand = {
4938
5099
  await handleDependents(argv.json || '');
4939
5100
  return;
4940
5101
  }
4941
- // Subcommand: codeyam editor audit
5102
+ // Subcommand: codeyam editor audit [--fix]
4942
5103
  if (argv.step === 'audit') {
4943
- await handleAudit();
5104
+ await handleAudit({ fix: argv.fix || false });
4944
5105
  return;
4945
5106
  }
4946
5107
  // Subcommand: codeyam editor scenarios
@@ -4973,6 +5134,11 @@ const editorCommand = {
4973
5134
  await handleValidateSeed(argv.json || '');
4974
5135
  return;
4975
5136
  }
5137
+ // Subcommand: codeyam editor design-system <id>
5138
+ if (argv.step === 'design-system') {
5139
+ handleDesignSystem(argv.json || '');
5140
+ return;
5141
+ }
4976
5142
  // Subcommand: codeyam editor delete <scenarioId>
4977
5143
  if (argv.step === 'delete') {
4978
5144
  await handleDelete(argv.json || '');