gentle-pi 3.2.1 → 3.3.0
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/docs/gentle-shell.md +27 -14
- package/docs/readme-reference.md +41 -7
- package/docs/review-integration.md +22 -17
- package/extensions/gentle-agents.ts +85 -17
- package/extensions/gentle-ai.ts +123 -21
- package/extensions/gentle-shell.ts +379 -31
- package/extensions/gentle-todo.ts +19 -1
- package/lib/agents-view.ts +41 -14
- package/lib/agents-widget.ts +84 -13
- package/lib/command-palette-catalog.ts +1 -0
- package/lib/double-esc-cancel-policy.ts +138 -0
- package/lib/inprocess-reviewer.ts +260 -0
- package/lib/native-review-cli.ts +14 -0
- package/lib/odd-runtime-delegation-gate.ts +88 -0
- package/lib/review-host-relay.ts +246 -171
- package/lib/review-integration-v2.ts +110 -26
- package/lib/shell-bar.ts +150 -75
- package/lib/shell-card.ts +19 -9
- package/lib/shell-changes-view.ts +43 -5
- package/lib/shell-changes.ts +92 -5
- package/lib/shell-hover.ts +39 -0
- package/lib/shell-prompt.ts +10 -1
- package/lib/shell-sidebar-layout.ts +111 -15
- package/lib/shell-sidebar.ts +16 -0
- package/lib/shell-todo.ts +7 -1
- package/lib/shell-usage-view.ts +98 -10
- package/package.json +1 -1
- package/runtime/native-review-cli.mjs +14 -0
- package/runtime/review-integration-v2.mjs +110 -26
- package/scripts/gentle-ai-installer.mjs +10 -10
- package/scripts/maintainer/provider-relay-matrix.mjs +118 -47
- package/scripts/verify-package-files.mjs +3 -3
- package/tests/agents-grouping.test.ts +75 -18
- package/tests/agents-view.test.ts +28 -18
- package/tests/agents-widget.test.ts +100 -12
- package/tests/command-palette.test.ts +1 -0
- package/tests/devbinary/pi-host-relay.devtest.ts +176 -138
- package/tests/double-esc-cancel-policy.test.ts +194 -0
- package/tests/gentle-agents.test.ts +528 -5
- package/tests/gentle-ai-binary.test.ts +1 -1
- package/tests/gentle-ai-installer.test.ts +47 -47
- package/tests/gentle-ai.test.ts +69 -5
- package/tests/gentle-shell.test.ts +795 -23
- package/tests/gentle-todo.test.ts +17 -4
- package/tests/inprocess-reviewer.test.ts +368 -0
- package/tests/maintainer/provider-relay.maintest.ts +101 -143
- package/tests/native-review-capability-contract.test.ts +19 -1
- package/tests/odd-runtime-delegation-gate.test.ts +212 -0
- package/tests/orchestrator-rdd-ownership.test.ts +3 -3
- package/tests/package-manifest.test.ts +6 -6
- package/tests/review-host-relay-routing.test.ts +77 -0
- package/tests/review-host-relay.test.ts +277 -300
- package/tests/review-integration-v2-forward.test.ts +61 -0
- package/tests/review-integration-v2.test.ts +116 -1
- package/tests/review-relay-transport-agent.test.ts +22 -24
- package/tests/runtime-harness.mjs +11 -0
- package/tests/session-changes-shell.test.ts +27 -0
- package/tests/session-worktree-registry.test.ts +41 -0
- package/tests/shell-bar.test.ts +192 -124
- package/tests/shell-card.test.ts +5 -3
- package/tests/shell-changes-view.test.ts +47 -0
- package/tests/shell-changes.test.ts +177 -0
- package/tests/shell-hover.test.ts +19 -0
- package/tests/shell-prompt.test.ts +20 -0
- package/tests/shell-sidebar-fullscreen.test.ts +59 -0
- package/tests/shell-sidebar-layout.test.ts +243 -5
- package/tests/shell-sidebar.test.ts +25 -1
- package/tests/shell-todo.test.ts +36 -0
- package/tests/shell-usage-view.test.ts +120 -1
- package/lib/opaque-pi-reviewer-adapter.ts +0 -404
- package/tests/opaque-pi-reviewer-adapter.test.ts +0 -410
package/lib/native-review-cli.ts
CHANGED
|
@@ -1004,6 +1004,20 @@ export const NATIVE_CLI_CONTRACTS = Object.freeze({
|
|
|
1004
1004
|
// remain dark because neither is proven to reach the negotiated START
|
|
1005
1005
|
// path Pi consumes.
|
|
1006
1006
|
"3.2.1": Object.freeze({ start: true, finalize: true, validate: true, bindSdd: true, status: true, inventory: true, reclaim: true, recover: true, abandon: true, quarantineLegacy: true, reconcileAuthority: true, repairLegacyAlias: true, mode: true, riskEvidence: false, hint: false, delivery: true }),
|
|
1007
|
+
// v3.4.0 (gentle-pi never pinned the intervening v3.3.0 tag, so it gets no
|
|
1008
|
+
// row here) added capabilities/v2.6 and status/v8-v9, and extended
|
|
1009
|
+
// `review assess` with review_due/review_due_reason/next_transition
|
|
1010
|
+
// (gentle-ai #4714 follow-up). Ground-truthed by diffing
|
|
1011
|
+
// contracts/review-integration/v2 and contracts/review-provider-contract
|
|
1012
|
+
// between the v3.2.1 and v3.4.0 tags in the gentle-ai source tree: the
|
|
1013
|
+
// provider contract stays byte-identical at 1.2.0, and every
|
|
1014
|
+
// review-integration/v2 change is an additive superset (new optional
|
|
1015
|
+
// schema/fields) that decodeReviewStatusV3 and the capabilities
|
|
1016
|
+
// negotiator already accept without touching the closed START/STATUS
|
|
1017
|
+
// fields this row negotiates, so it repeats 3.2.1 exactly. riskEvidence
|
|
1018
|
+
// and hint remain dark because neither is proven to reach the negotiated
|
|
1019
|
+
// START path Pi consumes.
|
|
1020
|
+
"3.4.0": Object.freeze({ start: true, finalize: true, validate: true, bindSdd: true, status: true, inventory: true, reclaim: true, recover: true, abandon: true, quarantineLegacy: true, reconcileAuthority: true, repairLegacyAlias: true, mode: true, riskEvidence: false, hint: false, delivery: true }),
|
|
1007
1021
|
});
|
|
1008
1022
|
|
|
1009
1023
|
export interface NativeReviewProcessDiagnostics {
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { realpathSync } from "node:fs";
|
|
2
|
+
import { basename, dirname, isAbsolute, relative, resolve, sep } from "node:path";
|
|
3
|
+
import { resolveSessionWorktree } from "./session-worktree-registry.ts";
|
|
4
|
+
|
|
5
|
+
export interface OddDelegationRefusal {
|
|
6
|
+
block: true;
|
|
7
|
+
reason: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface SessionState {
|
|
11
|
+
primary: boolean;
|
|
12
|
+
childDepth: number;
|
|
13
|
+
firstSuccessfulPath?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function canonicalTarget(path: string): string {
|
|
17
|
+
let candidate = path;
|
|
18
|
+
const missing: string[] = [];
|
|
19
|
+
while (true) {
|
|
20
|
+
try { return resolve(realpathSync(candidate), ...missing); }
|
|
21
|
+
catch {
|
|
22
|
+
const parent = dirname(candidate);
|
|
23
|
+
if (parent === candidate) return path;
|
|
24
|
+
missing.unshift(basename(candidate));
|
|
25
|
+
candidate = parent;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function sessionPath(toolName: string, input: unknown, cwd: string): string | undefined {
|
|
31
|
+
if ((toolName !== "edit" && toolName !== "write") || !input || typeof input !== "object") return undefined;
|
|
32
|
+
const path = (input as { path?: unknown }).path;
|
|
33
|
+
if (typeof path !== "string" || path.trim().length === 0) return undefined;
|
|
34
|
+
const root = resolveSessionWorktree(cwd, cwd)?.root;
|
|
35
|
+
if (!root) return undefined;
|
|
36
|
+
const spelling = path.replace(/^@/, "");
|
|
37
|
+
const canonicalCwd = realpathSync(cwd);
|
|
38
|
+
const lexicalTarget = isAbsolute(spelling)
|
|
39
|
+
? resolve(spelling)
|
|
40
|
+
: resolve(canonicalCwd, spelling);
|
|
41
|
+
const target = canonicalTarget(lexicalTarget);
|
|
42
|
+
const repositoryPath = relative(root, target);
|
|
43
|
+
if (repositoryPath === "" || repositoryPath === ".." || repositoryPath.startsWith(`..${sep}`) || isAbsolute(repositoryPath)) return undefined;
|
|
44
|
+
const canonical = repositoryPath.split(sep).join("/");
|
|
45
|
+
return canonical === "odd/tasks" || canonical.startsWith("odd/tasks/") ? undefined : canonical;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export class OddRuntimeDelegationGate {
|
|
49
|
+
private readonly sessions = new Map<string, SessionState>();
|
|
50
|
+
|
|
51
|
+
start(sessionId: string, primary: boolean): void {
|
|
52
|
+
const state = this.sessions.get(sessionId);
|
|
53
|
+
if (primary) this.sessions.set(sessionId, { primary: true, childDepth: 0 });
|
|
54
|
+
else if (state?.primary) state.childDepth += 1;
|
|
55
|
+
else this.sessions.set(sessionId, { primary: false, childDepth: 1 });
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
endChild(sessionId: string): void {
|
|
59
|
+
const state = this.sessions.get(sessionId);
|
|
60
|
+
if (state && state.childDepth > 0) state.childDepth -= 1;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
beforeTool(
|
|
64
|
+
sessionId: string,
|
|
65
|
+
toolName: string,
|
|
66
|
+
input: unknown,
|
|
67
|
+
cwd: string,
|
|
68
|
+
availableTools: readonly string[],
|
|
69
|
+
): OddDelegationRefusal | undefined {
|
|
70
|
+
const state = this.sessions.get(sessionId);
|
|
71
|
+
if (!state?.primary || state.childDepth > 0) return undefined;
|
|
72
|
+
const path = sessionPath(toolName, input, cwd);
|
|
73
|
+
if (!path || !state.firstSuccessfulPath || path === state.firstSuccessfulPath) return undefined;
|
|
74
|
+
return {
|
|
75
|
+
block: true,
|
|
76
|
+
reason: availableTools.includes("subagent_run")
|
|
77
|
+
? `ODD multi-file write refused before mutation: direct edits already changed ${state.firstSuccessfulPath}. Delegate this additional file through subagent_run, preferring gentle-ai-worker and then worker.`
|
|
78
|
+
: "ODD multi-file write refused before mutation: direct edits already changed another file, but subagent_run is not callable. Stop and report that no delegation mechanism is callable.",
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
recordSuccess(sessionId: string, toolName: string, input: unknown, cwd: string): void {
|
|
83
|
+
const state = this.sessions.get(sessionId);
|
|
84
|
+
if (!state?.primary || state.childDepth > 0 || state.firstSuccessfulPath) return;
|
|
85
|
+
const path = sessionPath(toolName, input, cwd);
|
|
86
|
+
if (path) state.firstSuccessfulPath = path;
|
|
87
|
+
}
|
|
88
|
+
}
|