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.
- package/extensions/gentle-ai.ts +54 -9
- package/lib/native-review-cli.ts +62 -25
- package/package.json +1 -1
- package/runtime/native-review-cli.mjs +61 -24
- package/tests/native-review-cli.test.ts +27 -0
- package/tests/native-review-consent.test.ts +77 -0
- package/tests/native-review-parity.test.ts +80 -14
- package/tests/package-manifest.test.ts +2 -2
- package/tests/review-controller-lock-status.test.ts +25 -7
- package/tests/review-controller-native-routing.test.ts +172 -14
- package/tests/review-controller-workspace-root.test.ts +40 -10
|
@@ -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
|
-
?
|
|
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
|
|
120
|
+
baseTree,
|
|
116
121
|
initialReviewTree: tree,
|
|
117
122
|
currentCandidateTree: tree,
|
|
118
123
|
pathsDigest: sha,
|
|
119
|
-
paths
|
|
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:
|
|
154
|
+
base_tree: baseTree,
|
|
150
155
|
initial_review_tree: tree,
|
|
151
156
|
current_candidate_tree: tree,
|
|
152
157
|
paths_digest: sha,
|
|
153
|
-
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
|
|
227
|
+
const startRequests: Parameters<NativeReviewCli["start"]>[0][] = [];
|
|
204
228
|
const { controller, toolCall } = runtime(fakeNative({
|
|
205
229
|
start: async (request) => {
|
|
206
|
-
|
|
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(
|
|
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 () =>
|
|
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);
|