@slowcook-ai/cli 0.19.5 → 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 +184 -28
- package/dist/cli.js +53 -73
- package/dist/cli.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.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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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `packages/cli/src/commands.manifest.ts`
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth for slowcook's user-facing command surface.
|
|
5
|
+
* Drives BOTH `slowcook help` output AND the auto-generated command
|
|
6
|
+
* catalog in `packages/cli/README.md`.
|
|
7
|
+
*
|
|
8
|
+
* Adding a command: append an entry below. Update both `slowcook help`
|
|
9
|
+
* AND README sync at the same time via the CI gate in
|
|
10
|
+
* `.github/workflows/readme-help-sync.yml`.
|
|
11
|
+
*
|
|
12
|
+
* Removing a command: don't. Mark `status: "deprecated"` + keep the
|
|
13
|
+
* entry for one release with a deprecation warning, then remove.
|
|
14
|
+
* Backward compat is a public commitment.
|
|
15
|
+
*/
|
|
16
|
+
export type CommandStatus = "stable" | "alpha" | "experimental" | "deprecated";
|
|
17
|
+
export type CommandGroup = "pipeline" | "plumbing" | "checks" | "knowledge" | "ops" | "experimental";
|
|
18
|
+
export interface CommandEntry {
|
|
19
|
+
/** Top-level subcommand name (e.g. "refine", "brew", "stories"). */
|
|
20
|
+
name: string;
|
|
21
|
+
/** One-line usage signature shown in `slowcook help`. */
|
|
22
|
+
usage: string;
|
|
23
|
+
/** One-sentence description. Avoid version stamps + sc# refs (those rot). */
|
|
24
|
+
description: string;
|
|
25
|
+
/** Grouping for README catalog rendering. */
|
|
26
|
+
group: CommandGroup;
|
|
27
|
+
/** Stability marker. Defaults to "stable" if omitted. */
|
|
28
|
+
status?: CommandStatus;
|
|
29
|
+
/** Aliases honored by the cli's switch (e.g. "testgen" → "recipe"). */
|
|
30
|
+
aliases?: string[];
|
|
31
|
+
/** Hide from `slowcook help` + README (still callable). Used for `version`, `help`. */
|
|
32
|
+
hidden?: boolean;
|
|
33
|
+
}
|
|
34
|
+
export declare const COMMANDS: ReadonlyArray<CommandEntry>;
|
|
35
|
+
export declare function findCommand(nameOrAlias: string): CommandEntry | undefined;
|
|
36
|
+
export declare function visibleCommands(): CommandEntry[];
|
|
37
|
+
//# sourceMappingURL=commands.manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.manifest.d.ts","sourceRoot":"","sources":["../src/commands.manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,OAAO,GAAG,cAAc,GAAG,YAAY,CAAC;AAE/E,MAAM,MAAM,YAAY,GACpB,UAAU,GACV,UAAU,GACV,QAAQ,GACR,WAAW,GACX,KAAK,GACL,cAAc,CAAC;AAEnB,MAAM,WAAW,YAAY;IAC3B,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAC;IACd,6EAA6E;IAC7E,WAAW,EAAE,MAAM,CAAC;IACpB,6CAA6C;IAC7C,KAAK,EAAE,YAAY,CAAC;IACpB,yDAAyD;IACzD,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,uFAAuF;IACvF,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,eAAO,MAAM,QAAQ,EAAE,aAAa,CAAC,YAAY,CAwQhD,CAAC;AAWF,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAEzE;AAED,wBAAgB,eAAe,IAAI,YAAY,EAAE,CAEhD"}
|