@slowcook-ai/cli 0.16.0-alpha.3 → 0.17.0-alpha.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 +10 -0
- package/dist/cli.js +49 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/brew/agent.d.ts +25 -1
- package/dist/commands/brew/agent.d.ts.map +1 -1
- package/dist/commands/brew/agent.js +123 -20
- package/dist/commands/brew/agent.js.map +1 -1
- package/dist/commands/brew/halt.d.ts +1 -1
- package/dist/commands/brew/halt.d.ts.map +1 -1
- package/dist/commands/brew/halt.js +13 -0
- package/dist/commands/brew/halt.js.map +1 -1
- package/dist/commands/check/index.d.ts +14 -0
- package/dist/commands/check/index.d.ts.map +1 -0
- package/dist/commands/check/index.js +75 -0
- package/dist/commands/check/index.js.map +1 -0
- package/dist/commands/check/mock-isolation.d.ts +52 -0
- package/dist/commands/check/mock-isolation.d.ts.map +1 -0
- package/dist/commands/check/mock-isolation.js +186 -0
- package/dist/commands/check/mock-isolation.js.map +1 -0
- package/dist/commands/init/mock.d.ts.map +1 -1
- package/dist/commands/init/mock.js +47 -13
- package/dist/commands/init/mock.js.map +1 -1
- package/dist/commands/on-mockup-approved/index.d.ts +25 -0
- package/dist/commands/on-mockup-approved/index.d.ts.map +1 -0
- package/dist/commands/on-mockup-approved/index.js +359 -0
- package/dist/commands/on-mockup-approved/index.js.map +1 -0
- package/dist/commands/plate/classify.d.ts +65 -0
- package/dist/commands/plate/classify.d.ts.map +1 -0
- package/dist/commands/plate/classify.js +194 -0
- package/dist/commands/plate/classify.js.map +1 -0
- package/dist/commands/plate/index.d.ts.map +1 -1
- package/dist/commands/plate/index.js +259 -34
- package/dist/commands/plate/index.js.map +1 -1
- package/dist/commands/port/index.d.ts +30 -0
- package/dist/commands/port/index.d.ts.map +1 -0
- package/dist/commands/port/index.js +237 -0
- package/dist/commands/port/index.js.map +1 -0
- package/dist/commands/port/transform.d.ts +68 -0
- package/dist/commands/port/transform.d.ts.map +1 -0
- package/dist/commands/port/transform.js +122 -0
- package/dist/commands/port/transform.js.map +1 -0
- package/dist/commands/preview/config.d.ts +73 -0
- package/dist/commands/preview/config.d.ts.map +1 -0
- package/dist/commands/preview/config.js +200 -0
- package/dist/commands/preview/config.js.map +1 -0
- package/dist/commands/preview/deploy.d.ts +35 -0
- package/dist/commands/preview/deploy.d.ts.map +1 -0
- package/dist/commands/preview/deploy.js +247 -0
- package/dist/commands/preview/deploy.js.map +1 -0
- package/dist/commands/preview/index.d.ts +9 -0
- package/dist/commands/preview/index.d.ts.map +1 -0
- package/dist/commands/preview/index.js +67 -0
- package/dist/commands/preview/index.js.map +1 -0
- package/dist/commands/preview/ssh.d.ts +49 -0
- package/dist/commands/preview/ssh.d.ts.map +1 -0
- package/dist/commands/preview/ssh.js +99 -0
- package/dist/commands/preview/ssh.js.map +1 -0
- package/dist/commands/preview/teardown.d.ts +25 -0
- package/dist/commands/preview/teardown.d.ts.map +1 -0
- package/dist/commands/preview/teardown.js +164 -0
- package/dist/commands/preview/teardown.js.map +1 -0
- package/dist/commands/recon/index.d.ts +60 -0
- package/dist/commands/recon/index.d.ts.map +1 -0
- package/dist/commands/recon/index.js +278 -0
- package/dist/commands/recon/index.js.map +1 -0
- package/dist/commands/refine/context.d.ts +12 -0
- package/dist/commands/refine/context.d.ts.map +1 -1
- package/dist/commands/refine/context.js +72 -0
- package/dist/commands/refine/context.js.map +1 -1
- package/dist/commands/refine/history-index.d.ts +84 -0
- package/dist/commands/refine/history-index.d.ts.map +1 -0
- package/dist/commands/refine/history-index.js +289 -0
- package/dist/commands/refine/history-index.js.map +1 -0
- package/dist/commands/refine/index.d.ts.map +1 -1
- package/dist/commands/refine/index.js +28 -0
- package/dist/commands/refine/index.js.map +1 -1
- package/dist/commands/run-mock/index.d.ts +34 -0
- package/dist/commands/run-mock/index.d.ts.map +1 -0
- package/dist/commands/run-mock/index.js +308 -0
- package/dist/commands/run-mock/index.js.map +1 -0
- package/dist/commands/vibe/emit.d.ts +6 -0
- package/dist/commands/vibe/emit.d.ts.map +1 -1
- package/dist/commands/vibe/emit.js +12 -0
- package/dist/commands/vibe/emit.js.map +1 -1
- package/dist/commands/vibe/index.d.ts.map +1 -1
- package/dist/commands/vibe/index.js +180 -47
- package/dist/commands/vibe/index.js.map +1 -1
- package/package.json +4 -3
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `slowcook on-mockup-approved --pr <number>` — 0.16.0-α.25.
|
|
3
|
+
*
|
|
4
|
+
* Called from a workflow that fires on `pull_request.labeled` with
|
|
5
|
+
* label = `slowcook-mockup-approved`. Walks every cost source for the
|
|
6
|
+
* story (refine on the source issue, refine + spec-merge on the spec
|
|
7
|
+
* PR, recipe on the tests PR, vibe + plate on the mockup PR), itemizes
|
|
8
|
+
* each run, and posts (or UPDATES) a cost-rollup audit comment on the
|
|
9
|
+
* originating GitHub issue.
|
|
10
|
+
*
|
|
11
|
+
* α.25 changes vs α.23:
|
|
12
|
+
* - Walks ALL related sources, not just the mockup PR. Captures
|
|
13
|
+
* refine + recipe runs that previously went uncounted.
|
|
14
|
+
* - Itemizes each run (one row per cost marker) instead of grouping
|
|
15
|
+
* by agent. Includes timestamp, agent, model, $, source link, and
|
|
16
|
+
* commit SHA when available (parsed from plate's breadcrumb JSON).
|
|
17
|
+
* - Idempotent: looks for an existing `slowcook:on-mockup-approved`
|
|
18
|
+
* marker in the issue's comments; updates that comment in place
|
|
19
|
+
* instead of double-posting.
|
|
20
|
+
*
|
|
21
|
+
* Pairs with on-spec-merged / on-tests-merged / on-brew-merged so the
|
|
22
|
+
* issue thread tells the full pipeline story end-to-end.
|
|
23
|
+
*/
|
|
24
|
+
import { execSync } from "node:child_process";
|
|
25
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
26
|
+
import { join } from "node:path";
|
|
27
|
+
import YAML from "yaml";
|
|
28
|
+
import { Octokit } from "@octokit/rest";
|
|
29
|
+
function parseArgs(argv) {
|
|
30
|
+
const args = { prNumber: 0, repoRoot: process.cwd() };
|
|
31
|
+
for (let i = 0; i < argv.length; i++) {
|
|
32
|
+
const arg = argv[i];
|
|
33
|
+
const next = argv[i + 1];
|
|
34
|
+
if (arg === "--pr" && next) {
|
|
35
|
+
args.prNumber = parseInt(next, 10);
|
|
36
|
+
i++;
|
|
37
|
+
}
|
|
38
|
+
else if (arg === "--cwd" && next) {
|
|
39
|
+
args.repoRoot = next;
|
|
40
|
+
i++;
|
|
41
|
+
}
|
|
42
|
+
else if (arg === "--owner" && next) {
|
|
43
|
+
args.owner = next;
|
|
44
|
+
i++;
|
|
45
|
+
}
|
|
46
|
+
else if (arg === "--repo" && next) {
|
|
47
|
+
args.repo = next;
|
|
48
|
+
i++;
|
|
49
|
+
}
|
|
50
|
+
else if (arg === "--help" || arg === "-h") {
|
|
51
|
+
printHelp();
|
|
52
|
+
process.exit(0);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (!args.prNumber || isNaN(args.prNumber)) {
|
|
56
|
+
console.error("Missing required --pr <number>");
|
|
57
|
+
printHelp();
|
|
58
|
+
process.exit(64);
|
|
59
|
+
}
|
|
60
|
+
return args;
|
|
61
|
+
}
|
|
62
|
+
function printHelp() {
|
|
63
|
+
console.log(`
|
|
64
|
+
slowcook on-mockup-approved — post (or update) a cost rollup on the source issue
|
|
65
|
+
|
|
66
|
+
Triggered by a workflow listening for pull_request.labeled events on
|
|
67
|
+
PRs labeled \`slowcook-mockup\` when the \`slowcook-mockup-approved\`
|
|
68
|
+
label is added. Walks every related source (issue, spec PR, tests PR,
|
|
69
|
+
mockup PR), itemizes every cost marker, posts a chronological table.
|
|
70
|
+
|
|
71
|
+
Idempotent: re-running updates the existing rollup comment on the
|
|
72
|
+
issue rather than posting a new one.
|
|
73
|
+
|
|
74
|
+
Usage:
|
|
75
|
+
slowcook on-mockup-approved --pr <number> [options]
|
|
76
|
+
|
|
77
|
+
Options:
|
|
78
|
+
--pr <number> Mockup PR number (required)
|
|
79
|
+
--cwd <path> Repo working directory (default: .)
|
|
80
|
+
--owner <login> Repo owner (default: detected from git remote)
|
|
81
|
+
--repo <name> Repo name (default: detected from git remote)
|
|
82
|
+
|
|
83
|
+
Environment:
|
|
84
|
+
GITHUB_TOKEN (required) Token with issues:write + pull-requests:read
|
|
85
|
+
|
|
86
|
+
Exit codes:
|
|
87
|
+
0 comment posted/updated (or nothing to do)
|
|
88
|
+
2 script error
|
|
89
|
+
`);
|
|
90
|
+
}
|
|
91
|
+
function detectOwnerRepo(cwd) {
|
|
92
|
+
try {
|
|
93
|
+
const url = execSync("git remote get-url origin", {
|
|
94
|
+
cwd,
|
|
95
|
+
encoding: "utf8",
|
|
96
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
97
|
+
}).trim();
|
|
98
|
+
const m = url.match(/github\.com[:/]([^/]+)\/([^/.]+)(?:\.git)?$/);
|
|
99
|
+
if (m && m[1] && m[2])
|
|
100
|
+
return { owner: m[1], repo: m[2] };
|
|
101
|
+
}
|
|
102
|
+
catch { /* ignore */ }
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
const COST_MARKER_RE = /<!--\s*slowcook:cost\s+([^>]+?)\s*-->/g;
|
|
106
|
+
const ROLLUP_MARKER = "slowcook:on-mockup-approved";
|
|
107
|
+
/** Parse `key1=value1 key2=value2` pairs from a cost-marker body. */
|
|
108
|
+
function parseMarkerKvs(s) {
|
|
109
|
+
const out = {};
|
|
110
|
+
for (const m of s.matchAll(/(\w+)=([^\s]+)/g)) {
|
|
111
|
+
out[m[1]] = m[2];
|
|
112
|
+
}
|
|
113
|
+
return out;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* 0.16.0-α.25 — legacy-prose fallback for vibe runs that pre-date α.24's
|
|
117
|
+
* structured `<!-- slowcook:cost -->` emission. Vibe ≤α.11 wrote
|
|
118
|
+
* "Generated by `slowcook vibe@VERSION` (spend $X.XXXX)" in its PR
|
|
119
|
+
* body. We pluck that out so dogfood rollups stay accurate.
|
|
120
|
+
*/
|
|
121
|
+
const VIBE_LEGACY_PROSE_RE = /Generated by `slowcook vibe@([^`]+)`[^(]*\(spend \$([0-9.]+)\)/;
|
|
122
|
+
function extractCostRunsFromBody(body, source, timestamp) {
|
|
123
|
+
const out = [];
|
|
124
|
+
// Legacy prose vibe — only fires when no structured vibe marker
|
|
125
|
+
// also exists (so we don't double-count post-α.24 vibe runs).
|
|
126
|
+
if (!/slowcook:cost\s+agent=vibe/.test(body)) {
|
|
127
|
+
const proseMatch = body.match(VIBE_LEGACY_PROSE_RE);
|
|
128
|
+
if (proseMatch) {
|
|
129
|
+
const usd = parseFloat(proseMatch[2]);
|
|
130
|
+
if (!Number.isNaN(usd)) {
|
|
131
|
+
out.push({
|
|
132
|
+
agent: "vibe",
|
|
133
|
+
usd,
|
|
134
|
+
cli: proseMatch[1],
|
|
135
|
+
timestamp,
|
|
136
|
+
source,
|
|
137
|
+
commitSha: null,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
COST_MARKER_RE.lastIndex = 0;
|
|
143
|
+
// For plate-reply breadcrumbs, look for the amendment_commit so we
|
|
144
|
+
// can link to the diff. Same comment body usually carries both
|
|
145
|
+
// markers (cost + breadcrumb).
|
|
146
|
+
let amendmentCommit = null;
|
|
147
|
+
const breadcrumbMatch = body.match(/slowcook:plate-reply\s*\n\s*(\{[\s\S]*?\})\s*\n\s*-->/);
|
|
148
|
+
if (breadcrumbMatch && breadcrumbMatch[1]) {
|
|
149
|
+
try {
|
|
150
|
+
const payload = JSON.parse(breadcrumbMatch[1]);
|
|
151
|
+
if (payload.amendment_commit)
|
|
152
|
+
amendmentCommit = payload.amendment_commit;
|
|
153
|
+
}
|
|
154
|
+
catch { /* ignore */ }
|
|
155
|
+
}
|
|
156
|
+
let m;
|
|
157
|
+
while ((m = COST_MARKER_RE.exec(body)) !== null) {
|
|
158
|
+
const kvs = parseMarkerKvs(m[1]);
|
|
159
|
+
const usd = parseFloat(kvs["usd"] ?? "0");
|
|
160
|
+
if (!kvs["agent"] || Number.isNaN(usd))
|
|
161
|
+
continue;
|
|
162
|
+
out.push({
|
|
163
|
+
agent: kvs["agent"],
|
|
164
|
+
usd,
|
|
165
|
+
model: kvs["model"],
|
|
166
|
+
cli: kvs["cli"],
|
|
167
|
+
timestamp,
|
|
168
|
+
source,
|
|
169
|
+
commitSha: amendmentCommit,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
return out;
|
|
173
|
+
}
|
|
174
|
+
async function fetchPrComments(octokit, owner, repo, prNumber) {
|
|
175
|
+
return octokit.paginate(octokit.rest.issues.listComments, {
|
|
176
|
+
owner, repo, issue_number: prNumber, per_page: 100,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
async function fetchIssueComments(octokit, owner, repo, issueNumber) {
|
|
180
|
+
return octokit.paginate(octokit.rest.issues.listComments, {
|
|
181
|
+
owner, repo, issue_number: issueNumber, per_page: 100,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
async function findRelatedPrs(octokit, owner, repo, storyId) {
|
|
185
|
+
// Search PRs by title for `story-{id}`. Captures spec, tests,
|
|
186
|
+
// mockup, brew PRs all in one pass. Excludes superseded specs etc.
|
|
187
|
+
const q = `repo:${owner}/${repo} is:pr in:title story-${storyId}`;
|
|
188
|
+
const res = await octokit.rest.search.issuesAndPullRequests({ q, per_page: 50 });
|
|
189
|
+
const out = [];
|
|
190
|
+
for (const item of res.data.items) {
|
|
191
|
+
if (!item.pull_request)
|
|
192
|
+
continue;
|
|
193
|
+
const title = item.title.toLowerCase();
|
|
194
|
+
let kind;
|
|
195
|
+
if (title.startsWith("spec:"))
|
|
196
|
+
kind = "spec";
|
|
197
|
+
else if (title.startsWith("tests:") || title.startsWith("recipe:"))
|
|
198
|
+
kind = "tests";
|
|
199
|
+
else if (title.startsWith("mockup:"))
|
|
200
|
+
kind = "mockup";
|
|
201
|
+
else if (title.startsWith("brew") || title.startsWith("brew ("))
|
|
202
|
+
kind = "brew";
|
|
203
|
+
else
|
|
204
|
+
continue; // unknown — likely a manual PR; skip
|
|
205
|
+
out.push({
|
|
206
|
+
kind,
|
|
207
|
+
number: item.number,
|
|
208
|
+
url: item.html_url,
|
|
209
|
+
body: item.body,
|
|
210
|
+
bodyTimestamp: item.created_at,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
return out;
|
|
214
|
+
}
|
|
215
|
+
export async function onMockupApproved(argv) {
|
|
216
|
+
const args = parseArgs(argv);
|
|
217
|
+
const token = process.env["GITHUB_TOKEN"];
|
|
218
|
+
if (!token) {
|
|
219
|
+
console.error("GITHUB_TOKEN environment variable is not set.");
|
|
220
|
+
process.exit(2);
|
|
221
|
+
}
|
|
222
|
+
let owner = args.owner;
|
|
223
|
+
let repo = args.repo;
|
|
224
|
+
if (!owner || !repo) {
|
|
225
|
+
const detected = detectOwnerRepo(args.repoRoot);
|
|
226
|
+
if (!detected) {
|
|
227
|
+
console.error("Could not detect owner/repo from git remote. Pass --owner and --repo.");
|
|
228
|
+
process.exit(2);
|
|
229
|
+
}
|
|
230
|
+
owner = owner ?? detected.owner;
|
|
231
|
+
repo = repo ?? detected.repo;
|
|
232
|
+
}
|
|
233
|
+
const octokit = new Octokit({ auth: token, userAgent: "slowcook-ai/cli" });
|
|
234
|
+
// 1. Fetch the mockup PR to get its head ref + verify shape.
|
|
235
|
+
const pr = await octokit.rest.pulls.get({ owner, repo, pull_number: args.prNumber });
|
|
236
|
+
const headRef = pr.data.head.ref;
|
|
237
|
+
const headRefMatch = headRef.match(/^slowcook\/mockup\/story-([\w-]+)$/);
|
|
238
|
+
if (!headRefMatch || !headRefMatch[1]) {
|
|
239
|
+
console.error(`PR #${args.prNumber} head ref "${headRef}" doesn't match slowcook/mockup/story-N. Skipping.`);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
const storyId = headRefMatch[1];
|
|
243
|
+
// 2. Read the spec to find source_issue.
|
|
244
|
+
const specPath = join(args.repoRoot, "specs", `story-${storyId}.yaml`);
|
|
245
|
+
if (!existsSync(specPath)) {
|
|
246
|
+
console.error(`Spec not found at ${specPath}; cannot resolve source_issue.`);
|
|
247
|
+
process.exit(0);
|
|
248
|
+
}
|
|
249
|
+
const spec = YAML.parse(readFileSync(specPath, "utf8"));
|
|
250
|
+
if (!spec.source_issue) {
|
|
251
|
+
console.log(`Spec story-${storyId} has no source_issue. Nothing to bill.`);
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
const issueMatchYaml = spec.source_issue.match(/^#?(\d+)$/);
|
|
255
|
+
if (!issueMatchYaml || !issueMatchYaml[1]) {
|
|
256
|
+
console.error(`spec source_issue "${spec.source_issue}" not numeric.`);
|
|
257
|
+
process.exit(0);
|
|
258
|
+
}
|
|
259
|
+
const issueNumber = parseInt(issueMatchYaml[1], 10);
|
|
260
|
+
// 3. Walk every related source for cost markers.
|
|
261
|
+
const issue = await octokit.rest.issues.get({ owner, repo, issue_number: issueNumber });
|
|
262
|
+
const issueUrl = issue.data.html_url;
|
|
263
|
+
const allRuns = [];
|
|
264
|
+
// 3a. Issue body + comments (refine often posts here).
|
|
265
|
+
if (issue.data.body) {
|
|
266
|
+
allRuns.push(...extractCostRunsFromBody(issue.data.body, { kind: "issue", number: issueNumber, url: issueUrl }, issue.data.created_at));
|
|
267
|
+
}
|
|
268
|
+
const issueComments = await fetchIssueComments(octokit, owner, repo, issueNumber);
|
|
269
|
+
for (const c of issueComments) {
|
|
270
|
+
if (!c.body)
|
|
271
|
+
continue;
|
|
272
|
+
allRuns.push(...extractCostRunsFromBody(c.body, { kind: "issue", number: issueNumber, url: c.html_url ?? issueUrl }, c.created_at ?? ""));
|
|
273
|
+
}
|
|
274
|
+
// 3b. Every PR matching `story-{id}` in title (spec / tests / mockup / brew).
|
|
275
|
+
const relatedPrs = await findRelatedPrs(octokit, owner, repo, storyId);
|
|
276
|
+
for (const pr of relatedPrs) {
|
|
277
|
+
// PR body (vibe's initial cost lives here for the mockup PR).
|
|
278
|
+
if (pr.body) {
|
|
279
|
+
allRuns.push(...extractCostRunsFromBody(pr.body, { kind: pr.kind, number: pr.number, url: pr.url }, pr.bodyTimestamp ?? ""));
|
|
280
|
+
}
|
|
281
|
+
// PR comments.
|
|
282
|
+
const prComments = await fetchPrComments(octokit, owner, repo, pr.number);
|
|
283
|
+
for (const c of prComments) {
|
|
284
|
+
if (!c.body)
|
|
285
|
+
continue;
|
|
286
|
+
allRuns.push(...extractCostRunsFromBody(c.body, { kind: pr.kind, number: pr.number, url: c.html_url ?? pr.url }, c.created_at ?? ""));
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
// Sort chronologically.
|
|
290
|
+
allRuns.sort((a, b) => (a.timestamp || "").localeCompare(b.timestamp || ""));
|
|
291
|
+
// 4. Build the rollup body.
|
|
292
|
+
const total = allRuns.reduce((s, r) => s + r.usd, 0);
|
|
293
|
+
const totalsByAgent = new Map();
|
|
294
|
+
for (const r of allRuns) {
|
|
295
|
+
const t = totalsByAgent.get(r.agent) ?? { runs: 0, usd: 0 };
|
|
296
|
+
t.runs += 1;
|
|
297
|
+
t.usd += r.usd;
|
|
298
|
+
totalsByAgent.set(r.agent, t);
|
|
299
|
+
}
|
|
300
|
+
const lines = [];
|
|
301
|
+
lines.push(`### slowcook · mockup approved (story-${storyId})`);
|
|
302
|
+
lines.push("");
|
|
303
|
+
lines.push(`Mockup PR #${args.prNumber} signed off; \`slowcook-mockup-approved\` label applied. ` +
|
|
304
|
+
`Plate refuses further amendments. **Next**: merge the PR to fire \`brew --mode plate\` ` +
|
|
305
|
+
`(once the recipe-tests PR is also merged).`);
|
|
306
|
+
lines.push("");
|
|
307
|
+
// Itemized rollup — one row per cost marker.
|
|
308
|
+
lines.push(`#### Itemised runs (${allRuns.length})`);
|
|
309
|
+
lines.push("");
|
|
310
|
+
if (allRuns.length === 0) {
|
|
311
|
+
lines.push("_No cost markers found across this story's PRs + issue. (Likely a pre-α.24 vibe run that didn't emit the structured marker.)_");
|
|
312
|
+
}
|
|
313
|
+
else {
|
|
314
|
+
lines.push("| # | When | Agent | Model | Source | $ | Diff |");
|
|
315
|
+
lines.push("|--:|---|---|---|---|---:|---|");
|
|
316
|
+
let i = 1;
|
|
317
|
+
for (const r of allRuns) {
|
|
318
|
+
const when = r.timestamp ? new Date(r.timestamp).toISOString().slice(0, 16).replace("T", " ") : "—";
|
|
319
|
+
const sourceLabel = `${r.source.kind} #${r.source.number}`;
|
|
320
|
+
const sourceLink = `[${sourceLabel}](${r.source.url})`;
|
|
321
|
+
const diff = r.commitSha
|
|
322
|
+
? `[\`${r.commitSha.slice(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${r.commitSha})`
|
|
323
|
+
: "—";
|
|
324
|
+
lines.push(`| ${i} | ${when} | \`${r.agent}\` | ${r.model ? `\`${r.model}\`` : "—"} | ${sourceLink} | $${r.usd.toFixed(4)} | ${diff} |`);
|
|
325
|
+
i++;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
lines.push("");
|
|
329
|
+
// Totals by agent.
|
|
330
|
+
lines.push(`#### Totals by agent`);
|
|
331
|
+
lines.push("");
|
|
332
|
+
lines.push("| Agent | Runs | $ |");
|
|
333
|
+
lines.push("|---|---:|---:|");
|
|
334
|
+
for (const [agent, t] of [...totalsByAgent.entries()].sort()) {
|
|
335
|
+
lines.push(`| \`${agent}\` | ${t.runs} | $${t.usd.toFixed(4)} |`);
|
|
336
|
+
}
|
|
337
|
+
lines.push(`| **Total so far** | **${allRuns.length}** | **$${total.toFixed(4)}** |`);
|
|
338
|
+
lines.push("");
|
|
339
|
+
lines.push(`_Post-merge brew run will add its own line; \`on-brew-merged\` updates this comment when that lands._`);
|
|
340
|
+
lines.push("");
|
|
341
|
+
lines.push(`<!-- ${ROLLUP_MARKER} pr=${args.prNumber} story=${storyId} usd=${total.toFixed(4)} runs=${allRuns.length} -->`);
|
|
342
|
+
const newBody = lines.join("\n");
|
|
343
|
+
// 5. Post or update the rollup comment on the source issue.
|
|
344
|
+
const existingComments = await fetchIssueComments(octokit, owner, repo, issueNumber);
|
|
345
|
+
const existing = existingComments.find((c) => (c.body ?? "").includes(ROLLUP_MARKER));
|
|
346
|
+
if (existing) {
|
|
347
|
+
await octokit.rest.issues.updateComment({
|
|
348
|
+
owner, repo, comment_id: existing.id, body: newBody,
|
|
349
|
+
});
|
|
350
|
+
console.log(`Updated existing rollup comment on issue #${issueNumber} (story-${storyId}, ${allRuns.length} runs / $${total.toFixed(4)} total).`);
|
|
351
|
+
}
|
|
352
|
+
else {
|
|
353
|
+
await octokit.rest.issues.createComment({
|
|
354
|
+
owner, repo, issue_number: issueNumber, body: newBody,
|
|
355
|
+
});
|
|
356
|
+
console.log(`Posted new rollup comment on issue #${issueNumber} (story-${storyId}, ${allRuns.length} runs / $${total.toFixed(4)} total).`);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/on-mockup-approved/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PM-comment classifier — 0.16.0-α.7.
|
|
3
|
+
*
|
|
4
|
+
* Each element-anchored review-overlay comment on a slowcook-mockup PR
|
|
5
|
+
* gets categorized so plate knows what to do with it:
|
|
6
|
+
*
|
|
7
|
+
* - "cosmetic" → amend the mock with minimum diff
|
|
8
|
+
* - "spec-altering" → ESCALATE: would invalidate a spec assertion or
|
|
9
|
+
* acceptance scenario; PM must confirm the spec
|
|
10
|
+
* change before plate touches the mock
|
|
11
|
+
* - "mock-divergence" → the mock diverged from the spec; align mock
|
|
12
|
+
* to spec; note in summary why the PM ask is
|
|
13
|
+
* being interpreted this way
|
|
14
|
+
*
|
|
15
|
+
* α.7 ships a deterministic heuristic. Each classification has a clear
|
|
16
|
+
* rationale string so the escalation comment can quote the trigger.
|
|
17
|
+
*
|
|
18
|
+
* Heuristic structure:
|
|
19
|
+
* 1. Parse the spec YAML to extract the salient assertion targets:
|
|
20
|
+
* - acceptance_scenarios prose lines
|
|
21
|
+
* - api_contract response field names
|
|
22
|
+
* - invariants prose
|
|
23
|
+
* - ui_behavior viewport prose
|
|
24
|
+
* → a flat set of "spec terms" (lowercased, normalized words).
|
|
25
|
+
* 2. Score the comment prose against those terms:
|
|
26
|
+
* - any direct mention of an acceptance keyword phrase → spec-altering
|
|
27
|
+
* - mention of a domain noun + a "remove/change/replace" → spec-altering
|
|
28
|
+
* - mentions only adjective/style words (color, padding, → cosmetic
|
|
29
|
+
* font, spacing, alignment, shadow, etc.)
|
|
30
|
+
* - else → mock-divergence
|
|
31
|
+
*
|
|
32
|
+
* The heuristic is intentionally conservative on spec-altering: false
|
|
33
|
+
* positives only cost a PM confirm round; false negatives let plate
|
|
34
|
+
* silently weaken the spec, which is the failure mode the architecture
|
|
35
|
+
* is designed to prevent. When in doubt → escalate.
|
|
36
|
+
*
|
|
37
|
+
* No LLM dep here — pure functions over inputs. LLM-backed classifier
|
|
38
|
+
* is a future α.7.1 upgrade if heuristic shows real misses.
|
|
39
|
+
*/
|
|
40
|
+
export type Classification = "cosmetic" | "spec-altering" | "mock-divergence";
|
|
41
|
+
export interface ClassifyResult {
|
|
42
|
+
classification: Classification;
|
|
43
|
+
/** Why this classification — included verbatim in escalation comments. */
|
|
44
|
+
rationale: string;
|
|
45
|
+
/** The spec terms (if any) that matched in the comment prose. */
|
|
46
|
+
matchedSpecTerms: string[];
|
|
47
|
+
}
|
|
48
|
+
export interface ClassifyArgs {
|
|
49
|
+
/** Free prose written by the PM in the review-overlay comment. */
|
|
50
|
+
prose: string;
|
|
51
|
+
/**
|
|
52
|
+
* Spec YAML body. Hand-parsed for the assertion targets; we don't
|
|
53
|
+
* need a full YAML parser since the heuristic only needs salient
|
|
54
|
+
* words from acceptance_scenarios / invariants / api_contract.
|
|
55
|
+
*/
|
|
56
|
+
specYaml: string;
|
|
57
|
+
}
|
|
58
|
+
export declare function classifyComment(args: ClassifyArgs): ClassifyResult;
|
|
59
|
+
/**
|
|
60
|
+
* Extract candidate "spec terms" — lowercase, deduplicated significant
|
|
61
|
+
* tokens from the spec sections plate cares about. Used by the
|
|
62
|
+
* classifier to detect overlap between PM prose and spec assertions.
|
|
63
|
+
*/
|
|
64
|
+
export declare function extractSpecTerms(specYaml: string): string[];
|
|
65
|
+
//# sourceMappingURL=classify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classify.d.ts","sourceRoot":"","sources":["../../../src/commands/plate/classify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,eAAe,GAAG,iBAAiB,CAAC;AAE9E,MAAM,WAAW,cAAc;IAC7B,cAAc,EAAE,cAAc,CAAC;IAC/B,0EAA0E;IAC1E,SAAS,EAAE,MAAM,CAAC;IAClB,iEAAiE;IACjE,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B;AAyBD,MAAM,WAAW,YAAY;IAC3B,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,YAAY,GAAG,cAAc,CAgElE;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAe3D"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PM-comment classifier — 0.16.0-α.7.
|
|
3
|
+
*
|
|
4
|
+
* Each element-anchored review-overlay comment on a slowcook-mockup PR
|
|
5
|
+
* gets categorized so plate knows what to do with it:
|
|
6
|
+
*
|
|
7
|
+
* - "cosmetic" → amend the mock with minimum diff
|
|
8
|
+
* - "spec-altering" → ESCALATE: would invalidate a spec assertion or
|
|
9
|
+
* acceptance scenario; PM must confirm the spec
|
|
10
|
+
* change before plate touches the mock
|
|
11
|
+
* - "mock-divergence" → the mock diverged from the spec; align mock
|
|
12
|
+
* to spec; note in summary why the PM ask is
|
|
13
|
+
* being interpreted this way
|
|
14
|
+
*
|
|
15
|
+
* α.7 ships a deterministic heuristic. Each classification has a clear
|
|
16
|
+
* rationale string so the escalation comment can quote the trigger.
|
|
17
|
+
*
|
|
18
|
+
* Heuristic structure:
|
|
19
|
+
* 1. Parse the spec YAML to extract the salient assertion targets:
|
|
20
|
+
* - acceptance_scenarios prose lines
|
|
21
|
+
* - api_contract response field names
|
|
22
|
+
* - invariants prose
|
|
23
|
+
* - ui_behavior viewport prose
|
|
24
|
+
* → a flat set of "spec terms" (lowercased, normalized words).
|
|
25
|
+
* 2. Score the comment prose against those terms:
|
|
26
|
+
* - any direct mention of an acceptance keyword phrase → spec-altering
|
|
27
|
+
* - mention of a domain noun + a "remove/change/replace" → spec-altering
|
|
28
|
+
* - mentions only adjective/style words (color, padding, → cosmetic
|
|
29
|
+
* font, spacing, alignment, shadow, etc.)
|
|
30
|
+
* - else → mock-divergence
|
|
31
|
+
*
|
|
32
|
+
* The heuristic is intentionally conservative on spec-altering: false
|
|
33
|
+
* positives only cost a PM confirm round; false negatives let plate
|
|
34
|
+
* silently weaken the spec, which is the failure mode the architecture
|
|
35
|
+
* is designed to prevent. When in doubt → escalate.
|
|
36
|
+
*
|
|
37
|
+
* No LLM dep here — pure functions over inputs. LLM-backed classifier
|
|
38
|
+
* is a future α.7.1 upgrade if heuristic shows real misses.
|
|
39
|
+
*/
|
|
40
|
+
const COSMETIC_WORDS = [
|
|
41
|
+
"color", "colour", "shade", "tint", "hue", "rgb", "hex",
|
|
42
|
+
"padding", "margin", "spacing", "gap", "indent",
|
|
43
|
+
"font", "typeface", "weight", "italic", "underline",
|
|
44
|
+
"alignment", "align", "center", "centre", "left-aligned", "right-aligned",
|
|
45
|
+
"shadow", "border", "outline", "radius", "rounded",
|
|
46
|
+
"size", "smaller", "bigger", "larger", "tighter", "looser",
|
|
47
|
+
"background", "bg",
|
|
48
|
+
"icon", "emoji",
|
|
49
|
+
"feel", "vibe", "look",
|
|
50
|
+
"ratio", "scale",
|
|
51
|
+
];
|
|
52
|
+
const STRUCTURAL_VERBS = [
|
|
53
|
+
"remove", "removed", "delete", "deleted", "drop",
|
|
54
|
+
"replace", "swap", "switch",
|
|
55
|
+
"add", "introduce", "include",
|
|
56
|
+
"change", "rename",
|
|
57
|
+
"split", "merge", "combine",
|
|
58
|
+
"block", "prevent", "disallow",
|
|
59
|
+
"require", "enforce",
|
|
60
|
+
];
|
|
61
|
+
export function classifyComment(args) {
|
|
62
|
+
const proseNorm = normalize(args.prose);
|
|
63
|
+
const specTerms = extractSpecTerms(args.specYaml);
|
|
64
|
+
const matched = [];
|
|
65
|
+
for (const term of specTerms) {
|
|
66
|
+
if (proseNorm.includes(term))
|
|
67
|
+
matched.push(term);
|
|
68
|
+
}
|
|
69
|
+
const cosmeticHits = COSMETIC_WORDS.filter((w) => containsWord(proseNorm, w));
|
|
70
|
+
const structuralVerb = STRUCTURAL_VERBS.find((v) => containsWord(proseNorm, v));
|
|
71
|
+
// Rule 1 — spec term + structural verb → spec-altering. Highest
|
|
72
|
+
// priority; this is the failure mode we MUST escalate. "Remove the
|
|
73
|
+
// pinned strip" / "replace pinned with bookmarked" etc.
|
|
74
|
+
if (matched.length > 0 && structuralVerb) {
|
|
75
|
+
return {
|
|
76
|
+
classification: "spec-altering",
|
|
77
|
+
rationale: `Mentions spec term${matched.length > 1 ? "s" : ""} (${matched.slice(0, 5).map((m) => `"${m}"`).join(", ")}) ` +
|
|
78
|
+
`together with structural verb "${structuralVerb}". This would change the spec's contract; ` +
|
|
79
|
+
`PM must confirm before the mock changes.`,
|
|
80
|
+
matchedSpecTerms: matched,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
// Rule 2 — cosmetic word present (with or without spec term, but
|
|
84
|
+
// no structural verb) → cosmetic. A PM saying "the Pinned button
|
|
85
|
+
// background should be coral" is naming the element AND asking for
|
|
86
|
+
// a style change; that's still cosmetic. Amend the mock with min diff.
|
|
87
|
+
if (cosmeticHits.length > 0) {
|
|
88
|
+
return {
|
|
89
|
+
classification: "cosmetic",
|
|
90
|
+
rationale: `Style-only feedback (matched: ${cosmeticHits.slice(0, 5).map((w) => `"${w}"`).join(", ")})` +
|
|
91
|
+
(matched.length > 0
|
|
92
|
+
? `; spec term${matched.length > 1 ? "s" : ""} (${matched.slice(0, 3).map((m) => `"${m}"`).join(", ")}) named the element but no structural verb present.`
|
|
93
|
+
: `; no spec terms triggered.`),
|
|
94
|
+
matchedSpecTerms: matched,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
// Rule 3 — spec terms with no cosmetic word and no structural verb
|
|
98
|
+
// → mock-divergence. The PM is talking about something the spec
|
|
99
|
+
// mentions but neither styling it nor changing the contract.
|
|
100
|
+
// Likely "mock shows X but spec says Y."
|
|
101
|
+
if (matched.length > 0) {
|
|
102
|
+
return {
|
|
103
|
+
classification: "mock-divergence",
|
|
104
|
+
rationale: `Mentions spec term${matched.length > 1 ? "s" : ""} (${matched.slice(0, 5).map((m) => `"${m}"`).join(", ")}) ` +
|
|
105
|
+
`without a structural verb or styling cue. Likely the mock diverged from spec; align mock to spec.`,
|
|
106
|
+
matchedSpecTerms: matched,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
// Rule 4 — fallthrough. No signal in any direction. Default to
|
|
110
|
+
// mock-divergence so plate's LLM still gets the chance to reason
|
|
111
|
+
// about both spec + comment in context (false-positive cost is low).
|
|
112
|
+
return {
|
|
113
|
+
classification: "mock-divergence",
|
|
114
|
+
rationale: `No clear spec or style signal in the prose. Defaulting to mock-divergence so plate has a chance to reconcile against the spec.`,
|
|
115
|
+
matchedSpecTerms: [],
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Extract candidate "spec terms" — lowercase, deduplicated significant
|
|
120
|
+
* tokens from the spec sections plate cares about. Used by the
|
|
121
|
+
* classifier to detect overlap between PM prose and spec assertions.
|
|
122
|
+
*/
|
|
123
|
+
export function extractSpecTerms(specYaml) {
|
|
124
|
+
const sections = ["acceptance_scenarios", "invariants", "api_contract"];
|
|
125
|
+
const terms = new Set();
|
|
126
|
+
// Also include ui_behavior viewport prose — a comment about
|
|
127
|
+
// "remove the desktop_light pinned strip" is spec-altering.
|
|
128
|
+
for (const sec of [...sections, "ui_behavior"]) {
|
|
129
|
+
const body = extractYamlSection(specYaml, sec);
|
|
130
|
+
if (!body)
|
|
131
|
+
continue;
|
|
132
|
+
for (const tok of tokenize(body)) {
|
|
133
|
+
if (isStopword(tok))
|
|
134
|
+
continue;
|
|
135
|
+
if (tok.length < 4)
|
|
136
|
+
continue; // skip short noise
|
|
137
|
+
terms.add(tok);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return Array.from(terms);
|
|
141
|
+
}
|
|
142
|
+
function extractYamlSection(yaml, sectionName) {
|
|
143
|
+
// Find the line `sectionName:` at indent 0; capture indented body
|
|
144
|
+
// until the next zero-indent line.
|
|
145
|
+
const lines = yaml.split(/\r?\n/);
|
|
146
|
+
const out = [];
|
|
147
|
+
let inSection = false;
|
|
148
|
+
for (const raw of lines) {
|
|
149
|
+
const m = raw.match(/^(\s*)([a-zA-Z_][\w]*)\s*:/);
|
|
150
|
+
if (m && m[1].length === 0) {
|
|
151
|
+
if (m[2] === sectionName) {
|
|
152
|
+
inSection = true;
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
else if (inSection) {
|
|
156
|
+
// hit a sibling top-level key
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (inSection)
|
|
161
|
+
out.push(raw);
|
|
162
|
+
}
|
|
163
|
+
return out.join("\n");
|
|
164
|
+
}
|
|
165
|
+
function normalize(s) {
|
|
166
|
+
return s.toLowerCase().replace(/\s+/g, " ").trim();
|
|
167
|
+
}
|
|
168
|
+
function tokenize(s) {
|
|
169
|
+
// Split on non-word; preserve underscores (snake_case identifiers)
|
|
170
|
+
return s
|
|
171
|
+
.toLowerCase()
|
|
172
|
+
.split(/[^a-z0-9_]+/)
|
|
173
|
+
.filter((w) => w.length > 0);
|
|
174
|
+
}
|
|
175
|
+
function containsWord(haystackNorm, needle) {
|
|
176
|
+
// Word-boundary check; needle is already lowercase.
|
|
177
|
+
const re = new RegExp(`(^|[^a-z0-9_])${escapeRe(needle)}([^a-z0-9_]|$)`);
|
|
178
|
+
return re.test(haystackNorm);
|
|
179
|
+
}
|
|
180
|
+
function escapeRe(s) {
|
|
181
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
182
|
+
}
|
|
183
|
+
const STOPWORDS = new Set([
|
|
184
|
+
"the", "a", "an", "and", "or", "but", "of", "in", "on", "at", "to", "for", "with", "by", "is", "are", "was", "were", "be", "been", "being", "have", "has", "had", "do", "does", "did", "this", "that", "these", "those", "it", "its", "as", "if", "then", "else", "when", "while", "each", "every", "any", "all", "not", "no", "yes", "true", "false", "null", "can", "will", "may", "must", "should", "would", "also", "only", "very", "more", "most", "such", "than", "into", "from", "over", "under", "between", "through", "because", "since", "once", "yaml", "example", "note", "todo", "null_", "status", "approved", "draft", "paused", "active",
|
|
185
|
+
]);
|
|
186
|
+
function isStopword(w) {
|
|
187
|
+
if (STOPWORDS.has(w))
|
|
188
|
+
return true;
|
|
189
|
+
// Pure-numeric tokens are noise
|
|
190
|
+
if (/^[0-9]+$/.test(w))
|
|
191
|
+
return true;
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=classify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classify.js","sourceRoot":"","sources":["../../../src/commands/plate/classify.ts"],"names":[],"mappings":"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"}
|