@osovv/vv-opencode 1.4.5 → 1.6.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.
Files changed (143) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +47 -16
  3. package/dist/commands/patch-provider.d.ts +5 -5
  4. package/dist/commands/patch-provider.js +10 -6
  5. package/dist/commands/patch-provider.js.map +1 -1
  6. package/dist/lib/agent-tool-catalog.d.ts +144 -0
  7. package/dist/lib/agent-tool-catalog.js +2551 -0
  8. package/dist/lib/agent-tool-catalog.js.map +1 -0
  9. package/dist/lib/agent-tool-contract.d.ts +200 -0
  10. package/dist/lib/agent-tool-contract.js +407 -0
  11. package/dist/lib/agent-tool-contract.js.map +1 -0
  12. package/dist/lib/opencode/agent-registrations.d.ts +33 -0
  13. package/dist/lib/opencode/agent-registrations.js +469 -0
  14. package/dist/lib/opencode/agent-registrations.js.map +1 -0
  15. package/dist/lib/opencode/inspection.d.ts +84 -0
  16. package/dist/lib/opencode/inspection.js +367 -0
  17. package/dist/lib/opencode/inspection.js.map +1 -0
  18. package/dist/lib/opencode/model-overrides.d.ts +19 -0
  19. package/dist/lib/opencode/model-overrides.js +221 -0
  20. package/dist/lib/opencode/model-overrides.js.map +1 -0
  21. package/dist/lib/opencode/paths.d.ts +21 -0
  22. package/dist/lib/opencode/paths.js +62 -0
  23. package/dist/lib/opencode/paths.js.map +1 -0
  24. package/dist/lib/opencode/plugin-registration.d.ts +17 -0
  25. package/dist/lib/opencode/plugin-registration.js +210 -0
  26. package/dist/lib/opencode/plugin-registration.js.map +1 -0
  27. package/dist/lib/opencode/shared-utils.d.ts +30 -0
  28. package/dist/lib/opencode/shared-utils.js +183 -0
  29. package/dist/lib/opencode/shared-utils.js.map +1 -0
  30. package/dist/lib/opencode/vvoc-config-io.d.ts +9 -0
  31. package/dist/lib/opencode/vvoc-config-io.js +58 -0
  32. package/dist/lib/opencode/vvoc-config-io.js.map +1 -0
  33. package/dist/lib/opencode.d.ts +15 -174
  34. package/dist/lib/opencode.js +19 -1387
  35. package/dist/lib/opencode.js.map +1 -1
  36. package/dist/lib/spec-lint/cross-file-rules.d.ts +2 -0
  37. package/dist/lib/spec-lint/cross-file-rules.js +33 -0
  38. package/dist/lib/spec-lint/cross-file-rules.js.map +1 -0
  39. package/dist/lib/spec-lint/delegated-extraction.d.ts +8 -0
  40. package/dist/lib/spec-lint/delegated-extraction.js +112 -0
  41. package/dist/lib/spec-lint/delegated-extraction.js.map +1 -0
  42. package/dist/lib/spec-lint/lint.d.ts +7 -0
  43. package/dist/lib/spec-lint/lint.js +92 -0
  44. package/dist/lib/spec-lint/lint.js.map +1 -0
  45. package/dist/lib/spec-lint/parser.d.ts +101 -0
  46. package/dist/lib/spec-lint/parser.js +482 -0
  47. package/dist/lib/spec-lint/parser.js.map +1 -0
  48. package/dist/lib/spec-lint/plan-rules.d.ts +38 -0
  49. package/dist/lib/spec-lint/plan-rules.js +745 -0
  50. package/dist/lib/spec-lint/plan-rules.js.map +1 -0
  51. package/dist/lib/spec-lint/spec-rules.d.ts +8 -0
  52. package/dist/lib/spec-lint/spec-rules.js +188 -0
  53. package/dist/lib/spec-lint/spec-rules.js.map +1 -0
  54. package/dist/lib/spec-lint.d.ts +4 -63
  55. package/dist/lib/spec-lint.js +13 -1505
  56. package/dist/lib/spec-lint.js.map +1 -1
  57. package/dist/lib/vvoc-preset-registry.d.ts +7 -7
  58. package/dist/lib/vvoc-preset-registry.js +8 -8
  59. package/dist/lib/vvoc-preset-registry.js.map +1 -1
  60. package/dist/lib/workflow-contract.d.ts +12 -0
  61. package/dist/lib/workflow-contract.js +71 -18
  62. package/dist/lib/workflow-contract.js.map +1 -1
  63. package/dist/plugins/hashline-edit/index.js +102 -97
  64. package/dist/plugins/hashline-edit/index.js.map +1 -1
  65. package/dist/plugins/hashline-edit/normalize-edits.d.ts +2 -8
  66. package/dist/plugins/hashline-edit/normalize-edits.js +32 -17
  67. package/dist/plugins/hashline-edit/normalize-edits.js.map +1 -1
  68. package/dist/plugins/hashline-edit/schemas.d.ts +246 -0
  69. package/dist/plugins/hashline-edit/schemas.js +659 -0
  70. package/dist/plugins/hashline-edit/schemas.js.map +1 -0
  71. package/dist/plugins/hashline-edit/str-replace-editor.d.ts +6 -17
  72. package/dist/plugins/hashline-edit/str-replace-editor.js +19 -21
  73. package/dist/plugins/hashline-edit/str-replace-editor.js.map +1 -1
  74. package/dist/plugins/hashline-edit/tool-description.d.ts +1 -0
  75. package/dist/plugins/hashline-edit/tool-description.js +20 -4
  76. package/dist/plugins/hashline-edit/tool-description.js.map +1 -1
  77. package/dist/plugins/web-tools/fetch-service.d.ts +8 -5
  78. package/dist/plugins/web-tools/fetch-service.js +30 -45
  79. package/dist/plugins/web-tools/fetch-service.js.map +1 -1
  80. package/dist/plugins/web-tools/index.js +23 -5
  81. package/dist/plugins/web-tools/index.js.map +1 -1
  82. package/dist/plugins/web-tools/schemas.d.ts +469 -0
  83. package/dist/plugins/web-tools/schemas.js +523 -0
  84. package/dist/plugins/web-tools/schemas.js.map +1 -0
  85. package/dist/plugins/web-tools/search-service.d.ts +6 -3
  86. package/dist/plugins/web-tools/search-service.js +24 -29
  87. package/dist/plugins/web-tools/search-service.js.map +1 -1
  88. package/dist/plugins/workflow/authority.d.ts +6 -0
  89. package/dist/plugins/workflow/authority.js +45 -10
  90. package/dist/plugins/workflow/authority.js.map +1 -1
  91. package/dist/plugins/workflow/authorization.d.ts +30 -0
  92. package/dist/plugins/workflow/authorization.js +147 -0
  93. package/dist/plugins/workflow/authorization.js.map +1 -0
  94. package/dist/plugins/workflow/checkpoints.d.ts +41 -2
  95. package/dist/plugins/workflow/checkpoints.js +176 -47
  96. package/dist/plugins/workflow/checkpoints.js.map +1 -1
  97. package/dist/plugins/workflow/delegated.d.ts +15 -1
  98. package/dist/plugins/workflow/delegated.js +65 -35
  99. package/dist/plugins/workflow/delegated.js.map +1 -1
  100. package/dist/plugins/workflow/execution.d.ts +15 -30
  101. package/dist/plugins/workflow/execution.js +133 -33
  102. package/dist/plugins/workflow/execution.js.map +1 -1
  103. package/dist/plugins/workflow/index.js +197 -435
  104. package/dist/plugins/workflow/index.js.map +1 -1
  105. package/dist/plugins/workflow/input-validation.d.ts +48 -0
  106. package/dist/plugins/workflow/input-validation.js +536 -0
  107. package/dist/plugins/workflow/input-validation.js.map +1 -0
  108. package/dist/plugins/workflow/inspection.d.ts +60 -0
  109. package/dist/plugins/workflow/inspection.js +316 -0
  110. package/dist/plugins/workflow/inspection.js.map +1 -0
  111. package/dist/plugins/workflow/protocol.d.ts +2 -0
  112. package/dist/plugins/workflow/protocol.js +26 -4
  113. package/dist/plugins/workflow/protocol.js.map +1 -1
  114. package/dist/plugins/workflow/recovery.d.ts +18 -0
  115. package/dist/plugins/workflow/recovery.js +217 -0
  116. package/dist/plugins/workflow/recovery.js.map +1 -0
  117. package/dist/plugins/workflow/repair.d.ts +1 -1
  118. package/dist/plugins/workflow/repair.js +9 -10
  119. package/dist/plugins/workflow/repair.js.map +1 -1
  120. package/dist/plugins/workflow/results.d.ts +2566 -0
  121. package/dist/plugins/workflow/results.js +1111 -0
  122. package/dist/plugins/workflow/results.js.map +1 -0
  123. package/dist/plugins/workflow/schemas.d.ts +398 -0
  124. package/dist/plugins/workflow/schemas.js +399 -0
  125. package/dist/plugins/workflow/schemas.js.map +1 -0
  126. package/dist/plugins/workflow/state.d.ts +3 -2
  127. package/dist/plugins/workflow/state.js +15 -8
  128. package/dist/plugins/workflow/state.js.map +1 -1
  129. package/dist/plugins/workflow/system-instruction.md +17 -1
  130. package/dist/plugins/workflow/tooling.d.ts +11 -82
  131. package/dist/plugins/workflow/tooling.js +478 -461
  132. package/dist/plugins/workflow/tooling.js.map +1 -1
  133. package/dist/plugins/workflow/transactions.d.ts +13 -0
  134. package/dist/plugins/workflow/transactions.js +13 -3
  135. package/dist/plugins/workflow/transactions.js.map +1 -1
  136. package/package.json +6 -3
  137. package/schemas/vvoc/v3.json +1 -1
  138. package/templates/agents/vv-code-reviewer.md +13 -4
  139. package/templates/agents/vv-implementer.md +16 -9
  140. package/templates/agents/vv-spec-reviewer.md +13 -4
  141. package/templates/skills/vv-execute/SKILL.md +3 -3
  142. package/templates/skills/vv-execute/references/tool-contracts.md +1750 -0
  143. package/templates/skills/vv-review/SKILL.md +1 -1
