md4ai 0.12.0 → 0.13.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 +236 -93
- package/package.json +1 -1
package/dist/index.bundled.js
CHANGED
|
@@ -73,7 +73,7 @@ var CURRENT_VERSION;
|
|
|
73
73
|
var init_check_update = __esm({
|
|
74
74
|
"dist/check-update.js"() {
|
|
75
75
|
"use strict";
|
|
76
|
-
CURRENT_VERSION = true ? "0.
|
|
76
|
+
CURRENT_VERSION = true ? "0.13.0" : "0.0.0-dev";
|
|
77
77
|
}
|
|
78
78
|
});
|
|
79
79
|
|
|
@@ -1656,21 +1656,40 @@ var init_marketplace_scanner = __esm({
|
|
|
1656
1656
|
|
|
1657
1657
|
// dist/doppler/auth.js
|
|
1658
1658
|
async function resolveDopplerToken() {
|
|
1659
|
+
const { join: join17 } = await import("node:path");
|
|
1660
|
+
const { homedir: homedir10 } = await import("node:os");
|
|
1661
|
+
const credPath = join17(homedir10(), ".md4ai", "credentials.json");
|
|
1659
1662
|
const creds = await loadCredentials();
|
|
1660
1663
|
if (creds?.dopplerToken) {
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1664
|
+
return { token: creds.dopplerToken, sourcePath: credPath };
|
|
1665
|
+
}
|
|
1666
|
+
if (!creds?.accessToken || !creds?.userId)
|
|
1667
|
+
return null;
|
|
1668
|
+
try {
|
|
1669
|
+
let supabase = createSupabaseClient(getAnonKey(), creds.accessToken);
|
|
1670
|
+
let userId = creds.userId;
|
|
1671
|
+
if (Date.now() > creds.expiresAt) {
|
|
1672
|
+
const refreshed = await refreshSession();
|
|
1673
|
+
if (!refreshed)
|
|
1674
|
+
return null;
|
|
1675
|
+
supabase = refreshed.supabase;
|
|
1676
|
+
userId = refreshed.userId;
|
|
1677
|
+
}
|
|
1678
|
+
const { data } = await supabase.from("user_secrets").select("doppler_token").eq("user_id", userId).maybeSingle();
|
|
1679
|
+
if (!data?.doppler_token)
|
|
1680
|
+
return null;
|
|
1681
|
+
await mergeCredentials({ dopplerToken: data.doppler_token });
|
|
1682
|
+
return { token: data.doppler_token, sourcePath: "Supabase (cached locally)" };
|
|
1683
|
+
} catch {
|
|
1684
|
+
return null;
|
|
1667
1685
|
}
|
|
1668
|
-
return null;
|
|
1669
1686
|
}
|
|
1670
1687
|
var init_auth3 = __esm({
|
|
1671
1688
|
"dist/doppler/auth.js"() {
|
|
1672
1689
|
"use strict";
|
|
1673
1690
|
init_config();
|
|
1691
|
+
init_auth();
|
|
1692
|
+
init_dist();
|
|
1674
1693
|
}
|
|
1675
1694
|
});
|
|
1676
1695
|
|
|
@@ -2175,7 +2194,7 @@ var init_push_toolings = __esm({
|
|
|
2175
2194
|
|
|
2176
2195
|
// dist/commands/push-health-results.js
|
|
2177
2196
|
import chalk11 from "chalk";
|
|
2178
|
-
async function pushHealthResults(supabase, folderId, manifest) {
|
|
2197
|
+
async function pushHealthResults(supabase, folderId, manifest, deviceId) {
|
|
2179
2198
|
const { data: checks } = await supabase.from("env_health_checks").select("id, check_type, check_config").eq("folder_id", folderId).eq("enabled", true);
|
|
2180
2199
|
if (!checks?.length)
|
|
2181
2200
|
return;
|
|
@@ -2193,7 +2212,8 @@ async function pushHealthResults(supabase, folderId, manifest) {
|
|
|
2193
2212
|
check_id: chk.id,
|
|
2194
2213
|
status: localStatus === "present" ? "pass" : "fail",
|
|
2195
2214
|
message: localStatus === "present" ? "Set" : "Missing",
|
|
2196
|
-
ran_at: ranAt
|
|
2215
|
+
ran_at: ranAt,
|
|
2216
|
+
device_id: deviceId ?? null
|
|
2197
2217
|
});
|
|
2198
2218
|
}
|
|
2199
2219
|
} else if (chk.check_type === "file_exists") {
|
|
@@ -2201,7 +2221,8 @@ async function pushHealthResults(supabase, folderId, manifest) {
|
|
|
2201
2221
|
check_id: chk.id,
|
|
2202
2222
|
status: "pass",
|
|
2203
2223
|
message: "Found",
|
|
2204
|
-
ran_at: ranAt
|
|
2224
|
+
ran_at: ranAt,
|
|
2225
|
+
device_id: deviceId ?? null
|
|
2205
2226
|
});
|
|
2206
2227
|
} else if (chk.check_type === "gh_secret") {
|
|
2207
2228
|
const variable = config2.secret;
|
|
@@ -2211,7 +2232,8 @@ async function pushHealthResults(supabase, folderId, manifest) {
|
|
|
2211
2232
|
check_id: chk.id,
|
|
2212
2233
|
status: ghStatus === "present" ? "pass" : ghStatus === "missing" ? "fail" : "warn",
|
|
2213
2234
|
message: ghStatus === "present" ? "Exists" : ghStatus === "missing" ? "Missing" : "Unknown",
|
|
2214
|
-
ran_at: ranAt
|
|
2235
|
+
ran_at: ranAt,
|
|
2236
|
+
device_id: deviceId ?? null
|
|
2215
2237
|
});
|
|
2216
2238
|
} else if (chk.check_type === "vercel_env") {
|
|
2217
2239
|
const variable = config2.variable;
|
|
@@ -2226,14 +2248,16 @@ async function pushHealthResults(supabase, folderId, manifest) {
|
|
|
2226
2248
|
check_id: chk.id,
|
|
2227
2249
|
status: hasTarget ? "pass" : "warn",
|
|
2228
2250
|
message: hasTarget ? `Present (${target})` : `Present but not in ${target}`,
|
|
2229
|
-
ran_at: ranAt
|
|
2251
|
+
ran_at: ranAt,
|
|
2252
|
+
device_id: deviceId ?? null
|
|
2230
2253
|
});
|
|
2231
2254
|
} else {
|
|
2232
2255
|
results.push({
|
|
2233
2256
|
check_id: chk.id,
|
|
2234
2257
|
status: "fail",
|
|
2235
2258
|
message: `Not found in ${projectName}`,
|
|
2236
|
-
ran_at: ranAt
|
|
2259
|
+
ran_at: ranAt,
|
|
2260
|
+
device_id: deviceId ?? null
|
|
2237
2261
|
});
|
|
2238
2262
|
}
|
|
2239
2263
|
}
|
|
@@ -2369,10 +2393,12 @@ async function mapCommand(path, options) {
|
|
|
2369
2393
|
Local preview: ${htmlPath}`));
|
|
2370
2394
|
if (!options.offline) {
|
|
2371
2395
|
try {
|
|
2372
|
-
const { supabase } = await getAuthenticatedClient();
|
|
2396
|
+
const { supabase, userId } = await getAuthenticatedClient();
|
|
2373
2397
|
const { data: devicePaths } = await supabase.from("device_paths").select("folder_id, device_name").eq("path", projectRoot);
|
|
2374
2398
|
if (devicePaths?.length) {
|
|
2375
2399
|
const { folder_id, device_name } = devicePaths[0];
|
|
2400
|
+
const { data: deviceRow } = await supabase.from("devices").select("id").eq("user_id", userId).eq("device_name", device_name).single();
|
|
2401
|
+
const deviceId = deviceRow?.id;
|
|
2376
2402
|
const { data: proposedFiles } = await supabase.from("folder_files").select("id, file_path, proposed_at").eq("folder_id", folder_id).eq("proposed_for_deletion", true);
|
|
2377
2403
|
if (proposedFiles?.length && process.stdin.isTTY) {
|
|
2378
2404
|
const { checkbox } = await import("@inquirer/prompts");
|
|
@@ -2436,39 +2462,60 @@ ${proposedFiles.length} file(s) proposed for deletion:
|
|
|
2436
2462
|
if (result.doppler) {
|
|
2437
2463
|
updatePayload.doppler_json = result.doppler;
|
|
2438
2464
|
}
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
await pushToolings(supabase, folder_id, result.toolings);
|
|
2444
|
-
const manifestForHealth = result.envManifest ?? storedManifest;
|
|
2445
|
-
if (manifestForHealth) {
|
|
2446
|
-
await pushHealthResults(supabase, folder_id, manifestForHealth);
|
|
2465
|
+
try {
|
|
2466
|
+
const { error } = await supabase.from("claude_folders").update(updatePayload).eq("id", folder_id);
|
|
2467
|
+
if (error) {
|
|
2468
|
+
console.log(chalk12.dim(`Debug: claude_folders update skipped (${error.message})`));
|
|
2447
2469
|
}
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2470
|
+
} catch (err) {
|
|
2471
|
+
console.log(chalk12.dim(`Debug: claude_folders update skipped (${err instanceof Error ? err.message : String(err)})`));
|
|
2472
|
+
}
|
|
2473
|
+
if (deviceId) {
|
|
2474
|
+
await supabase.from("device_scans").upsert({
|
|
2475
|
+
folder_id,
|
|
2476
|
+
device_id: deviceId,
|
|
2477
|
+
user_id: userId,
|
|
2478
|
+
graph_json: result.graph,
|
|
2479
|
+
orphans_json: result.orphans,
|
|
2480
|
+
skills_table_json: result.skills,
|
|
2481
|
+
stale_files_json: result.staleFiles,
|
|
2482
|
+
broken_refs_json: result.brokenRefs,
|
|
2483
|
+
env_manifest_json: result.envManifest,
|
|
2484
|
+
doppler_json: result.doppler,
|
|
2485
|
+
marketplace_plugins_json: result.marketplacePlugins,
|
|
2486
|
+
data_hash: result.dataHash,
|
|
2487
|
+
scanned_at: result.scannedAt
|
|
2488
|
+
}, { onConflict: "folder_id,device_id" });
|
|
2489
|
+
}
|
|
2490
|
+
await pushToolings(supabase, folder_id, result.toolings);
|
|
2491
|
+
const manifestForHealth = result.envManifest ?? storedManifest;
|
|
2492
|
+
if (manifestForHealth) {
|
|
2493
|
+
await pushHealthResults(supabase, folder_id, manifestForHealth, deviceId);
|
|
2494
|
+
}
|
|
2495
|
+
await supabase.from("device_paths").update({ last_synced: (/* @__PURE__ */ new Date()).toISOString() }).eq("folder_id", folder_id).eq("device_name", device_name);
|
|
2496
|
+
await saveState({
|
|
2497
|
+
lastFolderId: folder_id,
|
|
2498
|
+
lastDeviceName: device_name,
|
|
2499
|
+
lastSyncAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2500
|
+
});
|
|
2501
|
+
console.log(chalk12.green("Synced to Supabase."));
|
|
2502
|
+
console.log(chalk12.cyan(`
|
|
2456
2503
|
https://www.md4ai.com/project/${folder_id}
|
|
2457
2504
|
`));
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
}
|
|
2470
|
-
console.log(chalk12.green(` Uploaded ${configFiles.length} config file(s).`));
|
|
2505
|
+
const graphPaths = result.graph.nodes.map((n) => n.filePath);
|
|
2506
|
+
const configFiles = await readClaudeConfigFiles(projectRoot, graphPaths);
|
|
2507
|
+
if (configFiles.length > 0) {
|
|
2508
|
+
for (const file of configFiles) {
|
|
2509
|
+
await supabase.from("folder_files").upsert({
|
|
2510
|
+
folder_id,
|
|
2511
|
+
file_path: file.filePath,
|
|
2512
|
+
content: file.content,
|
|
2513
|
+
size_bytes: file.sizeBytes,
|
|
2514
|
+
last_modified: file.lastModified,
|
|
2515
|
+
device_id: deviceId
|
|
2516
|
+
}, { onConflict: "folder_id,file_path,device_id" });
|
|
2471
2517
|
}
|
|
2518
|
+
console.log(chalk12.green(` Uploaded ${configFiles.length} config file(s).`));
|
|
2472
2519
|
}
|
|
2473
2520
|
} else {
|
|
2474
2521
|
console.log(chalk12.yellow("\nThis folder is not linked to a project on your dashboard."));
|
|
@@ -2480,7 +2527,7 @@ ${proposedFiles.length} file(s) proposed for deletion:
|
|
|
2480
2527
|
if (!shouldLink) {
|
|
2481
2528
|
console.log(chalk12.dim("Skipped \u2014 local preview still generated."));
|
|
2482
2529
|
} else {
|
|
2483
|
-
const { supabase: sb, userId } = await getAuthenticatedClient();
|
|
2530
|
+
const { supabase: sb, userId: userId2 } = await getAuthenticatedClient();
|
|
2484
2531
|
const { data: folders } = await sb.from("claude_folders").select("id, name").order("name");
|
|
2485
2532
|
const choices = [
|
|
2486
2533
|
{ name: "+ Create a new project", value: "__new__" },
|
|
@@ -2496,7 +2543,7 @@ ${proposedFiles.length} file(s) proposed for deletion:
|
|
|
2496
2543
|
message: "Project name:",
|
|
2497
2544
|
default: basename2(projectRoot)
|
|
2498
2545
|
});
|
|
2499
|
-
const { data: newFolder, error: createErr } = await sb.from("claude_folders").insert({ user_id:
|
|
2546
|
+
const { data: newFolder, error: createErr } = await sb.from("claude_folders").insert({ user_id: userId2, name: projectName }).select("id").single();
|
|
2500
2547
|
if (createErr || !newFolder) {
|
|
2501
2548
|
console.error(chalk12.red(`Failed to create project: ${createErr?.message}`));
|
|
2502
2549
|
return;
|
|
@@ -2509,33 +2556,59 @@ ${proposedFiles.length} file(s) proposed for deletion:
|
|
|
2509
2556
|
const deviceName = detectDeviceName();
|
|
2510
2557
|
const osType = detectOs2();
|
|
2511
2558
|
await sb.from("devices").upsert({
|
|
2512
|
-
user_id:
|
|
2559
|
+
user_id: userId2,
|
|
2513
2560
|
device_name: deviceName,
|
|
2514
2561
|
os_type: osType
|
|
2515
2562
|
}, { onConflict: "user_id,device_name" });
|
|
2563
|
+
const { data: inlineDeviceRow } = await sb.from("devices").select("id").eq("user_id", userId2).eq("device_name", deviceName).single();
|
|
2564
|
+
const inlineDeviceId = inlineDeviceRow?.id;
|
|
2516
2565
|
await sb.from("device_paths").upsert({
|
|
2517
|
-
user_id:
|
|
2566
|
+
user_id: userId2,
|
|
2518
2567
|
folder_id: folderId,
|
|
2519
2568
|
device_name: deviceName,
|
|
2520
2569
|
os_type: osType,
|
|
2521
2570
|
path: projectRoot,
|
|
2522
2571
|
last_synced: (/* @__PURE__ */ new Date()).toISOString()
|
|
2523
2572
|
}, { onConflict: "folder_id,device_name" });
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2573
|
+
try {
|
|
2574
|
+
const { error: inlineFolderErr } = await sb.from("claude_folders").update({
|
|
2575
|
+
graph_json: result.graph,
|
|
2576
|
+
orphans_json: result.orphans,
|
|
2577
|
+
broken_refs_json: result.brokenRefs,
|
|
2578
|
+
skills_table_json: result.skills,
|
|
2579
|
+
stale_files_json: result.staleFiles,
|
|
2580
|
+
env_manifest_json: result.envManifest,
|
|
2581
|
+
doppler_json: result.doppler,
|
|
2582
|
+
marketplace_plugins_json: result.marketplacePlugins,
|
|
2583
|
+
last_scanned: result.scannedAt,
|
|
2584
|
+
data_hash: result.dataHash
|
|
2585
|
+
}).eq("id", folderId);
|
|
2586
|
+
if (inlineFolderErr) {
|
|
2587
|
+
console.log(chalk12.dim(`Debug: claude_folders update skipped (${inlineFolderErr.message})`));
|
|
2588
|
+
}
|
|
2589
|
+
} catch (err) {
|
|
2590
|
+
console.log(chalk12.dim(`Debug: claude_folders update skipped (${err instanceof Error ? err.message : String(err)})`));
|
|
2591
|
+
}
|
|
2592
|
+
if (inlineDeviceId) {
|
|
2593
|
+
await sb.from("device_scans").upsert({
|
|
2594
|
+
folder_id: folderId,
|
|
2595
|
+
device_id: inlineDeviceId,
|
|
2596
|
+
user_id: userId2,
|
|
2597
|
+
graph_json: result.graph,
|
|
2598
|
+
orphans_json: result.orphans,
|
|
2599
|
+
skills_table_json: result.skills,
|
|
2600
|
+
stale_files_json: result.staleFiles,
|
|
2601
|
+
broken_refs_json: result.brokenRefs,
|
|
2602
|
+
env_manifest_json: result.envManifest,
|
|
2603
|
+
doppler_json: result.doppler,
|
|
2604
|
+
marketplace_plugins_json: result.marketplacePlugins,
|
|
2605
|
+
data_hash: result.dataHash,
|
|
2606
|
+
scanned_at: result.scannedAt
|
|
2607
|
+
}, { onConflict: "folder_id,device_id" });
|
|
2608
|
+
}
|
|
2536
2609
|
await pushToolings(sb, folderId, result.toolings);
|
|
2537
2610
|
if (result.envManifest) {
|
|
2538
|
-
await pushHealthResults(sb, folderId, result.envManifest);
|
|
2611
|
+
await pushHealthResults(sb, folderId, result.envManifest, inlineDeviceId);
|
|
2539
2612
|
}
|
|
2540
2613
|
const graphPaths2 = result.graph.nodes.map((n) => n.filePath);
|
|
2541
2614
|
const configFiles = await readClaudeConfigFiles(projectRoot, graphPaths2);
|
|
@@ -2545,8 +2618,9 @@ ${proposedFiles.length} file(s) proposed for deletion:
|
|
|
2545
2618
|
file_path: file.filePath,
|
|
2546
2619
|
content: file.content,
|
|
2547
2620
|
size_bytes: file.sizeBytes,
|
|
2548
|
-
last_modified: file.lastModified
|
|
2549
|
-
|
|
2621
|
+
last_modified: file.lastModified,
|
|
2622
|
+
device_id: inlineDeviceId
|
|
2623
|
+
}, { onConflict: "folder_id,file_path,device_id" });
|
|
2550
2624
|
}
|
|
2551
2625
|
await saveState({
|
|
2552
2626
|
lastFolderId: folderId,
|
|
@@ -2591,7 +2665,7 @@ function isValidProjectPath(p) {
|
|
|
2591
2665
|
return resolved.startsWith("/") && !resolved.includes("..") && existsSync11(resolved);
|
|
2592
2666
|
}
|
|
2593
2667
|
async function syncCommand(options) {
|
|
2594
|
-
const { supabase } = await getAuthenticatedClient();
|
|
2668
|
+
const { supabase, userId } = await getAuthenticatedClient();
|
|
2595
2669
|
if (options.all) {
|
|
2596
2670
|
const { data: devices, error } = await supabase.from("device_paths").select("folder_id, device_name, path");
|
|
2597
2671
|
if (error || !devices?.length) {
|
|
@@ -2610,16 +2684,40 @@ async function syncCommand(options) {
|
|
|
2610
2684
|
}
|
|
2611
2685
|
try {
|
|
2612
2686
|
const result = await scanProject(device.path);
|
|
2613
|
-
await supabase.from("
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2687
|
+
const { data: allDeviceRow } = await supabase.from("devices").select("id").eq("user_id", userId).eq("device_name", device.device_name).single();
|
|
2688
|
+
const allDeviceId = allDeviceRow?.id;
|
|
2689
|
+
try {
|
|
2690
|
+
const { error: allFolderErr } = await supabase.from("claude_folders").update({
|
|
2691
|
+
graph_json: result.graph,
|
|
2692
|
+
orphans_json: result.orphans,
|
|
2693
|
+
broken_refs_json: result.brokenRefs,
|
|
2694
|
+
skills_table_json: result.skills,
|
|
2695
|
+
stale_files_json: result.staleFiles,
|
|
2696
|
+
env_manifest_json: result.envManifest,
|
|
2697
|
+
last_scanned: result.scannedAt,
|
|
2698
|
+
data_hash: result.dataHash
|
|
2699
|
+
}).eq("id", device.folder_id);
|
|
2700
|
+
if (allFolderErr) {
|
|
2701
|
+
console.log(chalk15.dim(` Debug: claude_folders update skipped (${allFolderErr.message})`));
|
|
2702
|
+
}
|
|
2703
|
+
} catch (folderErr) {
|
|
2704
|
+
console.log(chalk15.dim(` Debug: claude_folders update skipped (${folderErr instanceof Error ? folderErr.message : String(folderErr)})`));
|
|
2705
|
+
}
|
|
2706
|
+
if (allDeviceId) {
|
|
2707
|
+
await supabase.from("device_scans").upsert({
|
|
2708
|
+
folder_id: device.folder_id,
|
|
2709
|
+
device_id: allDeviceId,
|
|
2710
|
+
user_id: userId,
|
|
2711
|
+
graph_json: result.graph,
|
|
2712
|
+
orphans_json: result.orphans,
|
|
2713
|
+
skills_table_json: result.skills,
|
|
2714
|
+
stale_files_json: result.staleFiles,
|
|
2715
|
+
broken_refs_json: result.brokenRefs,
|
|
2716
|
+
env_manifest_json: result.envManifest,
|
|
2717
|
+
data_hash: result.dataHash,
|
|
2718
|
+
scanned_at: result.scannedAt
|
|
2719
|
+
}, { onConflict: "folder_id,device_id" });
|
|
2720
|
+
}
|
|
2623
2721
|
await pushToolings(supabase, device.folder_id, result.toolings);
|
|
2624
2722
|
await supabase.from("device_paths").update({ last_synced: (/* @__PURE__ */ new Date()).toISOString() }).eq("folder_id", device.folder_id).eq("device_name", device.device_name);
|
|
2625
2723
|
console.log(chalk15.green(` Done: ${device.device_name}`));
|
|
@@ -2650,15 +2748,38 @@ async function syncCommand(options) {
|
|
|
2650
2748
|
console.log(chalk15.yellow(` ${proposedSingle.length} file(s) proposed for deletion \u2014 run \`md4ai scan\` to review.`));
|
|
2651
2749
|
}
|
|
2652
2750
|
const result = await scanProject(device.path);
|
|
2653
|
-
await supabase.from("
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2751
|
+
const { data: singleDeviceRow } = await supabase.from("devices").select("id").eq("user_id", userId).eq("device_name", device.device_name).single();
|
|
2752
|
+
const singleDeviceId = singleDeviceRow?.id;
|
|
2753
|
+
try {
|
|
2754
|
+
const { error: singleFolderErr } = await supabase.from("claude_folders").update({
|
|
2755
|
+
graph_json: result.graph,
|
|
2756
|
+
orphans_json: result.orphans,
|
|
2757
|
+
broken_refs_json: result.brokenRefs,
|
|
2758
|
+
skills_table_json: result.skills,
|
|
2759
|
+
stale_files_json: result.staleFiles,
|
|
2760
|
+
last_scanned: result.scannedAt,
|
|
2761
|
+
data_hash: result.dataHash
|
|
2762
|
+
}).eq("id", device.folder_id);
|
|
2763
|
+
if (singleFolderErr) {
|
|
2764
|
+
console.log(chalk15.dim(`Debug: claude_folders update skipped (${singleFolderErr.message})`));
|
|
2765
|
+
}
|
|
2766
|
+
} catch (err) {
|
|
2767
|
+
console.log(chalk15.dim(`Debug: claude_folders update skipped (${err instanceof Error ? err.message : String(err)})`));
|
|
2768
|
+
}
|
|
2769
|
+
if (singleDeviceId) {
|
|
2770
|
+
await supabase.from("device_scans").upsert({
|
|
2771
|
+
folder_id: device.folder_id,
|
|
2772
|
+
device_id: singleDeviceId,
|
|
2773
|
+
user_id: userId,
|
|
2774
|
+
graph_json: result.graph,
|
|
2775
|
+
orphans_json: result.orphans,
|
|
2776
|
+
skills_table_json: result.skills,
|
|
2777
|
+
stale_files_json: result.staleFiles,
|
|
2778
|
+
broken_refs_json: result.brokenRefs,
|
|
2779
|
+
data_hash: result.dataHash,
|
|
2780
|
+
scanned_at: result.scannedAt
|
|
2781
|
+
}, { onConflict: "folder_id,device_id" });
|
|
2782
|
+
}
|
|
2662
2783
|
await pushToolings(supabase, device.folder_id, result.toolings);
|
|
2663
2784
|
await supabase.from("device_paths").update({ last_synced: (/* @__PURE__ */ new Date()).toISOString() }).eq("folder_id", device.folder_id).eq("device_name", device.device_name);
|
|
2664
2785
|
await saveState({ lastSyncAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
@@ -3805,6 +3926,8 @@ Linking "${folder.name}" to this device...
|
|
|
3805
3926
|
device_name: deviceName,
|
|
3806
3927
|
os_type: osType
|
|
3807
3928
|
}, { onConflict: "user_id,device_name" });
|
|
3929
|
+
const { data: deviceRow } = await supabase.from("devices").select("id").eq("user_id", userId).eq("device_name", deviceName).single();
|
|
3930
|
+
const deviceId = deviceRow.id;
|
|
3808
3931
|
const { data: existing } = await supabase.from("device_paths").select("id").eq("folder_id", folder.id).eq("device_name", deviceName).maybeSingle();
|
|
3809
3932
|
if (existing) {
|
|
3810
3933
|
await supabase.from("device_paths").update({ path: cwd, os_type: osType, last_synced: (/* @__PURE__ */ new Date()).toISOString() }).eq("id", existing.id);
|
|
@@ -3832,21 +3955,40 @@ Linking "${folder.name}" to this device...
|
|
|
3832
3955
|
console.log(` Env Vars: ${result.envManifest?.variables.length ?? 0} (${result.envManifest ? "manifest found" : "no manifest"})`);
|
|
3833
3956
|
console.log(` Doppler: ${result.doppler ? `${result.doppler.configs.length} config(s) \u2014 ${result.doppler.project}` : "see above"}`);
|
|
3834
3957
|
console.log(` Plugins: ${result.marketplacePlugins.length} (${result.marketplacePlugins.reduce((n, p) => n + p.skills.length, 0)} skills)`);
|
|
3835
|
-
|
|
3958
|
+
try {
|
|
3959
|
+
const { error: scanErr } = await supabase.from("claude_folders").update({
|
|
3960
|
+
graph_json: result.graph,
|
|
3961
|
+
orphans_json: result.orphans,
|
|
3962
|
+
broken_refs_json: result.brokenRefs,
|
|
3963
|
+
skills_table_json: result.skills,
|
|
3964
|
+
stale_files_json: result.staleFiles,
|
|
3965
|
+
env_manifest_json: result.envManifest,
|
|
3966
|
+
doppler_json: result.doppler,
|
|
3967
|
+
marketplace_plugins_json: result.marketplacePlugins,
|
|
3968
|
+
last_scanned: result.scannedAt,
|
|
3969
|
+
data_hash: result.dataHash
|
|
3970
|
+
}).eq("id", folder.id);
|
|
3971
|
+
if (scanErr) {
|
|
3972
|
+
console.log(chalk16.dim(`Debug: claude_folders update skipped (${scanErr.message})`));
|
|
3973
|
+
}
|
|
3974
|
+
} catch (err) {
|
|
3975
|
+
console.log(chalk16.dim(`Debug: claude_folders update skipped (${err instanceof Error ? err.message : String(err)})`));
|
|
3976
|
+
}
|
|
3977
|
+
await supabase.from("device_scans").upsert({
|
|
3978
|
+
folder_id: folder.id,
|
|
3979
|
+
device_id: deviceId,
|
|
3980
|
+
user_id: userId,
|
|
3836
3981
|
graph_json: result.graph,
|
|
3837
3982
|
orphans_json: result.orphans,
|
|
3838
|
-
broken_refs_json: result.brokenRefs,
|
|
3839
3983
|
skills_table_json: result.skills,
|
|
3840
3984
|
stale_files_json: result.staleFiles,
|
|
3985
|
+
broken_refs_json: result.brokenRefs,
|
|
3841
3986
|
env_manifest_json: result.envManifest,
|
|
3842
3987
|
doppler_json: result.doppler,
|
|
3843
3988
|
marketplace_plugins_json: result.marketplacePlugins,
|
|
3844
|
-
|
|
3845
|
-
|
|
3846
|
-
}
|
|
3847
|
-
if (scanErr) {
|
|
3848
|
-
console.error(chalk16.yellow(`Scan upload warning: ${scanErr.message}`));
|
|
3849
|
-
}
|
|
3989
|
+
data_hash: result.dataHash,
|
|
3990
|
+
scanned_at: result.scannedAt
|
|
3991
|
+
}, { onConflict: "folder_id,device_id" });
|
|
3850
3992
|
await pushToolings(supabase, folder.id, result.toolings);
|
|
3851
3993
|
const graphPaths = result.graph.nodes.map((n) => n.filePath);
|
|
3852
3994
|
const configFiles = await readClaudeConfigFiles(cwd, graphPaths);
|
|
@@ -3857,8 +3999,9 @@ Linking "${folder.name}" to this device...
|
|
|
3857
3999
|
file_path: file.filePath,
|
|
3858
4000
|
content: file.content,
|
|
3859
4001
|
size_bytes: file.sizeBytes,
|
|
3860
|
-
last_modified: file.lastModified
|
|
3861
|
-
|
|
4002
|
+
last_modified: file.lastModified,
|
|
4003
|
+
device_id: deviceId
|
|
4004
|
+
}, { onConflict: "folder_id,file_path,device_id" });
|
|
3862
4005
|
}
|
|
3863
4006
|
console.log(chalk16.green(` Uploaded ${configFiles.length} config file(s).`));
|
|
3864
4007
|
}
|