@henryqw/pi-pr 6.2.5 → 6.2.7

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 CHANGED
@@ -82,5 +82,5 @@ In-progress feedback sweeps keep private recovery under `<agent-dir>/config/pi-p
82
82
  - `/pr` does not open a browser, run `/done` or `/sweep`, enable auto-merge, or use a merge queue. It only starts workflows when explicitly invoked.
83
83
  - Pushes use a saved exact remote OID lease and revalidate the destination. Concurrent updates block publication instead of being overwritten. Creation does not change the base branch, and a configured push target does not change upstream settings.
84
84
  - Direct merge requires a clean, safe local Git state and fresh matching head; it always squashes. GitHub repository policy may still reject it. No branch or worktree is deleted.
85
- - A Git operation in progress blocks direct merge. An unverified conflict rebase needs manual recovery; a verified rebase can resume through `/pr`. Branches with merge commits since the fork point require manual rebase resolution.
85
+ - A Git operation in progress blocks direct merge. An unverified conflict rebase needs manual recovery; a verified rebase can resume through `/pr`. Rebasing leaves other local branch refs unchanged, even with `rebase.updateRefs=true`. Branches with merge commits since the fork point require manual rebase resolution.
86
86
  - Only authenticated GitHub.com and GitHub Enterprise repositories are supported. Resolve ambiguous remotes, unrelated local changes, or GitHub blockers before retrying `/pr`.
@@ -257,7 +257,7 @@ export class PullRequestBranchUpdater {
257
257
  if (mergeCommits) throw new Error("Branch update cannot rebase a branch with merge commits; preserve its resolutions manually");
258
258
  await this.freshAuthority(this.authority.head.oid, true);
259
259
  await this.writeRecovery("pending", null);
260
- const result = await this.exec("git", ["-c", "core.editor=true", "-c", "rebase.backend=merge", "rebase", "--no-autostash", "--onto", this.authority.base.oid, mergeBase], this.execOptions());
260
+ const result = await this.exec("git", ["-c", "core.editor=true", "-c", "rebase.backend=merge", "-c", "rebase.updateRefs=false", "rebase", "--no-autostash", "--onto", this.authority.base.oid, mergeBase], this.execOptions());
261
261
  if (result.killed) throw new Error("git rebase was killed; its outcome is unknown");
262
262
  if (result.code === 0) return await this.verifyRebase();
263
263
  try {
@@ -289,7 +289,7 @@ export class PullRequestBranchUpdater {
289
289
  await runChecked(this.exec, "git", ["--literal-pathspecs", "add", "--", ...paths], this.execOptions());
290
290
  const unmerged = parseNulPaths((await runChecked(this.exec, "git", ["diff", "--name-only", "-z", "--diff-filter=U"], this.execOptions())).stdout, "Unmerged paths");
291
291
  if (unmerged.length) throw new Error(`Conflict paths remain unresolved: ${unmerged.join(", ")}`);
292
- const result = await this.exec("git", ["-c", "core.editor=true", "rebase", "--continue"], this.execOptions());
292
+ const result = await this.exec("git", ["-c", "core.editor=true", "-c", "rebase.updateRefs=false", "rebase", "--continue"], this.execOptions());
293
293
  if (result.killed) throw new Error("git rebase continuation was killed; its outcome is unknown");
294
294
  if (result.code === 0) return await this.verifyRebase();
295
295
  return await this.captureConflict();
package/extensions/pr.ts CHANGED
@@ -76,11 +76,12 @@ const SweepChecks = Type.Array(Type.Object({
76
76
  args: Type.Array(Type.String({ maxLength: 4_096 }), { maxItems: 256 }),
77
77
  }, CLOSED), { maxItems: 32 });
78
78
 
79
+ // OpenAI-compatible endpoints require an object root even when every union variant is an object.
79
80
  const UpdateBranchParameters = Type.Union([
80
81
  Type.Object({ runId: RouteRunId, action: Type.Literal("rebase") }, CLOSED),
81
82
  Type.Object({ runId: RouteRunId, action: Type.Literal("continue"), resolvedPaths: ResolvedPaths }, CLOSED),
82
83
  Type.Object({ runId: RouteRunId, action: Type.Literal("publish") }, CLOSED),
83
- ]);
84
+ ], { type: "object" });
84
85
  const CreateParameters = Type.Union([
85
86
  Type.Object({ runId: RouteRunId, action: Type.Literal("prepare") }, CLOSED),
86
87
  Type.Object({ runId: RouteRunId, action: Type.Literal("inspect") }, CLOSED),
@@ -93,7 +94,7 @@ const CreateParameters = Type.Union([
93
94
  title: Type.String({ minLength: 1, maxLength: 256 }),
94
95
  body: Type.String({ maxLength: 65_536 }),
95
96
  }, CLOSED),
96
- ]);
97
+ ], { type: "object" });
97
98
  const SweepParameters = Type.Union([
98
99
  Type.Object({ runId: RouteRunId, action: Type.Literal("start") }, CLOSED),
99
100
  Type.Object({ runId: RouteRunId, action: Type.Literal("resume") }, CLOSED),
@@ -110,17 +111,17 @@ const SweepParameters = Type.Union([
110
111
  Type.Object({ runId: RouteRunId, action: Type.Literal("refresh"), guard: SweepGuard }, CLOSED),
111
112
  Type.Object({ runId: RouteRunId, action: Type.Literal("resolve"), guard: SweepGuard }, CLOSED),
112
113
  Type.Object({ runId: RouteRunId, action: Type.Literal("finalize"), guard: SweepGuard, checks: SweepChecks }, CLOSED),
113
- ]);
114
+ ], { type: "object" });
114
115
  const WorkParameters = Type.Union([
115
116
  Type.Object({ runId: RouteRunId, action: Type.Literal("inspect") }, CLOSED),
116
117
  Type.Object({ runId: RouteRunId, action: Type.Literal("commit"), ownedPaths: OwnedPaths, message: Type.String({ minLength: 1, maxLength: 256 }) }, CLOSED),
117
118
  Type.Object({ runId: RouteRunId, action: Type.Literal("validate"), checks: SweepChecks }, CLOSED),
118
119
  Type.Object({ runId: RouteRunId, action: Type.Literal("publish") }, CLOSED),
119
- ]);
120
+ ], { type: "object" });
120
121
  const FixCiParameters = Type.Union([
121
122
  Type.Object({ runId: RouteRunId, action: Type.Literal("collect") }, CLOSED),
122
123
  Type.Object({ runId: RouteRunId, action: Type.Literal("publish") }, CLOSED),
123
- ]);
124
+ ], { type: "object" });
124
125
 
125
126
  type UpdateBranchWorkflow = Pick<PullRequestBranchUpdater, "state" | "recoveryLaunchAction" | "rebase" | "continue" | "publish">;
126
127
  type CreateWorkflow = Pick<PullRequestCreator, "state" | "prepare" | "inspect" | "commit" | "verify" | "push" | "publish">;
@@ -431,6 +432,8 @@ export default function pullRequestExtension(
431
432
  selected.controller.signal.throwIfAborted();
432
433
  if (worktree !== selected.worktree) throw new Error("PR workflow worktree is wrong or stale");
433
434
  selected.usedSinceSettlement = true;
435
+ // Drained follow-ups need not emit before_agent_start; this run has been consumed.
436
+ selected.queuedPrompt = undefined;
434
437
  return toolResult(await action(selected as Extract<WorkflowContext, { route: Route }>));
435
438
  } finally {
436
439
  signal?.removeEventListener("abort", abortRun);
@@ -782,7 +785,8 @@ export default function pullRequestExtension(
782
785
 
783
786
  pi.on("agent_before_settle", async (event, ctx) => {
784
787
  const selected = workflowContext;
785
- if (event.outcome !== "completed" || !event.context.canContinue || !selected?.completed ||
788
+ // Pi evaluates continuation again after this handler queues the next workflow.
789
+ if (event.outcome !== "completed" || !selected?.completed ||
786
790
  selected.queuedPrompt || selected.sessionGeneration !== sessionGeneration) return;
787
791
  const invocation = [...activeInvocations].find(([, phase]) => phase === "workflow" || phase === "create-workflow")?.[0];
788
792
  if (invocation === undefined) return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@henryqw/pi-pr",
3
- "version": "6.2.5",
3
+ "version": "6.2.7",
4
4
  "description": "Run /pr to safely discover or link the current pull request, then create, update, address feedback, fix CI, or merge when ready.",
5
5
  "keywords": [
6
6
  "pi-package",