@ravshansbox/pi-next-issue 1.1.0 → 1.2.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.
Files changed (3) hide show
  1. package/README.md +12 -14
  2. package/index.ts +26 -46
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -10,13 +10,11 @@ It needs `git` and an authenticated [`gh`](https://cli.github.com/). It works wi
10
10
 
11
11
  ## Use
12
12
 
13
- Run these in pi, inside a git repository:
13
+ Run this in pi, inside a git repository:
14
14
 
15
- - `/next-issue start` starts a run.
16
- - `/next-issue stop` stops the run. The issue keeps its saved state, and the next run resumes it.
17
- - `/next-issue status` shows where the run is.
15
+ - `/next-issue` starts a run when none is going, and stops the run when one is going or stopping. A stopped issue keeps its saved state, and the next run resumes it.
18
16
 
19
- The footer shows the issue, the stage, the number of tool calls and the time spent on the issue, for example `next-issue #12 · review 1/3 · 37 tools · 4m12s`. A line above the editor shows the last tool call. In the terminal, both use the dim colour of the theme, like the rest of the footer. A note appears when an issue is merged or needs a human.
17
+ The footer shows the issue, the stage, the number of tool calls and the time spent on the issue, for example `next-issue #12 · review 1/3 · 37 tools · 4m12s`. After a run ends, it keeps the last summary. A line above the editor shows the last tool call. In the terminal, both use the dim colour of the theme, like the rest of the footer. A note appears when an issue is merged or needs a human.
20
18
 
21
19
  The run does not belong to a session: it goes on after `/new`, `/resume`, a fork or a reload, and the new session shows it. It stops when you quit pi.
22
20
 
@@ -28,7 +26,7 @@ Each loop fetches the 200 oldest open issues with the `status:todo` label and no
28
26
  2. Add a git worktree at `.worktrees/<n>` on the `<n>` branch, from the remote default branch.
29
27
  3. The implementer agent does the work. The extension commits it, with the subject from a `commit:` line in the reply of the agent, and pushes. When a resumed issue already has a commit ahead of the base, the extension keeps it and skips the implementer.
30
28
  4. Open a pull request that closes the issue.
31
- 5. Wait for the checks. On a red build, the fixer agent gets the failed logs, up to `maxCiFixes` times.
29
+ 5. Wait for the checks. On a red build, the fixer agent gets the failed logs. It gets at most `maxCiFixes` such fixes for the whole issue, and this count includes the checks after review fixes.
32
30
  6. The reviewer agent judges the diff and gives a verdict with `blocking` and `minor` findings, which goes on the pull request. Any change the reviewer makes is thrown away.
33
31
  7. While review rounds are left, the fixer gets every finding, and the checks and the review run again. In the last round only a blocking finding stops the merge.
34
32
  8. Squash-merge the pull request, wait until it is merged, set `status:done`, and remove the worktree, the local branch, the remote branch and the saved state.
@@ -45,11 +43,11 @@ The state of each issue is saved in `.worktrees/<n>.json`. Each loop removes the
45
43
 
46
44
  An optional `.pi/next-issue.json` in the repository sets these fields:
47
45
 
48
- | Field | Default | Meaning |
49
- | --------------------- | ---------- | ------------------------------------------------- |
50
- | `remote` | `"origin"` | The git remote to push to. |
51
- | `maxCiFixes` | `3` | Fixes of red checks per issue. |
52
- | `maxReviewRounds` | `3` | Review rounds per issue. |
53
- | `checkTimeoutMinutes` | `30` | The longest wait for the checks, and for a merge. |
54
- | `diffMaxChars` | `60000` | The longest diff that the reviewer gets. |
55
- | `logMaxChars` | `20000` | The longest failed log that the fixer gets. |
46
+ | Field | Default | Meaning |
47
+ | --------------------- | ---------- | --------------------------------------------------------------------------------- |
48
+ | `remote` | `"origin"` | The git remote to push to. |
49
+ | `maxCiFixes` | `3` | Fixes of red checks for the whole issue, including the checks after review fixes. |
50
+ | `maxReviewRounds` | `3` | Review rounds per issue. |
51
+ | `checkTimeoutMinutes` | `30` | The longest wait for the checks, and for a merge. |
52
+ | `diffMaxChars` | `60000` | The longest diff that the reviewer gets. |
53
+ | `logMaxChars` | `20000` | The longest failed log that the fixer gets. |
package/index.ts CHANGED
@@ -148,59 +148,39 @@ export function createExtension(launch: Launch) {
148
148
  });
149
149
 
150
150
  pi.registerCommand('next-issue', {
151
- description: 'Work through the GitHub issues of this repository in the background',
152
- getArgumentCompletions: (prefix) => {
153
- const items = ['start', 'stop', 'status']
154
- .filter((name) => name.startsWith(prefix))
155
- .map((name) => ({ value: name, label: name }));
156
- return items.length > 0 ? items : null;
157
- },
158
- handler: async (args, ctx) => {
159
- const action = args.trim() || 'status';
151
+ description: 'Start or stop working through the GitHub issues of this repository',
152
+ handler: async (_args, ctx) => {
160
153
  const current = holder().runner;
161
154
  const busy =
162
155
  current?.progress.status === 'running' || current?.progress.status === 'stopping';
163
- if (action === 'start') {
164
- if (busy || holder().launching) {
165
- ctx.ui.notify('next-issue is running already', 'warning');
166
- return;
167
- }
168
- holder().launching = true;
169
- let runner: Runner;
170
- try {
171
- runner = await launch(ctx.cwd);
172
- } catch (error) {
173
- ctx.ui.notify(
174
- `next-issue cannot start: ${error instanceof Error ? error.message : String(error)}`,
175
- 'error',
176
- );
177
- return;
178
- } finally {
179
- holder().launching = false;
180
- }
181
- holder().runner = runner;
182
- if (ctx.hasUI) {
183
- ui = ctx.ui;
184
- coloured = ctx.mode === 'tui';
185
- follow(runner);
186
- }
187
- void runner.run();
188
- } else if (action === 'stop') {
189
- if (!busy) {
190
- ctx.ui.notify('next-issue is not running', 'info');
191
- return;
192
- }
156
+ if (busy) {
193
157
  current?.stop();
194
- } else if (action === 'status') {
158
+ return;
159
+ }
160
+ if (holder().launching) {
161
+ ctx.ui.notify('next-issue is starting already', 'warning');
162
+ return;
163
+ }
164
+ holder().launching = true;
165
+ let runner: Runner;
166
+ try {
167
+ runner = await launch(ctx.cwd);
168
+ } catch (error) {
195
169
  ctx.ui.notify(
196
- current === undefined
197
- ? 'next-issue has not run yet'
198
- : formatStatus(current.progress, Date.now()),
199
- 'info',
170
+ `next-issue cannot start: ${error instanceof Error ? error.message : String(error)}`,
171
+ 'error',
200
172
  );
201
- } else {
202
- ctx.ui.notify('usage: /next-issue start | stop | status', 'warning');
173
+ return;
174
+ } finally {
175
+ holder().launching = false;
176
+ }
177
+ holder().runner = runner;
178
+ if (ctx.hasUI) {
179
+ ui = ctx.ui;
180
+ coloured = ctx.mode === 'tui';
181
+ follow(runner);
203
182
  }
183
+ void runner.run();
204
184
  },
205
185
  });
206
186
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ravshansbox/pi-next-issue",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Pi extension that works through GitHub issues in the background",
5
5
  "license": "MIT",
6
6
  "type": "module",