@nikelyh/metamorph 2.1.1 → 2.1.2

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/index.js CHANGED
@@ -12,14 +12,17 @@ import {
12
12
  createRenameFileTool,
13
13
  createRunBuildTool,
14
14
  createWriteFileTool
15
- } from "./chunk-L7B6KUCW.js";
15
+ } from "./chunk-APRESSUR.js";
16
16
  import {
17
17
  formatCatalogRules,
18
- resolveMigrationCatalog
19
- } from "./chunk-VEAYUIOZ.js";
18
+ resolveMigrationCatalog,
19
+ resolvePackageManagerCommands
20
+ } from "./chunk-WLHSZWET.js";
20
21
  import {
21
- detectTechnologies
22
- } from "./chunk-3QN2Q75J.js";
22
+ detectMonorepo,
23
+ inspectManifest,
24
+ inspectProject
25
+ } from "./chunk-XLD7NXYU.js";
23
26
  import {
24
27
  MetamorphState,
25
28
  initializeRuntime,
@@ -381,7 +384,7 @@ async function startWorkerLoop(planId, filePath, prompt, participant) {
381
384
  const shadowRoot = findShadowRoot2(filePath);
382
385
  let workerTools = participant.getTools();
383
386
  if (shadowRoot) {
384
- const { createShadowTools } = await import("./src-JHOGUCRS.js");
387
+ const { createShadowTools } = await import("./src-Q3DGKZEQ.js");
385
388
  workerTools = createShadowTools(shadowRoot);
386
389
  }
387
390
  const tempAgent = createMozaikAgent({
@@ -1216,7 +1219,7 @@ var managePackagesProcessor = {
1216
1219
  type: "system.log" /* SYSTEM_LOG */,
1217
1220
  producerId: participant.getId(),
1218
1221
  occurredAt: /* @__PURE__ */ new Date(),
1219
- payload: { planId: payload.planId, message: "PackageManager updated package.json. IntegrationAgent will run npm install in the shadow workspace \u2014 the original project is untouched until you Apply.", level: "info" }
1222
+ payload: { planId: payload.planId, message: "Dependencies updated in package.json: target framework libraries and build scripts configured.", level: "info" }
1220
1223
  }, participant.getId());
1221
1224
  } catch (err) {
1222
1225
  console.error(`[PackageManagerAgent] Error editing package.json:`, err);
@@ -1317,7 +1320,7 @@ var startWatchdogProcessor = {
1317
1320
  occurredAt: /* @__PURE__ */ new Date(),
1318
1321
  payload: {
1319
1322
  planId: p.planId,
1320
- message: "Coordinator watchdog is on: if file work settles and Integration never starts, it will kick within 8s. No extra model calls.",
1323
+ message: "Swarm coordinator active: orchestrating agent tasks and monitoring workflow progress.",
1321
1324
  level: "info"
1322
1325
  }
1323
1326
  }, producerId);
@@ -1336,7 +1339,7 @@ var startWatchdogProcessor = {
1336
1339
  occurredAt: /* @__PURE__ */ new Date(),
1337
1340
  payload: {
1338
1341
  planId: p.planId,
1339
- message: "Coordinator watchdog timed out after 30 minutes. Integration never became ready or the run stalled.",
1342
+ message: "Migration session timed out after 30 minutes: task completion could not be verified.",
1340
1343
  level: "error"
1341
1344
  }
1342
1345
  }, producerId);
@@ -1395,7 +1398,7 @@ function log(participantId, planId, message, level = "info") {
1395
1398
  }
1396
1399
  async function shadowPathFor(plan, journal) {
1397
1400
  if (journal?.shadowPath) return journal.shadowPath;
1398
- const { ShadowWorkspace: ShadowWorkspace2 } = await import("./src-JHOGUCRS.js");
1401
+ const { ShadowWorkspace: ShadowWorkspace2 } = await import("./src-Q3DGKZEQ.js");
1399
1402
  return new ShadowWorkspace2().getShadowPath(plan.runId);
1400
1403
  }
1401
1404
  function fallbackReport(params) {
@@ -1404,10 +1407,15 @@ function fallbackReport(params) {
1404
1407
  const rejected = params.notes.filter((n) => n.outcome === "rejected" || n.outcome === "fatal");
1405
1408
  const fileLines = params.tasks.filter((t) => !t.filePath.startsWith("system:")).slice(0, 40).map((t) => `- \`${t.filePath}\` \u2014 ${t.status}${t.error ? ` (${t.error})` : ""}`).join("\n");
1406
1409
  const riskLines = rejected.slice(0, 12).map((n) => `- \`${n.filePath}\`: ${n.detail || n.outcome}`).join("\n");
1410
+ const pm = params.packageManager || "npm";
1411
+ const devCmd = pm === "yarn" ? "yarn dev" : `${pm} run dev`;
1412
+ const buildCmd = pm === "yarn" ? "yarn build" : `${pm} run build`;
1407
1413
  return `# What changed
1408
1414
 
1409
1415
  Metamorph migrated this project from **${params.source}** to **${params.target}**.
1410
- ${params.phase === "failed" ? "\n**Status:** shadow `npm run build` (or catalog checks) did not pass. Treat this as an incomplete migration.\n" : ""}
1416
+ ${params.phase === "failed" ? `
1417
+ **Status:** shadow \`${buildCmd}\` (or catalog checks) did not pass. Treat this as an incomplete migration.
1418
+ ` : ""}
1411
1419
  Your original files were not overwritten until you click **Apply Migration**. After apply, the result lives on a git branch named like \`metamorph/${params.runId}\`.
1412
1420
 
1413
1421
  ## How to run it
@@ -1415,8 +1423,8 @@ Your original files were not overwritten until you click **Apply Migration**. Af
1415
1423
  1. Apply the migration in the dashboard (or keep working in the shadow workspace).
1416
1424
  2. From the project folder:
1417
1425
  \`\`\`bash
1418
- npm install
1419
- npm run dev
1426
+ ${pm} install
1427
+ ${devCmd}
1420
1428
  \`\`\`
1421
1429
  3. Open the URL the framework prints (\`next dev\` \u2192 port 3000, Vite \u2192 5173).
1422
1430
 
@@ -1548,6 +1556,8 @@ var fatalProcessor = {
1548
1556
  };
1549
1557
  function draftPrompt(params) {
1550
1558
  const notable = params.notes.filter((n) => n.outcome === "rejected" || n.outcome === "fatal").slice(-15).map((n) => `${n.filePath}: ${n.detail || n.outcome}`).join("\n");
1559
+ const pm = params.plan.packageManager || "npm";
1560
+ const devCmd = pm === "yarn" ? "yarn dev" : `${pm} run dev`;
1551
1561
  return `Write a user-facing migration briefing to this exact path:
1552
1562
  ${params.reportAbs}
1553
1563
 
@@ -1560,10 +1570,10 @@ Run id: ${params.plan.runId}
1560
1570
 
1561
1571
  Include these sections, in this order, with markdown headings:
1562
1572
  1. What changed \u2014 1-2 short paragraphs in plain language
1563
- 2. How to run it \u2014 concrete commands (npm install, npm run dev, which port if you can infer from package.json)
1573
+ 2. How to run it \u2014 concrete commands (${pm} install, ${devCmd}, which port if you can infer from package.json)
1564
1574
  3. What we touched \u2014 group by area (routes, styles, config, dependencies). Do not dump every file as a checklist unless there are under 12 files.
1565
1575
  4. Watch out for \u2014 honest risks from the notes below and from reading package.json / the new entry files
1566
- 5. Next steps after Apply \u2014 git branch checkout if they applied, npm install on the real project
1576
+ 5. Next steps after Apply \u2014 git branch checkout if they applied, ${pm} install on the real project
1567
1577
 
1568
1578
  You may read package.json, README, src/app/layout.tsx, src/main.tsx, index.html, or MIGRATION.md if they exist.
1569
1579
 
@@ -1596,7 +1606,8 @@ var draftDuringInstallProcessor = {
1596
1606
  phase: plan.phase,
1597
1607
  tasks: plan.tasks || [],
1598
1608
  notes: board.notes,
1599
- startedAt: board.startedAt
1609
+ startedAt: board.startedAt,
1610
+ packageManager: plan.packageManager
1600
1611
  });
1601
1612
  const tools = participant.getTools();
1602
1613
  if (tools.length === 0) {
@@ -1677,14 +1688,15 @@ var completedProcessor = {
1677
1688
  phase: effectivePhase,
1678
1689
  tasks: plan.tasks || [],
1679
1690
  notes: board.notes,
1680
- startedAt: board.startedAt
1691
+ startedAt: board.startedAt,
1692
+ packageManager: plan.packageManager
1681
1693
  });
1682
1694
  board.pendingStatusPhase = isFailed ? "failed" : "completed";
1683
1695
  try {
1684
1696
  const path12 = await import("path");
1685
1697
  const dest = path12.join(shadowPath, "MIGRATION.md");
1686
1698
  if (board.reportLoopActive) {
1687
- log(participant.getId(), p.planId, "Reporter draft is still running; Status will be patched when it finishes (no second model call).");
1699
+ log(participant.getId(), p.planId, "Compiling comprehensive migration briefing in the background...");
1688
1700
  return;
1689
1701
  }
1690
1702
  const result = await writeOrPatchMigrationMd(dest, effectivePhase, draft);
@@ -1692,11 +1704,11 @@ var completedProcessor = {
1692
1704
  log(
1693
1705
  participant.getId(),
1694
1706
  p.planId,
1695
- result === "patched" ? "Reporter patched MIGRATION.md with the final build Status (no extra model call)." : "Reporter finished. Open MIGRATION.md in the shadow workspace (it is copied to your project when you Apply)."
1707
+ result === "patched" ? "Updated MIGRATION.md with final build verification status." : "Migration report ready in MIGRATION.md: review changes and run Apply to merge into your project."
1696
1708
  );
1697
1709
  } catch (error) {
1698
1710
  console.error("[ReporterAgent] Could not ensure MIGRATION.md:", error);
1699
- log(participant.getId(), p.planId, "Reporter could not write MIGRATION.md.", "warning");
1711
+ log(participant.getId(), p.planId, "Could not generate MIGRATION.md report.", "warning");
1700
1712
  }
1701
1713
  }
1702
1714
  };
