Files
deepseek-harness/packages/ui/acp-agent/src/bin.ts
T
Tianyi Cui 4a0941fb4b feat(ui): share the app bins' boot glue in @deepseek-ai/dsh-app-boot
The four near-twin helpers the two published bins carried — loadEnv,
installFailLoud, assertEntriesLoaded, boot — live once in
packages/ui/app-boot, parameterized by the bin's diagnostic prefix and
injectable at their side-effect seams (warn sink, process slice), so
every branch sits under the per-file 100% coverage gate: the unit suite
drives boot() in-process against the real Loader (relative-specifier
configs) through both the settled-tree path and the fiber-less-entry
rejection, and exercises the ENOENT/unloadable .env split, the
Error/non-Error/stackless fail-loud arms, and the disabled-entry
exclusion. resolveConfigPath (snapshot-aware) becomes the single path
resolver for both bins.

Each bin.ts is now a thin self-executing composition plus its
app-specific lifecycle (acp: replay env-skip + stdin-EOF dispose;
stdio: nothing extra), exports nothing, and stays coverage-excluded;
the built-bin smokes still prove both artifacts under plain node in the
node_modules-shaped temp dir (now symlinking ui/app-boot), including
the missing-config non-zero exit.

Implements docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.md
(moved from proposed/ and amended); the extract-example-app-packages
RFC's bin-ownership facts are amended in the same change.
2026-07-04 16:43:06 +08:00

47 lines
2.0 KiB
JavaScript

#!/usr/bin/env node
/**
* The `dsh-acp-agent` bin: boot the ACP server from a leaf `cordis.yml` that
* loads the {@link @deepseek-ai/dsh-acp-agent} app plugin (plus an LLM adapter
* and a bash executor), speaking ACP JSON-RPC on stdio. The shared boot glue —
* `.env` loading, the fail-loud Loader guards, snapshot-aware config
* resolution, the settle-the-tree boot sequence — lives in
* {@link @deepseek-ai/dsh-app-boot}; this bin owns only the ACP-specific
* lifecycle:
*
* - `.env` loading is SKIPPED in snapshot REPLAY so a stray key can never
* trigger a live model call.
* - `DSH_SNAPSHOT=replay` swaps the given `cordis.yml` for its sibling
* `cordis.snapshot.yml` (the keyless replay tree: `llm-replay` in place of
* `llm-deepseek`).
* - In a snapshot run the harness closes stdin when done, so dispose the
* context (flushing persistence) and exit cleanly. In a normal editor
* session stdin stays open for the connection's lifetime (the editor kills
* the process), so the EOF handler never fires.
*
* IMPORTANT: stdout is the ACP JSON-RPC channel. This bin writes diagnostics to
* STDERR only (the app plugin loads no stdout logger, and the shared guards
* write to stderr); a stray stdout write corrupts the protocol frames.
*
* Usage: `dsh-acp-agent [path-to-cordis.yml]` (default `./cordis.yml`).
*
* @module @deepseek-ai/dsh-acp-agent/bin
*/
import { boot, installFailLoud, loadEnv, resolveConfigPath } from '@deepseek-ai/dsh-app-boot'
const NAME = 'dsh-acp-agent'
/* v8 ignore start -- thin self-executing composition over the unit-tested
dsh-app-boot helpers; exercised end-to-end by the snapshot suite and the
built-bin smoke */
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))
if (snapshotMode !== undefined) {
process.stdin.on('end', () => {
void ctx.fiber.dispose().then(() => { process.exit(0) })
})
}
/* v8 ignore stop */