strikethroo 3.0.2 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -2
- package/dist/cli.js +28 -0
- package/dist/cli.js.map +1 -1
- package/dist/serve/archive.d.ts +43 -0
- package/dist/serve/archive.d.ts.map +1 -0
- package/dist/serve/archive.js +124 -0
- package/dist/serve/archive.js.map +1 -0
- package/dist/serve/derivation.d.ts +78 -0
- package/dist/serve/derivation.d.ts.map +1 -0
- package/dist/serve/derivation.js +237 -0
- package/dist/serve/derivation.js.map +1 -0
- package/dist/serve/events.d.ts +41 -0
- package/dist/serve/events.d.ts.map +1 -0
- package/dist/serve/events.js +91 -0
- package/dist/serve/events.js.map +1 -0
- package/dist/serve/markdown.d.ts +75 -0
- package/dist/serve/markdown.d.ts.map +1 -0
- package/dist/serve/markdown.js +221 -0
- package/dist/serve/markdown.js.map +1 -0
- package/dist/serve/root.d.ts +48 -0
- package/dist/serve/root.d.ts.map +1 -0
- package/dist/serve/root.js +110 -0
- package/dist/serve/root.js.map +1 -0
- package/dist/serve/self-review.d.ts +70 -0
- package/dist/serve/self-review.d.ts.map +1 -0
- package/dist/serve/self-review.js +164 -0
- package/dist/serve/self-review.js.map +1 -0
- package/dist/serve/server.d.ts +70 -0
- package/dist/serve/server.d.ts.map +1 -0
- package/dist/serve/server.js +368 -0
- package/dist/serve/server.js.map +1 -0
- package/dist/serve/watcher.d.ts +32 -0
- package/dist/serve/watcher.d.ts.map +1 -0
- package/dist/serve/watcher.js +99 -0
- package/dist/serve/watcher.js.map +1 -0
- package/dist/serve/workspace-model.d.ts +80 -0
- package/dist/serve/workspace-model.d.ts.map +1 -0
- package/dist/serve/workspace-model.js +176 -0
- package/dist/serve/workspace-model.js.map +1 -0
- package/dist/skill-scripts/shared/frontmatter.d.ts +2 -0
- package/dist/skill-scripts/shared/frontmatter.d.ts.map +1 -0
- package/dist/skill-scripts/shared/frontmatter.js +37 -0
- package/dist/skill-scripts/shared/frontmatter.js.map +1 -0
- package/dist/skill-scripts/shared/plan-scan.d.ts +10 -0
- package/dist/skill-scripts/shared/plan-scan.d.ts.map +1 -0
- package/dist/skill-scripts/shared/plan-scan.js +91 -0
- package/dist/skill-scripts/shared/plan-scan.js.map +1 -0
- package/dist/skill-scripts/shared/root.d.ts +2 -0
- package/dist/skill-scripts/shared/root.d.ts.map +1 -0
- package/dist/skill-scripts/shared/root.js +104 -0
- package/dist/skill-scripts/shared/root.js.map +1 -0
- package/dist-web/assets/Fraunces-Italic-VariableFont_SOFT_WONK_opsz_wght-CuXX_kIb.ttf +0 -0
- package/dist-web/assets/Fraunces-VariableFont_SOFT_WONK_opsz_wght-DLWfSgHL.ttf +0 -0
- package/dist-web/assets/Outfit-VariableFont_wght-B6lQlNBM.ttf +0 -0
- package/dist-web/assets/SFMonoBold-DXHgGUoo.otf +0 -0
- package/dist-web/assets/SFMonoBoldItalic-CdGEImHi.otf +0 -0
- package/dist-web/assets/SFMonoHeavy-DL92f7rT.otf +0 -0
- package/dist-web/assets/SFMonoHeavyItalic-DnE00LFH.otf +0 -0
- package/dist-web/assets/SFMonoLight-CaMC1gg-.otf +0 -0
- package/dist-web/assets/SFMonoLightItalic-DG3Owzn7.otf +0 -0
- package/dist-web/assets/SFMonoMedium-ypRDCKSo.otf +0 -0
- package/dist-web/assets/SFMonoMediumItalic-DkJk-c-x.otf +0 -0
- package/dist-web/assets/SFMonoRegular-77Uh1IPk.otf +0 -0
- package/dist-web/assets/SFMonoRegularItalic-Cn01bACm.otf +0 -0
- package/dist-web/assets/SFMonoSemibold-CvhtzcyM.otf +0 -0
- package/dist-web/assets/SFMonoSemiboldItalic-D75NMH13.otf +0 -0
- package/dist-web/assets/arc-JkuhZ_PU.js +1 -0
- package/dist-web/assets/architectureDiagram-3BPJPVTR-DwCgGxAM.js +36 -0
- package/dist-web/assets/blockDiagram-GPEHLZMM-BCwcsKdi.js +132 -0
- package/dist-web/assets/c4Diagram-AAUBKEIU-Cm1cMFQT.js +10 -0
- package/dist-web/assets/channel-8UZd6AbH.js +1 -0
- package/dist-web/assets/chunk-2J33WTMH-BHDreu9q.js +1 -0
- package/dist-web/assets/chunk-4BX2VUAB-CvH1iMKB.js +1 -0
- package/dist-web/assets/chunk-55IACEB6-C02LfbKU.js +1 -0
- package/dist-web/assets/chunk-727SXJPM-BYDaeCJW.js +206 -0
- package/dist-web/assets/chunk-AQP2D5EJ-CW-sdA3M.js +231 -0
- package/dist-web/assets/chunk-FMBD7UC4-BE3hNKOn.js +15 -0
- package/dist-web/assets/chunk-ND2GUHAM-BosLJTdj.js +1 -0
- package/dist-web/assets/chunk-QZHKN3VN-Bf44xttm.js +1 -0
- package/dist-web/assets/classDiagram-4FO5ZUOK-D7aMNqbH.js +1 -0
- package/dist-web/assets/classDiagram-v2-Q7XG4LA2-D7aMNqbH.js +1 -0
- package/dist-web/assets/cose-bilkent-S5V4N54A-BZS-xBec.js +1 -0
- package/dist-web/assets/cytoscape.esm-BHYC38rz.js +331 -0
- package/dist-web/assets/dagre-BM42HDAG-Be_HyeG7.js +4 -0
- package/dist-web/assets/defaultLocale-CrowFXzY.js +1 -0
- package/dist-web/assets/diagram-2AECGRRQ-BVt23uOL.js +43 -0
- package/dist-web/assets/diagram-5GNKFQAL-BF-OZRmP.js +10 -0
- package/dist-web/assets/diagram-KO2AKTUF-BvW-uYc2.js +3 -0
- package/dist-web/assets/diagram-LMA3HP47-CG2JR86G.js +24 -0
- package/dist-web/assets/diagram-OG6HWLK6-PZ5nR1AF.js +24 -0
- package/dist-web/assets/erDiagram-TEJ5UH35-D2GJWnIo.js +85 -0
- package/dist-web/assets/flowDiagram-I6XJVG4X-DGboZXQm.js +162 -0
- package/dist-web/assets/ganttDiagram-6RSMTGT7-IPOlSI7E.js +292 -0
- package/dist-web/assets/gitGraphDiagram-PVQCEYII-DO9E2tXK.js +106 -0
- package/dist-web/assets/graph-Dqkl27Ch.js +1 -0
- package/dist-web/assets/index-B8AJFM1Y.js +125 -0
- package/dist-web/assets/index-Bm5I46eC.css +1 -0
- package/dist-web/assets/infoDiagram-5YYISTIA-Clg2ubQz.js +2 -0
- package/dist-web/assets/init-Gi6I4Gst.js +1 -0
- package/dist-web/assets/ishikawaDiagram-YF4QCWOH-CDyYc7AV.js +70 -0
- package/dist-web/assets/journeyDiagram-JHISSGLW-CIz55Ff7.js +139 -0
- package/dist-web/assets/kanban-definition-UN3LZRKU-OzC_r8lI.js +89 -0
- package/dist-web/assets/katex-C5jXJg4s.js +257 -0
- package/dist-web/assets/layout-DO9UvE1P.js +1 -0
- package/dist-web/assets/linear-rdoP0iOK.js +1 -0
- package/dist-web/assets/mermaid.core-DOgS-uvF.js +307 -0
- package/dist-web/assets/mindmap-definition-RKZ34NQL-52nfuxxC.js +96 -0
- package/dist-web/assets/ordinal-Cboi1Yqb.js +1 -0
- package/dist-web/assets/pieDiagram-4H26LBE5-Drwd0WV7.js +30 -0
- package/dist-web/assets/quadrantDiagram-W4KKPZXB-DYJRwtFj.js +7 -0
- package/dist-web/assets/requirementDiagram-4Y6WPE33-HOL8fCwg.js +84 -0
- package/dist-web/assets/sankeyDiagram-5OEKKPKP-CyA-ExUk.js +40 -0
- package/dist-web/assets/sequenceDiagram-3UESZ5HK-C6Zr5XVd.js +162 -0
- package/dist-web/assets/stateDiagram-AJRCARHV-DSAZMis2.js +1 -0
- package/dist-web/assets/stateDiagram-v2-BHNVJYJU-nDV4UH9R.js +1 -0
- package/dist-web/assets/timeline-definition-PNZ67QCA-CUPjxRlk.js +120 -0
- package/dist-web/assets/vennDiagram-CIIHVFJN-CtjMS4vh.js +34 -0
- package/dist-web/assets/wardley-L42UT6IY-Bk6PjBWD.js +173 -0
- package/dist-web/assets/wardleyDiagram-YWT4CUSO-Bjb8yHyW.js +78 -0
- package/dist-web/assets/xychartDiagram-2RQKCTM6-C3ukcEfW.js +7 -0
- package/dist-web/favicon.svg +13 -0
- package/dist-web/index.html +30 -0
- package/package.json +28 -8
- package/templates/harness/skills/st-full-workflow/SKILL.md +2 -2
- package/templates/harness/skills/st-generate-tasks/SKILL.md +2 -2
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Server-Sent Events change stream for `npx strikethroo serve`.
|
|
4
|
+
*
|
|
5
|
+
* Provides `GET /api/events`: a `text/event-stream` that broadcasts a single
|
|
6
|
+
* coalesced `changed` ping whenever the workspace mutates on disk. The event
|
|
7
|
+
* carries no diff payload — clients refetch the affected API data (the browser
|
|
8
|
+
* consumer is a later plan).
|
|
9
|
+
*
|
|
10
|
+
* Exposes an {@link EventsHub} that owns the connected-client set and the
|
|
11
|
+
* workspace watcher, plus an `ApiHandler` the server registers so this module
|
|
12
|
+
* stays decoupled from routing. Connections are cleaned up on disconnect so no
|
|
13
|
+
* listeners or sockets leak. Node built-ins only.
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.EventsHub = void 0;
|
|
17
|
+
const watcher_1 = require("./watcher");
|
|
18
|
+
/** Keep-alive comment interval (ms) to hold idle proxies/streams open. */
|
|
19
|
+
const KEEP_ALIVE_MS = 15000;
|
|
20
|
+
/**
|
|
21
|
+
* Owns the SSE client set and the workspace watcher. One hub per server. Start
|
|
22
|
+
* the watcher with {@link start} after the server is listening; release it with
|
|
23
|
+
* {@link close} when the server closes.
|
|
24
|
+
*/
|
|
25
|
+
class EventsHub {
|
|
26
|
+
constructor(workspaceDir, debounceMs) {
|
|
27
|
+
this.workspaceDir = workspaceDir;
|
|
28
|
+
this.debounceMs = debounceMs;
|
|
29
|
+
this.clients = new Set();
|
|
30
|
+
this.watcher = null;
|
|
31
|
+
/** An {@link ApiHandler} for `GET /api/events`; returns false otherwise. */
|
|
32
|
+
this.apiHandler = (req, res, ctx) => {
|
|
33
|
+
if (ctx.pathname === '/api/events' || ctx.pathname === '/api/events/') {
|
|
34
|
+
this.handleConnection(req, res);
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/** Begins watching the workspace; coalesced changes broadcast to all clients. */
|
|
41
|
+
start() {
|
|
42
|
+
if (this.watcher)
|
|
43
|
+
return;
|
|
44
|
+
this.watcher = (0, watcher_1.createWorkspaceWatcher)(this.workspaceDir, () => this.broadcast(), this.debounceMs);
|
|
45
|
+
}
|
|
46
|
+
/** Stops the watcher and ends every open client connection. */
|
|
47
|
+
close() {
|
|
48
|
+
if (this.watcher) {
|
|
49
|
+
this.watcher.close();
|
|
50
|
+
this.watcher = null;
|
|
51
|
+
}
|
|
52
|
+
for (const res of this.clients) {
|
|
53
|
+
res.end();
|
|
54
|
+
}
|
|
55
|
+
this.clients.clear();
|
|
56
|
+
}
|
|
57
|
+
/** Number of currently connected SSE clients (used by tests). */
|
|
58
|
+
get clientCount() {
|
|
59
|
+
return this.clients.size;
|
|
60
|
+
}
|
|
61
|
+
/** Sends a single coalesced `changed` event to every connected client. */
|
|
62
|
+
broadcast() {
|
|
63
|
+
for (const res of this.clients) {
|
|
64
|
+
res.write('event: changed\ndata: {}\n\n');
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/** Attaches an SSE response: writes headers, registers cleanup on close. */
|
|
68
|
+
handleConnection(req, res) {
|
|
69
|
+
res.writeHead(200, {
|
|
70
|
+
'Content-Type': 'text/event-stream',
|
|
71
|
+
'Cache-Control': 'no-cache',
|
|
72
|
+
Connection: 'keep-alive',
|
|
73
|
+
});
|
|
74
|
+
// Initial comment opens the stream and flushes headers to the client.
|
|
75
|
+
res.write(': connected\n\n');
|
|
76
|
+
this.clients.add(res);
|
|
77
|
+
const keepAlive = setInterval(() => {
|
|
78
|
+
res.write(': keep-alive\n\n');
|
|
79
|
+
}, KEEP_ALIVE_MS);
|
|
80
|
+
// Don't let the keep-alive timer hold the event loop / process open.
|
|
81
|
+
keepAlive.unref?.();
|
|
82
|
+
const cleanup = () => {
|
|
83
|
+
clearInterval(keepAlive);
|
|
84
|
+
this.clients.delete(res);
|
|
85
|
+
};
|
|
86
|
+
req.on('close', cleanup);
|
|
87
|
+
res.on('close', cleanup);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
exports.EventsHub = EventsHub;
|
|
91
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/serve/events.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG;;;AAGH,uCAAqE;AAErE,0EAA0E;AAC1E,MAAM,aAAa,GAAG,KAAK,CAAC;AAE5B;;;;GAIG;AACH,MAAa,SAAS;IAIpB,YACmB,YAAoB,EACpB,UAAmB;QADnB,iBAAY,GAAZ,YAAY,CAAQ;QACpB,eAAU,GAAV,UAAU,CAAS;QALrB,YAAO,GAAG,IAAI,GAAG,EAAuB,CAAC;QAClD,YAAO,GAA4B,IAAI,CAAC;QAmEhD,4EAA4E;QAC5E,eAAU,GAAG,CACX,GAAyB,EACzB,GAAwB,EACxB,GAAyB,EAChB,EAAE;YACX,IAAI,GAAG,CAAC,QAAQ,KAAK,aAAa,IAAI,GAAG,CAAC,QAAQ,KAAK,cAAc,EAAE,CAAC;gBACtE,IAAI,CAAC,gBAAgB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;gBAChC,OAAO,IAAI,CAAC;YACd,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC,CAAC;IAzEC,CAAC;IAEJ,iFAAiF;IACjF,KAAK;QACH,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO;QACzB,IAAI,CAAC,OAAO,GAAG,IAAA,gCAAsB,EACnC,IAAI,CAAC,YAAY,EACjB,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE,EACtB,IAAI,CAAC,UAAU,CAChB,CAAC;IACJ,CAAC;IAED,+DAA+D;IAC/D,KAAK;QACH,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YACrB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACtB,CAAC;QACD,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAC/B,GAAG,CAAC,GAAG,EAAE,CAAC;QACZ,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IAED,iEAAiE;IACjE,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IAC3B,CAAC;IAED,0EAA0E;IAClE,SAAS;QACf,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAC/B,GAAG,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC;IAED,4EAA4E;IAC5E,gBAAgB,CAAC,GAAyB,EAAE,GAAwB;QAClE,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;YACjB,cAAc,EAAE,mBAAmB;YACnC,eAAe,EAAE,UAAU;YAC3B,UAAU,EAAE,YAAY;SACzB,CAAC,CAAC;QACH,sEAAsE;QACtE,GAAG,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;QAE7B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAEtB,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE;YACjC,GAAG,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;QAChC,CAAC,EAAE,aAAa,CAAC,CAAC;QAClB,qEAAqE;QACrE,SAAS,CAAC,KAAK,EAAE,EAAE,CAAC;QAEpB,MAAM,OAAO,GAAG,GAAS,EAAE;YACzB,aAAa,CAAC,SAAS,CAAC,CAAC;YACzB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC3B,CAAC,CAAC;QACF,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACzB,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC3B,CAAC;CAcF;AAjFD,8BAiFC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure, dependency-light markdown parsing primitives for the serve data layer.
|
|
3
|
+
*
|
|
4
|
+
* These functions operate on already-read string content. File reading itself
|
|
5
|
+
* belongs to the task scanner and the model assembler. Everything here is
|
|
6
|
+
* synchronous, read-only, and side-effect-free: no `fs`, no network, no writes.
|
|
7
|
+
*
|
|
8
|
+
* The existing `src/skill-scripts/shared/frontmatter.ts` only recovers the
|
|
9
|
+
* numeric `id`; it is intentionally not forked. This module provides a richer
|
|
10
|
+
* frontmatter reader the UI needs (summary, created, status, group,
|
|
11
|
+
* dependencies[], skills[]).
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Parsed frontmatter. All fields are optional because real-world files vary and
|
|
15
|
+
* malformed/missing frontmatter must degrade gracefully rather than throw.
|
|
16
|
+
* `extra` retains any scalar keys not covered by the typed fields.
|
|
17
|
+
*/
|
|
18
|
+
export interface ParsedFrontmatter {
|
|
19
|
+
id?: number;
|
|
20
|
+
summary?: string;
|
|
21
|
+
created?: string;
|
|
22
|
+
status?: string;
|
|
23
|
+
group?: string;
|
|
24
|
+
dependencies: Array<number | string>;
|
|
25
|
+
skills: string[];
|
|
26
|
+
extra: Record<string, string>;
|
|
27
|
+
}
|
|
28
|
+
/** A named `## ` section of a markdown body. */
|
|
29
|
+
export interface MarkdownSection {
|
|
30
|
+
/** Heading text (the remainder of the `## ` line, trimmed). */
|
|
31
|
+
heading: string;
|
|
32
|
+
/** Section content from just after the heading line up to the next `## ` or EOF. */
|
|
33
|
+
content: string;
|
|
34
|
+
/** Character offset of the heading start within the body. */
|
|
35
|
+
start: number;
|
|
36
|
+
/** Character offset of the section end (exclusive) within the body. */
|
|
37
|
+
end: number;
|
|
38
|
+
}
|
|
39
|
+
/** Result of sectioning a markdown body. */
|
|
40
|
+
export interface SectionedBody {
|
|
41
|
+
/** Everything after the closing frontmatter `---`, verbatim. */
|
|
42
|
+
rawBody: string;
|
|
43
|
+
/** Ordered list of `## ` sections. */
|
|
44
|
+
sections: MarkdownSection[];
|
|
45
|
+
}
|
|
46
|
+
/** A single extracted mermaid fenced block. */
|
|
47
|
+
export interface MermaidBlock {
|
|
48
|
+
/** Raw mermaid source (inner content of the fenced block). */
|
|
49
|
+
source: string;
|
|
50
|
+
/** True when the block falls within an "Architectural Approach" section. */
|
|
51
|
+
isArchitecturalApproach: boolean;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Reads the leading frontmatter block into typed fields. Never throws: malformed
|
|
55
|
+
* lines are skipped and absent keys fall back to defaults (undefined scalars,
|
|
56
|
+
* empty arrays).
|
|
57
|
+
*/
|
|
58
|
+
export declare const parseFrontmatter: (content: string) => ParsedFrontmatter;
|
|
59
|
+
/** Returns the body: everything after the closing frontmatter `---`, or the whole content. */
|
|
60
|
+
export declare const extractBody: (content: string) => string;
|
|
61
|
+
/**
|
|
62
|
+
* Splits a markdown body into the verbatim `rawBody` plus an ordered list of
|
|
63
|
+
* `## ` sections addressable by heading text. Section access is additive:
|
|
64
|
+
* callers may always fall back to `rawBody`.
|
|
65
|
+
*/
|
|
66
|
+
export declare const sectionBody: (body: string) => SectionedBody;
|
|
67
|
+
/**
|
|
68
|
+
* Extracts every fenced ```mermaid block's raw source from a body. Blocks whose
|
|
69
|
+
* position falls within an "Architectural Approach" section are flagged. Plans
|
|
70
|
+
* with no mermaid block yield an empty list (never an error).
|
|
71
|
+
*/
|
|
72
|
+
export declare const extractMermaidBlocks: (body: string) => MermaidBlock[];
|
|
73
|
+
/** Returns the text of the first `# ` (level-1) heading in a body, or undefined. */
|
|
74
|
+
export declare const extractTitle: (body: string) => string | undefined;
|
|
75
|
+
//# sourceMappingURL=markdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/serve/markdown.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;IACrC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAED,gDAAgD;AAChD,MAAM,WAAW,eAAe;IAC9B,+DAA+D;IAC/D,OAAO,EAAE,MAAM,CAAC;IAChB,oFAAoF;IACpF,OAAO,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAC;IACd,uEAAuE;IACvE,GAAG,EAAE,MAAM,CAAC;CACb;AAED,4CAA4C;AAC5C,MAAM,WAAW,aAAa;IAC5B,gEAAgE;IAChE,OAAO,EAAE,MAAM,CAAC;IAChB,sCAAsC;IACtC,QAAQ,EAAE,eAAe,EAAE,CAAC;CAC7B;AAED,+CAA+C;AAC/C,MAAM,WAAW,YAAY;IAC3B,8DAA8D;IAC9D,MAAM,EAAE,MAAM,CAAC;IACf,4EAA4E;IAC5E,uBAAuB,EAAE,OAAO,CAAC;CAClC;AAwCD;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAAI,SAAS,MAAM,KAAG,iBAqFlD,CAAC;AAEF,8FAA8F;AAC9F,eAAO,MAAM,WAAW,GAAI,SAAS,MAAM,KAAG,MAI7C,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,WAAW,GAAI,MAAM,MAAM,KAAG,aA6B1C,CAAC;AAIF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAAI,MAAM,MAAM,KAAG,YAAY,EAmB/D,CAAC;AAEF,oFAAoF;AACpF,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,KAAG,MAAM,GAAG,SAGpD,CAAC"}
|
|
@@ -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"}
|