md4ai 0.9.1 → 0.9.2

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 +127 -50
  2. package/package.json +1 -1
@@ -1262,7 +1262,7 @@ var CURRENT_VERSION;
1262
1262
  var init_check_update = __esm({
1263
1263
  "dist/check-update.js"() {
1264
1264
  "use strict";
1265
- CURRENT_VERSION = true ? "0.9.1" : "0.0.0-dev";
1265
+ CURRENT_VERSION = true ? "0.9.2" : "0.0.0-dev";
1266
1266
  }
1267
1267
  });
1268
1268
 
@@ -1290,6 +1290,44 @@ var init_push_toolings = __esm({
1290
1290
  }
1291
1291
  });
1292
1292
 
1293
+ // dist/device-utils.js
1294
+ import { hostname as hostname2, platform as platform2 } from "node:os";
1295
+ function detectOs2() {
1296
+ const p = platform2();
1297
+ if (p === "win32")
1298
+ return "windows";
1299
+ if (p === "darwin")
1300
+ return "macos";
1301
+ if (p === "linux")
1302
+ return "linux";
1303
+ return "other";
1304
+ }
1305
+ function detectDeviceName() {
1306
+ const os = detectOs2();
1307
+ const host = hostname2().split(".")[0];
1308
+ const osLabel = os.charAt(0).toUpperCase() + os.slice(1);
1309
+ return `${host}-${osLabel}`;
1310
+ }
1311
+ async function resolveDeviceId(supabase, userId) {
1312
+ const deviceName = detectDeviceName();
1313
+ const osType = detectOs2();
1314
+ await supabase.from("devices").upsert({
1315
+ user_id: userId,
1316
+ device_name: deviceName,
1317
+ os_type: osType
1318
+ }, { onConflict: "user_id,device_name" });
1319
+ const { data, error } = await supabase.from("devices").select("id").eq("user_id", userId).eq("device_name", deviceName).single();
1320
+ if (error || !data) {
1321
+ throw new Error(`Failed to resolve device ID: ${error?.message ?? "not found"}`);
1322
+ }
1323
+ return data.id;
1324
+ }
1325
+ var init_device_utils = __esm({
1326
+ "dist/device-utils.js"() {
1327
+ "use strict";
1328
+ }
1329
+ });
1330
+
1293
1331
  // dist/commands/sync.js
1294
1332
  var sync_exports = {};
