gentle-pi 2.1.0 → 2.1.2

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.
@@ -84,7 +84,7 @@ function fakeNative(overrides: Partial<NativeReviewCli> = {}): NativeReviewCli {
84
84
  sddStatus: async () => ({ ready: false }),
85
85
  reviewStatus: async () => ({ schema: "gentle-ai.review-authority-status/v1", repository: "/repo", complete: true, authoritative: true, status: "clean", entries: [], locks: [], diagnostics: [], raw: { schema: "gentle-ai.review-authority-status/v1", operation: "review/status", repository: "/repo", complete: true, authoritative: true, status: "clean", entries: [], locks: [], diagnostics: [] } }),
86
86
  targetStatus: async (request) => request.lineageId === undefined
87
- ? targetStatusFixture({ applicability: "unrelated", action: "start" })
87
+ ? candidateStartTargetStatus(request)
88
88
  : targetStatusFixture({ lineageId: request.lineageId }),
89
89
  ...overrides,
90
90
  };
@@ -102,21 +102,26 @@ function targetStatusFixture(options: {
102
102
  applicability?: "current_target" | "unrelated";
103
103
  action?: ReviewStatusV3["action"];
104
104
  lineageId?: string;
105
+ baseTree?: string;
106
+ currentCandidateTree?: string;
107
+ paths?: readonly string[];
105
108
  } = {}): ReviewStatusV3 {
106
109
  const applicability = options.applicability ?? "current_target";
107
110
  const action = options.action ?? (applicability === "current_target" ? "finalize" : "start");
108
111
  const lineageId = options.lineageId ?? "native-lineage";
109
112
  const sha = `sha256:${"a".repeat(64)}`;
110
- const tree = "b".repeat(40);
113
+ const tree = options.currentCandidateTree ?? "b".repeat(40);
114
+ const baseTree = options.baseTree ?? tree;
115
+ const paths = options.paths ?? ["app.ts"];
111
116
  const projection = {
112
117
  schema: "gentle-ai.review-integration.projection/v1" as const,
113
118
  kind: "current-changes" as const,
114
119
  projection: "workspace" as const,
115
- baseTree: tree,
120
+ baseTree,
116
121
  initialReviewTree: tree,
117
122
  currentCandidateTree: tree,
118
123
  pathsDigest: sha,
119
- paths: ["app.ts"],
124
+ paths,
120
125
  intendedUntracked: [],
121
126
  intendedUntrackedProof: sha,
122
127
  initialSnapshotIdentity: sha,
@@ -146,11 +151,11 @@ function targetStatusFixture(options: {
146
151
  schema: projection.schema,
147
152
  kind: projection.kind,
148
153
  projection: projection.projection,
149
- base_tree: tree,
154
+ base_tree: baseTree,
150
155
  initial_review_tree: tree,
151
156
  current_candidate_tree: tree,
152
157
  paths_digest: sha,
153
- paths: projection.paths,
158
+ paths,
154
159
  intended_untracked: [],
155
160
  intended_untracked_proof: sha,
156
161
  initial_snapshot_identity: sha,
@@ -178,6 +183,25 @@ function targetStatusFixture(options: {
178
183
  };
179
184
  }
180
185
 
186
+ function candidateStartTargetStatus(request: Parameters<NonNullable<NativeReviewCli["targetStatus"]>>[0]): ReviewStatusV3 {
187
+ let candidate: ReturnType<CandidateViewRegistry["create"]> | undefined;
188
+ try {
189
+ candidate = new CandidateViewRegistry().create({
190
+ contributorRoot: request.cwd,
191
+ ...(request.baseRef === undefined ? {} : { baseRef: request.baseRef, committedOnly: true }),
192
+ });
193
+ return targetStatusFixture({
194
+ applicability: "unrelated",
195
+ action: "start",
196
+ baseTree: candidate.baseTree,
197
+ currentCandidateTree: candidate.candidateTree,
198
+ paths: candidate.paths,
199
+ });
200
+ } finally {
201
+ candidate?.cleanup();
202
+ }
203
+ }
204
+
181
205
  test("INSPECT and STATUS operate on the explicit workspace root while the session cwd stays elsewhere", async (t) => {
182
206
  const sessionCwd = repository(t);
183
207
  const worktree = addWorktree(t, sessionCwd, "feat-binding");
@@ -200,10 +224,10 @@ test("START freezes the candidate from the explicit workspace root and returns t
200
224
  const worktree = addWorktree(t, sessionCwd, "feat-candidate");
201
225
  writeFileSync(join(worktree, "app.ts"), "export const value = 2; // worktree candidate\n");
202
226
  const candidateViews = new CandidateViewRegistry();
203
- const startCwds: string[] = [];
227
+ const startRequests: Parameters<NativeReviewCli["start"]>[0][] = [];
204
228
  const { controller, toolCall } = runtime(fakeNative({
205
229
  start: async (request) => {
206
- startCwds.push(request.cwd);
230
+ startRequests.push(request);
207
231
  return { lineageId: "worktree-lineage", state: "reviewing", riskLevel: "medium", selectedLenses: ["review-reliability"], changedFiles: 1, changedLines: 1, correctionBudget: 1, action: "created", lensesRequired: true };
208
232
  },
209
233
  }), candidateViews);
@@ -219,7 +243,8 @@ test("START freezes the candidate from the explicit workspace root and returns t
219
243
  const view = candidateViews.resolveForLens("worktree-lineage", "review-reliability");
220
244
  assert.equal(details.actor_binding.candidate_root, view.root);
221
245
  assert.equal(details.actor_binding.candidate_tree, view.candidateTree);
222
- assert.deepEqual(startCwds, [view.root]);
246
+ assert.deepEqual(startRequests, [{ cwd: root, targetIdentity: `sha256:${"a".repeat(64)}`, projection: "workspace" }]);
247
+ assert.notEqual(startRequests[0]?.cwd, view.root);
223
248
  assert.equal(readFileSync(join(view.root, "app.ts"), "utf8"), "export const value = 2; // worktree candidate\n");
224
249
  assert.equal(view.paths.includes("unrelated.ts"), false);
225
250
  const dispatch = { agent: "review-reliability", task: "review the change", mode: "task" };
@@ -234,8 +259,12 @@ test("absent workspaceRoot keeps the session-cwd flow and still reports the acto
234
259
  const sessionCwd = repository(t);
235
260
  writeFileSync(join(sessionCwd, "app.ts"), "export const value = 3;\n");
236
261
  const candidateViews = new CandidateViewRegistry();
262
+ const startRequests: Parameters<NativeReviewCli["start"]>[0][] = [];
237
263
  const { controller } = runtime(fakeNative({
238
- start: async () => ({ lineageId: "session-lineage", state: "reviewing", riskLevel: "medium", selectedLenses: ["review-reliability"], changedFiles: 1, changedLines: 1, correctionBudget: 1, action: "created", lensesRequired: true }),
264
+ start: async (request) => {
265
+ startRequests.push(request);
266
+ return { lineageId: "session-lineage", state: "reviewing", riskLevel: "medium", selectedLenses: ["review-reliability"], changedFiles: 1, changedLines: 1, correctionBudget: 1, action: "created", lensesRequired: true };
267
+ },
239
268
  }), candidateViews);
240
269
  const started = await controller.execute("start-session", { operation: "start", input: JSON.stringify({ mode: "ordinary" }) }, undefined, undefined, context(sessionCwd));
241
270
  const details = started.details as {
@@ -245,6 +274,7 @@ test("absent workspaceRoot keeps the session-cwd flow and still reports the acto
245
274
  assert.equal(details.workspace_root, sessionCwd);
246
275
  assert.equal(details.actor_binding.workspace_root, sessionCwd);
247
276
  assert.deepEqual(details.actor_binding.candidate_paths, ["app.ts"]);
277
+ assert.deepEqual(startRequests, [{ cwd: sessionCwd, targetIdentity: `sha256:${"a".repeat(64)}`, projection: "workspace" }]);
248
278
  const view = candidateViews.resolveForLens("session-lineage", "review-reliability");
249
279
  assert.equal(details.actor_binding.candidate_root, view.root);
250
280
  candidateViews.cleanup(view.token);