md4ai 0.14.0 → 0.15.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 +87 -45
- package/package.json +2 -2
package/dist/index.bundled.js
CHANGED
|
@@ -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.
|
|
125
|
+
CURRENT_VERSION = true ? "0.15.0" : "0.0.0-dev";
|
|
126
126
|
}
|
|
127
127
|
});
|
|
128
128
|
|
|
@@ -1109,7 +1109,9 @@ var init_tooling_detector = __esm({
|
|
|
1109
1109
|
{ name: "pnpm", command: "pnpm", args: ["--version"], conditionFile: "pnpm-lock.yaml" },
|
|
1110
1110
|
{ name: "supabase-cli", command: "npx", args: ["supabase", "--version"] },
|
|
1111
1111
|
{ name: "vercel-cli", command: "npx", args: ["vercel", "--version"] },
|
|
1112
|
-
{ name: "claude-code", command: "claude", args: ["--version"] }
|
|
1112
|
+
{ name: "claude-code", command: "claude", args: ["--version"] },
|
|
1113
|
+
{ name: "gh", command: "gh", args: ["--version"] },
|
|
1114
|
+
{ name: "git", command: "git", args: ["--version"] }
|
|
1113
1115
|
];
|
|
1114
1116
|
}
|
|
1115
1117
|
});
|
|
@@ -1151,11 +1153,23 @@ var init_auth2 = __esm({
|
|
|
1151
1153
|
});
|
|
1152
1154
|
|
|
1153
1155
|
// dist/vercel/discover-projects.js
|
|
1154
|
-
import { readFile as readFile6,
|
|
1156
|
+
import { readFile as readFile6, readdir as readdir2 } from "node:fs/promises";
|
|
1155
1157
|
import { join as join8, dirname as dirname2, relative } from "node:path";
|
|
1156
1158
|
async function discoverVercelProjects(projectRoot) {
|
|
1157
1159
|
const found = /* @__PURE__ */ new Map();
|
|
1158
|
-
|
|
1160
|
+
let entries;
|
|
1161
|
+
try {
|
|
1162
|
+
entries = await readdir2(projectRoot, { recursive: true, withFileTypes: true });
|
|
1163
|
+
} catch {
|
|
1164
|
+
return [];
|
|
1165
|
+
}
|
|
1166
|
+
for (const entry of entries) {
|
|
1167
|
+
if (!entry.isFile() || entry.name !== "project.json")
|
|
1168
|
+
continue;
|
|
1169
|
+
const parentName = typeof entry.parentPath === "string" ? entry.parentPath : entry.path;
|
|
1170
|
+
if (!parentName.endsWith(".vercel"))
|
|
1171
|
+
continue;
|
|
1172
|
+
const filePath = join8(parentName, entry.name);
|
|
1159
1173
|
try {
|
|
1160
1174
|
const data = await readFile6(filePath, "utf-8");
|
|
1161
1175
|
const parsed = JSON.parse(data);
|
|
@@ -1250,7 +1264,7 @@ var init_fetch_env_vars = __esm({
|
|
|
1250
1264
|
});
|
|
1251
1265
|
|
|
1252
1266
|
// dist/scanner/env-manifest-scanner.js
|
|
1253
|
-
import { readFile as readFile7,
|
|
1267
|
+
import { readFile as readFile7, readdir as readdir3 } from "node:fs/promises";
|
|
1254
1268
|
import { execFile } from "node:child_process";
|
|
1255
1269
|
import { promisify } from "node:util";
|
|
1256
1270
|
import { join as join9, relative as relative2 } from "node:path";
|
|
@@ -1519,21 +1533,23 @@ async function parseWorkflowSecrets(projectRoot) {
|
|
|
1519
1533
|
return [];
|
|
1520
1534
|
const refs = [];
|
|
1521
1535
|
const secretRe = /\$\{\{\s*secrets\.([A-Za-z_][A-Za-z0-9_]*)\s*\}\}/g;
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1536
|
+
const files = await readdir3(workflowsDir);
|
|
1537
|
+
for (const file of files) {
|
|
1538
|
+
if (!file.endsWith(".yml") && !file.endsWith(".yaml"))
|
|
1539
|
+
continue;
|
|
1540
|
+
const filePath = join9(workflowsDir, file);
|
|
1541
|
+
const content = await readFile7(filePath, "utf-8");
|
|
1542
|
+
const secrets = /* @__PURE__ */ new Set();
|
|
1543
|
+
let m;
|
|
1544
|
+
while ((m = secretRe.exec(content)) !== null) {
|
|
1545
|
+
secrets.add(m[1]);
|
|
1546
|
+
}
|
|
1547
|
+
secretRe.lastIndex = 0;
|
|
1548
|
+
if (secrets.size > 0) {
|
|
1549
|
+
refs.push({
|
|
1550
|
+
workflowFile: relative2(projectRoot, filePath),
|
|
1551
|
+
secretsUsed: [...secrets].sort()
|
|
1552
|
+
});
|
|
1537
1553
|
}
|
|
1538
1554
|
}
|
|
1539
1555
|
return refs;
|
|
@@ -1660,7 +1676,7 @@ var init_env_manifest_scanner = __esm({
|
|
|
1660
1676
|
});
|
|
1661
1677
|
|
|
1662
1678
|
// dist/scanner/marketplace-scanner.js
|
|
1663
|
-
import { readFile as readFile8, readdir as
|
|
1679
|
+
import { readFile as readFile8, readdir as readdir4, stat } from "node:fs/promises";
|
|
1664
1680
|
import { join as join10, resolve as resolve3 } from "node:path";
|
|
1665
1681
|
import { existsSync as existsSync5 } from "node:fs";
|
|
1666
1682
|
import { homedir as homedir6 } from "node:os";
|
|
@@ -1729,7 +1745,7 @@ async function discoverSkills(installPath) {
|
|
|
1729
1745
|
return [];
|
|
1730
1746
|
const skills = [];
|
|
1731
1747
|
try {
|
|
1732
|
-
const entries = await
|
|
1748
|
+
const entries = await readdir4(skillsDir, { withFileTypes: true });
|
|
1733
1749
|
for (const entry of entries) {
|
|
1734
1750
|
if (!entry.isDirectory())
|
|
1735
1751
|
continue;
|
|
@@ -1986,7 +2002,7 @@ var init_doppler_scanner = __esm({
|
|
|
1986
2002
|
});
|
|
1987
2003
|
|
|
1988
2004
|
// dist/scanner/index.js
|
|
1989
|
-
import { readdir as
|
|
2005
|
+
import { readdir as readdir5 } from "node:fs/promises";
|
|
1990
2006
|
import { join as join12, relative as relative3 } from "node:path";
|
|
1991
2007
|
import { existsSync as existsSync7 } from "node:fs";
|
|
1992
2008
|
import { homedir as homedir7 } from "node:os";
|
|
@@ -2073,7 +2089,7 @@ async function discoverFiles(projectRoot) {
|
|
|
2073
2089
|
return [...new Set(files)];
|
|
2074
2090
|
}
|
|
2075
2091
|
async function walkDir(dir, projectRoot, files) {
|
|
2076
|
-
const entries = await
|
|
2092
|
+
const entries = await readdir5(dir, { withFileTypes: true });
|
|
2077
2093
|
for (const entry of entries) {
|
|
2078
2094
|
const fullPath = join12(dir, entry.name);
|
|
2079
2095
|
if (entry.isDirectory()) {
|
|
@@ -2274,12 +2290,14 @@ var init_html_generator = __esm({
|
|
|
2274
2290
|
});
|
|
2275
2291
|
|
|
2276
2292
|
// dist/commands/push-toolings.js
|
|
2277
|
-
async function pushToolings(supabase, folderId, toolings) {
|
|
2293
|
+
async function pushToolings(supabase, folderId, toolings, deviceId) {
|
|
2278
2294
|
if (!toolings.length)
|
|
2279
2295
|
return;
|
|
2280
2296
|
const { data: registry } = await supabase.from("tools_registry").select("id, name");
|
|
2281
2297
|
const registryMap = new Map((registry ?? []).map((r) => [r.name, r.id]));
|
|
2282
|
-
|
|
2298
|
+
const projectToolings = toolings.filter((t) => t.detection_source !== "cli");
|
|
2299
|
+
const deviceToolings = toolings.filter((t) => t.detection_source === "cli");
|
|
2300
|
+
for (const tooling of projectToolings) {
|
|
2283
2301
|
const toolId = registryMap.get(tooling.tool_name) ?? null;
|
|
2284
2302
|
await supabase.from("project_toolings").upsert({
|
|
2285
2303
|
folder_id: folderId,
|
|
@@ -2290,6 +2308,19 @@ async function pushToolings(supabase, folderId, toolings) {
|
|
|
2290
2308
|
detected_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
2291
2309
|
}, { onConflict: "folder_id,tool_name,detection_source" });
|
|
2292
2310
|
}
|
|
2311
|
+
if (deviceId && deviceToolings.length) {
|
|
2312
|
+
for (const tooling of deviceToolings) {
|
|
2313
|
+
const toolId = registryMap.get(tooling.tool_name) ?? null;
|
|
2314
|
+
await supabase.from("device_toolings").upsert({
|
|
2315
|
+
device_id: deviceId,
|
|
2316
|
+
tool_id: toolId,
|
|
2317
|
+
tool_name: tooling.tool_name,
|
|
2318
|
+
detected_version: tooling.detected_version,
|
|
2319
|
+
detection_source: tooling.detection_source,
|
|
2320
|
+
detected_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
2321
|
+
}, { onConflict: "device_id,tool_name,detection_source" });
|
|
2322
|
+
}
|
|
2323
|
+
}
|
|
2293
2324
|
}
|
|
2294
2325
|
var init_push_toolings = __esm({
|
|
2295
2326
|
"dist/commands/push-toolings.js"() {
|
|
@@ -2560,7 +2591,7 @@ ${proposedFiles.length} file(s) proposed for deletion:
|
|
|
2560
2591
|
cli_version: CURRENT_VERSION
|
|
2561
2592
|
}, { onConflict: "folder_id,device_id" });
|
|
2562
2593
|
}
|
|
2563
|
-
await pushToolings(supabase, folder_id, result.toolings);
|
|
2594
|
+
await pushToolings(supabase, folder_id, result.toolings, deviceId);
|
|
2564
2595
|
const manifestForHealth = result.envManifest ?? storedManifest;
|
|
2565
2596
|
if (manifestForHealth) {
|
|
2566
2597
|
await pushHealthResults(supabase, folder_id, manifestForHealth, deviceId);
|
|
@@ -2680,7 +2711,7 @@ ${proposedFiles.length} file(s) proposed for deletion:
|
|
|
2680
2711
|
cli_version: CURRENT_VERSION
|
|
2681
2712
|
}, { onConflict: "folder_id,device_id" });
|
|
2682
2713
|
}
|
|
2683
|
-
await pushToolings(sb, folderId, result.toolings);
|
|
2714
|
+
await pushToolings(sb, folderId, result.toolings, inlineDeviceId);
|
|
2684
2715
|
if (result.envManifest) {
|
|
2685
2716
|
await pushHealthResults(sb, folderId, result.envManifest, inlineDeviceId);
|
|
2686
2717
|
}
|
|
@@ -2793,7 +2824,7 @@ async function syncCommand(options) {
|
|
|
2793
2824
|
cli_version: CURRENT_VERSION
|
|
2794
2825
|
}, { onConflict: "folder_id,device_id" });
|
|
2795
2826
|
}
|
|
2796
|
-
await pushToolings(supabase, device.folder_id, result.toolings);
|
|
2827
|
+
await pushToolings(supabase, device.folder_id, result.toolings, allDeviceId);
|
|
2797
2828
|
await supabase.from("device_paths").update({ last_synced: (/* @__PURE__ */ new Date()).toISOString() }).eq("folder_id", device.folder_id).eq("device_name", device.device_name);
|
|
2798
2829
|
console.log(chalk15.green(` Done: ${device.device_name}`));
|
|
2799
2830
|
} catch (err) {
|
|
@@ -2856,7 +2887,7 @@ async function syncCommand(options) {
|
|
|
2856
2887
|
cli_version: CURRENT_VERSION
|
|
2857
2888
|
}, { onConflict: "folder_id,device_id" });
|
|
2858
2889
|
}
|
|
2859
|
-
await pushToolings(supabase, device.folder_id, result.toolings);
|
|
2890
|
+
await pushToolings(supabase, device.folder_id, result.toolings, singleDeviceId);
|
|
2860
2891
|
await supabase.from("device_paths").update({ last_synced: (/* @__PURE__ */ new Date()).toISOString() }).eq("folder_id", device.folder_id).eq("device_name", device.device_name);
|
|
2861
2892
|
await saveState({ lastSyncAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
2862
2893
|
console.log(chalk15.green("Synced."));
|
|
@@ -2878,7 +2909,7 @@ import { readFile as readFile12 } from "node:fs/promises";
|
|
|
2878
2909
|
import { join as join15 } from "node:path";
|
|
2879
2910
|
import { homedir as homedir9 } from "node:os";
|
|
2880
2911
|
import { existsSync as existsSync13 } from "node:fs";
|
|
2881
|
-
import { readdir as
|
|
2912
|
+
import { readdir as readdir6 } from "node:fs/promises";
|
|
2882
2913
|
async function readJsonSafe(path) {
|
|
2883
2914
|
try {
|
|
2884
2915
|
if (!existsSync13(path))
|
|
@@ -2954,14 +2985,14 @@ async function readAllMcpConfigs() {
|
|
|
2954
2985
|
const pluginsBase = join15(home, ".claude", "plugins", "marketplaces");
|
|
2955
2986
|
if (existsSync13(pluginsBase)) {
|
|
2956
2987
|
try {
|
|
2957
|
-
const marketplaces = await
|
|
2988
|
+
const marketplaces = await readdir6(pluginsBase, { withFileTypes: true });
|
|
2958
2989
|
for (const mp of marketplaces) {
|
|
2959
2990
|
if (!mp.isDirectory())
|
|
2960
2991
|
continue;
|
|
2961
2992
|
const extDir = join15(pluginsBase, mp.name, "external_plugins");
|
|
2962
2993
|
if (!existsSync13(extDir))
|
|
2963
2994
|
continue;
|
|
2964
|
-
const plugins = await
|
|
2995
|
+
const plugins = await readdir6(extDir, { withFileTypes: true });
|
|
2965
2996
|
for (const plugin of plugins) {
|
|
2966
2997
|
if (!plugin.isDirectory())
|
|
2967
2998
|
continue;
|
|
@@ -2975,16 +3006,16 @@ async function readAllMcpConfigs() {
|
|
|
2975
3006
|
const cacheBase = join15(home, ".claude", "plugins", "cache");
|
|
2976
3007
|
if (existsSync13(cacheBase)) {
|
|
2977
3008
|
try {
|
|
2978
|
-
const registries = await
|
|
3009
|
+
const registries = await readdir6(cacheBase, { withFileTypes: true });
|
|
2979
3010
|
for (const reg of registries) {
|
|
2980
3011
|
if (!reg.isDirectory())
|
|
2981
3012
|
continue;
|
|
2982
3013
|
const regDir = join15(cacheBase, reg.name);
|
|
2983
|
-
const plugins = await
|
|
3014
|
+
const plugins = await readdir6(regDir, { withFileTypes: true });
|
|
2984
3015
|
for (const plugin of plugins) {
|
|
2985
3016
|
if (!plugin.isDirectory())
|
|
2986
3017
|
continue;
|
|
2987
|
-
const versionDirs = await
|
|
3018
|
+
const versionDirs = await readdir6(join15(regDir, plugin.name), { withFileTypes: true });
|
|
2988
3019
|
for (const ver of versionDirs) {
|
|
2989
3020
|
if (!ver.isDirectory())
|
|
2990
3021
|
continue;
|
|
@@ -3581,7 +3612,7 @@ async function checkPendingRescans(supabase, deviceId, deviceName) {
|
|
|
3581
3612
|
data_hash: result.dataHash,
|
|
3582
3613
|
rescan_requested_at: null
|
|
3583
3614
|
}).eq("id", folder.id);
|
|
3584
|
-
await pushToolings(supabase, folder.id, result.toolings);
|
|
3615
|
+
await pushToolings(supabase, folder.id, result.toolings, deviceId);
|
|
3585
3616
|
await supabase.from("device_paths").update({ last_synced: (/* @__PURE__ */ new Date()).toISOString() }).eq("folder_id", folder.id).eq("device_name", deviceName);
|
|
3586
3617
|
} catch {
|
|
3587
3618
|
await supabase.from("claude_folders").update({ rescan_requested_at: null }).eq("id", folder.id);
|
|
@@ -4072,7 +4103,7 @@ Linking "${folder.name}" to this device...
|
|
|
4072
4103
|
scanned_at: result.scannedAt,
|
|
4073
4104
|
cli_version: CURRENT_VERSION
|
|
4074
4105
|
}, { onConflict: "folder_id,device_id" });
|
|
4075
|
-
await pushToolings(supabase, folder.id, result.toolings);
|
|
4106
|
+
await pushToolings(supabase, folder.id, result.toolings, deviceId);
|
|
4076
4107
|
const graphPaths = result.graph.nodes.map((n) => n.filePath);
|
|
4077
4108
|
const configFiles = await readClaudeConfigFiles(cwd, graphPaths);
|
|
4078
4109
|
if (configFiles.length > 0) {
|
|
@@ -5023,18 +5054,29 @@ initSentry();
|
|
|
5023
5054
|
if (process.argv.length <= 2) {
|
|
5024
5055
|
void startCommand();
|
|
5025
5056
|
} else {
|
|
5026
|
-
program.
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
|
|
5031
|
-
|
|
5057
|
+
program.parseAsync().then(() => {
|
|
5058
|
+
const ran = program.args[0];
|
|
5059
|
+
const skipAutoCheck = ["update", "check-update", "mcp-watch", "start"];
|
|
5060
|
+
if (!skipAutoCheck.includes(ran)) {
|
|
5061
|
+
autoCheckForUpdate();
|
|
5062
|
+
}
|
|
5063
|
+
}).catch(async (err) => {
|
|
5064
|
+
captureException2(err);
|
|
5065
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
5066
|
+
console.error(`\x1B[31mError: ${msg}\x1B[0m`);
|
|
5067
|
+
await flushSentry();
|
|
5068
|
+
process.exit(1);
|
|
5069
|
+
});
|
|
5032
5070
|
}
|
|
5033
5071
|
process.on("uncaughtException", async (err) => {
|
|
5034
5072
|
captureException2(err);
|
|
5035
5073
|
await flushSentry();
|
|
5036
5074
|
process.exit(1);
|
|
5037
5075
|
});
|
|
5038
|
-
process.on("unhandledRejection", (reason) => {
|
|
5076
|
+
process.on("unhandledRejection", async (reason) => {
|
|
5039
5077
|
captureException2(reason);
|
|
5078
|
+
const msg = reason instanceof Error ? reason.message : String(reason);
|
|
5079
|
+
console.error(`\x1B[31mError: ${msg}\x1B[0m`);
|
|
5080
|
+
await flushSentry();
|
|
5081
|
+
process.exit(1);
|
|
5040
5082
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "md4ai",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "CLI for MD4AI — scan Claude projects and sync to your dashboard",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"directory": "cli"
|
|
32
32
|
},
|
|
33
33
|
"engines": {
|
|
34
|
-
"node": ">=
|
|
34
|
+
"node": ">=20"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@inquirer/prompts": "^8.3.0",
|