Merge remote-tracking branch 'origin/master' into codex/trim-ai-prose

# Conflicts:
#	docs/config-catalog.md
#	docs/development.i18n.yaml
#	docs/development.zh.md
#	docs/rfc/implemented/feature/2026-06-14-acp-agent-client-protocol.md
#	docs/rfc/implemented/feature/2026-07-06-sandbox.md
#	examples/AGENTS.md
#	examples/README.md
#	examples/acp-agent/README.md
#	examples/acp-agent/cordis.yml
#	examples/acp-agent/tests/acp.e2e.ts
#	examples/acp-agent/tests/escalation.e2e.ts
#	examples/sandbox-acp-agent/README.md
#	examples/sandbox-acp-agent/cordis.snapshot.yml
#	examples/sandbox-acp-agent/cordis.yml
#	examples/sandbox-acp-agent/tests/acp.snapshot.ts
#	packages/ui/acp-agent/src/bin.ts
#	packages/ui/acp/README.md
#	packages/ui/jsonrpc-agent/README.md
#	packages/ui/jsonrpc-agent/src/bin.ts
#	scripts/verify-translation-pairing.ts
This commit is contained in:
Tianyi Cui
2026-07-14 12:34:14 +08:00
180 changed files with 3874 additions and 1935 deletions

View File

@@ -38,8 +38,8 @@ interface Spawned {
function spawnAcpAgent(cwd: string): Spawned {
const child = spawn(
process.execPath,
['--import', tsxLoader, binScript, configPath],
{ cwd, env: { ...process.env, TSX_TSCONFIG_PATH: repoTsconfig }, stdio: ['pipe', 'pipe', 'pipe'] },
['--import', tsxLoader, binScript, '--config', configPath],
{ cwd, env: { ...process.env, TSX_TSCONFIG_PATH: repoTsconfig, DSH_PERMISSION_MODE: 'danger-full-access' }, stdio: ['pipe', 'pipe', 'pipe'] },
)
const stderr: string[] = []
child.stderr.setEncoding('utf8')
@@ -98,12 +98,10 @@ describe.skipIf(!process.env.DEEPSEEK_API_KEY)('acp-agent e2e: a PreToolUse hook
// the model, not a turn failure).
expect(['end_turn', 'max_tokens']).toContain(res.stopReason)
// Verify the WORLD: the hook denied execution, so the file must NOT exist —
// a keyword probe a "cheating" agent could fake in prose cannot pass this.
// Verify that the denied hook left no filesystem effect.
await expect(access(join(workdir, 'proof.txt'))).rejects.toThrow()
// The client still saw a tool_call stream (the model TRIED), and its result
// carried the hook's block reason back as an error.
// A blocked call is still streamed with the hook's reason as an error.
const toolCalls = updates.filter(u => u.sessionUpdate === 'tool_call' || u.sessionUpdate === 'tool_call_update')
expect(toolCalls.length).toBeGreaterThan(0)
}, 180_000)