@ravshansbox/pi-next-issue 1.0.12 → 1.0.14
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/git.ts +10 -0
- package/src/ports.ts +1 -0
- package/src/runner.ts +12 -1
package/README.md
CHANGED
|
@@ -22,11 +22,11 @@ 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.
|
|
29
|
-
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.
|
|
29
|
+
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
30
|
4. Open a pull request that closes the issue.
|
|
31
31
|
5. Wait for the checks. On a red build, the fixer agent gets the failed logs, up to `maxCiFixes` times.
|
|
32
32
|
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.
|
package/package.json
CHANGED
package/src/git.ts
CHANGED
|
@@ -77,6 +77,16 @@ export async function commit(cwd: string, message: string): Promise<boolean> {
|
|
|
77
77
|
return true;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
+
export async function ahead(
|
|
81
|
+
cwd: string,
|
|
82
|
+
remote: string,
|
|
83
|
+
base: string,
|
|
84
|
+
): Promise<string | undefined> {
|
|
85
|
+
const range = `${remote}/${base}..HEAD`;
|
|
86
|
+
const subjects = await must('git', ['log', '--reverse', '--format=%s', range], { cwd });
|
|
87
|
+
return subjects.split('\n')[0] || undefined;
|
|
88
|
+
}
|
|
89
|
+
|
|
80
90
|
export async function push(cwd: string, remote: string, branch: string): Promise<void> {
|
|
81
91
|
await must('git', ['push', '-u', remote, `HEAD:refs/heads/${branch}`], { cwd });
|
|
82
92
|
}
|
package/src/ports.ts
CHANGED
|
@@ -20,6 +20,7 @@ export async function createPorts(root: string, config: Config): Promise<Ports>
|
|
|
20
20
|
commentOnIssue: (issue, body) => github.commentOnIssue(repo, issue, body),
|
|
21
21
|
worktree: (issue, branch) => git.worktree(root, config.remote, base, issue, branch),
|
|
22
22
|
commit: (cwd, message) => git.commit(cwd, message),
|
|
23
|
+
ahead: (cwd) => git.ahead(cwd, config.remote, base),
|
|
23
24
|
push: (cwd, branch) => git.push(cwd, config.remote, branch),
|
|
24
25
|
discard: (cwd, branch) => git.discard(cwd, config.remote, branch),
|
|
25
26
|
diff: (cwd) => git.diff(cwd, config.remote, base),
|
package/src/runner.ts
CHANGED
|
@@ -45,6 +45,7 @@ export type Ports = {
|
|
|
45
45
|
commentOnIssue(issue: number, body: string): Promise<void>;
|
|
46
46
|
worktree(issue: number, branch: string): Promise<string>;
|
|
47
47
|
commit(cwd: string, message: string): Promise<boolean>;
|
|
48
|
+
ahead(cwd: string): Promise<string | undefined>;
|
|
48
49
|
push(cwd: string, branch: string): Promise<void>;
|
|
49
50
|
discard(cwd: string, branch: string): Promise<void>;
|
|
50
51
|
diff(cwd: string): Promise<string>;
|
|
@@ -99,6 +100,10 @@ function ready(issue: Issue): boolean {
|
|
|
99
100
|
);
|
|
100
101
|
}
|
|
101
102
|
|
|
103
|
+
function resumable(issue: Issue): boolean {
|
|
104
|
+
return !issue.labels.some((label) => label !== LABELS.inProgress && STOP_LABELS.includes(label));
|
|
105
|
+
}
|
|
106
|
+
|
|
102
107
|
export class Runner {
|
|
103
108
|
progress: Progress = { status: 'idle', tools: 0, handled: [] };
|
|
104
109
|
private readonly controller = new AbortController();
|
|
@@ -137,7 +142,8 @@ export class Runner {
|
|
|
137
142
|
const saved = new Set(await this.ports.savedIssues());
|
|
138
143
|
const fresh = issues.filter((item) => !seen.has(item.number));
|
|
139
144
|
const next =
|
|
140
|
-
fresh.find((item) => saved.has(item.number)
|
|
145
|
+
fresh.find((item) => saved.has(item.number) && resumable(item)) ??
|
|
146
|
+
fresh.find((item) => ready(item));
|
|
141
147
|
if (next === undefined) {
|
|
142
148
|
this.update({ status: 'finished', stage: undefined, issue: undefined, title: undefined });
|
|
143
149
|
return;
|
|
@@ -237,6 +243,11 @@ export class Runner {
|
|
|
237
243
|
switch (state.phase) {
|
|
238
244
|
case 'implement': {
|
|
239
245
|
this.stage('implement');
|
|
246
|
+
const kept = saved === undefined ? undefined : await ports.ahead(cwd);
|
|
247
|
+
if (kept !== undefined) {
|
|
248
|
+
await save({ phase: 'publish', title: kept });
|
|
249
|
+
break;
|
|
250
|
+
}
|
|
240
251
|
const reply = await this.agent('work', cwd, implementPrompt(issue, comments));
|
|
241
252
|
const title = parseCommitSubject(reply, `feat: ${issue.title}`);
|
|
242
253
|
if (!(await ports.commit(cwd, title))) {
|