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:
@@ -29,11 +29,11 @@ Because the package wires no logger entry, an ACP leaf has **nothing to get wron
|
||||
| `toolOrder` | — | explicit model-facing tool order (a name list with one `'<unlisted-tools>'` rest entry; absent — lexicographic; an unregistered name fails each turn at prompt assembly), routed to `dsh-system-prompt` |
|
||||
| `persistenceRoot` | `./.sessions` | the JSONL backend's root directory |
|
||||
|
||||
The leaf supplies the swappable backends: an LLM adapter (`llm-deepseek` for the real model, `llm-replay` for keyless snapshot replay) and a bash executor (`bash-local`).
|
||||
The leaf supplies the swappable backends: an LLM adapter (`llm-deepseek` for the real model, `llm-replay` for keyless snapshot replay) and a bash executor.
|
||||
|
||||
## The bin
|
||||
|
||||
`dsh-acp-agent [path-to-cordis.yml]` (default `./cordis.yml`):
|
||||
`dsh-acp-agent [--config path-to-cordis.yml]` (short form `-c`; default `./cordis.yml`):
|
||||
|
||||
- loads a gitignored `.env` from the cwd — **skipped** in snapshot REPLAY so a stray key can never trigger a live call;
|
||||
- honors `DSH_SNAPSHOT=replay` by booting the sibling `cordis.snapshot.yml` (the keyless replay tree, `llm-replay` in place of `llm-deepseek`);
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Boot an ACP stdio server from `cordis.yml`; usage is `dsh-acp-agent [config]`, defaulting to the
|
||||
* cwd file. Shared env loading, Loader guards, snapshot config selection, and settled-tree boot live
|
||||
* in dsh-app-boot. Replay skips `.env` and selects sibling `cordis.snapshot.yml` so a stray key
|
||||
* cannot trigger a model call. EOF disposes and flushes snapshot runs; editors normally own process
|
||||
* lifetime. Stdout is reserved for JSON-RPC—write diagnostics only to stderr.
|
||||
* Boot an ACP stdio server from `cordis.yml`; usage is
|
||||
* `dsh-acp-agent [--config path]`, defaulting to `./cordis.yml`. Shared env
|
||||
* loading, Loader guards, snapshot config selection, and settled-tree boot live
|
||||
* in dsh-app-boot. Replay skips `.env` and selects sibling
|
||||
* `cordis.snapshot.yml` so a stray key cannot trigger a model call. EOF disposes
|
||||
* and flushes snapshot runs; editors normally own process lifetime. Stdout is
|
||||
* reserved for JSON-RPC, so diagnostics go only to stderr.
|
||||
* @module @deepseek-ai/dsh-acp-agent/bin
|
||||
*/
|
||||
|
||||
import { parseArgs } from 'node:util'
|
||||
import { boot, installFailLoud, loadEnv, resolveConfigPath } from '@deepseek-ai/dsh-app-boot'
|
||||
|
||||
const NAME = 'dsh-acp-agent'
|
||||
@@ -18,7 +21,12 @@ const NAME = 'dsh-acp-agent'
|
||||
installFailLoud(NAME)
|
||||
const snapshotMode = process.env['DSH_SNAPSHOT']
|
||||
if (snapshotMode !== 'replay') loadEnv(NAME)
|
||||
const ctx = await boot(NAME, resolveConfigPath(process.argv[2] ?? './cordis.yml', snapshotMode))
|
||||
const { values } = parseArgs({
|
||||
args: process.argv.slice(2),
|
||||
options: { config: { type: 'string', short: 'c' } },
|
||||
strict: true,
|
||||
})
|
||||
const ctx = await boot(NAME, resolveConfigPath(values.config ?? './cordis.yml', snapshotMode))
|
||||
if (snapshotMode !== undefined) {
|
||||
process.stdin.on('end', () => {
|
||||
void ctx.fiber.dispose().then(() => { process.exit(0) })
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* The ACP server app: the default agent spine ({@link @deepseek-ai/dsh-agent-core}) plus the
|
||||
* coupled front-door cluster an ACP server needs — JSONL session persistence and the {@link
|
||||
* @deepseek-ai/dsh-acp} bridge, and deliberately NOTHING that writes to stdout.
|
||||
* The ACP server app: the default agent spine ({@link @deepseek-ai/dsh-agent-core}),
|
||||
* JSONL session persistence, and the {@link @deepseek-ai/dsh-acp} bridge. It
|
||||
* writes nothing to stdout.
|
||||
* It pre-creates no agents and leaves adapters, executors, and optional tools to
|
||||
* the leaf, which must likewise avoid stdout loggers. Named exports are
|
||||
* required so Loader retains this plugin's `Config` schema (see
|
||||
|
||||
@@ -103,7 +103,7 @@ afterEach(async () => {
|
||||
describe.skipIf(!existsSync(acpBin))('dsh-acp-agent BUILT bin (node lib/bin.js, no tsx)', () => {
|
||||
it('boots the published bin and answers an initialize JSON-RPC frame on stdout', async () => {
|
||||
consumer = await makeConsumer()
|
||||
child = spawn(process.execPath, ['--expose-internals', acpBin, './cordis.yml'], {
|
||||
child = spawn(process.execPath, ['--expose-internals', acpBin, '--config', './cordis.yml'], {
|
||||
cwd: consumer,
|
||||
// Dummy key: initialize never reaches the model, so it is never used.
|
||||
env: {
|
||||
@@ -166,7 +166,7 @@ describe.skipIf(!existsSync(acpBin))('dsh-acp-agent BUILT bin (node lib/bin.js,
|
||||
/** Spawn the built acp bin against `configArg` and resolve with its exit code + stderr. */
|
||||
function runBinExpectingExit(configArg: string, cwd: string = tmpdir()): Promise<{ code: number; stderr: string }> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const proc = spawn(process.execPath, ['--expose-internals', acpBin, configArg], {
|
||||
const proc = spawn(process.execPath, ['--expose-internals', acpBin, '--config', configArg], {
|
||||
cwd,
|
||||
env: {
|
||||
...process.env,
|
||||
|
||||
@@ -71,7 +71,7 @@ async function boot(): Promise<Spawned & { cwd: string }> {
|
||||
await writeFile(configPath, CORDIS_YML)
|
||||
const child = spawn(
|
||||
process.execPath,
|
||||
['--import', tsxLoader, binScript, configPath],
|
||||
['--import', tsxLoader, binScript, '--config', configPath],
|
||||
{
|
||||
cwd,
|
||||
env: {
|
||||
|
||||
Reference in New Issue
Block a user