@@ -1895,23 +1907,24 @@ var integrationProcessor = {
1895
1907
  createRunBuildTool: createRunBuildTool2,
1896
1908
  runInShadowWorkspace,
1897
1909
  parseImplicatedFiles
1898
- } = await import("./src-JHOGUCRS.js");
1910
+ } = await import("./src-Q3DGKZEQ.js");
1899
1911
  const { collectShadowIssues, collectRepairTargets } = await import("./registry-7WZ5RTGE.js");
1900
- const { resolveMigrationCatalog: resolveMigrationCatalog2 } = await import("./src-UC3SN46X.js");
1912
+ const { resolveMigrationCatalog: resolveMigrationCatalog2 } = await import("./src-YPCIVBLZ.js");
1901
1913
  const shadowPath = payload.shadowWorkspacePath || new ShadowWorkspace2().getShadowPath(plan.runId);
1914
+ const pmCommands = resolvePackageManagerCommands(plan.packageManager);
1902
1915
  console.log(
1903
1916
  `[IntegrationAgent] Shadow build round ${plan.integrationRounds}/${MAX_INTEGRATION_ROUNDS} in ${shadowPath}`
1904
1917
  );
1905
1918
  log2(
1906
1919
  producerId,
1907
1920
  planId,
1908
- `File migration is done. Next: install dependencies in the shadow workspace (npm install). This can take several minutes \u2014 counters staying at 0 is expected.`
1921
+ `Source files transformed. Installing dependencies in shadow workspace with ${pmCommands.cleanInstall}...`
1909
1922
  );
