strikethroo 3.0.1 → 3.1.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 (137) hide show
  1. package/README.md +20 -5
  2. package/dist/cli.js +19 -128
  3. package/dist/cli.js.map +1 -1
  4. package/dist/serve/archive.d.ts +43 -0
  5. package/dist/serve/archive.d.ts.map +1 -0
  6. package/dist/serve/archive.js +124 -0
  7. package/dist/serve/archive.js.map +1 -0
  8. package/dist/serve/derivation.d.ts +78 -0
  9. package/dist/serve/derivation.d.ts.map +1 -0
  10. package/dist/serve/derivation.js +237 -0
  11. package/dist/serve/derivation.js.map +1 -0
  12. package/dist/serve/events.d.ts +41 -0
  13. package/dist/serve/events.d.ts.map +1 -0
  14. package/dist/serve/events.js +91 -0
  15. package/dist/serve/events.js.map +1 -0
  16. package/dist/serve/markdown.d.ts +75 -0
  17. package/dist/serve/markdown.d.ts.map +1 -0
  18. package/dist/serve/markdown.js +221 -0
  19. package/dist/serve/markdown.js.map +1 -0
  20. package/dist/serve/root.d.ts +48 -0
  21. package/dist/serve/root.d.ts.map +1 -0
  22. package/dist/serve/root.js +110 -0
  23. package/dist/serve/root.js.map +1 -0
  24. package/dist/serve/self-review.d.ts +70 -0
  25. package/dist/serve/self-review.d.ts.map +1 -0
  26. package/dist/serve/self-review.js +164 -0
  27. package/dist/serve/self-review.js.map +1 -0
  28. package/dist/serve/server.d.ts +70 -0
  29. package/dist/serve/server.d.ts.map +1 -0
  30. package/dist/serve/server.js +368 -0
  31. package/dist/serve/server.js.map +1 -0
  32. package/dist/serve/watcher.d.ts +32 -0
  33. package/dist/serve/watcher.d.ts.map +1 -0
  34. package/dist/serve/watcher.js +99 -0
  35. package/dist/serve/watcher.js.map +1 -0
  36. package/dist/serve/workspace-model.d.ts +80 -0
  37. package/dist/serve/workspace-model.d.ts.map +1 -0
  38. package/dist/serve/workspace-model.js +176 -0
  39. package/dist/serve/workspace-model.js.map +1 -0
  40. package/dist/skill-scripts/shared/frontmatter.d.ts +2 -0
  41. package/dist/skill-scripts/shared/frontmatter.d.ts.map +1 -0
  42. package/dist/skill-scripts/shared/frontmatter.js +37 -0
  43. package/dist/skill-scripts/shared/frontmatter.js.map +1 -0
  44. package/dist/skill-scripts/shared/plan-scan.d.ts +10 -0
  45. package/dist/skill-scripts/shared/plan-scan.d.ts.map +1 -0
  46. package/dist/skill-scripts/shared/plan-scan.js +91 -0
  47. package/dist/skill-scripts/shared/plan-scan.js.map +1 -0
  48. package/dist/skill-scripts/shared/root.d.ts +2 -0
  49. package/dist/skill-scripts/shared/root.d.ts.map +1 -0
  50. package/dist/skill-scripts/shared/root.js +104 -0
  51. package/dist/skill-scripts/shared/root.js.map +1 -0
  52. package/dist-web/assets/Fraunces-Italic-VariableFont_SOFT_WONK_opsz_wght-CuXX_kIb.ttf +0 -0
  53. package/dist-web/assets/Fraunces-VariableFont_SOFT_WONK_opsz_wght-DLWfSgHL.ttf +0 -0
  54. package/dist-web/assets/Outfit-VariableFont_wght-B6lQlNBM.ttf +0 -0
  55. package/dist-web/assets/SFMonoBold-DXHgGUoo.otf +0 -0
  56. package/dist-web/assets/SFMonoBoldItalic-CdGEImHi.otf +0 -0
  57. package/dist-web/assets/SFMonoHeavy-DL92f7rT.otf +0 -0
  58. package/dist-web/assets/SFMonoHeavyItalic-DnE00LFH.otf +0 -0
  59. package/dist-web/assets/SFMonoLight-CaMC1gg-.otf +0 -0
  60. package/dist-web/assets/SFMonoLightItalic-DG3Owzn7.otf +0 -0
  61. package/dist-web/assets/SFMonoMedium-ypRDCKSo.otf +0 -0
  62. package/dist-web/assets/SFMonoMediumItalic-DkJk-c-x.otf +0 -0
  63. package/dist-web/assets/SFMonoRegular-77Uh1IPk.otf +0 -0
  64. package/dist-web/assets/SFMonoRegularItalic-Cn01bACm.otf +0 -0
  65. package/dist-web/assets/SFMonoSemibold-CvhtzcyM.otf +0 -0
  66. package/dist-web/assets/SFMonoSemiboldItalic-D75NMH13.otf +0 -0
  67. package/dist-web/assets/arc-BWWIDtzc.js +1 -0
  68. package/dist-web/assets/architectureDiagram-3BPJPVTR-DeYxmq4e.js +36 -0
  69. package/dist-web/assets/blockDiagram-GPEHLZMM-DR85OQGh.js +132 -0
  70. package/dist-web/assets/c4Diagram-AAUBKEIU-B5p4vlmU.js +10 -0
  71. package/dist-web/assets/channel-BaP08-ph.js +1 -0
  72. package/dist-web/assets/chunk-2J33WTMH-duXs_Bbu.js +1 -0
  73. package/dist-web/assets/chunk-4BX2VUAB-DR1619KE.js +1 -0
  74. package/dist-web/assets/chunk-55IACEB6-UacLKom4.js +1 -0
  75. package/dist-web/assets/chunk-727SXJPM-DW2a_NI7.js +206 -0
  76. package/dist-web/assets/chunk-AQP2D5EJ-Bu5jn-_L.js +231 -0
  77. package/dist-web/assets/chunk-FMBD7UC4-eJsExyuh.js +15 -0
  78. package/dist-web/assets/chunk-ND2GUHAM-BqKmGd94.js +1 -0
  79. package/dist-web/assets/chunk-QZHKN3VN--ynTiOCz.js +1 -0
  80. package/dist-web/assets/classDiagram-4FO5ZUOK-V5dHIfdR.js +1 -0
  81. package/dist-web/assets/classDiagram-v2-Q7XG4LA2-V5dHIfdR.js +1 -0
  82. package/dist-web/assets/cose-bilkent-S5V4N54A-Ccz3r4S1.js +1 -0
  83. package/dist-web/assets/cytoscape.esm-BHYC38rz.js +331 -0
  84. package/dist-web/assets/dagre-BM42HDAG-BESSLbjB.js +4 -0
  85. package/dist-web/assets/defaultLocale-CrowFXzY.js +1 -0
  86. package/dist-web/assets/diagram-2AECGRRQ-BB5cYRbY.js +43 -0
  87. package/dist-web/assets/diagram-5GNKFQAL-3lmcZFDS.js +10 -0
  88. package/dist-web/assets/diagram-KO2AKTUF-DUMp202y.js +3 -0
  89. package/dist-web/assets/diagram-LMA3HP47-DCGXhLm1.js +24 -0
  90. package/dist-web/assets/diagram-OG6HWLK6-D247gj5y.js +24 -0
  91. package/dist-web/assets/erDiagram-TEJ5UH35-GI1vhsr2.js +85 -0
  92. package/dist-web/assets/flowDiagram-I6XJVG4X-iqUPWZuf.js +162 -0
  93. package/dist-web/assets/ganttDiagram-6RSMTGT7-DfG1X-Pe.js +292 -0
  94. package/dist-web/assets/gitGraphDiagram-PVQCEYII-B2MrV3y6.js +106 -0
  95. package/dist-web/assets/graph-Dqkl27Ch.js +1 -0
  96. package/dist-web/assets/index-Bm5I46eC.css +1 -0
  97. package/dist-web/assets/index-CvfrFREc.js +125 -0
  98. package/dist-web/assets/infoDiagram-5YYISTIA-DGqU5K4a.js +2 -0
  99. package/dist-web/assets/init-Gi6I4Gst.js +1 -0
  100. package/dist-web/assets/ishikawaDiagram-YF4QCWOH-DrMH3jRf.js +70 -0
  101. package/dist-web/assets/journeyDiagram-JHISSGLW-BH4wiwsd.js +139 -0
  102. package/dist-web/assets/kanban-definition-UN3LZRKU-DEV_dEgE.js +89 -0
  103. package/dist-web/assets/katex-C5jXJg4s.js +257 -0
  104. package/dist-web/assets/layout-DO9UvE1P.js +1 -0
  105. package/dist-web/assets/linear-D81nAxzR.js +1 -0
  106. package/dist-web/assets/mermaid.core-BaP7clO2.js +307 -0
  107. package/dist-web/assets/mindmap-definition-RKZ34NQL-DM4iAZ4M.js +96 -0
  108. package/dist-web/assets/ordinal-Cboi1Yqb.js +1 -0
  109. package/dist-web/assets/pieDiagram-4H26LBE5-DinO6q5i.js +30 -0
  110. package/dist-web/assets/quadrantDiagram-W4KKPZXB-CYvCm7U6.js +7 -0
  111. package/dist-web/assets/requirementDiagram-4Y6WPE33-DXfPIJ5m.js +84 -0
  112. package/dist-web/assets/sankeyDiagram-5OEKKPKP-CfovFay4.js +40 -0
  113. package/dist-web/assets/sequenceDiagram-3UESZ5HK-BboUGmEB.js +162 -0
  114. package/dist-web/assets/stateDiagram-AJRCARHV-CsB2FtnQ.js +1 -0
  115. package/dist-web/assets/stateDiagram-v2-BHNVJYJU-D0D_KesS.js +1 -0
  116. package/dist-web/assets/timeline-definition-PNZ67QCA-Cma1yLcq.js +120 -0
  117. package/dist-web/assets/vennDiagram-CIIHVFJN-DhFGEgCQ.js +34 -0
  118. package/dist-web/assets/wardley-L42UT6IY-DYkCeynG.js +173 -0
  119. package/dist-web/assets/wardleyDiagram-YWT4CUSO-jogT61m_.js +78 -0
  120. package/dist-web/assets/xychartDiagram-2RQKCTM6-Cn3W0E3s.js +7 -0
  121. package/dist-web/favicon.svg +13 -0
  122. package/dist-web/index.html +30 -0
  123. package/package.json +28 -8
  124. package/templates/harness/skills/st-full-workflow/SKILL.md +2 -2
  125. package/templates/harness/skills/st-generate-tasks/SKILL.md +2 -2
  126. package/dist/plan-utils.d.ts +0 -35
  127. package/dist/plan-utils.d.ts.map +0 -1
  128. package/dist/plan-utils.js +0 -123
  129. package/dist/plan-utils.js.map +0 -1
  130. package/dist/plan.d.ts +0 -27
  131. package/dist/plan.d.ts.map +0 -1
  132. package/dist/plan.js +0 -279
  133. package/dist/plan.js.map +0 -1
  134. package/dist/status.d.ts +0 -73
  135. package/dist/status.d.ts.map +0 -1
  136. package/dist/status.js +0 -375
  137. package/dist/status.js.map +0 -1
