workflow-agent-cli 2.4.2 → 2.6.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.
package/dist/cli/index.js CHANGED
@@ -1,11 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ analyzeProject,
4
+ detectPackageManager,
3
5
  generateAuditReport,
4
6
  hasUncommittedChanges,
7
+ isMonorepo,
5
8
  runAllChecks,
6
9
  runAllSetups,
7
10
  stageAllChanges
8
- } from "../chunk-WXXFUPYO.js";
11
+ } from "../chunk-6NWQLGHI.js";
9
12
  import {
10
13
  validateBranchName,
11
14
  validateCommitMessage,
@@ -15,7 +18,12 @@ import {
15
18
  hasConfig,
16
19
  loadConfig,
17
20
  validateScopeDefinitions
18
- } from "../chunk-RDVTKGQV.js";
21
+ } from "../chunk-DEAF7P4L.js";
22
+ import {
23
+ SCRIPT_CATEGORIES,
24
+ TOTAL_SCRIPTS,
25
+ WORKFLOW_SCRIPTS
26
+ } from "../chunk-LN5OAWEQ.js";
19
27
 
20
28
  // src/cli/index.ts
21
29
  import { Command } from "commander";
@@ -302,10 +310,10 @@ async function initCommand(options) {
302
310
  try {
303
311
  const presetModule = await import(`@workflow/scopes-${preset}`);
304
312
  scopes = presetModule.scopes || presetModule.default.scopes;
305
- const spinner6 = p.spinner();
306
- spinner6.start(`Loading ${presetModule.default?.name || preset} preset`);
313
+ const spinner7 = p.spinner();
314
+ spinner7.start(`Loading ${presetModule.default?.name || preset} preset`);
307
315
  await new Promise((resolve2) => setTimeout(resolve2, 500));
308
- spinner6.stop(`\u2713 Loaded ${scopes.length} scopes from preset`);
316
+ spinner7.stop(`\u2713 Loaded ${scopes.length} scopes from preset`);
309
317
  } catch (error) {
310
318
  console.log(
311
319
  chalk.yellow(
@@ -352,8 +360,8 @@ async function initCommand(options) {
352
360
  process.exit(0);
353
361
  }
354
362
  if (shouldGenerateGuidelines) {
355
- const spinner6 = p.spinner();
356
- spinner6.start("Generating guidelines...");
363
+ const spinner7 = p.spinner();
364
+ spinner7.start("Generating guidelines...");
357
365
  try {
358
366
  const templatesDir = join(__dirname, "../../templates");
359
367
  await validateTemplateDirectory(templatesDir);
@@ -365,9 +373,9 @@ async function initCommand(options) {
365
373
  guidelinesDir,
366
374
  context
367
375
  );
368
- spinner6.stop(`\u2713 Generated ${renderedFiles.length} guideline documents`);
376
+ spinner7.stop(`\u2713 Generated ${renderedFiles.length} guideline documents`);
369
377
  } catch (error) {
370
- spinner6.stop("\u26A0\uFE0F Could not generate guidelines");
378
+ spinner7.stop("\u26A0\uFE0F Could not generate guidelines");
371
379
  console.log(
372
380
  chalk.yellow(
373
381
  `
@@ -590,12 +598,6 @@ import * as p3 from "@clack/prompts";
590
598
  import chalk6 from "chalk";
591
599
  import { readFileSync, writeFileSync, existsSync as existsSync2 } from "fs";
592
600
  import { join as join2 } from "path";
593
- var WORKFLOW_SCRIPTS = {
594
- "workflow:init": "workflow-agent init",
595
- "workflow:validate": "workflow-agent validate",
596
- "workflow:suggest": "workflow-agent suggest",
597
- "workflow:doctor": "workflow-agent doctor"
598
- };
599
601
  async function setupCommand() {
600
602
  p3.intro(chalk6.bgBlue(" workflow-agent setup "));
601
603
  const cwd = process.cwd();
@@ -609,48 +611,57 @@ async function setupCommand() {
609
611
  if (!packageJson.scripts) {
610
612
  packageJson.scripts = {};
611
613
  }
612
- const existingScripts = [];
613
- const scriptsToAdd = {};
614
+ const addedScripts = [];
615
+ const updatedScripts = [];
614
616
  for (const [scriptName, scriptCommand] of Object.entries(WORKFLOW_SCRIPTS)) {
615
- if (packageJson.scripts[scriptName]) {
616
- existingScripts.push(scriptName);
617
- } else {
618
- scriptsToAdd[scriptName] = scriptCommand;
617
+ if (!packageJson.scripts[scriptName]) {
618
+ packageJson.scripts[scriptName] = scriptCommand;
619
+ addedScripts.push(scriptName);
620
+ } else if (packageJson.scripts[scriptName] !== scriptCommand) {
621
+ packageJson.scripts[scriptName] = scriptCommand;
622
+ updatedScripts.push(scriptName);
619
623
  }
620
624
  }
621
- if (Object.keys(scriptsToAdd).length === 0) {
622
- p3.outro(chalk6.green("\u2713 All workflow scripts are already configured!"));
625
+ const totalChanges = addedScripts.length + updatedScripts.length;
626
+ if (totalChanges === 0) {
627
+ p3.outro(
628
+ chalk6.green(
629
+ `\u2713 All ${TOTAL_SCRIPTS} workflow scripts are already configured!`
630
+ )
631
+ );
623
632
  return;
624
633
  }
625
- console.log(chalk6.dim("\nScripts to add:"));
626
- for (const [scriptName, scriptCommand] of Object.entries(scriptsToAdd)) {
627
- console.log(chalk6.dim(` ${scriptName}: ${scriptCommand}`));
628
- }
629
- if (existingScripts.length > 0) {
630
- console.log(chalk6.yellow("\nExisting scripts (will be skipped):"));
631
- existingScripts.forEach((name) => {
632
- console.log(chalk6.yellow(` ${name}`));
633
- });
634
- }
635
- const shouldAdd = await p3.confirm({
636
- message: "Add these scripts to package.json?",
637
- initialValue: true
638
- });
639
- if (p3.isCancel(shouldAdd) || !shouldAdd) {
640
- p3.cancel("Setup cancelled");
641
- process.exit(0);
642
- }
643
- for (const [scriptName, scriptCommand] of Object.entries(scriptsToAdd)) {
644
- packageJson.scripts[scriptName] = scriptCommand;
645
- }
646
634
  writeFileSync(
647
635
  packageJsonPath,
648
636
  JSON.stringify(packageJson, null, 2) + "\n",
649
637
  "utf-8"
650
638
  );
639
+ const summaryParts = [];
640
+ if (addedScripts.length > 0) {
641
+ summaryParts.push(`${addedScripts.length} new`);
642
+ }
643
+ if (updatedScripts.length > 0) {
644
+ summaryParts.push(`${updatedScripts.length} updated`);
645
+ }
646
+ console.log(
647
+ chalk6.green(
648
+ `
649
+ \u2713 Workflow scripts configured (${summaryParts.join(", ")}):
650
+ `
651
+ )
652
+ );
653
+ for (const [category, scripts] of Object.entries(SCRIPT_CATEGORIES)) {
654
+ console.log(chalk6.cyan(` ${category}:`));
655
+ for (const script of scripts) {
656
+ const isNew = addedScripts.includes(script);
657
+ const isUpdated = updatedScripts.includes(script);
658
+ const marker = isNew ? chalk6.green(" (new)") : isUpdated ? chalk6.yellow(" (updated)") : "";
659
+ console.log(chalk6.dim(` - ${script}`) + marker);
660
+ }
661
+ }
651
662
  p3.outro(
652
663
  chalk6.green(
653
- `\u2713 Added ${Object.keys(scriptsToAdd).length} workflow scripts to package.json!`
664
+ `\u2713 ${TOTAL_SCRIPTS} workflow scripts available in package.json!`
654
665
  )
655
666
  );
656
667
  console.log(chalk6.dim("\nRun them with:"));
@@ -668,8 +679,8 @@ async function scopeCreateCommand(options) {
668
679
  console.log(chalk7.bold.cyan("\n\u{1F3A8} Create Custom Scope Package\n"));
669
680
  const cwd = process.cwd();
670
681
  const isNonInteractive = !!(options.name && options.scopes && options.presetName);
671
- const isMonorepo = existsSync3(join3(cwd, "pnpm-workspace.yaml"));
672
- if (isMonorepo) {
682
+ const isMonorepo2 = existsSync3(join3(cwd, "pnpm-workspace.yaml"));
683
+ if (isMonorepo2) {
673
684
  console.log(chalk7.dim("\u2713 Detected monorepo workspace\n"));
674
685
  }
675
686
  const packageNameInput = isNonInteractive ? options.name : await p4.text({
@@ -813,7 +824,7 @@ async function scopeCreateCommand(options) {
813
824
  let outputDir;
814
825
  if (options.outputDir) {
815
826
  outputDir = options.outputDir;
816
- } else if (isMonorepo) {
827
+ } else if (isMonorepo2) {
817
828
  outputDir = join3(cwd, "packages", `scopes-${packageName}`);
818
829
  } else {
819
830
  const customDir = await p4.text({
@@ -837,8 +848,8 @@ async function scopeCreateCommand(options) {
837
848
  process.exit(0);
838
849
  }
839
850
  }
840
- const spinner6 = p4.spinner();
841
- spinner6.start("Creating package structure...");
851
+ const spinner7 = p4.spinner();
852
+ spinner7.start("Creating package structure...");
842
853
  try {
843
854
  await mkdir2(join3(outputDir, "src"), { recursive: true });
844
855
  const packageJson = {
@@ -969,8 +980,8 @@ describe('${presetName} Scope Preset', () => {
969
980
  "utf-8"
970
981
  );
971
982
  }
972
- spinner6.stop("\u2713 Package structure created");
973
- if (isMonorepo) {
983
+ spinner7.stop("\u2713 Package structure created");
984
+ if (isMonorepo2) {
974
985
  const workspaceFile = join3(cwd, "pnpm-workspace.yaml");
975
986
  const workspaceContent = await readFile(workspaceFile, "utf-8");
976
987
  const packagePath = `packages/scopes-${packageName}`;
@@ -1021,7 +1032,7 @@ describe('${presetName} Scope Preset', () => {
1021
1032
  );
1022
1033
  }
1023
1034
  } catch (error) {
1024
- spinner6.stop("\u2717 Failed to create package");
1035
+ spinner7.stop("\u2717 Failed to create package");
1025
1036
  console.error(chalk7.red("\nError:"), error);
1026
1037
  process.exit(1);
1027
1038
  }
@@ -1076,8 +1087,8 @@ async function scopeMigrateCommand(options) {
1076
1087
  p5.cancel("Migration cancelled");
1077
1088
  process.exit(0);
1078
1089
  }
1079
- const isMonorepo = existsSync4(join4(cwd, "pnpm-workspace.yaml"));
1080
- if (isMonorepo) {
1090
+ const isMonorepo2 = existsSync4(join4(cwd, "pnpm-workspace.yaml"));
1091
+ if (isMonorepo2) {
1081
1092
  console.log(chalk8.dim("\n\u2713 Detected monorepo workspace\n"));
1082
1093
  }
1083
1094
  const packageNameInput = options.name || await p5.text({
@@ -1125,7 +1136,7 @@ async function scopeMigrateCommand(options) {
1125
1136
  let outputDir;
1126
1137
  if (options.outputDir) {
1127
1138
  outputDir = options.outputDir;
1128
- } else if (isMonorepo) {
1139
+ } else if (isMonorepo2) {
1129
1140
  outputDir = join4(cwd, "packages", `scopes-${packageName}`);
1130
1141
  } else {
1131
1142
  const customDir = await p5.text({
@@ -1149,8 +1160,8 @@ async function scopeMigrateCommand(options) {
1149
1160
  process.exit(0);
1150
1161
  }
1151
1162
  }
1152
- const spinner6 = p5.spinner();
1153
- spinner6.start("Migrating scopes to package...");
1163
+ const spinner7 = p5.spinner();
1164
+ spinner7.start("Migrating scopes to package...");
1154
1165
  try {
1155
1166
  await mkdir3(join4(outputDir, "src"), { recursive: true });
1156
1167
  const packageJson = {
@@ -1278,8 +1289,8 @@ describe('${presetName} Scope Preset (Migrated)', () => {
1278
1289
  });
1279
1290
  `;
1280
1291
  await writeFile3(join4(outputDir, "src", "index.test.ts"), testFile, "utf-8");
1281
- spinner6.stop("\u2713 Package created from migrated scopes");
1282
- if (isMonorepo) {
1292
+ spinner7.stop("\u2713 Package created from migrated scopes");
1293
+ if (isMonorepo2) {
1283
1294
  const workspaceFile = join4(cwd, "pnpm-workspace.yaml");
1284
1295
  const workspaceContent = await readFile2(workspaceFile, "utf-8");
1285
1296
  const packagePath = `packages/scopes-${packageName}`;
@@ -1350,7 +1361,7 @@ describe('${presetName} Scope Preset (Migrated)', () => {
1350
1361
  )
1351
1362
  );
1352
1363
  } catch (error) {
1353
- spinner6.stop("\u2717 Migration failed");
1364
+ spinner7.stop("\u2717 Migration failed");
1354
1365
  console.error(chalk8.red("\nError:"), error);
1355
1366
  process.exit(1);
1356
1367
  }
@@ -1379,7 +1390,9 @@ async function verifyCommand(options) {
1379
1390
  console.log(chalk9.dim(` Max retries: ${maxRetries}`));
1380
1391
  console.log(chalk9.dim(` Commit on success: ${shouldCommit ? "yes" : "no"}`));
1381
1392
  console.log(chalk9.dim(` Dry-run: ${dryRun ? "yes" : "no"}`));
1382
- console.log(chalk9.dim(` Learn from fixes: ${learnFromFixes ? "yes" : "no"}`));
1393
+ console.log(
1394
+ chalk9.dim(` Learn from fixes: ${learnFromFixes ? "yes" : "no"}`)
1395
+ );
1383
1396
  const startTime = Date.now();
1384
1397
  const result = await runAllChecks(cwd, {
1385
1398
  maxRetries,
@@ -1489,7 +1502,9 @@ async function recordSuccessfulFixes(cwd, result) {
1489
1502
  } catch {
1490
1503
  }
1491
1504
  if (result.appliedFixes && result.appliedFixes.length > 0) {
1492
- console.log(chalk9.cyan("\n\u{1F4DA} Recording successful fixes for learning...\n"));
1505
+ console.log(
1506
+ chalk9.cyan("\n\u{1F4DA} Recording successful fixes for learning...\n")
1507
+ );
1493
1508
  for (const fix of result.appliedFixes) {
1494
1509
  const patternName = `Auto-fix: ${fix.displayName}`;
1495
1510
  const patternId = crypto.randomUUID();
@@ -1572,8 +1587,10 @@ async function recordSuccessfulFixes(cwd, result) {
1572
1587
  }
1573
1588
  } catch (error) {
1574
1589
  console.log(
1575
- chalk9.dim(`
1576
- Note: Could not record learning patterns: ${error.message}`)
1590
+ chalk9.dim(
1591
+ `
1592
+ Note: Could not record learning patterns: ${error.message}`
1593
+ )
1577
1594
  );
1578
1595
  }
1579
1596
  }
@@ -1584,14 +1601,14 @@ import chalk10 from "chalk";
1584
1601
  async function autoSetupCommand(options) {
1585
1602
  console.log(chalk10.bold.cyan("\n\u{1F527} Workflow Agent Auto-Setup\n"));
1586
1603
  const cwd = process.cwd();
1587
- const spinner6 = p6.spinner();
1588
- spinner6.start("Analyzing project...");
1604
+ const spinner7 = p6.spinner();
1605
+ spinner7.start("Analyzing project...");
1589
1606
  let report;
1590
1607
  try {
1591
1608
  report = await generateAuditReport(cwd);
1592
- spinner6.stop("\u2713 Project analysis complete");
1609
+ spinner7.stop("\u2713 Project analysis complete");
1593
1610
  } catch (error) {
1594
- spinner6.stop("\u2717 Failed to analyze project");
1611
+ spinner7.stop("\u2717 Failed to analyze project");
1595
1612
  console.error(
1596
1613
  chalk10.red(
1597
1614
  `Error: ${error instanceof Error ? error.message : String(error)}`
@@ -1724,204 +1741,2852 @@ function formatAuditReportColored(report) {
1724
1741
  return lines.join("\n");
1725
1742
  }
1726
1743
 
1727
- // src/cli/commands/learn.ts
1728
- import chalk11 from "chalk";
1744
+ // src/cli/commands/advisory.ts
1729
1745
  import * as p7 from "@clack/prompts";
1730
- import {
1731
- PatternStore as PatternStore2,
1732
- ContributorManager as ContributorManager2,
1733
- PatternAnonymizer,
1734
- TelemetryCollector as TelemetryCollector2
1735
- } from "@hawkinside_out/workflow-improvement-tracker";
1736
- function getWorkspacePath() {
1737
- return process.cwd();
1738
- }
1739
- function formatDate(isoString) {
1740
- return new Date(isoString).toLocaleDateString("en-US", {
1741
- year: "numeric",
1742
- month: "short",
1743
- day: "numeric"
1744
- });
1745
- }
1746
- function formatTags(tags) {
1747
- return tags.map((t) => `${t.category}:${t.name}`).join(", ");
1748
- }
1749
- async function learnRecordCommand(options) {
1750
- const cwd = getWorkspacePath();
1751
- const store = new PatternStore2(cwd);
1752
- console.log(chalk11.cyan("\n\u{1F4DA} Record a Learning Pattern\n"));
1753
- let patternType = options.type;
1754
- if (!patternType) {
1755
- const typeChoice = await p7.select({
1756
- message: "What type of pattern are you recording?",
1757
- options: [
1758
- {
1759
- value: "fix",
1760
- label: "\u{1F527} Fix Pattern - A specific solution to a problem"
1761
- },
1762
- {
1763
- value: "blueprint",
1764
- label: "\u{1F4D0} Blueprint - A project structure template"
1765
- }
1766
- ]
1767
- });
1768
- if (p7.isCancel(typeChoice)) {
1769
- p7.cancel("Recording cancelled");
1770
- process.exit(0);
1746
+ import chalk11 from "chalk";
1747
+ import { existsSync as existsSync6 } from "fs";
1748
+ import { readFile as readFile4, writeFile as writeFile4, mkdir as mkdir4 } from "fs/promises";
1749
+ import { join as join6 } from "path";
1750
+
1751
+ // src/utils/advisory-analyzer.ts
1752
+ import { existsSync as existsSync5 } from "fs";
1753
+ import { readFile as readFile3 } from "fs/promises";
1754
+ import { join as join5 } from "path";
1755
+ import fg from "fast-glob";
1756
+ var AdvisoryAnalyzer = class {
1757
+ options;
1758
+ constructor(options) {
1759
+ this.options = options;
1760
+ }
1761
+ /**
1762
+ * Run analysis at specified depth level
1763
+ */
1764
+ async analyze() {
1765
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
1766
+ const { depth } = this.options;
1767
+ const project = await this.analyzeProject();
1768
+ if (depth === "executive") {
1769
+ return this.analyzeExecutive(timestamp, project);
1771
1770
  }
1772
- patternType = typeChoice;
1771
+ const technology = await this.analyzeTechnology();
1772
+ const packages = await this.analyzePackages();
1773
+ const risks = await this.assessRisks(project, technology, packages);
1774
+ const opportunities = await this.assessOpportunities(
1775
+ project,
1776
+ technology,
1777
+ packages
1778
+ );
1779
+ if (depth === "quick") {
1780
+ return {
1781
+ depth,
1782
+ timestamp,
1783
+ project,
1784
+ technology,
1785
+ packages,
1786
+ risks,
1787
+ opportunities
1788
+ };
1789
+ }
1790
+ const architecture = await this.analyzeArchitecture();
1791
+ if (depth === "standard") {
1792
+ const health2 = this.options.includeHealth ? await this.analyzeHealth() : void 0;
1793
+ return {
1794
+ depth,
1795
+ timestamp,
1796
+ project,
1797
+ technology,
1798
+ packages,
1799
+ architecture,
1800
+ risks,
1801
+ opportunities,
1802
+ health: health2
1803
+ };
1804
+ }
1805
+ const codePatterns = await this.analyzeCodePatterns();
1806
+ const health = this.options.includeHealth ? await this.analyzeHealth() : void 0;
1807
+ return {
1808
+ depth,
1809
+ timestamp,
1810
+ project,
1811
+ technology,
1812
+ packages,
1813
+ architecture,
1814
+ codePatterns,
1815
+ risks,
1816
+ opportunities,
1817
+ health
1818
+ };
1773
1819
  }
1774
- let name = options.name;
1775
- if (!name) {
1776
- const nameInput = await p7.text({
1777
- message: "Pattern name:",
1778
- placeholder: "e.g., Next.js App Router Migration",
1779
- validate: (value) => {
1780
- if (!value || value.length < 3) return "Name must be at least 3 characters";
1781
- if (value.length > 100) return "Name must be less than 100 characters";
1782
- return void 0;
1783
- }
1820
+ /**
1821
+ * Executive depth: High-level business summary only
1822
+ */
1823
+ async analyzeExecutive(timestamp, project) {
1824
+ const packageJson = await this.readPackageJson();
1825
+ const deps = packageJson.dependencies || {};
1826
+ const devDeps = packageJson.devDependencies || {};
1827
+ const techCategories = this.categorizeTechnologies(deps, devDeps);
1828
+ const risks = this.calculateExecutiveRisks(project, techCategories);
1829
+ const opportunities = this.calculateExecutiveOpportunities(
1830
+ project,
1831
+ techCategories
1832
+ );
1833
+ return {
1834
+ depth: "executive",
1835
+ timestamp,
1836
+ project,
1837
+ technology: {
1838
+ language: this.detectLanguage(deps, devDeps),
1839
+ runtime: this.detectRuntime(deps, devDeps),
1840
+ buildTools: this.detectBuildTools(devDeps),
1841
+ platforms: this.detectPlatforms(deps),
1842
+ infrastructure: this.detectInfrastructure(deps, devDeps)
1843
+ },
1844
+ packages: {
1845
+ total: Object.keys(deps).length + Object.keys(devDeps).length,
1846
+ production: [],
1847
+ development: [],
1848
+ categories: techCategories,
1849
+ outdated: [],
1850
+ security: []
1851
+ },
1852
+ risks,
1853
+ opportunities
1854
+ };
1855
+ }
1856
+ /**
1857
+ * Analyze project overview
1858
+ */
1859
+ async analyzeProject() {
1860
+ const packageJson = await this.readPackageJson();
1861
+ const isMonorepoProject = await isMonorepo(this.options.cwd);
1862
+ const fileCount = await this.countFiles();
1863
+ const totalLines = await this.countTotalLines();
1864
+ let workspaceCount;
1865
+ if (isMonorepoProject && packageJson.workspaces) {
1866
+ workspaceCount = Array.isArray(packageJson.workspaces) ? packageJson.workspaces.length : 0;
1867
+ }
1868
+ return {
1869
+ name: packageJson.name || "Unknown Project",
1870
+ version: packageJson.version || "0.0.0",
1871
+ description: packageJson.description,
1872
+ isMonorepo: isMonorepoProject,
1873
+ packageManager: await detectPackageManager(this.options.cwd),
1874
+ workspaceCount,
1875
+ fileCount,
1876
+ totalLines
1877
+ };
1878
+ }
1879
+ /**
1880
+ * Analyze technology stack
1881
+ */
1882
+ async analyzeTechnology() {
1883
+ const packageJson = await this.readPackageJson();
1884
+ const deps = packageJson.dependencies || {};
1885
+ const devDeps = packageJson.devDependencies || {};
1886
+ const projectAnalysis = await analyzeProject(this.options.cwd);
1887
+ return {
1888
+ framework: projectAnalysis.framework,
1889
+ frameworkVersion: deps[projectAnalysis.framework || ""] || devDeps[projectAnalysis.framework || ""],
1890
+ language: this.detectLanguage(deps, devDeps),
1891
+ runtime: this.detectRuntime(deps, devDeps),
1892
+ buildTools: this.detectBuildTools(devDeps),
1893
+ platforms: this.detectPlatforms(deps),
1894
+ infrastructure: this.detectInfrastructure(deps, devDeps)
1895
+ };
1896
+ }
1897
+ /**
1898
+ * Analyze packages in detail
1899
+ */
1900
+ async analyzePackages() {
1901
+ const packageJson = await this.readPackageJson();
1902
+ const deps = packageJson.dependencies || {};
1903
+ const devDeps = packageJson.devDependencies || {};
1904
+ const production = this.analyzeDependencies(deps, "production");
1905
+ const development = this.analyzeDependencies(devDeps, "development");
1906
+ const categories = this.categorizeTechnologies(deps, devDeps);
1907
+ return {
1908
+ total: Object.keys(deps).length + Object.keys(devDeps).length,
1909
+ production,
1910
+ development,
1911
+ categories,
1912
+ outdated: [],
1913
+ // TODO: Implement outdated check
1914
+ security: []
1915
+ // TODO: Implement security audit
1916
+ };
1917
+ }
1918
+ /**
1919
+ * Analyze dependencies and categorize them
1920
+ */
1921
+ analyzeDependencies(deps, _type) {
1922
+ return Object.entries(deps).map(([name, version]) => {
1923
+ const category = this.categorizeDependency(name);
1924
+ const info = this.getDependencyInfo(name, category);
1925
+ return {
1926
+ name,
1927
+ version,
1928
+ category,
1929
+ ...info
1930
+ };
1784
1931
  });
1785
- if (p7.isCancel(nameInput)) {
1786
- p7.cancel("Recording cancelled");
1787
- process.exit(0);
1932
+ }
1933
+ /**
1934
+ * Categorize a dependency
1935
+ */
1936
+ categorizeDependency(name) {
1937
+ if (["react", "vue", "angular", "svelte", "solid-js"].some(
1938
+ (fw) => name.includes(fw)
1939
+ )) {
1940
+ return "UI Framework";
1788
1941
  }
1789
- name = nameInput;
1942
+ if (["next", "nuxt", "remix", "sveltekit", "astro"].some(
1943
+ (fw) => name.includes(fw)
1944
+ )) {
1945
+ return "Meta-Framework";
1946
+ }
1947
+ if (["redux", "zustand", "jotai", "recoil", "mobx", "pinia"].includes(name)) {
1948
+ return "State Management";
1949
+ }
1950
+ if ([
1951
+ "axios",
1952
+ "fetch",
1953
+ "swr",
1954
+ "react-query",
1955
+ "@tanstack/react-query",
1956
+ "apollo",
1957
+ "urql"
1958
+ ].some((lib) => name.includes(lib))) {
1959
+ return "API/Data Fetching";
1960
+ }
1961
+ if (["react-router", "vue-router", "@tanstack/router"].some(
1962
+ (r) => name.includes(r)
1963
+ )) {
1964
+ return "Routing";
1965
+ }
1966
+ if (["formik", "react-hook-form", "final-form"].some((f) => name.includes(f))) {
1967
+ return "Forms";
1968
+ }
1969
+ if ([
1970
+ "styled-components",
1971
+ "emotion",
1972
+ "tailwind",
1973
+ "sass",
1974
+ "less",
1975
+ "@mui",
1976
+ "antd",
1977
+ "chakra-ui"
1978
+ ].some((s) => name.includes(s))) {
1979
+ return "Styling/UI Components";
1980
+ }
1981
+ if ([
1982
+ "vitest",
1983
+ "jest",
1984
+ "mocha",
1985
+ "chai",
1986
+ "testing-library",
1987
+ "playwright",
1988
+ "cypress"
1989
+ ].some((t) => name.includes(t))) {
1990
+ return "Testing";
1991
+ }
1992
+ if (["vite", "webpack", "rollup", "esbuild", "turbo", "tsup"].includes(name)) {
1993
+ return "Build Tools";
1994
+ }
1995
+ if (["eslint", "prettier", "stylelint"].some((l) => name.includes(l))) {
1996
+ return "Code Quality";
1997
+ }
1998
+ if (["prisma", "drizzle", "mongoose", "sequelize", "typeorm", "knex"].some(
1999
+ (db) => name.includes(db)
2000
+ )) {
2001
+ return "Database ORM";
2002
+ }
2003
+ if (["next-auth", "auth0", "supabase", "clerk"].some((a) => name.includes(a))) {
2004
+ return "Authentication";
2005
+ }
2006
+ if (["vercel", "netlify", "aws-sdk", "@google-cloud"].some(
2007
+ (d) => name.includes(d)
2008
+ )) {
2009
+ return "Infrastructure";
2010
+ }
2011
+ if (["@analytics", "posthog", "mixpanel", "segment"].some(
2012
+ (a) => name.includes(a)
2013
+ )) {
2014
+ return "Analytics";
2015
+ }
2016
+ return "Other";
1790
2017
  }
1791
- let description = options.description;
1792
- if (!description) {
1793
- const descInput = await p7.text({
1794
- message: "Description:",
1795
- placeholder: "What does this pattern solve?",
1796
- validate: (value) => {
1797
- if (!value || value.length < 10) return "Description must be at least 10 characters";
1798
- if (value.length > 500) return "Description must be less than 500 characters";
1799
- return void 0;
2018
+ /**
2019
+ * Get detailed info about a dependency
2020
+ */
2021
+ getDependencyInfo(name, category) {
2022
+ const defaultInfo = {
2023
+ purpose: `${category} library`,
2024
+ businessValue: "Supports application functionality",
2025
+ usagePatterns: ["Used throughout the application"]
2026
+ };
2027
+ const knownPackages = {
2028
+ react: {
2029
+ purpose: "Core UI library for building component-based interfaces",
2030
+ businessValue: "Enables fast, interactive user experiences with reusable components",
2031
+ usagePatterns: [
2032
+ "Component rendering",
2033
+ "State management",
2034
+ "Event handling"
2035
+ ],
2036
+ alternatives: ["Vue", "Svelte", "Solid"]
2037
+ },
2038
+ next: {
2039
+ purpose: "React meta-framework with SSR, routing, and optimization",
2040
+ businessValue: "Improves SEO, performance, and developer productivity",
2041
+ usagePatterns: [
2042
+ "Server-side rendering",
2043
+ "API routes",
2044
+ "File-based routing"
2045
+ ],
2046
+ alternatives: ["Remix", "Gatsby"]
2047
+ },
2048
+ typescript: {
2049
+ purpose: "Static type checking for JavaScript",
2050
+ businessValue: "Reduces bugs, improves code quality, and enhances developer experience",
2051
+ usagePatterns: ["Type definitions", "Compile-time checks"]
2052
+ }
2053
+ // Add more as needed
2054
+ };
2055
+ return knownPackages[name] || defaultInfo;
2056
+ }
2057
+ /**
2058
+ * Categorize technologies at high level
2059
+ */
2060
+ categorizeTechnologies(deps, devDeps) {
2061
+ const allDeps = { ...deps, ...devDeps };
2062
+ const categories = /* @__PURE__ */ new Map();
2063
+ Object.keys(allDeps).forEach((name) => {
2064
+ const category = this.categorizeDependency(name);
2065
+ if (!categories.has(category)) {
2066
+ categories.set(category, []);
1800
2067
  }
2068
+ categories.get(category).push(name);
1801
2069
  });
1802
- if (p7.isCancel(descInput)) {
1803
- p7.cancel("Recording cancelled");
1804
- process.exit(0);
2070
+ return Array.from(categories.entries()).map(([name, packages]) => ({
2071
+ name,
2072
+ count: packages.length,
2073
+ packages,
2074
+ businessImpact: this.getCategoryBusinessImpact(name)
2075
+ }));
2076
+ }
2077
+ /**
2078
+ * Get business impact description for a category
2079
+ */
2080
+ getCategoryBusinessImpact(category) {
2081
+ const impacts = {
2082
+ "UI Framework": "Core user experience - directly impacts customer satisfaction and engagement",
2083
+ "Meta-Framework": "Application performance and SEO - affects discoverability and user retention",
2084
+ "State Management": "Data consistency - ensures reliable application behavior",
2085
+ "API/Data Fetching": "Backend integration - enables core business functionality",
2086
+ Routing: "Navigation - affects user flow and conversion rates",
2087
+ Forms: "Data collection - critical for user onboarding and conversions",
2088
+ "Styling/UI Components": "Visual design - impacts brand perception and usability",
2089
+ Testing: "Quality assurance - reduces production bugs and support costs",
2090
+ "Build Tools": "Development efficiency - affects time-to-market for new features",
2091
+ "Code Quality": "Maintainability - reduces technical debt and long-term costs",
2092
+ "Database ORM": "Data persistence - ensures business data integrity",
2093
+ Authentication: "Security and user management - protects business and customer data",
2094
+ Infrastructure: "Hosting and scalability - affects uptime and operational costs",
2095
+ Analytics: "Business intelligence - enables data-driven decision making"
2096
+ };
2097
+ return impacts[category] || "Supports various application features";
2098
+ }
2099
+ /**
2100
+ * Analyze architecture patterns
2101
+ */
2102
+ async analyzeArchitecture() {
2103
+ const files = await this.getProjectFiles();
2104
+ const entryPoints = this.detectEntryPoints(files);
2105
+ const pattern = this.detectArchitecturePattern(files);
2106
+ const layers = this.detectLayers(files);
2107
+ return {
2108
+ pattern,
2109
+ layers,
2110
+ entryPoints,
2111
+ dataFlow: this.analyzeDataFlow(files),
2112
+ keyDecisions: this.extractKeyDecisions(files)
2113
+ };
2114
+ }
2115
+ /**
2116
+ * Analyze code patterns in detail
2117
+ */
2118
+ async analyzeCodePatterns() {
2119
+ const files = await this.getProjectFiles();
2120
+ return {
2121
+ components: await this.analyzeComponents(files),
2122
+ services: await this.analyzeServices(files),
2123
+ utilities: await this.analyzeUtilities(files),
2124
+ tests: await this.analyzeTests(files),
2125
+ customPatterns: await this.detectCustomPatterns(files)
2126
+ };
2127
+ }
2128
+ /**
2129
+ * Assess risks
2130
+ */
2131
+ async assessRisks(project, technology, packages) {
2132
+ const categories = [];
2133
+ const critical = [];
2134
+ const high = [];
2135
+ const medium = [];
2136
+ const low = [];
2137
+ const depRisk = this.assessDependencyRisk(packages);
2138
+ categories.push(depRisk);
2139
+ this.categorizeRiskItems(depRisk, critical, high, medium, low);
2140
+ const techRisk = this.assessTechnologyRisk(technology);
2141
+ categories.push(techRisk);
2142
+ this.categorizeRiskItems(techRisk, critical, high, medium, low);
2143
+ const complexityRisk = this.assessComplexityRisk(project);
2144
+ categories.push(complexityRisk);
2145
+ this.categorizeRiskItems(complexityRisk, critical, high, medium, low);
2146
+ const overall = categories.reduce((sum, cat) => sum + cat.score, 0) / categories.length;
2147
+ return { overall, categories, critical, high, medium, low };
2148
+ }
2149
+ /**
2150
+ * Assess opportunities
2151
+ */
2152
+ async assessOpportunities(project, technology, packages) {
2153
+ const categories = [];
2154
+ const immediate = [];
2155
+ const shortTerm = [];
2156
+ const longTerm = [];
2157
+ const modernization = this.assessModernizationOpportunities(
2158
+ technology,
2159
+ packages
2160
+ );
2161
+ categories.push(modernization);
2162
+ this.categorizeOpportunityItems(
2163
+ modernization,
2164
+ immediate,
2165
+ shortTerm,
2166
+ longTerm
2167
+ );
2168
+ const optimization = this.assessOptimizationOpportunities(project);
2169
+ categories.push(optimization);
2170
+ this.categorizeOpportunityItems(
2171
+ optimization,
2172
+ immediate,
2173
+ shortTerm,
2174
+ longTerm
2175
+ );
2176
+ const growth = this.assessGrowthOpportunities(technology, packages);
2177
+ categories.push(growth);
2178
+ this.categorizeOpportunityItems(growth, immediate, shortTerm, longTerm);
2179
+ const overall = categories.reduce((sum, cat) => sum + cat.potential, 0) / categories.length;
2180
+ return { overall, categories, immediate, shortTerm, longTerm };
2181
+ }
2182
+ /**
2183
+ * Analyze health metrics
2184
+ */
2185
+ async analyzeHealth() {
2186
+ return {
2187
+ typecheck: false,
2188
+ lint: false,
2189
+ tests: false,
2190
+ build: false,
2191
+ issues: 0
2192
+ };
2193
+ }
2194
+ // ============================================================================
2195
+ // Helper Methods
2196
+ // ============================================================================
2197
+ async readPackageJson() {
2198
+ const pkgPath = join5(this.options.cwd, "package.json");
2199
+ if (!existsSync5(pkgPath)) {
2200
+ throw new Error("package.json not found");
1805
2201
  }
1806
- description = descInput;
2202
+ const content = await readFile3(pkgPath, "utf-8");
2203
+ return JSON.parse(content);
1807
2204
  }
1808
- let framework = options.framework;
1809
- if (!framework) {
1810
- const fwInput = await p7.text({
1811
- message: "Framework:",
1812
- placeholder: "e.g., next, react, vue, express"
2205
+ async countFiles() {
2206
+ const patterns = ["**/*.{ts,tsx,js,jsx,py,go,rs,java}"];
2207
+ const files = await fg(patterns, {
2208
+ cwd: this.options.cwd,
2209
+ ignore: [
2210
+ "node_modules/**",
2211
+ "dist/**",
2212
+ "build/**",
2213
+ ".next/**",
2214
+ "coverage/**"
2215
+ ]
1813
2216
  });
1814
- if (p7.isCancel(fwInput)) {
1815
- p7.cancel("Recording cancelled");
1816
- process.exit(0);
2217
+ return files.length;
2218
+ }
2219
+ async countTotalLines() {
2220
+ const fileCount = await this.countFiles();
2221
+ return fileCount * 50;
2222
+ }
2223
+ detectLanguage(deps, devDeps) {
2224
+ if (devDeps.typescript || deps.typescript) return "TypeScript";
2225
+ if (Object.keys(deps).some((d) => d.includes("react") || d.includes("vue"))) {
2226
+ return "JavaScript";
1817
2227
  }
1818
- framework = fwInput;
2228
+ return "JavaScript";
1819
2229
  }
1820
- let version = options.version;
1821
- if (!version) {
1822
- const versionInput = await p7.text({
1823
- message: "Framework version (semver range):",
1824
- placeholder: "e.g., >=14.0.0, ^18.0.0",
1825
- initialValue: ">=1.0.0"
1826
- });
1827
- if (p7.isCancel(versionInput)) {
1828
- p7.cancel("Recording cancelled");
1829
- process.exit(0);
2230
+ detectRuntime(deps, devDeps) {
2231
+ if (deps.next || devDeps.next) return "Node.js (Next.js)";
2232
+ if (Object.keys(deps).some((d) => d.includes("react"))) {
2233
+ return "Browser + Node.js";
1830
2234
  }
1831
- version = versionInput;
2235
+ return "Node.js";
1832
2236
  }
1833
- let category = options.category;
1834
- if (patternType === "fix" && !category) {
1835
- const catChoice = await p7.select({
1836
- message: "Category:",
1837
- options: [
1838
- { value: "migration", label: "\u{1F504} Migration" },
1839
- { value: "security", label: "\u{1F512} Security" },
1840
- { value: "performance", label: "\u26A1 Performance" },
1841
- { value: "compatibility", label: "\u{1F517} Compatibility" },
1842
- { value: "deprecation", label: "\u26A0\uFE0F Deprecation" },
1843
- { value: "configuration", label: "\u2699\uFE0F Configuration" },
1844
- { value: "best-practice", label: "\u2728 Best Practice" },
1845
- { value: "error-handling", label: "\u{1F6A8} Error Handling" },
1846
- { value: "testing", label: "\u{1F9EA} Testing" },
1847
- { value: "other", label: "\u{1F4E6} Other" }
1848
- ]
1849
- });
1850
- if (p7.isCancel(catChoice)) {
1851
- p7.cancel("Recording cancelled");
1852
- process.exit(0);
2237
+ detectBuildTools(devDeps) {
2238
+ const tools = [];
2239
+ if (devDeps.vite) tools.push("Vite");
2240
+ if (devDeps.webpack) tools.push("Webpack");
2241
+ if (devDeps.rollup) tools.push("Rollup");
2242
+ if (devDeps.esbuild) tools.push("esbuild");
2243
+ if (devDeps.turbo || devDeps.turborepo) tools.push("Turborepo");
2244
+ if (devDeps.tsup) tools.push("tsup");
2245
+ return tools;
2246
+ }
2247
+ detectPlatforms(deps) {
2248
+ const platforms = [];
2249
+ if (deps.react || deps.next) platforms.push("Web");
2250
+ if (deps["react-native"]) platforms.push("Mobile (React Native)");
2251
+ if (deps.electron) platforms.push("Desktop (Electron)");
2252
+ return platforms.length > 0 ? platforms : ["Web"];
2253
+ }
2254
+ detectInfrastructure(deps, devDeps) {
2255
+ const infra = [];
2256
+ const allDeps = { ...deps, ...devDeps };
2257
+ if (allDeps.vercel || allDeps["@vercel/node"]) infra.push("Vercel");
2258
+ if (Object.keys(allDeps).some((d) => d.includes("aws-"))) {
2259
+ infra.push("AWS");
1853
2260
  }
1854
- category = catChoice;
2261
+ if (Object.keys(allDeps).some((d) => d.includes("@google-cloud"))) {
2262
+ infra.push("Google Cloud");
2263
+ }
2264
+ if (allDeps.netlify) infra.push("Netlify");
2265
+ if (allDeps.supabase || allDeps["@supabase/supabase-js"]) {
2266
+ infra.push("Supabase");
2267
+ }
2268
+ if (allDeps.firebase || allDeps["firebase-admin"]) infra.push("Firebase");
2269
+ return infra;
1855
2270
  }
1856
- const tags = [];
1857
- if (options.tags) {
1858
- const tagPairs = options.tags.split(",").map((t) => t.trim());
1859
- for (const pair of tagPairs) {
1860
- const [cat, val] = pair.split(":");
1861
- if (cat && val) {
1862
- tags.push({
1863
- category: cat,
1864
- name: val
1865
- });
1866
- }
2271
+ calculateExecutiveRisks(project, categories) {
2272
+ const risks = [];
2273
+ let overallScore = 0;
2274
+ if (project.fileCount > 1e3) {
2275
+ risks.push(
2276
+ "Large codebase may require significant maintenance resources"
2277
+ );
2278
+ overallScore += 0.3;
2279
+ }
2280
+ if (categories.length > 15) {
2281
+ risks.push(
2282
+ "High number of technology categories indicates potential complexity"
2283
+ );
2284
+ overallScore += 0.2;
1867
2285
  }
2286
+ const totalPackages = categories.reduce((sum, cat) => sum + cat.count, 0);
2287
+ if (totalPackages > 100) {
2288
+ risks.push(
2289
+ "Large dependency footprint increases security and maintenance burden"
2290
+ );
2291
+ overallScore += 0.3;
2292
+ }
2293
+ overallScore = Math.min(overallScore, 1);
2294
+ return {
2295
+ overall: overallScore,
2296
+ categories: [
2297
+ {
2298
+ name: "Technical Complexity",
2299
+ score: overallScore,
2300
+ issues: risks,
2301
+ impact: "May affect development velocity and operational costs"
2302
+ }
2303
+ ],
2304
+ critical: [],
2305
+ high: overallScore > 0.7 ? risks : [],
2306
+ medium: overallScore > 0.4 && overallScore <= 0.7 ? risks : [],
2307
+ low: overallScore <= 0.4 ? risks : []
2308
+ };
1868
2309
  }
1869
- tags.push({ category: "framework", name: framework });
1870
- if (patternType === "fix") {
1871
- const now = (/* @__PURE__ */ new Date()).toISOString();
1872
- const fixPattern = {
1873
- id: crypto.randomUUID(),
1874
- name,
1875
- description,
1876
- category,
1877
- tags,
1878
- trigger: {
1879
- errorPattern: ".*",
1880
- errorMessage: "Generic error pattern",
1881
- filePattern: "**/*"
1882
- },
1883
- solution: {
1884
- type: "command",
1885
- steps: [
1886
- {
1887
- order: 1,
1888
- action: "run",
1889
- target: "npm run fix",
1890
- description: "Follow the pattern instructions"
1891
- }
1892
- ]
1893
- },
1894
- compatibility: {
1895
- framework,
1896
- frameworkVersion: version,
1897
- runtime: "node",
1898
- runtimeVersion: ">=18.0.0",
1899
- dependencies: []
1900
- },
1901
- metrics: {
1902
- applications: 0,
1903
- successes: 0,
1904
- failures: 0,
1905
- successRate: 0
1906
- },
1907
- source: "manual",
1908
- isPrivate: true,
1909
- createdAt: now,
1910
- updatedAt: now
2310
+ calculateExecutiveOpportunities(_project, categories) {
2311
+ const opportunities = [];
2312
+ let overallScore = 0.5;
2313
+ const hasModernFramework = categories.some(
2314
+ (cat) => cat.name.includes("Meta-Framework")
2315
+ );
2316
+ if (hasModernFramework) {
2317
+ opportunities.push(
2318
+ "Modern framework provides foundation for rapid feature development"
2319
+ );
2320
+ overallScore += 0.2;
2321
+ }
2322
+ const hasTestingTools = categories.some((cat) => cat.name === "Testing");
2323
+ if (hasTestingTools) {
2324
+ opportunities.push(
2325
+ "Testing infrastructure enables quality-driven expansion"
2326
+ );
2327
+ overallScore += 0.1;
2328
+ }
2329
+ return {
2330
+ overall: Math.min(overallScore, 1),
2331
+ categories: [
2332
+ {
2333
+ name: "Growth Potential",
2334
+ potential: overallScore,
2335
+ recommendations: opportunities,
2336
+ businessValue: "Strong foundation for scaling features and market reach"
2337
+ }
2338
+ ],
2339
+ immediate: [],
2340
+ shortTerm: opportunities,
2341
+ longTerm: []
1911
2342
  };
1912
- const result = await store.saveFixPattern(fixPattern);
1913
- if (result.success) {
1914
- console.log(chalk11.green("\n\u2705 Fix pattern recorded successfully!\n"));
1915
- console.log(chalk11.dim(` ID: ${fixPattern.id}`));
1916
- console.log(chalk11.dim(` Name: ${name}`));
1917
- console.log(chalk11.dim(` Category: ${category}`));
1918
- console.log(chalk11.dim(` Framework: ${framework} ${version}`));
1919
- } else {
1920
- console.log(chalk11.red("\n\u274C Failed to record pattern"));
1921
- console.log(chalk11.dim(` Error: ${result.error}`));
1922
- process.exit(1);
2343
+ }
2344
+ assessDependencyRisk(packages) {
2345
+ let score = 0;
2346
+ const issues = [];
2347
+ if (packages.total > 100) {
2348
+ score += 0.3;
2349
+ issues.push(`High dependency count (${packages.total} packages)`);
1923
2350
  }
1924
- } else {
2351
+ if (packages.outdated.length > 10) {
2352
+ score += 0.3;
2353
+ issues.push(`${packages.outdated.length} outdated packages`);
2354
+ }
2355
+ if (packages.security.length > 0) {
2356
+ score += 0.4;
2357
+ issues.push(`${packages.security.length} security vulnerabilities`);
2358
+ }
2359
+ return {
2360
+ name: "Dependency Management",
2361
+ score: Math.min(score, 1),
2362
+ issues,
2363
+ impact: "Affects security, stability, and maintenance costs"
2364
+ };
2365
+ }
2366
+ assessTechnologyRisk(technology) {
2367
+ let score = 0;
2368
+ const issues = [];
2369
+ const legacyFrameworks = ["angular.js", "backbone", "ember"];
2370
+ if (technology.framework && legacyFrameworks.some((f) => technology.framework?.includes(f))) {
2371
+ score += 0.5;
2372
+ issues.push("Legacy framework may limit future development");
2373
+ }
2374
+ return {
2375
+ name: "Technology Stack",
2376
+ score,
2377
+ issues,
2378
+ impact: "May affect ability to attract talent and adopt new features"
2379
+ };
2380
+ }
2381
+ assessComplexityRisk(project) {
2382
+ let score = 0;
2383
+ const issues = [];
2384
+ if (project.fileCount > 1e3) {
2385
+ score += 0.2;
2386
+ issues.push("Large codebase requires careful management");
2387
+ }
2388
+ if (project.isMonorepo && (project.workspaceCount || 0) > 10) {
2389
+ score += 0.2;
2390
+ issues.push("Complex monorepo structure");
2391
+ }
2392
+ return {
2393
+ name: "Project Complexity",
2394
+ score,
2395
+ issues,
2396
+ impact: "Affects onboarding time and development velocity"
2397
+ };
2398
+ }
2399
+ assessModernizationOpportunities(_technology, packages) {
2400
+ const recommendations = [];
2401
+ let potential = 0.5;
2402
+ if (packages.outdated.length > 0) {
2403
+ recommendations.push(
2404
+ "Upgrade dependencies to access new features and improvements"
2405
+ );
2406
+ potential += 0.2;
2407
+ }
2408
+ return {
2409
+ name: "Modernization",
2410
+ potential: Math.min(potential, 1),
2411
+ recommendations,
2412
+ businessValue: "Improved performance, security, and developer experience"
2413
+ };
2414
+ }
2415
+ assessOptimizationOpportunities(project) {
2416
+ const recommendations = [];
2417
+ if (project.fileCount > 500) {
2418
+ recommendations.push(
2419
+ "Consider code splitting and lazy loading strategies"
2420
+ );
2421
+ }
2422
+ return {
2423
+ name: "Performance Optimization",
2424
+ potential: 0.6,
2425
+ recommendations,
2426
+ businessValue: "Faster load times and better user experience"
2427
+ };
2428
+ }
2429
+ assessGrowthOpportunities(_technology, packages) {
2430
+ const recommendations = [];
2431
+ let potential = 0.5;
2432
+ const hasAnalytics = packages.categories.some(
2433
+ (cat) => cat.name.includes("Analytics")
2434
+ );
2435
+ if (!hasAnalytics) {
2436
+ recommendations.push("Add analytics to enable data-driven decisions");
2437
+ potential += 0.2;
2438
+ }
2439
+ return {
2440
+ name: "Growth & Expansion",
2441
+ potential: Math.min(potential, 1),
2442
+ recommendations,
2443
+ businessValue: "Data-driven growth and improved user insights"
2444
+ };
2445
+ }
2446
+ categorizeRiskItems(risk, critical, high, medium, low) {
2447
+ if (risk.score > 0.7) {
2448
+ critical.push(...risk.issues);
2449
+ } else if (risk.score > 0.5) {
2450
+ high.push(...risk.issues);
2451
+ } else if (risk.score > 0.3) {
2452
+ medium.push(...risk.issues);
2453
+ } else {
2454
+ low.push(...risk.issues);
2455
+ }
2456
+ }
2457
+ categorizeOpportunityItems(opportunity, immediate, shortTerm, longTerm) {
2458
+ if (opportunity.potential > 0.7) {
2459
+ immediate.push(...opportunity.recommendations);
2460
+ } else if (opportunity.potential > 0.5) {
2461
+ shortTerm.push(...opportunity.recommendations);
2462
+ } else {
2463
+ longTerm.push(...opportunity.recommendations);
2464
+ }
2465
+ }
2466
+ async getProjectFiles() {
2467
+ const patterns = ["**/*.{ts,tsx,js,jsx}"];
2468
+ return await fg(patterns, {
2469
+ cwd: this.options.cwd,
2470
+ ignore: this.options.excludePatterns || [
2471
+ "node_modules/**",
2472
+ "dist/**",
2473
+ "build/**",
2474
+ ".next/**",
2475
+ "coverage/**"
2476
+ ]
2477
+ });
2478
+ }
2479
+ detectEntryPoints(files) {
2480
+ const entryPoints = files.filter(
2481
+ (f) => f.includes("index.") || f.includes("main.") || f.includes("app.") || f.includes("_app.") || f.includes("layout.")
2482
+ );
2483
+ return entryPoints.slice(0, 5);
2484
+ }
2485
+ detectArchitecturePattern(files) {
2486
+ const hasComponents = files.some((f) => f.includes("components/"));
2487
+ const hasPages = files.some(
2488
+ (f) => f.includes("pages/") || f.includes("app/")
2489
+ );
2490
+ const hasServices = files.some((f) => f.includes("services/"));
2491
+ if (hasComponents && hasPages && hasServices) {
2492
+ return "Layered Architecture (Pages \u2192 Components \u2192 Services)";
2493
+ }
2494
+ if (hasComponents && hasPages) {
2495
+ return "Component-Based Architecture";
2496
+ }
2497
+ return "Standard Application Structure";
2498
+ }
2499
+ detectLayers(files) {
2500
+ const layers = [];
2501
+ if (files.some((f) => f.includes("pages/") || f.includes("app/"))) {
2502
+ layers.push("Presentation (Pages/Routes)");
2503
+ }
2504
+ if (files.some((f) => f.includes("components/"))) {
2505
+ layers.push("UI Components");
2506
+ }
2507
+ if (files.some((f) => f.includes("services/") || f.includes("api/"))) {
2508
+ layers.push("Business Logic/Services");
2509
+ }
2510
+ if (files.some((f) => f.includes("lib/") || f.includes("utils/"))) {
2511
+ layers.push("Utilities/Helpers");
2512
+ }
2513
+ if (files.some((f) => f.includes("models/") || f.includes("types/"))) {
2514
+ layers.push("Data Models");
2515
+ }
2516
+ return layers;
2517
+ }
2518
+ analyzeDataFlow(files) {
2519
+ const hasStateManagement = files.some(
2520
+ (f) => f.includes("store") || f.includes("context")
2521
+ );
2522
+ const hasApi = files.some(
2523
+ (f) => f.includes("api") || f.includes("services")
2524
+ );
2525
+ if (hasStateManagement && hasApi) {
2526
+ return "API \u2192 Services \u2192 State Management \u2192 Components";
2527
+ }
2528
+ if (hasApi) {
2529
+ return "API \u2192 Components (Direct)";
2530
+ }
2531
+ return "Props-based Component Communication";
2532
+ }
2533
+ extractKeyDecisions(files) {
2534
+ const decisions = [];
2535
+ if (files.some((f) => f.includes(".ts") || f.includes(".tsx"))) {
2536
+ decisions.push("TypeScript for type safety");
2537
+ }
2538
+ if (files.some((f) => f.includes("app/") && !f.includes("pages/"))) {
2539
+ decisions.push("App Router architecture (Next.js)");
2540
+ }
2541
+ if (files.some((f) => f.includes("server") || f.includes("api"))) {
2542
+ decisions.push("API routes for backend functionality");
2543
+ }
2544
+ return decisions;
2545
+ }
2546
+ async analyzeComponents(files) {
2547
+ const components = files.filter((f) => f.includes("components/"));
2548
+ const patterns = [];
2549
+ const ui = components.filter(
2550
+ (f) => f.includes("/ui/") || f.includes("/common/")
2551
+ );
2552
+ const feature = components.filter(
2553
+ (f) => ["features/", "modules/"].some((dir) => f.includes(dir))
2554
+ );
2555
+ if (ui.length > 0) {
2556
+ patterns.push({
2557
+ type: "UI Components",
2558
+ count: ui.length,
2559
+ examples: ui.slice(0, 3),
2560
+ conventions: ["Reusable", "Presentation-focused"]
2561
+ });
2562
+ }
2563
+ if (feature.length > 0) {
2564
+ patterns.push({
2565
+ type: "Feature Components",
2566
+ count: feature.length,
2567
+ examples: feature.slice(0, 3),
2568
+ conventions: ["Business logic", "Domain-specific"]
2569
+ });
2570
+ }
2571
+ return patterns;
2572
+ }
2573
+ async analyzeServices(files) {
2574
+ const services = files.filter(
2575
+ (f) => f.includes("services/") || f.includes("api/")
2576
+ );
2577
+ return services.slice(0, 5).map((file) => ({
2578
+ name: file,
2579
+ purpose: "API integration or business logic",
2580
+ integrations: []
2581
+ }));
2582
+ }
2583
+ async analyzeUtilities(files) {
2584
+ const utils = files.filter(
2585
+ (f) => f.includes("utils/") || f.includes("lib/")
2586
+ );
2587
+ return [
2588
+ {
2589
+ category: "Utilities",
2590
+ count: utils.length,
2591
+ usage: "Helper functions and shared utilities"
2592
+ }
2593
+ ];
2594
+ }
2595
+ async analyzeTests(files) {
2596
+ const tests = files.filter(
2597
+ (f) => f.includes(".test.") || f.includes(".spec.")
2598
+ );
2599
+ const hasVitest = tests.some((f) => f.includes("vitest"));
2600
+ const hasJest = tests.some((f) => f.includes("jest"));
2601
+ return {
2602
+ framework: hasVitest ? "Vitest" : hasJest ? "Jest" : "Unknown",
2603
+ count: tests.length,
2604
+ types: ["Unit tests"]
2605
+ };
2606
+ }
2607
+ async detectCustomPatterns(files) {
2608
+ const patterns = [];
2609
+ if (files.some((f) => f.includes("hooks/"))) {
2610
+ patterns.push("Custom React Hooks");
2611
+ }
2612
+ if (files.some((f) => f.includes("middleware"))) {
2613
+ patterns.push("Middleware Pattern");
2614
+ }
2615
+ if (files.some((f) => f.includes("providers"))) {
2616
+ patterns.push("Context Providers");
2617
+ }
2618
+ return patterns;
2619
+ }
2620
+ };
2621
+
2622
+ // src/utils/question-generator.ts
2623
+ var QuestionGenerator = class {
2624
+ analysis;
2625
+ config;
2626
+ constructor(analysis, config) {
2627
+ this.analysis = analysis;
2628
+ this.config = config;
2629
+ }
2630
+ /**
2631
+ * Generate all advisory board questions
2632
+ */
2633
+ generate() {
2634
+ const questions = [];
2635
+ questions.push(...this.generateTechnologyQuestions());
2636
+ questions.push(...this.generatePackageQuestions());
2637
+ questions.push(...this.generatePlatformQuestions());
2638
+ questions.push(...this.generateBusinessQuestions());
2639
+ questions.push(...this.generateTechnicalDebtQuestions());
2640
+ questions.push(...this.generateGrowthQuestions());
2641
+ if (this.config?.customQuestions) {
2642
+ questions.push(
2643
+ ...this.formatCustomQuestions(this.config.customQuestions)
2644
+ );
2645
+ }
2646
+ const sorted = this.sortByPriority(questions);
2647
+ return {
2648
+ questions: sorted,
2649
+ summary: this.generateSummary(sorted)
2650
+ };
2651
+ }
2652
+ /**
2653
+ * Technology Decisions questions
2654
+ */
2655
+ generateTechnologyQuestions() {
2656
+ const questions = [];
2657
+ const { technology, project } = this.analysis;
2658
+ if (technology.framework) {
2659
+ questions.push({
2660
+ category: "Technology Decisions",
2661
+ question: `Why was ${technology.framework} chosen as the primary framework, and does it still align with our strategic goals?`,
2662
+ context: `Project uses ${technology.framework}${technology.frameworkVersion ? ` v${technology.frameworkVersion}` : ""} as the foundation`,
2663
+ findings: [
2664
+ `Framework: ${technology.framework}`,
2665
+ `Language: ${technology.language}`,
2666
+ `Runtime: ${technology.runtime}`
2667
+ ],
2668
+ recommendations: [
2669
+ "Validate framework continues to meet performance and scalability needs",
2670
+ "Assess community support and long-term viability",
2671
+ "Consider migration costs vs. benefits if alternatives exist"
2672
+ ],
2673
+ priority: "high",
2674
+ businessImpact: "Framework choice affects development velocity, talent acquisition, and long-term maintenance costs"
2675
+ });
2676
+ }
2677
+ if (technology.buildTools && technology.buildTools.length > 0) {
2678
+ questions.push({
2679
+ category: "Technology Decisions",
2680
+ question: `How are our build tools (${technology.buildTools.join(", ")}) optimizing development workflow and deployment efficiency?`,
2681
+ context: `Build pipeline uses ${technology.buildTools.join(", ")}`,
2682
+ findings: technology.buildTools.map(
2683
+ (tool) => `Using ${tool} for build process`
2684
+ ),
2685
+ recommendations: [
2686
+ "Measure build time impacts on CI/CD pipeline",
2687
+ "Evaluate if modern alternatives could improve developer experience",
2688
+ "Consider caching strategies to optimize build performance"
2689
+ ],
2690
+ priority: "medium",
2691
+ businessImpact: "Build efficiency directly impacts time-to-market for new features"
2692
+ });
2693
+ }
2694
+ if (project.isMonorepo) {
2695
+ questions.push({
2696
+ category: "Technology Decisions",
2697
+ question: `Is the monorepo structure providing expected benefits in code sharing and deployment coordination?`,
2698
+ context: `Project uses monorepo with ${project.workspaceCount || "multiple"} workspaces`,
2699
+ findings: [
2700
+ `Monorepo with ${project.workspaceCount} packages`,
2701
+ `Total ${project.fileCount} files managed`
2702
+ ],
2703
+ recommendations: [
2704
+ "Assess if shared code is properly abstracted and reused",
2705
+ "Evaluate build caching and selective deployment strategies",
2706
+ "Consider workspace organization for scaling"
2707
+ ],
2708
+ priority: "medium",
2709
+ businessImpact: "Monorepo architecture affects team collaboration and deployment complexity"
2710
+ });
2711
+ }
2712
+ return questions;
2713
+ }
2714
+ /**
2715
+ * Package Utilization questions
2716
+ */
2717
+ generatePackageQuestions() {
2718
+ const questions = [];
2719
+ const { packages } = this.analysis;
2720
+ if (packages.total > 80) {
2721
+ questions.push({
2722
+ category: "Package Utilization",
2723
+ question: `With ${packages.total} dependencies, are we maintaining optimal balance between functionality and maintenance burden?`,
2724
+ context: `Project has ${packages.production.length} production and ${packages.development.length} development dependencies`,
2725
+ findings: [
2726
+ `Total packages: ${packages.total}`,
2727
+ `Production: ${packages.production.length}`,
2728
+ `Development: ${packages.development.length}`
2729
+ ],
2730
+ recommendations: [
2731
+ "Audit for unused or redundant packages",
2732
+ "Evaluate if critical functionality should be internalized",
2733
+ "Implement dependency update strategy"
2734
+ ],
2735
+ priority: packages.total > 150 ? "high" : "medium",
2736
+ businessImpact: "Dependency count affects security surface area and maintenance costs"
2737
+ });
2738
+ }
2739
+ if (packages.categories.length > 0) {
2740
+ const topCategories = packages.categories.sort((a, b) => b.count - a.count).slice(0, 3);
2741
+ topCategories.forEach((cat) => {
2742
+ if (cat.count > 5) {
2743
+ questions.push({
2744
+ category: "Package Utilization",
2745
+ question: `How are we leveraging our ${cat.count} ${cat.name} packages to deliver business value?`,
2746
+ context: `${cat.name}: ${cat.packages.slice(0, 3).join(", ")}${cat.count > 3 ? `, +${cat.count - 3} more` : ""}`,
2747
+ findings: [
2748
+ `${cat.count} packages in ${cat.name} category`,
2749
+ cat.businessImpact
2750
+ ],
2751
+ recommendations: this.getCategoryRecommendations(cat),
2752
+ priority: this.getCategoryPriority(cat),
2753
+ businessImpact: cat.businessImpact
2754
+ });
2755
+ }
2756
+ });
2757
+ }
2758
+ if (packages.security && packages.security.length > 0) {
2759
+ const criticalCount = packages.security.filter(
2760
+ (s) => s.severity === "critical"
2761
+ ).length;
2762
+ questions.push({
2763
+ category: "Package Utilization",
2764
+ question: `What is our strategy for addressing ${packages.security.length} identified security vulnerabilities${criticalCount > 0 ? ` (${criticalCount} critical)` : ""}?`,
2765
+ context: "Security audit identified vulnerabilities in dependencies",
2766
+ findings: packages.security.map(
2767
+ (s) => `${s.package}: ${s.severity} - ${s.issue}`
2768
+ ),
2769
+ recommendations: packages.security.map((s) => s.recommendation),
2770
+ priority: criticalCount > 0 ? "high" : "medium",
2771
+ businessImpact: "Security vulnerabilities pose risk to customer data and business operations"
2772
+ });
2773
+ }
2774
+ return questions;
2775
+ }
2776
+ /**
2777
+ * Platform Strategy questions
2778
+ */
2779
+ generatePlatformQuestions() {
2780
+ const questions = [];
2781
+ const { technology } = this.analysis;
2782
+ if (technology.platforms && technology.platforms.length > 0) {
2783
+ questions.push({
2784
+ category: "Platform Strategy",
2785
+ question: `Are our platform choices (${technology.platforms.join(", ")}) aligned with target market and growth plans?`,
2786
+ context: `Currently deployed on ${technology.platforms.join(" + ")}`,
2787
+ findings: technology.platforms.map((p10) => `Supports ${p10} platform`),
2788
+ recommendations: [
2789
+ "Validate platform coverage matches user demographics",
2790
+ "Assess cross-platform development efficiency",
2791
+ "Consider platform-specific optimization opportunities"
2792
+ ],
2793
+ priority: "medium",
2794
+ businessImpact: "Platform strategy determines market reach and development costs"
2795
+ });
2796
+ }
2797
+ if (technology.infrastructure && technology.infrastructure.length > 0) {
2798
+ questions.push({
2799
+ category: "Platform Strategy",
2800
+ question: `How is our infrastructure choice (${technology.infrastructure.join(", ")}) supporting scalability and cost efficiency?`,
2801
+ context: `Infrastructure: ${technology.infrastructure.join(", ")}`,
2802
+ findings: technology.infrastructure.map((i) => `Deployed on ${i}`),
2803
+ recommendations: [
2804
+ "Monitor infrastructure costs vs. usage patterns",
2805
+ "Evaluate auto-scaling and redundancy capabilities",
2806
+ "Consider multi-region deployment for global users"
2807
+ ],
2808
+ priority: "high",
2809
+ businessImpact: "Infrastructure directly impacts operational costs, uptime, and scalability"
2810
+ });
2811
+ }
2812
+ return questions;
2813
+ }
2814
+ /**
2815
+ * Business Alignment questions
2816
+ */
2817
+ generateBusinessQuestions() {
2818
+ const questions = [];
2819
+ const { packages } = this.analysis;
2820
+ const hasAnalytics = packages.categories.some(
2821
+ (cat) => cat.name.toLowerCase().includes("analytics")
2822
+ );
2823
+ if (!hasAnalytics) {
2824
+ questions.push({
2825
+ category: "Business Alignment",
2826
+ question: "Why don't we have analytics infrastructure, and how are we making data-driven product decisions?",
2827
+ context: "No analytics packages detected in the project",
2828
+ findings: ["Missing analytics implementation"],
2829
+ recommendations: [
2830
+ "Implement analytics to track user behavior and feature adoption",
2831
+ "Set up conversion funnels and key metric tracking",
2832
+ "Enable A/B testing capabilities for product experiments"
2833
+ ],
2834
+ priority: "high",
2835
+ businessImpact: "Lack of analytics limits ability to measure ROI and optimize user experience"
2836
+ });
2837
+ }
2838
+ const hasAuth = packages.categories.some(
2839
+ (cat) => cat.name.toLowerCase().includes("auth")
2840
+ );
2841
+ if (hasAuth) {
2842
+ const authCat = packages.categories.find(
2843
+ (cat) => cat.name.toLowerCase().includes("auth")
2844
+ );
2845
+ questions.push({
2846
+ category: "Business Alignment",
2847
+ question: `How is our authentication solution (${authCat.packages.join(", ")}) supporting user onboarding and security requirements?`,
2848
+ context: `Using ${authCat.packages.join(" + ")} for authentication`,
2849
+ findings: authCat.packages.map((p10) => `Auth provider: ${p10}`),
2850
+ recommendations: [
2851
+ "Measure authentication success rates and friction points",
2852
+ "Ensure compliance with security standards (SOC2, GDPR, etc.)",
2853
+ "Evaluate social login options to reduce signup friction"
2854
+ ],
2855
+ priority: "high",
2856
+ businessImpact: "Authentication affects conversion rates and security posture"
2857
+ });
2858
+ }
2859
+ const hasTestingtools = packages.categories.some(
2860
+ (cat) => cat.name.toLowerCase().includes("testing")
2861
+ );
2862
+ if (hasTestingtools) {
2863
+ questions.push({
2864
+ category: "Business Alignment",
2865
+ question: "How is our testing strategy contributing to product quality and customer satisfaction?",
2866
+ context: "Testing infrastructure is in place",
2867
+ findings: ["Testing tools available"],
2868
+ recommendations: [
2869
+ "Set coverage targets aligned with quality goals",
2870
+ "Implement testing in CI/CD for every release",
2871
+ "Track bugs-in-production as quality metric"
2872
+ ],
2873
+ priority: "medium",
2874
+ businessImpact: "Quality assurance directly affects customer satisfaction and support costs"
2875
+ });
2876
+ }
2877
+ return questions;
2878
+ }
2879
+ /**
2880
+ * Technical Debt questions
2881
+ */
2882
+ generateTechnicalDebtQuestions() {
2883
+ const questions = [];
2884
+ const { risks, packages } = this.analysis;
2885
+ if (risks.high && risks.high.length > 0) {
2886
+ questions.push({
2887
+ category: "Technical Debt",
2888
+ question: `What is our strategy for addressing ${risks.high.length} high-priority technical risks?`,
2889
+ context: "Analysis identified significant technical risks",
2890
+ findings: risks.high,
2891
+ recommendations: [
2892
+ "Prioritize risks by business impact",
2893
+ "Allocate dedicated time for technical debt in sprints",
2894
+ "Track debt reduction as OKR/KPI"
2895
+ ],
2896
+ priority: "high",
2897
+ businessImpact: "Unaddressed technical debt slows feature velocity and increases costs"
2898
+ });
2899
+ }
2900
+ if (packages.outdated && packages.outdated.length > 10) {
2901
+ const breakingCount = packages.outdated.filter((p10) => p10.breaking).length;
2902
+ questions.push({
2903
+ category: "Technical Debt",
2904
+ question: `How should we prioritize updating ${packages.outdated.length} outdated packages${breakingCount > 0 ? ` (${breakingCount} with breaking changes)` : ""}?`,
2905
+ context: "Dependency audit found outdated packages",
2906
+ findings: packages.outdated.slice(0, 5).map((p10) => `${p10.name}: ${p10.current} \u2192 ${p10.latest}`),
2907
+ recommendations: [
2908
+ "Create update roadmap starting with non-breaking changes",
2909
+ "Test breaking changes in feature branches",
2910
+ "Consider automated dependency updates (Dependabot, Renovate)"
2911
+ ],
2912
+ priority: breakingCount > 5 ? "high" : "medium",
2913
+ businessImpact: "Outdated dependencies miss performance improvements and security patches"
2914
+ });
2915
+ }
2916
+ const complexityRisk = risks.categories.find(
2917
+ (c) => c.name.includes("Complexity")
2918
+ );
2919
+ if (complexityRisk && complexityRisk.score > 0.5) {
2920
+ questions.push({
2921
+ category: "Technical Debt",
2922
+ question: "How are we managing codebase complexity to maintain development velocity?",
2923
+ context: `Complexity score: ${(complexityRisk.score * 100).toFixed(0)}%`,
2924
+ findings: complexityRisk.issues,
2925
+ recommendations: [
2926
+ "Implement code quality metrics and monitoring",
2927
+ "Establish refactoring goals for each sprint",
2928
+ "Consider modularization strategies"
2929
+ ],
2930
+ priority: complexityRisk.score > 0.7 ? "high" : "medium",
2931
+ businessImpact: "High complexity slows new feature development and increases bugs"
2932
+ });
2933
+ }
2934
+ return questions;
2935
+ }
2936
+ /**
2937
+ * Growth Opportunities questions
2938
+ */
2939
+ generateGrowthQuestions() {
2940
+ const questions = [];
2941
+ const { opportunities } = this.analysis;
2942
+ if (opportunities.immediate && opportunities.immediate.length > 0) {
2943
+ questions.push({
2944
+ category: "Growth Opportunities",
2945
+ question: "Which immediate technical opportunities should we prioritize for maximum business impact?",
2946
+ context: `${opportunities.immediate.length} immediate opportunities identified`,
2947
+ findings: opportunities.immediate,
2948
+ recommendations: [
2949
+ "Evaluate ROI and effort for each opportunity",
2950
+ "Align opportunities with business OKRs",
2951
+ "Quick wins can build momentum for larger initiatives"
2952
+ ],
2953
+ priority: "high",
2954
+ businessImpact: "Immediate opportunities can deliver quick ROI with minimal investment"
2955
+ });
2956
+ }
2957
+ opportunities.categories.forEach((cat) => {
2958
+ if (cat.potential > 0.6) {
2959
+ questions.push({
2960
+ category: "Growth Opportunities",
2961
+ question: `How can we capitalize on ${cat.name.toLowerCase()} opportunities to drive business growth?`,
2962
+ context: `Potential score: ${(cat.potential * 100).toFixed(0)}%`,
2963
+ findings: cat.recommendations,
2964
+ recommendations: [
2965
+ "Develop roadmap for implementing recommendations",
2966
+ "Assign owners and timelines",
2967
+ "Define success metrics"
2968
+ ],
2969
+ priority: cat.potential > 0.8 ? "high" : "medium",
2970
+ businessImpact: cat.businessValue
2971
+ });
2972
+ }
2973
+ });
2974
+ return questions;
2975
+ }
2976
+ /**
2977
+ * Format custom questions from config
2978
+ */
2979
+ formatCustomQuestions(customQuestions) {
2980
+ return customQuestions.map((q) => ({
2981
+ category: q.category,
2982
+ question: q.question,
2983
+ context: q.context || "Custom advisory question",
2984
+ findings: [],
2985
+ recommendations: [],
2986
+ priority: q.priority || "medium",
2987
+ businessImpact: "Custom question defined by organization"
2988
+ }));
2989
+ }
2990
+ /**
2991
+ * Sort questions by priority
2992
+ */
2993
+ sortByPriority(questions) {
2994
+ const priorityOrder = { high: 0, medium: 1, low: 2 };
2995
+ return questions.sort(
2996
+ (a, b) => priorityOrder[a.priority] - priorityOrder[b.priority]
2997
+ );
2998
+ }
2999
+ /**
3000
+ * Generate summary of questions
3001
+ */
3002
+ generateSummary(questions) {
3003
+ const categories = Array.from(new Set(questions.map((q) => q.category)));
3004
+ return {
3005
+ totalQuestions: questions.length,
3006
+ highPriority: questions.filter((q) => q.priority === "high").length,
3007
+ mediumPriority: questions.filter((q) => q.priority === "medium").length,
3008
+ lowPriority: questions.filter((q) => q.priority === "low").length,
3009
+ categories
3010
+ };
3011
+ }
3012
+ /**
3013
+ * Get recommendations for a package category
3014
+ */
3015
+ getCategoryRecommendations(cat) {
3016
+ const recommendations = [];
3017
+ if (cat.name.includes("UI") || cat.name.includes("Styling")) {
3018
+ recommendations.push(
3019
+ "Ensure design system consistency across components"
3020
+ );
3021
+ recommendations.push("Consider component library optimization");
3022
+ } else if (cat.name.includes("API") || cat.name.includes("Data")) {
3023
+ recommendations.push("Implement proper error handling and retry logic");
3024
+ recommendations.push("Consider caching strategies for performance");
3025
+ } else if (cat.name.includes("Testing")) {
3026
+ recommendations.push("Increase test coverage for critical paths");
3027
+ recommendations.push("Automate testing in CI/CD pipeline");
3028
+ } else if (cat.name.includes("Database") || cat.name.includes("ORM")) {
3029
+ recommendations.push("Optimize queries and indexes");
3030
+ recommendations.push("Implement database migration strategy");
3031
+ }
3032
+ if (recommendations.length === 0) {
3033
+ recommendations.push("Review usage patterns for optimization");
3034
+ recommendations.push("Consider if functionality meets current needs");
3035
+ }
3036
+ return recommendations;
3037
+ }
3038
+ /**
3039
+ * Get priority for a package category
3040
+ */
3041
+ getCategoryPriority(cat) {
3042
+ if (["Authentication", "Database", "Infrastructure", "API"].some(
3043
+ (key) => cat.name.includes(key)
3044
+ )) {
3045
+ return "high";
3046
+ }
3047
+ if (["UI", "Testing", "State Management", "Forms"].some(
3048
+ (key) => cat.name.includes(key)
3049
+ )) {
3050
+ return "medium";
3051
+ }
3052
+ return "low";
3053
+ }
3054
+ };
3055
+
3056
+ // src/utils/report-comparator.ts
3057
+ var ReportComparator = class {
3058
+ baseline;
3059
+ current;
3060
+ constructor(baseline, current) {
3061
+ this.baseline = baseline;
3062
+ this.current = current;
3063
+ }
3064
+ /**
3065
+ * Compare two reports and generate diff
3066
+ */
3067
+ compare() {
3068
+ const baselineSummary = this.extractSummary(this.baseline);
3069
+ const currentSummary = this.extractSummary(this.current);
3070
+ const changes = this.calculateChanges(baselineSummary, currentSummary);
3071
+ const details = this.analyzeDetailedChanges();
3072
+ return {
3073
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3074
+ baseline: baselineSummary,
3075
+ current: currentSummary,
3076
+ changes,
3077
+ details
3078
+ };
3079
+ }
3080
+ /**
3081
+ * Extract summary from analysis
3082
+ */
3083
+ extractSummary(analysis) {
3084
+ return {
3085
+ timestamp: analysis.timestamp,
3086
+ depth: analysis.depth,
3087
+ projectName: analysis.project.name,
3088
+ overallRiskScore: analysis.risks.overall,
3089
+ overallOpportunityScore: analysis.opportunities.overall,
3090
+ packageCount: analysis.packages.total
3091
+ };
3092
+ }
3093
+ /**
3094
+ * Calculate high-level changes
3095
+ */
3096
+ calculateChanges(baseline, current) {
3097
+ const riskScoreChange = current.overallRiskScore - baseline.overallRiskScore;
3098
+ const opportunityScoreChange = current.overallOpportunityScore - baseline.overallOpportunityScore;
3099
+ const packageCountChange = current.packageCount - baseline.packageCount;
3100
+ const baselineHighRisks = new Set(this.baseline.risks.high);
3101
+ const currentHighRisks = new Set(this.current.risks.high);
3102
+ const newHighRisks = Array.from(currentHighRisks).filter(
3103
+ (risk) => !baselineHighRisks.has(risk)
3104
+ ).length;
3105
+ const resolvedHighRisks = Array.from(baselineHighRisks).filter(
3106
+ (risk) => !currentHighRisks.has(risk)
3107
+ ).length;
3108
+ const baselineImmediate = new Set(this.baseline.opportunities.immediate);
3109
+ const currentImmediate = new Set(this.current.opportunities.immediate);
3110
+ const newOpportunities = Array.from(currentImmediate).filter(
3111
+ (opp) => !baselineImmediate.has(opp)
3112
+ ).length;
3113
+ return {
3114
+ riskScoreChange,
3115
+ opportunityScoreChange,
3116
+ packageCountChange,
3117
+ newHighRisks,
3118
+ resolvedHighRisks,
3119
+ newOpportunities
3120
+ };
3121
+ }
3122
+ /**
3123
+ * Analyze detailed changes
3124
+ */
3125
+ analyzeDetailedChanges() {
3126
+ return {
3127
+ risks: this.compareRisks(),
3128
+ opportunities: this.compareOpportunities(),
3129
+ packages: this.comparePackages(),
3130
+ technology: this.compareTechnology()
3131
+ };
3132
+ }
3133
+ /**
3134
+ * Compare risks between reports
3135
+ */
3136
+ compareRisks() {
3137
+ const baselineRisks = /* @__PURE__ */ new Set([
3138
+ ...this.baseline.risks.critical,
3139
+ ...this.baseline.risks.high,
3140
+ ...this.baseline.risks.medium
3141
+ ]);
3142
+ const currentRisks = /* @__PURE__ */ new Set([
3143
+ ...this.current.risks.critical,
3144
+ ...this.current.risks.high,
3145
+ ...this.current.risks.medium
3146
+ ]);
3147
+ const newRisks = Array.from(currentRisks).filter(
3148
+ (risk) => !baselineRisks.has(risk)
3149
+ );
3150
+ const resolved = Array.from(baselineRisks).filter(
3151
+ (risk) => !currentRisks.has(risk)
3152
+ );
3153
+ const changed = [];
3154
+ const baselineCatMap = new Map(
3155
+ this.baseline.risks.categories.map((c) => [c.name, c])
3156
+ );
3157
+ const currentCatMap = new Map(
3158
+ this.current.risks.categories.map((c) => [c.name, c])
3159
+ );
3160
+ for (const [name, current] of currentCatMap) {
3161
+ const baseline = baselineCatMap.get(name);
3162
+ if (baseline && Math.abs(current.score - baseline.score) > 0.05) {
3163
+ changed.push({
3164
+ category: name,
3165
+ before: baseline.score,
3166
+ after: current.score,
3167
+ change: current.score - baseline.score
3168
+ });
3169
+ }
3170
+ }
3171
+ return { new: newRisks, resolved, changed };
3172
+ }
3173
+ /**
3174
+ * Compare opportunities between reports
3175
+ */
3176
+ compareOpportunities() {
3177
+ const baselineOpps = /* @__PURE__ */ new Set([
3178
+ ...this.baseline.opportunities.immediate,
3179
+ ...this.baseline.opportunities.shortTerm
3180
+ ]);
3181
+ const currentOpps = /* @__PURE__ */ new Set([
3182
+ ...this.current.opportunities.immediate,
3183
+ ...this.current.opportunities.shortTerm
3184
+ ]);
3185
+ const newOpps = Array.from(currentOpps).filter(
3186
+ (opp) => !baselineOpps.has(opp)
3187
+ );
3188
+ const completed = Array.from(baselineOpps).filter(
3189
+ (opp) => !currentOpps.has(opp)
3190
+ );
3191
+ const changed = [];
3192
+ const baselineCatMap = new Map(
3193
+ this.baseline.opportunities.categories.map((c) => [c.name, c])
3194
+ );
3195
+ const currentCatMap = new Map(
3196
+ this.current.opportunities.categories.map((c) => [c.name, c])
3197
+ );
3198
+ for (const [name, current] of currentCatMap) {
3199
+ const baseline = baselineCatMap.get(name);
3200
+ if (baseline && Math.abs(current.potential - baseline.potential) > 0.05) {
3201
+ changed.push({
3202
+ category: name,
3203
+ before: baseline.potential,
3204
+ after: current.potential,
3205
+ change: current.potential - baseline.potential
3206
+ });
3207
+ }
3208
+ }
3209
+ return { new: newOpps, completed, changed };
3210
+ }
3211
+ /**
3212
+ * Compare packages between reports
3213
+ */
3214
+ comparePackages() {
3215
+ const baselineProduction = new Map(
3216
+ this.baseline.packages.production.map((p10) => [p10.name, p10])
3217
+ );
3218
+ const currentProduction = new Map(
3219
+ this.current.packages.production.map((p10) => [p10.name, p10])
3220
+ );
3221
+ const added = [];
3222
+ const removed = [];
3223
+ const updated = [];
3224
+ for (const [name, pkg] of currentProduction) {
3225
+ if (!baselineProduction.has(name)) {
3226
+ added.push({
3227
+ name,
3228
+ version: pkg.version,
3229
+ category: pkg.category
3230
+ });
3231
+ }
3232
+ }
3233
+ for (const [name, baselinePkg] of baselineProduction) {
3234
+ const currentPkg = currentProduction.get(name);
3235
+ if (!currentPkg) {
3236
+ removed.push({
3237
+ name,
3238
+ version: baselinePkg.version,
3239
+ category: baselinePkg.category
3240
+ });
3241
+ } else if (baselinePkg.version !== currentPkg.version) {
3242
+ updated.push({
3243
+ name,
3244
+ version: currentPkg.version,
3245
+ previousVersion: baselinePkg.version,
3246
+ category: currentPkg.category
3247
+ });
3248
+ }
3249
+ }
3250
+ const baselineDev = new Map(
3251
+ this.baseline.packages.development.map((p10) => [p10.name, p10])
3252
+ );
3253
+ const currentDev = new Map(
3254
+ this.current.packages.development.map((p10) => [p10.name, p10])
3255
+ );
3256
+ for (const [name, pkg] of currentDev) {
3257
+ if (!baselineDev.has(name)) {
3258
+ added.push({
3259
+ name,
3260
+ version: pkg.version,
3261
+ category: pkg.category
3262
+ });
3263
+ }
3264
+ }
3265
+ for (const [name, baselinePkg] of baselineDev) {
3266
+ const currentPkg = currentDev.get(name);
3267
+ if (!currentPkg) {
3268
+ removed.push({
3269
+ name,
3270
+ version: baselinePkg.version,
3271
+ category: baselinePkg.category
3272
+ });
3273
+ } else if (baselinePkg.version !== currentPkg.version) {
3274
+ updated.push({
3275
+ name,
3276
+ version: currentPkg.version,
3277
+ previousVersion: baselinePkg.version,
3278
+ category: currentPkg.category
3279
+ });
3280
+ }
3281
+ }
3282
+ return { added, removed, updated };
3283
+ }
3284
+ /**
3285
+ * Compare technology stack between reports
3286
+ */
3287
+ compareTechnology() {
3288
+ const baselineTech = this.baseline.technology;
3289
+ const currentTech = this.current.technology;
3290
+ const frameworkChanged = baselineTech.framework !== currentTech.framework || baselineTech.frameworkVersion !== currentTech.frameworkVersion;
3291
+ const baselineTools = new Set(baselineTech.buildTools);
3292
+ const currentTools = new Set(currentTech.buildTools);
3293
+ const newBuildTools = currentTech.buildTools.filter(
3294
+ (tool) => !baselineTools.has(tool)
3295
+ );
3296
+ const removedTools = baselineTech.buildTools.filter(
3297
+ (tool) => !currentTools.has(tool)
3298
+ );
3299
+ const baselineInfra = new Set(baselineTech.infrastructure);
3300
+ const newInfrastructure = currentTech.infrastructure.filter(
3301
+ (infra) => !baselineInfra.has(infra)
3302
+ );
3303
+ return {
3304
+ frameworkChanged,
3305
+ newBuildTools,
3306
+ newInfrastructure,
3307
+ removedTools
3308
+ };
3309
+ }
3310
+ /**
3311
+ * Generate markdown summary of changes
3312
+ */
3313
+ generateMarkdownSummary() {
3314
+ const comparison = this.compare();
3315
+ const { changes, details } = comparison;
3316
+ let md = `# Advisory Report Comparison
3317
+
3318
+ `;
3319
+ md += `**Baseline:** ${new Date(comparison.baseline.timestamp).toLocaleDateString()}
3320
+ `;
3321
+ md += `**Current:** ${new Date(comparison.current.timestamp).toLocaleDateString()}
3322
+
3323
+ `;
3324
+ md += `## Executive Summary
3325
+
3326
+ `;
3327
+ const riskChange = changes.riskScoreChange;
3328
+ const riskEmoji = riskChange < 0 ? "\u2705" : riskChange > 0 ? "\u26A0\uFE0F" : "\u2796";
3329
+ md += `${riskEmoji} **Risk Score:** ${(comparison.baseline.overallRiskScore * 100).toFixed(0)}% \u2192 ${(comparison.current.overallRiskScore * 100).toFixed(0)}% `;
3330
+ md += `(${riskChange > 0 ? "+" : ""}${(riskChange * 100).toFixed(0)}%)
3331
+ `;
3332
+ const oppChange = changes.opportunityScoreChange;
3333
+ const oppEmoji = oppChange > 0 ? "\u2705" : oppChange < 0 ? "\u26A0\uFE0F" : "\u2796";
3334
+ md += `${oppEmoji} **Opportunity Score:** ${(comparison.baseline.overallOpportunityScore * 100).toFixed(0)}% \u2192 ${(comparison.current.overallOpportunityScore * 100).toFixed(0)}% `;
3335
+ md += `(${oppChange > 0 ? "+" : ""}${(oppChange * 100).toFixed(0)}%)
3336
+ `;
3337
+ md += `\u{1F4E6} **Packages:** ${comparison.baseline.packageCount} \u2192 ${comparison.current.packageCount} `;
3338
+ md += `(${changes.packageCountChange > 0 ? "+" : ""}${changes.packageCountChange})
3339
+
3340
+ `;
3341
+ md += `## Key Changes
3342
+
3343
+ `;
3344
+ if (changes.newHighRisks > 0) {
3345
+ md += `\u26A0\uFE0F **${changes.newHighRisks}** new high-priority risks identified
3346
+ `;
3347
+ }
3348
+ if (changes.resolvedHighRisks > 0) {
3349
+ md += `\u2705 **${changes.resolvedHighRisks}** high-priority risks resolved
3350
+ `;
3351
+ }
3352
+ if (changes.newOpportunities > 0) {
3353
+ md += `\u{1F31F} **${changes.newOpportunities}** new opportunities identified
3354
+ `;
3355
+ }
3356
+ if (details.technology.frameworkChanged) {
3357
+ md += `\u{1F504} Framework changed: ${comparison.baseline.projectName}
3358
+ `;
3359
+ }
3360
+ md += `
3361
+ ---
3362
+
3363
+ `;
3364
+ if (details.risks.new.length > 0 || details.risks.resolved.length > 0) {
3365
+ md += `## Risk Changes
3366
+
3367
+ `;
3368
+ if (details.risks.new.length > 0) {
3369
+ md += `### New Risks
3370
+
3371
+ `;
3372
+ details.risks.new.forEach((risk) => {
3373
+ md += `- ${risk}
3374
+ `;
3375
+ });
3376
+ md += `
3377
+ `;
3378
+ }
3379
+ if (details.risks.resolved.length > 0) {
3380
+ md += `### Resolved Risks
3381
+
3382
+ `;
3383
+ details.risks.resolved.forEach((risk) => {
3384
+ md += `- ~~${risk}~~
3385
+ `;
3386
+ });
3387
+ md += `
3388
+ `;
3389
+ }
3390
+ if (details.risks.changed.length > 0) {
3391
+ md += `### Risk Score Changes
3392
+
3393
+ `;
3394
+ md += `| Category | Before | After | Change |
3395
+ `;
3396
+ md += `|----------|--------|-------|--------|
3397
+ `;
3398
+ details.risks.changed.forEach((change) => {
3399
+ const changeStr = change.change > 0 ? `+${(change.change * 100).toFixed(0)}%` : `${(change.change * 100).toFixed(0)}%`;
3400
+ md += `| ${change.category} | ${(change.before * 100).toFixed(0)}% | ${(change.after * 100).toFixed(0)}% | ${changeStr} |
3401
+ `;
3402
+ });
3403
+ md += `
3404
+ `;
3405
+ }
3406
+ }
3407
+ if (details.packages.added.length > 0 || details.packages.removed.length > 0 || details.packages.updated.length > 0) {
3408
+ md += `## Package Changes
3409
+
3410
+ `;
3411
+ if (details.packages.added.length > 0) {
3412
+ md += `### Added (${details.packages.added.length})
3413
+
3414
+ `;
3415
+ details.packages.added.slice(0, 10).forEach((pkg) => {
3416
+ md += `- **${pkg.name}** \`${pkg.version}\` (${pkg.category})
3417
+ `;
3418
+ });
3419
+ if (details.packages.added.length > 10) {
3420
+ md += `
3421
+ _...and ${details.packages.added.length - 10} more_
3422
+ `;
3423
+ }
3424
+ md += `
3425
+ `;
3426
+ }
3427
+ if (details.packages.removed.length > 0) {
3428
+ md += `### Removed (${details.packages.removed.length})
3429
+
3430
+ `;
3431
+ details.packages.removed.slice(0, 10).forEach((pkg) => {
3432
+ md += `- ~~${pkg.name}~~ \`${pkg.version}\`
3433
+ `;
3434
+ });
3435
+ if (details.packages.removed.length > 10) {
3436
+ md += `
3437
+ _...and ${details.packages.removed.length - 10} more_
3438
+ `;
3439
+ }
3440
+ md += `
3441
+ `;
3442
+ }
3443
+ if (details.packages.updated.length > 0) {
3444
+ md += `### Updated (${details.packages.updated.length})
3445
+
3446
+ `;
3447
+ details.packages.updated.slice(0, 10).forEach((pkg) => {
3448
+ md += `- **${pkg.name}** \`${pkg.previousVersion}\` \u2192 \`${pkg.version}\`
3449
+ `;
3450
+ });
3451
+ if (details.packages.updated.length > 10) {
3452
+ md += `
3453
+ _...and ${details.packages.updated.length - 10} more_
3454
+ `;
3455
+ }
3456
+ md += `
3457
+ `;
3458
+ }
3459
+ }
3460
+ return md;
3461
+ }
3462
+ };
3463
+
3464
+ // src/cli/commands/advisory.ts
3465
+ async function advisoryCommand(options) {
3466
+ console.log(chalk11.bold.cyan("\n\u{1F3AF} Advisory Board Analysis\n"));
3467
+ const cwd = process.cwd();
3468
+ let config;
3469
+ try {
3470
+ config = await loadConfig(cwd);
3471
+ } catch (error) {
3472
+ config = void 0;
3473
+ }
3474
+ const advisoryConfig = config?.advisory;
3475
+ const isInteractive = options.interactive || !options.depth && !options.ci;
3476
+ let depth = options.depth || advisoryConfig?.defaultDepth || "standard";
3477
+ let outputDir = options.output || advisoryConfig?.outputDir || "docs/advisory";
3478
+ let includeHealth = options.includeHealth ?? advisoryConfig?.includeHealthMetrics ?? false;
3479
+ if (isInteractive && !options.depth) {
3480
+ const depthChoice = await p7.select({
3481
+ message: "Select analysis depth:",
3482
+ options: [
3483
+ {
3484
+ value: "executive",
3485
+ label: "\u{1F4CA} Executive - Business summary for non-technical stakeholders",
3486
+ hint: "High-level overview only"
3487
+ },
3488
+ {
3489
+ value: "quick",
3490
+ label: "\u26A1 Quick - Package scan and framework detection",
3491
+ hint: "~30 seconds"
3492
+ },
3493
+ {
3494
+ value: "standard",
3495
+ label: "\u{1F50D} Standard - Includes architecture analysis",
3496
+ hint: "~1-2 minutes (recommended)"
3497
+ },
3498
+ {
3499
+ value: "comprehensive",
3500
+ label: "\u{1F52C} Comprehensive - Full code-level pattern detection",
3501
+ hint: "~3-5 minutes"
3502
+ }
3503
+ ],
3504
+ initialValue: "standard"
3505
+ });
3506
+ if (p7.isCancel(depthChoice)) {
3507
+ p7.cancel("Analysis cancelled");
3508
+ process.exit(0);
3509
+ }
3510
+ depth = depthChoice;
3511
+ }
3512
+ if (isInteractive && !options.output) {
3513
+ const outputChoice = await p7.text({
3514
+ message: "Output directory:",
3515
+ placeholder: "docs/advisory",
3516
+ defaultValue: outputDir
3517
+ });
3518
+ if (p7.isCancel(outputChoice)) {
3519
+ p7.cancel("Analysis cancelled");
3520
+ process.exit(0);
3521
+ }
3522
+ outputDir = outputChoice;
3523
+ }
3524
+ if (isInteractive && !options.includeHealth) {
3525
+ const healthChoice = await p7.confirm({
3526
+ message: "Include code health metrics?",
3527
+ initialValue: includeHealth
3528
+ });
3529
+ if (p7.isCancel(healthChoice)) {
3530
+ p7.cancel("Analysis cancelled");
3531
+ process.exit(0);
3532
+ }
3533
+ includeHealth = healthChoice;
3534
+ }
3535
+ const analyzer = new AdvisoryAnalyzer({
3536
+ depth,
3537
+ cwd,
3538
+ config,
3539
+ includeHealth,
3540
+ excludePatterns: advisoryConfig?.excludePatterns
3541
+ });
3542
+ const spinner7 = p7.spinner();
3543
+ const depthLabels = {
3544
+ executive: "executive summary",
3545
+ quick: "quick scan",
3546
+ standard: "standard analysis",
3547
+ comprehensive: "comprehensive analysis"
3548
+ };
3549
+ spinner7.start(`Running ${depthLabels[depth]}...`);
3550
+ let analysis;
3551
+ try {
3552
+ analysis = await analyzer.analyze();
3553
+ spinner7.stop(`\u2713 Analysis complete`);
3554
+ } catch (error) {
3555
+ spinner7.stop("\u2717 Analysis failed");
3556
+ console.error(
3557
+ chalk11.red(
3558
+ `Error: ${error instanceof Error ? error.message : String(error)}`
3559
+ )
3560
+ );
3561
+ process.exit(1);
3562
+ }
3563
+ const questionGenerator = new QuestionGenerator(analysis, advisoryConfig);
3564
+ const questions = questionGenerator.generate();
3565
+ console.log("");
3566
+ displaySummary(analysis, questions);
3567
+ let comparisonReport;
3568
+ let comparator;
3569
+ if (options.compare) {
3570
+ const comparisonPath = options.compare.endsWith(".json") ? join6(cwd, options.compare) : join6(cwd, options.compare, "analysis.json");
3571
+ if (existsSync6(comparisonPath)) {
3572
+ spinner7.start("Comparing with previous report...");
3573
+ try {
3574
+ const previousContent = await readFile4(comparisonPath, "utf-8");
3575
+ const previousAnalysis = JSON.parse(previousContent);
3576
+ comparator = new ReportComparator(previousAnalysis, analysis);
3577
+ comparisonReport = comparator.compare();
3578
+ spinner7.stop("\u2713 Comparison complete");
3579
+ console.log("");
3580
+ displayComparisonSummary(comparisonReport);
3581
+ } catch (error) {
3582
+ spinner7.stop("\u26A0 Comparison failed");
3583
+ console.warn(chalk11.yellow(`Could not compare reports: ${error}`));
3584
+ }
3585
+ } else {
3586
+ console.warn(
3587
+ chalk11.yellow(
3588
+ `
3589
+ \u26A0 No previous report found at ${comparisonPath}. Skipping comparison.
3590
+ `
3591
+ )
3592
+ );
3593
+ }
3594
+ }
3595
+ if (options.dryRun) {
3596
+ console.log(chalk11.dim("\n--dry-run mode: No files written.\n"));
3597
+ return;
3598
+ }
3599
+ const fullOutputDir = join6(cwd, outputDir);
3600
+ await mkdir4(fullOutputDir, { recursive: true });
3601
+ spinner7.start("Generating reports...");
3602
+ try {
3603
+ const timestamp = options.timestamp ? (/* @__PURE__ */ new Date()).toISOString().split("T")[0] : "";
3604
+ if (options.format === "json") {
3605
+ await writeAnalysisJson(fullOutputDir, analysis, questions, timestamp);
3606
+ } else {
3607
+ await writeMarkdownReports(
3608
+ fullOutputDir,
3609
+ analysis,
3610
+ questions,
3611
+ comparator,
3612
+ timestamp
3613
+ );
3614
+ }
3615
+ spinner7.stop("\u2713 Reports generated");
3616
+ } catch (error) {
3617
+ spinner7.stop("\u2717 Failed to write reports");
3618
+ console.error(chalk11.red(`Error: ${error}`));
3619
+ process.exit(1);
3620
+ }
3621
+ console.log("");
3622
+ console.log(chalk11.green("\u{1F4DD} Reports written to:"));
3623
+ const suffix = options.timestamp ? `-${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}` : "";
3624
+ if (options.format === "json") {
3625
+ console.log(chalk11.dim(` ${join6(outputDir, `analysis${suffix}.json`)}`));
3626
+ console.log(chalk11.dim(` ${join6(outputDir, `questions${suffix}.json`)}`));
3627
+ } else {
3628
+ console.log(
3629
+ chalk11.dim(` ${join6(outputDir, `EXECUTIVE_SUMMARY${suffix}.md`)}`)
3630
+ );
3631
+ console.log(
3632
+ chalk11.dim(` ${join6(outputDir, `TECHNOLOGY_AUDIT${suffix}.md`)}`)
3633
+ );
3634
+ console.log(
3635
+ chalk11.dim(` ${join6(outputDir, `STRATEGIC_ROADMAP${suffix}.md`)}`)
3636
+ );
3637
+ console.log(
3638
+ chalk11.dim(` ${join6(outputDir, `BOARD_QUESTIONS${suffix}.md`)}`)
3639
+ );
3640
+ if (comparisonReport) {
3641
+ console.log(
3642
+ chalk11.dim(` ${join6(outputDir, `DIFF_REPORT${suffix}.md`)}`)
3643
+ );
3644
+ }
3645
+ }
3646
+ if (options.ci) {
3647
+ console.log("");
3648
+ const exitCode = checkCIThresholds(analysis, advisoryConfig);
3649
+ if (exitCode !== 0) {
3650
+ console.log(chalk11.red(`
3651
+ \u274C CI check failed (exit code ${exitCode})
3652
+ `));
3653
+ process.exit(exitCode);
3654
+ } else {
3655
+ console.log(chalk11.green("\n\u2713 CI check passed\n"));
3656
+ }
3657
+ }
3658
+ p7.outro(chalk11.green("\u2713 Advisory analysis complete!"));
3659
+ }
3660
+ function displaySummary(analysis, questions) {
3661
+ console.log(chalk11.bold("\u{1F4CA} Analysis Summary\n"));
3662
+ console.log(
3663
+ chalk11.dim(`Project: ${analysis.project.name} v${analysis.project.version}`)
3664
+ );
3665
+ console.log(
3666
+ chalk11.dim(
3667
+ `Framework: ${analysis.technology.framework || "N/A"} (${analysis.technology.language})`
3668
+ )
3669
+ );
3670
+ console.log(chalk11.dim(`Total Packages: ${analysis.packages.total}`));
3671
+ console.log(chalk11.dim(`Files Analyzed: ${analysis.project.fileCount}`));
3672
+ console.log("");
3673
+ const riskScore = (analysis.risks.overall * 100).toFixed(0);
3674
+ const riskColor = analysis.risks.overall > 0.7 ? chalk11.red : analysis.risks.overall > 0.4 ? chalk11.yellow : chalk11.green;
3675
+ console.log(riskColor(`\u26A0\uFE0F Risk Score: ${riskScore}%`));
3676
+ const oppScore = (analysis.opportunities.overall * 100).toFixed(0);
3677
+ const oppColor = analysis.opportunities.overall > 0.7 ? chalk11.green : analysis.opportunities.overall > 0.5 ? chalk11.yellow : chalk11.dim;
3678
+ console.log(oppColor(`\u{1F31F} Opportunity Score: ${oppScore}%`));
3679
+ console.log("");
3680
+ console.log(chalk11.bold("\u2753 Advisory Questions\n"));
3681
+ console.log(
3682
+ chalk11.dim(`Total Questions: ${questions.summary.totalQuestions}`)
3683
+ );
3684
+ console.log(chalk11.red(` High Priority: ${questions.summary.highPriority}`));
3685
+ console.log(
3686
+ chalk11.yellow(` Medium Priority: ${questions.summary.mediumPriority}`)
3687
+ );
3688
+ console.log(chalk11.dim(` Low Priority: ${questions.summary.lowPriority}`));
3689
+ console.log("");
3690
+ const highPriorityQuestions = questions.questions.filter(
3691
+ (q) => q.priority === "high"
3692
+ );
3693
+ if (highPriorityQuestions.length > 0) {
3694
+ console.log(chalk11.bold.yellow("\u{1F525} Top Priority Questions:\n"));
3695
+ highPriorityQuestions.slice(0, 3).forEach((q, i) => {
3696
+ console.log(chalk11.yellow(`${i + 1}. ${q.question}`));
3697
+ console.log(chalk11.dim(` Category: ${q.category}`));
3698
+ console.log("");
3699
+ });
3700
+ }
3701
+ }
3702
+ function displayComparisonSummary(comparison) {
3703
+ console.log(chalk11.bold("\u{1F4C8} Changes Since Last Report\n"));
3704
+ const riskChange = comparison.changes.riskScoreChange;
3705
+ const riskEmoji = riskChange < 0 ? "\u2705" : riskChange > 0 ? "\u26A0\uFE0F" : "\u2796";
3706
+ console.log(
3707
+ `${riskEmoji} Risk Score: ${(riskChange * 100).toFixed(0)}% change`
3708
+ );
3709
+ const oppChange = comparison.changes.opportunityScoreChange;
3710
+ const oppEmoji = oppChange > 0 ? "\u2705" : oppChange < 0 ? "\u26A0\uFE0F" : "\u2796";
3711
+ console.log(
3712
+ `${oppEmoji} Opportunity Score: ${(oppChange * 100).toFixed(0)}% change`
3713
+ );
3714
+ console.log(
3715
+ `\u{1F4E6} Packages: ${comparison.changes.packageCountChange > 0 ? "+" : ""}${comparison.changes.packageCountChange}`
3716
+ );
3717
+ if (comparison.changes.newHighRisks > 0) {
3718
+ console.log(
3719
+ chalk11.red(
3720
+ `\u26A0\uFE0F ${comparison.changes.newHighRisks} new high-priority risks`
3721
+ )
3722
+ );
3723
+ }
3724
+ if (comparison.changes.resolvedHighRisks > 0) {
3725
+ console.log(
3726
+ chalk11.green(
3727
+ `\u2705 ${comparison.changes.resolvedHighRisks} high-priority risks resolved`
3728
+ )
3729
+ );
3730
+ }
3731
+ console.log("");
3732
+ }
3733
+ async function writeAnalysisJson(outputDir, analysis, questions, timestamp) {
3734
+ const suffix = timestamp ? `-${timestamp}` : "";
3735
+ await writeFile4(
3736
+ join6(outputDir, `analysis${suffix}.json`),
3737
+ JSON.stringify(analysis, null, 2),
3738
+ "utf-8"
3739
+ );
3740
+ await writeFile4(
3741
+ join6(outputDir, `questions${suffix}.json`),
3742
+ JSON.stringify(questions, null, 2),
3743
+ "utf-8"
3744
+ );
3745
+ }
3746
+ async function writeMarkdownReports(outputDir, analysis, questions, comparator, timestamp) {
3747
+ const suffix = timestamp ? `-${timestamp}` : "";
3748
+ await writeFile4(
3749
+ join6(outputDir, `analysis.json`),
3750
+ JSON.stringify(analysis, null, 2),
3751
+ "utf-8"
3752
+ );
3753
+ await writeFile4(
3754
+ join6(outputDir, `EXECUTIVE_SUMMARY${suffix}.md`),
3755
+ generateExecutiveSummary(analysis, questions),
3756
+ "utf-8"
3757
+ );
3758
+ await writeFile4(
3759
+ join6(outputDir, `TECHNOLOGY_AUDIT${suffix}.md`),
3760
+ generateTechnologyAudit(analysis),
3761
+ "utf-8"
3762
+ );
3763
+ await writeFile4(
3764
+ join6(outputDir, `STRATEGIC_ROADMAP${suffix}.md`),
3765
+ generateStrategicRoadmap(analysis, questions),
3766
+ "utf-8"
3767
+ );
3768
+ await writeFile4(
3769
+ join6(outputDir, `BOARD_QUESTIONS${suffix}.md`),
3770
+ generateBoardQuestions(questions),
3771
+ "utf-8"
3772
+ );
3773
+ if (comparator) {
3774
+ await writeFile4(
3775
+ join6(outputDir, `DIFF_REPORT${suffix}.md`),
3776
+ comparator.generateMarkdownSummary(),
3777
+ "utf-8"
3778
+ );
3779
+ }
3780
+ }
3781
+ function generateExecutiveSummary(analysis, questions) {
3782
+ let md = `# Executive Summary
3783
+
3784
+ `;
3785
+ md += `> **Generated:** ${new Date(analysis.timestamp).toLocaleDateString()}
3786
+
3787
+ `;
3788
+ md += `---
3789
+
3790
+ `;
3791
+ md += `## Project Overview
3792
+
3793
+ `;
3794
+ md += `**${analysis.project.name}** is a ${analysis.technology.framework || "modern"} application `;
3795
+ md += `built with ${analysis.technology.language}. `;
3796
+ if (analysis.project.description) {
3797
+ md += `${analysis.project.description}
3798
+
3799
+ `;
3800
+ } else {
3801
+ md += `
3802
+
3803
+ `;
3804
+ }
3805
+ md += `### Key Metrics
3806
+
3807
+ `;
3808
+ md += `| Metric | Value |
3809
+ `;
3810
+ md += `|--------|-------|
3811
+ `;
3812
+ md += `| Version | ${analysis.project.version} |
3813
+ `;
3814
+ md += `| Dependencies | ${analysis.packages.total} packages |
3815
+ `;
3816
+ md += `| Codebase Size | ${analysis.project.fileCount} files (~${(analysis.project.totalLines / 1e3).toFixed(0)}K lines) |
3817
+ `;
3818
+ md += `| Architecture | ${analysis.project.isMonorepo ? "Monorepo" : "Single repository"} |
3819
+ `;
3820
+ md += `
3821
+ `;
3822
+ md += `## Strategic Assessment
3823
+
3824
+ `;
3825
+ const riskScore = analysis.risks.overall;
3826
+ const oppScore = analysis.opportunities.overall;
3827
+ md += `### Risk & Opportunity Matrix
3828
+
3829
+ `;
3830
+ md += `| Category | Score | Status |
3831
+ `;
3832
+ md += `|----------|-------|--------|
3833
+ `;
3834
+ md += `| **Technical Risk** | ${(riskScore * 100).toFixed(0)}% | ${getRiskLabel(riskScore)} |
3835
+ `;
3836
+ md += `| **Growth Opportunity** | ${(oppScore * 100).toFixed(0)}% | ${getOpportunityLabel(oppScore)} |
3837
+ `;
3838
+ md += `
3839
+ `;
3840
+ md += `### Technology Foundation
3841
+
3842
+ `;
3843
+ md += `**Primary Stack:**
3844
+ `;
3845
+ md += `- Framework: ${analysis.technology.framework || "N/A"}
3846
+ `;
3847
+ md += `- Language: ${analysis.technology.language}
3848
+ `;
3849
+ md += `- Runtime: ${analysis.technology.runtime}
3850
+ `;
3851
+ if (analysis.technology.platforms.length > 0) {
3852
+ md += `- Platforms: ${analysis.technology.platforms.join(", ")}
3853
+ `;
3854
+ }
3855
+ md += `
3856
+ `;
3857
+ if (analysis.technology.infrastructure.length > 0) {
3858
+ md += `**Infrastructure:** ${analysis.technology.infrastructure.join(", ")}
3859
+
3860
+ `;
3861
+ }
3862
+ if (analysis.packages.categories.length > 0) {
3863
+ md += `### Technology Categories
3864
+
3865
+ `;
3866
+ const topCategories = analysis.packages.categories.sort((a, b) => b.count - a.count).slice(0, 5);
3867
+ topCategories.forEach((cat) => {
3868
+ md += `- **${cat.name}** (${cat.count} packages) - ${cat.businessImpact}
3869
+ `;
3870
+ });
3871
+ md += `
3872
+ `;
3873
+ }
3874
+ md += `## Key Strategic Questions
3875
+
3876
+ `;
3877
+ const highPriorityQuestions = questions.questions.filter(
3878
+ (q) => q.priority === "high"
3879
+ );
3880
+ if (highPriorityQuestions.length > 0) {
3881
+ highPriorityQuestions.slice(0, 5).forEach((q, i) => {
3882
+ md += `### ${i + 1}. ${q.question}
3883
+
3884
+ `;
3885
+ md += `**Context:** ${q.context}
3886
+
3887
+ `;
3888
+ md += `**Business Impact:** ${q.businessImpact}
3889
+
3890
+ `;
3891
+ });
3892
+ }
3893
+ if (analysis.risks.critical && analysis.risks.critical.length > 0) {
3894
+ md += `## Critical Risks
3895
+
3896
+ `;
3897
+ analysis.risks.critical.forEach((risk) => {
3898
+ md += `- \u26A0\uFE0F ${risk}
3899
+ `;
3900
+ });
3901
+ md += `
3902
+ `;
3903
+ }
3904
+ if (analysis.opportunities.immediate && analysis.opportunities.immediate.length > 0) {
3905
+ md += `## Immediate Opportunities
3906
+
3907
+ `;
3908
+ analysis.opportunities.immediate.slice(0, 5).forEach((opp) => {
3909
+ md += `- \u{1F31F} ${opp}
3910
+ `;
3911
+ });
3912
+ md += `
3913
+ `;
3914
+ }
3915
+ md += `---
3916
+
3917
+ `;
3918
+ md += `*For detailed technical analysis, see [TECHNOLOGY_AUDIT.md](TECHNOLOGY_AUDIT.md)*
3919
+ `;
3920
+ md += `*For strategic recommendations, see [STRATEGIC_ROADMAP.md](STRATEGIC_ROADMAP.md)*
3921
+ `;
3922
+ return md;
3923
+ }
3924
+ function generateTechnologyAudit(analysis) {
3925
+ let md = `# Technology Audit
3926
+
3927
+ `;
3928
+ md += `> **Generated:** ${new Date(analysis.timestamp).toLocaleDateString()}
3929
+ `;
3930
+ md += `> **Analysis Depth:** ${analysis.depth}
3931
+
3932
+ `;
3933
+ md += `---
3934
+
3935
+ `;
3936
+ md += `## Project Details
3937
+
3938
+ `;
3939
+ md += `| Property | Value |
3940
+ `;
3941
+ md += `|----------|-------|
3942
+ `;
3943
+ md += `| Name | ${analysis.project.name} |
3944
+ `;
3945
+ md += `| Version | ${analysis.project.version} |
3946
+ `;
3947
+ md += `| Package Manager | ${analysis.project.packageManager} |
3948
+ `;
3949
+ md += `| Repository Type | ${analysis.project.isMonorepo ? "Monorepo" : "Single"} |
3950
+ `;
3951
+ if (analysis.project.workspaceCount) {
3952
+ md += `| Workspaces | ${analysis.project.workspaceCount} |
3953
+ `;
3954
+ }
3955
+ md += `| Total Files | ${analysis.project.fileCount} |
3956
+ `;
3957
+ md += `| Estimated Lines | ${analysis.project.totalLines.toLocaleString()} |
3958
+ `;
3959
+ md += `
3960
+ `;
3961
+ md += `## Technology Stack
3962
+
3963
+ `;
3964
+ md += `### Core Technologies
3965
+
3966
+ `;
3967
+ md += `| Component | Technology |
3968
+ `;
3969
+ md += `|-----------|------------|
3970
+ `;
3971
+ md += `| Framework | ${analysis.technology.framework || "N/A"} ${analysis.technology.frameworkVersion || ""} |
3972
+ `;
3973
+ md += `| Language | ${analysis.technology.language} |
3974
+ `;
3975
+ md += `| Runtime | ${analysis.technology.runtime} |
3976
+ `;
3977
+ md += `| Platforms | ${analysis.technology.platforms.join(", ")} |
3978
+ `;
3979
+ md += `
3980
+ `;
3981
+ if (analysis.technology.buildTools.length > 0) {
3982
+ md += `### Build Tools
3983
+
3984
+ `;
3985
+ analysis.technology.buildTools.forEach((tool) => {
3986
+ md += `- ${tool}
3987
+ `;
3988
+ });
3989
+ md += `
3990
+ `;
3991
+ }
3992
+ if (analysis.technology.infrastructure.length > 0) {
3993
+ md += `### Infrastructure
3994
+
3995
+ `;
3996
+ analysis.technology.infrastructure.forEach((infra) => {
3997
+ md += `- ${infra}
3998
+ `;
3999
+ });
4000
+ md += `
4001
+ `;
4002
+ }
4003
+ md += `## Dependency Analysis
4004
+
4005
+ `;
4006
+ md += `### Overview
4007
+
4008
+ `;
4009
+ md += `- **Total Packages:** ${analysis.packages.total}
4010
+ `;
4011
+ md += `- **Production:** ${analysis.packages.production.length}
4012
+ `;
4013
+ md += `- **Development:** ${analysis.packages.development.length}
4014
+ `;
4015
+ md += `
4016
+ `;
4017
+ if (analysis.packages.categories.length > 0) {
4018
+ md += `### Package Categories
4019
+
4020
+ `;
4021
+ md += `| Category | Count | Business Impact |
4022
+ `;
4023
+ md += `|----------|-------|----------------|
4024
+ `;
4025
+ analysis.packages.categories.sort((a, b) => b.count - a.count).forEach((cat) => {
4026
+ md += `| ${cat.name} | ${cat.count} | ${cat.businessImpact} |
4027
+ `;
4028
+ });
4029
+ md += `
4030
+ `;
4031
+ }
4032
+ if (analysis.packages.production.length > 0) {
4033
+ md += `### Key Production Dependencies
4034
+
4035
+ `;
4036
+ md += `| Package | Version | Category | Purpose |
4037
+ `;
4038
+ md += `|---------|---------|----------|--------|
4039
+ `;
4040
+ analysis.packages.production.slice(0, 15).forEach((pkg) => {
4041
+ md += `| ${pkg.name} | \`${pkg.version}\` | ${pkg.category} | ${pkg.purpose} |
4042
+ `;
4043
+ });
4044
+ if (analysis.packages.production.length > 15) {
4045
+ md += `
4046
+ *...and ${analysis.packages.production.length - 15} more*
4047
+ `;
4048
+ }
4049
+ md += `
4050
+ `;
4051
+ }
4052
+ if (analysis.architecture) {
4053
+ md += `## Architecture Overview
4054
+
4055
+ `;
4056
+ md += `**Pattern:** ${analysis.architecture.pattern}
4057
+
4058
+ `;
4059
+ md += `### Layers
4060
+
4061
+ `;
4062
+ analysis.architecture.layers.forEach((layer) => {
4063
+ md += `- ${layer}
4064
+ `;
4065
+ });
4066
+ md += `
4067
+ `;
4068
+ md += `**Data Flow:** ${analysis.architecture.dataFlow}
4069
+
4070
+ `;
4071
+ if (analysis.architecture.keyDecisions.length > 0) {
4072
+ md += `### Key Architecture Decisions
4073
+
4074
+ `;
4075
+ analysis.architecture.keyDecisions.forEach((decision) => {
4076
+ md += `- ${decision}
4077
+ `;
4078
+ });
4079
+ md += `
4080
+ `;
4081
+ }
4082
+ }
4083
+ if (analysis.codePatterns) {
4084
+ md += `## Code Patterns
4085
+
4086
+ `;
4087
+ if (analysis.codePatterns.components.length > 0) {
4088
+ md += `### Components
4089
+
4090
+ `;
4091
+ analysis.codePatterns.components.forEach((comp) => {
4092
+ md += `**${comp.type}** (${comp.count})
4093
+ `;
4094
+ md += `- Conventions: ${comp.conventions.join(", ")}
4095
+ `;
4096
+ md += `
4097
+ `;
4098
+ });
4099
+ }
4100
+ if (analysis.codePatterns.tests) {
4101
+ md += `### Testing
4102
+
4103
+ `;
4104
+ md += `- Framework: ${analysis.codePatterns.tests.framework}
4105
+ `;
4106
+ md += `- Test Count: ${analysis.codePatterns.tests.count}
4107
+ `;
4108
+ md += `- Types: ${analysis.codePatterns.tests.types.join(", ")}
4109
+ `;
4110
+ if (analysis.codePatterns.tests.coverage) {
4111
+ md += `- Coverage: ${analysis.codePatterns.tests.coverage}%
4112
+ `;
4113
+ }
4114
+ md += `
4115
+ `;
4116
+ }
4117
+ }
4118
+ if (analysis.health) {
4119
+ md += `## Code Health
4120
+
4121
+ `;
4122
+ md += `| Check | Status |
4123
+ `;
4124
+ md += `|-------|--------|
4125
+ `;
4126
+ md += `| TypeScript | ${analysis.health.typecheck ? "\u2705 Passing" : "\u274C Failing"} |
4127
+ `;
4128
+ md += `| Linting | ${analysis.health.lint ? "\u2705 Passing" : "\u274C Failing"} |
4129
+ `;
4130
+ md += `| Tests | ${analysis.health.tests ? "\u2705 Passing" : "\u274C Failing"} |
4131
+ `;
4132
+ md += `| Build | ${analysis.health.build ? "\u2705 Passing" : "\u274C Failing"} |
4133
+ `;
4134
+ if (analysis.health.coverage) {
4135
+ md += `| Coverage | ${analysis.health.coverage}% |
4136
+ `;
4137
+ }
4138
+ md += `
4139
+ `;
4140
+ }
4141
+ return md;
4142
+ }
4143
+ function generateStrategicRoadmap(analysis, questions) {
4144
+ let md = `# Strategic Roadmap
4145
+
4146
+ `;
4147
+ md += `> **Generated:** ${new Date(analysis.timestamp).toLocaleDateString()}
4148
+
4149
+ `;
4150
+ md += `---
4151
+
4152
+ `;
4153
+ md += `## Overview
4154
+
4155
+ `;
4156
+ md += `This roadmap outlines strategic recommendations based on the technical analysis of ${analysis.project.name}. `;
4157
+ md += `Recommendations are prioritized by business impact and feasibility.
4158
+
4159
+ `;
4160
+ md += `## Risk Management
4161
+
4162
+ `;
4163
+ if (analysis.risks.critical.length > 0) {
4164
+ md += `### \u{1F534} Critical Priorities
4165
+
4166
+ `;
4167
+ analysis.risks.critical.forEach((risk, i) => {
4168
+ md += `${i + 1}. ${risk}
4169
+ `;
4170
+ });
4171
+ md += `
4172
+ `;
4173
+ }
4174
+ if (analysis.risks.high.length > 0) {
4175
+ md += `### \u{1F7E1} High Priority
4176
+
4177
+ `;
4178
+ analysis.risks.high.forEach((risk, i) => {
4179
+ md += `${i + 1}. ${risk}
4180
+ `;
4181
+ });
4182
+ md += `
4183
+ `;
4184
+ }
4185
+ md += `## Growth Opportunities
4186
+
4187
+ `;
4188
+ if (analysis.opportunities.immediate.length > 0) {
4189
+ md += `### \u26A1 Immediate (0-30 days)
4190
+
4191
+ `;
4192
+ analysis.opportunities.immediate.forEach((opp, i) => {
4193
+ md += `${i + 1}. ${opp}
4194
+ `;
4195
+ });
4196
+ md += `
4197
+ `;
4198
+ }
4199
+ if (analysis.opportunities.shortTerm.length > 0) {
4200
+ md += `### \u{1F4C5} Short-term (1-3 months)
4201
+
4202
+ `;
4203
+ analysis.opportunities.shortTerm.forEach((opp, i) => {
4204
+ md += `${i + 1}. ${opp}
4205
+ `;
4206
+ });
4207
+ md += `
4208
+ `;
4209
+ }
4210
+ if (analysis.opportunities.longTerm.length > 0) {
4211
+ md += `### \u{1F3AF} Long-term (3-12 months)
4212
+
4213
+ `;
4214
+ analysis.opportunities.longTerm.forEach((opp, i) => {
4215
+ md += `${i + 1}. ${opp}
4216
+ `;
4217
+ });
4218
+ md += `
4219
+ `;
4220
+ }
4221
+ md += `## Detailed Recommendations
4222
+
4223
+ `;
4224
+ const categoryMap = /* @__PURE__ */ new Map();
4225
+ questions.questions.forEach((q) => {
4226
+ if (!categoryMap.has(q.category)) {
4227
+ categoryMap.set(q.category, []);
4228
+ }
4229
+ categoryMap.get(q.category).push(q);
4230
+ });
4231
+ for (const [category, qs] of categoryMap) {
4232
+ md += `### ${category}
4233
+
4234
+ `;
4235
+ qs.forEach((q) => {
4236
+ md += `#### ${q.question}
4237
+
4238
+ `;
4239
+ if (q.findings.length > 0) {
4240
+ md += `**Current State:**
4241
+ `;
4242
+ q.findings.forEach((f) => {
4243
+ md += `- ${f}
4244
+ `;
4245
+ });
4246
+ md += `
4247
+ `;
4248
+ }
4249
+ if (q.recommendations.length > 0) {
4250
+ md += `**Recommendations:**
4251
+ `;
4252
+ q.recommendations.forEach((r) => {
4253
+ md += `- ${r}
4254
+ `;
4255
+ });
4256
+ md += `
4257
+ `;
4258
+ }
4259
+ md += `**Business Impact:** ${q.businessImpact}
4260
+
4261
+ `;
4262
+ md += `**Priority:** ${q.priority.toUpperCase()}
4263
+
4264
+ `;
4265
+ md += `---
4266
+
4267
+ `;
4268
+ });
4269
+ }
4270
+ return md;
4271
+ }
4272
+ function generateBoardQuestions(questions) {
4273
+ let md = `# Advisory Board Questions
4274
+
4275
+ `;
4276
+ md += `> **Total Questions:** ${questions.summary.totalQuestions}
4277
+ `;
4278
+ md += `> **High Priority:** ${questions.summary.highPriority} | `;
4279
+ md += `**Medium:** ${questions.summary.mediumPriority} | `;
4280
+ md += `**Low:** ${questions.summary.lowPriority}
4281
+
4282
+ `;
4283
+ md += `---
4284
+
4285
+ `;
4286
+ md += `## Table of Contents
4287
+
4288
+ `;
4289
+ questions.summary.categories.forEach((cat) => {
4290
+ const slug = cat.toLowerCase().replace(/\s+/g, "-");
4291
+ md += `- [${cat}](#${slug})
4292
+ `;
4293
+ });
4294
+ md += `
4295
+ ---
4296
+
4297
+ `;
4298
+ const categoryMap = /* @__PURE__ */ new Map();
4299
+ questions.questions.forEach((q) => {
4300
+ if (!categoryMap.has(q.category)) {
4301
+ categoryMap.set(q.category, []);
4302
+ }
4303
+ categoryMap.get(q.category).push(q);
4304
+ });
4305
+ for (const [category, qs] of categoryMap) {
4306
+ const slug = category.toLowerCase().replace(/\s+/g, "-");
4307
+ md += `## ${category}
4308
+
4309
+ `;
4310
+ md += `<a id="${slug}"></a>
4311
+
4312
+ `;
4313
+ qs.forEach((q, i) => {
4314
+ const priorityEmoji = q.priority === "high" ? "\u{1F534}" : q.priority === "medium" ? "\u{1F7E1}" : "\u{1F7E2}";
4315
+ md += `### ${i + 1}. ${priorityEmoji} ${q.question}
4316
+
4317
+ `;
4318
+ md += `**Context:** ${q.context}
4319
+
4320
+ `;
4321
+ if (q.findings.length > 0) {
4322
+ md += `**Findings:**
4323
+ `;
4324
+ q.findings.forEach((f) => {
4325
+ md += `- ${f}
4326
+ `;
4327
+ });
4328
+ md += `
4329
+ `;
4330
+ }
4331
+ if (q.recommendations.length > 0) {
4332
+ md += `**Recommendations:**
4333
+ `;
4334
+ q.recommendations.forEach((r) => {
4335
+ md += `- ${r}
4336
+ `;
4337
+ });
4338
+ md += `
4339
+ `;
4340
+ }
4341
+ md += `**Business Impact:** ${q.businessImpact}
4342
+
4343
+ `;
4344
+ md += `---
4345
+
4346
+ `;
4347
+ });
4348
+ }
4349
+ return md;
4350
+ }
4351
+ function getRiskLabel(score) {
4352
+ if (score > 0.7) return "\u{1F534} High Risk";
4353
+ if (score > 0.4) return "\u{1F7E1} Moderate Risk";
4354
+ return "\u{1F7E2} Low Risk";
4355
+ }
4356
+ function getOpportunityLabel(score) {
4357
+ if (score > 0.7) return "\u{1F31F} High Potential";
4358
+ if (score > 0.5) return "\u{1F4C8} Moderate Potential";
4359
+ return "\u{1F4A1} Identified";
4360
+ }
4361
+ function checkCIThresholds(analysis, config) {
4362
+ const thresholds = config?.riskThresholds || {
4363
+ high: 0.7,
4364
+ medium: 0.4
4365
+ };
4366
+ const riskScore = analysis.risks.overall;
4367
+ if (riskScore >= thresholds.high) {
4368
+ console.log(
4369
+ chalk11.red(
4370
+ `High risk threshold exceeded: ${(riskScore * 100).toFixed(0)}%`
4371
+ )
4372
+ );
4373
+ return 1;
4374
+ }
4375
+ if (analysis.packages.security && analysis.packages.security.length > 0) {
4376
+ const criticalCount = analysis.packages.security.filter(
4377
+ (s) => s.severity === "critical"
4378
+ ).length;
4379
+ if (criticalCount > 0) {
4380
+ console.log(
4381
+ chalk11.red(`Critical security vulnerabilities found: ${criticalCount}`)
4382
+ );
4383
+ return 1;
4384
+ }
4385
+ }
4386
+ return 0;
4387
+ }
4388
+
4389
+ // src/cli/commands/learn.ts
4390
+ import chalk12 from "chalk";
4391
+ import * as p8 from "@clack/prompts";
4392
+ import {
4393
+ PatternStore as PatternStore2,
4394
+ ContributorManager as ContributorManager2,
4395
+ PatternAnonymizer,
4396
+ TelemetryCollector as TelemetryCollector2
4397
+ } from "@hawkinside_out/workflow-improvement-tracker";
4398
+ function getWorkspacePath() {
4399
+ return process.cwd();
4400
+ }
4401
+ function formatDate(isoString) {
4402
+ return new Date(isoString).toLocaleDateString("en-US", {
4403
+ year: "numeric",
4404
+ month: "short",
4405
+ day: "numeric"
4406
+ });
4407
+ }
4408
+ function formatTags(tags) {
4409
+ return tags.map((t) => `${t.category}:${t.name}`).join(", ");
4410
+ }
4411
+ async function learnRecordCommand(options) {
4412
+ const cwd = getWorkspacePath();
4413
+ const store = new PatternStore2(cwd);
4414
+ console.log(chalk12.cyan("\n\u{1F4DA} Record a Learning Pattern\n"));
4415
+ let patternType = options.type;
4416
+ if (!patternType) {
4417
+ const typeChoice = await p8.select({
4418
+ message: "What type of pattern are you recording?",
4419
+ options: [
4420
+ {
4421
+ value: "fix",
4422
+ label: "\u{1F527} Fix Pattern - A specific solution to a problem"
4423
+ },
4424
+ {
4425
+ value: "blueprint",
4426
+ label: "\u{1F4D0} Blueprint - A project structure template"
4427
+ }
4428
+ ]
4429
+ });
4430
+ if (p8.isCancel(typeChoice)) {
4431
+ p8.cancel("Recording cancelled");
4432
+ process.exit(0);
4433
+ }
4434
+ patternType = typeChoice;
4435
+ }
4436
+ let name = options.name;
4437
+ if (!name) {
4438
+ const nameInput = await p8.text({
4439
+ message: "Pattern name:",
4440
+ placeholder: "e.g., Next.js App Router Migration",
4441
+ validate: (value) => {
4442
+ if (!value || value.length < 3)
4443
+ return "Name must be at least 3 characters";
4444
+ if (value.length > 100) return "Name must be less than 100 characters";
4445
+ return void 0;
4446
+ }
4447
+ });
4448
+ if (p8.isCancel(nameInput)) {
4449
+ p8.cancel("Recording cancelled");
4450
+ process.exit(0);
4451
+ }
4452
+ name = nameInput;
4453
+ }
4454
+ let description = options.description;
4455
+ if (!description) {
4456
+ const descInput = await p8.text({
4457
+ message: "Description:",
4458
+ placeholder: "What does this pattern solve?",
4459
+ validate: (value) => {
4460
+ if (!value || value.length < 10)
4461
+ return "Description must be at least 10 characters";
4462
+ if (value.length > 500)
4463
+ return "Description must be less than 500 characters";
4464
+ return void 0;
4465
+ }
4466
+ });
4467
+ if (p8.isCancel(descInput)) {
4468
+ p8.cancel("Recording cancelled");
4469
+ process.exit(0);
4470
+ }
4471
+ description = descInput;
4472
+ }
4473
+ let framework = options.framework;
4474
+ if (!framework) {
4475
+ const fwInput = await p8.text({
4476
+ message: "Framework:",
4477
+ placeholder: "e.g., next, react, vue, express"
4478
+ });
4479
+ if (p8.isCancel(fwInput)) {
4480
+ p8.cancel("Recording cancelled");
4481
+ process.exit(0);
4482
+ }
4483
+ framework = fwInput;
4484
+ }
4485
+ let version = options.version;
4486
+ if (!version) {
4487
+ const versionInput = await p8.text({
4488
+ message: "Framework version (semver range):",
4489
+ placeholder: "e.g., >=14.0.0, ^18.0.0",
4490
+ initialValue: ">=1.0.0"
4491
+ });
4492
+ if (p8.isCancel(versionInput)) {
4493
+ p8.cancel("Recording cancelled");
4494
+ process.exit(0);
4495
+ }
4496
+ version = versionInput;
4497
+ }
4498
+ let category = options.category;
4499
+ if (patternType === "fix" && !category) {
4500
+ const catChoice = await p8.select({
4501
+ message: "Category:",
4502
+ options: [
4503
+ { value: "migration", label: "\u{1F504} Migration" },
4504
+ { value: "security", label: "\u{1F512} Security" },
4505
+ { value: "performance", label: "\u26A1 Performance" },
4506
+ { value: "compatibility", label: "\u{1F517} Compatibility" },
4507
+ { value: "deprecation", label: "\u26A0\uFE0F Deprecation" },
4508
+ { value: "configuration", label: "\u2699\uFE0F Configuration" },
4509
+ { value: "best-practice", label: "\u2728 Best Practice" },
4510
+ { value: "error-handling", label: "\u{1F6A8} Error Handling" },
4511
+ { value: "testing", label: "\u{1F9EA} Testing" },
4512
+ { value: "other", label: "\u{1F4E6} Other" }
4513
+ ]
4514
+ });
4515
+ if (p8.isCancel(catChoice)) {
4516
+ p8.cancel("Recording cancelled");
4517
+ process.exit(0);
4518
+ }
4519
+ category = catChoice;
4520
+ }
4521
+ const tags = [];
4522
+ if (options.tags) {
4523
+ const tagPairs = options.tags.split(",").map((t) => t.trim());
4524
+ for (const pair of tagPairs) {
4525
+ const [cat, val] = pair.split(":");
4526
+ if (cat && val) {
4527
+ tags.push({
4528
+ category: cat,
4529
+ name: val
4530
+ });
4531
+ }
4532
+ }
4533
+ }
4534
+ tags.push({ category: "framework", name: framework });
4535
+ if (patternType === "fix") {
4536
+ const now = (/* @__PURE__ */ new Date()).toISOString();
4537
+ const fixPattern = {
4538
+ id: crypto.randomUUID(),
4539
+ name,
4540
+ description,
4541
+ category,
4542
+ tags,
4543
+ trigger: {
4544
+ errorPattern: ".*",
4545
+ errorMessage: "Generic error pattern",
4546
+ filePattern: "**/*"
4547
+ },
4548
+ solution: {
4549
+ type: "command",
4550
+ steps: [
4551
+ {
4552
+ order: 1,
4553
+ action: "run",
4554
+ target: "npm run fix",
4555
+ description: "Follow the pattern instructions"
4556
+ }
4557
+ ]
4558
+ },
4559
+ compatibility: {
4560
+ framework,
4561
+ frameworkVersion: version,
4562
+ runtime: "node",
4563
+ runtimeVersion: ">=18.0.0",
4564
+ dependencies: []
4565
+ },
4566
+ metrics: {
4567
+ applications: 0,
4568
+ successes: 0,
4569
+ failures: 0,
4570
+ successRate: 0
4571
+ },
4572
+ source: "manual",
4573
+ isPrivate: true,
4574
+ createdAt: now,
4575
+ updatedAt: now
4576
+ };
4577
+ const result = await store.saveFixPattern(fixPattern);
4578
+ if (result.success) {
4579
+ console.log(chalk12.green("\n\u2705 Fix pattern recorded successfully!\n"));
4580
+ console.log(chalk12.dim(` ID: ${fixPattern.id}`));
4581
+ console.log(chalk12.dim(` Name: ${name}`));
4582
+ console.log(chalk12.dim(` Category: ${category}`));
4583
+ console.log(chalk12.dim(` Framework: ${framework} ${version}`));
4584
+ } else {
4585
+ console.log(chalk12.red("\n\u274C Failed to record pattern"));
4586
+ console.log(chalk12.dim(` Error: ${result.error}`));
4587
+ process.exit(1);
4588
+ }
4589
+ } else {
1925
4590
  const now = (/* @__PURE__ */ new Date()).toISOString();
1926
4591
  const blueprint = {
1927
4592
  id: crypto.randomUUID(),
@@ -1965,13 +4630,13 @@ async function learnRecordCommand(options) {
1965
4630
  };
1966
4631
  const result = await store.saveBlueprint(blueprint);
1967
4632
  if (result.success) {
1968
- console.log(chalk11.green("\n\u2705 Blueprint recorded successfully!\n"));
1969
- console.log(chalk11.dim(` ID: ${blueprint.id}`));
1970
- console.log(chalk11.dim(` Name: ${name}`));
1971
- console.log(chalk11.dim(` Framework: ${framework} ${version}`));
4633
+ console.log(chalk12.green("\n\u2705 Blueprint recorded successfully!\n"));
4634
+ console.log(chalk12.dim(` ID: ${blueprint.id}`));
4635
+ console.log(chalk12.dim(` Name: ${name}`));
4636
+ console.log(chalk12.dim(` Framework: ${framework} ${version}`));
1972
4637
  } else {
1973
- console.log(chalk11.red("\n\u274C Failed to record blueprint"));
1974
- console.log(chalk11.dim(` Error: ${result.error}`));
4638
+ console.log(chalk12.red("\n\u274C Failed to record blueprint"));
4639
+ console.log(chalk12.dim(` Error: ${result.error}`));
1975
4640
  process.exit(1);
1976
4641
  }
1977
4642
  }
@@ -1981,7 +4646,7 @@ async function learnListCommand(options) {
1981
4646
  const store = new PatternStore2(cwd);
1982
4647
  const patternType = options.type ?? "all";
1983
4648
  const showDeprecated = options.deprecated ?? false;
1984
- console.log(chalk11.cyan("\n\u{1F4DA} Recorded Learning Patterns\n"));
4649
+ console.log(chalk12.cyan("\n\u{1F4DA} Recorded Learning Patterns\n"));
1985
4650
  if (patternType === "all" || patternType === "fix") {
1986
4651
  const fixResult = await store.listFixPatterns({
1987
4652
  tags: options.tag ? [{ category: "framework", name: options.tag }] : void 0,
@@ -1989,27 +4654,29 @@ async function learnListCommand(options) {
1989
4654
  includeDeprecated: showDeprecated
1990
4655
  });
1991
4656
  if (fixResult.success && fixResult.data && fixResult.data.length > 0) {
1992
- console.log(chalk11.bold.yellow("\u{1F527} Fix Patterns:\n"));
4657
+ console.log(chalk12.bold.yellow("\u{1F527} Fix Patterns:\n"));
1993
4658
  for (const pattern of fixResult.data) {
1994
4659
  const isDeprecated = pattern.deprecatedAt !== void 0;
1995
4660
  const statusIcon = isDeprecated ? "\u26A0\uFE0F" : "\u2713";
1996
- const nameColor = isDeprecated ? chalk11.dim : chalk11.white;
4661
+ const nameColor = isDeprecated ? chalk12.dim : chalk12.white;
1997
4662
  console.log(` ${statusIcon} ${nameColor(pattern.name)}`);
1998
- console.log(chalk11.dim(` ID: ${pattern.id}`));
1999
- console.log(chalk11.dim(` Category: ${pattern.category}`));
2000
- console.log(chalk11.dim(` Created: ${formatDate(pattern.createdAt)}`));
4663
+ console.log(chalk12.dim(` ID: ${pattern.id}`));
4664
+ console.log(chalk12.dim(` Category: ${pattern.category}`));
4665
+ console.log(
4666
+ chalk12.dim(` Created: ${formatDate(pattern.createdAt)}`)
4667
+ );
2001
4668
  console.log(
2002
- chalk11.dim(
4669
+ chalk12.dim(
2003
4670
  ` Success Rate: ${(pattern.metrics.successRate * 100).toFixed(0)}% (${pattern.metrics.successes}/${pattern.metrics.applications})`
2004
4671
  )
2005
4672
  );
2006
4673
  if (pattern.tags.length > 0) {
2007
- console.log(chalk11.dim(` Tags: ${formatTags(pattern.tags)}`));
4674
+ console.log(chalk12.dim(` Tags: ${formatTags(pattern.tags)}`));
2008
4675
  }
2009
4676
  console.log("");
2010
4677
  }
2011
4678
  } else if (patternType === "fix") {
2012
- console.log(chalk11.dim(" No fix patterns found.\n"));
4679
+ console.log(chalk12.dim(" No fix patterns found.\n"));
2013
4680
  }
2014
4681
  }
2015
4682
  if (patternType === "all" || patternType === "blueprint") {
@@ -2019,44 +4686,46 @@ async function learnListCommand(options) {
2019
4686
  includeDeprecated: showDeprecated
2020
4687
  });
2021
4688
  if (bpResult.success && bpResult.data && bpResult.data.length > 0) {
2022
- console.log(chalk11.bold.blue("\u{1F4D0} Blueprints:\n"));
4689
+ console.log(chalk12.bold.blue("\u{1F4D0} Blueprints:\n"));
2023
4690
  for (const blueprint of bpResult.data) {
2024
4691
  const isDeprecated = blueprint.deprecatedAt !== void 0;
2025
4692
  const statusIcon = isDeprecated ? "\u26A0\uFE0F" : "\u2713";
2026
- const nameColor = isDeprecated ? chalk11.dim : chalk11.white;
4693
+ const nameColor = isDeprecated ? chalk12.dim : chalk12.white;
2027
4694
  console.log(` ${statusIcon} ${nameColor(blueprint.name)}`);
2028
- console.log(chalk11.dim(` ID: ${blueprint.id}`));
2029
- console.log(chalk11.dim(` Language: ${blueprint.stack.language}`));
2030
- console.log(chalk11.dim(` Created: ${formatDate(blueprint.createdAt)}`));
4695
+ console.log(chalk12.dim(` ID: ${blueprint.id}`));
4696
+ console.log(chalk12.dim(` Language: ${blueprint.stack.language}`));
2031
4697
  console.log(
2032
- chalk11.dim(
4698
+ chalk12.dim(` Created: ${formatDate(blueprint.createdAt)}`)
4699
+ );
4700
+ console.log(
4701
+ chalk12.dim(
2033
4702
  ` Success Rate: ${(blueprint.metrics.successRate * 100).toFixed(0)}% (${blueprint.metrics.successes}/${blueprint.metrics.applications})`
2034
4703
  )
2035
4704
  );
2036
4705
  if (blueprint.tags.length > 0) {
2037
- console.log(chalk11.dim(` Tags: ${formatTags(blueprint.tags)}`));
4706
+ console.log(chalk12.dim(` Tags: ${formatTags(blueprint.tags)}`));
2038
4707
  }
2039
4708
  console.log("");
2040
4709
  }
2041
4710
  } else if (patternType === "blueprint") {
2042
- console.log(chalk11.dim(" No blueprints found.\n"));
4711
+ console.log(chalk12.dim(" No blueprints found.\n"));
2043
4712
  }
2044
4713
  }
2045
4714
  const stats = await store.getStats();
2046
4715
  const totalPatterns = stats.totalFixes + stats.totalBlueprints;
2047
4716
  const totalDeprecated = stats.deprecatedFixes + stats.deprecatedBlueprints;
2048
- console.log(chalk11.dim("\u2501".repeat(40)));
2049
- console.log(chalk11.dim(`Total: ${totalPatterns} patterns`));
2050
- console.log(chalk11.dim(` Fix Patterns: ${stats.totalFixes}`));
2051
- console.log(chalk11.dim(` Blueprints: ${stats.totalBlueprints}`));
2052
- console.log(chalk11.dim(` Deprecated: ${totalDeprecated}`));
4717
+ console.log(chalk12.dim("\u2501".repeat(40)));
4718
+ console.log(chalk12.dim(`Total: ${totalPatterns} patterns`));
4719
+ console.log(chalk12.dim(` Fix Patterns: ${stats.totalFixes}`));
4720
+ console.log(chalk12.dim(` Blueprints: ${stats.totalBlueprints}`));
4721
+ console.log(chalk12.dim(` Deprecated: ${totalDeprecated}`));
2053
4722
  console.log("");
2054
4723
  }
2055
4724
  async function learnApplyCommand(patternId, options) {
2056
4725
  const cwd = getWorkspacePath();
2057
4726
  const store = new PatternStore2(cwd);
2058
4727
  const telemetry = new TelemetryCollector2(cwd);
2059
- console.log(chalk11.cyan("\n\u{1F527} Apply Learning Pattern\n"));
4728
+ console.log(chalk12.cyan("\n\u{1F527} Apply Learning Pattern\n"));
2060
4729
  let pattern = await store.getFixPattern(patternId);
2061
4730
  let patternType = "fix";
2062
4731
  if (!pattern.success || !pattern.data) {
@@ -2065,88 +4734,110 @@ async function learnApplyCommand(patternId, options) {
2065
4734
  pattern = bpResult;
2066
4735
  patternType = "blueprint";
2067
4736
  } else {
2068
- console.log(chalk11.red(`
4737
+ console.log(chalk12.red(`
2069
4738
  \u274C Pattern not found: ${patternId}`));
2070
- console.log(chalk11.dim(" Use 'workflow learn:list' to see available patterns"));
4739
+ console.log(
4740
+ chalk12.dim(" Use 'workflow learn:list' to see available patterns")
4741
+ );
2071
4742
  process.exit(1);
2072
4743
  }
2073
4744
  }
2074
4745
  const patternData = pattern.data;
2075
- console.log(chalk11.white(` Pattern: ${patternData.name}`));
2076
- console.log(chalk11.dim(` Type: ${patternType}`));
2077
- console.log(chalk11.dim(` Description: ${patternData.description}`));
4746
+ console.log(chalk12.white(` Pattern: ${patternData.name}`));
4747
+ console.log(chalk12.dim(` Type: ${patternType}`));
4748
+ console.log(chalk12.dim(` Description: ${patternData.description}`));
2078
4749
  if (options.dryRun) {
2079
- console.log(chalk11.yellow("\n\u{1F4CB} DRY-RUN MODE: No changes will be applied\n"));
4750
+ console.log(
4751
+ chalk12.yellow("\n\u{1F4CB} DRY-RUN MODE: No changes will be applied\n")
4752
+ );
2080
4753
  }
2081
4754
  const framework = options.framework ?? patternData.compatibility.frameworks[0]?.name ?? "unknown";
2082
4755
  const version = options.version ?? patternData.compatibility.frameworks[0]?.version ?? "0.0.0";
2083
4756
  await telemetry.recordApplication(patternId, patternType, framework, version);
2084
4757
  if (patternType === "fix") {
2085
4758
  const fixPattern = patternData;
2086
- console.log(chalk11.cyan("\n\u{1F4CB} Solution Steps:\n"));
4759
+ console.log(chalk12.cyan("\n\u{1F4CB} Solution Steps:\n"));
2087
4760
  if (fixPattern.solution.steps) {
2088
4761
  for (let i = 0; i < fixPattern.solution.steps.length; i++) {
2089
4762
  const step = fixPattern.solution.steps[i];
2090
- console.log(chalk11.white(` ${i + 1}. [${step.action}] ${step.description}`));
4763
+ console.log(
4764
+ chalk12.white(` ${i + 1}. [${step.action}] ${step.description}`)
4765
+ );
2091
4766
  if (step.file) {
2092
- console.log(chalk11.dim(` File: ${step.file}`));
4767
+ console.log(chalk12.dim(` File: ${step.file}`));
2093
4768
  }
2094
4769
  }
2095
4770
  }
2096
4771
  } else {
2097
4772
  const blueprint = patternData;
2098
- console.log(chalk11.cyan("\n\u{1F4CB} Setup Steps:\n"));
4773
+ console.log(chalk12.cyan("\n\u{1F4CB} Setup Steps:\n"));
2099
4774
  if (blueprint.setup.steps) {
2100
4775
  for (let i = 0; i < blueprint.setup.steps.length; i++) {
2101
4776
  const step = blueprint.setup.steps[i];
2102
- console.log(chalk11.white(` ${i + 1}. ${step.description}`));
4777
+ console.log(chalk12.white(` ${i + 1}. ${step.description}`));
2103
4778
  if (step.command) {
2104
- console.log(chalk11.dim(` Command: ${step.command}`));
4779
+ console.log(chalk12.dim(` Command: ${step.command}`));
2105
4780
  }
2106
4781
  }
2107
4782
  }
2108
4783
  }
2109
4784
  if (!options.dryRun) {
2110
- const confirmed = await p7.confirm({
4785
+ const confirmed = await p8.confirm({
2111
4786
  message: "Mark this pattern as successfully applied?",
2112
4787
  initialValue: true
2113
4788
  });
2114
- if (p7.isCancel(confirmed)) {
2115
- p7.cancel("Application cancelled");
4789
+ if (p8.isCancel(confirmed)) {
4790
+ p8.cancel("Application cancelled");
2116
4791
  process.exit(0);
2117
4792
  }
2118
4793
  if (confirmed) {
2119
4794
  await store.updatePatternMetrics(patternId, patternType, true);
2120
4795
  await telemetry.recordSuccess(patternId, patternType, framework, version);
2121
- console.log(chalk11.green("\n\u2705 Pattern marked as successfully applied!"));
4796
+ console.log(chalk12.green("\n\u2705 Pattern marked as successfully applied!"));
2122
4797
  } else {
2123
4798
  await store.updatePatternMetrics(patternId, patternType, false);
2124
- await telemetry.recordFailure(patternId, patternType, framework, version, "unknown");
2125
- console.log(chalk11.yellow("\n\u26A0\uFE0F Pattern application marked as unsuccessful."));
4799
+ await telemetry.recordFailure(
4800
+ patternId,
4801
+ patternType,
4802
+ framework,
4803
+ version,
4804
+ "unknown"
4805
+ );
4806
+ console.log(
4807
+ chalk12.yellow("\n\u26A0\uFE0F Pattern application marked as unsuccessful.")
4808
+ );
2126
4809
  }
2127
4810
  }
2128
4811
  }
2129
4812
  async function learnSyncCommand(options) {
2130
4813
  const cwd = getWorkspacePath();
2131
4814
  const contributorManager = new ContributorManager2(cwd);
2132
- console.log(chalk11.cyan("\n\u{1F504} Sync Learning Patterns\n"));
4815
+ console.log(chalk12.cyan("\n\u{1F504} Sync Learning Patterns\n"));
2133
4816
  const config = await contributorManager.getConfig();
2134
4817
  if (!config.success || !config.data?.syncOptIn) {
2135
- console.log(chalk11.yellow("\u26A0\uFE0F Sync is not enabled.\n"));
2136
- console.log(chalk11.dim(" To enable sync, run:"));
2137
- console.log(chalk11.dim(" workflow learn:config --enable-sync\n"));
2138
- console.log(chalk11.dim(" This allows you to share anonymized patterns with the community."));
4818
+ console.log(chalk12.yellow("\u26A0\uFE0F Sync is not enabled.\n"));
4819
+ console.log(chalk12.dim(" To enable sync, run:"));
4820
+ console.log(chalk12.dim(" workflow learn:config --enable-sync\n"));
4821
+ console.log(
4822
+ chalk12.dim(
4823
+ " This allows you to share anonymized patterns with the community."
4824
+ )
4825
+ );
2139
4826
  process.exit(0);
2140
4827
  }
2141
4828
  if (options.dryRun) {
2142
- console.log(chalk11.yellow("\u{1F4CB} DRY-RUN MODE: No changes will be synced\n"));
4829
+ console.log(chalk12.yellow("\u{1F4CB} DRY-RUN MODE: No changes will be synced\n"));
2143
4830
  }
2144
4831
  const store = new PatternStore2(cwd);
2145
4832
  const anonymizer = new PatternAnonymizer();
2146
4833
  const { fixes, blueprints } = await store.getPatternsForSync();
2147
- console.log(chalk11.dim(` Patterns ready to sync: ${fixes.length} fixes, ${blueprints.length} blueprints`));
4834
+ console.log(
4835
+ chalk12.dim(
4836
+ ` Patterns ready to sync: ${fixes.length} fixes, ${blueprints.length} blueprints`
4837
+ )
4838
+ );
2148
4839
  if (options.push) {
2149
- console.log(chalk11.cyan("\n\u{1F4E4} Pushing patterns...\n"));
4840
+ console.log(chalk12.cyan("\n\u{1F4E4} Pushing patterns...\n"));
2150
4841
  let anonymizedFixes = 0;
2151
4842
  let anonymizedBlueprints = 0;
2152
4843
  for (const fix of fixes) {
@@ -2154,7 +4845,7 @@ async function learnSyncCommand(options) {
2154
4845
  if (result.success) {
2155
4846
  anonymizedFixes++;
2156
4847
  if (!options.dryRun) {
2157
- console.log(chalk11.dim(` \u2713 Anonymized: ${fix.name}`));
4848
+ console.log(chalk12.dim(` \u2713 Anonymized: ${fix.name}`));
2158
4849
  }
2159
4850
  }
2160
4851
  }
@@ -2163,102 +4854,126 @@ async function learnSyncCommand(options) {
2163
4854
  if (result.success) {
2164
4855
  anonymizedBlueprints++;
2165
4856
  if (!options.dryRun) {
2166
- console.log(chalk11.dim(` \u2713 Anonymized: ${bp.name}`));
4857
+ console.log(chalk12.dim(` \u2713 Anonymized: ${bp.name}`));
2167
4858
  }
2168
4859
  }
2169
4860
  }
2170
4861
  console.log(
2171
- chalk11.green(`
2172
- \u2705 Ready to push ${anonymizedFixes} fixes and ${anonymizedBlueprints} blueprints`)
4862
+ chalk12.green(
4863
+ `
4864
+ \u2705 Ready to push ${anonymizedFixes} fixes and ${anonymizedBlueprints} blueprints`
4865
+ )
2173
4866
  );
2174
- console.log(chalk11.dim(" (Registry push not yet implemented)"));
4867
+ console.log(chalk12.dim(" (Registry push not yet implemented)"));
2175
4868
  }
2176
4869
  if (options.pull) {
2177
- console.log(chalk11.cyan("\n\u{1F4E5} Pulling patterns from registry...\n"));
2178
- console.log(chalk11.dim(" (Registry pull not yet implemented)"));
4870
+ console.log(chalk12.cyan("\n\u{1F4E5} Pulling patterns from registry...\n"));
4871
+ console.log(chalk12.dim(" (Registry pull not yet implemented)"));
2179
4872
  }
2180
4873
  if (!options.push && !options.pull) {
2181
- console.log(chalk11.dim(" Specify --push to upload or --pull to download patterns.\n"));
4874
+ console.log(
4875
+ chalk12.dim(" Specify --push to upload or --pull to download patterns.\n")
4876
+ );
2182
4877
  }
2183
4878
  }
2184
4879
  async function learnConfigCommand(options) {
2185
4880
  const cwd = getWorkspacePath();
2186
4881
  const contributorManager = new ContributorManager2(cwd);
2187
- console.log(chalk11.cyan("\n\u2699\uFE0F Learning Configuration\n"));
4882
+ console.log(chalk12.cyan("\n\u2699\uFE0F Learning Configuration\n"));
2188
4883
  if (options.enableSync) {
2189
4884
  const result = await contributorManager.enableSync();
2190
4885
  if (result.success) {
2191
- console.log(chalk11.green("\u2705 Sync enabled"));
2192
- console.log(chalk11.dim(" Your patterns will be anonymized before sharing."));
4886
+ console.log(chalk12.green("\u2705 Sync enabled"));
4887
+ console.log(
4888
+ chalk12.dim(" Your patterns will be anonymized before sharing.")
4889
+ );
2193
4890
  } else {
2194
- console.log(chalk11.red(`\u274C Failed: ${result.error}`));
4891
+ console.log(chalk12.red(`\u274C Failed: ${result.error}`));
2195
4892
  }
2196
4893
  return;
2197
4894
  }
2198
4895
  if (options.disableSync) {
2199
4896
  const result = await contributorManager.disableSync();
2200
4897
  if (result.success) {
2201
- console.log(chalk11.green("\u2705 Sync disabled"));
4898
+ console.log(chalk12.green("\u2705 Sync disabled"));
2202
4899
  } else {
2203
- console.log(chalk11.red(`\u274C Failed: ${result.error}`));
4900
+ console.log(chalk12.red(`\u274C Failed: ${result.error}`));
2204
4901
  }
2205
4902
  return;
2206
4903
  }
2207
4904
  if (options.enableTelemetry) {
2208
4905
  const result = await contributorManager.enableTelemetry();
2209
4906
  if (result.success) {
2210
- console.log(chalk11.green("\u2705 Telemetry enabled"));
2211
- console.log(chalk11.dim(" Anonymous usage data helps improve pattern recommendations."));
4907
+ console.log(chalk12.green("\u2705 Telemetry enabled"));
4908
+ console.log(
4909
+ chalk12.dim(
4910
+ " Anonymous usage data helps improve pattern recommendations."
4911
+ )
4912
+ );
2212
4913
  } else {
2213
- console.log(chalk11.red(`\u274C Failed: ${result.error}`));
4914
+ console.log(chalk12.red(`\u274C Failed: ${result.error}`));
2214
4915
  }
2215
4916
  return;
2216
4917
  }
2217
4918
  if (options.disableTelemetry) {
2218
4919
  const result = await contributorManager.disableTelemetry();
2219
4920
  if (result.success) {
2220
- console.log(chalk11.green("\u2705 Telemetry disabled"));
4921
+ console.log(chalk12.green("\u2705 Telemetry disabled"));
2221
4922
  } else {
2222
- console.log(chalk11.red(`\u274C Failed: ${result.error}`));
4923
+ console.log(chalk12.red(`\u274C Failed: ${result.error}`));
2223
4924
  }
2224
4925
  return;
2225
4926
  }
2226
4927
  if (options.resetId) {
2227
- const confirmed = await p7.confirm({
4928
+ const confirmed = await p8.confirm({
2228
4929
  message: "Are you sure you want to reset your contributor ID? This cannot be undone.",
2229
4930
  initialValue: false
2230
4931
  });
2231
- if (p7.isCancel(confirmed) || !confirmed) {
2232
- p7.cancel("Reset cancelled");
4932
+ if (p8.isCancel(confirmed) || !confirmed) {
4933
+ p8.cancel("Reset cancelled");
2233
4934
  return;
2234
4935
  }
2235
4936
  const result = await contributorManager.resetId();
2236
4937
  if (result.success) {
2237
- console.log(chalk11.green("\u2705 Contributor ID reset"));
2238
- console.log(chalk11.dim(` New ID: ${result.data?.id}`));
4938
+ console.log(chalk12.green("\u2705 Contributor ID reset"));
4939
+ console.log(chalk12.dim(` New ID: ${result.data?.id}`));
2239
4940
  } else {
2240
- console.log(chalk11.red(`\u274C Failed: ${result.error}`));
4941
+ console.log(chalk12.red(`\u274C Failed: ${result.error}`));
2241
4942
  }
2242
4943
  return;
2243
4944
  }
2244
4945
  const config = await contributorManager.getConfig();
2245
4946
  if (config.success && config.data) {
2246
- console.log(chalk11.white(" Current Settings:\n"));
2247
- console.log(chalk11.dim(` Contributor ID: ${config.data.id}`));
2248
- console.log(chalk11.dim(` Created: ${formatDate(config.data.createdAt)}`));
2249
- console.log(chalk11.dim(` Sync Enabled: ${config.data.syncOptIn ? "Yes" : "No"}`));
2250
- console.log(chalk11.dim(` Telemetry Enabled: ${config.data.telemetryEnabled ? "Yes" : "No"}`));
4947
+ console.log(chalk12.white(" Current Settings:\n"));
4948
+ console.log(chalk12.dim(` Contributor ID: ${config.data.id}`));
4949
+ console.log(chalk12.dim(` Created: ${formatDate(config.data.createdAt)}`));
4950
+ console.log(
4951
+ chalk12.dim(` Sync Enabled: ${config.data.syncOptIn ? "Yes" : "No"}`)
4952
+ );
4953
+ console.log(
4954
+ chalk12.dim(
4955
+ ` Telemetry Enabled: ${config.data.telemetryEnabled ? "Yes" : "No"}`
4956
+ )
4957
+ );
2251
4958
  if (config.data.syncEnabledAt) {
2252
- console.log(chalk11.dim(` Sync Enabled At: ${formatDate(config.data.syncEnabledAt)}`));
4959
+ console.log(
4960
+ chalk12.dim(
4961
+ ` Sync Enabled At: ${formatDate(config.data.syncEnabledAt)}`
4962
+ )
4963
+ );
2253
4964
  }
2254
4965
  } else {
2255
- console.log(chalk11.dim(" No configuration found. Settings will be created on first use.\n"));
4966
+ console.log(
4967
+ chalk12.dim(
4968
+ " No configuration found. Settings will be created on first use.\n"
4969
+ )
4970
+ );
2256
4971
  }
2257
4972
  }
2258
4973
  async function learnDeprecateCommand(patternId, reason) {
2259
4974
  const cwd = getWorkspacePath();
2260
4975
  const store = new PatternStore2(cwd);
2261
- console.log(chalk11.cyan("\n\u26A0\uFE0F Deprecate Pattern\n"));
4976
+ console.log(chalk12.cyan("\n\u26A0\uFE0F Deprecate Pattern\n"));
2262
4977
  let patternType = "fix";
2263
4978
  let pattern = await store.getFixPattern(patternId);
2264
4979
  if (!pattern.success || !pattern.data) {
@@ -2267,26 +4982,26 @@ async function learnDeprecateCommand(patternId, reason) {
2267
4982
  pattern = bpResult;
2268
4983
  patternType = "blueprint";
2269
4984
  } else {
2270
- console.log(chalk11.red(`
4985
+ console.log(chalk12.red(`
2271
4986
  \u274C Pattern not found: ${patternId}`));
2272
4987
  process.exit(1);
2273
4988
  }
2274
4989
  }
2275
- console.log(chalk11.white(` Pattern: ${pattern.data.name}`));
2276
- console.log(chalk11.dim(` Reason: ${reason}`));
2277
- const confirmed = await p7.confirm({
4990
+ console.log(chalk12.white(` Pattern: ${pattern.data.name}`));
4991
+ console.log(chalk12.dim(` Reason: ${reason}`));
4992
+ const confirmed = await p8.confirm({
2278
4993
  message: "Are you sure you want to deprecate this pattern?",
2279
4994
  initialValue: false
2280
4995
  });
2281
- if (p7.isCancel(confirmed) || !confirmed) {
2282
- p7.cancel("Deprecation cancelled");
4996
+ if (p8.isCancel(confirmed) || !confirmed) {
4997
+ p8.cancel("Deprecation cancelled");
2283
4998
  return;
2284
4999
  }
2285
5000
  const result = await store.deprecatePattern(patternId, patternType, reason);
2286
5001
  if (result.success) {
2287
- console.log(chalk11.green("\n\u2705 Pattern deprecated successfully"));
5002
+ console.log(chalk12.green("\n\u2705 Pattern deprecated successfully"));
2288
5003
  } else {
2289
- console.log(chalk11.red(`
5004
+ console.log(chalk12.red(`
2290
5005
  \u274C Failed: ${result.error}`));
2291
5006
  process.exit(1);
2292
5007
  }
@@ -2295,28 +5010,32 @@ async function learnStatsCommand() {
2295
5010
  const cwd = getWorkspacePath();
2296
5011
  const store = new PatternStore2(cwd);
2297
5012
  const telemetry = new TelemetryCollector2(cwd);
2298
- console.log(chalk11.cyan("\n\u{1F4CA} Learning Statistics\n"));
5013
+ console.log(chalk12.cyan("\n\u{1F4CA} Learning Statistics\n"));
2299
5014
  const storeStats = await store.getStats();
2300
5015
  const totalPatterns = storeStats.totalFixes + storeStats.totalBlueprints;
2301
5016
  const totalDeprecated = storeStats.deprecatedFixes + storeStats.deprecatedBlueprints;
2302
- console.log(chalk11.bold.white(" Patterns:\n"));
2303
- console.log(chalk11.dim(` Total: ${totalPatterns}`));
2304
- console.log(chalk11.dim(` Fix Patterns: ${storeStats.totalFixes}`));
2305
- console.log(chalk11.dim(` Blueprints: ${storeStats.totalBlueprints}`));
2306
- console.log(chalk11.dim(` Deprecated: ${totalDeprecated}`));
5017
+ console.log(chalk12.bold.white(" Patterns:\n"));
5018
+ console.log(chalk12.dim(` Total: ${totalPatterns}`));
5019
+ console.log(chalk12.dim(` Fix Patterns: ${storeStats.totalFixes}`));
5020
+ console.log(chalk12.dim(` Blueprints: ${storeStats.totalBlueprints}`));
5021
+ console.log(chalk12.dim(` Deprecated: ${totalDeprecated}`));
2307
5022
  const telemetryStats = await telemetry.getStats();
2308
- console.log(chalk11.bold.white("\n Telemetry:\n"));
2309
- console.log(chalk11.dim(` Pending Events: ${telemetryStats.pendingEvents}`));
2310
- console.log(chalk11.dim(` Total Events Sent: ${telemetryStats.totalEventsSent}`));
5023
+ console.log(chalk12.bold.white("\n Telemetry:\n"));
5024
+ console.log(chalk12.dim(` Pending Events: ${telemetryStats.pendingEvents}`));
5025
+ console.log(
5026
+ chalk12.dim(` Total Events Sent: ${telemetryStats.totalEventsSent}`)
5027
+ );
2311
5028
  if (telemetryStats.lastFlushAt) {
2312
- console.log(chalk11.dim(` Last Flush: ${formatDate(telemetryStats.lastFlushAt)}`));
5029
+ console.log(
5030
+ chalk12.dim(` Last Flush: ${formatDate(telemetryStats.lastFlushAt)}`)
5031
+ );
2313
5032
  }
2314
5033
  console.log("");
2315
5034
  }
2316
5035
 
2317
5036
  // src/cli/commands/solution.ts
2318
- import chalk12 from "chalk";
2319
- import * as p8 from "@clack/prompts";
5037
+ import chalk13 from "chalk";
5038
+ import * as p9 from "@clack/prompts";
2320
5039
  import * as path2 from "path";
2321
5040
  import {
2322
5041
  PatternStore as PatternStore3,
@@ -2358,10 +5077,10 @@ function truncate(str, maxLen) {
2358
5077
  async function solutionCaptureCommand(options) {
2359
5078
  const cwd = getWorkspacePath2();
2360
5079
  const store = new PatternStore3(cwd);
2361
- console.log(chalk12.cyan("\n\u{1F4E6} Capture Solution Pattern\n"));
5080
+ console.log(chalk13.cyan("\n\u{1F4E6} Capture Solution Pattern\n"));
2362
5081
  let targetPath = options.path;
2363
5082
  if (!targetPath) {
2364
- const pathInput = await p8.text({
5083
+ const pathInput = await p9.text({
2365
5084
  message: "Path to the solution directory:",
2366
5085
  placeholder: "./src/auth",
2367
5086
  validate: (val) => {
@@ -2369,8 +5088,8 @@ async function solutionCaptureCommand(options) {
2369
5088
  return void 0;
2370
5089
  }
2371
5090
  });
2372
- if (p8.isCancel(pathInput)) {
2373
- p8.cancel("Operation cancelled");
5091
+ if (p9.isCancel(pathInput)) {
5092
+ p9.cancel("Operation cancelled");
2374
5093
  process.exit(0);
2375
5094
  }
2376
5095
  targetPath = pathInput;
@@ -2378,7 +5097,7 @@ async function solutionCaptureCommand(options) {
2378
5097
  const absolutePath = path2.isAbsolute(targetPath) ? targetPath : path2.resolve(cwd, targetPath);
2379
5098
  let name = options.name;
2380
5099
  if (!name) {
2381
- const nameInput = await p8.text({
5100
+ const nameInput = await p9.text({
2382
5101
  message: "Solution name:",
2383
5102
  placeholder: "JWT Authentication",
2384
5103
  validate: (val) => {
@@ -2386,15 +5105,15 @@ async function solutionCaptureCommand(options) {
2386
5105
  return void 0;
2387
5106
  }
2388
5107
  });
2389
- if (p8.isCancel(nameInput)) {
2390
- p8.cancel("Operation cancelled");
5108
+ if (p9.isCancel(nameInput)) {
5109
+ p9.cancel("Operation cancelled");
2391
5110
  process.exit(0);
2392
5111
  }
2393
5112
  name = nameInput;
2394
5113
  }
2395
5114
  let description = options.description;
2396
5115
  if (!description) {
2397
- const descInput = await p8.text({
5116
+ const descInput = await p9.text({
2398
5117
  message: "Solution description:",
2399
5118
  placeholder: "Complete JWT-based authentication with refresh tokens",
2400
5119
  validate: (val) => {
@@ -2403,15 +5122,15 @@ async function solutionCaptureCommand(options) {
2403
5122
  return void 0;
2404
5123
  }
2405
5124
  });
2406
- if (p8.isCancel(descInput)) {
2407
- p8.cancel("Operation cancelled");
5125
+ if (p9.isCancel(descInput)) {
5126
+ p9.cancel("Operation cancelled");
2408
5127
  process.exit(0);
2409
5128
  }
2410
5129
  description = descInput;
2411
5130
  }
2412
5131
  let category = options.category;
2413
5132
  if (!category) {
2414
- const categoryChoice = await p8.select({
5133
+ const categoryChoice = await p9.select({
2415
5134
  message: "Solution category:",
2416
5135
  options: [
2417
5136
  { value: "auth", label: "\u{1F510} Authentication" },
@@ -2430,8 +5149,8 @@ async function solutionCaptureCommand(options) {
2430
5149
  { value: "other", label: "\u{1F4E6} Other" }
2431
5150
  ]
2432
5151
  });
2433
- if (p8.isCancel(categoryChoice)) {
2434
- p8.cancel("Operation cancelled");
5152
+ if (p9.isCancel(categoryChoice)) {
5153
+ p9.cancel("Operation cancelled");
2435
5154
  process.exit(0);
2436
5155
  }
2437
5156
  category = categoryChoice;
@@ -2440,20 +5159,20 @@ async function solutionCaptureCommand(options) {
2440
5159
  if (options.keywords) {
2441
5160
  keywords = options.keywords.split(",").map((k) => k.trim());
2442
5161
  } else {
2443
- const keywordsInput = await p8.text({
5162
+ const keywordsInput = await p9.text({
2444
5163
  message: "Keywords (comma-separated):",
2445
5164
  placeholder: "jwt, authentication, login, refresh-token"
2446
5165
  });
2447
- if (p8.isCancel(keywordsInput)) {
2448
- p8.cancel("Operation cancelled");
5166
+ if (p9.isCancel(keywordsInput)) {
5167
+ p9.cancel("Operation cancelled");
2449
5168
  process.exit(0);
2450
5169
  }
2451
5170
  if (keywordsInput) {
2452
5171
  keywords = keywordsInput.split(",").map((k) => k.trim());
2453
5172
  }
2454
5173
  }
2455
- const spinner6 = p8.spinner();
2456
- spinner6.start("Analyzing solution...");
5174
+ const spinner7 = p9.spinner();
5175
+ spinner7.start("Analyzing solution...");
2457
5176
  const analyzer = new CodeAnalyzer({
2458
5177
  anonymize: options.anonymize ?? false
2459
5178
  });
@@ -2465,34 +5184,38 @@ async function solutionCaptureCommand(options) {
2465
5184
  category,
2466
5185
  keywords
2467
5186
  );
2468
- spinner6.stop("Solution analyzed");
2469
- console.log(chalk12.green("\n\u2713 Solution captured successfully!\n"));
2470
- console.log(chalk12.dim("\u2500".repeat(50)));
2471
- console.log(`${chalk12.bold("Name:")} ${pattern.name}`);
2472
- console.log(`${chalk12.bold("Category:")} ${formatCategory(pattern.category)}`);
2473
- console.log(`${chalk12.bold("Files:")} ${pattern.implementation.files.length}`);
5187
+ spinner7.stop("Solution analyzed");
5188
+ console.log(chalk13.green("\n\u2713 Solution captured successfully!\n"));
5189
+ console.log(chalk13.dim("\u2500".repeat(50)));
5190
+ console.log(`${chalk13.bold("Name:")} ${pattern.name}`);
5191
+ console.log(
5192
+ `${chalk13.bold("Category:")} ${formatCategory(pattern.category)}`
5193
+ );
5194
+ console.log(
5195
+ `${chalk13.bold("Files:")} ${pattern.implementation.files.length}`
5196
+ );
2474
5197
  console.log(
2475
- `${chalk12.bold("Dependencies:")} ${pattern.implementation.dependencies.length}`
5198
+ `${chalk13.bold("Dependencies:")} ${pattern.implementation.dependencies.length}`
2476
5199
  );
2477
5200
  console.log(
2478
- `${chalk12.bold("Framework:")} ${pattern.compatibility.framework || "generic"}`
5201
+ `${chalk13.bold("Framework:")} ${pattern.compatibility.framework || "generic"}`
2479
5202
  );
2480
- console.log(chalk12.dim("\u2500".repeat(50)));
2481
- const confirm8 = await p8.confirm({
5203
+ console.log(chalk13.dim("\u2500".repeat(50)));
5204
+ const confirm8 = await p9.confirm({
2482
5205
  message: "Save this solution pattern?",
2483
5206
  initialValue: true
2484
5207
  });
2485
- if (p8.isCancel(confirm8) || !confirm8) {
2486
- p8.cancel("Solution not saved");
5208
+ if (p9.isCancel(confirm8) || !confirm8) {
5209
+ p9.cancel("Solution not saved");
2487
5210
  process.exit(0);
2488
5211
  }
2489
5212
  await store.saveSolution(pattern);
2490
- console.log(chalk12.green(`
5213
+ console.log(chalk13.green(`
2491
5214
  \u2713 Solution saved with ID: ${pattern.id}
2492
5215
  `));
2493
5216
  } catch (error) {
2494
- spinner6.stop("Analysis failed");
2495
- console.error(chalk12.red(`
5217
+ spinner7.stop("Analysis failed");
5218
+ console.error(chalk13.red(`
2496
5219
  \u2717 Error: ${error.message}
2497
5220
  `));
2498
5221
  process.exit(1);
@@ -2501,7 +5224,7 @@ async function solutionCaptureCommand(options) {
2501
5224
  async function solutionSearchCommand(query, options) {
2502
5225
  const cwd = getWorkspacePath2();
2503
5226
  const store = new PatternStore3(cwd);
2504
- console.log(chalk12.cyan("\n\u{1F50D} Search Solution Patterns\n"));
5227
+ console.log(chalk13.cyan("\n\u{1F50D} Search Solution Patterns\n"));
2505
5228
  const keywords = query.split(/\s+/).filter((k) => k.length > 0);
2506
5229
  const result = await store.searchSolutions(keywords, {
2507
5230
  category: options.category,
@@ -2509,37 +5232,39 @@ async function solutionSearchCommand(query, options) {
2509
5232
  limit: options.limit ?? 10
2510
5233
  });
2511
5234
  if (!result.success || !result.data) {
2512
- console.error(chalk12.red(`
5235
+ console.error(chalk13.red(`
2513
5236
  \u2717 Search failed: ${result.error}
2514
5237
  `));
2515
5238
  return;
2516
5239
  }
2517
5240
  const solutions = result.data;
2518
5241
  if (solutions.length === 0) {
2519
- console.log(chalk12.yellow("No solutions found matching your query.\n"));
2520
- console.log(chalk12.dim("Try different keywords or fewer filters."));
5242
+ console.log(chalk13.yellow("No solutions found matching your query.\n"));
5243
+ console.log(chalk13.dim("Try different keywords or fewer filters."));
2521
5244
  return;
2522
5245
  }
2523
- console.log(chalk12.green(`Found ${solutions.length} solution(s):
5246
+ console.log(chalk13.green(`Found ${solutions.length} solution(s):
2524
5247
  `));
2525
- console.log(chalk12.dim("\u2500".repeat(70)));
5248
+ console.log(chalk13.dim("\u2500".repeat(70)));
2526
5249
  for (const solution of solutions) {
2527
5250
  console.log(
2528
- `${chalk12.bold(solution.name)} ${chalk12.dim(`(${solution.id.slice(0, 8)})`)}`
5251
+ `${chalk13.bold(solution.name)} ${chalk13.dim(`(${solution.id.slice(0, 8)})`)}`
2529
5252
  );
2530
5253
  console.log(` ${formatCategory(solution.category)}`);
2531
- console.log(` ${chalk12.dim(truncate(solution.description, 60))}`);
5254
+ console.log(` ${chalk13.dim(truncate(solution.description, 60))}`);
2532
5255
  console.log(
2533
5256
  ` Files: ${solution.implementation.files.length} | Framework: ${solution.compatibility.framework || "generic"} | Uses: ${solution.metrics.applications}`
2534
5257
  );
2535
- console.log(chalk12.dim("\u2500".repeat(70)));
5258
+ console.log(chalk13.dim("\u2500".repeat(70)));
2536
5259
  }
2537
- console.log(chalk12.dim("\nUse 'workflow solution:apply <id>' to apply a solution."));
5260
+ console.log(
5261
+ chalk13.dim("\nUse 'workflow solution:apply <id>' to apply a solution.")
5262
+ );
2538
5263
  }
2539
5264
  async function solutionListCommand(options) {
2540
5265
  const cwd = getWorkspacePath2();
2541
5266
  const store = new PatternStore3(cwd);
2542
- console.log(chalk12.cyan("\n\u{1F4CB} Solution Patterns\n"));
5267
+ console.log(chalk13.cyan("\n\u{1F4CB} Solution Patterns\n"));
2543
5268
  const result = await store.listSolutions({
2544
5269
  category: options.category,
2545
5270
  framework: options.framework,
@@ -2547,18 +5272,20 @@ async function solutionListCommand(options) {
2547
5272
  limit: options.limit ?? 20
2548
5273
  });
2549
5274
  if (!result.success || !result.data) {
2550
- console.error(chalk12.red(`
5275
+ console.error(chalk13.red(`
2551
5276
  \u2717 List failed: ${result.error}
2552
5277
  `));
2553
5278
  return;
2554
5279
  }
2555
5280
  const solutions = result.data;
2556
5281
  if (solutions.length === 0) {
2557
- console.log(chalk12.yellow("No solutions found.\n"));
2558
- console.log(chalk12.dim("Use 'workflow solution:capture' to capture a solution."));
5282
+ console.log(chalk13.yellow("No solutions found.\n"));
5283
+ console.log(
5284
+ chalk13.dim("Use 'workflow solution:capture' to capture a solution.")
5285
+ );
2559
5286
  return;
2560
5287
  }
2561
- console.log(chalk12.green(`${solutions.length} solution(s):
5288
+ console.log(chalk13.green(`${solutions.length} solution(s):
2562
5289
  `));
2563
5290
  const byCategory = /* @__PURE__ */ new Map();
2564
5291
  for (const solution of solutions) {
@@ -2567,33 +5294,35 @@ async function solutionListCommand(options) {
2567
5294
  byCategory.set(solution.category, list);
2568
5295
  }
2569
5296
  for (const [category, items] of byCategory) {
2570
- console.log(chalk12.bold(`
5297
+ console.log(chalk13.bold(`
2571
5298
  ${formatCategory(category)}`));
2572
- console.log(chalk12.dim("\u2500".repeat(50)));
5299
+ console.log(chalk13.dim("\u2500".repeat(50)));
2573
5300
  for (const solution of items) {
2574
- const deprecated = solution.deprecatedAt ? chalk12.red(" [DEPRECATED]") : "";
5301
+ const deprecated = solution.deprecatedAt ? chalk13.red(" [DEPRECATED]") : "";
2575
5302
  console.log(
2576
- ` ${chalk12.cyan(solution.id.slice(0, 8))} ${solution.name}${deprecated}`
5303
+ ` ${chalk13.cyan(solution.id.slice(0, 8))} ${solution.name}${deprecated}`
2577
5304
  );
2578
- console.log(` ${chalk12.dim(truncate(solution.description, 50))}`);
5305
+ console.log(` ${chalk13.dim(truncate(solution.description, 50))}`);
2579
5306
  console.log(
2580
- chalk12.dim(
5307
+ chalk13.dim(
2581
5308
  ` Created: ${formatDate2(solution.createdAt)} | Files: ${solution.implementation.files.length}`
2582
5309
  )
2583
5310
  );
2584
5311
  }
2585
5312
  }
2586
5313
  console.log(
2587
- chalk12.dim("\nUse 'workflow solution:search <query>' to find specific solutions.")
5314
+ chalk13.dim(
5315
+ "\nUse 'workflow solution:search <query>' to find specific solutions."
5316
+ )
2588
5317
  );
2589
5318
  }
2590
5319
  async function solutionApplyCommand(solutionId, options) {
2591
5320
  const cwd = getWorkspacePath2();
2592
5321
  const store = new PatternStore3(cwd);
2593
- console.log(chalk12.cyan("\n\u{1F680} Apply Solution Pattern\n"));
5322
+ console.log(chalk13.cyan("\n\u{1F680} Apply Solution Pattern\n"));
2594
5323
  const result = await store.getSolution(solutionId);
2595
5324
  if (!result.success || !result.data) {
2596
- console.error(chalk12.red(`
5325
+ console.error(chalk13.red(`
2597
5326
  \u2717 Solution not found: ${solutionId}
2598
5327
  `));
2599
5328
  process.exit(1);
@@ -2601,58 +5330,60 @@ async function solutionApplyCommand(solutionId, options) {
2601
5330
  const solution = result.data;
2602
5331
  if (solution.deprecatedAt) {
2603
5332
  console.log(
2604
- chalk12.yellow(
5333
+ chalk13.yellow(
2605
5334
  `\u26A0\uFE0F This solution is deprecated: ${solution.deprecationReason || "No reason provided"}
2606
5335
  `
2607
5336
  )
2608
5337
  );
2609
- const proceed = await p8.confirm({
5338
+ const proceed = await p9.confirm({
2610
5339
  message: "Do you want to continue?",
2611
5340
  initialValue: false
2612
5341
  });
2613
- if (p8.isCancel(proceed) || !proceed) {
2614
- p8.cancel("Operation cancelled");
5342
+ if (p9.isCancel(proceed) || !proceed) {
5343
+ p9.cancel("Operation cancelled");
2615
5344
  process.exit(0);
2616
5345
  }
2617
5346
  }
2618
- console.log(chalk12.bold(`Solution: ${solution.name}`));
2619
- console.log(chalk12.dim(solution.description));
5347
+ console.log(chalk13.bold(`Solution: ${solution.name}`));
5348
+ console.log(chalk13.dim(solution.description));
2620
5349
  console.log();
2621
- console.log(chalk12.bold("Files to create:"));
2622
- const filesToApply = options.includeTests ? solution.implementation.files : solution.implementation.files.filter((f) => f.role !== "test");
5350
+ console.log(chalk13.bold("Files to create:"));
5351
+ const filesToApply = options.includeTests ? solution.implementation.files : solution.implementation.files.filter(
5352
+ (f) => f.role !== "test"
5353
+ );
2623
5354
  for (const file of filesToApply) {
2624
- console.log(chalk12.dim(` \u2022 ${file.path} (${file.role})`));
5355
+ console.log(chalk13.dim(` \u2022 ${file.path} (${file.role})`));
2625
5356
  }
2626
5357
  console.log();
2627
5358
  if (solution.implementation.dependencies.length > 0) {
2628
- console.log(chalk12.bold("Dependencies to install:"));
5359
+ console.log(chalk13.bold("Dependencies to install:"));
2629
5360
  for (const dep of solution.implementation.dependencies) {
2630
- console.log(chalk12.dim(` \u2022 ${dep.name}@${dep.version}`));
5361
+ console.log(chalk13.dim(` \u2022 ${dep.name}@${dep.version}`));
2631
5362
  }
2632
5363
  console.log();
2633
5364
  }
2634
5365
  if (solution.implementation.envVars.length > 0) {
2635
- console.log(chalk12.bold("Environment variables needed:"));
5366
+ console.log(chalk13.bold("Environment variables needed:"));
2636
5367
  for (const env of solution.implementation.envVars) {
2637
- const required = env.required ? chalk12.red("*") : "";
2638
- console.log(chalk12.dim(` \u2022 ${env.name}${required}`));
5368
+ const required = env.required ? chalk13.red("*") : "";
5369
+ console.log(chalk13.dim(` \u2022 ${env.name}${required}`));
2639
5370
  }
2640
5371
  console.log();
2641
5372
  }
2642
5373
  if (options.dryRun) {
2643
- console.log(chalk12.yellow("Dry run mode - no files were created.\n"));
5374
+ console.log(chalk13.yellow("Dry run mode - no files were created.\n"));
2644
5375
  return;
2645
5376
  }
2646
- const confirm8 = await p8.confirm({
5377
+ const confirm8 = await p9.confirm({
2647
5378
  message: "Apply this solution?",
2648
5379
  initialValue: true
2649
5380
  });
2650
- if (p8.isCancel(confirm8) || !confirm8) {
2651
- p8.cancel("Operation cancelled");
5381
+ if (p9.isCancel(confirm8) || !confirm8) {
5382
+ p9.cancel("Operation cancelled");
2652
5383
  process.exit(0);
2653
5384
  }
2654
- const spinner6 = p8.spinner();
2655
- spinner6.start("Applying solution...");
5385
+ const spinner7 = p9.spinner();
5386
+ spinner7.start("Applying solution...");
2656
5387
  try {
2657
5388
  const outputDir = options.output || cwd;
2658
5389
  const fs2 = await import("fs");
@@ -2664,22 +5395,20 @@ async function solutionApplyCommand(solutionId, options) {
2664
5395
  await fs2.promises.writeFile(filePath, file.content);
2665
5396
  }
2666
5397
  await store.updateSolutionMetrics(solution.id, true);
2667
- spinner6.stop("Solution applied");
2668
- console.log(chalk12.green(`
5398
+ spinner7.stop("Solution applied");
5399
+ console.log(chalk13.green(`
2669
5400
  \u2713 Solution applied successfully!
2670
5401
  `));
2671
- console.log(chalk12.dim(`Created ${filesToApply.length} file(s).`));
5402
+ console.log(chalk13.dim(`Created ${filesToApply.length} file(s).`));
2672
5403
  if (solution.implementation.dependencies.length > 0) {
2673
- console.log(
2674
- chalk12.cyan("\nNext step: Install dependencies with:")
2675
- );
5404
+ console.log(chalk13.cyan("\nNext step: Install dependencies with:"));
2676
5405
  const deps = solution.implementation.dependencies.map((d) => `${d.name}@${d.version}`).join(" ");
2677
- console.log(chalk12.dim(` npm install ${deps}`));
5406
+ console.log(chalk13.dim(` npm install ${deps}`));
2678
5407
  }
2679
5408
  } catch (error) {
2680
- spinner6.stop("Application failed");
5409
+ spinner7.stop("Application failed");
2681
5410
  await store.updateSolutionMetrics(solution.id, false);
2682
- console.error(chalk12.red(`
5411
+ console.error(chalk13.red(`
2683
5412
  \u2717 Error: ${error.message}
2684
5413
  `));
2685
5414
  process.exit(1);
@@ -2688,48 +5417,48 @@ async function solutionApplyCommand(solutionId, options) {
2688
5417
  async function solutionDeprecateCommand(solutionId, reason) {
2689
5418
  const cwd = getWorkspacePath2();
2690
5419
  const store = new PatternStore3(cwd);
2691
- console.log(chalk12.cyan("\n\u26A0\uFE0F Deprecate Solution Pattern\n"));
5420
+ console.log(chalk13.cyan("\n\u26A0\uFE0F Deprecate Solution Pattern\n"));
2692
5421
  const result = await store.getSolution(solutionId);
2693
5422
  if (!result.success || !result.data) {
2694
- console.error(chalk12.red(`
5423
+ console.error(chalk13.red(`
2695
5424
  \u2717 Solution not found: ${solutionId}
2696
5425
  `));
2697
5426
  process.exit(1);
2698
5427
  }
2699
5428
  const solution = result.data;
2700
- console.log(`Solution: ${chalk12.bold(solution.name)}`);
5429
+ console.log(`Solution: ${chalk13.bold(solution.name)}`);
2701
5430
  console.log(`Reason: ${reason}
2702
5431
  `);
2703
- const confirm8 = await p8.confirm({
5432
+ const confirm8 = await p9.confirm({
2704
5433
  message: "Deprecate this solution?",
2705
5434
  initialValue: false
2706
5435
  });
2707
- if (p8.isCancel(confirm8) || !confirm8) {
2708
- p8.cancel("Operation cancelled");
5436
+ if (p9.isCancel(confirm8) || !confirm8) {
5437
+ p9.cancel("Operation cancelled");
2709
5438
  process.exit(0);
2710
5439
  }
2711
5440
  await store.deprecateSolution(solutionId, reason);
2712
- console.log(chalk12.green(`
5441
+ console.log(chalk13.green(`
2713
5442
  \u2713 Solution deprecated.
2714
5443
  `));
2715
5444
  }
2716
5445
  async function solutionStatsCommand() {
2717
5446
  const cwd = getWorkspacePath2();
2718
5447
  const store = new PatternStore3(cwd);
2719
- console.log(chalk12.cyan("\n\u{1F4CA} Solution Pattern Statistics\n"));
5448
+ console.log(chalk13.cyan("\n\u{1F4CA} Solution Pattern Statistics\n"));
2720
5449
  const stats = await store.getStats();
2721
- console.log(chalk12.dim("\u2500".repeat(40)));
2722
- console.log(`${chalk12.bold("Solutions:")} ${stats.totalSolutions}`);
5450
+ console.log(chalk13.dim("\u2500".repeat(40)));
5451
+ console.log(`${chalk13.bold("Solutions:")} ${stats.totalSolutions}`);
2723
5452
  console.log(` Active: ${stats.totalSolutions - stats.deprecatedSolutions}`);
2724
5453
  console.log(` Deprecated: ${stats.deprecatedSolutions}`);
2725
5454
  console.log(` Private: ${stats.privateSolutions}`);
2726
5455
  console.log(` Synced: ${stats.syncedSolutions}`);
2727
- console.log(chalk12.dim("\u2500".repeat(40)));
2728
- console.log(`${chalk12.bold("Fixes:")} ${stats.totalFixes}`);
2729
- console.log(`${chalk12.bold("Blueprints:")} ${stats.totalBlueprints}`);
2730
- console.log(chalk12.dim("\u2500".repeat(40)));
5456
+ console.log(chalk13.dim("\u2500".repeat(40)));
5457
+ console.log(`${chalk13.bold("Fixes:")} ${stats.totalFixes}`);
5458
+ console.log(`${chalk13.bold("Blueprints:")} ${stats.totalBlueprints}`);
5459
+ console.log(chalk13.dim("\u2500".repeat(40)));
2731
5460
  console.log(`
2732
- ${chalk12.bold("By Category:")}`);
5461
+ ${chalk13.bold("By Category:")}`);
2733
5462
  const listResult = await store.listSolutions({ limit: 1e3 });
2734
5463
  if (listResult.success && listResult.data) {
2735
5464
  const categories = /* @__PURE__ */ new Map();
@@ -2773,14 +5502,27 @@ program.command("scope:create").description("Create a custom scope package").opt
2773
5502
  program.command("scope:migrate").description("Migrate inline scopes to a custom package").option("--name <name>", "Package name for the preset").option("--output-dir <dir>", "Output directory").option("--keep-config", "Keep inline scopes in config after migration").action(scopeMigrateCommand);
2774
5503
  program.command("verify").description("Run all quality checks with fix-and-revalidate pattern").option("--fix", "Enable auto-fix for lint and format issues").option("--max-retries <n>", "Maximum retry cycles (default: 10)", "10").option("--commit", "Commit changes if all checks pass").option("--dry-run", "Preview fixes without applying them").option("--learn", "Record successful fixes as learning patterns").action(verifyCommand);
2775
5504
  program.command("auto-setup").description("Automatically configure linting, formatting, testing, and CI").option("-y, --yes", "Auto-approve all prompts").option("--audit", "Show audit report without applying changes").action(autoSetupCommand);
2776
- program.command("learn:record").description("Record a new pattern from a successful implementation").option("--name <name>", "Pattern name").option("--description <desc>", "Pattern description").option("--category <cat>", "Category (migration, security, performance, etc.)").option("--framework <fw>", "Framework (next, react, vue, etc.)").option("--version <ver>", "Framework version range").option("--tags <tags>", "Comma-separated tags (category:value)").option("--type <type>", "Pattern type (fix, blueprint)").action(learnRecordCommand);
5505
+ program.command("advisory").description("Generate advisory board analysis and documentation").option(
5506
+ "--depth <level>",
5507
+ "Analysis depth: executive, quick, standard, comprehensive"
5508
+ ).option("--output <path>", "Output directory (default: docs/advisory)").option("--interactive", "Enable interactive mode").option("--dry-run", "Preview analysis without writing files").option(
5509
+ "--format <type>",
5510
+ "Output format: markdown, json (default: markdown)"
5511
+ ).option("--timestamp", "Append timestamp to filenames").option("--include-health", "Include code health metrics from verify/doctor").option("--ci", "CI mode with exit codes on high-risk findings").option("--compare <path>", "Compare with previous report").action(advisoryCommand);
5512
+ program.command("learn:record").description("Record a new pattern from a successful implementation").option("--name <name>", "Pattern name").option("--description <desc>", "Pattern description").option(
5513
+ "--category <cat>",
5514
+ "Category (migration, security, performance, etc.)"
5515
+ ).option("--framework <fw>", "Framework (next, react, vue, etc.)").option("--version <ver>", "Framework version range").option("--tags <tags>", "Comma-separated tags (category:value)").option("--type <type>", "Pattern type (fix, blueprint)").action(learnRecordCommand);
2777
5516
  program.command("learn:list").description("List recorded learning patterns").option("--type <type>", "Filter by type (fix, blueprint, all)").option("--framework <fw>", "Filter by framework").option("--tag <tag>", "Filter by tag").option("--deprecated", "Include deprecated patterns").action(learnListCommand);
2778
5517
  program.command("learn:apply <patternId>").description("Apply a pattern to the current project").argument("<patternId>", "Pattern ID to apply").option("--framework <fw>", "Override framework").option("--version <ver>", "Override version").option("--dry-run", "Preview without applying").action(learnApplyCommand);
2779
5518
  program.command("learn:sync").description("Sync patterns with remote registry").option("--push", "Push local patterns to registry").option("--pull", "Pull patterns from registry").option("--dry-run", "Preview without syncing").action(learnSyncCommand);
2780
5519
  program.command("learn:config").description("Configure learning settings").option("--enable-sync", "Enable pattern sync").option("--disable-sync", "Disable pattern sync").option("--enable-telemetry", "Enable anonymous telemetry").option("--disable-telemetry", "Disable telemetry").option("--reset-id", "Reset contributor ID").option("--show", "Show current configuration").action(learnConfigCommand);
2781
5520
  program.command("learn:deprecate <patternId> <reason>").description("Deprecate an outdated pattern").argument("<patternId>", "Pattern ID to deprecate").argument("<reason>", "Reason for deprecation").action(learnDeprecateCommand);
2782
5521
  program.command("learn:stats").description("Show learning statistics").action(learnStatsCommand);
2783
- program.command("solution:capture").description("Capture a solution pattern from working code").option("--name <name>", "Solution name").option("--description <desc>", "Solution description").option("--category <cat>", "Category (auth, api, database, ui, testing, deployment, integration, performance, security, other)").option("--keywords <kw>", "Comma-separated keywords").option("--path <path>", "Path to the solution directory").option("--anonymize", "Anonymize sensitive data in code").action(solutionCaptureCommand);
5522
+ program.command("solution:capture").description("Capture a solution pattern from working code").option("--name <name>", "Solution name").option("--description <desc>", "Solution description").option(
5523
+ "--category <cat>",
5524
+ "Category (auth, api, database, ui, testing, deployment, integration, performance, security, other)"
5525
+ ).option("--keywords <kw>", "Comma-separated keywords").option("--path <path>", "Path to the solution directory").option("--anonymize", "Anonymize sensitive data in code").action(solutionCaptureCommand);
2784
5526
  program.command("solution:search <query>").description("Search for solution patterns").argument("<query>", "Search query (keywords, problem description)").option("--category <cat>", "Filter by category").option("--framework <fw>", "Filter by framework").option("--limit <n>", "Maximum results", "10").action(solutionSearchCommand);
2785
5527
  program.command("solution:list").description("List all solution patterns").option("--category <cat>", "Filter by category").option("--framework <fw>", "Filter by framework").option("--deprecated", "Include deprecated solutions").option("--limit <n>", "Maximum results", "20").action(solutionListCommand);
2786
5528
  program.command("solution:apply <solutionId>").description("Apply a solution pattern to the current project").argument("<solutionId>", "Solution ID to apply").option("--output <dir>", "Output directory").option("--dry-run", "Preview without applying").option("--include-tests", "Include test files").action(solutionApplyCommand);