@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/README.md +5 -3
- package/dist/ProjectDetector-WU3OD6WT.js +16 -0
- package/dist/{chunk-L7B6KUCW.js → chunk-APRESSUR.js} +17 -7
- package/dist/{chunk-VEAYUIOZ.js → chunk-WLHSZWET.js} +39 -0
- package/dist/chunk-XLD7NXYU.js +528 -0
- package/dist/index.js +115 -52
- package/dist/public/assets/index-BX5N2qs-.js +63 -0
- package/dist/public/assets/index-C7odDrsP.css +1 -0
- package/dist/public/index.html +2 -2
- package/dist/{src-JHOGUCRS.js → src-Q3DGKZEQ.js} +14 -4
- package/dist/{src-UC3SN46X.js → src-YPCIVBLZ.js} +3 -1
- package/package.json +2 -2
- package/dist/TechDetector-5YP44RVR.js +0 -6
- package/dist/chunk-3QN2Q75J.js +0 -101
- package/dist/public/assets/index-C0AxAuiv.css +0 -1
- package/dist/public/assets/index-DtMWFmXl.js +0 -63
package/dist/index.js
CHANGED
|
@@ -12,14 +12,17 @@ import {
|
|
|
12
12
|
createRenameFileTool,
|
|
13
13
|
createRunBuildTool,
|
|
14
14
|
createWriteFileTool
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-APRESSUR.js";
|
|
16
16
|
import {
|
|
17
17
|
formatCatalogRules,
|
|
18
|
-
resolveMigrationCatalog
|
|
19
|
-
|
|
18
|
+
resolveMigrationCatalog,
|
|
19
|
+
resolvePackageManagerCommands
|
|
20
|
+
} from "./chunk-WLHSZWET.js";
|
|
20
21
|
import {
|
|
21
|
-
|
|
22
|
-
|
|
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-
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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-
|
|
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" ?
|
|
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
|
-
|
|
1419
|
-
|
|
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 (
|
|
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,
|
|
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, "
|
|
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" ? "
|
|
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, "
|
|
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-
|
|
1910
|
+
} = await import("./src-Q3DGKZEQ.js");
|
|
1899
1911
|
const { collectShadowIssues, collectRepairTargets } = await import("./registry-7WZ5RTGE.js");
|
|
1900
|
-
const { resolveMigrationCatalog: resolveMigrationCatalog2 } = await import("./src-
|
|
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
|
-
`
|
|
1921
|
+
`Source files transformed. Installing dependencies in shadow workspace with ${pmCommands.cleanInstall}...`
|
|
1909
1922
|
);
|
|
1910
|
-
console.log(`[IntegrationAgent]
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
[
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
"
|
|
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
|
-
"
|
|
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 ? [] : [
|
|
2090
|
+
...install.ok ? [] : [`${pmCommands.cleanInstall} failed:
|
|
2078
2091
|
${install.output.slice(0, 1500)}`],
|
|
2079
|
-
...build.ok ? [] : [
|
|
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 ?
|
|
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 ? `
|
|
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.
|
|
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
|
|
2904
|
-
const
|
|
2905
|
-
if (
|
|
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:
|
|
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
|
|
3104
|
+
program.command("detect [path]").description("Detect frameworks, architectural variants and monorepo structure in a directory").action(async (targetPath) => {
|
|
3061
3105
|
try {
|
|
3062
|
-
const
|
|
3063
|
-
|
|
3064
|
-
|
|
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
|
-
|
|
3069
|
-
|
|
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)}`));
|