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