@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 CHANGED
@@ -1065,56 +1065,35 @@ function buildRepairPrompt(ctx, hookLog) {
1065
1065
  ];
1066
1066
  return lines2.join("\n");
1067
1067
  }
1068
- function buildReleasePrompt(ctx, baseChecks) {
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, apply the bumps to package.json files and update CHANGELOG.md (Phase 2). Do NOT commit or push \u2014 the runner handles that and opens the bump PR.`;
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 on the release bump branch "${ctx.repo.checkoutBranch}".`,
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 and applying 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 write them to package.json, CHANGELOG.md, and the `flumecode:versions` comment as usual."
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 applied the bumps (Phase 2), make it the report the skill produced. The runner appends the pull-request link."
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
- `${apiBase}/pulls?state=open&head=${owner}:${checkoutBranch}&base=${mergeBranch}`,
1433
- { headers }
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, resumed, config, abort) {
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
- const installResult = await installDependencies(dir);
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, baseChecks),
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
- let reply = result.text.trim() || "(the agent produced no reply)";
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
- const { outcome, autoMerged } = await pushAndOpenPr(ctx, dir, config, abort, {
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 the version bump, 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.`;
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@flumecode/runner",
3
- "version": "0.21.0-beta.1",
3
+ "version": "0.22.0",
4
4
  "type": "module",
5
5
  "description": "FlumeCode local runner — claims jobs and drives your local Claude Code against a real checkout.",
6
6
  "bin": {
@@ -1,10 +1,10 @@
1
1
  ---
2
2
  name: create-release
3
3
  description: >-
4
- Draft release notes and version suggestions for a release, then (after the
5
- user confirms) open a bump PR that updates package.json version(s) and
6
- CHANGELOG.md. Two-turn flow: first turn asks the user to confirm versions via
7
- widgets; second turn (answers in thread) writes the bumps and opens the PR.
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** — apply the bumps and report.
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 open a PR in Phase 1.
102
+ **After calling widgets, end your turn.** Do NOT edit any files in Phase 1.
103
103
 
104
104
  ---
105
105
 
106
- ## Phase 2 — Apply the bumps and report
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. Update package.json files
114
+ ### 2. Emit the structured report
115
115
 
116
- For each package whose version changed, edit the `"version"` field in:
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
- ## [X.Y.Z / runner-X.Y.Z] - YYYY-MM-DD
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, bump only
175
- `apps/runner/package.json`. Leave `apps/web/package.json` unchanged.
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
- - **Edit only version files with one exception.** Normally edit only
179
- `apps/web/package.json`, `apps/runner/package.json`, and `CHANGELOG.md`. The sole
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 (apply):** write the pre-release version string (e.g.
206
- `0.9.0-beta.1`) to `package.json`, `CHANGELOG.md`, and the
207
- `<!-- flumecode:versions {...} -->` comment exactly as you would for a
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.