Merge remote-tracking branch 'origin/master' into worktree/web-multimodal-image-input

# Conflicts:
#	.agents/notes/implemented/architecture/2026-07-05-reconstructable-requests.i18n.yaml
#	.agents/notes/implemented/architecture/2026-07-05-reconstructable-requests.md
#	.agents/notes/implemented/architecture/2026-07-05-reconstructable-requests.zh.md
#	.agents/notes/implemented/architecture/2026-07-25-web-input-machine-and-slash-pipeline.i18n.yaml
#	.agents/notes/implemented/architecture/2026-07-25-web-input-machine-and-slash-pipeline.md
#	.agents/notes/implemented/architecture/2026-07-25-web-input-machine-and-slash-pipeline.zh.md
#	THIRD_PARTY_NOTICES.md
#	apps/cli/composition.md
#	apps/cli/config/base.cordis.yml
#	apps/cli/package.json
#	apps/cli/src/app-cli-entry.ts
#	apps/cli/src/bin.ts
#	apps/cli/tests/args.spec.ts
#	apps/web/tests/built-boot.snapshot.ts
#	apps/web/tests/navigation-panes.e2e.ts
#	docs/architecture.i18n.yaml
#	docs/architecture.md
#	docs/architecture.zh.md
#	docs/config-catalog.md
#	docs/cordis-catalog/services.md
#	docs/core-data-structures/core.i18n.yaml
#	docs/core-data-structures/llm-streaming.i18n.yaml
#	docs/event-producer-consumer.md
#	docs/module-graph.md
#	examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/session.jsonl
#	packages/README.i18n.yaml
#	packages/bundle/README.i18n.yaml
#	packages/client/connection/README.i18n.yaml
#	packages/client/connection/README.md
#	packages/client/connection/README.zh.md
#	packages/client/connection/src/client/fixture.ts
#	packages/client/connection/src/http-bridge.ts
#	packages/client/connection/src/index.ts
#	packages/client/connection/tests/fixture.spec.ts
#	packages/client/connection/tests/node-half.spec.ts
#	packages/client/runtime/README.i18n.yaml
#	packages/client/runtime/README.md
#	packages/client/runtime/README.zh.md
#	packages/client/runtime/src/client/contract/session.ts
#	packages/client/runtime/src/client/sessions/session.ts
#	packages/client/ui-conversation/README.i18n.yaml
#	packages/client/ui-conversation/README.md
#	packages/client/ui-conversation/README.zh.md
#	packages/client/ui-conversation/src/client/apply.ts
#	packages/client/ui-conversation/src/client/chat/AssistantMarkdown.tsx
#	packages/client/ui-conversation/src/client/chat/ChatView.tsx
#	packages/client/ui-conversation/src/client/chat/MessageItem.module.css
#	packages/client/ui-conversation/src/client/chat/MessageItem.tsx
#	packages/client/ui-conversation/src/client/contract/slots.ts
#	packages/client/ui-conversation/src/client/index.ts
#	packages/client/ui-conversation/src/client/input/contract.ts
#	packages/client/ui-conversation/src/client/input/facade.ts
#	packages/client/ui-conversation/src/client/input/hub.ts
#	packages/client/ui-conversation/src/client/locales.ts
#	packages/client/ui-conversation/src/client/service.ts
#	packages/client/ui-conversation/src/client/skeleton/ConversationSession.tsx
#	packages/client/ui-conversation/src/client/skeleton/InputBar.tsx
#	packages/client/ui-conversation/tests/apply-inject.spec.tsx
#	packages/client/ui-conversation/tests/input-bar.spec.tsx
#	packages/client/ui-conversation/tests/input-matrix.spec.tsx
#	packages/client/ui-conversation/tests/input-scenarios.spec.tsx
#	packages/client/ui-conversation/tests/service-orchestration.spec.ts
#	packages/client/ui-conversation/tests/skeleton.spec.tsx
#	packages/client/ui-trajectory/tests/views.spec.tsx
#	packages/compact/compact-basic/README.i18n.yaml
#	packages/cordis/tool-cordis/src/api-catalog.ts
#	packages/host/apiproxy/README.i18n.yaml
#	packages/host/apiproxy/README.md
#	packages/host/apiproxy/README.zh.md
#	packages/host/apiproxy/src/api-proxy.ts
#	packages/host/apiproxy/src/api/rpc.ts
#	packages/host/apiproxy/src/api/sessions.ts
#	packages/host/apiproxy/src/index.ts
#	packages/host/apiproxy/tests/api-proxy-models.spec.ts
#	packages/host/apiproxy/tests/rpc-schemas.spec.ts
#	packages/llm/llm-pi-ai/README.i18n.yaml
#	packages/llm/llm-pi-ai/README.md
#	packages/llm/llm-pi-ai/README.zh.md
#	packages/llm/llm-pi-ai/src/adapter.ts
#	packages/llm/llm/README.i18n.yaml
#	packages/ui/tui/README.md
#	packages/ui/tui/README.zh.md
#	packages/ui/tui/src/components/content.ts
#	packages/ui/tui/src/components/transcript.ts
#	packages/ui/tui/tests/tui.spec.ts
#	pnpm-lock.yaml
This commit is contained in:
Yichen Jiang
2026-08-08 01:56:29 +08:00
3973 changed files with 144864 additions and 60887 deletions
@@ -12,6 +12,7 @@ import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { describe, expect, it, vi } from 'vitest'
import { Context } from 'cordis'
import { LAUNCHER_FAILURE_EXIT } from 'node-addon-landlock-run'
import { SANDBOX_UNAVAILABLE, SandboxUnavailableError } from '@deepseek-ai/dsh-sandbox'
import type { SandboxPolicy } from '@deepseek-ai/dsh-sandbox'
import {
@@ -35,7 +36,7 @@ async function setup(config: Config = {}, internals: LocalSandboxProvider['inter
function fakeLauncher(report = 'landlock: fully enforced'): string {
const dir = mkdtempSync(join(tmpdir(), 'dsh-fake-landlock-'))
const launcher = join(dir, 'landlock-run')
writeFileSync(launcher, `#!/bin/sh\nif [ "$1" = "--probe" ]; then echo "${report}"; exit 0; fi\nexit 125\n`, { mode: 0o755 })
writeFileSync(launcher, `#!/bin/sh\nif [ "$1" = "--probe" ]; then echo "${report}"; exit 0; fi\nexit ${LAUNCHER_FAILURE_EXIT}\n`, { mode: 0o755 })
return launcher
}
@@ -111,16 +112,7 @@ describe('runnerCommand config', () => {
// An operator runner's kernel mechanism is unknown: both Linux
// file-denial dialects, never bare EPERM.
denialSignatures: ['read-only file system', 'permission denied'],
// The runner's own dialect is unknown, but the consumer re-joins the
// wrap through an outer `bash -c 'exec …'` — a missing or
// unexecutable runner fails with the OUTER shell's argv0-scoped
// shapes, and those classify as sandbox failures like any rung.
runnerFailureSignatures: [
'fake-runner: profile rejected',
'exec: fake-runner: not found',
'fake-runner: No such file or directory',
'fake-runner: Permission denied',
],
runnerFailureRules: [{ fatalSignatures: ['fake-runner: profile rejected'] }],
})
expect(probeBwrap).not.toHaveBeenCalled()
expect(probeLandlock).not.toHaveBeenCalled()
@@ -146,11 +138,14 @@ describe('runnerCommand config', () => {
)
})
it('rejects blank configured-runner failure signatures', async () => {
await expect(setup({ runnerCommand: ['fake-runner'], runnerFailureSignatures: [' '] })).rejects.toThrow(
'runnerFailureSignatures entries must be non-empty',
)
})
it.each([' ', 'fatal\ncontinued', 'fatal\rcontinued'])(
'rejects an unusable configured-runner failure signature %j',
async (signature) => {
await expect(setup({ runnerCommand: ['fake-runner'], runnerFailureSignatures: [signature] })).rejects.toThrow(
'runnerFailureSignatures entries must be non-empty single-line strings',
)
},
)
})
describe('the platform chains', () => {
@@ -163,7 +158,7 @@ describe('the platform chains', () => {
argv: ['bwrap', ...bwrapProfileArgs(RO), '--', 'true'],
enforcement: 'full',
denialSignatures: ['read-only file system'],
runnerFailureSignatures: ['bwrap: '],
runnerFailureRules: [{ fatalSignatures: ['bwrap: '] }],
})
expect(probeLandlock).not.toHaveBeenCalled()
})
@@ -178,14 +173,18 @@ describe('the platform chains', () => {
argv: [launcher, ...landlockProfileArgs(WW), '--', 'bash', '-c', 'echo hi'],
enforcement: 'full',
denialSignatures: ['permission denied'],
runnerFailureSignatures: ['landlock-run: '],
runnerFailureRules: [{
allowedExitCodes: [LAUNCHER_FAILURE_EXIT],
fatalSignatures: ['landlock-run: '],
informationalLines: ['landlock-run: partial enforcement (older Landlock ABI)'],
}],
})
expect(probeLandlock).toHaveBeenCalledWith(launcher)
})
it('darwin selects its sole candidate WITHOUT probing: nothing to arbitrate', async () => {
// The safety property moves to execution time: an unusable sandbox-exec
// refuses to run the command, and the wrap's runnerFailureSignatures let
// refuses to run the command, and the wrap's runnerFailureRules let
// the consumer classify that as a sandbox failure, not a task failure.
const probeSeatbelt = vi.fn(() => true)
const { sandbox } = await setup({}, { platform: 'darwin', probeSeatbelt })
@@ -194,7 +193,7 @@ describe('the platform chains', () => {
argv: ['sandbox-exec', ...seatbeltProfileArgs(RO), '--', 'bash', '-c', 'echo hi'],
enforcement: 'full',
denialSignatures: ['operation not permitted'],
runnerFailureSignatures: ['sandbox-exec: '],
runnerFailureRules: [{ fatalSignatures: ['sandbox-exec: '] }],
})
expect(probeSeatbelt).not.toHaveBeenCalled()
})
@@ -311,7 +310,7 @@ describe('the default landlock probe (launcher CLI contract)', () => {
it('reads a failing launcher as unusable: the chain ends and fails closed', async () => {
const dir = mkdtempSync(join(tmpdir(), 'dsh-fake-landlock-'))
const launcher = join(dir, 'landlock-run')
writeFileSync(launcher, '#!/bin/sh\nexit 125\n', { mode: 0o755 })
writeFileSync(launcher, `#!/bin/sh\nexit ${LAUNCHER_FAILURE_EXIT}\n`, { mode: 0o755 })
const { sandbox } = await setup({}, { platform: 'linux', probeBwrap: () => false, landlockLauncher: launcher })
expect(() => sandbox.confine(['true'], RO)).toThrow(expect.objectContaining({ code: SANDBOX_UNAVAILABLE }))
})
@@ -360,7 +359,7 @@ describe('the default seatbelt probe (sandbox-exec contract)', () => {
argv: [exec, ...seatbeltProfileArgs(RO), '--', 'true'],
enforcement: 'full',
denialSignatures: ['operation not permitted'],
runnerFailureSignatures: ['sandbox-exec: '],
runnerFailureRules: [{ fatalSignatures: ['sandbox-exec: '] }],
})
})