@aiready/cli 0.9.28 → 0.9.29
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.js +91 -89
- package/dist/cli.mjs +91 -89
- package/package.json +4 -4
- package/src/commands/visualize.ts +104 -100
package/dist/cli.js
CHANGED
|
@@ -1011,7 +1011,9 @@ Or specify a custom report:
|
|
|
1011
1011
|
console.log("Building graph from report...");
|
|
1012
1012
|
const { GraphBuilder } = await import("@aiready/visualizer/graph");
|
|
1013
1013
|
const graph = GraphBuilder.buildFromReport(report, dirPath);
|
|
1014
|
-
|
|
1014
|
+
let useDevMode = options.dev || false;
|
|
1015
|
+
let devServerStarted = false;
|
|
1016
|
+
if (useDevMode) {
|
|
1015
1017
|
try {
|
|
1016
1018
|
const monorepoWebDir = (0, import_path6.resolve)(dirPath, "packages/visualizer");
|
|
1017
1019
|
let webDir = "";
|
|
@@ -1047,96 +1049,100 @@ Or specify a custom report:
|
|
|
1047
1049
|
}
|
|
1048
1050
|
}
|
|
1049
1051
|
}
|
|
1050
|
-
const
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1052
|
+
const webViteConfigExists = webDir && (0, import_fs3.existsSync)((0, import_path6.resolve)(webDir, "web", "vite.config.ts"));
|
|
1053
|
+
if (visualizerAvailable && webViteConfigExists) {
|
|
1054
|
+
const spawnCwd = webDir;
|
|
1055
|
+
const { watch } = await import("fs");
|
|
1056
|
+
const copyReportToViz = () => {
|
|
1057
|
+
try {
|
|
1058
|
+
const destPath = (0, import_path6.resolve)(spawnCwd, "web", "report-data.json");
|
|
1059
|
+
(0, import_fs3.copyFileSync)(reportPath, destPath);
|
|
1060
|
+
console.log(`\u{1F4CB} Report synced to ${destPath}`);
|
|
1061
|
+
} catch (e) {
|
|
1062
|
+
console.error("Failed to sync report:", e);
|
|
1063
|
+
}
|
|
1064
|
+
};
|
|
1065
|
+
copyReportToViz();
|
|
1066
|
+
let watchTimeout = null;
|
|
1067
|
+
const reportWatcher = watch(reportPath, () => {
|
|
1068
|
+
if (watchTimeout) clearTimeout(watchTimeout);
|
|
1069
|
+
watchTimeout = setTimeout(copyReportToViz, 100);
|
|
1070
|
+
});
|
|
1071
|
+
const envForSpawn = {
|
|
1072
|
+
...process.env,
|
|
1073
|
+
AIREADY_REPORT_PATH: reportPath,
|
|
1074
|
+
AIREADY_VISUALIZER_CONFIG: envVisualizerConfig
|
|
1075
|
+
};
|
|
1076
|
+
const vite = (0, import_child_process.spawn)("pnpm", ["run", "dev:web"], { cwd: spawnCwd, stdio: "inherit", shell: true, env: envForSpawn });
|
|
1077
|
+
const onExit = () => {
|
|
1078
|
+
try {
|
|
1079
|
+
reportWatcher.close();
|
|
1080
|
+
} catch (e) {
|
|
1081
|
+
}
|
|
1082
|
+
try {
|
|
1083
|
+
vite.kill();
|
|
1084
|
+
} catch (e) {
|
|
1085
|
+
}
|
|
1086
|
+
process.exit(0);
|
|
1087
|
+
};
|
|
1088
|
+
process.on("SIGINT", onExit);
|
|
1089
|
+
process.on("SIGTERM", onExit);
|
|
1090
|
+
devServerStarted = true;
|
|
1056
1091
|
return;
|
|
1092
|
+
} else {
|
|
1093
|
+
console.log(import_chalk6.default.yellow("\u26A0\uFE0F Dev server not available (requires local @aiready/visualizer with web assets)."));
|
|
1094
|
+
console.log(import_chalk6.default.cyan(" Falling back to static HTML generation...\n"));
|
|
1095
|
+
useDevMode = false;
|
|
1057
1096
|
}
|
|
1058
|
-
const { watch } = await import("fs");
|
|
1059
|
-
const copyReportToViz = () => {
|
|
1060
|
-
try {
|
|
1061
|
-
const destPath = (0, import_path6.resolve)(spawnCwd, "web", "report-data.json");
|
|
1062
|
-
(0, import_fs3.copyFileSync)(reportPath, destPath);
|
|
1063
|
-
console.log(`\u{1F4CB} Report synced to ${destPath}`);
|
|
1064
|
-
} catch (e) {
|
|
1065
|
-
console.error("Failed to sync report:", e);
|
|
1066
|
-
}
|
|
1067
|
-
};
|
|
1068
|
-
copyReportToViz();
|
|
1069
|
-
let watchTimeout = null;
|
|
1070
|
-
const reportWatcher = watch(reportPath, () => {
|
|
1071
|
-
if (watchTimeout) clearTimeout(watchTimeout);
|
|
1072
|
-
watchTimeout = setTimeout(copyReportToViz, 100);
|
|
1073
|
-
});
|
|
1074
|
-
const envForSpawn = {
|
|
1075
|
-
...process.env,
|
|
1076
|
-
AIREADY_REPORT_PATH: reportPath,
|
|
1077
|
-
AIREADY_VISUALIZER_CONFIG: envVisualizerConfig
|
|
1078
|
-
};
|
|
1079
|
-
const vite = (0, import_child_process.spawn)("pnpm", ["run", "dev:web"], { cwd: spawnCwd, stdio: "inherit", shell: true, env: envForSpawn });
|
|
1080
|
-
const onExit = () => {
|
|
1081
|
-
try {
|
|
1082
|
-
reportWatcher.close();
|
|
1083
|
-
} catch (e) {
|
|
1084
|
-
}
|
|
1085
|
-
try {
|
|
1086
|
-
vite.kill();
|
|
1087
|
-
} catch (e) {
|
|
1088
|
-
}
|
|
1089
|
-
process.exit(0);
|
|
1090
|
-
};
|
|
1091
|
-
process.on("SIGINT", onExit);
|
|
1092
|
-
process.on("SIGTERM", onExit);
|
|
1093
|
-
return;
|
|
1094
1097
|
} catch (err) {
|
|
1095
1098
|
console.error("Failed to start dev server:", err);
|
|
1099
|
+
console.log(import_chalk6.default.cyan(" Falling back to static HTML generation...\n"));
|
|
1100
|
+
useDevMode = false;
|
|
1096
1101
|
}
|
|
1097
1102
|
}
|
|
1098
1103
|
console.log("Generating HTML...");
|
|
1099
1104
|
const html = (0, import_core6.generateHTML)(graph);
|
|
1100
|
-
const
|
|
1105
|
+
const defaultOutput = "visualization.html";
|
|
1106
|
+
const outPath = (0, import_path6.resolve)(dirPath, options.output || defaultOutput);
|
|
1101
1107
|
(0, import_fs3.writeFileSync)(outPath, html, "utf8");
|
|
1102
|
-
console.log(
|
|
1103
|
-
if (options.open) {
|
|
1108
|
+
console.log(import_chalk6.default.green(`\u2705 Visualization written to: ${outPath}`));
|
|
1109
|
+
if (options.open || options.serve) {
|
|
1104
1110
|
const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
1105
|
-
(
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1111
|
+
if (options.serve) {
|
|
1112
|
+
try {
|
|
1113
|
+
const port = typeof options.serve === "number" ? options.serve : 5173;
|
|
1114
|
+
const http = await import("http");
|
|
1115
|
+
const fsp = await import("fs/promises");
|
|
1116
|
+
const server = http.createServer(async (req, res) => {
|
|
1117
|
+
try {
|
|
1118
|
+
const urlPath = req.url || "/";
|
|
1119
|
+
if (urlPath === "/" || urlPath === "/index.html") {
|
|
1120
|
+
const content = await fsp.readFile(outPath, "utf8");
|
|
1121
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
1122
|
+
res.end(content);
|
|
1123
|
+
return;
|
|
1124
|
+
}
|
|
1125
|
+
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
1126
|
+
res.end("Not found");
|
|
1127
|
+
} catch (e) {
|
|
1128
|
+
res.writeHead(500, { "Content-Type": "text/plain" });
|
|
1129
|
+
res.end("Server error");
|
|
1120
1130
|
}
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
}
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
}
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
process.exit(0);
|
|
1137
|
-
});
|
|
1138
|
-
} catch (err) {
|
|
1139
|
-
console.error("Failed to start local server:", err);
|
|
1131
|
+
});
|
|
1132
|
+
server.listen(port, () => {
|
|
1133
|
+
const addr = `http://localhost:${port}/`;
|
|
1134
|
+
console.log(import_chalk6.default.cyan(`\u{1F310} Local visualization server running at ${addr}`));
|
|
1135
|
+
(0, import_child_process.spawn)(opener, [`"${addr}"`], { shell: true });
|
|
1136
|
+
});
|
|
1137
|
+
process.on("SIGINT", () => {
|
|
1138
|
+
server.close();
|
|
1139
|
+
process.exit(0);
|
|
1140
|
+
});
|
|
1141
|
+
} catch (err) {
|
|
1142
|
+
console.error("Failed to start local server:", err);
|
|
1143
|
+
}
|
|
1144
|
+
} else if (options.open) {
|
|
1145
|
+
(0, import_child_process.spawn)(opener, [`"${outPath}"`], { shell: true });
|
|
1140
1146
|
}
|
|
1141
1147
|
}
|
|
1142
1148
|
} catch (err) {
|
|
@@ -1145,7 +1151,7 @@ Or specify a custom report:
|
|
|
1145
1151
|
}
|
|
1146
1152
|
var visualizeHelpText = `
|
|
1147
1153
|
EXAMPLES:
|
|
1148
|
-
$ aiready visualize . # Auto-detects latest report
|
|
1154
|
+
$ aiready visualize . # Auto-detects latest report, generates HTML
|
|
1149
1155
|
$ aiready visualize . --report .aiready/aiready-report-20260217-143022.json
|
|
1150
1156
|
$ aiready visualize . --report report.json -o out/visualization.html --open
|
|
1151
1157
|
$ aiready visualize . --report report.json --serve
|
|
@@ -1155,23 +1161,19 @@ EXAMPLES:
|
|
|
1155
1161
|
NOTES:
|
|
1156
1162
|
- The value passed to --report is interpreted relative to the directory argument (first positional).
|
|
1157
1163
|
If the report is not found, the CLI will suggest running 'aiready scan' to generate it.
|
|
1158
|
-
- Default output path:
|
|
1164
|
+
- Default output path: visualization.html (in the current directory).
|
|
1159
1165
|
- --serve starts a tiny single-file HTTP server (default port: 5173) and opens your browser.
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
reduce clutter and improve interactivity on large graphs.
|
|
1163
|
-
- For very large graphs, consider narrowing the input with --include/--exclude or use --serve and
|
|
1164
|
-
allow the browser a moment to stabilize after load.
|
|
1166
|
+
- --dev starts a Vite dev server with live reload (requires local @aiready/visualizer installation).
|
|
1167
|
+
When --dev is not available, it falls back to static HTML generation.
|
|
1165
1168
|
`;
|
|
1166
1169
|
var visualiseHelpText = `
|
|
1167
1170
|
EXAMPLES:
|
|
1168
1171
|
$ aiready visualise . # Auto-detects latest report
|
|
1169
1172
|
$ aiready visualise . --report .aiready/aiready-report-20260217-143022.json
|
|
1170
|
-
$ aiready visualise . --report report.json --dev
|
|
1171
1173
|
$ aiready visualise . --report report.json --serve 8080
|
|
1172
1174
|
|
|
1173
1175
|
NOTES:
|
|
1174
|
-
- Same options as 'visualize'. Use --
|
|
1176
|
+
- Same options as 'visualize'. Use --serve to host the static HTML, or --dev for live reload.
|
|
1175
1177
|
`;
|
|
1176
1178
|
|
|
1177
1179
|
// src/cli.ts
|
package/dist/cli.mjs
CHANGED
|
@@ -939,7 +939,9 @@ Or specify a custom report:
|
|
|
939
939
|
console.log("Building graph from report...");
|
|
940
940
|
const { GraphBuilder } = await import("@aiready/visualizer/graph");
|
|
941
941
|
const graph = GraphBuilder.buildFromReport(report, dirPath);
|
|
942
|
-
|
|
942
|
+
let useDevMode = options.dev || false;
|
|
943
|
+
let devServerStarted = false;
|
|
944
|
+
if (useDevMode) {
|
|
943
945
|
try {
|
|
944
946
|
const monorepoWebDir = resolvePath6(dirPath, "packages/visualizer");
|
|
945
947
|
let webDir = "";
|
|
@@ -975,96 +977,100 @@ Or specify a custom report:
|
|
|
975
977
|
}
|
|
976
978
|
}
|
|
977
979
|
}
|
|
978
|
-
const
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
980
|
+
const webViteConfigExists = webDir && existsSync2(resolvePath6(webDir, "web", "vite.config.ts"));
|
|
981
|
+
if (visualizerAvailable && webViteConfigExists) {
|
|
982
|
+
const spawnCwd = webDir;
|
|
983
|
+
const { watch } = await import("fs");
|
|
984
|
+
const copyReportToViz = () => {
|
|
985
|
+
try {
|
|
986
|
+
const destPath = resolvePath6(spawnCwd, "web", "report-data.json");
|
|
987
|
+
copyFileSync2(reportPath, destPath);
|
|
988
|
+
console.log(`\u{1F4CB} Report synced to ${destPath}`);
|
|
989
|
+
} catch (e) {
|
|
990
|
+
console.error("Failed to sync report:", e);
|
|
991
|
+
}
|
|
992
|
+
};
|
|
993
|
+
copyReportToViz();
|
|
994
|
+
let watchTimeout = null;
|
|
995
|
+
const reportWatcher = watch(reportPath, () => {
|
|
996
|
+
if (watchTimeout) clearTimeout(watchTimeout);
|
|
997
|
+
watchTimeout = setTimeout(copyReportToViz, 100);
|
|
998
|
+
});
|
|
999
|
+
const envForSpawn = {
|
|
1000
|
+
...process.env,
|
|
1001
|
+
AIREADY_REPORT_PATH: reportPath,
|
|
1002
|
+
AIREADY_VISUALIZER_CONFIG: envVisualizerConfig
|
|
1003
|
+
};
|
|
1004
|
+
const vite = spawn("pnpm", ["run", "dev:web"], { cwd: spawnCwd, stdio: "inherit", shell: true, env: envForSpawn });
|
|
1005
|
+
const onExit = () => {
|
|
1006
|
+
try {
|
|
1007
|
+
reportWatcher.close();
|
|
1008
|
+
} catch (e) {
|
|
1009
|
+
}
|
|
1010
|
+
try {
|
|
1011
|
+
vite.kill();
|
|
1012
|
+
} catch (e) {
|
|
1013
|
+
}
|
|
1014
|
+
process.exit(0);
|
|
1015
|
+
};
|
|
1016
|
+
process.on("SIGINT", onExit);
|
|
1017
|
+
process.on("SIGTERM", onExit);
|
|
1018
|
+
devServerStarted = true;
|
|
984
1019
|
return;
|
|
1020
|
+
} else {
|
|
1021
|
+
console.log(chalk6.yellow("\u26A0\uFE0F Dev server not available (requires local @aiready/visualizer with web assets)."));
|
|
1022
|
+
console.log(chalk6.cyan(" Falling back to static HTML generation...\n"));
|
|
1023
|
+
useDevMode = false;
|
|
985
1024
|
}
|
|
986
|
-
const { watch } = await import("fs");
|
|
987
|
-
const copyReportToViz = () => {
|
|
988
|
-
try {
|
|
989
|
-
const destPath = resolvePath6(spawnCwd, "web", "report-data.json");
|
|
990
|
-
copyFileSync2(reportPath, destPath);
|
|
991
|
-
console.log(`\u{1F4CB} Report synced to ${destPath}`);
|
|
992
|
-
} catch (e) {
|
|
993
|
-
console.error("Failed to sync report:", e);
|
|
994
|
-
}
|
|
995
|
-
};
|
|
996
|
-
copyReportToViz();
|
|
997
|
-
let watchTimeout = null;
|
|
998
|
-
const reportWatcher = watch(reportPath, () => {
|
|
999
|
-
if (watchTimeout) clearTimeout(watchTimeout);
|
|
1000
|
-
watchTimeout = setTimeout(copyReportToViz, 100);
|
|
1001
|
-
});
|
|
1002
|
-
const envForSpawn = {
|
|
1003
|
-
...process.env,
|
|
1004
|
-
AIREADY_REPORT_PATH: reportPath,
|
|
1005
|
-
AIREADY_VISUALIZER_CONFIG: envVisualizerConfig
|
|
1006
|
-
};
|
|
1007
|
-
const vite = spawn("pnpm", ["run", "dev:web"], { cwd: spawnCwd, stdio: "inherit", shell: true, env: envForSpawn });
|
|
1008
|
-
const onExit = () => {
|
|
1009
|
-
try {
|
|
1010
|
-
reportWatcher.close();
|
|
1011
|
-
} catch (e) {
|
|
1012
|
-
}
|
|
1013
|
-
try {
|
|
1014
|
-
vite.kill();
|
|
1015
|
-
} catch (e) {
|
|
1016
|
-
}
|
|
1017
|
-
process.exit(0);
|
|
1018
|
-
};
|
|
1019
|
-
process.on("SIGINT", onExit);
|
|
1020
|
-
process.on("SIGTERM", onExit);
|
|
1021
|
-
return;
|
|
1022
1025
|
} catch (err) {
|
|
1023
1026
|
console.error("Failed to start dev server:", err);
|
|
1027
|
+
console.log(chalk6.cyan(" Falling back to static HTML generation...\n"));
|
|
1028
|
+
useDevMode = false;
|
|
1024
1029
|
}
|
|
1025
1030
|
}
|
|
1026
1031
|
console.log("Generating HTML...");
|
|
1027
1032
|
const html = generateHTML(graph);
|
|
1028
|
-
const
|
|
1033
|
+
const defaultOutput = "visualization.html";
|
|
1034
|
+
const outPath = resolvePath6(dirPath, options.output || defaultOutput);
|
|
1029
1035
|
writeFileSync2(outPath, html, "utf8");
|
|
1030
|
-
console.log(
|
|
1031
|
-
if (options.open) {
|
|
1036
|
+
console.log(chalk6.green(`\u2705 Visualization written to: ${outPath}`));
|
|
1037
|
+
if (options.open || options.serve) {
|
|
1032
1038
|
const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1039
|
+
if (options.serve) {
|
|
1040
|
+
try {
|
|
1041
|
+
const port = typeof options.serve === "number" ? options.serve : 5173;
|
|
1042
|
+
const http = await import("http");
|
|
1043
|
+
const fsp = await import("fs/promises");
|
|
1044
|
+
const server = http.createServer(async (req, res) => {
|
|
1045
|
+
try {
|
|
1046
|
+
const urlPath = req.url || "/";
|
|
1047
|
+
if (urlPath === "/" || urlPath === "/index.html") {
|
|
1048
|
+
const content = await fsp.readFile(outPath, "utf8");
|
|
1049
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
1050
|
+
res.end(content);
|
|
1051
|
+
return;
|
|
1052
|
+
}
|
|
1053
|
+
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
1054
|
+
res.end("Not found");
|
|
1055
|
+
} catch (e) {
|
|
1056
|
+
res.writeHead(500, { "Content-Type": "text/plain" });
|
|
1057
|
+
res.end("Server error");
|
|
1048
1058
|
}
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
}
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
}
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
process.exit(0);
|
|
1065
|
-
});
|
|
1066
|
-
} catch (err) {
|
|
1067
|
-
console.error("Failed to start local server:", err);
|
|
1059
|
+
});
|
|
1060
|
+
server.listen(port, () => {
|
|
1061
|
+
const addr = `http://localhost:${port}/`;
|
|
1062
|
+
console.log(chalk6.cyan(`\u{1F310} Local visualization server running at ${addr}`));
|
|
1063
|
+
spawn(opener, [`"${addr}"`], { shell: true });
|
|
1064
|
+
});
|
|
1065
|
+
process.on("SIGINT", () => {
|
|
1066
|
+
server.close();
|
|
1067
|
+
process.exit(0);
|
|
1068
|
+
});
|
|
1069
|
+
} catch (err) {
|
|
1070
|
+
console.error("Failed to start local server:", err);
|
|
1071
|
+
}
|
|
1072
|
+
} else if (options.open) {
|
|
1073
|
+
spawn(opener, [`"${outPath}"`], { shell: true });
|
|
1068
1074
|
}
|
|
1069
1075
|
}
|
|
1070
1076
|
} catch (err) {
|
|
@@ -1073,7 +1079,7 @@ Or specify a custom report:
|
|
|
1073
1079
|
}
|
|
1074
1080
|
var visualizeHelpText = `
|
|
1075
1081
|
EXAMPLES:
|
|
1076
|
-
$ aiready visualize . # Auto-detects latest report
|
|
1082
|
+
$ aiready visualize . # Auto-detects latest report, generates HTML
|
|
1077
1083
|
$ aiready visualize . --report .aiready/aiready-report-20260217-143022.json
|
|
1078
1084
|
$ aiready visualize . --report report.json -o out/visualization.html --open
|
|
1079
1085
|
$ aiready visualize . --report report.json --serve
|
|
@@ -1083,23 +1089,19 @@ EXAMPLES:
|
|
|
1083
1089
|
NOTES:
|
|
1084
1090
|
- The value passed to --report is interpreted relative to the directory argument (first positional).
|
|
1085
1091
|
If the report is not found, the CLI will suggest running 'aiready scan' to generate it.
|
|
1086
|
-
- Default output path:
|
|
1092
|
+
- Default output path: visualization.html (in the current directory).
|
|
1087
1093
|
- --serve starts a tiny single-file HTTP server (default port: 5173) and opens your browser.
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
reduce clutter and improve interactivity on large graphs.
|
|
1091
|
-
- For very large graphs, consider narrowing the input with --include/--exclude or use --serve and
|
|
1092
|
-
allow the browser a moment to stabilize after load.
|
|
1094
|
+
- --dev starts a Vite dev server with live reload (requires local @aiready/visualizer installation).
|
|
1095
|
+
When --dev is not available, it falls back to static HTML generation.
|
|
1093
1096
|
`;
|
|
1094
1097
|
var visualiseHelpText = `
|
|
1095
1098
|
EXAMPLES:
|
|
1096
1099
|
$ aiready visualise . # Auto-detects latest report
|
|
1097
1100
|
$ aiready visualise . --report .aiready/aiready-report-20260217-143022.json
|
|
1098
|
-
$ aiready visualise . --report report.json --dev
|
|
1099
1101
|
$ aiready visualise . --report report.json --serve 8080
|
|
1100
1102
|
|
|
1101
1103
|
NOTES:
|
|
1102
|
-
- Same options as 'visualize'. Use --
|
|
1104
|
+
- Same options as 'visualize'. Use --serve to host the static HTML, or --dev for live reload.
|
|
1103
1105
|
`;
|
|
1104
1106
|
|
|
1105
1107
|
// src/cli.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiready/cli",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.29",
|
|
4
4
|
"description": "Unified CLI for AIReady analysis tools",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -11,11 +11,11 @@
|
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"commander": "^14.0.0",
|
|
13
13
|
"chalk": "^5.3.0",
|
|
14
|
-
"@aiready/pattern-detect": "0.11.22",
|
|
15
14
|
"@aiready/core": "0.9.22",
|
|
16
|
-
"@aiready/
|
|
15
|
+
"@aiready/pattern-detect": "0.11.22",
|
|
17
16
|
"@aiready/visualizer": "0.1.28",
|
|
18
|
-
"@aiready/consistency": "0.8.22"
|
|
17
|
+
"@aiready/consistency": "0.8.22",
|
|
18
|
+
"@aiready/context-analyzer": "0.9.26"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"tsup": "^8.3.5",
|
|
@@ -65,17 +65,21 @@ export async function visualizeAction(directory: string, options: VisualizeOptio
|
|
|
65
65
|
const { GraphBuilder } = await import('@aiready/visualizer/graph');
|
|
66
66
|
const graph = GraphBuilder.buildFromReport(report, dirPath);
|
|
67
67
|
|
|
68
|
-
if
|
|
68
|
+
// Check if --dev mode is requested and available
|
|
69
|
+
let useDevMode = options.dev || false;
|
|
70
|
+
let devServerStarted = false;
|
|
71
|
+
|
|
72
|
+
if (useDevMode) {
|
|
69
73
|
try {
|
|
70
74
|
const monorepoWebDir = resolvePath(dirPath, 'packages/visualizer');
|
|
71
75
|
let webDir = '';
|
|
72
76
|
let visualizerAvailable = false;
|
|
77
|
+
|
|
73
78
|
if (existsSync(monorepoWebDir)) {
|
|
74
79
|
webDir = monorepoWebDir;
|
|
75
80
|
visualizerAvailable = true;
|
|
76
81
|
} else {
|
|
77
82
|
// Try to resolve installed @aiready/visualizer package from node_modules
|
|
78
|
-
// Check multiple locations to support pnpm, npm, yarn, etc.
|
|
79
83
|
const nodemodulesLocations: string[] = [
|
|
80
84
|
resolvePath(dirPath, 'node_modules', '@aiready', 'visualizer'),
|
|
81
85
|
resolvePath(process.cwd(), 'node_modules', '@aiready', 'visualizer'),
|
|
@@ -86,7 +90,7 @@ export async function visualizeAction(directory: string, options: VisualizeOptio
|
|
|
86
90
|
while (currentDir !== '/' && currentDir !== '.') {
|
|
87
91
|
nodemodulesLocations.push(resolvePath(currentDir, 'node_modules', '@aiready', 'visualizer'));
|
|
88
92
|
const parent = resolvePath(currentDir, '..');
|
|
89
|
-
if (parent === currentDir) break;
|
|
93
|
+
if (parent === currentDir) break;
|
|
90
94
|
currentDir = parent;
|
|
91
95
|
}
|
|
92
96
|
|
|
@@ -109,109 +113,113 @@ export async function visualizeAction(directory: string, options: VisualizeOptio
|
|
|
109
113
|
}
|
|
110
114
|
}
|
|
111
115
|
}
|
|
112
|
-
const spawnCwd = webDir || process.cwd();
|
|
113
|
-
const nodeBinCandidate = process.execPath;
|
|
114
|
-
const nodeBin = existsSync(nodeBinCandidate) ? nodeBinCandidate : 'node';
|
|
115
|
-
if (!visualizerAvailable) {
|
|
116
|
-
console.error(chalk.red('❌ Cannot start dev server: @aiready/visualizer not available.'));
|
|
117
|
-
console.log(chalk.dim('Install @aiready/visualizer in your project with:\n npm install @aiready/visualizer'));
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Inline report watcher: copy report to web/report-data.json and watch for changes
|
|
122
|
-
const { watch } = await import('fs');
|
|
123
|
-
const copyReportToViz = () => {
|
|
124
|
-
try {
|
|
125
|
-
const destPath = resolvePath(spawnCwd, 'web', 'report-data.json');
|
|
126
|
-
copyFileSync(reportPath!, destPath);
|
|
127
|
-
console.log(`📋 Report synced to ${destPath}`);
|
|
128
|
-
} catch (e) {
|
|
129
|
-
console.error('Failed to sync report:', e);
|
|
130
|
-
}
|
|
131
|
-
};
|
|
132
116
|
|
|
133
|
-
//
|
|
134
|
-
|
|
117
|
+
// Check if web directory with vite config exists (required for dev mode)
|
|
118
|
+
const webViteConfigExists = webDir && existsSync(resolvePath(webDir, 'web', 'vite.config.ts'));
|
|
135
119
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
120
|
+
if (visualizerAvailable && webViteConfigExists) {
|
|
121
|
+
// Dev mode is available - start Vite dev server
|
|
122
|
+
const spawnCwd = webDir!;
|
|
123
|
+
|
|
124
|
+
// Inline report watcher: copy report to web/report-data.json and watch for changes
|
|
125
|
+
const { watch } = await import('fs');
|
|
126
|
+
const copyReportToViz = () => {
|
|
127
|
+
try {
|
|
128
|
+
const destPath = resolvePath(spawnCwd, 'web', 'report-data.json');
|
|
129
|
+
copyFileSync(reportPath!, destPath);
|
|
130
|
+
console.log(`📋 Report synced to ${destPath}`);
|
|
131
|
+
} catch (e) {
|
|
132
|
+
console.error('Failed to sync report:', e);
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
// Initial copy
|
|
137
|
+
copyReportToViz();
|
|
138
|
+
|
|
139
|
+
// Watch source report for changes
|
|
140
|
+
let watchTimeout: NodeJS.Timeout | null = null;
|
|
141
|
+
const reportWatcher = watch(reportPath, () => {
|
|
142
|
+
if (watchTimeout) clearTimeout(watchTimeout);
|
|
143
|
+
watchTimeout = setTimeout(copyReportToViz, 100);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
const envForSpawn = {
|
|
147
|
+
...process.env,
|
|
148
|
+
AIREADY_REPORT_PATH: reportPath,
|
|
149
|
+
AIREADY_VISUALIZER_CONFIG: envVisualizerConfig
|
|
150
|
+
};
|
|
151
|
+
const vite = spawn("pnpm", ["run", "dev:web"], { cwd: spawnCwd, stdio: "inherit", shell: true, env: envForSpawn });
|
|
152
|
+
const onExit = () => {
|
|
153
|
+
try { reportWatcher.close(); } catch (e) {}
|
|
154
|
+
try { vite.kill(); } catch (e) {}
|
|
155
|
+
process.exit(0);
|
|
156
|
+
};
|
|
157
|
+
process.on("SIGINT", onExit);
|
|
158
|
+
process.on("SIGTERM", onExit);
|
|
159
|
+
devServerStarted = true;
|
|
160
|
+
return;
|
|
161
|
+
} else {
|
|
162
|
+
console.log(chalk.yellow('⚠️ Dev server not available (requires local @aiready/visualizer with web assets).'));
|
|
163
|
+
console.log(chalk.cyan(' Falling back to static HTML generation...\n'));
|
|
164
|
+
useDevMode = false;
|
|
165
|
+
}
|
|
162
166
|
} catch (err) {
|
|
163
167
|
console.error("Failed to start dev server:", err);
|
|
168
|
+
console.log(chalk.cyan(' Falling back to static HTML generation...\n'));
|
|
169
|
+
useDevMode = false;
|
|
164
170
|
}
|
|
165
171
|
}
|
|
166
172
|
|
|
173
|
+
// Generate static HTML (default behavior or fallback from failed --dev)
|
|
167
174
|
console.log("Generating HTML...");
|
|
168
175
|
const html = generateHTML(graph);
|
|
169
|
-
const
|
|
176
|
+
const defaultOutput = 'visualization.html';
|
|
177
|
+
const outPath = resolvePath(dirPath, options.output || defaultOutput);
|
|
170
178
|
writeFileSync(outPath, html, 'utf8');
|
|
171
|
-
console.log(
|
|
179
|
+
console.log(chalk.green(`✅ Visualization written to: ${outPath}`));
|
|
172
180
|
|
|
173
181
|
|
|
174
|
-
if (options.open) {
|
|
182
|
+
if (options.open || options.serve) {
|
|
175
183
|
const opener = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open';
|
|
176
|
-
|
|
177
|
-
|
|
184
|
+
|
|
185
|
+
if (options.serve) {
|
|
186
|
+
try {
|
|
187
|
+
const port = typeof options.serve === 'number' ? options.serve : 5173;
|
|
188
|
+
const http = await import('http');
|
|
189
|
+
const fsp = await import('fs/promises');
|
|
178
190
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
res.
|
|
192
|
-
|
|
191
|
+
const server = http.createServer(async (req, res) => {
|
|
192
|
+
try {
|
|
193
|
+
const urlPath = req.url || '/';
|
|
194
|
+
if (urlPath === '/' || urlPath === '/index.html') {
|
|
195
|
+
const content = await fsp.readFile(outPath, 'utf8');
|
|
196
|
+
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
197
|
+
res.end(content);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
|
201
|
+
res.end('Not found');
|
|
202
|
+
} catch (e: any) {
|
|
203
|
+
res.writeHead(500, { 'Content-Type': 'text/plain' });
|
|
204
|
+
res.end('Server error');
|
|
193
205
|
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
process.exit(0);
|
|
212
|
-
});
|
|
213
|
-
} catch (err) {
|
|
214
|
-
console.error('Failed to start local server:', err);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
server.listen(port, () => {
|
|
209
|
+
const addr = `http://localhost:${port}/`;
|
|
210
|
+
console.log(chalk.cyan(`🌐 Local visualization server running at ${addr}`));
|
|
211
|
+
spawn(opener, [`"${addr}"`], { shell: true });
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
process.on('SIGINT', () => {
|
|
215
|
+
server.close();
|
|
216
|
+
process.exit(0);
|
|
217
|
+
});
|
|
218
|
+
} catch (err) {
|
|
219
|
+
console.error('Failed to start local server:', err);
|
|
220
|
+
}
|
|
221
|
+
} else if (options.open) {
|
|
222
|
+
spawn(opener, [`"${outPath}"`], { shell: true });
|
|
215
223
|
}
|
|
216
224
|
}
|
|
217
225
|
|
|
@@ -222,7 +230,7 @@ export async function visualizeAction(directory: string, options: VisualizeOptio
|
|
|
222
230
|
|
|
223
231
|
export const visualizeHelpText = `
|
|
224
232
|
EXAMPLES:
|
|
225
|
-
$ aiready visualize . # Auto-detects latest report
|
|
233
|
+
$ aiready visualize . # Auto-detects latest report, generates HTML
|
|
226
234
|
$ aiready visualize . --report .aiready/aiready-report-20260217-143022.json
|
|
227
235
|
$ aiready visualize . --report report.json -o out/visualization.html --open
|
|
228
236
|
$ aiready visualize . --report report.json --serve
|
|
@@ -232,22 +240,18 @@ EXAMPLES:
|
|
|
232
240
|
NOTES:
|
|
233
241
|
- The value passed to --report is interpreted relative to the directory argument (first positional).
|
|
234
242
|
If the report is not found, the CLI will suggest running 'aiready scan' to generate it.
|
|
235
|
-
- Default output path:
|
|
243
|
+
- Default output path: visualization.html (in the current directory).
|
|
236
244
|
- --serve starts a tiny single-file HTTP server (default port: 5173) and opens your browser.
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
reduce clutter and improve interactivity on large graphs.
|
|
240
|
-
- For very large graphs, consider narrowing the input with --include/--exclude or use --serve and
|
|
241
|
-
allow the browser a moment to stabilize after load.
|
|
245
|
+
- --dev starts a Vite dev server with live reload (requires local @aiready/visualizer installation).
|
|
246
|
+
When --dev is not available, it falls back to static HTML generation.
|
|
242
247
|
`;
|
|
243
248
|
|
|
244
249
|
export const visualiseHelpText = `
|
|
245
250
|
EXAMPLES:
|
|
246
251
|
$ aiready visualise . # Auto-detects latest report
|
|
247
252
|
$ aiready visualise . --report .aiready/aiready-report-20260217-143022.json
|
|
248
|
-
$ aiready visualise . --report report.json --dev
|
|
249
253
|
$ aiready visualise . --report report.json --serve 8080
|
|
250
254
|
|
|
251
255
|
NOTES:
|
|
252
|
-
- Same options as 'visualize'. Use --
|
|
256
|
+
- Same options as 'visualize'. Use --serve to host the static HTML, or --dev for live reload.
|
|
253
257
|
`;
|