@@ -0,0 +1,221 @@
1
+ "use strict";
2
+ /**
3
+ * Pure, dependency-light markdown parsing primitives for the serve data layer.
4
+ *
5
+ * These functions operate on already-read string content. File reading itself
6
+ * belongs to the task scanner and the model assembler. Everything here is
7
+ * synchronous, read-only, and side-effect-free: no `fs`, no network, no writes.
8
+ *
9
+ * The existing `src/skill-scripts/shared/frontmatter.ts` only recovers the
10
+ * numeric `id`; it is intentionally not forked. This module provides a richer
11
+ * frontmatter reader the UI needs (summary, created, status, group,
12
+ * dependencies[], skills[]).
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.extractTitle = exports.extractMermaidBlocks = exports.sectionBody = exports.extractBody = exports.parseFrontmatter = void 0;
16
+ /** Anchors the leading `---`-delimited frontmatter block (same as frontmatter.ts). */
17
+ const FRONTMATTER_RE = /^---\s*\r?\n([\s\S]*?)\r?\n---/;
18
+ const stripQuotes = (value) => {
19
+ const trimmed = value.trim();
20
+ if (trimmed.length >= 2) {
21
+ const first = trimmed[0];
22
+ const last = trimmed[trimmed.length - 1];
23
+ if ((first === '"' && last === '"') || (first === "'" && last === "'")) {
24
+ return trimmed.slice(1, -1);
25
+ }
26
+ }
27
+ return trimmed;
28
+ };
29
+ /** Strips a trailing unquoted YAML comment (`# ...`). Quoted scalars are left intact. */
30
+ const stripComment = (value) => {
31
+ const trimmed = value.trim();
32
+ if (trimmed.startsWith('"') || trimmed.startsWith("'"))
33
+ return trimmed;
34
+ const hashIndex = trimmed.indexOf('#');
35
+ return hashIndex === -1 ? trimmed : trimmed.slice(0, hashIndex).trim();
36
+ };
37
+ /** Parses a bracketed inline array like `[a, b]` or `[]` into trimmed, unquoted items. */
38
+ const parseInlineArray = (value) => {
39
+ const inner = value.slice(1, -1).trim();
40
+ if (inner.length === 0)
41
+ return [];
42
+ return inner
43
+ .split(',')
44
+ .map(item => stripQuotes(item))
45
+ .filter(item => item.length > 0);
46
+ };
47
+ /** Coerces a dependency item to a number when it is purely numeric, else leaves it as-is. */
48
+ const coerceDependency = (item) => {
49
+ if (/^-?\d+$/.test(item)) {
50
+ return parseInt(item, 10);
51
+ }
52
+ return item;
53
+ };
54
+ /**
55
+ * Reads the leading frontmatter block into typed fields. Never throws: malformed
56
+ * lines are skipped and absent keys fall back to defaults (undefined scalars,
57
+ * empty arrays).
58
+ */
59
+ const parseFrontmatter = (content) => {
60
+ const result = {
61
+ dependencies: [],
62
+ skills: [],
63
+ extra: {},
64
+ };
65
+ const match = content.match(FRONTMATTER_RE);
66
+ if (!match || match[1] === undefined)
67
+ return result;
68
+ const lines = match[1].split(/\r?\n/);
69
+ const listFields = new Set(['dependencies', 'skills']);
70
+ for (let i = 0; i < lines.length; i++) {
71
+ const line = lines[i];
72
+ if (line === undefined)
73
+ continue;
74
+ // Skip blank lines and dashed list items (they are consumed by their owning key).
75
+ if (line.trim().length === 0)
76
+ continue;
77
+ if (/^\s*-\s+/.test(line))
78
+ continue;
79
+ const colonIndex = line.indexOf(':');
80
+ if (colonIndex === -1)
81
+ continue;
82
+ const key = line.slice(0, colonIndex).trim();
83
+ const rawValue = line.slice(colonIndex + 1);
84
+ if (key.length === 0)
85
+ continue;
86
+ if (listFields.has(key)) {
87
+ const value = stripComment(rawValue);
88
+ let items;
89
+ if (value.startsWith('[') && value.endsWith(']')) {
90
+ items = parseInlineArray(value);
91
+ }
92
+ else if (value.length > 0) {
93
+ // A scalar on the same line that is not a bracketed array: treat as a
94
+ // single-item list (lenient).
95
+ items = [stripQuotes(value)];
96
+ }
97
+ else {
98
+ // Empty value: collect subsequent dashed-list items until indentation ends.
99
+ items = [];
100
+ let j = i + 1;
101
+ while (j < lines.length) {
102
+ const next = lines[j];
103
+ if (next === undefined)
104
+ break;
105
+ const dashMatch = next.match(/^\s*-\s+(.*)$/);
106
+ if (!dashMatch || dashMatch[1] === undefined)
107
+ break;
108
+ items.push(stripQuotes(stripComment(dashMatch[1])));
109
+ j++;
110
+ }
111
+ i = j - 1; // advance the outer cursor past the consumed items
112
+ }
113
+ if (key === 'dependencies') {
114
+ result.dependencies = items.map(coerceDependency);
115
+ }
116
+ else {
117
+ result.skills = items;
118
+ }
119
+ continue;
120
+ }
121
+ const value = stripQuotes(stripComment(rawValue));
122
+ switch (key) {
123
+ case 'id': {
124
+ const parsed = parseInt(value, 10);
125
+ if (!Number.isNaN(parsed))
126
+ result.id = parsed;
127
+ break;
128
+ }
129
+ case 'summary':
130
+ result.summary = value;
131
+ break;
132
+ case 'created':
133
+ result.created = value;
134
+ break;
135
+ case 'status':
136
+ result.status = value;
137
+ break;
138
+ case 'group':
139
+ result.group = value;
140
+ break;
141
+ default:
142
+ result.extra[key] = value;
143
+ break;
144
+ }
145
+ }
146
+ return result;
147
+ };
148
+ exports.parseFrontmatter = parseFrontmatter;
149
+ /** Returns the body: everything after the closing frontmatter `---`, or the whole content. */
150
+ const extractBody = (content) => {
151
+ const match = content.match(FRONTMATTER_RE);
152
+ if (!match)
153
+ return content;
154
+ return content.slice(match.index + match[0].length).replace(/^\r?\n/, '');
155
+ };
156
+ exports.extractBody = extractBody;
157
+ /**
158
+ * Splits a markdown body into the verbatim `rawBody` plus an ordered list of
159
+ * `## ` sections addressable by heading text. Section access is additive:
160
+ * callers may always fall back to `rawBody`.
161
+ */
162
+ const sectionBody = (body) => {
163
+ const sections = [];
164
+ const headingRe = /^##[ \t]+(.+?)[ \t]*$/gm;
165
+ const matches = [];
166
+ let m;
167
+ while ((m = headingRe.exec(body)) !== null) {
168
+ const heading = (m[1] ?? '').trim();
169
+ matches.push({
170
+ heading,
171
+ index: m.index,
172
+ afterHeading: m.index + m[0].length,
173
+ });
174
+ }
175
+ for (let i = 0; i < matches.length; i++) {
176
+ const current = matches[i];
177
+ const next = matches[i + 1];
178
+ const end = next ? next.index : body.length;
179
+ const content = body.slice(current.afterHeading, end).replace(/^\r?\n/, '');
180
+ sections.push({
181
+ heading: current.heading,
182
+ content,
183
+ start: current.index,
184
+ end,
185
+ });
186
+ }
187
+ return { rawBody: body, sections };
188
+ };
189
+ exports.sectionBody = sectionBody;
190
+ const ARCH_APPROACH_RE = /architectural\s+approach/i;
191
+ /**
192
+ * Extracts every fenced ```mermaid block's raw source from a body. Blocks whose
193
+ * position falls within an "Architectural Approach" section are flagged. Plans
194
+ * with no mermaid block yield an empty list (never an error).
195
+ */
196
+ const extractMermaidBlocks = (body) => {
197
+ const blocks = [];
198
+ const { sections } = (0, exports.sectionBody)(body);
199
+ const archSpans = sections
200
+ .filter(s => ARCH_APPROACH_RE.test(s.heading))
201
+ .map(s => ({ start: s.start, end: s.end }));
202
+ // Match a fence opening with ```mermaid (optional trailing whitespace) and
203
+ // closing with a line of three backticks.
204
+ const fenceRe = /^[ \t]*```mermaid[ \t]*\r?\n([\s\S]*?)\r?\n[ \t]*```[ \t]*$/gm;
205
+ let m;
206
+ while ((m = fenceRe.exec(body)) !== null) {
207
+ const source = m[1] ?? '';
208
+ const offset = m.index;
209
+ const isArch = archSpans.some(span => offset >= span.start && offset < span.end);
210
+ blocks.push({ source, isArchitecturalApproach: isArch });
211
+ }
212
+ return blocks;
213
+ };
214
+ exports.extractMermaidBlocks = extractMermaidBlocks;
215
+ /** Returns the text of the first `# ` (level-1) heading in a body, or undefined. */
216
+ const extractTitle = (body) => {
217
+ const match = body.match(/^#[ \t]+(.+?)[ \t]*$/m);
218
+ return match && match[1] !== undefined ? match[1].trim() : undefined;
219
+ };
220
+ exports.extractTitle = extractTitle;
221
+ //# sourceMappingURL=markdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/serve/markdown.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Self-contained workspace root resolver for `npx strikethroo serve`.
3
+ *
4
+ * Determines which initialized `.ai/strikethroo/` workspace the `serve` command
5
+ * should host. Discovery keys on the presence of
6
+ * `<root>/.ai/strikethroo/.init-metadata.json`, the same contract the skills use,
7
+ * but the logic is reimplemented here with Node built-ins only.
8
+ *
9
+ * This deliberately does NOT import `findStrikethrooRoot` from
10
+ * `src/skill-scripts/shared/`: that subtree carries the skill-bundle build
11
+ * contract (esbuild, schema-version `define`) and is excluded from the main `tsc`
12
+ * pipeline. Crossing that boundary would drag build-time concerns into the
13
+ * runtime path. The discovery walk is short and cheap to keep self-contained.
14
+ */
15
+ /**
16
+ * Successful resolution. `root` is the absolute path of the `.ai/strikethroo`
17
+ * directory itself (NOT the repository root) so it can be passed directly to the
18
+ * workspace model's `root` argument, whose readers join `plans`/`archive`/`config`
19
+ * onto it.
20
+ */
21
+ export interface ResolvedRoot {
22
+ root: string;
23
+ }
24
+ /** Failure result carrying a user-facing message. Never a stack trace. */
25
+ export interface ResolveError {
26
+ error: string;
27
+ }
28
+ export type ResolveResult = ResolvedRoot | ResolveError;
29
+ /** Narrows a {@link ResolveResult} to its error variant. */
30
+ export declare const isResolveError: (result: ResolveResult) => result is ResolveError;
31
+ /**
32
+ * Resolves the `.ai/strikethroo` workspace directory to host.
33
+ *
34
+ * - When `options.workspace` is given, it is treated as a project directory; the
35
+ * resolver validates that `<workspace>/.ai/strikethroo/.init-metadata.json`
36
+ * exists and returns that `.ai/strikethroo` directory.
37
+ * - Otherwise it walks upward from `options.cwd` (default `process.cwd()`),
38
+ * testing each ancestor for `.ai/strikethroo/.init-metadata.json`.
39
+ *
40
+ * On failure it returns an `{ error }` shape with a clear, user-facing message
41
+ * so the command layer can print it and exit non-zero. It never throws an
42
+ * unhandled error for the "not found" case.
43
+ */
44
+ export declare const resolveWorkspaceRoot: (options?: {
45
+ workspace?: string;
46
+ cwd?: string;
47
+ }) => ResolveResult;
48
+ //# sourceMappingURL=root.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"root.d.ts","sourceRoot":"","sources":["../../src/serve/root.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,0EAA0E;AAC1E,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,aAAa,GAAG,YAAY,GAAG,YAAY,CAAC;AAExD,4DAA4D;AAC5D,eAAO,MAAM,cAAc,GAAI,QAAQ,aAAa,KAAG,MAAM,IAAI,YACnB,CAAC;AAe/C;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,oBAAoB,GAC/B,UAAS;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,KACjD,aA6BF,CAAC"}
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ /**
3
+ * Self-contained workspace root resolver for `npx strikethroo serve`.
4
+ *
5
+ * Determines which initialized `.ai/strikethroo/` workspace the `serve` command
6
+ * should host. Discovery keys on the presence of
7
+ * `<root>/.ai/strikethroo/.init-metadata.json`, the same contract the skills use,
8
+ * but the logic is reimplemented here with Node built-ins only.
9
+ *
10
+ * This deliberately does NOT import `findStrikethrooRoot` from
11
+ * `src/skill-scripts/shared/`: that subtree carries the skill-bundle build
12
+ * contract (esbuild, schema-version `define`) and is excluded from the main `tsc`
13
+ * pipeline. Crossing that boundary would drag build-time concerns into the
14
+ * runtime path. The discovery walk is short and cheap to keep self-contained.
15
+ */
16
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ var desc = Object.getOwnPropertyDescriptor(m, k);
19
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
20
+ desc = { enumerable: true, get: function() { return m[k]; } };
21
+ }
22
+ Object.defineProperty(o, k2, desc);
23
+ }) : (function(o, m, k, k2) {
24
+ if (k2 === undefined) k2 = k;
25
+ o[k2] = m[k];
26
+ }));
27
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
28
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
29
+ }) : function(o, v) {
30
+ o["default"] = v;
31
+ });
32
+ var __importStar = (this && this.__importStar) || (function () {
33
+ var ownKeys = function(o) {
34
+ ownKeys = Object.getOwnPropertyNames || function (o) {
35
+ var ar = [];
36
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
37
+ return ar;
38
+ };
39
+ return ownKeys(o);
40
+ };
41
+ return function (mod) {
42
+ if (mod && mod.__esModule) return mod;
43
+ var result = {};
44
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
45
+ __setModuleDefault(result, mod);
46
+ return result;
47
+ };
48
+ })();
49
+ Object.defineProperty(exports, "__esModule", { value: true });
50
+ exports.resolveWorkspaceRoot = exports.isResolveError = void 0;
51
+ const fs = __importStar(require("fs"));
52
+ const path = __importStar(require("path"));
53
+ /** Narrows a {@link ResolveResult} to its error variant. */
54
+ const isResolveError = (result) => result.error !== undefined;
55
+ exports.isResolveError = isResolveError;
56
+ const INIT_MESSAGE = 'Run `npx strikethroo init` first.';
57
+ /** True when `<dir>/.init-metadata.json` exists and `<dir>` is a directory. */
58
+ const isInitializedStrikethrooDir = (strikethrooDir) => {
59
+ try {
60
+ if (!fs.statSync(strikethrooDir).isDirectory())
61
+ return false;
62
+ const metadataPath = path.join(strikethrooDir, '.init-metadata.json');
63
+ return fs.statSync(metadataPath).isFile();
64
+ }
65
+ catch {
66
+ return false;
67
+ }
68
+ };
69
+ /**
70
+ * Resolves the `.ai/strikethroo` workspace directory to host.
71
+ *
72
+ * - When `options.workspace` is given, it is treated as a project directory; the
73
+ * resolver validates that `<workspace>/.ai/strikethroo/.init-metadata.json`
74
+ * exists and returns that `.ai/strikethroo` directory.
75
+ * - Otherwise it walks upward from `options.cwd` (default `process.cwd()`),
76
+ * testing each ancestor for `.ai/strikethroo/.init-metadata.json`.
77
+ *
78
+ * On failure it returns an `{ error }` shape with a clear, user-facing message
79
+ * so the command layer can print it and exit non-zero. It never throws an
80
+ * unhandled error for the "not found" case.
81
+ */
82
+ const resolveWorkspaceRoot = (options = {}) => {
83
+ if (options.workspace) {
84
+ const projectDir = path.resolve(options.workspace);
85
+ const strikethrooDir = path.join(projectDir, '.ai', 'strikethroo');
86
+ if (isInitializedStrikethrooDir(strikethrooDir)) {
87
+ return { root: strikethrooDir };
88
+ }
89
+ return {
90
+ error: `Path ${projectDir} is not an initialized strikethroo workspace. ${INIT_MESSAGE}`,
91
+ };
92
+ }
93
+ let current = path.resolve(options.cwd ?? process.cwd());
94
+ // Walk upward until the filesystem root, where dirname(current) === current.
95
+ for (;;) {
96
+ const strikethrooDir = path.join(current, '.ai', 'strikethroo');
97
+ if (isInitializedStrikethrooDir(strikethrooDir)) {
98
+ return { root: strikethrooDir };
99
+ }
100
+ const parent = path.dirname(current);
101
+ if (parent === current)
102
+ break;
103
+ current = parent;
104
+ }
105
+ return {
106
+ error: `No initialized strikethroo workspace found from ${path.resolve(options.cwd ?? process.cwd())} upward. ${INIT_MESSAGE}`,
107
+ };
108
+ };
109
+ exports.resolveWorkspaceRoot = resolveWorkspaceRoot;
110
+ //# sourceMappingURL=root.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"root.js","sourceRoot":"","sources":["../../src/serve/root.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;GAaG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,uCAAyB;AACzB,2CAA6B;AAmB7B,4DAA4D;AACrD,MAAM,cAAc,GAAG,CAAC,MAAqB,EAA0B,EAAE,CAC7E,MAAuB,CAAC,KAAK,KAAK,SAAS,CAAC;AADlC,QAAA,cAAc,kBACoB;AAE/C,MAAM,YAAY,GAAG,mCAAmC,CAAC;AAEzD,+EAA+E;AAC/E,MAAM,2BAA2B,GAAG,CAAC,cAAsB,EAAW,EAAE;IACtE,IAAI,CAAC;QACH,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,WAAW,EAAE;YAAE,OAAO,KAAK,CAAC;QAC7D,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,qBAAqB,CAAC,CAAC;QACtE,OAAO,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,MAAM,EAAE,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC,CAAC;AAEF;;;;;;;;;;;;GAYG;AACI,MAAM,oBAAoB,GAAG,CAClC,UAAgD,EAAE,EACnC,EAAE;IACjB,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QACtB,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACnD,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC;QACnE,IAAI,2BAA2B,CAAC,cAAc,CAAC,EAAE,CAAC;YAChD,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;QAClC,CAAC;QACD,OAAO;YACL,KAAK,EAAE,QAAQ,UAAU,iDAAiD,YAAY,EAAE;SACzF,CAAC;IACJ,CAAC;IAED,IAAI,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACzD,6EAA6E;IAC7E,SAAS,CAAC;QACR,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC;QAChE,IAAI,2BAA2B,CAAC,cAAc,CAAC,EAAE,CAAC;YAChD,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;QAClC,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACrC,IAAI,MAAM,KAAK,OAAO;YAAE,MAAM;QAC9B,OAAO,GAAG,MAAM,CAAC;IACnB,CAAC;IAED,OAAO;QACL,KAAK,EAAE,mDAAmD,IAAI,CAAC,OAAO,CACpE,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAC7B,YAAY,YAAY,EAAE;KAC5B,CAAC;AACJ,CAAC,CAAC;AA/BW,QAAA,oBAAoB,wBA+B/B"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Self-review launch capability for `npx strikethroo serve`.
3
+ *
4
+ * The serve API is otherwise read-only. This module adds the single, narrowly
5
+ * scoped exception the SPA's "Launch self-review" button needs:
6
+ *
7
+ * - {@link isSelfReviewAvailable} — a PATH scan answering "is the `self-review`
8
+ * binary installed?", exposed to the SPA via `GET /api/capabilities` so the
9
+ * button only renders when launching can actually succeed;
10
+ * - {@link launchSelfReview} — validates a client-supplied plan path stays
11
+ * inside the workspace's `plans/` or `archive/` subtree, then spawns the
12
+ * binary detached (fire-and-forget, like the browser auto-open).
13
+ *
14
+ * Untrusted input (the path string) is never passed to the shell: `spawn` is
15
+ * invoked with an argv array, and the path is rejected before spawning unless it
16
+ * resolves to an existing file under `plans/` or `archive/`. Node built-ins only.
17
+ */
18
+ /** The binary name looked up on PATH and spawned. */
19
+ export declare const SELF_REVIEW_BINARY = "self-review";
20
+ /** Where to obtain self-review; surfaced by the SPA when it is not installed. */
21
+ export declare const SELF_REVIEW_URL = "https://github.com/e0ipso/self-review";
22
+ /**
23
+ * Returns `true` when the `self-review` binary is found on the process `PATH`.
24
+ *
25
+ * A presence check, matching the literal "binary is in path" contract: each
26
+ * `PATH` entry is probed for a regular file named `self-review` (plus the
27
+ * `PATHEXT` variants on Windows). It deliberately does not execute the binary,
28
+ * so it cannot hang and has no side effects.
29
+ */
30
+ export declare const isSelfReviewAvailable: (env?: Record<string, string | undefined>) => boolean;
31
+ /** Outcome of resolving and launching a self-review request. */
32
+ export interface LaunchResult {
33
+ /** HTTP status the endpoint should send. */
34
+ status: number;
35
+ /** JSON body the endpoint should send. */
36
+ body: {
37
+ ok: true;
38
+ } | {
39
+ ok: false;
40
+ error: string;
41
+ };
42
+ }
43
+ /** Seams for testing: availability probe and the detached spawn. */
44
+ export interface LaunchDeps {
45
+ available?: () => boolean;
46
+ spawnDetached?: (command: string, args: string[]) => void;
47
+ }
48
+ /**
49
+ * Resolves a client-supplied plan path to an absolute path, requiring it to be
50
+ * an existing file inside `<root>/plans` or `<root>/archive`. Returns the
51
+ * absolute path on success or a user-facing error otherwise.
52
+ *
53
+ * `root` is the absolute `.ai/strikethroo` directory; client paths are the
54
+ * workspace-relative form the SPA shows (e.g. `.ai/strikethroo/plans/NN--s/…`),
55
+ * so they are resolved against the project root (`root/../..`). Absolute client
56
+ * paths are accepted too — the containment check is what enforces safety.
57
+ */
58
+ export declare const resolveReviewPath: (root: string, clientPath: string) => {
59
+ absPath: string;
60
+ } | {
61
+ error: string;
62
+ status: number;
63
+ };
64
+ /**
65
+ * Validates `clientPath` and, if the binary is available, launches
66
+ * `self-review <absolutePath>` detached. Pure of HTTP concerns: returns the
67
+ * status/body the endpoint should send so it stays unit-testable.
68
+ */
69
+ export declare const launchSelfReview: (root: string, clientPath: string, deps?: LaunchDeps) => LaunchResult;
70
+ //# sourceMappingURL=self-review.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"self-review.d.ts","sourceRoot":"","sources":["../../src/serve/self-review.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,qDAAqD;AACrD,eAAO,MAAM,kBAAkB,gBAAgB,CAAC;AAEhD,iFAAiF;AACjF,eAAO,MAAM,eAAe,0CAA0C,CAAC;AAEvE;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,GAChC,MAAK,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,KACpD,OAoBF,CAAC;AAEF,gEAAgE;AAChE,MAAM,WAAW,YAAY;IAC3B,4CAA4C;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,IAAI,EAAE;QAAE,EAAE,EAAE,IAAI,CAAA;KAAE,GAAG;QAAE,EAAE,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CACnD;AAED,oEAAoE;AACpE,MAAM,WAAW,UAAU;IACzB,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC;IAC1B,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;CAC3D;AAWD;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,GAC5B,MAAM,MAAM,EACZ,YAAY,MAAM,KACjB;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CA4BvD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAC3B,MAAM,MAAM,EACZ,YAAY,MAAM,EAClB,OAAM,UAAe,KACpB,YAwBF,CAAC"}
@@ -0,0 +1,164 @@
1
+ "use strict";
2
+ /**
3
+ * Self-review launch capability for `npx strikethroo serve`.
4
+ *
5
+ * The serve API is otherwise read-only. This module adds the single, narrowly
6
+ * scoped exception the SPA's "Launch self-review" button needs:
7
+ *
8
+ * - {@link isSelfReviewAvailable} — a PATH scan answering "is the `self-review`
9
+ * binary installed?", exposed to the SPA via `GET /api/capabilities` so the
10
+ * button only renders when launching can actually succeed;
11
+ * - {@link launchSelfReview} — validates a client-supplied plan path stays
12
+ * inside the workspace's `plans/` or `archive/` subtree, then spawns the
13
+ * binary detached (fire-and-forget, like the browser auto-open).
14
+ *
15
+ * Untrusted input (the path string) is never passed to the shell: `spawn` is
16
+ * invoked with an argv array, and the path is rejected before spawning unless it
17
+ * resolves to an existing file under `plans/` or `archive/`. Node built-ins only.
18
+ */
19
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
20
+ if (k2 === undefined) k2 = k;
21
+ var desc = Object.getOwnPropertyDescriptor(m, k);
22
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
23
+ desc = { enumerable: true, get: function() { return m[k]; } };
24
+ }
25
+ Object.defineProperty(o, k2, desc);
26
+ }) : (function(o, m, k, k2) {
27
+ if (k2 === undefined) k2 = k;
28
+ o[k2] = m[k];
29
+ }));
30
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
31
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
32
+ }) : function(o, v) {
33
+ o["default"] = v;
34
+ });
35
+ var __importStar = (this && this.__importStar) || (function () {
36
+ var ownKeys = function(o) {
37
+ ownKeys = Object.getOwnPropertyNames || function (o) {
38
+ var ar = [];
39
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
40
+ return ar;
41
+ };
42
+ return ownKeys(o);
43
+ };
44
+ return function (mod) {
45
+ if (mod && mod.__esModule) return mod;
46
+ var result = {};
47
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
48
+ __setModuleDefault(result, mod);
49
+ return result;
50
+ };
51
+ })();
52
+ Object.defineProperty(exports, "__esModule", { value: true });
53
+ exports.launchSelfReview = exports.resolveReviewPath = exports.isSelfReviewAvailable = exports.SELF_REVIEW_URL = exports.SELF_REVIEW_BINARY = void 0;
54
+ const fs = __importStar(require("fs"));
55
+ const path = __importStar(require("path"));
56
+ const child_process_1 = require("child_process");
57
+ /** The binary name looked up on PATH and spawned. */
58
+ exports.SELF_REVIEW_BINARY = 'self-review';
59
+ /** Where to obtain self-review; surfaced by the SPA when it is not installed. */
60
+ exports.SELF_REVIEW_URL = 'https://github.com/e0ipso/self-review';
61
+ /**
62
+ * Returns `true` when the `self-review` binary is found on the process `PATH`.
63
+ *
64
+ * A presence check, matching the literal "binary is in path" contract: each
65
+ * `PATH` entry is probed for a regular file named `self-review` (plus the
66
+ * `PATHEXT` variants on Windows). It deliberately does not execute the binary,
67
+ * so it cannot hang and has no side effects.
68
+ */
69
+ const isSelfReviewAvailable = (env = process.env) => {
70
+ const pathVar = env.PATH ?? env.Path ?? '';
71
+ if (!pathVar)
72
+ return false;
73
+ const exts = process.platform === 'win32'
74
+ ? (env.PATHEXT ?? '.EXE;.CMD;.BAT;.COM').split(';').filter(Boolean)
75
+ : [''];
76
+ for (const dir of pathVar.split(path.delimiter).filter(Boolean)) {
77
+ for (const ext of exts) {
78
+ const candidate = path.join(dir, exports.SELF_REVIEW_BINARY + ext);
79
+ try {
80
+ if (fs.statSync(candidate).isFile())
81
+ return true;
82
+ }
83
+ catch {
84
+ // Not present in this directory; keep scanning.
85
+ }
86
+ }
87
+ }
88
+ return false;
89
+ };
90
+ exports.isSelfReviewAvailable = isSelfReviewAvailable;
91
+ /** Spawns the binary detached and unref'd so it outlives the request. */
92
+ const spawnDetached = (command, args) => {
93
+ const child = (0, child_process_1.spawn)(command, args, { stdio: 'ignore', detached: true });
94
+ child.on('error', () => {
95
+ /* a failed launch must not crash the server */
96
+ });
97
+ child.unref();
98
+ };
99
+ /**
100
+ * Resolves a client-supplied plan path to an absolute path, requiring it to be
101
+ * an existing file inside `<root>/plans` or `<root>/archive`. Returns the
102
+ * absolute path on success or a user-facing error otherwise.
103
+ *
104
+ * `root` is the absolute `.ai/strikethroo` directory; client paths are the
105
+ * workspace-relative form the SPA shows (e.g. `.ai/strikethroo/plans/NN--s/…`),
106
+ * so they are resolved against the project root (`root/../..`). Absolute client
107
+ * paths are accepted too — the containment check is what enforces safety.
108
+ */
109
+ const resolveReviewPath = (root, clientPath) => {
110
+ if (typeof clientPath !== 'string' || clientPath.trim() === '') {
111
+ return { error: 'A plan path is required.', status: 400 };
112
+ }
113
+ const projectRoot = path.resolve(root, '..', '..');
114
+ const resolved = path.resolve(projectRoot, clientPath);
115
+ const plansDir = path.join(root, 'plans');
116
+ const archiveDir = path.join(root, 'archive');
117
+ const within = (dir) => resolved === dir || resolved.startsWith(dir + path.sep);
118
+ if (!within(plansDir) && !within(archiveDir)) {
119
+ return {
120
+ error: 'Plan path must be inside the workspace plans/ or archive/ directory.',
121
+ status: 400,
122
+ };
123
+ }
124
+ try {
125
+ if (!fs.statSync(resolved).isFile()) {
126
+ return { error: 'Plan path does not point to a file.', status: 404 };
127
+ }
128
+ }
129
+ catch {
130
+ return { error: 'Plan file not found.', status: 404 };
131
+ }
132
+ return { absPath: resolved };
133
+ };
134
+ exports.resolveReviewPath = resolveReviewPath;
135
+ /**
136
+ * Validates `clientPath` and, if the binary is available, launches
137
+ * `self-review <absolutePath>` detached. Pure of HTTP concerns: returns the
138
+ * status/body the endpoint should send so it stays unit-testable.
139
+ */
140
+ const launchSelfReview = (root, clientPath, deps = {}) => {
141
+ const available = deps.available ?? exports.isSelfReviewAvailable;
142
+ if (!available()) {
143
+ return {
144
+ status: 409,
145
+ body: { ok: false, error: 'self-review is not installed on PATH.' },
146
+ };
147
+ }
148
+ const resolved = (0, exports.resolveReviewPath)(root, clientPath);
149
+ if ('error' in resolved) {
150
+ return { status: resolved.status, body: { ok: false, error: resolved.error } };
151
+ }
152
+ try {
153
+ (deps.spawnDetached ?? spawnDetached)(exports.SELF_REVIEW_BINARY, [resolved.absPath]);
154
+ }
155
+ catch (err) {
156
+ return {
157
+ status: 500,
158
+ body: { ok: false, error: `Failed to launch self-review: ${err.message}` },
159
+ };
160
+ }
161
+ return { status: 200, body: { ok: true } };
162
+ };
163
+ exports.launchSelfReview = launchSelfReview;
164
+ //# sourceMappingURL=self-review.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"self-review.js","sourceRoot":"","sources":["../../src/serve/self-review.ts"],"names":[],"mappings":"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"}