Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 71 additions & 3 deletions components/adapters/deepseek-harness/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,43 @@ To cancel before that next request:
```

`/context-cleaner` remains an alias for older profiles. The native DSH command
is the supported interactive entry point. An external CLI TTY picker is not
advertised here because an external process has no safe access to DSH's live
session surface.
is the supported DSH entry point.

## External CLI safety boundary (GX-01)

The DSH process owns its live Cordis `SessionStore`; an external process must
never deserialize that store, DSH events, or a model-visible message body.
During a normal `agent/pre-step` and when native analysis runs, this adapter
atomically publishes a **metadata-only** snapshot under
`<stateDir>/cleaner-snapshot/`. The persisted record has schema
`lightrsi.deepseek-harness.cleaner-snapshot/v1`, carries the canonical surface
revision and item digests/counts, and contains no raw prompt or response text.

An external integration must use the public
`createDshPersistedCleanerControlService({ stateDir })` factory. It accepts
only snapshots that have the matching schema and host ID and are fresh (five
minutes by default). A DSH Host/session that has not published a fresh snapshot,
a malformed file, inaccessible state directory, or expired snapshot is reported
as *unavailable*; the service does not invent a context. A process that exits
just after publishing remains usable only until that bounded freshness window
expires; the next live DSH `agent/pre-step` still validates the plan revision
and is the only place that can call the canonical surface transaction. The
external service can analyze a published snapshot and write a durable schedule
pointer, but it cannot rewrite a DSH surface.

This adapter exposes the safe factory for the shared CLI product; it does not
register a duplicate product CLI command itself.

## Same-host interactive-selector limitation (GX-03)

DeepSeek Harness's current command contract supplies parsed `rawInput`, while
its web terminal block is a settled-output renderer rather than an interactive
raw-key TTY. Consequently this adapter provides the reproducible native text
workflow (`/tokenpilot-clean`, then `--plan ... --select ...`) but **does not
claim an arrow-key/space/enter selector inside DSH**. Implementing that UX
requires a host-supported raw-key terminal capability or a DSH-owned web
selector. The persisted-snapshot boundary above enables the separate CLI/TTY
path without weakening DSH's surface-mutation boundary.

## Verification

Expand All @@ -82,9 +116,43 @@ corepack pnpm --dir .\components\adapters\deepseek-harness typecheck
corepack pnpm --dir .\components\adapters\deepseek-harness test
```

Current branch validation: `typecheck` passed and `test` passed (107 tests,
including persisted-snapshot restart, freshness, no-raw-text, protected/unknown
selection rejection, and schedule-without-surface-mutation coverage).

`compatibility:smoke` also passed against the pinned local DSH
`0.1.2-alpha.3` (`dd6322d604e00eec1ba5e0c8541159906a21094a`). It verifies
the packed adapter, profile install/remove, and keyless Web startup. The smoke
deliberately does not create a model-backed Cleaner session or mutate a live
surface, so it is a package/compatibility check rather than evidence of a
production Cleaner rollout.

For the pinned DSH compatibility smoke, pass a checkout of the required DSH
revision:

```powershell
corepack pnpm --dir .\components\adapters\deepseek-harness compatibility:smoke -- --dsh-checkout="C:\path\to\deepseek-harness"
```

### GX-02 real DSH-session verification

The unit suite intentionally uses small structural session fixtures for fault
injection. For GX-02 acceptance, also run the following command against the
pinned DSH checkout:

```powershell
corepack pnpm --dir .\components\adapters\deepseek-harness gx02:real-session -- --dsh-checkout="C:\path\to\deepseek-harness"
```

It starts an isolated, **real DSH Cordis runtime** with its real `SessionStore`,
`AgentLoop`, `TokenMeter`, and `agent/pre-step` waterfall. It persists A/B
completed and C active task state, verifies that analysis and selection leave
the canonical surface revision unchanged, then sends one ordinary agent request
to perform the selected A cleanup. The JSON evidence records the before/after
revision, replaced and retained source-event IDs, the applied receipt, and the
terminal replay guard; its temporary state directory is always removed.

The model adapter in this verifier is DSH's deterministic local keyless mock.
That avoids API keys and network calls; it is **not** presented as evidence of
an external production model. The separate compatibility smoke remains the
profile install/remove and Web-startup check.
1 change: 1 addition & 0 deletions components/adapters/deepseek-harness/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"build": "tsx build.ts",
"test": "pnpm run build && node --import tsx --test tests/*.test.ts",
"typecheck": "tsc -p tsconfig.json --noEmit",
"gx02:real-session": "node scripts/gx02-real-session-runner.mjs",
"compatibility:smoke": "node scripts/compatibility-smoke.mjs",
"prepack": "pnpm run build"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* Start the GX-02 verifier through the checked-out DSH tsconfig.
*
* DSH's source packages rely on its workspace path aliases. Running the
* verifier through this tiny launcher prevents Node from accidentally mixing
* the adapter's dependency graph with DSH's built-package graph.
*/

import { access } from 'node:fs/promises'
import { spawn } from 'node:child_process'
import { dirname, join, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'

const args = process.argv.slice(2)
const checkoutArgument = args.find(value => value.startsWith('--dsh-checkout='))
if (checkoutArgument === undefined) {
throw new Error('GX-02 requires --dsh-checkout=<absolute path to deepseek-harness>')
}

const checkout = resolve(checkoutArgument.slice('--dsh-checkout='.length))
const tsxCli = join(checkout, 'node_modules', 'tsx', 'dist', 'cli.mjs')
const tsconfig = join(checkout, 'tsconfig.json')
await Promise.all([access(tsxCli), access(tsconfig)])

const script = join(dirname(fileURLToPath(import.meta.url)), 'gx02-real-session.ts')
const child = spawn(process.execPath, [tsxCli, '--tsconfig', tsconfig, script, ...args], {
stdio: 'inherit',
})

const exitCode = await new Promise(resolveChild => {
child.once('error', () => resolveChild(1))
child.once('exit', code => resolveChild(code ?? 1))
})
process.exitCode = exitCode
Loading
Loading