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