@@ -0,0 +1,482 @@
1
+ // FILE: src/lib/spec-lint/parser.ts
2
+ // VERSION: 1.0.0
3
+ // START_MODULE_CONTRACT
4
+ // PURPOSE: Strict XML document model, vocabulary, and template contract tables shared by every spec-lint rule zone.
5
+ // SCOPE: htmlparser2 xmlMode event-stream parse with a positioned element tree and well-formedness findings, identity/status/mode vocabularies, child-rule contract tables for spec/plan/design-context templates, tree and completeness helpers, child-contract checking, package layout checks, artifact-kind detection, and archive-path detection. Rule orchestration lives in sibling zone modules.
6
+ // DEPENDS: [htmlparser2]
7
+ // LINKS: [M-SPEC-LINT]
8
+ // ROLE: RUNTIME
9
+ // MAP_MODE: EXPORTS
10
+ // END_MODULE_CONTRACT
11
+ //
12
+ // START_MODULE_MAP
13
+ // LINT_VERSION - Rule-set version constant; cache keys include it so rule changes invalidate cached verdicts.
14
+ // SpecLintArtifactKind - Artifact kinds detected by root element name.
15
+ // SpecLintSeverity - Finding severity levels error and warning.
16
+ // SpecLintFinding - One rule violation with rule id, message, file label, and 1-based line.
17
+ // SpecLintVerdict - Per-artifact lint result with kind, ok flag, and findings.
18
+ // SpecLintArtifactInput - One artifact to lint identified by a file label and raw content.
19
+ // SpecLintOptions - Options for lint runs (skipCrossFile for single-file contexts).
20
+ // XmlNode - Positioned element tree node produced by the strict parser.
21
+ // ParseResult - Root element plus well-formedness findings from parseSpecXml.
22
+ // ChildRule - Allowed fixed child names or identity-pattern rule for one container element.
23
+ // parseSpecXml - Strict xmlMode parse producing a positioned element tree or well-formedness findings.
24
+ // detectSpecArtifactKind - Map a root element name onto an artifact kind.
25
+ // isSpecArchivePath - True when a file label sits inside an archive directory.
26
+ // child/children/textOf/nonEmpty - Positioned-tree readers used by every rule zone.
27
+ // requiresCompleteness - True when the document status demands completeness rules.
28
+ // checkChildren - Report children outside the template contract.
29
+ // checkPackageLayout - Enforce specs-package id and reserved-slug layout rules.
30
+ // IDENTITY_PATTERNS - Element identity regexes for component, task, wave, and checkpoint.
31
+ // TASK_ID_REF - Bare task reference regex T-NNN.
32
+ // DOC_STATUSES - Accepted document statuses.
33
+ // TASK_STATUSES - Accepted task statuses.
34
+ // EXECUTION_MODES - Accepted execution modes.
35
+ // CHECKPOINT_KINDS - Accepted checkpoint kinds.
36
+ // DELEGATED_REVIEWERS - Accepted delegated reviewer roles.
37
+ // SPEC_CONTRACT - Spec template child-rule table.
38
+ // PLAN_CONTRACT - Plan template child-rule table.
39
+ // DESIGN_CONTEXT_CONTRACT - Design-context template child-rule table.
40
+ // COMPONENT_CHILDREN - Fixed children of one spec component element.
41
+ // TASK_CHILDREN - Fixed children of one plan task element.
42
+ // TASK_DEPENDS_CHILDREN - Fixed children of one task depends_on element.
43
+ // ACCEPTANCE_CHILDREN - Fixed children of one acceptance element.
44
+ // VERIFICATION_CHILDREN - Fixed children of one verification element.
45
+ // WAVE_CHILDREN - Fixed children of one wave element.
46
+ // PLAN_FILE_CHILDREN - Fixed children of one plan file element.
47
+ // TASK_WRITE_SCOPE_CHILDREN - Fixed children of one task write_scope element.
48
+ // CHECKPOINT_CHILDREN - Fixed children of one checkpoint element.
49
+ // CHECKPOINT_COVERS_CHILDREN - Fixed children of one checkpoint covers element.
50
+ // CHECKPOINT_SCOPE_CHILDREN - Fixed children of one checkpoint scope element.
51
+ // CHECKPOINT_REVIEWERS_CHILDREN - Fixed children of one checkpoint reviewers element.
52
+ // child - First named child of a node.
53
+ // children - All named children of a node.
54
+ // textOf - Trimmed text of a node.
55
+ // nonEmpty - True when a node has non-empty trimmed text.
56
+ // END_MODULE_MAP
57
+ //
58
+ // START_CHANGE_SUMMARY
59
+ // LAST_CHANGE: [C-SPEC-LINT-RULES-SPLIT-R1 - Extracted the strict parser, vocabularies, contract tables, and shared tree helpers from the former src/lib/spec-lint.ts monolith into this foundation zone module.]
60
+ // END_CHANGE_SUMMARY
61
+ import { Tokenizer } from "htmlparser2";
62
+ // START_BLOCK_PUBLIC_TYPES
63
+ export const LINT_VERSION = 2;
64
+ export const IDENTITY_PATTERNS = {
65
+ component: /^COMPONENT-[A-Z0-9]+(-[A-Z0-9]+)*$/,
66
+ task: /^TASK-T-\d{3,}$/,
67
+ wave: /^WAVE-\d+$/,
68
+ checkpoint: /^CHECKPOINT-R-\d{3,}$/,
69
+ };
70
+ export const TASK_ID_REF = /^T-\d{3,}$/;
71
+ export const DOC_STATUSES = new Set(["draft", "approved", "applied"]);
72
+ export const TASK_STATUSES = new Set(["pending", "in_progress", "done", "skipped"]);
73
+ export const EXECUTION_MODES = new Set(["inline", "classic", "delegated"]);
74
+ export const CHECKPOINT_KINDS = new Set(["milestone", "final"]);
75
+ export const DELEGATED_REVIEWERS = new Set(["spec", "code"]);
76
+ const RESERVED_PACKAGE_SLUGS = new Set(["draft", "archive", "template", "plan", "spec", "vvoc"]);
77
+ const PACKAGE_ID_PATTERN = /^\d{4}-\d{2}-\d{2}-[a-z0-9]([a-z0-9_-]*[a-z0-9_])?$/;
78
+ // END_BLOCK_PARSER_TYPES
79
+ // START_BLOCK_LINE_INDEX
80
+ /** 1-based line number for a character index in source text. */
81
+ function lineAt(content, index) {
82
+ let line = 1;
83
+ const stop = Math.max(0, Math.min(index, content.length));
84
+ for (let i = 0; i < stop; i++) {
85
+ if (content.charCodeAt(i) === 10)
86
+ line++;
87
+ }
88
+ return line;
89
+ }
90
+ /**
91
+ * Strict XML parse over htmlparser2's xmlMode Tokenizer event stream.
92
+ * The low-level tokenizer is used directly (not Parser) because the Parser
93
+ * silently drops unmatched closing tags and implies closes at end-of-input;
94
+ * strict artifacts need both violation classes reported. Builds a positioned
95
+ * element tree and reports well-formedness violations: tokenizer errors,
96
+ * mismatched or unmatched closing tags, unclosed elements, stray top-level
97
+ * content, multiple roots, and content after the root element.
98
+ */
99
+ export function parseSpecXml(content, file) {
100
+ const findings = [];
101
+ const rootCandidates = [];
102
+ const stack = [];
103
+ let rootClosed = false;
104
+ let pendingAttribNames = [];
105
+ let pendingAttribName = null;
106
+ const current = () => stack[stack.length - 1];
107
+ const tokenizer = new Tokenizer({ xmlMode: true, recognizeSelfClosing: true, decodeEntities: false }, {
108
+ onopentagname(start, endIndex) {
109
+ const name = content.slice(start, endIndex);
110
+ const line = lineAt(content, start);
111
+ pendingAttribNames = [];
112
+ pendingAttribName = null;
113
+ if (rootClosed) {
114
+ findings.push({
115
+ severity: "error",
116
+ rule: "xml.content-after-root",
117
+ message: `element <${name}> appears after the root element closed`,
118
+ file,
119
+ line,
120
+ });
121
+ return;
122
+ }
123
+ const node = {
124
+ name,
125
+ line,
126
+ attribs: {},
127
+ children: [],
128
+ text: "",
129
+ cdataCount: 0,
130
+ attribNames: [],
131
+ };
132
+ const parent = current();
133
+ if (parent) {
134
+ parent.children.push(node);
135
+ }
136
+ else {
137
+ rootCandidates.push(node);
138
+ }
139
+ stack.push(node);
140
+ },
141
+ onattribname(start, endIndex) {
142
+ pendingAttribName = content.slice(start, endIndex);
143
+ },
144
+ onattribdata() {
145
+ // attribute values are irrelevant: the format forbids attributes outright
146
+ },
147
+ onattribentity() {
148
+ // no-op: attribute values are not inspected
149
+ },
150
+ onattribend() {
151
+ if (pendingAttribName)
152
+ pendingAttribNames.push(pendingAttribName);
153
+ pendingAttribName = null;
154
+ },
155
+ onopentagend(endIndex) {
156
+ const node = current();
157
+ if (!node)
158
+ return;
159
+ if (pendingAttribNames.length > 0) {
160
+ findings.push({
161
+ severity: "error",
162
+ rule: "attr.forbidden",
163
+ message: `element <${node.name}> uses XML attributes (${pendingAttribNames.join(", ")}); the artifact format allows child elements only`,
164
+ file,
165
+ line: node.line,
166
+ });
167
+ }
168
+ void endIndex;
169
+ },
170
+ onselfclosingtag() {
171
+ const node = current();
172
+ if (!node)
173
+ return;
174
+ if (pendingAttribNames.length > 0) {
175
+ findings.push({
176
+ severity: "error",
177
+ rule: "attr.forbidden",
178
+ message: `element <${node.name}> uses XML attributes (${pendingAttribNames.join(", ")}); the artifact format allows child elements only`,
179
+ file,
180
+ line: node.line,
181
+ });
182
+ }
183
+ pendingAttribNames = [];
184
+ stack.pop();
185
+ if (stack.length === 0)
186
+ rootClosed = true;
187
+ },
188
+ onclosetag(start, endIndex) {
189
+ const name = content.slice(start, endIndex);
190
+ const line = lineAt(content, start);
191
+ const top = current();
192
+ if (!top) {
193
+ findings.push({
194
+ severity: "error",
195
+ rule: rootClosed ? "xml.content-after-root" : "xml.stray-close",
196
+ message: `closing tag </${name}> has no matching open element`,
197
+ file,
198
+ line,
199
+ });
200
+ return;
201
+ }
202
+ if (top.name !== name) {
203
+ const namedIndex = stack.findIndex((n) => n.name === name);
204
+ if (namedIndex === -1) {
205
+ findings.push({
206
+ severity: "error",
207
+ rule: "xml.mismatched-close",
208
+ message: `closing tag </${name}> does not match any open element (innermost open is <${top.name}> from line ${top.line})`,
209
+ file,
210
+ line,
211
+ });
212
+ return;
213
+ }
214
+ for (let i = stack.length - 1; i > namedIndex; i--) {
215
+ findings.push({
216
+ severity: "error",
217
+ rule: "xml.unclosed",
218
+ message: `element <${stack[i].name}> opened on line ${stack[i].line} is closed implicitly by </${name}> and must be closed explicitly`,
219
+ file,
220
+ line: stack[i].line,
221
+ });
222
+ }
223
+ stack.length = namedIndex;
224
+ }
225
+ else {
226
+ stack.pop();
227
+ }
228
+ if (stack.length === 0)
229
+ rootClosed = true;
230
+ },
231
+ ontext(start, endIndex) {
232
+ const raw = content.slice(start, endIndex);
233
+ const parent = current();
234
+ if (parent) {
235
+ parent.text += raw;
236
+ }
237
+ else if (raw.trim()) {
238
+ findings.push({
239
+ severity: "error",
240
+ rule: rootClosed ? "xml.content-after-root" : "xml.stray-text",
241
+ message: `text content outside the root element: ${JSON.stringify(raw.trim().slice(0, 40))}`,
242
+ file,
243
+ line: lineAt(content, start),
244
+ });
245
+ }
246
+ },
247
+ oncdata() {
248
+ const parent = current();
249
+ if (parent)
250
+ parent.cdataCount++;
251
+ },
252
+ oncomment() {
253
+ // comments are legal noise in artifacts and carry no contract meaning
254
+ },
255
+ ondeclaration() {
256
+ // XML declarations and DOCTYPE are tolerated without contract meaning
257
+ },
258
+ onprocessinginstruction() {
259
+ // processing instructions are tolerated without contract meaning
260
+ },
261
+ ontextentity() {
262
+ // unreachable with decodeEntities disabled; raw slices keep entities verbatim
263
+ },
264
+ onend() {
265
+ // required by the tokenizer interface; end-of-input handling happens after tokenizer.end() returns
266
+ },
267
+ });
268
+ tokenizer.write(content);
269
+ tokenizer.end();
270
+ for (const unclosed of stack) {
271
+ findings.push({
272
+ severity: "error",
273
+ rule: "xml.unclosed",
274
+ message: `element <${unclosed.name}> opened on line ${unclosed.line} is never closed`,
275
+ file,
276
+ line: unclosed.line,
277
+ });
278
+ }
279
+ if (rootCandidates.length > 1) {
280
+ findings.push({
281
+ severity: "error",
282
+ rule: "xml.multiple-roots",
283
+ message: `document has ${rootCandidates.length} root elements; exactly one is allowed`,
284
+ file,
285
+ line: rootCandidates[1].line,
286
+ });
287
+ }
288
+ return { root: rootCandidates[0] ?? null, findings };
289
+ }
290
+ export const SPEC_CONTRACT = {
291
+ spec: {
292
+ names: [
293
+ "status",
294
+ "goal",
295
+ "architecture",
296
+ "tech_stack",
297
+ "components",
298
+ "data_flow",
299
+ "error_handling",
300
+ "testing",
301
+ "non_goals",
302
+ ],
303
+ },
304
+ testing: { names: ["strategy", "coverage"] },
305
+ components: { identity: "component" },
306
+ non_goals: { names: ["non_goal"] },
307
+ };
308
+ export const COMPONENT_CHILDREN = ["name", "responsibility", "depends_on"];
309
+ export const PLAN_CONTRACT = {
310
+ plan: {
311
+ names: [
312
+ "spec",
313
+ "design_context",
314
+ "created",
315
+ "status",
316
+ "meta",
317
+ "architecture",
318
+ "tasks",
319
+ "execution",
320
+ ],
321
+ },
322
+ meta: { names: ["summary", "waves", "affected_modules", "complexity"] },
323
+ architecture: { identity: "component" },
324
+ tasks: { identity: "wave" },
325
+ execution: { names: ["mode", "review_checkpoints"] },
326
+ review_checkpoints: { identity: "checkpoint" },
327
+ };
328
+ export const TASK_CHILDREN = [
329
+ "title",
330
+ "file",
331
+ "status",
332
+ "description",
333
+ "depends_on",
334
+ "snippet",
335
+ "acceptance",
336
+ "verification",
337
+ "write_scope",
338
+ ];
339
+ export const TASK_DEPENDS_CHILDREN = ["task_id"];
340
+ export const ACCEPTANCE_CHILDREN = ["criterion"];
341
+ export const VERIFICATION_CHILDREN = ["command"];
342
+ export const WAVE_CHILDREN = ["goal"];
343
+ export const PLAN_FILE_CHILDREN = ["path", "role"];
344
+ export const TASK_WRITE_SCOPE_CHILDREN = ["file"];
345
+ export const CHECKPOINT_CHILDREN = [
346
+ "kind",
347
+ "after_wave",
348
+ "covers",
349
+ "scope",
350
+ "reviewers",
351
+ "acceptance",
352
+ "verification",
353
+ ];
354
+ export const CHECKPOINT_COVERS_CHILDREN = ["task_id"];
355
+ export const CHECKPOINT_SCOPE_CHILDREN = ["file"];
356
+ export const CHECKPOINT_REVIEWERS_CHILDREN = ["reviewer"];
357
+ export const DESIGN_CONTEXT_CONTRACT = {
358
+ "design-context": {
359
+ names: ["decisions", "assumptions", "deferred", "scenarios", "external_constraints"],
360
+ },
361
+ decisions: { names: ["decision"] },
362
+ decision: { names: ["topic", "choice", "rationale", "alternatives_considered"] },
363
+ alternatives_considered: { names: ["alternative"] },
364
+ alternative: { names: ["name", "reason_rejected"] },
365
+ assumptions: { names: ["assumption"] },
366
+ assumption: { names: ["statement", "confidence", "fragile_if"] },
367
+ deferred: { names: ["deferred_decision"] },
368
+ deferred_decision: { names: ["decision", "why_deferred", "revisit_trigger"] },
369
+ scenarios: { names: ["scenario"] },
370
+ scenario: { names: ["name", "context", "implications"] },
371
+ external_constraints: { names: ["constraint"] },
372
+ constraint: { names: ["source", "impact"] },
373
+ };
374
+ // END_BLOCK_CONTRACT_TABLES
375
+ // START_BLOCK_LIFECYNESS_HELPER
376
+ /**
377
+ * Completeness rules apply only to known non-draft statuses. An invalid
378
+ * status is reported once by the vocabulary rule without cascading
379
+ * emptiness noise for a document that may still be mid-composition.
380
+ */
381
+ export function requiresCompleteness(root) {
382
+ const status = textOf(child(root, "status"));
383
+ return status === "approved" || status === "applied";
384
+ }
385
+ // END_BLOCK_LIFECYNESS_HELPER
386
+ // START_BLOCK_TREE_HELPERS
387
+ export function child(node, name) {
388
+ return node.children.find((c) => c.name === name);
389
+ }
390
+ export function children(node, name) {
391
+ return node.children.filter((c) => c.name === name);
392
+ }
393
+ export function textOf(node) {
394
+ return node ? node.text.trim() : "";
395
+ }
396
+ export function nonEmpty(node) {
397
+ return textOf(node) !== "";
398
+ }
399
+ // END_BLOCK_TREE_HELPERS
400
+ // START_BLOCK_CONTRACT_CHECKS
401
+ /** Report children that are neither allowed fixed names nor valid identity elements. */
402
+ export function checkChildren(node, rule, file, findings, extraAllowed = []) {
403
+ const allowed = new Set([...(rule?.names ?? []), ...extraAllowed]);
404
+ for (const c of node.children) {
405
+ if (allowed.has(c.name))
406
+ continue;
407
+ if (rule?.identity && IDENTITY_PATTERNS[rule.identity].test(c.name))
408
+ continue;
409
+ const expected = rule?.identity
410
+ ? `${(rule.names ?? []).join(", ") || "(none)"}, or ${rule.identity} identity elements`
411
+ : (rule?.names ?? []).join(", ") || "(none)";
412
+ findings.push({
413
+ severity: "error",
414
+ rule: "element.unknown",
415
+ message: `element <${c.name}> is not part of the template contract under <${node.name}>; allowed: ${expected}`,
416
+ file,
417
+ line: c.line,
418
+ });
419
+ }
420
+ }
421
+ // END_BLOCK_CONTRACT_CHECKS
422
+ // START_BLOCK_LAYOUT_CHECKS
423
+ /** True when a file label sits under an archive/ directory. */
424
+ export function isSpecArchivePath(file) {
425
+ return /(^|\/)archive\//.test(file.replace(/\\/g, "/"));
426
+ }
427
+ /**
428
+ * Package layout checks applied when the label is a specs-package artifact
429
+ * (.vvoc/specs/<id>/<artifact>.xml or an equivalent specs/ segment). Foreign
430
+ * paths (plain filenames, temp fixtures without a specs segment) are skipped.
431
+ */
432
+ export function checkPackageLayout(file, findings) {
433
+ const segments = file.replace(/\\/g, "/").split("/");
434
+ const fileName = segments[segments.length - 1];
435
+ if (!["spec.xml", "plan.xml", "design-context.xml"].includes(fileName))
436
+ return;
437
+ const specsIndex = segments.lastIndexOf("specs");
438
+ if (specsIndex === -1)
439
+ return;
440
+ const dirSegments = segments.slice(specsIndex + 1, -1).filter((s) => s !== "archive");
441
+ if (dirSegments.length === 0)
442
+ return;
443
+ const packageId = dirSegments[dirSegments.length - 1];
444
+ if (dirSegments.length > 1)
445
+ return; // nested dirs inside a package: skip id checks
446
+ if (!PACKAGE_ID_PATTERN.test(packageId)) {
447
+ findings.push({
448
+ severity: "error",
449
+ rule: "layout.package_id",
450
+ message: `package directory "${packageId}" does not match the required date-prefixed id YYYY-MM-DD-<slug> with a lowercase slug`,
451
+ file,
452
+ line: 1,
453
+ });
454
+ return;
455
+ }
456
+ const slug = packageId.slice(11);
457
+ if (RESERVED_PACKAGE_SLUGS.has(slug)) {
458
+ findings.push({
459
+ severity: "error",
460
+ rule: "layout.reserved_slug",
461
+ message: `package slug "${slug}" is reserved`,
462
+ file,
463
+ line: 1,
464
+ });
465
+ }
466
+ }
467
+ // END_BLOCK_LAYOUT_CHECKS
468
+ // START_BLOCK_KIND_DETECTION
469
+ export function detectSpecArtifactKind(rootName) {
470
+ switch (rootName) {
471
+ case "spec":
472
+ return "spec";
473
+ case "plan":
474
+ return "plan";
475
+ case "design-context":
476
+ return "design-context";
477
+ default:
478
+ return "unknown";
479
+ }
480
+ }
481
+ // END_BLOCK_KIND_DETECTION
482
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../../src/lib/spec-lint/parser.ts"],"names":[],"mappings":"AAAA,oCAAoC;AACpC,iBAAiB;AACjB,wBAAwB;AACxB,sHAAsH;AACtH,2YAA2Y;AAC3Y,2BAA2B;AAC3B,yBAAyB;AACzB,kBAAkB;AAClB,sBAAsB;AACtB,sBAAsB;AACtB,EAAE;AACF,mBAAmB;AACnB,gHAAgH;AAChH,yEAAyE;AACzE,kEAAkE;AAClE,8FAA8F;AAC9F,iFAAiF;AACjF,6FAA6F;AAC7F,sFAAsF;AACtF,0EAA0E;AAC1E,gFAAgF;AAChF,8FAA8F;AAC9F,yGAAyG;AACzG,4EAA4E;AAC5E,iFAAiF;AACjF,sFAAsF;AACtF,qFAAqF;AACrF,mEAAmE;AACnE,kFAAkF;AAClF,4FAA4F;AAC5F,mDAAmD;AACnD,+CAA+C;AAC/C,4CAA4C;AAC5C,gDAAgD;AAChD,kDAAkD;AAClD,6DAA6D;AAC7D,oDAAoD;AACpD,oDAAoD;AACpD,wEAAwE;AACxE,uEAAuE;AACvE,6DAA6D;AAC7D,2EAA2E;AAC3E,oEAAoE;AACpE,wEAAwE;AACxE,wDAAwD;AACxD,kEAAkE;AAClE,gFAAgF;AAChF,oEAAoE;AACpE,kFAAkF;AAClF,gFAAgF;AAChF,wFAAwF;AACxF,yCAAyC;AACzC,6CAA6C;AAC7C,qCAAqC;AACrC,4DAA4D;AAC5D,iBAAiB;AACjB,EAAE;AACF,uBAAuB;AACvB,oNAAoN;AACpN,qBAAqB;AAErB,OAAO,EAAE,SAAS,EAA2B,MAAM,aAAa,CAAC;AAEjE,2BAA2B;AAC3B,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC;AAgD9B,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,SAAS,EAAE,oCAAoC;IAC/C,IAAI,EAAE,iBAAiB;IACvB,IAAI,EAAE,YAAY;IAClB,UAAU,EAAE,uBAAuB;CAC3B,CAAC;AAEX,MAAM,CAAC,MAAM,WAAW,GAAG,YAAY,CAAC;AAExC,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC;AACtE,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;AAEpF,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC;AAC3E,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC;AAChE,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAE7D,MAAM,sBAAsB,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAEjG,MAAM,kBAAkB,GAAG,qDAAqD,CAAC;AACjF,yBAAyB;AAEzB,yBAAyB;AACzB,gEAAgE;AAChE,SAAS,MAAM,CAAC,OAAe,EAAE,KAAa;IAC5C,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IAC1D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;QAC9B,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE;YAAE,IAAI,EAAE,CAAC;IAC3C,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAQD;;;;;;;;GAQG;AACH,MAAM,UAAU,YAAY,CAAC,OAAe,EAAE,IAAY;IACxD,MAAM,QAAQ,GAAsB,EAAE,CAAC;IACvC,MAAM,cAAc,GAAc,EAAE,CAAC;IACrC,MAAM,KAAK,GAAkB,EAAE,CAAC;IAChC,IAAI,UAAU,GAAG,KAAK,CAAC;IACvB,IAAI,kBAAkB,GAAa,EAAE,CAAC;IACtC,IAAI,iBAAiB,GAAkB,IAAI,CAAC;IAE5C,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAE9C,MAAM,SAAS,GAAG,IAAI,SAAS,CAC7B,EAAE,OAAO,EAAE,IAAI,EAAE,oBAAoB,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,EACpE;QACE,aAAa,CAAC,KAAK,EAAE,QAAQ;YAC3B,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;YAC5C,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YACpC,kBAAkB,GAAG,EAAE,CAAC;YACxB,iBAAiB,GAAG,IAAI,CAAC;YACzB,IAAI,UAAU,EAAE,CAAC;gBACf,QAAQ,CAAC,IAAI,CAAC;oBACZ,QAAQ,EAAE,OAAO;oBACjB,IAAI,EAAE,wBAAwB;oBAC9B,OAAO,EAAE,YAAY,IAAI,yCAAyC;oBAClE,IAAI;oBACJ,IAAI;iBACL,CAAC,CAAC;gBACH,OAAO;YACT,CAAC;YACD,MAAM,IAAI,GAAgB;gBACxB,IAAI;gBACJ,IAAI;gBACJ,OAAO,EAAE,EAAE;gBACX,QAAQ,EAAE,EAAE;gBACZ,IAAI,EAAE,EAAE;gBACR,UAAU,EAAE,CAAC;gBACb,WAAW,EAAE,EAAE;aAChB,CAAC;YACF,MAAM,MAAM,GAAG,OAAO,EAAE,CAAC;YACzB,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC7B,CAAC;iBAAM,CAAC;gBACN,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC5B,CAAC;YACD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnB,CAAC;QACD,YAAY,CAAC,KAAK,EAAE,QAAQ;YAC1B,iBAAiB,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QACrD,CAAC;QACD,YAAY;YACV,0EAA0E;QAC5E,CAAC;QACD,cAAc;YACZ,4CAA4C;QAC9C,CAAC;QACD,WAAW;YACT,IAAI,iBAAiB;gBAAE,kBAAkB,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;YAClE,iBAAiB,GAAG,IAAI,CAAC;QAC3B,CAAC;QACD,YAAY,CAAC,QAAQ;YACnB,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;YACvB,IAAI,CAAC,IAAI;gBAAE,OAAO;YAClB,IAAI,kBAAkB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAClC,QAAQ,CAAC,IAAI,CAAC;oBACZ,QAAQ,EAAE,OAAO;oBACjB,IAAI,EAAE,gBAAgB;oBACtB,OAAO,EAAE,YAAY,IAAI,CAAC,IAAI,0BAA0B,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,mDAAmD;oBACxI,IAAI;oBACJ,IAAI,EAAE,IAAI,CAAC,IAAI;iBAChB,CAAC,CAAC;YACL,CAAC;YACD,KAAK,QAAQ,CAAC;QAChB,CAAC;QACD,gBAAgB;YACd,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;YACvB,IAAI,CAAC,IAAI;gBAAE,OAAO;YAClB,IAAI,kBAAkB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAClC,QAAQ,CAAC,IAAI,CAAC;oBACZ,QAAQ,EAAE,OAAO;oBACjB,IAAI,EAAE,gBAAgB;oBACtB,OAAO,EAAE,YAAY,IAAI,CAAC,IAAI,0BAA0B,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,mDAAmD;oBACxI,IAAI;oBACJ,IAAI,EAAE,IAAI,CAAC,IAAI;iBAChB,CAAC,CAAC;YACL,CAAC;YACD,kBAAkB,GAAG,EAAE,CAAC;YACxB,KAAK,CAAC,GAAG,EAAE,CAAC;YACZ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;gBAAE,UAAU,GAAG,IAAI,CAAC;QAC5C,CAAC;QACD,UAAU,CAAC,KAAK,EAAE,QAAQ;YACxB,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;YAC5C,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YACpC,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;YACtB,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,QAAQ,CAAC,IAAI,CAAC;oBACZ,QAAQ,EAAE,OAAO;oBACjB,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC,iBAAiB;oBAC/D,OAAO,EAAE,iBAAiB,IAAI,gCAAgC;oBAC9D,IAAI;oBACJ,IAAI;iBACL,CAAC,CAAC;gBACH,OAAO;YACT,CAAC;YACD,IAAI,GAAG,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;gBACtB,MAAM,UAAU,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;gBAC3D,IAAI,UAAU,KAAK,CAAC,CAAC,EAAE,CAAC;oBACtB,QAAQ,CAAC,IAAI,CAAC;wBACZ,QAAQ,EAAE,OAAO;wBACjB,IAAI,EAAE,sBAAsB;wBAC5B,OAAO,EAAE,iBAAiB,IAAI,yDAAyD,GAAG,CAAC,IAAI,eAAe,GAAG,CAAC,IAAI,GAAG;wBACzH,IAAI;wBACJ,IAAI;qBACL,CAAC,CAAC;oBACH,OAAO;gBACT,CAAC;gBACD,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,CAAC,EAAE,EAAE,CAAC;oBACnD,QAAQ,CAAC,IAAI,CAAC;wBACZ,QAAQ,EAAE,OAAO;wBACjB,IAAI,EAAE,cAAc;wBACpB,OAAO,EAAE,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,oBAAoB,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,8BAA8B,IAAI,iCAAiC;wBACtI,IAAI;wBACJ,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI;qBACpB,CAAC,CAAC;gBACL,CAAC;gBACD,KAAK,CAAC,MAAM,GAAG,UAAU,CAAC;YAC5B,CAAC;iBAAM,CAAC;gBACN,KAAK,CAAC,GAAG,EAAE,CAAC;YACd,CAAC;YACD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;gBAAE,UAAU,GAAG,IAAI,CAAC;QAC5C,CAAC;QACD,MAAM,CAAC,KAAK,EAAE,QAAQ;YACpB,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;YAC3C,MAAM,MAAM,GAAG,OAAO,EAAE,CAAC;YACzB,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,CAAC,IAAI,IAAI,GAAG,CAAC;YACrB,CAAC;iBAAM,IAAI,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;gBACtB,QAAQ,CAAC,IAAI,CAAC;oBACZ,QAAQ,EAAE,OAAO;oBACjB,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC,gBAAgB;oBAC9D,OAAO,EAAE,0CAA0C,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE;oBAC5F,IAAI;oBACJ,IAAI,EAAE,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC;iBAC7B,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QACD,OAAO;YACL,MAAM,MAAM,GAAG,OAAO,EAAE,CAAC;YACzB,IAAI,MAAM;gBAAE,MAAM,CAAC,UAAU,EAAE,CAAC;QAClC,CAAC;QACD,SAAS;YACP,sEAAsE;QACxE,CAAC;QACD,aAAa;YACX,sEAAsE;QACxE,CAAC;QACD,uBAAuB;YACrB,iEAAiE;QACnE,CAAC;QACD,YAAY;YACV,8EAA8E;QAChF,CAAC;QACD,KAAK;YACH,mGAAmG;QACrG,CAAC;KAC2B,CAC/B,CAAC;IAEF,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACzB,SAAS,CAAC,GAAG,EAAE,CAAC;IAEhB,KAAK,MAAM,QAAQ,IAAI,KAAK,EAAE,CAAC;QAC7B,QAAQ,CAAC,IAAI,CAAC;YACZ,QAAQ,EAAE,OAAO;YACjB,IAAI,EAAE,cAAc;YACpB,OAAO,EAAE,YAAY,QAAQ,CAAC,IAAI,oBAAoB,QAAQ,CAAC,IAAI,kBAAkB;YACrF,IAAI;YACJ,IAAI,EAAE,QAAQ,CAAC,IAAI;SACpB,CAAC,CAAC;IACL,CAAC;IAED,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,QAAQ,CAAC,IAAI,CAAC;YACZ,QAAQ,EAAE,OAAO;YACjB,IAAI,EAAE,oBAAoB;YAC1B,OAAO,EAAE,gBAAgB,cAAc,CAAC,MAAM,wCAAwC;YACtF,IAAI;YACJ,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,IAAI;SAC7B,CAAC,CAAC;IACL,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,QAAQ,EAAE,CAAC;AACvD,CAAC;AAYD,MAAM,CAAC,MAAM,aAAa,GAA8B;IACtD,IAAI,EAAE;QACJ,KAAK,EAAE;YACL,QAAQ;YACR,MAAM;YACN,cAAc;YACd,YAAY;YACZ,YAAY;YACZ,WAAW;YACX,gBAAgB;YAChB,SAAS;YACT,WAAW;SACZ;KACF;IACD,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,UAAU,EAAE,UAAU,CAAC,EAAE;IAC5C,UAAU,EAAE,EAAE,QAAQ,EAAE,WAAW,EAAE;IACrC,SAAS,EAAE,EAAE,KAAK,EAAE,CAAC,UAAU,CAAC,EAAE;CACnC,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,MAAM,EAAE,gBAAgB,EAAE,YAAY,CAAU,CAAC;AAEpF,MAAM,CAAC,MAAM,aAAa,GAA8B;IACtD,IAAI,EAAE;QACJ,KAAK,EAAE;YACL,MAAM;YACN,gBAAgB;YAChB,SAAS;YACT,QAAQ;YACR,MAAM;YACN,cAAc;YACd,OAAO;YACP,WAAW;SACZ;KACF;IACD,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,SAAS,EAAE,OAAO,EAAE,kBAAkB,EAAE,YAAY,CAAC,EAAE;IACvE,YAAY,EAAE,EAAE,QAAQ,EAAE,WAAW,EAAE;IACvC,KAAK,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE;IAC3B,SAAS,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,oBAAoB,CAAC,EAAE;IACpD,kBAAkB,EAAE,EAAE,QAAQ,EAAE,YAAY,EAAE;CAC/C,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,OAAO;IACP,MAAM;IACN,QAAQ;IACR,aAAa;IACb,YAAY;IACZ,SAAS;IACT,YAAY;IACZ,cAAc;IACd,aAAa;CACL,CAAC;AACX,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,SAAS,CAAU,CAAC;AAC1D,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,WAAW,CAAU,CAAC;AAC1D,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,SAAS,CAAU,CAAC;AAC1D,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,MAAM,CAAU,CAAC;AAC/C,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,MAAM,EAAE,MAAM,CAAU,CAAC;AAC5D,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,MAAM,CAAU,CAAC;AAE3D,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,MAAM;IACN,YAAY;IACZ,QAAQ;IACR,OAAO;IACP,WAAW;IACX,YAAY;IACZ,cAAc;CACN,CAAC;AACX,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,SAAS,CAAU,CAAC;AAC/D,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,MAAM,CAAU,CAAC;AAC3D,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,UAAU,CAAU,CAAC;AAEnE,MAAM,CAAC,MAAM,uBAAuB,GAA8B;IAChE,gBAAgB,EAAE;QAChB,KAAK,EAAE,CAAC,WAAW,EAAE,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE,sBAAsB,CAAC;KACrF;IACD,SAAS,EAAE,EAAE,KAAK,EAAE,CAAC,UAAU,CAAC,EAAE;IAClC,QAAQ,EAAE,EAAE,KAAK,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,yBAAyB,CAAC,EAAE;IAChF,uBAAuB,EAAE,EAAE,KAAK,EAAE,CAAC,aAAa,CAAC,EAAE;IACnD,WAAW,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,iBAAiB,CAAC,EAAE;IACnD,WAAW,EAAE,EAAE,KAAK,EAAE,CAAC,YAAY,CAAC,EAAE;IACtC,UAAU,EAAE,EAAE,KAAK,EAAE,CAAC,WAAW,EAAE,YAAY,EAAE,YAAY,CAAC,EAAE;IAChE,QAAQ,EAAE,EAAE,KAAK,EAAE,CAAC,mBAAmB,CAAC,EAAE;IAC1C,iBAAiB,EAAE,EAAE,KAAK,EAAE,CAAC,UAAU,EAAE,cAAc,EAAE,iBAAiB,CAAC,EAAE;IAC7E,SAAS,EAAE,EAAE,KAAK,EAAE,CAAC,UAAU,CAAC,EAAE;IAClC,QAAQ,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,cAAc,CAAC,EAAE;IACxD,oBAAoB,EAAE,EAAE,KAAK,EAAE,CAAC,YAAY,CAAC,EAAE;IAC/C,UAAU,EAAE,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE;CAC5C,CAAC;AACF,4BAA4B;AAE5B,gCAAgC;AAChC;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAa;IAChD,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC7C,OAAO,MAAM,KAAK,UAAU,IAAI,MAAM,KAAK,SAAS,CAAC;AACvD,CAAC;AACD,8BAA8B;AAE9B,2BAA2B;AAC3B,MAAM,UAAU,KAAK,CAAC,IAAa,EAAE,IAAY;IAC/C,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,IAAa,EAAE,IAAY;IAClD,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,IAAyB;IAC9C,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,IAAyB;IAChD,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;AAC7B,CAAC;AACD,yBAAyB;AAEzB,8BAA8B;AAC9B,wFAAwF;AACxF,MAAM,UAAU,aAAa,CAC3B,IAAa,EACb,IAA2B,EAC3B,IAAY,EACZ,QAA2B,EAC3B,eAAkC,EAAE;IAEpC,MAAM,OAAO,GAAG,IAAI,GAAG,CAAS,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,EAAE,GAAG,YAAY,CAAC,CAAC,CAAC;IAC3E,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC9B,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;YAAE,SAAS;QAClC,IAAI,IAAI,EAAE,QAAQ,IAAI,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;YAAE,SAAS;QAC9E,MAAM,QAAQ,GAAG,IAAI,EAAE,QAAQ;YAC7B,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,QAAQ,QAAQ,IAAI,CAAC,QAAQ,oBAAoB;YACvF,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC;QAC/C,QAAQ,CAAC,IAAI,CAAC;YACZ,QAAQ,EAAE,OAAO;YACjB,IAAI,EAAE,iBAAiB;YACvB,OAAO,EAAE,YAAY,CAAC,CAAC,IAAI,iDAAiD,IAAI,CAAC,IAAI,eAAe,QAAQ,EAAE;YAC9G,IAAI;YACJ,IAAI,EAAE,CAAC,CAAC,IAAI;SACb,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AACD,4BAA4B;AAE5B,4BAA4B;AAC5B,+DAA+D;AAC/D,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC;AAC1D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY,EAAE,QAA2B;IAC1E,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACrD,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC/C,IAAI,CAAC,CAAC,UAAU,EAAE,UAAU,EAAE,oBAAoB,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO;IAC/E,MAAM,UAAU,GAAG,QAAQ,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACjD,IAAI,UAAU,KAAK,CAAC,CAAC;QAAE,OAAO;IAC9B,MAAM,WAAW,GAAG,QAAQ,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;IACtF,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IACrC,MAAM,SAAS,GAAG,WAAW,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACtD,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,CAAC,+CAA+C;IACnF,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QACxC,QAAQ,CAAC,IAAI,CAAC;YACZ,QAAQ,EAAE,OAAO;YACjB,IAAI,EAAE,mBAAmB;YACzB,OAAO,EAAE,sBAAsB,SAAS,wFAAwF;YAChI,IAAI;YACJ,IAAI,EAAE,CAAC;SACR,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IACD,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACjC,IAAI,sBAAsB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QACrC,QAAQ,CAAC,IAAI,CAAC;YACZ,QAAQ,EAAE,OAAO;YACjB,IAAI,EAAE,sBAAsB;YAC5B,OAAO,EAAE,iBAAiB,IAAI,eAAe;YAC7C,IAAI;YACJ,IAAI,EAAE,CAAC;SACR,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AACD,0BAA0B;AAE1B,6BAA6B;AAC7B,MAAM,UAAU,sBAAsB,CAAC,QAAgB;IACrD,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,MAAM;YACT,OAAO,MAAM,CAAC;QAChB,KAAK,MAAM;YACT,OAAO,MAAM,CAAC;QAChB,KAAK,gBAAgB;YACnB,OAAO,gBAAgB,CAAC;QAC1B;YACE,OAAO,SAAS,CAAC;IACrB,CAAC;AACH,CAAC;AACD,2BAA2B"}
@@ -0,0 +1,38 @@
1
+ import { SpecLintFinding, SpecLintOptions, SpecLintVerdict, type XmlNode } from "./parser.js";
2
+ import type { SpecFacts } from "./spec-rules.js";
3
+ export interface DelegatedTaskFactsEntry {
4
+ taskElement: string;
5
+ taskId: string;
6
+ wave: string;
7
+ line: number;
8
+ writeScope: string[];
9
+ writeScopeDeclared: boolean;
10
+ writeScopeDuplicates: string[];
11
+ primaryFile: string;
12
+ title: string;
13
+ acceptance: string[];
14
+ verification: string[];
15
+ dependsOn: string[];
16
+ }
17
+ export interface DelegatedTaskFacts {
18
+ waveOrder: string[];
19
+ tasks: DelegatedTaskFactsEntry[];
20
+ duplicateTaskElements: string[];
21
+ }
22
+ /**
23
+ * Collect wave order and per-task delegated facts with a standalone walk so
24
+ * lintPlan's main task validation and extractDelegatedPlanDefinition share one
25
+ * interpretation of the declared task/write-scope vocabulary.
26
+ */
27
+ export declare function collectDelegatedTaskFacts(root: XmlNode): DelegatedTaskFacts;
28
+ /** Emit write-scope obligations for every declared delegated task. */
29
+ export declare function lintDelegatedWriteScopes(facts: DelegatedTaskFacts, completeness: boolean, findings: SpecLintFinding[], file: string): void;
30
+ /**
31
+ * Validate the optional <execution> section. Structural violations of declared
32
+ * content (unknown modes/children, duplicate identities, dangling references,
33
+ * future-wave coverage, multiple or misplaced finals, incomplete declared
34
+ * coverage) are always errors; presence obligations for approved/applied plans
35
+ * escalate from draft warnings.
36
+ */
37
+ export declare function lintExecutionSection(root: XmlNode, file: string, facts: DelegatedTaskFacts, completeness: boolean, findings: SpecLintFinding[]): void;
38
+ export declare function lintPlan(root: XmlNode, file: string, parseFindings: SpecLintFinding[], specByLabel: Map<string, SpecFacts>, options: SpecLintOptions): SpecLintVerdict;