md4ai 0.1.0 → 0.2.1
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.bundled.js +141 -54
- package/package.json +1 -1
package/dist/index.bundled.js
CHANGED
|
@@ -320,7 +320,7 @@ ${deviceName}`) + chalk7.dim(` (${first.os_type})`));
|
|
|
320
320
|
import { resolve as resolve3 } from "node:path";
|
|
321
321
|
import { writeFile as writeFile2, mkdir as mkdir2 } from "node:fs/promises";
|
|
322
322
|
import { existsSync as existsSync5 } from "node:fs";
|
|
323
|
-
import
|
|
323
|
+
import chalk9 from "chalk";
|
|
324
324
|
|
|
325
325
|
// dist/scanner/index.js
|
|
326
326
|
import { readdir } from "node:fs/promises";
|
|
@@ -912,14 +912,60 @@ function escapeHtml(text) {
|
|
|
912
912
|
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
913
913
|
}
|
|
914
914
|
|
|
915
|
+
// dist/check-update.js
|
|
916
|
+
import chalk8 from "chalk";
|
|
917
|
+
var CURRENT_VERSION = "0.2.1";
|
|
918
|
+
async function checkForUpdate() {
|
|
919
|
+
try {
|
|
920
|
+
const controller = new AbortController();
|
|
921
|
+
const timeout = setTimeout(() => controller.abort(), 3e3);
|
|
922
|
+
const res = await fetch("https://registry.npmjs.org/md4ai/latest", {
|
|
923
|
+
signal: controller.signal
|
|
924
|
+
});
|
|
925
|
+
clearTimeout(timeout);
|
|
926
|
+
if (!res.ok)
|
|
927
|
+
return;
|
|
928
|
+
const data = await res.json();
|
|
929
|
+
const latest = data.version;
|
|
930
|
+
if (!latest)
|
|
931
|
+
return;
|
|
932
|
+
if (latest !== CURRENT_VERSION && isNewer(latest, CURRENT_VERSION)) {
|
|
933
|
+
console.log("");
|
|
934
|
+
console.log(chalk8.yellow("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"));
|
|
935
|
+
console.log(chalk8.yellow("\u2502") + chalk8.bold(" Update available! ") + chalk8.dim(`${CURRENT_VERSION}`) + chalk8.white(" \u2192 ") + chalk8.green.bold(`${latest}`) + " " + chalk8.yellow("\u2502"));
|
|
936
|
+
console.log(chalk8.yellow("\u2502") + " " + chalk8.yellow("\u2502"));
|
|
937
|
+
console.log(chalk8.yellow("\u2502") + " Run: " + chalk8.cyan("npm install -g md4ai") + " " + chalk8.yellow("\u2502"));
|
|
938
|
+
console.log(chalk8.yellow("\u2502") + " " + chalk8.yellow("\u2502"));
|
|
939
|
+
console.log(chalk8.yellow("\u2502") + chalk8.dim(" Changelog: https://www.md4ai.com/how-it-works") + " " + chalk8.yellow("\u2502"));
|
|
940
|
+
console.log(chalk8.yellow("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"));
|
|
941
|
+
console.log("");
|
|
942
|
+
} else {
|
|
943
|
+
console.log(chalk8.green(`md4ai v${CURRENT_VERSION} \u2014 you're on the latest version.`));
|
|
944
|
+
}
|
|
945
|
+
} catch {
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
function isNewer(a, b) {
|
|
949
|
+
const pa = a.split(".").map(Number);
|
|
950
|
+
const pb = b.split(".").map(Number);
|
|
951
|
+
for (let i = 0; i < 3; i++) {
|
|
952
|
+
if ((pa[i] ?? 0) > (pb[i] ?? 0))
|
|
953
|
+
return true;
|
|
954
|
+
if ((pa[i] ?? 0) < (pb[i] ?? 0))
|
|
955
|
+
return false;
|
|
956
|
+
}
|
|
957
|
+
return false;
|
|
958
|
+
}
|
|
959
|
+
|
|
915
960
|
// dist/commands/map.js
|
|
916
961
|
async function mapCommand(path, options) {
|
|
962
|
+
await checkForUpdate();
|
|
917
963
|
const projectRoot = resolve3(path ?? process.cwd());
|
|
918
964
|
if (!existsSync5(projectRoot)) {
|
|
919
|
-
console.error(
|
|
965
|
+
console.error(chalk9.red(`Path not found: ${projectRoot}`));
|
|
920
966
|
process.exit(1);
|
|
921
967
|
}
|
|
922
|
-
console.log(
|
|
968
|
+
console.log(chalk9.blue(`Scanning: ${projectRoot}
|
|
923
969
|
`));
|
|
924
970
|
const result = await scanProject(projectRoot);
|
|
925
971
|
console.log(` Files found: ${result.graph.nodes.length}`);
|
|
@@ -935,7 +981,7 @@ async function mapCommand(path, options) {
|
|
|
935
981
|
const htmlPath = resolve3(outputDir, "index.html");
|
|
936
982
|
const html = generateOfflineHtml(result, projectRoot);
|
|
937
983
|
await writeFile2(htmlPath, html, "utf-8");
|
|
938
|
-
console.log(
|
|
984
|
+
console.log(chalk9.green(`
|
|
939
985
|
Local preview: ${htmlPath}`));
|
|
940
986
|
if (!options.offline) {
|
|
941
987
|
try {
|
|
@@ -943,6 +989,39 @@ Local preview: ${htmlPath}`));
|
|
|
943
989
|
const { data: devicePaths } = await supabase.from("device_paths").select("folder_id, device_name").eq("path", projectRoot);
|
|
944
990
|
if (devicePaths?.length) {
|
|
945
991
|
const { folder_id, device_name } = devicePaths[0];
|
|
992
|
+
const { data: proposedFiles } = await supabase.from("folder_files").select("id, file_path, proposed_at").eq("folder_id", folder_id).eq("proposed_for_deletion", true);
|
|
993
|
+
if (proposedFiles?.length) {
|
|
994
|
+
const { checkbox } = await import("@inquirer/prompts");
|
|
995
|
+
console.log(chalk9.yellow(`
|
|
996
|
+
${proposedFiles.length} file(s) proposed for deletion:
|
|
997
|
+
`));
|
|
998
|
+
const toDelete = await checkbox({
|
|
999
|
+
message: "Select files to delete (space to toggle, enter to confirm)",
|
|
1000
|
+
choices: proposedFiles.map((f) => ({
|
|
1001
|
+
name: `${f.file_path}${f.proposed_at ? ` (proposed ${new Date(f.proposed_at).toLocaleDateString("en-GB", { weekday: "short", day: "numeric", month: "short", year: "numeric" })})` : ""}`,
|
|
1002
|
+
value: f
|
|
1003
|
+
}))
|
|
1004
|
+
});
|
|
1005
|
+
for (const file of toDelete) {
|
|
1006
|
+
const fullPath = resolve3(projectRoot, file.file_path);
|
|
1007
|
+
try {
|
|
1008
|
+
const { unlink } = await import("node:fs/promises");
|
|
1009
|
+
await unlink(fullPath);
|
|
1010
|
+
await supabase.from("folder_files").delete().eq("id", file.id);
|
|
1011
|
+
console.log(chalk9.green(` Deleted: ${file.file_path}`));
|
|
1012
|
+
} catch (err) {
|
|
1013
|
+
console.error(chalk9.red(` Failed to delete ${file.file_path}: ${err}`));
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
const keptIds = proposedFiles.filter((f) => !toDelete.some((d) => d.id === f.id)).map((f) => f.id);
|
|
1017
|
+
if (keptIds.length > 0) {
|
|
1018
|
+
for (const id of keptIds) {
|
|
1019
|
+
await supabase.from("folder_files").update({ proposed_for_deletion: false, proposed_at: null, proposed_by: null }).eq("id", id);
|
|
1020
|
+
}
|
|
1021
|
+
console.log(chalk9.cyan(` Kept ${keptIds.length} file(s) \u2014 proposals cleared.`));
|
|
1022
|
+
}
|
|
1023
|
+
console.log("");
|
|
1024
|
+
}
|
|
946
1025
|
const { error } = await supabase.from("claude_folders").update({
|
|
947
1026
|
graph_json: result.graph,
|
|
948
1027
|
orphans_json: result.orphans,
|
|
@@ -952,7 +1031,7 @@ Local preview: ${htmlPath}`));
|
|
|
952
1031
|
data_hash: result.dataHash
|
|
953
1032
|
}).eq("id", folder_id);
|
|
954
1033
|
if (error) {
|
|
955
|
-
console.error(
|
|
1034
|
+
console.error(chalk9.yellow(`Sync warning: ${error.message}`));
|
|
956
1035
|
} else {
|
|
957
1036
|
await supabase.from("device_paths").update({ last_synced: (/* @__PURE__ */ new Date()).toISOString() }).eq("folder_id", folder_id).eq("device_name", device_name);
|
|
958
1037
|
await saveState({
|
|
@@ -960,8 +1039,8 @@ Local preview: ${htmlPath}`));
|
|
|
960
1039
|
lastDeviceName: device_name,
|
|
961
1040
|
lastSyncAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
962
1041
|
});
|
|
963
|
-
console.log(
|
|
964
|
-
console.log(
|
|
1042
|
+
console.log(chalk9.green("Synced to Supabase."));
|
|
1043
|
+
console.log(chalk9.cyan(`
|
|
965
1044
|
https://www.md4ai.com/project/${folder_id}
|
|
966
1045
|
`));
|
|
967
1046
|
const configFiles = await readClaudeConfigFiles(projectRoot);
|
|
@@ -975,14 +1054,14 @@ Local preview: ${htmlPath}`));
|
|
|
975
1054
|
last_modified: file.lastModified
|
|
976
1055
|
}, { onConflict: "folder_id,file_path" });
|
|
977
1056
|
}
|
|
978
|
-
console.log(
|
|
1057
|
+
console.log(chalk9.green(` Uploaded ${configFiles.length} config file(s).`));
|
|
979
1058
|
}
|
|
980
1059
|
}
|
|
981
1060
|
} else {
|
|
982
|
-
console.log(
|
|
1061
|
+
console.log(chalk9.yellow("No device path matches this folder. Run: md4ai add-device\n(Local preview still generated.)"));
|
|
983
1062
|
}
|
|
984
1063
|
} catch {
|
|
985
|
-
console.log(
|
|
1064
|
+
console.log(chalk9.yellow("Not logged in \u2014 local preview only."));
|
|
986
1065
|
}
|
|
987
1066
|
}
|
|
988
1067
|
}
|
|
@@ -991,20 +1070,20 @@ Local preview: ${htmlPath}`));
|
|
|
991
1070
|
import { join as join7 } from "node:path";
|
|
992
1071
|
import { existsSync as existsSync6 } from "node:fs";
|
|
993
1072
|
import { homedir as homedir5 } from "node:os";
|
|
994
|
-
import
|
|
1073
|
+
import chalk10 from "chalk";
|
|
995
1074
|
async function simulateCommand(prompt) {
|
|
996
1075
|
const projectRoot = process.cwd();
|
|
997
|
-
console.log(
|
|
1076
|
+
console.log(chalk10.blue(`Simulating prompt: "${prompt}"
|
|
998
1077
|
`));
|
|
999
|
-
console.log(
|
|
1078
|
+
console.log(chalk10.dim("Files Claude would load:\n"));
|
|
1000
1079
|
const globalClaude = join7(homedir5(), ".claude", "CLAUDE.md");
|
|
1001
1080
|
if (existsSync6(globalClaude)) {
|
|
1002
|
-
console.log(
|
|
1081
|
+
console.log(chalk10.green(" \u2713 ~/.claude/CLAUDE.md (global)"));
|
|
1003
1082
|
}
|
|
1004
1083
|
for (const rootFile of ROOT_FILES) {
|
|
1005
1084
|
const fullPath = join7(projectRoot, rootFile);
|
|
1006
1085
|
if (existsSync6(fullPath)) {
|
|
1007
|
-
console.log(
|
|
1086
|
+
console.log(chalk10.green(` \u2713 ${rootFile} (project root)`));
|
|
1008
1087
|
}
|
|
1009
1088
|
}
|
|
1010
1089
|
const settingsFiles = [
|
|
@@ -1016,7 +1095,7 @@ async function simulateCommand(prompt) {
|
|
|
1016
1095
|
for (const sf of settingsFiles) {
|
|
1017
1096
|
if (existsSync6(sf)) {
|
|
1018
1097
|
const display = sf.startsWith(homedir5()) ? sf.replace(homedir5(), "~") : sf.replace(projectRoot + "/", "");
|
|
1019
|
-
console.log(
|
|
1098
|
+
console.log(chalk10.green(` \u2713 ${display} (settings)`));
|
|
1020
1099
|
}
|
|
1021
1100
|
}
|
|
1022
1101
|
const words = prompt.split(/\s+/);
|
|
@@ -1024,35 +1103,35 @@ async function simulateCommand(prompt) {
|
|
|
1024
1103
|
const cleaned = word.replace(/['"]/g, "");
|
|
1025
1104
|
const candidatePath = join7(projectRoot, cleaned);
|
|
1026
1105
|
if (existsSync6(candidatePath) && cleaned.includes("/")) {
|
|
1027
|
-
console.log(
|
|
1106
|
+
console.log(chalk10.cyan(` \u2192 ${cleaned} (referenced in prompt)`));
|
|
1028
1107
|
}
|
|
1029
1108
|
}
|
|
1030
|
-
console.log(
|
|
1109
|
+
console.log(chalk10.dim("\nNote: This is an approximation. Actual file loading depends on Claude Code internals."));
|
|
1031
1110
|
}
|
|
1032
1111
|
|
|
1033
1112
|
// dist/commands/print.js
|
|
1034
1113
|
import { join as join8 } from "node:path";
|
|
1035
1114
|
import { readFile as readFile4, writeFile as writeFile3 } from "node:fs/promises";
|
|
1036
1115
|
import { existsSync as existsSync7 } from "node:fs";
|
|
1037
|
-
import
|
|
1116
|
+
import chalk11 from "chalk";
|
|
1038
1117
|
async function printCommand(title) {
|
|
1039
1118
|
const projectRoot = process.cwd();
|
|
1040
1119
|
const scanDataPath = join8(projectRoot, "output", "index.html");
|
|
1041
1120
|
if (!existsSync7(scanDataPath)) {
|
|
1042
|
-
console.error(
|
|
1121
|
+
console.error(chalk11.red("No scan data found. Run: md4ai update"));
|
|
1043
1122
|
process.exit(1);
|
|
1044
1123
|
}
|
|
1045
1124
|
const html = await readFile4(scanDataPath, "utf-8");
|
|
1046
1125
|
const match = html.match(/<script type="application\/json" id="scan-data">([\s\S]*?)<\/script>/);
|
|
1047
1126
|
if (!match) {
|
|
1048
|
-
console.error(
|
|
1127
|
+
console.error(chalk11.red("Could not extract scan data from output/index.html"));
|
|
1049
1128
|
process.exit(1);
|
|
1050
1129
|
}
|
|
1051
1130
|
const result = JSON.parse(match[1]);
|
|
1052
1131
|
const printHtml = generatePrintHtml(result, title);
|
|
1053
1132
|
const outputPath = join8(projectRoot, "output", `print-${Date.now()}.html`);
|
|
1054
1133
|
await writeFile3(outputPath, printHtml, "utf-8");
|
|
1055
|
-
console.log(
|
|
1134
|
+
console.log(chalk11.green(`Print-ready wall sheet: ${outputPath}`));
|
|
1056
1135
|
}
|
|
1057
1136
|
function escapeHtml2(text) {
|
|
1058
1137
|
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
@@ -1109,17 +1188,21 @@ function generatePrintHtml(result, title) {
|
|
|
1109
1188
|
}
|
|
1110
1189
|
|
|
1111
1190
|
// dist/commands/sync.js
|
|
1112
|
-
import
|
|
1191
|
+
import chalk12 from "chalk";
|
|
1113
1192
|
async function syncCommand(options) {
|
|
1114
1193
|
const { supabase } = await getAuthenticatedClient();
|
|
1115
1194
|
if (options.all) {
|
|
1116
1195
|
const { data: devices, error } = await supabase.from("device_paths").select("folder_id, device_name, path");
|
|
1117
1196
|
if (error || !devices?.length) {
|
|
1118
|
-
console.error(
|
|
1197
|
+
console.error(chalk12.red("No devices found."));
|
|
1119
1198
|
process.exit(1);
|
|
1120
1199
|
}
|
|
1121
1200
|
for (const device of devices) {
|
|
1122
|
-
console.log(
|
|
1201
|
+
console.log(chalk12.blue(`Syncing: ${device.path}`));
|
|
1202
|
+
const { data: proposedAll } = await supabase.from("folder_files").select("file_path").eq("folder_id", device.folder_id).eq("proposed_for_deletion", true);
|
|
1203
|
+
if (proposedAll?.length) {
|
|
1204
|
+
console.log(chalk12.yellow(` ${proposedAll.length} file(s) proposed for deletion \u2014 run \`md4ai update\` to review.`));
|
|
1205
|
+
}
|
|
1123
1206
|
try {
|
|
1124
1207
|
const result = await scanProject(device.path);
|
|
1125
1208
|
await supabase.from("claude_folders").update({
|
|
@@ -1131,25 +1214,29 @@ async function syncCommand(options) {
|
|
|
1131
1214
|
data_hash: result.dataHash
|
|
1132
1215
|
}).eq("id", device.folder_id);
|
|
1133
1216
|
await supabase.from("device_paths").update({ last_synced: (/* @__PURE__ */ new Date()).toISOString() }).eq("folder_id", device.folder_id).eq("device_name", device.device_name);
|
|
1134
|
-
console.log(
|
|
1217
|
+
console.log(chalk12.green(` Done: ${device.device_name}`));
|
|
1135
1218
|
} catch (err) {
|
|
1136
|
-
console.error(
|
|
1219
|
+
console.error(chalk12.red(` Failed: ${device.path}: ${err}`));
|
|
1137
1220
|
}
|
|
1138
1221
|
}
|
|
1139
1222
|
await saveState({ lastSyncAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
1140
|
-
console.log(
|
|
1223
|
+
console.log(chalk12.green("\nAll devices synced."));
|
|
1141
1224
|
} else {
|
|
1142
1225
|
const state = await loadState();
|
|
1143
1226
|
if (!state.lastFolderId) {
|
|
1144
|
-
console.error(
|
|
1227
|
+
console.error(chalk12.yellow("No recent sync. Use: md4ai sync --all, or md4ai update <path> first."));
|
|
1145
1228
|
process.exit(1);
|
|
1146
1229
|
}
|
|
1147
1230
|
const { data: device } = await supabase.from("device_paths").select("folder_id, device_name, path").eq("folder_id", state.lastFolderId).eq("device_name", state.lastDeviceName).single();
|
|
1148
1231
|
if (!device) {
|
|
1149
|
-
console.error(
|
|
1232
|
+
console.error(chalk12.red("Could not find last synced device/folder."));
|
|
1150
1233
|
process.exit(1);
|
|
1151
1234
|
}
|
|
1152
|
-
console.log(
|
|
1235
|
+
console.log(chalk12.blue(`Syncing: ${device.path}`));
|
|
1236
|
+
const { data: proposedSingle } = await supabase.from("folder_files").select("file_path").eq("folder_id", device.folder_id).eq("proposed_for_deletion", true);
|
|
1237
|
+
if (proposedSingle?.length) {
|
|
1238
|
+
console.log(chalk12.yellow(` ${proposedSingle.length} file(s) proposed for deletion \u2014 run \`md4ai update\` to review.`));
|
|
1239
|
+
}
|
|
1153
1240
|
const result = await scanProject(device.path);
|
|
1154
1241
|
await supabase.from("claude_folders").update({
|
|
1155
1242
|
graph_json: result.graph,
|
|
@@ -1161,14 +1248,14 @@ async function syncCommand(options) {
|
|
|
1161
1248
|
}).eq("id", device.folder_id);
|
|
1162
1249
|
await supabase.from("device_paths").update({ last_synced: (/* @__PURE__ */ new Date()).toISOString() }).eq("folder_id", device.folder_id).eq("device_name", device.device_name);
|
|
1163
1250
|
await saveState({ lastSyncAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
1164
|
-
console.log(
|
|
1251
|
+
console.log(chalk12.green("Synced."));
|
|
1165
1252
|
}
|
|
1166
1253
|
}
|
|
1167
1254
|
|
|
1168
1255
|
// dist/commands/link.js
|
|
1169
1256
|
import { resolve as resolve4 } from "node:path";
|
|
1170
1257
|
import { hostname as hostname2, platform as platform2 } from "node:os";
|
|
1171
|
-
import
|
|
1258
|
+
import chalk13 from "chalk";
|
|
1172
1259
|
function detectOs2() {
|
|
1173
1260
|
const p = platform2();
|
|
1174
1261
|
if (p === "win32")
|
|
@@ -1192,11 +1279,11 @@ async function linkCommand(projectId) {
|
|
|
1192
1279
|
const osType = detectOs2();
|
|
1193
1280
|
const { data: folder, error: folderErr } = await supabase.from("claude_folders").select("id, name").eq("id", projectId).single();
|
|
1194
1281
|
if (folderErr || !folder) {
|
|
1195
|
-
console.error(
|
|
1196
|
-
console.error(
|
|
1282
|
+
console.error(chalk13.red("Project not found, or you do not have access."));
|
|
1283
|
+
console.error(chalk13.yellow("Check the project ID in the MD4AI web dashboard."));
|
|
1197
1284
|
process.exit(1);
|
|
1198
1285
|
}
|
|
1199
|
-
console.log(
|
|
1286
|
+
console.log(chalk13.blue(`
|
|
1200
1287
|
Linking "${folder.name}" to this device...
|
|
1201
1288
|
`));
|
|
1202
1289
|
console.log(` Project: ${folder.name}`);
|
|
@@ -1220,12 +1307,12 @@ Linking "${folder.name}" to this device...
|
|
|
1220
1307
|
path: cwd
|
|
1221
1308
|
});
|
|
1222
1309
|
if (pathErr) {
|
|
1223
|
-
console.error(
|
|
1310
|
+
console.error(chalk13.red(`Failed to link: ${pathErr.message}`));
|
|
1224
1311
|
process.exit(1);
|
|
1225
1312
|
}
|
|
1226
1313
|
}
|
|
1227
|
-
console.log(
|
|
1228
|
-
console.log(
|
|
1314
|
+
console.log(chalk13.green("\nLinked successfully."));
|
|
1315
|
+
console.log(chalk13.blue("\nRunning initial scan...\n"));
|
|
1229
1316
|
const result = await scanProject(cwd);
|
|
1230
1317
|
console.log(` Files: ${result.graph.nodes.length}`);
|
|
1231
1318
|
console.log(` References:${result.graph.edges.length}`);
|
|
@@ -1240,7 +1327,7 @@ Linking "${folder.name}" to this device...
|
|
|
1240
1327
|
data_hash: result.dataHash
|
|
1241
1328
|
}).eq("id", folder.id);
|
|
1242
1329
|
if (scanErr) {
|
|
1243
|
-
console.error(
|
|
1330
|
+
console.error(chalk13.yellow(`Scan upload warning: ${scanErr.message}`));
|
|
1244
1331
|
}
|
|
1245
1332
|
const configFiles = await readClaudeConfigFiles(cwd);
|
|
1246
1333
|
if (configFiles.length > 0) {
|
|
@@ -1253,7 +1340,7 @@ Linking "${folder.name}" to this device...
|
|
|
1253
1340
|
last_modified: file.lastModified
|
|
1254
1341
|
}, { onConflict: "folder_id,file_path" });
|
|
1255
1342
|
}
|
|
1256
|
-
console.log(
|
|
1343
|
+
console.log(chalk13.green(` Uploaded ${configFiles.length} config file(s).`));
|
|
1257
1344
|
}
|
|
1258
1345
|
await supabase.from("device_paths").update({ last_synced: (/* @__PURE__ */ new Date()).toISOString() }).eq("folder_id", folder.id).eq("device_name", deviceName);
|
|
1259
1346
|
await saveState({
|
|
@@ -1262,22 +1349,22 @@ Linking "${folder.name}" to this device...
|
|
|
1262
1349
|
lastSyncAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1263
1350
|
});
|
|
1264
1351
|
const projectUrl = `https://www.md4ai.com/project/${folder.id}`;
|
|
1265
|
-
console.log(
|
|
1266
|
-
console.log(
|
|
1352
|
+
console.log(chalk13.green("\nDone! Project linked and scanned."));
|
|
1353
|
+
console.log(chalk13.cyan(`
|
|
1267
1354
|
${projectUrl}
|
|
1268
1355
|
`));
|
|
1269
|
-
console.log(
|
|
1356
|
+
console.log(chalk13.grey('Run "md4ai update" to rescan at any time.'));
|
|
1270
1357
|
}
|
|
1271
1358
|
|
|
1272
1359
|
// dist/commands/import-bundle.js
|
|
1273
1360
|
import { readFile as readFile5, writeFile as writeFile4, mkdir as mkdir3 } from "node:fs/promises";
|
|
1274
1361
|
import { join as join9, dirname as dirname2 } from "node:path";
|
|
1275
1362
|
import { existsSync as existsSync8 } from "node:fs";
|
|
1276
|
-
import
|
|
1363
|
+
import chalk14 from "chalk";
|
|
1277
1364
|
import { confirm, input as input4 } from "@inquirer/prompts";
|
|
1278
1365
|
async function importBundleCommand(zipPath) {
|
|
1279
1366
|
if (!existsSync8(zipPath)) {
|
|
1280
|
-
console.error(
|
|
1367
|
+
console.error(chalk14.red(`File not found: ${zipPath}`));
|
|
1281
1368
|
process.exit(1);
|
|
1282
1369
|
}
|
|
1283
1370
|
const JSZip = (await import("jszip")).default;
|
|
@@ -1285,11 +1372,11 @@ async function importBundleCommand(zipPath) {
|
|
|
1285
1372
|
const zip = await JSZip.loadAsync(zipData);
|
|
1286
1373
|
const manifestFile = zip.file("manifest.json");
|
|
1287
1374
|
if (!manifestFile) {
|
|
1288
|
-
console.error(
|
|
1375
|
+
console.error(chalk14.red("Invalid bundle: missing manifest.json"));
|
|
1289
1376
|
process.exit(1);
|
|
1290
1377
|
}
|
|
1291
1378
|
const manifest = JSON.parse(await manifestFile.async("string"));
|
|
1292
|
-
console.log(
|
|
1379
|
+
console.log(chalk14.blue(`
|
|
1293
1380
|
Bundle: ${manifest.folderName}`));
|
|
1294
1381
|
console.log(` Exported by: ${manifest.ownerEmail}`);
|
|
1295
1382
|
console.log(` Exported at: ${manifest.exportedAt}`);
|
|
@@ -1303,10 +1390,10 @@ Bundle: ${manifest.folderName}`));
|
|
|
1303
1390
|
}
|
|
1304
1391
|
}
|
|
1305
1392
|
if (files.length === 0) {
|
|
1306
|
-
console.log(
|
|
1393
|
+
console.log(chalk14.yellow("No Claude config files found in bundle."));
|
|
1307
1394
|
return;
|
|
1308
1395
|
}
|
|
1309
|
-
console.log(
|
|
1396
|
+
console.log(chalk14.blue(`
|
|
1310
1397
|
Files to extract:`));
|
|
1311
1398
|
for (const f of files) {
|
|
1312
1399
|
console.log(` ${f.filePath}`);
|
|
@@ -1319,7 +1406,7 @@ Files to extract:`));
|
|
|
1319
1406
|
message: `Extract ${files.length} file(s) to ${targetDir}?`
|
|
1320
1407
|
});
|
|
1321
1408
|
if (!proceed) {
|
|
1322
|
-
console.log(
|
|
1409
|
+
console.log(chalk14.yellow("Cancelled."));
|
|
1323
1410
|
return;
|
|
1324
1411
|
}
|
|
1325
1412
|
for (const file of files) {
|
|
@@ -1329,15 +1416,15 @@ Files to extract:`));
|
|
|
1329
1416
|
await mkdir3(dir, { recursive: true });
|
|
1330
1417
|
}
|
|
1331
1418
|
await writeFile4(fullPath, file.content, "utf-8");
|
|
1332
|
-
console.log(
|
|
1419
|
+
console.log(chalk14.green(` \u2713 ${file.filePath}`));
|
|
1333
1420
|
}
|
|
1334
|
-
console.log(
|
|
1421
|
+
console.log(chalk14.green(`
|
|
1335
1422
|
Done! ${files.length} file(s) extracted to ${targetDir}`));
|
|
1336
1423
|
}
|
|
1337
1424
|
|
|
1338
1425
|
// dist/index.js
|
|
1339
1426
|
var program = new Command();
|
|
1340
|
-
program.name("md4ai").description("MD4AI \u2014 Claude tooling visualiser").version(
|
|
1427
|
+
program.name("md4ai").description("MD4AI \u2014 Claude tooling visualiser").version(CURRENT_VERSION);
|
|
1341
1428
|
program.command("login").description("Log in to MD4AI with email and password").action(loginCommand);
|
|
1342
1429
|
program.command("logout").description("Log out and clear stored credentials").action(logoutCommand);
|
|
1343
1430
|
program.command("status").description("Show login status, device count, folder count, last sync").action(statusCommand);
|