@ravshansbox/pi-next-issue 1.0.11 → 1.0.13
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 +2 -2
- package/package.json +1 -1
- package/src/github.ts +9 -2
- package/src/ports.ts +5 -1
- package/src/runner.ts +6 -1
package/README.md
CHANGED
|
@@ -22,7 +22,7 @@ The run does not belong to a session: it goes on after `/new`, `/resume`, a fork
|
|
|
22
22
|
|
|
23
23
|
## What it does
|
|
24
24
|
|
|
25
|
-
Each loop fetches the 200 oldest open issues with the `status:todo` label and none of `status:in-progress`, `status:done`, `status:needs-human` or `status:blocked`, and the open issues with saved state that it can read. It takes the oldest one with saved state
|
|
25
|
+
Each loop fetches the 200 oldest open issues with the `status:todo` label and none of `status:in-progress`, `status:done`, `status:needs-human` or `status:blocked`, and the open issues with saved state that it can read. It takes the oldest one with saved state and none of `status:done`, `status:needs-human` or `status:blocked`, else the oldest one with the `status:todo` label and none of `status:in-progress`, `status:done`, `status:needs-human` or `status:blocked`. The run ends when no such issue is left, or at the first error. For each issue:
|
|
26
26
|
|
|
27
27
|
1. Swap `status:todo` for `status:in-progress`.
|
|
28
28
|
2. Add a git worktree at `.worktrees/<n>` on the `<n>` branch, from the remote default branch.
|
|
@@ -39,7 +39,7 @@ The implementer and the reviewer read the issue title, the body and the comments
|
|
|
39
39
|
|
|
40
40
|
Each agent is a pi session in the worktree. It uses the model and thinking level from your pi settings, and loads all of your extensions except this one.
|
|
41
41
|
|
|
42
|
-
The state of each issue is saved in `.worktrees/<n>.json`. A run holds `.worktrees/run.lock`, which keeps the process id, so that only one pi at a time works on a repository. A second run fails at once. A lock whose process is no longer alive is taken over. If the operating system gives that process id to another process, the lock stays; remove `.worktrees/run.lock` by hand when no run is going. The extension adds `/.worktrees/` to `.git/info/exclude`.
|
|
42
|
+
The state of each issue is saved in `.worktrees/<n>.json`. Each loop removes the saved state of an issue that is closed. A run holds `.worktrees/run.lock`, which keeps the process id, so that only one pi at a time works on a repository. A second run fails at once. A lock whose process is no longer alive is taken over. If the operating system gives that process id to another process, the lock stays; remove `.worktrees/run.lock` by hand when no run is going. The extension adds `/.worktrees/` to `.git/info/exclude`.
|
|
43
43
|
|
|
44
44
|
## Config
|
|
45
45
|
|
package/package.json
CHANGED
package/src/github.ts
CHANGED
|
@@ -38,7 +38,10 @@ type RawIssue = {
|
|
|
38
38
|
|
|
39
39
|
const ISSUE_FIELDS = 'number,title,body,labels,createdAt';
|
|
40
40
|
|
|
41
|
-
export async function openIssues(
|
|
41
|
+
export async function openIssues(
|
|
42
|
+
repo: Repo,
|
|
43
|
+
saved: number[],
|
|
44
|
+
): Promise<{ open: Issue[]; closed: number[] }> {
|
|
42
45
|
const raw = await gh(repo, [
|
|
43
46
|
'issue',
|
|
44
47
|
'list',
|
|
@@ -55,6 +58,7 @@ export async function openIssues(repo: Repo, saved: number[]): Promise<Issue[]>
|
|
|
55
58
|
]);
|
|
56
59
|
const listed = JSON.parse(raw) as RawIssue[];
|
|
57
60
|
const known = new Set(listed.map((item) => item.number));
|
|
61
|
+
const closed: number[] = [];
|
|
58
62
|
for (const number of saved.filter((item) => !known.has(item))) {
|
|
59
63
|
const view = await run(
|
|
60
64
|
'gh',
|
|
@@ -67,9 +71,11 @@ export async function openIssues(repo: Repo, saved: number[]): Promise<Issue[]>
|
|
|
67
71
|
const item = JSON.parse(view.stdout) as RawIssue & { state: string };
|
|
68
72
|
if (item.state === 'OPEN') {
|
|
69
73
|
listed.push(item);
|
|
74
|
+
} else {
|
|
75
|
+
closed.push(number);
|
|
70
76
|
}
|
|
71
77
|
}
|
|
72
|
-
|
|
78
|
+
const open = listed
|
|
73
79
|
.sort((a, b) => a.createdAt.localeCompare(b.createdAt))
|
|
74
80
|
.map((item) => ({
|
|
75
81
|
number: item.number,
|
|
@@ -77,6 +83,7 @@ export async function openIssues(repo: Repo, saved: number[]): Promise<Issue[]>
|
|
|
77
83
|
body: item.body ?? '',
|
|
78
84
|
labels: item.labels.map((label) => label.name),
|
|
79
85
|
}));
|
|
86
|
+
return { open, closed };
|
|
80
87
|
}
|
|
81
88
|
|
|
82
89
|
export async function comments(repo: Repo, issue: number): Promise<string[]> {
|
package/src/ports.ts
CHANGED
|
@@ -10,7 +10,11 @@ export async function createPorts(root: string, config: Config): Promise<Ports>
|
|
|
10
10
|
const base = await github.defaultBranch(repo);
|
|
11
11
|
const timeoutMs = config.checkTimeoutMinutes * 60_000;
|
|
12
12
|
return {
|
|
13
|
-
openIssues: async () =>
|
|
13
|
+
openIssues: async () => {
|
|
14
|
+
const { open, closed } = await github.openIssues(repo, await state.savedIssues(root));
|
|
15
|
+
await Promise.all(closed.map((issue) => state.dropState(root, issue)));
|
|
16
|
+
return open;
|
|
17
|
+
},
|
|
14
18
|
comments: (issue) => github.comments(repo, issue),
|
|
15
19
|
setLabel: (issue, add, remove) => github.setLabel(repo, issue, add, remove),
|
|
16
20
|
commentOnIssue: (issue, body) => github.commentOnIssue(repo, issue, body),
|
package/src/runner.ts
CHANGED
|
@@ -99,6 +99,10 @@ function ready(issue: Issue): boolean {
|
|
|
99
99
|
);
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
function resumable(issue: Issue): boolean {
|
|
103
|
+
return !issue.labels.some((label) => label !== LABELS.inProgress && STOP_LABELS.includes(label));
|
|
104
|
+
}
|
|
105
|
+
|
|
102
106
|
export class Runner {
|
|
103
107
|
progress: Progress = { status: 'idle', tools: 0, handled: [] };
|
|
104
108
|
private readonly controller = new AbortController();
|
|
@@ -137,7 +141,8 @@ export class Runner {
|
|
|
137
141
|
const saved = new Set(await this.ports.savedIssues());
|
|
138
142
|
const fresh = issues.filter((item) => !seen.has(item.number));
|
|
139
143
|
const next =
|
|
140
|
-
fresh.find((item) => saved.has(item.number)
|
|
144
|
+
fresh.find((item) => saved.has(item.number) && resumable(item)) ??
|
|
145
|
+
fresh.find((item) => ready(item));
|
|
141
146
|
if (next === undefined) {
|
|
142
147
|
this.update({ status: 'finished', stage: undefined, issue: undefined, title: undefined });
|
|
143
148
|
return;
|