strikethroo 3.16.0 → 3.17.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 (86) hide show
  1. package/README.md +8 -0
  2. package/dist/cli.js +37 -0
  3. package/dist/cli.js.map +1 -1
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +43 -3
  6. package/dist/index.js.map +1 -1
  7. package/dist/serve/root.d.ts +27 -11
  8. package/dist/serve/root.d.ts.map +1 -1
  9. package/dist/serve/root.js +36 -16
  10. package/dist/serve/root.js.map +1 -1
  11. package/dist/validation/graph-checks.d.ts +45 -0
  12. package/dist/validation/graph-checks.d.ts.map +1 -0
  13. package/dist/validation/graph-checks.js +388 -0
  14. package/dist/validation/graph-checks.js.map +1 -0
  15. package/dist/validation/metadata-gate.d.ts +26 -0
  16. package/dist/validation/metadata-gate.d.ts.map +1 -0
  17. package/dist/validation/metadata-gate.js +123 -0
  18. package/dist/validation/metadata-gate.js.map +1 -0
  19. package/dist/validation/strict-pass.d.ts +38 -0
  20. package/dist/validation/strict-pass.d.ts.map +1 -0
  21. package/dist/validation/strict-pass.js +338 -0
  22. package/dist/validation/strict-pass.js.map +1 -0
  23. package/dist/validation/types.d.ts +30 -0
  24. package/dist/validation/types.d.ts.map +1 -0
  25. package/dist/validation/types.js +12 -0
  26. package/dist/validation/types.js.map +1 -0
  27. package/dist/validation/workspace.d.ts +31 -0
  28. package/dist/validation/workspace.d.ts.map +1 -0
  29. package/dist/validation/workspace.js +49 -0
  30. package/dist/validation/workspace.js.map +1 -0
  31. package/dist-web/assets/{arc-DMHUv2NY.js → arc-CtIXTnp-.js} +1 -1
  32. package/dist-web/assets/{architectureDiagram-3BPJPVTR-CeAAqVS4.js → architectureDiagram-3BPJPVTR-DjLBuYL_.js} +1 -1
  33. package/dist-web/assets/{blockDiagram-GPEHLZMM-Hns_u_jz.js → blockDiagram-GPEHLZMM-CyUvqZi1.js} +1 -1
  34. package/dist-web/assets/{c4Diagram-AAUBKEIU-BH3RLVAi.js → c4Diagram-AAUBKEIU-DbT3qzdM.js} +1 -1
  35. package/dist-web/assets/channel-ejrFqLJP.js +1 -0
  36. package/dist-web/assets/{chunk-2J33WTMH-h6Ws9VXu.js → chunk-2J33WTMH-w1zteFnE.js} +1 -1
  37. package/dist-web/assets/{chunk-4BX2VUAB-BSBeNNnS.js → chunk-4BX2VUAB-AXaQBlkr.js} +1 -1
  38. package/dist-web/assets/{chunk-55IACEB6-BmUY060b.js → chunk-55IACEB6-YxIJIoS8.js} +1 -1
  39. package/dist-web/assets/{chunk-727SXJPM-CmemMVvQ.js → chunk-727SXJPM-Ec_YNRXy.js} +1 -1
  40. package/dist-web/assets/{chunk-AQP2D5EJ-LQpUb_FL.js → chunk-AQP2D5EJ-Bq3XSb33.js} +1 -1
  41. package/dist-web/assets/{chunk-FMBD7UC4-wk7OYcdf.js → chunk-FMBD7UC4-D3hDHEbQ.js} +1 -1
  42. package/dist-web/assets/{chunk-ND2GUHAM-O3K3rkHW.js → chunk-ND2GUHAM-D7qdmfIe.js} +1 -1
  43. package/dist-web/assets/{chunk-QZHKN3VN-CvppUbp9.js → chunk-QZHKN3VN-CnaHYcq_.js} +1 -1
  44. package/dist-web/assets/classDiagram-4FO5ZUOK-D4kGOS-J.js +1 -0
  45. package/dist-web/assets/classDiagram-v2-Q7XG4LA2-D4kGOS-J.js +1 -0
  46. package/dist-web/assets/{cose-bilkent-S5V4N54A-Cf1nQ4V_.js → cose-bilkent-S5V4N54A-B-C7BPM4.js} +1 -1
  47. package/dist-web/assets/{dagre-BM42HDAG-YyP7mwPP.js → dagre-BM42HDAG-Ce21GDpz.js} +1 -1
  48. package/dist-web/assets/{diagram-2AECGRRQ-BmAtTKkQ.js → diagram-2AECGRRQ-DHwtwYvI.js} +1 -1
  49. package/dist-web/assets/{diagram-5GNKFQAL-Bem8_DUK.js → diagram-5GNKFQAL-Cz3oNPoV.js} +1 -1
  50. package/dist-web/assets/{diagram-KO2AKTUF-0gNyY9-f.js → diagram-KO2AKTUF-DvTrw4fW.js} +1 -1
  51. package/dist-web/assets/{diagram-LMA3HP47-CJJh_IUU.js → diagram-LMA3HP47-BkoqJsup.js} +1 -1
  52. package/dist-web/assets/{diagram-OG6HWLK6-DJcCho7F.js → diagram-OG6HWLK6-D-g29Bkd.js} +1 -1
  53. package/dist-web/assets/{erDiagram-TEJ5UH35-D-TI_EbX.js → erDiagram-TEJ5UH35-CTjmf6Xm.js} +1 -1
  54. package/dist-web/assets/{flowDiagram-I6XJVG4X-BUrB4EYN.js → flowDiagram-I6XJVG4X-Bw77m94u.js} +1 -1
  55. package/dist-web/assets/{ganttDiagram-6RSMTGT7-C9_ItheP.js → ganttDiagram-6RSMTGT7-gzA4FOSg.js} +1 -1
  56. package/dist-web/assets/{gitGraphDiagram-PVQCEYII-DYQEmll0.js → gitGraphDiagram-PVQCEYII-BRaUUXaJ.js} +1 -1
  57. package/dist-web/assets/{index-mEUl0sqe.js → index-B_YjLzSw.js} +1 -1
  58. package/dist-web/assets/{index-X-a-o-AT.js → index-DJpZGE86.js} +1 -1
  59. package/dist-web/assets/{index-DULKNhw0.js → index-YT2EMDff.js} +4 -4
  60. package/dist-web/assets/{infoDiagram-5YYISTIA-B06Tp7cb.js → infoDiagram-5YYISTIA-h6n8eqGu.js} +1 -1
  61. package/dist-web/assets/{ishikawaDiagram-YF4QCWOH-DY9iP3P6.js → ishikawaDiagram-YF4QCWOH-BiJ3tbak.js} +1 -1
  62. package/dist-web/assets/{journeyDiagram-JHISSGLW-Bk4MV49m.js → journeyDiagram-JHISSGLW-Q31kk_hH.js} +1 -1
  63. package/dist-web/assets/{kanban-definition-UN3LZRKU-B9-wsNt9.js → kanban-definition-UN3LZRKU-ZV5ks__v.js} +1 -1
  64. package/dist-web/assets/{linear-DEY9HwQB.js → linear-F-j1CAaU.js} +1 -1
  65. package/dist-web/assets/{mermaid.core-Cn0e4l6V.js → mermaid.core-C6KsMc78.js} +4 -4
  66. package/dist-web/assets/{mindmap-definition-RKZ34NQL-pN4Q2WNG.js → mindmap-definition-RKZ34NQL-D-qRccYa.js} +1 -1
  67. package/dist-web/assets/{pieDiagram-4H26LBE5-DTkPv6S2.js → pieDiagram-4H26LBE5-y1b8Tbaa.js} +1 -1
  68. package/dist-web/assets/{quadrantDiagram-W4KKPZXB-BS9LhTv0.js → quadrantDiagram-W4KKPZXB-BMoept3P.js} +1 -1
  69. package/dist-web/assets/{requirementDiagram-4Y6WPE33-BlSOLsQe.js → requirementDiagram-4Y6WPE33-BL-2jNsJ.js} +1 -1
  70. package/dist-web/assets/{sankeyDiagram-5OEKKPKP-B1xl-B1U.js → sankeyDiagram-5OEKKPKP-dfD7Fow2.js} +1 -1
  71. package/dist-web/assets/{sequenceDiagram-3UESZ5HK-BoiYrW_0.js → sequenceDiagram-3UESZ5HK-DEkvMHGP.js} +1 -1
  72. package/dist-web/assets/{stateDiagram-AJRCARHV-BxvfZYDK.js → stateDiagram-AJRCARHV-4t9PvMom.js} +1 -1
  73. package/dist-web/assets/stateDiagram-v2-BHNVJYJU-5xE8WrG_.js +1 -0
  74. package/dist-web/assets/{timeline-definition-PNZ67QCA-CUEbrRkc.js → timeline-definition-PNZ67QCA-V1D7tV43.js} +1 -1
  75. package/dist-web/assets/{vennDiagram-CIIHVFJN-CgQiBucH.js → vennDiagram-CIIHVFJN-Tw5zLG0T.js} +1 -1
  76. package/dist-web/assets/{wardley-L42UT6IY-BsGW6T55.js → wardley-L42UT6IY-CrYt_lTh.js} +1 -1
  77. package/dist-web/assets/{wardleyDiagram-YWT4CUSO-Cq3RMp6B.js → wardleyDiagram-YWT4CUSO-CDe_cIHY.js} +1 -1
  78. package/dist-web/assets/{xychartDiagram-2RQKCTM6-WaoV-V3f.js → xychartDiagram-2RQKCTM6-DNoNd0tl.js} +1 -1
  79. package/dist-web/index.html +1 -1
  80. package/package.json +1 -1
  81. package/templates/strikethroo/gitignore +30 -0
  82. package/dist-web/assets/channel-Dk0dEQIT.js +0 -1
  83. package/dist-web/assets/classDiagram-4FO5ZUOK-gqDJqcDV.js +0 -1
  84. package/dist-web/assets/classDiagram-v2-Q7XG4LA2-gqDJqcDV.js +0 -1
  85. package/dist-web/assets/stateDiagram-v2-BHNVJYJU-XGZY1tGg.js +0 -1
  86. package/templates/strikethroo/runtime/.gitignore +0 -2
