refactor: apply repository naming contract
Apply the accepted pre-release package, service, type, directory, and role renames as one repository-wide change.
This commit is contained in:
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write apps/cli/README.md
|
||||
README.md: d36183c545475020207bbf23e58d3c98b07ac6a6
|
||||
README.zh.md: 4693339e836d81c0b069704fb43451fb22accfdb
|
||||
README.md: 9a8d722b044ed5d8e31e3c27e54f8c9ef0839f82
|
||||
README.zh.md: dc40a4a6f54f99507bccb6b989aee0015e9604b3
|
||||
|
||||
@@ -9,7 +9,7 @@ The `dsh` command is the product launcher for profiles: ordered stacks of plugin
|
||||
| Command | Purpose |
|
||||
|---|---|
|
||||
| `dsh --profile <name>` | Boot the named profile under `$DSH_HOME/profiles/<name>`. |
|
||||
| `dsh --profile headless "task"` | Run one fresh persisted session, print the final answer, and exit. |
|
||||
| `dsh --profile headless "job"` | Run one fresh persisted session, print the final answer, and exit. |
|
||||
| `dsh web` | Alias of `--profile web`. |
|
||||
| `dsh plugin --profile <name> <pnpm args>` | Manage a profile's plugins by forwarding to pnpm in the profile directory. |
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
| 命令 | 用途 |
|
||||
|---|---|
|
||||
| `dsh --profile <name>` | 启动位于 `$DSH_HOME/profiles/<name>` 的指定 profile。 |
|
||||
| `dsh --profile headless "task"` | 运行一个新的持久化会话,打印最终答案并退出。 |
|
||||
| `dsh --profile headless "job"` | 运行一个新的持久化会话,打印最终答案并退出。 |
|
||||
| `dsh web` | `--profile web` 的别名。 |
|
||||
| `dsh plugin --profile <name> <pnpm args>` | 通过在 profile 目录中转发给 pnpm 来管理该 profile 的插件。 |
|
||||
|
||||
|
||||
@@ -24,19 +24,19 @@ flowchart LR
|
||||
cfg --> plugin_dsh_base_typert_gateway
|
||||
plugin_dsh_base_session_title["session-title<br/>@deepseek-ai/dsh-session-title"]
|
||||
cfg --> plugin_dsh_base_session_title
|
||||
plugin_dsh_base_session_title_llm["session-title-llm<br/>@deepseek-ai/dsh-session-title-first-message-llm"]
|
||||
plugin_dsh_base_session_title_llm["session-title-llm<br/>@deepseek-ai/dsh-session-title-first-prompt-llm"]
|
||||
cfg --> plugin_dsh_base_session_title_llm
|
||||
plugin_dsh_base_user_interaction["user-interaction<br/>@deepseek-ai/dsh-user-interaction"]
|
||||
cfg --> plugin_dsh_base_user_interaction
|
||||
plugin_dsh_base_user_questions["user-questions<br/>@deepseek-ai/dsh-user-questions"]
|
||||
cfg --> plugin_dsh_base_user_questions
|
||||
plugin_dsh_base_agent["agent<br/>@deepseek-ai/dsh-agent"]
|
||||
cfg --> plugin_dsh_base_agent
|
||||
plugin_dsh_base_agent_default_model["agent-default-model<br/>@deepseek-ai/dsh-agent-default-model"]
|
||||
cfg --> plugin_dsh_base_agent_default_model
|
||||
plugin_dsh_base_tasks["tasks<br/>@deepseek-ai/dsh-tasks-local"]
|
||||
cfg --> plugin_dsh_base_tasks
|
||||
plugin_dsh_base_jobs["jobs<br/>@deepseek-ai/dsh-jobs-local"]
|
||||
cfg --> plugin_dsh_base_jobs
|
||||
plugin_dsh_base_llm_retry["llm-retry<br/>@deepseek-ai/dsh-llm-retry"]
|
||||
cfg --> plugin_dsh_base_llm_retry
|
||||
plugin_dsh_base_settings["settings<br/>@deepseek-ai/dsh-settings-local"]
|
||||
plugin_dsh_base_settings["settings<br/>@deepseek-ai/dsh-settings-file"]
|
||||
cfg --> plugin_dsh_base_settings
|
||||
plugin_dsh_base_credentials["credentials<br/>@deepseek-ai/dsh-credentials-local"]
|
||||
cfg --> plugin_dsh_base_credentials
|
||||
@@ -50,8 +50,8 @@ flowchart LR
|
||||
cfg --> plugin_dsh_base_session_query_sqlite
|
||||
plugin_dsh_base_session_projection["session-projection<br/>@deepseek-ai/dsh-session-projection"]
|
||||
cfg --> plugin_dsh_base_session_projection
|
||||
plugin_dsh_base_telemetry_otel["telemetry-otel<br/>@deepseek-ai/dsh-session-telemetry-otel"]
|
||||
cfg --> plugin_dsh_base_telemetry_otel
|
||||
plugin_dsh_base_session_telemetry_otel["session-telemetry-otel<br/>@deepseek-ai/dsh-session-telemetry-otel"]
|
||||
cfg --> plugin_dsh_base_session_telemetry_otel
|
||||
plugin_dsh_base_subprocess["subprocess<br/>@deepseek-ai/dsh-subprocess-local"]
|
||||
cfg --> plugin_dsh_base_subprocess
|
||||
plugin_dsh_base_sandbox["sandbox<br/>@deepseek-ai/dsh-sandbox-local"]
|
||||
@@ -64,28 +64,28 @@ flowchart LR
|
||||
cfg --> plugin_dsh_base_pwsh_sandbox
|
||||
plugin_dsh_base_approval["approval<br/>@deepseek-ai/dsh-user-approval"]
|
||||
cfg --> plugin_dsh_base_approval
|
||||
plugin_dsh_base_permission["permission<br/>@deepseek-ai/dsh-permission"]
|
||||
plugin_dsh_base_permission["permission<br/>@deepseek-ai/dsh-permission-presets"]
|
||||
cfg --> plugin_dsh_base_permission
|
||||
plugin_dsh_base_bash_env["bash-env<br/>@deepseek-ai/dsh-bash-env"]
|
||||
cfg --> plugin_dsh_base_bash_env
|
||||
plugin_dsh_base_shell_env["shell-env<br/>@deepseek-ai/dsh-shell-env"]
|
||||
cfg --> plugin_dsh_base_shell_env
|
||||
plugin_dsh_base_tool_bash["tool-bash<br/>@deepseek-ai/dsh-tool-bash"]
|
||||
cfg --> plugin_dsh_base_tool_bash
|
||||
plugin_dsh_base_tool_pwsh["tool-pwsh<br/>@deepseek-ai/dsh-tool-pwsh"]
|
||||
cfg --> plugin_dsh_base_tool_pwsh
|
||||
plugin_dsh_base_tool_tasks["tool-tasks<br/>@deepseek-ai/dsh-tool-tasks"]
|
||||
cfg --> plugin_dsh_base_tool_tasks
|
||||
plugin_dsh_base_fs_policy["fs-policy<br/>@deepseek-ai/dsh-fs-policy"]
|
||||
cfg --> plugin_dsh_base_fs_policy
|
||||
plugin_dsh_base_tool_jobs["tool-jobs<br/>@deepseek-ai/dsh-tool-jobs"]
|
||||
cfg --> plugin_dsh_base_tool_jobs
|
||||
plugin_dsh_base_fs_observation_policy["fs-observation-policy<br/>@deepseek-ai/dsh-fs-observation-policy"]
|
||||
cfg --> plugin_dsh_base_fs_observation_policy
|
||||
plugin_dsh_base_tool_fs["tool-fs<br/>@deepseek-ai/dsh-tool-fs"]
|
||||
cfg --> plugin_dsh_base_tool_fs
|
||||
plugin_dsh_base_tool_fs_search["tool-fs-search<br/>@deepseek-ai/dsh-tool-fs-search"]
|
||||
cfg --> plugin_dsh_base_tool_fs_search
|
||||
plugin_dsh_base_workspace_context["workspace-context<br/>@deepseek-ai/dsh-workspace-context"]
|
||||
cfg --> plugin_dsh_base_workspace_context
|
||||
plugin_dsh_base_agent_instructions["agent-instructions<br/>@deepseek-ai/dsh-agent-instructions"]
|
||||
cfg --> plugin_dsh_base_agent_instructions
|
||||
plugin_dsh_base_skill["skill<br/>@deepseek-ai/dsh-skill"]
|
||||
cfg --> plugin_dsh_base_skill
|
||||
plugin_dsh_base_skill_local["skill-local<br/>@deepseek-ai/dsh-skill-local"]
|
||||
cfg --> plugin_dsh_base_skill_local
|
||||
plugin_dsh_base_skill_filesystem["skill-filesystem<br/>@deepseek-ai/dsh-skill-filesystem"]
|
||||
cfg --> plugin_dsh_base_skill_filesystem
|
||||
plugin_dsh_base_skill_badge["skill-badge<br/>@deepseek-ai/dsh-skill-badge"]
|
||||
cfg --> plugin_dsh_base_skill_badge
|
||||
plugin_dsh_base_tool_skill["tool-skill<br/>@deepseek-ai/dsh-tool-skill"]
|
||||
@@ -96,24 +96,24 @@ flowchart LR
|
||||
cfg --> plugin_dsh_base_command_feedback
|
||||
plugin_dsh_base_goal["goal<br/>@deepseek-ai/dsh-goal"]
|
||||
cfg --> plugin_dsh_base_goal
|
||||
plugin_dsh_base_goal_session["goal-session<br/>@deepseek-ai/dsh-goal-session"]
|
||||
cfg --> plugin_dsh_base_goal_session
|
||||
plugin_dsh_base_goal_round_driver["goal-round-driver<br/>@deepseek-ai/dsh-goal-round-driver"]
|
||||
cfg --> plugin_dsh_base_goal_round_driver
|
||||
plugin_dsh_base_command_goal["command-goal<br/>@deepseek-ai/dsh-command-goal"]
|
||||
cfg --> plugin_dsh_base_command_goal
|
||||
plugin_dsh_base_plan_mode["plan-mode<br/>@deepseek-ai/dsh-plan-mode"]
|
||||
cfg --> plugin_dsh_base_plan_mode
|
||||
plugin_dsh_base_token_meter["token-meter<br/>@deepseek-ai/dsh-token-meter"]
|
||||
cfg --> plugin_dsh_base_token_meter
|
||||
plugin_dsh_base_compact_basic["compact-basic<br/>@deepseek-ai/dsh-compact-basic"]
|
||||
cfg --> plugin_dsh_base_compact_basic
|
||||
plugin_dsh_base_compaction_basic["compaction-basic<br/>@deepseek-ai/dsh-compaction-basic"]
|
||||
cfg --> plugin_dsh_base_compaction_basic
|
||||
plugin_dsh_base_command_compact["command-compact<br/>@deepseek-ai/dsh-command-compact"]
|
||||
cfg --> plugin_dsh_base_command_compact
|
||||
plugin_dsh_base_subagent["subagent<br/>@deepseek-ai/dsh-subagent"]
|
||||
cfg --> plugin_dsh_base_subagent
|
||||
plugin_dsh_base_subagent_spawn["subagent-spawn<br/>@deepseek-ai/dsh-subagent-spawn"]
|
||||
cfg --> plugin_dsh_base_subagent_spawn
|
||||
plugin_dsh_base_subagent_fork["subagent-fork<br/>@deepseek-ai/dsh-subagent-fork"]
|
||||
cfg --> plugin_dsh_base_subagent_fork
|
||||
plugin_dsh_base_subagent_spawn_in_process["subagent-spawn-in-process<br/>@deepseek-ai/dsh-subagent-spawn-in-process"]
|
||||
cfg --> plugin_dsh_base_subagent_spawn_in_process
|
||||
plugin_dsh_base_subagent_fork_in_process["subagent-fork-in-process<br/>@deepseek-ai/dsh-subagent-fork-in-process"]
|
||||
cfg --> plugin_dsh_base_subagent_fork_in_process
|
||||
plugin_dsh_base_subagent_codex["subagent-codex<br/>@deepseek-ai/dsh-subagent-codex"]
|
||||
cfg --> plugin_dsh_base_subagent_codex
|
||||
plugin_dsh_base_subagent_claude_code["subagent-claude-code<br/>@deepseek-ai/dsh-subagent-claude-code"]
|
||||
@@ -128,11 +128,11 @@ flowchart LR
|
||||
cfg --> plugin_dsh_base_tool_subagent_fork
|
||||
plugin_dsh_base_tool_subagent_report["tool-subagent-report<br/>@deepseek-ai/dsh-tool-subagent-report"]
|
||||
cfg --> plugin_dsh_base_tool_subagent_report
|
||||
plugin_dsh_base_workflow_workerthread["workflow-workerthread<br/>@deepseek-ai/dsh-workflow-workerthread"]
|
||||
cfg --> plugin_dsh_base_workflow_workerthread
|
||||
plugin_dsh_base_workflow_worker_thread["workflow-worker-thread<br/>@deepseek-ai/dsh-workflow-worker-thread"]
|
||||
cfg --> plugin_dsh_base_workflow_worker_thread
|
||||
plugin_dsh_base_tool_workflow["tool-workflow<br/>@deepseek-ai/dsh-tool-workflow"]
|
||||
cfg --> plugin_dsh_base_tool_workflow
|
||||
plugin_dsh_base_timeout_policy["timeout-policy<br/>@deepseek-ai/dsh-timeout-policy"]
|
||||
plugin_dsh_base_timeout_policy["timeout-policy<br/>@deepseek-ai/dsh-tool-call-timeout-policy"]
|
||||
cfg --> plugin_dsh_base_timeout_policy
|
||||
plugin_dsh_base_spill_local["spill-local<br/>@deepseek-ai/dsh-spill-local"]
|
||||
cfg --> plugin_dsh_base_spill_local
|
||||
@@ -140,8 +140,8 @@ flowchart LR
|
||||
cfg --> plugin_dsh_base_spill_policy
|
||||
plugin_dsh_base_session_checkpoint_policy["session-checkpoint-policy<br/>@deepseek-ai/dsh-session-checkpoint-policy"]
|
||||
cfg --> plugin_dsh_base_session_checkpoint_policy
|
||||
plugin_dsh_base_tool_result_prune["tool-result-prune<br/>@deepseek-ai/dsh-compact-tool-result-prune"]
|
||||
cfg --> plugin_dsh_base_tool_result_prune
|
||||
plugin_dsh_base_tool_result_pruner["tool-result-pruner<br/>@deepseek-ai/dsh-compaction-tool-result-pruner"]
|
||||
cfg --> plugin_dsh_base_tool_result_pruner
|
||||
plugin_dsh_base_tool_todo["tool-todo<br/>@deepseek-ai/dsh-tool-todo"]
|
||||
cfg --> plugin_dsh_base_tool_todo
|
||||
plugin_dsh_base_tool_goal["tool-goal<br/>@deepseek-ai/dsh-tool-goal"]
|
||||
@@ -150,8 +150,8 @@ flowchart LR
|
||||
cfg --> plugin_dsh_base_tool_ralph
|
||||
plugin_dsh_base_tool_str_replace_editor["tool-str-replace-editor<br/>@deepseek-ai/dsh-tool-str-replace-editor"]
|
||||
cfg --> plugin_dsh_base_tool_str_replace_editor
|
||||
plugin_dsh_base_repeat_tool_guard["repeat-tool-guard<br/>@deepseek-ai/dsh-repeat-tool-guard"]
|
||||
cfg --> plugin_dsh_base_repeat_tool_guard
|
||||
plugin_dsh_base_repeat_tool_reminder["repeat-tool-reminder<br/>@deepseek-ai/dsh-repeat-tool-reminder"]
|
||||
cfg --> plugin_dsh_base_repeat_tool_reminder
|
||||
plugin_dsh_base_web["web<br/>@deepseek-ai/dsh-web"]
|
||||
cfg --> plugin_dsh_base_web
|
||||
plugin_dsh_base_web_search_deepseek["web-search-deepseek<br/>@deepseek-ai/dsh-web-search-deepseek"]
|
||||
@@ -180,51 +180,51 @@ flowchart LR
|
||||
| `typert-loader` | `@deepseek-ai/dsh-typert-loader` |
|
||||
| `typert-gateway` | `@deepseek-ai/dsh-api-gateway` |
|
||||
| `session-title` | `@deepseek-ai/dsh-session-title` |
|
||||
| `session-title-llm` | `@deepseek-ai/dsh-session-title-first-message-llm` |
|
||||
| `user-interaction` | `@deepseek-ai/dsh-user-interaction` |
|
||||
| `session-title-llm` | `@deepseek-ai/dsh-session-title-first-prompt-llm` |
|
||||
| `user-questions` | `@deepseek-ai/dsh-user-questions` |
|
||||
| `agent` | `@deepseek-ai/dsh-agent` |
|
||||
| `agent-default-model` | `@deepseek-ai/dsh-agent-default-model` |
|
||||
| `tasks` | `@deepseek-ai/dsh-tasks-local` |
|
||||
| `jobs` | `@deepseek-ai/dsh-jobs-local` |
|
||||
| `llm-retry` | `@deepseek-ai/dsh-llm-retry` |
|
||||
| `settings` | `@deepseek-ai/dsh-settings-local` |
|
||||
| `settings` | `@deepseek-ai/dsh-settings-file` |
|
||||
| `credentials` | `@deepseek-ai/dsh-credentials-local` |
|
||||
| `llm-pi-ai` | `@deepseek-ai/dsh-llm-pi-ai` |
|
||||
| `session-persistence-jsonl` | `@deepseek-ai/dsh-session-persistence-jsonl` |
|
||||
| `attachment-local` | `@deepseek-ai/dsh-attachment-local` |
|
||||
| `session-query-sqlite` | `@deepseek-ai/dsh-session-query-sqlite` |
|
||||
| `session-projection` | `@deepseek-ai/dsh-session-projection` |
|
||||
| `telemetry-otel` | `@deepseek-ai/dsh-session-telemetry-otel` |
|
||||
| `session-telemetry-otel` | `@deepseek-ai/dsh-session-telemetry-otel` |
|
||||
| `subprocess` | `@deepseek-ai/dsh-subprocess-local` |
|
||||
| `sandbox` | `@deepseek-ai/dsh-sandbox-local` |
|
||||
| `sandbox-policy` | `@deepseek-ai/dsh-sandbox-policy` |
|
||||
| `bash-sandbox` | `@deepseek-ai/dsh-bash-sandbox` |
|
||||
| `pwsh-sandbox` | `@deepseek-ai/dsh-pwsh-sandbox` |
|
||||
| `approval` | `@deepseek-ai/dsh-user-approval` |
|
||||
| `permission` | `@deepseek-ai/dsh-permission` |
|
||||
| `bash-env` | `@deepseek-ai/dsh-bash-env` |
|
||||
| `permission` | `@deepseek-ai/dsh-permission-presets` |
|
||||
| `shell-env` | `@deepseek-ai/dsh-shell-env` |
|
||||
| `tool-bash` | `@deepseek-ai/dsh-tool-bash` |
|
||||
| `tool-pwsh` | `@deepseek-ai/dsh-tool-pwsh` |
|
||||
| `tool-tasks` | `@deepseek-ai/dsh-tool-tasks` |
|
||||
| `fs-policy` | `@deepseek-ai/dsh-fs-policy` |
|
||||
| `tool-jobs` | `@deepseek-ai/dsh-tool-jobs` |
|
||||
| `fs-observation-policy` | `@deepseek-ai/dsh-fs-observation-policy` |
|
||||
| `tool-fs` | `@deepseek-ai/dsh-tool-fs` |
|
||||
| `tool-fs-search` | `@deepseek-ai/dsh-tool-fs-search` |
|
||||
| `workspace-context` | `@deepseek-ai/dsh-workspace-context` |
|
||||
| `agent-instructions` | `@deepseek-ai/dsh-agent-instructions` |
|
||||
| `skill` | `@deepseek-ai/dsh-skill` |
|
||||
| `skill-local` | `@deepseek-ai/dsh-skill-local` |
|
||||
| `skill-filesystem` | `@deepseek-ai/dsh-skill-filesystem` |
|
||||
| `skill-badge` | `@deepseek-ai/dsh-skill-badge` |
|
||||
| `tool-skill` | `@deepseek-ai/dsh-tool-skill` |
|
||||
| `commands` | `@deepseek-ai/dsh-commands` |
|
||||
| `command-feedback` | `@deepseek-ai/dsh-command-feedback` |
|
||||
| `goal` | `@deepseek-ai/dsh-goal` |
|
||||
| `goal-session` | `@deepseek-ai/dsh-goal-session` |
|
||||
| `goal-round-driver` | `@deepseek-ai/dsh-goal-round-driver` |
|
||||
| `command-goal` | `@deepseek-ai/dsh-command-goal` |
|
||||
| `plan-mode` | `@deepseek-ai/dsh-plan-mode` |
|
||||
| `token-meter` | `@deepseek-ai/dsh-token-meter` |
|
||||
| `compact-basic` | `@deepseek-ai/dsh-compact-basic` |
|
||||
| `compaction-basic` | `@deepseek-ai/dsh-compaction-basic` |
|
||||
| `command-compact` | `@deepseek-ai/dsh-command-compact` |
|
||||
| `subagent` | `@deepseek-ai/dsh-subagent` |
|
||||
| `subagent-spawn` | `@deepseek-ai/dsh-subagent-spawn` |
|
||||
| `subagent-fork` | `@deepseek-ai/dsh-subagent-fork` |
|
||||
| `subagent-spawn-in-process` | `@deepseek-ai/dsh-subagent-spawn-in-process` |
|
||||
| `subagent-fork-in-process` | `@deepseek-ai/dsh-subagent-fork-in-process` |
|
||||
| `subagent-codex` | `@deepseek-ai/dsh-subagent-codex` |
|
||||
| `subagent-claude-code` | `@deepseek-ai/dsh-subagent-claude-code` |
|
||||
| `tool-subagent-control` | `@deepseek-ai/dsh-tool-subagent-control` |
|
||||
@@ -232,18 +232,18 @@ flowchart LR
|
||||
| `tool-subagent` | `@deepseek-ai/dsh-tool-subagent` |
|
||||
| `tool-subagent-fork` | `@deepseek-ai/dsh-tool-subagent` |
|
||||
| `tool-subagent-report` | `@deepseek-ai/dsh-tool-subagent-report` |
|
||||
| `workflow-workerthread` | `@deepseek-ai/dsh-workflow-workerthread` |
|
||||
| `workflow-worker-thread` | `@deepseek-ai/dsh-workflow-worker-thread` |
|
||||
| `tool-workflow` | `@deepseek-ai/dsh-tool-workflow` |
|
||||
| `timeout-policy` | `@deepseek-ai/dsh-timeout-policy` |
|
||||
| `timeout-policy` | `@deepseek-ai/dsh-tool-call-timeout-policy` |
|
||||
| `spill-local` | `@deepseek-ai/dsh-spill-local` |
|
||||
| `spill-policy` | `@deepseek-ai/dsh-spill-policy` |
|
||||
| `session-checkpoint-policy` | `@deepseek-ai/dsh-session-checkpoint-policy` |
|
||||
| `tool-result-prune` | `@deepseek-ai/dsh-compact-tool-result-prune` |
|
||||
| `tool-result-pruner` | `@deepseek-ai/dsh-compaction-tool-result-pruner` |
|
||||
| `tool-todo` | `@deepseek-ai/dsh-tool-todo` |
|
||||
| `tool-goal` | `@deepseek-ai/dsh-tool-goal` |
|
||||
| `tool-ralph` | `@deepseek-ai/dsh-tool-ralph` |
|
||||
| `tool-str-replace-editor` | `@deepseek-ai/dsh-tool-str-replace-editor` |
|
||||
| `repeat-tool-guard` | `@deepseek-ai/dsh-repeat-tool-guard` |
|
||||
| `repeat-tool-reminder` | `@deepseek-ai/dsh-repeat-tool-reminder` |
|
||||
| `web` | `@deepseek-ai/dsh-web` |
|
||||
| `web-search-deepseek` | `@deepseek-ai/dsh-web-search-deepseek` |
|
||||
| `tool-web` | `@deepseek-ai/dsh-tool-web` |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# The `code` agent preset: the standard coding agent, presented as Code Mode.
|
||||
#
|
||||
# Everything in `standard` is here unchanged. What is added is the `tool-mode`
|
||||
# Everything in `standard` is here unchanged. What is added is the `tool-presentation`
|
||||
# row: instead of one tool call per action, the model writes a TypeScript
|
||||
# program against a generated SDK and `run_code` executes it, so a sequence
|
||||
# that would be five round trips becomes one.
|
||||
@@ -34,14 +34,14 @@
|
||||
text: >-
|
||||
You are a coding agent powered by the {{model}} model. Your working directory is {{cwd}}.
|
||||
|
||||
- id: workspace-context
|
||||
name: '@deepseek-ai/dsh-workspace-context'
|
||||
- id: agent-instructions
|
||||
name: '@deepseek-ai/dsh-agent-instructions'
|
||||
config:
|
||||
maxBytes: 65536
|
||||
|
||||
# ── shell ───────────────────────────────────────────────────────────────────
|
||||
|
||||
# `bash-env` stays in the HOST composition: `apps/cli/src/web.ts` injects it to
|
||||
# `shell-env` stays in the HOST composition: `apps/cli/src/web.ts` injects it to
|
||||
# publish `DSH_WEB_URL`/`DSH_WEB_MODE`, and a host row that injects a service is
|
||||
# the criterion for host-plane ownership — injection resolves before any session
|
||||
# exists, so there is no agent to key by. Behind a preset realm those variables
|
||||
@@ -68,27 +68,27 @@
|
||||
config:
|
||||
sampleOverCapGlobResults: false
|
||||
|
||||
# ── background tasks ────────────────────────────────────────────────────────
|
||||
# ── background jobs ────────────────────────────────────────────────────────
|
||||
|
||||
# Only the model-facing controls. The task REGISTRY stays on the host plane:
|
||||
# its producers sit outside any realm this file could put it in — `tool-bash`
|
||||
# above resolves it with `ctx.get`, and an entry-local realm here is invisible
|
||||
# to every sibling row, so `run_in_background` would answer "background tasks
|
||||
# to every sibling row, so `run_in_background` would answer "background jobs
|
||||
# unavailable" while these controls sat in the catalog. The registry is keyed by
|
||||
# owning agent anyway, so one host instance serves every session. What a preset
|
||||
# chooses is whether its agent can collect and stop background work at all.
|
||||
- id: tool-tasks
|
||||
name: '@deepseek-ai/dsh-tool-tasks'
|
||||
- id: tool-jobs
|
||||
name: '@deepseek-ai/dsh-tool-jobs'
|
||||
|
||||
# ── skills ──────────────────────────────────────────────────────────────────
|
||||
|
||||
# The skill REGISTRY lives in the host composition and is layered per scope:
|
||||
# these rows register into THIS preset's layer of it, so they need no realm.
|
||||
# `skill-local` contributes local-root discovery for agents on this preset, and
|
||||
# `skill-filesystem` contributes local-root discovery for agents on this preset, and
|
||||
# `tool-skill` gives them the catalog and loader; the merged catalog also
|
||||
# carries whatever the deployment registered globally (repository plugins).
|
||||
- id: skill-local
|
||||
name: '@deepseek-ai/dsh-skill-local'
|
||||
- id: skill-filesystem
|
||||
name: '@deepseek-ai/dsh-skill-filesystem'
|
||||
|
||||
- id: tool-skill
|
||||
name: '@deepseek-ai/dsh-tool-skill'
|
||||
@@ -132,7 +132,7 @@
|
||||
|
||||
# ── compaction ──────────────────────────────────────────────────────────────
|
||||
|
||||
# `compact-basic` reads `toolResultPrune` through `ctx.get`, so the pruner must
|
||||
# `compaction-basic` reads `toolResultPrune` through `ctx.get`, so the pruner must
|
||||
# share this realm rather than sit outside it.
|
||||
#
|
||||
# `tokenMeter` is deliberately NOT in this realm: the meter stays on the HOST
|
||||
@@ -140,22 +140,22 @@
|
||||
# keys every fold by Session, and owns the context-meter projection units the
|
||||
# browser reads for every session — behind a realm those units would come and go
|
||||
# with whichever presets happen to be mounted. What a preset chooses is whether
|
||||
# its agent compacts at all, which is `compact-basic` below.
|
||||
# its agent compacts at all, which is `compaction-basic` below.
|
||||
- id: compaction
|
||||
name: cordis:group
|
||||
group: true
|
||||
isolate:
|
||||
compact: true
|
||||
toolResultPrune: true
|
||||
compaction: true
|
||||
toolResultPruner: true
|
||||
config:
|
||||
- id: compact-basic
|
||||
name: '@deepseek-ai/dsh-compact-basic'
|
||||
- id: compaction-basic
|
||||
name: '@deepseek-ai/dsh-compaction-basic'
|
||||
|
||||
- id: command-compact
|
||||
name: '@deepseek-ai/dsh-command-compact'
|
||||
|
||||
- id: tool-result-prune
|
||||
name: '@deepseek-ai/dsh-compact-tool-result-prune'
|
||||
- id: tool-result-pruner
|
||||
name: '@deepseek-ai/dsh-compaction-tool-result-pruner'
|
||||
config:
|
||||
thresholdChars: 8192
|
||||
headChars: 4096
|
||||
@@ -176,7 +176,7 @@
|
||||
name: cordis:group
|
||||
group: true
|
||||
isolate:
|
||||
workflows: true
|
||||
workflowEngine: true
|
||||
config:
|
||||
- id: tool-subagent-control
|
||||
name: '@deepseek-ai/dsh-tool-subagent-control'
|
||||
@@ -219,8 +219,8 @@
|
||||
enableRunInBackground: false
|
||||
maxDepth: provider-managed
|
||||
|
||||
- id: workflow-workerthread
|
||||
name: '@deepseek-ai/dsh-workflow-workerthread'
|
||||
- id: workflow-worker-thread
|
||||
name: '@deepseek-ai/dsh-workflow-worker-thread'
|
||||
config:
|
||||
provider: spawn
|
||||
|
||||
@@ -256,7 +256,7 @@
|
||||
# Code Mode for this agent alone. The row waits for the host's `codeRuntime`
|
||||
# rather than assuming it: a deployment that composes no TypeScript runtime
|
||||
# fails this preset at mount, naming this id, instead of at the first request.
|
||||
- id: tool-mode
|
||||
name: '@deepseek-ai/dsh-agent-tool-mode'
|
||||
- id: tool-presentation
|
||||
name: '@deepseek-ai/dsh-agent-tool-presentation'
|
||||
config:
|
||||
mode: code
|
||||
|
||||
@@ -28,14 +28,14 @@
|
||||
|
||||
Load the `editing-cordis-compositions` skill before writing or changing a composition.
|
||||
|
||||
- id: workspace-context
|
||||
name: '@deepseek-ai/dsh-workspace-context'
|
||||
- id: agent-instructions
|
||||
name: '@deepseek-ai/dsh-agent-instructions'
|
||||
config:
|
||||
maxBytes: 65536
|
||||
|
||||
# ── shell ───────────────────────────────────────────────────────────────────
|
||||
|
||||
# `bash-env` stays in the HOST composition: `apps/cli/src/web.ts` injects it to
|
||||
# `shell-env` stays in the HOST composition: `apps/cli/src/web.ts` injects it to
|
||||
# publish `DSH_WEB_URL`/`DSH_WEB_MODE`, and a host row that injects a service is
|
||||
# the criterion for host-plane ownership — injection resolves before any session
|
||||
# exists, so there is no agent to key by. Behind a preset realm those variables
|
||||
@@ -62,17 +62,17 @@
|
||||
config:
|
||||
sampleOverCapGlobResults: false
|
||||
|
||||
# ── background tasks ────────────────────────────────────────────────────────
|
||||
# ── background jobs ────────────────────────────────────────────────────────
|
||||
|
||||
# Only the model-facing controls. The task REGISTRY stays on the host plane:
|
||||
# its producers sit outside any realm this file could put it in — `tool-bash`
|
||||
# above resolves it with `ctx.get`, and an entry-local realm here is invisible
|
||||
# to every sibling row, so `run_in_background` would answer "background tasks
|
||||
# to every sibling row, so `run_in_background` would answer "background jobs
|
||||
# unavailable" while these controls sat in the catalog. The registry is keyed by
|
||||
# owning agent anyway, so one host instance serves every session. What a preset
|
||||
# chooses is whether its agent can collect and stop background work at all.
|
||||
- id: tool-tasks
|
||||
name: '@deepseek-ai/dsh-tool-tasks'
|
||||
- id: tool-jobs
|
||||
name: '@deepseek-ai/dsh-tool-jobs'
|
||||
|
||||
# ── goals ───────────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -113,7 +113,7 @@
|
||||
|
||||
# ── compaction ──────────────────────────────────────────────────────────────
|
||||
|
||||
# `compact-basic` reads `toolResultPrune` through `ctx.get`, so the pruner must
|
||||
# `compaction-basic` reads `toolResultPrune` through `ctx.get`, so the pruner must
|
||||
# share this realm rather than sit outside it.
|
||||
#
|
||||
# `tokenMeter` is deliberately NOT in this realm: the meter stays on the HOST
|
||||
@@ -121,22 +121,22 @@
|
||||
# keys every fold by Session, and owns the context-meter projection units the
|
||||
# browser reads for every session — behind a realm those units would come and go
|
||||
# with whichever presets happen to be mounted. What a preset chooses is whether
|
||||
# its agent compacts at all, which is `compact-basic` below.
|
||||
# its agent compacts at all, which is `compaction-basic` below.
|
||||
- id: compaction
|
||||
name: cordis:group
|
||||
group: true
|
||||
isolate:
|
||||
compact: true
|
||||
toolResultPrune: true
|
||||
compaction: true
|
||||
toolResultPruner: true
|
||||
config:
|
||||
- id: compact-basic
|
||||
name: '@deepseek-ai/dsh-compact-basic'
|
||||
- id: compaction-basic
|
||||
name: '@deepseek-ai/dsh-compaction-basic'
|
||||
|
||||
- id: command-compact
|
||||
name: '@deepseek-ai/dsh-command-compact'
|
||||
|
||||
- id: tool-result-prune
|
||||
name: '@deepseek-ai/dsh-compact-tool-result-prune'
|
||||
- id: tool-result-pruner
|
||||
name: '@deepseek-ai/dsh-compaction-tool-result-pruner'
|
||||
config:
|
||||
thresholdChars: 8192
|
||||
headChars: 4096
|
||||
@@ -163,7 +163,7 @@
|
||||
name: cordis:group
|
||||
group: true
|
||||
isolate:
|
||||
workflows: true
|
||||
workflowEngine: true
|
||||
config:
|
||||
- id: tool-subagent-control
|
||||
name: '@deepseek-ai/dsh-tool-subagent-control'
|
||||
@@ -206,8 +206,8 @@
|
||||
enableRunInBackground: false
|
||||
maxDepth: provider-managed
|
||||
|
||||
- id: workflow-workerthread
|
||||
name: '@deepseek-ai/dsh-workflow-workerthread'
|
||||
- id: workflow-worker-thread
|
||||
name: '@deepseek-ai/dsh-workflow-worker-thread'
|
||||
config:
|
||||
provider: spawn
|
||||
|
||||
@@ -252,8 +252,8 @@
|
||||
# Both rows register into THIS preset's layer of the host skill registry, so
|
||||
# they need no realm; the agent's merged catalog also carries whatever the
|
||||
# deployment registered globally (repository plugins).
|
||||
- id: skill-local
|
||||
name: '@deepseek-ai/dsh-skill-local'
|
||||
- id: skill-filesystem
|
||||
name: '@deepseek-ai/dsh-skill-filesystem'
|
||||
config:
|
||||
customSkillDirs:
|
||||
- !!js "process.getBuiltinModule('node:url').fileURLToPath(new URL('skills/', baseUrl))"
|
||||
|
||||
@@ -88,8 +88,8 @@ When a preset genuinely owns a service, wrap the provider **and every consumer t
|
||||
isolate:
|
||||
workflows: true
|
||||
config:
|
||||
- id: workflow-workerthread
|
||||
name: '@deepseek-ai/dsh-workflow-workerthread'
|
||||
- id: workflow-worker-thread
|
||||
name: '@deepseek-ai/dsh-workflow-worker-thread'
|
||||
config:
|
||||
provider: spawn
|
||||
- id: tool-workflow
|
||||
@@ -100,7 +100,7 @@ When a preset genuinely owns a service, wrap the provider **and every consumer t
|
||||
|
||||
A consumer left outside the group resolves the host's registry, which the preset did not populate, and then contributes nothing. Mount-validation catches that as a row that never activated.
|
||||
|
||||
Realms are for services a preset owns, not for every group. A host capability the preset only consumes must stay outside a realm, or the row cannot resolve it: `tool-bash`, `tool-tasks`, and `tool-goal` publish nothing and sit loose in `standard`, which explains in comments which host instance each one resolves and why a realm would break it. Wrapping a consumer row in a realm of its own is the same error as leaving one outside its provider's realm.
|
||||
Realms are for services a preset owns, not for every group. A host capability the preset only consumes must stay outside a realm, or the row cannot resolve it: `tool-bash`, `tool-jobs`, and `tool-goal` publish nothing and sit loose in `standard`, which explains in comments which host instance each one resolves and why a realm would break it. Wrapping a consumer row in a realm of its own is the same error as leaving one outside its provider's realm.
|
||||
|
||||
## Verifying a change
|
||||
|
||||
|
||||
@@ -18,13 +18,13 @@
|
||||
name: cordis:group
|
||||
group: true
|
||||
isolate:
|
||||
pty: true
|
||||
terminals: true
|
||||
config:
|
||||
- id: pty
|
||||
name: '@deepseek-ai/dsh-pty'
|
||||
name: '@deepseek-ai/dsh-terminal'
|
||||
|
||||
- id: pty-local
|
||||
name: '@deepseek-ai/dsh-pty-local'
|
||||
- id: terminal-bash
|
||||
name: '@deepseek-ai/dsh-terminal-bash'
|
||||
config:
|
||||
timeoutMs: 300000
|
||||
|
||||
|
||||
@@ -27,14 +27,14 @@
|
||||
text: >-
|
||||
You are a coding agent powered by the {{model}} model. Your working directory is {{cwd}}.
|
||||
|
||||
- id: workspace-context
|
||||
name: '@deepseek-ai/dsh-workspace-context'
|
||||
- id: agent-instructions
|
||||
name: '@deepseek-ai/dsh-agent-instructions'
|
||||
config:
|
||||
maxBytes: 65536
|
||||
|
||||
# ── shell ───────────────────────────────────────────────────────────────────
|
||||
|
||||
# `bash-env` stays in the HOST composition: `apps/cli/src/web.ts` injects it to
|
||||
# `shell-env` stays in the HOST composition: `apps/cli/src/web.ts` injects it to
|
||||
# publish `DSH_WEB_URL`/`DSH_WEB_MODE`, and a host row that injects a service is
|
||||
# the criterion for host-plane ownership — injection resolves before any session
|
||||
# exists, so there is no agent to key by. Behind a preset realm those variables
|
||||
@@ -61,27 +61,27 @@
|
||||
config:
|
||||
sampleOverCapGlobResults: false
|
||||
|
||||
# ── background tasks ────────────────────────────────────────────────────────
|
||||
# ── background jobs ────────────────────────────────────────────────────────
|
||||
|
||||
# Only the model-facing controls. The task REGISTRY stays on the host plane:
|
||||
# its producers sit outside any realm this file could put it in — `tool-bash`
|
||||
# above resolves it with `ctx.get`, and an entry-local realm here is invisible
|
||||
# to every sibling row, so `run_in_background` would answer "background tasks
|
||||
# to every sibling row, so `run_in_background` would answer "background jobs
|
||||
# unavailable" while these controls sat in the catalog. The registry is keyed by
|
||||
# owning agent anyway, so one host instance serves every session. What a preset
|
||||
# chooses is whether its agent can collect and stop background work at all.
|
||||
- id: tool-tasks
|
||||
name: '@deepseek-ai/dsh-tool-tasks'
|
||||
- id: tool-jobs
|
||||
name: '@deepseek-ai/dsh-tool-jobs'
|
||||
|
||||
# ── skills ──────────────────────────────────────────────────────────────────
|
||||
|
||||
# The skill REGISTRY lives in the host composition and is layered per scope:
|
||||
# these rows register into THIS preset's layer of it, so they need no realm.
|
||||
# `skill-local` contributes local-root discovery for agents on this preset, and
|
||||
# `skill-filesystem` contributes local-root discovery for agents on this preset, and
|
||||
# `tool-skill` gives them the catalog and loader; the merged catalog also
|
||||
# carries whatever the deployment registered globally (repository plugins).
|
||||
- id: skill-local
|
||||
name: '@deepseek-ai/dsh-skill-local'
|
||||
- id: skill-filesystem
|
||||
name: '@deepseek-ai/dsh-skill-filesystem'
|
||||
|
||||
- id: tool-skill
|
||||
name: '@deepseek-ai/dsh-tool-skill'
|
||||
@@ -125,7 +125,7 @@
|
||||
|
||||
# ── compaction ──────────────────────────────────────────────────────────────
|
||||
|
||||
# `compact-basic` reads `toolResultPrune` through `ctx.get`, so the pruner must
|
||||
# `compaction-basic` reads `toolResultPrune` through `ctx.get`, so the pruner must
|
||||
# share this realm rather than sit outside it.
|
||||
#
|
||||
# `tokenMeter` is deliberately NOT in this realm: the meter stays on the HOST
|
||||
@@ -133,22 +133,22 @@
|
||||
# keys every fold by Session, and owns the context-meter projection units the
|
||||
# browser reads for every session — behind a realm those units would come and go
|
||||
# with whichever presets happen to be mounted. What a preset chooses is whether
|
||||
# its agent compacts at all, which is `compact-basic` below.
|
||||
# its agent compacts at all, which is `compaction-basic` below.
|
||||
- id: compaction
|
||||
name: cordis:group
|
||||
group: true
|
||||
isolate:
|
||||
compact: true
|
||||
toolResultPrune: true
|
||||
compaction: true
|
||||
toolResultPruner: true
|
||||
config:
|
||||
- id: compact-basic
|
||||
name: '@deepseek-ai/dsh-compact-basic'
|
||||
- id: compaction-basic
|
||||
name: '@deepseek-ai/dsh-compaction-basic'
|
||||
|
||||
- id: command-compact
|
||||
name: '@deepseek-ai/dsh-command-compact'
|
||||
|
||||
- id: tool-result-prune
|
||||
name: '@deepseek-ai/dsh-compact-tool-result-prune'
|
||||
- id: tool-result-pruner
|
||||
name: '@deepseek-ai/dsh-compaction-tool-result-pruner'
|
||||
config:
|
||||
thresholdChars: 8192
|
||||
headChars: 4096
|
||||
@@ -175,7 +175,7 @@
|
||||
name: cordis:group
|
||||
group: true
|
||||
isolate:
|
||||
workflows: true
|
||||
workflowEngine: true
|
||||
config:
|
||||
- id: tool-subagent-control
|
||||
name: '@deepseek-ai/dsh-tool-subagent-control'
|
||||
@@ -218,8 +218,8 @@
|
||||
enableRunInBackground: false
|
||||
maxDepth: provider-managed
|
||||
|
||||
- id: workflow-workerthread
|
||||
name: '@deepseek-ai/dsh-workflow-workerthread'
|
||||
- id: workflow-worker-thread
|
||||
name: '@deepseek-ai/dsh-workflow-worker-thread'
|
||||
config:
|
||||
provider: spawn
|
||||
|
||||
|
||||
@@ -24,33 +24,33 @@
|
||||
"@deepseek-ai/cordis-plugin-include": "workspace:^",
|
||||
"@deepseek-ai/cordis-plugin-loader": "workspace:^",
|
||||
"@deepseek-ai/cordis-plugin-timer": "workspace:^",
|
||||
"@deepseek-ai/dsh-agent-tool-mode": "workspace:^",
|
||||
"@deepseek-ai/dsh-agent-tool-presentation": "workspace:^",
|
||||
"@deepseek-ai/dsh-app-boot": "workspace:^",
|
||||
"@deepseek-ai/dsh-base": "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-compaction-basic": "workspace:^",
|
||||
"@deepseek-ai/dsh-compaction-tool-result-pruner": "workspace:^",
|
||||
"@deepseek-ai/dsh-goal": "workspace:^",
|
||||
"@deepseek-ai/dsh-goal-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-goal-round-driver": "workspace:^",
|
||||
"@deepseek-ai/dsh-cmdline": "workspace:^",
|
||||
"@deepseek-ai/dsh-environment": "workspace:^",
|
||||
"@deepseek-ai/dsh-launch-environment": "workspace:^",
|
||||
"@deepseek-ai/dsh-fs-local": "workspace:^",
|
||||
"@deepseek-ai/dsh-headless": "workspace:^",
|
||||
"@deepseek-ai/dsh-mcp-client": "workspace:^",
|
||||
"@deepseek-ai/dsh-paths": "workspace:^",
|
||||
"@deepseek-ai/dsh-home-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-terminal": "workspace:^",
|
||||
"@deepseek-ai/dsh-terminal-bash": "workspace:^",
|
||||
"@deepseek-ai/dsh-pwsh-local": "workspace:^",
|
||||
"@deepseek-ai/dsh-pwsh-sandbox": "workspace:^",
|
||||
"@deepseek-ai/dsh-session-projection": "workspace:^",
|
||||
"@deepseek-ai/dsh-session-reference": "workspace:^",
|
||||
"@deepseek-ai/dsh-time-context": "workspace:^",
|
||||
"@deepseek-ai/dsh-skill": "workspace:^",
|
||||
"@deepseek-ai/dsh-skill-local": "workspace:^",
|
||||
"@deepseek-ai/dsh-tasks-local": "workspace:^",
|
||||
"@deepseek-ai/dsh-skill-filesystem": "workspace:^",
|
||||
"@deepseek-ai/dsh-jobs-local": "workspace:^",
|
||||
"@deepseek-ai/dsh-tmux-context": "workspace:^",
|
||||
"@deepseek-ai/dsh-token-meter": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-ask-user": "workspace:^",
|
||||
@@ -62,18 +62,18 @@
|
||||
"@deepseek-ai/dsh-tool-goal": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-pwsh": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-ralph": "workspace:^",
|
||||
"@deepseek-ai/dsh-tool-schedule": "workspace:^",
|
||||
"@deepseek-ai/dsh-schedule": "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-jobs": "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:^",
|
||||
"@deepseek-ai/dsh-workflow-worker-thread": "workspace:^",
|
||||
"@deepseek-ai/dsh-agent-instructions": "workspace:^",
|
||||
"commander": "^15.0.0",
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"js-yaml": "^4.2.0",
|
||||
@@ -81,7 +81,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/dsh-agent": "workspace:^",
|
||||
"@deepseek-ai/dsh-frontend-static": "workspace:^",
|
||||
"@deepseek-ai/dsh-host-frontend-static": "workspace:^",
|
||||
"@deepseek-ai/dsh-host-apiproxy": "workspace:^",
|
||||
"@deepseek-ai/dsh-host-webserver": "workspace:^",
|
||||
"@deepseek-ai/dsh-llm": "workspace:^",
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write apps/cli/reference/README.md
|
||||
README.md: 17d63fe73ea2b3bda74e9c4da91555b34c21f4ab
|
||||
README.zh.md: 452d024c1411c4c239b5fc54ec2586e1891e74f3
|
||||
README.md: 0b23db293c304807b5959f5eae9a2faf868caa62
|
||||
README.zh.md: 1ca91fb69c3ed34d925f6b8a6454866e82c8dcf7
|
||||
|
||||
@@ -81,4 +81,4 @@ Install external plugin bundles through `dsh plugin --profile <name> add <packag
|
||||
|
||||
## Source execution
|
||||
|
||||
From the repository root, run `pnpm run build` separately after a fresh checkout and whenever artifacts need updating, then use `pnpm dsh <args...>`. The `package.json` script launches `apps/cli/src/bin.ts` with `node --import tsx/esm` without building and forwards every argument. Missing TypeRT host artifacts fail profile boot through module-resolution errors without a build instruction. Once those host artifacts exist, missing frontend or client-plugin bundles fail at startup with an instruction to run `pnpm run build`. The launcher does not check freshness, so existing stale bundles can run older browser code until rebuilt. The process inherits the launch environment; set `NODE_USE_ENV_PROXY=1` when a supporting Node version must honor `HTTP_PROXY` and `HTTPS_PROXY`. The installed form launches the built `apps/cli/lib/bin.js` without rebuilding the repository.
|
||||
From the repository root, run `pnpm run build` separately after a fresh checkout and whenever artifacts need updating, then use `pnpm dsh <args...>`. The `package.json` script launches `apps/cli/src/bin.ts` with `node --import tsx/esm` without building and forwards every argument. Missing Typert host artifacts fail profile boot through module-resolution errors without a build instruction. Once those host artifacts exist, missing frontend or client-plugin bundles fail at startup with an instruction to run `pnpm run build`. The launcher does not check freshness, so existing stale bundles can run older browser code until rebuilt. The process inherits the launch environment; set `NODE_USE_ENV_PROXY=1` when a supporting Node version must honor `HTTP_PROXY` and `HTTPS_PROXY`. The installed form launches the built `apps/cli/lib/bin.js` without rebuilding the repository.
|
||||
|
||||
@@ -82,4 +82,4 @@ dsh web --help
|
||||
|
||||
## 源码执行
|
||||
|
||||
请在仓库根目录中,于全新 checkout 之后及产物需要更新时单独运行 `pnpm run build`,然后使用 `pnpm dsh <args...>`。`package.json` 中的脚本不会构建,而是通过 `node --import tsx/esm` 启动 `apps/cli/src/bin.ts`,并转发所有参数。TypeRT Host 产物缺失时,profile 启动会因不含构建指引的模块解析错误而失败。这些 Host 产物存在后,如果前端或 Client plugin 组合包缺失,启动会失败并提示运行 `pnpm run build`。启动器不会检查产物是否为最新,因此已有的陈旧组合包可能继续运行旧版浏览器代码,直至重新构建。该进程会继承启动环境;当支持环境代理的 Node 版本必须遵循 `HTTP_PROXY` 和 `HTTPS_PROXY` 时,请设置 `NODE_USE_ENV_PROXY=1`。安装形式会直接启动构建后的 `apps/cli/lib/bin.js`,不会重新构建仓库。
|
||||
请在仓库根目录中,于全新 checkout 之后及产物需要更新时单独运行 `pnpm run build`,然后使用 `pnpm dsh <args...>`。`package.json` 中的脚本不会构建,而是通过 `node --import tsx/esm` 启动 `apps/cli/src/bin.ts`,并转发所有参数。Typert Host 产物缺失时,profile 启动会因不含构建指引的模块解析错误而失败。这些 Host 产物存在后,如果前端或 Client plugin 组合包缺失,启动会失败并提示运行 `pnpm run build`。启动器不会检查产物是否为最新,因此已有的陈旧组合包可能继续运行旧版浏览器代码,直至重新构建。该进程会继承启动环境;当支持环境代理的 Node 版本必须遵循 `HTTP_PROXY` 和 `HTTPS_PROXY` 时,请设置 `NODE_USE_ENV_PROXY=1`。安装形式会直接启动构建后的 `apps/cli/lib/bin.js`,不会重新构建仓库。
|
||||
|
||||
@@ -29,12 +29,12 @@ import {
|
||||
watchUserPatches,
|
||||
type Profile,
|
||||
} from '@deepseek-ai/dsh-app-boot'
|
||||
import { resolveDshHome } from '@deepseek-ai/dsh-paths'
|
||||
import { resolveDshHome } from '@deepseek-ai/dsh-home-paths'
|
||||
|
||||
/** Shipped agent-preset root: beside this app's own config, in both source and built layouts. */
|
||||
const SHIPPED_PRESET_ROOT = fileURLToPath(new URL('../config/agent-presets/', import.meta.url))
|
||||
|
||||
import { DSH_ENVIRONMENT_KEY, type EnvironmentSnapshot } from '@deepseek-ai/dsh-environment'
|
||||
import { DSH_LAUNCH_ENVIRONMENT_KEY, type LaunchEnvironmentSnapshot } from '@deepseek-ai/dsh-launch-environment'
|
||||
import { provideCmdline } from '@deepseek-ai/dsh-cmdline'
|
||||
import { createProcessShutdown, type ProcessShutdown } from './process-shutdown.ts'
|
||||
|
||||
@@ -54,7 +54,7 @@ export function homePatchPath(): string {
|
||||
export const INSTALL_ANCHOR = fileURLToPath(new URL('../package.json', import.meta.url))
|
||||
|
||||
/** The session-telemetry row id the DSH_TELEMETRY_DISABLED switch targets. */
|
||||
const TELEMETRY_ROW_ID = 'telemetry-otel'
|
||||
const TELEMETRY_ROW_ID = 'session-telemetry-otel'
|
||||
|
||||
/** The empty root entry list every profile tree patches over. */
|
||||
const PROFILE_ROOT_CONFIG = `# dsh profile root — an empty entry list. The tree is composed as patches:
|
||||
@@ -173,7 +173,7 @@ function composeProfile(
|
||||
/** Options for {@link runProfile}. */
|
||||
export interface RunProfileOptions {
|
||||
/** This run's frozen environment snapshot, provided before any entry mounts. */
|
||||
environment: EnvironmentSnapshot
|
||||
environment: LaunchEnvironmentSnapshot
|
||||
/** The profile name to boot. */
|
||||
profile: string
|
||||
/** `--patch` overlay paths, in argv order. */
|
||||
@@ -249,7 +249,7 @@ export async function runProfile(options: RunProfileOptions): Promise<{ ctx: Con
|
||||
app.current = hostCtx
|
||||
// Before any config-tree entry mounts, so plugins resolve all launch-time
|
||||
// environment values from the same immutable provenance snapshot.
|
||||
hostCtx.provide(DSH_ENVIRONMENT_KEY, options.environment)
|
||||
hostCtx.provide(DSH_LAUNCH_ENVIRONMENT_KEY, options.environment)
|
||||
// The command line and bounded exit request are launcher facts available
|
||||
// to every app plugin that injects the argument snapshot.
|
||||
provideCmdline(hostCtx, {
|
||||
|
||||
4
apps/cli/tests/fixtures/dsh-badge/cordis.yml
vendored
4
apps/cli/tests/fixtures/dsh-badge/cordis.yml
vendored
@@ -1,9 +1,9 @@
|
||||
- id: skill-badge
|
||||
disabled: false
|
||||
|
||||
- id: skill-local
|
||||
- id: skill-filesystem
|
||||
config:
|
||||
watch: false
|
||||
|
||||
- id: telemetry-otel
|
||||
- id: session-telemetry-otel
|
||||
disabled: true
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
- id: skill-local
|
||||
- id: skill-filesystem
|
||||
config:
|
||||
watch: false
|
||||
|
||||
- id: telemetry-otel
|
||||
- id: session-telemetry-otel
|
||||
disabled: true
|
||||
|
||||
@@ -31,7 +31,7 @@ try {
|
||||
steer: () => {},
|
||||
inject: () => { throw new Error('dsh-badge snapshot must receive the catalog at the step boundary') },
|
||||
cancel: () => {},
|
||||
runMaintenance: task => task(new AbortController().signal),
|
||||
runMaintenance: job => job(new AbortController().signal),
|
||||
whenIdle: () => Promise.resolve(),
|
||||
}
|
||||
const decision = await agentEvents(ctx, agent).waterfall(
|
||||
|
||||
@@ -12,7 +12,7 @@ import type { Context } from '@deepseek-ai/cordis'
|
||||
import type { PatchOptions } from '@deepseek-ai/cordis-plugin-include'
|
||||
import { boot, loadOverlayPatches } from '@deepseek-ai/dsh-app-boot'
|
||||
import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
|
||||
import ToolRegistry from '@deepseek-ai/dsh-tools'
|
||||
import ToolRuntime from '@deepseek-ai/dsh-tools'
|
||||
import * as McpClient from '@deepseek-ai/dsh-mcp-client/src/index.ts'
|
||||
|
||||
interface ExampleContract {
|
||||
@@ -123,7 +123,7 @@ describe('third-party memory MCP example overlays', () => {
|
||||
(ctx) => {
|
||||
liveContexts.add(ctx)
|
||||
ctx.loader.builtins['memory-test-system-prompt'] = SystemPrompt
|
||||
ctx.loader.builtins['memory-test-tools'] = ToolRegistry
|
||||
ctx.loader.builtins['memory-test-tools'] = ToolRuntime
|
||||
ctx.loader.builtins['memory-test-mcp-client'] = McpClient
|
||||
},
|
||||
)
|
||||
|
||||
@@ -9,7 +9,7 @@ describe('resolveTelemetryPatch', () => {
|
||||
|
||||
it('disables on ANY non-empty value, including falsy-looking ones', () => {
|
||||
for (const value of ['1', '0', 'false', 'no']) {
|
||||
expect(resolveTelemetryPatch(value, true)).toEqual({ id: 'telemetry-otel', disabled: true })
|
||||
expect(resolveTelemetryPatch(value, true)).toEqual({ id: 'session-telemetry-otel', disabled: true })
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import { settingsNamespace } from '@deepseek-ai/dsh-settings'
|
||||
import { resolveSessionPreset, SETTINGS_NAMESPACE } from '@deepseek-ai/dsh-agent-presets'
|
||||
import { applyChildComposition, childSessionMeta } from '@deepseek-ai/dsh-subagent'
|
||||
import { CallId } from '@deepseek-ai/dsh-llm'
|
||||
import type {} from '@deepseek-ai/dsh-compact-basic'
|
||||
import type {} from '@deepseek-ai/dsh-compaction-basic'
|
||||
import type {} from '@deepseek-ai/dsh-skill'
|
||||
import type {} from '@deepseek-ai/dsh-tools'
|
||||
// Type-only: resolves `ctx.get('sessionProjections')` and `ctx.get('tokenMeter')`.
|
||||
@@ -67,12 +67,12 @@ 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
|
||||
// The web bundle's runtime row injects `webServer`, 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: 'session-telemetry-otel', disabled: true },
|
||||
// A deployment-level skill on the host registry's GLOBAL layer — the same
|
||||
// registration shape a repository plugin's skill root uses. The layered
|
||||
// skills test below proves it reaches preset-composed agents.
|
||||
@@ -88,7 +88,7 @@ async function bootWeb(settingsFile: string, extra: PatchOptions[] = []): Promis
|
||||
{ id: 'directory-picker', disabled: true },
|
||||
{ insert: [
|
||||
{ id: 'directory-picker-browse', name: '@deepseek-ai/dsh-host-directory-picker-browse' },
|
||||
{ id: 'ui-directory-picker', name: '@deepseek-ai/dsh-client-ui-directory-picker' },
|
||||
{ id: 'ui-directory-picker-browse', name: '@deepseek-ai/dsh-client-ui-directory-picker-browse' },
|
||||
] },
|
||||
// The roster AppCLIEntry would patch in; only the shipped root, so a
|
||||
// developer's own `~/.dsh/.preset` cannot change this test's outcome.
|
||||
@@ -199,9 +199,8 @@ describe('the shipped Web composition', () => {
|
||||
// depend on ripgrep being present on the machine.
|
||||
expect(toolNames(ctx, handle.agent).filter(name => name !== 'glob' && name !== 'grep')).toEqual([
|
||||
'ask_user_question', 'bash', 'create_goal', 'edit', 'exit_plan_mode',
|
||||
'get_goal', 'interrupt_agent', 'list_agents', 'ralph', 'read', 'read_image', 'send_message', 'skill',
|
||||
'subagent', 'subagent_fork', 'task_kill',
|
||||
'task_list', 'task_output', 'todo_write', 'update_goal', 'web_search',
|
||||
'get_goal', 'interrupt_agent', 'job_kill', 'job_list', 'job_output', 'list_agents', 'ralph', 'read', 'read_image', 'send_message', 'skill',
|
||||
'subagent', 'subagent_fork', 'todo_write', 'update_goal', 'web_search',
|
||||
'workflow', 'write',
|
||||
])
|
||||
} finally {
|
||||
@@ -223,8 +222,8 @@ describe('the shipped Web composition', () => {
|
||||
expect(assembly.tools.find(tool => tool.name === 'bash')?.description).toBe(MINIMAL_BASH_DESCRIPTION)
|
||||
expect(JSON.stringify(assembly.tools.find(tool => tool.name === 'str_replace_editor')?.parameters))
|
||||
.toContain('Absolute path')
|
||||
expect(ctx.agentPresets.serviceFor(handle.agent, 'compact')).toBeUndefined()
|
||||
expect(handle.agent.ctx.get('compact')).toBeUndefined()
|
||||
expect(ctx.agentPresets.serviceFor(handle.agent, 'compaction')).toBeUndefined()
|
||||
expect(handle.agent.ctx.get('compaction')).toBeUndefined()
|
||||
} finally {
|
||||
await handle.dispose()
|
||||
}
|
||||
@@ -352,7 +351,7 @@ describe('the shipped Web composition', () => {
|
||||
})
|
||||
try {
|
||||
// The host (global) view carries the deployment-level provider alone:
|
||||
// local discovery moved behind the presets with `skill-local`.
|
||||
// local discovery moved behind the presets with `skill-filesystem`.
|
||||
expect((await ctx.skills.list({ cwd: proj })).map(skill => skill.name)).toEqual(['dsh-badge'])
|
||||
|
||||
// The standard agent's view merges the global layer with its preset's
|
||||
|
||||
@@ -51,25 +51,25 @@
|
||||
"path": "../../packages/core/tools"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/util/environment"
|
||||
"path": "../../packages/util/launch-environment"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/util/paths"
|
||||
"path": "../../packages/util/home-paths"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/mcp/mcp-client"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/support/loader-smoke"
|
||||
"path": "../../packages/test-support/loader-smoke"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/session-query/session-query-sqlite"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/bash/bash-env"
|
||||
"path": "../../packages/shell/shell-env"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/bash/tool-bash"
|
||||
"path": "../../packages/shell/tool-bash"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "@deepseek-ai/dsh-frontend",
|
||||
"name": "@deepseek-ai/dsh-web-frontend",
|
||||
"description": "Web application entry: vite build over the @deepseek-ai/dsh-client-web shell library; dist/ served by apps/cli's dsh web",
|
||||
"version": "0.0.1-rc.2",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -34,7 +34,7 @@ const HEADER_EXPECTED = join(SNAPSHOT_DIR, 'header.expected.md')
|
||||
const SHIPPED_PRESETS = fileURLToPath(new URL('../../cli/config/agent-presets', import.meta.url))
|
||||
const MODE = webSnapshotMode()
|
||||
const SEED_ID = 'agent-preset-selection-web-e2e'
|
||||
/** A project skill only a preset that mounts `skill-local` can discover. */
|
||||
/** A project skill only a preset that mounts `skill-filesystem` can discover. */
|
||||
const SKILL_NAME = 'preset-catalog-demo'
|
||||
|
||||
/**
|
||||
|
||||
@@ -43,7 +43,7 @@ const PLUGINS: readonly (WebBootEntry & { bundlePath: string })[] = [
|
||||
'@deepseek-ai/dsh-client-ui-sidebar',
|
||||
],
|
||||
},
|
||||
{ id: '@deepseek-ai/dsh-session-export', bundlePath: 'packages/session-query/session-export/lib/client.js', url: '/plugins/session-export.js', rev: 'fx', inject: ['@deepseek-ai/dsh-client-ui-command', '@deepseek-ai/dsh-client-ui-conversation'] },
|
||||
{ id: '@deepseek-ai/dsh-session-log-download', bundlePath: 'packages/session-query/session-log-download/lib/client.js', url: '/plugins/session-log-download.js', rev: 'fx', inject: ['@deepseek-ai/dsh-client-ui-commands', '@deepseek-ai/dsh-client-ui-conversation'] },
|
||||
{ id: '@deepseek-ai/dsh-client-ui-trajectory', bundlePath: 'packages/client/ui-trajectory/lib/client.js', url: '/plugins/ui-trajectory.js', rev: 'fx', inject: ['@deepseek-ai/dsh-client-ui-conversation'] },
|
||||
]
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// Web e2e scenario: the session-header background-task list over the real
|
||||
// Web e2e scenario: the session-header background-job list over the real
|
||||
// host. No model call is involved — a genuine `run_in_background` bash call
|
||||
// registers with `ctx.tasks`, and the assertion chain is the whole delivery
|
||||
// path: registry change feed → api-proxy `session/tasks` frame → the client's
|
||||
// `tasksBySession` mirror → the header action.
|
||||
// registers with `ctx.jobs`, and the assertion chain is the whole delivery
|
||||
// path: registry change feed → api-proxy `session/jobs` frame → the client's
|
||||
// `jobsBySession` mirror → the header action.
|
||||
import { readFile } from 'node:fs/promises'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { join } from 'node:path'
|
||||
@@ -12,7 +12,7 @@ import { afterAll, beforeAll, describe, expect, it, onTestFailed } from 'vitest'
|
||||
import type { Agent } from '@deepseek-ai/dsh-agent'
|
||||
import { CallId } from '@deepseek-ai/dsh-llm'
|
||||
import { SessionId } from '@deepseek-ai/dsh-session'
|
||||
import { TaskId } from '@deepseek-ai/dsh-tasks'
|
||||
import { JobId } from '@deepseek-ai/dsh-jobs'
|
||||
import {
|
||||
assertFixtureInventory, captureStableAria, compareOrRefreshGolden,
|
||||
launchWebScaffold, seedSession, watchConsole, webSnapshotMode, type WebScaffold,
|
||||
@@ -20,11 +20,11 @@ import {
|
||||
import { newEnglishPage, saveFailureShot } from './support.ts'
|
||||
|
||||
const FIXTURE = fileURLToPath(new URL('./snapshots/fresh-round-trip/session.jsonl', import.meta.url))
|
||||
const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/background-task-list', import.meta.url))
|
||||
const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/background-job-list', import.meta.url))
|
||||
const RUNNING_EXPECTED = join(SNAPSHOT_DIR, 'running.expected.md')
|
||||
const SETTLED_EXPECTED = join(SNAPSHOT_DIR, 'settled.expected.md')
|
||||
const MODE = webSnapshotMode()
|
||||
const SEED_ID = 'background-task-list-web-e2e'
|
||||
const SEED_ID = 'background-job-list-web-e2e'
|
||||
// Long enough that the running assertions never race the process exiting on
|
||||
// their own; the test kills it explicitly to reach the settled state.
|
||||
const COMMAND = 'sleep 45'
|
||||
@@ -45,13 +45,13 @@ async function liveAgent(scaffold: WebScaffold, sessionId: SessionId): Promise<A
|
||||
}
|
||||
}
|
||||
|
||||
describe.skipIf(MODE === 'record')('web e2e: background task list', () => {
|
||||
describe.skipIf(MODE === 'record')('web e2e: background job list', () => {
|
||||
let scaffold: WebScaffold
|
||||
let browser: Browser
|
||||
let page: Page
|
||||
let tripwire: ReturnType<typeof watchConsole>
|
||||
let agent: Agent
|
||||
let taskId: TaskId
|
||||
let jobId: JobId
|
||||
|
||||
beforeAll(async () => {
|
||||
scaffold = await launchWebScaffold({})
|
||||
@@ -70,7 +70,7 @@ describe.skipIf(MODE === 'record')('web e2e: background task list', () => {
|
||||
await sessionRow.click()
|
||||
|
||||
// Opening the session drives the Host's ordinary Agent resolution; the
|
||||
// task owner must be that exact live instance, never a second one.
|
||||
// job owner must be that exact live instance, never a second one.
|
||||
// `expect.poll` is test-scoped, so this hook polls by hand.
|
||||
agent = await liveAgent(scaffold, SessionId(SEED_ID))
|
||||
}, 120_000)
|
||||
@@ -80,29 +80,29 @@ describe.skipIf(MODE === 'record')('web e2e: background task list', () => {
|
||||
await scaffold?.close()
|
||||
})
|
||||
|
||||
it('shows a running background task in the session header without a refresh', async () => {
|
||||
onTestFailed(() => saveFailureShot(page, 'web-e2e-background-task-running'))
|
||||
it('shows a running background job in the session header without a refresh', async () => {
|
||||
onTestFailed(() => saveFailureShot(page, 'web-e2e-background-job-running'))
|
||||
// Point assertion, not a poll: `expect.poll` retries until a predicate
|
||||
// holds, so polling for zero passes at t=0 and proves nothing. The
|
||||
// "renders nothing without a task" branch is owned by the component suite.
|
||||
const trigger = page.getByRole('button', { name: '1 background task running' })
|
||||
const trigger = page.getByRole('button', { name: '1 background job running' })
|
||||
expect(await trigger.count()).toBe(0)
|
||||
|
||||
const started = await scaffold.ctx.tools.execute({
|
||||
signal: new AbortController().signal,
|
||||
callId: CallId('background-task-list-e2e'),
|
||||
callId: CallId('background-job-list-e2e'),
|
||||
name: 'bash',
|
||||
arguments: { command: COMMAND, description: 'Hold a background slot open', run_in_background: true },
|
||||
agent,
|
||||
})
|
||||
const reported = started.content.map(block => block.type === 'text' ? block.text : '').join('')
|
||||
const matched = /\bbash-\d+\b/.exec(reported)
|
||||
if (matched === null) throw new Error(`background bash reported no task id: ${reported}`)
|
||||
taskId = TaskId(matched[0])
|
||||
if (matched === null) throw new Error(`background bash reported no job id: ${reported}`)
|
||||
jobId = JobId(matched[0])
|
||||
|
||||
await trigger.waitFor({ timeout: 15_000 })
|
||||
await trigger.click()
|
||||
const row = page.getByRole('list', { name: 'Background tasks' }).getByRole('listitem').first()
|
||||
const row = page.getByRole('list', { name: 'Background jobs' }).getByRole('listitem').first()
|
||||
await row.waitFor({ timeout: 10_000 })
|
||||
await expect.poll(() => row.textContent()).toContain(COMMAND)
|
||||
|
||||
@@ -113,12 +113,12 @@ describe.skipIf(MODE === 'record')('web e2e: background task list', () => {
|
||||
}, 60_000)
|
||||
|
||||
it('flips the open list to the cancelled outcome when the registry settles it', async () => {
|
||||
onTestFailed(() => saveFailureShot(page, 'web-e2e-background-task-settled'))
|
||||
expect(scaffold.ctx.tasks.kill(taskId, agent, 'web e2e cancellation')).toBe('requested')
|
||||
onTestFailed(() => saveFailureShot(page, 'web-e2e-background-job-settled'))
|
||||
expect(scaffold.ctx.jobs.kill(jobId, agent, 'web e2e cancellation')).toBe('requested')
|
||||
|
||||
// The trigger drops its live count once the task leaves running/stopping,
|
||||
// which is also the proof that settlement reached the browser unprompted.
|
||||
const idle = page.getByRole('button', { name: '1 background task' })
|
||||
const idle = page.getByRole('button', { name: '1 background job' })
|
||||
await idle.waitFor({ timeout: 20_000 })
|
||||
|
||||
const snapshot = await captureStableAria(page, '[class*="menu"]', scaffold.workspaceCwd)
|
||||
@@ -268,7 +268,7 @@ async function openSeed(page: Page, fixture: ChatScrollFixture, tailMarker?: str
|
||||
if (await searchButton.getAttribute('aria-expanded') !== 'true') await searchButton.click()
|
||||
const search = page.getByRole('textbox', { name: 'Search sessions...', exact: true })
|
||||
// Cold summaries initially show the temporary workspace basename, so the
|
||||
// persisted first-message marker is the stable user-facing identity. The
|
||||
// persisted first-prompt marker is the stable user-facing identity. The
|
||||
// query itself triggers lazy content-index reconciliation; no transient
|
||||
// empty-state paint is used as a barrier.
|
||||
await search.fill(fixture.markers.user(1))
|
||||
|
||||
@@ -39,11 +39,11 @@ const PACKAGE_FILES: Readonly<Record<string, string>> = {
|
||||
'packages/llm/token-meter/package.json': '{"name":"@deepseek-ai/dsh-token-meter"}\n',
|
||||
'packages/llm/token-meter/src/index.ts': 'export {}\n',
|
||||
'packages/llm/token-meter/tests/token-meter.spec.ts': 'export {}\n',
|
||||
'packages/skill/skill-local/README.md': '# Local skill provider\n',
|
||||
'packages/skill/skill-local/package.json': '{"name":"@deepseek-ai/dsh-skill-local"}\n',
|
||||
'packages/skill/skill-local/src/index.ts': 'export {}\n',
|
||||
'packages/skill/skill-local/src/invariant.ts': 'export {}\n',
|
||||
'packages/skill/skill-local/tests/skill-local.spec.ts': 'export {}\n',
|
||||
'packages/skill/skill-filesystem/README.md': '# Local skill provider\n',
|
||||
'packages/skill/skill-filesystem/package.json': '{"name":"@deepseek-ai/dsh-skill-filesystem"}\n',
|
||||
'packages/skill/skill-filesystem/src/index.ts': 'export {}\n',
|
||||
'packages/skill/skill-filesystem/src/invariant.ts': 'export {}\n',
|
||||
'packages/skill/skill-filesystem/tests/skill-filesystem.spec.ts': 'export {}\n',
|
||||
}
|
||||
|
||||
/** Materialize a stable package inventory inside the isolated session workspace. */
|
||||
|
||||
@@ -8,7 +8,7 @@ import { chromium } from 'playwright'
|
||||
import { expect, it } from 'vitest'
|
||||
import { Context } from '@deepseek-ai/cordis'
|
||||
import type { Fiber } from '@deepseek-ai/cordis'
|
||||
import LocalSubprocessService from '@deepseek-ai/dsh-subprocess-local'
|
||||
import LocalSubprocessRuntime from '@deepseek-ai/dsh-subprocess-local'
|
||||
import type { SubprocessHandle, SubprocessSpawnSpec } from '@deepseek-ai/dsh-subprocess'
|
||||
import { REPO_ROOT } from './support.ts'
|
||||
|
||||
@@ -88,7 +88,7 @@ it('hot-reloads a real client-plugin source edit without refreshing the page', a
|
||||
let browser: Awaited<ReturnType<typeof chromium.launch>> | undefined
|
||||
const failures: unknown[] = []
|
||||
try {
|
||||
subprocessFiber = await subprocessCtx.plugin(LocalSubprocessService)
|
||||
subprocessFiber = await subprocessCtx.plugin(LocalSubprocessRuntime)
|
||||
watcher = subprocessCtx.subprocess.spawn(spawnSpec(['pnpm', 'run', 'dev:web'], REPO_ROOT))
|
||||
await waitForOutput(watcher, /dev-web: watching/, 'pnpm run dev:web')
|
||||
host = subprocessCtx.subprocess.spawn(spawnSpec(
|
||||
|
||||
@@ -238,7 +238,7 @@ describe('web e2e: lifecycle & chrome (workspace flow / reload / dark mode)', ()
|
||||
|
||||
it.skipIf(MODE === 'record')('cascades the dark theme from the body attribute to painted surfaces', async () => {
|
||||
onTestFailed(() => saveFailureShot(page, 'web-e2e-lifecycle-dark'))
|
||||
// This scenario pins the ThemeService's DOM contract directly (the
|
||||
// This scenario pins the ThemeRuntime's DOM contract directly (the
|
||||
// body[data-ds-dark-theme] attribute -> stylesheet cascade); the REAL
|
||||
// user gesture above it (Settings -> Appearance cubes) is owned by
|
||||
// settings-chrome.e2e.ts. Driving the attribute here keeps the cascade
|
||||
|
||||
@@ -58,7 +58,7 @@ describe('minimal agent preset', () => {
|
||||
const presetFileSystem = scaffold.ctx.agentPresets.serviceFor(agentHandle.agent, 'fs')
|
||||
expect(presetFileSystem).toBeDefined()
|
||||
expect(presetFileSystem?.sandboxMode).toBeUndefined()
|
||||
expect(scaffold.ctx.agentPresets.serviceFor(agentHandle.agent, 'compact')).toBeUndefined()
|
||||
expect(scaffold.ctx.agentPresets.serviceFor(agentHandle.agent, 'compaction')).toBeUndefined()
|
||||
|
||||
const stateDir = join(scaffold.workspaceCwd, 'persistent-state')
|
||||
await mkdir(stateDir)
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
- insert:
|
||||
- id: directory-picker-browse
|
||||
name: '@deepseek-ai/dsh-host-directory-picker-browse'
|
||||
- id: ui-directory-picker
|
||||
name: '@deepseek-ai/dsh-client-ui-directory-picker'
|
||||
- id: ui-directory-picker-browse
|
||||
name: '@deepseek-ai/dsh-client-ui-directory-picker-browse'
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
name: '@deepseek-ai/dsh-bash-sandbox'
|
||||
disabled: true
|
||||
- id: permission
|
||||
name: '@deepseek-ai/dsh-permission'
|
||||
name: '@deepseek-ai/dsh-permission-presets'
|
||||
disabled: true
|
||||
- insert:
|
||||
- id: pwsh-local
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Web e2e scenario: the resident question composer. The shipped composition
|
||||
// already exposes ask_user_question (the ui-question row's node half mounts
|
||||
// already exposes ask_user_question (the ui-user-questions row's node half mounts
|
||||
// the tool), so a recorded turn where the model asks blocks mid-turn on the
|
||||
// real userInteraction seam: the composer renders in the browser, the test
|
||||
// answers through it, and the turn completes with the answer in the log.
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
// Composition divergences from `dsh web`, all deliberate, all via include
|
||||
// patches after the shipped bundle layers, over the SAME tree (never a
|
||||
// second yml): temp persistenceRoot; host-level skill roots confined to the
|
||||
// temp workspace while project skill discovery remains real; workspace-context
|
||||
// temp workspace while project skill discovery remains real; agent-instructions
|
||||
// disabled (recorded fixtures must not embed this repo's AGENTS.md);
|
||||
// session-title-llm disabled (its fire-and-forget title call would race the
|
||||
// loop for the session's replay cursor); webserver pinned to port 0 with the
|
||||
@@ -40,7 +40,7 @@ import {
|
||||
healProfilesModuleFallback,
|
||||
loadOverlayPatches,
|
||||
} from '@deepseek-ai/dsh-app-boot'
|
||||
import { dshHomePath } from '@deepseek-ai/dsh-paths'
|
||||
import { dshHomePath } from '@deepseek-ai/dsh-home-paths'
|
||||
// Client packages must not be imported here: these e2e type-check in the Host
|
||||
// aggregate, so a Client import pulls that package's whole project — and every
|
||||
// project it references — into the Host build graph. Mirrored from
|
||||
@@ -69,9 +69,9 @@ import SessionStore, {
|
||||
type SessionEvent,
|
||||
type SessionHeader,
|
||||
} from '@deepseek-ai/dsh-session'
|
||||
import SessionPersistenceJsonl from '@deepseek-ai/dsh-session-persistence-jsonl'
|
||||
import JsonlSessionPersistence from '@deepseek-ai/dsh-session-persistence-jsonl'
|
||||
import * as ToolCordis from '@deepseek-ai/dsh-tool-cordis'
|
||||
// Empty type imports carry the httpServer/agents/sessionPersistence Context merges.
|
||||
// Empty type imports carry the webServer/agents/sessionPersistence Context merges.
|
||||
import type {} from '@deepseek-ai/dsh-host-webserver'
|
||||
import type {} from '@deepseek-ai/dsh-agent'
|
||||
import { provideCmdline } from '@deepseek-ai/dsh-cmdline'
|
||||
@@ -101,7 +101,7 @@ const SHIPPED_PRESET_DIR = join(REPO_ROOT, 'apps/cli/config/agent-presets')
|
||||
|
||||
// Replay publishes the provider catalog the gateway routes to (providers
|
||||
// mode, never catch-all: with llm-deepseek disabled no adapter exists, so a
|
||||
// catch-all would leave resolveModelInfo unroutable and compact-basic's
|
||||
// catch-all would leave resolveModelInfo unroutable and compaction-basic's
|
||||
// post-step pressure check would warn every step). The published
|
||||
// contextWindow keeps that pressure path provably inert for small fixtures.
|
||||
const REPLAY_PROVIDERS = [{
|
||||
@@ -166,7 +166,7 @@ export interface WebScaffold {
|
||||
baseUrl: string
|
||||
/** Settled root context (the in-process readiness barrier; headless event subscription is its sanctioned use). */
|
||||
ctx: Context
|
||||
/** Temp project directory sessions run in (bash/fs tool cwd). */
|
||||
/** Temp project directory sessions run in (shell/fs tool cwd). */
|
||||
workspaceCwd: string
|
||||
/** Temp persistence root (seeded sessions land here through the real API). */
|
||||
persistenceRoot: string
|
||||
@@ -402,7 +402,7 @@ export async function launchWebScaffold(options: LaunchOptions = {}): Promise<We
|
||||
// cannot change replay requests or conversation goldens. Project roots stay
|
||||
// enabled against the same empty temp workspace, preserving the real seam.
|
||||
{
|
||||
id: 'skill-local',
|
||||
id: 'skill-filesystem',
|
||||
config: {
|
||||
dshHome: join(workspaceCwd, '.dsh-home'),
|
||||
agentsHome: join(workspaceCwd, '.agents-home'),
|
||||
@@ -413,16 +413,16 @@ export async function launchWebScaffold(options: LaunchOptions = {}): Promise<We
|
||||
// fs/bash cwd default to process.cwd(); the gateway injects the same
|
||||
// value into session.cwd — chdir below anchors all three to the temp
|
||||
// workspace, keeping the composition untouched.
|
||||
{ id: 'workspace-context', disabled: true },
|
||||
{ id: 'agent-instructions', disabled: true },
|
||||
{ id: 'session-title-llm', disabled: true },
|
||||
// Fixture sessions must never leave the process: the shipped row defaults
|
||||
// to the production OTLP endpoint (or whatever DSH_TELEMETRY_OTLP_URL
|
||||
// names in the ambient environment). A scenario that pins a real backend
|
||||
// disclosure passes a local dead endpoint instead of disabling the row.
|
||||
options.telemetryUrl === undefined
|
||||
? { id: 'telemetry-otel', disabled: true }
|
||||
? { id: 'session-telemetry-otel', disabled: true }
|
||||
: {
|
||||
id: 'telemetry-otel',
|
||||
id: 'session-telemetry-otel',
|
||||
config: {
|
||||
mode: 'FULL',
|
||||
exporter: { url: options.telemetryUrl },
|
||||
@@ -434,7 +434,7 @@ export async function launchWebScaffold(options: LaunchOptions = {}): Promise<We
|
||||
config: { host: '127.0.0.1', port: 0 },
|
||||
},
|
||||
// The bundle's web-runtime row resolves the same built dist under test
|
||||
// (apps/web IS @deepseek-ai/dsh-frontend); only the URL line is silenced.
|
||||
// (apps/web IS @deepseek-ai/dsh-web-frontend); only the URL line is silenced.
|
||||
// Preserve the composed surface-context choice because a patch replaces
|
||||
// the row's complete config.
|
||||
{ id: 'web-runtime', config: { printUrl: false, surfaceContext } },
|
||||
@@ -452,7 +452,7 @@ export async function launchWebScaffold(options: LaunchOptions = {}): Promise<We
|
||||
{ id: 'directory-picker', disabled: true },
|
||||
{ insert: [
|
||||
{ id: 'directory-picker-browse', name: '@deepseek-ai/dsh-host-directory-picker-browse' },
|
||||
{ id: 'ui-directory-picker', name: '@deepseek-ai/dsh-client-ui-directory-picker' },
|
||||
{ id: 'ui-directory-picker-browse', name: '@deepseek-ai/dsh-client-ui-directory-picker-browse' },
|
||||
] },
|
||||
...options.agentPresets === undefined
|
||||
? []
|
||||
@@ -527,9 +527,9 @@ export async function launchWebScaffold(options: LaunchOptions = {}): Promise<We
|
||||
op: 'set', path: [WELCOME_NOTICE_ACK_FIELD], value: WELCOME_NOTICE_VERSION,
|
||||
}])
|
||||
}
|
||||
const boundPort = ctx.get('httpServer')?.port
|
||||
const boundPort = ctx.get('webServer')?.port
|
||||
if (boundPort === undefined) {
|
||||
throw new Error('web e2e scaffold: httpServer service missing after settled boot')
|
||||
throw new Error('web e2e scaffold: webServer service missing after settled boot')
|
||||
}
|
||||
port = boundPort
|
||||
|
||||
@@ -725,7 +725,7 @@ export async function seedSession(
|
||||
await seeder.plugin(SessionStore)
|
||||
// Same root as the booted tree with the plugin's own default compression,
|
||||
// so the host's directory-scan list() sees one consistent encoding.
|
||||
await seeder.plugin(SessionPersistenceJsonl, { root: scaffold.persistenceRoot })
|
||||
await seeder.plugin(JsonlSessionPersistence, { root: scaffold.persistenceRoot })
|
||||
await seeder.sessionPersistence.create(meta)
|
||||
await seeder.sessionPersistence.append(meta.id, events)
|
||||
// Deterministic sidebar order: cold summaries take updatedAt from mtime.
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
foldScheduleEvents,
|
||||
resolveEveryOccurrence,
|
||||
type EveryScheduleRecord,
|
||||
} from '@deepseek-ai/dsh-tool-schedule'
|
||||
} from '@deepseek-ai/dsh-schedule'
|
||||
import {
|
||||
assertFixtureInventory,
|
||||
captureStableAria,
|
||||
@@ -167,7 +167,7 @@ function requestText(options: GenerateOptions): string {
|
||||
/** Require one assembled request to preserve the reminder-content trust boundary. */
|
||||
function expectReminderFraming(options: GenerateOptions): void {
|
||||
const reminder = options.messages.find(message => (
|
||||
message.source.kind === 'plugin' && message.source.plugin === 'tool-schedule'
|
||||
message.source.kind === 'plugin' && message.source.plugin === 'schedule'
|
||||
))
|
||||
expect(reminder?.role).toBe('user')
|
||||
const text = reminder?.content.find(block => block.type === 'text')?.text
|
||||
@@ -242,7 +242,7 @@ describe.skipIf(MODE === 'record')('web e2e: conversational reminders', () => {
|
||||
.toBe(AT_BROWSER_ZONE)
|
||||
|
||||
const cwd = join(scaffold.workspaceCwd, 'workspace')
|
||||
const workspace = await scaffold.ctx.workspace.resolveByPath(cwd)
|
||||
const workspace = await scaffold.ctx.workspaceRegistry.resolveByPath(cwd)
|
||||
if (workspace === undefined) throw new Error('connected Web workspace was not registered')
|
||||
|
||||
afterHandle = await scaffold.ctx.agents.create({
|
||||
@@ -421,7 +421,7 @@ describe.skipIf(MODE === 'record')('web e2e: conversational reminders', () => {
|
||||
const batch = everyHandle.agent.session.events.find(event => (
|
||||
event.type === 'user/message'
|
||||
&& event.data.source.kind === 'plugin'
|
||||
&& event.data.source.plugin === 'tool-schedule'
|
||||
&& event.data.source.plugin === 'schedule'
|
||||
&& event.data.content.some(block => block.type === 'text'
|
||||
&& block.text.startsWith('[SCHEDULE REMINDER BATCH]'))
|
||||
))
|
||||
|
||||
@@ -19,7 +19,7 @@ import { createUserMessage } from '@deepseek-ai/dsh-llm'
|
||||
import type { ContentBlock, Message } from '@deepseek-ai/dsh-llm'
|
||||
import { deriveEventMessage, SessionId } from '@deepseek-ai/dsh-session'
|
||||
import type { SessionEvent } from '@deepseek-ai/dsh-session'
|
||||
import type { TokenMeterService } from '@deepseek-ai/dsh-token-meter'
|
||||
import type { TokenMeter } from '@deepseek-ai/dsh-token-meter'
|
||||
import { join } from 'node:path'
|
||||
import {
|
||||
assertFixtureInventory, captureStableAria, compareOrRefreshGolden, fixtureUserPrompts,
|
||||
@@ -46,13 +46,13 @@ const PROMPT = 'Use the read tool twice in one assistant message: read a.txt and
|
||||
* presentation through the real host and browser.
|
||||
* @param raw - the seed fixture text, already realized (placeholder-free) so
|
||||
* the shadow price below is computed from the exact strings the host folds.
|
||||
* @param meter - the composed token meter; the appended `compact/summary`'s
|
||||
* @param meter - the composed token meter; the appended `compaction/summary`'s
|
||||
* shadow price must be the exact heuristic price of the shadowed nodes, the
|
||||
* way compact-basic derives it, because the token-meter projections subtract
|
||||
* way compaction-basic derives it, because the token-meter projections subtract
|
||||
* it verbatim.
|
||||
* @returns the fixture with a manual compaction lifecycle appended.
|
||||
*/
|
||||
function withCompaction(raw: string, meter: TokenMeterService): string {
|
||||
function withCompaction(raw: string, meter: TokenMeter): string {
|
||||
const lines = raw.trimEnd().split('\n')
|
||||
const events = lines.slice(1).map(line => JSON.parse(line) as {
|
||||
type: string
|
||||
@@ -96,7 +96,7 @@ function withCompaction(raw: string, meter: TokenMeterService): string {
|
||||
data: { commandId, name: 'compact', args: '', source: { kind: 'user' } },
|
||||
})
|
||||
const startSeq = at({
|
||||
type: 'compact/start',
|
||||
type: 'compaction/start',
|
||||
data: { compactionId, sourceCommandId: commandId, turn: null },
|
||||
})
|
||||
// Load-bearing exactness: the projections subtract this count verbatim, so
|
||||
@@ -125,7 +125,7 @@ function withCompaction(raw: string, meter: TokenMeterService): string {
|
||||
return total + priceRow(event)
|
||||
}, 0)
|
||||
const summarySeq = at({
|
||||
type: 'compact/summary',
|
||||
type: 'compaction/summary',
|
||||
data: {
|
||||
compactionId,
|
||||
sourceCommandId: commandId,
|
||||
@@ -155,7 +155,7 @@ function withCompaction(raw: string, meter: TokenMeterService): string {
|
||||
sourceEventSeqs: [startSeq, summarySeq, ...surfaceSeqs],
|
||||
})
|
||||
at({
|
||||
type: 'compact/end',
|
||||
type: 'compaction/end',
|
||||
data: { compactionId, sourceCommandId: commandId, turn: null },
|
||||
})
|
||||
at({
|
||||
@@ -302,7 +302,7 @@ describe('web e2e: seeded history renders through cold resume', () => {
|
||||
+ '\n</system-reminder>',
|
||||
}],
|
||||
source: {
|
||||
kind: 'workspace-instructions',
|
||||
kind: 'agent-instructions',
|
||||
form: 'instructions',
|
||||
baseline: true,
|
||||
changes: [{
|
||||
@@ -463,9 +463,9 @@ describe('web e2e: seeded history renders through cold resume', () => {
|
||||
if (done?.type !== 'command/done') throw new Error('feedback command did not settle')
|
||||
const [sessionLine, userLine, extraLine] = done.data.text?.split('\n') ?? []
|
||||
expect(sessionLine).toBe(`Feedback recorded for session ${SEED_ID}`)
|
||||
expect(userLine).toMatch(/^User: [0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\./i)
|
||||
expect(userLine).toMatch(/^Anonymous user: [0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\./i)
|
||||
expect(extraLine).toBeUndefined()
|
||||
const userId = userLine?.match(/^User: ([0-9a-f-]+)/i)?.[1]
|
||||
const userId = userLine?.match(/^Anonymous user: ([0-9a-f-]+)/i)?.[1]
|
||||
if (userId === undefined) throw new Error('feedback command omitted the user id')
|
||||
|
||||
const snapshot = (await captureStableAria(page, '[class*="centerCol"]', scaffold.workspaceCwd))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Web e2e scenarios: the settings surface — the modal shell (trigger, nav,
|
||||
// section switching, both close paths), the Appearance preference row (the
|
||||
// real theme gesture — click 深色 and the whole cascade runs: ThemeService preference -> Host settings
|
||||
// real theme gesture — click 深色 and the whole cascade runs: ThemeRuntime preference -> Host settings
|
||||
// -> theme/change -> ui-layout's presenter -> body attribute -> alias token +
|
||||
// browser theme-color metadata)
|
||||
// the Language row and busy-state Enter preference (both Host-backed), plus
|
||||
|
||||
@@ -14,7 +14,7 @@ import { SessionId } from '@deepseek-ai/dsh-session'
|
||||
import type {} from '@deepseek-ai/dsh-tools'
|
||||
import type {} from '@deepseek-ai/dsh-sandbox-policy'
|
||||
import type {} from '@deepseek-ai/dsh-user-approval'
|
||||
import type {} from '@deepseek-ai/dsh-permission'
|
||||
import type {} from '@deepseek-ai/dsh-permission-presets'
|
||||
import type {} from '@deepseek-ai/dsh-agent-presets'
|
||||
import type {} from '@deepseek-ai/dsh-commands'
|
||||
import type {} from '@deepseek-ai/dsh-system-prompt'
|
||||
@@ -29,7 +29,7 @@ const FILE_REFERENCE_PROMPT = fileURLToPath(new URL(
|
||||
* ripgrep-dependent pair below. The absences are deliberate, not incidental
|
||||
* gaps: the `cordis_*` toolset executes model-written JavaScript that no
|
||||
* sandbox row confines, `web_fetch` chooses its own request target, and
|
||||
* `mcp_*` servers spawn outside `ctx.bash`. The composition Agent Note owns the
|
||||
* `mcp_*` servers spawn outside `ctx.shell`. The composition Agent Note owns the
|
||||
* rationale and its sources.
|
||||
*/
|
||||
const EXPECTED_TOOLS = [
|
||||
@@ -40,6 +40,9 @@ const EXPECTED_TOOLS = [
|
||||
'exit_plan_mode',
|
||||
'get_goal',
|
||||
'interrupt_agent',
|
||||
'job_kill',
|
||||
'job_list',
|
||||
'job_output',
|
||||
'list_agents',
|
||||
'ralph',
|
||||
'read',
|
||||
@@ -48,9 +51,6 @@ const EXPECTED_TOOLS = [
|
||||
'skill',
|
||||
'subagent',
|
||||
'subagent_fork',
|
||||
'task_kill',
|
||||
'task_list',
|
||||
'task_output',
|
||||
'todo_write',
|
||||
'update_goal',
|
||||
'web_search',
|
||||
@@ -108,7 +108,7 @@ it('assembles the shipped Web catalog, file-reference guidance, and confined acc
|
||||
)
|
||||
expect(scaffold.ctx.sandboxPolicy.defaultMode).toBe('workspace-write')
|
||||
expect(scaffold.ctx.approval.config.policy).toBe('ask')
|
||||
expect(scaffold.ctx.permission.defaultPreset).toBe('workspace-write')
|
||||
expect(scaffold.ctx.permissionPresets.defaultPreset).toBe('workspace-write')
|
||||
|
||||
const commandHandle = await scaffold.ctx.agents.create({
|
||||
sessionId: SessionId('shipped-command-catalog'),
|
||||
@@ -126,11 +126,11 @@ it('assembles the shipped Web catalog, file-reference guidance, and confined acc
|
||||
}
|
||||
}, 120_000)
|
||||
|
||||
it('lets a preset producer reach the background-task registry', async () => {
|
||||
it('lets a preset producer reach the background-job registry', async () => {
|
||||
scaffold = await launchWebScaffold()
|
||||
const ctx = scaffold.ctx
|
||||
const handle = await ctx.agents.create({
|
||||
sessionId: SessionId('shipped-background-task'),
|
||||
sessionId: SessionId('shipped-background-job'),
|
||||
meta: { cwd: scaffold.workspaceCwd },
|
||||
setup: agentCtx => ctx.agentPresets.mount(agentCtx).then(() => undefined),
|
||||
})
|
||||
@@ -152,7 +152,7 @@ it('lets a preset producer reach the background-task registry', async () => {
|
||||
})
|
||||
expect({ isError: started.isError, content: started.content }).toEqual({
|
||||
isError: false,
|
||||
content: [{ type: 'text', text: 'started background task bash-1' }],
|
||||
content: [{ type: 'text', text: 'started background job bash-1' }],
|
||||
})
|
||||
|
||||
// The controller reads what the producer started: same registry, one
|
||||
@@ -160,7 +160,7 @@ it('lets a preset producer reach the background-task registry', async () => {
|
||||
const listed = await ctx.tools.execute({
|
||||
signal,
|
||||
callId: CallId('shipped-task-list'),
|
||||
name: 'task_list',
|
||||
name: 'job_list',
|
||||
arguments: {},
|
||||
agent: handle.agent,
|
||||
})
|
||||
@@ -174,8 +174,8 @@ it('lets a preset producer reach the background-task registry', async () => {
|
||||
const collected = await ctx.tools.execute({
|
||||
signal,
|
||||
callId: CallId('shipped-task-output'),
|
||||
name: 'task_output',
|
||||
arguments: { task_id: 'bash-1', wait: true },
|
||||
name: 'job_output',
|
||||
arguments: { job_id: 'bash-1', wait: true },
|
||||
agent: handle.agent,
|
||||
})
|
||||
expect(collected.isError).toBe(false)
|
||||
|
||||
@@ -92,7 +92,7 @@ describe('web e2e: sidebar subagent activity', () => {
|
||||
agentOptions: { provider: HOLD_PROVIDER, model: HOLD_MODEL },
|
||||
})
|
||||
parentHandle.agent.followup(createUserMessage({
|
||||
content: [{ type: 'text', text: 'Delegate a background task.' }],
|
||||
content: [{ type: 'text', text: 'Delegate a background job.' }],
|
||||
source: { kind: 'user' },
|
||||
}))
|
||||
await parentHandle.agent.whenIdle()
|
||||
@@ -114,7 +114,7 @@ describe('web e2e: sidebar subagent activity', () => {
|
||||
await page.goto(scaffold.baseUrl, { waitUntil: 'load' })
|
||||
await page.waitForSelector('[class*="frame"]', { timeout: 30_000 })
|
||||
await connectFreshWorkspace(page, scaffold.workspaceCwd)
|
||||
const workspace = await scaffold.ctx.workspace.resolveByPath(cwd)
|
||||
const workspace = await scaffold.ctx.workspaceRegistry.resolveByPath(cwd)
|
||||
if (workspace === undefined) throw new Error('connected Web workspace was not registered')
|
||||
await workspace.attachSession(parentHandle.agent.session.id)
|
||||
}, 60_000)
|
||||
@@ -136,7 +136,7 @@ describe('web e2e: sidebar subagent activity', () => {
|
||||
it('pins a running descendant on its visible idle owner row', async () => {
|
||||
onTestFailed(() => saveFailureShot(page, 'web-e2e-sidebar-subagent-activity'))
|
||||
const sidebar = page.getByRole('tree', { name: 'Sessions' })
|
||||
const ownerRow = sidebar.getByRole('treeitem', { name: /1 subagent running Delegate a background task/ })
|
||||
const ownerRow = sidebar.getByRole('treeitem', { name: /1 subagent running Delegate a background job/ })
|
||||
await ownerRow.waitFor({ timeout: 10_000 })
|
||||
expect(parentHandle.agent.status).toBe('idle')
|
||||
await compareOrRefreshGolden(
|
||||
|
||||
@@ -143,8 +143,8 @@ async function detailsTrack(page: Page): Promise<number> {
|
||||
// the frame never appears.
|
||||
const UI_PLUGIN_DIRS = [
|
||||
'connection', 'runtime', 'ui-theme', 'locale', 'ui-layout', 'ui-sidebar',
|
||||
'ui-settings', 'ui-settings-general', 'ui-models', 'ui-conversation',
|
||||
'ui-model', 'ui-question', 'ui-trajectory', '../session-query/session-export',
|
||||
'ui-settings', 'ui-settings-general', 'ui-settings-models', 'ui-conversation',
|
||||
'ui-model-selection', 'ui-user-questions', 'ui-trajectory', '../session-query/session-log-download',
|
||||
]
|
||||
const ROUND_DONE_MARKER = 'WEB_ROUND_DONE'
|
||||
const notReady = UI_PLUGIN_DIRS.filter((dir) => {
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
- list "Background tasks":
|
||||
- list "Background jobs":
|
||||
- listitem: bash sleep 45 running {{duration}}
|
||||
@@ -1,2 +1,2 @@
|
||||
- list "Background tasks":
|
||||
- list "Background jobs":
|
||||
- listitem: "bash sleep 45 signal: SIGTERM {{duration}}"
|
||||
@@ -30,10 +30,10 @@
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s
|
||||
- 'button "feedback Feedback recorded for session session-{{uuid}} User: {{uuid}}. Session sharing is enabled."':
|
||||
- 'button "feedback Feedback recorded for session session-{{uuid}} Anonymous user: {{uuid}}. Session sharing is enabled."':
|
||||
- img
|
||||
- img
|
||||
- text: "feedback Feedback recorded for session session-{{uuid}} User: {{uuid}}. Session sharing is enabled."
|
||||
- text: "feedback Feedback recorded for session session-{{uuid}} Anonymous user: {{uuid}}. Session sharing is enabled."
|
||||
- textbox "Message the agent"
|
||||
- button "Commands":
|
||||
- img
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
You are an AI agent powered by the DeepSeek Harness SDK.
|
||||
You are an AI agent powered by DeepSeek Harness.
|
||||
|
||||
The DeepSeek Harness implementation checkout is at {{sourceRoot}}. The checkout location and current working directory are separate values and may differ; never infer the working directory from this path. Use pwd to determine the current working directory. Use this checkout only to inspect or extend DSH itself.
|
||||
|
||||
You are interacting with the user through the DeepSeek Harness Web GUI at {{webUrl}}. When the user refers to "this page", "this GUI", or "this app" without naming another target, they mean this GUI. The browser provides no implicit DOM, route, or screenshot context. The client-plugin HMR receiver is active, but client-plugin changes reload without a refresh only while `pnpm run dev:web` is also running from this same checkout to rebuild their bundles; verify that watcher before promising automatic updates. Every other change — the apps/web shell and plain packages — requires rebuilding the affected Web artifacts and verifying this existing URL after a page refresh. Starting another server does not update this GUI. The apps/web Vite entry builds the shell but is not a standalone application because only dsh web injects window.__DSH_BOOT__. Do not start a replacement server unless the user asks; if one is needed, use a managed background task and verify its exact URL.
|
||||
You are interacting with the user through the DeepSeek Harness Web GUI at {{webUrl}}. When the user refers to "this page", "this GUI", or "this app" without naming another target, they mean this GUI. The browser provides no implicit DOM, route, or screenshot context. The client-plugin HMR receiver is active, but client-plugin changes reload without a refresh only while `pnpm run dev:web` is also running from this same checkout to rebuild their bundles; verify that watcher before promising automatic updates. Every other change — the apps/web shell and plain packages — requires rebuilding the affected Web artifacts and verifying this existing URL after a page refresh. Starting another server does not update this GUI. The apps/web Vite entry builds the shell but is not a standalone application because only dsh web injects window.__DSH_BOOT__. Do not start a replacement server unless the user asks; if one is needed, use a managed background job and verify its exact URL.
|
||||
|
||||
You are a coding agent powered by the deepseek-v4-flash model. Your working directory is {{cwd}}.
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
"kind": "chunks",
|
||||
"chunks": [
|
||||
{ "type": "block-start", "index": 0, "blockType": "reasoning" },
|
||||
{ "type": "reasoning-delta", "index": 0, "text": "There are 4 packages:\n- client/ui-conversation\n- context/session-reference\n- llm/token-meter\n- skill/skill-local\n\nFor this turn (turn 1 of 2), I should randomly pick one package and output its file structure. Let me pick randomly — I'll use $RANDOM or just pick one. Let me use a quick random selection." },
|
||||
{ "type": "block-end", "index": 0, "block": { "type": "reasoning", "text": "There are 4 packages:\n- client/ui-conversation\n- context/session-reference\n- llm/token-meter\n- skill/skill-local\n\nFor this turn (turn 1 of 2), I should randomly pick one package and output its file structure. Let me pick randomly — I'll use $RANDOM or just pick one. Let me use a quick random selection." } },
|
||||
{ "type": "reasoning-delta", "index": 0, "text": "There are 4 packages:\n- client/ui-conversation\n- context/session-reference\n- llm/token-meter\n- skill/skill-filesystem\n\nFor this turn (turn 1 of 2), I should randomly pick one package and output its file structure. Let me pick randomly — I'll use $RANDOM or just pick one. Let me use a quick random selection." },
|
||||
{ "type": "block-end", "index": 0, "block": { "type": "reasoning", "text": "There are 4 packages:\n- client/ui-conversation\n- context/session-reference\n- llm/token-meter\n- skill/skill-filesystem\n\nFor this turn (turn 1 of 2), I should randomly pick one package and output its file structure. Let me pick randomly — I'll use $RANDOM or just pick one. Let me use a quick random selection." } },
|
||||
{ "type": "block-start", "index": 1, "blockType": "tool-call" },
|
||||
{ "type": "tool-call-delta", "index": 1, "id": "call_00_dAM4qfVp4LLtRCiJi7d71418", "name": "bash", "argumentsDelta": "{\"command\": \"find packages -maxdepth 2 -mindepth 2 -type d | sort | awk '{print NR\\\": \\\"$0}' && echo \\\"---random pick---\\\" && find packages -maxdepth 2 -mindepth 2 -type d | sort | PATH=/__dsh_fixture_missing__ shuf -n 1\", \"description\": \"Randomly pick one package directory\"}" },
|
||||
{ "type": "block-end", "index": 1, "block": { "type": "tool-call", "id": "call_00_dAM4qfVp4LLtRCiJi7d71418", "name": "bash", "arguments": "{\"command\": \"find packages -maxdepth 2 -mindepth 2 -type d | sort | awk '{print NR\\\": \\\"$0}' && echo \\\"---random pick---\\\" && find packages -maxdepth 2 -mindepth 2 -type d | sort | PATH=/__dsh_fixture_missing__ shuf -n 1\", \"description\": \"Randomly pick one package directory\"}" } },
|
||||
|
||||
@@ -42,20 +42,20 @@
|
||||
{"type":"assistant/chunk","seq":335,"time":1786073822633,"data":{"turn":1,"step":2,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}
|
||||
{"type":"assistant/message","seq":336,"time":1786073822633,"data":{"turn":1,"step":2,"message":{"role":"assistant","content":[{"type":"reasoning","text":"There's a `packages` directory. Let me look inside to see what packages are available."},{"type":"tool-call","id":"call_00_XlYaTHoKielffCybfcXb9253","name":"bash","arguments":"{\"command\": \"ls packages && echo \\\"---\\\" && find packages -maxdepth 2 -type d\", \"description\": \"List packages directory contents\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"4f03ca00-aa2d-4a69-9675-58833e8d1b30"},"usage":{"inputTokens":363,"outputTokens":99,"cacheReadTokens":8064,"reasoningTokens":20}},"sourceEventSeqs":[272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335],"surfaceOp":"append"}
|
||||
{"type":"tool/call","seq":337,"time":1786073822634,"data":{"turn":1,"step":2,"callId":"call_00_XlYaTHoKielffCybfcXb9253","name":"bash","arguments":"{\"command\": \"ls packages && echo \\\"---\\\" && find packages -maxdepth 2 -type d\", \"description\": \"List packages directory contents\"}"}}
|
||||
{"type":"tool/result","seq":338,"time":1786073822659,"data":{"turn":1,"step":2,"message":{"source":{"kind":"tool","callId":"call_00_XlYaTHoKielffCybfcXb9253"},"content":[{"type":"tool-result","toolCallId":"call_00_XlYaTHoKielffCybfcXb9253","content":[{"type":"text","text":"client\ncontext\nllm\nskill\n---\npackages\npackages/llm\npackages/llm/token-meter\npackages/context\npackages/context/session-reference\npackages/skill\npackages/skill/skill-local\npackages/client\npackages/client/ui-conversation\n"}],"isError":false}],"role":"user","id":"8a53ae07-7f7a-424f-8095-96f216746bc4"}},"sourceEventSeqs":[337],"surfaceOp":"append"}
|
||||
{"type":"tool/result","seq":338,"time":1786073822659,"data":{"turn":1,"step":2,"message":{"source":{"kind":"tool","callId":"call_00_XlYaTHoKielffCybfcXb9253"},"content":[{"type":"tool-result","toolCallId":"call_00_XlYaTHoKielffCybfcXb9253","content":[{"type":"text","text":"client\ncontext\nllm\nskill\n---\npackages\npackages/llm\npackages/llm/token-meter\npackages/context\npackages/context/session-reference\npackages/skill\npackages/skill/skill-filesystem\npackages/client\npackages/client/ui-conversation\n"}],"isError":false}],"role":"user","id":"8a53ae07-7f7a-424f-8095-96f216746bc4"}},"sourceEventSeqs":[337],"surfaceOp":"append"}
|
||||
{"type":"step/end","seq":339,"time":1786073822659,"data":{"turn":1,"step":2}}
|
||||
{"type":"step/start","seq":340,"time":1786073822668,"data":{"turn":1,"step":3}}
|
||||
{"type":"assistant/chunk","seq":341,"time":1786073823725,"data":{"turn":1,"step":3,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}}}
|
||||
{"type":"reasoning-chunks","seq0":342,"time0":1786073823726,"data":{"turn":1,"step":3,"index":0,"dt":[82,26,0,0,27,0,0,0,23,0,0,0,0,0,21,0,0,0,0,0,21,1,0,0,24,0,1,0,0,0,23,0,0,21,1,0,23,0,0,0,0,0,22,1,0,0,0,0,24,0,0,0,0,0,24,0,0,1,24,1,0,0,17,24,1,0,0,0,29,0,0,16,1,0,31,0,0,18,0],"texts":["There"," are"," ","4"," packages",":\n","-"," client","/ui","-con","vers","ation","\n","-"," context","/s","ession","-reference","\n","-"," ll","m","/t","oken","-meter","\n","-"," skill","/s","kill","-local","\n\n","For"," this"," turn"," (","turn"," ","1"," of"," ","2","),"," I"," should"," randomly"," pick"," one"," package"," and"," output"," its"," file"," structure","."," Let"," me"," pick"," randomly"," —"," I","'ll"," use"," $","R","AND","OM"," or"," just"," pick"," one","."," Let"," me"," use"," a"," quick"," random"," selection","."]}}
|
||||
{"type":"assistant/chunk","seq":422,"time":1786073824320,"data":{"turn":1,"step":3,"chunk":{"type":"block-start","index":1,"blockType":"tool-call"}}}
|
||||
{"type":"tool-call-chunks","seq0":423,"time0":1786073824321,"data":{"turn":1,"step":3,"index":1,"dt":[24,1,1,0,0,29,1,14,1,0,0,0,24,0,1,21,0,0,41,1,0,0,0,0,11,0,0,20,0,0,26,0,0,16,1,0,28,1,23,0,1,0,28,0,0,19,0,0,0,0,1,13,1,0,0,0,0,27,1,0,28,0,0,0,28,1,26,1,0,0,19,1,0,0,22,1,0,18,0,23],"id":"call_00_dAM4qfVp4LLtRCiJi7d71418","name":"bash","args":["","{","\"","command","\"",": ","\"","find"," packages"," -","max","depth"," ","2"," -","mind","epth"," ","2"," -","type"," d"," |"," sort"," |"," awk"," '{","print"," NR","\\\":"," \\\"$","0","}'"," &&"," echo"," \\\"","---","random"," pick","---","\\\""," &&"," find"," packages"," -","max","depth"," ","2"," -","mind","epth"," ","2"," -","type"," d"," |"," sort"," |"," sh","uf"," -","n"," ","1","\"",", ","\"","description","\"",": ","\"","Random","ly"," pick"," one"," package"," directory","\"","}"]}}
|
||||
{"type":"assistant/chunk","seq":504,"time":1786073824907,"data":{"turn":1,"step":3,"chunk":{"type":"block-end","index":0,"block":{"type":"reasoning","text":"There are 4 packages:\n- client/ui-conversation\n- context/session-reference\n- llm/token-meter\n- skill/skill-local\n\nFor this turn (turn 1 of 2), I should randomly pick one package and output its file structure. Let me pick randomly — I'll use $RANDOM or just pick one. Let me use a quick random selection."}}}}
|
||||
{"type":"assistant/chunk","seq":504,"time":1786073824907,"data":{"turn":1,"step":3,"chunk":{"type":"block-end","index":0,"block":{"type":"reasoning","text":"There are 4 packages:\n- client/ui-conversation\n- context/session-reference\n- llm/token-meter\n- skill/skill-filesystem\n\nFor this turn (turn 1 of 2), I should randomly pick one package and output its file structure. Let me pick randomly — I'll use $RANDOM or just pick one. Let me use a quick random selection."}}}}
|
||||
{"type":"assistant/chunk","seq":505,"time":1786073824908,"data":{"turn":1,"step":3,"chunk":{"type":"block-end","index":1,"block":{"type":"tool-call","id":"call_00_dAM4qfVp4LLtRCiJi7d71418","name":"bash","arguments":"{\"command\": \"find packages -maxdepth 2 -mindepth 2 -type d | sort | awk '{print NR\\\": \\\"$0}' && echo \\\"---random pick---\\\" && find packages -maxdepth 2 -mindepth 2 -type d | sort | shuf -n 1\", \"description\": \"Randomly pick one package directory\"}"}}}}
|
||||
{"type":"assistant/chunk","seq":506,"time":1786073824908,"data":{"turn":1,"step":3,"chunk":{"type":"usage","usage":{"inputTokens":156,"outputTokens":202,"cacheReadTokens":8448,"reasoningTokens":80}}}}
|
||||
{"type":"assistant/chunk","seq":507,"time":1786073824908,"data":{"turn":1,"step":3,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}
|
||||
{"type":"assistant/message","seq":508,"time":1786073824909,"data":{"turn":1,"step":3,"message":{"role":"assistant","content":[{"type":"reasoning","text":"There are 4 packages:\n- client/ui-conversation\n- context/session-reference\n- llm/token-meter\n- skill/skill-local\n\nFor this turn (turn 1 of 2), I should randomly pick one package and output its file structure. Let me pick randomly — I'll use $RANDOM or just pick one. Let me use a quick random selection."},{"type":"tool-call","id":"call_00_dAM4qfVp4LLtRCiJi7d71418","name":"bash","arguments":"{\"command\": \"find packages -maxdepth 2 -mindepth 2 -type d | sort | awk '{print NR\\\": \\\"$0}' && echo \\\"---random pick---\\\" && find packages -maxdepth 2 -mindepth 2 -type d | sort | shuf -n 1\", \"description\": \"Randomly pick one package directory\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"9e27c6d1-afa2-464c-b4c9-2ca7a44035f6"},"usage":{"inputTokens":156,"outputTokens":202,"cacheReadTokens":8448,"reasoningTokens":80}},"sourceEventSeqs":[341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507],"surfaceOp":"append"}
|
||||
{"type":"assistant/message","seq":508,"time":1786073824909,"data":{"turn":1,"step":3,"message":{"role":"assistant","content":[{"type":"reasoning","text":"There are 4 packages:\n- client/ui-conversation\n- context/session-reference\n- llm/token-meter\n- skill/skill-filesystem\n\nFor this turn (turn 1 of 2), I should randomly pick one package and output its file structure. Let me pick randomly — I'll use $RANDOM or just pick one. Let me use a quick random selection."},{"type":"tool-call","id":"call_00_dAM4qfVp4LLtRCiJi7d71418","name":"bash","arguments":"{\"command\": \"find packages -maxdepth 2 -mindepth 2 -type d | sort | awk '{print NR\\\": \\\"$0}' && echo \\\"---random pick---\\\" && find packages -maxdepth 2 -mindepth 2 -type d | sort | shuf -n 1\", \"description\": \"Randomly pick one package directory\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"9e27c6d1-afa2-464c-b4c9-2ca7a44035f6"},"usage":{"inputTokens":156,"outputTokens":202,"cacheReadTokens":8448,"reasoningTokens":80}},"sourceEventSeqs":[341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507],"surfaceOp":"append"}
|
||||
{"type":"tool/call","seq":509,"time":1786073824910,"data":{"turn":1,"step":3,"callId":"call_00_dAM4qfVp4LLtRCiJi7d71418","name":"bash","arguments":"{\"command\": \"find packages -maxdepth 2 -mindepth 2 -type d | sort | awk '{print NR\\\": \\\"$0}' && echo \\\"---random pick---\\\" && find packages -maxdepth 2 -mindepth 2 -type d | sort | shuf -n 1\", \"description\": \"Randomly pick one package directory\"}"}}
|
||||
{"type":"tool/result","seq":510,"time":1786073824937,"data":{"turn":1,"step":3,"message":{"source":{"kind":"tool","callId":"call_00_dAM4qfVp4LLtRCiJi7d71418"},"content":[{"type":"tool-result","toolCallId":"call_00_dAM4qfVp4LLtRCiJi7d71418","content":[{"type":"text","text":"1: packages/client/ui-conversation\n2: packages/context/session-reference\n3: packages/llm/token-meter\n4: packages/skill/skill-local\n---random pick---\n[stderr]\nbash: shuf: command not found\n[exit code: 127]"}],"isError":false}],"role":"user","id":"3227ba71-d0f0-4b4e-82e0-b01c6cd1ded1"}},"sourceEventSeqs":[509],"surfaceOp":"append"}
|
||||
{"type":"tool/result","seq":510,"time":1786073824937,"data":{"turn":1,"step":3,"message":{"source":{"kind":"tool","callId":"call_00_dAM4qfVp4LLtRCiJi7d71418"},"content":[{"type":"tool-result","toolCallId":"call_00_dAM4qfVp4LLtRCiJi7d71418","content":[{"type":"text","text":"1: packages/client/ui-conversation\n2: packages/context/session-reference\n3: packages/llm/token-meter\n4: packages/skill/skill-filesystem\n---random pick---\n[stderr]\nbash: shuf: command not found\n[exit code: 127]"}],"isError":false}],"role":"user","id":"3227ba71-d0f0-4b4e-82e0-b01c6cd1ded1"}},"sourceEventSeqs":[509],"surfaceOp":"append"}
|
||||
{"type":"step/end","seq":511,"time":1786073824938,"data":{"turn":1,"step":3}}
|
||||
{"type":"step/start","seq":512,"time":1786073824947,"data":{"turn":1,"step":4}}
|
||||
{"type":"assistant/chunk","seq":513,"time":1786073826168,"data":{"turn":1,"step":4,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}}}
|
||||
@@ -175,9 +175,9 @@
|
||||
{"type":"user/message","seq":1749,"time":1786073844598,"data":{"content":[{"type":"text","text":"<goal_complete>\nObjective: \"做两个turn,每个turn输出随机一个包的文件结构。注意你做完一个turn之后,直接输出内容,停止,我们的系统会帮你再开一个turn,你看着做一个类似的\"\nThe goal is marked complete and this autonomous run is ending. Write the closing message to the user now: state the outcome, summarize what was done and how it was verified, and point to the concrete results (files, commits, or other artifacts). Report only what earlier rounds and tool results in this session actually establish; when a detail is not in the session, say so instead of inventing it. Note anything the user should review or do next. Address the user directly. Do not call any more tools in this run; further work waits for the user's next instruction.\n</goal_complete>"}],"source":{"kind":"plugin","plugin":"tool-goal","form":"notice","summary":"complete: 做两个turn,每个turn输出随机一个包的文件结构。注意你做完一个turn之后,直接输出内容,停止,我们的系统会帮你再开一个turn,你看着做一个类似的"},"role":"user","id":"34261fc8-220c-40c0-819d-c9c0332bf965"},"surfaceOp":"append"}
|
||||
{"type":"assistant/chunk","seq":1750,"time":1786073845862,"data":{"turn":2,"step":6,"chunk":{"type":"block-start","index":0,"blockType":"text"}}}
|
||||
{"type":"text-chunks","seq0":1751,"time0":1786073845863,"data":{"turn":2,"step":6,"index":0,"dt":[22,1,0,0,22,1,0,0,0,22,0,0,0,0,0,24,0,25,0,0,0,22,1,0,19,1,0,0,23,0,0,27,0,20,0,0,25,0,1,0,0,0,21,0,1,0,0,23,0,0,0,0,0,24,0,0,0,0,0,0,24,0,0,0,0,0,20,0,1,0,0,27,0,0,0,1,20,0,0,1,0,24,0,1,0,0,0,19,0,0,0,0,0,24,0,0,0,0,0,24,1,0,0,0,0,20,0,0,0,0,24,0,0,0,0,24,0,0,1,0,0,23,0,0,0,0,0,23,1,0,0,0,0,22,0,0,1,0,0,22,1,0,0,0,24,1,0,0,0,0,26,0,0,0,1,21,0,0,0,0,24,0,0,0,0,0,26,0,0,0,0,0,20,20,24,23,1,24,0,22,0,45,3,1,0,25,1,23,0,0,0,0,25,0,0,1,17,0,23,26,1,0,0,23,0,0,23,0,22,28,1,0,0,0,0,23,0,0,0,0,1,23,0,1,0,0,0,21,0,1,0,22,0,0,0,23,0,0,24,22,25,21,38,1,0,10,24,27,1,0,0,26,0,0,0,1,0,19,21,27,0,0,29,0,0,0,0,0,23,20,0,21,25,1,54,0,0,30,0,0,0,0,22,24,1,0,25,0,1,19,24,0,24,1,0,23,1,22,0,0,22,1,25,21,0,22,23,28,0,23,1,0,0,0,22,0,0,0,0,0,24,0,1,0,0,0,18,24,26,1,0,20,23,24,1,26,0,1,0,39],"texts":["两个"," turn"," ","都","完成了"," ✅","\n\n","**","总结",":","**\n\n","-"," **","Turn"," ","1","**"," —"," ","随机","选中"," `","pack","ages","/","context","/s","ession","-reference","`",",","输","出了","文件","结构",":\n"," "," ```\n"," "," session","-reference","/\n"," "," ├","──"," READ","ME",".md","\n"," "," ├","──"," package",".json","\n"," "," ├","──"," src","/\n"," "," │"," "," ├","──"," index",".ts","\n"," "," │"," "," └","──"," uri",".ts","\n"," "," └","──"," tests","/\n"," "," └","──"," session","-reference",".s","pec",".ts","\n"," "," ```\n","-"," **","Turn"," ","2","**"," —"," ","随机","选中"," `","pack","ages","/","ll","m","/t","oken","-meter","`",",","输","出了","文件","结构",":\n"," "," ```\n"," "," token","-meter","/\n"," "," ├","──"," READ","ME",".md","\n"," "," ├","──"," package",".json","\n"," "," ├","──"," src","/\n"," "," │"," "," └","──"," index",".ts","\n"," "," └","──"," tests","/\n"," "," └","──"," token","-meter",".s","pec",".ts","\n"," "," ```\n\n","**","验证","方式",":","**"," ","两个","包的","随机","选择","都","通过"," `","python","3"," random",".choice","`"," ","从","工作","区的"," `","pack","ages","/","`"," ","目录","下","实际","枚举","的"," ","4"," ","个","候选","包","中","抽取","(","`","ui","-con","vers","ation","`","、","`","session","-reference","`","、","`","token","-meter","`","、","`","skill","-local","`","),","文件","结构","则","用"," `","find","`"," ","实际","列出","文件","后","整理","输出",",","均已","排除"," `","node","_modules","`"," ","和"," `.","git","`","。","第二次","随机","抽","到了","与"," turn"," ","1"," ","相同的","包",",","为避免","重复","换","抽","了","另一个","。\n\n","**","说明",":","**"," ","本轮","没有","产生","任何","文件","修改","或","提交","——","任务","本身就是","\"","输出","文件","结构","\",","所有","产物","都在","上面的","消息","文本","里","。\n\n","如果你","还想","看","剩下","两个","包","(","`","ui","-con","vers","ation","`","、","`","skill","-local","`",")","的结构",",","或者其他","格式","的输出","(","比如","带","文件","大小的","树","形","图","),","随时","告诉我","。"]}}
|
||||
{"type":"assistant/chunk","seq":2092,"time":1786073848306,"data":{"turn":2,"step":6,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"两个 turn 都完成了 ✅\n\n**总结:**\n\n- **Turn 1** — 随机选中 `packages/context/session-reference`,输出了文件结构:\n ```\n session-reference/\n ├── README.md\n ├── package.json\n ├── src/\n │ ├── index.ts\n │ └── uri.ts\n └── tests/\n └── session-reference.spec.ts\n ```\n- **Turn 2** — 随机选中 `packages/llm/token-meter`,输出了文件结构:\n ```\n token-meter/\n ├── README.md\n ├── package.json\n ├── src/\n │ └── index.ts\n └── tests/\n └── token-meter.spec.ts\n ```\n\n**验证方式:** 两个包的随机选择都通过 `python3 random.choice` 从工作区的 `packages/` 目录下实际枚举的 4 个候选包中抽取(`ui-conversation`、`session-reference`、`token-meter`、`skill-local`),文件结构则用 `find` 实际列出文件后整理输出,均已排除 `node_modules` 和 `.git`。第二次随机抽到了与 turn 1 相同的包,为避免重复换抽了另一个。\n\n**说明:** 本轮没有产生任何文件修改或提交——任务本身就是\"输出文件结构\",所有产物都在上面的消息文本里。\n\n如果你还想看剩下两个包(`ui-conversation`、`skill-local`)的结构,或者其他格式的输出(比如带文件大小的树形图),随时告诉我。"}}}}
|
||||
{"type":"assistant/chunk","seq":2092,"time":1786073848306,"data":{"turn":2,"step":6,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"两个 turn 都完成了 ✅\n\n**总结:**\n\n- **Turn 1** — 随机选中 `packages/context/session-reference`,输出了文件结构:\n ```\n session-reference/\n ├── README.md\n ├── package.json\n ├── src/\n │ ├── index.ts\n │ └── uri.ts\n └── tests/\n └── session-reference.spec.ts\n ```\n- **Turn 2** — 随机选中 `packages/llm/token-meter`,输出了文件结构:\n ```\n token-meter/\n ├── README.md\n ├── package.json\n ├── src/\n │ └── index.ts\n └── tests/\n └── token-meter.spec.ts\n ```\n\n**验证方式:** 两个包的随机选择都通过 `python3 random.choice` 从工作区的 `packages/` 目录下实际枚举的 4 个候选包中抽取(`ui-conversation`、`session-reference`、`token-meter`、`skill-filesystem`),文件结构则用 `find` 实际列出文件后整理输出,均已排除 `node_modules` 和 `.git`。第二次随机抽到了与 turn 1 相同的包,为避免重复换抽了另一个。\n\n**说明:** 本轮没有产生任何文件修改或提交——任务本身就是\"输出文件结构\",所有产物都在上面的消息文本里。\n\n如果你还想看剩下两个包(`ui-conversation`、`skill-filesystem`)的结构,或者其他格式的输出(比如带文件大小的树形图),随时告诉我。"}}}}
|
||||
{"type":"assistant/chunk","seq":2093,"time":1786073848307,"data":{"turn":2,"step":6,"chunk":{"type":"usage","usage":{"inputTokens":311,"outputTokens":348,"cacheReadTokens":10624,"reasoningTokens":0}}}}
|
||||
{"type":"assistant/chunk","seq":2094,"time":1786073848307,"data":{"turn":2,"step":6,"chunk":{"type":"finish","reason":{"kind":"stop"}}}}
|
||||
{"type":"assistant/message","seq":2095,"time":1786073848307,"data":{"turn":2,"step":6,"message":{"role":"assistant","content":[{"type":"text","text":"两个 turn 都完成了 ✅\n\n**总结:**\n\n- **Turn 1** — 随机选中 `packages/context/session-reference`,输出了文件结构:\n ```\n session-reference/\n ├── README.md\n ├── package.json\n ├── src/\n │ ├── index.ts\n │ └── uri.ts\n └── tests/\n └── session-reference.spec.ts\n ```\n- **Turn 2** — 随机选中 `packages/llm/token-meter`,输出了文件结构:\n ```\n token-meter/\n ├── README.md\n ├── package.json\n ├── src/\n │ └── index.ts\n └── tests/\n └── token-meter.spec.ts\n ```\n\n**验证方式:** 两个包的随机选择都通过 `python3 random.choice` 从工作区的 `packages/` 目录下实际枚举的 4 个候选包中抽取(`ui-conversation`、`session-reference`、`token-meter`、`skill-local`),文件结构则用 `find` 实际列出文件后整理输出,均已排除 `node_modules` 和 `.git`。第二次随机抽到了与 turn 1 相同的包,为避免重复换抽了另一个。\n\n**说明:** 本轮没有产生任何文件修改或提交——任务本身就是\"输出文件结构\",所有产物都在上面的消息文本里。\n\n如果你还想看剩下两个包(`ui-conversation`、`skill-local`)的结构,或者其他格式的输出(比如带文件大小的树形图),随时告诉我。"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"5a1daadd-6f23-49ea-980b-6f96f67e3f52"},"usage":{"inputTokens":311,"outputTokens":348,"cacheReadTokens":10624,"reasoningTokens":0}},"sourceEventSeqs":[1750,1751,1752,1753,1754,1755,1756,1757,1758,1759,1760,1761,1762,1763,1764,1765,1766,1767,1768,1769,1770,1771,1772,1773,1774,1775,1776,1777,1778,1779,1780,1781,1782,1783,1784,1785,1786,1787,1788,1789,1790,1791,1792,1793,1794,1795,1796,1797,1798,1799,1800,1801,1802,1803,1804,1805,1806,1807,1808,1809,1810,1811,1812,1813,1814,1815,1816,1817,1818,1819,1820,1821,1822,1823,1824,1825,1826,1827,1828,1829,1830,1831,1832,1833,1834,1835,1836,1837,1838,1839,1840,1841,1842,1843,1844,1845,1846,1847,1848,1849,1850,1851,1852,1853,1854,1855,1856,1857,1858,1859,1860,1861,1862,1863,1864,1865,1866,1867,1868,1869,1870,1871,1872,1873,1874,1875,1876,1877,1878,1879,1880,1881,1882,1883,1884,1885,1886,1887,1888,1889,1890,1891,1892,1893,1894,1895,1896,1897,1898,1899,1900,1901,1902,1903,1904,1905,1906,1907,1908,1909,1910,1911,1912,1913,1914,1915,1916,1917,1918,1919,1920,1921,1922,1923,1924,1925,1926,1927,1928,1929,1930,1931,1932,1933,1934,1935,1936,1937,1938,1939,1940,1941,1942,1943,1944,1945,1946,1947,1948,1949,1950,1951,1952,1953,1954,1955,1956,1957,1958,1959,1960,1961,1962,1963,1964,1965,1966,1967,1968,1969,1970,1971,1972,1973,1974,1975,1976,1977,1978,1979,1980,1981,1982,1983,1984,1985,1986,1987,1988,1989,1990,1991,1992,1993,1994,1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021,2022,2023,2024,2025,2026,2027,2028,2029,2030,2031,2032,2033,2034,2035,2036,2037,2038,2039,2040,2041,2042,2043,2044,2045,2046,2047,2048,2049,2050,2051,2052,2053,2054,2055,2056,2057,2058,2059,2060,2061,2062,2063,2064,2065,2066,2067,2068,2069,2070,2071,2072,2073,2074,2075,2076,2077,2078,2079,2080,2081,2082,2083,2084,2085,2086,2087,2088,2089,2090,2091,2092,2093,2094],"surfaceOp":"append"}
|
||||
{"type":"assistant/message","seq":2095,"time":1786073848307,"data":{"turn":2,"step":6,"message":{"role":"assistant","content":[{"type":"text","text":"两个 turn 都完成了 ✅\n\n**总结:**\n\n- **Turn 1** — 随机选中 `packages/context/session-reference`,输出了文件结构:\n ```\n session-reference/\n ├── README.md\n ├── package.json\n ├── src/\n │ ├── index.ts\n │ └── uri.ts\n └── tests/\n └── session-reference.spec.ts\n ```\n- **Turn 2** — 随机选中 `packages/llm/token-meter`,输出了文件结构:\n ```\n token-meter/\n ├── README.md\n ├── package.json\n ├── src/\n │ └── index.ts\n └── tests/\n └── token-meter.spec.ts\n ```\n\n**验证方式:** 两个包的随机选择都通过 `python3 random.choice` 从工作区的 `packages/` 目录下实际枚举的 4 个候选包中抽取(`ui-conversation`、`session-reference`、`token-meter`、`skill-filesystem`),文件结构则用 `find` 实际列出文件后整理输出,均已排除 `node_modules` 和 `.git`。第二次随机抽到了与 turn 1 相同的包,为避免重复换抽了另一个。\n\n**说明:** 本轮没有产生任何文件修改或提交——任务本身就是\"输出文件结构\",所有产物都在上面的消息文本里。\n\n如果你还想看剩下两个包(`ui-conversation`、`skill-filesystem`)的结构,或者其他格式的输出(比如带文件大小的树形图),随时告诉我。"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"5a1daadd-6f23-49ea-980b-6f96f67e3f52"},"usage":{"inputTokens":311,"outputTokens":348,"cacheReadTokens":10624,"reasoningTokens":0}},"sourceEventSeqs":[1750,1751,1752,1753,1754,1755,1756,1757,1758,1759,1760,1761,1762,1763,1764,1765,1766,1767,1768,1769,1770,1771,1772,1773,1774,1775,1776,1777,1778,1779,1780,1781,1782,1783,1784,1785,1786,1787,1788,1789,1790,1791,1792,1793,1794,1795,1796,1797,1798,1799,1800,1801,1802,1803,1804,1805,1806,1807,1808,1809,1810,1811,1812,1813,1814,1815,1816,1817,1818,1819,1820,1821,1822,1823,1824,1825,1826,1827,1828,1829,1830,1831,1832,1833,1834,1835,1836,1837,1838,1839,1840,1841,1842,1843,1844,1845,1846,1847,1848,1849,1850,1851,1852,1853,1854,1855,1856,1857,1858,1859,1860,1861,1862,1863,1864,1865,1866,1867,1868,1869,1870,1871,1872,1873,1874,1875,1876,1877,1878,1879,1880,1881,1882,1883,1884,1885,1886,1887,1888,1889,1890,1891,1892,1893,1894,1895,1896,1897,1898,1899,1900,1901,1902,1903,1904,1905,1906,1907,1908,1909,1910,1911,1912,1913,1914,1915,1916,1917,1918,1919,1920,1921,1922,1923,1924,1925,1926,1927,1928,1929,1930,1931,1932,1933,1934,1935,1936,1937,1938,1939,1940,1941,1942,1943,1944,1945,1946,1947,1948,1949,1950,1951,1952,1953,1954,1955,1956,1957,1958,1959,1960,1961,1962,1963,1964,1965,1966,1967,1968,1969,1970,1971,1972,1973,1974,1975,1976,1977,1978,1979,1980,1981,1982,1983,1984,1985,1986,1987,1988,1989,1990,1991,1992,1993,1994,1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021,2022,2023,2024,2025,2026,2027,2028,2029,2030,2031,2032,2033,2034,2035,2036,2037,2038,2039,2040,2041,2042,2043,2044,2045,2046,2047,2048,2049,2050,2051,2052,2053,2054,2055,2056,2057,2058,2059,2060,2061,2062,2063,2064,2065,2066,2067,2068,2069,2070,2071,2072,2073,2074,2075,2076,2077,2078,2079,2080,2081,2082,2083,2084,2085,2086,2087,2088,2089,2090,2091,2092,2093,2094],"surfaceOp":"append"}
|
||||
{"type":"step/end","seq":2096,"time":1786073848308,"data":{"turn":2,"step":6}}
|
||||
{"type":"turn/end","seq":2097,"time":1786073848308,"data":{"turn":2,"reason":{"kind":"completed"}}}
|
||||
|
||||
@@ -175,7 +175,7 @@
|
||||
- text: 、
|
||||
- code: token-meter
|
||||
- text: 、
|
||||
- code: skill-local
|
||||
- code: skill-filesystem
|
||||
- text: ),文件结构则用
|
||||
- code: find
|
||||
- text: 实际列出文件后整理输出,均已排除
|
||||
@@ -190,7 +190,7 @@
|
||||
- text: 如果你还想看剩下两个包(
|
||||
- code: ui-conversation
|
||||
- text: 、
|
||||
- code: skill-local
|
||||
- code: skill-filesystem
|
||||
- text: )的结构,或者其他格式的输出(比如带文件大小的树形图),随时告诉我。
|
||||
- button "Copy":
|
||||
- img
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -45,10 +45,10 @@
|
||||
- text: Context injection AGENTS.md
|
||||
- img
|
||||
- text: permission preset read-only
|
||||
- 'button "feedback Feedback recorded for session {{seededId}} User: {{uuid}}. Session sharing is not configured." [expanded]':
|
||||
- 'button "feedback Feedback recorded for session {{seededId}} Anonymous user: {{uuid}}. Session sharing is not configured." [expanded]':
|
||||
- img
|
||||
- text: "feedback Feedback recorded for session {{seededId}} User: {{uuid}}. Session sharing is not configured."
|
||||
- text: "Feedback recorded for session {{seededId}} User: {{uuid}}. Session sharing is not configured."
|
||||
- text: "feedback Feedback recorded for session {{seededId}} Anonymous user: {{uuid}}. Session sharing is not configured."
|
||||
- text: "Feedback recorded for session {{seededId}} Anonymous user: {{uuid}}. Session sharing is not configured."
|
||||
- textbox "Message the agent"
|
||||
- button "Commands":
|
||||
- img
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
- img
|
||||
- text: workspace
|
||||
- treeitem "New Session" [selected]
|
||||
- treeitem "1 subagent running Delegate a background task. now"
|
||||
- treeitem "1 subagent running Delegate a background job. now"
|
||||
|
||||
@@ -1 +1 @@
|
||||
You are interacting with the user through the DeepSeek Harness Web GUI at {{webUrl}}. When the user refers to "this page", "this GUI", or "this app" without naming another target, they mean this GUI. The browser provides no implicit DOM, route, or screenshot context. The client-plugin HMR receiver is active, but client-plugin changes reload without a refresh only while `pnpm run dev:web` is also running from this same checkout to rebuild their bundles; verify that watcher before promising automatic updates. Every other change — the apps/web shell and plain packages — requires rebuilding the affected Web artifacts and verifying this existing URL after a page refresh. Starting another server does not update this GUI. The apps/web Vite entry builds the shell but is not a standalone application because only dsh web injects window.__DSH_BOOT__. Do not start a replacement server unless the user asks; if one is needed, use a managed background task and verify its exact URL.
|
||||
You are interacting with the user through the DeepSeek Harness Web GUI at {{webUrl}}. When the user refers to "this page", "this GUI", or "this app" without naming another target, they mean this GUI. The browser provides no implicit DOM, route, or screenshot context. The client-plugin HMR receiver is active, but client-plugin changes reload without a refresh only while `pnpm run dev:web` is also running from this same checkout to rebuild their bundles; verify that watcher before promising automatic updates. Every other change — the apps/web shell and plain packages — requires rebuilding the affected Web artifacts and verifying this existing URL after a page refresh. Starting another server does not update this GUI. The apps/web Vite entry builds the shell but is not a standalone application because only dsh web injects window.__DSH_BOOT__. Do not start a replacement server unless the user asks; if one is needed, use a managed background job and verify its exact URL.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Web e2e scenario: startup auto-selection keeps the hero on screen.
|
||||
//
|
||||
// A page load with a workspace already registered runs
|
||||
// `WorkspacesService.startInitialSelection`: it connects the most recent
|
||||
// `WorkspaceRuntime.startInitialSelection`: it connects the most recent
|
||||
// workspace and opens its blank session. `openState` flips to `loading` the
|
||||
// moment `open()` lands; driving `data-phase=settling` on the conversation
|
||||
// root from that flip would hide the composer seat and the header
|
||||
|
||||
@@ -70,7 +70,7 @@ describe('web e2e: workspace management (create / rename / flat view / hover aff
|
||||
await dialog.getByRole('button', { name: 'Open', exact: true }).click()
|
||||
await dialog.waitFor({ state: 'hidden', timeout: 10_000 })
|
||||
await expect.poll(
|
||||
() => scaffold.ctx.workspace.resolveByPath(join(parent, name)),
|
||||
() => scaffold.ctx.workspaceRegistry.resolveByPath(join(parent, name)),
|
||||
{ timeout: 10_000 },
|
||||
).not.toBeUndefined()
|
||||
}
|
||||
@@ -86,7 +86,7 @@ describe('web e2e: workspace management (create / rename / flat view / hover aff
|
||||
await dialog.getByRole('button', { name: 'Open', exact: true }).click()
|
||||
await dialog.waitFor({ state: 'hidden', timeout: 10_000 })
|
||||
await expect.poll(
|
||||
() => scaffold.ctx.workspace.resolveByPath(path),
|
||||
() => scaffold.ctx.workspaceRegistry.resolveByPath(path),
|
||||
{ timeout: 10_000 },
|
||||
).not.toBeUndefined()
|
||||
// First adoption births a blank Session+Agent whose workspace attach must
|
||||
@@ -143,7 +143,7 @@ describe('web e2e: workspace management (create / rename / flat view / hover aff
|
||||
await add('beta-ws')
|
||||
// Durable on the host: both registered, newest first (create prepends),
|
||||
// each titled after the folder the dialog made.
|
||||
const titles = scaffold.ctx.workspace.list().map(workspace => workspace.title)
|
||||
const titles = scaffold.ctx.workspaceRegistry.list().map(workspace => workspace.title)
|
||||
expect(titles.slice(0, 2)).toEqual(['beta-ws', 'alpha-ws'])
|
||||
expect(tripwire.pageErrors).toEqual([])
|
||||
}, 90_000)
|
||||
@@ -169,7 +169,7 @@ describe('web e2e: workspace management (create / rename / flat view / hover aff
|
||||
await expect.poll(() => page.getByText('gamma-ws', { exact: true }).count(), { timeout: 10_000 }).toBeGreaterThanOrEqual(1)
|
||||
expect(await page.getByText('alpha-ws', { exact: true }).count()).toBe(0)
|
||||
// Host durability, then reload: the projection is rebuilt from the wire.
|
||||
expect(scaffold.ctx.workspace.list().map(workspace => workspace.title)).toContain('gamma-ws')
|
||||
expect(scaffold.ctx.workspaceRegistry.list().map(workspace => workspace.title)).toContain('gamma-ws')
|
||||
const warningStart = tripwire.warnings.length
|
||||
await page.reload({ waitUntil: 'load' })
|
||||
await page.waitForSelector('[class*="frame"]', { timeout: 30_000 })
|
||||
@@ -207,7 +207,7 @@ describe('web e2e: workspace management (create / rename / flat view / hover aff
|
||||
})
|
||||
// Register the scaffold's existing project directory through the real UI.
|
||||
await adoptDirectory(scaffold.workspaceCwd, { waitForAgent: true })
|
||||
const workspace = await scaffold.ctx.workspace.resolveByPath(scaffold.workspaceCwd)
|
||||
const workspace = await scaffold.ctx.workspaceRegistry.resolveByPath(scaffold.workspaceCwd)
|
||||
if (workspace === undefined) throw new Error('GUI did not register the existing project directory')
|
||||
await workspace.attachSession(SessionId(SEED_ID))
|
||||
const header = (await scaffold.ctx.sessionPersistence.list())
|
||||
@@ -248,7 +248,7 @@ describe('web e2e: workspace management (create / rename / flat view / hover aff
|
||||
await dialog.getByRole('button', { name: 'Delete workspace' }).click()
|
||||
await expect.poll(() => dialog.count(), { timeout: 10_000 }).toBe(0)
|
||||
|
||||
expect(scaffold.ctx.workspace.get(workspace.id)).toBeUndefined()
|
||||
expect(scaffold.ctx.workspaceRegistry.get(workspace.id)).toBeUndefined()
|
||||
await expect.poll(
|
||||
() => page.getByRole('button', { name: `Workspace actions for ${workspace.title}` }).count(),
|
||||
{ timeout: 10_000 },
|
||||
@@ -270,10 +270,10 @@ describe('web e2e: workspace management (create / rename / flat view / hover aff
|
||||
// (no cwd-based blank reuse exists, so the account is never empty).
|
||||
await adoptDirectory(scaffold.workspaceCwd)
|
||||
await expect.poll(
|
||||
() => scaffold.ctx.workspace.resolveByPath(scaffold.workspaceCwd),
|
||||
() => scaffold.ctx.workspaceRegistry.resolveByPath(scaffold.workspaceCwd),
|
||||
{ timeout: 10_000 },
|
||||
).not.toBeUndefined()
|
||||
const reregistered = await scaffold.ctx.workspace.resolveByPath(scaffold.workspaceCwd)
|
||||
const reregistered = await scaffold.ctx.workspaceRegistry.resolveByPath(scaffold.workspaceCwd)
|
||||
expect(reregistered?.id).toBeDefined()
|
||||
expect(reregistered?.id).not.toBe(workspace.id)
|
||||
await expect.poll(
|
||||
@@ -289,7 +289,7 @@ describe('web e2e: workspace management (create / rename / flat view / hover aff
|
||||
// Restore the deleted-registry state so reload still verifies deletion
|
||||
// persistence independently of the successful re-registration above.
|
||||
if (reregistered === undefined) throw new Error('same-path re-registration did not materialize')
|
||||
await scaffold.ctx.workspace.delete(reregistered.id)
|
||||
await scaffold.ctx.workspaceRegistry.delete(reregistered.id)
|
||||
await expect.poll(
|
||||
() => page.getByRole('button', { name: `Workspace actions for ${reregistered.title}` }).count(),
|
||||
{ timeout: 10_000 },
|
||||
@@ -305,7 +305,7 @@ describe('web e2e: workspace management (create / rename / flat view / hover aff
|
||||
() => page.locator('[role="treeitem"][aria-selected="true"]').count(),
|
||||
{ timeout: 15_000 },
|
||||
).toBe(1)
|
||||
expect(scaffold.ctx.workspace.get(workspace.id)).toBeUndefined()
|
||||
expect(scaffold.ctx.workspaceRegistry.get(workspace.id)).toBeUndefined()
|
||||
expect(await readFile(join(scaffold.workspaceCwd, 'workspace', 'a.txt'), 'utf8')).toBe('alpha\n')
|
||||
await stat(logLocation.path)
|
||||
expect((await scaffold.ctx.sessionPersistence.inspect(SessionId(SEED_ID))).events.length).toBeGreaterThan(0)
|
||||
@@ -344,10 +344,10 @@ describe('web e2e: workspace management (create / rename / flat view / hover aff
|
||||
|
||||
await adoptDirectory(oldPath)
|
||||
await expect.poll(
|
||||
() => scaffold.ctx.workspace.resolveByPath(oldPath),
|
||||
() => scaffold.ctx.workspaceRegistry.resolveByPath(oldPath),
|
||||
{ timeout: 10_000 },
|
||||
).not.toBeUndefined()
|
||||
const oldWorkspace = await scaffold.ctx.workspace.resolveByPath(oldPath)
|
||||
const oldWorkspace = await scaffold.ctx.workspaceRegistry.resolveByPath(oldPath)
|
||||
if (oldWorkspace === undefined) throw new Error('old same-name Workspace was not registered')
|
||||
|
||||
const oldRow = page.locator('[role="treeitem"]').filter({ hasText: title }).first()
|
||||
@@ -355,10 +355,10 @@ describe('web e2e: workspace management (create / rename / flat view / hover aff
|
||||
await page.getByRole('menuitem', { name: 'Delete workspace' }).click()
|
||||
await page.getByRole('dialog', { name: 'Delete workspace' })
|
||||
.getByRole('button', { name: 'Delete workspace' }).click()
|
||||
await expect.poll(() => scaffold.ctx.workspace.get(oldWorkspace.id), { timeout: 10_000 }).toBeUndefined()
|
||||
await expect.poll(() => scaffold.ctx.workspaceRegistry.get(oldWorkspace.id), { timeout: 10_000 }).toBeUndefined()
|
||||
|
||||
await addNewFolderWorkspace(scaffold.workspaceCwd, title)
|
||||
const fresh = scaffold.ctx.workspace.list().find(workspace => workspace.title === title)
|
||||
const fresh = scaffold.ctx.workspaceRegistry.list().find(workspace => workspace.title === title)
|
||||
expect(fresh?.id).toBeDefined()
|
||||
expect(fresh?.id).not.toBe(oldWorkspace.id)
|
||||
expect(fresh?.path).toBe(join(scaffold.workspaceCwd, title))
|
||||
@@ -581,7 +581,7 @@ describe('web e2e: workspace management (create / rename / flat view / hover aff
|
||||
await expect.poll(() => page.getByText('Ungrouped', { exact: true }).count(), { timeout: 10_000 }).toBe(0)
|
||||
// Durable on the host: the registry-global set carries the id while the
|
||||
// session log itself stays in persistence untouched.
|
||||
expect([...scaffold.ctx.workspace.archivedSessionIds]).toEqual([SessionId(SEED_ID)])
|
||||
expect([...scaffold.ctx.workspaceRegistry.archivedSessionIds]).toEqual([SessionId(SEED_ID)])
|
||||
expect((await scaffold.ctx.sessionPersistence.list()).map(header => header.id)).toContain(SessionId(SEED_ID))
|
||||
// Reload: the hidden state is rebuilt from the workspace.list baseline.
|
||||
const warningStart = tripwire.warnings.length
|
||||
@@ -606,7 +606,7 @@ describe('web e2e: workspace management (create / rename / flat view / hover aff
|
||||
await adoptDirectory(firstPath, { waitForAgent: true })
|
||||
await adoptDirectory(secondPath, { waitForAgent: true })
|
||||
|
||||
const matchingWorkspaces = scaffold.ctx.workspace.list()
|
||||
const matchingWorkspaces = scaffold.ctx.workspaceRegistry.list()
|
||||
.filter(workspace => workspace.title === 'xx')
|
||||
expect(matchingWorkspaces.map(workspace => workspace.path).sort())
|
||||
.toEqual([firstPath, secondPath].sort())
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
"tests/subagent-interrupt.e2e.ts",
|
||||
"tests/subagent-interrupt-ui.e2e.ts",
|
||||
"tests/sidebar-subagent-activity.e2e.ts",
|
||||
"tests/background-task-list.e2e.ts",
|
||||
"tests/background-job-list.e2e.ts",
|
||||
"tests/bash-abort-row.e2e.ts",
|
||||
"tests/skill-tool-row.e2e.ts",
|
||||
"tests/turn-tail-actions.e2e.ts",
|
||||
|
||||
Reference in New Issue
Block a user