diff --git a/apps/cli/package.json b/apps/cli/package.json index 1553f02ed5..263edce734 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -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", diff --git a/apps/cli/tests/web-agent-presets.spec.ts b/apps/cli/tests/web-agent-presets.spec.ts index 4b6e6b0b5b..28b35d67e1 100644 --- a/apps/cli/tests/web-agent-presets.spec.ts +++ b/apps/cli/tests/web-agent-presets.spec.ts @@ -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 { 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, [{ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 44ed3a2620..072987794f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -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