artifact-graph 0.6.0 → 0.7.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.cjs CHANGED
@@ -5,6 +5,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __esm = (fn, res) => function __init() {
9
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
+ };
8
11
  var __export = (target, all) => {
9
12
  for (var name in all)
10
13
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -27,121 +30,47 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
30
  ));
28
31
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
32
 
30
- // src/index.ts
31
- var index_exports = {};
32
- __export(index_exports, {
33
- ALWAYS_PRESENT: () => ALWAYS_PRESENT_ITEMS,
34
- BASELINE_CONSTRAINTS: () => BASELINE_CONSTRAINTS,
35
- BASELINE_CONSTRAINTS_COUNT: () => BASELINE_CONSTRAINTS_COUNT,
36
- BASELINE_ITEMS_COUNT: () => BASELINE_ITEMS_COUNT,
37
- DEFAULT_MAX_CHARS: () => DEFAULT_MAX_CHARS,
38
- DEFAULT_SCHEMA: () => DEFAULT_SCHEMA,
39
- MIN_PROMPT_CHARS: () => MIN_PROMPT_CHARS,
40
- TARGET_ARTIFACT_TYPES: () => TARGET_ARTIFACT_TYPES,
41
- VALID_PACKET_TARGET_TYPES: () => VALID_PACKET_TARGET_TYPES,
42
- VERSION_INDEX_SCHEMA_VERSION: () => VERSION_INDEX_SCHEMA_VERSION,
43
- VERSION_LOCK_PATH: () => VERSION_LOCK_PATH,
44
- VERSION_LOCK_SCHEMA_VERSION: () => VERSION_LOCK_SCHEMA_VERSION,
45
- applyPreparedManagedHookBlocks: () => applyPreparedManagedHookBlocks,
46
- assemblePacket: () => assemblePacket,
47
- auditPackets: () => auditPackets,
48
- auditVersionLock: () => auditVersionLock,
49
- bootstrapVersionLock: () => bootstrapVersionLock,
50
- buildGraph: () => buildGraph,
51
- buildVersionIndex: () => buildVersionIndex,
52
- collectChangedPaths: () => collectChangedPaths,
53
- computeE2eCoverageStats: () => computeE2eCoverageStats,
54
- dirname: () => import_node_path6.dirname,
55
- discoverAndAuditPackets: () => discoverAndAuditPackets,
56
- discoverTargets: () => discoverTargets,
57
- doctorArtifactChain: () => doctorArtifactChain,
58
- extname: () => import_node_path6.extname,
59
- formatContextMarkdown: () => formatContextMarkdown,
60
- generateE2eRegistry: () => generateE2eRegistry,
61
- getArtifactTypeMetadata: () => getArtifactTypeMetadata,
62
- getTargetArtifactTypes: () => getTargetArtifactTypes,
63
- installManagedHookBlock: () => installManagedHookBlock,
64
- isPacketTargetType: () => isPacketTargetType,
65
- isPacketTargetTypeDynamic: () => isPacketTargetTypeDynamic,
66
- isTargetArtifactType: () => isTargetArtifactType,
67
- loadConfig: () => loadConfig,
68
- nextId: () => nextId,
69
- parseTargetSelector: () => parseTargetSelector,
70
- parseTargetsFile: () => parseTargetsFile,
71
- prepareManagedHookBlock: () => prepareManagedHookBlock,
72
- queryGraph: () => queryGraph,
73
- refreshVersionLock: () => refreshVersionLock,
74
- renderDoctorMarkdown: () => renderDoctorMarkdown,
75
- renderMermaid: () => renderMermaid,
76
- renderPacketMarkdown: () => renderPacketMarkdown,
77
- renderPacketPrompt: () => renderPacketPrompt,
78
- renderTraceVersionMarkdown: () => renderTraceVersionMarkdown,
79
- renderVersionLockAuditMarkdown: () => renderVersionLockAuditMarkdown,
80
- renderVersionLockRefreshMarkdown: () => renderVersionLockRefreshMarkdown,
81
- resolveArtifactContext: () => resolveArtifactContext,
82
- resolveArtifactGraphCli: () => resolveArtifactGraphCli,
83
- resolveArtifactTypeName: () => resolveArtifactTypeName,
84
- resolveCliTarget: () => resolveCliTarget,
85
- resolveGitHookPath: () => resolveGitHookPath,
86
- resolveMatrixEdges: () => resolveMatrixEdges,
87
- scanArtifacts: () => scanArtifacts,
88
- traceVersion: () => traceVersion,
89
- updateVersionLock: () => updateVersionLock,
90
- validateExecutableTraceability: () => validateExecutableTraceability,
91
- validateGraph: () => validateGraph,
92
- validatePacket: () => validatePacket,
93
- validatePacketMarkdown: () => validatePacketMarkdown,
94
- validatePacketPrompt: () => validatePacketPrompt,
95
- validateReviewResult: () => validateReviewResult,
96
- validateScenarioPrdLinkIndex: () => validateScenarioPrdLinkIndex,
97
- validateScenarioPrdLinks: () => validateScenarioPrdLinks,
98
- writeGraphCache: () => writeGraphCache
99
- });
100
- module.exports = __toCommonJS(index_exports);
101
- var import_better_sqlite3 = __toESM(require("better-sqlite3"), 1);
102
- var import_gray_matter = __toESM(require("gray-matter"), 1);
103
- var import_js_yaml = __toESM(require("js-yaml"), 1);
104
- var import_node_fs4 = require("fs");
105
- var import_promises5 = require("fs/promises");
106
- var import_node_path6 = require("path");
107
-
108
33
  // src/packet-constants.ts
109
- var ALWAYS_PRESENT_ITEMS = [
110
- { path: "AGENTS.md", reason: "project agent instructions" },
111
- { path: "CLAUDE.md", reason: "project instructions" },
112
- { path: "artifacts/artifact-chain-spec.md", reason: "artifact chain specification" },
113
- { path: "artifacts/blueprints/generation-packet-spec.md", reason: "generation packet spec" },
114
- { path: "artifacts/blueprints/implementation-blueprint.md", reason: "implementation blueprint" },
115
- { path: "artifacts/contracts/interface-contracts.md", reason: "interface contracts" },
116
- { path: "artifacts/contracts/data-contracts.md", reason: "data contracts" },
117
- { path: "artifacts/contracts/application-state-machines.md", reason: "application state machines" },
118
- { path: "artifacts/contracts/error-model.md", reason: "error model" },
119
- { path: "artifacts/contracts/report-contracts.md", reason: "report contracts" },
120
- { path: "artifacts/contracts/ui-flow-contracts.md", reason: "UI flow contracts" },
121
- { path: "artifacts/contracts/non-functional-budgets.md", reason: "non-functional budgets" },
122
- { path: "artifacts/domain/domain-glossary.md", reason: "domain glossary" },
123
- { path: "artifacts/domain/bounded-context-map.md", reason: "bounded context map" },
124
- { path: "artifacts/domain/domain-invariants.md", reason: "domain invariants" },
125
- { path: "artifacts/tests/rule-golden-cases.md", reason: "rule golden cases" },
126
- { path: "artifacts/tests/verification-fixtures.md", reason: "verification fixtures" },
127
- { path: "artifacts/design/test-strategy.md", reason: "test strategy" },
128
- { path: "artifacts/traceability-matrix-v2.md", reason: "traceability matrix" }
129
- ];
130
- var BASELINE_ITEMS_COUNT = ALWAYS_PRESENT_ITEMS.length;
131
- var BASELINE_CONSTRAINTS = [
132
- { id: "C-ARCH-01", description: "\u6280\u672F\u6808\u5FC5\u987B\u4E3A TypeScript \u5168\u6808", source: "artifacts/decisions/D-ARCH-01.md" },
133
- { id: "C-ARCH-03", description: "\u4E0D\u53EF\u5728 Quick Check \u8DEF\u5F84\u5F15\u5165 LLM", source: "artifacts/decisions/D-ARCH-03.md" },
134
- { id: "C-ARCH-05", description: "\u4EA7\u54C1\u5F62\u6001\u4E3A Tauri v2 \u684C\u9762\u5E94\u7528\uFF0C\u4E0D\u4F7F\u7528\u5DF2\u5E9F\u5F03\u7684 Web Dashboard", source: "artifacts/decisions/D-ARCH-05.md" },
135
- { id: "C-RULE-01", description: "SEC severity \u4E0D\u5141\u8BB8\u964D\u7EA7", source: "artifacts/decisions/D-RULE-01.md" },
136
- { id: "C-GEN-01", description: "\u5B9E\u73B0\u84DD\u56FE\u4E0D\u5F97\u5F15\u5165 PRD \u4E2D\u672A\u51FA\u73B0\u7684\u65B0\u529F\u80FD", source: "artifacts/blueprints/implementation-blueprint.md" },
137
- { id: "C-GEN-02", description: "\u6587\u4EF6\u53D8\u66F4\u5FC5\u987B\u5148\u68C0\u67E5 interface-contracts\u3001data-contracts\u3001error-model \u662F\u5426\u9700\u8981\u540C\u6B65", source: "artifacts/blueprints/implementation-blueprint.md" },
138
- { id: "C-GEN-03", description: "\u4E0D\u5F97\u5C06\u5E9F\u5F03 Web Dashboard \u8BBE\u8BA1\u4F5C\u4E3A\u5B9E\u73B0\u4F9D\u636E", source: "artifacts/blueprints/implementation-blueprint.md" }
139
- ];
140
- var BASELINE_CONSTRAINTS_COUNT = BASELINE_CONSTRAINTS.length;
34
+ var ALWAYS_PRESENT_ITEMS, BASELINE_ITEMS_COUNT, BASELINE_CONSTRAINTS, BASELINE_CONSTRAINTS_COUNT;
35
+ var init_packet_constants = __esm({
36
+ "src/packet-constants.ts"() {
37
+ "use strict";
38
+ ALWAYS_PRESENT_ITEMS = [
39
+ { path: "AGENTS.md", reason: "project agent instructions" },
40
+ { path: "CLAUDE.md", reason: "project instructions" },
41
+ { path: "artifacts/artifact-chain-spec.md", reason: "artifact chain specification" },
42
+ { path: "artifacts/blueprints/generation-packet-spec.md", reason: "generation packet spec" },
43
+ { path: "artifacts/blueprints/implementation-blueprint.md", reason: "implementation blueprint" },
44
+ { path: "artifacts/contracts/interface-contracts.md", reason: "interface contracts" },
45
+ { path: "artifacts/contracts/data-contracts.md", reason: "data contracts" },
46
+ { path: "artifacts/contracts/application-state-machines.md", reason: "application state machines" },
47
+ { path: "artifacts/contracts/error-model.md", reason: "error model" },
48
+ { path: "artifacts/contracts/report-contracts.md", reason: "report contracts" },
49
+ { path: "artifacts/contracts/ui-flow-contracts.md", reason: "UI flow contracts" },
50
+ { path: "artifacts/contracts/non-functional-budgets.md", reason: "non-functional budgets" },
51
+ { path: "artifacts/domain/domain-glossary.md", reason: "domain glossary" },
52
+ { path: "artifacts/domain/bounded-context-map.md", reason: "bounded context map" },
53
+ { path: "artifacts/domain/domain-invariants.md", reason: "domain invariants" },
54
+ { path: "artifacts/tests/rule-golden-cases.md", reason: "rule golden cases" },
55
+ { path: "artifacts/tests/verification-fixtures.md", reason: "verification fixtures" },
56
+ { path: "artifacts/design/test-strategy.md", reason: "test strategy" },
57
+ { path: "artifacts/traceability-matrix-v2.md", reason: "traceability matrix" }
58
+ ];
59
+ BASELINE_ITEMS_COUNT = ALWAYS_PRESENT_ITEMS.length;
60
+ BASELINE_CONSTRAINTS = [
61
+ { id: "C-ARCH-01", description: "\u6280\u672F\u6808\u5FC5\u987B\u4E3A TypeScript \u5168\u6808", source: "artifacts/decisions/D-ARCH-01.md" },
62
+ { id: "C-ARCH-03", description: "\u4E0D\u53EF\u5728 Quick Check \u8DEF\u5F84\u5F15\u5165 LLM", source: "artifacts/decisions/D-ARCH-03.md" },
63
+ { id: "C-ARCH-05", description: "\u4EA7\u54C1\u5F62\u6001\u4E3A Tauri v2 \u684C\u9762\u5E94\u7528\uFF0C\u4E0D\u4F7F\u7528\u5DF2\u5E9F\u5F03\u7684 Web Dashboard", source: "artifacts/decisions/D-ARCH-05.md" },
64
+ { id: "C-RULE-01", description: "SEC severity \u4E0D\u5141\u8BB8\u964D\u7EA7", source: "artifacts/decisions/D-RULE-01.md" },
65
+ { id: "C-GEN-01", description: "\u5B9E\u73B0\u84DD\u56FE\u4E0D\u5F97\u5F15\u5165 PRD \u4E2D\u672A\u51FA\u73B0\u7684\u65B0\u529F\u80FD", source: "artifacts/blueprints/implementation-blueprint.md" },
66
+ { id: "C-GEN-02", description: "\u6587\u4EF6\u53D8\u66F4\u5FC5\u987B\u5148\u68C0\u67E5 interface-contracts\u3001data-contracts\u3001error-model \u662F\u5426\u9700\u8981\u540C\u6B65", source: "artifacts/blueprints/implementation-blueprint.md" },
67
+ { id: "C-GEN-03", description: "\u4E0D\u5F97\u5C06\u5E9F\u5F03 Web Dashboard \u8BBE\u8BA1\u4F5C\u4E3A\u5B9E\u73B0\u4F9D\u636E", source: "artifacts/blueprints/implementation-blueprint.md" }
68
+ ];
69
+ BASELINE_CONSTRAINTS_COUNT = BASELINE_CONSTRAINTS.length;
70
+ }
71
+ });
141
72
 
142
73
  // src/packet-validator.ts
143
- var MIN_VALIDATION_COMMANDS = 4;
144
- var VALID_PACKET_TARGET_TYPES = ["feature", "scenario", "decision", "design", "e2e_test"];
145
74
  function isPacketTargetType(type) {
146
75
  return VALID_PACKET_TARGET_TYPES.includes(type);
147
76
  }
@@ -154,7 +83,6 @@ function isPacketTargetTypeDynamic(type, schema) {
154
83
  }
155
84
  return isPacketTargetType(type);
156
85
  }
