@flumecode/runner 0.21.0-beta.1 → 0.22.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/dist/cli.js +14 -79
- package/package.json +1 -1
- package/skills-plugin/skills/create-release/SKILL.md +25 -80
package/dist/cli.js
CHANGED
|
@@ -1065,56 +1065,35 @@ function buildRepairPrompt(ctx, hookLog) {
|
|
|
1065
1065
|
];
|
|
1066
1066
|
return lines2.join("\n");
|
|
1067
1067
|
}
|
|
1068
|
-
function buildReleasePrompt(ctx
|
|
1069
|
-
const task = `Use the \`flumecode:create-release\` skill to handle this turn. You are driving a release: first analyse commits since the last tag, propose version bumps, and ask the user to confirm via widgets (Phase 1); once the user's widget answers appear in the thread,
|
|
1068
|
+
function buildReleasePrompt(ctx) {
|
|
1069
|
+
const task = `Use the \`flumecode:create-release\` skill to handle this turn. You are driving a release: first analyse commits since the last tag, propose version bumps, and ask the user to confirm via widgets (Phase 1); once the user's widget answers appear in the thread, emit the final report with the confirmed versions (Phase 2). Do NOT edit package.json or CHANGELOG.md, do NOT commit, push, or open a PR.`;
|
|
1070
1070
|
const orient = `Before investigating raw source, check for a FlumeCode wiki at \`.flumecode/wiki/\`. If it exists, read \`.flumecode/wiki/README.md\` first \u2014 it is the index \u2014 and follow its links to the pages and source paths relevant to this release. If there is no wiki, work from the code directly.`;
|
|
1071
1071
|
const widgets = `When you need the user to choose, ask it as a widget rather than writing the options as prose: call \`single_select\` for a one-of-N choice (radio buttons) or \`multi_select\` for a "select all that apply" choice (checkboxes). Don't add your own "Other" option \u2014 the UI always provides one. After calling a widget tool, end your turn \u2014 the user's answer comes back as their next message and starts a fresh run.`;
|
|
1072
1072
|
const lines2 = [
|
|
1073
1073
|
`You are "${ctx.agentName}", an autonomous coding agent driving a FlumeCode release.`,
|
|
1074
|
-
`The repository ${ctx.repo.fullName} is checked out in your current working directory
|
|
1074
|
+
`The repository ${ctx.repo.fullName} is checked out in your current working directory at the frozen release commit (branch "${ctx.repo.checkoutBranch}").`,
|
|
1075
1075
|
task,
|
|
1076
1076
|
orient,
|
|
1077
1077
|
widgets,
|
|
1078
1078
|
LANGUAGE_DIRECTIVE,
|
|
1079
1079
|
"",
|
|
1080
|
-
"These coding guidelines apply to all code produced in this run:",
|
|
1081
|
-
"",
|
|
1082
|
-
loadRule("coding-guideline"),
|
|
1083
|
-
"",
|
|
1084
1080
|
`# Release: ${ctx.request?.title ?? ""}`
|
|
1085
1081
|
];
|
|
1086
1082
|
if (ctx.request?.body) {
|
|
1087
1083
|
lines2.push("", ctx.request.body);
|
|
1088
1084
|
}
|
|
1089
|
-
if (baseChecks && !baseChecks.ok) {
|
|
1090
|
-
lines2.push(
|
|
1091
|
-
"",
|
|
1092
|
-
"# Pre-release check status",
|
|
1093
|
-
"",
|
|
1094
|
-
"\u26A0\uFE0F The repository's pre-commit checks (lint / typecheck / tests) are currently FAILING on the base branch, independently of any version bump. A release must not ship a broken base:",
|
|
1095
|
-
"",
|
|
1096
|
-
"- **Phase 1 (propose):** tell the user, in your reply, that the base currently fails these checks and that the release will fix them as part of the bump.",
|
|
1097
|
-
"- **Phase 2 (apply):** fix the failing code at its root so the checks pass, THEN apply the version bumps and CHANGELOG. Do NOT delete/skip tests or weaken assertions. The fixes ship in the same bump PR. Still do NOT commit or push \u2014 the runner does.",
|
|
1098
|
-
"",
|
|
1099
|
-
"Failing check output:",
|
|
1100
|
-
"",
|
|
1101
|
-
"```",
|
|
1102
|
-
baseChecks.log,
|
|
1103
|
-
"```"
|
|
1104
|
-
);
|
|
1105
|
-
}
|
|
1106
1085
|
if (ctx.prerelease) {
|
|
1107
1086
|
lines2.push(
|
|
1108
1087
|
"",
|
|
1109
1088
|
"# Pre-release",
|
|
1110
1089
|
"",
|
|
1111
|
-
"This is a PRE-RELEASE. When proposing
|
|
1090
|
+
"This is a PRE-RELEASE. When proposing versions, use a semver pre-release version string (e.g. `0.9.0-beta.1`): take the next stable version you would otherwise pick and append `-beta.N`, where N is the next unused beta number for that version (check existing `v<version>-beta.*` tags). Offer these pre-release strings in the version-confirmation widgets, and include them in the `flumecode:versions` comment as usual."
|
|
1112
1091
|
);
|
|
1113
1092
|
}
|
|
1114
1093
|
appendThread(lines2, ctx);
|
|
1115
1094
|
lines2.push(
|
|
1116
1095
|
"",
|
|
1117
|
-
"Your final reply is posted verbatim as your comment in the release thread \u2014 if you called widgets (Phase 1), your reply text accompanies the questions; if you
|
|
1096
|
+
"Your final reply is posted verbatim as your comment in the release thread \u2014 if you called widgets (Phase 1), your reply text accompanies the questions; if you emitted the final report (Phase 2), make it the report the skill produced."
|
|
1118
1097
|
);
|
|
1119
1098
|
return lines2.join("\n");
|
|
1120
1099
|
}
|
|
@@ -1311,27 +1290,6 @@ function commitFailureLog(err) {
|
|
|
1311
1290
|
const parts = [e.stdout, e.stderr].map((s) => typeof s === "string" ? s.trim() : "").filter((s) => s.length > 0);
|
|
1312
1291
|
return parts.length > 0 ? parts.join("\n") : e.message ?? String(err);
|
|
1313
1292
|
}
|
|
1314
|
-
function isUnsupportedGitSubcommand(err) {
|
|
1315
|
-
const e = err;
|
|
1316
|
-
const text = `${typeof e.stderr === "string" ? e.stderr : ""}
|
|
1317
|
-
${e.message ?? ""}`;
|
|
1318
|
-
return /is not a git command|unknown subcommand|usage: git hook/i.test(text);
|
|
1319
|
-
}
|
|
1320
|
-
async function runRepoChecks(dir) {
|
|
1321
|
-
try {
|
|
1322
|
-
await git(["-C", dir, "hook", "run", "pre-commit"]);
|
|
1323
|
-
logEvent("checks", "pre-commit hook passed");
|
|
1324
|
-
return { ok: true, log: "", skipped: false };
|
|
1325
|
-
} catch (err) {
|
|
1326
|
-
if (isUnsupportedGitSubcommand(err)) {
|
|
1327
|
-
logEvent("checks", "pre-commit hook skipped (git too old)");
|
|
1328
|
-
return { ok: true, log: "", skipped: true };
|
|
1329
|
-
}
|
|
1330
|
-
const log = commitFailureLog(err);
|
|
1331
|
-
logEvent("checks:err", log);
|
|
1332
|
-
return { ok: false, log, skipped: false };
|
|
1333
|
-
}
|
|
1334
|
-
}
|
|
1335
1293
|
async function commitChanges(ctx, dir) {
|
|
1336
1294
|
if (!await hasChanges(dir)) return false;
|
|
1337
1295
|
try {
|
|
@@ -1428,10 +1386,9 @@ async function openPullRequest(ctx) {
|
|
|
1428
1386
|
return { number: data.number, url: data.html_url };
|
|
1429
1387
|
}
|
|
1430
1388
|
if (res.status === 422) {
|
|
1431
|
-
const list = await fetch(
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
);
|
|
1389
|
+
const list = await fetch(`${apiBase}/pulls?state=open&head=${owner}:${checkoutBranch}`, {
|
|
1390
|
+
headers
|
|
1391
|
+
});
|
|
1435
1392
|
if (list.ok) {
|
|
1436
1393
|
const open = await list.json();
|
|
1437
1394
|
if (open[0]) return { number: open[0].number, url: open[0].html_url };
|
|
@@ -1897,48 +1854,26 @@ async function processResolveJob(ctx, dir, config, abort) {
|
|
|
1897
1854
|
reply += outcomeBanner(outcome, { branch: ctx.repo.checkoutBranch });
|
|
1898
1855
|
return { text: reply, widgets: [], ...report ? { report } : {}, ...pr ? { pr } : {} };
|
|
1899
1856
|
}
|
|
1900
|
-
async function processReleaseJob(ctx, dir,
|
|
1857
|
+
async function processReleaseJob(ctx, dir, _resumed, _config, abort) {
|
|
1901
1858
|
console.log(`
|
|
1902
1859
|
\u25B6 Release ${ctx.jobId} \u2014 ${ctx.repo.fullName}: "${jobTitle(ctx)}"`);
|
|
1903
|
-
|
|
1904
|
-
const checks = await runRepoChecks(dir);
|
|
1905
|
-
if (checks.skipped) {
|
|
1906
|
-
console.log(` \u2026release ${ctx.jobId}: pre-release checks skipped (git too old for 'hook run')`);
|
|
1907
|
-
} else {
|
|
1908
|
-
console.log(` \u2026release ${ctx.jobId}: pre-release checks ${checks.ok ? "passed" : "FAILED"}`);
|
|
1909
|
-
}
|
|
1910
|
-
const baseChecks = checks.ok ? void 0 : { ok: false, log: trimHookLog(checks.log) };
|
|
1860
|
+
await installDependencies(dir);
|
|
1911
1861
|
const result = await runClaudeCode({
|
|
1912
1862
|
cwd: dir,
|
|
1913
|
-
prompt: buildReleasePrompt(ctx
|
|
1863
|
+
prompt: buildReleasePrompt(ctx),
|
|
1914
1864
|
permissionMode: ctx.permissionMode,
|
|
1915
1865
|
model: orchestratorModel(ctx),
|
|
1916
1866
|
maxTurns: ORCHESTRATOR_MAX_TURNS,
|
|
1917
1867
|
abortController: abort
|
|
1918
1868
|
});
|
|
1919
|
-
|
|
1920
|
-
if (installResult.status === "failed") {
|
|
1921
|
-
reply += `
|
|
1922
|
-
|
|
1923
|
-
> \u26A0\uFE0F Dependencies failed to install (\`${installResult.manager}\`); tests may not have run.`;
|
|
1924
|
-
}
|
|
1869
|
+
const reply = result.text.trim() || "(the agent produced no reply)";
|
|
1925
1870
|
if (result.widgets.length > 0) {
|
|
1926
1871
|
console.log(
|
|
1927
1872
|
` \u2026release ${ctx.jobId} posted ${result.widgets.length} widget(s); awaiting reply`
|
|
1928
1873
|
);
|
|
1929
1874
|
return { text: reply, widgets: result.widgets };
|
|
1930
1875
|
}
|
|
1931
|
-
|
|
1932
|
-
rebase: !resumed
|
|
1933
|
-
});
|
|
1934
|
-
if (outcome.kind !== "none") {
|
|
1935
|
-
reply += outcomeBanner(outcome, { branch: ctx.repo.checkoutBranch, autoMerged });
|
|
1936
|
-
}
|
|
1937
|
-
return {
|
|
1938
|
-
text: reply,
|
|
1939
|
-
widgets: [],
|
|
1940
|
-
...outcome.kind === "pr" ? { pr: outcome.pr } : {}
|
|
1941
|
-
};
|
|
1876
|
+
return { text: reply, widgets: [] };
|
|
1942
1877
|
}
|
|
1943
1878
|
async function heartbeat(config) {
|
|
1944
1879
|
const health = await checkClaudeCode();
|
|
@@ -2075,7 +2010,7 @@ ${trimmed}` : trimmed;
|
|
|
2075
2010
|
}
|
|
2076
2011
|
function formatJobError(ctx, err) {
|
|
2077
2012
|
if (!(err instanceof PreCommitError)) return errorMessage2(err);
|
|
2078
|
-
const nextStep = ctx.kind === "release" ? `These checks are failing on \`${ctx.repo.mergeBranch}\` independently of
|
|
2013
|
+
const nextStep = ctx.kind === "release" ? `These checks are failing on \`${ctx.repo.mergeBranch}\` independently of this release, and the release couldn't fix them after ${MAX_COMMIT_REPAIRS} automatic attempts. Open a request on **${ctx.repo.fullName}** to fix the failing checks above, then start the release again once that fix has merged.` : `The agent couldn't get its change past these checks after ${MAX_COMMIT_REPAIRS} automatic repair attempts. Open a request on **${ctx.repo.fullName}** describing the failing checks above so the agent can fix them at their root, then try again.`;
|
|
2079
2014
|
return [
|
|
2080
2015
|
"\u274C **Blocked by failing pre-commit checks.**",
|
|
2081
2016
|
"",
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: create-release
|
|
3
3
|
description: >-
|
|
4
|
-
Draft release notes and version suggestions for a release
|
|
5
|
-
user
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
Draft release notes and version suggestions for a release. Two-turn flow:
|
|
5
|
+
first turn asks the user to confirm versions via widgets; second turn (answers
|
|
6
|
+
in thread) emits the structured report with confirmed versions and notes. Does
|
|
7
|
+
NOT edit package.json or CHANGELOG.md, and does NOT commit, push, or open a PR.
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# create-release
|
|
@@ -17,7 +17,7 @@ which one applies before acting.
|
|
|
17
17
|
Check the thread (`# Conversation so far` in the prompt). If **no widget answers**
|
|
18
18
|
appear in any prior agent turn, this is **Phase 1** — propose versions and ask.
|
|
19
19
|
If a prior turn contains widget-answer selections (the user picked a version), this
|
|
20
|
-
is **Phase 2** —
|
|
20
|
+
is **Phase 2** — emit the final report.
|
|
21
21
|
|
|
22
22
|
---
|
|
23
23
|
|
|
@@ -99,11 +99,11 @@ can read them inside the question widget:
|
|
|
99
99
|
- `options`: `Yes, use these notes`, `I'll edit them in the PR`
|
|
100
100
|
(You may still summarise in the reply text, but the notes MUST be in the widget `body`.)
|
|
101
101
|
|
|
102
|
-
**After calling widgets, end your turn.** Do NOT
|
|
102
|
+
**After calling widgets, end your turn.** Do NOT edit any files in Phase 1.
|
|
103
103
|
|
|
104
104
|
---
|
|
105
105
|
|
|
106
|
-
## Phase 2 —
|
|
106
|
+
## Phase 2 — Emit the final report
|
|
107
107
|
|
|
108
108
|
### 1. Read the widget answers
|
|
109
109
|
|
|
@@ -111,52 +111,19 @@ The user's confirmed version selections appear in the `# Conversation so far`
|
|
|
111
111
|
thread as agent messages (the widget-answer turn). Extract the chosen version for
|
|
112
112
|
each package from those selections.
|
|
113
113
|
|
|
114
|
-
### 2.
|
|
114
|
+
### 2. Emit the structured report
|
|
115
115
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
- `apps/web/package.json` — for `@flumecode/web`
|
|
119
|
-
- `apps/runner/package.json` — for `@flumecode/runner`
|
|
120
|
-
|
|
121
|
-
Change only the `"version"` line; do not reformat the file.
|
|
122
|
-
|
|
123
|
-
### 3. Update CHANGELOG.md
|
|
124
|
-
|
|
125
|
-
Edit (or create) `CHANGELOG.md` at the repo root. Insert a new section at the
|
|
126
|
-
top, below any existing `# Changelog` title line:
|
|
116
|
+
Your final message must match this shape (adjust versions and notes to match what
|
|
117
|
+
was confirmed):
|
|
127
118
|
|
|
128
119
|
```
|
|
129
|
-
|
|
120
|
+
**Confirmed versions:**
|
|
121
|
+
- `@flumecode/web`: `0.9.0`
|
|
122
|
+
- `@flumecode/runner`: `0.5.0`
|
|
130
123
|
|
|
124
|
+
**Release notes:**
|
|
131
125
|
- Bullet point from release notes
|
|
132
126
|
- Another bullet point
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
Use the ISO date format (`YYYY-MM-DD`). Preserve all existing entries — do not
|
|
136
|
-
delete or rewrite prior sections.
|
|
137
|
-
|
|
138
|
-
If both packages are bumped, list both versions in the heading (e.g.
|
|
139
|
-
`## [0.9.0 / runner-0.5.0] - 2026-06-06`). If only one package is bumped, list
|
|
140
|
-
only that version in the heading.
|
|
141
|
-
|
|
142
|
-
### 4. Stop — do not commit or push
|
|
143
|
-
|
|
144
|
-
Leave the edited files in the working tree. The runner commits them and opens the
|
|
145
|
-
pull request.
|
|
146
|
-
|
|
147
|
-
### 5. End with this exact report format
|
|
148
|
-
|
|
149
|
-
Your final message must match this shape (adjust versions and files to match what
|
|
150
|
-
actually changed):
|
|
151
|
-
|
|
152
|
-
```
|
|
153
|
-
**Bumped versions:**
|
|
154
|
-
- `@flumecode/web`: `0.8.0` → `0.9.0`
|
|
155
|
-
- `@flumecode/runner`: `0.4.0` → `0.5.0`
|
|
156
|
-
|
|
157
|
-
**CHANGELOG updated** with release notes.
|
|
158
|
-
|
|
159
|
-
**Files changed:** `apps/web/package.json`, `apps/runner/package.json`, `CHANGELOG.md`
|
|
160
127
|
|
|
161
128
|
<!-- flumecode:versions {"@flumecode/web":"0.9.0","@flumecode/runner":"0.5.0"} -->
|
|
162
129
|
```
|
|
@@ -167,21 +134,20 @@ reads it to persist the confirmed versions on the release entity. Use the exact
|
|
|
167
134
|
JSON key names `@flumecode/web` and `@flumecode/runner`; omit a package if its
|
|
168
135
|
version did not change.
|
|
169
136
|
|
|
137
|
+
**Do NOT edit package.json, CHANGELOG.md, or any other file. Do NOT commit,
|
|
138
|
+
push, or open a pull request.** The GitHub Release is cut directly from the
|
|
139
|
+
frozen commit by the web interface.
|
|
140
|
+
|
|
170
141
|
---
|
|
171
142
|
|
|
172
143
|
## Notes
|
|
173
144
|
|
|
174
|
-
- **Runner-only bump:** if only `apps/runner/` has commits,
|
|
175
|
-
`apps/runner/package.json
|
|
145
|
+
- **Runner-only bump:** if only `apps/runner/` has commits, include only
|
|
146
|
+
`apps/runner/package.json`'s version in the `flumecode:versions` comment.
|
|
176
147
|
- **Clear Phase 1 text:** be explicit about what changed since the last tag so the
|
|
177
148
|
user can confidently confirm or override your suggestions.
|
|
178
|
-
- **
|
|
179
|
-
|
|
180
|
-
exception: when the prompt includes a **`# Pre-release check status`** section
|
|
181
|
-
reporting failing checks, you must also fix the failing code (any file needed) so
|
|
182
|
-
the tree is green — see "Pre-release checks" below. Never weaken or skip checks to
|
|
183
|
-
silence them.
|
|
184
|
-
- **Never commit, push, or open a PR** — the runner does that.
|
|
149
|
+
- **Read-only:** do not edit any files at any point. This skill is purely
|
|
150
|
+
analytical — it reads the repo, proposes versions, and emits a report.
|
|
185
151
|
|
|
186
152
|
## Pre-release
|
|
187
153
|
|
|
@@ -202,27 +168,6 @@ pre-release version strings instead of stable ones:
|
|
|
202
168
|
`0.9.0-beta.1`) in the version-confirmation widgets instead of the stable
|
|
203
169
|
version.
|
|
204
170
|
|
|
205
|
-
- **Phase 2 (
|
|
206
|
-
`0.9.0-beta.1`)
|
|
207
|
-
|
|
208
|
-
stable release, just with the pre-release suffix included.
|
|
209
|
-
|
|
210
|
-
---
|
|
211
|
-
|
|
212
|
-
## Pre-release checks
|
|
213
|
-
|
|
214
|
-
We cannot release code with failing checks. Before this turn, the runner ran the
|
|
215
|
-
repository's own pre-commit hook (lint / typecheck / tests). If the prompt contains
|
|
216
|
-
a **`# Pre-release check status`** section, the base branch is currently broken
|
|
217
|
-
_independently of the version bump_:
|
|
218
|
-
|
|
219
|
-
- **Phase 1:** state plainly in your reply that the base currently fails these
|
|
220
|
-
checks and that the release will fix them as part of the bump, then ask the
|
|
221
|
-
version questions as usual.
|
|
222
|
-
- **Phase 2:** fix the failing code at its root **first** (so the checks pass),
|
|
223
|
-
**then** apply the version bumps and CHANGELOG. The fixes ship in the same bump
|
|
224
|
-
PR. Do not delete or skip tests, weaken assertions, or disable checks. Still do
|
|
225
|
-
not commit or push — the runner commits everything together.
|
|
226
|
-
|
|
227
|
-
If there is no `# Pre-release check status` section, the base is clean (or the check
|
|
228
|
-
was skipped); proceed normally and edit only the version files.
|
|
171
|
+
- **Phase 2 (emit):** include the pre-release version string (e.g.
|
|
172
|
+
`0.9.0-beta.1`) in the `<!-- flumecode:versions {...} -->` comment — exactly
|
|
173
|
+
as you would for a stable release, just with the pre-release suffix included.
|