mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
fix: boot use internal loader and fix path resolve
This commit is contained in:
@@ -147,11 +147,11 @@ describe.skipIf(!existsSync(acpBin))('dsh-acp-agent BUILT bin (node lib/bin.js,
|
||||
}, 30_000)
|
||||
|
||||
it('fails LOUD (non-zero exit + stderr) on a config whose directory does not exist', async () => {
|
||||
// A nonexistent directory prevents even the include plugin import. Loader logs the failure and
|
||||
// leaves no fiber; boot's settled-entry guard must convert that state into non-zero exit.
|
||||
// boot() pre-resolves the bootstrap include to an absolute URL, so a nonexistent config
|
||||
// directory cannot break its import; the include plugin's own read must fail loud instead.
|
||||
const { code, stderr } = await runBinExpectingExit('/nonexistent/dir/cordis.yml')
|
||||
expect(code).not.toBe(0)
|
||||
expect(stderr).toContain('failed to load')
|
||||
expect(stderr).toContain('config file not found')
|
||||
}, 30_000)
|
||||
|
||||
it('fails LOUD (non-zero exit + stderr) on a missing config file in a real directory', async () => {
|
||||
|
||||
@@ -8,7 +8,7 @@ Shared boot glue for the app bins ([`dsh-stdio-agent`](../stdio-agent/README.md)
|
||||
| `loadEnv(binName, dir?, warn?)` | Load the gitignored `.env` (Node `process.loadEnvFile`); absent file is fine, an unloadable one warns a single labelled line (default: stderr) |
|
||||
| `installFailLoud(binName, proc?)` | Turn a post-`boot()` unhandled Loader rejection into one labelled stderr line + `exit(1)`; returns the uninstaller (for tests) |
|
||||
| `assertEntriesLoaded(ctx, binName)` | Throw when a settled tree holds an enabled entry with no fiber (a plugin module that failed to import) |
|
||||
| `boot(binName, absoluteConfigPath)` | Mount the Loader, include the config by absolute `file://` URL, await the whole tree, assert entries loaded, return the root context |
|
||||
| `boot(binName, absoluteConfigPath)` | Mount the Loader, mount the statically imported include plugin as the `cordis:include` builtin (so the config may live outside `node_modules` reach), include the config by absolute `file://` URL, await the whole tree, assert entries loaded, return the root context |
|
||||
|
||||
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.
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import { pathToFileURL } from 'node:url'
|
||||
import { basename, dirname, resolve } from 'node:path'
|
||||
import { Context } from 'cordis'
|
||||
import Loader from '@cordisjs/plugin-loader'
|
||||
import Include from '@cordisjs/plugin-include'
|
||||
|
||||
/**
|
||||
* Resolve the config to boot. Replay swaps a `cordis.yml` basename for
|
||||
@@ -95,11 +96,16 @@ export function assertEntriesLoaded(ctx: Context, binName: string): void {
|
||||
|
||||
/**
|
||||
* Boot the Loader against `absoluteConfigPath` and return only after the whole
|
||||
* tree settles. The include uses an absolute file URL while `baseUrl` stays at
|
||||
* the config directory for its relative imports. 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.
|
||||
* tree settles. Entry names load through the Loader's internal module loader
|
||||
* against `baseUrl` (the config directory), which may live outside
|
||||
* `node_modules` reach and, unbuilt, cannot load vendored source; the
|
||||
* bootstrap include is therefore statically imported and mounted as the
|
||||
* `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.
|
||||
* @param binName - the diagnostic prefix for load-failure errors.
|
||||
* @param absoluteConfigPath - the config to include; must already be absolute
|
||||
* (see {@link resolveConfigPath}).
|
||||
@@ -109,8 +115,9 @@ export async function boot(binName: string, absoluteConfigPath: string): Promise
|
||||
const ctx = new Context()
|
||||
ctx.baseUrl = pathToFileURL(dirname(absoluteConfigPath)).href + '/'
|
||||
await ctx.plugin(Loader)
|
||||
ctx.loader.builtins.include = Include
|
||||
await ctx.loader.create({
|
||||
name: '@cordisjs/plugin-include',
|
||||
name: 'cordis:include',
|
||||
config: { path: pathToFileURL(absoluteConfigPath).href },
|
||||
})
|
||||
await ctx.loader.await()
|
||||
|
||||
@@ -146,12 +146,12 @@ describe.skipIf(!existsSync(stdioBin))('dsh-stdio-agent BUILT bin (node lib/bin.
|
||||
}, 30_000)
|
||||
|
||||
it('fails LOUD (non-zero exit + stderr) on a config whose directory does not exist', async () => {
|
||||
// A nonexistent directory prevents even the include plugin import. Loader leaves no fiber, and
|
||||
// boot's settled-entry guard must turn that state into a clear non-zero failure.
|
||||
// boot() pre-resolves the bootstrap include to an absolute URL, so a nonexistent config
|
||||
// directory cannot break its import; the include plugin's own read must fail loud instead.
|
||||
consumer = await makeConsumer('unused')
|
||||
const { code, stderr } = await runBuiltBin(consumer, '/nonexistent/dir/cordis.yml', '')
|
||||
expect(code).not.toBe(0)
|
||||
expect(stderr).toContain('failed to load')
|
||||
expect(stderr).toContain('config file not found')
|
||||
}, 30_000)
|
||||
|
||||
it('fails LOUD (non-zero exit + stderr) on a missing config file in a real directory', async () => {
|
||||
|
||||
Reference in New Issue
Block a user