1295
1333
  __export(sync_exports, {
@@ -1371,44 +1409,6 @@ var init_sync = __esm({
1371
1409
  }
1372
1410
  });
1373
1411
 
1374
- // dist/device-utils.js
1375
- import { hostname as hostname2, platform as platform2 } from "node:os";
1376
- function detectOs2() {
1377
- const p = platform2();
1378
- if (p === "win32")
1379
- return "windows";
1380
- if (p === "darwin")
1381
- return "macos";
1382
- if (p === "linux")
1383
- return "linux";
1384
- return "other";
1385
- }
1386
- function detectDeviceName() {
1387
- const os = detectOs2();
1388
- const host = hostname2().split(".")[0];
1389
- const osLabel = os.charAt(0).toUpperCase() + os.slice(1);
1390
- return `${host}-${osLabel}`;
1391
- }
1392
- async function resolveDeviceId(supabase, userId) {
1393
- const deviceName = detectDeviceName();
1394
- const osType = detectOs2();
1395
- await supabase.from("devices").upsert({
1396
- user_id: userId,
1397
- device_name: deviceName,
1398
- os_type: osType
1399
- }, { onConflict: "user_id,device_name" });
1400
- const { data, error } = await supabase.from("devices").select("id").eq("user_id", userId).eq("device_name", deviceName).single();
1401
- if (error || !data) {
1402
- throw new Error(`Failed to resolve device ID: ${error?.message ?? "not found"}`);
1403
- }
1404
- return data.id;
1405
- }
1406
- var init_device_utils = __esm({
1407
- "dist/device-utils.js"() {
1408
- "use strict";
1409
- }
1410
- });
1411
-
1412
1412
  // dist/mcp/read-configs.js
1413
1413
  import { readFile as readFile8 } from "node:fs/promises";
1414
1414
  import { join as join12 } from "node:path";
@@ -2247,7 +2247,7 @@ ${deviceName}`) + chalk7.dim(` (${first.os_type})`));
2247
2247
  init_scanner();
2248
2248
  init_auth();
2249
2249
  init_config();
2250
- import { resolve as resolve3 } from "node:path";
2250
+ import { resolve as resolve3, basename } from "node:path";
2251
2251
  import { writeFile as writeFile2, mkdir as mkdir2 } from "node:fs/promises";
2252
2252
  import { existsSync as existsSync7 } from "node:fs";
2253
2253
  import chalk9 from "chalk";
@@ -2366,6 +2366,8 @@ function escapeHtml(text) {
2366
2366
  // dist/commands/map.js
2367
2367
  init_check_update();
2368
2368
  init_push_toolings();
2369
+ init_device_utils();
2370
+ import { select as select3, input as input5, confirm as confirm2 } from "@inquirer/prompts";
2369
2371
  async function mapCommand(path, options) {
2370
2372
  await checkForUpdate();
2371
2373
  const projectRoot = resolve3(path ?? process.cwd());
@@ -2470,7 +2472,82 @@ ${proposedFiles.length} file(s) proposed for deletion:
2470
2472
  }
2471
2473
  }
2472
2474
  } else {
2473
- console.log(chalk9.yellow("No device path matches this folder. Run: md4ai add-device\n(Local preview still generated.)"));
2475
+ console.log(chalk9.yellow("\nThis folder is not linked to a project on your dashboard."));
2476
+ const shouldLink = await confirm2({ message: "Would you like to link it now?" });
2477
+ if (!shouldLink) {
2478
+ console.log(chalk9.dim("Skipped \u2014 local preview still generated."));
2479
+ } else {
2480
+ const { supabase: sb, userId } = await getAuthenticatedClient();
2481
+ const { data: folders } = await sb.from("claude_folders").select("id, name").order("name");
2482
+ const choices = [
2483
+ { name: "+ Create a new project", value: "__new__" },
2484
+ ...(folders ?? []).map((f) => ({ name: f.name, value: f.id }))
2485
+ ];
2486
+ const chosen = await select3({
2487
+ message: "Link to which project?",
2488
+ choices
2489
+ });
2490
+ let folderId;
2491
+ if (chosen === "__new__") {
2492
+ const projectName = await input5({
2493
+ message: "Project name:",
2494
+ default: basename(projectRoot)
2495
+ });
2496
+ const { data: newFolder, error: createErr } = await sb.from("claude_folders").insert({ user_id: userId, name: projectName }).select("id").single();
2497
+ if (createErr || !newFolder) {
2498
+ console.error(chalk9.red(`Failed to create project: ${createErr?.message}`));
2499
+ return;
2500
+ }
2501
+ folderId = newFolder.id;
2502
+ console.log(chalk9.green(`Created project "${projectName}".`));
2503
+ } else {
2504
+ folderId = chosen;
2505
+ }
2506
+ const deviceName = detectDeviceName();
2507
+ const osType = detectOs2();
2508
+ await sb.from("devices").upsert({
2509
+ user_id: userId,
2510
+ device_name: deviceName,
2511
+ os_type: osType
2512
+ }, { onConflict: "user_id,device_name" });
2513
+ await sb.from("device_paths").upsert({
2514
+ user_id: userId,
2515
+ folder_id: folderId,
2516
+ device_name: deviceName,
2517
+ os_type: osType,
2518
+ path: projectRoot,
2519
+ last_synced: (/* @__PURE__ */ new Date()).toISOString()
2520
+ }, { onConflict: "folder_id,device_name" });
2521
+ await sb.from("claude_folders").update({
2522
+ graph_json: result.graph,
2523
+ orphans_json: result.orphans,
2524
+ skills_table_json: result.skills,
2525
+ stale_files_json: result.staleFiles,
2526
+ env_manifest_json: result.envManifest,
2527
+ last_scanned: result.scannedAt,
2528
+ data_hash: result.dataHash
2529
+ }).eq("id", folderId);
2530
+ await pushToolings(sb, folderId, result.toolings);
2531
+ const configFiles = await readClaudeConfigFiles(projectRoot);
2532
+ for (const file of configFiles) {
2533
+ await sb.from("folder_files").upsert({
2534
+ folder_id: folderId,
2535
+ file_path: file.filePath,
2536
+ content: file.content,
2537
+ size_bytes: file.sizeBytes,
2538
+ last_modified: file.lastModified
2539
+ }, { onConflict: "folder_id,file_path" });
2540
+ }
2541
+ await saveState({
2542
+ lastFolderId: folderId,
2543
+ lastDeviceName: deviceName,
2544
+ lastSyncAt: (/* @__PURE__ */ new Date()).toISOString()
2545
+ });
2546
+ console.log(chalk9.green("\nLinked and synced."));
2547
+ console.log(chalk9.cyan(`
2548
+ https://www.md4ai.com/project/${folderId}
2549
+ `));
2550
+ }
2474
2551
  }
2475
2552
  } catch {
2476
2553
  console.log(chalk9.yellow("Not logged in \u2014 local preview only."));
@@ -2704,7 +2781,7 @@ import { readFile as readFile7, writeFile as writeFile4, mkdir as mkdir3 } from
2704
2781
  import { join as join11, dirname as dirname2 } from "node:path";
2705
2782
  import { existsSync as existsSync10 } from "node:fs";
2706
2783
  import chalk14 from "chalk";
2707
- import { confirm as confirm2, input as input5 } from "@inquirer/prompts";
2784
+ import { confirm as confirm3, input as input6 } from "@inquirer/prompts";
2708
2785
  async function importBundleCommand(zipPath) {
2709
2786
  if (!existsSync10(zipPath)) {
2710
2787
  console.error(chalk14.red(`File not found: ${zipPath}`));
@@ -2741,11 +2818,11 @@ Files to extract:`));
2741
2818
  for (const f of files) {
2742
2819
  console.log(` ${f.filePath}`);
2743
2820
  }
