artifact-graph 0.8.4 → 0.9.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/CHANGELOG.md +18 -0
- package/dist/cli.js +108 -81
- package/dist/index.cjs +147 -119
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +95 -68
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -362,6 +362,41 @@ var init_glob_matcher = __esm({
|
|
|
362
362
|
}
|
|
363
363
|
});
|
|
364
364
|
|
|
365
|
+
// src/file-walker.ts
|
|
366
|
+
async function walkFiles(root, current = root, readDirectory = defaultReadDirectory) {
|
|
367
|
+
let entries;
|
|
368
|
+
try {
|
|
369
|
+
entries = await readDirectory(current, { withFileTypes: true });
|
|
370
|
+
} catch (error) {
|
|
371
|
+
if (current !== root && error.code === "ENOENT") {
|
|
372
|
+
return [];
|
|
373
|
+
}
|
|
374
|
+
throw error;
|
|
375
|
+
}
|
|
376
|
+
const files = [];
|
|
377
|
+
for (const entry of entries) {
|
|
378
|
+
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === ".git" || entry.name === ".artifact-graph") {
|
|
379
|
+
continue;
|
|
380
|
+
}
|
|
381
|
+
const fullPath = (0, import_node_path.join)(current, entry.name);
|
|
382
|
+
if (entry.isDirectory()) {
|
|
383
|
+
files.push(...await walkFiles(root, fullPath, readDirectory));
|
|
384
|
+
} else {
|
|
385
|
+
files.push((0, import_node_path.relative)(root, fullPath).split("\\").join("/"));
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
return files;
|
|
389
|
+
}
|
|
390
|
+
var import_promises, import_node_path, defaultReadDirectory;
|
|
391
|
+
var init_file_walker = __esm({
|
|
392
|
+
"src/file-walker.ts"() {
|
|
393
|
+
"use strict";
|
|
394
|
+
import_promises = require("fs/promises");
|
|
395
|
+
import_node_path = require("path");
|
|
396
|
+
defaultReadDirectory = import_promises.readdir;
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
|
|
365
400
|
// src/target-selector.ts
|
|
366
401
|
function parseTargetSelector(value) {
|
|
367
402
|
const separator = value.indexOf(":");
|
|
@@ -965,14 +1000,14 @@ async function auditSingleTarget(target, graph, options) {
|
|
|
965
1000
|
const fmt = options.format ?? "markdown";
|
|
966
1001
|
const ext = fmt === "json" ? "json" : "md";
|
|
967
1002
|
const filename = `${target.type}-${target.id}.packet.${ext}`;
|
|
968
|
-
const outPath = (0,
|
|
1003
|
+
const outPath = (0, import_node_path2.join)(options.outDir, filename);
|
|
969
1004
|
let content;
|
|
970
1005
|
if (fmt === "json") {
|
|
971
1006
|
content = JSON.stringify(packet, null, 2) + "\n";
|
|
972
1007
|
} else {
|
|
973
1008
|
content = renderPacketMarkdown(packet);
|
|
974
1009
|
}
|
|
975
|
-
await (0,
|
|
1010
|
+
await (0, import_promises2.writeFile)(outPath, content, "utf-8");
|
|
976
1011
|
entry.outputPath = outPath;
|
|
977
1012
|
}
|
|
978
1013
|
} catch (error) {
|
|
@@ -993,7 +1028,7 @@ async function auditPackets(root, targets, options, graph) {
|
|
|
993
1028
|
}
|
|
994
1029
|
}
|
|
995
1030
|
if (options.outDir) {
|
|
996
|
-
await (0,
|
|
1031
|
+
await (0, import_promises2.mkdir)(options.outDir, { recursive: true });
|
|
997
1032
|
}
|
|
998
1033
|
const sampleSet = options.sampleTargets ? new Set(options.sampleTargets) : null;
|
|
999
1034
|
const sampleOutputPaths = [];
|
|
@@ -1045,8 +1080,8 @@ async function auditPackets(root, targets, options, graph) {
|
|
|
1045
1080
|
...isCompact ? { summaryDetail: "compact", countsByType } : {}
|
|
1046
1081
|
};
|
|
1047
1082
|
if (options.outDir) {
|
|
1048
|
-
const summaryPath = (0,
|
|
1049
|
-
await (0,
|
|
1083
|
+
const summaryPath = (0, import_node_path2.join)(options.outDir, "summary.json");
|
|
1084
|
+
await (0, import_promises2.writeFile)(summaryPath, JSON.stringify(summary, null, 2) + "\n", "utf-8");
|
|
1050
1085
|
}
|
|
1051
1086
|
return summary;
|
|
1052
1087
|
}
|
|
@@ -1072,14 +1107,14 @@ async function discoverAndAuditPackets(root, options) {
|
|
|
1072
1107
|
universalBaseline: effectiveBaseline
|
|
1073
1108
|
}, graph);
|
|
1074
1109
|
}
|
|
1075
|
-
var
|
|
1110
|
+
var import_promises2, import_node_path2, VALID_TYPES, VALID_TYPES_LABEL;
|
|
1076
1111
|
var init_packet_audit = __esm({
|
|
1077
1112
|
"src/packet-audit.ts"() {
|
|
1078
1113
|
"use strict";
|
|
1079
1114
|
init_index();
|
|
1080
1115
|
init_packet_validator();
|
|
1081
|
-
|
|
1082
|
-
|
|
1116
|
+
import_promises2 = require("fs/promises");
|
|
1117
|
+
import_node_path2 = require("path");
|
|
1083
1118
|
VALID_TYPES = new Set(VALID_PACKET_TARGET_TYPES);
|
|
1084
1119
|
VALID_TYPES_LABEL = VALID_PACKET_TARGET_TYPES.join(", ");
|
|
1085
1120
|
}
|
|
@@ -1551,7 +1586,7 @@ async function auditVersionLock(root, lockPath = VERSION_LOCK_PATH, graph, confi
|
|
|
1551
1586
|
for (const entry of lock.locks) {
|
|
1552
1587
|
if (entry.kind !== "verifies") continue;
|
|
1553
1588
|
const sourcePath = entry.source.path;
|
|
1554
|
-
const fullSourcePath = (0,
|
|
1589
|
+
const fullSourcePath = (0, import_node_path3.join)(root, sourcePath);
|
|
1555
1590
|
if (!(0, import_node_fs.existsSync)(fullSourcePath)) continue;
|
|
1556
1591
|
let liveness = livenessCache.get(sourcePath);
|
|
1557
1592
|
if (liveness === void 0) {
|
|
@@ -1646,14 +1681,14 @@ async function auditVersionLock(root, lockPath = VERSION_LOCK_PATH, graph, confi
|
|
|
1646
1681
|
currentArtifactHash: targetNode.contentHash
|
|
1647
1682
|
});
|
|
1648
1683
|
}
|
|
1649
|
-
if (!(0, import_node_fs.existsSync)((0,
|
|
1684
|
+
if (!(0, import_node_fs.existsSync)((0, import_node_path3.join)(root, sourceNode.path))) {
|
|
1650
1685
|
entryIssues.push({
|
|
1651
1686
|
status: "orphan_lock",
|
|
1652
1687
|
edgeId: relEdgeId,
|
|
1653
1688
|
message: `Artifact relation source file ${sourceNode.path} no longer exists`
|
|
1654
1689
|
});
|
|
1655
1690
|
}
|
|
1656
|
-
if (!(0, import_node_fs.existsSync)((0,
|
|
1691
|
+
if (!(0, import_node_fs.existsSync)((0, import_node_path3.join)(root, targetNode.path))) {
|
|
1657
1692
|
entryIssues.push({
|
|
1658
1693
|
status: "orphan_lock",
|
|
1659
1694
|
edgeId: relEdgeId,
|
|
@@ -2226,7 +2261,7 @@ function renderTraceVersionMarkdown(result) {
|
|
|
2226
2261
|
async function readVersionLock(root, lockPath) {
|
|
2227
2262
|
const safeLockPath = normalizeRelativePath(root, lockPath);
|
|
2228
2263
|
try {
|
|
2229
|
-
const raw = await (0,
|
|
2264
|
+
const raw = await (0, import_promises3.readFile)((0, import_node_path3.join)(root, safeLockPath), "utf-8");
|
|
2230
2265
|
let parsed;
|
|
2231
2266
|
try {
|
|
2232
2267
|
parsed = JSON.parse(raw);
|
|
@@ -2385,9 +2420,9 @@ function requireSafeRelativePath(value, path) {
|
|
|
2385
2420
|
}
|
|
2386
2421
|
async function writeVersionLock(root, lockPath, lock) {
|
|
2387
2422
|
const safeLockPath = normalizeRelativePath(root, lockPath);
|
|
2388
|
-
const fullPath = (0,
|
|
2389
|
-
await (0,
|
|
2390
|
-
await (0,
|
|
2423
|
+
const fullPath = (0, import_node_path3.join)(root, safeLockPath);
|
|
2424
|
+
await (0, import_promises3.mkdir)((0, import_node_path3.dirname)(fullPath), { recursive: true });
|
|
2425
|
+
await (0, import_promises3.writeFile)(fullPath, `${JSON.stringify(lock, null, 2)}
|
|
2391
2426
|
`);
|
|
2392
2427
|
}
|
|
2393
2428
|
function implementationEdges(index) {
|
|
@@ -2568,14 +2603,14 @@ async function hashRelativePath(root, path, cache) {
|
|
|
2568
2603
|
const normalized = normalizeRelativePath(root, path);
|
|
2569
2604
|
const cached = cache.get(normalized);
|
|
2570
2605
|
if (cached) return cached;
|
|
2571
|
-
const content = await (0,
|
|
2606
|
+
const content = await (0, import_promises3.readFile)((0, import_node_path3.join)(root, normalized));
|
|
2572
2607
|
const hash = `sha256:${(0, import_node_crypto.createHash)("sha256").update(content).digest("hex")}`;
|
|
2573
2608
|
cache.set(normalized, hash);
|
|
2574
2609
|
return hash;
|
|
2575
2610
|
}
|
|
2576
2611
|
function normalizeRelativePath(root, path) {
|
|
2577
2612
|
const normalized = path.replace(/\\/g, "/");
|
|
2578
|
-
const relativePath = normalized.startsWith("/") ? (0,
|
|
2613
|
+
const relativePath = normalized.startsWith("/") ? (0, import_node_path3.relative)(root, normalized).replace(/\\/g, "/") : normalized.replace(/^\.\//, "");
|
|
2579
2614
|
if (relativePath === ".." || relativePath.startsWith("../")) {
|
|
2580
2615
|
throw new Error(`Path is outside root: ${path}`);
|
|
2581
2616
|
}
|
|
@@ -2591,10 +2626,10 @@ async function getTestFileRunnerLiveness(root, filePath, config) {
|
|
|
2591
2626
|
if (!/e2e/i.test(filePath) && !/\.e2e\./i.test(filePath)) {
|
|
2592
2627
|
return "active";
|
|
2593
2628
|
}
|
|
2594
|
-
const fullSourcePath = (0,
|
|
2629
|
+
const fullSourcePath = (0, import_node_path3.join)(root, filePath);
|
|
2595
2630
|
if (!(0, import_node_fs.existsSync)(fullSourcePath)) return "inactive";
|
|
2596
2631
|
try {
|
|
2597
|
-
const content = await (0,
|
|
2632
|
+
const content = await (0, import_promises3.readFile)(fullSourcePath, "utf-8");
|
|
2598
2633
|
return /\/\/!?\s*@(?:e2e_test|tc)\s+/.test(content) ? "active" : "inactive";
|
|
2599
2634
|
} catch {
|
|
2600
2635
|
return "inactive";
|
|
@@ -2634,14 +2669,14 @@ async function isFileActiveInRunner(root, filePath, runner) {
|
|
|
2634
2669
|
function sortUnique(items) {
|
|
2635
2670
|
return [...new Set(items)].sort((left, right) => left.localeCompare(right));
|
|
2636
2671
|
}
|
|
2637
|
-
var import_node_crypto, import_node_fs,
|
|
2672
|
+
var import_node_crypto, import_node_fs, import_promises3, import_node_path3, VERSION_LOCK_PATH, VERSION_INDEX_SCHEMA_VERSION, VERSION_LOCK_SCHEMA_VERSION, LIVENESS_MESSAGE_PREFIX, VERSION_LOCK_STATUS_LABELS;
|
|
2638
2673
|
var init_versioned_traceability = __esm({
|
|
2639
2674
|
"src/versioned-traceability.ts"() {
|
|
2640
2675
|
"use strict";
|
|
2641
2676
|
import_node_crypto = require("crypto");
|
|
2642
2677
|
import_node_fs = require("fs");
|
|
2643
|
-
|
|
2644
|
-
|
|
2678
|
+
import_promises3 = require("fs/promises");
|
|
2679
|
+
import_node_path3 = require("path");
|
|
2645
2680
|
init_index();
|
|
2646
2681
|
init_glob_matcher();
|
|
2647
2682
|
VERSION_LOCK_PATH = "artifacts/traceability-version-lock.json";
|
|
@@ -2667,7 +2702,7 @@ async function resolveArtifactGraphCli(root, options = {}) {
|
|
|
2667
2702
|
const candidates = [
|
|
2668
2703
|
{
|
|
2669
2704
|
source: "node_modules",
|
|
2670
|
-
path: (0,
|
|
2705
|
+
path: (0, import_node_path4.join)(root, "node_modules/.bin/artifact-graph"),
|
|
2671
2706
|
exists: false
|
|
2672
2707
|
},
|
|
2673
2708
|
{
|
|
@@ -2700,8 +2735,8 @@ async function resolveArtifactGraphCli(root, options = {}) {
|
|
|
2700
2735
|
}
|
|
2701
2736
|
async function doctorArtifactChain(root, options = {}) {
|
|
2702
2737
|
const cli = await resolveArtifactGraphCli(root, options);
|
|
2703
|
-
const configPath = (0,
|
|
2704
|
-
const lockPath = (0,
|
|
2738
|
+
const configPath = (0, import_node_path4.join)(root, "artifact-graph.config.yaml");
|
|
2739
|
+
const lockPath = (0, import_node_path4.join)(root, VERSION_LOCK_PATH);
|
|
2705
2740
|
const supportedCommands = cli.path ? await detectSupportedCommands(cli.path) : [];
|
|
2706
2741
|
const nodeCompatible = isNodeCompatible(process.versions.node);
|
|
2707
2742
|
const warnings = [
|
|
@@ -2774,7 +2809,7 @@ ${maybe.stderr ?? ""}`;
|
|
|
2774
2809
|
}
|
|
2775
2810
|
async function pathExists(path) {
|
|
2776
2811
|
try {
|
|
2777
|
-
await (0,
|
|
2812
|
+
await (0, import_promises4.access)(path, import_node_fs2.constants.R_OK);
|
|
2778
2813
|
return true;
|
|
2779
2814
|
} catch {
|
|
2780
2815
|
return false;
|
|
@@ -2790,20 +2825,20 @@ async function findCommandOnPath(command) {
|
|
|
2790
2825
|
}
|
|
2791
2826
|
}
|
|
2792
2827
|
function resolveCandidatePath(root, candidatePath) {
|
|
2793
|
-
return (0,
|
|
2828
|
+
return (0, import_node_path4.isAbsolute)(candidatePath) ? candidatePath : (0, import_node_path4.resolve)(root, candidatePath);
|
|
2794
2829
|
}
|
|
2795
2830
|
function isNodeCompatible(version) {
|
|
2796
2831
|
const major = Number(version.split(".")[0]);
|
|
2797
2832
|
return Number.isFinite(major) && major >= 22;
|
|
2798
2833
|
}
|
|
2799
|
-
var import_node_child_process, import_node_fs2,
|
|
2834
|
+
var import_node_child_process, import_node_fs2, import_promises4, import_node_path4, import_node_util, execFileAsync, KNOWN_COMMANDS;
|
|
2800
2835
|
var init_cli_resolver = __esm({
|
|
2801
2836
|
"src/cli-resolver.ts"() {
|
|
2802
2837
|
"use strict";
|
|
2803
2838
|
import_node_child_process = require("child_process");
|
|
2804
2839
|
import_node_fs2 = require("fs");
|
|
2805
|
-
|
|
2806
|
-
|
|
2840
|
+
import_promises4 = require("fs/promises");
|
|
2841
|
+
import_node_path4 = require("path");
|
|
2807
2842
|
import_node_util = require("util");
|
|
2808
2843
|
init_versioned_traceability();
|
|
2809
2844
|
execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
|
|
@@ -2914,14 +2949,14 @@ async function resolveGitHookPath(root, hookName) {
|
|
|
2914
2949
|
]);
|
|
2915
2950
|
const value = stdout.trim();
|
|
2916
2951
|
if (!value) throw new Error(`Git returned an empty hook path for ${hookName}`);
|
|
2917
|
-
return (0,
|
|
2952
|
+
return (0, import_node_path5.isAbsolute)(value) ? (0, import_node_path5.resolve)(value) : (0, import_node_path5.resolve)(root, value);
|
|
2918
2953
|
}
|
|
2919
|
-
var import_node_child_process3,
|
|
2954
|
+
var import_node_child_process3, import_node_path5, import_node_util3, execFileAsync3;
|
|
2920
2955
|
var init_git_hook_path = __esm({
|
|
2921
2956
|
"src/git-hook-path.ts"() {
|
|
2922
2957
|
"use strict";
|
|
2923
2958
|
import_node_child_process3 = require("child_process");
|
|
2924
|
-
|
|
2959
|
+
import_node_path5 = require("path");
|
|
2925
2960
|
import_node_util3 = require("util");
|
|
2926
2961
|
execFileAsync3 = (0, import_node_util3.promisify)(import_node_child_process3.execFile);
|
|
2927
2962
|
}
|
|
@@ -3144,7 +3179,7 @@ async function readHookSnapshot(hookPath) {
|
|
|
3144
3179
|
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
3145
3180
|
let metadata;
|
|
3146
3181
|
try {
|
|
3147
|
-
metadata = await (0,
|
|
3182
|
+
metadata = await (0, import_promises5.lstat)(hookPath, { bigint: true });
|
|
3148
3183
|
} catch (error) {
|
|
3149
3184
|
if (error.code === "ENOENT") {
|
|
3150
3185
|
return { kind: "missing", bytes: Buffer.alloc(0) };
|
|
@@ -3160,7 +3195,7 @@ async function readHookSnapshot(hookPath) {
|
|
|
3160
3195
|
size: metadata.size,
|
|
3161
3196
|
mtimeNs: metadata.mtimeNs,
|
|
3162
3197
|
mode: metadata.mode,
|
|
3163
|
-
linkTarget: await (0,
|
|
3198
|
+
linkTarget: await (0, import_promises5.readlink)(hookPath)
|
|
3164
3199
|
};
|
|
3165
3200
|
}
|
|
3166
3201
|
if (!metadata.isFile()) {
|
|
@@ -3176,7 +3211,7 @@ async function readHookSnapshot(hookPath) {
|
|
|
3176
3211
|
}
|
|
3177
3212
|
let handle;
|
|
3178
3213
|
try {
|
|
3179
|
-
handle = await (0,
|
|
3214
|
+
handle = await (0, import_promises5.open)(hookPath, import_node_fs3.constants.O_RDONLY | (import_node_fs3.constants.O_NOFOLLOW ?? 0));
|
|
3180
3215
|
const opened = await handle.stat({ bigint: true });
|
|
3181
3216
|
if (opened.dev !== metadata.dev || opened.ino !== metadata.ino) {
|
|
3182
3217
|
await handle.close();
|
|
@@ -3234,15 +3269,15 @@ async function removeHookAtomically(hookPath, snapshot) {
|
|
|
3234
3269
|
throw new ConcurrentHookModificationError(hookPath);
|
|
3235
3270
|
}
|
|
3236
3271
|
if (current.kind !== "missing") {
|
|
3237
|
-
await (0,
|
|
3272
|
+
await (0, import_promises5.unlink)(hookPath);
|
|
3238
3273
|
}
|
|
3239
3274
|
}
|
|
3240
3275
|
async function writeHookAtomically(hookPath, content, snapshot, mode) {
|
|
3241
|
-
await (0,
|
|
3242
|
-
const temporaryPath = (0,
|
|
3276
|
+
await (0, import_promises5.mkdir)((0, import_node_path6.dirname)(hookPath), { recursive: true });
|
|
3277
|
+
const temporaryPath = (0, import_node_path6.join)((0, import_node_path6.dirname)(hookPath), `.${(0, import_node_path6.basename)(hookPath)}.${(0, import_node_crypto2.randomUUID)()}.tmp`);
|
|
3243
3278
|
let temporaryExists = false;
|
|
3244
3279
|
try {
|
|
3245
|
-
const temporary = await (0,
|
|
3280
|
+
const temporary = await (0, import_promises5.open)(temporaryPath, "wx", mode);
|
|
3246
3281
|
temporaryExists = true;
|
|
3247
3282
|
try {
|
|
3248
3283
|
await temporary.writeFile(content);
|
|
@@ -3255,11 +3290,11 @@ async function writeHookAtomically(hookPath, content, snapshot, mode) {
|
|
|
3255
3290
|
if (!sameHookSnapshot(snapshot, current)) {
|
|
3256
3291
|
throw new ConcurrentHookModificationError(hookPath);
|
|
3257
3292
|
}
|
|
3258
|
-
await (0,
|
|
3293
|
+
await (0, import_promises5.rename)(temporaryPath, hookPath);
|
|
3259
3294
|
temporaryExists = false;
|
|
3260
3295
|
} finally {
|
|
3261
3296
|
if (temporaryExists) {
|
|
3262
|
-
await (0,
|
|
3297
|
+
await (0, import_promises5.unlink)(temporaryPath).catch((error) => {
|
|
3263
3298
|
if (error.code !== "ENOENT") {
|
|
3264
3299
|
throw error;
|
|
3265
3300
|
}
|
|
@@ -3285,14 +3320,14 @@ function findManagedRange(content, begin, end) {
|
|
|
3285
3320
|
end: endLine < 0 ? content.length : endLine + 1
|
|
3286
3321
|
};
|
|
3287
3322
|
}
|
|
3288
|
-
var import_node_fs3, import_node_crypto2,
|
|
3323
|
+
var import_node_fs3, import_node_crypto2, import_promises5, import_node_path6, DEFAULT_MARKER_ID, MANAGED_STATE_PREFIX, UnsupportedHookInterpreterError, SymlinkHookUnsupportedError, UnsupportedHookTypeError, InvalidManagedHookStateError, ConcurrentHookModificationError, HookTransactionRollbackError;
|
|
3289
3324
|
var init_hook_installer = __esm({
|
|
3290
3325
|
"src/hook-installer.ts"() {
|
|
3291
3326
|
"use strict";
|
|
3292
3327
|
import_node_fs3 = require("fs");
|
|
3293
3328
|
import_node_crypto2 = require("crypto");
|
|
3294
|
-
|
|
3295
|
-
|
|
3329
|
+
import_promises5 = require("fs/promises");
|
|
3330
|
+
import_node_path6 = require("path");
|
|
3296
3331
|
DEFAULT_MARKER_ID = "artifact-chain-assistant";
|
|
3297
3332
|
MANAGED_STATE_PREFIX = "# artifact-chain-assistant managed state v1:";
|
|
3298
3333
|
UnsupportedHookInterpreterError = class extends Error {
|
|
@@ -3959,7 +3994,7 @@ function validatePolicyCompatibility(policy, baseContract) {
|
|
|
3959
3994
|
};
|
|
3960
3995
|
}
|
|
3961
3996
|
async function loadContract(contractPath, options) {
|
|
3962
|
-
const rawContent = await (0,
|
|
3997
|
+
const rawContent = await (0, import_promises6.readFile)(contractPath, "utf-8");
|
|
3963
3998
|
let schema;
|
|
3964
3999
|
try {
|
|
3965
4000
|
schema = JSON.parse(rawContent);
|
|
@@ -4007,10 +4042,10 @@ async function loadContract(contractPath, options) {
|
|
|
4007
4042
|
}
|
|
4008
4043
|
async function loadContractsFromDirectory(contractsDir, options) {
|
|
4009
4044
|
const contracts = [];
|
|
4010
|
-
const entries = await (0,
|
|
4045
|
+
const entries = await (0, import_promises6.readdir)(contractsDir, { withFileTypes: true });
|
|
4011
4046
|
for (const entry of entries) {
|
|
4012
4047
|
if (entry.isDirectory()) {
|
|
4013
|
-
const schemaPath = (0,
|
|
4048
|
+
const schemaPath = (0, import_node_path7.join)(contractsDir, entry.name, "schema.json");
|
|
4014
4049
|
const contract = await loadContract(schemaPath, options);
|
|
4015
4050
|
contracts.push(contract);
|
|
4016
4051
|
}
|
|
@@ -4125,13 +4160,13 @@ async function loadContractCatalog(contractsDir, options) {
|
|
|
4125
4160
|
}
|
|
4126
4161
|
return catalog;
|
|
4127
4162
|
}
|
|
4128
|
-
var import_node_crypto3,
|
|
4163
|
+
var import_node_crypto3, import_promises6, import_node_path7, import_ajv, CONTRACT_ERROR_CODES, ContractError, OFFICIAL_AUTHORITY, OFFICIAL_NAMESPACE_PATTERN, ContractRegistry, _validatorCache, E2E_NORMALIZER_CONFIG, ContractCatalog;
|
|
4129
4164
|
var init_contract_kernel = __esm({
|
|
4130
4165
|
"src/contract-kernel.ts"() {
|
|
4131
4166
|
"use strict";
|
|
4132
4167
|
import_node_crypto3 = require("crypto");
|
|
4133
|
-
|
|
4134
|
-
|
|
4168
|
+
import_promises6 = require("fs/promises");
|
|
4169
|
+
import_node_path7 = require("path");
|
|
4135
4170
|
import_ajv = __toESM(require("ajv"), 1);
|
|
4136
4171
|
CONTRACT_ERROR_CODES = {
|
|
4137
4172
|
/** Contract identity not found */
|
|
@@ -4484,11 +4519,11 @@ __export(index_exports, {
|
|
|
4484
4519
|
collectChangedPaths: () => collectChangedPaths,
|
|
4485
4520
|
computeE2eCoverageStats: () => computeE2eCoverageStats,
|
|
4486
4521
|
computeRevisionDigest: () => computeRevisionDigest,
|
|
4487
|
-
dirname: () =>
|
|
4522
|
+
dirname: () => import_node_path8.dirname,
|
|
4488
4523
|
discoverAndAuditPackets: () => discoverAndAuditPackets,
|
|
4489
4524
|
discoverTargets: () => discoverTargets,
|
|
4490
4525
|
doctorArtifactChain: () => doctorArtifactChain,
|
|
4491
|
-
extname: () =>
|
|
4526
|
+
extname: () => import_node_path8.extname,
|
|
4492
4527
|
formatContextMarkdown: () => formatContextMarkdown,
|
|
4493
4528
|
generateE2eRegistry: () => generateE2eRegistry,
|
|
4494
4529
|
getArtifactTypeMetadata: () => getArtifactTypeMetadata,
|
|
@@ -4503,6 +4538,7 @@ __export(index_exports, {
|
|
|
4503
4538
|
loadContract: () => loadContract,
|
|
4504
4539
|
loadContractCatalog: () => loadContractCatalog,
|
|
4505
4540
|
loadContractsFromDirectory: () => loadContractsFromDirectory,
|
|
4541
|
+
matchesConfiguredArtifactPath: () => matchesConfiguredArtifactPath,
|
|
4506
4542
|
nextId: () => nextId,
|
|
4507
4543
|
normalizeE2eLegacyArtifact: () => normalizeE2eLegacyArtifact,
|
|
4508
4544
|
normalizeToCanonical: () => normalizeToCanonical,
|
|
@@ -4584,10 +4620,10 @@ function resolveArtifactTypeName(schema, token) {
|
|
|
4584
4620
|
return void 0;
|
|
4585
4621
|
}
|
|
4586
4622
|
async function loadConfig(root) {
|
|
4587
|
-
const configPath = (0,
|
|
4623
|
+
const configPath = (0, import_node_path8.join)(root, "artifact-graph.config.yaml");
|
|
4588
4624
|
let parsed = {};
|
|
4589
4625
|
try {
|
|
4590
|
-
const raw = await (0,
|
|
4626
|
+
const raw = await (0, import_promises7.readFile)(configPath, "utf-8");
|
|
4591
4627
|
parsed = import_js_yaml.default.load(raw) ?? {};
|
|
4592
4628
|
} catch (error) {
|
|
4593
4629
|
if (error.code !== "ENOENT") {
|
|
@@ -4677,7 +4713,7 @@ function validateE2eConfig(e2e) {
|
|
|
4677
4713
|
if (typeof runner.root !== "string" || !runner.root.trim()) {
|
|
4678
4714
|
throw new Error(`Invalid e2e.runners[${runner.name}].root: must be a non-empty string.`);
|
|
4679
4715
|
}
|
|
4680
|
-
if ((0,
|
|
4716
|
+
if ((0, import_node_path8.isAbsolute)(runner.root)) {
|
|
4681
4717
|
throw new Error(`Invalid e2e.runners[${runner.name}].root: "${runner.root}" must not be an absolute path.`);
|
|
4682
4718
|
}
|
|
4683
4719
|
if (runner.root.replace(/\\/g, "/").split("/").includes("..")) {
|
|
@@ -4761,14 +4797,14 @@ async function scanArtifacts(root, schema) {
|
|
|
4761
4797
|
continue;
|
|
4762
4798
|
}
|
|
4763
4799
|
scannedFiles.set(file, type);
|
|
4764
|
-
const raw = await (0,
|
|
4800
|
+
const raw = await (0, import_promises7.readFile)((0, import_node_path8.join)(root, file), "utf-8");
|
|
4765
4801
|
const parsed = parseFile(type, file, raw, config);
|
|
4766
4802
|
nodes.push(...parsed.nodes);
|
|
4767
4803
|
edges.push(...parsed.edges);
|
|
4768
4804
|
scanDiagnostics.push(...parsed.diagnostics);
|
|
4769
4805
|
}
|
|
4770
4806
|
}
|
|
4771
|
-
const absoluteRoot = (0,
|
|
4807
|
+
const absoluteRoot = (0, import_node_path8.isAbsolute)(root) ? root : (0, import_node_path8.resolve)(root);
|
|
4772
4808
|
const graph = buildGraph(nodes, edges, scanDiagnostics, absoluteRoot);
|
|
4773
4809
|
return resolveMatrixEdges(graph);
|
|
4774
4810
|
}
|
|
@@ -5073,7 +5109,7 @@ async function validateScenarioPrdLinkIndex(root, graph) {
|
|
|
5073
5109
|
const indexPath = "artifacts/prd/feature-index.md";
|
|
5074
5110
|
let raw = "";
|
|
5075
5111
|
try {
|
|
5076
|
-
raw = await (0,
|
|
5112
|
+
raw = await (0, import_promises7.readFile)((0, import_node_path8.join)(root, indexPath), "utf-8");
|
|
5077
5113
|
} catch (error) {
|
|
5078
5114
|
if (error.code === "ENOENT") {
|
|
5079
5115
|
return [];
|
|
@@ -5263,11 +5299,11 @@ function nextId(graph, schema, type, rangeName) {
|
|
|
5263
5299
|
throw new Error(`ID range ${type}.${rangeName} is exhausted`);
|
|
5264
5300
|
}
|
|
5265
5301
|
async function writeGraphCache(root, graph) {
|
|
5266
|
-
const cacheDir = (0,
|
|
5267
|
-
await (0,
|
|
5268
|
-
await (0,
|
|
5302
|
+
const cacheDir = (0, import_node_path8.join)(root, ".artifact-graph");
|
|
5303
|
+
await (0, import_promises7.mkdir)(cacheDir, { recursive: true });
|
|
5304
|
+
await (0, import_promises7.writeFile)((0, import_node_path8.join)(cacheDir, "index.json"), `${JSON.stringify(graph, null, 2)}
|
|
5269
5305
|
`);
|
|
5270
|
-
const db = new import_better_sqlite3.default((0,
|
|
5306
|
+
const db = new import_better_sqlite3.default((0, import_node_path8.join)(cacheDir, "graph.sqlite"));
|
|
5271
5307
|
try {
|
|
5272
5308
|
db.exec(`
|
|
5273
5309
|
DROP TABLE IF EXISTS nodes;
|
|
@@ -5378,7 +5414,7 @@ function parseFile(type, path, raw, schema = DEFAULT_SCHEMA) {
|
|
|
5378
5414
|
}
|
|
5379
5415
|
function parseGenericMarkdown(type, path, raw, schema) {
|
|
5380
5416
|
const diagnostics = [];
|
|
5381
|
-
const ext = (0,
|
|
5417
|
+
const ext = (0, import_node_path8.extname)(path).toLowerCase();
|
|
5382
5418
|
if (ext !== ".md" && ext !== ".markdown") {
|
|
5383
5419
|
diagnostics.push(issue(
|
|
5384
5420
|
"UNSUPPORTED_FORMAT",
|
|
@@ -5605,7 +5641,7 @@ function parseDecisions(path, raw) {
|
|
|
5605
5641
|
}
|
|
5606
5642
|
function isTestFile(filePath) {
|
|
5607
5643
|
const normalized = filePath.replace(/\\/g, "/");
|
|
5608
|
-
const name = (0,
|
|
5644
|
+
const name = (0, import_node_path8.basename)(normalized);
|
|
5609
5645
|
if (/\.(test|spec)\.[^.]+$/.test(name)) return true;
|
|
5610
5646
|
if (/(^|\/)(tests|test|__tests__)\//.test(normalized)) return true;
|
|
5611
5647
|
if (/\w+Tests?\.java$/.test(name)) return true;
|
|
@@ -5896,7 +5932,7 @@ function parseE2eTest(path, raw) {
|
|
|
5896
5932
|
});
|
|
5897
5933
|
const nodes = [];
|
|
5898
5934
|
const edges = [];
|
|
5899
|
-
const batch = String(data.test_batch ?? (0,
|
|
5935
|
+
const batch = String(data.test_batch ?? (0, import_node_path8.basename)(path, (0, import_node_path8.extname)(path))).trim();
|
|
5900
5936
|
const frontmatterScenarios = toArray(data.related_scenarios).map((value) => String(value).trim()).filter(Boolean);
|
|
5901
5937
|
const scopeFeatures = extractCodes(String(data.scope ?? ""), "feature");
|
|
5902
5938
|
const frontmatterFeatures = [.../* @__PURE__ */ new Set([...Object.keys(asRecord(data.ac_coverage)), ...scopeFeatures])];
|
|
@@ -5969,7 +6005,7 @@ function parseE2eRegistry(path, raw) {
|
|
|
5969
6005
|
data = { parseError: error.message };
|
|
5970
6006
|
}
|
|
5971
6007
|
return {
|
|
5972
|
-
nodes: [{ type: "e2e_registry", code: (0,
|
|
6008
|
+
nodes: [{ type: "e2e_registry", code: (0, import_node_path8.basename)(path, (0, import_node_path8.extname)(path)), title: "E2E Test Registry", path, line: 1, attrs: data }],
|
|
5973
6009
|
edges: []
|
|
5974
6010
|
};
|
|
5975
6011
|
}
|
|
@@ -6950,10 +6986,10 @@ function validateE2eRegistry(graph) {
|
|
|
6950
6986
|
async function validateExecutableTraceability(root, config) {
|
|
6951
6987
|
const issues = [];
|
|
6952
6988
|
const schema = config ?? await loadConfig(root);
|
|
6953
|
-
const e2eDir = (0,
|
|
6989
|
+
const e2eDir = (0, import_node_path8.join)(root, "artifacts", "tests", "e2e");
|
|
6954
6990
|
let e2eFiles;
|
|
6955
6991
|
try {
|
|
6956
|
-
e2eFiles = (await (0,
|
|
6992
|
+
e2eFiles = (await (0, import_promises7.readdir)(e2eDir)).filter((name) => /^test-.*\.md$/.test(name)).map((name) => (0, import_node_path8.join)(e2eDir, name));
|
|
6957
6993
|
} catch {
|
|
6958
6994
|
return [];
|
|
6959
6995
|
}
|
|
@@ -6962,11 +6998,11 @@ async function validateExecutableTraceability(root, config) {
|
|
|
6962
6998
|
const tcKeyToFields = /* @__PURE__ */ new Map();
|
|
6963
6999
|
const mdBatches = /* @__PURE__ */ new Set();
|
|
6964
7000
|
for (const filePath of e2eFiles) {
|
|
6965
|
-
const raw = await (0,
|
|
6966
|
-
const relPath = (0,
|
|
7001
|
+
const raw = await (0, import_promises7.readFile)(filePath, "utf-8");
|
|
7002
|
+
const relPath = (0, import_node_path8.relative)(root, filePath).split("\\").join("/");
|
|
6967
7003
|
const parsed = (0, import_gray_matter.default)(raw);
|
|
6968
7004
|
const data = parsed.data;
|
|
6969
|
-
const batch = String(data.test_batch ?? (0,
|
|
7005
|
+
const batch = String(data.test_batch ?? (0, import_node_path8.basename)(filePath, (0, import_node_path8.extname)(filePath))).trim();
|
|
6970
7006
|
const lines = raw.split(/\r?\n/);
|
|
6971
7007
|
const tcStarts = [];
|
|
6972
7008
|
lines.forEach((line, index) => {
|
|
@@ -6991,7 +7027,7 @@ async function validateExecutableTraceability(root, config) {
|
|
|
6991
7027
|
}
|
|
6992
7028
|
}
|
|
6993
7029
|
}
|
|
6994
|
-
const allFiles = await
|
|
7030
|
+
const allFiles = await walkFiles(root);
|
|
6995
7031
|
const specFiles = /* @__PURE__ */ new Set();
|
|
6996
7032
|
const configuredRunners = schema.e2e?.runners ?? [];
|
|
6997
7033
|
if (configuredRunners.length > 0) {
|
|
@@ -7011,23 +7047,25 @@ async function validateExecutableTraceability(root, config) {
|
|
|
7011
7047
|
const tcAnnotationRegex = /\/\/!?\s*@(?:e2e_test|tc)\s+(\S+?)\s+\[(\w+)\]/;
|
|
7012
7048
|
const tcAnnotationNoLevelRegex = /\/\/!?\s*@(?:e2e_test|tc)\s+(\S+)/;
|
|
7013
7049
|
for (const specFile of specFiles) {
|
|
7014
|
-
const fullSpecPath = (0,
|
|
7050
|
+
const fullSpecPath = (0, import_node_path8.join)(root, specFile);
|
|
7015
7051
|
let content;
|
|
7016
7052
|
try {
|
|
7017
|
-
content = await (0,
|
|
7053
|
+
content = await (0, import_promises7.readFile)(fullSpecPath, "utf-8");
|
|
7018
7054
|
} catch {
|
|
7019
7055
|
continue;
|
|
7020
7056
|
}
|
|
7021
7057
|
const level = detectTestLevel(specFile, content);
|
|
7022
7058
|
const specLines = content.split(/\r?\n/);
|
|
7023
|
-
|
|
7024
|
-
|
|
7025
|
-
|
|
7059
|
+
const lineComments = scanCodeComments(content).filter((comment) => comment.kind === "line" && comment.standalone);
|
|
7060
|
+
for (const comment of lineComments) {
|
|
7061
|
+
const lineIndex = comment.lineNumber - 1;
|
|
7062
|
+
const commentText = comment.text.replace(/^!/, "");
|
|
7063
|
+
let match = tcAnnotationRegex.exec(`//${commentText}`);
|
|
7026
7064
|
let annotatedLevel = "";
|
|
7027
7065
|
if (match) {
|
|
7028
7066
|
annotatedLevel = match[2];
|
|
7029
7067
|
} else {
|
|
7030
|
-
match = tcAnnotationNoLevelRegex.exec(
|
|
7068
|
+
match = tcAnnotationNoLevelRegex.exec(`//${commentText}`);
|
|
7031
7069
|
}
|
|
7032
7070
|
if (!match) {
|
|
7033
7071
|
continue;
|
|
@@ -7054,7 +7092,7 @@ async function validateExecutableTraceability(root, config) {
|
|
|
7054
7092
|
level: effectiveLevel,
|
|
7055
7093
|
file: specFile,
|
|
7056
7094
|
testName,
|
|
7057
|
-
line:
|
|
7095
|
+
line: comment.lineNumber
|
|
7058
7096
|
};
|
|
7059
7097
|
const key = `${batch}:${tcId}`;
|
|
7060
7098
|
const existing = refToSource.get(key) ?? [];
|
|
@@ -7091,7 +7129,7 @@ async function validateExecutableTraceability(root, config) {
|
|
|
7091
7129
|
if (entry.testId) {
|
|
7092
7130
|
let content;
|
|
7093
7131
|
try {
|
|
7094
|
-
content = await (0,
|
|
7132
|
+
content = await (0, import_promises7.readFile)((0, import_node_path8.join)(root, normalizedRefFile), "utf-8");
|
|
7095
7133
|
} catch {
|
|
7096
7134
|
continue;
|
|
7097
7135
|
}
|
|
@@ -7268,16 +7306,16 @@ async function computeE2eCoverageStats(graph, root, thresholds = {}) {
|
|
|
7268
7306
|
let withExecutableRef = 0;
|
|
7269
7307
|
const statusBreakdown = {};
|
|
7270
7308
|
const chainTypeBreakdown = {};
|
|
7271
|
-
const e2eDir = (0,
|
|
7309
|
+
const e2eDir = (0, import_node_path8.join)(root, "artifacts", "tests", "e2e");
|
|
7272
7310
|
const tcFieldsMap = /* @__PURE__ */ new Map();
|
|
7273
7311
|
let e2eFiles;
|
|
7274
7312
|
try {
|
|
7275
|
-
e2eFiles = (await (0,
|
|
7313
|
+
e2eFiles = (await (0, import_promises7.readdir)(e2eDir)).filter((name) => /^test-.*\.md$/.test(name)).map((name) => (0, import_node_path8.join)(e2eDir, name));
|
|
7276
7314
|
} catch {
|
|
7277
7315
|
e2eFiles = [];
|
|
7278
7316
|
}
|
|
7279
7317
|
for (const filePath of e2eFiles) {
|
|
7280
|
-
const raw = await (0,
|
|
7318
|
+
const raw = await (0, import_promises7.readFile)(filePath, "utf-8");
|
|
7281
7319
|
const lines = raw.split(/\r?\n/);
|
|
7282
7320
|
const tcStarts = [];
|
|
7283
7321
|
lines.forEach((line, index) => {
|
|
@@ -7287,7 +7325,7 @@ async function computeE2eCoverageStats(graph, root, thresholds = {}) {
|
|
|
7287
7325
|
}
|
|
7288
7326
|
});
|
|
7289
7327
|
const parsed = (0, import_gray_matter.default)(raw);
|
|
7290
|
-
const batch = String(parsed.data.test_batch ?? (0,
|
|
7328
|
+
const batch = String(parsed.data.test_batch ?? (0, import_node_path8.basename)(filePath, (0, import_node_path8.extname)(filePath))).trim();
|
|
7291
7329
|
for (let i = 0; i < tcStarts.length; i++) {
|
|
7292
7330
|
const start = tcStarts[i];
|
|
7293
7331
|
const end = tcStarts[i + 1]?.index ?? lines.length;
|
|
@@ -7339,7 +7377,7 @@ async function computeE2eCoverageStats(graph, root, thresholds = {}) {
|
|
|
7339
7377
|
}
|
|
7340
7378
|
}
|
|
7341
7379
|
const runners = (await loadConfig(root)).e2e?.runners ?? [];
|
|
7342
|
-
const allProjectFiles = await
|
|
7380
|
+
const allProjectFiles = await walkFiles(root);
|
|
7343
7381
|
for (const node of e2eNodes) {
|
|
7344
7382
|
const fields = tcFieldsMap.get(node.code) ?? asRecord(node.attrs?.tcFields);
|
|
7345
7383
|
const status = String(fields["status"] ?? "").trim().toLowerCase();
|
|
@@ -7350,7 +7388,7 @@ async function computeE2eCoverageStats(graph, root, thresholds = {}) {
|
|
|
7350
7388
|
let hasActiveE2eRef = false;
|
|
7351
7389
|
for (const entry of parseExecutableRefLines(execRef)) {
|
|
7352
7390
|
const normalized = resolveExecutableRefFile(entry.file, allProjectFiles);
|
|
7353
|
-
if (!normalized || !(0, import_node_fs4.existsSync)((0,
|
|
7391
|
+
if (!normalized || !(0, import_node_fs4.existsSync)((0, import_node_path8.join)(root, normalized))) continue;
|
|
7354
7392
|
const accepting = await getAcceptingRunners(root, normalized, runners);
|
|
7355
7393
|
if (accepting.some((runner) => runner.kind === "e2e")) {
|
|
7356
7394
|
hasActiveE2eRef = true;
|
|
@@ -7409,7 +7447,7 @@ async function computeE2eCoverageStats(graph, root, thresholds = {}) {
|
|
|
7409
7447
|
const acCoverageRateByFeature = {};
|
|
7410
7448
|
const featureAcMap = /* @__PURE__ */ new Map();
|
|
7411
7449
|
for (const node of featureNodes) {
|
|
7412
|
-
const acs = parseAcceptanceCriteria(await (0,
|
|
7450
|
+
const acs = parseAcceptanceCriteria(await (0, import_promises7.readFile)((0, import_node_path8.join)(root, node.path), "utf-8"));
|
|
7413
7451
|
featureAcMap.set(node.code, new Set(acs));
|
|
7414
7452
|
}
|
|
7415
7453
|
const coveredAcByFeature = /* @__PURE__ */ new Map();
|
|
@@ -7451,10 +7489,10 @@ async function computeE2eCoverageStats(graph, root, thresholds = {}) {
|
|
|
7451
7489
|
};
|
|
7452
7490
|
}
|
|
7453
7491
|
async function generateE2eRegistry(root, opts) {
|
|
7454
|
-
const e2eDir = (0,
|
|
7492
|
+
const e2eDir = (0, import_node_path8.join)(root, "artifacts", "tests", "e2e");
|
|
7455
7493
|
let files;
|
|
7456
7494
|
try {
|
|
7457
|
-
files = (await (0,
|
|
7495
|
+
files = (await (0, import_promises7.readdir)(e2eDir)).filter((name) => /^test-.*\.md$/.test(name)).sort();
|
|
7458
7496
|
} catch {
|
|
7459
7497
|
return {
|
|
7460
7498
|
registry_version: "1.0",
|
|
@@ -7467,11 +7505,11 @@ async function generateE2eRegistry(root, opts) {
|
|
|
7467
7505
|
const batches = [];
|
|
7468
7506
|
let totalTestCases = 0;
|
|
7469
7507
|
for (const file of files) {
|
|
7470
|
-
const filePath = (0,
|
|
7471
|
-
const raw = await (0,
|
|
7508
|
+
const filePath = (0, import_node_path8.join)(e2eDir, file);
|
|
7509
|
+
const raw = await (0, import_promises7.readFile)(filePath, "utf-8");
|
|
7472
7510
|
const parsed = (0, import_gray_matter.default)(raw);
|
|
7473
7511
|
const data = parsed.data;
|
|
7474
|
-
const batch = String(data.test_batch ?? (0,
|
|
7512
|
+
const batch = String(data.test_batch ?? (0, import_node_path8.basename)(file, (0, import_node_path8.extname)(file))).trim();
|
|
7475
7513
|
const relPath = `artifacts/tests/e2e/${file}`;
|
|
7476
7514
|
const scope = String(data.scope ?? "").trim();
|
|
7477
7515
|
const acCoverage = normalizeAcCoverageForRegistry(data.ac_coverage);
|
|
@@ -7595,10 +7633,10 @@ async function validatePartialRustEvidence(tcFields, tcKey, root, allFiles) {
|
|
|
7595
7633
|
if (!normalizedPath) {
|
|
7596
7634
|
return { hasValidPartialRust: false, detail: `partial_rust file not found: ${ref.file}` };
|
|
7597
7635
|
}
|
|
7598
|
-
const fullPath = (0,
|
|
7636
|
+
const fullPath = (0, import_node_path8.join)(root, normalizedPath);
|
|
7599
7637
|
let content;
|
|
7600
7638
|
try {
|
|
7601
|
-
content = await (0,
|
|
7639
|
+
content = await (0, import_promises7.readFile)(fullPath, "utf-8");
|
|
7602
7640
|
} catch {
|
|
7603
7641
|
return { hasValidPartialRust: false, detail: `partial_rust file not found: ${ref.file}` };
|
|
7604
7642
|
}
|
|
@@ -7632,7 +7670,7 @@ function detectTestLevel(specFile, content) {
|
|
|
7632
7670
|
}
|
|
7633
7671
|
function resolveExecutableRefFile(refFile, allFiles) {
|
|
7634
7672
|
const normalized = refFile.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
7635
|
-
if (!normalized || (0,
|
|
7673
|
+
if (!normalized || (0, import_node_path8.isAbsolute)(refFile) || normalized.split("/").includes("..")) {
|
|
7636
7674
|
return void 0;
|
|
7637
7675
|
}
|
|
7638
7676
|
if (allFiles.includes(normalized)) {
|
|
@@ -7707,9 +7745,9 @@ function escapeRegExp(value) {
|
|
|
7707
7745
|
}
|
|
7708
7746
|
async function hasMarkdownTc(tcKey, e2eDir) {
|
|
7709
7747
|
const [batch, tcId] = tcKey.split(":");
|
|
7710
|
-
const filePath = (0,
|
|
7748
|
+
const filePath = (0, import_node_path8.join)(e2eDir, `${batch}.md`);
|
|
7711
7749
|
try {
|
|
7712
|
-
const raw = await (0,
|
|
7750
|
+
const raw = await (0, import_promises7.readFile)(filePath, "utf-8");
|
|
7713
7751
|
const tcRegex = new RegExp(`^#{2,3}\\s+${escapeRegExp(tcId)}\\s*[:\uFF1A]?`, "m");
|
|
7714
7752
|
return tcRegex.test(raw);
|
|
7715
7753
|
} catch {
|
|
@@ -7717,7 +7755,7 @@ async function hasMarkdownTc(tcKey, e2eDir) {
|
|
|
7717
7755
|
}
|
|
7718
7756
|
}
|
|
7719
7757
|
async function findFiles(root, patterns) {
|
|
7720
|
-
const all = await
|
|
7758
|
+
const all = await walkFiles(root);
|
|
7721
7759
|
const matched = /* @__PURE__ */ new Set();
|
|
7722
7760
|
for (const pattern of patterns) {
|
|
7723
7761
|
for (const file of all) {
|
|
@@ -7728,21 +7766,9 @@ async function findFiles(root, patterns) {
|
|
|
7728
7766
|
}
|
|
7729
7767
|
return [...matched].sort();
|
|
7730
7768
|
}
|
|
7731
|
-
|
|
7732
|
-
const
|
|
7733
|
-
|
|
7734
|
-
for (const entry of entries) {
|
|
7735
|
-
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === ".git" || entry.name === ".artifact-graph") {
|
|
7736
|
-
continue;
|
|
7737
|
-
}
|
|
7738
|
-
const fullPath = (0, import_node_path7.join)(current, entry.name);
|
|
7739
|
-
if (entry.isDirectory()) {
|
|
7740
|
-
files.push(...await walk(root, fullPath));
|
|
7741
|
-
} else {
|
|
7742
|
-
files.push((0, import_node_path7.relative)(root, fullPath).split("\\").join("/"));
|
|
7743
|
-
}
|
|
7744
|
-
}
|
|
7745
|
-
return files;
|
|
7769
|
+
function matchesConfiguredArtifactPath(path, schema) {
|
|
7770
|
+
const normalizedPath = path.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
7771
|
+
return Object.values(schema.types).some((definition) => definition.paths.some((pattern) => matchesPattern(normalizedPath, pattern)));
|
|
7746
7772
|
}
|
|
7747
7773
|
function matchesPattern(file, pattern) {
|
|
7748
7774
|
if (!pattern.includes("*")) {
|
|
@@ -7954,7 +7980,7 @@ function normalizeDesignCode(value) {
|
|
|
7954
7980
|
if (!raw) {
|
|
7955
7981
|
return "";
|
|
7956
7982
|
}
|
|
7957
|
-
return (0,
|
|
7983
|
+
return (0, import_node_path8.basename)(raw, (0, import_node_path8.extname)(raw));
|
|
7958
7984
|
}
|
|
7959
7985
|
function toUid(type, code) {
|
|
7960
7986
|
return `${type}:${code}`;
|
|
@@ -8219,7 +8245,7 @@ function resolveArtifactContext(graph, opts) {
|
|
|
8219
8245
|
}
|
|
8220
8246
|
if (root) {
|
|
8221
8247
|
for (const ap of ALWAYS_PRESENT_ITEMS) {
|
|
8222
|
-
const fullPath = (0,
|
|
8248
|
+
const fullPath = (0, import_node_path8.join)(root, ap.path);
|
|
8223
8249
|
let stat;
|
|
8224
8250
|
try {
|
|
8225
8251
|
stat = (0, import_node_fs4.statSync)(fullPath);
|
|
@@ -8449,18 +8475,19 @@ function formatContextMarkdown(manifest) {
|
|
|
8449
8475
|
}
|
|
8450
8476
|
return lines.join("\n");
|
|
8451
8477
|
}
|
|
8452
|
-
var import_better_sqlite3, import_gray_matter, import_js_yaml, import_node_fs4,
|
|
8478
|
+
var import_better_sqlite3, import_gray_matter, import_js_yaml, import_node_fs4, import_promises7, import_node_path8, TARGET_ARTIFACT_TYPES, NON_TARGET_ROLES, DEFAULT_SCHEMA, VALID_TC_STATUSES, VALID_CHAIN_TYPES, DEPRECATED_CHAIN_TYPE_ALIASES, CONTEXT_CATEGORIES, TIER_ORDER;
|
|
8453
8479
|
var init_index = __esm({
|
|
8454
8480
|
"src/index.ts"() {
|
|
8455
8481
|
import_better_sqlite3 = __toESM(require("better-sqlite3"), 1);
|
|
8456
8482
|
import_gray_matter = __toESM(require("gray-matter"), 1);
|
|
8457
8483
|
import_js_yaml = __toESM(require("js-yaml"), 1);
|
|
8458
8484
|
import_node_fs4 = require("fs");
|
|
8459
|
-
|
|
8460
|
-
|
|
8485
|
+
import_promises7 = require("fs/promises");
|
|
8486
|
+
import_node_path8 = require("path");
|
|
8461
8487
|
init_packet_constants();
|
|
8462
8488
|
init_packet_validator();
|
|
8463
8489
|
init_glob_matcher();
|
|
8490
|
+
init_file_walker();
|
|
8464
8491
|
init_packet_constants();
|
|
8465
8492
|
init_target_selector();
|
|
8466
8493
|
init_packet_assembler();
|
|
@@ -8611,6 +8638,7 @@ init_index();
|
|
|
8611
8638
|
loadContract,
|
|
8612
8639
|
loadContractCatalog,
|
|
8613
8640
|
loadContractsFromDirectory,
|
|
8641
|
+
matchesConfiguredArtifactPath,
|
|
8614
8642
|
nextId,
|
|
8615
8643
|
normalizeE2eLegacyArtifact,
|
|
8616
8644
|
normalizeToCanonical,
|