Merge remote-tracking branch 'origin/master' into feature/subagent-policy-inheritance

# Conflicts:
#	.agents/notes/implemented/feature/2026-07-06-approval-seam.i18n.yaml
#	.agents/notes/implemented/feature/2026-07-06-approval-seam.md
#	.agents/notes/implemented/feature/2026-07-06-approval-seam.zh.md
#	.agents/notes/implemented/feature/2026-07-06-sandbox.i18n.yaml
#	.agents/notes/implemented/feature/2026-07-06-sandbox.md
#	.agents/notes/implemented/feature/2026-07-06-sandbox.zh.md
#	docs/event-producer-consumer.md
#	examples/acp-agent/tests/acp.snapshot.ts
This commit is contained in:
kingwl
2026-07-25 14:37:21 +08:00
647 changed files with 14011 additions and 25019 deletions
+39 -46
View File
@@ -43,6 +43,9 @@ const LSP_CONFIG = fileURLToPath(new URL('./lsp.cordis.yml', import.meta.url))
const SNAPSHOTS_DIR = join(dirname(fileURLToPath(import.meta.url)), 'snapshots')
const PACKED_CHUNKS_SOURCE = 'hook-cc-pretool-deny'
// FIXME: Migrate backend-oriented scenarios to the headless stream-json suite;
// this ACP suite should eventually retain only automation-protocol contracts.
function fixtureRecords(name: string): unknown[] {
return readFileSync(join(SNAPSHOTS_DIR, name, 'session.jsonl'), 'utf8')
.trimEnd()
@@ -68,22 +71,6 @@ function snapshotModeFromEnv(value: string | undefined): SnapshotSuiteOptions['m
const SCENARIOS: Scenario[] = [
{ name: 'handshake', hasModelTurn: false, recorded: false },
{ name: 'reject-extra-dirs', hasModelTurn: false, recorded: false },
// Direct command dispatch reports goal state without spending a model turn.
{ name: 'goal-command-status', hasModelTurn: false, recorded: false },
// Protocol-only (keyless, authored): session/new advertises the mode picker,
// session/set_mode acknowledges a valid selection, and an unknown mode id
// fails loudly. With no model turn, its membership in the plan header class
// is vacuous; the class still needs one explicit pin below.
{ name: 'modes-advertise', hasModelTurn: false, recorded: false, headerClass: 'plan' },
// The plan header pin covers the full arc: setMode(plan), a real read under
// the independently configured sandbox, plan review through exit_plan_mode,
// an approved boundary flip back to default, and a real edit in the next
// step. Leaving plan removes the policy section and exit tool, producing one
// changed request header.
{ name: 'plan-mode', hasModelTurn: true, recorded: true, pinsHeader: true, headerClass: 'plan', expectedHeaderChanges: 1 },
// Free-text review feedback returns as a corrective error and leaves the
// session in plan mode, so this scenario shares the pinned plan header.
{ name: 'plan-mode-reject', hasModelTurn: true, recorded: true, headerClass: 'plan' },
// text-turn is the pinned-header scenario: the minimal single text turn.
// Its prompt and tool-schema sidecars pin the composed header.
{ name: 'text-turn', hasModelTurn: true, recorded: true, pinsHeader: true },
@@ -109,15 +96,14 @@ const SCENARIOS: Scenario[] = [
headerClass: 'pty',
configPath: PTY_CONFIG,
},
{ name: 'fs-terminal-card', hasModelTurn: true, recorded: true },
{ name: 'todo-plan', hasModelTurn: true, recorded: true },
{ name: 'bash-tool-turn', hasModelTurn: true, recorded: true },
{ name: 'todo-write', hasModelTurn: true, recorded: true },
{ name: 'skill-load', hasModelTurn: true, recorded: false, pinsHeader: true, headerClass: 'skill' },
{ name: 'lsp-definition', hasModelTurn: true, recorded: false, pinsHeader: true, headerClass: 'lsp', configPath: LSP_CONFIG },
{
name: 'workspace-edit',
hasModelTurn: true,
recorded: true,
pinsNativeWindowsStdout: true,
},
{ name: 'fs-read', hasModelTurn: true, recorded: true },
{ name: 'fs-write', hasModelTurn: true, recorded: true },
@@ -126,17 +112,6 @@ const SCENARIOS: Scenario[] = [
{ name: 'fs-read-window', hasModelTurn: true, recorded: true },
{ name: 'fs-policy-reject', hasModelTurn: true, recorded: true },
{ name: 'multi-turn', hasModelTurn: true, recorded: true },
// ACP exposes the adapter catalog as a session-scoped model select. This
// scenario pins the default flash request, the switch response, and the
// resulting changed request-header snapshot for pro.
{
name: 'model-switching',
hasModelTurn: true,
recorded: true,
pinsHeader: true,
expectedHeaderChanges: 1,
headerClass: 'model-switching',
},
{ name: 'error-finish', hasModelTurn: true, recorded: false, overridden: true },
// Keyless, authored (like error-finish/cancel): deterministically forcing a
// LIVE model to repeat one call three times is not a stable recording, so
@@ -232,28 +207,45 @@ const SCENARIOS: Scenario[] = [
configPath: CODE_MODE_WORKSPACE_CONTEXT_CONFIG,
},
{ name: 'both-mode-turn', hasModelTurn: true, recorded: true, pinsHeader: true, headerClass: 'both', configPath: BOTH_MODE_CONFIG },
// The default tree also owns the Permissions select. Snapshot mode starts in
// danger-full-access so established fixtures stay runner-independent; these
// policy scenarios switch to workspace-write in their input scripts.
// Real-kernel confinement remains in escalation.e2e.ts and the sandbox
// packages' e2e suites.
{ name: 'config-options', hasModelTurn: false, recorded: false, headerClass: 'sandbox' },
{ name: 'permission-switching', hasModelTurn: true, recorded: true, pinsHeader: true, expectedHeaderChanges: 1, headerClass: 'sandbox' },
{ name: 'escalation-approved', hasModelTurn: true, recorded: true, headerClass: 'sandbox' },
{ name: 'escalation-rejected', hasModelTurn: true, recorded: true, headerClass: 'sandbox' },
{ name: 'fs-escalation-approved', hasModelTurn: true, recorded: true, headerClass: 'sandbox' },
// Policy inheritance across delegation: the overlay adds a read-only preset,
// the script tightens the PARENT session to it, and the delegated child's
// real write is then denied by the fs fence — proving the parent's override
// crossed the delegation boundary instead of the child escaping to the
// composition default (the subagent policy-inheritance Agent Note).
// Machine permission scenarios use an explicit deployment policy; there is
// no session-scoped UI picker on the automation protocol.
{
name: 'escalation-approved',
hasModelTurn: true,
recorded: true,
pinsHeader: true,
headerClass: 'sandbox',
env: { DSH_PERMISSION_MODE: 'workspace-write' },
},
{
name: 'escalation-rejected',
hasModelTurn: true,
recorded: true,
headerClass: 'sandbox',
env: { DSH_PERMISSION_MODE: 'workspace-write' },
},
{
name: 'fs-escalation-approved',
hasModelTurn: true,
recorded: true,
headerClass: 'sandbox',
env: { DSH_PERMISSION_MODE: 'workspace-write' },
},
// Delegation under a read-only DEPLOYMENT policy: the child's real write is
// denied by the fs fence and its denial report surfaces in the parent
// transcript. This is the strength the automation protocol can express — no
// session-scoped picker exists to tighten only the parent, so the
// parent-override-vs-wider-default half of the inheritance contract stays
// pinned by the real-wall unit suite (the subagent policy-inheritance Agent
// Note records the downgrade).
{
name: 'subagent-sandbox-inheritance',
hasModelTurn: true,
recorded: true,
headerClass: 'subagent-inheritance',
pinsHeader: true,
headerClass: 'subagent-inheritance',
configPath: SUBAGENT_INHERITANCE_CONFIG,
env: { DSH_PERMISSION_MODE: 'read-only' },
},
// Unlike ordinary snapshots, this session cwd is outside the platform temp
// roots that workspace-write always grants. The overlay points the
@@ -266,6 +258,7 @@ const SCENARIOS: Scenario[] = [
overridden: true,
headerClass: 'sandbox',
configPath: SESSION_SANDBOX_ROOT_CONFIG,
env: { DSH_PERMISSION_MODE: 'workspace-write' },
workspaceParent: homedir(),
},
]