Merge remote-tracking branch 'origin/master' into codex/simp-snapshot-fixture-inventory
This commit is contained in:
38 files changed
+821
-191
No files matched your search
+2
-2
@@ -1,6 +1,6 @@
|
||||
# AGENTS.md — Examples
|
||||
|
||||
Runnable harness compositions. **Examples are NOT workspaces**: their private `package.json` files are dependency-free stubs, and the cordis Loader boots each `cordis.yml` unbuilt through `tsx` plus the root tsconfig paths.
|
||||
Runnable harness compositions. `examples/` is one workspace member and the module-resolution root for runnable and test Cordis configs; it is not a build target. [package.json](package.json) declares the packages loaded by those configs, while each leaf's private `package.json` remains metadata only.
|
||||
|
||||
Extract reusable logic into `packages/`, where per-file coverage and README gates apply. Examples keep only `cordis.yml` wiring, demo artifacts, and e2e/snapshot scenarios; app package bins own boot glue.
|
||||
|
||||
@@ -13,7 +13,7 @@ Each example has both:
|
||||
|
||||
Mock-only examples require only the keyless tier; state that exception in the test.
|
||||
|
||||
Keyless stdio smokes use `@deepseek-ai/dsh-loader-smoke` for isolation, root-tsconfig loading, subprocess lifecycle, diagnostics, EOF, and cleanup; tests supply paths, environment, input, and assertions.
|
||||
Keyless stdio smokes use `@deepseek-ai/dsh-loader-smoke`; tests supply paths, environment, input, and assertions. Every checked-in test Cordis config lives under its corresponding `examples/<agent>/` leaf. Map a package-owned config to `examples/<agent>/tests/fixtures/<group>/<package>/cordis.yml`, keep its driver and assertions package-local, and declare every package it names in both root `tsconfig.json` references and `examples/package.json`.
|
||||
|
||||
Do not inventory example tests here; the `tests/` trees and root scripts are authoritative.
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
type RequestPermissionResponse,
|
||||
type SessionNotification,
|
||||
} from '@agentclientprotocol/sdk'
|
||||
import { resolveExampleLaunch } from '@deepseek-ai/dsh-loader-smoke'
|
||||
|
||||
/**
|
||||
* Boots examples/acp-agent as an ACP subprocess. The key-gated prompt leg
|
||||
@@ -25,8 +26,6 @@ import {
|
||||
// The child runs from a temp cwd, so its bin and config path are absolute.
|
||||
const binScript = fileURLToPath(new URL('../../../packages/examples/acp-demo/src/bin.ts', import.meta.url))
|
||||
const configPath = fileURLToPath(new URL('../cordis.yml', import.meta.url))
|
||||
// Resolve tsx absolutely because the subprocess runs outside the repo.
|
||||
const tsxLoader = fileURLToPath(import.meta.resolve('tsx'))
|
||||
// The root tsconfig supplies unbuilt workspace `paths`; making it explicit
|
||||
// avoids accidental resolution through stale built output.
|
||||
const repoTsconfig = fileURLToPath(new URL('../../../tsconfig.json', import.meta.url))
|
||||
@@ -38,24 +37,21 @@ interface Spawned {
|
||||
stderr: string[]
|
||||
}
|
||||
|
||||
// TODO(acp-test-harness): this subprocess/client boot glue is duplicated with
|
||||
// hooks.e2e.ts and partly with dsh-acp-snapshot's harness. Migrate both e2e
|
||||
// files onto that launcher before the TSX/env/permission-stub details drift.
|
||||
function spawnAcpAgent(cwd: string, env: NodeJS.ProcessEnv = process.env): Spawned {
|
||||
const child = spawn(
|
||||
process.execPath,
|
||||
['--import', tsxLoader, binScript, '--config', configPath],
|
||||
{
|
||||
cwd,
|
||||
env: {
|
||||
...env,
|
||||
TSX_TSCONFIG_PATH: repoTsconfig,
|
||||
DSH_PERMISSION_MODE: 'danger-full-access',
|
||||
DSH_HOME: join(cwd, '.dsh'),
|
||||
DSH_AGENTS_HOME: join(cwd, '.agents'),
|
||||
},
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
const launch = resolveExampleLaunch({
|
||||
srcBin: binScript,
|
||||
configArgs: ['--config', configPath],
|
||||
tsconfigPath: repoTsconfig,
|
||||
env: {
|
||||
DSH_PERMISSION_MODE: 'danger-full-access',
|
||||
DSH_HOME: join(cwd, '.dsh'),
|
||||
DSH_AGENTS_HOME: join(cwd, '.agents'),
|
||||
},
|
||||
})
|
||||
const child = spawn(
|
||||
launch.command,
|
||||
launch.args,
|
||||
{ cwd, env: { ...env, ...launch.env }, stdio: ['pipe', 'pipe', 'pipe'] },
|
||||
)
|
||||
const stderr: string[] = []
|
||||
child.stderr.setEncoding('utf8')
|
||||
@@ -138,16 +134,20 @@ describe('acp-agent over real stdio (no key required)', () => {
|
||||
workdir = await mkdtemp(join(tmpdir(), 'acp-e2e-'))
|
||||
// Collect raw stdout bytes directly (bypass the SDK framing) to inspect.
|
||||
// A dummy key boots the adapter; this purity test sends no prompt and makes no model call.
|
||||
const child = spawn(process.execPath, ['--import', tsxLoader, binScript, '--config', configPath], {
|
||||
cwd: workdir,
|
||||
const launch = resolveExampleLaunch({
|
||||
srcBin: binScript,
|
||||
configArgs: ['--config', configPath],
|
||||
tsconfigPath: repoTsconfig,
|
||||
env: {
|
||||
...process.env,
|
||||
DEEPSEEK_API_KEY: process.env.DEEPSEEK_API_KEY ?? 'sk-dummy-for-boot',
|
||||
TSX_TSCONFIG_PATH: repoTsconfig,
|
||||
DSH_PERMISSION_MODE: 'danger-full-access',
|
||||
DSH_HOME: join(workdir, '.dsh'),
|
||||
DSH_AGENTS_HOME: join(workdir, '.agents'),
|
||||
},
|
||||
})
|
||||
const child = spawn(launch.command, launch.args, {
|
||||
cwd: workdir,
|
||||
env: { ...process.env, ...launch.env },
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
})
|
||||
const out: string[] = []
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
type RequestPermissionResponse,
|
||||
type SessionNotification,
|
||||
} from '@agentclientprotocol/sdk'
|
||||
import { resolveExampleLaunch } from '@deepseek-ai/dsh-loader-smoke'
|
||||
|
||||
/**
|
||||
* Exercises the default ACP composition through the real bin and Loader. The
|
||||
@@ -28,9 +29,8 @@ import {
|
||||
|
||||
const binScript = fileURLToPath(new URL('../../../packages/examples/acp-demo/src/bin.ts', import.meta.url))
|
||||
const configPath = fileURLToPath(new URL('../cordis.yml', import.meta.url))
|
||||
const tsxLoader = fileURLToPath(import.meta.resolve('tsx'))
|
||||
// The subprocess runs from a temp cwd outside the repo; point tsx at the repo
|
||||
// tsconfig so the unbuilt `paths` map resolves (see examples/AGENTS.md).
|
||||
// tsconfig so the unbuilt `paths` map resolves in src mode (see examples/AGENTS.md).
|
||||
const repoTsconfig = fileURLToPath(new URL('../../../tsconfig.json', import.meta.url))
|
||||
|
||||
// Without a usable bwrap/Seatbelt runner, the strict attempt fails closed with
|
||||
@@ -55,17 +55,19 @@ interface Spawned {
|
||||
|
||||
/** Boot the example as an ACP subprocess; the scripted client answers every permission prompt with `answer`. */
|
||||
function spawnAcpAgent(cwd: string, answer: 'allow-once' | 'reject-once'): Spawned {
|
||||
const launch = resolveExampleLaunch({
|
||||
srcBin: binScript,
|
||||
configArgs: ['--config', configPath],
|
||||
tsconfigPath: repoTsconfig,
|
||||
// A dummy key lets the deepseek adapter boot keyless (presence-checked at
|
||||
// apply, used only on a real model call); the with-key tests carry the
|
||||
// real key, so the fallback is inert there.
|
||||
env: { DEEPSEEK_API_KEY: process.env.DEEPSEEK_API_KEY || 'sk-dummy-for-boot' },
|
||||
})
|
||||
const child = spawn(
|
||||
process.execPath,
|
||||
['--import', tsxLoader, binScript, '--config', configPath],
|
||||
{
|
||||
cwd,
|
||||
// A dummy key lets the deepseek adapter boot keyless (presence-checked at
|
||||
// apply, used only on a real model call); the with-key tests carry the
|
||||
// real key, so the fallback is inert there.
|
||||
env: { ...process.env, DEEPSEEK_API_KEY: process.env.DEEPSEEK_API_KEY || 'sk-dummy-for-boot', TSX_TSCONFIG_PATH: repoTsconfig },
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
},
|
||||
launch.command,
|
||||
launch.args,
|
||||
{ cwd, env: { ...process.env, ...launch.env }, stdio: ['pipe', 'pipe', 'pipe'] },
|
||||
)
|
||||
const stderr: string[] = []
|
||||
child.stderr.setEncoding('utf8')
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
type RequestPermissionResponse,
|
||||
type SessionNotification,
|
||||
} from '@agentclientprotocol/sdk'
|
||||
import { resolveExampleLaunch } from '@deepseek-ai/dsh-loader-smoke'
|
||||
|
||||
/**
|
||||
* With-key e2e for the Claude hook bridge. The process-level `./hooks.json` is
|
||||
@@ -25,7 +26,6 @@ import {
|
||||
|
||||
const binScript = fileURLToPath(new URL('../../../packages/examples/acp-demo/src/bin.ts', import.meta.url))
|
||||
const configPath = fileURLToPath(new URL('../cordis.yml', import.meta.url))
|
||||
const tsxLoader = fileURLToPath(import.meta.resolve('tsx'))
|
||||
const repoTsconfig = fileURLToPath(new URL('../../../tsconfig.json', import.meta.url))
|
||||
|
||||
interface Spawned {
|
||||
@@ -36,10 +36,16 @@ interface Spawned {
|
||||
}
|
||||
|
||||
function spawnAcpAgent(cwd: string): Spawned {
|
||||
const launch = resolveExampleLaunch({
|
||||
srcBin: binScript,
|
||||
configArgs: ['--config', configPath],
|
||||
tsconfigPath: repoTsconfig,
|
||||
env: { DSH_PERMISSION_MODE: 'danger-full-access' },
|
||||
})
|
||||
const child = spawn(
|
||||
process.execPath,
|
||||
['--import', tsxLoader, binScript, '--config', configPath],
|
||||
{ cwd, env: { ...process.env, TSX_TSCONFIG_PATH: repoTsconfig, DSH_PERMISSION_MODE: 'danger-full-access' }, stdio: ['pipe', 'pipe', 'pipe'] },
|
||||
launch.command,
|
||||
launch.args,
|
||||
{ cwd, env: { ...process.env, ...launch.env }, stdio: ['pipe', 'pipe', 'pipe'] },
|
||||
)
|
||||
const stderr: string[] = []
|
||||
child.stderr.setEncoding('utf8')
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# Test-only composition: keep time-context opt-in while exercising its real Loader/app path.
|
||||
- id: mock-llm
|
||||
name: '../../../../src/mock-llm.ts'
|
||||
|
||||
- id: bash
|
||||
name: '@deepseek-ai/dsh-bash-local'
|
||||
|
||||
- id: time-context
|
||||
name: '@deepseek-ai/dsh-time-context'
|
||||
|
||||
- id: stdio-agent
|
||||
name: '@deepseek-ai/dsh-stdio-demo'
|
||||
config:
|
||||
provider: mock
|
||||
model: mock-echo
|
||||
persona: 'Test the time-context plugin.'
|
||||
welcome: 'time-context e2e ready.'
|
||||
persistenceRoot: './.sessions'
|
||||
workspaceContext: false
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"name": "dsh-examples",
|
||||
"private": true,
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"description": "Workspace umbrella for runnable demos and example-owned test compositions: declares their cordis.yml packages so plain Node resolves real exports→lib. Not a build target.",
|
||||
"dependencies": {
|
||||
"@cordisjs/plugin-hmr": "workspace:*",
|
||||
"@cordisjs/plugin-include": "workspace:*",
|
||||
"@deepseek-ai/dsh-acp-demo": "workspace:*",
|
||||
"@deepseek-ai/dsh-bash-local": "workspace:*",
|
||||
"@deepseek-ai/dsh-bash-sandbox": "workspace:*",
|
||||
"@deepseek-ai/dsh-code-runtime-worker": "workspace:*",
|
||||
"@deepseek-ai/dsh-compact-basic": "workspace:*",
|
||||
"@deepseek-ai/dsh-fs-local": "workspace:*",
|
||||
"@deepseek-ai/dsh-fs-policy": "workspace:*",
|
||||
"@deepseek-ai/dsh-hooks-claude": "workspace:*",
|
||||
"@deepseek-ai/dsh-hooks-codex": "workspace:*",
|
||||
"@deepseek-ai/dsh-llm": "workspace:*",
|
||||
"@deepseek-ai/dsh-llm-deepseek": "workspace:*",
|
||||
"@deepseek-ai/dsh-llm-replay": "workspace:*",
|
||||
"@deepseek-ai/dsh-permission": "workspace:*",
|
||||
"@deepseek-ai/dsh-repeat-tool-guard": "workspace:*",
|
||||
"@deepseek-ai/dsh-sandbox-local": "workspace:*",
|
||||
"@deepseek-ai/dsh-spill-local": "workspace:*",
|
||||
"@deepseek-ai/dsh-spill-policy": "workspace:*",
|
||||
"@deepseek-ai/dsh-stdio-demo": "workspace:*",
|
||||
"@deepseek-ai/dsh-subagent": "workspace:*",
|
||||
"@deepseek-ai/dsh-subagent-fork": "workspace:*",
|
||||
"@deepseek-ai/dsh-subagent-spawn": "workspace:*",
|
||||
"@deepseek-ai/dsh-time-context": "workspace:*",
|
||||
"@deepseek-ai/dsh-timeout-policy": "workspace:*",
|
||||
"@deepseek-ai/dsh-token-meter": "workspace:*",
|
||||
"@deepseek-ai/dsh-tool-cordis": "workspace:*",
|
||||
"@deepseek-ai/dsh-tool-fs": "workspace:*",
|
||||
"@deepseek-ai/dsh-tool-fs-search": "workspace:*",
|
||||
"@deepseek-ai/dsh-tool-subagent": "workspace:*",
|
||||
"@deepseek-ai/dsh-tool-todo": "workspace:*",
|
||||
"@deepseek-ai/dsh-tool-workflow": "workspace:*",
|
||||
"@deepseek-ai/dsh-tools": "workspace:*",
|
||||
"@deepseek-ai/dsh-user-approval": "workspace:*",
|
||||
"@deepseek-ai/dsh-web": "workspace:*",
|
||||
"@deepseek-ai/dsh-web-fetch-local": "workspace:*",
|
||||
"@deepseek-ai/dsh-workflow-workerthread": "workspace:*"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user