md4ai 0.17.2 → 0.17.3

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.
@@ -122,7 +122,7 @@ var CURRENT_VERSION;
122
122
  var init_check_update = __esm({
123
123
  "dist/check-update.js"() {
124
124
  "use strict";
125
- CURRENT_VERSION = true ? "0.17.2" : "0.0.0-dev";
125
+ CURRENT_VERSION = true ? "0.17.3" : "0.0.0-dev";
126
126
  }
127
127
  });
128
128
 
@@ -365,14 +365,26 @@ import chalk5 from "chalk";
365
365
  import { confirm, input as input2, password as password2 } from "@inquirer/prompts";
366
366
  async function getAuthenticatedClient() {
367
367
  const creds = await loadCredentials();
368
- const needsLogin = !creds?.accessToken || Date.now() > creds.expiresAt;
369
- if (needsLogin) {
370
- const reason = !creds?.accessToken ? "Not logged in." : "Session expired.";
371
- console.log(chalk5.yellow(`${reason}`));
368
+ if (!creds?.accessToken) {
369
+ console.log(chalk5.yellow("Not logged in."));
372
370
  const shouldLogin = await confirm({ message: "Would you like to log in now?" });
373
- if (!shouldLogin) {
371
+ if (!shouldLogin)
374
372
  process.exit(0);
373
+ return promptLogin();
374
+ }
375
+ if (creds.refreshToken) {
376
+ const refreshed = await refreshSession();
377
+ if (refreshed) {
378
+ updateDeviceCliVersion(refreshed.supabase, refreshed.userId).catch(() => {
379
+ });
380
+ return refreshed;
375
381
  }
382
+ }
383
+ if (Date.now() > creds.expiresAt) {
384
+ console.log(chalk5.yellow("Session expired."));
385
+ const shouldLogin = await confirm({ message: "Would you like to log in now?" });
386
+ if (!shouldLogin)
387
+ process.exit(0);
376
388
  return promptLogin();
377
389
  }
378
390
  const anonKey = getAnonKey();
@@ -2069,6 +2081,11 @@ var init_doppler_scanner = __esm({
2069
2081
  });
2070
2082
 
2071
2083
  // dist/scanner/index.js
2084
+ var scanner_exports = {};
2085
+ __export(scanner_exports, {
2086
+ readClaudeConfigFiles: () => readClaudeConfigFiles,
2087
+ scanProject: () => scanProject
2088
+ });
2072
2089
  import { readdir as readdir5 } from "node:fs/promises";
2073
2090
  import { join as join12, relative as relative3 } from "node:path";
2074
2091
  import { existsSync as existsSync7 } from "node:fs";
@@ -2619,7 +2636,7 @@ ${proposedFiles.length} file(s) proposed for deletion:
2619
2636
  }
2620
2637
  }
2621
2638
  if (deviceId) {
2622
- await supabase.from("device_scans").upsert({
2639
+ const scanPayload = {
2623
2640
  folder_id,
2624
2641
  device_id: deviceId,
2625
2642
  user_id: userId,
@@ -2635,7 +2652,14 @@ ${proposedFiles.length} file(s) proposed for deletion:
2635
2652
  data_hash: result.dataHash,
2636
2653
  scanned_at: result.scannedAt,
2637
2654
  cli_version: CURRENT_VERSION
2638
- }, { onConflict: "folder_id,device_id" });
2655
+ };
2656
+ const { data: updated, error: updateErr } = await supabase.from("device_scans").update(scanPayload).eq("folder_id", folder_id).eq("device_id", deviceId).select("id");
2657
+ if (updateErr || !updated?.length) {
2658
+ const { error: insertErr } = await supabase.from("device_scans").insert(scanPayload);
2659
+ if (insertErr) {
2660
+ console.error(chalk12.red(` Failed to save scan data: ${insertErr.message}`));
2661
+ }
2662
+ }
2639
2663
  }
2640
2664
  await pushToolings(supabase, folder_id, result.toolings, deviceId);
2641
2665
  const manifestForHealth = result.envManifest ?? storedManifest;
@@ -3593,12 +3617,13 @@ async function checkPendingRescans(supabase, deviceId, deviceName) {
3593
3617
  if (!paths?.length)
3594
3618
  return;
3595
3619
  const folderIds = paths.map((p) => p.folder_id);
3596
- const { data: folders } = await supabase.from("claude_folders").select("id, last_scanned, rescan_requested_at").in("id", folderIds).not("rescan_requested_at", "is", null);
3620
+ const { data: folders } = await supabase.from("claude_folders").select("id, rescan_requested_at").in("id", folderIds).not("rescan_requested_at", "is", null);
3597
3621
  if (!folders?.length)
3598
3622
  return;
3599
3623
  for (const folder of folders) {
3600
3624
  const requested = new Date(folder.rescan_requested_at).getTime();
3601
- const scanned = folder.last_scanned ? new Date(folder.last_scanned).getTime() : 0;
3625
+ const { data: scanRow } = await supabase.from("device_scans").select("scanned_at").eq("folder_id", folder.id).eq("device_id", deviceId).maybeSingle();
3626
+ const scanned = scanRow?.scanned_at ? new Date(scanRow.scanned_at).getTime() : 0;
3602
3627
  if (requested <= scanned)
3603
3628
  continue;
3604
3629
  const dp = paths.find((p) => p.folder_id === folder.id);
@@ -3606,24 +3631,46 @@ async function checkPendingRescans(supabase, deviceId, deviceName) {
3606
3631
  continue;
3607
3632
  try {
3608
3633
  const result = await scanProject(dp.path);
3609
- await supabase.from("device_scans").upsert({
3634
+ const userId = (await supabase.auth.getUser()).data.user.id;
3635
+ const scanPayload = {
3610
3636
  folder_id: folder.id,
3611
3637
  device_id: deviceId,
3612
- user_id: (await supabase.auth.getUser()).data.user.id,
3638
+ user_id: userId,
3613
3639
  graph_json: result.graph,
3614
3640
  orphans_json: result.orphans,
3615
3641
  skills_table_json: result.skills,
3616
3642
  stale_files_json: result.staleFiles,
3617
3643
  broken_refs_json: result.brokenRefs,
3618
3644
  env_manifest_json: result.envManifest,
3645
+ doppler_json: result.doppler,
3646
+ marketplace_plugins_json: result.marketplacePlugins,
3647
+ plugin_versions_json: result.pluginVersions,
3619
3648
  data_hash: result.dataHash,
3620
3649
  scanned_at: result.scannedAt,
3621
3650
  cli_version: CURRENT_VERSION
3622
- }, { onConflict: "folder_id,device_id" });
3651
+ };
3652
+ const { data: updated } = await supabase.from("device_scans").update(scanPayload).eq("folder_id", folder.id).eq("device_id", deviceId).select("id");
3653
+ if (!updated?.length) {
3654
+ await supabase.from("device_scans").insert(scanPayload);
3655
+ }
3623
3656
  await supabase.from("claude_folders").update({
3624
3657
  rescan_requested_at: null
3625
3658
  }).eq("id", folder.id);
3626
3659
  await pushToolings(supabase, folder.id, result.toolings, deviceId);
3660
+ const graphPaths = result.graph.nodes.map((n) => n.filePath);
3661
+ const { readClaudeConfigFiles: readClaudeConfigFiles2 } = await Promise.resolve().then(() => (init_scanner(), scanner_exports));
3662
+ const configFiles = await readClaudeConfigFiles2(dp.path, graphPaths);
3663
+ for (const cf of configFiles) {
3664
+ await supabase.from("folder_files").upsert({
3665
+ folder_id: folder.id,
3666
+ file_path: cf.filePath,
3667
+ content: cf.content,
3668
+ size_bytes: cf.sizeBytes,
3669
+ last_modified: cf.lastModified,
3670
+ synced_at: (/* @__PURE__ */ new Date()).toISOString(),
3671
+ device_id: deviceId
3672
+ }, { onConflict: "folder_id,file_path,device_id" });
3673
+ }
3627
3674
  await supabase.from("device_paths").update({ last_synced: (/* @__PURE__ */ new Date()).toISOString() }).eq("folder_id", folder.id).eq("device_name", deviceName);
3628
3675
  } catch {
3629
3676
  await supabase.from("claude_folders").update({ rescan_requested_at: null }).eq("id", folder.id);
@@ -4340,7 +4387,15 @@ var VERSION_SOURCES = {
4340
4387
  "turborepo": { type: "npm", package: "turbo" },
4341
4388
  "npm": { type: "npm", package: "npm" },
4342
4389
  "node": { type: "github", repo: "nodejs/node" },
4343
- "supabase-cli": { type: "npm", package: "supabase" }
4390
+ "supabase-cli": { type: "npm", package: "supabase" },
4391
+ "vercel-cli": { type: "npm", package: "vercel" },
4392
+ "@sentry/node": { type: "npm", package: "@sentry/node" },
4393
+ "react-markdown": { type: "npm", package: "react-markdown" },
4394
+ "rehype-sanitize": { type: "npm", package: "rehype-sanitize" },
4395
+ "@react-email/render": { type: "npm", package: "@react-email/render" },
4396
+ "@anthropic-ai/sdk": { type: "npm", package: "@anthropic-ai/sdk" },
4397
+ "@xyflow/react": { type: "npm", package: "@xyflow/react" },
4398
+ "fflate": { type: "npm", package: "fflate" }
4344
4399
  };
4345
4400
 
4346
4401
  // dist/commands/admin-fetch-versions.js
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "md4ai",
3
- "version": "0.17.2",
3
+ "version": "0.17.3",
4
4
  "description": "CLI for MD4AI — scan Claude projects and sync to your dashboard",
5
5
  "type": "module",
6
6
  "bin": {