Merge remote-tracking branch 'origin/master' into cross-family-fs-sandbox

# Conflicts:
#	.agents/notes/implemented/feature/2026-07-14-cross-family-fs-sandbox.i18n.yaml
#	.agents/notes/implemented/feature/2026-07-14-cross-family-fs-sandbox.md
#	.agents/notes/implemented/feature/2026-07-14-cross-family-fs-sandbox.zh.md
#	docs/capability-seams.md
#	docs/cordis-catalog/events.md
#	docs/cordis-catalog/services.md
#	docs/event-producer-consumer.md
#	docs/module-graph.md
#	docs/persistence-catalog.md
#	docs/rfc/INDEX.md
#	examples/acp-agent/README.md
#	examples/acp-agent/fs.cordis.snapshot.yml
#	examples/acp-agent/fs.cordis.yml
#	examples/acp-agent/tests/snapshots/escalation-approved/session.jsonl
#	examples/acp-agent/tests/snapshots/escalation-rejected/session.jsonl
#	examples/acp-agent/tests/snapshots/hook-cc-pretool-ask/session.jsonl
#	examples/acp-agent/tests/snapshots/permission-switching/session.jsonl
#	examples/acp-agent/tests/snapshots/workspace-context/system-prompt.expected.md
#	examples/acp-agent/tests/snapshots/workspace-context/tool-schemas.expected.json
#	examples/acp-agent/tests/snapshots/workspace-edit/system-prompt.expected.md
#	examples/acp-agent/tests/snapshots/workspace-edit/tool-schemas.expected.json
#	packages/bash/bash/src/index.ts
#	packages/bash/tool-bash/package.json
#	packages/bash/tool-bash/src/index.ts
#	packages/bash/tool-bash/tests/tools.spec.ts
#	packages/cordis/tool-cordis/src/api-catalog.ts
#	packages/fs/README.md
#	packages/fs/tool-fs/src/edit.ts
#	packages/fs/tool-fs/src/write.ts
#	packages/sandbox/README.md
#	pnpm-lock.yaml
This commit is contained in:
kingwl
2026-07-20 11:40:29 +08:00
1293 changed files with 74019 additions and 16297 deletions
+2 -3
View File
@@ -12,7 +12,7 @@ import type { ContentBlock } from '@deepseek-ai/dsh-llm'
import type {} from '@deepseek-ai/dsh-fs'
import type {} from '@deepseek-ai/dsh-system-prompt'
import { computeHunkDiffs, diffsFromMeta, type FsDiffMeta } from './diff.ts'
import { sessionCwd } from './session-cwd.ts'
import { sessionResolveOptions } from './session-cwd.ts'
import type { FsSandboxSurface } from './sandbox.ts'
/** Validated `edit` arguments after defaulting. */
@@ -95,8 +95,7 @@ export function applyEditTool(ctx: Context, sandbox: FsSandboxSurface): void {
// Resolve the per-call sandbox mode (escalation grant > session override
// > backend default) BEFORE anything executes.
const sandboxMode = await sandbox.stampMode('edit', args, exec)
const cwd = sessionCwd(exec)
const target = await ctx.fs.resolve(input.filePath, cwd !== undefined ? { cwd } : undefined)
const target = await ctx.fs.resolve(input.filePath, sessionResolveOptions(exec))
// Single-slot decision: the policy plugin returns { version: vObserved } or
// throws FS_NOT_OBSERVED; the bare default is undefined (unconditional edit).
// No stat — the bare default never manufactures a version basis.
+4 -3
View File
@@ -13,7 +13,7 @@ import type {} from '@deepseek-ai/dsh-fs'
import type {} from '@deepseek-ai/dsh-system-prompt'
import { buildWindow, formatReadOutput } from './read-render.ts'
import type { FileReadOutcome } from './read-render.ts'
import { sessionCwd } from './session-cwd.ts'
import { sessionResolveOptions } from './session-cwd.ts'
/** Default and maximum number of lines returned by one `read` call (the `readLimit` config). */
export const READ_LIMIT = 2000
@@ -84,10 +84,11 @@ export function applyReadTool(ctx: Context, caps: ReadToolCaps): void {
offset: { type: 'number', description: '1-based first line to return. Defaults to 1.' },
limit: { type: 'number', description: `Maximum number of lines to return. Defaults to ${caps.limit}.` },
},
// Observation races fail closed because guarded mutations re-check the version in-lock.
isConcurrencySafe: () => true,
async execute(args, exec): Promise<ContentBlock[]> {
const input = parseReadArgs(args, caps.limit)
const cwd = sessionCwd(exec)
const target = await ctx.fs.resolve(input.filePath, cwd !== undefined ? { cwd } : undefined)
const target = await ctx.fs.resolve(input.filePath, sessionResolveOptions(exec))
// One stat: type check + size routing + the version recorded as observed.
// A concurrent write can only make a later guarded mutation fail stale and require reread.
+13
View File
@@ -18,3 +18,16 @@ import type { ToolExecution } from '@deepseek-ai/dsh-tools'
export function sessionCwd(exec: ToolExecution): string | undefined {
return exec.agent?.session.header.cwd
}
/**
* Resolution options shared by all model-facing filesystem tools.
* @param exec - the tool-execution context supplying session cwd and cancellation.
* @returns provider resolution options for the current tool call.
*/
export function sessionResolveOptions(exec: ToolExecution): { cwd?: string; signal?: AbortSignal } {
const cwd = sessionCwd(exec)
return {
...cwd !== undefined ? { cwd } : {},
...exec.signal !== undefined ? { signal: exec.signal } : {},
}
}
+2 -3
View File
@@ -13,7 +13,7 @@ import type { FsWriteOutcome } from '@deepseek-ai/dsh-fs'
import type {} from '@deepseek-ai/dsh-fs'
import type {} from '@deepseek-ai/dsh-system-prompt'
import { computeHunkDiffs, diffsFromMeta, type FsDiffMeta } from './diff.ts'
import { sessionCwd } from './session-cwd.ts'
import { sessionResolveOptions } from './session-cwd.ts'
import type { FsSandboxSurface } from './sandbox.ts'
/**
@@ -80,8 +80,7 @@ export function applyWriteTool(ctx: Context, sandbox: FsSandboxSurface): void {
// > backend default) BEFORE anything executes; an escalating call
// resolves approval here and throws its distinct text on any non-grant.
const sandboxMode = await sandbox.stampMode('write', args, exec)
const cwd = sessionCwd(exec)
const target = await ctx.fs.resolve(input.filePath, cwd !== undefined ? { cwd } : undefined)
const target = await ctx.fs.resolve(input.filePath, sessionResolveOptions(exec))
// Single-slot decision: the policy plugin produces createIfAbsent/
// replaceIfVersion; the bare default is undefined (unconditional). No stat.
const intent = await ctx.waterfall('fs/write-intent', target, exec, () => undefined)