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.
Files changed (2) hide show
  1. package/dist/index.bundled.js +141 -54
  2. package/package.json +1 -1
@@ -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 chalk8 from "chalk";
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, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
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(chalk8.red(`Path not found: ${projectRoot}`));
965
+ console.error(chalk9.red(`Path not found: ${projectRoot}`));
920
966
  process.exit(1);
921
967
  }
922
- console.log(chalk8.blue(`Scanning: ${projectRoot}
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(chalk8.green(`
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(chalk8.yellow(`Sync warning: ${error.message}`));
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(chalk8.green("Synced to Supabase."));
964
- console.log(chalk8.cyan(`
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(chalk8.green(` Uploaded ${configFiles.length} config file(s).`));
1057
+ console.log(chalk9.green(` Uploaded ${configFiles.length} config file(s).`));
979
1058
  }
980
1059
  }
981
1060
  } else {
982
- console.log(chalk8.yellow("No device path matches this folder. Run: md4ai add-device\n(Local preview still generated.)"));
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(chalk8.yellow("Not logged in \u2014 local preview only."));
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 chalk9 from "chalk";
1073
+ import chalk10 from "chalk";
995
1074
  async function simulateCommand(prompt) {
996
1075
  const projectRoot = process.cwd();
997
- console.log(chalk9.blue(`Simulating prompt: "${prompt}"
1076
+ console.log(chalk10.blue(`Simulating prompt: "${prompt}"
998
1077
  `));
999
- console.log(chalk9.dim("Files Claude would load:\n"));
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(chalk9.green(" \u2713 ~/.claude/CLAUDE.md (global)"));
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(chalk9.green(` \u2713 ${rootFile} (project root)`));
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(chalk9.green(` \u2713 ${display} (settings)`));
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(chalk9.cyan(` \u2192 ${cleaned} (referenced in prompt)`));
1106
+ console.log(chalk10.cyan(` \u2192 ${cleaned} (referenced in prompt)`));
1028
1107
  }
1029
1108
  }
1030
- console.log(chalk9.dim("\nNote: This is an approximation. Actual file loading depends on Claude Code internals."));
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 chalk10 from "chalk";
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(chalk10.red("No scan data found. Run: md4ai update"));
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(chalk10.red("Could not extract scan data from output/index.html"));
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(chalk10.green(`Print-ready wall sheet: ${outputPath}`));
1134
+ console.log(chalk11.green(`Print-ready wall sheet: ${outputPath}`));
1056
1135
  }
1057
1136
  function escapeHtml2(text) {
1058
1137
  return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
@@ -1109,17 +1188,21 @@ function generatePrintHtml(result, title) {
1109
1188
  }
1110
1189
 
1111
1190
  // dist/commands/sync.js
1112
- import chalk11 from "chalk";
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(chalk11.red("No devices found."));
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(chalk11.blue(`Syncing: ${device.path}`));
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(chalk11.green(` Done: ${device.device_name}`));
1217
+ console.log(chalk12.green(` Done: ${device.device_name}`));
1135
1218
  } catch (err) {
1136
- console.error(chalk11.red(` Failed: ${device.path}: ${err}`));
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(chalk11.green("\nAll devices synced."));
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(chalk11.yellow("No recent sync. Use: md4ai sync --all, or md4ai update <path> first."));
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(chalk11.red("Could not find last synced device/folder."));
1232
+ console.error(chalk12.red("Could not find last synced device/folder."));
1150
1233
  process.exit(1);
1151
1234
  }
1152
- console.log(chalk11.blue(`Syncing: ${device.path}`));
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(chalk11.green("Synced."));
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 chalk12 from "chalk";
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(chalk12.red("Project not found, or you do not have access."));
1196
- console.error(chalk12.yellow("Check the project ID in the MD4AI web dashboard."));
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(chalk12.blue(`
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(chalk12.red(`Failed to link: ${pathErr.message}`));
1310
+ console.error(chalk13.red(`Failed to link: ${pathErr.message}`));
1224
1311
  process.exit(1);
1225
1312
  }
1226
1313
  }
1227
- console.log(chalk12.green("\nLinked successfully."));
1228
- console.log(chalk12.blue("\nRunning initial scan...\n"));
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(chalk12.yellow(`Scan upload warning: ${scanErr.message}`));
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(chalk12.green(` Uploaded ${configFiles.length} config file(s).`));
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(chalk12.green("\nDone! Project linked and scanned."));
1266
- console.log(chalk12.cyan(`
1352
+ console.log(chalk13.green("\nDone! Project linked and scanned."));
1353
+ console.log(chalk13.cyan(`
1267
1354
  ${projectUrl}
1268
1355
  `));
1269
- console.log(chalk12.grey('Run "md4ai update" to rescan at any time.'));
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 chalk13 from "chalk";
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(chalk13.red(`File not found: ${zipPath}`));
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(chalk13.red("Invalid bundle: missing manifest.json"));
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(chalk13.blue(`
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(chalk13.yellow("No Claude config files found in bundle."));
1393
+ console.log(chalk14.yellow("No Claude config files found in bundle."));
1307
1394
  return;
1308
1395
  }
1309
- console.log(chalk13.blue(`
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(chalk13.yellow("Cancelled."));
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(chalk13.green(` \u2713 ${file.filePath}`));
1419
+ console.log(chalk14.green(` \u2713 ${file.filePath}`));
1333
1420
  }
1334
- console.log(chalk13.green(`
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("0.1.0");
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);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "md4ai",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "description": "CLI for MD4AI — scan Claude projects and sync to your dashboard",
5
5
  "type": "module",
6
6
  "bin": {