refactor: drop obsolete expose-internals flag
This commit is contained in:
@@ -58,7 +58,7 @@ The leaf supplies the swappable backends: an LLM adapter (`llm-deepseek` for the
|
||||
- honors `DSH_SNAPSHOT=replay` by booting the sibling `cordis.snapshot.yml` (the keyless replay tree, `llm-replay` in place of `llm-deepseek`);
|
||||
- in a snapshot run, disposes the context on stdin EOF so the session log is fully flushed before exit.
|
||||
|
||||
Run it under `node --expose-internals`, or Loader's optional `node-addon-require-builtin` fallback is required, so the cordis Loader can resolve the config's bare plugin specifiers through its internal module loader. (`demo:acp` runs under tsx, whose tsconfig `paths` map resolves them instead.)
|
||||
The repository installs Loader's optional `node-addon-require-builtin` peer, so the built bin resolves bare plugin specifiers through the internal module loader under plain Node. (`demo:acp` runs under tsx, whose tsconfig `paths` map resolves them instead.)
|
||||
|
||||
All diagnostics go to **stderr** — stdout is the protocol.
|
||||
|
||||
|
||||
@@ -23,8 +23,7 @@ import { ACP_SESSION_REFERENCE_META_KEY } from '@deepseek-ai/dsh-acp'
|
||||
/**
|
||||
* Published-entry smoke: run `lib/bin.js` under plain Node in a symlinked external consumer and
|
||||
* complete a mock-backed turn. This catches built-only settle races, stdout protocol leaks, and
|
||||
* published persistence behavior that the tsx source-path smoke cannot. It skips before build;
|
||||
* `--expose-internals` enables Cordis bare-plugin loading.
|
||||
* published persistence behavior that the tsx source-path smoke cannot. It skips before build.
|
||||
*/
|
||||
|
||||
const repoRoot = fileURLToPath(new URL('../../../../', import.meta.url))
|
||||
@@ -133,7 +132,7 @@ afterEach(async () => {
|
||||
describe.skipIf(!existsSync(acpBin))('dsh-acp-demo BUILT bin (node lib/bin.js, no tsx)', () => {
|
||||
it('boots the published bin, completes a turn, and writes default Zstandard persistence', async () => {
|
||||
consumer = await makeConsumer()
|
||||
child = spawn(process.execPath, ['--expose-internals', acpBin, '--config', './cordis.yml'], {
|
||||
child = spawn(process.execPath, [acpBin, '--config', './cordis.yml'], {
|
||||
cwd: consumer,
|
||||
env: {
|
||||
...process.env,
|
||||
@@ -226,7 +225,7 @@ describe.skipIf(!existsSync(acpBin))('dsh-acp-demo BUILT bin (node lib/bin.js, n
|
||||
/** Spawn the built acp bin against `configArg` and resolve with its exit code + stderr. */
|
||||
function runBinExpectingExit(configArg: string, cwd: string = tmpdir()): Promise<{ code: number; stderr: string }> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const proc = spawn(process.execPath, ['--expose-internals', acpBin, '--config', configArg], {
|
||||
const proc = spawn(process.execPath, [acpBin, '--config', configArg], {
|
||||
cwd,
|
||||
env: {
|
||||
...process.env,
|
||||
|
||||
@@ -38,7 +38,7 @@ The root headless-agent example supplies its leaf:
|
||||
pnpm run demo:headless "inspect the failing test and fix it"
|
||||
```
|
||||
|
||||
Loader configs with bare package specifiers require `node --expose-internals` or the Loader's optional native fallback. The root command supplies the Node flag.
|
||||
Loader configs resolve bare package specifiers through the optional native helper installed by the repository, so the root command needs no special Node flags.
|
||||
|
||||
### Output formats
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ interface BinResult {
|
||||
|
||||
function runBuiltBin(cwd: string, args: readonly string[], interrupt?: NodeJS.Signals): Promise<BinResult> {
|
||||
return new Promise((resolveResult, reject) => {
|
||||
const child = spawn(process.execPath, ['--expose-internals', cliBin, ...args], {
|
||||
const child = spawn(process.execPath, [cliBin, ...args], {
|
||||
cwd,
|
||||
env: { ...process.env, DSH_HOME: join(cwd, '.dsh'), DSH_AGENTS_HOME: join(cwd, '.agents') },
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
|
||||
@@ -48,7 +48,7 @@ Fresh runs mint a `main-session-<uuid>` session id and pass it to both the TUI a
|
||||
|
||||
## The bin
|
||||
|
||||
`dsh-tui-demo [path-to-cordis.yml]` defaults to `./cordis.yml`, loads the optional cwd `.env`, boots the Cordis Loader, and waits for the full plugin tree. Bare package specifiers require `node --expose-internals` or the Loader's optional native fallback; the repository scripts use `--expose-internals`.
|
||||
`dsh-tui-demo [path-to-cordis.yml]` defaults to `./cordis.yml`, loads the optional cwd `.env`, boots the Cordis Loader, and waits for the full plugin tree. The repository installs Loader's optional native helper, so bare package specifiers resolve under plain Node.
|
||||
|
||||
## Example leaf
|
||||
|
||||
|
||||
@@ -54,9 +54,9 @@ async function makeConsumer(): Promise<string> {
|
||||
/** Run the built bin in `cwd` with PIPED stdio; resolve with output + exit code. */
|
||||
function runBuiltBin(cwd: string): Promise<{ stdout: string; code: number; stderr: string }> {
|
||||
return new Promise((resolve, reject) => {
|
||||
// NO tsx — this is the published `node lib/bin.js` path (`--expose-internals`
|
||||
// matches the demo command; the guard fires before the Loader needs it).
|
||||
const child = spawn(process.execPath, ['--expose-internals', tuiBin, './cordis.yml'], {
|
||||
// NO tsx — this is the published `node lib/bin.js` path; the guard fires
|
||||
// before the Loader resolves the config tree.
|
||||
const child = spawn(process.execPath, [tuiBin, './cordis.yml'], {
|
||||
cwd,
|
||||
env: { ...process.env, DSH_HOME: join(cwd, '.dsh'), DSH_AGENTS_HOME: join(cwd, '.agents') },
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
|
||||
@@ -59,8 +59,6 @@ export interface ExampleLaunchOptions {
|
||||
readonly mode?: ExampleMode
|
||||
/** Absolute repo tsconfig whose `paths` map resolves unbuilt workspace imports. Required in `src` mode, ignored in `lib`. */
|
||||
readonly tsconfigPath?: string
|
||||
/** Prepend `--expose-internals` (the Cordis Loader's bare-plugin resolver needs it for some bins); defaults to `false`. */
|
||||
readonly exposeInternals?: boolean
|
||||
/** Extra environment entries the mode-specific ones layer over; the caller then merges the result over `process.env`. */
|
||||
readonly env?: NodeJS.ProcessEnv
|
||||
}
|
||||
@@ -90,9 +88,9 @@ function toLibBin(srcBin: string): string {
|
||||
/**
|
||||
* Resolve how to spawn an example bin in the selected mode.
|
||||
*
|
||||
* `src` yields `node [--expose-internals] --import <tsx> <srcBin> <configArgs>` with `TSX_TSCONFIG_PATH`
|
||||
* set so the tsconfig `paths` map resolves workspace imports to source. `lib` yields
|
||||
* `node [--expose-internals] <libBin> <configArgs>` under plain Node with no tsx and no paths map, so
|
||||
* `src` yields `node --import <tsx> <srcBin> <configArgs>` with `TSX_TSCONFIG_PATH` set so the
|
||||
* tsconfig `paths` map resolves workspace imports to source. `lib` yields
|
||||
* `node <libBin> <configArgs>` under plain Node with no tsx and no paths map, so
|
||||
* bare package plugins resolve through real package `exports` into built `lib/`; relative example-local
|
||||
* TypeScript plugins remain source files loaded through Node's built-in type stripping. Bare resolution
|
||||
* requires the config to live below a workspace that declares its `cordis.yml` package dependencies.
|
||||
@@ -103,7 +101,6 @@ function toLibBin(srcBin: string): string {
|
||||
export function resolveExampleLaunch(options: ExampleLaunchOptions): ExampleLaunch {
|
||||
const mode = options.mode ?? resolveExampleMode()
|
||||
const configArgs = options.configArgs ?? []
|
||||
const flags = options.exposeInternals === true ? ['--expose-internals'] : []
|
||||
const env: NodeJS.ProcessEnv = { ...options.env }
|
||||
|
||||
if (mode === 'src') {
|
||||
@@ -112,10 +109,10 @@ export function resolveExampleLaunch(options: ExampleLaunchOptions): ExampleLaun
|
||||
}
|
||||
const tsxLoader = import.meta.resolve('tsx')
|
||||
env.TSX_TSCONFIG_PATH = options.tsconfigPath
|
||||
return { command: process.execPath, args: [...flags, '--import', tsxLoader, options.srcBin, ...configArgs], env }
|
||||
return { command: process.execPath, args: ['--import', tsxLoader, options.srcBin, ...configArgs], env }
|
||||
}
|
||||
|
||||
return { command: process.execPath, args: [...flags, options.libBin ?? toLibBin(options.srcBin), ...configArgs], env }
|
||||
return { command: process.execPath, args: [options.libBin ?? toLibBin(options.srcBin), ...configArgs], env }
|
||||
}
|
||||
|
||||
/** Inputs that vary between real-Loader example smokes. */
|
||||
@@ -172,7 +169,6 @@ export async function runLoaderSmoke(options: LoaderSmokeOptions): Promise<Loade
|
||||
configArgs: options.binArgs ?? [options.configPath],
|
||||
...options.mode !== undefined ? { mode: options.mode } : {},
|
||||
tsconfigPath: options.tsconfigPath,
|
||||
exposeInternals: true,
|
||||
env: { DSH_HOME: join(cwd, '.dsh'), DSH_AGENTS_HOME: join(cwd, '.agents'), ...options.env },
|
||||
})
|
||||
const result = await new Promise<LoaderSmokeResult>((resolve, reject) => {
|
||||
|
||||
@@ -50,7 +50,6 @@ describe('resolveExampleLaunch', () => {
|
||||
expect(args).toContain('--import')
|
||||
expect(args).toContain(SRC_BIN)
|
||||
expect(args[args.length - 1]).toBe('./cordis.yml')
|
||||
expect(args).not.toContain('--expose-internals')
|
||||
expect(env.TSX_TSCONFIG_PATH).toBe(TSCONFIG)
|
||||
})
|
||||
|
||||
@@ -78,11 +77,6 @@ describe('resolveExampleLaunch', () => {
|
||||
expect(args).toContain(fixture)
|
||||
})
|
||||
|
||||
it('prepends --expose-internals when requested', () => {
|
||||
const { args } = resolveExampleLaunch({ srcBin: SRC_BIN, mode: 'lib', exposeInternals: true })
|
||||
expect(args[0]).toBe('--expose-internals')
|
||||
})
|
||||
|
||||
it('lib mode: rewrites only the last /src/ segment', () => {
|
||||
const { args } = resolveExampleLaunch({
|
||||
srcBin: '/repo/src/packages/examples/acp-demo/src/bin.ts',
|
||||
|
||||
@@ -16,7 +16,7 @@ Shared boot glue for the app bins ([`dsh-tui-demo`](../../examples/tui-demo/READ
|
||||
|
||||
Two failure classes the guards handle: `loader.await()` swallows init rejections (`Promise.allSettled`) — Node still exits non-zero on the resulting unhandled rejection, and `installFailLoud` replaces the noisy dump with one labelled line and a guaranteed `exit(1)`; a failed plugin IMPORT is only logged by the Loader (the process would otherwise exit 0 on a usable config typo), leaving a fiber-less entry that `assertEntriesLoaded` turns into a `boot()` rejection.
|
||||
|
||||
Bare plugin specifiers in a config (`@deepseek-ai/dsh-*`, npm packages) resolve through the cordis Loader's internal module loader when Node runs with `--expose-internals` or the optional `node-addon-require-builtin` fallback is installed; without either, consumers must install plugins where plain Node import resolution can find them. Relative specifiers resolve against the config directory with no flag. The bins' subprocess smokes exercise the internal-loader path, while this package's unit suite drives `boot()` in-process against configs with relative specifiers.
|
||||
Bare plugin specifiers in a config (`@deepseek-ai/dsh-*`, npm packages) resolve through the Cordis Loader's internal module loader. Repository bins install Loader's optional `node-addon-require-builtin` peer; external callers must supply it or install plugins where plain Node import resolution can find them. Relative specifiers resolve against the config directory without the native helper. The bins' subprocess smokes exercise the internal-loader path, while this package's unit suite drives `boot()` in-process against configs with relative specifiers.
|
||||
|
||||
This package carries no loader hooks and no dev-mode surface: the `dsh-scripts` launcher ([`sdk/scripts`](../../sdk/scripts/README.md), with the shared project model in [`sdk/helper`](../../sdk/helper/README.md)) owns process startup, tsx registration, and local-plugin source resolution, and consumes these helpers for the boot sequence itself.
|
||||
|
||||
@@ -39,7 +39,7 @@ No direct invalidation from `boot()`; a consumer that calls `addHarnessSourceSec
|
||||
|
||||
## Known Limitations and Deferred Work
|
||||
|
||||
- **Bare package specifiers depend on Loader internals** — production bins need `node --expose-internals` or the Loader's optional native fallback; an in-process caller without either must use resolvable relative/file specifiers or tsx path mapping.
|
||||
- **Bare package specifiers depend on Loader internals** — production bins need Loader's optional native helper; an in-process caller without it must use resolvable relative/file specifiers or tsx path mapping.
|
||||
- **Snapshot replay swapping is basename-specific** — only a config ending in `cordis.yml` or `cordis.yaml` maps to the sibling `cordis.snapshot.yml`; custom config names require caller-managed selection.
|
||||
- **Environment loading is cwd-scoped and optional** — the helper loads one `.env` file and warns on failure; it does not search parents, merge profiles, or validate required variables.
|
||||
- **Personal config is patch-shaped** — an id-targeted patch replaces the entry's whole `config` rather than deep-merging, so a personal override restates the base fields it keeps.
|
||||
|
||||
@@ -209,9 +209,8 @@ export function assertEntriesLoaded(ctx: Context, binName: string): void {
|
||||
* `cordis:include` builtin, loading through the ambient module pipeline
|
||||
* (vite/tsx/plain ESM) while the included tree's own specifiers stay
|
||||
* config-relative. A missing fiber rejects here; a later init rejection is
|
||||
* handled by {@link installFailLoud}. Built bins need `--expose-internals` or
|
||||
* the Loader's native fallback for bare plugin specifiers; relative specifiers
|
||||
* do not.
|
||||
* handled by {@link installFailLoud}. Built bins need the Loader's native
|
||||
* helper for bare plugin specifiers; relative specifiers do not.
|
||||
* @param binName - the diagnostic prefix for load-failure errors.
|
||||
* @param absoluteConfigPath - the config to include; must already be absolute
|
||||
* (see {@link resolveConfigPath}).
|
||||
|
||||
Reference in New Issue
Block a user