@slowcook-ai/cli 0.19.0-alpha.11 → 0.19.0-alpha.16
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/AGENTS.md +239 -0
- package/REPORTING.md +193 -0
- package/dist/cli.js +22 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/chef/drift-fix.d.ts +1 -1
- package/dist/commands/chef/drift-fix.d.ts.map +1 -1
- package/dist/commands/chef/drift-fix.js +36 -15
- package/dist/commands/chef/drift-fix.js.map +1 -1
- package/dist/commands/chef/index.js +13 -3
- package/dist/commands/chef/index.js.map +1 -1
- package/dist/commands/chef/orchestrate.d.ts +1 -1
- package/dist/commands/chef/orchestrate.d.ts.map +1 -1
- package/dist/commands/chef/orchestrate.js +32 -9
- package/dist/commands/chef/orchestrate.js.map +1 -1
- package/dist/commands/docs/index.d.ts +16 -0
- package/dist/commands/docs/index.d.ts.map +1 -0
- package/dist/commands/docs/index.js +127 -0
- package/dist/commands/docs/index.js.map +1 -0
- package/dist/commands/garnish/index.d.ts +56 -0
- package/dist/commands/garnish/index.d.ts.map +1 -0
- package/dist/commands/garnish/index.js +281 -0
- package/dist/commands/garnish/index.js.map +1 -0
- package/dist/commands/garnish/trailer.d.ts +79 -0
- package/dist/commands/garnish/trailer.d.ts.map +1 -0
- package/dist/commands/garnish/trailer.js +118 -0
- package/dist/commands/garnish/trailer.js.map +1 -0
- package/dist/commands/recon/index.d.ts +1 -1
- package/dist/commands/recon/index.d.ts.map +1 -1
- package/dist/commands/recon/index.js +9 -5
- package/dist/commands/recon/index.js.map +1 -1
- package/dist/commands/recon/stale-stubs.d.ts +4 -1
- package/dist/commands/recon/stale-stubs.d.ts.map +1 -1
- package/dist/commands/recon/stale-stubs.js +6 -1
- package/dist/commands/recon/stale-stubs.js.map +1 -1
- package/dist/commands/run-mock/index.d.ts.map +1 -1
- package/dist/commands/run-mock/index.js +128 -21
- package/dist/commands/run-mock/index.js.map +1 -1
- package/dist/lib/read-only.d.ts +22 -0
- package/dist/lib/read-only.d.ts.map +1 -0
- package/dist/lib/read-only.js +34 -0
- package/dist/lib/read-only.js.map +1 -0
- package/package.json +7 -5
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `slowcook garnish` — 0.19.0-α.15.
|
|
3
|
+
*
|
|
4
|
+
* Local commit-gate for human (or other-agent) tweaks layered on top
|
|
5
|
+
* of an agent's work. The PM (or engineer) edits files in the working
|
|
6
|
+
* tree — by hand, via DevTools Workspaces, via any editor — then runs
|
|
7
|
+
* `slowcook garnish`. The cli:
|
|
8
|
+
*
|
|
9
|
+
* 1. Detects uncommitted changes in the working tree.
|
|
10
|
+
* 2. For each changed file, identifies the agent (if any) whose last
|
|
11
|
+
* commit touched the file. Files last touched by humans get no
|
|
12
|
+
* trailer entry (no learning signal for an agent).
|
|
13
|
+
* 3. Runs the relevant tests scoped to the changed files (or the
|
|
14
|
+
* caller-provided test glob via --scope).
|
|
15
|
+
* 4. If tests pass: commits the staged changes with a subject naming
|
|
16
|
+
* the touched files + `Tweaks-output-of:` trailer lines marking
|
|
17
|
+
* each agent-authored file the tweak touched. Optionally pushes.
|
|
18
|
+
* 5. If tests fail: prints the failure summary + exits non-zero
|
|
19
|
+
* without committing.
|
|
20
|
+
*
|
|
21
|
+
* The trailer lines are the load-bearing piece — a future `slowcook
|
|
22
|
+
* reflect` command mines them to surface learning signal for the
|
|
23
|
+
* upstream agent (eval-set fixtures, prompt-amendment candidates).
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* 0.19.0-α.16 — runGarnish, the reusable core. Other commands
|
|
27
|
+
* (run-mock --garnish, for one) call this in-process on debounced
|
|
28
|
+
* file-save batches; doing it as a subprocess invocation would
|
|
29
|
+
* re-pay node startup every time.
|
|
30
|
+
*
|
|
31
|
+
* Returns a structured result; never calls process.exit. Caller
|
|
32
|
+
* decides what to do on each kind.
|
|
33
|
+
*/
|
|
34
|
+
export interface RunGarnishOptions {
|
|
35
|
+
repoRoot: string;
|
|
36
|
+
scope?: string | null;
|
|
37
|
+
message?: string | null;
|
|
38
|
+
push?: boolean;
|
|
39
|
+
silent?: boolean;
|
|
40
|
+
}
|
|
41
|
+
export type RunGarnishResult = {
|
|
42
|
+
kind: "no-changes";
|
|
43
|
+
} | {
|
|
44
|
+
kind: "tests-failed";
|
|
45
|
+
touchedFiles: string[];
|
|
46
|
+
outputTail: string;
|
|
47
|
+
} | {
|
|
48
|
+
kind: "committed";
|
|
49
|
+
sha: string;
|
|
50
|
+
touchedFiles: string[];
|
|
51
|
+
agentRefCount: number;
|
|
52
|
+
pushed: boolean;
|
|
53
|
+
};
|
|
54
|
+
export declare function runGarnish(opts: RunGarnishOptions): Promise<RunGarnishResult>;
|
|
55
|
+
export declare function garnish(argv: string[], _cliVersion: string): Promise<void>;
|
|
56
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/garnish/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAsJH;;;;;;;;GAQG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,MAAM,gBAAgB,GACxB;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,GACtB;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,YAAY,EAAE,MAAM,EAAE,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GACpE;IACE,IAAI,EAAE,WAAW,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAEN,wBAAsB,UAAU,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAmEnF;AAED,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAiDhF"}
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `slowcook garnish` — 0.19.0-α.15.
|
|
3
|
+
*
|
|
4
|
+
* Local commit-gate for human (or other-agent) tweaks layered on top
|
|
5
|
+
* of an agent's work. The PM (or engineer) edits files in the working
|
|
6
|
+
* tree — by hand, via DevTools Workspaces, via any editor — then runs
|
|
7
|
+
* `slowcook garnish`. The cli:
|
|
8
|
+
*
|
|
9
|
+
* 1. Detects uncommitted changes in the working tree.
|
|
10
|
+
* 2. For each changed file, identifies the agent (if any) whose last
|
|
11
|
+
* commit touched the file. Files last touched by humans get no
|
|
12
|
+
* trailer entry (no learning signal for an agent).
|
|
13
|
+
* 3. Runs the relevant tests scoped to the changed files (or the
|
|
14
|
+
* caller-provided test glob via --scope).
|
|
15
|
+
* 4. If tests pass: commits the staged changes with a subject naming
|
|
16
|
+
* the touched files + `Tweaks-output-of:` trailer lines marking
|
|
17
|
+
* each agent-authored file the tweak touched. Optionally pushes.
|
|
18
|
+
* 5. If tests fail: prints the failure summary + exits non-zero
|
|
19
|
+
* without committing.
|
|
20
|
+
*
|
|
21
|
+
* The trailer lines are the load-bearing piece — a future `slowcook
|
|
22
|
+
* reflect` command mines them to surface learning signal for the
|
|
23
|
+
* upstream agent (eval-set fixtures, prompt-amendment candidates).
|
|
24
|
+
*/
|
|
25
|
+
import { execSync, spawnSync } from "node:child_process";
|
|
26
|
+
import { existsSync, writeFileSync } from "node:fs";
|
|
27
|
+
import { join } from "node:path";
|
|
28
|
+
import { composeCommitMessage, agentFromAuthor, } from "./trailer.js";
|
|
29
|
+
function parseArgs(argv) {
|
|
30
|
+
const args = {
|
|
31
|
+
repoRoot: process.cwd(),
|
|
32
|
+
scope: null,
|
|
33
|
+
push: false,
|
|
34
|
+
message: null,
|
|
35
|
+
dryRun: false,
|
|
36
|
+
};
|
|
37
|
+
for (let i = 0; i < argv.length; i++) {
|
|
38
|
+
const a = argv[i];
|
|
39
|
+
const next = argv[i + 1];
|
|
40
|
+
if (a === "--cwd" && next) {
|
|
41
|
+
args.repoRoot = next;
|
|
42
|
+
i++;
|
|
43
|
+
}
|
|
44
|
+
else if (a === "--scope" && next) {
|
|
45
|
+
args.scope = next;
|
|
46
|
+
i++;
|
|
47
|
+
}
|
|
48
|
+
else if (a === "--push") {
|
|
49
|
+
args.push = true;
|
|
50
|
+
}
|
|
51
|
+
else if (a === "--message" && next) {
|
|
52
|
+
args.message = next;
|
|
53
|
+
i++;
|
|
54
|
+
}
|
|
55
|
+
else if (a === "-m" && next) {
|
|
56
|
+
args.message = next;
|
|
57
|
+
i++;
|
|
58
|
+
}
|
|
59
|
+
else if (a === "--dry-run") {
|
|
60
|
+
args.dryRun = true;
|
|
61
|
+
}
|
|
62
|
+
else if (a === "--help" || a === "-h") {
|
|
63
|
+
printHelp();
|
|
64
|
+
process.exit(0);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return args;
|
|
68
|
+
}
|
|
69
|
+
function printHelp() {
|
|
70
|
+
console.log(`
|
|
71
|
+
slowcook garnish — commit a human (or other-agent) tweak on top of agent work
|
|
72
|
+
|
|
73
|
+
Detects uncommitted changes, runs the relevant tests, and (if green) commits
|
|
74
|
+
with \`Tweaks-output-of:\` trailers marking which upstream agent's work was
|
|
75
|
+
tweaked. A future \`slowcook reflect\` mines these trailers for learning signal.
|
|
76
|
+
|
|
77
|
+
Usage:
|
|
78
|
+
slowcook garnish [options]
|
|
79
|
+
|
|
80
|
+
Options:
|
|
81
|
+
--cwd <path> Repo root (default: cwd).
|
|
82
|
+
--scope <glob> Pass through to vitest (\`vitest run <glob>\`). Default:
|
|
83
|
+
run vitest related to the changed files.
|
|
84
|
+
--message <text> Optional commit body. Default: subject-only.
|
|
85
|
+
-m <text> Short form of --message.
|
|
86
|
+
--push Push to origin after committing.
|
|
87
|
+
--dry-run Print what would happen; do not run tests or commit.
|
|
88
|
+
|
|
89
|
+
Examples:
|
|
90
|
+
# Edit some files via DevTools Workspaces / by hand, then:
|
|
91
|
+
slowcook garnish
|
|
92
|
+
|
|
93
|
+
# Force a specific test scope:
|
|
94
|
+
slowcook garnish --scope 'tests/integration/story-018-*'
|
|
95
|
+
|
|
96
|
+
# Commit + push:
|
|
97
|
+
slowcook garnish -m "Tightened the spacing on the Pin button." --push
|
|
98
|
+
`);
|
|
99
|
+
}
|
|
100
|
+
function gitChangedFiles(repoRoot) {
|
|
101
|
+
const out = execSync(`git -C "${repoRoot}" status --porcelain`, {
|
|
102
|
+
encoding: "utf8",
|
|
103
|
+
});
|
|
104
|
+
const lines = out.split("\n").filter((l) => l.length > 0);
|
|
105
|
+
return lines
|
|
106
|
+
.map((line) => {
|
|
107
|
+
// Format: "XY path" or "XY path-old -> path-new" for renames.
|
|
108
|
+
// Take the rightmost path; safe enough for our use.
|
|
109
|
+
const status = line.slice(0, 2).trim();
|
|
110
|
+
const rest = line.slice(3).trim();
|
|
111
|
+
const path = rest.includes(" -> ") ? rest.split(" -> ")[1] : rest;
|
|
112
|
+
return { path, status };
|
|
113
|
+
})
|
|
114
|
+
.filter((f) => f.status !== "??"); // skip untracked-only (user can `git add` first)
|
|
115
|
+
}
|
|
116
|
+
function lastTouchingCommit(repoRoot, file) {
|
|
117
|
+
try {
|
|
118
|
+
const sha = execSync(`git -C "${repoRoot}" log -n 1 --format=%H -- "${file}"`, { encoding: "utf8" }).trim();
|
|
119
|
+
if (!sha)
|
|
120
|
+
return null;
|
|
121
|
+
const author = execSync(`git -C "${repoRoot}" show -s --format=%an "${sha}"`, { encoding: "utf8" }).trim();
|
|
122
|
+
return { sha, author };
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function resolveUpstreamRefs(repoRoot, files) {
|
|
129
|
+
const refs = [];
|
|
130
|
+
const humanFiles = [];
|
|
131
|
+
for (const file of files) {
|
|
132
|
+
const upstream = lastTouchingCommit(repoRoot, file);
|
|
133
|
+
if (!upstream) {
|
|
134
|
+
// File doesn't exist in history yet — must be newly-added by this tweak.
|
|
135
|
+
humanFiles.push(file);
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
const agent = agentFromAuthor(upstream.author);
|
|
139
|
+
if (agent) {
|
|
140
|
+
refs.push({ agent, sha: upstream.sha, file });
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
humanFiles.push(file);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return { refs, humanFiles };
|
|
147
|
+
}
|
|
148
|
+
function runTests(repoRoot, files, scopeOverride) {
|
|
149
|
+
const cmd = scopeOverride
|
|
150
|
+
? `npx vitest run ${scopeOverride}`
|
|
151
|
+
: `npx vitest related ${files.map((f) => `"${f}"`).join(" ")}`;
|
|
152
|
+
const result = spawnSync(cmd, {
|
|
153
|
+
cwd: repoRoot,
|
|
154
|
+
shell: true,
|
|
155
|
+
encoding: "utf8",
|
|
156
|
+
maxBuffer: 4 * 1024 * 1024,
|
|
157
|
+
});
|
|
158
|
+
const output = (result.stdout || "") + (result.stderr || "");
|
|
159
|
+
const ok = result.status === 0;
|
|
160
|
+
return { ok, output };
|
|
161
|
+
}
|
|
162
|
+
export async function runGarnish(opts) {
|
|
163
|
+
const repoRoot = opts.repoRoot;
|
|
164
|
+
const scope = opts.scope ?? null;
|
|
165
|
+
const log = opts.silent ? () => undefined : (msg) => console.log(msg);
|
|
166
|
+
const warn = opts.silent ? () => undefined : (msg) => console.warn(msg);
|
|
167
|
+
const changed = gitChangedFiles(repoRoot);
|
|
168
|
+
if (changed.length === 0) {
|
|
169
|
+
return { kind: "no-changes" };
|
|
170
|
+
}
|
|
171
|
+
const touchedFiles = changed.map((c) => c.path);
|
|
172
|
+
const { refs, humanFiles } = resolveUpstreamRefs(repoRoot, touchedFiles);
|
|
173
|
+
if (!opts.silent) {
|
|
174
|
+
log(` ${touchedFiles.length} file(s) with uncommitted changes:`);
|
|
175
|
+
for (const f of touchedFiles)
|
|
176
|
+
log(` ${f}`);
|
|
177
|
+
log(` upstream: ${refs.length} agent-authored, ${humanFiles.length} human/new`);
|
|
178
|
+
if (refs.length > 0) {
|
|
179
|
+
const byAgent = {};
|
|
180
|
+
for (const r of refs)
|
|
181
|
+
byAgent[r.agent] = (byAgent[r.agent] ?? 0) + 1;
|
|
182
|
+
const summary = Object.entries(byAgent).map(([a, n]) => `${a}=${n}`).join(", ");
|
|
183
|
+
log(` (${summary})`);
|
|
184
|
+
}
|
|
185
|
+
log("\n running tests" + (scope ? ` (--scope ${scope})` : " (vitest related)") + "...");
|
|
186
|
+
}
|
|
187
|
+
const tests = runTests(repoRoot, touchedFiles, scope);
|
|
188
|
+
if (!tests.ok) {
|
|
189
|
+
const tail = tests.output.split("\n").slice(-40).join("\n");
|
|
190
|
+
return { kind: "tests-failed", touchedFiles, outputTail: tail };
|
|
191
|
+
}
|
|
192
|
+
log(" ✓ tests passed.");
|
|
193
|
+
const message = composeCommitMessage({
|
|
194
|
+
touchedFiles,
|
|
195
|
+
upstreamRefs: refs,
|
|
196
|
+
userMessage: opts.message ?? undefined,
|
|
197
|
+
});
|
|
198
|
+
const msgFile = join(repoRoot, ".brewing/.garnish-commit-msg.tmp");
|
|
199
|
+
if (!existsSync(join(repoRoot, ".brewing"))) {
|
|
200
|
+
execSync(`mkdir -p "${join(repoRoot, ".brewing")}"`);
|
|
201
|
+
}
|
|
202
|
+
writeFileSync(msgFile, message, "utf8");
|
|
203
|
+
for (const f of touchedFiles) {
|
|
204
|
+
try {
|
|
205
|
+
execSync(`git -C "${repoRoot}" add -- "${f}"`, { stdio: "ignore" });
|
|
206
|
+
}
|
|
207
|
+
catch { /* deleted file; ignore */ }
|
|
208
|
+
}
|
|
209
|
+
try {
|
|
210
|
+
execSync(`git -C "${repoRoot}" commit -F "${msgFile}"`, {
|
|
211
|
+
stdio: opts.silent ? "ignore" : "inherit",
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
catch (e) {
|
|
215
|
+
warn(` garnish commit failed: ${e.message.slice(0, 200)}`);
|
|
216
|
+
return { kind: "tests-failed", touchedFiles, outputTail: e.message };
|
|
217
|
+
}
|
|
218
|
+
const sha = execSync(`git -C "${repoRoot}" rev-parse HEAD`, { encoding: "utf8" }).trim();
|
|
219
|
+
let pushed = false;
|
|
220
|
+
if (opts.push) {
|
|
221
|
+
try {
|
|
222
|
+
execSync(`git -C "${repoRoot}" push`, { stdio: opts.silent ? "ignore" : "inherit" });
|
|
223
|
+
pushed = true;
|
|
224
|
+
}
|
|
225
|
+
catch (e) {
|
|
226
|
+
warn(` warn: push failed: ${e.message.slice(0, 200)}`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return { kind: "committed", sha, touchedFiles, agentRefCount: refs.length, pushed };
|
|
230
|
+
}
|
|
231
|
+
export async function garnish(argv, _cliVersion) {
|
|
232
|
+
const args = parseArgs(argv);
|
|
233
|
+
console.log(`slowcook garnish · cwd: ${args.repoRoot.replace(process.cwd() + "/", ".")}`);
|
|
234
|
+
if (args.dryRun) {
|
|
235
|
+
const changed = gitChangedFiles(args.repoRoot);
|
|
236
|
+
if (changed.length === 0) {
|
|
237
|
+
console.log(" no uncommitted changes; nothing to garnish.");
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
const touchedFiles = changed.map((c) => c.path);
|
|
241
|
+
const { refs, humanFiles } = resolveUpstreamRefs(args.repoRoot, touchedFiles);
|
|
242
|
+
console.log(` ${touchedFiles.length} file(s) with uncommitted changes:`);
|
|
243
|
+
for (const f of touchedFiles)
|
|
244
|
+
console.log(` ${f}`);
|
|
245
|
+
console.log(` upstream: ${refs.length} agent-authored, ${humanFiles.length} human/new`);
|
|
246
|
+
if (refs.length > 0) {
|
|
247
|
+
const byAgent = {};
|
|
248
|
+
for (const r of refs)
|
|
249
|
+
byAgent[r.agent] = (byAgent[r.agent] ?? 0) + 1;
|
|
250
|
+
const summary = Object.entries(byAgent).map(([a, n]) => `${a}=${n}`).join(", ");
|
|
251
|
+
console.log(` (${summary})`);
|
|
252
|
+
}
|
|
253
|
+
console.log("\n [dry-run] would run tests + commit; skipping.");
|
|
254
|
+
const message = composeCommitMessage({
|
|
255
|
+
touchedFiles,
|
|
256
|
+
upstreamRefs: refs,
|
|
257
|
+
userMessage: args.message ?? undefined,
|
|
258
|
+
});
|
|
259
|
+
console.log("\n commit message would be:\n");
|
|
260
|
+
for (const line of message.split("\n"))
|
|
261
|
+
console.log(` ${line}`);
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
const result = await runGarnish({
|
|
265
|
+
repoRoot: args.repoRoot,
|
|
266
|
+
scope: args.scope,
|
|
267
|
+
message: args.message,
|
|
268
|
+
push: args.push,
|
|
269
|
+
});
|
|
270
|
+
if (result.kind === "no-changes") {
|
|
271
|
+
console.log(" no uncommitted changes; nothing to garnish.");
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
if (result.kind === "tests-failed") {
|
|
275
|
+
console.error("\n ✗ tests failed. Garnish blocked; working tree unchanged.\n");
|
|
276
|
+
console.error(result.outputTail);
|
|
277
|
+
process.exit(1);
|
|
278
|
+
}
|
|
279
|
+
console.log(`\n ✓ garnished: ${result.sha.slice(0, 7)} (${result.agentRefCount} agent ref(s) recorded)${result.pushed ? " · pushed" : ""}`);
|
|
280
|
+
}
|
|
281
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/garnish/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 0.19.0-α.15 — `slowcook garnish` trailer helpers.
|
|
3
|
+
*
|
|
4
|
+
* When a human (or another agent) commits a tweak on top of an agent's
|
|
5
|
+
* work, we mark the commit with `Tweaks-output-of:` git trailer lines —
|
|
6
|
+
* one per file the tweak touched, naming the upstream agent + sha. A
|
|
7
|
+
* future `slowcook reflect` command mines these trailers to surface
|
|
8
|
+
* learning signal for the upstream agent (eval-set fixtures, prompt
|
|
9
|
+
* amendment candidates, drift catalogs).
|
|
10
|
+
*
|
|
11
|
+
* Trailer format (one line per file):
|
|
12
|
+
*
|
|
13
|
+
* Tweaks-output-of: agent=<name> sha=<commit-sha> file=<repo-relative-path>
|
|
14
|
+
*
|
|
15
|
+
* Examples:
|
|
16
|
+
* Tweaks-output-of: agent=vibe sha=a7df238 file=mock/src/components/Foo.tsx
|
|
17
|
+
* Tweaks-output-of: agent=plate sha=00905ae file=mock/src/components/Bar.tsx
|
|
18
|
+
*
|
|
19
|
+
* Pure module — no IO. Caller composes the trailer lines into the commit
|
|
20
|
+
* message and runs git separately.
|
|
21
|
+
*/
|
|
22
|
+
export interface UpstreamRef {
|
|
23
|
+
/** Upstream agent name (vibe / plate / brew / chef / etc). */
|
|
24
|
+
agent: string;
|
|
25
|
+
/** Upstream commit SHA (short or full; renderer trims to 7). */
|
|
26
|
+
sha: string;
|
|
27
|
+
/** Repo-relative file path the tweak touched. */
|
|
28
|
+
file: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Format a list of upstream refs into trailer lines (one per ref).
|
|
32
|
+
* Pure: returns a single string with `\n` separators, no leading or
|
|
33
|
+
* trailing newline. Caller appends to the commit-message body.
|
|
34
|
+
*/
|
|
35
|
+
export declare function formatTrailer(refs: UpstreamRef[]): string;
|
|
36
|
+
/**
|
|
37
|
+
* Parse a single trailer line, returning the parsed ref or null if the
|
|
38
|
+
* line doesn't match the expected shape. Tolerates leading/trailing
|
|
39
|
+
* whitespace + the optional " " indent some `git interpret-trailers`
|
|
40
|
+
* outputs add.
|
|
41
|
+
*/
|
|
42
|
+
export declare function parseTrailerLine(line: string): UpstreamRef | null;
|
|
43
|
+
/**
|
|
44
|
+
* Parse all `Tweaks-output-of:` trailers from a full commit-message
|
|
45
|
+
* body (multi-line). Returns refs in the order they appeared.
|
|
46
|
+
*/
|
|
47
|
+
export declare function parseTrailers(commitBody: string): UpstreamRef[];
|
|
48
|
+
/**
|
|
49
|
+
* Inspect a git author line + return the upstream agent name, if the
|
|
50
|
+
* author follows slowcook's agent convention. Otherwise null.
|
|
51
|
+
*
|
|
52
|
+
* Conventions detected:
|
|
53
|
+
* slowcook-vibe[bot] → "vibe"
|
|
54
|
+
* slowcook-plate[bot] → "plate"
|
|
55
|
+
* slowcook-brew[bot] → "brew"
|
|
56
|
+
* slowcook-chef[bot] → "chef"
|
|
57
|
+
* slowcook-refine[bot] → "refine"
|
|
58
|
+
* slowcook-testgen[bot] → "testgen"
|
|
59
|
+
* slowcook-recipe[bot] → "recipe"
|
|
60
|
+
* anything else → null (human or unrelated bot)
|
|
61
|
+
*
|
|
62
|
+
* Pure: no IO. Caller pipes git author through it.
|
|
63
|
+
*/
|
|
64
|
+
export declare function agentFromAuthor(author: string): string | null;
|
|
65
|
+
/**
|
|
66
|
+
* Compose the full commit message body for a garnish commit: a one-line
|
|
67
|
+
* subject naming the touched files, a blank line, optional user-provided
|
|
68
|
+
* body, a blank line, then the trailer block.
|
|
69
|
+
*
|
|
70
|
+
* Pure: caller passes the staged-file list + the parsed upstream refs +
|
|
71
|
+
* the optional user message. Returns the body string ready for `git
|
|
72
|
+
* commit -F`.
|
|
73
|
+
*/
|
|
74
|
+
export declare function composeCommitMessage(args: {
|
|
75
|
+
touchedFiles: string[];
|
|
76
|
+
upstreamRefs: UpstreamRef[];
|
|
77
|
+
userMessage?: string;
|
|
78
|
+
}): string;
|
|
79
|
+
//# sourceMappingURL=trailer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trailer.d.ts","sourceRoot":"","sources":["../../../src/commands/garnish/trailer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,WAAW,WAAW;IAC1B,8DAA8D;IAC9D,KAAK,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,GAAG,EAAE,MAAM,CAAC;IACZ,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,MAAM,CAIzD;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAYjE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,WAAW,EAAE,CAO/D;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI7D;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IACzC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,MAAM,CAUT"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 0.19.0-α.15 — `slowcook garnish` trailer helpers.
|
|
3
|
+
*
|
|
4
|
+
* When a human (or another agent) commits a tweak on top of an agent's
|
|
5
|
+
* work, we mark the commit with `Tweaks-output-of:` git trailer lines —
|
|
6
|
+
* one per file the tweak touched, naming the upstream agent + sha. A
|
|
7
|
+
* future `slowcook reflect` command mines these trailers to surface
|
|
8
|
+
* learning signal for the upstream agent (eval-set fixtures, prompt
|
|
9
|
+
* amendment candidates, drift catalogs).
|
|
10
|
+
*
|
|
11
|
+
* Trailer format (one line per file):
|
|
12
|
+
*
|
|
13
|
+
* Tweaks-output-of: agent=<name> sha=<commit-sha> file=<repo-relative-path>
|
|
14
|
+
*
|
|
15
|
+
* Examples:
|
|
16
|
+
* Tweaks-output-of: agent=vibe sha=a7df238 file=mock/src/components/Foo.tsx
|
|
17
|
+
* Tweaks-output-of: agent=plate sha=00905ae file=mock/src/components/Bar.tsx
|
|
18
|
+
*
|
|
19
|
+
* Pure module — no IO. Caller composes the trailer lines into the commit
|
|
20
|
+
* message and runs git separately.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* Format a list of upstream refs into trailer lines (one per ref).
|
|
24
|
+
* Pure: returns a single string with `\n` separators, no leading or
|
|
25
|
+
* trailing newline. Caller appends to the commit-message body.
|
|
26
|
+
*/
|
|
27
|
+
export function formatTrailer(refs) {
|
|
28
|
+
return refs
|
|
29
|
+
.map((r) => `Tweaks-output-of: agent=${r.agent} sha=${r.sha.slice(0, 7)} file=${r.file}`)
|
|
30
|
+
.join("\n");
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Parse a single trailer line, returning the parsed ref or null if the
|
|
34
|
+
* line doesn't match the expected shape. Tolerates leading/trailing
|
|
35
|
+
* whitespace + the optional " " indent some `git interpret-trailers`
|
|
36
|
+
* outputs add.
|
|
37
|
+
*/
|
|
38
|
+
export function parseTrailerLine(line) {
|
|
39
|
+
const trimmed = line.trim();
|
|
40
|
+
if (!trimmed.startsWith("Tweaks-output-of:"))
|
|
41
|
+
return null;
|
|
42
|
+
const body = trimmed.slice("Tweaks-output-of:".length).trim();
|
|
43
|
+
// body looks like: "agent=vibe sha=abc1234 file=mock/src/X.tsx"
|
|
44
|
+
// file= may contain spaces in the rare case of weird paths; capture
|
|
45
|
+
// greedily as the last field.
|
|
46
|
+
const m = body.match(/^agent=(\S+)\s+sha=(\S+)\s+file=(.+)$/);
|
|
47
|
+
if (!m)
|
|
48
|
+
return null;
|
|
49
|
+
const [, agent, sha, file] = m;
|
|
50
|
+
if (!agent || !sha || !file)
|
|
51
|
+
return null;
|
|
52
|
+
return { agent, sha, file };
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Parse all `Tweaks-output-of:` trailers from a full commit-message
|
|
56
|
+
* body (multi-line). Returns refs in the order they appeared.
|
|
57
|
+
*/
|
|
58
|
+
export function parseTrailers(commitBody) {
|
|
59
|
+
const out = [];
|
|
60
|
+
for (const line of commitBody.split("\n")) {
|
|
61
|
+
const ref = parseTrailerLine(line);
|
|
62
|
+
if (ref)
|
|
63
|
+
out.push(ref);
|
|
64
|
+
}
|
|
65
|
+
return out;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Inspect a git author line + return the upstream agent name, if the
|
|
69
|
+
* author follows slowcook's agent convention. Otherwise null.
|
|
70
|
+
*
|
|
71
|
+
* Conventions detected:
|
|
72
|
+
* slowcook-vibe[bot] → "vibe"
|
|
73
|
+
* slowcook-plate[bot] → "plate"
|
|
74
|
+
* slowcook-brew[bot] → "brew"
|
|
75
|
+
* slowcook-chef[bot] → "chef"
|
|
76
|
+
* slowcook-refine[bot] → "refine"
|
|
77
|
+
* slowcook-testgen[bot] → "testgen"
|
|
78
|
+
* slowcook-recipe[bot] → "recipe"
|
|
79
|
+
* anything else → null (human or unrelated bot)
|
|
80
|
+
*
|
|
81
|
+
* Pure: no IO. Caller pipes git author through it.
|
|
82
|
+
*/
|
|
83
|
+
export function agentFromAuthor(author) {
|
|
84
|
+
const m = author.match(/^slowcook-([a-z][\w-]*)\[bot\]$/);
|
|
85
|
+
if (!m)
|
|
86
|
+
return null;
|
|
87
|
+
return m[1];
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Compose the full commit message body for a garnish commit: a one-line
|
|
91
|
+
* subject naming the touched files, a blank line, optional user-provided
|
|
92
|
+
* body, a blank line, then the trailer block.
|
|
93
|
+
*
|
|
94
|
+
* Pure: caller passes the staged-file list + the parsed upstream refs +
|
|
95
|
+
* the optional user message. Returns the body string ready for `git
|
|
96
|
+
* commit -F`.
|
|
97
|
+
*/
|
|
98
|
+
export function composeCommitMessage(args) {
|
|
99
|
+
const subject = `[garnish] ${formatTouchedFilesSummary(args.touchedFiles)}`;
|
|
100
|
+
const parts = [subject, ""];
|
|
101
|
+
if (args.userMessage && args.userMessage.trim().length > 0) {
|
|
102
|
+
parts.push(args.userMessage.trim(), "");
|
|
103
|
+
}
|
|
104
|
+
if (args.upstreamRefs.length > 0) {
|
|
105
|
+
parts.push(formatTrailer(args.upstreamRefs));
|
|
106
|
+
}
|
|
107
|
+
return parts.join("\n");
|
|
108
|
+
}
|
|
109
|
+
function formatTouchedFilesSummary(files) {
|
|
110
|
+
if (files.length === 0)
|
|
111
|
+
return "(no files)";
|
|
112
|
+
if (files.length === 1)
|
|
113
|
+
return files[0];
|
|
114
|
+
if (files.length === 2)
|
|
115
|
+
return `${files[0]} + ${files[1]}`;
|
|
116
|
+
return `${files[0]} + ${files.length - 1} more`;
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=trailer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trailer.js","sourceRoot":"","sources":["../../../src/commands/garnish/trailer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAWH;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,IAAmB;IAC/C,OAAO,IAAI;SACR,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,2BAA2B,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,CAAC;SACxF,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,mBAAmB,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1D,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IAC9D,gEAAgE;IAChE,oEAAoE;IACpE,8BAA8B;IAC9B,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC9D,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,MAAM,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/B,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACzC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;AAC9B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,UAAkB;IAC9C,MAAM,GAAG,GAAkB,EAAE,CAAC;IAC9B,KAAK,MAAM,IAAI,IAAI,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1C,MAAM,GAAG,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,GAAG;YAAE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;IAC1D,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,OAAO,CAAC,CAAC,CAAC,CAAE,CAAC;AACf,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAIpC;IACC,MAAM,OAAO,GAAG,aAAa,yBAAyB,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;IAC5E,MAAM,KAAK,GAAa,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IACtC,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3D,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;IAC1C,CAAC;IACD,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;IAC/C,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,yBAAyB,CAAC,KAAe;IAChD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,YAAY,CAAC;IAC5C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,CAAC,CAAE,CAAC;IACzC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3D,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC;AAClD,CAAC"}
|
|
@@ -52,7 +52,7 @@ export interface ReconResult {
|
|
|
52
52
|
history_index_components: number;
|
|
53
53
|
warnings: string[];
|
|
54
54
|
}
|
|
55
|
-
export declare function recon(argv: string[],
|
|
55
|
+
export declare function recon(argv: string[], cliVersion: string): Promise<void>;
|
|
56
56
|
export declare function findStoryTestFiles(repoRoot: string, story: string): string[];
|
|
57
57
|
export declare function extractImports(body: string): string[];
|
|
58
58
|
export declare function extractTestids(body: string): string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/recon/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAIH,OAAO,EAAqB,KAAK,YAAY,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/recon/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAIH,OAAO,EAAqB,KAAK,YAAY,EAAE,MAAM,4BAA4B,CAAC;AA0ClF,UAAU,cAAc;IACtB,IAAI,EAAE,WAAW,GAAG,aAAa,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,SAAS;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,UAAU,aAAa;IACrB,IAAI,EAAE,mBAAmB,GAAG,eAAe,GAAG,qBAAqB,GAAG,wBAAwB,CAAC;IAC/F,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,uBAAuB,CAAC;IACnC,MAAM,EAAE,OAAO,GAAG,eAAe,GAAG,UAAU,CAAC;IAC/C,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,WAAW,EAAE,SAAS,EAAE,CAAC;IACzB,eAAe,EAAE,aAAa,EAAE,CAAC;IACjC,wBAAwB,EAAE,MAAM,CAAC;IACjC,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AA0FD,wBAAsB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA0J7E;AAID,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAU5E;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAMrD;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAYrD;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAoB1E;AAyBD,YAAY,EAAE,YAAY,EAAE,CAAC"}
|
|
@@ -25,6 +25,7 @@ import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSy
|
|
|
25
25
|
import { dirname, join, relative } from "node:path";
|
|
26
26
|
import { buildHistoryIndex } from "../refine/history-index.js";
|
|
27
27
|
import { extractShape, synthesiseShapeTestFile, findMockFilesForStory } from "./shape-preserve.js";
|
|
28
|
+
import { isReadOnlyMode } from "../../lib/read-only.js";
|
|
28
29
|
function parseArgs(argv) {
|
|
29
30
|
const args = {
|
|
30
31
|
story: "",
|
|
@@ -150,14 +151,14 @@ Exit codes:
|
|
|
150
151
|
2 status=escalate (STORY_HISTORY_CONFLICT or VIBE_RECIPE_NAME_DRIFT)
|
|
151
152
|
`);
|
|
152
153
|
}
|
|
153
|
-
export async function recon(argv,
|
|
154
|
+
export async function recon(argv, cliVersion) {
|
|
154
155
|
const args = parseArgs(argv);
|
|
155
156
|
if (args.reuseScan) {
|
|
156
157
|
await runReuseScan(args);
|
|
157
158
|
return;
|
|
158
159
|
}
|
|
159
160
|
if (args.stubScan) {
|
|
160
|
-
await runStubScan(args);
|
|
161
|
+
await runStubScan(args, cliVersion);
|
|
161
162
|
return;
|
|
162
163
|
}
|
|
163
164
|
console.log(`slowcook recon · story-${args.story} · cwd: ${relative(process.cwd(), args.repoRoot) || "."}`);
|
|
@@ -479,7 +480,7 @@ function walkTsFiles(root, out) {
|
|
|
479
480
|
* reports stale ones + (when --stub-escalate) posts PM comment on each
|
|
480
481
|
* stub's source issue.
|
|
481
482
|
*/
|
|
482
|
-
async function runStubScan(args) {
|
|
483
|
+
async function runStubScan(args, cliVersion) {
|
|
483
484
|
const { execSync } = await import("node:child_process");
|
|
484
485
|
const { detectStubMarker, daysBetween, classifyStubAge, buildStaleStubComment, } = await import("./stale-stubs.js");
|
|
485
486
|
console.log(`slowcook recon --stub-scan · root: ${args.stubRoot} · grace: ${args.stubMaxAgeDays} days · cwd: ${relative(process.cwd(), args.repoRoot) || "."}`);
|
|
@@ -539,7 +540,10 @@ async function runStubScan(args) {
|
|
|
539
540
|
const story = s.storyId ? `story-${s.storyId}` : "(no story id)";
|
|
540
541
|
console.log(` ${tag} ${ageStr} ${story.padEnd(14)} ${s.path}`);
|
|
541
542
|
}
|
|
542
|
-
if (args.stubEscalate && stale.length > 0) {
|
|
543
|
+
if (args.stubEscalate && stale.length > 0 && isReadOnlyMode()) {
|
|
544
|
+
console.log(`\n [SLOWCOOK_READ_ONLY=1] --stub-escalate set but read-only mode is on; would post comments on ${stale.length} source issues. Skipping.`);
|
|
545
|
+
}
|
|
546
|
+
else if (args.stubEscalate && stale.length > 0) {
|
|
543
547
|
console.log("\n --stub-escalate set; posting PM comments on source issues...");
|
|
544
548
|
let repoSlug = "";
|
|
545
549
|
try {
|
|
@@ -570,7 +574,7 @@ async function runStubScan(args) {
|
|
|
570
574
|
continue;
|
|
571
575
|
}
|
|
572
576
|
const issueNumber = parseInt(issueMatch[1], 10);
|
|
573
|
-
const body = buildStaleStubComment(s, args.stubMaxAgeDays);
|
|
577
|
+
const body = buildStaleStubComment(s, args.stubMaxAgeDays, cliVersion);
|
|
574
578
|
const tmp = "/tmp/slowcook-stale-stub-comment.md";
|
|
575
579
|
writeFileSync(tmp, body, "utf8");
|
|
576
580
|
try {
|