md4ai 0.9.5 → 0.9.6
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 +64 -6
- package/package.json +1 -1
package/dist/index.bundled.js
CHANGED
|
@@ -233,6 +233,7 @@ import { resolve as resolve2, dirname, join as join2 } from "node:path";
|
|
|
233
233
|
import { homedir as homedir2 } from "node:os";
|
|
234
234
|
async function parseFileReferences(filePath, projectRoot) {
|
|
235
235
|
const refs = [];
|
|
236
|
+
const brokenRefs = [];
|
|
236
237
|
const content = await readFile2(filePath, "utf-8");
|
|
237
238
|
const relPath = filePath.startsWith(projectRoot) ? filePath.slice(projectRoot.length + 1) : filePath;
|
|
238
239
|
const markdownLinkPattern = /\[.*?\]\(([^)]+)\)/g;
|
|
@@ -254,20 +255,34 @@ async function parseFileReferences(filePath, projectRoot) {
|
|
|
254
255
|
const resolved = resolveTarget(target, filePath, projectRoot);
|
|
255
256
|
if (resolved && existsSync2(resolved)) {
|
|
256
257
|
addRef(refs, relPath, resolved, projectRoot);
|
|
258
|
+
} else if (resolved) {
|
|
259
|
+
const targetRel = resolved.startsWith(projectRoot) ? resolved.slice(projectRoot.length + 1) : resolved;
|
|
260
|
+
if (targetRel !== relPath) {
|
|
261
|
+
brokenRefs.push({ from: relPath, to: targetRel, rawRef: target });
|
|
262
|
+
}
|
|
257
263
|
}
|
|
258
264
|
}
|
|
259
265
|
}
|
|
260
266
|
if (filePath.endsWith(".json")) {
|
|
261
|
-
parseJsonPathReferences(content, relPath, projectRoot, refs);
|
|
267
|
+
parseJsonPathReferences(content, relPath, projectRoot, refs, brokenRefs);
|
|
262
268
|
}
|
|
263
269
|
const seen = /* @__PURE__ */ new Set();
|
|
264
|
-
|
|
270
|
+
const dedupedRefs = refs.filter((r) => {
|
|
265
271
|
const key = `${r.from}->${r.to}`;
|
|
266
272
|
if (seen.has(key))
|
|
267
273
|
return false;
|
|
268
274
|
seen.add(key);
|
|
269
275
|
return true;
|
|
270
276
|
});
|
|
277
|
+
const brokenSeen = /* @__PURE__ */ new Set();
|
|
278
|
+
const dedupedBroken = brokenRefs.filter((r) => {
|
|
279
|
+
const key = `${r.from}->${r.to}`;
|
|
280
|
+
if (brokenSeen.has(key))
|
|
281
|
+
return false;
|
|
282
|
+
brokenSeen.add(key);
|
|
283
|
+
return true;
|
|
284
|
+
});
|
|
285
|
+
return { refs: dedupedRefs, brokenRefs: dedupedBroken };
|
|
271
286
|
}
|
|
272
287
|
function resolveTarget(target, sourceFilePath, projectRoot) {
|
|
273
288
|
if (target.startsWith("~")) {
|
|
@@ -287,7 +302,7 @@ function addRef(refs, fromRel, resolvedAbsolute, projectRoot) {
|
|
|
287
302
|
refs.push({ from: fromRel, to: targetRel });
|
|
288
303
|
}
|
|
289
304
|
}
|
|
290
|
-
function parseJsonPathReferences(content, fromRel, projectRoot, refs) {
|
|
305
|
+
function parseJsonPathReferences(content, fromRel, projectRoot, refs, brokenRefs) {
|
|
291
306
|
let parsed;
|
|
292
307
|
try {
|
|
293
308
|
parsed = JSON.parse(content);
|
|
@@ -304,6 +319,8 @@ function parseJsonPathReferences(content, fromRel, projectRoot, refs) {
|
|
|
304
319
|
const resolved = join2(projectRoot, relTarget);
|
|
305
320
|
if (existsSync2(resolved)) {
|
|
306
321
|
addRef(refs, fromRel, resolved, projectRoot);
|
|
322
|
+
} else {
|
|
323
|
+
brokenRefs.push({ from: fromRel, to: relTarget, rawRef: relTarget });
|
|
307
324
|
}
|
|
308
325
|
}
|
|
309
326
|
}
|
|
@@ -316,6 +333,8 @@ function parseJsonPathReferences(content, fromRel, projectRoot, refs) {
|
|
|
316
333
|
const resolved = join2(projectRoot, target);
|
|
317
334
|
if (existsSync2(resolved)) {
|
|
318
335
|
addRef(refs, fromRel, resolved, projectRoot);
|
|
336
|
+
} else {
|
|
337
|
+
brokenRefs.push({ from: fromRel, to: target, rawRef: target });
|
|
319
338
|
}
|
|
320
339
|
}
|
|
321
340
|
});
|
|
@@ -1259,11 +1278,13 @@ async function scanProject(projectRoot) {
|
|
|
1259
1278
|
const allFiles = await discoverFiles(projectRoot);
|
|
1260
1279
|
const rootFiles = identifyRoots(allFiles, projectRoot);
|
|
1261
1280
|
const allRefs = [];
|
|
1281
|
+
const allBrokenRefs = [];
|
|
1262
1282
|
for (const file of allFiles) {
|
|
1263
1283
|
const fullPath = file.startsWith("/") ? file : join10(projectRoot, file);
|
|
1264
1284
|
try {
|
|
1265
|
-
const refs = await parseFileReferences(fullPath, projectRoot);
|
|
1285
|
+
const { refs, brokenRefs: brokenRefs2 } = await parseFileReferences(fullPath, projectRoot);
|
|
1266
1286
|
allRefs.push(...refs);
|
|
1287
|
+
allBrokenRefs.push(...brokenRefs2);
|
|
1267
1288
|
} catch {
|
|
1268
1289
|
}
|
|
1269
1290
|
}
|
|
@@ -1273,11 +1294,31 @@ async function scanProject(projectRoot) {
|
|
|
1273
1294
|
const skills = await parseSkills(projectRoot);
|
|
1274
1295
|
const toolings = await detectToolings(projectRoot);
|
|
1275
1296
|
const envManifest = await scanEnvManifest(projectRoot);
|
|
1276
|
-
const
|
|
1297
|
+
const depthMap = /* @__PURE__ */ new Map();
|
|
1298
|
+
const queue = [...rootFiles];
|
|
1299
|
+
for (const r of queue)
|
|
1300
|
+
depthMap.set(r, 0);
|
|
1301
|
+
while (queue.length > 0) {
|
|
1302
|
+
const current = queue.shift();
|
|
1303
|
+
const currentDepth = depthMap.get(current);
|
|
1304
|
+
for (const ref of allRefs) {
|
|
1305
|
+
if (ref.from === current && !depthMap.has(ref.to)) {
|
|
1306
|
+
depthMap.set(ref.to, currentDepth + 1);
|
|
1307
|
+
queue.push(ref.to);
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
const brokenRefs = allBrokenRefs.map((br) => ({
|
|
1312
|
+
...br,
|
|
1313
|
+
depth: depthMap.get(br.from) ?? 999
|
|
1314
|
+
}));
|
|
1315
|
+
brokenRefs.sort((a, b) => a.depth - b.depth || a.from.localeCompare(b.from));
|
|
1316
|
+
const scanData = JSON.stringify({ graph, orphans, brokenRefs, skills, staleFiles, toolings, envManifest });
|
|
1277
1317
|
const dataHash = createHash("sha256").update(scanData).digest("hex");
|
|
1278
1318
|
return {
|
|
1279
1319
|
graph,
|
|
1280
1320
|
orphans,
|
|
1321
|
+
brokenRefs,
|
|
1281
1322
|
skills,
|
|
1282
1323
|
staleFiles,
|
|
1283
1324
|
toolings,
|
|
@@ -1595,7 +1636,7 @@ var CURRENT_VERSION;
|
|
|
1595
1636
|
var init_check_update = __esm({
|
|
1596
1637
|
"dist/check-update.js"() {
|
|
1597
1638
|
"use strict";
|
|
1598
|
-
CURRENT_VERSION = true ? "0.9.
|
|
1639
|
+
CURRENT_VERSION = true ? "0.9.6" : "0.0.0-dev";
|
|
1599
1640
|
}
|
|
1600
1641
|
});
|
|
1601
1642
|
|
|
@@ -1764,12 +1805,23 @@ async function mapCommand(path, options) {
|
|
|
1764
1805
|
const result = await scanProject(projectRoot);
|
|
1765
1806
|
console.log(` Files found: ${result.graph.nodes.length}`);
|
|
1766
1807
|
console.log(` References: ${result.graph.edges.length}`);
|
|
1808
|
+
console.log(` Broken refs: ${result.brokenRefs.length}`);
|
|
1767
1809
|
console.log(` Orphans: ${result.orphans.length}`);
|
|
1768
1810
|
console.log(` Stale files: ${result.staleFiles.length}`);
|
|
1769
1811
|
console.log(` Skills: ${result.skills.length}`);
|
|
1770
1812
|
console.log(` Toolings: ${result.toolings.length}`);
|
|
1771
1813
|
console.log(` Env Vars: ${result.envManifest?.variables.length ?? 0} (${result.envManifest ? "manifest found" : "no manifest"})`);
|
|
1772
1814
|
console.log(` Data hash: ${result.dataHash.slice(0, 12)}...`);
|
|
1815
|
+
if (result.brokenRefs.length > 0) {
|
|
1816
|
+
console.log(chalk11.red(`
|
|
1817
|
+
Warning: ${result.brokenRefs.length} broken reference(s) found:`));
|
|
1818
|
+
for (const br of result.brokenRefs.slice(0, 5)) {
|
|
1819
|
+
console.log(chalk11.red(` ${br.from} -> ${br.to}`));
|
|
1820
|
+
}
|
|
1821
|
+
if (result.brokenRefs.length > 5) {
|
|
1822
|
+
console.log(chalk11.red(` ... and ${result.brokenRefs.length - 5} more`));
|
|
1823
|
+
}
|
|
1824
|
+
}
|
|
1773
1825
|
const outputDir = resolve3(projectRoot, "output");
|
|
1774
1826
|
if (!existsSync7(outputDir)) {
|
|
1775
1827
|
await mkdir2(outputDir, { recursive: true });
|
|
@@ -1823,6 +1875,7 @@ ${proposedFiles.length} file(s) proposed for deletion:
|
|
|
1823
1875
|
const { error } = await supabase.from("claude_folders").update({
|
|
1824
1876
|
graph_json: result.graph,
|
|
1825
1877
|
orphans_json: result.orphans,
|
|
1878
|
+
broken_refs_json: result.brokenRefs,
|
|
1826
1879
|
skills_table_json: result.skills,
|
|
1827
1880
|
stale_files_json: result.staleFiles,
|
|
1828
1881
|
env_manifest_json: result.envManifest,
|
|
@@ -1914,6 +1967,7 @@ ${proposedFiles.length} file(s) proposed for deletion:
|
|
|
1914
1967
|
await sb.from("claude_folders").update({
|
|
1915
1968
|
graph_json: result.graph,
|
|
1916
1969
|
orphans_json: result.orphans,
|
|
1970
|
+
broken_refs_json: result.brokenRefs,
|
|
1917
1971
|
skills_table_json: result.skills,
|
|
1918
1972
|
stale_files_json: result.staleFiles,
|
|
1919
1973
|
env_manifest_json: result.envManifest,
|
|
@@ -1989,6 +2043,7 @@ async function syncCommand(options) {
|
|
|
1989
2043
|
await supabase.from("claude_folders").update({
|
|
1990
2044
|
graph_json: result.graph,
|
|
1991
2045
|
orphans_json: result.orphans,
|
|
2046
|
+
broken_refs_json: result.brokenRefs,
|
|
1992
2047
|
skills_table_json: result.skills,
|
|
1993
2048
|
stale_files_json: result.staleFiles,
|
|
1994
2049
|
env_manifest_json: result.envManifest,
|
|
@@ -2024,6 +2079,7 @@ async function syncCommand(options) {
|
|
|
2024
2079
|
await supabase.from("claude_folders").update({
|
|
2025
2080
|
graph_json: result.graph,
|
|
2026
2081
|
orphans_json: result.orphans,
|
|
2082
|
+
broken_refs_json: result.brokenRefs,
|
|
2027
2083
|
skills_table_json: result.skills,
|
|
2028
2084
|
stale_files_json: result.staleFiles,
|
|
2029
2085
|
last_scanned: result.scannedAt,
|
|
@@ -2651,6 +2707,7 @@ async function checkPendingRescans(supabase, deviceId, deviceName) {
|
|
|
2651
2707
|
await supabase.from("claude_folders").update({
|
|
2652
2708
|
graph_json: result.graph,
|
|
2653
2709
|
orphans_json: result.orphans,
|
|
2710
|
+
broken_refs_json: result.brokenRefs,
|
|
2654
2711
|
skills_table_json: result.skills,
|
|
2655
2712
|
stale_files_json: result.staleFiles,
|
|
2656
2713
|
env_manifest_json: result.envManifest,
|
|
@@ -3066,6 +3123,7 @@ Linking "${folder.name}" to this device...
|
|
|
3066
3123
|
const { error: scanErr } = await supabase.from("claude_folders").update({
|
|
3067
3124
|
graph_json: result.graph,
|
|
3068
3125
|
orphans_json: result.orphans,
|
|
3126
|
+
broken_refs_json: result.brokenRefs,
|
|
3069
3127
|
skills_table_json: result.skills,
|
|
3070
3128
|
stale_files_json: result.staleFiles,
|
|
3071
3129
|
env_manifest_json: result.envManifest,
|