2744
- const targetDir = await input5({
2821
+ const targetDir = await input6({
2745
2822
  message: "Extract to directory:",
2746
2823
  default: process.cwd()
2747
2824
  });
2748
- const proceed = await confirm2({
2825
+ const proceed = await confirm3({
2749
2826
  message: `Extract ${files.length} file(s) to ${targetDir}?`
2750
2827
  });
2751
2828
  if (!proceed) {
@@ -3235,7 +3312,7 @@ function spawnPostUpdate() {
3235
3312
  child.on("exit", (code) => process.exit(code ?? 0));
3236
3313
  }
3237
3314
  async function postUpdateFlow() {
3238
- const { confirm: confirm3 } = await import("@inquirer/prompts");
3315
+ const { confirm: confirm4 } = await import("@inquirer/prompts");
3239
3316
  console.log(chalk20.green(`
3240
3317
  md4ai v${CURRENT_VERSION} \u2014 you're on the latest version.
3241
3318
  `));
@@ -3243,7 +3320,7 @@ async function postUpdateFlow() {
3243
3320
  const isLoggedIn = !!creds?.accessToken && Date.now() < creds.expiresAt;
3244
3321
  if (!isLoggedIn) {
3245
3322
  console.log(chalk20.yellow(" You are not logged in.\n"));
3246
- const wantLogin = await confirm3({
3323
+ const wantLogin = await confirm4({
3247
3324
  message: "Log in now?",
3248
3325
  default: true
3249
3326
  });
@@ -3260,7 +3337,7 @@ async function postUpdateFlow() {
3260
3337
  const state = await loadState();
3261
3338
  const hasProject = !!state.lastFolderId;
3262
3339
  if (hasProject) {
3263
- const wantScan = await confirm3({
3340
+ const wantScan = await confirm4({
3264
3341
  message: "Rescan your project and refresh the dashboard?",
3265
3342
  default: true
3266
3343
  });
@@ -3271,7 +3348,7 @@ async function postUpdateFlow() {
3271
3348
  console.log("");
3272
3349
  }
3273
3350
  }
3274
- const wantWatch = await confirm3({
3351
+ const wantWatch = await confirm4({
3275
3352
  message: "Start monitoring MCP servers? (runs until you press Ctrl+C)",
3276
3353
  default: true
3277
3354
  });
@@ -3302,8 +3379,8 @@ async function updateCommand(options) {
3302
3379
  }
3303
3380
  console.log(chalk20.white(" Update available: ") + chalk20.dim(`v${CURRENT_VERSION}`) + chalk20.white(" \u2192 ") + chalk20.green.bold(`v${latest}
3304
3381
  `));
3305
- const { confirm: confirm3 } = await import("@inquirer/prompts");
3306
- const wantUpdate = await confirm3({
3382
+ const { confirm: confirm4 } = await import("@inquirer/prompts");
3383
+ const wantUpdate = await confirm4({
3307
3384
  message: `Install md4ai v${latest}?`,
3308
3385
  default: true
3309
3386
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "md4ai",
3
- "version": "0.9.1",
3
+ "version": "0.9.2",
4
4
  "description": "CLI for MD4AI — scan Claude projects and sync to your dashboard",
5
5
  "type": "module",
6
6
  "bin": {