Merge remote-tracking branch 'github/master' into xtr/session-format-migration

# Conflicts:
#	docs/config-catalog.i18n.yaml
#	docs/config-catalog.md
#	docs/config-catalog.zh.md
#	packages/session/session-persistence-jsonl/src/index.ts
#	packages/session/session-persistence/src/coordinator.ts
#	packages/session/session-persistence/src/index.ts
This commit is contained in:
_Kerman
2026-08-25 12:41:23 +08:00
2357 changed files with 46214 additions and 18025 deletions
@@ -0,0 +1,27 @@
import { spawnSync } from 'node:child_process'
import { resolve } from 'node:path'
import { describe, expect, it } from 'vitest'
const root = resolve(import.meta.dirname, '..')
const script = resolve(root, 'scripts/build-exe-for-python-sdk.ts')
describe('Python runtime executable assets', () => {
it('packages the dynamically resolved web frontend distribution', () => {
const result = spawnSync(process.execPath, [
'--import',
'tsx/esm',
script,
'--skip-build',
'--dry-run',
'--targets=node24-macos-arm64',
], {
cwd: root,
encoding: 'utf8',
env: { ...process.env, npm_execpath: 'C:\\tools\\pnpm.cjs' },
})
expect(result.status).toBe(0)
expect(result.stdout).toContain('node_modules/@deepseek-ai/dsh-web-frontend/dist/**/*')
expect(result.stdout).toContain('node_modules/@deepseek-ai/dsh-skill-badge/assets/**/*')
})
})
@@ -2,7 +2,7 @@ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { dirname, join } from 'node:path'
import { afterEach, describe, expect, it } from 'vitest'
import { resolveLinuxNodePtyAddon } from './build-exe-for-python-sdk-native-pty.ts'
import { resolveLinuxNodePtyAddon, resolveWindowsNodePtyAddons } from './build-exe-for-python-sdk-native-pty.ts'
const roots: string[] = []
@@ -35,6 +35,24 @@ describe('resolveLinuxNodePtyAddon', () => {
})
})
describe('resolveWindowsNodePtyAddons', () => {
it('requires both ConPTY addons from the x64 prebuild', () => {
const root = temporaryPackage()
const conpty = createAddon(root, 'prebuilds', 'win32-x64', 'conpty.node')
const consoleList = createAddon(root, 'prebuilds', 'win32-x64', 'conpty_console_list.node')
expect(resolveWindowsNodePtyAddons(root, 'x64')).toEqual([conpty, consoleList])
})
it('names every missing Windows addon', () => {
const root = temporaryPackage()
expect(() => resolveWindowsNodePtyAddons(root, 'x64')).toThrow(
`Windows node-pty addons are missing: ${join(root, 'prebuilds', 'win32-x64', 'conpty.node')}, ${join(root, 'prebuilds', 'win32-x64', 'conpty_console_list.node')}`,
)
})
})
function temporaryPackage(): string {
const root = mkdtempSync(join(tmpdir(), 'dsh-node-pty-addon-'))
roots.push(root)
@@ -21,3 +21,25 @@ export function resolveLinuxNodePtyAddon(
`build-exe-for-python-sdk: node-pty addon is absent from both ${built} and ${prebuilt}.`,
)
}
/**
* Require both node-pty addons used by the Windows ConPTY backend.
* @param packageDirectory - staged node-pty package directory.
* @param arch - Windows target architecture.
* @returns the existing addon paths in load order.
*/
export function resolveWindowsNodePtyAddons(
packageDirectory: string,
arch: 'x64',
): string[] {
const directory = join(packageDirectory, 'prebuilds', `win32-${arch}`)
const addons = [
join(directory, 'conpty.node'),
join(directory, 'conpty_console_list.node'),
]
const missing = addons.filter(path => !existsSync(path))
if (missing.length > 0) {
throw new Error(`build-exe-for-python-sdk: Windows node-pty addons are missing: ${missing.join(', ')}.`)
}
return addons
}
+81
View File
@@ -0,0 +1,81 @@
import { spawnSync } from 'node:child_process'
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { dirname, join, resolve } from 'node:path'
import { afterEach, describe, expect, it } from 'vitest'
const root = resolve(import.meta.dirname, '..')
const script = resolve(root, 'scripts/build-exe-for-python-sdk.ts')
const temporaryDirectories: string[] = []
afterEach(() => {
for (const directory of temporaryDirectories.splice(0)) {
rmSync(directory, { recursive: true, force: true })
}
})
function run(env: NodeJS.ProcessEnv, ...args: string[]) {
return spawnSync(process.execPath, ['--import', 'tsx/esm', script, ...args], {
cwd: root,
encoding: 'utf8',
env: isolatedPnpmEnvironment(env),
})
}
describe('Python runtime executable builder CLI', () => {
it('runs pnpm through its JavaScript entrypoint without a command shell', () => {
const result = run(
{ npm_execpath: 'C:\\tools\\pnpm.cjs' },
'--skip-build',
'--dry-run',
'--targets=node24-macos-arm64',
)
expect(result.status).toBe(0)
expect(result.stdout).toContain(`${process.execPath} C:\\tools\\pnpm.cjs run verify-runtime-closure`)
expect(result.stdout).toContain(`${process.execPath} C:\\tools\\pnpm.cjs --filter dsh-python-runtime-closure deploy`)
expect(result.stdout).toContain(`${process.execPath} C:\\tools\\pnpm.cjs dlx @yao-pkg/pkg@6.21.0`)
expect(result.stdout).not.toMatch(/pnpm\.cmd/i)
})
it('resolves the pnpm package behind a Windows command shim', () => {
const setup = mkdtempSync(join(tmpdir(), 'dsh-pnpm-home-'))
temporaryDirectories.push(setup)
const home = join(setup, 'node_modules', '.bin')
const entrypoint = join(setup, 'node_modules', 'pnpm', 'bin', 'pnpm.mjs')
mkdirSync(home, { recursive: true })
mkdirSync(dirname(entrypoint), { recursive: true })
writeFileSync(entrypoint, '')
const result = run(
{ npm_execpath: 'C:\\tools\\pnpm.cmd', PNPM_HOME: home },
'--skip-build',
'--dry-run',
'--targets=node24-macos-arm64',
)
expect(result.status).toBe(0)
expect(result.stdout).toContain(`${process.execPath} ${entrypoint} run verify-runtime-closure`)
expect(result.stdout).not.toMatch(/pnpm\.cmd/i)
})
it('rejects a Windows arm64 product before any build step', () => {
const result = run(
{ npm_execpath: 'C:\\tools\\pnpm.cjs' },
'--skip-build',
'--dry-run',
'--targets=node24-win-arm64',
)
expect(result.status).not.toBe(0)
expect(result.stderr).toContain('Windows supports x64 only')
expect(result.stdout).toBe('')
})
})
function isolatedPnpmEnvironment(overrides: NodeJS.ProcessEnv): NodeJS.ProcessEnv {
const environment = Object.fromEntries(
Object.entries(process.env).filter(([key]) => !['npm_execpath', 'pnpm_home'].includes(key.toLowerCase())),
)
return { ...environment, ...overrides }
}
+91 -28
View File
@@ -1,5 +1,5 @@
/**
* Build the SDK runtime executables and Python node carrier. The fixed
* Build the dsh executables and development Node carrier for the Python runtime wheel. The fixed
* `@yao-pkg/pkg --sea` route, deploy flags, and artifact layout are owned by
* .agents/notes/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.md.
* The staged closure is symlink-free, and whole-tree assets cover Cordis's
@@ -9,18 +9,18 @@
import { spawn } from 'node:child_process'
import { existsSync, statSync } from 'node:fs'
import { chmod, copyFile, cp, lstat, mkdir, readFile, readdir, realpath, rm, writeFile } from 'node:fs/promises'
import { basename, dirname, join, resolve, sep } from 'node:path'
import { basename, dirname, extname, join, resolve, sep } from 'node:path'
import { parseArgs } from 'node:util'
import { resolveLinuxNodePtyAddon } from './build-exe-for-python-sdk-native-pty.ts'
import { resolveLinuxNodePtyAddon, resolveWindowsNodePtyAddons } from './build-exe-for-python-sdk-native-pty.ts'
const root = resolve(import.meta.dirname, '..')
/** The closure manifest whose dependencies define the executable. */
const DEPLOY_ROOT_PACKAGE = 'dsh-sdk-python-runtime-closure'
/** The closed-runtime app entry inside the deployed closure. */
const ENTRY_BIN = 'node_modules/@deepseek-ai/dsh-sdk-python-runtime/lib/packaged-bin.js'
/** Stable Python-visible executable basename; rename with the later Python runtime migration. */
const OUTPUT_BASENAME = 'dsh-jsonrpc-agent-pkg'
const DEPLOY_ROOT_PACKAGE = 'dsh-python-runtime-closure'
/** The sole application launcher inside the deployed closure. */
const ENTRY_BIN = 'node_modules/@deepseek-ai/dsh/lib/bin.js'
/** Python-visible executable basename. */
const OUTPUT_BASENAME = 'deepseek-harness-sdk-runtime'
/** Default Node major; SEA mode requires at least Node 22. */
const DEFAULT_NODE_RANGE = 'node24'
/** Pinned for reproducible builds. */
@@ -47,11 +47,23 @@ const ASSET_GLOBS = [
'node_modules/**/*.mjs',
'node_modules/**/package.json',
'node_modules/**/*.json',
// Package-owned Markdown includes runtime skill instructions and badge content.
'node_modules/**/*.md',
'node_modules/**/*.dylib',
'node_modules/**/*.dll',
'node_modules/**/*.node',
'node_modules/**/*.so',
'node_modules/**/*.so.*',
'node_modules/**/*.wasm',
'node_modules/**/*.yaml',
'node_modules/**/*.yml',
// web-app builds this path dynamically, so pkg cannot discover the static frontend.
'node_modules/@deepseek-ai/dsh-web-frontend/dist/**/*',
// skill-badge resolves both Markdown and image resources through import.meta.url.
'node_modules/@deepseek-ai/dsh-skill-badge/assets/**/*',
]
const PLATFORMS = ['linux', 'macos'] as const
const PLATFORMS = ['linux', 'macos', 'win'] as const
const ARCHES = ['x64', 'arm64'] as const
type Platform = (typeof PLATFORMS)[number]
type Arch = (typeof ARCHES)[number]
@@ -71,10 +83,7 @@ class Target {
private constructor(
/** pkg Node range (`node<major>`). */
readonly nodeRange: string,
/**
* pkg platform tag. Windows is a documented non-goal
* (.agents/notes/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.md).
*/
/** pkg platform tag. */
readonly platform: Platform,
/** pkg CPU tag. */
readonly arch: Arch,
@@ -105,6 +114,9 @@ class Target {
if (!isArch(arch)) {
throw new Error(`build-exe-for-python-sdk: target ${JSON.stringify(spec)}: arch must be one of ${ARCHES.join(', ')}, got ${JSON.stringify(arch)}.`)
}
if (platform === 'win' && arch !== 'x64') {
throw new Error(`build-exe-for-python-sdk: target ${JSON.stringify(spec)}: Windows supports x64 only.`)
}
return new Target(nodeRange, platform, arch)
}
@@ -113,7 +125,13 @@ class Target {
* @returns the host target; throws on an unsupported host platform or arch.
*/
static host(): Target {
const platform = process.platform === 'darwin' ? 'macos' : process.platform === 'linux' ? 'linux' : undefined
const platform = process.platform === 'darwin'
? 'macos'
: process.platform === 'linux'
? 'linux'
: process.platform === 'win32'
? 'win'
: undefined
if (platform === undefined) {
throw new Error(`build-exe-for-python-sdk: unsupported host platform ${process.platform}; pass --targets explicitly.`)
}
@@ -121,6 +139,9 @@ class Target {
if (arch === undefined) {
throw new Error(`build-exe-for-python-sdk: unsupported host arch ${process.arch}; pass --targets explicitly.`)
}
if (platform === 'win' && arch !== 'x64') {
throw new Error('build-exe-for-python-sdk: Windows supports x64 only; use an x64 Node process.')
}
return new Target(DEFAULT_NODE_RANGE, platform, arch)
}
}
@@ -188,7 +209,7 @@ class BuildCli {
return [
'Usage: pnpm exec tsx scripts/build-exe-for-python-sdk.ts [flags]',
'',
' --targets=<t1,t2,...> pkg targets, e.g. node24-linux-x64,node24-linux-arm64,node24-macos-arm64.',
' --targets=<t1,t2,...> pkg targets, e.g. node24-linux-x64,node24-linux-arm64,node24-macos-arm64,node24-win-x64.',
' Default: the host platform only (on node24).',
' --skip-build skip `pnpm run build` (lib/ artifacts must already exist).',
' --dry-run print every command and config patch without executing.',
@@ -200,8 +221,27 @@ class BuildCli {
}
}
function pnpmBin(): string {
return process.platform === 'win32' ? 'pnpm.cmd' : 'pnpm'
function pnpmInvocation(args: string[]): [command: string, args: string[]] {
const entrypoint = process.env.npm_execpath?.trim()
if (entrypoint !== undefined && entrypoint !== '') {
const extension = extname(entrypoint).toLowerCase()
if (extension === '.js' || extension === '.cjs' || extension === '.mjs') {
return [process.execPath, [entrypoint, ...args]]
}
if (extension !== '.cmd') return [entrypoint, args]
}
const home = process.env.PNPM_HOME?.trim()
if (home !== undefined && home !== '') {
const packageBin = resolve(home, '..', 'pnpm', 'bin')
for (const filename of ['pnpm.mjs', 'pnpm.cjs']) {
const candidate = resolve(packageBin, filename)
if (existsSync(candidate)) return [process.execPath, [candidate, ...args]]
}
}
if (process.platform === 'win32') {
throw new Error('build-exe-for-python-sdk: pnpm must expose a JavaScript entrypoint through npm_execpath or PNPM_HOME on Windows.')
}
return ['pnpm', args]
}
/**
@@ -220,8 +260,7 @@ function formatCommand(command: string, args: string[]): string {
*/
class SingleExeBuild {
/**
* The cleared deploy target, pkg input, and Python node-mode carrier. The
* checked-in default `cordis.yml` remains in its parent directory.
* The cleared deploy target, pkg input, and Python node-mode carrier.
*/
readonly staging = resolve(root, PYTHON_RUNTIME_DIR, PYTHON_NODE_SUBDIR)
private readonly outDir = resolve(root, OUT_DIR)
@@ -230,7 +269,7 @@ class SingleExeBuild {
/** Verify the closure before compiling or packaging. */
async verifyClosure(): Promise<void> {
await this.run('runtime dependency closure', pnpmBin(), ['run', 'verify-runtime-closure'])
await this.runPnpm('runtime dependency closure', ['run', 'verify-runtime-closure'])
}
/** Build all package artifacts unless `--skip-build` was passed. */
@@ -239,7 +278,7 @@ class SingleExeBuild {
console.log('build-exe-for-python-sdk: skipping pnpm run build (--skip-build)')
return
}
await this.run('build', pnpmBin(), ['run', 'build'])
await this.runPnpm('build', ['run', 'build'])
}
/** Clear and deploy the runtime closure into the node carrier. */
@@ -249,7 +288,7 @@ class SingleExeBuild {
}
if (this.cli.dryRun) console.log(`build-exe-for-python-sdk: [dry-run] rm -rf ${this.staging}`)
else await rm(this.staging, { recursive: true, force: true })
await this.run('deploy', pnpmBin(), [
await this.runPnpm('deploy', [
'--filter',
DEPLOY_ROOT_PACKAGE,
'deploy',
@@ -382,10 +421,11 @@ class SingleExeBuild {
* @returns the executable and ripgrep sidecar paths, plus the macOS spawn helper path when required.
*/
async pack(target: Target): Promise<string[]> {
const product = join(this.outDir, `${OUTPUT_BASENAME}-${target.platform}-${target.arch}`)
const productBase = join(this.outDir, `${OUTPUT_BASENAME}-${target.platform}-${target.arch}`)
const product = target.platform === 'win' ? `${productBase}.exe` : productBase
await this.prepareNativePty(target)
if (!this.cli.dryRun) await mkdir(this.outDir, { recursive: true })
await this.run(`pkg ${target.spec}`, pnpmBin(), [
await this.runPnpm(`pkg ${target.spec}`, [
'dlx',
PKG_SPEC,
this.staging,
@@ -413,16 +453,19 @@ class SingleExeBuild {
/** Copy the target ripgrep binary beside the executable so Node can spawn it outside pkg's virtual filesystem. */
private async copyRipgrepSidecar(target: Target, product: string): Promise<string> {
const platform = target.platform === 'macos' ? 'darwin' : target.platform
const platform = target.platform === 'macos' ? 'darwin' : target.platform === 'win' ? 'win32' : target.platform
const executable = target.platform === 'win' ? 'rg.exe' : 'rg'
const source = join(
this.staging,
'node_modules',
'@vscode',
`ripgrep-${platform}-${target.arch}`,
'bin',
'rg',
executable,
)
const destination = `${product}-rg`
const destination = target.platform === 'win'
? `${product.slice(0, -'.exe'.length)}-rg.exe`
: `${product}-rg`
if (this.cli.dryRun) {
console.log(`build-exe-for-python-sdk: [dry-run] cp ${source} ${destination}`)
return destination
@@ -444,7 +487,6 @@ class SingleExeBuild {
const stagedBuild = join(this.staging, 'node_modules', 'node-pty', 'build')
if (this.cli.dryRun) console.log(`build-exe-for-python-sdk: [dry-run] rm -rf ${stagedBuild}`)
else await rm(stagedBuild, { recursive: true, force: true })
if (target.platform !== 'linux') return
const packageDirectory = join(
root,
'packages',
@@ -453,6 +495,21 @@ class SingleExeBuild {
'node_modules',
'node-pty',
)
if (target.platform === 'win') {
if (target.arch !== 'x64') {
throw new Error('build-exe-for-python-sdk: Windows supports x64 only.')
}
const host = Target.host()
if (target.platform !== host.platform || target.arch !== host.arch) {
throw new Error(
'build-exe-for-python-sdk: build the Windows runtime under x64 Node on its target host; '
+ `target ${target.platform}-${target.arch} does not match host ${host.platform}-${host.arch}.`,
)
}
resolveWindowsNodePtyAddons(join(this.staging, 'node_modules', 'node-pty'), target.arch)
return
}
if (target.platform !== 'linux') return
const destination = join(stagedBuild, 'Release', 'pty.node')
const source = resolveLinuxNodePtyAddon(packageDirectory, target.arch)
if (this.cli.dryRun) {
@@ -542,6 +599,12 @@ class SingleExeBuild {
})
})
}
/** Run pnpm through its JavaScript entrypoint when the caller supplies one. */
private async runPnpm(label: string, args: string[]): Promise<void> {
const [command, invocationArgs] = pnpmInvocation(args)
await this.run(label, command, invocationArgs)
}
}
async function main(): Promise<void> {
+17 -9
View File
@@ -47,9 +47,12 @@ def load_platforms(path: Path = PLATFORM_MANIFEST) -> dict[str, tuple[str, str]]
PLATFORMS = load_platforms()
def runtime_suffixes(executable_name: str) -> tuple[str, ...]:
suffixes = ("", "-rg")
return (*suffixes, "-spawn-helper") if "-macos-" in executable_name else suffixes
def runtime_filenames(executable_name: str) -> tuple[str, ...]:
"""Return the exact platform payload names for one runtime executable."""
if executable_name.endswith(".exe"):
return (executable_name, f"{executable_name.removesuffix('.exe')}-rg.exe")
names = (executable_name, f"{executable_name}-rg")
return (*names, f"{executable_name}-spawn-helper") if "-macos-" in executable_name else names
def main() -> None:
@@ -150,7 +153,7 @@ def copy_package(source: Path, destination: Path) -> None:
"*.pyc",
"dist",
"node_modules",
"dsh-jsonrpc-agent-pkg-*",
"deepseek-harness-sdk-runtime-*",
),
)
@@ -205,13 +208,18 @@ def stage_sdk(destination: Path, version: str) -> None:
def stage_runtime(destination: Path, version: str, executable: Path, executable_name: str) -> None:
if executable.name != executable_name:
raise ValueError(
f"runtime executable must be named {executable_name}, got {executable.name}"
)
copy_package(ROOT / "python" / "sdk-runtime", destination)
stage_license_files(destination, include_notices=True)
rewrite_version(destination / "pyproject.toml", version)
runtime_dir = destination / "src" / "deepseek_harness_runtime" / "runtime"
runtime_dir.mkdir(parents=True, exist_ok=True)
for suffix in runtime_suffixes(executable_name):
shutil.copy2(Path(f"{executable}{suffix}"), runtime_dir / f"{executable_name}{suffix}")
source_directory = executable.parent
for filename in runtime_filenames(executable_name):
shutil.copy2(source_directory / filename, runtime_dir / filename)
def verify_wheel(
@@ -246,17 +254,17 @@ def verify_wheel(
f"{wheel} has license files {license_files}, expected {expected_license_files}"
)
runtime_files = [
name for name in archive.namelist() if "/runtime/dsh-jsonrpc-agent-pkg-" in name
name for name in archive.namelist() if "/runtime/deepseek-harness-sdk-runtime-" in name
]
if package == "runtime":
assert platform is not None
expected_files = [f"{platform[1]}{suffix}" for suffix in runtime_suffixes(platform[1])]
expected_files = sorted(runtime_filenames(platform[1]))
found_files = sorted(Path(name).name for name in runtime_files)
if found_files != expected_files:
raise RuntimeError(f"{wheel} runtime payload must be {expected_files}, found {found_files}")
for runtime_file in runtime_files:
mode = archive.getinfo(runtime_file).external_attr >> 16
if mode & stat.S_IXUSR == 0:
if platform[0] != "win_amd64" and mode & stat.S_IXUSR == 0:
raise RuntimeError(f"{wheel} runtime executable lost its executable bit: {runtime_file}")
elif runtime_files:
raise RuntimeError(f"SDK wheel unexpectedly contains runtime executables: {runtime_files}")
+6 -7
View File
@@ -6,8 +6,9 @@ import { resolve } from 'node:path'
import { parseArgs } from 'node:util'
import {
CLIENT_BUILD_RECORD_PATH,
CLIENT_BUILD_PROFILE_SELECTOR,
clientBuildProcessEnvironment,
repositoryCommitHash,
repositoryClientBuildEnvironment,
resolveClientBuildEnvironment,
writeClientBuildRecord,
} from './client-build-environment.ts'
@@ -34,12 +35,10 @@ function main(): void {
allowPositionals: false,
})
const root = resolve(import.meta.dirname, '..')
const parentEnvironment = {
...process.env,
DSH_CLIENT_COMMIT_HASH: repositoryCommitHash(root, process.env),
}
const clientEnvironment = resolveClientBuildEnvironment(parentEnvironment, values.profile)
const buildEnvironment = clientBuildProcessEnvironment(parentEnvironment, clientEnvironment)
const repositoryEnvironment = repositoryClientBuildEnvironment(root, process.env)
const profile = values.profile ?? process.env[CLIENT_BUILD_PROFILE_SELECTOR]
const clientEnvironment = resolveClientBuildEnvironment(repositoryEnvironment, profile)
const buildEnvironment = clientBuildProcessEnvironment(process.env, clientEnvironment)
rmSync(resolve(root, CLIENT_BUILD_RECORD_PATH), { force: true })
runScript('build:lib', buildEnvironment)
@@ -1,12 +1,9 @@
/** Experimental-package publication and dependency constraints. */
import { readFileSync } from 'node:fs'
import { join } from 'node:path'
import { describe, expect, it } from 'vitest'
import {
checkExperimentalDependencyIsolation,
checkExperimentalManifest,
checkWorkspaceManifest,
type WorkspaceManifest,
} from './check-workspace-constraints.ts'
@@ -77,24 +74,3 @@ describe('experimental workspace constraints', () => {
])
})
})
describe('private Python runtime carrier', () => {
const manifest = JSON.parse(
readFileSync(new URL('../packages/sdk/python-runtime/package.json', import.meta.url), 'utf8'),
) as WorkspaceManifest['manifest']
it('participates in dsh package checks without becoming an npm release member', () => {
expect(checkWorkspaceManifest({ dir: 'packages/sdk/python-runtime', manifest })).toEqual([])
})
it('rejects publication metadata on the private carrier', () => {
const path = join('packages', 'sdk', 'python-runtime', 'package.json')
expect(checkWorkspaceManifest({
dir: 'packages/sdk/python-runtime',
manifest: { ...manifest, private: false, publishConfig: { access: 'public' } },
})).toEqual([
`${path}: @deepseek-ai/dsh-sdk-python-runtime: private carrier must set "private": true`,
`${path}: @deepseek-ai/dsh-sdk-python-runtime: private carrier must omit publishConfig`,
])
})
})
+6 -13
View File
@@ -54,12 +54,9 @@ const experimentalPackageDirectory = /^packages\/experimental\/[^/]+$/
const experimentalPackageNamePrefix = '@deepseek-ai/dsh-experimental-'
/** Directories whose packages this repository publishes: one release member each. */
const releaseMemberDirectory = /^(?:packages\/(?!experimental\/)[^/]+\/[^/]+|apps\/[^/]+|vendor\/[^/]+)$/
/** Named dsh packages that remain private because another distribution embeds them. */
const privateCarrierDirectories = new Set(['packages/sdk/python-runtime'])
const localArtifactDirs = new Set(['node_modules'])
const appPackageFiles: Readonly<Record<string, readonly string[]>> = {
'@deepseek-ai/dsh': ['lib/*.js', 'config'],
'@deepseek-ai/dsh': ['lib/*.js'],
// Sourcemaps stay out by payload policy; the worker-preview surface
// (dist/preview.html and dist/preview/) backs private experimental
// packages and is not published.
@@ -154,8 +151,11 @@ const packageFileExtras: Readonly<Record<string, readonly string[]>> = {
'@deepseek-ai/dsh-client-ui-theme': ['lib/styles'],
// The CPython side ships as source .py files, published as-is rather than built.
'@deepseek-ai/dsh-code-runtime-python': ['py/**/*.py'],
// The private Python carrier ships only its closed-resolution entry.
'@deepseek-ai/dsh-sdk-python-runtime': ['lib/packaged-bin.js'],
// The shipped preset compositions travel inside the roster package.
'@deepseek-ai/dsh-agent-presets': ['presets'],
// The Web Host mounts the default-off settings owner independently of each
// Agent-scoped delegation-tool instance.
'@deepseek-ai/dsh-tool-subagent': ['lib/model-selection-settings.js'],
// The argv-prefix runner entry ships beside the lib as its own bundle;
// sandbox-local resolves it through the package's ./runner export. tsdown
// also shares its generated FFI code through a hashed runtime chunk.
@@ -290,13 +290,6 @@ export function checkWorkspaceManifest({ dir, manifest }: WorkspaceManifest): st
|| manifest.repository.directory !== expectedDirectory) {
errors.push(`${label}: published Landlock package repository must use ${repositoryUrl} with directory ${expectedDirectory} for trusted publishing`)
}
} else if (privateCarrierDirectories.has(dir)) {
if (manifest.private !== true) {
errors.push(`${label}: private carrier must set "private": true`)
}
if (manifest.publishConfig !== undefined) {
errors.push(`${label}: private carrier must omit publishConfig`)
}
} else if (releaseMemberDirectory.test(dir)) {
// Release members state that they are publishable: npm refuses a private
// package, and the repository field is how a consumer finds the source of
+60 -28
View File
@@ -36,7 +36,7 @@ describe('CI workflow', () => {
}
})
it('keeps required Wine and native Windows jobs with failover, plus a master-only standby', () => {
it('keeps a required Wine Windows job, a non-blocking native Windows job with failover, and a master-only standby', () => {
const workflow = loadWorkflow('.github/workflows/ci.yml')
const masterWorkflow = loadWorkflow('.github/workflows/ci-master.yml')
if (!isRecord(workflow.jobs)
@@ -73,7 +73,7 @@ describe('CI workflow', () => {
expect(windows.if).toBe("github.event_name == 'pull_request'")
expect(commandSteps.some(step => step.run.includes('wine-windows-gates.sh'))).toBe(true)
// windows-native: blocking native job with failover, runs windows-complete.
// windows-native: non-blocking native job with failover, runs windows-complete.
// Its pool is resolved by the Windows-specific switch.
expect(typeof windowsNative['runs-on']).toBe('string')
expect(windowsNative['runs-on']).toContain('DSH_CI_FAILOVER_WINDOWS')
@@ -84,10 +84,7 @@ describe('CI workflow', () => {
expect(windowsNative.name).toBe('windows node 24 / native complete')
expect(windowsNative.if).toBe("github.event_name == 'pull_request'")
expect(windowsNative.env).toMatchObject({
DSH_COVERAGE_MAX_WORKERS: '12',
DSH_COVERAGE_PARTITIONS: '16',
DSH_COVERAGE_TEST_TIMEOUT_MS: '30000',
DSH_GATE_CONCURRENCY: '8',
})
const nativeSteps = windowsNative.steps as unknown[]
const nativeCommandSteps = nativeSteps.filter((step): step is Record<string, unknown> & { run: string } => (
@@ -104,9 +101,9 @@ describe('CI workflow', () => {
expect(serialWindows['runs-on']).toEqual(['self-hosted', 'dsh-win-ci', 'windows'])
expect(serialWindows.name).toBe('serial / windows (self-hosted standby)')
// Aggregate: both complementary Windows jobs are required.
// Aggregate: Wine `windows` required, native `windows-native` excluded.
expect(aggregate.needs).toContain('windows')
expect(aggregate.needs).toContain('windows-native')
expect(aggregate.needs).not.toContain('windows-native')
expect(aggregate.needs).not.toContain('serial-windows')
// Linux failover is a separate switch: the three required Linux workers
@@ -231,7 +228,7 @@ describe('CI workflow', () => {
name: 'python runtime / release-shaped matrix',
uses: './.github/workflows/build-exe-for-python-sdk.yml',
with: {
targets: 'node24-linux-x64,node24-linux-arm64,node24-macos-arm64',
targets: 'node24-linux-x64,node24-linux-arm64,node24-macos-arm64,node24-win-x64',
ci: true,
},
secrets: {
@@ -323,7 +320,7 @@ describe('Python release workflows', () => {
expect(build).toMatchObject({
uses: './.github/workflows/build-exe-for-python-sdk.yml',
with: {
targets: 'node24-linux-x64,node24-linux-arm64,node24-macos-arm64',
targets: 'node24-linux-x64,node24-linux-arm64,node24-macos-arm64,node24-win-x64',
release: true,
},
})
@@ -393,11 +390,19 @@ describe('Python release workflows', () => {
const manylinuxAddon = buildSteps.find(step => isRecord(step) && step.name === 'Rebuild Linux node-pty against manylinux 2.28')
const macosCheck = buildSteps.find(step => isRecord(step) && step.name === 'Check macOS deployment target')
const manylinuxSmoke = buildSteps.find(step => isRecord(step) && step.name === 'Run wheel in a manylinux 2.28 container')
const installedKeyless = buildSteps.find(step => isRecord(step) && step.name === 'Run installed-wheel keyless black-box tests')
const realApiPreflight = buildSteps.find(step => isRecord(step) && step.name === 'Preflight installed-wheel real API test')
const installedRealApi = buildSteps.find(step => isRecord(step) && step.name === 'Run installed-wheel real API black-box test')
if (!isRecord(installedKeyless) || !isRecord(realApiPreflight) || !isRecord(installedRealApi)) {
throw new TypeError('Python wheel builder must define installed-wheel keyless and real API steps')
const cleanVenvPosix = buildSteps.find(step => isRecord(step) && step.name === 'Install local SDK and runtime wheels into a clean venv (POSIX)')
const cleanVenvWindows = buildSteps.find(step => isRecord(step) && step.name === 'Install local SDK and runtime wheels into a clean venv (Windows)')
const installedKeylessPosix = buildSteps.find(step => isRecord(step) && step.name === 'Run installed-wheel keyless black-box tests (POSIX)')
const installedKeylessWindows = buildSteps.find(step => isRecord(step) && step.name === 'Run installed-wheel keyless black-box tests (Windows)')
const realApiPreflightPosix = buildSteps.find(step => isRecord(step) && step.name === 'Preflight installed-wheel real API test (POSIX)')
const realApiPreflightWindows = buildSteps.find(step => isRecord(step) && step.name === 'Preflight installed-wheel real API test (Windows)')
const installedRealApiPosix = buildSteps.find(step => isRecord(step) && step.name === 'Run installed-wheel real API black-box test (POSIX)')
const installedRealApiWindows = buildSteps.find(step => isRecord(step) && step.name === 'Run installed-wheel real API black-box test (Windows)')
if (!isRecord(cleanVenvPosix) || !isRecord(cleanVenvWindows)
|| !isRecord(installedKeylessPosix) || !isRecord(installedKeylessWindows)
|| !isRecord(realApiPreflightPosix) || !isRecord(realApiPreflightWindows)
|| !isRecord(installedRealApiPosix) || !isRecord(installedRealApiWindows)) {
throw new TypeError('Python wheel builder must define native POSIX and Windows installed-wheel steps')
}
expect(call.inputs).toHaveProperty('targets')
expect(call.inputs).toMatchObject({
@@ -410,47 +415,56 @@ describe('Python release workflows', () => {
expect(workflow.concurrency).toMatchObject({
group: 'build-single-exe-${{ github.workflow }}-${{ github.ref }}',
})
expect(build.defaults).toBeUndefined()
expect(plan.if).toContain('inputs.ci')
expect(plan.if).toContain('inputs.release')
expect(JSON.stringify(plan.steps)).toContain('pep440_version')
const workflowJson = JSON.stringify(workflow)
expect(workflowJson).toContain('macosx_14_0_arm64')
expect(workflowJson).toContain('win_amd64')
expect(workflowJson).toContain('node24-win-x64')
expect(workflowJson).toContain('windows-2025')
expect(workflowJson).toContain('dist-python/$SDK_WHEEL')
expect(workflowJson).toContain('dist-python/$RUNTIME_WHEEL')
expect(workflowJson).toContain('/work/dist-python/$SDK_WHEEL')
expect(workflowJson).toContain('/work/dist-python/$RUNTIME_WHEEL')
expect(workflowJson).not.toContain('--find-links dist-python')
expect(workflowJson).not.toContain('--find-links /work/dist-python')
expect(workflowJson).not.toContain('cygpath')
expect(manylinuxAddon).toMatchObject({ if: "runner.os == 'Linux'" })
expect(JSON.stringify(manylinuxAddon)).toContain('manylinux_2_28_x86_64')
expect(JSON.stringify(manylinuxAddon)).toContain('manylinux_2_28_aarch64')
expect(JSON.stringify(manylinuxAddon)).toContain('npm_config_build_from_source=true pnpm run install')
expect(JSON.stringify(manylinuxAddon)).toContain('$HOME/setup-pnpm:$HOME/setup-pnpm:ro')
expect(JSON.stringify(manylinuxAddon)).toContain('pnpm_setup_root')
expect(JSON.stringify(manylinuxAddon)).toContain('$pnpm_setup_root:$pnpm_setup_root:ro')
expect(JSON.stringify(manylinuxAddon)).toContain('node-pty-glibc-versions.txt')
expect(JSON.stringify(manylinuxAddon)).toContain('le 2.28')
expect(macosCheck).toMatchObject({ if: "runner.os == 'macOS'" })
expect(JSON.stringify(macosCheck)).toContain('scripts/check-macos-deployment-target.py')
expect(JSON.stringify(macosCheck)).toContain('$EXE-spawn-helper')
expect(JSON.stringify(installedKeyless)).toContain('--scenario all')
expect(JSON.stringify(installedKeyless)).toContain('--installed-wheel')
expect(JSON.stringify(installedKeyless)).toContain('env -u PYTHONPATH')
expect(JSON.stringify(installedKeyless)).toContain('-u DSH_RUNTIME_MODE')
expect(realApiPreflight).toMatchObject({
expect(JSON.stringify(installedKeylessPosix)).toContain('--scenario all')
expect(JSON.stringify(installedKeylessPosix)).toContain('env -u PYTHONPATH')
expect(JSON.stringify(installedKeylessWindows)).toContain('--scenario all --installed-wheel')
expect(installedKeylessWindows).toMatchObject({ if: "runner.os == 'Windows'", shell: 'pwsh' })
expect(cleanVenvWindows).toMatchObject({ if: "runner.os == 'Windows'", shell: 'pwsh' })
expect(JSON.stringify(cleanVenvWindows)).toContain('Scripts\\\\python.exe')
expect(realApiPreflightPosix).toMatchObject({
env: { DEEPSEEK_API_KEY: '${{ secrets.DEEPSEEK_API_KEY_EXTERNAL }}' },
})
expect(String(realApiPreflight.if)).toContain('inputs.ci')
expect(String(realApiPreflight.if)).toContain('head.repo.fork')
expect(String(realApiPreflight.if)).toContain('dependabot[bot]')
expect(installedRealApi).toMatchObject({
expect(String(realApiPreflightPosix.if)).toContain('inputs.ci')
expect(String(realApiPreflightPosix.if)).toContain('head.repo.fork')
expect(String(realApiPreflightPosix.if)).toContain('dependabot[bot]')
expect(realApiPreflightWindows).toMatchObject({ shell: 'pwsh' })
expect(installedRealApiPosix).toMatchObject({
env: {
DEEPSEEK_API_KEY: '${{ secrets.DEEPSEEK_API_KEY_EXTERNAL }}',
DEEPSEEK_BASE_URL: 'https://api.deepseek.com',
},
})
expect(installedRealApi.if).toBe(realApiPreflight.if)
expect(JSON.stringify(installedRealApi)).toContain('--scenario sdk-live')
expect(JSON.stringify(installedRealApi)).toContain('--installed-wheel')
expect(JSON.stringify(installedRealApi)).toContain('-u DSH_RUNTIME_MODE')
expect(JSON.stringify(installedRealApiPosix)).toContain('--scenario sdk-live')
expect(JSON.stringify(installedRealApiPosix)).toContain('-u DSH_RUNTIME_MODE')
expect(installedRealApiWindows).toMatchObject({ shell: 'pwsh' })
expect(JSON.stringify(installedRealApiWindows)).toContain('--scenario sdk-live --installed-wheel')
expect(manylinuxSmoke).toMatchObject({ if: "runner.os == 'Linux'" })
expect(JSON.stringify(manylinuxSmoke)).toContain('-e DSH_TELEMETRY_DISABLED')
})
@@ -472,6 +486,24 @@ describe('Python release workflows', () => {
expect(macosCheck).toContain('scripts/check-macos-deployment-target.py')
expect(macosCheck).toContain('"$EXE" "$EXE-spawn-helper"')
})
it('builds and black-box tests the Windows x64 wheel in GitLab', () => {
const workflow = loadWorkflow('.gitlab-ci.yml')
const windows = workflow['runtime-windows-x64']
const publish = workflow['publish-python']
if (!isRecord(windows) || !Array.isArray(windows.before_script) || !Array.isArray(windows.script)
|| !isRecord(publish) || !Array.isArray(publish.needs)) {
throw new TypeError('GitLab CI must define the Windows runtime and aggregate publication jobs')
}
expect(windows.tags).toEqual(['windows-x64'])
expect(windows.variables).toMatchObject({ PKG_TARGET: 'node24-win-x64', PLATFORM: 'win-x64' })
expect(JSON.stringify(windows.before_script)).toContain('.ci-python\\\\Scripts')
expect(JSON.stringify(windows.before_script)).toContain('[IO.Path]::PathSeparator')
expect(JSON.stringify(windows.script)).toContain('win_amd64.whl')
expect(JSON.stringify(windows.script)).toContain('--scenario all --installed-wheel')
expect(publish.needs).toContainEqual({ job: 'runtime-windows-x64', artifacts: true })
})
})
describe('Issue lifecycle workflow', () => {
@@ -1,3 +1,4 @@
import { execFileSync } from 'node:child_process'
import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { dirname, join, resolve } from 'node:path'
@@ -7,8 +8,12 @@ import {
assertClientBuildEnvironment,
clientBuildEnvironmentDefines,
clientBuildProcessEnvironment,
officialClientBuildEnvironment,
readClientBuildRecord,
repositoryClientBuildEnvironment,
repositoryCommitHash,
repositoryGitDirty,
repositoryVersion,
resolveClientBuildEnvironment,
writeClientBuildRecord,
} from './client-build-environment.ts'
@@ -51,12 +56,34 @@ function buildFixture(environment: Record<string, string>): string {
return fixtureRoot
}
function git(root: string, args: readonly string[]): string {
return execFileSync('git', [...args], {
cwd: root,
encoding: 'utf8',
stdio: ['ignore', 'pipe', 'pipe'],
}).trim()
}
function repositoryFixture(version = '1.2.3-rc.4'): string {
const fixtureRoot = mkdtempSync(join(tmpdir(), 'dsh-client-build-repository-'))
roots.push(fixtureRoot)
write(join(fixtureRoot, 'package.json'), `${JSON.stringify({ version })}\n`)
write(join(fixtureRoot, 'tracked.txt'), 'committed\n')
git(fixtureRoot, ['init'])
git(fixtureRoot, ['config', 'user.name', 'DSH test'])
git(fixtureRoot, ['config', 'user.email', 'dsh-test@example.invalid'])
git(fixtureRoot, ['add', 'package.json', 'tracked.txt'])
git(fixtureRoot, ['commit', '-m', 'fixture'])
return fixtureRoot
}
describe('client build environment', () => {
it('requires an exact public environment for a named artifact profile', () => {
const expected = {
DSH_CLIENT_BUILD_PROFILE: 'official',
DSH_CLIENT_COMMIT_HASH: COMMIT_HASH.slice(0, 7),
DSH_CLIENT_TITLE: 'DeepSeek Harness',
DSH_CLIENT_VERSION: '1.2.3',
} as const
expect(() => { assertClientBuildEnvironment({ PATH: '/bin', ...expected }, expected) }).not.toThrow()
@@ -73,7 +100,9 @@ describe('client build environment', () => {
DSH_BUILD_CLIENT_PROFILE: 'official',
DSH_CLIENT_BUILD_PROFILE: 'local',
DSH_CLIENT_COMMIT_HASH: COMMIT_HASH.slice(0, 7),
DSH_CLIENT_GIT_DIRTY: 'true',
DSH_CLIENT_TITLE: 'Local title',
DSH_CLIENT_VERSION: '1.2.3',
DSH_CLIENT_EXTRA: 'local-extra',
}
@@ -84,24 +113,108 @@ describe('client build environment', () => {
DSH_CLIENT_BUILD_PROFILE: 'official',
DSH_CLIENT_COMMIT_HASH: COMMIT_HASH.slice(0, 7),
DSH_CLIENT_TITLE: 'DeepSeek Harness',
DSH_CLIENT_VERSION: '1.2.3',
})
expect(() => {
resolveClientBuildEnvironment({ DSH_BUILD_CLIENT_PROFILE: 'official' })
}).toThrow(/DSH_CLIENT_COMMIT_HASH/)
expect(() => {
resolveClientBuildEnvironment({
DSH_BUILD_CLIENT_PROFILE: 'official',
DSH_CLIENT_COMMIT_HASH: COMMIT_HASH.slice(0, 7),
})
}).toThrow(/DSH_CLIENT_VERSION/)
expect(() => { resolveClientBuildEnvironment({}, 'unknown') }).toThrow(/unknown client build profile/)
expect(clientBuildProcessEnvironment(parent, {
DSH_CLIENT_BUILD_PROFILE: 'official',
DSH_CLIENT_COMMIT_HASH: COMMIT_HASH.slice(0, 7),
DSH_CLIENT_TITLE: 'DeepSeek Harness',
DSH_CLIENT_VERSION: '1.2.3',
})).toEqual({
PATH: '/bin',
DSH_CLIENT_BUILD_PROFILE: 'official',
DSH_CLIENT_COMMIT_HASH: COMMIT_HASH.slice(0, 7),
DSH_CLIENT_TITLE: 'DeepSeek Harness',
DSH_CLIENT_VERSION: '1.2.3',
})
expect(repositoryCommitHash('/unused', { DSH_CLIENT_COMMIT_HASH: COMMIT_HASH })).toBe(COMMIT_HASH.slice(0, 7))
})
it('owns repository version, commit, and dirty metadata for complete builds', () => {
const fixtureRoot = repositoryFixture()
const commit = git(fixtureRoot, ['rev-parse', '--short=7', 'HEAD'])
expect(repositoryVersion(fixtureRoot)).toBe('1.2.3-rc.4')
expect(repositoryGitDirty(fixtureRoot)).toBe(false)
expect(repositoryClientBuildEnvironment(fixtureRoot, {
DSH_CLIENT_COMMIT_HASH: COMMIT_HASH,
DSH_CLIENT_EXTRA: 'preserved',
DSH_CLIENT_GIT_DIRTY: 'true',
DSH_CLIENT_VERSION: 'spoofed',
})).toEqual({
DSH_CLIENT_COMMIT_HASH: COMMIT_HASH.slice(0, 7),
DSH_CLIENT_EXTRA: 'preserved',
DSH_CLIENT_VERSION: '1.2.3-rc.4',
})
expect(officialClientBuildEnvironment(fixtureRoot)).toEqual({
DSH_CLIENT_BUILD_PROFILE: 'official',
DSH_CLIENT_COMMIT_HASH: commit,
DSH_CLIENT_TITLE: 'DeepSeek Harness',
DSH_CLIENT_VERSION: '1.2.3-rc.4',
})
write(join(fixtureRoot, '.gitignore'), 'ignored.txt\n')
git(fixtureRoot, ['add', '.gitignore'])
git(fixtureRoot, ['commit', '-m', 'ignore fixture'])
write(join(fixtureRoot, 'ignored.txt'), 'ignored\n')
expect(repositoryGitDirty(fixtureRoot)).toBe(false)
rmSync(join(fixtureRoot, 'ignored.txt'))
write(join(fixtureRoot, 'tracked.txt'), 'unstaged\n')
expect(repositoryGitDirty(fixtureRoot)).toBe(true)
write(join(fixtureRoot, 'tracked.txt'), 'committed\n')
expect(repositoryGitDirty(fixtureRoot)).toBe(false)
write(join(fixtureRoot, 'tracked.txt'), 'staged\n')
git(fixtureRoot, ['add', 'tracked.txt'])
expect(repositoryGitDirty(fixtureRoot)).toBe(true)
git(fixtureRoot, ['commit', '-m', 'staged fixture'])
expect(repositoryGitDirty(fixtureRoot)).toBe(false)
write(join(fixtureRoot, 'untracked.txt'), 'untracked\n')
expect(repositoryGitDirty(fixtureRoot)).toBe(true)
expect(repositoryClientBuildEnvironment(fixtureRoot, {
DSH_CLIENT_COMMIT_HASH: COMMIT_HASH,
})).toEqual({
DSH_CLIENT_COMMIT_HASH: COMMIT_HASH.slice(0, 7),
DSH_CLIENT_GIT_DIRTY: 'true',
DSH_CLIENT_VERSION: '1.2.3-rc.4',
})
rmSync(join(fixtureRoot, 'untracked.txt'))
const submoduleSource = repositoryFixture('9.8.7')
git(fixtureRoot, ['-c', 'protocol.file.allow=always', 'submodule', 'add', submoduleSource, 'submodule'])
git(fixtureRoot, ['commit', '-am', 'submodule fixture'])
expect(repositoryGitDirty(fixtureRoot)).toBe(false)
write(join(fixtureRoot, 'submodule/tracked.txt'), 'modified submodule\n')
expect(repositoryGitDirty(fixtureRoot)).toBe(true)
})
it('omits dirty metadata when repository metadata is unavailable', () => {
const fixtureRoot = mkdtempSync(join(tmpdir(), 'dsh-client-build-no-git-'))
roots.push(fixtureRoot)
write(join(fixtureRoot, 'package.json'), '{"version":"2.0.0"}\n')
expect(repositoryGitDirty(fixtureRoot)).toBeUndefined()
expect(repositoryClientBuildEnvironment(fixtureRoot, {
DSH_CLIENT_COMMIT_HASH: COMMIT_HASH,
DSH_CLIENT_GIT_DIRTY: 'true',
})).toEqual({
DSH_CLIENT_COMMIT_HASH: COMMIT_HASH.slice(0, 7),
DSH_CLIENT_VERSION: '2.0.0',
})
})
it('defines only public client values over a non-enumerable fallback', () => {
expect(clientBuildEnvironmentDefines({
PATH: '/bin',
@@ -151,6 +264,7 @@ describe('client build environment', () => {
DSH_CLIENT_BUILD_PROFILE: 'official',
DSH_CLIENT_COMMIT_HASH: COMMIT_HASH.slice(0, 7),
DSH_CLIENT_TITLE: 'DeepSeek Harness',
DSH_CLIENT_VERSION: '1.2.3',
}
const official = buildFixture(officialEnvironment)
const defaultBuild = buildFixture({})
+84 -2
View File
@@ -1,5 +1,5 @@
import { createHash } from 'node:crypto'
import { execFileSync } from 'node:child_process'
import { execFileSync, spawnSync } from 'node:child_process'
import {
existsSync,
globSync,
@@ -25,6 +25,9 @@ const OFFICIAL_CLIENT_BUILD_ENVIRONMENT = {
/** Public variable carrying the source commit embedded in client artifacts. */
const CLIENT_COMMIT_HASH_VARIABLE = 'DSH_CLIENT_COMMIT_HASH'
/** Public variable carrying the repository package version embedded in client artifacts. */
const CLIENT_VERSION_VARIABLE = 'DSH_CLIENT_VERSION'
/** Repository-relative path of the complete client build record. */
export const CLIENT_BUILD_RECORD_PATH = '.dsh-build/client-build-environment.json'
@@ -57,6 +60,76 @@ export function repositoryCommitHash(root: string, environment: NodeJS.ProcessEn
return value.slice(0, 7).toLowerCase()
}
/**
* Resolve the repository package version used by browser build metadata.
* @param root - repository root containing the authoritative package.json.
* @returns the repository's semver-compatible package version.
*/
export function repositoryVersion(root: string): string {
const path = resolve(root, 'package.json')
let manifest: unknown
try {
manifest = JSON.parse(readFileSync(path, 'utf8'))
} catch (error) {
const detail = error instanceof Error ? error.message : String(error)
throw new Error(`cannot read repository version from ${path}: ${detail}`)
}
if (!isObject(manifest) || typeof manifest.version !== 'string'
|| !/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(manifest.version)) {
throw new Error(`repository package.json has an invalid version ${JSON.stringify(isObject(manifest) ? manifest.version : undefined)}`)
}
return manifest.version
}
/**
* Read whether Git reports any staged, unstaged, untracked, or submodule change.
* @param root - repository root whose worktree is inspected.
* @returns true or false inside a Git worktree; undefined without Git metadata.
*/
export function repositoryGitDirty(root: string): boolean | undefined {
const probe = spawnSync('git', ['rev-parse', '--is-inside-work-tree'], {
cwd: root,
encoding: 'utf8',
stdio: ['ignore', 'pipe', 'ignore'],
})
if (probe.error !== undefined || probe.status !== 0 || probe.stdout.trim() !== 'true') return undefined
const status = spawnSync('git', ['status', '--porcelain=v1', '--untracked-files=normal'], {
cwd: root,
encoding: 'utf8',
stdio: ['ignore', 'pipe', 'pipe'],
})
if (status.error !== undefined) throw status.error
if (status.status !== 0) {
throw new Error(`git status failed in ${root}: ${status.stderr.trim() || String(status.status)}`)
}
return status.stdout !== ''
}
/**
* Resolve the public environment for a complete default build from one checkout.
* Repository-owned metadata replaces inherited values; other public values pass through.
* @param root - repository root supplying version and Git metadata.
* @param environment - caller environment supplying optional commit and public extensions.
* @returns complete public client environment for the default build.
*/
export function repositoryClientBuildEnvironment(
root: string,
environment: NodeJS.ProcessEnv = process.env,
): ClientBuildEnvironment {
const inherited = { ...clientBuildEnvironment(environment) }
delete inherited.DSH_CLIENT_COMMIT_HASH
delete inherited.DSH_CLIENT_GIT_DIRTY
delete inherited.DSH_CLIENT_VERSION
const dirty = repositoryGitDirty(root)
return {
...inherited,
DSH_CLIENT_COMMIT_HASH: repositoryCommitHash(root, environment),
...(dirty === true ? { DSH_CLIENT_GIT_DIRTY: 'true' } : {}),
DSH_CLIENT_VERSION: repositoryVersion(root),
}
}
/**
* Resolve the exact public values required by an official build at one commit.
* @param root - repository root whose HEAD must match the built source.
@@ -69,6 +142,7 @@ export function officialClientBuildEnvironment(
): Readonly<Record<`DSH_CLIENT_${string}`, string>> {
return {
DSH_CLIENT_COMMIT_HASH: repositoryCommitHash(root, environment),
DSH_CLIENT_VERSION: repositoryVersion(root),
...OFFICIAL_CLIENT_BUILD_ENVIRONMENT,
}
}
@@ -115,10 +189,18 @@ export function resolveClientBuildEnvironment(
if (profile === undefined) return clientBuildEnvironment(environment)
if (profile === 'official') {
const commitHash = environment[CLIENT_COMMIT_HASH_VARIABLE]
const version = environment[CLIENT_VERSION_VARIABLE]
if (commitHash === undefined) {
throw new Error(`${CLIENT_COMMIT_HASH_VARIABLE} is required for the official client build profile`)
}
return { DSH_CLIENT_COMMIT_HASH: commitHash, ...OFFICIAL_CLIENT_BUILD_ENVIRONMENT }
if (version === undefined) {
throw new Error(`${CLIENT_VERSION_VARIABLE} is required for the official client build profile`)
}
return {
DSH_CLIENT_COMMIT_HASH: commitHash,
DSH_CLIENT_VERSION: version,
...OFFICIAL_CLIENT_BUILD_ENVIRONMENT,
}
}
throw new Error(`unknown client build profile ${JSON.stringify(profile)}; expected "official"`)
}
+40 -2
View File
@@ -1,7 +1,10 @@
/**
* Pins shared client-bundle preset rules: the module-edge purity gate and
* the physical watch dependencies hidden behind virtual CSS Modules.
* Pins shared client-bundle preset rules: module-edge purity, source-map
* chaining, and physical watch dependencies hidden behind virtual CSS Modules.
*/
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { fileURLToPath } from 'node:url'
import { describe, expect, it, vi } from 'vitest'
import { clientBundle, requestedExternals } from '../packages/client/tsdown.client.ts'
@@ -14,6 +17,11 @@ interface CssModulePlugin {
load?: (this: { addWatchFile: (id: string) => void }, id: string) => Promise<unknown>
}
interface SourceMapPlugin {
name: string
load?: (id: string) => Promise<unknown>
}
/** A representative dynamic bundle using the shared client baseline. */
const REQUESTING_PACKAGE = '@deepseek-ai/dsh-client-ui-conversation'
@@ -59,6 +67,14 @@ function cssModulePlugin(): CssModulePlugin {
return plugin
}
function sourceMapPlugin(): SourceMapPlugin {
const configs = clientConfigs()
const plugins = (configs[0] as { plugins: SourceMapPlugin[] }).plugins
const plugin = plugins.find(candidate => candidate.name === 'dsh-tsc-sourcemap')
if (plugin?.load === undefined) throw new Error('tsc sourcemap plugin missing from client config')
return plugin
}
describe('client bundle purity gate', () => {
const resolveId = purityResolveId()
@@ -143,6 +159,28 @@ describe('client bundle debug artifacts', () => {
it('emits source maps for plugin TS and TSX outside the Vite module graph', () => {
const configs = clientConfigs()
expect(configs[0]?.sourcemap).toBe(true)
expect(configs[0]?.outputOptions).toMatchObject({ sourcemapExcludeSources: false })
})
it('chains emitted tsc maps when the production Client build consumes lib/types', async () => {
const root = mkdtempSync(join(tmpdir(), 'dsh-client-sourcemap-'))
try {
const entry = join(root, 'lib', 'types', 'client', 'index.js')
const source = join(root, 'src', 'client', 'index.ts')
const map = { version: 3, names: [], mappings: 'AAAA', sources: ['../../../src/client/index.ts'] }
mkdirSync(join(root, 'lib', 'types', 'client'), { recursive: true })
mkdirSync(join(root, 'src', 'client'), { recursive: true })
writeFileSync(entry, 'export const marker = true\n//# sourceMappingURL=index.js.map\n')
writeFileSync(`${entry}.map`, JSON.stringify(map))
writeFileSync(source, 'export const marker: true = true\n')
await expect(sourceMapPlugin().load!(entry)).resolves.toEqual({
code: 'export const marker = true',
map: { ...map, sourcesContent: ['export const marker: true = true\n'] },
})
} finally {
rmSync(root, { recursive: true, force: true })
}
})
it('maps first-party sources to their repository package paths', () => {
+5 -5
View File
@@ -14,14 +14,14 @@ describe('cordisConfigFiles', () => {
it('finds Loader YAML without treating translation records as configs', () => {
const root = mkdtempSync(join(tmpdir(), 'dsh-cordis-config-files-'))
roots.push(root)
for (const directory of ['.claude', 'docs', 'examples', 'node_modules/pkg', 'vendor/pkg']) {
for (const directory of ['.claude', 'apps/cli/config/examples', 'docs', 'node_modules/pkg', 'vendor/pkg']) {
mkdirSync(join(root, directory), { recursive: true })
}
for (const file of [
'.claude/hidden.cordis.yml',
'docs/cordis-primer.i18n.yaml',
'examples/agent.cordis.yaml',
'examples/headless.cordis.yml',
'apps/cli/config/examples/agent.cordis.yaml',
'apps/cli/config/examples/headless.cordis.yml',
'node_modules/pkg/hidden.cordis.yml',
'vendor/pkg/hidden.cordis.yml',
]) {
@@ -29,8 +29,8 @@ describe('cordisConfigFiles', () => {
}
expect(cordisConfigFiles(root)).toEqual([
join('examples', 'agent.cordis.yaml'),
join('examples', 'headless.cordis.yml'),
join('apps', 'cli', 'config', 'examples', 'agent.cordis.yaml'),
join('apps', 'cli', 'config', 'examples', 'headless.cordis.yml'),
])
})
})
-1
View File
@@ -17,7 +17,6 @@ const allSpecs = new Set([
...globSync('packages/*/*/tests/**/*.spec.ts', { cwd: root }),
...globSync('packages/*/*/tests/**/*.spec.tsx', { cwd: root }),
...globSync('apps/*/tests/**/*.spec.ts', { cwd: root }),
...globSync('examples/*/tests/**/*.spec.ts', { cwd: root }),
...globSync('scripts/**/*.spec.ts', { cwd: root }),
].map(path => path.replaceAll('\\', '/')))
-6
View File
@@ -39,10 +39,4 @@ export const coverageExemptHeavySuites: readonly CoverageExemptSuite[] = [
{ filter: 'scripts/oxlint-contract.spec.ts', exclude: 'scripts/oxlint-contract.spec.ts' },
{ filter: 'scripts/change-scope.spec.ts', exclude: 'scripts/change-scope.spec.ts' },
{ filter: 'scripts/translation-pairing-merge.spec.ts', exclude: 'scripts/translation-pairing-merge.spec.ts' },
// The real corpus transform runs package src only in a spawned Node process,
// outside the parent Vitest worker's v8 coverage session.
{
filter: 'packages/experimental/webworker-runtime/tests/compile/transform-corpus.spec.ts',
exclude: 'packages/experimental/webworker-runtime/tests/compile/transform-corpus.spec.ts',
},
]
+9 -11
View File
@@ -1,20 +1,18 @@
/** Boot the ACP Code Mode overlay. Requires a DeepSeek API key. */
/** Run one headless task through the shipped Code Mode composition. Requires a model credential. */
import { spawn } from 'node:child_process'
if (process.argv.length > 2) {
console.error('usage: pnpm run demo:code-mode')
process.exit(2)
}
const task = process.argv.slice(2).join(' ').trim()
|| 'Inspect this repository with Code Mode and report its top-level architecture.'
const child = spawn(process.execPath, [
'--import',
'tsx/esm',
'apps/cli/src/bin.ts',
'--profile',
'acp',
'--patch',
'examples/acp-agent/cordis.yml',
'--patch',
'examples/acp-agent/code-mode.cordis.yml',
], { stdio: 'inherit' })
'headless',
task,
], {
stdio: 'inherit',
env: { ...process.env, DSH_TOOLS_MODE: 'code' },
})
child.on('exit', (code, signal) => { process.exit(signal !== null ? 1 : code ?? 1) })
-26
View File
@@ -1,26 +0,0 @@
/**
* Boot the self-referential Cordis tools under Web or ACP, defaulting to Web. This is a repository demo wrapper, not a product CLI feature.
*/
import { spawn } from 'node:child_process'
const SURFACES = new Map([
// The browser surface with the cordis toolset layered on: `dsh web --config`
// applies this overlay over the shipped web composition; it owns port 3081.
['web', ['--import', 'tsx/esm', 'apps/cli/src/bin.ts', 'web', '--patch', 'examples/web-cordis/cordis.yml']],
['acp', [
'--import', 'tsx/esm', 'apps/cli/src/bin.ts', '--profile', 'acp',
'--patch', 'examples/acp-agent/cordis.yml',
'--patch', 'examples/acp-agent/cordis-tools.cordis.yml',
]],
])
const surface = process.argv[2] ?? 'web'
const args = SURFACES.get(surface)
if (args === undefined || process.argv.length > 3) {
console.error('usage: pnpm run demo:cordis [web|acp]')
process.exit(2)
}
if (surface === 'web') console.log('Cordis Web: http://127.0.0.1:3081')
const child = spawn(process.execPath, args, { stdio: 'inherit' })
child.on('exit', (code, signal) => { process.exit(signal === null ? code ?? 1 : 1) })
+39 -1
View File
@@ -3,7 +3,45 @@ import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { expect, it } from 'vitest'
import type { TsdownBundle } from 'tsdown'
import { discoverLibraryDirs, discoverPluginDirs, watchClientPlugins } from './dev-web.ts'
import { writeClientBuildRecord } from './client-build-environment.ts'
import {
devWebBuildEnvironment,
discoverLibraryDirs,
discoverPluginDirs,
watchClientPlugins,
} from './dev-web.ts'
it('samples one local environment at startup without validating watcher outputs', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-dev-web-environment-'))
try {
await mkdir(join(root, 'apps/web/dist'), { recursive: true })
await mkdir(join(root, 'packages/client/example/lib'), { recursive: true })
await writeFile(join(root, 'package.json'), JSON.stringify({ version: '1.2.3' }))
await writeFile(join(root, 'apps/web/dist/index.html'), '<main></main>')
await writeFile(join(root, 'packages/client/example/lib/client.js'), 'module.exports = {}\n')
writeClientBuildRecord(root, {
DSH_CLIENT_BUILD_PROFILE: 'official',
DSH_CLIENT_COMMIT_HASH: 'fffffff',
DSH_CLIENT_TITLE: 'DeepSeek Harness',
DSH_CLIENT_VERSION: '1.2.2',
})
await writeFile(join(root, 'packages/client/example/lib/client.js'), 'module.exports = { changed: true }\n')
expect(devWebBuildEnvironment(root, {
PATH: '/bin',
DSH_BUILD_CLIENT_PROFILE: 'official',
DSH_CLIENT_COMMIT_HASH: 'abc1234',
DSH_CLIENT_EXTRA: 'launch-value',
})).toEqual({
PATH: '/bin',
DSH_CLIENT_COMMIT_HASH: 'abc1234',
DSH_CLIENT_EXTRA: 'launch-value',
DSH_CLIENT_VERSION: '1.2.3',
})
} finally {
await rm(root, { recursive: true, force: true })
}
})
it('discovers dsh.client packages with sibling roles', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-dev-web-discovery-'))
+28
View File
@@ -34,6 +34,11 @@ import { fileURLToPath, pathToFileURL } from 'node:url'
import { execa } from 'execa'
import { build } from 'tsdown'
import type { TsdownBundle } from 'tsdown'
import {
CLIENT_BUILD_PROFILE_SELECTOR,
clientBuildProcessEnvironment,
repositoryClientBuildEnvironment,
} from './client-build-environment.ts'
const repoRoot = fileURLToPath(new URL('..', import.meta.url))
@@ -49,6 +54,19 @@ const SHELL_PACKAGE = '@deepseek-ai/dsh-web-frontend'
*/
const TEST_INFRASTRUCTURE_PREFIX = 'packages/test-support/'
/**
* Sample one local public environment for every long-lived watcher stage.
* @param root - repository root supplying version and Git metadata.
* @param environment - watcher launch environment supplying public extensions.
* @returns process environment shared by tsdown and spawned watcher stages.
*/
export function devWebBuildEnvironment(
root: string,
environment: NodeJS.ProcessEnv = process.env,
): NodeJS.ProcessEnv {
return clientBuildProcessEnvironment(environment, repositoryClientBuildEnvironment(root, environment))
}
/**
* Discover the watch workspace by declaration: every packages/<group>/<name>
* whose package.json carries `dsh.client` with platform "web" is a client
@@ -175,6 +193,16 @@ interface StageHandle {
const invokedPath = process.argv[1]
const isMain = invokedPath !== undefined && import.meta.url === pathToFileURL(resolve(invokedPath)).href
if (isMain) {
const buildEnvironment = devWebBuildEnvironment(repoRoot, process.env)
for (const name of Object.keys(process.env)) {
if (name === CLIENT_BUILD_PROFILE_SELECTOR || name.startsWith('DSH_CLIENT_')) {
Reflect.deleteProperty(process.env, name)
}
}
for (const [name, value] of Object.entries(buildEnvironment)) {
if (name.startsWith('DSH_CLIENT_') && value !== undefined) process.env[name] = value
}
const pluginDirs = discoverPluginDirs()
const libraryDirs = discoverLibraryDirs()
if (pluginDirs.length === 0) {
-1
View File
@@ -5,7 +5,6 @@
"docs/cordis-primer.md": 600,
"docs/defensive-patterns.md": 550,
"docs/testing.md": 1150,
"examples/AGENTS.md": 310,
"packages/AGENTS.md": 675,
"packages/README.md": 994
}
+7
View File
@@ -100,6 +100,7 @@ export const SERVICE_PAGE: Record<string, string> = {
spillStore: 'spill.md',
storage: 'storage.md',
storageDomain: 'storage.md',
subagentModelSelection: 'subagent.md',
subagents: 'subagent.md',
subprocess: 'subprocess.md',
systemPrompt: 'system-prompt.md',
@@ -335,6 +336,7 @@ export const LINK_MAP: Readonly<Record<string, string>> = {
ApprovalService: 'approval.md',
AskUserQuestionRequestEvent: 'user-questions.md',
EncodedImageAttachment: 'attachment.md',
ImageAttachmentAccess: 'llm-streaming.md',
ImageAttachmentRef: 'attachment.md',
ImageRequestPolicy: 'attachment.md',
RequestImageAttachment: 'attachment.md',
@@ -394,6 +396,7 @@ export const LINK_MAP: Readonly<Record<string, string>> = {
PrepareSessionOptions: 'persistence.md',
SessionHeader: 'persistence.md',
SessionInspection: 'persistence.md',
BorrowedSessionSource: 'persistence.md',
SessionLocation: 'persistence.md',
SessionPreparation: 'persistence.md',
SessionPersistenceSnapshot: 'persistence.md',
@@ -433,6 +436,8 @@ export const LINK_MAP: Readonly<Record<string, string>> = {
SessionEventTraceRequest: 'session-query.md',
SessionEventWindow: 'session-query.md',
SessionLineageTrace: 'session-query.md',
SessionObservation: 'session-query.md',
SessionObservationOptions: 'session-query.md',
SessionRecord: 'session-query.md',
SessionResultFilter: 'session-query.md',
SessionSearchExecContext: 'session-query.md',
@@ -571,6 +576,7 @@ export const LINK_MAP: Readonly<Record<string, string>> = {
WorkspaceOrderValue: 'workspace.md',
WorkspaceRenameRequest: 'workspace.md',
WorkspaceValue: 'workspace.md',
ClientArtifactBaseline: 'client-modules.md',
WebBootGraph: 'client-modules.md',
SessionTelemetryRecord: 'session-telemetry.md',
WorkflowRunInfo: 'workflow.md',
@@ -599,6 +605,7 @@ export const FOUNDATION_TYPE_NAMES: ReadonlySet<string> = new Set([
'Error',
'EntryTree',
'Exclude',
'Extract',
'Map',
'NonNullable',
'Omit',
+10 -26
View File
@@ -205,6 +205,14 @@ const SERVICE_ROLES: ServiceRole[] = [
consumers: ['llm-deepseek', 'llm-pi-ai', 'apiproxy'],
note: 'Plugins register namespace schemas and resolve layered values; providers store the raw document. The LLM adapters register their entry config as the composition base under the user section; the web gateway serves redacted layered descriptors and writes the user layer.',
},
{
key: 'subagentModelSelection',
pkg: 'tool-subagent',
title: 'Subagent model-selection preference',
mode: 'core',
consumers: ['tool-subagent'],
note: 'Owns the default-off settings namespace that Agent-scoped delegation tools sample when composing a new top-level Session.',
},
{
key: 'credentials',
pkg: 'credentials',
@@ -763,23 +771,7 @@ const APP_EXAMPLES = [
title: 'DSH Base Composition',
label: 'packages/bundle/base/cordis.patch.yml',
config: 'packages/bundle/base/cordis.patch.yml',
summary: 'The dsh-base bundle patch every profile applies first; mode bundles (dsh-web-app, dsh-headless) and the user\'s profile layer patch over it.',
},
{
id: 'headless',
rel: 'examples/headless-agent/composition.md',
title: 'Headless Agent Snapshot Composition',
label: 'examples/headless-agent',
config: 'examples/headless-agent/cordis.yml',
summary: 'The headless snapshot composition combines the real DeepSeek adapter and coding capabilities with one explicitly configured persisted top-level agent; its JSONL driver is test-only.',
},
{
id: 'acp',
rel: 'examples/acp-agent/composition.md',
title: 'ACP Automation Profile Patch',
label: 'examples/acp-agent',
config: 'examples/acp-agent/cordis.yml',
summary: 'The ACP example patches the shipped base + acp-app profile for demos and snapshots; dsh owns launch, and the ACP bridge exposes fresh automation sessions without a stdout logger or pre-created agent.',
summary: 'The dsh-base bundle patch shared by the web, headless, sdk, and acp profiles; their mode bundles and user layers patch over it, while sdk-minimal owns a separate standalone tree.',
},
]
@@ -787,9 +779,7 @@ type AppExample = typeof APP_EXAMPLES[number]
function renderAppComposition(example: AppExample): string {
const plugins = parseExampleCordis(example.config)
const maintenance = example.id === 'acp'
? 'hybrid: the patch row list is parsed from its `cordis.yml`; the scope summary is curated'
: 'hybrid: the leaf plugin list is parsed from its `cordis.yml`; app package expansion is curated from package source'
const maintenance = 'hybrid: the patch row list is parsed from its `cordis.yml`; app package expansion is curated from package source'
const lines = generatedHeader(example.title)
lines.push(
example.summary,
@@ -1432,9 +1422,6 @@ function renderIndex(docs: GraphDoc[]): string {
const labels: Record<string, string> = {
'docs/capability-seams.md': 'capability seams and core services',
'apps/cli/composition.md': 'dsh shared base composition',
'examples/headless-agent/composition.md': 'headless-agent app composition',
'examples/cordis-agent/composition.md': 'cordis-agent app composition',
'examples/acp-agent/composition.md': 'acp-agent app composition',
'docs/event-producer-consumer.md': 'event producer/consumer matrix',
'docs/agent-lifecycle.md': 'agent turn and step lifecycle',
'docs/tool-execution-pipeline.md': 'tool execution pipeline',
@@ -1442,9 +1429,6 @@ function renderIndex(docs: GraphDoc[]): string {
const modes: Record<string, string> = {
'docs/capability-seams.md': 'hybrid generated',
'apps/cli/composition.md': 'hybrid generated',
'examples/headless-agent/composition.md': 'hybrid generated',
'examples/cordis-agent/composition.md': 'hybrid generated',
'examples/acp-agent/composition.md': 'hybrid generated',
'docs/event-producer-consumer.md': 'hybrid generated',
'docs/agent-lifecycle.md': 'curated',
'docs/tool-execution-pipeline.md': 'curated',
-1
View File
@@ -339,7 +339,6 @@ describe('manifestPatterns', () => {
'tools/*/package.json',
'native/landlock-run/package.json',
'native/landlock-run/packages/*/package.json',
'examples/*/package.json',
])
})
})
+2 -6
View File
@@ -24,8 +24,8 @@ const ALL_KINDS = ['dependencies', 'devDependencies', 'optionalDependencies', 'p
/**
* Workspace areas that never reach a user: repository tooling and gates (the
* root manifest), test infrastructure, the documentation site, the runnable
* demo leaves, and the native launcher's build workspace. A runtime
* root manifest), test infrastructure, the documentation site, and the native
* launcher's build workspace. A runtime
* declaration by anything outside these areas is a disclosure-relevant
* runtime dependency because any plugin package can be mounted from a user's
* `cordis.yml`.
@@ -35,7 +35,6 @@ const DEV_ONLY_AREAS = [
'packages/test-support/',
'packages/test-support/client-runtime/',
'website/',
'examples/',
'native/',
] as const
@@ -136,9 +135,6 @@ export function manifestPatterns(rootMembers: readonly string[]): string[] {
return [
'package.json',
...rootMembers.map(member => `${member}/package.json`),
// The demo leaves join the workspace through `examples/package.json`, so
// their own manifests are members of nothing and no glob above reaches them.
'examples/*/package.json',
]
}
+10 -5
View File
@@ -9,6 +9,7 @@
import { globSync, readFileSync, writeFileSync } from 'node:fs'
import { basename, resolve } from 'node:path'
import { Context } from '@deepseek-ai/cordis'
import LlmRuntime from '@deepseek-ai/dsh-llm'
import type { ToolSchema } from '@deepseek-ai/dsh-llm'
import AgentRegistry from '@deepseek-ai/dsh-agent'
import type { Agent } from '@deepseek-ai/dsh-agent'
@@ -104,7 +105,7 @@ const OUT = 'docs/tool-catalog.md'
function registerCatalogSubagentProvider(ctx: Context, name: string): void {
const provider: SubagentProvider = {
name,
capabilities: { outputSchema: true, depthLimit: true, toolFilter: true, persona: true },
capabilities: { agentOptions: true, outputSchema: true, depthLimit: true, toolFilter: true, persona: true },
inheritsParentContext: false,
start: () => Promise.reject(new Error('tool-catalog provider cannot start a child')),
// Declared so consumers configured for continuable background mode mount.
@@ -455,17 +456,21 @@ const TOOL_PACKAGES: ToolPackage[] = [
{
pkg: '@deepseek-ai/dsh-tool-subagent',
dir: 'tool-subagent',
source: 'packages/subagent/tool-subagent/src/index.ts',
requires: ['ctx.tools', 'ctx.subagents', 'ctx.systemPrompt'],
source: {
list_subagent_models: 'packages/subagent/tool-subagent/src/list-models.ts',
subagent: 'packages/subagent/tool-subagent/src/index.ts',
},
requires: ['ctx.tools', 'ctx.subagents', 'ctx.systemPrompt', 'ctx.llm for model discovery and selected-route validation'],
writes: ['tool/call', 'tool/result', 'child session events through the chosen provider'],
shippedNames: ['subagent', 'subagent_fork'],
async mount(ctx) {
await ctx.plugin(SubagentRuntime)
await ctx.plugin(LlmRuntime)
registerCatalogSubagentProvider(ctx, 'mock')
await ctx.plugin(ToolSubagent, { provider: 'mock' })
await ctx.plugin(ToolSubagent, { provider: 'mock', enableModelSelection: true })
},
note:
'The registered tool name is the load-time `toolName` config (default `subagent`); the schema above is that default. The shipped compositions load this package once per subagent backend, so the model additionally sees `subagent_fork` bound to the fork backend. Each instance\'s description, `run_in_background` parameter, and system-prompt policy follow its own `backgroundMode` and `enableRunInBackground`, so the two shipped schemas are not identical: `subagent` is `continuable` and defaults omitted calls to background with automatic settlement delivery, while `subagent_fork` stays `one-shot` and defaults them to foreground — see `packages/bundle/base/cordis.patch.yml` and `examples/acp-agent/cordis.yml`.',
'The registered delegation name is the load-time `toolName` config (default `subagent`); the schema above shows static model selection enabled for reference. Model selection defaults off. Web presets sample the default-off Models preference for each new top-level Session and preserve that decision for its child Sessions; `subagent_fork` remains fixed-route. Explicit compositions may instead use static `enableModelSelection`. Each instance independently controls model selection, discovery ownership, and background behavior through `enableModelSelection`, `modelSelectionSettings`, `backgroundMode`, and `enableRunInBackground`.',
},
{
pkg: '@deepseek-ai/dsh-tool-subagent-control',
+11 -32
View File
@@ -1,8 +1,8 @@
import { spawnSync } from 'node:child_process'
import { randomUUID } from 'node:crypto'
import { existsSync } from 'node:fs'
import { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises'
import { basename, dirname, join, relative } from 'node:path'
import { mkdir, readFile, rm, writeFile } from 'node:fs/promises'
import { join, relative } from 'node:path'
import { fileURLToPath } from 'node:url'
import { flattenDiagnosticMessageText, parseConfigFileTextToJson } from 'typescript'
import { describe, expect, it } from 'vitest'
@@ -39,26 +39,6 @@ function normalizedOutput(result: ReturnType<typeof runOxlint>): string {
return `${result.stdout}${result.stderr}`.replaceAll('\\', '/')
}
/** @returns A transient filename excluded from concurrent repository-wide glob discovery. */
function hiddenProbeName(prefix: string, suffix: string, extension = '.ts'): string {
return `.${prefix}-${suffix}${extension}`
}
/**
* Publish a complete probe so concurrent repository scans never read a partial write.
* @param path - Final probe path that the owning project must discover.
* @param source - Complete TypeScript source to publish.
*/
async function publishProbe(path: string, source: string): Promise<void> {
const staging = join(dirname(path), `.${basename(path)}.staging`)
try {
await writeFile(staging, source)
await rename(staging, path)
} finally {
await rm(staging, { force: true })
}
}
async function writeContractConfig(suffix: string): Promise<string> {
const path = join(repositoryRoot, `.oxlintrc.contract-${suffix}.json`)
await writeFile(path, JSON.stringify({ extends: ['./.oxlintrc.json'], ignorePatterns: [] }))
@@ -76,11 +56,10 @@ describe('Oxlint executable contract', () => {
// A test under packages/client states its face in the filename, so the
// probe carries the Client suffix to reach the Client aggregate.
['client package test', 'packages/client/ui-trajectory/tests', 'tsconfig.client.json', '.client.ts'],
['example', 'examples/headless-agent/tests', 'tsconfig.host.json'],
['CLI profile test', 'apps/cli/tests/profiles/headless/tests', 'tsconfig.host.json'],
['website', 'website', 'tsconfig.host.json'],
] as const
const source = `/** Produce a settled promise for type-aware linting. */
export function probePromise(): Promise<void> {
const source = `export function probePromise(): Promise<void> {
return Promise.resolve()
}
@@ -91,7 +70,7 @@ probePromise()
const paths: Array<readonly [label: string, path: string, tsconfig: string]> = []
for (const [label, parent, tsconfig, extension = '.ts'] of probes) {
const path = join(repositoryRoot, parent, `oxlint-contract-${suffix}${extension}`)
await publishProbe(path, source)
await writeFile(path, source)
paths.push([label, relative(repositoryRoot, path), tsconfig])
}
const clientScript = 'scripts/client-bundle-purity.spec.ts'
@@ -109,7 +88,7 @@ probePromise()
expect(result.error).toBeUndefined()
expect(result.status, output).toBe(1)
for (const [label, path, tsconfig] of paths) {
expect(output, label).toContain(`${path.replaceAll('\\', '/')}:6:1: Promises must be awaited`)
expect(output, label).toContain(`${path.replaceAll('\\', '/')}:5:1: Promises must be awaited`)
expect(output, `${label} project`).toContain(
`Got tsconfig for file ${join(repositoryRoot, path).replaceAll('\\', '/')}: ${join(repositoryRoot, tsconfig).replaceAll('\\', '/')}`,
)
@@ -131,7 +110,7 @@ probePromise()
it('runs JavaScript compatibility and nursery rules', async () => {
const suffix = randomUUID()
const configPath = await writeContractConfig(suffix)
const path = join(repositoryRoot, 'scripts', hiddenProbeName('oxlint-contract', suffix))
const path = join(repositoryRoot, 'scripts', `oxlint-contract-${suffix}.ts`)
const source = `export function firstProbe(): number {
const first = 1
const second = 2
@@ -251,7 +230,7 @@ export const longProbe = 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 +
it('reports an unused suppression', async () => {
const suffix = randomUUID()
const configPath = await writeContractConfig(suffix)
const path = join(repositoryRoot, 'scripts', hiddenProbeName('oxlint-contract', suffix))
const path = join(repositoryRoot, 'scripts', `oxlint-contract-${suffix}.ts`)
try {
await writeFile(path, '// oxlint-disable-next-line no-console\nexport const value = 1\n')
@@ -301,7 +280,7 @@ export const longProbe = 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 +
expect(stagedConfig.ignorePatterns).not.toContain('packages/typert/generator/tests/fixtures/type-model/**')
const suffix = randomUUID()
const path = join(repositoryRoot, 'scripts', hiddenProbeName('staged-lint-probe', suffix))
const path = join(repositoryRoot, 'scripts', `staged-lint-probe-${suffix}.ts`)
try {
await writeFile(path, 'export const value={answer:1};\n')
const lint = runOxlint([
@@ -324,7 +303,7 @@ export const longProbe = 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 +
it('preserves successful fix output channels', async () => {
const suffix = randomUUID()
const path = join(repositoryRoot, 'scripts', hiddenProbeName('staged-lint-probe', suffix))
const path = join(repositoryRoot, 'scripts', `staged-lint-probe-${suffix}.ts`)
try {
await writeFile(path, '// oxlint-disable-next-line no-console\nexport const value = 1\n')
@@ -348,7 +327,7 @@ export const longProbe = 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 +
it('prints only the final diagnostics when a fix retry still fails', async () => {
const suffix = randomUUID()
const path = join(repositoryRoot, 'scripts', hiddenProbeName('staged-lint-probe', suffix))
const path = join(repositoryRoot, 'scripts', `staged-lint-probe-${suffix}.ts`)
try {
await writeFile(path, `export const longProbe = ${'1 + '.repeat(80)}1\n`)
+5 -2
View File
@@ -29,6 +29,7 @@ function write(path: string, content: string): void {
function buildFixture(environment: Record<string, string>): string {
const root = mkdtempSync(join(tmpdir(), 'dsh-release-build-'))
roots.push(root)
write(join(root, 'package.json'), `${JSON.stringify({ version: environment.DSH_CLIENT_VERSION ?? '0.0.1' })}\n`)
write(join(root, 'apps/web/dist/index.html'), '<main></main>')
write(join(root, 'packages/client/example/lib/client.js'), 'module.exports = {}\n')
writeClientBuildRecord(root, environment)
@@ -106,11 +107,13 @@ describe('release families', () => {
vi.stubEnv('DSH_CLIENT_COMMIT_HASH', officialEnvironment.DSH_CLIENT_COMMIT_HASH)
const official = buildFixture(officialEnvironment)
const defaultBuild = buildFixture({})
const missing = join(defaultBuild, 'missing')
write(join(missing, 'package.json'), `${JSON.stringify({ version: officialEnvironment.DSH_CLIENT_VERSION })}\n`)
expect(() => { dsh.verifyBuildArtifacts(official) }).not.toThrow()
expect(() => { dsh.verifyBuildArtifacts(defaultBuild) }).toThrow(/DSH_CLIENT_TITLE/)
expect(() => { dsh.verifyBuildArtifacts(join(defaultBuild, 'missing')) }).toThrow(/record.*missing/)
expect(() => { vendor.verifyBuildArtifacts(join(defaultBuild, 'missing')) }).not.toThrow()
expect(() => { dsh.verifyBuildArtifacts(missing) }).toThrow(/record.*missing/)
expect(() => { vendor.verifyBuildArtifacts(missing) }).not.toThrow()
write(join(official, 'packages/client/example/lib/client.js'), 'module.exports = { changed: true }\n')
expect(() => { dsh.verifyBuildArtifacts(official) }).toThrow(/artifacts differ/)
+5 -21
View File
@@ -82,10 +82,11 @@ const GENERIC_SKIPS: readonly GenericSkip[] = [
// Asserts the vendored-manifest table, which gains an upstream-name column.
{ file: 'scripts/gen-third-party-notices.spec.ts', upstream: RENAMES.map(rename => rename.upstream) },
// `cordis` is also an agent-preset id — the directory name under
// apps/cli/config/agent-presets/ — so in these files the bare name is
// packages/preset/agent-presets/presets/ — so in these files the bare name is
// product data, not a package reference. Renaming it changed which preset
// the creator flow stages and which id the roster reports.
{ file: 'packages/client/ui-agent-preset/src/client/AgentPresetSection.tsx', upstream: ['cordis'] },
{ file: 'packages/preset/agent-presets/tests/shipped-root.spec.ts', upstream: ['cordis'] },
{ file: 'packages/client/ui-agent-preset/src/client/index.ts', upstream: ['cordis'] },
{ file: 'packages/client/ui-agent-preset/tests/apply.client.spec.ts', upstream: ['cordis'] },
{ file: 'packages/client/ui-agent-preset/tests/locales.client.spec.ts', upstream: ['cordis'] },
@@ -96,7 +97,7 @@ const GENERIC_SKIPS: readonly GenericSkip[] = [
// The preset's own composition: its header comment and its system prompt name
// the preset a model mounts, so the scoped name would send the model after an
// id no roster reports.
{ file: 'apps/cli/config/agent-presets/cordis/agent.cordis.yml', upstream: ['cordis'] },
{ file: 'packages/preset/agent-presets/presets/cordis/agent.cordis.yml', upstream: ['cordis'] },
// The preset-roster loop names the `cordis` preset id, not a package.
{ file: 'apps/cli/tests/windows-shell.spec.ts', upstream: ['cordis'] },
// GROUP_ORDER holds `packages/<group>/` directory names, not package names.
@@ -157,8 +158,8 @@ const POSTCONDITIONS: readonly PostCondition[] = [
// The preset ids in this table are product data, not package names.
{ file: 'packages/client/ui-agent-preset/tests/locales.client.spec.ts', text: '[\'cordis\', \'presetCordisName\'', count: 1 },
// The preset id the shipped composition documents to its own model.
{ file: 'apps/cli/config/agent-presets/cordis/agent.cordis.yml', text: 'The `cordis` agent preset', count: 1 },
{ file: 'apps/cli/config/agent-presets/cordis/agent.cordis.yml', text: 'corrupting the `cordis` preset', count: 1 },
{ file: 'packages/preset/agent-presets/presets/cordis/agent.cordis.yml', text: 'The `cordis` agent preset', count: 1 },
{ file: 'packages/preset/agent-presets/presets/cordis/agent.cordis.yml', text: 'corrupting the `cordis` preset', count: 1 },
]
/**
@@ -193,23 +194,6 @@ const EXACT_EDITS: readonly ExactEdit[] = [
errors.push(\`\${label}: @deepseek-ai/cordis peer (\${peer}) and dev (\${dev}) ranges must match\`)`,
expect: 1,
},
{
// The rescoped name is already covered by the `@deepseek-ai/.+` pattern beside it.
id: 'knip-logger-console',
file: 'knip.json',
find: ` "ignoreDependencies": [
"@cordisjs/plugin-logger-console",
"@deepseek-ai/.+"
]
},
"packages/host/directory-picker-auto": {`,
replace: ` "ignoreDependencies": [
"@deepseek-ai/.+"
]
},
"packages/host/directory-picker-auto": {`,
expect: 1,
},
{
id: 'knip-bundle-base',
file: 'knip.json',
+10 -5
View File
@@ -160,7 +160,7 @@ describe('gate graph validation', () => {
},
)
it('keeps native Windows coverage blocking while retaining the observational inventory', () => {
it('keeps native Windows coverage blocking and behind the complete build', () => {
const complete = withPnpmEntrypoint(() => gatesForMode('ci-windows-complete'))
const observational = withPnpmEntrypoint(() => gatesForMode('ci-windows-observational'))
.filter(gate => gate.id !== 'build' && gate.id !== 'docs-site-build')
@@ -168,14 +168,16 @@ describe('gate graph validation', () => {
expect(byId.get('coverage')?.allowFailure).not.toBe(true)
expect(byId.get('coverage-exempt-heavy')?.allowFailure).not.toBe(true)
expect(byId.get('coverage')?.needs).toContain('build')
expect(byId.get('coverage-exempt-heavy')?.needs).toContain('build')
expect(byId.get('coverage-exempt-heavy')?.after).toContain('coverage')
expect(observational).not.toHaveLength(0)
for (const gate of observational) {
const completeGate = byId.get(gate.id)
expect(completeGate?.allowFailure).toBe(true)
expect(completeGate?.after).toContain('coverage')
expect(completeGate?.after).not.toContain('coverage-exempt-heavy')
expect(completeGate?.after).toEqual(expect.arrayContaining([
'coverage',
'coverage-exempt-heavy',
]))
expect(completeGate?.needs).toEqual(gate.needs)
}
})
@@ -386,7 +388,7 @@ describe('Node 24 lane ownership', () => {
const subject = withPnpmEntrypoint(() => gatesForMode('ci-consumers'))
expect(defaultConcurrency('ci-consumers', subject.length, 4)).toEqual({
workers: 10,
workers: 11,
source: 'ci-consumers gate count',
})
expect(subject.map(item => item.id)).toEqual([
@@ -396,6 +398,7 @@ describe('Node 24 lane ownership', () => {
'built-package-invariants',
'lint-and-duplication',
'snapshot',
'expected-output',
'web-snapshot',
'doc-typecheck',
'node-next-types',
@@ -412,6 +415,7 @@ describe('Node 24 lane ownership', () => {
expect(subject.find(item => item.id === 'lint-and-duplication')?.needs).toEqual(['built-package-invariants'])
for (const id of [
'snapshot',
'expected-output',
'web-snapshot',
'doc-typecheck',
'node-next-types',
@@ -420,6 +424,7 @@ describe('Node 24 lane ownership', () => {
expect(subject.find(item => item.id === id)?.needs).toEqual(['built-package-invariants'])
}
expect(subject.find(item => item.id === 'snapshot')?.env).toEqual({ DSH_EXAMPLE_MODE: 'lib' })
expect(subject.find(item => item.id === 'expected-output')?.env).toEqual({ DSH_EXAMPLE_MODE: 'lib' })
expect(subject.find(item => item.id === 'doc-typecheck')?.env).toEqual({
DSH_DOC_TYPECHECK_USE_BUILD_OUTPUT: '1',
})
+20 -12
View File
@@ -241,6 +241,7 @@ export function gatesForMode(selected: Mode): Gate[] {
pnpmScript('issue-management', 'test:issue-management', { label: 'Issue management policy' }),
pnpmScript('duplication', 'duplication'),
snapshotGate(),
expectedOutputGate(),
pnpmScript('build', 'build'),
pnpmScript('build:web', 'build:web'),
...hygieneLeafGates({ artifactNeeds: ['build'] }),
@@ -427,6 +428,7 @@ function ciConsumerGates(): Gate[] {
needs: validatedBuild,
}),
snapshotGate(validatedBuild),
expectedOutputGate(validatedBuild),
webSnapshotGate(validatedBuild),
pnpmScript('doc-typecheck', 'doc-typecheck:contracts-ready', {
needs: validatedBuild,
@@ -471,13 +473,11 @@ function ciWindowsBlockingGates(): Gate[] {
}
function ciWindowsCompleteGates(): Gate[] {
const coverage = coverageGates().map(gate => gate.id === 'coverage-exempt-heavy'
? {
...gate,
needs: [...new Set(['build', ...(gate.needs ?? [])])],
after: [...new Set(['coverage', ...(gate.after ?? [])])],
}
: gate)
const coverage = coverageGates().map(gate => ({
...gate,
needs: [...new Set(['build', ...(gate.needs ?? [])])],
}))
const coverageAfter = coverage.map(gate => gate.id)
const observational = ciWindowsObservationalGates()
// The required production site replaces the observational MPA build; both
// VitePress modes write the same output directory and cannot overlap.
@@ -485,7 +485,7 @@ function ciWindowsCompleteGates(): Gate[] {
.map(gate => ({
...gate,
allowFailure: true,
after: [...new Set(['coverage', ...(gate.after ?? [])])],
after: [...new Set([...coverageAfter, ...(gate.after ?? [])])],
}))
return [
ciBuildGate(),
@@ -588,9 +588,8 @@ function coverageGates(): Gate[] {
]
}
// Example and package snapshots boot their bins in `lib` mode (built artifacts under plain Node,
// plugins via real exports); script snapshots execute their real source entry path.
// Callers wait either on `build` or on a validation gate that transitively owns that build.
// Recorded-session adapters boot process scenarios in `lib` mode. Callers wait
// either on `build` or on a validation gate that transitively owns that build.
function snapshotGate(needs: string[] = ['build']): Gate {
return pnpmScript('snapshot', 'test:snapshot', {
env: { DSH_EXAMPLE_MODE: 'lib' },
@@ -598,6 +597,15 @@ function snapshotGate(needs: string[] = ['build']): Gate {
})
}
// Owner-local process expectations consume built package exports without entering
// the recorded-session corpus or the credentialed provider lane.
function expectedOutputGate(needs: string[] = ['build']): Gate {
return pnpmScript('expected-output', 'test:expected', {
env: { DSH_EXAMPLE_MODE: 'lib' },
needs,
})
}
function builtPackageInvariantsGate(needs?: string[]): Gate {
return pnpmScript('built-package-invariants', 'verify-built-package-invariants', {
label: 'built package invariants',
@@ -700,7 +708,7 @@ function builtBinSmokeGate(needs: string[] = ['build']): Gate {
'run',
'--config',
'vitest.e2e.config.ts',
'examples/headless-agent/tests/keyless-smoke.e2e.ts',
'apps/cli/tests/profiles/headless/tests/keyless-smoke.e2e.ts',
'apps/cli/tests/built-bin.e2e.ts',
'packages/host/directory-picker-native/tests/built-worker.e2e.ts',
'packages/sdk/server/tests/built-scope-carrier.e2e.ts',
@@ -1,17 +0,0 @@
/** Repository-wide canonical-layout check for committed session snapshots. */
import { resolve } from 'node:path'
import { expect, it } from 'vitest'
import { inspectSessionFixtureLayouts } from './session-fixture-layout.ts'
const root = resolve(import.meta.dirname, '..')
it('keeps every session-format JSONL fixture projected into canonical packed layout', () => {
const nonCanonical = inspectSessionFixtureLayouts(root)
.filter(fixture => fixture.source !== fixture.canonical)
.map(fixture => fixture.path)
expect(
nonCanonical,
'Run `pnpm run migrate:packed-session-fixtures` and commit the mechanical fixture rewrite.',
).toEqual([])
})
+29 -1
View File
@@ -1,9 +1,15 @@
import { resolve } from 'node:path'
import { describe, expect, it } from 'vitest'
import { type SessionEvent } from '@deepseek-ai/dsh-session'
import { parseSessionLog } from '@deepseek-ai/dsh-llm-replay'
import { canonicalSessionFixture } from './session-fixture-layout.ts'
import {
canonicalSessionFixture,
inspectSessionFixtureLayouts,
isPhysicalSessionFixture,
} from './session-fixture-layout.ts'
const HEADER = ' {"type":"session","version":0,"id":"fixture","createdAt":1,"delegationDepth":0} '
const root = resolve(import.meta.dirname, '..')
function chunkRun(): SessionEvent[] {
return Array.from({ length: 4 }, (_, index) => ({
@@ -68,3 +74,25 @@ describe('canonicalSessionFixture', () => {
.toThrow(/broken\.jsonl: session snapshot line 2: malformed text-chunks storage row/)
})
})
describe('isPhysicalSessionFixture', () => {
it('excludes only persisted logs under the WebWorker example root', () => {
expect(isPhysicalSessionFixture(
'packages/experimental/webworker-runtime/tests/fixtures/vfs-example/home/sessions/--dsh-workspace--/main/session.jsonl',
)).toBe(true)
expect(isPhysicalSessionFixture(
'packages/experimental/webworker-runtime/tests/fixtures/vfs-example/home/sessions/README.jsonl',
)).toBe(false)
expect(isPhysicalSessionFixture('apps/web/tests/snapshots/example/session.jsonl')).toBe(false)
})
})
it('keeps every session-format JSONL fixture projected into canonical packed layout', () => {
const nonCanonical = inspectSessionFixtureLayouts(root)
.filter(fixture => fixture.source !== fixture.canonical)
.map(fixture => fixture.path)
expect(
nonCanonical,
'Run `pnpm run migrate:packed-session-fixtures` and commit the mechanical fixture rewrite.',
).toEqual([])
})
+15
View File
@@ -7,6 +7,10 @@ import { resolve } from 'node:path'
import { packChunkRuns, type SessionEvent } from '@deepseek-ai/dsh-session'
import { parseSessionLog } from '@deepseek-ai/dsh-llm-replay'
/** Physical persistence artifacts validated by the WebWorker runtime fixture spec. */
const PHYSICAL_SESSION_FIXTURE_ROOT =
'packages/experimental/webworker-runtime/tests/fixtures/vfs-example/home/sessions/'
/** One repository session fixture and its canonical projected representation. */
export interface SessionFixtureLayout {
/** Repository-relative path with `/` separators. */
@@ -17,6 +21,16 @@ export interface SessionFixtureLayout {
canonical: string
}
/**
* Whether a repository JSONL is a production-layout persistence artifact rather
* than an envelope-free replay snapshot owned by this script.
* @param path - Repository-relative path with `/` separators.
* @returns True only for Session logs under the WebWorker VFS example root.
*/
export function isPhysicalSessionFixture(path: string): boolean {
return path.startsWith(PHYSICAL_SESSION_FIXTURE_ROOT) && path.endsWith('/session.jsonl')
}
function isSessionHeader(value: unknown): boolean {
return value !== null && typeof value === 'object' && (value as { type?: unknown }).type === 'session'
}
@@ -109,6 +123,7 @@ function discoverJsonlFiles(root: string): string[] {
*/
export function inspectSessionFixtureLayouts(root: string): SessionFixtureLayout[] {
return discoverJsonlFiles(root).flatMap((path) => {
if (isPhysicalSessionFixture(path)) return []
const source = readFileSync(resolve(root, path), 'utf8')
const canonical = canonicalSessionFixture(source, path)
return canonical === undefined ? [] : [{ path, source, canonical }]
+180
View File
@@ -0,0 +1,180 @@
/** Repository-wide ownership and storage invariants for the recorded-session corpus. */
import { existsSync } from 'node:fs'
import { lstat, readFile, readdir, realpath } from 'node:fs/promises'
import { dirname, join, relative, resolve } from 'node:path'
import { expect, it } from 'vitest'
import {
captureExpectedWorkspaceSnapshot,
EMPTY_WORKSPACE_MARKER,
parseSnapshotManifest,
redactSessionSnapshotIds,
scrubSystemPrompts,
scrubToolSchemas,
sessionFixtureNames,
type SnapshotManifest,
} from '@deepseek-ai/dsh-session-snapshot'
const repoRoot = resolve(import.meta.dirname, '..')
const corpusRoot = join(repoRoot, 'snapshots')
const profiles = ['acp', 'sdk', 'session', 'web'] as const
const snapshotAdapters = [
'apps/web/tests/message-feedback-protocol.snapshot.ts',
'apps/web/tests/minimal-preset.snapshot.ts',
'snapshots/acp/acp.snapshot.ts',
'snapshots/sdk/sdk.snapshot.ts',
'snapshots/session/headless.snapshot.ts',
] as const
interface Scenario {
readonly key: string
readonly profile: string
readonly name: string
readonly dir: string
readonly manifest: SnapshotManifest & {
composition: string
recording: 'live' | 'authored'
header: NonNullable<SnapshotManifest['header']>
}
}
async function scenarios(): Promise<Scenario[]> {
const result: Scenario[] = []
for (const profile of profiles) {
const root = join(corpusRoot, profile)
for (const entry of await readdir(root, { withFileTypes: true })) {
if (!entry.isDirectory()) continue
const dir = join(root, entry.name)
const path = join(dir, 'snapshot.yml')
expect(existsSync(path), `${profile}/${entry.name}/snapshot.yml`).toBe(true)
const manifest = parseSnapshotManifest(await readFile(path, 'utf8'), path)
expect(manifest.scenario, `${profile}/${entry.name}: scenario`).toBe(entry.name)
expect(manifest.profile, `${profile}/${entry.name}: profile`).toBe(profile === 'session' ? 'headless' : profile)
expect(manifest.composition, `${profile}/${entry.name}: composition`).toBeTypeOf('string')
expect(manifest.recording, `${profile}/${entry.name}: recording`).toMatch(/^(live|authored)$/)
expect(manifest.header, `${profile}/${entry.name}: header`).toBeDefined()
result.push({
key: `${profile}/${entry.name}`,
profile,
name: entry.name,
dir,
manifest: {
...manifest,
composition: manifest.composition as string,
recording: manifest.recording as 'live' | 'authored',
header: manifest.header as NonNullable<SnapshotManifest['header']>,
},
})
}
}
return result
}
function referencedScenario(owner: Scenario, source: string): string {
return source.includes('/') ? source : `${owner.profile}/${source}`
}
async function snapshotNamedTests(): Promise<string[]> {
const files: string[] = []
const visit = async (directory: string, relativeDir: string): Promise<void> => {
for (const entry of await readdir(directory, { withFileTypes: true })) {
if (entry.isDirectory()) {
if (['dist', 'lib', 'node_modules'].includes(entry.name)) continue
await visit(join(directory, entry.name), join(relativeDir, entry.name))
} else if (entry.isFile() && /\.snapshot\.tsx?$/u.test(entry.name)) {
files.push(join(relativeDir, entry.name).split(/[/\\]/u).join('/'))
}
}
}
for (const root of ['apps', 'native', 'packages', 'python', 'scripts', 'snapshots', 'website']) {
await visit(join(repoRoot, root), root)
}
return files.sort()
}
it('reserves the snapshot test suffix for recorded-session adapters', async () => {
expect(await snapshotNamedTests()).toEqual([...snapshotAdapters])
})
it('keeps every recorded session owned, pinned, redacted, and header-scrubbed', async () => {
const all = await scenarios()
const byKey = new Map(all.map(scenario => [scenario.key, scenario]))
const pinByClass = new Map<string, Scenario>()
for (const scenario of all) {
if (scenario.manifest.header.pin !== true) continue
const key = `${scenario.manifest.composition}/${scenario.manifest.header.class}`
expect(pinByClass.has(key), `${key}: duplicate header pin`).toBe(false)
pinByClass.set(key, scenario)
}
for (const scenario of all) {
const { manifest, dir, key } = scenario
const classKey = `${manifest.composition}/${manifest.header.class}`
expect(pinByClass.has(classKey), `${key}: missing composition/header pin ${classKey}`).toBe(true)
const localSession = join(dir, 'session.jsonl')
if (manifest.session === undefined) {
expect(existsSync(localSession), `${key}: owner session.jsonl`).toBe(true)
} else {
expect(existsSync(localSession), `${key}: borrower must not own session.jsonl`).toBe(false)
const target = resolve(dir, manifest.session.source)
expect(existsSync(target), `${key}: session source`).toBe(true)
const targetDir = await realpath(dirname(target))
const sourceKey = relative(corpusRoot, targetDir).split(/[/\\]/).join('/')
expect(byKey.has(sourceKey), `${key}: session source must name a corpus owner`).toBe(true)
expect(byKey.get(sourceKey)?.manifest.session, `${key}: session source cannot chain through a borrower`).toBeUndefined()
}
expect(existsSync(join(dir, 'replay.override.json')), `${key}: replay override presence`)
.toBe(manifest.replay?.override === true)
expect(existsSync(join(dir, 'workspace.expected')), `${key}: final workspace presence`)
.toBe(manifest.workspace?.final === true)
if (manifest.workspace?.final === true) {
const expectedRoot = join(dir, 'workspace.expected')
const expectedWorkspace = await captureExpectedWorkspaceSnapshot(expectedRoot)
expect(existsSync(join(expectedRoot, EMPTY_WORKSPACE_MARKER)), `${key}: empty workspace marker`)
.toBe(expectedWorkspace.length === 0)
}
expect(existsSync(join(dir, 'input.json')), `${key}: executable input metadata is ACP-only`)
.toBe(scenario.profile === 'acp')
if (scenario.profile !== 'acp') {
expect(existsSync(join(dir, 'stdout.expected.jsonl')), `${key}: ACP transcript outside ACP`).toBe(false)
}
if (manifest.header.pin === true) {
const promptSource = byKey.get(referencedScenario(scenario, manifest.header.systemPromptSource ?? scenario.name))
const schemaSource = byKey.get(referencedScenario(scenario, manifest.header.toolSchemasSource ?? scenario.name))
expect(promptSource, `${key}: system-prompt source`).toBeDefined()
expect(schemaSource, `${key}: tool-schema source`).toBeDefined()
expect(existsSync(join((promptSource as Scenario).dir, 'system-prompt.expected.md')), `${key}: system-prompt sidecar`).toBe(true)
expect(existsSync(join((schemaSource as Scenario).dir, 'tool-schemas.expected.json')), `${key}: tool-schema sidecar`).toBe(true)
for (const [field, source] of [
['system-prompt.expected.md', promptSource],
['tool-schemas.expected.json', schemaSource],
] as const) {
const local = join(dir, field)
if (!existsSync(local) || !(await lstat(local)).isSymbolicLink()) continue
expect(await realpath(local), `${key}: ${field} symlink follows its manifest source`)
.toBe(await realpath(join((source as Scenario).dir, field)))
}
}
if (manifest.session !== undefined) continue
const names = sessionFixtureNames(await readdir(dir))
const fixtures = await Promise.all(names.map(name => readFile(join(dir, name), 'utf8')))
expect(redactSessionSnapshotIds(fixtures), `${key}: typed identity fixed point`).toEqual(fixtures)
for (const [index, fixture] of fixtures.entries()) {
expect(scrubSystemPrompts(fixture), `${key}/${names[index]}: system prompt must be a sidecar`).toBe(fixture)
expect(scrubToolSchemas(fixture), `${key}/${names[index]}: tool schemas must be a sidecar`).toBe(fixture)
}
for (const index of manifest.header.childSystemPrompts ?? []) {
expect(names[index], `${key}: child prompt index ${index}`).toBeDefined()
expect(existsSync(join(dir, `system-prompt.${index}.expected.md`)), `${key}: child prompt sidecar ${index}`).toBe(true)
}
for (const index of manifest.header.childToolSchemas ?? []) {
expect(names[index], `${key}: child schema index ${index}`).toBeDefined()
expect(existsSync(join(dir, `tool-schemas.${index}.expected.json`)), `${key}: child schema sidecar ${index}`).toBe(true)
}
}
})
+342 -179
View File
@@ -12,6 +12,7 @@ import os
import queue
import subprocess
import sys
import sysconfig
import tempfile
import threading
import time
@@ -29,7 +30,7 @@ CODE_PROMPT = "Use run_code to compute the packaged worker smoke value."
CODE_WORKER_TEXT = "code worker smoke ok"
WORKFLOW_PROMPT = "Use workflow to compute the packaged worker smoke value without agents."
WORKFLOW_WORKER_TEXT = "workflow worker smoke ok"
MINIMAL_PROMPT = "Exercise the packaged minimal agent's persistent Bash and string-replacement editor."
MINIMAL_PROMPT = "Exercise the packaged minimal agent's persistent shell and string-replacement editor."
MINIMAL_TEXT = "minimal agent smoke ok"
MINIMAL_EDITOR_PATH_PREFIX = "Editor path: "
FS_SEARCH_PROMPT = "Exercise the packaged filesystem search tools."
@@ -37,13 +38,43 @@ FS_SEARCH_TEXT = "filesystem search smoke ok"
FS_SEARCH_MARKER = "PACKAGED_FS_SEARCH_OK"
MCP_PROMPT = "Exercise the packaged MCP client with one external stdio server."
MCP_TEXT = "MCP client smoke ok"
MINIMAL_CORDIS = (
Path(__file__).resolve().parent.parent / "examples" / "python-sdk-agent" / "minimal.cordis.yml"
PROFILE_PLUGIN_PROMPT = "Verify the Python-installed dsh profile plugin."
PROFILE_PLUGIN_TEXT = "profile plugin smoke ok"
PROFILE_PLUGIN_MARKER = "PYTHON_INSTALLED_DSH_PROFILE_PLUGIN"
IS_WINDOWS = sys.platform == "win32"
MINIMAL_SHELL_TOOL = "pwsh" if IS_WINDOWS else "bash"
MINIMAL_SHELL_COMMAND = (
"$global:dshSdkCounter = [int]$global:dshSdkCounter + 1; "
'Write-Output "COUNT=$global:dshSdkCounter CWD=$((Get-Location).Path)"; '
"if ($global:dshSdkCounter -eq 1) { Set-Location $env:TEMP }"
if IS_WINDOWS
else (
"counter=$(( ${counter:-0} + 1 )); export counter; "
"printf 'COUNT=%s CWD=%s\\n' \"$counter\" \"$PWD\"; "
"if [ \"$counter\" -eq 1 ]; then cd /tmp; fi"
)
)
MINIMAL_BASH_COMMAND = (
"counter=$(( ${counter:-0} + 1 )); export counter; "
"printf 'COUNT=%s CWD=%s\\n' \"$counter\" \"$PWD\"; "
"if [ \"$counter\" -eq 1 ]; then cd /tmp; fi"
MINIMAL_SHELL_SECOND_CWD = str(Path(tempfile.gettempdir()).resolve()) if IS_WINDOWS else "/tmp"
LEGACY_CUSTOM_DISABLED_ROWS = (
"agent-instructions",
"goal",
"goal-round-driver",
"command-goal",
"plan-mode",
"skill",
"skill-filesystem",
"tool-fs",
"tool-fs-search",
"tool-goal",
"tool-ralph",
"tool-skill",
"tool-str-replace-editor",
"tool-subagent-control",
"tool-subagent-list-agents",
"tool-subagent-fork",
"tool-subagent-report",
"tool-todo",
"tool-web",
)
SNAPSHOT_PROMPT = "Run the advanced packaged-runtime snapshot scenario."
SNAPSHOT_SESSION_ID = "advanced-executable"
@@ -86,84 +117,13 @@ ADVANCED_SNAPSHOT_FILENAMES = ("result.json", "session.jsonl", "session.1.jsonl"
MINIMAL_SNAPSHOT_DIRECTORY = (
Path(__file__).resolve().parent / "snapshots" / "python-sdk-single-exe" / "minimal"
)
if IS_WINDOWS:
MINIMAL_SNAPSHOT_DIRECTORY /= "win-x64"
MINIMAL_SNAPSHOT_FILENAMES = ("model-visible.json",)
RESTART_SNAPSHOT_DIRECTORY = (
Path(__file__).resolve().parent / "snapshots" / "python-sdk-single-exe" / "restart"
)
RESTART_SNAPSHOT_FILENAMES = ("result.json", "requests.json", "session.1.jsonl", "session.2.jsonl")
# The agent loop's dynamic runtime-context snapshot is the one model-visible message this
# expected output cannot carry: the same composition emits it on macOS and not on Linux
# (deepseek-harness#2488), and the file must replay on both. Everything else is compared.
RUNTIME_CONTEXT_PREFIX = "Current runtime context"
CUSTOM_CORDIS = """\
- id: sdk-jsonrpc-server
name: '@deepseek-ai/dsh-sdk-jsonrpc-server'
- id: deepseek-llm-api-extensions
name: '@deepseek-ai/dsh-deepseek-llm-api-extensions'
- id: session-log-deepseek
name: '@deepseek-ai/dsh-session-log-deepseek'
config:
enabled: true
- id: agent-core
name: '@deepseek-ai/dsh-agent-spine-demo'
config:
workspaceContext: false
skills:
enabled: false
toolBash: false
tools:
mode: both
- id: sessions
name: '@deepseek-ai/dsh-session-persistence-jsonl'
config:
root: !!js process.env.DSH_SESSION_ROOT
compression: 'none'
- id: code-runtime
name: '@deepseek-ai/dsh-code-runtime-worker-thread'
- id: subagents
name: '@deepseek-ai/dsh-subagent'
- id: subagent-spawn-in-process
name: '@deepseek-ai/dsh-subagent-spawn-in-process'
config:
providerName: spawn
- id: subagent-tool
name: '@deepseek-ai/dsh-tool-subagent'
config:
provider: spawn
- id: workflow-engine
name: '@deepseek-ai/dsh-workflow-worker-thread'
config:
provider: spawn
- id: workflow-tool
name: '@deepseek-ai/dsh-tool-workflow'
- id: cordis-host-runner
name: '@deepseek-ai/dsh-cordis-host-runner'
- id: cordis-tool
name: '@deepseek-ai/dsh-tool-cordis'
"""
FS_SEARCH_CORDIS = """\
- id: sdk-jsonrpc-server
name: '@deepseek-ai/dsh-sdk-jsonrpc-server'
- id: agent-core
name: '@deepseek-ai/dsh-agent-spine-demo'
config:
workspaceContext: false
skills:
enabled: false
toolBash: false
toolJobs: false
- id: sessions
name: '@deepseek-ai/dsh-session-persistence-jsonl'
config:
root: !!js process.env.DSH_SESSION_ROOT
compression: 'none'
- id: subprocess
name: '@deepseek-ai/dsh-subprocess-local'
- id: fs-search
name: '@deepseek-ai/dsh-tool-fs-search'
config:
sampleOverCapGlobResults: false
"""
MCP_SERVER_SCRIPT = """\
import json
import os
@@ -242,28 +202,29 @@ for line in sys.stdin:
"""
def mcp_cordis(server_script: Path) -> str:
"""Build an external config that mounts the packaged MCP client."""
return json.dumps([
def write_profile_patch(
root: Path,
name: str,
sessions: Path,
patches: list[dict[str, object]],
) -> Path:
"""Write one JSON-form dsh profile patch with deterministic persistence."""
path = root / name
path.write_text(json.dumps([
{
"id": "sdk-jsonrpc-server",
"name": "@deepseek-ai/dsh-sdk-jsonrpc-server",
"id": "session-persistence-jsonl",
"config": {"root": str(sessions), "compression": "none"},
},
{
"id": "agent-core",
"name": "@deepseek-ai/dsh-agent-spine-demo",
"config": {
"workspaceContext": False,
"skills": {"enabled": False},
"toolBash": False,
},
},
{
"id": "sessions",
"name": "@deepseek-ai/dsh-session-persistence-jsonl",
"config": {"root": "./sessions", "compression": "none"},
},
{
{"id": "session-telemetry-otel", "disabled": True},
*patches,
], indent=2))
return path
def write_mcp_patch(root: Path, sessions: Path, server_script: Path) -> Path:
"""Write a profile patch that mounts the packaged MCP client."""
return write_profile_patch(root, "mcp.patch.yml", sessions, [{
"insert": [{
"id": "mcp-fixture",
"name": "@deepseek-ai/dsh-mcp-client",
"config": {
@@ -275,8 +236,8 @@ def mcp_cordis(server_script: Path) -> str:
"failOnStartupError": True,
"reconnect": {"enabled": False},
},
},
], indent=2)
}],
}])
class MockModelHandler(BaseHTTPRequestHandler):
@@ -351,8 +312,8 @@ def completion_chunks(body: dict[str, object]) -> list[dict[str, object]]:
if minimal_prompt is not None:
return tool_call_chunks(
"minimal-bash-1",
"bash",
{"command": MINIMAL_BASH_COMMAND},
MINIMAL_SHELL_TOOL,
{"command": MINIMAL_SHELL_COMMAND},
)
scenario_prompts = {
SNAPSHOT_DIRECT_CHILD_PROMPT,
@@ -364,6 +325,7 @@ def completion_chunks(body: dict[str, object]) -> list[dict[str, object]]:
MCP_PROMPT,
RESTART_FIRST_PROMPT,
RESTART_SECOND_PROMPT,
PROFILE_PLUGIN_PROMPT,
}
prompt = next(
(candidate for candidate in user_prompts if candidate in scenario_prompts),
@@ -430,6 +392,15 @@ def completion_chunks(body: dict[str, object]) -> list[dict[str, object]]:
"mcp__fixture__add",
{"a": 19, "b": 23},
)
if prompt == PROFILE_PLUGIN_PROMPT:
system_text = "\n".join(
message_text(message.get("content"))
for message in messages
if isinstance(message, dict) and message.get("role") == "system"
)
if PROFILE_PLUGIN_MARKER not in system_text:
raise AssertionError("external profile plugin contributed no model-visible marker")
return text_chunks(PROFILE_PLUGIN_TEXT)
return text_chunks(EXPECTED_TEXT)
@@ -478,17 +449,18 @@ def minimal_tool_followup(
"""Verify the checked-in minimal composition's PTY and editor."""
if not call_id.startswith("minimal-"):
return None
if call_id == "minimal-bash-1" and tool_name == "bash":
if call_id == "minimal-bash-1" and tool_name == MINIMAL_SHELL_TOOL:
if "COUNT=1" not in tool_text:
raise AssertionError(f"first persistent bash call lost its output: {tool_text}")
raise AssertionError(f"first persistent shell call lost its output: {tool_text}")
return tool_call_chunks(
"minimal-bash-2",
"bash",
{"command": MINIMAL_BASH_COMMAND},
MINIMAL_SHELL_TOOL,
{"command": MINIMAL_SHELL_COMMAND},
)
if call_id == "minimal-bash-2" and tool_name == "bash":
if "COUNT=2 CWD=/tmp" not in tool_text:
raise AssertionError(f"persistent bash did not retain state: {tool_text}")
if call_id == "minimal-bash-2" and tool_name == MINIMAL_SHELL_TOOL:
expected = f"COUNT=2 CWD={MINIMAL_SHELL_SECOND_CWD}"
if expected.lower() not in tool_text.lower():
raise AssertionError(f"persistent shell did not retain state: {tool_text}")
messages = body.get("messages")
if not isinstance(messages, list):
raise AssertionError("persistent editor smoke request has no messages")
@@ -710,7 +682,7 @@ def main() -> None:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
"--scenario",
choices=("all", "sdk-default", "sdk-custom", "sdk-minimal", "sdk-fs-search", "sdk-mcp", "sdk-snapshot", "sdk-restart", "sdk-live", "direct"),
choices=("all", "sdk-default", "sdk-custom", "sdk-minimal", "sdk-fs-search", "sdk-mcp", "sdk-snapshot", "sdk-restart", "sdk-profile-plugin", "sdk-live", "direct"),
default="all",
)
parser.add_argument("--exe", type=Path)
@@ -725,6 +697,8 @@ def main() -> None:
parser.error("--installed-wheel resolves the wheel's own runtime and cannot be combined with --exe")
if args.scenario == "sdk-live" and not args.installed_wheel:
parser.error("--scenario sdk-live requires --installed-wheel")
if args.scenario == "sdk-profile-plugin" and not args.installed_wheel:
parser.error("--scenario sdk-profile-plugin requires --installed-wheel")
if args.installed_wheel:
args.exe = assert_installed_wheel_environment()
if args.scenario in {"all", "sdk-custom", "sdk-minimal", "sdk-fs-search", "sdk-snapshot", "sdk-restart", "direct"} and args.exe is None:
@@ -759,6 +733,8 @@ def main() -> None:
if args.scenario in {"all", "sdk-restart"}:
assert args.exe is not None
smoke_sdk_restart_snapshot(model.url, args.exe.resolve(), args.update_snapshots)
if args.installed_wheel and args.scenario in {"all", "sdk-profile-plugin"}:
smoke_sdk_profile_plugin(model.url)
if args.scenario in {"all", "direct"}:
assert args.exe is not None
smoke_direct(model.url, args.exe.resolve())
@@ -832,11 +808,13 @@ def smoke_sdk_live() -> None:
with tempfile.TemporaryDirectory(prefix="dsh-sdk-live-") as temporary:
root = Path(temporary).resolve()
sessions = root / "sessions"
dsh_home = root / "home"
sessions = dsh_home / "sessions"
marker = root / "live-api-marker.txt"
session_id = "installed-wheel-live-api"
shell_tool = "pwsh" if IS_WINDOWS else "bash"
create_prompt = (
"Use the bash tool to create the file at the absolute path below with exactly one line "
f"Use the {shell_tool} tool to create the file at the absolute path below with exactly one line "
f"containing {LIVE_API_SENTINEL}. Then reply with exactly {LIVE_API_SENTINEL}.\n{marker}"
)
verify_prompt = (
@@ -847,7 +825,11 @@ def smoke_sdk_live() -> None:
provider="deepseek-official",
model="deepseek-v4-flash",
cwd=str(root),
session_root=str(sessions),
dsh_home=str(dsh_home),
env={
"DSH_PERMISSION_MODE": "danger-full-access",
"DSH_TELEMETRY_DISABLED": "1",
},
api_key=api_key,
base_url=base_url,
request_timeout_seconds=180,
@@ -876,8 +858,8 @@ def smoke_sdk_live() -> None:
raise AssertionError(f"{label} turn returned {result.final_response!r}")
if not marker.is_file():
raise AssertionError(f"real-model tool turn did not create {marker}")
if marker.read_bytes() != f"{LIVE_API_SENTINEL}\n".encode():
raise AssertionError(f"real-model tool turn wrote unexpected bytes to {marker}")
if marker.read_text(encoding="utf-8").splitlines() != [LIVE_API_SENTINEL]:
raise AssertionError(f"real-model tool turn wrote unexpected text to {marker}")
assert_zstd_session_log(sessions)
@@ -910,18 +892,27 @@ def smoke_sdk_default(base_url: str) -> None:
with tempfile.TemporaryDirectory(prefix="dsh-sdk-default-") as temporary:
root = Path(temporary).resolve()
sessions = root / "sessions"
dsh_home = root / "home"
sessions = dsh_home / "sessions"
with DeepSeekHarness(
provider="deepseek-official",
model="smoke-model",
cwd=str(root),
session_root=str(sessions),
dsh_home=str(dsh_home),
env={
"DSH_PERMISSION_MODE": "danger-full-access",
"DSH_TELEMETRY_DISABLED": "1",
},
api_key="sk-keyless-smoke",
base_url=base_url,
request_timeout_seconds=60,
) as harness:
result = harness.run("reply with the smoke text", session_id="default-smoke")
assert result.final_response == EXPECTED_TEXT, result.final_response
assert result.final_response == EXPECTED_TEXT, (
f"final={result.final_response!r} finish={result.finish_reason!r} "
f"events={[event.get('type') for event in result.events]!r} "
f"turn_end={safe_turn_end(next((event.get('data', event) for event in reversed(result.events) if event.get('type') == 'turn/end'), {}))!r}"
)
assert_zstd_session_log(sessions)
@@ -930,16 +921,45 @@ def smoke_sdk_custom(base_url: str, executable: Path) -> None:
with tempfile.TemporaryDirectory(prefix="dsh-sdk-custom-") as temporary:
root = Path(temporary).resolve()
sessions = root / "sessions"
cordis = root / "cordis.yml"
cordis.write_text(CUSTOM_CORDIS)
dsh_home = root / "home"
sessions = dsh_home / "sessions"
patch = write_profile_patch(root, "custom.patch.yml", sessions, [
{"id": "tools", "config": {"mode": "both"}},
{
"id": "system-prompt",
"config": {
"persona": "You are a coding agent powered by the {{model}} model. Your working directory is {{cwd}}.",
},
},
{"id": "session-log-deepseek", "config": {"enabled": True}},
*({"id": row_id, "disabled": True} for row_id in LEGACY_CUSTOM_DISABLED_ROWS),
{"id": "tool-bash", "disabled": True},
{"id": "tool-pwsh", "disabled": True},
{
"id": "tool-subagent",
"config": {
"provider": "spawn",
"toolName": "subagent",
"backgroundMode": "one-shot",
},
},
{"insert": [
{"id": "code-runtime", "name": "@deepseek-ai/dsh-code-runtime-worker-thread"},
{"id": "cordis-host-runner", "name": "@deepseek-ai/dsh-cordis-host-runner"},
{"id": "cordis-tool", "name": "@deepseek-ai/dsh-tool-cordis"},
]},
])
with DeepSeekHarness(
provider="deepseek-official",
model="smoke-model",
cwd=str(root),
session_root=str(sessions),
cordis=str(cordis),
runtime_bin=str(executable),
dsh_bin=str(executable),
dsh_home=str(dsh_home),
patches=(str(patch),),
env={
"DSH_PERMISSION_MODE": "danger-full-access",
"DSH_TELEMETRY_DISABLED": "1",
},
api_key="sk-keyless-smoke",
base_url=base_url,
request_timeout_seconds=60,
@@ -954,7 +974,7 @@ def smoke_sdk_custom(base_url: str, executable: Path) -> None:
def smoke_sdk_minimal(base_url: str, executable: Path, update_snapshots: bool) -> None:
"""Exercise the checked-in minimal composition through the packaged executable."""
"""Exercise the shipped standalone minimal profile through the packaged executable."""
from deepseek_harness import DeepSeekHarness
# One mock model serves every scenario of a run, so the snapshot takes this turn's slice.
@@ -963,14 +983,15 @@ def smoke_sdk_minimal(base_url: str, executable: Path, update_snapshots: bool) -
root = Path(temporary).resolve()
editor_path = root / "created.txt"
prompt = f"{MINIMAL_PROMPT}\n{MINIMAL_EDITOR_PATH_PREFIX}{editor_path}"
sessions = root / "sessions"
dsh_home = root / "home"
sessions = dsh_home / "sessions"
with DeepSeekHarness(
provider="deepseek-official",
model="smoke-model",
cwd=str(root),
session_root=str(sessions),
cordis=str(MINIMAL_CORDIS),
runtime_bin=str(executable),
dsh_bin=str(executable),
dsh_home=str(dsh_home),
profile="sdk-minimal",
api_key="sk-keyless-smoke",
base_url=base_url,
request_timeout_seconds=60,
@@ -982,7 +1003,7 @@ def smoke_sdk_minimal(base_url: str, executable: Path, update_snapshots: bool) -
raise AssertionError(f"minimal agent run emitted no final response: {result.events}")
if editor_path.read_text() != "created by packaged editor\n":
raise AssertionError(f"packaged editor wrote unexpected content: {editor_path.read_text()!r}")
assert_session_log(sessions, root, MINIMAL_TEXT, "COUNT=1", "COUNT=2 CWD=/tmp")
assert_session_log(sessions, root, MINIMAL_TEXT, "COUNT=1", "COUNT=2")
files = build_minimal_snapshot_files(MockModelHandler.requests[first_request:], root)
compare_snapshot_files(
@@ -997,16 +1018,23 @@ def smoke_sdk_fs_search(base_url: str, executable: Path) -> None:
with tempfile.TemporaryDirectory(prefix="dsh-sdk-fs-search-") as temporary:
root = Path(temporary).resolve()
(root / "needle.txt").write_text(f"{FS_SEARCH_MARKER}\n")
sessions = root / "sessions"
cordis = root / "cordis.yml"
cordis.write_text(FS_SEARCH_CORDIS)
dsh_home = root / "home"
sessions = dsh_home / "sessions"
patch = write_profile_patch(root, "fs-search.patch.yml", sessions, [
{"id": "skill-filesystem", "disabled": True},
{"id": "tool-fs-search", "config": {"sampleOverCapGlobResults": False}},
])
with DeepSeekHarness(
provider="deepseek-official",
model="smoke-model",
cwd=str(root),
session_root=str(sessions),
cordis=str(cordis),
runtime_bin=str(executable),
dsh_bin=str(executable),
dsh_home=str(dsh_home),
patches=(str(patch),),
env={
"DSH_PERMISSION_MODE": "danger-full-access",
"DSH_TELEMETRY_DISABLED": "1",
},
api_key="sk-keyless-smoke",
base_url=base_url,
request_timeout_seconds=60,
@@ -1023,19 +1051,23 @@ def smoke_sdk_mcp(base_url: str, executable: Path | None) -> None:
with tempfile.TemporaryDirectory(prefix="dsh-sdk-mcp-") as temporary:
root = Path(temporary).resolve()
sessions = root / "sessions"
dsh_home = root / "home"
sessions = dsh_home / "sessions"
server_script = root / "mcp_server.py"
server_script.write_text(MCP_SERVER_SCRIPT)
cordis = root / "cordis.yml"
cordis.write_text(mcp_cordis(server_script))
patch = write_mcp_patch(root, sessions, server_script)
discovery_log = server_script.with_suffix(".log")
with DeepSeekHarness(
provider="deepseek-official",
model="smoke-model",
cwd=str(root),
session_root=str(sessions),
cordis=str(cordis),
runtime_bin=None if executable is None else str(executable),
dsh_bin=None if executable is None else str(executable),
dsh_home=str(dsh_home),
patches=(str(patch),),
env={
"DSH_PERMISSION_MODE": "danger-full-access",
"DSH_TELEMETRY_DISABLED": "1",
},
api_key="sk-keyless-smoke",
base_url=base_url,
request_timeout_seconds=60,
@@ -1052,22 +1084,132 @@ def smoke_sdk_mcp(base_url: str, executable: Path | None) -> None:
assert_session_log(sessions, root, MCP_TEXT, "mcp__fixture__add", "42")
def smoke_sdk_profile_plugin(base_url: str) -> None:
"""Install an external bundle through Python's dsh command and load it in the SDK."""
from deepseek_harness import DeepSeekHarness
with tempfile.TemporaryDirectory(prefix="dsh-sdk-profile-plugin-") as temporary:
root = Path(temporary).resolve()
dsh_home = root / "home"
plugin = root / "plugin"
plugin.mkdir()
(plugin / "package.json").write_text(json.dumps({
"name": "dsh-python-blackbox-plugin",
"version": "1.0.0",
"private": True,
"type": "module",
"exports": "./index.js",
"peerDependencies": {"@deepseek-ai/cordis": "*"},
"dsh": {"bundle": {"patch": "./cordis.patch.yml"}},
}, indent=2))
(plugin / "index.js").write_text(
"import { Context } from '@deepseek-ai/cordis'\n"
"export const name = 'python-sdk-blackbox-plugin'\n"
"export const inject = ['systemPrompt']\n"
"export function apply(ctx) {\n"
" if (!(ctx instanceof Context)) throw new Error('external plugin loaded a second Cordis instance')\n"
" ctx.effect(() => ctx.systemPrompt.section({\n"
" name: 'python-sdk:blackbox-plugin',\n"
" order: 10,\n"
f" text: '{PROFILE_PLUGIN_MARKER}',\n"
" }))\n"
"}\n"
)
(plugin / "cordis.patch.yml").write_text(json.dumps([{
"insert": [{"id": "python-sdk-blackbox-plugin", "name": "dsh-python-blackbox-plugin"}],
}], indent=2))
dsh = Path(sysconfig.get_path("scripts")) / ("dsh.exe" if IS_WINDOWS else "dsh")
environment = {**os.environ, "DSH_HOME": str(dsh_home)}
installed = subprocess.run(
[str(dsh), "plugin", "--profile", "sdk", "add", f"file:{plugin}"],
cwd=root,
env=environment,
text=True,
capture_output=True,
check=False,
)
if installed.returncode != 0:
raise AssertionError(
f"Python-installed dsh could not add the external profile plugin: "
f"stdout={installed.stdout!r} stderr={installed.stderr!r}"
)
manifest = json.loads((dsh_home / "profiles" / "sdk" / "package.json").read_text())
if "dsh-python-blackbox-plugin" not in manifest.get("dependencies", {}):
raise AssertionError(f"dsh plugin did not record the external dependency: {manifest}")
if "dsh-python-blackbox-plugin" not in manifest["dsh"]["profile"]["bundles"]:
raise AssertionError(f"dsh plugin did not activate the external bundle: {manifest}")
harness = DeepSeekHarness(
provider="deepseek-official",
model="smoke-model",
cwd=str(root),
dsh_home=str(dsh_home),
env={
"DSH_PERMISSION_MODE": "danger-full-access",
"DSH_TELEMETRY_DISABLED": "1",
},
api_key="sk-keyless-smoke",
base_url=base_url,
request_timeout_seconds=60,
)
try:
with harness:
result = harness.run(PROFILE_PLUGIN_PROMPT, session_id="profile-plugin-smoke")
except Exception as error:
raise AssertionError(
f"external profile plugin runtime failed: {harness.client._runtime_diagnostics()}"
) from error
assert result.final_response == PROFILE_PLUGIN_TEXT, result.final_response
assert_zstd_session_log(dsh_home / "sessions")
def smoke_sdk_snapshot(base_url: str, executable: Path, update_snapshots: bool) -> None:
"""Drive and compare the advanced SDK/executable behavioral snapshot."""
from deepseek_harness import DeepSeekHarness
with tempfile.TemporaryDirectory(prefix="dsh-sdk-snapshot-") as temporary:
root = Path(temporary).resolve()
sessions = root / "sessions"
cordis = root / "cordis.yml"
cordis.write_text(CUSTOM_CORDIS)
dsh_home = root / "home"
sessions = dsh_home / "sessions"
patch = write_profile_patch(root, "snapshot.patch.yml", sessions, [
{"id": "tools", "config": {"mode": "both"}},
{
"id": "system-prompt",
"config": {
"persona": "You are a coding agent powered by the {{model}} model. Your working directory is {{cwd}}.",
},
},
{"id": "session-log-deepseek", "config": {"enabled": True}},
*({"id": row_id, "disabled": True} for row_id in LEGACY_CUSTOM_DISABLED_ROWS),
{"id": "tool-bash", "disabled": True},
{"id": "tool-pwsh", "disabled": True},
{
"id": "tool-subagent",
"config": {
"provider": "spawn",
"toolName": "subagent",
"backgroundMode": "one-shot",
},
},
{"insert": [
{"id": "code-runtime", "name": "@deepseek-ai/dsh-code-runtime-worker-thread"},
{"id": "cordis-host-runner", "name": "@deepseek-ai/dsh-cordis-host-runner"},
{"id": "cordis-tool", "name": "@deepseek-ai/dsh-tool-cordis"},
]},
])
with DeepSeekHarness(
provider="deepseek-official",
model="smoke-model",
cwd=str(root),
session_root=str(sessions),
cordis=str(cordis),
runtime_bin=str(executable),
dsh_bin=str(executable),
dsh_home=str(dsh_home),
patches=(str(patch),),
env={
"DSH_PERMISSION_MODE": "danger-full-access",
"DSH_TELEMETRY_DISABLED": "1",
},
api_key="sk-keyless-smoke",
base_url=base_url,
request_timeout_seconds=60,
@@ -1103,9 +1245,34 @@ def smoke_sdk_restart_snapshot(base_url: str, executable: Path, update_snapshots
with tempfile.TemporaryDirectory(prefix="dsh-sdk-restart-") as temporary:
root = Path(temporary).resolve()
sessions = root / "sessions"
cordis = root / "cordis.yml"
cordis.write_text(CUSTOM_CORDIS)
dsh_home = root / "home"
sessions = dsh_home / "sessions"
patch = write_profile_patch(root, "restart.patch.yml", sessions, [
{"id": "tools", "config": {"mode": "both"}},
{
"id": "system-prompt",
"config": {
"persona": "You are a coding agent powered by the {{model}} model. Your working directory is {{cwd}}.",
},
},
{"id": "session-log-deepseek", "config": {"enabled": True}},
*({"id": row_id, "disabled": True} for row_id in LEGACY_CUSTOM_DISABLED_ROWS),
{"id": "tool-bash", "disabled": True},
{"id": "tool-pwsh", "disabled": True},
{
"id": "tool-subagent",
"config": {
"provider": "spawn",
"toolName": "subagent",
"backgroundMode": "one-shot",
},
},
{"insert": [
{"id": "code-runtime", "name": "@deepseek-ai/dsh-code-runtime-worker-thread"},
{"id": "cordis-host-runner", "name": "@deepseek-ai/dsh-cordis-host-runner"},
{"id": "cordis-tool", "name": "@deepseek-ai/dsh-tool-cordis"},
]},
])
first_request = len(MockModelHandler.requests)
def run(prompt: str, session_id: str) -> "RunResult":
@@ -1113,9 +1280,13 @@ def smoke_sdk_restart_snapshot(base_url: str, executable: Path, update_snapshots
provider="deepseek-official",
model="smoke-model",
cwd=str(root),
session_root=str(sessions),
cordis=str(cordis),
runtime_bin=str(executable),
dsh_bin=str(executable),
dsh_home=str(dsh_home),
patches=(str(patch),),
env={
"DSH_PERMISSION_MODE": "danger-full-access",
"DSH_TELEMETRY_DISABLED": "1",
},
api_key="sk-keyless-smoke",
base_url=base_url,
request_timeout_seconds=60,
@@ -1155,18 +1326,22 @@ def smoke_sdk_restart_snapshot(base_url: str, executable: Path, update_snapshots
def smoke_direct(base_url: str, executable: Path) -> None:
with tempfile.TemporaryDirectory(prefix="dsh-direct-") as temporary:
root = Path(temporary).resolve()
sessions = root / "sessions"
cordis = root / "cordis.yml"
cordis.write_text(CUSTOM_CORDIS)
dsh_home = root / "home"
sessions = dsh_home / "sessions"
patch = write_profile_patch(root, "direct.patch.yml", sessions, [])
environment = {
**os.environ,
"DSH_CORDIS_CONFIG": str(cordis),
"DSH_SESSION_ROOT": str(sessions),
"DSH_CWD": str(root),
"DSH_HOME": str(dsh_home),
"DSH_PERMISSION_MODE": "danger-full-access",
"DSH_TELEMETRY_DISABLED": "1",
"DEEPSEEK_API_KEY": "sk-keyless-smoke",
"DEEPSEEK_BASE_URL": base_url,
}
peer = RuntimePeer([str(executable)], root, environment)
peer = RuntimePeer(
[str(executable), "--profile", "sdk", "--patch", str(patch)],
root,
environment,
)
try:
peer.send({"jsonrpc": "2.0", "id": "initialize", "method": "initialize", "params": {"cwd": str(root), "provider": "deepseek-official", "model": "smoke-model"}})
peer.read_until(lambda message: message.get("id") == "initialize")
@@ -1332,9 +1507,9 @@ def build_minimal_snapshot_files(
Every assembled system prompt, advertised tool schema, and system or user message is
kept verbatim: they carry what the deployment actually shows the model, so a plugin
that contributes an unintended system section or user message cannot pass unnoticed.
Assistant and tool payloads keep only their call identity, and the dynamic
runtime-context snapshot is dropped, because their text differs across the platforms
this expected output must replay on.
Assistant and tool payloads keep only their call identity because their text differs
across the platforms this expected output must replay on. The shipped profile omits
dynamic runtime context, so every message it emits is compared.
"""
snapshot = []
for body in requests:
@@ -1346,21 +1521,11 @@ def build_minimal_snapshot_files(
"messages": [
minimal_snapshot_message(message, cwd)
for message in messages
if not is_runtime_context_message(message)
],
})
return {"model-visible.json": json.dumps(snapshot, indent=2, ensure_ascii=False) + "\n"}
def is_runtime_context_message(message: object) -> bool:
"""Identify the agent loop's dynamic runtime-context snapshot, current or cleared."""
return (
isinstance(message, dict)
and message.get("role") == "user"
and message_text(message.get("content")).startswith(RUNTIME_CONTEXT_PREFIX)
)
def minimal_snapshot_message(message: object, cwd: Path) -> dict[str, object]:
"""Reduce one model-visible message to its stable, behavior-carrying parts."""
if not isinstance(message, dict):
@@ -1419,7 +1584,6 @@ def build_snapshot_files(
{"method": notification.method, "payload": notification.payload}
for notification in result.notifications
],
"session_root": result.session_root,
}
normalized_result = normalize_snapshot_value(result_value, replacements)
files = {
@@ -1461,7 +1625,6 @@ def build_restart_snapshot_files(
"finish_reason": result.finish_reason,
"eventTypes": [event.get("type") for event in result.events],
"notificationMethods": [notification.method for notification in result.notifications],
"session_root": result.session_root,
}
for result in (first, second)
]
@@ -1611,7 +1774,7 @@ def compare_snapshot_files(
if update:
directory.mkdir(parents=True, exist_ok=True)
for name, content in files.items():
(directory / name).write_text(content, encoding="utf-8")
(directory / name).write_text(content, encoding="utf-8", newline="\n")
print(f"smoke-python-runtime: updated snapshots in {directory}")
existing = {
File diff suppressed because it is too large Load Diff
@@ -1,20 +1,23 @@
{"type":"session","version":0,"id":"{{child-1}}","createdAt":0,"cwd":"{{cwd}}","parentSession":"{{parent}}","origin":"subagent","delegationDepth":1}
{"type":"sandbox/mode","data":{"mode":"danger-full-access","source":"delegation"}}
{"type":"approval/policy","data":{"policy":"never","source":"delegation"}}
{"type":"permission/preset","data":{"preset":"danger-full-access"}}
{"type":"agent/inbox/spliced","data":{"target":"next-turn","start":0,"inserted":[{"content":[{"type":"text","text":"Reply with exactly DIRECT_CHILD_OK and nothing else."}],"source":{"kind":"user"},"role":"user","id":"{{messageId}}"}]}}
{"type":"turn/start","data":{"turn":1}}
{"type":"agent/inbox/spliced","data":{"target":"next-turn","start":0,"removedCount":1,"inserted":[]}}
{"type":"subagent/descriptor","data":{"version":2,"mode":"one-shot","provider":"spawn","label":"Check direct child"}}
{"type":"subagent/descriptor","data":{"version":3,"mode":"one-shot","provider":"spawn","label":"Check direct child"}}
{"type":"step/start","data":{"turn":1,"step":1}}
{"type":"user/message","data":{"content":[{"type":"text","text":"Reply with exactly DIRECT_CHILD_OK and nothing else."}],"source":{"kind":"user"},"role":"user","id":"{{messageId}}"},"surfaceOp":"append"}
{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nYou are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the task needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it."}],"source":{"kind":"plugin","plugin":"@deepseek-ai/dsh-system-prompt","form":"snapshot","sections":[{"name":"subagent:delegation","text":"You are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the task needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it."}]},"role":"user","id":"{{messageId}}"},"surfaceOp":"append"}
{"type":"session/title","data":{"title":"Reply with exactly DIRECT_CHILD_OK and","messageSeqs":[5],"source":{"kind":"fallback"}}}
{"type":"request/header","data":{"header":{"config":{"provider":"deepseek-official","model":"smoke-model","maxTokens":256000,"reasoningEffort":"high"},"adapterDefaults":{"reasoningEffort":true,"maxTokens":true},"system":"{{system}}","tools":["cordis_define","cordis_inspect_list","cordis_inspect_query","cordis_inspect_self","cordis_run","cordis_stop","cordis_undefine","job_kill","job_list","job_output","run_code","snapshot_double","subagent","workflow"]},"reason":"initial"}}
{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations.\n\nApproval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`).\n\nYou are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the task needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it."}],"source":{"kind":"plugin","plugin":"@deepseek-ai/dsh-system-prompt","form":"snapshot","sections":[{"name":"sandbox:policy","text":"Current DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations."},{"name":"approval:policy","text":"Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."},{"name":"subagent:delegation","text":"You are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the task needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it."}]},"role":"user","id":"{{messageId}}"},"surfaceOp":"append"}
{"type":"session/title","data":{"title":"Reply with exactly DIRECT_CHILD_OK and","messageSeqs":[8],"source":{"kind":"fallback"}}}
{"type":"request/header","data":{"header":{"config":{"provider":"deepseek-official","model":"smoke-model","reasoningEffort":"high","maxTokens":256000},"adapterDefaults":{"maxTokens":true},"system":"{{system}}","tools":["cordis_define","cordis_inspect_list","cordis_inspect_query","cordis_inspect_self","cordis_run","cordis_stop","cordis_undefine","job_kill","job_list","job_output","run_code","snapshot_double","subagent","workflow"]},"reason":"initial"}}
{"type":"request/context","data":{"provider":"deepseek-official","model":"smoke-model","contextWindow":1000000}}
{"type":"session-log-deepseek/delivery-accepted","data":{"sessionId":"{{child-1}}","throughSeq":9}}
{"type":"session-log-deepseek/delivery-accepted","data":{"sessionId":"{{child-1}}","throughSeq":12}}
{"type":"assistant/chunk","data":{"turn":1,"step":1,"chunk":{"type":"block-start","index":0,"blockType":"text"}}}
{"type":"assistant/chunk","data":{"turn":1,"step":1,"chunk":{"type":"text-delta","index":0,"text":"DIRECT_CHILD_OK"}}}
{"type":"assistant/chunk","data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"DIRECT_CHILD_OK"}}}}
{"type":"assistant/chunk","data":{"turn":1,"step":1,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
{"type":"assistant/chunk","data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"stop"}}}}
{"type":"assistant/message","data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"text","text":"DIRECT_CHILD_OK"}],"source":{"kind":"model","provider":"deepseek-official","model":"smoke-model"},"id":"{{messageId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[11,12,13,14,15],"surfaceOp":"append"}
{"type":"assistant/message","data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"text","text":"DIRECT_CHILD_OK"}],"source":{"kind":"model","provider":"deepseek-official","model":"smoke-model"},"id":"{{messageId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[14,15,16,17,18],"surfaceOp":"append"}
{"type":"step/end","data":{"turn":1,"step":1}}
{"type":"turn/end","data":{"turn":1,"reason":{"kind":"completed"}}}
@@ -1,20 +1,23 @@
{"type":"session","version":0,"id":"{{child-2}}","createdAt":0,"cwd":"{{cwd}}","parentSession":"{{parent}}","origin":"subagent","delegationDepth":1}
{"type":"sandbox/mode","data":{"mode":"danger-full-access","source":"delegation"}}
{"type":"approval/policy","data":{"policy":"never","source":"delegation"}}
{"type":"permission/preset","data":{"preset":"danger-full-access"}}
{"type":"agent/inbox/spliced","data":{"target":"next-turn","start":0,"inserted":[{"content":[{"type":"text","text":"Reply with exactly WORKFLOW_CHILD_OK and nothing else."}],"source":{"kind":"user"},"role":"user","id":"{{messageId}}"}]}}
{"type":"turn/start","data":{"turn":1}}
{"type":"agent/inbox/spliced","data":{"target":"next-turn","start":0,"removedCount":1,"inserted":[]}}
{"type":"subagent/descriptor","data":{"version":2,"mode":"one-shot","provider":"spawn"}}
{"type":"subagent/descriptor","data":{"version":3,"mode":"one-shot","provider":"spawn"}}
{"type":"step/start","data":{"turn":1,"step":1}}
{"type":"user/message","data":{"content":[{"type":"text","text":"Reply with exactly WORKFLOW_CHILD_OK and nothing else."}],"source":{"kind":"user"},"role":"user","id":"{{messageId}}"},"surfaceOp":"append"}
{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nYou are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the task needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it."}],"source":{"kind":"plugin","plugin":"@deepseek-ai/dsh-system-prompt","form":"snapshot","sections":[{"name":"subagent:delegation","text":"You are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the task needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it."}]},"role":"user","id":"{{messageId}}"},"surfaceOp":"append"}
{"type":"session/title","data":{"title":"Reply with exactly WORKFLOW_CHILD_OK and","messageSeqs":[5],"source":{"kind":"fallback"}}}
{"type":"request/header","data":{"header":{"config":{"provider":"deepseek-official","model":"smoke-model","maxTokens":256000,"reasoningEffort":"high"},"adapterDefaults":{"reasoningEffort":true,"maxTokens":true},"system":"{{system}}","tools":["cordis_define","cordis_inspect_list","cordis_inspect_query","cordis_inspect_self","cordis_run","cordis_stop","cordis_undefine","job_kill","job_list","job_output","run_code","snapshot_double","subagent","workflow"]},"reason":"initial"}}
{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations.\n\nApproval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`).\n\nYou are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the task needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it."}],"source":{"kind":"plugin","plugin":"@deepseek-ai/dsh-system-prompt","form":"snapshot","sections":[{"name":"sandbox:policy","text":"Current DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations."},{"name":"approval:policy","text":"Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."},{"name":"subagent:delegation","text":"You are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the task needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it."}]},"role":"user","id":"{{messageId}}"},"surfaceOp":"append"}
{"type":"session/title","data":{"title":"Reply with exactly WORKFLOW_CHILD_OK and","messageSeqs":[8],"source":{"kind":"fallback"}}}
{"type":"request/header","data":{"header":{"config":{"provider":"deepseek-official","model":"smoke-model","reasoningEffort":"high","maxTokens":256000},"adapterDefaults":{"maxTokens":true},"system":"{{system}}","tools":["cordis_define","cordis_inspect_list","cordis_inspect_query","cordis_inspect_self","cordis_run","cordis_stop","cordis_undefine","job_kill","job_list","job_output","run_code","snapshot_double","subagent","workflow"]},"reason":"initial"}}
{"type":"request/context","data":{"provider":"deepseek-official","model":"smoke-model","contextWindow":1000000}}
{"type":"session-log-deepseek/delivery-accepted","data":{"sessionId":"{{child-2}}","throughSeq":9}}
{"type":"session-log-deepseek/delivery-accepted","data":{"sessionId":"{{child-2}}","throughSeq":12}}
{"type":"assistant/chunk","data":{"turn":1,"step":1,"chunk":{"type":"block-start","index":0,"blockType":"text"}}}
{"type":"assistant/chunk","data":{"turn":1,"step":1,"chunk":{"type":"text-delta","index":0,"text":"WORKFLOW_CHILD_OK"}}}
{"type":"assistant/chunk","data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"WORKFLOW_CHILD_OK"}}}}
{"type":"assistant/chunk","data":{"turn":1,"step":1,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
{"type":"assistant/chunk","data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"stop"}}}}
{"type":"assistant/message","data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"text","text":"WORKFLOW_CHILD_OK"}],"source":{"kind":"model","provider":"deepseek-official","model":"smoke-model"},"id":"{{messageId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[11,12,13,14,15],"surfaceOp":"append"}
{"type":"assistant/message","data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"text","text":"WORKFLOW_CHILD_OK"}],"source":{"kind":"model","provider":"deepseek-official","model":"smoke-model"},"id":"{{messageId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[14,15,16,17,18],"surfaceOp":"append"}
{"type":"step/end","data":{"turn":1,"step":1}}
{"type":"turn/end","data":{"turn":1,"reason":{"kind":"completed"}}}
@@ -1,92 +1,96 @@
{"type":"session","version":0,"id":"{{parent}}","createdAt":0,"cwd":"{{cwd}}","delegationDepth":0}
{"type":"permission/preset","data":{"preset":"danger-full-access"}}
{"type":"sandbox/mode","data":{"mode":"danger-full-access"}}
{"type":"approval/policy","data":{"policy":"never"}}
{"type":"agent/inbox/spliced","data":{"target":"next-turn","start":0,"inserted":[{"content":[{"type":"text","text":"Run the advanced packaged-runtime snapshot scenario."}],"source":{"kind":"user"},"role":"user","id":"{{messageId}}"}]}}
{"type":"turn/start","data":{"turn":1}}
{"type":"agent/inbox/spliced","data":{"target":"next-turn","start":0,"removedCount":1,"inserted":[]}}
{"type":"step/start","data":{"turn":1,"step":1}}
{"type":"user/message","data":{"content":[{"type":"text","text":"Run the advanced packaged-runtime snapshot scenario."}],"source":{"kind":"user"},"role":"user","id":"{{messageId}}"},"surfaceOp":"append"}
{"type":"session/title","data":{"title":"Run the advanced packaged-runtime snapsh","messageSeqs":[4],"source":{"kind":"fallback"}}}
{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations.\n\nApproval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."}],"source":{"kind":"plugin","plugin":"@deepseek-ai/dsh-system-prompt","form":"snapshot","sections":[{"name":"sandbox:policy","text":"Current DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations."},{"name":"approval:policy","text":"Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."}]},"role":"user","id":"{{messageId}}"},"surfaceOp":"append"}
{"type":"session/title","data":{"title":"Run the advanced packaged-runtime snapsh","messageSeqs":[7],"source":{"kind":"fallback"}}}
{"type":"request/header","data":{"header":{"config":{"provider":"deepseek-official","model":"smoke-model","maxTokens":256000,"reasoningEffort":"high"},"adapterDefaults":{"reasoningEffort":true,"maxTokens":true},"system":"{{system}}","tools":["cordis_define","cordis_inspect_list","cordis_inspect_query","cordis_inspect_self","cordis_run","cordis_stop","cordis_undefine","job_kill","job_list","job_output","run_code","subagent","workflow"]},"reason":"initial"}}
{"type":"request/context","data":{"provider":"deepseek-official","model":"smoke-model","contextWindow":1000000}}
{"type":"session-log-deepseek/delivery-accepted","data":{"sessionId":"{{parent}}","throughSeq":7}}
{"type":"session-log-deepseek/delivery-accepted","data":{"sessionId":"{{parent}}","throughSeq":11}}
{"type":"assistant/chunk","data":{"turn":1,"step":1,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}
{"type":"assistant/chunk","data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":0,"id":"advanced-define","name":"cordis_define","argumentsDelta":"{\"plugin\": {\"kind\": \"new\", \"idPrefix\": \"snap\"}, \"name\": \"Snapshot Double\", \"purpose\": \"Expose a deterministic doubling tool for executable snapshot verification.\", \"code\": {\"host\": \"return (ctx) => {\\n harness.registerTool(ctx, harness.defineTool({\\n name: 'snapshot_double',\\n description: 'Double a number for executable snapshot verification.',\\n parameters: { value: { type: 'number', required: true } },\\n output: {\\n schema: { type: 'number' },\\n render(_args, value) {\\n return [{ type: 'text', text: String(value) }]\\n }\\n },\\n async execute(args) {\\n return args.value * 2\\n }\\n }))\\n}\\n\"}}"}}}
{"type":"assistant/chunk","data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"advanced-define","name":"cordis_define","arguments":"{\"plugin\": {\"kind\": \"new\", \"idPrefix\": \"snap\"}, \"name\": \"Snapshot Double\", \"purpose\": \"Expose a deterministic doubling tool for executable snapshot verification.\", \"code\": {\"host\": \"return (ctx) => {\\n harness.registerTool(ctx, harness.defineTool({\\n name: 'snapshot_double',\\n description: 'Double a number for executable snapshot verification.',\\n parameters: { value: { type: 'number', required: true } },\\n output: {\\n schema: { type: 'number' },\\n render(_args, value) {\\n return [{ type: 'text', text: String(value) }]\\n }\\n },\\n async execute(args) {\\n return args.value * 2\\n }\\n }))\\n}\\n\"}}"}}}}
{"type":"assistant/chunk","data":{"turn":1,"step":1,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
{"type":"assistant/chunk","data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}
{"type":"assistant/message","data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"tool-call","id":"advanced-define","name":"cordis_define","arguments":"{\"plugin\": {\"kind\": \"new\", \"idPrefix\": \"snap\"}, \"name\": \"Snapshot Double\", \"purpose\": \"Expose a deterministic doubling tool for executable snapshot verification.\", \"code\": {\"host\": \"return (ctx) => {\\n harness.registerTool(ctx, harness.defineTool({\\n name: 'snapshot_double',\\n description: 'Double a number for executable snapshot verification.',\\n parameters: { value: { type: 'number', required: true } },\\n output: {\\n schema: { type: 'number' },\\n render(_args, value) {\\n return [{ type: 'text', text: String(value) }]\\n }\\n },\\n async execute(args) {\\n return args.value * 2\\n }\\n }))\\n}\\n\"}}"}],"source":{"kind":"model","provider":"deepseek-official","model":"smoke-model"},"id":"{{messageId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[9,10,11,12,13],"surfaceOp":"append"}
{"type":"assistant/message","data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"tool-call","id":"advanced-define","name":"cordis_define","arguments":"{\"plugin\": {\"kind\": \"new\", \"idPrefix\": \"snap\"}, \"name\": \"Snapshot Double\", \"purpose\": \"Expose a deterministic doubling tool for executable snapshot verification.\", \"code\": {\"host\": \"return (ctx) => {\\n harness.registerTool(ctx, harness.defineTool({\\n name: 'snapshot_double',\\n description: 'Double a number for executable snapshot verification.',\\n parameters: { value: { type: 'number', required: true } },\\n output: {\\n schema: { type: 'number' },\\n render(_args, value) {\\n return [{ type: 'text', text: String(value) }]\\n }\\n },\\n async execute(args) {\\n return args.value * 2\\n }\\n }))\\n}\\n\"}}"}],"source":{"kind":"model","provider":"deepseek-official","model":"smoke-model"},"id":"{{messageId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[13,14,15,16,17],"surfaceOp":"append"}
{"type":"tool/call","data":{"turn":1,"step":1,"callId":"advanced-define","name":"cordis_define","arguments":"{\"plugin\": {\"kind\": \"new\", \"idPrefix\": \"snap\"}, \"name\": \"Snapshot Double\", \"purpose\": \"Expose a deterministic doubling tool for executable snapshot verification.\", \"code\": {\"host\": \"return (ctx) => {\\n harness.registerTool(ctx, harness.defineTool({\\n name: 'snapshot_double',\\n description: 'Double a number for executable snapshot verification.',\\n parameters: { value: { type: 'number', required: true } },\\n output: {\\n schema: { type: 'number' },\\n render(_args, value) {\\n return [{ type: 'text', text: String(value) }]\\n }\\n },\\n async execute(args) {\\n return args.value * 2\\n }\\n }))\\n}\\n\"}}"}}
{"type":"tool/result","data":{"turn":1,"step":1,"message":{"source":{"kind":"tool","callId":"advanced-define"},"content":[{"type":"tool-result","toolCallId":"advanced-define","content":[{"type":"text","text":"Defined snap-1/pkg-1 (Snapshot Double); it is not running yet. Use cordis_run to activate this Package."}],"isError":false}],"role":"user","id":"{{messageId}}"},"meta":{"pluginId":"snap-1","packageId":"pkg-1"}},"sourceEventSeqs":[15],"surfaceOp":"append"}
{"type":"tool/result","data":{"turn":1,"step":1,"message":{"source":{"kind":"tool","callId":"advanced-define"},"content":[{"type":"tool-result","toolCallId":"advanced-define","content":[{"type":"text","text":"Defined snap-1/pkg-1 (Snapshot Double); it is not running yet. Use cordis_run to activate this Package."}],"isError":false}],"role":"user","id":"{{messageId}}"},"meta":{"pluginId":"snap-1","packageId":"pkg-1"}},"sourceEventSeqs":[19],"surfaceOp":"append"}
{"type":"step/end","data":{"turn":1,"step":1}}
{"type":"step/start","data":{"turn":1,"step":2}}
{"type":"session-log-deepseek/delivery-accepted","data":{"sessionId":"{{parent}}","throughSeq":18}}
{"type":"session-log-deepseek/delivery-accepted","data":{"sessionId":"{{parent}}","throughSeq":22}}
{"type":"assistant/chunk","data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}
{"type":"assistant/chunk","data":{"turn":1,"step":2,"chunk":{"type":"tool-call-delta","index":0,"id":"advanced-run","name":"cordis_run","argumentsDelta":"{\"pluginId\": \"snap-1\", \"packageId\": \"pkg-1\", \"mode\": \"run\"}"}}}
{"type":"assistant/chunk","data":{"turn":1,"step":2,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"advanced-run","name":"cordis_run","arguments":"{\"pluginId\": \"snap-1\", \"packageId\": \"pkg-1\", \"mode\": \"run\"}"}}}}
{"type":"assistant/chunk","data":{"turn":1,"step":2,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
{"type":"assistant/chunk","data":{"turn":1,"step":2,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}
{"type":"assistant/message","data":{"turn":1,"step":2,"message":{"role":"assistant","content":[{"type":"tool-call","id":"advanced-run","name":"cordis_run","arguments":"{\"pluginId\": \"snap-1\", \"packageId\": \"pkg-1\", \"mode\": \"run\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"smoke-model"},"id":"{{messageId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[20,21,22,23,24],"surfaceOp":"append"}
{"type":"assistant/message","data":{"turn":1,"step":2,"message":{"role":"assistant","content":[{"type":"tool-call","id":"advanced-run","name":"cordis_run","arguments":"{\"pluginId\": \"snap-1\", \"packageId\": \"pkg-1\", \"mode\": \"run\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"smoke-model"},"id":"{{messageId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[24,25,26,27,28],"surfaceOp":"append"}
{"type":"tool/call","data":{"turn":1,"step":2,"callId":"advanced-run","name":"cordis_run","arguments":"{\"pluginId\": \"snap-1\", \"packageId\": \"pkg-1\", \"mode\": \"run\"}"}}
{"type":"tool/result","data":{"turn":1,"step":2,"message":{"source":{"kind":"tool","callId":"advanced-run"},"content":[{"type":"tool-result","toolCallId":"advanced-run","content":[{"type":"text","text":"snap-1/pkg-1 is running (run-1)."}],"isError":false}],"role":"user","id":"{{messageId}}"},"meta":{"pluginId":"snap-1","packageId":"pkg-1","pluginRunId":"run-1"}},"sourceEventSeqs":[26],"surfaceOp":"append"}
{"type":"tool/result","data":{"turn":1,"step":2,"message":{"source":{"kind":"tool","callId":"advanced-run"},"content":[{"type":"tool-result","toolCallId":"advanced-run","content":[{"type":"text","text":"snap-1/pkg-1 is running (run-1)."}],"isError":false}],"role":"user","id":"{{messageId}}"},"meta":{"pluginId":"snap-1","packageId":"pkg-1","pluginRunId":"run-1"}},"sourceEventSeqs":[30],"surfaceOp":"append"}
{"type":"step/end","data":{"turn":1,"step":2}}
{"type":"step/start","data":{"turn":1,"step":3}}
{"type":"request/header","data":{"header":{"config":{"provider":"deepseek-official","model":"smoke-model","maxTokens":256000,"reasoningEffort":"high"},"adapterDefaults":{"reasoningEffort":true,"maxTokens":true},"system":"{{system}}","tools":["cordis_define","cordis_inspect_list","cordis_inspect_query","cordis_inspect_self","cordis_run","cordis_stop","cordis_undefine","job_kill","job_list","job_output","run_code","snapshot_double","subagent","workflow"]},"reason":"change"}}
{"type":"session-log-deepseek/delivery-accepted","data":{"sessionId":"{{parent}}","throughSeq":30}}
{"type":"session-log-deepseek/delivery-accepted","data":{"sessionId":"{{parent}}","throughSeq":34}}
{"type":"assistant/chunk","data":{"turn":1,"step":3,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}
{"type":"assistant/chunk","data":{"turn":1,"step":3,"chunk":{"type":"tool-call-delta","index":0,"id":"advanced-code","name":"run_code","argumentsDelta":"{\"code\": \"return await tools.snapshot_double({ value: 21 })\", \"description\": \"Run the temporary Plugin tool\"}"}}}
{"type":"assistant/chunk","data":{"turn":1,"step":3,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"advanced-code","name":"run_code","arguments":"{\"code\": \"return await tools.snapshot_double({ value: 21 })\", \"description\": \"Run the temporary Plugin tool\"}"}}}}
{"type":"assistant/chunk","data":{"turn":1,"step":3,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
{"type":"assistant/chunk","data":{"turn":1,"step":3,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}
{"type":"assistant/message","data":{"turn":1,"step":3,"message":{"role":"assistant","content":[{"type":"tool-call","id":"advanced-code","name":"run_code","arguments":"{\"code\": \"return await tools.snapshot_double({ value: 21 })\", \"description\": \"Run the temporary Plugin tool\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"smoke-model"},"id":"{{messageId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[32,33,34,35,36],"surfaceOp":"append"}
{"type":"assistant/message","data":{"turn":1,"step":3,"message":{"role":"assistant","content":[{"type":"tool-call","id":"advanced-code","name":"run_code","arguments":"{\"code\": \"return await tools.snapshot_double({ value: 21 })\", \"description\": \"Run the temporary Plugin tool\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"smoke-model"},"id":"{{messageId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[36,37,38,39,40],"surfaceOp":"append"}
{"type":"tool/call","data":{"turn":1,"step":3,"callId":"advanced-code","name":"run_code","arguments":"{\"code\": \"return await tools.snapshot_double({ value: 21 })\", \"description\": \"Run the temporary Plugin tool\"}"}}
{"type":"tool/code-dispatch-start","data":{"rootCallId":"advanced-code","parentCallId":"advanced-code","subCallId":"advanced-code:code:1","name":"snapshot_double","arguments":{"value":21}}}
{"type":"tool/code-dispatch","data":{"rootCallId":"advanced-code","parentCallId":"advanced-code","subCallId":"advanced-code:code:1","name":"snapshot_double","arguments":{"value":21},"isError":false,"content":[{"type":"text","text":"42"}]}}
{"type":"tool/result","data":{"turn":1,"step":3,"message":{"source":{"kind":"tool","callId":"advanced-code"},"content":[{"type":"tool-result","toolCallId":"advanced-code","content":[{"type":"text","text":"42"}],"isError":false}],"role":"user","id":"{{messageId}}"}},"sourceEventSeqs":[38],"surfaceOp":"append"}
{"type":"tool/result","data":{"turn":1,"step":3,"message":{"source":{"kind":"tool","callId":"advanced-code"},"content":[{"type":"tool-result","toolCallId":"advanced-code","content":[{"type":"text","text":"42"}],"isError":false}],"role":"user","id":"{{messageId}}"}},"sourceEventSeqs":[42],"surfaceOp":"append"}
{"type":"step/end","data":{"turn":1,"step":3}}
{"type":"step/start","data":{"turn":1,"step":4}}
{"type":"session-log-deepseek/delivery-accepted","data":{"sessionId":"{{parent}}","throughSeq":43}}
{"type":"session-log-deepseek/delivery-accepted","data":{"sessionId":"{{parent}}","throughSeq":47}}
{"type":"assistant/chunk","data":{"turn":1,"step":4,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}
{"type":"assistant/chunk","data":{"turn":1,"step":4,"chunk":{"type":"tool-call-delta","index":0,"id":"advanced-direct-child","name":"subagent","argumentsDelta":"{\"description\": \"Check direct child\", \"prompt\": \"Reply with exactly DIRECT_CHILD_OK and nothing else.\"}"}}}
{"type":"assistant/chunk","data":{"turn":1,"step":4,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"advanced-direct-child","name":"subagent","arguments":"{\"description\": \"Check direct child\", \"prompt\": \"Reply with exactly DIRECT_CHILD_OK and nothing else.\"}"}}}}
{"type":"assistant/chunk","data":{"turn":1,"step":4,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
{"type":"assistant/chunk","data":{"turn":1,"step":4,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}
{"type":"assistant/message","data":{"turn":1,"step":4,"message":{"role":"assistant","content":[{"type":"tool-call","id":"advanced-direct-child","name":"subagent","arguments":"{\"description\": \"Check direct child\", \"prompt\": \"Reply with exactly DIRECT_CHILD_OK and nothing else.\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"smoke-model"},"id":"{{messageId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[45,46,47,48,49],"surfaceOp":"append"}
{"type":"assistant/message","data":{"turn":1,"step":4,"message":{"role":"assistant","content":[{"type":"tool-call","id":"advanced-direct-child","name":"subagent","arguments":"{\"description\": \"Check direct child\", \"prompt\": \"Reply with exactly DIRECT_CHILD_OK and nothing else.\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"smoke-model"},"id":"{{messageId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[49,50,51,52,53],"surfaceOp":"append"}
{"type":"tool/call","data":{"turn":1,"step":4,"callId":"advanced-direct-child","name":"subagent","arguments":"{\"description\": \"Check direct child\", \"prompt\": \"Reply with exactly DIRECT_CHILD_OK and nothing else.\"}"}}
{"type":"tool/result","data":{"turn":1,"step":4,"message":{"source":{"kind":"tool","callId":"advanced-direct-child"},"content":[{"type":"tool-result","toolCallId":"advanced-direct-child","content":[{"type":"text","text":"DIRECT_CHILD_OK"}],"isError":false}],"role":"user","id":"{{messageId}}"}},"sourceEventSeqs":[51],"surfaceOp":"append"}
{"type":"tool/result","data":{"turn":1,"step":4,"message":{"source":{"kind":"tool","callId":"advanced-direct-child"},"content":[{"type":"tool-result","toolCallId":"advanced-direct-child","content":[{"type":"text","text":"DIRECT_CHILD_OK"}],"isError":false}],"role":"user","id":"{{messageId}}"}},"sourceEventSeqs":[55],"surfaceOp":"append"}
{"type":"step/end","data":{"turn":1,"step":4}}
{"type":"step/start","data":{"turn":1,"step":5}}
{"type":"session-log-deepseek/delivery-accepted","data":{"sessionId":"{{parent}}","throughSeq":54}}
{"type":"session-log-deepseek/delivery-accepted","data":{"sessionId":"{{parent}}","throughSeq":58}}
{"type":"assistant/chunk","data":{"turn":1,"step":5,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}
{"type":"assistant/chunk","data":{"turn":1,"step":5,"chunk":{"type":"tool-call-delta","index":0,"id":"advanced-workflow","name":"workflow","argumentsDelta":"{\"script\": \"phase('Delegate')\\nconst reply = await agent('Reply with exactly WORKFLOW_CHILD_OK and nothing else.', { label: 'workflow-child' })\\nreturn { reply }\", \"meta\": {\"name\": \"advanced-exe-snapshot\", \"description\": \"exercise one packaged workflow child\"}}"}}}
{"type":"assistant/chunk","data":{"turn":1,"step":5,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"advanced-workflow","name":"workflow","arguments":"{\"script\": \"phase('Delegate')\\nconst reply = await agent('Reply with exactly WORKFLOW_CHILD_OK and nothing else.', { label: 'workflow-child' })\\nreturn { reply }\", \"meta\": {\"name\": \"advanced-exe-snapshot\", \"description\": \"exercise one packaged workflow child\"}}"}}}}
{"type":"assistant/chunk","data":{"turn":1,"step":5,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
{"type":"assistant/chunk","data":{"turn":1,"step":5,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}
{"type":"assistant/message","data":{"turn":1,"step":5,"message":{"role":"assistant","content":[{"type":"tool-call","id":"advanced-workflow","name":"workflow","arguments":"{\"script\": \"phase('Delegate')\\nconst reply = await agent('Reply with exactly WORKFLOW_CHILD_OK and nothing else.', { label: 'workflow-child' })\\nreturn { reply }\", \"meta\": {\"name\": \"advanced-exe-snapshot\", \"description\": \"exercise one packaged workflow child\"}}"}],"source":{"kind":"model","provider":"deepseek-official","model":"smoke-model"},"id":"{{messageId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[56,57,58,59,60],"surfaceOp":"append"}
{"type":"assistant/message","data":{"turn":1,"step":5,"message":{"role":"assistant","content":[{"type":"tool-call","id":"advanced-workflow","name":"workflow","arguments":"{\"script\": \"phase('Delegate')\\nconst reply = await agent('Reply with exactly WORKFLOW_CHILD_OK and nothing else.', { label: 'workflow-child' })\\nreturn { reply }\", \"meta\": {\"name\": \"advanced-exe-snapshot\", \"description\": \"exercise one packaged workflow child\"}}"}],"source":{"kind":"model","provider":"deepseek-official","model":"smoke-model"},"id":"{{messageId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[60,61,62,63,64],"surfaceOp":"append"}
{"type":"tool/call","data":{"turn":1,"step":5,"callId":"advanced-workflow","name":"workflow","arguments":"{\"script\": \"phase('Delegate')\\nconst reply = await agent('Reply with exactly WORKFLOW_CHILD_OK and nothing else.', { label: 'workflow-child' })\\nreturn { reply }\", \"meta\": {\"name\": \"advanced-exe-snapshot\", \"description\": \"exercise one packaged workflow child\"}}"}}
{"type":"tool-workflow/run-start","data":{"runId":"{{workflow-run}}","name":"advanced-exe-snapshot"}}
{"type":"tool-workflow/agent-start","data":{"runId":"{{workflow-run}}","seq":1,"label":"workflow-child","phase":"Delegate","childId":"{{child-2}}"}}
{"type":"tool-workflow/agent-end","data":{"runId":"{{workflow-run}}","seq":1,"outcome":"completed"}}
{"type":"tool-workflow/run-end","data":{"runId":"{{workflow-run}}","stopReason":"completed"}}
{"type":"tool/result","data":{"turn":1,"step":5,"message":{"source":{"kind":"tool","callId":"advanced-workflow"},"content":[{"type":"tool-result","toolCallId":"advanced-workflow","content":[{"type":"text","text":"workflow \"advanced-exe-snapshot\" completed (1 agent).\nReturn value:\n{\n \"reply\": \"WORKFLOW_CHILD_OK\"\n}"}],"isError":false}],"role":"user","id":"{{messageId}}"}},"sourceEventSeqs":[62],"surfaceOp":"append"}
{"type":"tool/result","data":{"turn":1,"step":5,"message":{"source":{"kind":"tool","callId":"advanced-workflow"},"content":[{"type":"tool-result","toolCallId":"advanced-workflow","content":[{"type":"text","text":"workflow \"advanced-exe-snapshot\" completed (1 agent).\nReturn value:\n{\n \"reply\": \"WORKFLOW_CHILD_OK\"\n}"}],"isError":false}],"role":"user","id":"{{messageId}}"}},"sourceEventSeqs":[66],"surfaceOp":"append"}
{"type":"step/end","data":{"turn":1,"step":5}}
{"type":"step/start","data":{"turn":1,"step":6}}
{"type":"session-log-deepseek/delivery-accepted","data":{"sessionId":"{{parent}}","throughSeq":69}}
{"type":"session-log-deepseek/delivery-accepted","data":{"sessionId":"{{parent}}","throughSeq":73}}
{"type":"assistant/chunk","data":{"turn":1,"step":6,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}
{"type":"assistant/chunk","data":{"turn":1,"step":6,"chunk":{"type":"tool-call-delta","index":0,"id":"advanced-undefine","name":"cordis_undefine","argumentsDelta":"{\"pluginId\": \"snap-1\"}"}}}
{"type":"assistant/chunk","data":{"turn":1,"step":6,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"advanced-undefine","name":"cordis_undefine","arguments":"{\"pluginId\": \"snap-1\"}"}}}}
{"type":"assistant/chunk","data":{"turn":1,"step":6,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
{"type":"assistant/chunk","data":{"turn":1,"step":6,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}
{"type":"assistant/message","data":{"turn":1,"step":6,"message":{"role":"assistant","content":[{"type":"tool-call","id":"advanced-undefine","name":"cordis_undefine","arguments":"{\"pluginId\": \"snap-1\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"smoke-model"},"id":"{{messageId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[71,72,73,74,75],"surfaceOp":"append"}
{"type":"assistant/message","data":{"turn":1,"step":6,"message":{"role":"assistant","content":[{"type":"tool-call","id":"advanced-undefine","name":"cordis_undefine","arguments":"{\"pluginId\": \"snap-1\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"smoke-model"},"id":"{{messageId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[75,76,77,78,79],"surfaceOp":"append"}
{"type":"tool/call","data":{"turn":1,"step":6,"callId":"advanced-undefine","name":"cordis_undefine","arguments":"{\"pluginId\": \"snap-1\"}"}}
{"type":"tool/result","data":{"turn":1,"step":6,"message":{"source":{"kind":"tool","callId":"advanced-undefine"},"content":[{"type":"tool-result","toolCallId":"advanced-undefine","content":[{"type":"text","text":"Removed dynamic Plugin snap-1 and all of its Packages."}],"isError":false}],"role":"user","id":"{{messageId}}"}},"sourceEventSeqs":[77],"surfaceOp":"append"}
{"type":"tool/result","data":{"turn":1,"step":6,"message":{"source":{"kind":"tool","callId":"advanced-undefine"},"content":[{"type":"tool-result","toolCallId":"advanced-undefine","content":[{"type":"text","text":"Removed dynamic Plugin snap-1 and all of its Packages."}],"isError":false}],"role":"user","id":"{{messageId}}"}},"sourceEventSeqs":[81],"surfaceOp":"append"}
{"type":"step/end","data":{"turn":1,"step":6}}
{"type":"step/start","data":{"turn":1,"step":7}}
{"type":"request/header","data":{"header":{"config":{"provider":"deepseek-official","model":"smoke-model","maxTokens":256000,"reasoningEffort":"high"},"adapterDefaults":{"reasoningEffort":true,"maxTokens":true},"system":"{{system}}","tools":["cordis_define","cordis_inspect_list","cordis_inspect_query","cordis_inspect_self","cordis_run","cordis_stop","cordis_undefine","job_kill","job_list","job_output","run_code","subagent","workflow"]},"reason":"change"}}
{"type":"session-log-deepseek/delivery-accepted","data":{"sessionId":"{{parent}}","throughSeq":81}}
{"type":"session-log-deepseek/delivery-accepted","data":{"sessionId":"{{parent}}","throughSeq":85}}
{"type":"assistant/chunk","data":{"turn":1,"step":7,"chunk":{"type":"block-start","index":0,"blockType":"text"}}}
{"type":"assistant/chunk","data":{"turn":1,"step":7,"chunk":{"type":"text-delta","index":0,"text":"ADVANCED_EXECUTABLE_OK"}}}
{"type":"assistant/chunk","data":{"turn":1,"step":7,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"ADVANCED_EXECUTABLE_OK"}}}}
{"type":"assistant/chunk","data":{"turn":1,"step":7,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
{"type":"assistant/chunk","data":{"turn":1,"step":7,"chunk":{"type":"finish","reason":{"kind":"stop"}}}}
{"type":"assistant/message","data":{"turn":1,"step":7,"message":{"role":"assistant","content":[{"type":"text","text":"ADVANCED_EXECUTABLE_OK"}],"source":{"kind":"model","provider":"deepseek-official","model":"smoke-model"},"id":"{{messageId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[83,84,85,86,87],"surfaceOp":"append"}
{"type":"assistant/message","data":{"turn":1,"step":7,"message":{"role":"assistant","content":[{"type":"text","text":"ADVANCED_EXECUTABLE_OK"}],"source":{"kind":"model","provider":"deepseek-official","model":"smoke-model"},"id":"{{messageId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[87,88,89,90,91],"surfaceOp":"append"}
{"type":"step/end","data":{"turn":1,"step":7}}
{"type":"turn/end","data":{"turn":1,"reason":{"kind":"completed"}}}
@@ -81,7 +81,7 @@
},
{
"role": "user",
"text": "Exercise the packaged minimal agent's persistent Bash and string-replacement editor.\nEditor path: {{cwd}}/created.txt"
"text": "Exercise the packaged minimal agent's persistent shell and string-replacement editor.\nEditor path: {{cwd}}/created.txt"
}
]
},
@@ -167,7 +167,7 @@
},
{
"role": "user",
"text": "Exercise the packaged minimal agent's persistent Bash and string-replacement editor.\nEditor path: {{cwd}}/created.txt"
"text": "Exercise the packaged minimal agent's persistent shell and string-replacement editor.\nEditor path: {{cwd}}/created.txt"
},
{
"role": "assistant",
@@ -267,7 +267,7 @@
},
{
"role": "user",
"text": "Exercise the packaged minimal agent's persistent Bash and string-replacement editor.\nEditor path: {{cwd}}/created.txt"
"text": "Exercise the packaged minimal agent's persistent shell and string-replacement editor.\nEditor path: {{cwd}}/created.txt"
},
{
"role": "assistant",
@@ -381,7 +381,7 @@
},
{
"role": "user",
"text": "Exercise the packaged minimal agent's persistent Bash and string-replacement editor.\nEditor path: {{cwd}}/created.txt"
"text": "Exercise the packaged minimal agent's persistent shell and string-replacement editor.\nEditor path: {{cwd}}/created.txt"
},
{
"role": "assistant",
@@ -0,0 +1,430 @@
[
{
"tools": [
{
"type": "function",
"function": {
"name": "pwsh",
"description": "Run commands in a PowerShell shell\n* When invoking this tool, the contents of the \"command\" parameter does NOT need to be XML-escaped.\n* You don't have access to the internet via this tool.\n* State is persistent across command calls and discussions with the user.\n* Use native Windows paths (C:\\...) and $env:NAME variables; this is PowerShell, not bash.\n* Please avoid commands that may produce a very large amount of output.\n* Please run long lived commands in the background, e.g. 'Start-Job' or start a server with Start-Process.",
"parameters": {
"type": "object",
"properties": {
"command": {
"type": "string",
"description": "The PowerShell command to run. Relative path is preferred in the command."
}
},
"required": [
"command"
]
}
}
},
{
"type": "function",
"function": {
"name": "str_replace_editor",
"description": "Custom editing tool for viewing, creating and editing files\n* State is persistent across command calls and discussions with the user\n* If `path` is a file, `view` displays the result of applying `cat -n`. If `path` is a directory, `view` lists non-hidden files and directories up to 2 levels deep\n* The `create` command cannot be used if the specified `path` already exists as a file\n* If a `command` generates a long output, it will be truncated and marked with `<response clipped>`\n\nNotes for using the `str_replace` command:\n* The `old_str` parameter should match EXACTLY one or more consecutive lines from the original file. Be mindful of whitespaces!\n* If the `old_str` parameter is not unique in the file, the replacement will not be performed. Make sure to include enough context in `old_str` to make it unique\n* The `new_str` parameter should contain the edited lines that should replace the `old_str`",
"parameters": {
"type": "object",
"properties": {
"command": {
"type": "string",
"description": "The commands to run. Allowed options are: `view`, `create`, `str_replace`, `insert`.",
"enum": [
"view",
"create",
"str_replace",
"insert"
]
},
"path": {
"type": "string",
"description": "Absolute path to file or directory, e.g. `/repo/file.py` or `/repo`."
},
"file_text": {
"type": "string",
"description": "Required parameter of `create` command, with the content of the file to be created."
},
"insert_line": {
"type": "integer",
"description": "Required parameter of `insert` command. The `new_str` will be inserted AFTER the line `insert_line` of `path`."
},
"new_str": {
"type": "string",
"description": "Optional parameter of `str_replace` command containing the new string (if not given, no string will be added). Required parameter of `insert` command containing the string to insert."
},
"old_str": {
"type": "string",
"description": "Required parameter of `str_replace` command containing the string in `path` to replace."
},
"view_range": {
"type": "array",
"description": "Optional parameter of `view` command when `path` points to a file. If none is given, the full file is shown. If provided, the file will be shown in the indicated line number range, e.g. [11, 12] will show lines 11 and 12. Indexing at 1 to start. Setting `[start_line, -1]` shows all lines from `start_line` to the end of the file.",
"items": {
"type": "integer"
}
}
},
"required": [
"command",
"path"
]
}
}
}
],
"messages": [
{
"role": "system",
"text": "You are a helpful software engineer assistant."
},
{
"role": "user",
"text": "Exercise the packaged minimal agent's persistent shell and string-replacement editor.\nEditor path: {{cwd}}\\created.txt"
}
]
},
{
"tools": [
{
"type": "function",
"function": {
"name": "pwsh",
"description": "Run commands in a PowerShell shell\n* When invoking this tool, the contents of the \"command\" parameter does NOT need to be XML-escaped.\n* You don't have access to the internet via this tool.\n* State is persistent across command calls and discussions with the user.\n* Use native Windows paths (C:\\...) and $env:NAME variables; this is PowerShell, not bash.\n* Please avoid commands that may produce a very large amount of output.\n* Please run long lived commands in the background, e.g. 'Start-Job' or start a server with Start-Process.",
"parameters": {
"type": "object",
"properties": {
"command": {
"type": "string",
"description": "The PowerShell command to run. Relative path is preferred in the command."
}
},
"required": [
"command"
]
}
}
},
{
"type": "function",
"function": {
"name": "str_replace_editor",
"description": "Custom editing tool for viewing, creating and editing files\n* State is persistent across command calls and discussions with the user\n* If `path` is a file, `view` displays the result of applying `cat -n`. If `path` is a directory, `view` lists non-hidden files and directories up to 2 levels deep\n* The `create` command cannot be used if the specified `path` already exists as a file\n* If a `command` generates a long output, it will be truncated and marked with `<response clipped>`\n\nNotes for using the `str_replace` command:\n* The `old_str` parameter should match EXACTLY one or more consecutive lines from the original file. Be mindful of whitespaces!\n* If the `old_str` parameter is not unique in the file, the replacement will not be performed. Make sure to include enough context in `old_str` to make it unique\n* The `new_str` parameter should contain the edited lines that should replace the `old_str`",
"parameters": {
"type": "object",
"properties": {
"command": {
"type": "string",
"description": "The commands to run. Allowed options are: `view`, `create`, `str_replace`, `insert`.",
"enum": [
"view",
"create",
"str_replace",
"insert"
]
},
"path": {
"type": "string",
"description": "Absolute path to file or directory, e.g. `/repo/file.py` or `/repo`."
},
"file_text": {
"type": "string",
"description": "Required parameter of `create` command, with the content of the file to be created."
},
"insert_line": {
"type": "integer",
"description": "Required parameter of `insert` command. The `new_str` will be inserted AFTER the line `insert_line` of `path`."
},
"new_str": {
"type": "string",
"description": "Optional parameter of `str_replace` command containing the new string (if not given, no string will be added). Required parameter of `insert` command containing the string to insert."
},
"old_str": {
"type": "string",
"description": "Required parameter of `str_replace` command containing the string in `path` to replace."
},
"view_range": {
"type": "array",
"description": "Optional parameter of `view` command when `path` points to a file. If none is given, the full file is shown. If provided, the file will be shown in the indicated line number range, e.g. [11, 12] will show lines 11 and 12. Indexing at 1 to start. Setting `[start_line, -1]` shows all lines from `start_line` to the end of the file.",
"items": {
"type": "integer"
}
}
},
"required": [
"command",
"path"
]
}
}
}
],
"messages": [
{
"role": "system",
"text": "You are a helpful software engineer assistant."
},
{
"role": "user",
"text": "Exercise the packaged minimal agent's persistent shell and string-replacement editor.\nEditor path: {{cwd}}\\created.txt"
},
{
"role": "assistant",
"toolCalls": [
{
"id": "minimal-bash-1",
"name": "pwsh"
}
]
},
{
"role": "tool",
"toolCallId": "minimal-bash-1",
"text": "{{tool-result}}"
}
]
},
{
"tools": [
{
"type": "function",
"function": {
"name": "pwsh",
"description": "Run commands in a PowerShell shell\n* When invoking this tool, the contents of the \"command\" parameter does NOT need to be XML-escaped.\n* You don't have access to the internet via this tool.\n* State is persistent across command calls and discussions with the user.\n* Use native Windows paths (C:\\...) and $env:NAME variables; this is PowerShell, not bash.\n* Please avoid commands that may produce a very large amount of output.\n* Please run long lived commands in the background, e.g. 'Start-Job' or start a server with Start-Process.",
"parameters": {
"type": "object",
"properties": {
"command": {
"type": "string",
"description": "The PowerShell command to run. Relative path is preferred in the command."
}
},
"required": [
"command"
]
}
}
},
{
"type": "function",
"function": {
"name": "str_replace_editor",
"description": "Custom editing tool for viewing, creating and editing files\n* State is persistent across command calls and discussions with the user\n* If `path` is a file, `view` displays the result of applying `cat -n`. If `path` is a directory, `view` lists non-hidden files and directories up to 2 levels deep\n* The `create` command cannot be used if the specified `path` already exists as a file\n* If a `command` generates a long output, it will be truncated and marked with `<response clipped>`\n\nNotes for using the `str_replace` command:\n* The `old_str` parameter should match EXACTLY one or more consecutive lines from the original file. Be mindful of whitespaces!\n* If the `old_str` parameter is not unique in the file, the replacement will not be performed. Make sure to include enough context in `old_str` to make it unique\n* The `new_str` parameter should contain the edited lines that should replace the `old_str`",
"parameters": {
"type": "object",
"properties": {
"command": {
"type": "string",
"description": "The commands to run. Allowed options are: `view`, `create`, `str_replace`, `insert`.",
"enum": [
"view",
"create",
"str_replace",
"insert"
]
},
"path": {
"type": "string",
"description": "Absolute path to file or directory, e.g. `/repo/file.py` or `/repo`."
},
"file_text": {
"type": "string",
"description": "Required parameter of `create` command, with the content of the file to be created."
},
"insert_line": {
"type": "integer",
"description": "Required parameter of `insert` command. The `new_str` will be inserted AFTER the line `insert_line` of `path`."
},
"new_str": {
"type": "string",
"description": "Optional parameter of `str_replace` command containing the new string (if not given, no string will be added). Required parameter of `insert` command containing the string to insert."
},
"old_str": {
"type": "string",
"description": "Required parameter of `str_replace` command containing the string in `path` to replace."
},
"view_range": {
"type": "array",
"description": "Optional parameter of `view` command when `path` points to a file. If none is given, the full file is shown. If provided, the file will be shown in the indicated line number range, e.g. [11, 12] will show lines 11 and 12. Indexing at 1 to start. Setting `[start_line, -1]` shows all lines from `start_line` to the end of the file.",
"items": {
"type": "integer"
}
}
},
"required": [
"command",
"path"
]
}
}
}
],
"messages": [
{
"role": "system",
"text": "You are a helpful software engineer assistant."
},
{
"role": "user",
"text": "Exercise the packaged minimal agent's persistent shell and string-replacement editor.\nEditor path: {{cwd}}\\created.txt"
},
{
"role": "assistant",
"toolCalls": [
{
"id": "minimal-bash-1",
"name": "pwsh"
}
]
},
{
"role": "tool",
"toolCallId": "minimal-bash-1",
"text": "{{tool-result}}"
},
{
"role": "assistant",
"toolCalls": [
{
"id": "minimal-bash-2",
"name": "pwsh"
}
]
},
{
"role": "tool",
"toolCallId": "minimal-bash-2",
"text": "{{tool-result}}"
}
]
},
{
"tools": [
{
"type": "function",
"function": {
"name": "pwsh",
"description": "Run commands in a PowerShell shell\n* When invoking this tool, the contents of the \"command\" parameter does NOT need to be XML-escaped.\n* You don't have access to the internet via this tool.\n* State is persistent across command calls and discussions with the user.\n* Use native Windows paths (C:\\...) and $env:NAME variables; this is PowerShell, not bash.\n* Please avoid commands that may produce a very large amount of output.\n* Please run long lived commands in the background, e.g. 'Start-Job' or start a server with Start-Process.",
"parameters": {
"type": "object",
"properties": {
"command": {
"type": "string",
"description": "The PowerShell command to run. Relative path is preferred in the command."
}
},
"required": [
"command"
]
}
}
},
{
"type": "function",
"function": {
"name": "str_replace_editor",
"description": "Custom editing tool for viewing, creating and editing files\n* State is persistent across command calls and discussions with the user\n* If `path` is a file, `view` displays the result of applying `cat -n`. If `path` is a directory, `view` lists non-hidden files and directories up to 2 levels deep\n* The `create` command cannot be used if the specified `path` already exists as a file\n* If a `command` generates a long output, it will be truncated and marked with `<response clipped>`\n\nNotes for using the `str_replace` command:\n* The `old_str` parameter should match EXACTLY one or more consecutive lines from the original file. Be mindful of whitespaces!\n* If the `old_str` parameter is not unique in the file, the replacement will not be performed. Make sure to include enough context in `old_str` to make it unique\n* The `new_str` parameter should contain the edited lines that should replace the `old_str`",
"parameters": {
"type": "object",
"properties": {
"command": {
"type": "string",
"description": "The commands to run. Allowed options are: `view`, `create`, `str_replace`, `insert`.",
"enum": [
"view",
"create",
"str_replace",
"insert"
]
},
"path": {
"type": "string",
"description": "Absolute path to file or directory, e.g. `/repo/file.py` or `/repo`."
},
"file_text": {
"type": "string",
"description": "Required parameter of `create` command, with the content of the file to be created."
},
"insert_line": {
"type": "integer",
"description": "Required parameter of `insert` command. The `new_str` will be inserted AFTER the line `insert_line` of `path`."
},
"new_str": {
"type": "string",
"description": "Optional parameter of `str_replace` command containing the new string (if not given, no string will be added). Required parameter of `insert` command containing the string to insert."
},
"old_str": {
"type": "string",
"description": "Required parameter of `str_replace` command containing the string in `path` to replace."
},
"view_range": {
"type": "array",
"description": "Optional parameter of `view` command when `path` points to a file. If none is given, the full file is shown. If provided, the file will be shown in the indicated line number range, e.g. [11, 12] will show lines 11 and 12. Indexing at 1 to start. Setting `[start_line, -1]` shows all lines from `start_line` to the end of the file.",
"items": {
"type": "integer"
}
}
},
"required": [
"command",
"path"
]
}
}
}
],
"messages": [
{
"role": "system",
"text": "You are a helpful software engineer assistant."
},
{
"role": "user",
"text": "Exercise the packaged minimal agent's persistent shell and string-replacement editor.\nEditor path: {{cwd}}\\created.txt"
},
{
"role": "assistant",
"toolCalls": [
{
"id": "minimal-bash-1",
"name": "pwsh"
}
]
},
{
"role": "tool",
"toolCallId": "minimal-bash-1",
"text": "{{tool-result}}"
},
{
"role": "assistant",
"toolCalls": [
{
"id": "minimal-bash-2",
"name": "pwsh"
}
]
},
{
"role": "tool",
"toolCallId": "minimal-bash-2",
"text": "{{tool-result}}"
},
{
"role": "assistant",
"toolCalls": [
{
"id": "minimal-editor",
"name": "str_replace_editor"
}
]
},
{
"role": "tool",
"toolCallId": "minimal-editor",
"text": "{{tool-result}}"
}
]
}
]
@@ -9,6 +9,10 @@
{
"role": "user",
"content": "Complete the first isolated Python SDK process turn."
},
{
"role": "user",
"content": "Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations.\n\nApproval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."
}
],
"toolNames": [
@@ -37,6 +41,10 @@
{
"role": "user",
"content": "Complete the second isolated Python SDK process turn."
},
{
"role": "user",
"content": "Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations.\n\nApproval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."
}
],
"toolNames": [
@@ -9,51 +9,6 @@
"agent/inbox/spliced",
"step/start",
"user/message",
"session/title",
"request/header",
"request/context",
"session-log-deepseek/delivery-accepted",
"assistant/chunk",
"assistant/chunk",
"assistant/chunk",
"assistant/chunk",
"assistant/chunk",
"assistant/message",
"step/end",
"turn/end"
],
"notificationMethods": [
"session.event",
"session.status",
"session.event",
"session.event",
"session.event",
"session.event",
"session.event",
"session.event",
"session.event",
"session.event",
"session.event",
"session.event",
"session.event",
"session.event",
"session.event",
"session.event",
"session.event",
"session.event",
"session.status"
],
"session_root": "{{sessions}}"
},
{
"session_id": "{{session-2}}",
"final_response": "PROCESS_TWO_OK",
"finish_reason": "completed",
"eventTypes": [
"agent/inbox/spliced",
"turn/start",
"agent/inbox/spliced",
"step/start",
"user/message",
"session/title",
"request/header",
@@ -87,8 +42,55 @@
"session.event",
"session.event",
"session.event",
"session.event",
"session.status"
]
},
{
"session_id": "{{session-2}}",
"final_response": "PROCESS_TWO_OK",
"finish_reason": "completed",
"eventTypes": [
"agent/inbox/spliced",
"turn/start",
"agent/inbox/spliced",
"step/start",
"user/message",
"user/message",
"session/title",
"request/header",
"request/context",
"session-log-deepseek/delivery-accepted",
"assistant/chunk",
"assistant/chunk",
"assistant/chunk",
"assistant/chunk",
"assistant/chunk",
"assistant/message",
"step/end",
"turn/end"
],
"session_root": "{{sessions}}"
"notificationMethods": [
"session.event",
"session.status",
"session.event",
"session.event",
"session.event",
"session.event",
"session.event",
"session.event",
"session.event",
"session.event",
"session.event",
"session.event",
"session.event",
"session.event",
"session.event",
"session.event",
"session.event",
"session.event",
"session.event",
"session.status"
]
}
]
@@ -1,18 +1,22 @@
{"type":"session","version":0,"id":"{{session-1}}","createdAt":0,"cwd":"{{cwd}}","delegationDepth":0}
{"type":"permission/preset","data":{"preset":"danger-full-access"}}
{"type":"sandbox/mode","data":{"mode":"danger-full-access"}}
{"type":"approval/policy","data":{"policy":"never"}}
{"type":"agent/inbox/spliced","data":{"target":"next-turn","start":0,"inserted":[{"content":[{"type":"text","text":"Complete the first isolated Python SDK process turn."}],"source":{"kind":"user"},"role":"user","id":"{{messageId}}"}]}}
{"type":"turn/start","data":{"turn":1}}
{"type":"agent/inbox/spliced","data":{"target":"next-turn","start":0,"removedCount":1,"inserted":[]}}
{"type":"step/start","data":{"turn":1,"step":1}}
{"type":"user/message","data":{"content":[{"type":"text","text":"Complete the first isolated Python SDK process turn."}],"source":{"kind":"user"},"role":"user","id":"{{messageId}}"},"surfaceOp":"append"}
{"type":"session/title","data":{"title":"Complete the first isolated Python","messageSeqs":[4],"source":{"kind":"fallback"}}}
{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations.\n\nApproval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."}],"source":{"kind":"plugin","plugin":"@deepseek-ai/dsh-system-prompt","form":"snapshot","sections":[{"name":"sandbox:policy","text":"Current DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations."},{"name":"approval:policy","text":"Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."}]},"role":"user","id":"{{messageId}}"},"surfaceOp":"append"}
{"type":"session/title","data":{"title":"Complete the first isolated Python","messageSeqs":[7],"source":{"kind":"fallback"}}}
{"type":"request/header","data":{"header":{"config":{"provider":"deepseek-official","model":"smoke-model","maxTokens":256000,"reasoningEffort":"high"},"adapterDefaults":{"reasoningEffort":true,"maxTokens":true},"system":"{{system}}","tools":["cordis_define","cordis_inspect_list","cordis_inspect_query","cordis_inspect_self","cordis_run","cordis_stop","cordis_undefine","job_kill","job_list","job_output","run_code","subagent","workflow"]},"reason":"initial"}}
{"type":"request/context","data":{"provider":"deepseek-official","model":"smoke-model","contextWindow":1000000}}
{"type":"session-log-deepseek/delivery-accepted","data":{"sessionId":"{{session-1}}","throughSeq":7}}
{"type":"session-log-deepseek/delivery-accepted","data":{"sessionId":"{{session-1}}","throughSeq":11}}
{"type":"assistant/chunk","data":{"turn":1,"step":1,"chunk":{"type":"block-start","index":0,"blockType":"text"}}}
{"type":"assistant/chunk","data":{"turn":1,"step":1,"chunk":{"type":"text-delta","index":0,"text":"PROCESS_ONE_OK"}}}
{"type":"assistant/chunk","data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"PROCESS_ONE_OK"}}}}
{"type":"assistant/chunk","data":{"turn":1,"step":1,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
{"type":"assistant/chunk","data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"stop"}}}}
{"type":"assistant/message","data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"text","text":"PROCESS_ONE_OK"}],"source":{"kind":"model","provider":"deepseek-official","model":"smoke-model"},"id":"{{messageId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[9,10,11,12,13],"surfaceOp":"append"}
{"type":"assistant/message","data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"text","text":"PROCESS_ONE_OK"}],"source":{"kind":"model","provider":"deepseek-official","model":"smoke-model"},"id":"{{messageId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[13,14,15,16,17],"surfaceOp":"append"}
{"type":"step/end","data":{"turn":1,"step":1}}
{"type":"turn/end","data":{"turn":1,"reason":{"kind":"completed"}}}
@@ -1,18 +1,22 @@
{"type":"session","version":0,"id":"{{session-2}}","createdAt":0,"cwd":"{{cwd}}","delegationDepth":0}
{"type":"permission/preset","data":{"preset":"danger-full-access"}}
{"type":"sandbox/mode","data":{"mode":"danger-full-access"}}
{"type":"approval/policy","data":{"policy":"never"}}
{"type":"agent/inbox/spliced","data":{"target":"next-turn","start":0,"inserted":[{"content":[{"type":"text","text":"Complete the second isolated Python SDK process turn."}],"source":{"kind":"user"},"role":"user","id":"{{messageId}}"}]}}
{"type":"turn/start","data":{"turn":1}}
{"type":"agent/inbox/spliced","data":{"target":"next-turn","start":0,"removedCount":1,"inserted":[]}}
{"type":"step/start","data":{"turn":1,"step":1}}
{"type":"user/message","data":{"content":[{"type":"text","text":"Complete the second isolated Python SDK process turn."}],"source":{"kind":"user"},"role":"user","id":"{{messageId}}"},"surfaceOp":"append"}
{"type":"session/title","data":{"title":"Complete the second isolated Python","messageSeqs":[4],"source":{"kind":"fallback"}}}
{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations.\n\nApproval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."}],"source":{"kind":"plugin","plugin":"@deepseek-ai/dsh-system-prompt","form":"snapshot","sections":[{"name":"sandbox:policy","text":"Current DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations."},{"name":"approval:policy","text":"Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."}]},"role":"user","id":"{{messageId}}"},"surfaceOp":"append"}
{"type":"session/title","data":{"title":"Complete the second isolated Python","messageSeqs":[7],"source":{"kind":"fallback"}}}
{"type":"request/header","data":{"header":{"config":{"provider":"deepseek-official","model":"smoke-model","maxTokens":256000,"reasoningEffort":"high"},"adapterDefaults":{"reasoningEffort":true,"maxTokens":true},"system":"{{system}}","tools":["cordis_define","cordis_inspect_list","cordis_inspect_query","cordis_inspect_self","cordis_run","cordis_stop","cordis_undefine","job_kill","job_list","job_output","run_code","subagent","workflow"]},"reason":"initial"}}
{"type":"request/context","data":{"provider":"deepseek-official","model":"smoke-model","contextWindow":1000000}}
{"type":"session-log-deepseek/delivery-accepted","data":{"sessionId":"{{session-2}}","throughSeq":7}}
{"type":"session-log-deepseek/delivery-accepted","data":{"sessionId":"{{session-2}}","throughSeq":11}}
{"type":"assistant/chunk","data":{"turn":1,"step":1,"chunk":{"type":"block-start","index":0,"blockType":"text"}}}
{"type":"assistant/chunk","data":{"turn":1,"step":1,"chunk":{"type":"text-delta","index":0,"text":"PROCESS_TWO_OK"}}}
{"type":"assistant/chunk","data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"PROCESS_TWO_OK"}}}}
{"type":"assistant/chunk","data":{"turn":1,"step":1,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
{"type":"assistant/chunk","data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"stop"}}}}
{"type":"assistant/message","data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"text","text":"PROCESS_TWO_OK"}],"source":{"kind":"model","provider":"deepseek-official","model":"smoke-model"},"id":"{{messageId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[9,10,11,12,13],"surfaceOp":"append"}
{"type":"assistant/message","data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"text","text":"PROCESS_TWO_OK"}],"source":{"kind":"model","provider":"deepseek-official","model":"smoke-model"},"id":"{{messageId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[13,14,15,16,17],"surfaceOp":"append"}
{"type":"step/end","data":{"turn":1,"step":1}}
{"type":"turn/end","data":{"turn":1,"reason":{"kind":"completed"}}}
+1 -1
View File
@@ -120,7 +120,7 @@ describe('global test invariant host', () => {
it('mounts the owning package companion while leaving non-package roots service-only', () => {
expect(testInvariantCompanionPaths('/repo/packages/core/tools/tests/tools.spec.ts'))
.toEqual(['../packages/core/tools/src/invariant.ts'])
expect(testInvariantCompanionPaths('/repo/examples/echo-agent/tests/echo.spec.ts')).toEqual([])
expect(testInvariantCompanionPaths('/repo/apps/cli/tests/profiles/headless/example.spec.ts')).toEqual([])
expect(testInvariantCompanionPaths('/repo/scripts/test-invariants.spec.ts'))
.toEqual(Object.keys(testInvariantCompanions).sort())
})
+2 -2
View File
@@ -303,14 +303,14 @@ describe('translation scope discovery', () => {
'packages/example/guide.md',
'packages/example/CONTRIBUTING.md',
'packages/example/BRAND_GUIDELINES.md',
'examples/tutorial.md',
'other/tutorial.md',
'website/reference.md',
'packages/example/README.txt',
'vendor/example/README.md',
'packages/example/node_modules/dependency/README.md',
'packages/example/lib/README.md',
'coverage/report/README.md',
'python/sdk-runtime/src/deepseek_harness_runtime/runtime/dsh-jsonrpc-agent-macos-arm64/README.md',
'python/sdk-runtime/src/deepseek_harness_runtime/runtime/deepseek-harness-sdk-runtime-macos-arm64/README.md',
'python/sdk-runtime/src/deepseek_harness_runtime/runtime/node/README.md',
])('excludes non-source or non-README path %s', (file) => {
expect(isTranslationScopeFile(file)).toBe(false)
+2 -2
View File
@@ -165,7 +165,7 @@ export const TRANSLATION_SCOPE_GLOB_EXCLUDES = [
'**/.pytest_cache/**',
'apps/web/dist/**',
'.artifacts/**',
'python/sdk-runtime/src/deepseek_harness_runtime/runtime/dsh-jsonrpc-agent-*/**',
'python/sdk-runtime/src/deepseek_harness_runtime/runtime/deepseek-harness-sdk-runtime-*/**',
'python/sdk-runtime/src/deepseek_harness_runtime/runtime/node/**',
'vendor/**',
]
@@ -177,7 +177,7 @@ function isTranslationSourceExcluded(file: string): boolean {
|| segment.startsWith('.doc-typecheck-')
|| segment.startsWith('.node-next-types-'))
|| file.startsWith('apps/web/dist/')
|| file.startsWith('python/sdk-runtime/src/deepseek_harness_runtime/runtime/dsh-jsonrpc-agent-')
|| file.startsWith('python/sdk-runtime/src/deepseek_harness_runtime/runtime/deepseek-harness-sdk-runtime-')
|| file.startsWith('python/sdk-runtime/src/deepseek_harness_runtime/runtime/node/')
}
+20
View File
@@ -36,6 +36,11 @@
"symbol": "ContextFormed",
"source": "packages/llm/llm/src/message.ts"
},
{
"doc": "docs/subsystems/llm-streaming.md",
"symbol": "ImageAttachmentAccess",
"source": "packages/llm/llm/src/content.ts"
},
{
"doc": "docs/subsystems/llm-streaming.md",
"symbol": "FinishReasonMap",
@@ -1761,11 +1766,26 @@
"symbol": "WebBootEntry",
"source": "packages/client/modules/src/client/manifest.ts"
},
{
"doc": "docs/subsystems/client-modules.md",
"symbol": "WebBootBatchPhase",
"source": "packages/client/modules/src/client/manifest.ts"
},
{
"doc": "docs/subsystems/client-modules.md",
"symbol": "WebBootBatch",
"source": "packages/client/modules/src/client/manifest.ts"
},
{
"doc": "docs/subsystems/client-modules.md",
"symbol": "WebBootGraph",
"source": "packages/client/modules/src/client/manifest.ts"
},
{
"doc": "docs/subsystems/client-modules.md",
"symbol": "ClientArtifactBaseline",
"source": "packages/client/modules/src/index.ts"
},
{
"doc": "docs/subsystems/session-telemetry.md",
"symbol": "SessionTelemetrySharingStatus",
@@ -65,21 +65,23 @@ describe('application entrypoints', () => {
])
})
it('rejects an unclassified executable in an example workspace', () => {
it('rejects an unclassified executable in an app workspace', () => {
const root = fixture()
write(root, 'examples/rogue/src/bin.ts', '#!/usr/bin/env node\n')
write(root, 'apps/rogue/src/bin.ts', '#!/usr/bin/env node\n')
expect(applicationEntrypointViolations(root)).toEqual([
'examples/rogue/src/bin.ts: executable source has no application/build/test classification',
'apps/rogue/src/bin.ts: executable source has no application/build/test classification',
])
})
it('accepts the temporary private Python carrier source without an npm bin', () => {
it('rejects a private Python application carrier outside dsh', () => {
const root = fixture()
write(root, 'packages/sdk/python-runtime/package.json', JSON.stringify({ private: true }))
write(root, 'packages/sdk/python-runtime/src/packaged-bin.ts', '#!/usr/bin/env node\n')
write(root, 'packages/sdk/rogue-python-runtime/package.json', JSON.stringify({ private: true }))
write(root, 'packages/sdk/rogue-python-runtime/src/bin.ts', '#!/usr/bin/env node\n')
expect(applicationEntrypointViolations(root)).toEqual([])
expect(applicationEntrypointViolations(root)).toEqual([
'packages/sdk/rogue-python-runtime/src/bin.ts: executable source has no application/build/test classification',
])
})
it('rejects a classified demo wrapper that launches a package entry', () => {
+11 -18
View File
@@ -1,7 +1,7 @@
/**
* Enforce dsh profiles as the only supported Node application launcher.
* Vendor CLIs, build tools, test tools, and the temporary private Python
* runtime carrier are explicit classifications rather than implicit holes.
* Vendor CLIs, build tools, and test tools are explicit classifications
* rather than implicit holes.
*/
import { existsSync, globSync, readFileSync } from 'node:fs'
@@ -32,26 +32,23 @@ const MANIFEST_BIN_ALLOWLIST = new Map<string, ManifestBin>([
/** Every executable in a Node application workspace has one explicit role. */
const EXECUTABLE_SOURCE_ALLOWLIST = new Map<string, string>([
['apps/cli/src/bin.ts', 'supported dsh application launcher'],
['examples/acp-agent/tests/fixtures/shell/tool-pwsh/driver.ts', 'test-only subprocess driver'],
['examples/acp-agent/tests/fixtures/subagent/subagent-acp/driver.ts', 'test-only subprocess driver'],
['examples/acp-agent/tests/fixtures/subagent/subagent-claude-code/driver.ts', 'test-only subprocess driver'],
['examples/acp-agent/tests/fixtures/subagent/subagent-codex/driver.ts', 'test-only subprocess driver'],
['examples/headless-agent/tests/fixtures/headless-driver.ts', 'test-only subprocess driver'],
['examples/headless-agent/tests/fixtures/session-telemetry-otel-driver.ts', 'test-only subprocess driver'],
['examples/headless-agent/tests/fixtures/time-context-driver.ts', 'test-only subprocess driver'],
['examples/python-sdk-agent/tests/fixtures/subagent/subagent-dsh-sdk/driver.ts', 'test-only subprocess driver'],
['packages/context/time-context/tests/fixtures/driver.ts', 'test-only subprocess driver'],
['packages/experimental/webworker-packer/bin.js', 'private build-only wrapper'],
['packages/experimental/webworker-packer/src/bin.ts', 'private build-only implementation'],
['packages/sdk/client/tests/fake-runtime.ts', 'test-only SDK runtime peer'],
['packages/sdk/python-runtime/src/packaged-bin.ts', 'temporary private Python runtime carrier'],
['packages/session/session-telemetry-otel/tests/fixtures/driver.ts', 'test-only subprocess driver'],
['packages/shell/tool-pwsh/tests/fixtures/loader/driver.ts', 'test-only subprocess driver'],
['packages/subagent/subagent-acp/tests/fixtures/loader/driver.ts', 'test-only subprocess driver'],
['packages/subagent/subagent-claude-code/tests/fixtures/loader/driver.ts', 'test-only subprocess driver'],
['packages/subagent/subagent-codex/tests/fixtures/loader/driver.ts', 'test-only subprocess driver'],
['packages/subagent/subagent-dsh-sdk/tests/fixtures/loader/driver.ts', 'test-only subprocess driver'],
['packages/test-support/loader-smoke/tests/fixtures/headless-driver.ts', 'test-only subprocess driver'],
['packages/test-support/llm-mock-server/src/bin.ts', 'test-only model server'],
])
/** Root demos are application wrappers and therefore must visibly select dsh. */
const ROOT_DEMO_POLICIES = new Map<string, DemoPolicy>([
['demo:acp', { kind: 'dsh-direct' }],
['demo:code-mode', { kind: 'dsh-wrapper', wrapper: 'scripts/demo-code-mode.mjs' }],
['demo:cordis', { kind: 'dsh-wrapper', wrapper: 'scripts/demo-cordis.mjs' }],
])
const SOURCE_PATTERNS = [
@@ -63,10 +60,6 @@ const SOURCE_PATTERNS = [
'apps/**/*.js',
'apps/**/*.mjs',
'apps/**/*.cjs',
'examples/**/*.ts',
'examples/**/*.js',
'examples/**/*.mjs',
'examples/**/*.cjs',
'packages/**/*.ts',
'packages/**/*.js',
'packages/**/*.mjs',
@@ -194,6 +187,6 @@ if (process.argv[1] !== undefined && import.meta.url === pathToFileURL(resolve(p
for (const failure of failures) console.error(` ${failure}`)
process.exitCode = 1
} else {
console.log('verify-application-entrypoints: dsh is the only supported Node application launcher; the private Python carrier remains the temporary exception.')
console.log('verify-application-entrypoints: dsh is the only supported Node application launcher.')
}
}
+1 -3
View File
@@ -11,9 +11,7 @@ const ROOT = resolve(import.meta.dirname, '..')
/** Shipped Cordis configuration these rules apply to. */
const SHIPPED_CONFIG_GLOBS = [
'apps/*/config/*.yml',
'examples/*/*.cordis.yml',
'examples/*/cordis.yml',
'apps/*/config/**/*.yml',
// Bundle identity comes from the package manifest, not the domain directory.
'packages/*/*/cordis.patch.yml',
// The Python runtime ships its own default composition inside the wheel.
+67
View File
@@ -12,6 +12,8 @@ import {
bundleManifestPaths,
bundlePluginDependencyErrors,
metadataExpressionErrors,
packageTestFixtureDependencyErrors,
packageTestPluginDependencyErrors,
} from './verify-cordis-config.ts'
describe('verify-cordis-config metadata expressions', () => {
@@ -86,3 +88,68 @@ describe('workspace Bundle discovery and product dependency closures', () => {
])
})
})
describe('package-owned Loader test dependency closures', () => {
it('requires package test configs to declare each named plugin they load', () => {
const manifestPath = 'packages/example/owner/package.json'
const file = 'packages/example/owner/tests/fixtures/cordis.yml'
const manifest = {
name: '@deepseek-ai/dsh-owner',
dependencies: {},
devDependencies: {
'@deepseek-ai/dsh-declared': 'workspace:^',
},
}
expect(packageTestPluginDependencyErrors(manifestPath, manifest, [
{ file, name: '@deepseek-ai/dsh-owner' },
{ file, name: '@deepseek-ai/dsh-declared' },
{ file, name: '@deepseek-ai/dsh-missing' },
])).toEqual([
`${file}: @deepseek-ai/dsh-missing must be declared in ${manifestPath} dependencies or devDependencies`,
])
})
it('requires executable package test fixtures to declare their bare imports', () => {
const fixture = mkdtempSync(join(tmpdir(), 'dsh-package-test-entrypoint-'))
try {
const packageDir = join(fixture, 'packages/example/owner')
const driverDir = join(packageDir, 'tests/fixtures/loader')
mkdirSync(driverDir, { recursive: true })
writeFileSync(join(packageDir, 'package.json'), JSON.stringify({
name: '@deepseek-ai/dsh-owner',
devDependencies: {
'@deepseek-ai/dsh-declared': 'workspace:^',
},
}))
writeFileSync(join(driverDir, 'driver.ts'), [
"import '@deepseek-ai/dsh-owner'",
"import '@deepseek-ai/dsh-declared'",
"import '@deepseek-ai/dsh-missing'",
].join('\n'))
writeFileSync(join(driverDir, 'cordis.yml'), '[]\n')
writeFileSync(join(driverDir, 'fixture.mjs'), "import '@deepseek-ai/dsh-declared'\n")
const unrelatedDir = join(packageDir, 'tests/fixtures/unrelated')
mkdirSync(unrelatedDir, { recursive: true })
writeFileSync(join(unrelatedDir, 'driver.ts'), "import '@deepseek-ai/dsh-unrelated'\n")
expect(packageTestFixtureDependencyErrors(fixture)).toEqual([
'packages/example/owner/tests/fixtures/loader/driver.ts: '
+ '@deepseek-ai/dsh-missing must be declared in '
+ 'packages/example/owner/package.json dependencies or devDependencies',
])
} finally {
rmSync(fixture, { recursive: true, force: true })
}
})
it('fails loud when package-owned Loader fixtures disappear from the scan', () => {
const fixture = mkdtempSync(join(tmpdir(), 'dsh-empty-package-test-entrypoint-'))
try {
expect(packageTestFixtureDependencyErrors(fixture)).toEqual([
'package test fixture dependency scan found no package-owned Loader configs',
])
} finally {
rmSync(fixture, { recursive: true, force: true })
}
})
})
+115 -68
View File
@@ -5,9 +5,9 @@
* activate, against that plugin context) and the entry `disabled` field (at
* every mount decision, against the loader context). Every other entry
* metadata field stays static, so an expression there remains truthy data and
* silently changes composition. Example configs and the dsh Web composition
* resolve named plugins from their owning workspace manifests. Local example
* packages must also be in the root TypeScript project graph.
* silently changes composition. Shipped and test-only dsh overlays resolve
* named plugins from the CLI application's owning manifest; package-owned
* Loader fixtures resolve from their package manifest.
*/
import { globSync, readFileSync } from 'node:fs'
@@ -20,6 +20,7 @@ import { isCordisGroupEntry, isJsExpr, loadCordisYaml } from './cordis-yaml.ts'
export interface PackageManifest {
name?: string
dependencies?: Record<string, string>
devDependencies?: Record<string, string>
optionalDependencies?: Record<string, string>
dsh?: { bundle?: { patch?: string } }
}
@@ -30,14 +31,10 @@ export interface PluginReference {
}
const root = resolve(import.meta.dirname, '..')
// These example files are overlays consumed by the built dsh app, so their bare
// specifiers resolve from apps/cli rather than the examples workspace.
// These overlays are consumed by the built dsh app, so their bare specifiers
// resolve from apps/cli.
const appOverlayFiles = new Set([
'examples/web-github-review/tests/fixtures/real-cli/cordis.yml',
'examples/web-cordis/cordis.yml',
'examples/web-github-review/cordis.yml',
'examples/web-schedule/cordis.yml',
...globSync('examples/mcp-memory/*.cordis.yml', { cwd: root }),
...globSync('apps/cli/config/examples/**/*.yml', { cwd: root }),
])
const metadataFields = ['id', 'name', 'group', 'inject', 'intercept', 'isolate'] as const
@@ -74,8 +71,9 @@ if (import.meta.main) {
}
}
errors.push(...validateExampleResolution())
errors.push(...validateAppResolution())
errors.push(...validatePackageTestResolution())
errors.push(...packageTestFixtureDependencyErrors())
errors.push(...validateSourcePlaneResolution())
errors.push(...validatePresetPlaneSeparation())
errors.push(...validateClientHalvesDeclared())
@@ -149,7 +147,7 @@ function validatePresetPlaneSeparation(): string[] {
}
// The overlay's own inserts are host-plane too; its disables take them back out.
const active = new Set([...hostRows, ...rowIds(overlayFile)].filter(id => !disabled.has(id)))
for (const file of globSync('apps/cli/config/agent-presets/*/agent.cordis.yml', { cwd: root })) {
for (const file of globSync('packages/preset/agent-presets/presets/*/agent.cordis.yml', { cwd: root })) {
for (const id of rowIds(file)) {
if (!active.has(id)) continue
problems.push(
@@ -225,37 +223,14 @@ function recordPlugin(entry: Record<string, unknown>, file: string): void {
if (typeof entry.name === 'string') pluginReferences.push({ file, name: entry.name })
}
function validateExampleResolution(): string[] {
const violations: string[] = []
const exampleManifest = readManifest('examples/package.json')
const dependencies = exampleManifest.dependencies ?? {}
const localPackages = localPackageDirectories()
const rootReferences = rootProjectReferences()
const exampleReferences = pluginReferences.filter(reference => reference.file.startsWith('examples/') && !appOverlayFiles.has(reference.file))
violations.push(...missingPluginDependencies(exampleReferences, dependencies, 'examples/package.json'))
const requiredPackages = new Set(exampleReferences.map(reference => packageNameFromSpecifier(reference.name)))
const localExamplePackages = new Set([
...Object.keys(dependencies),
...[...requiredPackages].filter(packageName => packageName !== undefined),
])
for (const packageName of localExamplePackages) {
const packageDirectory = localPackages.get(packageName)
if (packageDirectory === undefined || rootReferences.has(packageDirectory)) continue
const repoPath = relative(root, packageDirectory).replaceAll('\\', '/')
violations.push(`tsconfig.json: missing project reference for ${packageName} (${repoPath})`)
}
return violations
}
function validateAppResolution(): string[] {
const violations: string[] = []
const bundleManifests = bundleManifestPaths()
// App overlays (and any config left under apps/cli/config) resolve from the
// dsh app's own dependency surface — the profile module fallback mirrors it.
const appManifest = readManifest('apps/cli/package.json')
const appDependencies = {
...readManifest('apps/cli/package.json').dependencies,
...appManifest.dependencies,
// The fallback also links every in-box bundle's own dependencies
// (healProfilesModuleFallback). Optional Profile bundles stay outside the
// app installation until that Profile installs them.
@@ -265,7 +240,17 @@ function validateAppResolution(): string[] {
const shipped = new Set(globSync('*.cordis.yml', { cwd: resolve(root, 'apps/cli/config') })
.map(file => `apps/cli/config/${file}`))
const appReferences = pluginReferences.filter(reference => shipped.has(reference.file) || appOverlayFiles.has(reference.file))
violations.push(...missingPluginDependencies(appReferences, appDependencies, 'apps/cli/package.json or a bundle manifest'))
violations.push(...missingPluginDependencies(
appReferences,
appDependencies,
'apps/cli/package.json dependencies or a bundle manifest',
))
const appTestReferences = pluginReferences.filter(reference => reference.file.startsWith('apps/cli/tests/'))
violations.push(...missingPluginDependencies(
appTestReferences,
{ ...appManifest.dependencies, ...appManifest.devDependencies },
'apps/cli/package.json dependencies or devDependencies',
))
// Each bundle's patch rows must resolve from that bundle's own dependencies:
// per-layer resolution anchors on the bundle package directory.
for (const manifestPath of bundleManifests) {
@@ -280,6 +265,95 @@ function validateAppResolution(): string[] {
return violations
}
/**
* Package-owned Loader fixtures resolve named plugins from their package's
* dependency surface, not from a repository-level test umbrella.
* @returns one violation per configured package absent from the owner manifest.
*/
function validatePackageTestResolution(): string[] {
const referencesByManifest = new Map<string, PluginReference[]>()
for (const reference of pluginReferences) {
const manifestPath = packageTestManifestPath(reference.file)
if (manifestPath === undefined) continue
const references = referencesByManifest.get(manifestPath) ?? []
references.push(reference)
referencesByManifest.set(manifestPath, references)
}
return [...referencesByManifest].flatMap(([manifestPath, references]) =>
packageTestPluginDependencyErrors(manifestPath, readManifest(manifestPath), references))
}
/**
* Validate the named plugins one package-owned Loader fixture resolves.
* Self-references use Node package self-resolution; every other package must
* be an ordinary production or test dependency of the owner.
* @param manifestPath Repository-relative owner manifest path.
* @param manifest Parsed owner manifest.
* @param references Named plugin references from owner-local test configs.
* @returns Missing dependency diagnostics.
*/
export function packageTestPluginDependencyErrors(
manifestPath: string,
manifest: PackageManifest,
references: readonly PluginReference[],
): string[] {
return missingPluginDependencies(
references.filter(reference => packageNameFromSpecifier(reference.name) !== manifest.name),
{ ...manifest.dependencies, ...manifest.devDependencies },
`${manifestPath} dependencies or devDependencies`,
)
}
/**
* Validate imports made by fixture modules adjacent to package-owned Loader
* configs. These files execute as plain Node/tsx children, so a stale root
* `node_modules` link must not hide an undeclared dependency.
* @param repoRoot Repository root to scan.
* @returns Missing dependency diagnostics.
*/
export function packageTestFixtureDependencyErrors(repoRoot: string = root): string[] {
const fixtureDirectories = new Set(cordisConfigFiles(repoRoot)
.filter(file => packageTestManifestPath(file) !== undefined)
.map(file => dirname(file).replaceAll('\\', '/')))
if (fixtureDirectories.size === 0) {
return ['package test fixture dependency scan found no package-owned Loader configs']
}
const referencesByManifest = new Map<string, PluginReference[]>()
let fixtureModuleCount = 0
for (const fixtureDirectory of fixtureDirectories) {
const files = globSync([
`${fixtureDirectory}/**/*.ts`,
`${fixtureDirectory}/**/*.mjs`,
], { cwd: repoRoot })
fixtureModuleCount += files.length
for (const file of files) {
const manifestPath = packageTestManifestPath(file)
if (manifestPath === undefined) continue
const references = referencesByManifest.get(manifestPath) ?? []
const source = readFileSync(resolve(repoRoot, file), 'utf8')
for (const imported of ts.preProcessFile(source, true, true).importedFiles) {
references.push({ file: file.replaceAll('\\', '/'), name: imported.fileName })
}
referencesByManifest.set(manifestPath, references)
}
}
if (fixtureModuleCount === 0) {
return ['package test fixture dependency scan found no fixture modules beside Loader configs']
}
return [...referencesByManifest].flatMap(([manifestPath, references]) =>
packageTestPluginDependencyErrors(
manifestPath,
readManifest(manifestPath, repoRoot),
references,
))
}
/** Owner manifest for a package-local test path. */
function packageTestManifestPath(file: string): string | undefined {
const match = /^(packages\/[^/]+\/[^/]+)\/tests(?:\/|$)/.exec(file.replaceAll('\\', '/'))
return match?.[1] === undefined ? undefined : `${match[1]}/package.json`
}
/**
* Discover workspace Bundle packages from their manifest declaration.
* @param repoRoot Repository root to scan.
@@ -308,7 +382,7 @@ export function bundlePluginDependencyErrors(
// A Bundle may mount its own package (for example, its provider or runtime row).
references.filter(reference => packageNameFromSpecifier(reference.name) !== manifest.name),
manifest.dependencies ?? {},
manifestPath,
`${manifestPath} dependencies`,
)
}
@@ -366,7 +440,7 @@ function validateSourcePlaneResolution(): string[] {
function missingPluginDependencies(
references: readonly PluginReference[],
dependencies: Readonly<Record<string, string>>,
manifestPath: string,
dependencyOwner: string,
): string[] {
const requiredPackages = new Map<string, Set<string>>()
const require = (packageName: string, file: string): void => {
@@ -384,7 +458,7 @@ function missingPluginDependencies(
}
return [...requiredPackages].flatMap(([packageName, locations]) => packageName in dependencies
? []
: `${[...locations].join(', ')}: ${packageName} must be declared in ${manifestPath} dependencies`)
: `${[...locations].join(', ')}: ${packageName} must be declared in ${dependencyOwner}`)
}
function readManifest(path: string, repoRoot: string = root): PackageManifest {
@@ -401,33 +475,6 @@ function localPackageDirectories(): Map<string, string> {
return packages
}
function rootProjectReferences(): Set<string> {
// The root solution references the host and client aggregates (the two
// sides merge cordis Context under the same keys, so one program cannot see
// both — but this BFS only collects reference paths, it never forms a
// program). Seed the solution and follow nested aggregate references to
// collect the covered leaf project set.
const collected = new Set<string>()
const queue = [resolve(root, 'tsconfig.json')]
const seen = new Set<string>()
for (let file = queue.pop(); file !== undefined; file = queue.pop()) {
if (seen.has(file)) continue
seen.add(file)
const config = ts.readConfigFile(file, path => ts.sys.readFile(path))
if (config.error !== undefined) {
throw new Error(ts.flattenDiagnosticMessageText(config.error.messageText, '\n'))
}
const references = (config.config as { references?: Array<{ path?: unknown }> }).references ?? []
for (const reference of references) {
if (typeof reference.path !== 'string') continue
const target = resolve(dirname(file), reference.path)
if (target.endsWith('.json')) queue.push(target)
else collected.add(target)
}
}
return collected
}
function packageNameFromSpecifier(specifier: string): string | undefined {
if (specifier.startsWith('.') || specifier.startsWith('/') || /^[a-z][a-z+.-]*:/i.test(specifier)) return undefined
const segments = specifier.split('/')
+1 -1
View File
@@ -12,7 +12,7 @@ import { findReferenceViolations, uniqueRepoFiles, type ReferenceViolation as Vi
const root = resolve(import.meta.dirname, '..')
/** Repo-authored TypeScript that may cite docs in comments. */
const PATTERNS = ['packages/**/*.ts', 'examples/**/*.ts']
const PATTERNS = ['packages/**/*.ts']
/** Paths excluded from the scan: built output and vendored upstream source. */
const isExcluded = (p: string): boolean =>
-1
View File
@@ -23,7 +23,6 @@ const PATTERNS = [
'docs/**/*.md',
'packages/*/*.md',
'packages/*/*/*.md',
'examples/**/*.md',
'AGENTS.md',
'packages/AGENTS.md',
'.agents/skills/**/*.md',
+2 -1
View File
@@ -22,10 +22,11 @@ const PATTERNS = [
'docs/**/*.md',
'packages/*/*.md',
'packages/*/*/*.md',
'examples/**/system-prompt.expected.md',
'snapshots/**/system-prompt.expected.md',
'packages/**/system-prompt.expected.md',
'AGENTS.md',
'packages/AGENTS.md',
'snapshots/AGENTS.md',
]
/** A located hard-wrap: a prose paragraph spanning more than one source line. */
-1
View File
@@ -22,7 +22,6 @@ const PATTERNS = [
'docs/**/*.md',
'packages/*/*.md',
'packages/*/*/*.md',
'examples/**/*.md',
'AGENTS.md',
'packages/AGENTS.md',
'.agents/skills/**/*.md',
-1
View File
@@ -26,7 +26,6 @@ const PATTERNS = [
'AGENTS.md',
'packages/AGENTS.md',
'packages/**/*.ts',
'examples/**/*.ts',
]
/** Paths excluded from the scan: built output and vendored upstream source. */
@@ -152,7 +152,7 @@ const SENTENCE_MODEL_EXPERIENCE: Readonly<Record<string, SentenceContract>> = {
'packages/skill/skill-filesystem': { kind: 'indirect', reason: 'The provider backend delegates model rendering to dsh-tool-skill.' },
'packages/spill/spill': { kind: 'indirect', reason: 'The storage seam delegates model rendering to spill consumers.' },
'packages/spill/spill-local': { kind: 'indirect', reason: 'The storage backend delegates model rendering to spill consumers.' },
'packages/test-support/acp-snapshot': { kind: 'none', reason: 'The test harness observes and normalizes transcripts without changing live requests.' },
'packages/test-support/session-snapshot': { kind: 'none', reason: 'The test harness observes and normalizes transcripts without changing live requests.' },
'packages/test-support/agent-loop-testkit': { kind: 'none', reason: 'The test helper mounts services but neither drives nor modifies model requests.' },
'packages/runtime-diagnostics/invariants': { kind: 'none', reason: 'The observer validates requests but never rewrites their context.' },
'packages/test-support/loader-smoke': { kind: 'none', reason: 'The test harness submits an ordinary user task but delegates prompt and tool composition to the loaded tree.' },
@@ -167,7 +167,6 @@ const SENTENCE_MODEL_EXPERIENCE: Readonly<Record<string, SentenceContract>> = {
'packages/jobs/jobs-local': { kind: 'indirect', reason: 'The registry backend delegates model rendering to producer plugins and dsh-tool-jobs.' },
'packages/boot/app-boot': { kind: 'indirect', reason: 'Only the loaded plugin tree contributes model context.' },
'packages/boot/cmdline': { kind: 'none', reason: 'Resolves the process command line before any session exists; configured rows own every model-visible consequence.' },
'packages/sdk/python-runtime': { kind: 'indirect', reason: 'Only the externally configured plugin tree contributes model context.' },
'packages/interaction/permission-presets': { kind: 'indirect', reason: 'The service writes mechanism events rendered by dsh-user-approval and dsh-tool-bash.' },
'packages/interaction/user-questions': { kind: 'indirect', reason: 'Model-facing consumers render provider answers and seam errors.' },
'packages/util/timeout': { kind: 'indirect', reason: 'Only timeout consumers render timeout outcomes.' },
+15 -10
View File
@@ -21,6 +21,7 @@ const platforms = {
'linux-x64': { tag: 'manylinux_2_28_x86_64', executable: 'runtime-linux-x64' },
'linux-arm64': { tag: 'manylinux_2_28_aarch64', executable: 'runtime-linux-arm64' },
'macos-arm64': { tag: 'macosx_14_0_arm64', executable: 'runtime-macos-arm64' },
'win-x64': { tag: 'win_amd64', executable: 'runtime-win-x64.exe' },
}
function workspace(root: string, name: string, manifest: Record<string, unknown>): void {
@@ -35,11 +36,11 @@ afterEach(() => {
})
describe('verifyRuntimeClosure', () => {
it('requires only plugins active for a Linux or macOS target', async () => {
it('requires only plugins active for each published target', async () => {
const root = fixture({
'python/sdk-runtime/package.json': { name: 'runtime', dependencies: { '@scope/shared': 'workspace:^' } },
'python/sdk-runtime/platforms.json': platforms,
'apps/cli/config/agent-presets/standard/agent.cordis.yml': `
'packages/preset/agent-presets/presets/standard/agent.cordis.yml': `
- id: tools
name: cordis:group
group: true
@@ -52,6 +53,9 @@ describe('verifyRuntimeClosure', () => {
- id: macos
name: '@scope/macos'
disabled: !!js process.platform !== 'darwin'
- id: windows
name: '@scope/windows'
disabled: !!js process.platform !== 'win32'
`,
})
@@ -61,6 +65,7 @@ describe('verifyRuntimeClosure', () => {
expect(result.failures).toEqual([
'standard preset -> @scope/linux (linux-arm64, linux-x64)',
'standard preset -> @scope/macos (macos-arm64)',
'standard preset -> @scope/windows (win-x64)',
])
})
@@ -68,7 +73,7 @@ describe('verifyRuntimeClosure', () => {
const root = fixture({
'python/sdk-runtime/package.json': { name: 'runtime', dependencies: {} },
'python/sdk-runtime/platforms.json': platforms,
'apps/cli/config/agent-presets/standard/agent.cordis.yml': `
'packages/preset/agent-presets/presets/standard/agent.cordis.yml': `
- id: conditional
name: '@scope/conditional'
disabled: !!js process.env.DSH_DISABLE_CONDITIONAL === '1'
@@ -78,7 +83,7 @@ describe('verifyRuntimeClosure', () => {
const result = await verifyRuntimeClosure(root)
expect(result.failures).toEqual([
'standard preset -> @scope/conditional (linux-arm64, linux-x64, macos-arm64)',
'standard preset -> @scope/conditional (linux-arm64, linux-x64, macos-arm64, win-x64)',
])
})
@@ -86,7 +91,7 @@ describe('verifyRuntimeClosure', () => {
const root = fixture({
'python/sdk-runtime/package.json': { name: 'runtime', dependencies: { '@scope/plugin': 'workspace:^' } },
'python/sdk-runtime/platforms.json': platforms,
'apps/cli/config/agent-presets/standard/agent.cordis.yml': `
'packages/preset/agent-presets/presets/standard/agent.cordis.yml': `
- id: plugin
name: '@scope/plugin'
config:
@@ -103,7 +108,7 @@ describe('verifyRuntimeClosure', () => {
const root = fixture({
'python/sdk-runtime/package.json': { name: 'runtime', dependencies: { '@scope/plugin': '1.2.3' } },
'python/sdk-runtime/platforms.json': platforms,
'apps/cli/config/agent-presets/standard/agent.cordis.yml': `
'packages/preset/agent-presets/presets/standard/agent.cordis.yml': `
- id: plugin
name: '@scope/plugin'
`,
@@ -112,7 +117,7 @@ describe('verifyRuntimeClosure', () => {
const result = await verifyRuntimeClosure(root)
expect(result.failures).toEqual([
'standard preset -> @scope/plugin [runtime dependency is "1.2.3"; expected workspace:] (linux-arm64, linux-x64, macos-arm64)',
'standard preset -> @scope/plugin [runtime dependency is "1.2.3"; expected workspace:] (linux-arm64, linux-x64, macos-arm64, win-x64)',
])
})
@@ -126,7 +131,7 @@ describe('verifyRuntimeClosure', () => {
expect(result.presetCount).toBe(0)
expect(result.failures).toEqual([
'no agent presets matched apps/cli/config/agent-presets/*/agent.cordis.yml',
'no agent presets matched packages/preset/agent-presets/presets/*/agent.cordis.yml',
])
})
@@ -134,7 +139,7 @@ describe('verifyRuntimeClosure', () => {
const root = fixture({
'python/sdk-runtime/package.json': { name: 'runtime', dependencies: {} },
'python/sdk-runtime/platforms.json': {},
'apps/cli/config/agent-presets/standard/agent.cordis.yml': '[]\n',
'packages/preset/agent-presets/presets/standard/agent.cordis.yml': '[]\n',
})
const result = await verifyRuntimeClosure(root)
@@ -148,7 +153,7 @@ describe('verifyRuntimeClosure', () => {
const root = fixture({
'python/sdk-runtime/package.json': { name: 'runtime', dependencies: { '@scope/root': 'workspace:^' } },
'python/sdk-runtime/platforms.json': platforms,
'apps/cli/config/agent-presets/minimal/agent.cordis.yml': '[]\n',
'packages/preset/agent-presets/presets/minimal/agent.cordis.yml': '[]\n',
})
workspace(root, '@scope/root', {
peerDependencies: { '@scope/required': 'workspace:^', '@scope/optional': 'workspace:^' },
+2 -1
View File
@@ -30,7 +30,7 @@ interface RuntimePlatform {
type RuntimePlatformManifest = Record<string, RuntimePlatform>
const AGENT_PRESET_GLOB = 'apps/cli/config/agent-presets/*/agent.cordis.yml'
const AGENT_PRESET_GLOB = 'packages/preset/agent-presets/presets/*/agent.cordis.yml'
export interface RuntimeClosureResult {
failures: string[]
@@ -181,6 +181,7 @@ function disabledOnPlatform(value: unknown, processPlatform: string): boolean {
function processPlatformForTarget(target: string): string {
if (target.startsWith('linux-')) return 'linux'
if (target.startsWith('macos-')) return 'darwin'
if (target.startsWith('win-')) return 'win32'
throw new Error(`verify-runtime-closure: unsupported runtime target ${JSON.stringify(target)}`)
}