fix(cli): boot the composition test the way the profile boot now does
The shipped surface stopped being two yml files: `base.cordis.yml` and `web.cordis.yml` are bundle patch layers now, applied over an empty preset root. This test still opened the old paths, so it failed before asserting anything. It composes the same two layers the profile boot composes, over the same empty root, and heals the flat module fallback the way the boot does — the root lives outside this workspace, so bare plugin names have no other way to resolve. The web bundle's runtime row is disabled beside the webserver: it injects `httpServer`, so a disabled port leaves it pending forever. It owns dist serving and the URL prompt line, neither of which decides an agent's capabilities. `apps/cli` declares the packages the shipped agent presets name again. The bundle split emptied its plugin dependencies, and the flat fallback links only the app's dependency closure — so a preset row naming `dsh-persona` resolved to nothing, and every preset mount failed. Which packages the shipped presets compose is not implied by any bundle: the presets live beside this app's config, so this app is what has to declare them.
This commit is contained in:
@@ -21,17 +21,44 @@
|
||||
"@deepseek-ai/dsh-app-boot": "workspace:^",
|
||||
"@deepseek-ai/dsh-base": "workspace:^",
|
||||
"@deepseek-ai/dsh-client-ui-agent-preset": "workspace:^",
|
||||
"@deepseek-ai/dsh-command-compact": "workspace:^",
|
||||
"@deepseek-ai/dsh-command-goal": "workspace:^",
|
||||
"@deepseek-ai/dsh-compact-basic": "workspace:^",
|
||||
"@deepseek-ai/dsh-compact-tool-result-prune": "workspace:^",
|
||||
"@deepseek-ai/dsh-goal": "workspace:^",
|
||||
"@deepseek-ai/dsh-goal-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-headless": "workspace:^",
|
||||
"@deepseek-ai/dsh-mcp-client": "workspace:^",
|
||||
"@deepseek-ai/dsh-paths": "workspace:^",
|
||||
"@deepseek-ai/dsh-persona": "workspace:^",
|
||||
"@deepseek-ai/dsh-plan-mode": "workspace:^",
|
||||
"@deepseek-ai/dsh-pty": "workspace:^",
|
||||
"@deepseek-ai/dsh-pty-local": "workspace:^",
|
||||
"@deepseek-ai/dsh-session-reference": "workspace:^",
|
||||
"@deepseek-ai/dsh-skill": "workspace:^",
|
||||
"@deepseek-ai/dsh-skill-local": "workspace:^",
|
||||
"@deepseek-ai/dsh-tasks-local": "workspace:^",
|
||||
"@deepseek-ai/dsh-tmux-context": "workspace:^",
|
||||
"@deepseek-ai/dsh-token-meter": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-ask-user": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-bash": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-bash-persistent": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-fs": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-fs-search": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-goal": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-ralph": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-skill": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-str-replace-editor": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-subagent": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-subagent-control": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-tasks": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-todo": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-web": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-workflow": "workspace:^",
|
||||
"@deepseek-ai/dsh-web-app": "workspace:^",
|
||||
"@deepseek-ai/dsh-workflow-workerthread": "workspace:^",
|
||||
"@deepseek-ai/dsh-workspace-context": "workspace:^",
|
||||
"commander": "^15.0.0",
|
||||
"cordis": "^4.0.0-rc.7",
|
||||
"js-yaml": "^4.2.0",
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { mkdtemp, readFile, stat, writeFile } from 'node:fs/promises'
|
||||
import { mkdir, mkdtemp, readFile, stat, writeFile } from 'node:fs/promises'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { dirname, 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'
|
||||
@@ -13,8 +13,12 @@ import { resolveSessionPreset, SETTINGS_NAMESPACE } from '@deepseek-ai/dsh-agent
|
||||
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,
|
||||
@@ -24,7 +28,8 @@ const WEB_OVERLAY = join(CONFIG_DIR, 'web.cordis.yml')
|
||||
async function bootWeb(settingsFile: string, extra: PatchOptions[] = []): Promise<Context> {
|
||||
const storageRoot = join(dirname(settingsFile), 'storages')
|
||||
const patches: PatchOptions[] = [
|
||||
...loadOverlayPatches('dsh-test', WEB_OVERLAY),
|
||||
...loadOverlayPatches('dsh-test', BASE_PATCH),
|
||||
...loadOverlayPatches('dsh-test', WEB_PATCH),
|
||||
// The settings row defaults to `$DSH_HOME/settings.yaml`. Left alone it
|
||||
// reads the developer's own document — and since the default preset is a
|
||||
// setting, a stored `agent-presets.default` would decide this file's
|
||||
@@ -44,6 +49,11 @@ async function bootWeb(settingsFile: string, extra: PatchOptions[] = []): Promis
|
||||
// moved into the presets that a host row still waits for. The boot audit
|
||||
// is that assertion.
|
||||
{ id: 'webserver', disabled: true },
|
||||
// The web bundle's runtime row injects `httpServer`, so it cannot
|
||||
// activate without the bound port disabled above. It owns dist serving
|
||||
// and the URL prompt line — surface glue, not anything that decides an
|
||||
// agent's capabilities, which is all this file asserts.
|
||||
{ id: 'web-runtime', disabled: true },
|
||||
{ id: 'telemetry-otel', disabled: true },
|
||||
{ id: 'modules', disabled: true },
|
||||
{ id: 'connection', disabled: true },
|
||||
@@ -62,7 +72,17 @@ async function bootWeb(settingsFile: string, extra: PatchOptions[] = []): Promis
|
||||
},
|
||||
...extra,
|
||||
]
|
||||
return await boot('dsh-test', BASE_CONFIG, patches)
|
||||
// The surface is patch layers over an empty preset root, so the root sits
|
||||
// outside this workspace and 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.
|
||||
const home = dirname(settingsFile)
|
||||
healProfilesModuleFallback(INSTALL_ANCHOR, home)
|
||||
const profileDir = join(home, 'profiles', 'spec')
|
||||
await mkdir(profileDir, { recursive: true })
|
||||
const rootConfig = join(profileDir, 'cordis.yml')
|
||||
await writeFile(rootConfig, '[]\n')
|
||||
return await boot('dsh-test', rootConfig, patches)
|
||||
}
|
||||
|
||||
const toolNames = (ctx: Context, agent?: Agent): string[] =>
|
||||
@@ -339,7 +359,7 @@ describe('authoring a preset on the shipped composition', () => {
|
||||
let userRoot: string
|
||||
|
||||
beforeAll(async () => {
|
||||
userRoot = join(await mkdtemp(join(tmpdir(), 'dsh-preset-authoring-')), 'presets')
|
||||
userRoot = join(await mkdtemp(join(tmpdir(), 'dsh-preset-authoring-')), 'profiles')
|
||||
const settingsFile = join(await mkdtemp(join(tmpdir(), 'dsh-preset-authoring-settings-')), 'settings.yaml')
|
||||
await writeFile(settingsFile, '{}\n')
|
||||
authorCtx = await bootWeb(settingsFile, [{
|
||||
|
||||
Generated
+81
@@ -152,6 +152,24 @@ importers:
|
||||
'@deepseek-ai/dsh-client-ui-agent-preset':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/client/ui-agent-preset
|
||||
'@deepseek-ai/dsh-command-compact':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/compact/command-compact
|
||||
'@deepseek-ai/dsh-command-goal':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/goal/command-goal
|
||||
'@deepseek-ai/dsh-compact-basic':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/compact/compact-basic
|
||||
'@deepseek-ai/dsh-compact-tool-result-prune':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/compact/compact-tool-result-prune
|
||||
'@deepseek-ai/dsh-goal':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/goal/goal
|
||||
'@deepseek-ai/dsh-goal-session':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/goal/goal-session
|
||||
'@deepseek-ai/dsh-headless':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/bundle/headless
|
||||
@@ -161,6 +179,12 @@ importers:
|
||||
'@deepseek-ai/dsh-paths':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/util/paths
|
||||
'@deepseek-ai/dsh-persona':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/preset/persona
|
||||
'@deepseek-ai/dsh-plan-mode':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/plan/plan-mode
|
||||
'@deepseek-ai/dsh-pty':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/pty/pty
|
||||
@@ -170,21 +194,78 @@ importers:
|
||||
'@deepseek-ai/dsh-session-reference':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/context/session-reference
|
||||
'@deepseek-ai/dsh-skill':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/skill/skill
|
||||
'@deepseek-ai/dsh-skill-local':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/skill/skill-local
|
||||
'@deepseek-ai/dsh-tasks-local':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/tasks/tasks-local
|
||||
'@deepseek-ai/dsh-tmux-context':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/context/tmux-context
|
||||
'@deepseek-ai/dsh-token-meter':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/llm/token-meter
|
||||
'@deepseek-ai/dsh-tool-ask-user':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/ui/tool-ask-user
|
||||
'@deepseek-ai/dsh-tool-bash':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/bash/tool-bash
|
||||
'@deepseek-ai/dsh-tool-bash-persistent':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/pty/tool-bash-persistent
|
||||
'@deepseek-ai/dsh-tool-cordis':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/cordis/tool-cordis
|
||||
'@deepseek-ai/dsh-tool-fs':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/fs/tool-fs
|
||||
'@deepseek-ai/dsh-tool-fs-search':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/fs/tool-fs-search
|
||||
'@deepseek-ai/dsh-tool-goal':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/goal/tool-goal
|
||||
'@deepseek-ai/dsh-tool-ralph':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/workflow/tool-ralph
|
||||
'@deepseek-ai/dsh-tool-skill':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/skill/tool-skill
|
||||
'@deepseek-ai/dsh-tool-str-replace-editor':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/fs/tool-str-replace-editor
|
||||
'@deepseek-ai/dsh-tool-subagent':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/subagent/tool-subagent
|
||||
'@deepseek-ai/dsh-tool-subagent-control':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/subagent/tool-subagent-control
|
||||
'@deepseek-ai/dsh-tool-tasks':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/tasks/tool-tasks
|
||||
'@deepseek-ai/dsh-tool-todo':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/todo/tool-todo
|
||||
'@deepseek-ai/dsh-tool-web':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/web/tool-web
|
||||
'@deepseek-ai/dsh-tool-workflow':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/workflow/tool-workflow
|
||||
'@deepseek-ai/dsh-web-app':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/bundle/web-app
|
||||
'@deepseek-ai/dsh-workflow-workerthread':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/workflow/workflow-workerthread
|
||||
'@deepseek-ai/dsh-workspace-context':
|
||||
specifier: workspace:^
|
||||
version: link:../../packages/context/workspace-context
|
||||
commander:
|
||||
specifier: ^15.0.0
|
||||
version: 15.0.0
|
||||
|
||||
Reference in New Issue
Block a user