# ACP server and snapshot-record composition. With `DSH_SNAPSHOT=record`, the
# app bin runs the real DeepSeek adapter and the harness harvests its persisted
# log. The bin loads the gitignored root `.env` before this config. This tree has
# no stdout logger or HMR because stdout carries ACP JSON-RPC.

# The DeepSeek adapter.
- id: llm-deepseek
  name: '@deepseek-ai/dsh-llm-deepseek'
  config:
    apiKey: !!js process.env.DEEPSEEK_API_KEY
    baseURL: !!js process.env.DEEPSEEK_BASE_URL
    models:
      - id: deepseek-v4-flash
        contextWindow: 256000
      - id: deepseek-v4-pro
        contextWindow: 256000

# The default composition confines bash AND the filesystem tools to the
# workspace and asks before a wider retry. Snapshot runs select
# danger-full-access so the established scenarios remain runner-independent;
# DSH_PERMISSION_MODE provides the same explicit deployment/test override
# outside the snapshot harness. The sandbox mode + workspace root live on
# ctx.sandboxPolicy — the one home both enforcing families (bash, fs) read.
- id: sandbox
  name: '@deepseek-ai/dsh-sandbox-local'

- id: sandbox-policy
  name: '@deepseek-ai/dsh-sandbox-policy'
  config:
    mode: !!js "process.env.DSH_PERMISSION_MODE ?? (process.env.DSH_SNAPSHOT === undefined ? 'workspace-write' : 'danger-full-access')"
    workspaceRoot: !!js process.cwd()

- id: bash
  name: '@deepseek-ai/dsh-bash-sandbox'
  config:
    timeoutMs: 60000

- id: approval
  name: '@deepseek-ai/dsh-user-approval'
  config:
    policy: !!js "(process.env.DSH_PERMISSION_MODE ?? (process.env.DSH_SNAPSHOT === undefined ? 'workspace-write' : 'danger-full-access')) === 'danger-full-access' ? 'never' : 'ask'"

- id: permission
  name: '@deepseek-ai/dsh-permission'

# The ACP server app: the agent-spine-demo spine + JSONL persistence + the ACP bridge.
# Persistence root: $DSH_SNAPSHOT_SESSIONS_ROOT when the snapshot harness sets it
# (so it can harvest / isolate the log), else ./.sessions for the demo.
# Snapshot modes use raw JSONL fixtures; ordinary runs keep the compressed default.
- id: acp-agent
  name: '@deepseek-ai/dsh-acp-demo'
  config:
    provider: deepseek
    model: deepseek-v4-flash
    persistenceRoot: !!js process.env.DSH_SNAPSHOT_SESSIONS_ROOT ?? './.sessions'
    persistenceCompression: !!js "process.env.DSH_SNAPSHOT === undefined ? 'zstd' : 'none'"
    workspaceContext:
      maxBytes: 65536
    # Keep the persona to identity and behavior; tool plugins own tool guidance.
    # The loop resolves {{model}} and each ACP session's client-supplied {{cwd}}.
    persona: |
      You are a coding assistant powered by the {{model}} model. Your working directory is {{cwd}}. Your bash tool runs under a file sandbox — a `[sandbox: file access denied …]` result is policy, not a command bug.

      Verify your work by running the code or tests. Keep answers brief and factual.

# Replay-aware request pressure; the routed adapter supplies model capacity.
- id: token-meter
  name: '@deepseek-ai/dsh-token-meter'

# Summarize an older range after measured pressure or a canonical provider overflow.
# Ratios scale against the routed model's context window.
- id: compact-basic
  name: '@deepseek-ai/dsh-compact-basic'
  config:
    thresholdRatio: 0.8
    retainRatio: 0.08
    maxTokens: 8192
    compactionRetries: 1

# Expose fresh-child `spawn` and completed-prefix `fork` through separate tool
# names so multi-child scenarios exercise both transports. These leaves follow
# the app because it provides `ctx.agents` and `ctx.tools`.
- id: subagent
  name: '@deepseek-ai/dsh-subagent'

- id: subagent-spawn
  name: '@deepseek-ai/dsh-subagent-spawn'
  config:
    providerName: spawn

- id: subagent-fork
  name: '@deepseek-ai/dsh-subagent-fork'
  config:
    providerName: fork

- id: tool-subagent
  name: '@deepseek-ai/dsh-tool-subagent'
  config:
    provider: spawn
    toolName: subagent
    maxDepth: 1

- id: tool-subagent-fork
  name: '@deepseek-ai/dsh-tool-subagent'
  config:
    provider: fork
    toolName: subagent_fork
    maxDepth: 1


# The worker-thread workflow engine fans a model-written JavaScript script's
# `agent()` calls out through the spawn backend; the adjacent tool exposes it to the model.
- id: workflow-workerthread
  name: '@deepseek-ai/dsh-workflow-workerthread'
  config:
    provider: spawn

- id: tool-workflow
  name: '@deepseek-ai/dsh-tool-workflow'

- id: tool-ralph
  name: '@deepseek-ai/dsh-tool-ralph'
# `todo_write` replaces the logged whole list and surfaces an ACP `plan` update.
- id: tool-todo
  name: '@deepseek-ai/dsh-tool-todo'

# Identical repeat calls trigger advisory context, never a block, at the default
# thresholds [3, 5, 8]. Only the repeat-tool-guard snapshot scenario reaches them.
- id: repeat-tool-guard
  name: '@deepseek-ai/dsh-repeat-tool-guard'

# The filesystem stack rides the SAME sandbox policy as bash: dsh-fs-sandbox
# replaces dsh-fs-local behind ctx.fs and fences write/edit by the effective
# mode (read-only denies, workspace-write contains to the workspace + temp
# roots, danger-full-access passes through), so read/write/edit are available
# under every mode. fs-policy (read-before-edit) composes orthogonally on top.
- id: fs-sandbox
  name: '@deepseek-ai/dsh-fs-sandbox'
  config:
    cwd: !!js process.cwd()

- id: fs-policy
  name: '@deepseek-ai/dsh-fs-policy'

- id: tool-fs
  name: '@deepseek-ai/dsh-tool-fs'

# `configPath` is read once at load and resolves from the server launch cwd, not
# `session/new.cwd`; one `hooks.json` therefore applies to every session and a
# project-local file is not discovered. Missing config registers nothing. Hook
# commands still run in the session cwd. Warnings use `ctx.logger`, never stdout;
# see packages/hooks/hooks-claude/README.md for the deferred per-session design.
- id: hooks-claude
  name: '@deepseek-ai/dsh-hooks-claude'
  config:
    configPath: ./hooks.json

# Codex uses its own `codex-hooks.json` and snake_case five-event dialect; it
# cannot share Claude's file. It has the same process-level, read-once, missing-is-no-op,
# logger-only contract. Shipping both bridges lets a scenario seed and exercise either dialect.
- id: hooks-codex
  name: '@deepseek-ai/dsh-hooks-codex'
  config:
    configPath: ./codex-hooks.json
