feat: enable permission-aware subagents

This commit is contained in:
叶林立
2026-08-26 10:49:26 +08:00
parent d3bf562189
commit 7571ba6dd9
185 changed files with 48365 additions and 26 deletions
+46
View File
@@ -0,0 +1,46 @@
import { describe, expect, it } from "vitest";
import { isolationParam } from "../src/invocation-config.js";
/**
* The `isolation` parameter's *shape* is the fix for #231, so it is worth
* asserting directly rather than only through behaviour.
*
* As a single-value optional literal it gave models that fill every optional
* parameter nothing harmless to fill it with: the session log on #231 shows one
* emitting `isolation: "worktree"` on three consecutive calls — alongside
* `resume: ""` and `schedule: ""` — while its own reasoning, its message to the
* user, and two explicit user instructions all said to omit the field. A second
* legal value is what lets it comply.
*/
describe("isolationParam", () => {
function schema(enabled: boolean) {
const built = isolationParam(enabled);
return built.isolation as { anyOf?: { const?: string }[] } | undefined;
}
it("offers a value meaning 'no isolation', not just 'worktree'", () => {
const values = schema(true)?.anyOf?.map(v => v.const);
expect(values).toContain("off");
expect(values).toContain("worktree");
});
// A model that fills optional fields tends to reach for what it reads first,
// so the inert value leads. This is the whole mitigation — if the order flips,
// the schema stops steering and the bug is back in practice.
it("lists the inert value first", () => {
expect(schema(true)?.anyOf?.[0]?.const).toBe("off");
});
it("warns that a worktree cannot see uncommitted work", () => {
// The specific trap in #231: the subagent reviewed an empty `git diff
// --cached` in a fresh copy and returned nothing, three times.
const described = JSON.stringify(schema(true));
expect(described).toMatch(/uncommitted or staged/);
});
it("omits the parameter entirely when the project disabled worktrees", () => {
// Nothing to pass beats accepting it and quietly downgrading — and it costs
// the model no context in disabled mode, as `scheduleParam` already does.
expect(isolationParam(false)).toEqual({});
});
});