gentle-pi 3.2.0 → 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/assets/orchestrator-delegation.md +13 -8
- package/assets/orchestrator.md +2 -2
- package/docs/gentle-shell.md +40 -17
- package/docs/readme-reference.md +41 -7
- package/docs/review-integration.md +25 -11
- package/extensions/gentle-agents.ts +85 -17
- package/extensions/gentle-ai.ts +179 -12
- package/extensions/gentle-shell.ts +408 -38
- 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/model-routing-authority.ts +1 -1
- package/lib/native-review-cli.ts +23 -0
- package/lib/odd-runtime-delegation-gate.ts +88 -0
- package/lib/review-host-relay.ts +262 -94
- package/lib/review-integration-v2.ts +110 -26
- package/lib/shell-bar.ts +158 -29
- 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/lib/shell-usage.ts +226 -10
- package/package.json +2 -1
- package/runtime/native-review-cli.mjs +23 -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/mirror-odd-routing.mjs +242 -0
- 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 +903 -25
- 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 +32 -1
- package/tests/odd-routing-canonical-ratchet.test.ts +293 -0
- package/tests/odd-routing-contract.test.ts +57 -0
- 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-controller-native-routing.test.ts +60 -1
- package/tests/review-host-relay-routing.test.ts +77 -0
- package/tests/review-host-relay.test.ts +285 -239
- 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 +83 -0
- 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 +224 -6
- 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 +123 -3
- package/tests/shell-usage.test.ts +254 -6
- package/lib/opaque-pi-reviewer-adapter.ts +0 -284
- package/tests/opaque-pi-reviewer-adapter.test.ts +0 -266
|
@@ -25,7 +25,7 @@ export type ModelConfigFileResult =
|
|
|
25
25
|
| { status: "invalid"; path: string }
|
|
26
26
|
| { status: "valid"; config: AgentModelConfig };
|
|
27
27
|
|
|
28
|
-
const SAFE_MODEL_ID_PATTERN = /^[A-Za-z0-9._~:@/+%-]+$/;
|
|
28
|
+
export const SAFE_MODEL_ID_PATTERN = /^[A-Za-z0-9._~:@/+%-]+$/;
|
|
29
29
|
const SAFE_AGENT_NAME_PATTERN = /^[A-Za-z0-9._:@/+%-]+$/;
|
|
30
30
|
|
|
31
31
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
package/lib/native-review-cli.ts
CHANGED
|
@@ -995,6 +995,29 @@ export const NATIVE_CLI_CONTRACTS = Object.freeze({
|
|
|
995
995
|
// remain dark because neither is proven to reach the negotiated START
|
|
996
996
|
// path Pi consumes.
|
|
997
997
|
"3.1.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 }),
|
|
998
|
+
// v3.2.1 changed the ODD orchestrator contract only (gentle-ai #4714
|
|
999
|
+
// follow-up). Ground-truthed by diffing contracts/review-integration/v2 and
|
|
1000
|
+
// contracts/review-provider-contract between the v3.1.0 and v3.2.1 tags
|
|
1001
|
+
// in the gentle-ai source tree: zero bytes changed (provider contract
|
|
1002
|
+
// stays 1.2.0). Neither change touches the closed START/STATUS fields
|
|
1003
|
+
// this row negotiates, so it repeats 3.1.0 exactly. riskEvidence and hint
|
|
1004
|
+
// remain dark because neither is proven to reach the negotiated START
|
|
1005
|
+
// path Pi consumes.
|
|
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 }),
|
|
998
1021
|
});
|
|
999
1022
|
|
|
1000
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
|
+
}
|