157
- var VALID_TARGET_TYPES = [...VALID_PACKET_TARGET_TYPES];
158
86
  function validatePacket(packet, schema) {
159
87
  const issues = [];
160
88
  if (packet.schemaVersion !== "1.0") {
@@ -332,16 +260,6 @@ function validatePacket(packet, schema) {
332
260
  const hasError = issues.some((i) => i.severity === "error");
333
261
  return { ok: !hasError, issues };
334
262
  }
335
- var REQUIRED_SECTIONS = [
336
- "## 1. \u5B9E\u73B0\u76EE\u6807",
337
- "## 2. \u4E0A\u4E0B\u6587\u6E05\u5355\u6458\u8981",
338
- "## 3. Required Baseline\uFF08\u5FC5\u8BFB\u5236\u54C1\uFF09",
339
- "## 8. Implementation Blueprint Draft\uFF08\u5B9E\u73B0\u84DD\u56FE\u8349\u6848\uFF09",
340
- "### 8.3 \u7EA6\u675F\u4E0E\u8FB9\u754C",
341
- "### 8.4 \u9A8C\u8BC1\u547D\u4EE4",
342
- "### 8.5 \u63A8\u8350\u5BA1\u9605\u987A\u5E8F",
343
- "### 8.6 \u98CE\u9669\u68C0\u67E5\u6E05\u5355"
344
- ];
345
263
  function validatePacketMarkdown(markdown) {
346
264
  const issues = [];
347
265
  for (const section of REQUIRED_SECTIONS) {
@@ -357,6 +275,26 @@ function validatePacketMarkdown(markdown) {
357
275
  const hasError = issues.some((i) => i.severity === "error");
358
276
  return { ok: !hasError, issues };
359
277
  }
278
+ var MIN_VALIDATION_COMMANDS, VALID_PACKET_TARGET_TYPES, VALID_TARGET_TYPES, REQUIRED_SECTIONS;
279
+ var init_packet_validator = __esm({
280
+ "src/packet-validator.ts"() {
281
+ "use strict";
282
+ init_packet_constants();
283
+ MIN_VALIDATION_COMMANDS = 4;
284
+ VALID_PACKET_TARGET_TYPES = ["feature", "scenario", "decision", "design", "e2e_test"];
285
+ VALID_TARGET_TYPES = [...VALID_PACKET_TARGET_TYPES];
286
+ REQUIRED_SECTIONS = [
287
+ "## 1. \u5B9E\u73B0\u76EE\u6807",
288
+ "## 2. \u4E0A\u4E0B\u6587\u6E05\u5355\u6458\u8981",
289
+ "## 3. Required Baseline\uFF08\u5FC5\u8BFB\u5236\u54C1\uFF09",
290
+ "## 8. Implementation Blueprint Draft\uFF08\u5B9E\u73B0\u84DD\u56FE\u8349\u6848\uFF09",
291
+ "### 8.3 \u7EA6\u675F\u4E0E\u8FB9\u754C",
292
+ "### 8.4 \u9A8C\u8BC1\u547D\u4EE4",
293
+ "### 8.5 \u63A8\u8350\u5BA1\u9605\u987A\u5E8F",
294
+ "### 8.6 \u98CE\u9669\u68C0\u67E5\u6E05\u5355"
295
+ ];
296
+ }
297
+ });
360
298
 
361
299
  // src/glob-matcher.ts
362
300
  function matchesRunnerGlob(filePath, pattern) {
@@ -396,6 +334,11 @@ function normalizeGlobValue(value) {
396
334
  function escapeRegexCharacter(character) {
397
335
  return "\\^$+?.()|{}[]".includes(character) ? String.fromCharCode(92) + character : character;
398
336
  }
337
+ var init_glob_matcher = __esm({
338
+ "src/glob-matcher.ts"() {
339
+ "use strict";
340
+ }
341
+ });
399
342
 
400
343
  // src/target-selector.ts
401
344
  function parseTargetSelector(value) {
@@ -405,14 +348,6 @@ function parseTargetSelector(value) {
405
348
  }
406
349
  return { type: value.slice(0, separator), id: value.slice(separator + 1) };
407
350
  }
408
- var LEGACY_FLAGS = ["feature", "scenario", "decision", "design", "e2e-test"];
409
- var LEGACY_FLAG_TO_TYPE = {
410
- feature: "feature",
411
- scenario: "scenario",
412
- decision: "decision",
413
- design: "design",
414
- "e2e-test": "e2e_test"
415
- };
416
351
  function resolveCliTarget(flags, schema) {
417
352
  const hasTarget = typeof flags.target === "string";
418
353
  const legacyEntries = LEGACY_FLAGS.filter((flag) => typeof flags[flag] === "string").map((flag) => flag);
@@ -445,14 +380,23 @@ function resolveCliTarget(flags, schema) {
445
380
  "\u672A\u6307\u5B9A target\uFF1A\u8BF7\u4F7F\u7528 --target <type>:<id> \u6216 --feature/--scenario/--decision/--design/--e2e-test <id>"
446
381
  );
447
382
  }
383
+ var LEGACY_FLAGS, LEGACY_FLAG_TO_TYPE;
384
+ var init_target_selector = __esm({
385
+ "src/target-selector.ts"() {
386
+ "use strict";
387
+ init_index();
388
+ LEGACY_FLAGS = ["feature", "scenario", "decision", "design", "e2e-test"];
389
+ LEGACY_FLAG_TO_TYPE = {
390
+ feature: "feature",
391
+ scenario: "scenario",
392
+ decision: "decision",
393
+ design: "design",
394
+ "e2e-test": "e2e_test"
395
+ };
396
+ }
397
+ });
448
398
 
449
399
  // src/packet-assembler.ts
450
- var DEFAULT_VALIDATION_COMMANDS = [
451
- "pnpm build",
452
- "pnpm test",
453
- "artifact-graph validate --root . --warning-only",
454
- "artifact-graph version-lock audit --root . --strict-missing-lock"
455
- ];
456
400
  function toPacketItem(item) {
457
401
  const pi = {
458
402
  path: item.path,
@@ -589,12 +533,6 @@ function renderContextCategory(cat, opts) {
589
533
  }
590
534
  return lines;
591
535
  }
592
- var COMMAND_COMMENTS = {
593
- "pnpm build": "\u6784\u5EFA\u9879\u76EE",
594
- "pnpm test": "\u8FD0\u884C\u9879\u76EE\u6D4B\u8BD5",
595
- "artifact-graph validate --root . --warning-only": "\u5236\u54C1\u94FE\u4E00\u81F4\u6027\u6821\u9A8C\uFF08warning-only\uFF09",
596
- "artifact-graph version-lock audit --root . --strict-missing-lock": "\u5236\u54C1\u94FE\u7248\u672C\u9501\u4E25\u683C\u5BA1\u8BA1"
597
- };
598
536
  function classifyCategories(manifest) {
599
537
  let baseline = { category: "baseline", total: 0, items: [] };
600
538
  const direct = [];
@@ -891,12 +829,27 @@ function renderPacketMarkdown(packet) {
891
829
  lines.push("> \u63D0\u793A\uFF1A\u4F7F\u7528 Ctrl+F \u641C\u7D22 `[\u5FC5\u8BFB]` \u5FEB\u901F\u5B9A\u4F4D\u5FC5\u8BFB\u5236\u54C1\u3002");
892
830
  return lines.join("\n");
893
831
  }
832
+ var DEFAULT_VALIDATION_COMMANDS, COMMAND_COMMENTS;
833
+ var init_packet_assembler = __esm({
834
+ "src/packet-assembler.ts"() {
835
+ "use strict";
836
+ init_packet_constants();
837
+ DEFAULT_VALIDATION_COMMANDS = [
838
+ "pnpm build",
839
+ "pnpm test",
840
+ "artifact-graph validate --root . --warning-only",
841
+ "artifact-graph version-lock audit --root . --strict-missing-lock"
842
+ ];
843
+ COMMAND_COMMENTS = {
844
+ "pnpm build": "\u6784\u5EFA\u9879\u76EE",
845
+ "pnpm test": "\u8FD0\u884C\u9879\u76EE\u6D4B\u8BD5",
846
+ "artifact-graph validate --root . --warning-only": "\u5236\u54C1\u94FE\u4E00\u81F4\u6027\u6821\u9A8C\uFF08warning-only\uFF09",
847
+ "artifact-graph version-lock audit --root . --strict-missing-lock": "\u5236\u54C1\u94FE\u7248\u672C\u9501\u4E25\u683C\u5BA1\u8BA1"
848
+ };
849
+ }
850
+ });
894
851
 
895
852
  // src/packet-audit.ts
896
- var import_promises = require("fs/promises");
897
- var import_node_path = require("path");
898
- var VALID_TYPES = new Set(VALID_PACKET_TARGET_TYPES);
899
- var VALID_TYPES_LABEL = VALID_PACKET_TARGET_TYPES.join(", ");
900
853
  function parseTargetsFile(content, schema) {
901
854
  const validTypes = schema ? new Set(getTargetArtifactTypes(schema)) : VALID_TYPES;
902
855
  const validTypesLabel = [...validTypes].join(", ");
@@ -1094,20 +1047,23 @@ async function discoverAndAuditPackets(root, options) {
1094
1047
  universalBaseline: effectiveBaseline
1095
1048
  }, graph);
1096
1049
  }
1050
+ var import_promises, import_node_path, VALID_TYPES, VALID_TYPES_LABEL;
1051
+ var init_packet_audit = __esm({
1052
+ "src/packet-audit.ts"() {
1053
+ "use strict";
1054
+ init_index();
1055
+ init_packet_validator();
1056
+ import_promises = require("fs/promises");
1057
+ import_node_path = require("path");
1058
+ VALID_TYPES = new Set(VALID_PACKET_TARGET_TYPES);
1059
+ VALID_TYPES_LABEL = VALID_PACKET_TARGET_TYPES.join(", ");
1060
+ }
1061
+ });
1097
1062
 
1098
1063
  // src/packet-prompt.ts
1099
- var TYPE_CLI_FLAG = {
1100
- feature: "feature",
1101
- scenario: "scenario",
1102
- decision: "decision",
1103
- design: "design",
1104
- e2e_test: "e2e-test"
1105
- };
1106
1064
  function cliFlag(type) {
1107
1065
  return TYPE_CLI_FLAG[type] ?? type;
1108
1066
  }
1109
- var DEFAULT_MAX_CHARS = 4e3;
1110
- var MIN_PROMPT_CHARS = 320;
1111
1067
  function renderPromptHeader(packet) {
1112
1068
  const t = packet.target;
1113
1069
  const typeLabelMap = { feature: "\u529F\u80FD", scenario: "\u573A\u666F", decision: "\u51B3\u7B56", design: "\u8BBE\u8BA1\u89C4\u683C", e2e_test: "E2E \u6D4B\u8BD5" };
@@ -1331,52 +1287,24 @@ function renderPacketPrompt(packet, options) {
1331
1287
  minRequired: absMinText.length
1332
1288
  };
1333
1289
  }
1290
+ var TYPE_CLI_FLAG, DEFAULT_MAX_CHARS, MIN_PROMPT_CHARS;
1291
+ var init_packet_prompt = __esm({
1292
+ "src/packet-prompt.ts"() {
1293
+ "use strict";
1294
+ init_packet_constants();
1295
+ TYPE_CLI_FLAG = {
1296
+ feature: "feature",
1297
+ scenario: "scenario",
1298
+ decision: "decision",
1299
+ design: "design",
1300
+ e2e_test: "e2e-test"
1301
+ };
1302
+ DEFAULT_MAX_CHARS = 4e3;
1303
+ MIN_PROMPT_CHARS = 320;
1304
+ }
1305
+ });
1334
1306
 
1335
1307
  // src/packet-prompt-validator.ts
1336
- var REQUIRED_CHECKS = [
1337
- {
1338
- code: "PP-001",
1339
- description: "\u76EE\u6807\u4FE1\u606F",
1340
- test: (t) => /实现任务/.test(t),
1341
- severity: "error"
1342
- },
1343
- {
1344
- code: "PP-002",
1345
- description: "packet \u547D\u4EE4\u6216\u6765\u6E90\u5F15\u7528",
1346
- test: (t) => /packet\s+--root/.test(t) || /packet\.json/.test(t) || /artifact-graph\s+packet/.test(t),
1347
- severity: "error"
1348
- },
1349
- {
1350
- code: "PP-003",
1351
- description: "\u9A8C\u8BC1\u547D\u4EE4",
1352
- test: (t) => /验证命令/.test(t) || /artifact-graph\s+(build|test)/.test(t),
1353
- severity: "error"
1354
- },
1355
- {
1356
- code: "PP-004",
1357
- description: "\u63D0\u4EA4\u8981\u6C42",
1358
- test: (t) => /提交要求/.test(t) || /git\s+diff\s+--check/.test(t),
1359
- severity: "error"
1360
- },
1361
- {
1362
- code: "PP-005",
1363
- description: "\u7981\u6B62\u4E8B\u9879",
1364
- test: (t) => /禁止事项/.test(t),
1365
- severity: "error"
1366
- },
1367
- {
1368
- code: "PP-006",
1369
- description: "\u4E0D\u5F97\u56DE\u9000\u89C4\u5219",
1370
- test: (t) => /不得回退/.test(t) || /不要回退/.test(t) || /no[- ]?revert/i.test(t),
1371
- severity: "error"
1372
- },
1373
- {
1374
- code: "PP-007",
1375
- description: "SEC severity \u89C4\u5219",
1376
- test: (t) => /SEC\s+severity/.test(t) || /severity/.test(t) && /降级/.test(t),
1377
- severity: "error"
1378
- }
1379
- ];
1380
1308
  function checkChineseDominance(text) {
1381
1309
  const textOutsideCode = text.replace(/```[\s\S]*?```/g, "");
1382
1310
  const cleanText = textOutsideCode.replace(/^[#>]+ .*$/gm, "").replace(/\[.*?\]\(.*?\)/g, "");
@@ -1411,15 +1339,58 @@ function validatePacketPrompt(prompt) {
1411
1339
  const hasErrors = issues.some((i) => i.severity === "error");
1412
1340
  return { ok: !hasErrors, issues };
1413
1341
  }
1342
+ var REQUIRED_CHECKS;
1343
+ var init_packet_prompt_validator = __esm({
1344
+ "src/packet-prompt-validator.ts"() {
1345
+ "use strict";
1346
+ REQUIRED_CHECKS = [
1347
+ {
1348
+ code: "PP-001",
1349
+ description: "\u76EE\u6807\u4FE1\u606F",
1350
+ test: (t) => /实现任务/.test(t),
1351
+ severity: "error"
1352
+ },
1353
+ {
1354
+ code: "PP-002",
1355
+ description: "packet \u547D\u4EE4\u6216\u6765\u6E90\u5F15\u7528",
1356
+ test: (t) => /packet\s+--root/.test(t) || /packet\.json/.test(t) || /artifact-graph\s+packet/.test(t),
1357
+ severity: "error"
1358
+ },
1359
+ {
1360
+ code: "PP-003",
1361
+ description: "\u9A8C\u8BC1\u547D\u4EE4",
1362
+ test: (t) => /验证命令/.test(t) || /artifact-graph\s+(build|test)/.test(t),
1363
+ severity: "error"
1364
+ },
1365
+ {
1366
+ code: "PP-004",
1367
+ description: "\u63D0\u4EA4\u8981\u6C42",
1368
+ test: (t) => /提交要求/.test(t) || /git\s+diff\s+--check/.test(t),
1369
+ severity: "error"
1370
+ },
1371
+ {
1372
+ code: "PP-005",
1373
+ description: "\u7981\u6B62\u4E8B\u9879",
1374
+ test: (t) => /禁止事项/.test(t),
1375
+ severity: "error"
1376
+ },
1377
+ {
1378
+ code: "PP-006",
1379
+ description: "\u4E0D\u5F97\u56DE\u9000\u89C4\u5219",
1380
+ test: (t) => /不得回退/.test(t) || /不要回退/.test(t) || /no[- ]?revert/i.test(t),
1381
+ severity: "error"
1382
+ },
1383
+ {
1384
+ code: "PP-007",
1385
+ description: "SEC severity \u89C4\u5219",
1386
+ test: (t) => /SEC\s+severity/.test(t) || /severity/.test(t) && /降级/.test(t),
1387
+ severity: "error"
1388
+ }
1389
+ ];
1390
+ }
1391
+ });
1414
1392
 
1415
1393
  // src/versioned-traceability.ts
1416
- var import_node_crypto = require("crypto");
1417
- var import_node_fs = require("fs");
1418
- var import_promises2 = require("fs/promises");
1419
- var import_node_path2 = require("path");
1420
- var VERSION_LOCK_PATH = "artifacts/traceability-version-lock.json";
1421
- var VERSION_INDEX_SCHEMA_VERSION = "1.0";
1422
- var VERSION_LOCK_SCHEMA_VERSION = "1.0";
1423
1394
  async function buildVersionIndex(root, graph) {
1424
1395
  const scannedGraph = graph ?? await scanArtifacts(root);
1425
1396
  const hashCache = /* @__PURE__ */ new Map();
@@ -2219,34 +2190,23 @@ async function isFileActiveInRunner(root, filePath, runner) {
2219
2190
  function sortUnique(items) {
2220
2191
  return [...new Set(items)].sort((left, right) => left.localeCompare(right));
2221
2192
  }
2193
+ var import_node_crypto, import_node_fs, import_promises2, import_node_path2, VERSION_LOCK_PATH, VERSION_INDEX_SCHEMA_VERSION, VERSION_LOCK_SCHEMA_VERSION;
2194
+ var init_versioned_traceability = __esm({
2195
+ "src/versioned-traceability.ts"() {
2196
+ "use strict";
2197
+ import_node_crypto = require("crypto");
2198
+ import_node_fs = require("fs");
2199
+ import_promises2 = require("fs/promises");
2200
+ import_node_path2 = require("path");
2201
+ init_index();
2202
+ init_glob_matcher();
2203
+ VERSION_LOCK_PATH = "artifacts/traceability-version-lock.json";
2204
+ VERSION_INDEX_SCHEMA_VERSION = "1.0";
2205
+ VERSION_LOCK_SCHEMA_VERSION = "1.0";
2206
+ }
2207
+ });
2222
2208
 
2223
2209
  // src/cli-resolver.ts
2224
- var import_node_child_process = require("child_process");
2225
- var import_node_fs2 = require("fs");
2226
- var import_promises3 = require("fs/promises");
2227
- var import_node_path3 = require("path");
2228
- var import_node_util = require("util");
2229
- var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
2230
- var KNOWN_COMMANDS = [
2231
- "init",
2232
- "scan",
2233
- "validate",
2234
- "query",
2235
- "context",
2236
- "packet",
2237
- "packet-prompt",
2238
- "packet-audit",
2239
- "packet-prompt-audit",
2240
- "version-index",
2241
- "version-lock audit",
2242
- "version-lock update",
2243
- "version-lock bootstrap",
2244
- "version-lock refresh",
2245
- "trace-version",
2246
- "next-id",
2247
- "render",
2248
- "doctor"
2249
- ];
2250
2210
  async function resolveArtifactGraphCli(root, options = {}) {
2251
2211
  const pathCli = await findCommandOnPath("artifact-graph");
2252
2212
  const legacyCliPath = options.projectCliPath ?? process.env.ARTIFACT_GRAPH_LEGACY_CLI;
@@ -2382,11 +2342,41 @@ function isNodeCompatible(version) {
2382
2342
  const major = Number(version.split(".")[0]);
2383
2343
  return Number.isFinite(major) && major >= 22;
2384
2344
  }
2345
+ var import_node_child_process, import_node_fs2, import_promises3, import_node_path3, import_node_util, execFileAsync, KNOWN_COMMANDS;
2346
+ var init_cli_resolver = __esm({
2347
+ "src/cli-resolver.ts"() {
2348
+ "use strict";
2349
+ import_node_child_process = require("child_process");
2350
+ import_node_fs2 = require("fs");
2351
+ import_promises3 = require("fs/promises");
2352
+ import_node_path3 = require("path");
2353
+ import_node_util = require("util");
2354
+ init_versioned_traceability();
2355
+ execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
2356
+ KNOWN_COMMANDS = [
2357
+ "init",
2358
+ "scan",
2359
+ "validate",
2360
+ "query",
2361
+ "context",
2362
+ "packet",
2363
+ "packet-prompt",
2364
+ "packet-audit",
2365
+ "packet-prompt-audit",
2366
+ "version-index",
2367
+ "version-lock audit",
2368
+ "version-lock update",
2369
+ "version-lock bootstrap",
2370
+ "version-lock refresh",
2371
+ "trace-version",
2372
+ "next-id",
2373
+ "render",
2374
+ "doctor"
2375
+ ];
2376
+ }
2377
+ });
2385
2378
 
2386
2379
  // src/git-changes.ts
2387
- var import_node_child_process2 = require("child_process");
2388
- var import_node_util2 = require("util");
2389
- var execFileAsync2 = (0, import_node_util2.promisify)(import_node_child_process2.execFile);
2390
2380
  async function collectChangedPaths(root, options) {
2391
2381
  const args = gitDiffArgs(options);
2392
2382
  let stdout;
@@ -2396,8 +2386,10 @@ async function collectChangedPaths(root, options) {
2396
2386
  const message = error instanceof Error ? error.message : String(error);
2397
2387
  throw new Error(`Unable to collect git changed paths (${options.mode}): ${message}`);
2398
2388
  }
2399
- const changedPaths = normalizeGitPathList(stdout);
2400
- const unstagedPaths = options.mode === "staged" ? await collectUnstagedPaths(root) : [];
2389
+ const trackedChangedPaths = normalizeGitPathList(stdout);
2390
+ const untrackedPaths = options.mode === "worktree" || options.mode === "staged" ? await collectUntrackedPaths(root) : [];
2391
+ const changedPaths = options.mode === "worktree" ? sortUnique2([...trackedChangedPaths, ...untrackedPaths]) : trackedChangedPaths;
2392
+ const unstagedPaths = options.mode === "staged" ? sortUnique2([...await collectUnstagedPaths(root), ...untrackedPaths]) : [];
2401
2393
  const stagedUnstagedConflictPaths = options.mode === "staged" ? intersect(changedPaths, unstagedPaths) : [];
2402
2394
  return {
2403
2395
  root,
@@ -2429,6 +2421,14 @@ async function collectUnstagedPaths(root) {
2429
2421
  return [];
2430
2422
  }
2431
2423
  }
2424
+ async function collectUntrackedPaths(root) {
2425
+ try {
2426
+ const { stdout } = await execFileAsync2("git", ["ls-files", "--others", "--exclude-standard"], { cwd: root });
2427
+ return normalizeGitPathList(stdout);
2428
+ } catch {
2429
+ return [];
2430
+ }
2431
+ }
2432
2432
  function normalizeGitPathList(stdout) {
2433
2433
  return sortUnique2(stdout.split(/\r?\n/).map((line) => line.trim().replace(/\\/g, "/").replace(/^\.\//, "")).filter((line) => line.length > 0 && !line.startsWith("../") && !line.startsWith("/")));
2434
2434
  }
@@ -2439,12 +2439,17 @@ function intersect(left, right) {
2439
2439
  function sortUnique2(items) {
2440
2440
  return [...new Set(items)].sort((left, right) => left.localeCompare(right));
2441
2441
  }
2442
+ var import_node_child_process2, import_node_util2, execFileAsync2;
2443
+ var init_git_changes = __esm({
2444
+ "src/git-changes.ts"() {
2445
+ "use strict";
2446
+ import_node_child_process2 = require("child_process");
2447
+ import_node_util2 = require("util");
2448
+ execFileAsync2 = (0, import_node_util2.promisify)(import_node_child_process2.execFile);
2449
+ }
2450
+ });
2442
2451
 
2443
2452
  // src/git-hook-path.ts
2444
- var import_node_child_process3 = require("child_process");
2445
- var import_node_path4 = require("path");
2446
- var import_node_util3 = require("util");
2447
- var execFileAsync3 = (0, import_node_util3.promisify)(import_node_child_process3.execFile);
2448
2453
  async function resolveGitHookPath(root, hookName) {
2449
2454
  const { stdout } = await execFileAsync3("git", [
2450
2455
  "-C",
@@ -2457,74 +2462,18 @@ async function resolveGitHookPath(root, hookName) {
2457
2462
  if (!value) throw new Error(`Git returned an empty hook path for ${hookName}`);
2458
2463
  return (0, import_node_path4.isAbsolute)(value) ? (0, import_node_path4.resolve)(value) : (0, import_node_path4.resolve)(root, value);
2459
2464
  }
2465
+ var import_node_child_process3, import_node_path4, import_node_util3, execFileAsync3;
2466
+ var init_git_hook_path = __esm({
2467
+ "src/git-hook-path.ts"() {
2468
+ "use strict";
2469
+ import_node_child_process3 = require("child_process");
2470
+ import_node_path4 = require("path");
2471
+ import_node_util3 = require("util");
2472
+ execFileAsync3 = (0, import_node_util3.promisify)(import_node_child_process3.execFile);
2473
+ }
2474
+ });
2460
2475
 
2461
2476
  // src/hook-installer.ts
2462
- var import_node_fs3 = require("fs");
2463
- var import_node_crypto2 = require("crypto");
2464
- var import_promises4 = require("fs/promises");
2465
- var import_node_path5 = require("path");
2466
- var DEFAULT_MARKER_ID = "artifact-chain-assistant";
2467
- var MANAGED_STATE_PREFIX = "# artifact-chain-assistant managed state v1:";
2468
- var UnsupportedHookInterpreterError = class extends Error {
2469
- constructor(hookPath, shebang) {
2470
- super(
2471
- `Refusing to modify non-shell Git hook ${hookPath} (${shebang || "missing shebang"}). Call the artifact-chain hook from the existing hook explicitly.`
2472
- );
2473
- this.hookPath = hookPath;
2474
- this.shebang = shebang;
2475
- }
2476
- hookPath;
2477
- shebang;
2478
- code = "UNSUPPORTED_HOOK_INTERPRETER";
2479
- };
2480
- var SymlinkHookUnsupportedError = class extends Error {
2481
- constructor(hookPath, linkTarget) {
2482
- super(
2483
- `SYMLINK_HOOK_UNSUPPORTED: Refusing to modify Git hook symlink ${hookPath} -> ${linkTarget}. Integrate the artifact-graph commands manually in the symlink target or replace the link yourself.`
2484
- );
2485
- this.hookPath = hookPath;
2486
- this.linkTarget = linkTarget;
2487
- }
2488
- hookPath;
2489
- linkTarget;
2490
- code = "SYMLINK_HOOK_UNSUPPORTED";
2491
- };
2492
- var UnsupportedHookTypeError = class extends Error {
2493
- constructor(hookPath) {
2494
- super(`UNSUPPORTED_HOOK_TYPE: Git hook path ${hookPath} is not a regular file. Resolve it manually before retrying.`);
2495
- this.hookPath = hookPath;
2496
- }
2497
- hookPath;
2498
- code = "UNSUPPORTED_HOOK_TYPE";
2499
- };
2500
- var InvalidManagedHookStateError = class extends Error {
2501
- constructor(hookPath, detail) {
2502
- super(`INVALID_MANAGED_HOOK_STATE: Cannot safely update ${hookPath}: ${detail}`);
2503
- this.hookPath = hookPath;
2504
- }
2505
- hookPath;
2506
- code = "INVALID_MANAGED_HOOK_STATE";
2507
- };
2508
- var ConcurrentHookModificationError = class extends Error {
2509
- constructor(hookPath) {
2510
- super(`Refusing to overwrite concurrently modified Git hook ${hookPath}. Retry the operation after reviewing the hook.`);
2511
- this.hookPath = hookPath;
2512
- }
2513
- hookPath;
2514
- code = "CONCURRENT_HOOK_MODIFICATION";
2515
- };
2516
- var HookTransactionRollbackError = class extends Error {
2517
- constructor(operationError, rollbackErrors) {
2518
- super(
2519
- `HOOK_TRANSACTION_ROLLBACK_FAILED: Hook update failed and ${rollbackErrors.length} rollback operation(s) also failed: ` + rollbackErrors.map(({ hookPath, error }) => `${hookPath}: ${error.message}`).join("; ")
2520
- );
2521
- this.operationError = operationError;
2522
- this.rollbackErrors = rollbackErrors;
2523
- }
2524
- operationError;
2525
- rollbackErrors;
2526
- code = "HOOK_TRANSACTION_ROLLBACK_FAILED";
2527
- };
2528
2477
  function detectHookInterpreter(content) {
2529
2478
  if (content.trim().length === 0) {
2530
2479
  return "empty";
@@ -2882,44 +2831,80 @@ function findManagedRange(content, begin, end) {
2882
2831
  end: endLine < 0 ? content.length : endLine + 1
2883
2832
  };
2884
2833
  }
2834
+ var import_node_fs3, import_node_crypto2, import_promises4, import_node_path5, DEFAULT_MARKER_ID, MANAGED_STATE_PREFIX, UnsupportedHookInterpreterError, SymlinkHookUnsupportedError, UnsupportedHookTypeError, InvalidManagedHookStateError, ConcurrentHookModificationError, HookTransactionRollbackError;
2835
+ var init_hook_installer = __esm({
2836
+ "src/hook-installer.ts"() {
2837
+ "use strict";
2838
+ import_node_fs3 = require("fs");
2839
+ import_node_crypto2 = require("crypto");
2840
+ import_promises4 = require("fs/promises");
2841
+ import_node_path5 = require("path");
2842
+ DEFAULT_MARKER_ID = "artifact-chain-assistant";
2843
+ MANAGED_STATE_PREFIX = "# artifact-chain-assistant managed state v1:";
2844
+ UnsupportedHookInterpreterError = class extends Error {
2845
+ constructor(hookPath, shebang) {
2846
+ super(
2847
+ `Refusing to modify non-shell Git hook ${hookPath} (${shebang || "missing shebang"}). Call the artifact-chain hook from the existing hook explicitly.`
2848
+ );
2849
+ this.hookPath = hookPath;
2850
+ this.shebang = shebang;
2851
+ }
2852
+ hookPath;
2853
+ shebang;
2854
+ code = "UNSUPPORTED_HOOK_INTERPRETER";
2855
+ };
2856
+ SymlinkHookUnsupportedError = class extends Error {
2857
+ constructor(hookPath, linkTarget) {
2858
+ super(
2859
+ `SYMLINK_HOOK_UNSUPPORTED: Refusing to modify Git hook symlink ${hookPath} -> ${linkTarget}. Integrate the artifact-graph commands manually in the symlink target or replace the link yourself.`
2860
+ );
2861
+ this.hookPath = hookPath;
2862
+ this.linkTarget = linkTarget;
2863
+ }
2864
+ hookPath;
2865
+ linkTarget;
2866
+ code = "SYMLINK_HOOK_UNSUPPORTED";
2867
+ };
2868
+ UnsupportedHookTypeError = class extends Error {
2869
+ constructor(hookPath) {
2870
+ super(`UNSUPPORTED_HOOK_TYPE: Git hook path ${hookPath} is not a regular file. Resolve it manually before retrying.`);
2871
+ this.hookPath = hookPath;
2872
+ }
2873
+ hookPath;
2874
+ code = "UNSUPPORTED_HOOK_TYPE";
2875
+ };
2876
+ InvalidManagedHookStateError = class extends Error {
2877
+ constructor(hookPath, detail) {
2878
+ super(`INVALID_MANAGED_HOOK_STATE: Cannot safely update ${hookPath}: ${detail}`);
2879
+ this.hookPath = hookPath;
2880
+ }
2881
+ hookPath;
2882
+ code = "INVALID_MANAGED_HOOK_STATE";
2883
+ };
2884
+ ConcurrentHookModificationError = class extends Error {
2885
+ constructor(hookPath) {
2886
+ super(`Refusing to overwrite concurrently modified Git hook ${hookPath}. Retry the operation after reviewing the hook.`);
2887
+ this.hookPath = hookPath;
2888
+ }
2889
+ hookPath;
2890
+ code = "CONCURRENT_HOOK_MODIFICATION";
2891
+ };
2892
+ HookTransactionRollbackError = class extends Error {
2893
+ constructor(operationError, rollbackErrors) {
2894
+ super(
2895
+ `HOOK_TRANSACTION_ROLLBACK_FAILED: Hook update failed and ${rollbackErrors.length} rollback operation(s) also failed: ` + rollbackErrors.map(({ hookPath, error }) => `${hookPath}: ${error.message}`).join("; ")
2896
+ );
2897
+ this.operationError = operationError;
2898
+ this.rollbackErrors = rollbackErrors;
2899
+ }
2900
+ operationError;
2901
+ rollbackErrors;
2902
+ code = "HOOK_TRANSACTION_ROLLBACK_FAILED";
2903
+ };
2904
+ }
2905
+ });
2885
2906
 
2886
2907
  // src/review-result-validator.ts
2887
- var VALID_STATUSES = /* @__PURE__ */ new Set([
2888
- "SUCCEEDED",
2889
- "FAILED",
2890
- "BLOCKED",
2891
- "NEEDS_INPUT",
2892
- "SKIPPED"
2893
- ]);
2894
- var VALID_DECISIONS = /* @__PURE__ */ new Set([
2895
- "PASS",
2896
- "FAIL",
2897
- "PASS_WITH_RESIDUAL_MINOR",
2898
- "BLOCKED",
2899
- "NEEDS_INPUT",
2900
- "NOT_APPLICABLE"
2901
- ]);
2902
- var VALID_SEVERITIES = /* @__PURE__ */ new Set(["block", "warn", "info"]);
2903
- var VALID_FINDING_STATUSES = /* @__PURE__ */ new Set(["open", "resolved", "accepted", "superseded"]);
2904
- var VALID_EXECUTORS = /* @__PURE__ */ new Set(["script", "worker", "agent", "manual", "cli"]);
2905
- var TOP_LEVEL_FIELDS = /* @__PURE__ */ new Set([
2906
- "schema_version",
2907
- "run_id",
2908
- "stage_id",
2909
- "attempt",
2910
- "status",
2911
- "decision",
2912
- "summary",
2913
- "outputs",
2914
- "warnings",
2915
- "blocking_reason",
2916
- "degradation",
2917
- "producer",
2918
- "acceptance",
2919
- "evidence",
2920
- "review",
2921
- "repair"
2922
- ]);
2923
2908
  function validateReviewResult(input) {
2924
2909
  const errors = [];
2925
2910
  if (!input || typeof input !== "object" || Array.isArray(input)) {
@@ -3168,19 +3153,6 @@ function validateBatches(val, path, errors) {
3168
3153
  checkOptionalInteger(b.chars, `${itemPath}.chars`, errors);
3169
3154
  }
3170
3155
  }
3171
- var METRIC_FIELDS = [
3172
- "files_reviewed",
3173
- "files_scanned",
3174
- "findings_count",
3175
- "deterministic_findings_count",
3176
- "semantic_findings_count",
3177
- "block_count",
3178
- "warn_count",
3179
- "info_count",
3180
- "resolved_count",
3181
- "batch_count",
3182
- "scenario_count"
3183
- ];
3184
3156
  function validateMetrics(val, path, errors) {
3185
3157
  if (!isPlainObject(val)) {
3186
3158
  errors.push({ path, message: "Must be an object" });
@@ -3197,10 +3169,924 @@ function validateRepairValidation(val, path, errors) {
3197
3169
  checkOptionalInteger(val.exit_code, `${path}.exit_code`, errors);
3198
3170
  checkOptionalInteger(val.findings_remaining, `${path}.findings_remaining`, errors, 0);
3199
3171
  }
3172
+ var VALID_STATUSES, VALID_DECISIONS, VALID_SEVERITIES, VALID_FINDING_STATUSES, VALID_EXECUTORS, TOP_LEVEL_FIELDS, METRIC_FIELDS;
3173
+ var init_review_result_validator = __esm({
3174
+ "src/review-result-validator.ts"() {
3175
+ "use strict";
3176
+ VALID_STATUSES = /* @__PURE__ */ new Set([
3177
+ "SUCCEEDED",
3178
+ "FAILED",
3179
+ "BLOCKED",
3180
+ "NEEDS_INPUT",
3181
+ "SKIPPED"
3182
+ ]);
3183
+ VALID_DECISIONS = /* @__PURE__ */ new Set([
3184
+ "PASS",
3185
+ "FAIL",
3186
+ "PASS_WITH_RESIDUAL_MINOR",
3187
+ "BLOCKED",
3188
+ "NEEDS_INPUT",
3189
+ "NOT_APPLICABLE"
3190
+ ]);
3191
+ VALID_SEVERITIES = /* @__PURE__ */ new Set(["block", "warn", "info"]);
3192
+ VALID_FINDING_STATUSES = /* @__PURE__ */ new Set(["open", "resolved", "accepted", "superseded"]);
3193
+ VALID_EXECUTORS = /* @__PURE__ */ new Set(["script", "worker", "agent", "manual", "cli"]);
3194
+ TOP_LEVEL_FIELDS = /* @__PURE__ */ new Set([
3195
+ "schema_version",
3196
+ "run_id",
3197
+ "stage_id",
3198
+ "attempt",
3199
+ "status",
3200
+ "decision",
3201
+ "summary",
3202
+ "outputs",
3203
+ "warnings",
3204
+ "blocking_reason",
3205
+ "degradation",
3206
+ "producer",
3207
+ "acceptance",
3208
+ "evidence",
3209
+ "review",
3210
+ "repair"
3211
+ ]);
3212
+ METRIC_FIELDS = [
3213
+ "files_reviewed",
3214
+ "files_scanned",
3215
+ "findings_count",
3216
+ "deterministic_findings_count",
3217
+ "semantic_findings_count",
3218
+ "block_count",
3219
+ "warn_count",
3220
+ "info_count",
3221
+ "resolved_count",
3222
+ "batch_count",
3223
+ "scenario_count"
3224
+ ];
3225
+ }
3226
+ });
3227
+
3228
+ // src/contract-kernel.ts
3229
+ function isOfficialNamespace(namespace) {
3230
+ return OFFICIAL_NAMESPACE_PATTERN.test(namespace);
3231
+ }
3232
+ function validateNamespaceAuthority(identity, expectedAuthority) {
3233
+ if (isOfficialNamespace(identity.namespace) && identity.authority !== OFFICIAL_AUTHORITY) {
3234
+ throw new ContractError(
3235
+ CONTRACT_ERROR_CODES.AUTHORITY_VIOLATION,
3236
+ `Namespace ${identity.namespace} requires authority "${OFFICIAL_AUTHORITY}", got "${identity.authority}"`,
3237
+ { identity, expectedAuthority: OFFICIAL_AUTHORITY }
3238
+ );
3239
+ }
3240
+ if (expectedAuthority && identity.authority !== expectedAuthority) {
3241
+ throw new ContractError(
3242
+ CONTRACT_ERROR_CODES.AUTHORITY_VIOLATION,
3243
+ `Expected authority "${expectedAuthority}", got "${identity.authority}"`,
3244
+ { identity, expectedAuthority }
3245
+ );
3246
+ }
3247
+ }
3248
+ function canonicalizeForDigest(rawContent) {
3249
+ try {
3250
+ const parsed = JSON.parse(rawContent);
3251
+ if (parsed.contractIdentity && typeof parsed.contractIdentity === "object") {
3252
+ const ci = { ...parsed.contractIdentity };
3253
+ delete ci.revisionDigest;
3254
+ parsed.contractIdentity = ci;
3255
+ }
3256
+ return JSON.stringify(parsed);
3257
+ } catch {
3258
+ return rawContent;
3259
+ }
3260
+ }
3261
+ function computeRevisionDigest(content) {
3262
+ const canonical = canonicalizeForDigest(content);
3263
+ const hash = (0, import_node_crypto3.createHash)("sha256").update(canonical, "utf-8").digest("hex");
3264
+ return `sha256:${hash}`;
3265
+ }
3266
+ function verifyDigest(content, expectedDigest) {
3267
+ const actualDigest = computeRevisionDigest(content);
3268
+ return actualDigest === expectedDigest;
3269
+ }
3270
+ function setNestedValue(obj, path, value) {
3271
+ const parts = path.split(".");
3272
+ let current = obj;
3273
+ for (let i = 0; i < parts.length - 1; i++) {
3274
+ const part = parts[i];
3275
+ if (current[part] === void 0 || typeof current[part] !== "object" || current[part] === null) {
3276
+ current[part] = {};
3277
+ }
3278
+ current = current[part];
3279
+ }
3280
+ current[parts[parts.length - 1]] = value;
3281
+ }
3282
+ function matchesSchemaType(value, definition) {
3283
+ const type = definition?.type;
3284
+ if (type === "array") return Array.isArray(value);
3285
+ if (type === "object") return typeof value === "object" && value !== null && !Array.isArray(value);
3286
+ if (type === "string") return typeof value === "string";
3287
+ if (type === "number" || type === "integer") return typeof value === "number";
3288
+ if (type === "boolean") return typeof value === "boolean";
3289
+ return value !== void 0;
3290
+ }
3291
+ function getNestedValue(source, path) {
3292
+ let current = source;
3293
+ for (const part of path.split(".")) {
3294
+ if (typeof current !== "object" || current === null || Array.isArray(current)) return void 0;
3295
+ current = current[part];
3296
+ }
3297
+ return current;
3298
+ }
3299
+ function valuesEqual(left, right) {
3300
+ return JSON.stringify(left) === JSON.stringify(right);
3301
+ }
3302
+ function normalizeToCanonical(legacyData, config, contract) {
3303
+ const errors = [];
3304
+ const warnings = [];
3305
+ const legacyFieldMap = /* @__PURE__ */ new Map();
3306
+ for (const mapping of config.fieldMappings) {
3307
+ legacyFieldMap.set(mapping.legacy, mapping.canonical);
3308
+ }
3309
+ const canonical = {};
3310
+ const canonicalRoots = new Set(Object.keys(contract.schema.properties));
3311
+ const presentCanonicalRoots = /* @__PURE__ */ new Set();
3312
+ for (const root of canonicalRoots) {
3313
+ const value = legacyData[root];
3314
+ if (value !== void 0 && matchesSchemaType(value, contract.schema.properties[root])) {
3315
+ canonical[root] = structuredClone(value);
3316
+ presentCanonicalRoots.add(root);
3317
+ }
3318
+ }
3319
+ const unmappedLegacyFields = new Set(
3320
+ Object.keys(legacyData).filter((field) => !presentCanonicalRoots.has(field) && !legacyFieldMap.has(field))
3321
+ );
3322
+ let usedLegacyExpression = false;
3323
+ for (const mapping of config.fieldMappings) {
3324
+ const legacyValue = legacyData[mapping.legacy];
3325
+ const existingCanonicalValue = getNestedValue(canonical, mapping.canonical);
3326
+ if (legacyValue !== void 0 && !presentCanonicalRoots.has(mapping.legacy)) {
3327
+ usedLegacyExpression = true;
3328
+ const canonicalValue = mapping.transform ? mapping.transform(legacyValue) : legacyValue;
3329
+ if (existingCanonicalValue !== void 0) {
3330
+ if (!valuesEqual(existingCanonicalValue, canonicalValue)) {
3331
+ errors.push({
3332
+ code: CONTRACT_ERROR_CODES.CANONICAL_LEGACY_CONFLICT,
3333
+ path: `/${mapping.canonical.replaceAll(".", "/")}`,
3334
+ message: `Canonical field "${mapping.canonical}" conflicts with legacy field "${mapping.legacy}"`
3335
+ });
3336
+ }
3337
+ } else {
3338
+ setNestedValue(canonical, mapping.canonical, canonicalValue);
3339
+ }
3340
+ }
3341
+ if (mapping.required && getNestedValue(canonical, mapping.canonical) === void 0) {
3342
+ errors.push({
3343
+ code: "MISSING_REQUIRED_FIELD",
3344
+ path: `/${mapping.canonical.replaceAll(".", "/")}`,
3345
+ message: `Required canonical field "${mapping.canonical}" missing (legacy: "${mapping.legacy}")`
3346
+ });
3347
+ }
3348
+ }
3349
+ for (const field of unmappedLegacyFields) {
3350
+ errors.push({
3351
+ code: "LOSSY_NORMALIZATION",
3352
+ path: field,
3353
+ message: `Legacy field "${field}" not mapped to canonical form \u2014 would be lost`
3354
+ });
3355
+ }
3356
+ if (config.validate) {
3357
+ const validationErrors = config.validate(canonical);
3358
+ for (const error of validationErrors) {
3359
+ errors.push({
3360
+ code: "VALIDATION_FAILED",
3361
+ path: "",
3362
+ message: error
3363
+ });
3364
+ }
3365
+ }
3366
+ if (errors.length > 0) {
3367
+ return { success: false, errors, warnings };
3368
+ }
3369
+ const schemaResult = validateContractAgainstSchema(canonical, contract);
3370
+ if (!schemaResult.valid) {
3371
+ return {
3372
+ success: false,
3373
+ errors: schemaResult.errors.map((e) => ({
3374
+ code: "SCHEMA_VALIDATION_FAILED",
3375
+ path: e.split(":")[0]?.trim() ?? "",
3376
+ message: e
3377
+ })),
3378
+ warnings
3379
+ };
3380
+ }
3381
+ if (Array.isArray(canonical.relations)) {
3382
+ const relationResult = validateRelations(canonical.relations, contract);
3383
+ if (!relationResult.valid) {
3384
+ return {
3385
+ success: false,
3386
+ errors: relationResult.issues.map((i) => ({
3387
+ code: i.code,
3388
+ path: i.path,
3389
+ message: i.message
3390
+ })),
3391
+ warnings
3392
+ };
3393
+ }
3394
+ }
3395
+ const sourceRevision = usedLegacyExpression ? "legacy" : "canonical";
3396
+ return {
3397
+ success: true,
3398
+ ir: {
3399
+ type: contract.identity.major.split(".")[1]?.split("@")[0] ?? "unknown",
3400
+ id: String(canonical.metadata?.id ?? canonical["id"] ?? ""),
3401
+ contractMajor: contract.identity.major,
3402
+ contractDigest: contract.identity.revisionDigest,
3403
+ canonical,
3404
+ sourceRevision,
3405
+ warnings
3406
+ },
3407
+ errors: [],
3408
+ warnings
3409
+ };
3410
+ }
3411
+ function resolvePropertyPath(schema, fieldPath) {
3412
+ const parts = fieldPath.split(".");
3413
+ let current = schema.properties;
3414
+ for (const part of parts) {
3415
+ if (!current || typeof current !== "object") return void 0;
3416
+ const propDef = current[part];
3417
+ if (!propDef) return void 0;
3418
+ if (parts.indexOf(part) < parts.length - 1) {
3419
+ current = propDef.properties;
3420
+ } else {
3421
+ return propDef;
3422
+ }
3423
+ }
3424
+ return void 0;
3425
+ }
3426
+ function validatePolicyCompatibility(policy, baseContract) {
3427
+ const errors = [];
3428
+ const warnings = [];
3429
+ if (policy.baseContractMajor !== baseContract.identity.major) {
3430
+ errors.push(
3431
+ `POLICY_INCOMPATIBLE: Policy references ${policy.baseContractMajor}, but base contract is ${baseContract.identity.major}`
3432
+ );
3433
+ return { compatible: false, errors, warnings };
3434
+ }
3435
+ const schema = baseContract.schema;
3436
+ if (policy.additionalRequired) {
3437
+ for (const field of policy.additionalRequired) {
3438
+ const propDef = resolvePropertyPath(schema, field);
3439
+ if (!propDef) {
3440
+ errors.push(`POLICY_INCOMPATIBLE: Policy requires field "${field}" which does not exist in base contract`);
3441
+ }
3442
+ }
3443
+ }
3444
+ if (policy.restrictedEnums) {
3445
+ for (const [field, values] of Object.entries(policy.restrictedEnums)) {
3446
+ const baseProperty = resolvePropertyPath(schema, field);
3447
+ if (!baseProperty) {
3448
+ errors.push(`POLICY_INCOMPATIBLE: Policy restricts enum for field "${field}" which does not exist in base contract`);
3449
+ continue;
3450
+ }
3451
+ if (!Array.isArray(baseProperty.enum)) {
3452
+ errors.push(`POLICY_INCOMPATIBLE: Field "${field}" is not an enum in base contract \u2014 cannot restrict`);
3453
+ continue;
3454
+ }
3455
+ for (const value of values) {
3456
+ if (!baseProperty.enum.includes(value)) {
3457
+ errors.push(`POLICY_INCOMPATIBLE: Policy enum value "${String(value)}" for field "${field}" not in base contract enum [${baseProperty.enum.join(", ")}]`);
3458
+ }
3459
+ }
3460
+ }
3461
+ }
3462
+ if (policy.minCardinality) {
3463
+ for (const [field, min] of Object.entries(policy.minCardinality)) {
3464
+ if (!Number.isFinite(min) || min < 0 || !Number.isInteger(min)) {
3465
+ errors.push(`POLICY_INCOMPATIBLE: Policy min cardinality for "${field}" must be a non-negative integer, got ${min}`);
3466
+ continue;
3467
+ }
3468
+ const baseProperty = resolvePropertyPath(schema, field);
3469
+ if (!baseProperty) {
3470
+ errors.push(`POLICY_INCOMPATIBLE: Policy sets min cardinality for field "${field}" which does not exist in base contract`);
3471
+ continue;
3472
+ }
3473
+ const baseMin = baseProperty.type === "array" ? baseProperty.minItems : baseProperty.minimum;
3474
+ if (baseMin !== void 0 && min < baseMin) {
3475
+ errors.push(`POLICY_INCOMPATIBLE: Policy min cardinality ${min} for field "${field}" loosens base ${baseProperty.type === "array" ? "minItems" : "minimum"}=${baseMin}`);
3476
+ }
3477
+ }
3478
+ }
3479
+ if (policy.maxCardinality) {
3480
+ for (const [field, max] of Object.entries(policy.maxCardinality)) {
3481
+ if (!Number.isFinite(max) || max < 0 || !Number.isInteger(max)) {
3482
+ errors.push(`POLICY_INCOMPATIBLE: Policy max cardinality for "${field}" must be a non-negative integer, got ${max}`);
3483
+ continue;
3484
+ }
3485
+ const baseProperty = resolvePropertyPath(schema, field);
3486
+ if (!baseProperty) {
3487
+ errors.push(`POLICY_INCOMPATIBLE: Policy sets max cardinality for field "${field}" which does not exist in base contract`);
3488
+ continue;
3489
+ }
3490
+ const baseMax = baseProperty.type === "array" ? baseProperty.maxItems : baseProperty.maximum;
3491
+ if (baseMax !== void 0 && max > baseMax) {
3492
+ errors.push(`POLICY_INCOMPATIBLE: Policy max cardinality ${max} for field "${field}" loosens base ${baseProperty.type === "array" ? "maxItems" : "maximum"}=${baseMax}`);
3493
+ }
3494
+ }
3495
+ }
3496
+ if (policy.constraints && Object.keys(policy.constraints).length > 0) {
3497
+ for (const key of Object.keys(policy.constraints)) {
3498
+ errors.push(`POLICY_INCOMPATIBLE: Constraint "${key}" is not implemented \u2014 rejected as unvalidated escape hatch`);
3499
+ }
3500
+ }
3501
+ return {
3502
+ compatible: errors.length === 0,
3503
+ errors,
3504
+ warnings
3505
+ };
3506
+ }
3507
+ async function loadContract(contractPath, options) {
3508
+ const rawContent = await (0, import_promises5.readFile)(contractPath, "utf-8");
3509
+ let schema;
3510
+ try {
3511
+ schema = JSON.parse(rawContent);
3512
+ } catch (error) {
3513
+ throw new ContractError(
3514
+ CONTRACT_ERROR_CODES.INVALID_IDENTITY,
3515
+ `Failed to parse contract JSON: ${error.message}`,
3516
+ { path: contractPath }
3517
+ );
3518
+ }
3519
+ if (!schema.contractIdentity) {
3520
+ throw new ContractError(
3521
+ CONTRACT_ERROR_CODES.INVALID_IDENTITY,
3522
+ "Contract missing contractIdentity",
3523
+ { path: contractPath }
3524
+ );
3525
+ }
3526
+ const identity = schema.contractIdentity;
3527
+ if (!identity.major || !identity.authority || !identity.namespace) {
3528
+ throw new ContractError(
3529
+ CONTRACT_ERROR_CODES.INVALID_IDENTITY,
3530
+ "Contract identity missing required fields (major, authority, namespace)",
3531
+ { identity }
3532
+ );
3533
+ }
3534
+ if (options?.expectedAuthority) {
3535
+ validateNamespaceAuthority(identity, options.expectedAuthority);
3536
+ } else {
3537
+ validateNamespaceAuthority(identity);
3538
+ }
3539
+ const computedDigest = computeRevisionDigest(rawContent);
3540
+ if (identity.revisionDigest && identity.revisionDigest !== computedDigest) {
3541
+ throw new ContractError(
3542
+ CONTRACT_ERROR_CODES.DIGEST_MISMATCH,
3543
+ `Contract digest mismatch: declared ${identity.revisionDigest}, computed ${computedDigest}`,
3544
+ { identity, computedDigest }
3545
+ );
3546
+ }
3547
+ identity.revisionDigest = computedDigest;
3548
+ return {
3549
+ identity,
3550
+ schema,
3551
+ rawContent
3552
+ };
3553
+ }
3554
+ async function loadContractsFromDirectory(contractsDir, options) {
3555
+ const contracts = [];
3556
+ const entries = await (0, import_promises5.readdir)(contractsDir, { withFileTypes: true });
3557
+ for (const entry of entries) {
3558
+ if (entry.isDirectory()) {
3559
+ const schemaPath = (0, import_node_path6.join)(contractsDir, entry.name, "schema.json");
3560
+ const contract = await loadContract(schemaPath, options);
3561
+ contracts.push(contract);
3562
+ }
3563
+ }
3564
+ return contracts;
3565
+ }
3566
+ function getValidator(schema) {
3567
+ const key = `${schema.$id || "default"}#${computeRevisionDigest(JSON.stringify(schema))}`;
3568
+ if (!_validatorCache.has(key)) {
3569
+ const AjvCtor = import_ajv.default;
3570
+ const ajv = new AjvCtor({ allErrors: true, strict: false });
3571
+ _validatorCache.set(key, ajv.compile(schema));
3572
+ }
3573
+ return _validatorCache.get(key);
3574
+ }
3575
+ function validateContractAgainstSchema(data, contract) {
3576
+ const validate = getValidator(contract.schema);
3577
+ const valid = validate(data);
3578
+ if (valid) {
3579
+ return { valid: true, errors: [] };
3580
+ }
3581
+ const errors = (validate.errors ?? []).map(
3582
+ (err) => `${err.instancePath || "/"}: ${err.message ?? "validation error"}`
3583
+ );
3584
+ return { valid: false, errors };
3585
+ }
3586
+ function validateRelations(relations, contract) {
3587
+ const issues = [];
3588
+ const relationRules = contract.identity.relationRules;
3589
+ if (!relationRules) {
3590
+ issues.push({
3591
+ code: "RELATION_RULES_MISSING",
3592
+ path: "/contractIdentity/relationRules",
3593
+ message: "Contract does not define relation rules \u2014 cannot validate relations"
3594
+ });
3595
+ return { valid: false, issues };
3596
+ }
3597
+ const relationsByKind = /* @__PURE__ */ new Map();
3598
+ for (const relation of relations) {
3599
+ const kind = relation.kind;
3600
+ if (!relationsByKind.has(kind)) {
3601
+ relationsByKind.set(kind, []);
3602
+ }
3603
+ relationsByKind.get(kind).push(relation);
3604
+ }
3605
+ for (let i = 0; i < relations.length; i++) {
3606
+ const relation = relations[i];
3607
+ const kind = relation.kind;
3608
+ const targetType = relation.target_type;
3609
+ const path = `/relations/${i}`;
3610
+ if (!relationRules[kind]) {
3611
+ issues.push({
3612
+ code: "RELATION_INVALID_KIND",
3613
+ path: `${path}/kind`,
3614
+ message: `Relation kind "${kind}" is not allowed by contract rules`
3615
+ });
3616
+ continue;
3617
+ }
3618
+ const rule = relationRules[kind];
3619
+ if (!rule.allowedTargetTypes.includes(targetType)) {
3620
+ issues.push({
3621
+ code: "RELATION_INVALID_TARGET_TYPE",
3622
+ path: `${path}/target_type`,
3623
+ message: `Target type "${targetType}" is not allowed for relation kind "${kind}". Allowed: ${rule.allowedTargetTypes.join(", ")}`
3624
+ });
3625
+ }
3626
+ const hasAnchor = relation.anchor !== void 0 && relation.anchor !== "";
3627
+ if (rule.anchorPolicy === "required" && !hasAnchor) {
3628
+ issues.push({
3629
+ code: "RELATION_MISSING_ANCHOR",
3630
+ path: `${path}/anchor`,
3631
+ message: `Relation kind "${kind}" requires an anchor`
3632
+ });
3633
+ } else if (rule.anchorPolicy === "forbidden" && hasAnchor) {
3634
+ issues.push({
3635
+ code: "RELATION_FORBIDDEN_ANCHOR",
3636
+ path: `${path}/anchor`,
3637
+ message: `Relation kind "${kind}" forbids anchors`
3638
+ });
3639
+ }
3640
+ }
3641
+ for (const [kind, rule] of Object.entries(relationRules)) {
3642
+ const count = relationsByKind.get(kind)?.length ?? 0;
3643
+ if (count < rule.min) {
3644
+ issues.push({
3645
+ code: "RELATION_BELOW_MIN",
3646
+ path: "/relations",
3647
+ message: `Relation kind "${kind}" has ${count} instances, minimum is ${rule.min}`
3648
+ });
3649
+ }
3650
+ if (count > rule.max) {
3651
+ issues.push({
3652
+ code: "RELATION_ABOVE_MAX",
3653
+ path: "/relations",
3654
+ message: `Relation kind "${kind}" has ${count} instances, maximum is ${rule.max}`
3655
+ });
3656
+ }
3657
+ }
3658
+ return {
3659
+ valid: issues.length === 0,
3660
+ issues
3661
+ };
3662
+ }
3663
+ function normalizeE2eLegacyArtifact(legacyData, contract) {
3664
+ return normalizeToCanonical(legacyData, E2E_NORMALIZER_CONFIG, contract);
3665
+ }
3666
+ async function loadContractCatalog(contractsDir, options) {
3667
+ const catalog = new ContractCatalog();
3668
+ const contracts = await loadContractsFromDirectory(contractsDir, options);
3669
+ for (const contract of contracts) {
3670
+ catalog.add(contract);
3671
+ }
3672
+ return catalog;
3673
+ }
3674
+ var import_node_crypto3, import_promises5, import_node_path6, import_ajv, CONTRACT_ERROR_CODES, ContractError, OFFICIAL_AUTHORITY, OFFICIAL_NAMESPACE_PATTERN, ContractRegistry, _validatorCache, E2E_NORMALIZER_CONFIG, ContractCatalog;
3675
+ var init_contract_kernel = __esm({
3676
+ "src/contract-kernel.ts"() {
3677
+ "use strict";
3678
+ import_node_crypto3 = require("crypto");
3679
+ import_promises5 = require("fs/promises");
3680
+ import_node_path6 = require("path");
3681
+ import_ajv = __toESM(require("ajv"), 1);
3682
+ CONTRACT_ERROR_CODES = {
3683
+ /** Contract identity not found */
3684
+ CONTRACT_NOT_FOUND: "CONTRACT_NOT_FOUND",
3685
+ /** Invalid contract identity format */
3686
+ INVALID_IDENTITY: "INVALID_IDENTITY",
3687
+ /** Revision digest mismatch */
3688
+ DIGEST_MISMATCH: "DIGEST_MISMATCH",
3689
+ /** Duplicate contract identity */
3690
+ DUPLICATE_IDENTITY: "DUPLICATE_IDENTITY",
3691
+ /** Multiple active write contracts for same type */
3692
+ MULTIPLE_ACTIVE_WRITE: "MULTIPLE_ACTIVE_WRITE",
3693
+ /** Unknown authority namespace */
3694
+ UNKNOWN_AUTHORITY: "UNKNOWN_AUTHORITY",
3695
+ /** Namespace authority violation */
3696
+ AUTHORITY_VIOLATION: "AUTHORITY_VIOLATION",
3697
+ /** Schema validation failed */
3698
+ SCHEMA_VALIDATION_FAILED: "SCHEMA_VALIDATION_FAILED",
3699
+ /** Canonical IR normalization failed */
3700
+ NORMALIZATION_FAILED: "NORMALIZATION_FAILED",
3701
+ /** Policy compatibility check failed */
3702
+ POLICY_INCOMPATIBLE: "POLICY_INCOMPATIBLE",
3703
+ /** Legacy revision cannot be normalized */
3704
+ LEGACY_NORMALIZATION_FAILED: "LEGACY_NORMALIZATION_FAILED",
3705
+ /** Canonical and legacy conflict */
3706
+ CANONICAL_LEGACY_CONFLICT: "CANONICAL_LEGACY_CONFLICT",
3707
+ /** Relation rule violation */
3708
+ RELATION_RULE_VIOLATION: "RELATION_RULE_VIOLATION",
3709
+ /** Relation rules missing in contract (fail closed) */
3710
+ RELATION_RULES_MISSING: "RELATION_RULES_MISSING",
3711
+ /** Ambiguous revision — multiple revisions found, no unique active write */
3712
+ AMBIGUOUS_REVISION: "AMBIGUOUS_REVISION",
3713
+ /** Invalid relation kind */
3714
+ RELATION_INVALID_KIND: "RELATION_INVALID_KIND",
3715
+ /** Invalid relation target type */
3716
+ RELATION_INVALID_TARGET_TYPE: "RELATION_INVALID_TARGET_TYPE",
3717
+ /** Relation below minimum cardinality */
3718
+ RELATION_BELOW_MIN: "RELATION_BELOW_MIN",
3719
+ /** Relation above maximum cardinality */
3720
+ RELATION_ABOVE_MAX: "RELATION_ABOVE_MAX",
3721
+ /** Missing required anchor */
3722
+ RELATION_MISSING_ANCHOR: "RELATION_MISSING_ANCHOR",
3723
+ /** Forbidden anchor present */
3724
+ RELATION_FORBIDDEN_ANCHOR: "RELATION_FORBIDDEN_ANCHOR",
3725
+ /** Missing required semantic marker */
3726
+ MARKER_MISSING: "MARKER_MISSING",
3727
+ /** Duplicate semantic marker */
3728
+ MARKER_DUPLICATE: "MARKER_DUPLICATE",
3729
+ /** Unknown semantic marker */
3730
+ MARKER_UNKNOWN: "MARKER_UNKNOWN"
3731
+ };
3732
+ ContractError = class extends Error {
3733
+ constructor(code, message, details) {
3734
+ super(message);
3735
+ this.code = code;
3736
+ this.details = details;
3737
+ this.name = "ContractError";
3738
+ }
3739
+ code;
3740
+ details;
3741
+ };
3742
+ OFFICIAL_AUTHORITY = "artifact";
3743
+ OFFICIAL_NAMESPACE_PATTERN = /^artifact(?:\.|$)/;
3744
+ ContractRegistry = class {
3745
+ contracts = /* @__PURE__ */ new Map();
3746
+ typeToActiveWrite = /* @__PURE__ */ new Map();
3747
+ majorToContracts = /* @__PURE__ */ new Map();
3748
+ /**
3749
+ * Register a contract
3750
+ * @throws ContractError if duplicate identity or multiple active write contracts
3751
+ */
3752
+ register(contract, options) {
3753
+ const major = contract.identity.major;
3754
+ const digest = contract.identity.revisionDigest;
3755
+ const key = `${major}@${digest}`;
3756
+ const isActive = options?.isActive ?? true;
3757
+ const isWriteTarget = options?.isWriteTarget ?? true;
3758
+ if (this.contracts.has(key)) {
3759
+ throw new ContractError(
3760
+ CONTRACT_ERROR_CODES.DUPLICATE_IDENTITY,
3761
+ `Contract ${key} already registered`,
3762
+ { identity: contract.identity }
3763
+ );
3764
+ }
3765
+ if (isActive && isWriteTarget) {
3766
+ const type = major.split("@")[0];
3767
+ if (this.typeToActiveWrite.has(type)) {
3768
+ throw new ContractError(
3769
+ CONTRACT_ERROR_CODES.MULTIPLE_ACTIVE_WRITE,
3770
+ `Type ${type} already has active write contract: ${this.typeToActiveWrite.get(type)}`,
3771
+ { identity: contract.identity, existing: this.typeToActiveWrite.get(type) }
3772
+ );
3773
+ }
3774
+ this.typeToActiveWrite.set(type, key);
3775
+ }
3776
+ this.contracts.set(key, {
3777
+ contract,
3778
+ isActive,
3779
+ isWriteTarget,
3780
+ loadedAt: (/* @__PURE__ */ new Date()).toISOString()
3781
+ });
3782
+ if (!this.majorToContracts.has(major)) {
3783
+ this.majorToContracts.set(major, /* @__PURE__ */ new Set());
3784
+ }
3785
+ this.majorToContracts.get(major).add(key);
3786
+ }
3787
+ /**
3788
+ * Resolve by major identity. Multiple revisions require a unique active write
3789
+ * revision; insertion order is never a resolution policy.
3790
+ */
3791
+ get(major) {
3792
+ const keys = this.majorToContracts.get(major);
3793
+ if (!keys || keys.size === 0) return void 0;
3794
+ if (keys.size === 1) {
3795
+ const onlyKey = keys.values().next().value;
3796
+ return onlyKey ? this.contracts.get(onlyKey)?.contract : void 0;
3797
+ }
3798
+ const type = major.split("@")[0];
3799
+ const activeWriteKey = this.typeToActiveWrite.get(type);
3800
+ if (activeWriteKey && keys.has(activeWriteKey)) {
3801
+ return this.contracts.get(activeWriteKey)?.contract;
3802
+ }
3803
+ throw new ContractError(
3804
+ CONTRACT_ERROR_CODES.AMBIGUOUS_REVISION,
3805
+ `Multiple revisions found for ${major} with no unique active write \u2014 specify digest`,
3806
+ {
3807
+ major,
3808
+ availableDigests: Array.from(keys).map((key) => this.contracts.get(key)?.contract.identity.revisionDigest).filter((digest) => Boolean(digest))
3809
+ }
3810
+ );
3811
+ }
3812
+ /**
3813
+ * Get contract by major identity and digest
3814
+ */
3815
+ getByMajorAndDigest(major, digest) {
3816
+ const key = `${major}@${digest}`;
3817
+ return this.contracts.get(key)?.contract;
3818
+ }
3819
+ /**
3820
+ * Get all contracts for a major identity
3821
+ */
3822
+ getByMajor(major) {
3823
+ const keys = this.majorToContracts.get(major);
3824
+ if (!keys) return [];
3825
+ return Array.from(keys).map((key) => this.contracts.get(key)?.contract).filter((c) => c !== void 0);
3826
+ }
3827
+ /**
3828
+ * Get active write contract for a type
3829
+ */
3830
+ getActiveWriteContract(typePrefix) {
3831
+ const key = this.typeToActiveWrite.get(typePrefix);
3832
+ return key ? this.contracts.get(key)?.contract : void 0;
3833
+ }
3834
+ /**
3835
+ * List all registered contracts
3836
+ */
3837
+ list() {
3838
+ return Array.from(this.contracts.values());
3839
+ }
3840
+ /**
3841
+ * Check if a contract is registered by major identity
3842
+ */
3843
+ has(major) {
3844
+ const keys = this.majorToContracts.get(major);
3845
+ return keys !== void 0 && keys.size > 0;
3846
+ }
3847
+ /**
3848
+ * Check if a contract is registered by major identity and digest
3849
+ */
3850
+ hasByMajorAndDigest(major, digest) {
3851
+ const key = `${major}@${digest}`;
3852
+ return this.contracts.has(key);
3853
+ }
3854
+ };
3855
+ _validatorCache = /* @__PURE__ */ new Map();
3856
+ E2E_NORMALIZER_CONFIG = {
3857
+ contractMajor: "artifact.e2e-test@1",
3858
+ fieldMappings: [
3859
+ { legacy: "id", canonical: "metadata.id", required: true },
3860
+ { legacy: "title", canonical: "metadata.title", required: true },
3861
+ { legacy: "status", canonical: "metadata.status", required: true },
3862
+ { legacy: "test_batch", canonical: "metadata.test_batch" },
3863
+ { legacy: "scope", canonical: "scope.business_goal", transform: (v) => String(v) },
3864
+ { legacy: "actors", canonical: "scope.actors", transform: (v) => Array.isArray(v) ? v : [v] },
3865
+ { legacy: "system_boundaries", canonical: "system_boundary.components", transform: (v) => Array.isArray(v) ? v : [v] },
3866
+ { legacy: "test_cases", canonical: "test_cases", required: true },
3867
+ { legacy: "relations", canonical: "relations" },
3868
+ // Map legacy coverage fields if present
3869
+ { legacy: "ac_coverage", canonical: "coverage.ac_coverage" },
3870
+ { legacy: "related_scenarios", canonical: "coverage.related_scenarios" },
3871
+ // Map legacy environment fields if present
3872
+ { legacy: "topology", canonical: "environment_data.topology" },
3873
+ { legacy: "fixtures", canonical: "environment_data.fixtures" },
3874
+ { legacy: "isolation_strategy", canonical: "environment_data.isolation_strategy" },
3875
+ // Map legacy evidence fields if present
3876
+ { legacy: "required_artifacts", canonical: "evidence_contract.required_artifacts" },
3877
+ { legacy: "runner_binding", canonical: "evidence_contract.runner_binding" }
3878
+ ],
3879
+ validate: (canonical) => {
3880
+ const errors = [];
3881
+ if (!canonical.metadata || typeof canonical.metadata !== "object") {
3882
+ errors.push("metadata must be an object");
3883
+ }
3884
+ if (!canonical.scope || typeof canonical.scope !== "object") {
3885
+ errors.push("scope must be an object");
3886
+ }
3887
+ if (!canonical.system_boundary || typeof canonical.system_boundary !== "object") {
3888
+ errors.push("system_boundary must be an object");
3889
+ }
3890
+ if (!Array.isArray(canonical.test_cases) || canonical.test_cases.length === 0) {
3891
+ errors.push("test_cases must be a non-empty array");
3892
+ }
3893
+ if (Array.isArray(canonical.test_cases)) {
3894
+ for (let i = 0; i < canonical.test_cases.length; i++) {
3895
+ const tc = canonical.test_cases[i];
3896
+ if (!Array.isArray(tc.trace_targets) || tc.trace_targets.length === 0) {
3897
+ errors.push(`test_cases[${i}].trace_targets must be a non-empty array`);
3898
+ }
3899
+ }
3900
+ }
3901
+ return errors;
3902
+ }
3903
+ };
3904
+ ContractCatalog = class {
3905
+ contracts = /* @__PURE__ */ new Map();
3906
+ majorToContracts = /* @__PURE__ */ new Map();
3907
+ majorToActiveWrite = /* @__PURE__ */ new Map();
3908
+ /**
3909
+ * Add a contract to the catalog
3910
+ * @throws ContractError if duplicate identity
3911
+ */
3912
+ add(contract, options) {
3913
+ const major = contract.identity.major;
3914
+ const digest = contract.identity.revisionDigest;
3915
+ const key = `${major}@${digest}`;
3916
+ const isActive = options?.isActive ?? true;
3917
+ const isWriteTarget = options?.isWriteTarget ?? true;
3918
+ if (this.contracts.has(key)) {
3919
+ throw new ContractError(
3920
+ CONTRACT_ERROR_CODES.DUPLICATE_IDENTITY,
3921
+ `Contract ${key} already in catalog`,
3922
+ { identity: contract.identity }
3923
+ );
3924
+ }
3925
+ this.contracts.set(key, contract);
3926
+ if (!this.majorToContracts.has(major)) {
3927
+ this.majorToContracts.set(major, /* @__PURE__ */ new Set());
3928
+ }
3929
+ this.majorToContracts.get(major).add(key);
3930
+ if (isActive && isWriteTarget) {
3931
+ const existingActive = this.majorToActiveWrite.get(major);
3932
+ if (existingActive && existingActive !== key) {
3933
+ this.contracts.delete(key);
3934
+ this.majorToContracts.get(major)?.delete(key);
3935
+ throw new ContractError(
3936
+ CONTRACT_ERROR_CODES.MULTIPLE_ACTIVE_WRITE,
3937
+ `Major ${major} already has active write revision`,
3938
+ { major, existing: existingActive, attempted: key }
3939
+ );
3940
+ }
3941
+ this.majorToActiveWrite.set(major, key);
3942
+ }
3943
+ }
3944
+ /**
3945
+ * Resolve a contract by major identity.
3946
+ * - 0 entries: returns undefined
3947
+ * - 1 entry: returns it
3948
+ * - multiple: if there's a unique active write, returns it; otherwise throws AMBIGUOUS_REVISION
3949
+ */
3950
+ resolve(major) {
3951
+ const keys = this.majorToContracts.get(major);
3952
+ if (!keys || keys.size === 0) return void 0;
3953
+ if (keys.size === 1) {
3954
+ const firstKey = keys.values().next().value;
3955
+ return firstKey ? this.contracts.get(firstKey) : void 0;
3956
+ }
3957
+ const activeWriteKey = this.majorToActiveWrite.get(major);
3958
+ if (activeWriteKey) {
3959
+ return this.contracts.get(activeWriteKey);
3960
+ }
3961
+ throw new ContractError(
3962
+ CONTRACT_ERROR_CODES.AMBIGUOUS_REVISION,
3963
+ `Multiple revisions found for ${major} with no unique active write \u2014 specify digest`,
3964
+ {
3965
+ major,
3966
+ availableDigests: Array.from(keys).map((key) => this.contracts.get(key)?.identity.revisionDigest).filter((digest) => Boolean(digest))
3967
+ }
3968
+ );
3969
+ }
3970
+ /**
3971
+ * Resolve a contract by major identity and exact digest
3972
+ */
3973
+ resolveByDigest(major, digest) {
3974
+ const key = `${major}@${digest}`;
3975
+ return this.contracts.get(key);
3976
+ }
3977
+ /**
3978
+ * List all catalog entries (all revisions)
3979
+ */
3980
+ list() {
3981
+ return Array.from(this.contracts.values()).map((contract) => ({
3982
+ identity: contract.identity,
3983
+ contract
3984
+ }));
3985
+ }
3986
+ /**
3987
+ * Get catalog as JSON-serializable object (all revisions)
3988
+ */
3989
+ toJSON() {
3990
+ return {
3991
+ contracts: this.list().map((entry) => ({
3992
+ major: entry.identity.major,
3993
+ authority: entry.identity.authority,
3994
+ namespace: entry.identity.namespace,
3995
+ revisionDigest: entry.identity.revisionDigest
3996
+ }))
3997
+ };
3998
+ }
3999
+ };
4000
+ }
4001
+ });
3200
4002
 
3201
4003
  // src/index.ts
3202
- var TARGET_ARTIFACT_TYPES = VALID_PACKET_TARGET_TYPES;
3203
- var NON_TARGET_ROLES = ["context", "candidate", "not-recommended"];
4004
+ var index_exports = {};
4005
+ __export(index_exports, {
4006
+ ALWAYS_PRESENT: () => ALWAYS_PRESENT_ITEMS,
4007
+ BASELINE_CONSTRAINTS: () => BASELINE_CONSTRAINTS,
4008
+ BASELINE_CONSTRAINTS_COUNT: () => BASELINE_CONSTRAINTS_COUNT,
4009
+ BASELINE_ITEMS_COUNT: () => BASELINE_ITEMS_COUNT,
4010
+ CONTRACT_ERROR_CODES: () => CONTRACT_ERROR_CODES,
4011
+ ContractCatalog: () => ContractCatalog,
4012
+ ContractError: () => ContractError,
4013
+ ContractRegistry: () => ContractRegistry,
4014
+ DEFAULT_MAX_CHARS: () => DEFAULT_MAX_CHARS,
4015
+ DEFAULT_SCHEMA: () => DEFAULT_SCHEMA,
4016
+ E2E_NORMALIZER_CONFIG: () => E2E_NORMALIZER_CONFIG,
4017
+ MIN_PROMPT_CHARS: () => MIN_PROMPT_CHARS,
4018
+ TARGET_ARTIFACT_TYPES: () => TARGET_ARTIFACT_TYPES,
4019
+ VALID_PACKET_TARGET_TYPES: () => VALID_PACKET_TARGET_TYPES,
4020
+ VERSION_INDEX_SCHEMA_VERSION: () => VERSION_INDEX_SCHEMA_VERSION,
4021
+ VERSION_LOCK_PATH: () => VERSION_LOCK_PATH,
4022
+ VERSION_LOCK_SCHEMA_VERSION: () => VERSION_LOCK_SCHEMA_VERSION,
4023
+ applyPreparedManagedHookBlocks: () => applyPreparedManagedHookBlocks,
4024
+ assemblePacket: () => assemblePacket,
4025
+ auditPackets: () => auditPackets,
4026
+ auditVersionLock: () => auditVersionLock,
4027
+ bootstrapVersionLock: () => bootstrapVersionLock,
4028
+ buildGraph: () => buildGraph,
4029
+ buildVersionIndex: () => buildVersionIndex,
4030
+ collectChangedPaths: () => collectChangedPaths,
4031
+ computeE2eCoverageStats: () => computeE2eCoverageStats,
4032
+ computeRevisionDigest: () => computeRevisionDigest,
4033
+ dirname: () => import_node_path7.dirname,
4034
+ discoverAndAuditPackets: () => discoverAndAuditPackets,
4035
+ discoverTargets: () => discoverTargets,
4036
+ doctorArtifactChain: () => doctorArtifactChain,
4037
+ extname: () => import_node_path7.extname,
4038
+ formatContextMarkdown: () => formatContextMarkdown,
4039
+ generateE2eRegistry: () => generateE2eRegistry,
4040
+ getArtifactTypeMetadata: () => getArtifactTypeMetadata,
4041
+ getTargetArtifactTypes: () => getTargetArtifactTypes,
4042
+ installManagedHookBlock: () => installManagedHookBlock,
4043
+ isOfficialNamespace: () => isOfficialNamespace,
4044
+ isPacketTargetType: () => isPacketTargetType,
4045
+ isPacketTargetTypeDynamic: () => isPacketTargetTypeDynamic,
4046
+ isTargetArtifactType: () => isTargetArtifactType,
4047
+ loadConfig: () => loadConfig,
4048
+ loadContract: () => loadContract,
4049
+ loadContractCatalog: () => loadContractCatalog,
4050
+ loadContractsFromDirectory: () => loadContractsFromDirectory,
4051
+ nextId: () => nextId,
4052
+ normalizeE2eLegacyArtifact: () => normalizeE2eLegacyArtifact,
4053
+ normalizeToCanonical: () => normalizeToCanonical,
4054
+ parseTargetSelector: () => parseTargetSelector,
4055
+ parseTargetsFile: () => parseTargetsFile,
4056
+ prepareManagedHookBlock: () => prepareManagedHookBlock,
4057
+ queryGraph: () => queryGraph,
4058
+ refreshVersionLock: () => refreshVersionLock,
4059
+ renderDoctorMarkdown: () => renderDoctorMarkdown,
4060
+ renderMermaid: () => renderMermaid,
4061
+ renderPacketMarkdown: () => renderPacketMarkdown,
4062
+ renderPacketPrompt: () => renderPacketPrompt,
4063
+ renderTraceVersionMarkdown: () => renderTraceVersionMarkdown,
4064
+ renderVersionLockAuditMarkdown: () => renderVersionLockAuditMarkdown,
4065
+ renderVersionLockRefreshMarkdown: () => renderVersionLockRefreshMarkdown,
4066
+ resolveArtifactContext: () => resolveArtifactContext,
4067
+ resolveArtifactGraphCli: () => resolveArtifactGraphCli,
4068
+ resolveArtifactTypeName: () => resolveArtifactTypeName,
4069
+ resolveCliTarget: () => resolveCliTarget,
4070
+ resolveGitHookPath: () => resolveGitHookPath,
4071
+ resolveMatrixEdges: () => resolveMatrixEdges,
4072
+ scanArtifacts: () => scanArtifacts,
4073
+ traceVersion: () => traceVersion,
4074
+ updateVersionLock: () => updateVersionLock,
4075
+ validateContractAgainstSchema: () => validateContractAgainstSchema,
4076
+ validateExecutableTraceability: () => validateExecutableTraceability,
4077
+ validateGraph: () => validateGraph,
4078
+ validateNamespaceAuthority: () => validateNamespaceAuthority,
4079
+ validatePacket: () => validatePacket,
4080
+ validatePacketMarkdown: () => validatePacketMarkdown,
4081
+ validatePacketPrompt: () => validatePacketPrompt,
4082
+ validatePolicyCompatibility: () => validatePolicyCompatibility,
4083
+ validateReviewResult: () => validateReviewResult,
4084
+ validateScenarioPrdLinkIndex: () => validateScenarioPrdLinkIndex,
4085
+ validateScenarioPrdLinks: () => validateScenarioPrdLinks,
4086
+ verifyDigest: () => verifyDigest,
4087
+ writeGraphCache: () => writeGraphCache
4088
+ });
4089
+ module.exports = __toCommonJS(index_exports);
3204
4090
  function isTargetArtifactType(type) {
3205
4091
  return isPacketTargetType(type);
3206
4092
  }
@@ -3241,56 +4127,11 @@ function resolveArtifactTypeName(schema, token) {
3241
4127
  }
3242
4128
  return void 0;
3243
4129
  }
3244
- var DEFAULT_SCHEMA = {
3245
- types: {
3246
- decision: { paths: ["artifacts/decisions/**/*.md"], displayName: "\u51B3\u7B56\u6587\u6863", role: "decision", layer: "decision", aliases: ["decisions", "adr"] },
3247
- entity: { paths: ["artifacts/entities/entity-registry.md"], displayName: "\u5B9E\u4F53\u6CE8\u518C\u8868", role: "context", layer: "domain", aliases: ["entity-registry"] },
3248
- feature: { paths: ["artifacts/prd/features/**/*.md"], displayName: "\u529F\u80FD\u7279\u6027", role: "feature", layer: "prd", aliases: ["prd-feature", "prd_features"] },
3249
- scenario: { paths: ["artifacts/scenarios/**/*.md"], displayName: "\u573A\u666F\u5267\u672C", role: "scenario", layer: "scenario", aliases: ["scenarios", "scenario-script"] },
3250
- design: { paths: ["artifacts/design/**/*.md"], displayName: "\u8BBE\u8BA1\u89C4\u683C", role: "design", layer: "design", aliases: ["design-spec", "design_docs"] },
3251
- test: { paths: ["heimdall/packages/**/*.test.ts"], displayName: "\u4EE3\u7801\u6CE8\u91CA\u8FFD\u6EAF", role: "context", layer: "implementation", aliases: ["code-test", "code-trace", "unit-test"] },
3252
- e2e_test: { paths: ["artifacts/tests/e2e/*.md"], displayName: "E2E \u6D4B\u8BD5\u89C4\u683C", role: "e2e_test", layer: "verification", aliases: ["e2e-test", "e2e_tests", "tc"] },
3253
- e2e_registry: { paths: ["artifacts/tests/e2e/e2e-test-registry.json"], displayName: "E2E \u6D4B\u8BD5\u6CE8\u518C\u8868", role: "context", layer: "verification", aliases: ["e2e-registry"] },
3254
- "rule-golden-cases": { paths: ["artifacts/tests/rule-golden-cases.md"], displayName: "\u89C4\u5219\u9EC4\u91D1\u6D4B\u8BD5\u7528\u4F8B", role: "context", layer: "verification", aliases: ["rule_golden_cases"] },
3255
- "test-strategy": { paths: ["artifacts/design/test-strategy.md"], displayName: "\u6D4B\u8BD5\u7B56\u7565", role: "context", layer: "verification", aliases: ["test_strategy"] },
3256
- "traceability-matrix-v2": { paths: ["artifacts/traceability-matrix-v2.md"], displayName: "\u8FFD\u6EAF\u77E9\u9635 v2", role: "context", layer: "traceability", aliases: ["traceability_matrix_v2"] }
3257
- },
3258
- idPatterns: {
3259
- decision: "^D-[A-Z]+-\\d+$",
3260
- entity: "^E-\\d{3,}$",
3261
- feature: "^[A-Z]{1,4}\\d+$",
3262
- scenario: "^S-\\d+[a-z]?$",
3263
- design: "^[A-Za-z0-9._-]+$",
3264
- test: "^.+\\.test\\.ts$",
3265
- e2e_test: "^.+:(TC-\\d+[a-z]?|FILE)$",
3266
- e2e_registry: "^e2e-test-registry$",
3267
- "rule-golden-cases": "^[A-Z]+-\\d{3}:(pass|fail|edge)$",
3268
- "test-strategy": "^(unit|integration|e2e|desktop_chain|rule|contract)$",
3269
- "traceability-matrix-v2": "^.+$"
3270
- },
3271
- relationFields: {
3272
- feature: ["scenarios", "decisions", "depends_on", "design_docs"],
3273
- scenario: ["\u5173\u8054\u529F\u80FD", "\u5173\u8054\u51B3\u7B56"],
3274
- design: ["related_features", "related_scenarios"],
3275
- test: ["@scenario", "@feature", "@entity", "@decision"],
3276
- e2e_test: ["test_batch", "scope", "ac_coverage", "related_scenarios", "related_decisions", "related_entities", "\u8986\u76D6\u573A\u666F", "\u8986\u76D6\u529F\u80FD"],
3277
- e2e_registry: ["batches"]
3278
- },
3279
- allowedEdges: [],
3280
- forbiddenEdges: [{ from: "scenario", to: "entity", kind: "references" }],
3281
- statuses: ["planned", "active", "done", "deprecated"],
3282
- idRanges: {},
3283
- e2e: {
3284
- report_uncovered_scenarios: true,
3285
- report_uncovered_features: true,
3286
- runners: []
3287
- }
3288
- };
3289
4130
  async function loadConfig(root) {
3290
- const configPath = (0, import_node_path6.join)(root, "artifact-graph.config.yaml");
4131
+ const configPath = (0, import_node_path7.join)(root, "artifact-graph.config.yaml");
3291
4132
  let parsed = {};
3292
4133
  try {
3293
- const raw = await (0, import_promises5.readFile)(configPath, "utf-8");
4134
+ const raw = await (0, import_promises6.readFile)(configPath, "utf-8");
3294
4135
  parsed = import_js_yaml.default.load(raw) ?? {};
3295
4136
  } catch (error) {
3296
4137
  if (error.code !== "ENOENT") {
@@ -3380,7 +4221,7 @@ function validateE2eConfig(e2e) {
3380
4221
  if (typeof runner.root !== "string" || !runner.root.trim()) {
3381
4222
  throw new Error(`Invalid e2e.runners[${runner.name}].root: must be a non-empty string.`);
3382
4223
  }
3383
- if ((0, import_node_path6.isAbsolute)(runner.root)) {
4224
+ if ((0, import_node_path7.isAbsolute)(runner.root)) {
3384
4225
  throw new Error(`Invalid e2e.runners[${runner.name}].root: "${runner.root}" must not be an absolute path.`);
3385
4226
  }
3386
4227
  if (runner.root.replace(/\\/g, "/").split("/").includes("..")) {
@@ -3464,14 +4305,14 @@ async function scanArtifacts(root, schema) {
3464
4305
  continue;
3465
4306
  }
3466
4307
  scannedFiles.set(file, type);
3467
- const raw = await (0, import_promises5.readFile)((0, import_node_path6.join)(root, file), "utf-8");
4308
+ const raw = await (0, import_promises6.readFile)((0, import_node_path7.join)(root, file), "utf-8");
3468
4309
  const parsed = parseFile(type, file, raw, config);
3469
4310
  nodes.push(...parsed.nodes);
3470
4311
  edges.push(...parsed.edges);
3471
4312
  scanDiagnostics.push(...parsed.diagnostics);
3472
4313
  }
3473
4314
  }
3474
- const absoluteRoot = (0, import_node_path6.isAbsolute)(root) ? root : (0, import_node_path6.resolve)(root);
4315
+ const absoluteRoot = (0, import_node_path7.isAbsolute)(root) ? root : (0, import_node_path7.resolve)(root);
3475
4316
  const graph = buildGraph(nodes, edges, scanDiagnostics, absoluteRoot);
3476
4317
  return resolveMatrixEdges(graph);
3477
4318
  }
@@ -3776,7 +4617,7 @@ async function validateScenarioPrdLinkIndex(root, graph) {
3776
4617
  const indexPath = "artifacts/prd/feature-index.md";
3777
4618
  let raw = "";
3778
4619
  try {
3779
- raw = await (0, import_promises5.readFile)((0, import_node_path6.join)(root, indexPath), "utf-8");
4620
+ raw = await (0, import_promises6.readFile)((0, import_node_path7.join)(root, indexPath), "utf-8");
3780
4621
  } catch (error) {
3781
4622
  if (error.code === "ENOENT") {
3782
4623
  return [];
@@ -3966,11 +4807,11 @@ function nextId(graph, schema, type, rangeName) {
3966
4807
  throw new Error(`ID range ${type}.${rangeName} is exhausted`);
3967
4808
  }
3968
4809
  async function writeGraphCache(root, graph) {
3969
- const cacheDir = (0, import_node_path6.join)(root, ".artifact-graph");
3970
- await (0, import_promises5.mkdir)(cacheDir, { recursive: true });
3971
- await (0, import_promises5.writeFile)((0, import_node_path6.join)(cacheDir, "index.json"), `${JSON.stringify(graph, null, 2)}
4810
+ const cacheDir = (0, import_node_path7.join)(root, ".artifact-graph");
4811
+ await (0, import_promises6.mkdir)(cacheDir, { recursive: true });
4812
+ await (0, import_promises6.writeFile)((0, import_node_path7.join)(cacheDir, "index.json"), `${JSON.stringify(graph, null, 2)}
3972
4813
  `);
3973
- const db = new import_better_sqlite3.default((0, import_node_path6.join)(cacheDir, "graph.sqlite"));
4814
+ const db = new import_better_sqlite3.default((0, import_node_path7.join)(cacheDir, "graph.sqlite"));
3974
4815
  try {
3975
4816
  db.exec(`
3976
4817
  DROP TABLE IF EXISTS nodes;
@@ -4081,7 +4922,7 @@ function parseFile(type, path, raw, schema = DEFAULT_SCHEMA) {
4081
4922
  }
4082
4923
  function parseGenericMarkdown(type, path, raw, schema) {
4083
4924
  const diagnostics = [];
4084
- const ext = (0, import_node_path6.extname)(path).toLowerCase();
4925
+ const ext = (0, import_node_path7.extname)(path).toLowerCase();
4085
4926
  if (ext !== ".md" && ext !== ".markdown") {
4086
4927
  diagnostics.push(issue(
4087
4928
  "UNSUPPORTED_FORMAT",
@@ -4308,7 +5149,7 @@ function parseDecisions(path, raw) {
4308
5149
  }
4309
5150
  function isTestFile(filePath) {
4310
5151
  const normalized = filePath.replace(/\\/g, "/");
4311
- const name = (0, import_node_path6.basename)(normalized);
5152
+ const name = (0, import_node_path7.basename)(normalized);
4312
5153
  if (/\.(test|spec)\.[^.]+$/.test(name)) return true;
4313
5154
  if (/(^|\/)(tests|test|__tests__)\//.test(normalized)) return true;
4314
5155
  if (/\w+Tests?\.java$/.test(name)) return true;
@@ -4599,7 +5440,7 @@ function parseE2eTest(path, raw) {
4599
5440
  });
4600
5441
  const nodes = [];
4601
5442
  const edges = [];
4602
- const batch = String(data.test_batch ?? (0, import_node_path6.basename)(path, (0, import_node_path6.extname)(path))).trim();
5443
+ const batch = String(data.test_batch ?? (0, import_node_path7.basename)(path, (0, import_node_path7.extname)(path))).trim();
4603
5444
  const frontmatterScenarios = toArray(data.related_scenarios).map((value) => String(value).trim()).filter(Boolean);
4604
5445
  const scopeFeatures = extractCodes(String(data.scope ?? ""), "feature");
4605
5446
  const frontmatterFeatures = [.../* @__PURE__ */ new Set([...Object.keys(asRecord(data.ac_coverage)), ...scopeFeatures])];
@@ -4672,7 +5513,7 @@ function parseE2eRegistry(path, raw) {
4672
5513
  data = { parseError: error.message };
4673
5514
  }
4674
5515
  return {
4675
- nodes: [{ type: "e2e_registry", code: (0, import_node_path6.basename)(path, (0, import_node_path6.extname)(path)), title: "E2E Test Registry", path, line: 1, attrs: data }],
5516
+ nodes: [{ type: "e2e_registry", code: (0, import_node_path7.basename)(path, (0, import_node_path7.extname)(path)), title: "E2E Test Registry", path, line: 1, attrs: data }],
4676
5517
  edges: []
4677
5518
  };
4678
5519
  }
@@ -5653,10 +6494,10 @@ function validateE2eRegistry(graph) {
5653
6494
  async function validateExecutableTraceability(root, config) {
5654
6495
  const issues = [];
5655
6496
  const schema = config ?? await loadConfig(root);
5656
- const e2eDir = (0, import_node_path6.join)(root, "artifacts", "tests", "e2e");
6497
+ const e2eDir = (0, import_node_path7.join)(root, "artifacts", "tests", "e2e");
5657
6498
  let e2eFiles;
5658
6499
  try {
5659
- e2eFiles = (await (0, import_promises5.readdir)(e2eDir)).filter((name) => /^test-.*\.md$/.test(name)).map((name) => (0, import_node_path6.join)(e2eDir, name));
6500
+ e2eFiles = (await (0, import_promises6.readdir)(e2eDir)).filter((name) => /^test-.*\.md$/.test(name)).map((name) => (0, import_node_path7.join)(e2eDir, name));
5660
6501
  } catch {
5661
6502
  return [];
5662
6503
  }
@@ -5665,11 +6506,11 @@ async function validateExecutableTraceability(root, config) {
5665
6506
  const tcKeyToFields = /* @__PURE__ */ new Map();
5666
6507
  const mdBatches = /* @__PURE__ */ new Set();
5667
6508
  for (const filePath of e2eFiles) {
5668
- const raw = await (0, import_promises5.readFile)(filePath, "utf-8");
5669
- const relPath = (0, import_node_path6.relative)(root, filePath).split("\\").join("/");
6509
+ const raw = await (0, import_promises6.readFile)(filePath, "utf-8");
6510
+ const relPath = (0, import_node_path7.relative)(root, filePath).split("\\").join("/");
5670
6511
  const parsed = (0, import_gray_matter.default)(raw);
5671
6512
  const data = parsed.data;
5672
- const batch = String(data.test_batch ?? (0, import_node_path6.basename)(filePath, (0, import_node_path6.extname)(filePath))).trim();
6513
+ const batch = String(data.test_batch ?? (0, import_node_path7.basename)(filePath, (0, import_node_path7.extname)(filePath))).trim();
5673
6514
  const lines = raw.split(/\r?\n/);
5674
6515
  const tcStarts = [];
5675
6516
  lines.forEach((line, index) => {
@@ -5714,10 +6555,10 @@ async function validateExecutableTraceability(root, config) {
5714
6555
  const tcAnnotationRegex = /\/\/!?\s*@(?:e2e_test|tc)\s+(\S+?)\s+\[(\w+)\]/;
5715
6556
  const tcAnnotationNoLevelRegex = /\/\/!?\s*@(?:e2e_test|tc)\s+(\S+)/;
5716
6557
  for (const specFile of specFiles) {
5717
- const fullSpecPath = (0, import_node_path6.join)(root, specFile);
6558
+ const fullSpecPath = (0, import_node_path7.join)(root, specFile);
5718
6559
  let content;
5719
6560
  try {
5720
- content = await (0, import_promises5.readFile)(fullSpecPath, "utf-8");
6561
+ content = await (0, import_promises6.readFile)(fullSpecPath, "utf-8");
5721
6562
  } catch {
5722
6563
  continue;
5723
6564
  }
@@ -5794,7 +6635,7 @@ async function validateExecutableTraceability(root, config) {
5794
6635
  if (entry.testId) {
5795
6636
  let content;
5796
6637
  try {
5797
- content = await (0, import_promises5.readFile)((0, import_node_path6.join)(root, normalizedRefFile), "utf-8");
6638
+ content = await (0, import_promises6.readFile)((0, import_node_path7.join)(root, normalizedRefFile), "utf-8");
5798
6639
  } catch {
5799
6640
  continue;
5800
6641
  }
@@ -5971,16 +6812,16 @@ async function computeE2eCoverageStats(graph, root, thresholds = {}) {
5971
6812
  let withExecutableRef = 0;
5972
6813
  const statusBreakdown = {};
5973
6814
  const chainTypeBreakdown = {};
5974
- const e2eDir = (0, import_node_path6.join)(root, "artifacts", "tests", "e2e");
6815
+ const e2eDir = (0, import_node_path7.join)(root, "artifacts", "tests", "e2e");
5975
6816
  const tcFieldsMap = /* @__PURE__ */ new Map();
5976
6817
  let e2eFiles;
5977
6818
  try {
5978
- e2eFiles = (await (0, import_promises5.readdir)(e2eDir)).filter((name) => /^test-.*\.md$/.test(name)).map((name) => (0, import_node_path6.join)(e2eDir, name));
6819
+ e2eFiles = (await (0, import_promises6.readdir)(e2eDir)).filter((name) => /^test-.*\.md$/.test(name)).map((name) => (0, import_node_path7.join)(e2eDir, name));
5979
6820
  } catch {
5980
6821
  e2eFiles = [];
5981
6822
  }
5982
6823
  for (const filePath of e2eFiles) {
5983
- const raw = await (0, import_promises5.readFile)(filePath, "utf-8");
6824
+ const raw = await (0, import_promises6.readFile)(filePath, "utf-8");
5984
6825
  const lines = raw.split(/\r?\n/);
5985
6826
  const tcStarts = [];
5986
6827
  lines.forEach((line, index) => {
@@ -5990,7 +6831,7 @@ async function computeE2eCoverageStats(graph, root, thresholds = {}) {
5990
6831
  }
5991
6832
  });
5992
6833
  const parsed = (0, import_gray_matter.default)(raw);
5993
- const batch = String(parsed.data.test_batch ?? (0, import_node_path6.basename)(filePath, (0, import_node_path6.extname)(filePath))).trim();
6834
+ const batch = String(parsed.data.test_batch ?? (0, import_node_path7.basename)(filePath, (0, import_node_path7.extname)(filePath))).trim();
5994
6835
  for (let i = 0; i < tcStarts.length; i++) {
5995
6836
  const start = tcStarts[i];
5996
6837
  const end = tcStarts[i + 1]?.index ?? lines.length;
@@ -6053,7 +6894,7 @@ async function computeE2eCoverageStats(graph, root, thresholds = {}) {
6053
6894
  let hasActiveE2eRef = false;
6054
6895
  for (const entry of parseExecutableRefLines(execRef)) {
6055
6896
  const normalized = resolveExecutableRefFile(entry.file, allProjectFiles);
6056
- if (!normalized || !(0, import_node_fs4.existsSync)((0, import_node_path6.join)(root, normalized))) continue;
6897
+ if (!normalized || !(0, import_node_fs4.existsSync)((0, import_node_path7.join)(root, normalized))) continue;
6057
6898
  const accepting = await getAcceptingRunners(root, normalized, runners);
6058
6899
  if (accepting.some((runner) => runner.kind === "e2e")) {
6059
6900
  hasActiveE2eRef = true;
@@ -6112,7 +6953,7 @@ async function computeE2eCoverageStats(graph, root, thresholds = {}) {
6112
6953
  const acCoverageRateByFeature = {};
6113
6954
  const featureAcMap = /* @__PURE__ */ new Map();
6114
6955
  for (const node of featureNodes) {
6115
- const acs = parseAcceptanceCriteria(await (0, import_promises5.readFile)((0, import_node_path6.join)(root, node.path), "utf-8"));
6956
+ const acs = parseAcceptanceCriteria(await (0, import_promises6.readFile)((0, import_node_path7.join)(root, node.path), "utf-8"));
6116
6957
  featureAcMap.set(node.code, new Set(acs));
6117
6958
  }
6118
6959
  const coveredAcByFeature = /* @__PURE__ */ new Map();
@@ -6154,10 +6995,10 @@ async function computeE2eCoverageStats(graph, root, thresholds = {}) {
6154
6995
  };
6155
6996
  }
6156
6997
  async function generateE2eRegistry(root, opts) {
6157
- const e2eDir = (0, import_node_path6.join)(root, "artifacts", "tests", "e2e");
6998
+ const e2eDir = (0, import_node_path7.join)(root, "artifacts", "tests", "e2e");
6158
6999
  let files;
6159
7000
  try {
6160
- files = (await (0, import_promises5.readdir)(e2eDir)).filter((name) => /^test-.*\.md$/.test(name)).sort();
7001
+ files = (await (0, import_promises6.readdir)(e2eDir)).filter((name) => /^test-.*\.md$/.test(name)).sort();
6161
7002
  } catch {
6162
7003
  return {
6163
7004
  registry_version: "1.0",
@@ -6170,11 +7011,11 @@ async function generateE2eRegistry(root, opts) {
6170
7011
  const batches = [];
6171
7012
  let totalTestCases = 0;
6172
7013
  for (const file of files) {
6173
- const filePath = (0, import_node_path6.join)(e2eDir, file);
6174
- const raw = await (0, import_promises5.readFile)(filePath, "utf-8");
7014
+ const filePath = (0, import_node_path7.join)(e2eDir, file);
7015
+ const raw = await (0, import_promises6.readFile)(filePath, "utf-8");
6175
7016
  const parsed = (0, import_gray_matter.default)(raw);
6176
7017
  const data = parsed.data;
6177
- const batch = String(data.test_batch ?? (0, import_node_path6.basename)(file, (0, import_node_path6.extname)(file))).trim();
7018
+ const batch = String(data.test_batch ?? (0, import_node_path7.basename)(file, (0, import_node_path7.extname)(file))).trim();
6178
7019
  const relPath = `artifacts/tests/e2e/${file}`;
6179
7020
  const scope = String(data.scope ?? "").trim();
6180
7021
  const acCoverage = normalizeAcCoverageForRegistry(data.ac_coverage);
@@ -6263,20 +7104,6 @@ function parseExecutableRefLines(ref) {
6263
7104
  }
6264
7105
  return results;
6265
7106
  }
6266
- var VALID_TC_STATUSES = /* @__PURE__ */ new Set(["created", "automated", "verified", "waived"]);
6267
- var VALID_CHAIN_TYPES = /* @__PURE__ */ new Set([
6268
- "desktop_chain",
6269
- "mock_playwright",
6270
- "core_e2e",
6271
- "cli_e2e",
6272
- "ui_sidecar_bridge",
6273
- "partial_sidecar",
6274
- "partial_rust"
6275
- ]);
6276
- var DEPRECATED_CHAIN_TYPE_ALIASES = {
6277
- core_only: "core_e2e",
6278
- frontend_only: "mock_playwright"
6279
- };
6280
7107
  function isDesktopChainType(chainType) {
6281
7108
  const normalizedChainType = chainType.trim().toLowerCase();
6282
7109
  return normalizedChainType === "desktop_chain" || normalizedChainType === "";
@@ -6312,10 +7139,10 @@ async function validatePartialRustEvidence(tcFields, tcKey, root, allFiles) {
6312
7139
  if (!normalizedPath) {
6313
7140
  return { hasValidPartialRust: false, detail: `partial_rust file not found: ${ref.file}` };
6314
7141
  }
6315
- const fullPath = (0, import_node_path6.join)(root, normalizedPath);
7142
+ const fullPath = (0, import_node_path7.join)(root, normalizedPath);
6316
7143
  let content;
6317
7144
  try {
6318
- content = await (0, import_promises5.readFile)(fullPath, "utf-8");
7145
+ content = await (0, import_promises6.readFile)(fullPath, "utf-8");
6319
7146
  } catch {
6320
7147
  return { hasValidPartialRust: false, detail: `partial_rust file not found: ${ref.file}` };
6321
7148
  }
@@ -6349,7 +7176,7 @@ function detectTestLevel(specFile, content) {
6349
7176
  }
6350
7177
  function resolveExecutableRefFile(refFile, allFiles) {
6351
7178
  const normalized = refFile.replace(/\\/g, "/").replace(/^\.\//, "");
6352
- if (!normalized || (0, import_node_path6.isAbsolute)(refFile) || normalized.split("/").includes("..")) {
7179
+ if (!normalized || (0, import_node_path7.isAbsolute)(refFile) || normalized.split("/").includes("..")) {
6353
7180
  return void 0;
6354
7181
  }
6355
7182
  if (allFiles.includes(normalized)) {
@@ -6424,9 +7251,9 @@ function escapeRegExp(value) {
6424
7251
  }
6425
7252
  async function hasMarkdownTc(tcKey, e2eDir) {
6426
7253
  const [batch, tcId] = tcKey.split(":");
6427
- const filePath = (0, import_node_path6.join)(e2eDir, `${batch}.md`);
7254
+ const filePath = (0, import_node_path7.join)(e2eDir, `${batch}.md`);
6428
7255
  try {
6429
- const raw = await (0, import_promises5.readFile)(filePath, "utf-8");
7256
+ const raw = await (0, import_promises6.readFile)(filePath, "utf-8");
6430
7257
  const tcRegex = new RegExp(`^#{2,3}\\s+${escapeRegExp(tcId)}\\s*[:\uFF1A]?`, "m");
6431
7258
  return tcRegex.test(raw);
6432
7259
  } catch {
@@ -6446,17 +7273,17 @@ async function findFiles(root, patterns) {
6446
7273
  return [...matched].sort();
6447
7274
  }
6448
7275
  async function walk(root, current = root) {
6449
- const entries = await (0, import_promises5.readdir)(current, { withFileTypes: true });
7276
+ const entries = await (0, import_promises6.readdir)(current, { withFileTypes: true });
6450
7277
  const files = [];
6451
7278
  for (const entry of entries) {
6452
7279
  if (entry.name === "node_modules" || entry.name === "dist" || entry.name === ".git" || entry.name === ".artifact-graph") {
6453
7280
  continue;
6454
7281
  }
6455
- const fullPath = (0, import_node_path6.join)(current, entry.name);
7282
+ const fullPath = (0, import_node_path7.join)(current, entry.name);
6456
7283
  if (entry.isDirectory()) {
6457
7284
  files.push(...await walk(root, fullPath));
6458
7285
  } else {
6459
- files.push((0, import_node_path6.relative)(root, fullPath).split("\\").join("/"));
7286
+ files.push((0, import_node_path7.relative)(root, fullPath).split("\\").join("/"));
6460
7287
  }
6461
7288
  }
6462
7289
  return files;
@@ -6671,7 +7498,7 @@ function normalizeDesignCode(value) {
6671
7498
  if (!raw) {
6672
7499
  return "";
6673
7500
  }
6674
- return (0, import_node_path6.basename)(raw, (0, import_node_path6.extname)(raw));
7501
+ return (0, import_node_path7.basename)(raw, (0, import_node_path7.extname)(raw));
6675
7502
  }
6676
7503
  function toUid(type, code) {
6677
7504
  return `${type}:${code}`;
@@ -6768,30 +7595,6 @@ function discoverTargets(graph, options) {
6768
7595
  }
6769
7596
  return result;
6770
7597
  }
6771
- var CONTEXT_CATEGORIES = {
6772
- feature: "prd",
6773
- scenario: "scenario",
6774
- decision: "decision",
6775
- design: "design",
6776
- entity: "entity",
6777
- "interface_contracts": "contract",
6778
- "data_contracts": "contract",
6779
- "application_state_machines": "contract",
6780
- "error_model": "contract",
6781
- "report-contracts": "contract",
6782
- "ui-flow-contracts": "contract",
6783
- "non-functional-budgets": "contract",
6784
- "domain-glossary": "domain",
6785
- "bounded-context-map": "domain",
6786
- "domain-invariants": "domain",
6787
- "generation-packet-spec": "domain",
6788
- "rule-golden-cases": "verification",
6789
- "test-strategy": "verification",
6790
- "verification-fixtures": "verification",
6791
- "implementation-blueprint": "blueprint",
6792
- "traceability-matrix-v2": "matrix"
6793
- };
6794
- var TIER_ORDER = ["baseline", "target", "direct", "matrix", "transitive"];
6795
7598
  function resolveArtifactContext(graph, opts) {
6796
7599
  const mode = opts.mode ?? "full";
6797
7600
  const maxPerCategory = opts.maxPerCategory ?? 20;
@@ -6960,7 +7763,7 @@ function resolveArtifactContext(graph, opts) {
6960
7763
  }
6961
7764
  if (root) {
6962
7765
  for (const ap of ALWAYS_PRESENT_ITEMS) {
6963
- const fullPath = (0, import_node_path6.join)(root, ap.path);
7766
+ const fullPath = (0, import_node_path7.join)(root, ap.path);
6964
7767
  let stat;
6965
7768
  try {
6966
7769
  stat = (0, import_node_fs4.statSync)(fullPath);
@@ -7190,14 +7993,133 @@ function formatContextMarkdown(manifest) {
7190
7993
  }
7191
7994
  return lines.join("\n");
7192
7995
  }
7996
+ var import_better_sqlite3, import_gray_matter, import_js_yaml, import_node_fs4, import_promises6, import_node_path7, TARGET_ARTIFACT_TYPES, NON_TARGET_ROLES, DEFAULT_SCHEMA, VALID_TC_STATUSES, VALID_CHAIN_TYPES, DEPRECATED_CHAIN_TYPE_ALIASES, CONTEXT_CATEGORIES, TIER_ORDER;
7997
+ var init_index = __esm({
7998
+ "src/index.ts"() {
7999
+ import_better_sqlite3 = __toESM(require("better-sqlite3"), 1);
8000
+ import_gray_matter = __toESM(require("gray-matter"), 1);
8001
+ import_js_yaml = __toESM(require("js-yaml"), 1);
8002
+ import_node_fs4 = require("fs");
8003
+ import_promises6 = require("fs/promises");
8004
+ import_node_path7 = require("path");
8005
+ init_packet_constants();
8006
+ init_packet_validator();
8007
+ init_glob_matcher();
8008
+ init_packet_constants();
8009
+ init_target_selector();
8010
+ init_packet_assembler();
8011
+ init_packet_audit();
8012
+ init_packet_validator();
8013
+ init_packet_prompt();
8014
+ init_packet_prompt_validator();
8015
+ init_versioned_traceability();
8016
+ init_cli_resolver();
8017
+ init_git_changes();
8018
+ init_git_hook_path();
8019
+ init_hook_installer();
8020
+ init_review_result_validator();
8021
+ init_contract_kernel();
8022
+ TARGET_ARTIFACT_TYPES = VALID_PACKET_TARGET_TYPES;
8023
+ NON_TARGET_ROLES = ["context", "candidate", "not-recommended"];
8024
+ DEFAULT_SCHEMA = {
8025
+ types: {
8026
+ decision: { paths: ["artifacts/decisions/**/*.md"], displayName: "\u51B3\u7B56\u6587\u6863", role: "decision", layer: "decision", aliases: ["decisions", "adr"] },
8027
+ entity: { paths: ["artifacts/entities/entity-registry.md"], displayName: "\u5B9E\u4F53\u6CE8\u518C\u8868", role: "context", layer: "domain", aliases: ["entity-registry"] },
8028
+ feature: { paths: ["artifacts/prd/features/**/*.md"], displayName: "\u529F\u80FD\u7279\u6027", role: "feature", layer: "prd", aliases: ["prd-feature", "prd_features"] },
8029
+ scenario: { paths: ["artifacts/scenarios/**/*.md"], displayName: "\u573A\u666F\u5267\u672C", role: "scenario", layer: "scenario", aliases: ["scenarios", "scenario-script"] },
8030
+ design: { paths: ["artifacts/design/**/*.md"], displayName: "\u8BBE\u8BA1\u89C4\u683C", role: "design", layer: "design", aliases: ["design-spec", "design_docs"] },
8031
+ test: { paths: ["heimdall/packages/**/*.test.ts"], displayName: "\u4EE3\u7801\u6CE8\u91CA\u8FFD\u6EAF", role: "context", layer: "implementation", aliases: ["code-test", "code-trace", "unit-test"] },
8032
+ e2e_test: { paths: ["artifacts/tests/e2e/*.md"], displayName: "E2E \u6D4B\u8BD5\u89C4\u683C", role: "e2e_test", layer: "verification", aliases: ["e2e-test", "e2e_tests", "tc"] },
8033
+ e2e_registry: { paths: ["artifacts/tests/e2e/e2e-test-registry.json"], displayName: "E2E \u6D4B\u8BD5\u6CE8\u518C\u8868", role: "context", layer: "verification", aliases: ["e2e-registry"] },
8034
+ "rule-golden-cases": { paths: ["artifacts/tests/rule-golden-cases.md"], displayName: "\u89C4\u5219\u9EC4\u91D1\u6D4B\u8BD5\u7528\u4F8B", role: "context", layer: "verification", aliases: ["rule_golden_cases"] },
8035
+ "test-strategy": { paths: ["artifacts/design/test-strategy.md"], displayName: "\u6D4B\u8BD5\u7B56\u7565", role: "context", layer: "verification", aliases: ["test_strategy"] },
8036
+ "traceability-matrix-v2": { paths: ["artifacts/traceability-matrix-v2.md"], displayName: "\u8FFD\u6EAF\u77E9\u9635 v2", role: "context", layer: "traceability", aliases: ["traceability_matrix_v2"] }
8037
+ },
8038
+ idPatterns: {
8039
+ decision: "^D-[A-Z]+-\\d+$",
8040
+ entity: "^E-\\d{3,}$",
8041
+ feature: "^[A-Z]{1,4}\\d+$",
8042
+ scenario: "^S-\\d+[a-z]?$",
8043
+ design: "^[A-Za-z0-9._-]+$",
8044
+ test: "^.+\\.test\\.ts$",
8045
+ e2e_test: "^.+:(TC-\\d+[a-z]?|FILE)$",
8046
+ e2e_registry: "^e2e-test-registry$",
8047
+ "rule-golden-cases": "^[A-Z]+-\\d{3}:(pass|fail|edge)$",
8048
+ "test-strategy": "^(unit|integration|e2e|desktop_chain|rule|contract)$",
8049
+ "traceability-matrix-v2": "^.+$"
8050
+ },
8051
+ relationFields: {
8052
+ feature: ["scenarios", "decisions", "depends_on", "design_docs"],
8053
+ scenario: ["\u5173\u8054\u529F\u80FD", "\u5173\u8054\u51B3\u7B56"],
8054
+ design: ["related_features", "related_scenarios"],
8055
+ test: ["@scenario", "@feature", "@entity", "@decision"],
8056
+ e2e_test: ["test_batch", "scope", "ac_coverage", "related_scenarios", "related_decisions", "related_entities", "\u8986\u76D6\u573A\u666F", "\u8986\u76D6\u529F\u80FD"],
8057
+ e2e_registry: ["batches"]
8058
+ },
8059
+ allowedEdges: [],
8060
+ forbiddenEdges: [{ from: "scenario", to: "entity", kind: "references" }],
8061
+ statuses: ["planned", "active", "done", "deprecated"],
8062
+ idRanges: {},
8063
+ e2e: {
8064
+ report_uncovered_scenarios: true,
8065
+ report_uncovered_features: true,
8066
+ runners: []
8067
+ }
8068
+ };
8069
+ VALID_TC_STATUSES = /* @__PURE__ */ new Set(["created", "automated", "verified", "waived"]);
8070
+ VALID_CHAIN_TYPES = /* @__PURE__ */ new Set([
8071
+ "desktop_chain",
8072
+ "mock_playwright",
8073
+ "core_e2e",
8074
+ "cli_e2e",
8075
+ "ui_sidecar_bridge",
8076
+ "partial_sidecar",
8077
+ "partial_rust"
8078
+ ]);
8079
+ DEPRECATED_CHAIN_TYPE_ALIASES = {
8080
+ core_only: "core_e2e",
8081
+ frontend_only: "mock_playwright"
8082
+ };
8083
+ CONTEXT_CATEGORIES = {
8084
+ feature: "prd",
8085
+ scenario: "scenario",
8086
+ decision: "decision",
8087
+ design: "design",
8088
+ entity: "entity",
8089
+ "interface_contracts": "contract",
8090
+ "data_contracts": "contract",
8091
+ "application_state_machines": "contract",
8092
+ "error_model": "contract",
8093
+ "report-contracts": "contract",
8094
+ "ui-flow-contracts": "contract",
8095
+ "non-functional-budgets": "contract",
8096
+ "domain-glossary": "domain",
8097
+ "bounded-context-map": "domain",
8098
+ "domain-invariants": "domain",
8099
+ "generation-packet-spec": "domain",
8100
+ "rule-golden-cases": "verification",
8101
+ "test-strategy": "verification",
8102
+ "verification-fixtures": "verification",
8103
+ "implementation-blueprint": "blueprint",
8104
+ "traceability-matrix-v2": "matrix"
8105
+ };
8106
+ TIER_ORDER = ["baseline", "target", "direct", "matrix", "transitive"];
8107
+ }
8108
+ });
8109
+ init_index();
7193
8110
  // Annotate the CommonJS export names for ESM import in node:
7194
8111
  0 && (module.exports = {
7195
8112
  ALWAYS_PRESENT,
7196
8113
  BASELINE_CONSTRAINTS,
7197
8114
  BASELINE_CONSTRAINTS_COUNT,
7198
8115
  BASELINE_ITEMS_COUNT,
8116
+ CONTRACT_ERROR_CODES,
8117
+ ContractCatalog,
8118
+ ContractError,
8119
+ ContractRegistry,
7199
8120
  DEFAULT_MAX_CHARS,
7200
8121
  DEFAULT_SCHEMA,
8122
+ E2E_NORMALIZER_CONFIG,
7201
8123
  MIN_PROMPT_CHARS,
7202
8124
  TARGET_ARTIFACT_TYPES,
7203
8125
  VALID_PACKET_TARGET_TYPES,
@@ -7213,6 +8135,7 @@ function formatContextMarkdown(manifest) {
7213
8135
  buildVersionIndex,
7214
8136
  collectChangedPaths,
7215
8137
  computeE2eCoverageStats,
8138
+ computeRevisionDigest,
7216
8139
  dirname,
7217
8140
  discoverAndAuditPackets,
7218
8141
  discoverTargets,
@@ -7223,11 +8146,17 @@ function formatContextMarkdown(manifest) {
7223
8146
  getArtifactTypeMetadata,
7224
8147
  getTargetArtifactTypes,
7225
8148
  installManagedHookBlock,
8149
+ isOfficialNamespace,
7226
8150
  isPacketTargetType,
7227
8151
  isPacketTargetTypeDynamic,
7228
8152
  isTargetArtifactType,
7229
8153
  loadConfig,
8154
+ loadContract,
8155
+ loadContractCatalog,
8156
+ loadContractsFromDirectory,
7230
8157
  nextId,
8158
+ normalizeE2eLegacyArtifact,
8159
+ normalizeToCanonical,
7231
8160
  parseTargetSelector,
7232
8161
  parseTargetsFile,
7233
8162
  prepareManagedHookBlock,
@@ -7249,13 +8178,17 @@ function formatContextMarkdown(manifest) {
7249
8178
  scanArtifacts,
7250
8179
  traceVersion,
7251
8180
  updateVersionLock,
8181
+ validateContractAgainstSchema,
7252
8182
  validateExecutableTraceability,
7253
8183
  validateGraph,
8184
+ validateNamespaceAuthority,
7254
8185
  validatePacket,
7255
8186
  validatePacketMarkdown,
7256
8187
  validatePacketPrompt,
8188
+ validatePolicyCompatibility,
7257
8189
  validateReviewResult,
7258
8190
  validateScenarioPrdLinkIndex,
7259
8191
  validateScenarioPrdLinks,
8192
+ verifyDigest,
7260
8193
  writeGraphCache
7261
8194
  });