@@ -0,0 +1,338 @@
1
+ "use strict";
2
+ /**
3
+ * Strict frontmatter pass over `plans/<plan>/plan-<name>.md` and
4
+ * `plans/<plan>/tasks/<name>.md`.
5
+ *
6
+ * Deliberately independent of the viewer's frontmatter reader in
7
+ * `src/serve/markdown.ts`: that one is lenient by design and cannot distinguish
8
+ * a missing field from a malformed one, which is precisely the distinction a
9
+ * validator must report. It runs `parseInt` and leaves the field `undefined` on
10
+ * failure, so `id: abc` and a file with no `id:` line at all produce
11
+ * byte-identical results. The two parsers coexist with different tolerance
12
+ * contracts, and the viewer's is not to be "fixed" — leniency is correct for
13
+ * rendering.
14
+ *
15
+ * Enumeration is likewise hand-rolled rather than routed through the shared
16
+ * plan-scan helpers in `src/skill-scripts/shared/`, which drop any plan whose
17
+ * `id` will not parse and are therefore structurally incapable of reporting the
18
+ * plans most likely to be broken.
19
+ *
20
+ * Scope is exactly `plans/`. Archived plans are immutable history, so a finding
21
+ * against one is unfixable noise; the shipped task template carries literal
22
+ * placeholders (`status: "[STATUS]"`), so a workspace-wide Markdown sweep would
23
+ * make the workspace report its own templates as broken.
24
+ *
25
+ * Required plan *sections* are deliberately not checked: no machine-readable
26
+ * list of them exists, and the templates are user-editable and wholesale
27
+ * replaceable by a strikethroo profile.
28
+ */
29
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
30
+ if (k2 === undefined) k2 = k;
31
+ var desc = Object.getOwnPropertyDescriptor(m, k);
32
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
33
+ desc = { enumerable: true, get: function() { return m[k]; } };
34
+ }
35
+ Object.defineProperty(o, k2, desc);
36
+ }) : (function(o, m, k, k2) {
37
+ if (k2 === undefined) k2 = k;
38
+ o[k2] = m[k];
39
+ }));
40
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
41
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
42
+ }) : function(o, v) {
43
+ o["default"] = v;
44
+ });
45
+ var __importStar = (this && this.__importStar) || (function () {
46
+ var ownKeys = function(o) {
47
+ ownKeys = Object.getOwnPropertyNames || function (o) {
48
+ var ar = [];
49
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
50
+ return ar;
51
+ };
52
+ return ownKeys(o);
53
+ };
54
+ return function (mod) {
55
+ if (mod && mod.__esModule) return mod;
56
+ var result = {};
57
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
58
+ __setModuleDefault(result, mod);
59
+ return result;
60
+ };
61
+ })();
62
+ Object.defineProperty(exports, "__esModule", { value: true });
63
+ exports.strictPass = strictPass;
64
+ const fs = __importStar(require("fs"));
65
+ const path = __importStar(require("path"));
66
+ const complexity_score_1 = require("../skill-scripts/shared/complexity-score");
67
+ /**
68
+ * The task `status` enum, from `templates/strikethroo/config/templates/TASK_TEMPLATE.md`.
69
+ * Encoded here because nothing machine-readable ships it.
70
+ */
71
+ const TASK_STATUSES = ['pending', 'in-progress', 'completed', 'needs-clarification'];
72
+ /** Anchors the leading `---`-delimited block. A later `---` is body, not frontmatter. */
73
+ const FRONTMATTER_RE = /^---[ \t]*\r?\n([\s\S]*?)\r?\n---[ \t]*(?:\r?\n|$)/;
74
+ /** A top-level frontmatter key line; leading whitespace excludes it (nested keys are ignored). */
75
+ const KEY_LINE_RE = /^([A-Za-z_][A-Za-z0-9_-]*)[ \t]*:(.*)$/;
76
+ /** A dashed list item belonging to the key above it. */
77
+ const DASH_ITEM_RE = /^[ \t]*-[ \t]+(.*)$/;
78
+ const INTEGER_RE = /^-?\d+$/;
79
+ const NON_NEGATIVE_INTEGER_RE = /^\d+$/;
80
+ const ISO_DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
81
+ /** Removes one layer of matching surrounding quotes. */
82
+ const stripQuotes = (value) => {
83
+ const trimmed = value.trim();
84
+ if (trimmed.length >= 2) {
85
+ const first = trimmed[0];
86
+ const last = trimmed[trimmed.length - 1];
87
+ if ((first === '"' && last === '"') || (first === "'" && last === "'")) {
88
+ return trimmed.slice(1, -1);
89
+ }
90
+ }
91
+ return trimmed;
92
+ };
93
+ /** Strips a trailing unquoted YAML comment. Quoted scalars keep their `#`. */
94
+ const stripComment = (value) => {
95
+ const trimmed = value.trim();
96
+ if (trimmed.startsWith('"') || trimmed.startsWith("'"))
97
+ return trimmed;
98
+ const hashIndex = trimmed.indexOf('#');
99
+ return hashIndex === -1 ? trimmed : trimmed.slice(0, hashIndex).trim();
100
+ };
101
+ /** Normalizes a written value to its bare text: comment stripped, then unquoted. */
102
+ const bareText = (value) => stripQuotes(stripComment(value));
103
+ /** Splits `[a, b]` into trimmed, unquoted items. `[]` yields an empty list. */
104
+ const parseInlineList = (value) => {
105
+ const inner = value.slice(1, -1).trim();
106
+ if (inner.length === 0)
107
+ return [];
108
+ return inner.split(',').map(item => stripQuotes(item));
109
+ };
110
+ /**
111
+ * Reads the first frontmatter block into raw per-key values.
112
+ *
113
+ * Returns `null` when the file has no leading frontmatter block at all — a
114
+ * different defect than an empty one. Duplicate keys are last-wins, matching the
115
+ * existing convention; a duplicate-key finding is out of scope.
116
+ */
117
+ const readFrontmatter = (content) => {
118
+ const match = content.match(FRONTMATTER_RE);
119
+ if (!match || match[1] === undefined)
120
+ return null;
121
+ const fields = new Map();
122
+ const lines = match[1].split(/\r?\n/);
123
+ for (let i = 0; i < lines.length; i++) {
124
+ const line = lines[i];
125
+ if (line === undefined)
126
+ continue;
127
+ const trimmed = line.trim();
128
+ // Blank lines, whole-line comments, and dashed items already consumed by
129
+ // their owning key.
130
+ if (trimmed.length === 0 || trimmed.startsWith('#') || DASH_ITEM_RE.test(line))
131
+ continue;
132
+ const keyMatch = line.match(KEY_LINE_RE);
133
+ if (!keyMatch || keyMatch[1] === undefined || keyMatch[2] === undefined)
134
+ continue;
135
+ const key = keyMatch[1];
136
+ const written = stripComment(keyMatch[2]);
137
+ if (written.startsWith('[') && written.endsWith(']')) {
138
+ fields.set(key, { kind: 'list', items: parseInlineList(written) });
139
+ continue;
140
+ }
141
+ if (written.length > 0) {
142
+ fields.set(key, { kind: 'scalar', text: stripQuotes(written) });
143
+ continue;
144
+ }
145
+ // Empty value: collect the dashed items that follow, if any.
146
+ const items = [];
147
+ let j = i + 1;
148
+ while (j < lines.length) {
149
+ const next = lines[j];
150
+ if (next === undefined)
151
+ break;
152
+ const dash = next.match(DASH_ITEM_RE);
153
+ if (!dash || dash[1] === undefined)
154
+ break;
155
+ items.push(bareText(dash[1]));
156
+ j++;
157
+ }
158
+ if (items.length > 0) {
159
+ fields.set(key, { kind: 'list', items });
160
+ i = j - 1;
161
+ }
162
+ else {
163
+ // A bare `key:` is YAML null. Treated as an empty scalar; the list-field
164
+ // checks accept it as an empty list, which is what every consumer already
165
+ // sees and therefore not a provable inconsistency.
166
+ fields.set(key, { kind: 'scalar', text: '' });
167
+ }
168
+ }
169
+ return fields;
170
+ };
171
+ /** Builds the finding for a key that is absent from the frontmatter block. */
172
+ const missingField = (kind, relPath, field) => ({
173
+ check: `${kind}/frontmatter-field-missing`,
174
+ path: relPath,
175
+ message: `${kind === 'plan' ? 'Plan' : 'Task'} frontmatter is missing required field \`${field}\`. Add it.`,
176
+ });
177
+ /** Builds the finding for a key that is present with a value failing its contract. */
178
+ const malformedField = (kind, relPath, field, written, expectation) => ({
179
+ check: `${kind}/frontmatter-field-malformed`,
180
+ path: relPath,
181
+ message: `${kind === 'plan' ? 'Plan' : 'Task'} frontmatter field \`${field}\` is \`${written}\`, which is not ${expectation}.`,
182
+ });
183
+ /** Renders a value the way it was written, for quoting back in a message. */
184
+ const renderValue = (value) => value.kind === 'scalar' ? value.text : `[${value.items.join(', ')}]`;
185
+ /**
186
+ * Checks a required scalar field against a predicate, distinguishing absent from
187
+ * present-but-wrong. A list where a scalar belongs is malformed, not missing.
188
+ */
189
+ const checkScalarField = (kind, relPath, fields, field, isValid, expectation) => {
190
+ const value = fields.get(field);
191
+ if (value === undefined)
192
+ return [missingField(kind, relPath, field)];
193
+ if (value.kind !== 'scalar' || !isValid(value.text)) {
194
+ return [malformedField(kind, relPath, field, renderValue(value), expectation)];
195
+ }
196
+ return [];
197
+ };
198
+ /**
199
+ * Checks a required list field. A bare `key:` (empty scalar) counts as an empty
200
+ * list; any other scalar is malformed. Items are validated individually and the
201
+ * offenders are named.
202
+ */
203
+ const checkListField = (relPath, fields, field, isValidItem, expectation) => {
204
+ const value = fields.get(field);
205
+ if (value === undefined)
206
+ return [missingField('task', relPath, field)];
207
+ if (value.kind === 'scalar') {
208
+ if (value.text.length === 0)
209
+ return [];
210
+ return [malformedField('task', relPath, field, value.text, expectation)];
211
+ }
212
+ const offenders = value.items.filter(item => !isValidItem(item));
213
+ if (offenders.length === 0)
214
+ return [];
215
+ return [
216
+ malformedField('task', relPath, field, renderValue(value), `${expectation} (offending entries: ${offenders.map(o => `\`${o}\``).join(', ')})`),
217
+ ];
218
+ };
219
+ /** Checks the frontmatter of one plan file. */
220
+ const checkPlanFields = (relPath, fields) => [
221
+ ...checkScalarField('plan', relPath, fields, 'id', text => NON_NEGATIVE_INTEGER_RE.test(text), 'a non-negative integer'),
222
+ ...checkScalarField('plan', relPath, fields, 'summary', text => text.length > 0, 'a non-empty string'),
223
+ ...checkScalarField('plan', relPath, fields, 'created', text => ISO_DATE_RE.test(text), 'a YYYY-MM-DD date'),
224
+ ];
225
+ /** Checks the `status` field: absent and unrecognized are different defects. */
226
+ const checkStatus = (relPath, fields) => {
227
+ const value = fields.get('status');
228
+ if (value === undefined)
229
+ return [missingField('task', relPath, 'status')];
230
+ const written = renderValue(value);
231
+ if (value.kind === 'scalar' && TASK_STATUSES.includes(value.text)) {
232
+ return [];
233
+ }
234
+ return [
235
+ {
236
+ check: 'task/status-invalid',
237
+ path: relPath,
238
+ message: `Task \`status\` is \`${written}\`, which is not one of ${TASK_STATUSES.map(s => `\`${s}\``).join(', ')}.`,
239
+ },
240
+ ];
241
+ };
242
+ /** Checks the frontmatter of one task file. */
243
+ const checkTaskFields = (relPath, fields) => {
244
+ const findings = [
245
+ ...checkScalarField('task', relPath, fields, 'id', text => NON_NEGATIVE_INTEGER_RE.test(text), 'a non-negative integer'),
246
+ ...checkStatus(relPath, fields),
247
+ ...checkListField(relPath, fields, 'dependencies', item => INTEGER_RE.test(item), 'a list of integer task ids'),
248
+ ...checkListField(relPath, fields, 'skills', item => item.length > 0, 'a list of skill names'),
249
+ ];
250
+ // `complexity_score` is required only on newly generated tasks, so its absence
251
+ // is legitimate on older ones. When present it must satisfy its 1-10 contract,
252
+ // which `validateComplexityScore` already encodes — reused rather than
253
+ // duplicated so the range cannot drift.
254
+ const complexity = fields.get('complexity_score');
255
+ if (complexity !== undefined) {
256
+ const written = renderValue(complexity);
257
+ const result = complexity.kind === 'scalar'
258
+ ? (0, complexity_score_1.validateComplexityScore)(complexity.text)
259
+ : { valid: false, reason: 'non-integer' };
260
+ if (!result.valid) {
261
+ findings.push(malformedField('task', relPath, 'complexity_score', written, 'an integer from 1 to 10'));
262
+ }
263
+ }
264
+ return findings;
265
+ };
266
+ /** Lists the names of a directory's entries of one type; missing/unreadable yields none. */
267
+ const listEntries = (dir, want) => {
268
+ let entries;
269
+ try {
270
+ entries = fs.readdirSync(dir, { withFileTypes: true });
271
+ }
272
+ catch {
273
+ return [];
274
+ }
275
+ return entries.filter(e => (want === 'file' ? e.isFile() : e.isDirectory())).map(e => e.name);
276
+ };
277
+ /**
278
+ * Reads and checks one document, converting an unreadable file or an absent
279
+ * frontmatter block into a finding rather than a throw.
280
+ */
281
+ const checkDocument = (absPath, relPath, kind) => {
282
+ let content;
283
+ try {
284
+ content = fs.readFileSync(absPath, 'utf-8');
285
+ }
286
+ catch {
287
+ return [
288
+ {
289
+ check: `${kind}/unreadable`,
290
+ path: relPath,
291
+ message: `${relPath} could not be read. Check that it exists and is readable.`,
292
+ },
293
+ ];
294
+ }
295
+ const fields = readFrontmatter(content);
296
+ if (fields === null) {
297
+ return [
298
+ {
299
+ check: `${kind}/frontmatter-absent`,
300
+ path: relPath,
301
+ message: `${relPath} has no leading \`---\` frontmatter block, so none of its metadata is readable.`,
302
+ },
303
+ ];
304
+ }
305
+ return kind === 'plan' ? checkPlanFields(relPath, fields) : checkTaskFields(relPath, fields);
306
+ };
307
+ const PLANS_DIR = 'plans';
308
+ const TASKS_DIR = 'tasks';
309
+ const PLAN_FILE_RE = /^plan-.*\.md$/;
310
+ const MARKDOWN_RE = /\.md$/;
311
+ /**
312
+ * Runs the strict frontmatter pass against an already-resolved absolute
313
+ * workspace root. Pure: reads only, never writes, never exits.
314
+ *
315
+ * @param root - Absolute path to the `.ai/strikethroo` directory.
316
+ * @returns One finding per proven frontmatter defect, each carrying a
317
+ * workspace-relative `path`.
318
+ */
319
+ function strictPass(root) {
320
+ const findings = [];
321
+ const plansRoot = path.join(root, PLANS_DIR);
322
+ for (const planDirName of listEntries(plansRoot, 'directory')) {
323
+ const planDir = path.join(plansRoot, planDirName);
324
+ for (const fileName of listEntries(planDir, 'file')) {
325
+ if (!PLAN_FILE_RE.test(fileName))
326
+ continue;
327
+ findings.push(...checkDocument(path.join(planDir, fileName), path.join(PLANS_DIR, planDirName, fileName), 'plan'));
328
+ }
329
+ const tasksDir = path.join(planDir, TASKS_DIR);
330
+ for (const fileName of listEntries(tasksDir, 'file')) {
331
+ if (!MARKDOWN_RE.test(fileName))
332
+ continue;
333
+ findings.push(...checkDocument(path.join(tasksDir, fileName), path.join(PLANS_DIR, planDirName, TASKS_DIR, fileName), 'task'));
334
+ }
335
+ }
336
+ return findings;
337
+ }
338
+ //# sourceMappingURL=strict-pass.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strict-pass.js","sourceRoot":"","sources":["../../src/validation/strict-pass.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * The findings model for `strikethroo validate`.
3
+ *
4
+ * There is deliberately no severity field. Plan 110's clarification 3 settled
5
+ * that every finding is an error, which collapses the exit rule to a single
6
+ * predicate over list emptiness (`findings.length > 0`). Re-introducing a
7
+ * severity axis is a scope change needing its own justification, not an
8
+ * implementation detail.
9
+ */
10
+ /** A single proven inconsistency in a workspace. */
11
+ export interface Finding {
12
+ /**
13
+ * Stable short identifier of the check that produced this finding, e.g.
14
+ * `metadata/files-map-absent`. Tests and downstream tooling assert on it, so
15
+ * it is a contract: rename only with the consumers.
16
+ */
17
+ check: string;
18
+ /** Human-readable description naming the specific defect. */
19
+ message: string;
20
+ /**
21
+ * Workspace-relative path the finding is about, using the separator recorded
22
+ * by its source. Omitted when the finding is not about a single file.
23
+ */
24
+ path?: string;
25
+ }
26
+ /** The complete result of validating one workspace. */
27
+ export interface ValidationResult {
28
+ findings: Finding[];
29
+ }
30
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/validation/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,oDAAoD;AACpD,MAAM,WAAW,OAAO;IACtB;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,uDAAuD;AACvD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB"}
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ /**
3
+ * The findings model for `strikethroo validate`.
4
+ *
5
+ * There is deliberately no severity field. Plan 110's clarification 3 settled
6
+ * that every finding is an error, which collapses the exit rule to a single
7
+ * predicate over list emptiness (`findings.length > 0`). Re-introducing a
8
+ * severity axis is a scope change needing its own justification, not an
9
+ * implementation detail.
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/validation/types.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * The pure validation core behind `strikethroo validate`.
3
+ *
4
+ * `validateWorkspace` takes an already-resolved absolute workspace root (the
5
+ * `.ai/strikethroo` directory itself) and returns a findings list. It performs
6
+ * no root discovery, writes nothing, prints nothing, and never terminates the
7
+ * process — the CLI shell owns resolution, reporting, and the exit code. That
8
+ * purity is what makes the same function reusable from CI and testable without
9
+ * spawning a process.
10
+ *
11
+ * The root resolver in `src/skill-scripts/shared/root.ts` must never be used
12
+ * here: it terminates the process on a schema-version mismatch, which would
13
+ * kill the validator on precisely the workspace it is most useful against.
14
+ * Schema skew is reported as a finding instead. The CLI shell resolves the root
15
+ * with `resolveWorkspaceRoot` from `src/serve/root.ts`, the same resolver
16
+ * `serve` uses.
17
+ *
18
+ * The orchestrator calls every check group and concatenates the results, so a
19
+ * check group is implemented by editing its own file — never this one.
20
+ */
21
+ import { ValidationResult } from './types';
22
+ /**
23
+ * Validates a workspace and returns every proven inconsistency.
24
+ *
25
+ * @param root - Absolute path to the `.ai/strikethroo` directory, already resolved.
26
+ * @returns All findings, in a deterministic order. Every finding is an error;
27
+ * there is no severity axis, so the caller's exit rule is
28
+ * `findings.length > 0`.
29
+ */
30
+ export declare function validateWorkspace(root: string): ValidationResult;
31
+ //# sourceMappingURL=workspace.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../src/validation/workspace.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAKH,OAAO,EAAW,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAcpD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAIhE"}
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ /**
3
+ * The pure validation core behind `strikethroo validate`.
4
+ *
5
+ * `validateWorkspace` takes an already-resolved absolute workspace root (the
6
+ * `.ai/strikethroo` directory itself) and returns a findings list. It performs
7
+ * no root discovery, writes nothing, prints nothing, and never terminates the
8
+ * process — the CLI shell owns resolution, reporting, and the exit code. That
9
+ * purity is what makes the same function reusable from CI and testable without
10
+ * spawning a process.
11
+ *
12
+ * The root resolver in `src/skill-scripts/shared/root.ts` must never be used
13
+ * here: it terminates the process on a schema-version mismatch, which would
14
+ * kill the validator on precisely the workspace it is most useful against.
15
+ * Schema skew is reported as a finding instead. The CLI shell resolves the root
16
+ * with `resolveWorkspaceRoot` from `src/serve/root.ts`, the same resolver
17
+ * `serve` uses.
18
+ *
19
+ * The orchestrator calls every check group and concatenates the results, so a
20
+ * check group is implemented by editing its own file — never this one.
21
+ */
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.validateWorkspace = validateWorkspace;
24
+ const metadata_gate_1 = require("./metadata-gate");
25
+ const strict_pass_1 = require("./strict-pass");
26
+ const graph_checks_1 = require("./graph-checks");
27
+ /**
28
+ * Total order over findings: `check`, then `path` (absent sorts first), then
29
+ * `message`.
30
+ *
31
+ * Directory enumeration order is filesystem-dependent and CI runs on Windows,
32
+ * so unsorted output would make both test assertions and reports unstable.
33
+ */
34
+ const compareFindings = (a, b) => a.check.localeCompare(b.check) ||
35
+ (a.path ?? '').localeCompare(b.path ?? '') ||
36
+ a.message.localeCompare(b.message);
37
+ /**
38
+ * Validates a workspace and returns every proven inconsistency.
39
+ *
40
+ * @param root - Absolute path to the `.ai/strikethroo` directory, already resolved.
41
+ * @returns All findings, in a deterministic order. Every finding is an error;
42
+ * there is no severity axis, so the caller's exit rule is
43
+ * `findings.length > 0`.
44
+ */
45
+ function validateWorkspace(root) {
46
+ const findings = [...(0, metadata_gate_1.metadataGate)(root), ...(0, strict_pass_1.strictPass)(root), ...(0, graph_checks_1.graphChecks)(root)];
47
+ return { findings: findings.sort(compareFindings) };
48
+ }
49
+ //# sourceMappingURL=workspace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../src/validation/workspace.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;GAmBG;;AA2BH,8CAIC;AA7BD,mDAA+C;AAC/C,+CAA2C;AAC3C,iDAA6C;AAG7C;;;;;;GAMG;AACH,MAAM,eAAe,GAAG,CAAC,CAAU,EAAE,CAAU,EAAU,EAAE,CACzD,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC;IAC9B,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;IAC1C,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;AAErC;;;;;;;GAOG;AACH,SAAgB,iBAAiB,CAAC,IAAY;IAC5C,MAAM,QAAQ,GAAc,CAAC,GAAG,IAAA,4BAAY,EAAC,IAAI,CAAC,EAAE,GAAG,IAAA,wBAAU,EAAC,IAAI,CAAC,EAAE,GAAG,IAAA,0BAAW,EAAC,IAAI,CAAC,CAAC,CAAC;IAE/F,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC;AACtD,CAAC"}
@@ -1 +1 @@
1
- import{bk as ln,aN as an,H as k,b7 as w,F as N,ag as un,V as g,bc as tn,b8 as C,aH as _,c as rn,m as o,aF as on,j as sn,d as fn}from"./mermaid.core-Cn0e4l6V.js";function cn(l){return l.innerRadius}function gn(l){return l.outerRadius}function yn(l){return l.startAngle}function dn(l){return l.endAngle}function mn(l){return l&&l.padAngle}function pn(l,h,j,F,v,A,O,a){var q=j-l,i=F-h,n=O-v,d=a-A,u=d*q-n*i;if(!(u*u<g))return u=(n*(h-A)-d*(l-v))/u,[l+u*q,h+u*i]}function Q(l,h,j,F,v,A,O){var a=l-j,q=h-F,i=(O?A:-A)/C(a*a+q*q),n=i*q,d=-i*a,u=l+n,s=h+d,f=j+n,c=F+d,S=(u+f)/2,t=(s+c)/2,m=f-u,y=c-s,R=m*m+y*y,T=v-A,P=u*c-f*s,D=(y<0?-1:1)*C(on(0,T*T*R-P*P)),E=(P*y-m*D)/R,I=(-P*m-y*D)/R,b=(P*y+m*D)/R,p=(-P*m+y*D)/R,x=E-S,e=I-t,r=b-S,V=p-t;return x*x+e*e>r*r+V*V&&(E=b,I=p),{cx:E,cy:I,x01:-n,y01:-d,x11:E*(v/T-1),y11:I*(v/T-1)}}function hn(){var l=cn,h=gn,j=N(0),F=null,v=yn,A=dn,O=mn,a=null,q=ln(i);function i(){var n,d,u=+l.apply(this,arguments),s=+h.apply(this,arguments),f=v.apply(this,arguments)-un,c=A.apply(this,arguments)-un,S=rn(c-f),t=c>f;if(a||(a=n=q()),s<u&&(d=s,s=u,u=d),!(s>g))a.moveTo(0,0);else if(S>tn-g)a.moveTo(s*k(f),s*w(f)),a.arc(0,0,s,f,c,!t),u>g&&(a.moveTo(u*k(c),u*w(c)),a.arc(0,0,u,c,f,t));else{var m=f,y=c,R=f,T=c,P=S,D=S,E=O.apply(this,arguments)/2,I=E>g&&(F?+F.apply(this,arguments):C(u*u+s*s)),b=_(rn(s-u)/2,+j.apply(this,arguments)),p=b,x=b,e,r;if(I>g){var V=sn(I/u*w(E)),G=sn(I/s*w(E));(P-=V*2)>g?(V*=t?1:-1,R+=V,T-=V):(P=0,R=T=(f+c)/2),(D-=G*2)>g?(G*=t?1:-1,m+=G,y-=G):(D=0,m=y=(f+c)/2)}var z=s*k(m),B=s*w(m),J=u*k(T),K=u*w(T);if(b>g){var L=s*k(y),M=s*w(y),U=u*k(R),W=u*w(R),H;if(S<an)if(H=pn(z,B,U,W,L,M,J,K)){var X=z-H[0],Y=B-H[1],Z=L-H[0],$=M-H[1],nn=1/w(fn((X*Z+Y*$)/(C(X*X+Y*Y)*C(Z*Z+$*$)))/2),en=C(H[0]*H[0]+H[1]*H[1]);p=_(b,(u-en)/(nn-1)),x=_(b,(s-en)/(nn+1))}else p=x=0}D>g?x>g?(e=Q(U,W,z,B,s,x,t),r=Q(L,M,J,K,s,x,t),a.moveTo(e.cx+e.x01,e.cy+e.y01),x<b?a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,s,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),!t),a.arc(r.cx,r.cy,x,o(r.y11,r.x11),o(r.y01,r.x01),!t))):(a.moveTo(z,B),a.arc(0,0,s,m,y,!t)):a.moveTo(z,B),!(u>g)||!(P>g)?a.lineTo(J,K):p>g?(e=Q(J,K,L,M,u,-p,t),r=Q(z,B,U,W,u,-p,t),a.lineTo(e.cx+e.x01,e.cy+e.y01),p<b?a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,u,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),t),a.arc(r.cx,r.cy,p,o(r.y11,r.x11),o(r.y01,r.x01),!t))):a.arc(0,0,u,T,R,t)}if(a.closePath(),n)return a=null,n+""||null}return i.centroid=function(){var n=(+l.apply(this,arguments)+ +h.apply(this,arguments))/2,d=(+v.apply(this,arguments)+ +A.apply(this,arguments))/2-an/2;return[k(d)*n,w(d)*n]},i.innerRadius=function(n){return arguments.length?(l=typeof n=="function"?n:N(+n),i):l},i.outerRadius=function(n){return arguments.length?(h=typeof n=="function"?n:N(+n),i):h},i.cornerRadius=function(n){return arguments.length?(j=typeof n=="function"?n:N(+n),i):j},i.padRadius=function(n){return arguments.length?(F=n==null?null:typeof n=="function"?n:N(+n),i):F},i.startAngle=function(n){return arguments.length?(v=typeof n=="function"?n:N(+n),i):v},i.endAngle=function(n){return arguments.length?(A=typeof n=="function"?n:N(+n),i):A},i.padAngle=function(n){return arguments.length?(O=typeof n=="function"?n:N(+n),i):O},i.context=function(n){return arguments.length?(a=n??null,i):a},i}export{hn as d};
1
+ import{bk as ln,aN as an,H as k,b7 as w,F as N,ag as un,V as g,bc as tn,b8 as C,aH as _,c as rn,m as o,aF as on,j as sn,d as fn}from"./mermaid.core-C6KsMc78.js";function cn(l){return l.innerRadius}function gn(l){return l.outerRadius}function yn(l){return l.startAngle}function dn(l){return l.endAngle}function mn(l){return l&&l.padAngle}function pn(l,h,j,F,v,A,O,a){var q=j-l,i=F-h,n=O-v,d=a-A,u=d*q-n*i;if(!(u*u<g))return u=(n*(h-A)-d*(l-v))/u,[l+u*q,h+u*i]}function Q(l,h,j,F,v,A,O){var a=l-j,q=h-F,i=(O?A:-A)/C(a*a+q*q),n=i*q,d=-i*a,u=l+n,s=h+d,f=j+n,c=F+d,S=(u+f)/2,t=(s+c)/2,m=f-u,y=c-s,R=m*m+y*y,T=v-A,P=u*c-f*s,D=(y<0?-1:1)*C(on(0,T*T*R-P*P)),E=(P*y-m*D)/R,I=(-P*m-y*D)/R,b=(P*y+m*D)/R,p=(-P*m+y*D)/R,x=E-S,e=I-t,r=b-S,V=p-t;return x*x+e*e>r*r+V*V&&(E=b,I=p),{cx:E,cy:I,x01:-n,y01:-d,x11:E*(v/T-1),y11:I*(v/T-1)}}function hn(){var l=cn,h=gn,j=N(0),F=null,v=yn,A=dn,O=mn,a=null,q=ln(i);function i(){var n,d,u=+l.apply(this,arguments),s=+h.apply(this,arguments),f=v.apply(this,arguments)-un,c=A.apply(this,arguments)-un,S=rn(c-f),t=c>f;if(a||(a=n=q()),s<u&&(d=s,s=u,u=d),!(s>g))a.moveTo(0,0);else if(S>tn-g)a.moveTo(s*k(f),s*w(f)),a.arc(0,0,s,f,c,!t),u>g&&(a.moveTo(u*k(c),u*w(c)),a.arc(0,0,u,c,f,t));else{var m=f,y=c,R=f,T=c,P=S,D=S,E=O.apply(this,arguments)/2,I=E>g&&(F?+F.apply(this,arguments):C(u*u+s*s)),b=_(rn(s-u)/2,+j.apply(this,arguments)),p=b,x=b,e,r;if(I>g){var V=sn(I/u*w(E)),G=sn(I/s*w(E));(P-=V*2)>g?(V*=t?1:-1,R+=V,T-=V):(P=0,R=T=(f+c)/2),(D-=G*2)>g?(G*=t?1:-1,m+=G,y-=G):(D=0,m=y=(f+c)/2)}var z=s*k(m),B=s*w(m),J=u*k(T),K=u*w(T);if(b>g){var L=s*k(y),M=s*w(y),U=u*k(R),W=u*w(R),H;if(S<an)if(H=pn(z,B,U,W,L,M,J,K)){var X=z-H[0],Y=B-H[1],Z=L-H[0],$=M-H[1],nn=1/w(fn((X*Z+Y*$)/(C(X*X+Y*Y)*C(Z*Z+$*$)))/2),en=C(H[0]*H[0]+H[1]*H[1]);p=_(b,(u-en)/(nn-1)),x=_(b,(s-en)/(nn+1))}else p=x=0}D>g?x>g?(e=Q(U,W,z,B,s,x,t),r=Q(L,M,J,K,s,x,t),a.moveTo(e.cx+e.x01,e.cy+e.y01),x<b?a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,s,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),!t),a.arc(r.cx,r.cy,x,o(r.y11,r.x11),o(r.y01,r.x01),!t))):(a.moveTo(z,B),a.arc(0,0,s,m,y,!t)):a.moveTo(z,B),!(u>g)||!(P>g)?a.lineTo(J,K):p>g?(e=Q(J,K,L,M,u,-p,t),r=Q(z,B,U,W,u,-p,t),a.lineTo(e.cx+e.x01,e.cy+e.y01),p<b?a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,u,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),t),a.arc(r.cx,r.cy,p,o(r.y11,r.x11),o(r.y01,r.x01),!t))):a.arc(0,0,u,T,R,t)}if(a.closePath(),n)return a=null,n+""||null}return i.centroid=function(){var n=(+l.apply(this,arguments)+ +h.apply(this,arguments))/2,d=(+v.apply(this,arguments)+ +A.apply(this,arguments))/2-an/2;return[k(d)*n,w(d)*n]},i.innerRadius=function(n){return arguments.length?(l=typeof n=="function"?n:N(+n),i):l},i.outerRadius=function(n){return arguments.length?(h=typeof n=="function"?n:N(+n),i):h},i.cornerRadius=function(n){return arguments.length?(j=typeof n=="function"?n:N(+n),i):j},i.padRadius=function(n){return arguments.length?(F=n==null?null:typeof n=="function"?n:N(+n),i):F},i.startAngle=function(n){return arguments.length?(v=typeof n=="function"?n:N(+n),i):v},i.endAngle=function(n){return arguments.length?(A=typeof n=="function"?n:N(+n),i):A},i.padAngle=function(n){return arguments.length?(O=typeof n=="function"?n:N(+n),i):O},i.context=function(n){return arguments.length?(a=n??null,i):a},i}export{hn as d};