From 43af75fca8bd72db4fc5ec973ccf66f312d92f63 Mon Sep 17 00:00:00 2001 From: Yichen Jiang Date: Fri, 7 Aug 2026 12:50:09 +0800 Subject: [PATCH] fix(cli): boot the composition test the way the preset boot now does MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `apps/cli/config/base.cordis.yml` and `web.cordis.yml` no longer exist — the bundle split replaced them with `packages/bundle/{base,web-app}/cordis.patch.yml` — so this file booted a path that was deleted under it and every CI run since the merge failed at `ENOENT`. It now boots what `dsh web` boots: an empty preset root with the two bundle patches over it. That root sits outside the workspace, so bare plugin names cannot resolve by Node's upward walk and the flat module fallback the preset boot maintains is what makes them resolvable — the same mechanism, not a test-only shim. That fallback links each package's PUBLISHED entry, so this file now consumes the artifact plane and moves to the lane that builds first (`.e2e.ts`, beside `built-bin.e2e.ts`), rather than the coverage lane, which installs and runs on a clean tree. --- ...esets.spec.ts => web-agent-presets.e2e.ts} | 32 +++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) rename apps/cli/tests/{web-agent-presets.spec.ts => web-agent-presets.e2e.ts} (84%) diff --git a/apps/cli/tests/web-agent-presets.spec.ts b/apps/cli/tests/web-agent-presets.e2e.ts similarity index 84% rename from apps/cli/tests/web-agent-presets.spec.ts rename to apps/cli/tests/web-agent-presets.e2e.ts index 80f397d916..0e01e23fce 100644 --- a/apps/cli/tests/web-agent-presets.spec.ts +++ b/apps/cli/tests/web-agent-presets.e2e.ts @@ -1,8 +1,9 @@ -import { readFile } from 'node:fs/promises' +import { mkdir, mkdtemp, readFile, writeFile } from 'node:fs/promises' +import { tmpdir } from 'node:os' import { fileURLToPath } from 'node:url' import { join } from 'node:path' import { Context } from 'cordis' -import { boot, loadOverlayPatches } from '@deepseek-ai/dsh-app-boot' +import { boot, healProfilesModuleFallback, loadOverlayPatches } from '@deepseek-ai/dsh-app-boot' import { SessionId } from '@deepseek-ai/dsh-session' import type { Agent } from '@deepseek-ai/dsh-agent' import type { PatchOptions } from '@cordisjs/plugin-include' @@ -11,8 +12,12 @@ import type {} from '@deepseek-ai/dsh-agent-presets' import type {} from '@deepseek-ai/dsh-tools' const CONFIG_DIR = fileURLToPath(new URL('../config/', import.meta.url)) -const BASE_CONFIG = join(CONFIG_DIR, 'base.cordis.yml') -const WEB_OVERLAY = join(CONFIG_DIR, 'web.cordis.yml') +const REPO_ROOT = fileURLToPath(new URL('../../..', import.meta.url)) +/** The shipped Web surface: the dsh-base and dsh-web-app bundle patches over an empty preset root. */ +const BASE_PATCH = join(REPO_ROOT, 'packages/bundle/base/cordis.patch.yml') +const WEB_PATCH = join(REPO_ROOT, 'packages/bundle/web-app/cordis.patch.yml') +/** The installation anchor whose dependency surface the preset module fallback mirrors. */ +const INSTALL_ANCHOR = join(REPO_ROOT, 'apps/cli/package.json') /** * Boot the shipped Web composition, minus the rows that would bind a port, @@ -21,10 +26,13 @@ const WEB_OVERLAY = join(CONFIG_DIR, 'web.cordis.yml') */ async function bootWeb(): Promise { const patches: PatchOptions[] = [ - ...loadOverlayPatches('dsh-test', WEB_OVERLAY), + ...loadOverlayPatches('dsh-test', BASE_PATCH), + ...loadOverlayPatches('dsh-test', WEB_PATCH), // Host rows with side effects outside this process: a bound port, a // served asset tree, a telemetry exporter. { id: 'webserver', disabled: true }, + // Waits for `httpServer`, which the disabled webserver above provides. + { id: 'web-runtime', disabled: true }, { id: 'telemetry-otel', disabled: true }, { id: 'modules', disabled: true }, { id: 'connection', disabled: true }, @@ -42,7 +50,19 @@ async function bootWeb(): Promise { config: { default: 'standard', roots: [{ path: join(CONFIG_DIR, 'agent-presets'), trust: 'system' }] }, }, ] - return await boot('dsh-test', BASE_CONFIG, patches) + // The composition boots from an empty preset root, exactly as `dsh web` + // does: the root's own directory is outside this workspace, so bare plugin + // names cannot resolve by Node's upward walk. The flat fallback the preset + // boot maintains is what makes them resolvable — the same mechanism, not a + // test-only shim. It links each package's published entry, so this file + // consumes the ARTIFACT plane and lives in the lane that builds. + const home = await mkdtemp(join(tmpdir(), 'dsh-web-presets-')) + healProfilesModuleFallback(INSTALL_ANCHOR, home) + const presetDir = join(home, 'profiles', 'spec') + await mkdir(presetDir, { recursive: true }) + const rootConfig = join(presetDir, 'cordis.yml') + await writeFile(rootConfig, '[]\n') + return await boot('dsh-test', rootConfig, patches) } const toolNames = (ctx: Context, agent?: Agent): string[] =>