1910
- console.log(`[IntegrationAgent] npm install starting in ${shadowPath}`);
1923
+ console.log(`[IntegrationAgent] ${pmCommands.cleanInstall} starting in ${shadowPath}`);
1911
1924
  let lastInstallBeat = Date.now();
1912
1925
  const install = await runInShadowWorkspace(
1913
1926
  shadowPath,
1914
- "npm install --no-fund --no-audit",
1927
+ pmCommands.cleanInstall,
1915
1928
  (chunk) => {
1916
1929
  process.stdout.write(chunk);
1917
1930
  if (Date.now() - lastInstallBeat >= 15e3) {
@@ -1919,27 +1932,27 @@ var integrationProcessor = {
1919
1932
  log2(
1920
1933
  producerId,
1921
1934
  planId,
1922
- "npm install is still running in the shadow workspace. Wait \u2014 this is not finished."
1935
+ `${pmCommands.cleanInstall} is in progress in the shadow workspace...`
1923
1936
  );
1924
1937
  }
1925
1938
  }
1926
1939
  );
1927
1940
  if (!install.ok) {
1928
1941
  console.warn(
1929
- "[IntegrationAgent] npm install failed in shadow:",
1942
+ `[IntegrationAgent] ${pmCommands.cleanInstall} failed in shadow:`,
1930
1943
  install.output.slice(0, 2e3)
1931
1944
  );
1932
1945
  log2(
1933
1946
  producerId,
1934
1947
  planId,
1935
- "npm install failed in the shadow workspace. Halting build to avoid noisy compile errors.",
1948
+ `${pmCommands.cleanInstall} failed in the shadow workspace. Halting to diagnose dependency conflicts.`,
1936
1949
  "error"
1937
1950
  );
1938
1951
  if (lastRound) {
1939
1952
  await failMigration(
1940
1953
  producerId,
1941
1954
  planId,
1942
- `npm install failed in the shadow workspace after ${MAX_INTEGRATION_ROUNDS} integration rounds. The migration is not successful.`
1955
+ `${pmCommands.cleanInstall} failed in the shadow workspace after ${MAX_INTEGRATION_ROUNDS} integration rounds. The migration could not complete.`
1943
1956
  );
1944
1957
  return;
1945
1958
  }
@@ -1949,7 +1962,7 @@ var integrationProcessor = {
1949
1962
  producerId,
1950
1963
  planId,
1951
1964
  [pkgPath],
1952
- [`npm install failed in shadow workspace:
1965
+ [`${pmCommands.cleanInstall} failed in shadow workspace:
1953
1966
  ${install.output.slice(0, 2500)}`]
1954
1967
  );
1955
1968
  return;
@@ -1957,12 +1970,12 @@ ${install.output.slice(0, 2500)}`]
1957
1970
  log2(
1958
1971
  producerId,
1959
1972
  planId,
1960
- "npm install finished. Next: npm run build in the shadow workspace."
1973
+ `Dependencies installed successfully. Running verification build (${pmCommands.runBuild})...`
1961
1974
  );
1962
1975
  let lastBuildBeat = Date.now();
1963
1976
  let build = await runInShadowWorkspace(
1964
1977
  shadowPath,
1965
- "npm run build",
1978
+ pmCommands.runBuild,
1966
1979
  (chunk) => {
1967
1980
  process.stdout.write(chunk);
1968
1981
  if (Date.now() - lastBuildBeat >= 15e3) {
@@ -1970,7 +1983,7 @@ ${install.output.slice(0, 2500)}`]
1970
1983
  log2(
1971
1984
  producerId,
1972
1985
  planId,
1973
- "npm run build is still running in the shadow workspace. Wait \u2014 this is not finished."
1986
+ `${pmCommands.runBuild} is in progress in the shadow workspace...`
1974
1987
  );
1975
1988
  }
1976
1989
  }
@@ -1979,7 +1992,7 @@ ${install.output.slice(0, 2500)}`]
1979
1992
  log2(
1980
1993
  producerId,
1981
1994
  planId,
1982
- "Shadow build failed. IntegrationAgent will attempt local repairs before requeueing files."
1995
+ "Verification build encountered errors. Analyzing diagnostics for automated repair..."
1983
1996
  );
1984
1997
  const shadowTools = [
1985
1998
  createReadFileTool2(shadowPath),
@@ -2057,7 +2070,7 @@ When you have applied fixes (or cannot fix further), stop. A deterministic rebui
2057
2070
  await completeMigration(
2058
2071
  producerId,
2059
2072
  planId,
2060
- "Shadow build succeeded. Reporter is writing MIGRATION.md next. Then Apply copies the result into your project.",
2073
+ "Verification build succeeded cleanly. Generating final migration report and instructions...",
2061
2074
  "info"
2062
2075
  );
2063
2076
  return;
@@ -2074,16 +2087,16 @@ When you have applied fixes (or cannot fix further), stop. A deterministic rebui
2074
2087
  });
2075
2088
  const errors = [
2076
2089
  ...structureIssues.flatMap((issue) => issue.errors),
2077
- ...install.ok ? [] : [`npm install failed:
2090
+ ...install.ok ? [] : [`${pmCommands.cleanInstall} failed:
2078
2091
  ${install.output.slice(0, 1500)}`],
2079
- ...build.ok ? [] : [`npm run build failed:
2092
+ ...build.ok ? [] : [`${pmCommands.runBuild} failed:
2080
2093
  ${build.output.slice(0, 2500)}`]
2081
2094
  ];
2082
2095
  if (!lastRound && repairFiles.length > 0) {
2083
2096
  log2(
2084
2097
  producerId,
2085
2098
  planId,
2086
- buildFailed ? "npm run build (or npm install) failed. Assigning repair tasks to Worker \u2014 the run is not finished." : `Shadow compile may succeed while the app is still wrong: ${structureIssues.length} verifier issue(s). Assigning repair tasks.`,
2099
+ buildFailed ? `Verification build failed. Reopening implicated files for automated repair...` : `Structure verifier identified ${structureIssues.length} architectural issue(s). Reopening files for repair...`,
2087
2100
  "warning"
2088
2101
  );
2089
2102
  await requeueBrokenFiles(
@@ -2097,7 +2110,7 @@ ${build.output.slice(0, 2500)}`]
2097
2110
  await failMigration(
2098
2111
  producerId,
2099
2112
  planId,
2100
- lastRound ? `npm run build still does not pass after ${MAX_INTEGRATION_ROUNDS} integration rounds. The migration is not successful.` : "Shadow verification failed and no repair files could be assigned."
2113
+ lastRound ? `Verification build did not pass after ${MAX_INTEGRATION_ROUNDS} integration rounds. Please inspect MIGRATION.md for diagnostic details.` : "Shadow verification failed and no repair targets could be assigned."
2101
2114
  );
2102
2115
  } catch (error) {
2103
2116
  console.error(`[IntegrationAgent] Error:`, error);
@@ -2767,11 +2780,14 @@ var MigrationRunner = class {
2767
2780
  const runId = `run_${Date.now()}`;
2768
2781
  const shadowPath = this.workspace.cloneDirectory(request.targetPath, runId);
2769
2782
  const planId = `plan_${randomUUID()}`;
2783
+ const manifest = inspectManifest(request.targetPath);
2784
+ const resolvedPackageManager = request.packageManager || manifest.packageManager || "npm";
2770
2785
  const plan = {
2771
2786
  id: planId,
2772
2787
  runId,
2773
2788
  profile: { source: request.from, target: request.to },
2774
2789
  targetPath: request.targetPath,
2790
+ packageManager: resolvedPackageManager,
2775
2791
  phase: "files",
2776
2792
  tasks: [
2777
2793
  { filePath: "system:package_manager", status: "pending" }
@@ -2791,7 +2807,8 @@ var MigrationRunner = class {
2791
2807
  payload: {
2792
2808
  planId,
2793
2809
  profile: plan.profile,
2794
- shadowWorkspacePath: shadowPath
2810
+ shadowWorkspacePath: shadowPath,
2811
+ packageManager: resolvedPackageManager
2795
2812
  }
2796
2813
  },
2797
2814
  dispatcherId
@@ -2880,7 +2897,7 @@ function logStartupContext() {
2880
2897
  }
2881
2898
  }
2882
2899
  var program = new Command();
2883
- program.name("metamorph").description("AI-powered technology migration tool using Mozaik Agents").version("2.1.1");
2900
+ program.name("metamorph").description("AI-powered technology migration tool using Mozaik Agents").version("2.1.2");
2884
2901
  program.command("run [path]").description("Run a migration on the specified directory").option("--from <source>", "Source framework (e.g. express)").option("--to <target>", "Target framework (e.g. fastify)").action(async (targetPathArg, options) => {
2885
2902
  logStartupContext();
2886
2903
  let targetPath = targetPathArg || ".";
@@ -2897,15 +2914,42 @@ program.command("run [path]").description("Run a migration on the specified dire
2897
2914
  angular: ["react", "next", "vue", "svelte"],
2898
2915
  svelte: ["react", "next", "vue", "angular"]
2899
2916
  };
2917
+ const monorepo = detectMonorepo(targetPath);
2918
+ if (monorepo.isMonorepo && monorepo.packages.length > 0) {
2919
+ console.log(chalk.cyan(`
2920
+ \u{1F4E6} Monorepo detected (${monorepo.tool || "workspaces"} with ${monorepo.packages.length} packages).`));
2921
+ const chosenPath = await select({
2922
+ message: "Select the workspace package you want to migrate:",
2923
+ choices: [
2924
+ ...monorepo.packages.map((p) => ({
2925
+ name: `${p.name} (${p.relativePath})`,
2926
+ value: p.absolutePath
2927
+ })),
2928
+ {
2929
+ name: `Whole root directory (${targetPath})`,
2930
+ value: targetPath
2931
+ }
2932
+ ]
2933
+ });
2934
+ targetPath = chosenPath;
2935
+ }
2900
2936
  if (!from) {
2901
2937
  console.log(chalk.gray(`
2902
2938
  \u{1F50D} Scanning directory: ${targetPath}`));
2903
- const detected = detectTechnologies(targetPath);
2904
- const supportedDetected = detected.filter((d) => Object.keys(SUPPORTED_MIGRATIONS).includes(d.framework));
2905
- if (supportedDetected.length > 0) {
2939
+ const profiles = inspectProject(targetPath);
2940
+ const supportedProfiles = profiles.filter((p) => Object.keys(SUPPORTED_MIGRATIONS).includes(p.framework));
2941
+ if (supportedProfiles.length > 0) {
2906
2942
  from = await select({
2907
2943
  message: "What technology do you want to migrate FROM?",
2908
- choices: supportedDetected.map((d) => ({ name: `${d.framework} (Detected ${d.confidence}%)`, value: d.framework }))
2944
+ choices: supportedProfiles.map((p) => {
2945
+ const details = [
2946
+ p.variant !== "none" ? p.variant : null,
2947
+ p.bundler !== "unknown" ? p.bundler : null,
2948
+ p.language === "typescript" ? "TS" : "JS"
2949
+ ].filter(Boolean).join(" | ");
2950
+ const label = details ? `${p.framework} (${details} - ${p.confidence}%)` : `${p.framework} (${p.confidence}%)`;
2951
+ return { name: label, value: p.framework };
2952
+ })
2909
2953
  });
2910
2954
  } else {
2911
2955
  console.log(chalk.yellow(`No supported technologies detected in the current directory.`));
@@ -3057,16 +3101,35 @@ program.command("reset").description("Clear all migration history and events fro
3057
3101
  process.exit(1);
3058
3102
  }
3059
3103
  });
3060
- program.command("detect [path]").description("Detect frameworks and libraries in a directory").action(async (targetPath) => {
3104
+ program.command("detect [path]").description("Detect frameworks, architectural variants and monorepo structure in a directory").action(async (targetPath) => {
3061
3105
  try {
3062
- const detected = detectTechnologies(targetPath || ".");
3063
- if (detected.length === 0) {
3064
- console.log(chalk.yellow(`No known technologies detected.`));
3106
+ const resolved = targetPath || ".";
3107
+ const monorepo = detectMonorepo(resolved);
3108
+ if (monorepo.isMonorepo) {
3109
+ console.log(chalk.cyan(`
3110
+ \u{1F4E6} Monorepo Detected: ${monorepo.tool || "workspaces"}`));
3111
+ console.log(chalk.gray(`Root: ${monorepo.rootPath}`));
3112
+ console.log(chalk.gray(`Workspace Packages (${monorepo.packages.length}):`));
3113
+ monorepo.packages.forEach((p) => console.log(` \u2022 ${chalk.white(p.name)}: ${chalk.gray(p.relativePath)}`));
3114
+ }
3115
+ const profiles = inspectProject(resolved);
3116
+ if (profiles.length === 0) {
3117
+ console.log(chalk.yellow(`
3118
+ No supported technologies detected.`));
3065
3119
  } else {
3066
3120
  console.log(chalk.blue(`
3067
- \u{1F50D} Detected Technologies:`));
3068
- detected.forEach((d) => console.log(` - ${chalk.green(d.framework)} (Confidence: ${d.confidence}%)
3069
- Evidence: ${chalk.gray(d.evidence.join(", "))}`));
3121
+ \u{1F50D} Detected Technologies & Architecture:`));
3122
+ profiles.forEach((p) => {
3123
+ console.log(`
3124
+ \u2022 ${chalk.bold.green(p.framework)} (Confidence: ${p.confidence}%)`);
3125
+ console.log(` Category: ${chalk.cyan(p.category)} | Variant: ${chalk.cyan(p.variant)} | Bundler: ${chalk.cyan(p.bundler)} | Lang: ${chalk.cyan(p.language.toUpperCase())}`);
3126
+ if (p.subsumedDependencies.length > 0) {
3127
+ console.log(` Subsumed Dependencies: ${chalk.yellow(p.subsumedDependencies.join(", "))}`);
3128
+ }
3129
+ console.log(` Suggested Targets: ${chalk.magenta(p.suggestedTargets.join(", "))}`);
3130
+ console.log(` Evidence: ${chalk.gray(p.evidence.join("; "))}`);
3131
+ });
3132
+ console.log("");
3070
3133
  }
3071
3134
  } catch (error) {
3072
3135
  console.error(chalk.red(`\u274C Detection failed: ${error instanceof Error ? error.message : String(error)}`));