@slowcook-ai/cli 0.19.4 → 0.19.6
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 +216 -191
- package/dist/cli.js +53 -73
- package/dist/cli.js.map +1 -1
- package/dist/commands/check/spec-validate.d.ts.map +1 -1
- package/dist/commands/check/spec-validate.js +3 -1
- package/dist/commands/check/spec-validate.js.map +1 -1
- package/dist/commands/plate/dto-columns.d.ts +55 -0
- package/dist/commands/plate/dto-columns.d.ts.map +1 -0
- package/dist/commands/plate/dto-columns.js +135 -0
- package/dist/commands/plate/dto-columns.js.map +1 -0
- package/dist/commands/refine/agent.d.ts.map +1 -1
- package/dist/commands/refine/agent.js +12 -1
- package/dist/commands/refine/agent.js.map +1 -1
- package/dist/commands/refine/spec-validate.d.ts +18 -0
- package/dist/commands/refine/spec-validate.d.ts.map +1 -1
- package/dist/commands/refine/spec-validate.js +42 -0
- package/dist/commands/refine/spec-validate.js.map +1 -1
- package/dist/commands/serve/config.d.ts +140 -0
- package/dist/commands/serve/config.d.ts.map +1 -0
- package/dist/commands/serve/config.js +174 -0
- package/dist/commands/serve/config.js.map +1 -0
- package/dist/commands/serve/detect.d.ts +31 -0
- package/dist/commands/serve/detect.d.ts.map +1 -0
- package/dist/commands/serve/detect.js +56 -0
- package/dist/commands/serve/detect.js.map +1 -0
- package/dist/commands/serve/dev.d.ts +51 -0
- package/dist/commands/serve/dev.d.ts.map +1 -0
- package/dist/commands/serve/dev.js +126 -0
- package/dist/commands/serve/dev.js.map +1 -0
- package/dist/commands/serve/index.d.ts +28 -0
- package/dist/commands/serve/index.d.ts.map +1 -0
- package/dist/commands/serve/index.js +216 -0
- package/dist/commands/serve/index.js.map +1 -0
- package/dist/commands/serve/mock.d.ts +39 -0
- package/dist/commands/serve/mock.d.ts.map +1 -0
- package/dist/commands/serve/mock.js +132 -0
- package/dist/commands/serve/mock.js.map +1 -0
- package/dist/commands/serve/staging.d.ts +39 -0
- package/dist/commands/serve/staging.d.ts.map +1 -0
- package/dist/commands/serve/staging.js +190 -0
- package/dist/commands/serve/staging.js.map +1 -0
- package/dist/commands/stories/index.d.ts +15 -0
- package/dist/commands/stories/index.d.ts.map +1 -0
- package/dist/commands/stories/index.js +280 -0
- package/dist/commands/stories/index.js.map +1 -0
- package/dist/commands/stories/status.d.ts +74 -0
- package/dist/commands/stories/status.d.ts.map +1 -0
- package/dist/commands/stories/status.js +176 -0
- package/dist/commands/stories/status.js.map +1 -0
- package/dist/commands/upsert-agent-docs.d.ts.map +1 -1
- package/dist/commands/upsert-agent-docs.js +42 -0
- package/dist/commands/upsert-agent-docs.js.map +1 -1
- package/dist/commands.manifest.d.ts +37 -0
- package/dist/commands.manifest.d.ts.map +1 -0
- package/dist/commands.manifest.js +289 -0
- package/dist/commands.manifest.js.map +1 -0
- package/dist/help.d.ts +43 -0
- package/dist/help.d.ts.map +1 -0
- package/dist/help.js +131 -0
- package/dist/help.js.map +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `slowcook stories <subcommand>` — 0.19.5-α (sc#146 #6).
|
|
3
|
+
*
|
|
4
|
+
* Subcommands:
|
|
5
|
+
* - `status` — per-story stage table (refine / testgen / vibe / brew / chef)
|
|
6
|
+
*
|
|
7
|
+
* Future subcommands tracked in sc#146:
|
|
8
|
+
* - `release` — release a story-id after supersede (parked, needs design)
|
|
9
|
+
*
|
|
10
|
+
* Stage detection delegates to the pure helper in `./status.ts`. This
|
|
11
|
+
* file is just the IO wrapper: read `specs/_index.yaml`, query the
|
|
12
|
+
* forge for PRs, render.
|
|
13
|
+
*/
|
|
14
|
+
export declare function stories(argv: string[]): Promise<void>;
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/stories/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAoBH,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB3D"}
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `slowcook stories <subcommand>` — 0.19.5-α (sc#146 #6).
|
|
3
|
+
*
|
|
4
|
+
* Subcommands:
|
|
5
|
+
* - `status` — per-story stage table (refine / testgen / vibe / brew / chef)
|
|
6
|
+
*
|
|
7
|
+
* Future subcommands tracked in sc#146:
|
|
8
|
+
* - `release` — release a story-id after supersede (parked, needs design)
|
|
9
|
+
*
|
|
10
|
+
* Stage detection delegates to the pure helper in `./status.ts`. This
|
|
11
|
+
* file is just the IO wrapper: read `specs/_index.yaml`, query the
|
|
12
|
+
* forge for PRs, render.
|
|
13
|
+
*/
|
|
14
|
+
import { execSync } from "node:child_process";
|
|
15
|
+
import { readIndex } from "../refine/spec-yaml.js";
|
|
16
|
+
import { GitHubAdapter } from "@slowcook-ai/forge-github";
|
|
17
|
+
import { buildStoriesStatus, renderStoriesStatusTable, } from "./status.js";
|
|
18
|
+
import { Octokit } from "@octokit/rest";
|
|
19
|
+
export async function stories(argv) {
|
|
20
|
+
const sub = argv[0];
|
|
21
|
+
switch (sub) {
|
|
22
|
+
case "status":
|
|
23
|
+
return runStatus(argv.slice(1));
|
|
24
|
+
case undefined:
|
|
25
|
+
case "help":
|
|
26
|
+
case "--help":
|
|
27
|
+
case "-h":
|
|
28
|
+
printHelp();
|
|
29
|
+
return;
|
|
30
|
+
default:
|
|
31
|
+
console.error(`Unknown stories subcommand: ${sub}`);
|
|
32
|
+
printHelp();
|
|
33
|
+
process.exit(64);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
async function runStatus(argv) {
|
|
37
|
+
const args = parseArgs(argv);
|
|
38
|
+
const index = readIndex(args.repoRoot);
|
|
39
|
+
const stories = index.stories ?? {};
|
|
40
|
+
const storyIds = Object.keys(stories);
|
|
41
|
+
if (storyIds.length === 0) {
|
|
42
|
+
console.log("(no stories in specs/_index.yaml)");
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
// Resolve owner/repo from git remote if not passed.
|
|
46
|
+
const { owner, repo } = resolveOwnerRepo(args);
|
|
47
|
+
let prs = [];
|
|
48
|
+
const token = process.env["GITHUB_TOKEN"] ?? process.env["GH_TOKEN"];
|
|
49
|
+
if (owner && repo && token) {
|
|
50
|
+
try {
|
|
51
|
+
prs = await fetchAllRelevantPRs({ owner, repo, token });
|
|
52
|
+
}
|
|
53
|
+
catch (e) {
|
|
54
|
+
console.error(`Warning: failed to fetch PRs (${e.message}). Status table will report all stages as absent.`);
|
|
55
|
+
prs = [];
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else if (!token) {
|
|
59
|
+
console.error("Warning: GITHUB_TOKEN / GH_TOKEN not set. Status table will report all stages as absent.\n" +
|
|
60
|
+
" Set the env var to query the forge; story metadata still renders from specs/_index.yaml.");
|
|
61
|
+
}
|
|
62
|
+
const rows = buildStoriesStatus(index, prs);
|
|
63
|
+
if (args.format === "json") {
|
|
64
|
+
console.log(JSON.stringify(rows, null, 2));
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
process.stdout.write(renderStoriesStatusTable(rows));
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Fetch every PR that's relevant to the slowcook pipeline for this
|
|
71
|
+
* consumer. Two sources, unioned by PR number:
|
|
72
|
+
*
|
|
73
|
+
* 1. **Branch-prefix search** (`head:slowcook/`) — catches all slowcook-
|
|
74
|
+
* shaped branches whether or not the PR carries slowcook-* labels.
|
|
75
|
+
* This is the primary source — local-pipeline PRs (per
|
|
76
|
+
* `docs/local-pipeline-role.md`) frequently lack labels but always
|
|
77
|
+
* use the branch convention.
|
|
78
|
+
* 2. **Label scan** — catches any slowcook PRs (bot or human) that
|
|
79
|
+
* DID get labelled but happen to NOT live on a slowcook/ branch
|
|
80
|
+
* (e.g. a Bijan-cumulative branch with a slowcook-spec label).
|
|
81
|
+
*
|
|
82
|
+
* The branch search uses GitHub's search API (single endpoint, single
|
|
83
|
+
* page for most consumers). The label scan uses the issues endpoint
|
|
84
|
+
* per-label (one paginated request per label).
|
|
85
|
+
*/
|
|
86
|
+
async function fetchAllRelevantPRs(args) {
|
|
87
|
+
const octokit = new Octokit({
|
|
88
|
+
auth: args.token,
|
|
89
|
+
userAgent: "slowcook-ai/cli",
|
|
90
|
+
});
|
|
91
|
+
const byNumber = new Map();
|
|
92
|
+
// 1. Branch-prefix search.
|
|
93
|
+
try {
|
|
94
|
+
const q = `is:pr repo:${args.owner}/${args.repo} head:slowcook/`;
|
|
95
|
+
const found = await octokit.paginate(octokit.search.issuesAndPullRequests, {
|
|
96
|
+
q,
|
|
97
|
+
per_page: 100,
|
|
98
|
+
});
|
|
99
|
+
for (const item of found) {
|
|
100
|
+
if (!item.pull_request)
|
|
101
|
+
continue;
|
|
102
|
+
const labels = (item.labels ?? [])
|
|
103
|
+
.map((l) => (typeof l === "string" ? l : l.name ?? ""))
|
|
104
|
+
.filter((s) => typeof s === "string" && s.length > 0);
|
|
105
|
+
// search API result doesn't give us head.ref or merged_at — need a
|
|
106
|
+
// pulls.get to fill these in. Batch via Promise.all later if perf
|
|
107
|
+
// becomes a concern.
|
|
108
|
+
let headBranch = "";
|
|
109
|
+
let merged = false;
|
|
110
|
+
try {
|
|
111
|
+
const { data: pr } = await octokit.pulls.get({
|
|
112
|
+
owner: args.owner,
|
|
113
|
+
repo: args.repo,
|
|
114
|
+
pull_number: item.number,
|
|
115
|
+
});
|
|
116
|
+
headBranch = pr.head?.ref ?? "";
|
|
117
|
+
merged = Boolean(pr.merged_at);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
// Best-effort — keep title/state from the search result.
|
|
121
|
+
}
|
|
122
|
+
byNumber.set(item.number, {
|
|
123
|
+
number: item.number,
|
|
124
|
+
title: item.title,
|
|
125
|
+
labels,
|
|
126
|
+
headBranch,
|
|
127
|
+
state: item.state === "closed" ? "closed" : "open",
|
|
128
|
+
merged,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
catch (e) {
|
|
133
|
+
console.error(`Warning: branch-prefix search failed (${e.message}). Continuing with label scan only.`);
|
|
134
|
+
}
|
|
135
|
+
// 2. Label scan — catches any slowcook PR that lacks a slowcook/
|
|
136
|
+
// branch but DID get labelled.
|
|
137
|
+
const labels = [
|
|
138
|
+
"slowcook-spec",
|
|
139
|
+
"slowcook-tests",
|
|
140
|
+
"slowcook-mockup",
|
|
141
|
+
"slowcook-brew",
|
|
142
|
+
"slowcook-chef",
|
|
143
|
+
];
|
|
144
|
+
for (const label of labels) {
|
|
145
|
+
try {
|
|
146
|
+
const issues = await octokit.paginate(octokit.issues.listForRepo, {
|
|
147
|
+
owner: args.owner,
|
|
148
|
+
repo: args.repo,
|
|
149
|
+
state: "all",
|
|
150
|
+
labels: label,
|
|
151
|
+
per_page: 100,
|
|
152
|
+
});
|
|
153
|
+
for (const issue of issues) {
|
|
154
|
+
if (!issue.pull_request)
|
|
155
|
+
continue;
|
|
156
|
+
if (byNumber.has(issue.number)) {
|
|
157
|
+
// Already counted — merge labels in case we missed one.
|
|
158
|
+
const existing = byNumber.get(issue.number);
|
|
159
|
+
if (!existing.labels.includes(label))
|
|
160
|
+
existing.labels.push(label);
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
let headBranch = "";
|
|
164
|
+
let merged = false;
|
|
165
|
+
try {
|
|
166
|
+
const { data: pr } = await octokit.pulls.get({
|
|
167
|
+
owner: args.owner,
|
|
168
|
+
repo: args.repo,
|
|
169
|
+
pull_number: issue.number,
|
|
170
|
+
});
|
|
171
|
+
headBranch = pr.head?.ref ?? "";
|
|
172
|
+
merged = Boolean(pr.merged_at);
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
// Best-effort.
|
|
176
|
+
}
|
|
177
|
+
byNumber.set(issue.number, {
|
|
178
|
+
number: issue.number,
|
|
179
|
+
title: issue.title,
|
|
180
|
+
labels: (issue.labels ?? [])
|
|
181
|
+
.map((l) => (typeof l === "string" ? l : l.name ?? ""))
|
|
182
|
+
.filter((s) => typeof s === "string" && s.length > 0),
|
|
183
|
+
headBranch,
|
|
184
|
+
state: issue.state === "closed" ? "closed" : "open",
|
|
185
|
+
merged,
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
// Label may not exist on the repo (e.g. consumer never used vibe).
|
|
191
|
+
// Skip silently — fine to be missing some categories.
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return Array.from(byNumber.values());
|
|
195
|
+
}
|
|
196
|
+
function parseArgs(argv) {
|
|
197
|
+
const out = {
|
|
198
|
+
repoRoot: process.cwd(),
|
|
199
|
+
owner: undefined,
|
|
200
|
+
repo: undefined,
|
|
201
|
+
format: "table",
|
|
202
|
+
};
|
|
203
|
+
for (let i = 0; i < argv.length; i++) {
|
|
204
|
+
const a = argv[i];
|
|
205
|
+
const next = argv[i + 1];
|
|
206
|
+
if (a === "--cwd" && next) {
|
|
207
|
+
out.repoRoot = next;
|
|
208
|
+
i++;
|
|
209
|
+
}
|
|
210
|
+
else if (a === "--owner" && next) {
|
|
211
|
+
out.owner = next;
|
|
212
|
+
i++;
|
|
213
|
+
}
|
|
214
|
+
else if (a === "--repo" && next) {
|
|
215
|
+
out.repo = next;
|
|
216
|
+
i++;
|
|
217
|
+
}
|
|
218
|
+
else if (a === "--json") {
|
|
219
|
+
out.format = "json";
|
|
220
|
+
}
|
|
221
|
+
else if (a === "--help" || a === "-h") {
|
|
222
|
+
printHelp();
|
|
223
|
+
process.exit(0);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return out;
|
|
227
|
+
}
|
|
228
|
+
function resolveOwnerRepo(args) {
|
|
229
|
+
if (args.owner && args.repo)
|
|
230
|
+
return { owner: args.owner, repo: args.repo };
|
|
231
|
+
// Detect from git remote.
|
|
232
|
+
try {
|
|
233
|
+
const url = execSync("git remote get-url origin", {
|
|
234
|
+
cwd: args.repoRoot,
|
|
235
|
+
encoding: "utf8",
|
|
236
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
237
|
+
}).trim();
|
|
238
|
+
const m = url.match(/github\.com[:/]([^/]+)\/([^/.]+)(?:\.git)?$/);
|
|
239
|
+
if (m) {
|
|
240
|
+
return { owner: args.owner ?? m[1], repo: args.repo ?? m[2] };
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
// not a git repo, or no origin — fine
|
|
245
|
+
}
|
|
246
|
+
return { owner: args.owner, repo: args.repo };
|
|
247
|
+
}
|
|
248
|
+
// Silence the unused-import warning when stories status doesn't need
|
|
249
|
+
// the adapter directly. Keep the import handy for future subcommands
|
|
250
|
+
// (e.g. `stories close --pr N` could use addIssueLabels).
|
|
251
|
+
void GitHubAdapter;
|
|
252
|
+
function printHelp() {
|
|
253
|
+
console.log(`
|
|
254
|
+
slowcook stories — per-story status across the slowcook pipeline (0.19.5-α)
|
|
255
|
+
|
|
256
|
+
Usage:
|
|
257
|
+
slowcook stories status [--cwd <path>] [--owner <login>] [--repo <name>] [--json]
|
|
258
|
+
|
|
259
|
+
Subcommands:
|
|
260
|
+
status Render a table of story id × pipeline stage (refine / testgen
|
|
261
|
+
/ vibe / brew / chef). Reads specs/_index.yaml + queries the
|
|
262
|
+
forge for PRs labelled with the slowcook-* stage labels.
|
|
263
|
+
|
|
264
|
+
Cell semantics:
|
|
265
|
+
✓ — merged PR exists for this stage
|
|
266
|
+
→ — open PR exists for this stage
|
|
267
|
+
✗ — PR was opened but closed unmerged
|
|
268
|
+
— — no PR found for this stage
|
|
269
|
+
|
|
270
|
+
With --json, emits the same data as machine-readable JSON.
|
|
271
|
+
|
|
272
|
+
Environment:
|
|
273
|
+
GITHUB_TOKEN | GH_TOKEN Required to query the forge. Without it,
|
|
274
|
+
the table renders from specs/_index.yaml
|
|
275
|
+
only and reports all stages as absent.
|
|
276
|
+
|
|
277
|
+
Refs: aminazar/slowcook#146 finding 6.
|
|
278
|
+
`);
|
|
279
|
+
}
|
|
280
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/stories/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `slowcook stories status` pure helper — 0.19.5-α (sc#146 #6).
|
|
3
|
+
*
|
|
4
|
+
* Cross-references the consumer's `specs/_index.yaml` against PR/label
|
|
5
|
+
* facts to produce a per-story stage table. Pure function — no fs, no
|
|
6
|
+
* network. The CLI wrapper (`./index.ts`) gathers the inputs.
|
|
7
|
+
*
|
|
8
|
+
* Stage mapping (per slowcook conventions):
|
|
9
|
+
*
|
|
10
|
+
* | Stage | Slowcook label evidence |
|
|
11
|
+
* |---------|-------------------------------|
|
|
12
|
+
* | refine | a `slowcook-spec` PR exists |
|
|
13
|
+
* | testgen | a `slowcook-tests` PR exists |
|
|
14
|
+
* | vibe | a `slowcook-mockup` PR exists |
|
|
15
|
+
* | brew | a `slowcook-brew` PR exists |
|
|
16
|
+
* | chef | a `slowcook-chef` PR exists |
|
|
17
|
+
*
|
|
18
|
+
* Per-stage cell semantics:
|
|
19
|
+
*
|
|
20
|
+
* - `✓` — a PR with the matching label exists AND is merged
|
|
21
|
+
* - `→` — a PR with the matching label exists AND is open
|
|
22
|
+
* - `✗` — a PR was opened but closed unmerged
|
|
23
|
+
* - `—` — no PR found for this stage
|
|
24
|
+
*
|
|
25
|
+
* For consumers running the local-pipeline pattern (see
|
|
26
|
+
* `docs/local-pipeline-role.md`), the slowcook labels may not be
|
|
27
|
+
* applied to human-driven PRs. In that case the helper falls back
|
|
28
|
+
* to matching by PR-branch-name (`slowcook/<kind>/story-N` →
|
|
29
|
+
* stage=<kind>).
|
|
30
|
+
*
|
|
31
|
+
* Gantt-style stage-by-stage output is parked for a follow-up
|
|
32
|
+
* (sc#146 #6 acceptance: "Defer the Gantt-style output to a follow-up.
|
|
33
|
+
* Just ship the underlying table first.").
|
|
34
|
+
*/
|
|
35
|
+
import type { SpecIndex, SpecIndexEntry } from "@slowcook-ai/core";
|
|
36
|
+
export type StoriesStatusCell = "merged" | "open" | "closed_unmerged" | "absent";
|
|
37
|
+
export interface StoriesStatusRow {
|
|
38
|
+
storyId: string;
|
|
39
|
+
title: string;
|
|
40
|
+
status: SpecIndexEntry["status"];
|
|
41
|
+
sourceIssue: string | undefined;
|
|
42
|
+
/** Per-stage status. Stages: refine / testgen / vibe / brew / chef. */
|
|
43
|
+
stages: Record<"refine" | "testgen" | "vibe" | "brew" | "chef", StoriesStatusCell>;
|
|
44
|
+
}
|
|
45
|
+
export interface PullRequestFact {
|
|
46
|
+
number: number;
|
|
47
|
+
title: string;
|
|
48
|
+
/** Source-of-truth labels on the PR. */
|
|
49
|
+
labels: string[];
|
|
50
|
+
/** Branch name; used as the fallback signal when labels are absent. */
|
|
51
|
+
headBranch: string;
|
|
52
|
+
/** "open" | "closed". */
|
|
53
|
+
state: "open" | "closed";
|
|
54
|
+
/** True iff the PR is closed AND was merged. */
|
|
55
|
+
merged: boolean;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Build the status table for every story in the index.
|
|
59
|
+
*
|
|
60
|
+
* @param specIndex - the parsed `specs/_index.yaml` content
|
|
61
|
+
* @param pullRequests - all PRs in the repo (merged + open + closed-unmerged).
|
|
62
|
+
* The CLI wrapper passes the union of label-matched
|
|
63
|
+
* results; pass an empty array if GH access is
|
|
64
|
+
* unavailable + the row will report all stages as
|
|
65
|
+
* absent (still useful for spec-only summary).
|
|
66
|
+
*/
|
|
67
|
+
export declare function buildStoriesStatus(specIndex: SpecIndex, pullRequests: PullRequestFact[]): StoriesStatusRow[];
|
|
68
|
+
/**
|
|
69
|
+
* Render a status row set as an ASCII-art table. Used by the CLI
|
|
70
|
+
* wrapper's stdout. Pure function — no colour codes, no terminal
|
|
71
|
+
* width detection.
|
|
72
|
+
*/
|
|
73
|
+
export declare function renderStoriesStatusTable(rows: StoriesStatusRow[]): string;
|
|
74
|
+
//# sourceMappingURL=status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/commands/stories/status.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnE,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,MAAM,GAAG,iBAAiB,GAAG,QAAQ,CAAC;AAEjF,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAC;IACjC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,uEAAuE;IACvE,MAAM,EAAE,MAAM,CAAC,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,iBAAiB,CAAC,CAAC;CACpF;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,uEAAuE;IACvE,UAAU,EAAE,MAAM,CAAC;IACnB,yBAAyB;IACzB,KAAK,EAAE,MAAM,GAAG,QAAQ,CAAC;IACzB,gDAAgD;IAChD,MAAM,EAAE,OAAO,CAAC;CACjB;AA2BD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,SAAS,EACpB,YAAY,EAAE,eAAe,EAAE,GAC9B,gBAAgB,EAAE,CAsBpB;AAiCD;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,gBAAgB,EAAE,GAAG,MAAM,CAuDzE"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `slowcook stories status` pure helper — 0.19.5-α (sc#146 #6).
|
|
3
|
+
*
|
|
4
|
+
* Cross-references the consumer's `specs/_index.yaml` against PR/label
|
|
5
|
+
* facts to produce a per-story stage table. Pure function — no fs, no
|
|
6
|
+
* network. The CLI wrapper (`./index.ts`) gathers the inputs.
|
|
7
|
+
*
|
|
8
|
+
* Stage mapping (per slowcook conventions):
|
|
9
|
+
*
|
|
10
|
+
* | Stage | Slowcook label evidence |
|
|
11
|
+
* |---------|-------------------------------|
|
|
12
|
+
* | refine | a `slowcook-spec` PR exists |
|
|
13
|
+
* | testgen | a `slowcook-tests` PR exists |
|
|
14
|
+
* | vibe | a `slowcook-mockup` PR exists |
|
|
15
|
+
* | brew | a `slowcook-brew` PR exists |
|
|
16
|
+
* | chef | a `slowcook-chef` PR exists |
|
|
17
|
+
*
|
|
18
|
+
* Per-stage cell semantics:
|
|
19
|
+
*
|
|
20
|
+
* - `✓` — a PR with the matching label exists AND is merged
|
|
21
|
+
* - `→` — a PR with the matching label exists AND is open
|
|
22
|
+
* - `✗` — a PR was opened but closed unmerged
|
|
23
|
+
* - `—` — no PR found for this stage
|
|
24
|
+
*
|
|
25
|
+
* For consumers running the local-pipeline pattern (see
|
|
26
|
+
* `docs/local-pipeline-role.md`), the slowcook labels may not be
|
|
27
|
+
* applied to human-driven PRs. In that case the helper falls back
|
|
28
|
+
* to matching by PR-branch-name (`slowcook/<kind>/story-N` →
|
|
29
|
+
* stage=<kind>).
|
|
30
|
+
*
|
|
31
|
+
* Gantt-style stage-by-stage output is parked for a follow-up
|
|
32
|
+
* (sc#146 #6 acceptance: "Defer the Gantt-style output to a follow-up.
|
|
33
|
+
* Just ship the underlying table first.").
|
|
34
|
+
*/
|
|
35
|
+
const STAGE_LABEL_MAP = {
|
|
36
|
+
refine: "slowcook-spec",
|
|
37
|
+
testgen: "slowcook-tests",
|
|
38
|
+
vibe: "slowcook-mockup",
|
|
39
|
+
brew: "slowcook-brew",
|
|
40
|
+
chef: "slowcook-chef",
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Branch-name → stage map, used when labels are absent (the
|
|
44
|
+
* local-pipeline pattern doesn't always apply labels to human PRs).
|
|
45
|
+
*
|
|
46
|
+
* `slowcook/<kind>/story-N` → kind.
|
|
47
|
+
*/
|
|
48
|
+
const BRANCH_KIND_TO_STAGE = {
|
|
49
|
+
spec: "refine",
|
|
50
|
+
tests: "testgen",
|
|
51
|
+
mockup: "vibe",
|
|
52
|
+
brew: "brew",
|
|
53
|
+
chef: "chef",
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Build the status table for every story in the index.
|
|
57
|
+
*
|
|
58
|
+
* @param specIndex - the parsed `specs/_index.yaml` content
|
|
59
|
+
* @param pullRequests - all PRs in the repo (merged + open + closed-unmerged).
|
|
60
|
+
* The CLI wrapper passes the union of label-matched
|
|
61
|
+
* results; pass an empty array if GH access is
|
|
62
|
+
* unavailable + the row will report all stages as
|
|
63
|
+
* absent (still useful for spec-only summary).
|
|
64
|
+
*/
|
|
65
|
+
export function buildStoriesStatus(specIndex, pullRequests) {
|
|
66
|
+
const rows = [];
|
|
67
|
+
const stories = specIndex.stories ?? {};
|
|
68
|
+
for (const [storyId, entry] of Object.entries(stories)) {
|
|
69
|
+
rows.push({
|
|
70
|
+
storyId,
|
|
71
|
+
title: entry.title,
|
|
72
|
+
status: entry.status,
|
|
73
|
+
sourceIssue: entry.source_issue,
|
|
74
|
+
stages: {
|
|
75
|
+
refine: stageStateForStory(storyId, "refine", pullRequests),
|
|
76
|
+
testgen: stageStateForStory(storyId, "testgen", pullRequests),
|
|
77
|
+
vibe: stageStateForStory(storyId, "vibe", pullRequests),
|
|
78
|
+
brew: stageStateForStory(storyId, "brew", pullRequests),
|
|
79
|
+
chef: stageStateForStory(storyId, "chef", pullRequests),
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
// Sort by story id ascending (lexicographic — works because ids are
|
|
84
|
+
// zero-padded strings in the convention).
|
|
85
|
+
rows.sort((a, b) => a.storyId.localeCompare(b.storyId));
|
|
86
|
+
return rows;
|
|
87
|
+
}
|
|
88
|
+
function stageStateForStory(storyId, stage, prs) {
|
|
89
|
+
const label = STAGE_LABEL_MAP[stage];
|
|
90
|
+
// Story id appears in PR title (slowcook bot convention) OR in branch
|
|
91
|
+
// name (slowcook/<kind>/story-N pattern).
|
|
92
|
+
const storyTitleRe = new RegExp(`\\bstory-${escapeRegex(storyId)}\\b`);
|
|
93
|
+
const storyBranchRe = new RegExp(`/story-${escapeRegex(storyId)}(?:-|$|/)`);
|
|
94
|
+
const matches = prs.filter((pr) => {
|
|
95
|
+
const titleMatches = storyTitleRe.test(pr.title);
|
|
96
|
+
const branchMatches = storyBranchRe.test(pr.headBranch);
|
|
97
|
+
if (!titleMatches && !branchMatches)
|
|
98
|
+
return false;
|
|
99
|
+
// Stage match: label OR branch-kind fallback.
|
|
100
|
+
if (pr.labels.includes(label))
|
|
101
|
+
return true;
|
|
102
|
+
// Fallback: branch shaped slowcook/<kind>/story-N — derive stage.
|
|
103
|
+
const branchKind = pr.headBranch.match(/^slowcook\/([a-z]+)\//)?.[1];
|
|
104
|
+
if (branchKind && BRANCH_KIND_TO_STAGE[branchKind] === stage)
|
|
105
|
+
return true;
|
|
106
|
+
return false;
|
|
107
|
+
});
|
|
108
|
+
if (matches.length === 0)
|
|
109
|
+
return "absent";
|
|
110
|
+
if (matches.some((m) => m.merged))
|
|
111
|
+
return "merged";
|
|
112
|
+
if (matches.some((m) => m.state === "open"))
|
|
113
|
+
return "open";
|
|
114
|
+
return "closed_unmerged";
|
|
115
|
+
}
|
|
116
|
+
function escapeRegex(s) {
|
|
117
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Render a status row set as an ASCII-art table. Used by the CLI
|
|
121
|
+
* wrapper's stdout. Pure function — no colour codes, no terminal
|
|
122
|
+
* width detection.
|
|
123
|
+
*/
|
|
124
|
+
export function renderStoriesStatusTable(rows) {
|
|
125
|
+
if (rows.length === 0)
|
|
126
|
+
return "(no stories in specs/_index.yaml)\n";
|
|
127
|
+
const cellGlyph = {
|
|
128
|
+
merged: "✓",
|
|
129
|
+
open: "→",
|
|
130
|
+
closed_unmerged: "✗",
|
|
131
|
+
absent: "—",
|
|
132
|
+
};
|
|
133
|
+
// Column widths (story id, title — truncate title at 50 chars).
|
|
134
|
+
const storyW = Math.max(5, ...rows.map((r) => r.storyId.length));
|
|
135
|
+
const titleW = Math.min(50, Math.max(5, ...rows.map((r) => Math.min(50, r.title.length))));
|
|
136
|
+
const stageW = 8; // "testgen" is widest header (7 chars) — add 1 for spacing
|
|
137
|
+
const sep = (w) => "─".repeat(w);
|
|
138
|
+
const header = pad("Story", storyW) +
|
|
139
|
+
" " +
|
|
140
|
+
pad("Title", titleW) +
|
|
141
|
+
" " +
|
|
142
|
+
"refine".padEnd(stageW) +
|
|
143
|
+
"testgen".padEnd(stageW) +
|
|
144
|
+
"vibe".padEnd(stageW) +
|
|
145
|
+
"brew".padEnd(stageW) +
|
|
146
|
+
"chef".padEnd(stageW);
|
|
147
|
+
const divider = sep(storyW) +
|
|
148
|
+
" " +
|
|
149
|
+
sep(titleW) +
|
|
150
|
+
" " +
|
|
151
|
+
sep(stageW - 1) + " " +
|
|
152
|
+
sep(stageW - 1) + " " +
|
|
153
|
+
sep(stageW - 1) + " " +
|
|
154
|
+
sep(stageW - 1) + " " +
|
|
155
|
+
sep(stageW - 1);
|
|
156
|
+
const lines = [header, divider];
|
|
157
|
+
for (const row of rows) {
|
|
158
|
+
const truncatedTitle = row.title.length > titleW ? row.title.slice(0, titleW - 1) + "…" : row.title;
|
|
159
|
+
lines.push(pad(row.storyId, storyW) +
|
|
160
|
+
" " +
|
|
161
|
+
pad(truncatedTitle, titleW) +
|
|
162
|
+
" " +
|
|
163
|
+
cellGlyph[row.stages.refine].padEnd(stageW) +
|
|
164
|
+
cellGlyph[row.stages.testgen].padEnd(stageW) +
|
|
165
|
+
cellGlyph[row.stages.vibe].padEnd(stageW) +
|
|
166
|
+
cellGlyph[row.stages.brew].padEnd(stageW) +
|
|
167
|
+
cellGlyph[row.stages.chef].padEnd(stageW));
|
|
168
|
+
}
|
|
169
|
+
lines.push("");
|
|
170
|
+
lines.push("Legend: ✓ merged · → open · ✗ closed-unmerged · — absent");
|
|
171
|
+
return lines.join("\n") + "\n";
|
|
172
|
+
}
|
|
173
|
+
function pad(s, w) {
|
|
174
|
+
return s.length >= w ? s : s + " ".repeat(w - s.length);
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/commands/stories/status.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upsert-agent-docs.d.ts","sourceRoot":"","sources":["../../src/commands/upsert-agent-docs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAmBH,wBAAgB,iBAAiB,IAAI,MAAM,
|
|
1
|
+
{"version":3,"file":"upsert-agent-docs.d.ts","sourceRoot":"","sources":["../../src/commands/upsert-agent-docs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAmBH,wBAAgB,iBAAiB,IAAI,MAAM,CA8J1C;AAmGD,MAAM,WAAW,qBAAqB;IACpC,aAAa,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,WAAW,CAAA;KAAE,CAAC,CAAC;IACtF,MAAM,EAAE,OAAO,GAAG,iBAAiB,GAAG,WAAW,CAAC;IAClD,SAAS,EAAE,OAAO,GAAG,iBAAiB,GAAG,cAAc,CAAC;CACzD;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,qBAAqB,CAsB5G;AAID,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAUnE"}
|
|
@@ -95,6 +95,48 @@ The slowcook pipeline opens one branch per stage (\`slowcook/<kind>/story-N\`).
|
|
|
95
95
|
- Slowcook agents stay on \`slowcook/<kind>/story-N\` branches; non-slowcook agents should use \`<your-name>/<short-description>\`.
|
|
96
96
|
- Don't \`--force-push\` to shared branches. The human PM holds admin bypass for emergencies; agents don't.
|
|
97
97
|
|
|
98
|
+
### When introducing a new package dependency in testgen
|
|
99
|
+
|
|
100
|
+
If your testgen scaffolds a file that NEEDS a not-yet-installed package (e.g. a WebSocket gateway needs \`@nestjs/websockets\` + \`socket.io\` before \`nest build\` will compile any file that imports them), follow the **no-import stub** pattern:
|
|
101
|
+
|
|
102
|
+
- **Do** add the dep to \`package.json\`. Brew runs \`pnpm install\` first and needs them present.
|
|
103
|
+
- **Don't** import the package in the stubbed file. \`nest build\` (or any test compile) runs at testgen time and will fail with "Cannot find module '<dep>'" until brew installs.
|
|
104
|
+
- **Do** scaffold the file as a no-import stub: a plain \`@Injectable()\` (or equivalent) with the decorators / types substituted by \`unknown\`-typed shims. Mark the file with \`@slowcook-stub\` on line 1.
|
|
105
|
+
- **Don't** skip the file entirely. Tests that reference the symbol need the declaration to exist for type-check; the runtime throw is fine, but the export must be importable.
|
|
106
|
+
|
|
107
|
+
Brew then \`pnpm install\`s the dep, swaps the no-import stub for the real decorators, and removes the \`@slowcook-stub\` marker.
|
|
108
|
+
|
|
109
|
+
Recorded sc#151 finding 2 — delgoosh story-006 added \`@nestjs/websockets\` for the peer-chat gateway. Initial testgen attempted the real decorators, \`nest build\` failed during the testgen PR's CI, and the workaround above was applied.
|
|
110
|
+
|
|
111
|
+
### Combined testgen+brew for small stories
|
|
112
|
+
|
|
113
|
+
The default pipeline cadence (testgen PR → merge → brew PR → merge) is sized for medium/large stories where the test contract benefits from independent human review before brew touches it. For stories where \`spec.estimate === 'small'\` AND brew is expected to touch < ~10 files, a **combined testgen+brew PR** is acceptable:
|
|
114
|
+
|
|
115
|
+
- Branch: \`slowcook/brew/story-N-<ts>\` (single branch — skip the separate \`slowcook/tests/story-N\` step)
|
|
116
|
+
- Commit: ONE commit containing both the failing test scaffold AND the impl. Title clearly states "combined testgen+brew" so reviewers know what they're looking at.
|
|
117
|
+
- PR body: explain why combined was chosen (small estimate, narrow surface). Reviewers can still red-line the test contract before approving — the diff just isn't split across two PRs.
|
|
118
|
+
|
|
119
|
+
When NOT to combine: any story with \`estimate: medium\` or \`large\`, any story that introduces a new dependency that brew will install, any story where the test contract reasonably might change during impl. When in doubt, split.
|
|
120
|
+
|
|
121
|
+
Recorded sc#151 finding 6 — the combined-PR variant was used for delgoosh story-017 (mirror of story-006) and shipped cleanly in one PR.
|
|
122
|
+
|
|
123
|
+
### Pattern: local pipeline (driving slowcook from your IDE)
|
|
124
|
+
|
|
125
|
+
The "local pipeline" pattern: a Claude Code (or similar IDE-bound) session drives the slowcook pipeline locally — emitting refine / testgen / vibe / plate / brew / chef artefacts on slowcook-shaped branches — WITHOUT calling \`slowcook brew\` / \`slowcook refine\` etc. Same artefact shapes the bots emit, but the LLM call is the human's IDE-bound agent rather than slowcook's worker.
|
|
126
|
+
|
|
127
|
+
When to use: API spend matters, you want to red-line every stage before it lands, or you're testing slowcook changes against a live consumer. When NOT: routine stories on a healthy bot pipeline, multiple parallel stories, anything where agent autonomy is the point.
|
|
128
|
+
|
|
129
|
+
Conventions:
|
|
130
|
+
- Branch names match the bot conventions (\`slowcook/<kind>/story-N\`); reviewers shouldn't have to tell.
|
|
131
|
+
- One PR per stage by default; combined small-story PR per the section above is allowed.
|
|
132
|
+
- Run \`slowcook cost log\` at the end of every story so the session's IDE cost shows in the aggregator alongside bot costs.
|
|
133
|
+
- After every slowcook PR you ship lands + version-bumps, re-run \`slowcook check spec specs/story-*.yaml\` against your consumer so new gates catch existing drift.
|
|
134
|
+
- DON'T run \`slowcook brew\` or any LLM-dispatch slowcook command from the local pipeline — that's a parallel agent you didn't authorise.
|
|
135
|
+
|
|
136
|
+
Full doc: [\`docs/local-pipeline-role.md\`](https://github.com/aminazar/slowcook/blob/main/docs/local-pipeline-role.md) in the slowcook repo.
|
|
137
|
+
|
|
138
|
+
Recorded sc#145 finding 6 — pattern emerged from the delgoosh dogfood (2026-05) and shipped 5 batches of slowcook feedback as a side effect.
|
|
139
|
+
|
|
98
140
|
### Working alongside other agents (multi-agent choreography)
|
|
99
141
|
|
|
100
142
|
When your work depends on another agent's still-open PR — common when one agent owns the app shell + another owns a feature inside it — follow this:
|