@dev-loops/core 1.0.0-rc.3 → 1.0.0-rc.4

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.
@@ -37,6 +37,10 @@ const MUST_FIX = "must-fix";
37
37
  * @param {object} seams - Injected IO (all required except clock/log defaults).
38
38
  * @param {(a:{repoRoot:string,pr:number,branch?:string})=>Promise<{path:string,created:boolean,reused:boolean}>} seams.ensureWorktree
39
39
  * @param {(a:{worktreePath:string,repoRoot:string})=>{ok:boolean,message?:string,mainWorktreePath?:string|null}} seams.assertNotPrimary
40
+ * @param {(a:{worktreePath:string,repoRoot:string,pr:number})=>Promise<{ok:boolean,sha?:string|null,detail?:string}>} [seams.pinPrHead] -
41
+ * Pin the worktree to the PR head and report the resolved SHA. Optional only
42
+ * for back-compat: omitting it leaves the ref UNVERIFIED and is logged as such.
43
+ * Runs after the primary-checkout guard, never before.
40
44
  * @param {(a:{repoRoot:string,worktreePath:string})=>Promise<{changed:boolean,detail:string}>} seams.detectDepDelta
41
45
  * @param {(a:{worktreePath:string})=>Promise<{ok:boolean,detail:string}>} seams.installDeps
42
46
  * @param {(worktreePath:string)=>Promise<object|null>} seams.resolveRunRecipe
@@ -58,6 +62,7 @@ export async function provisionAndBoot(
58
62
  {
59
63
  ensureWorktree,
60
64
  assertNotPrimary,
65
+ pinPrHead,
61
66
  detectDepDelta,
62
67
  installDeps,
63
68
  resolveRunRecipe,
@@ -111,6 +116,36 @@ export async function provisionAndBoot(
111
116
  );
112
117
  }
113
118
 
119
+ // 2b. Pin the worktree to the PR head, AFTER the primary-checkout guard above
120
+ // (this checks out a ref, so it must never run in the primary checkout).
121
+ // ensureWorktree resolves `branch` against what already exists, so the
122
+ // default `pr-<n>` lands wherever that name happens to point — the base
123
+ // branch when no remote carries it, and a same-named remote branch that
124
+ // is not this PR's head when one does. A fork PR's head branch is on no
125
+ // candidate remote at all. Reviewing the wrong commit still reports
126
+ // ok:true, so pin the head explicitly and record the resolved SHA.
127
+ let headSha = null;
128
+ if (pinPrHead) {
129
+ const pin = await pinPrHead({ worktreePath, repoRoot, pr });
130
+ if (!pin?.ok) {
131
+ return stop(
132
+ `cannot pin PR head: ${pin?.detail ?? "unknown failure"}`,
133
+ {
134
+ kind: "pr-head-unpinned",
135
+ severity: MUST_FIX,
136
+ message: `the worktree could not be pinned to PR #${pr}'s head, so it cannot be reviewed as that PR: ${pin?.detail ?? "unknown failure"}`,
137
+ },
138
+ { worktreePath },
139
+ );
140
+ }
141
+ headSha = pin.sha ?? null;
142
+ record(`worktree pinned to PR head ${headSha ?? "(sha unknown)"}${pin.detail ? ` (${pin.detail})` : ""}`);
143
+ } else {
144
+ // Never silent: a caller without the seam gets an unverified ref, which is
145
+ // exactly the failure mode this step exists to close.
146
+ record("WARNING: PR head not pinned (no pinPrHead seam) — worktree ref is UNVERIFIED");
147
+ }
148
+
114
149
  // 3. Install only the dependency-lock delta vs. the primary checkout. No delta
115
150
  // => deps are shared; installing anything would be a blind re-install.
116
151
  const delta = await detectDepDelta({ repoRoot, worktreePath });
@@ -256,6 +291,7 @@ export async function provisionAndBoot(
256
291
  worktreePath,
257
292
  created: wt.created,
258
293
  reused: wt.reused,
294
+ headSha,
259
295
  depInstall,
260
296
  migrations,
261
297
  boot: bootResult,
@@ -139,7 +139,7 @@ function resolveProjectSelector(args) {
139
139
  : null;
140
140
  if (!projectRef && !projectTitle) {
141
141
  throw Object.assign(
142
- new Error("--project is required (or set queue.board.number / queue.board.title in .devloops)"),
142
+ new Error("--project is required (or set tracker.board — or the deprecated queue.board — number / title in .devloops)"),
143
143
  { code: "INVALID_PROJECT" },
144
144
  );
145
145
  }