better-dsh 0.2.3 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cordis.patch.yml +1 -1
- package/docs/50_test-reports/2026-09-06-write/345/267/245/345/205/267sandbox/345/215/207/347/272/247/351/200/217/344/274/240bug/345/244/215/345/217/221/345/217/212/346/214/202/350/265/267-/344/272/213/344/273/266/346/212/245/345/221/212.md +176 -0
- package/docs/50_test-reports/2026-09-08-hashline-edit-E_RANGE_UNVERIFIED/350/267/250/350/275/256/344/274/232/350/257/235/351/224/256/345/244/261/346/225/210-/350/257/212/346/226/255/346/212/245/345/221/212.md +226 -0
- package/docs/50_test-reports/2026-09-11-control-prompt-into-eval-description/345/256/236/346/265/213/346/212/245/345/221/212.md +222 -0
- package/docs/50_test-reports/2026-09-12-fs-scheme-resolution-/345/256/236/346/265/213/346/212/245/345/221/212.md +81 -0
- package/docs/50_test-reports/2026-09-12-url-schemes-grammar-matrix/344/270/216catalog-centralize-/345/256/236/346/265/213/346/212/245/345/221/212.md +234 -0
- package/docs/50_test-reports/2026-09-12-url-schemes-recallable-context-design/351/252/214/350/257/201/346/212/245/345/221/212.md +160 -0
- package/docs/50_test-reports/2026-09-12-url-schemes-recallable-context-/345/256/236/346/265/213/345/211/247/346/234/254.md +44 -0
- package/docs/50_test-reports/2026-09-12-url-schemes-recallable-context-/345/256/236/346/265/213/346/212/245/345/221/212.md +89 -0
- package/docs/50_test-reports/2026-09-12-url-schemes-/345/205/255scheme/345/206/222/347/203/237/344/270/216/350/276/271/347/225/214/345/256/236/346/265/213/346/212/245/345/221/212.md +198 -0
- package/docs/50_test-reports/2026-09-13-hashline-off/344/270/213scheme/345/217/257/350/276/276/346/200/247/345/267/245/345/205/267/351/235/242/344/270/215/345/257/271/347/247/260-/345/256/236/346/265/213/346/212/245/345/221/212.md +246 -0
- package/docs/50_test-reports/2026-09-13-preact-ui-shell/345/256/236/346/265/213/346/212/245/345/221/212.md +50 -0
- package/docs/50_test-reports/2026-09-14-4999-skill/346/270/205/345/215/225/344/270/216lsp-gate/345/256/236/346/265/213/346/212/245/345/221/212.md +63 -0
- package/docs/50_test-reports/upstream-dsh-0.1.3-alpha.2-local-test-report.md +44 -0
- package/docs/50_test-reports/upstream-dsh-0.1.3-alpha.2-report.md +110 -0
- package/docs/50_test-reports/upstream-dsh-0.1.5-rc.2-local-test-report.md +79 -0
- package/docs/50_test-reports/v0.2.3b-hashline-content-locator/345/256/236/346/265/213/346/212/245/345/221/212.md +73 -0
- package/docs/50_test-reports/v0.2.3c-mobile-wave/345/256/236/346/265/213/346/212/245/345/221/212.md +47 -0
- package/docs/50_test-reports/v0.2.4-ios-focus-zoom-suppression/345/256/236/346/265/213/346/212/245/345/221/212.md +158 -0
- package/docs/specs/agent/spec.md +54 -0
- package/docs/specs/ast/spec.md +34 -0
- package/docs/specs/compaction-recall/spec.md +46 -0
- package/docs/specs/ctx/spec.md +107 -0
- package/docs/specs/dsh/spec.md +47 -0
- package/docs/specs/dvc/spec.md +87 -0
- package/docs/specs/escalation-guidance/spec.md +44 -0
- package/docs/specs/fs-scheme-resolution/spec.md +37 -0
- package/docs/specs/hash-edit/spec.md +41 -0
- package/docs/specs/http-read/spec.md +73 -0
- package/docs/specs/kernel-provisioning/spec.md +53 -0
- package/docs/specs/lsp/spec.md +121 -0
- package/docs/specs/mobile-layout/spec.md +108 -0
- package/docs/specs/model-failover/spec.md +20 -0
- package/docs/specs/preact-ui-shell/spec.md +22 -0
- package/docs/specs/repl-dispatch-resilience/spec.md +21 -0
- package/docs/specs/skill/spec.md +58 -0
- package/docs/specs/tool-surface/spec.md +222 -0
- package/docs/specs/url-schema/spec.md +148 -0
- package/docs/specs/web-trust-fence/spec.md +43 -0
- package/docs/upstream-dsh-0.1.5-rc.2-report.md +156 -0
- package/dsh-docs/AGENTS.md +75 -0
- package/dsh-docs/agent-lifecycle.md +84 -0
- package/dsh-docs/agent-lifecycle.zh.md +86 -0
- package/dsh-docs/api-gateway.md +164 -0
- package/dsh-docs/api-gateway.zh.md +164 -0
- package/dsh-docs/architecture.md +150 -0
- package/dsh-docs/architecture.zh.md +154 -0
- package/dsh-docs/capability-seams.md +543 -0
- package/dsh-docs/capability-seams.zh.md +545 -0
- package/dsh-docs/config-catalog.md +3473 -0
- package/dsh-docs/config-catalog.zh.md +3474 -0
- package/dsh-docs/cookbook/adding-a-package.md +117 -0
- package/dsh-docs/cookbook/adding-a-package.zh.md +119 -0
- package/dsh-docs/cookbook/adding-a-remote-api.md +197 -0
- package/dsh-docs/cookbook/adding-a-remote-api.zh.md +197 -0
- package/dsh-docs/cookbook/adding-a-session-format-version.md +109 -0
- package/dsh-docs/cookbook/adding-a-session-format-version.zh.md +109 -0
- package/dsh-docs/cookbook/adding-a-settings-card.md +102 -0
- package/dsh-docs/cookbook/adding-a-settings-card.zh.md +102 -0
- package/dsh-docs/cookbook/adding-a-tool.md +101 -0
- package/dsh-docs/cookbook/adding-a-tool.zh.md +103 -0
- package/dsh-docs/cookbook/adding-a-vendored-package.md +59 -0
- package/dsh-docs/cookbook/adding-a-vendored-package.zh.md +59 -0
- package/dsh-docs/cookbook/adding-an-llm-adapter.md +43 -0
- package/dsh-docs/cookbook/adding-an-llm-adapter.zh.md +43 -0
- package/dsh-docs/cookbook/extension-cookbook.md +132 -0
- package/dsh-docs/cookbook/extension-cookbook.zh.md +136 -0
- package/dsh-docs/cookbook/maintaining-dsh-code-review.md +64 -0
- package/dsh-docs/cookbook/maintaining-dsh-code-review.zh.md +64 -0
- package/dsh-docs/cookbook/responding-to-pr-review-on-a-stack.md +32 -0
- package/dsh-docs/cookbook/responding-to-pr-review-on-a-stack.zh.md +32 -0
- package/dsh-docs/cordis-api/context.md +364 -0
- package/dsh-docs/cordis-api/context.zh.md +366 -0
- package/dsh-docs/cordis-api/events.md +207 -0
- package/dsh-docs/cordis-api/events.zh.md +209 -0
- package/dsh-docs/cordis-api/fiber.md +375 -0
- package/dsh-docs/cordis-api/fiber.zh.md +377 -0
- package/dsh-docs/cordis-api/inherited.md +39 -0
- package/dsh-docs/cordis-api/registry.md +152 -0
- package/dsh-docs/cordis-api/registry.zh.md +154 -0
- package/dsh-docs/cordis-api/service.md +102 -0
- package/dsh-docs/cordis-api/service.zh.md +104 -0
- package/dsh-docs/cordis-primer.md +45 -0
- package/dsh-docs/cordis-primer.zh.md +51 -0
- package/dsh-docs/cordis-tutorial/01-first-plugin.md +95 -0
- package/dsh-docs/cordis-tutorial/01-first-plugin.zh.md +95 -0
- package/dsh-docs/cordis-tutorial/02-lifecycle-and-effects.md +98 -0
- package/dsh-docs/cordis-tutorial/02-lifecycle-and-effects.zh.md +98 -0
- package/dsh-docs/cordis-tutorial/03-services.md +98 -0
- package/dsh-docs/cordis-tutorial/03-services.zh.md +98 -0
- package/dsh-docs/cordis-tutorial/04-events.md +144 -0
- package/dsh-docs/cordis-tutorial/04-events.zh.md +144 -0
- package/dsh-docs/cordis-tutorial/05-config.md +84 -0
- package/dsh-docs/cordis-tutorial/05-config.zh.md +84 -0
- package/dsh-docs/cordis-tutorial/06-composition-and-hmr.md +113 -0
- package/dsh-docs/cordis-tutorial/06-composition-and-hmr.zh.md +113 -0
- package/dsh-docs/cordis-tutorial/07-into-the-harness.md +108 -0
- package/dsh-docs/cordis-tutorial/07-into-the-harness.zh.md +108 -0
- package/dsh-docs/cordis-tutorial/index.md +60 -0
- package/dsh-docs/cordis-tutorial/index.zh.md +62 -0
- package/dsh-docs/deepseek-llm-api-wire-extensions.md +163 -0
- package/dsh-docs/deepseek-llm-api-wire-extensions.zh.md +163 -0
- package/dsh-docs/defensive-patterns.md +33 -0
- package/dsh-docs/defensive-patterns.zh.md +35 -0
- package/dsh-docs/development.md +167 -0
- package/dsh-docs/development.zh.md +173 -0
- package/dsh-docs/event-producer-consumer.md +86 -0
- package/dsh-docs/event-producer-consumer.zh.md +88 -0
- package/dsh-docs/glossary.md +45 -0
- package/dsh-docs/glossary.zh.md +45 -0
- package/dsh-docs/graph-atlas.md +22 -0
- package/dsh-docs/graph-atlas.zh.md +24 -0
- package/dsh-docs/i18n/README.md +60 -0
- package/dsh-docs/i18n/README.zh.md +62 -0
- package/dsh-docs/i18n/style-samples.md +87 -0
- package/dsh-docs/i18n/terminology.md +214 -0
- package/dsh-docs/i18n/translation-prompt.md +263 -0
- package/dsh-docs/i18n/translation-rules.md +69 -0
- package/dsh-docs/i18n/translation-rules.zh.md +69 -0
- package/dsh-docs/module-graph.md +1411 -0
- package/dsh-docs/module-graph.zh.md +1413 -0
- package/dsh-docs/persistence-catalog.md +1075 -0
- package/dsh-docs/persistence-catalog.zh.md +1077 -0
- package/dsh-docs/postmortem/0001-acp-default-export-drops-inject.md +113 -0
- package/dsh-docs/postmortem/0001-acp-default-export-drops-inject.zh.md +113 -0
- package/dsh-docs/postmortem/0002-js-expression-disabled-filesystem-tools.md +47 -0
- package/dsh-docs/postmortem/0002-js-expression-disabled-filesystem-tools.zh.md +47 -0
- package/dsh-docs/postmortem/0003-web-agent-gui-feedback-loop.md +53 -0
- package/dsh-docs/postmortem/0003-web-agent-gui-feedback-loop.zh.md +53 -0
- package/dsh-docs/postmortem/0004-landlock-partial-notice-misclassified-child-failures.md +55 -0
- package/dsh-docs/postmortem/0004-landlock-partial-notice-misclassified-child-failures.zh.md +55 -0
- package/dsh-docs/postmortem/README.md +18 -0
- package/dsh-docs/postmortem/README.zh.md +18 -0
- package/dsh-docs/rescope.md +53 -0
- package/dsh-docs/rescope.zh.md +53 -0
- package/dsh-docs/session-format-status.md +47 -0
- package/dsh-docs/session-format-status.zh.md +47 -0
- package/dsh-docs/subsystems/README.md +61 -0
- package/dsh-docs/subsystems/README.zh.md +61 -0
- package/dsh-docs/subsystems/agent-team.md +207 -0
- package/dsh-docs/subsystems/agent-team.zh.md +207 -0
- package/dsh-docs/subsystems/approval.md +170 -0
- package/dsh-docs/subsystems/approval.zh.md +170 -0
- package/dsh-docs/subsystems/attachment.md +351 -0
- package/dsh-docs/subsystems/attachment.zh.md +351 -0
- package/dsh-docs/subsystems/client-modules.md +168 -0
- package/dsh-docs/subsystems/client-modules.zh.md +168 -0
- package/dsh-docs/subsystems/client-resources.md +91 -0
- package/dsh-docs/subsystems/client-resources.zh.md +91 -0
- package/dsh-docs/subsystems/code-runtime.md +195 -0
- package/dsh-docs/subsystems/code-runtime.zh.md +195 -0
- package/dsh-docs/subsystems/commands.md +219 -0
- package/dsh-docs/subsystems/commands.zh.md +219 -0
- package/dsh-docs/subsystems/compaction.md +238 -0
- package/dsh-docs/subsystems/compaction.zh.md +238 -0
- package/dsh-docs/subsystems/conversation.md +258 -0
- package/dsh-docs/subsystems/conversation.zh.md +258 -0
- package/dsh-docs/subsystems/core.md +1209 -0
- package/dsh-docs/subsystems/core.zh.md +1219 -0
- package/dsh-docs/subsystems/credentials.md +329 -0
- package/dsh-docs/subsystems/credentials.zh.md +329 -0
- package/dsh-docs/subsystems/extensions.md +382 -0
- package/dsh-docs/subsystems/extensions.zh.md +382 -0
- package/dsh-docs/subsystems/feedback.md +266 -0
- package/dsh-docs/subsystems/feedback.zh.md +266 -0
- package/dsh-docs/subsystems/filesystem.md +505 -0
- package/dsh-docs/subsystems/filesystem.zh.md +505 -0
- package/dsh-docs/subsystems/goal.md +277 -0
- package/dsh-docs/subsystems/goal.zh.md +277 -0
- package/dsh-docs/subsystems/invariants.md +88 -0
- package/dsh-docs/subsystems/invariants.zh.md +88 -0
- package/dsh-docs/subsystems/jobs.md +290 -0
- package/dsh-docs/subsystems/jobs.zh.md +290 -0
- package/dsh-docs/subsystems/llm-streaming.md +1080 -0
- package/dsh-docs/subsystems/llm-streaming.zh.md +1086 -0
- package/dsh-docs/subsystems/lsp.md +202 -0
- package/dsh-docs/subsystems/lsp.zh.md +202 -0
- package/dsh-docs/subsystems/permission-presets.md +131 -0
- package/dsh-docs/subsystems/permission-presets.zh.md +131 -0
- package/dsh-docs/subsystems/persistence.md +395 -0
- package/dsh-docs/subsystems/persistence.zh.md +395 -0
- package/dsh-docs/subsystems/plan.md +87 -0
- package/dsh-docs/subsystems/plan.zh.md +87 -0
- package/dsh-docs/subsystems/sandbox.md +220 -0
- package/dsh-docs/subsystems/sandbox.zh.md +220 -0
- package/dsh-docs/subsystems/schedule.md +192 -0
- package/dsh-docs/subsystems/schedule.zh.md +192 -0
- package/dsh-docs/subsystems/scope.md +59 -0
- package/dsh-docs/subsystems/scope.zh.md +59 -0
- package/dsh-docs/subsystems/session-projection.md +354 -0
- package/dsh-docs/subsystems/session-projection.zh.md +354 -0
- package/dsh-docs/subsystems/session-query.md +509 -0
- package/dsh-docs/subsystems/session-query.zh.md +509 -0
- package/dsh-docs/subsystems/session-reference.md +219 -0
- package/dsh-docs/subsystems/session-reference.zh.md +219 -0
- package/dsh-docs/subsystems/session-telemetry.md +194 -0
- package/dsh-docs/subsystems/session-telemetry.zh.md +194 -0
- package/dsh-docs/subsystems/session-title.md +204 -0
- package/dsh-docs/subsystems/session-title.zh.md +204 -0
- package/dsh-docs/subsystems/session.md +1155 -0
- package/dsh-docs/subsystems/session.zh.md +1159 -0
- package/dsh-docs/subsystems/settings.md +405 -0
- package/dsh-docs/subsystems/settings.zh.md +405 -0
- package/dsh-docs/subsystems/shell.md +303 -0
- package/dsh-docs/subsystems/shell.zh.md +303 -0
- package/dsh-docs/subsystems/sidebar-right.md +148 -0
- package/dsh-docs/subsystems/sidebar-right.zh.md +148 -0
- package/dsh-docs/subsystems/skills.md +354 -0
- package/dsh-docs/subsystems/skills.zh.md +354 -0
- package/dsh-docs/subsystems/slots.md +175 -0
- package/dsh-docs/subsystems/slots.zh.md +175 -0
- package/dsh-docs/subsystems/spill.md +117 -0
- package/dsh-docs/subsystems/spill.zh.md +117 -0
- package/dsh-docs/subsystems/storage.md +260 -0
- package/dsh-docs/subsystems/storage.zh.md +260 -0
- package/dsh-docs/subsystems/subagent.md +766 -0
- package/dsh-docs/subsystems/subagent.zh.md +770 -0
- package/dsh-docs/subsystems/subprocess.md +324 -0
- package/dsh-docs/subsystems/subprocess.zh.md +324 -0
- package/dsh-docs/subsystems/system-prompt.md +220 -0
- package/dsh-docs/subsystems/system-prompt.zh.md +220 -0
- package/dsh-docs/subsystems/terminal.md +184 -0
- package/dsh-docs/subsystems/terminal.zh.md +184 -0
- package/dsh-docs/subsystems/todo.md +32 -0
- package/dsh-docs/subsystems/todo.zh.md +32 -0
- package/dsh-docs/subsystems/token-meter.md +105 -0
- package/dsh-docs/subsystems/token-meter.zh.md +105 -0
- package/dsh-docs/subsystems/tools.md +720 -0
- package/dsh-docs/subsystems/tools.zh.md +720 -0
- package/dsh-docs/subsystems/typert.md +343 -0
- package/dsh-docs/subsystems/typert.zh.md +343 -0
- package/dsh-docs/subsystems/user-questions.md +178 -0
- package/dsh-docs/subsystems/user-questions.zh.md +178 -0
- package/dsh-docs/subsystems/web-client.md +95 -0
- package/dsh-docs/subsystems/web-client.zh.md +95 -0
- package/dsh-docs/subsystems/web-server.md +154 -0
- package/dsh-docs/subsystems/web-server.zh.md +154 -0
- package/dsh-docs/subsystems/web.md +206 -0
- package/dsh-docs/subsystems/web.zh.md +206 -0
- package/dsh-docs/subsystems/webhook.md +70 -0
- package/dsh-docs/subsystems/webhook.zh.md +70 -0
- package/dsh-docs/subsystems/workflow.md +278 -0
- package/dsh-docs/subsystems/workflow.zh.md +278 -0
- package/dsh-docs/subsystems/workspace.md +321 -0
- package/dsh-docs/subsystems/workspace.zh.md +321 -0
- package/dsh-docs/testing.md +54 -0
- package/dsh-docs/testing.zh.md +54 -0
- package/dsh-docs/tool-catalog.md +2225 -0
- package/dsh-docs/tool-catalog.zh.md +2233 -0
- package/dsh-docs/tool-execution-pipeline.md +62 -0
- package/dsh-docs/tool-execution-pipeline.zh.md +64 -0
- package/dsh-docs/user/develop/basic/config.md +106 -0
- package/dsh-docs/user/develop/basic/config.zh.md +106 -0
- package/dsh-docs/user/develop/basic/index.md +144 -0
- package/dsh-docs/user/develop/basic/index.zh.md +144 -0
- package/dsh-docs/user/develop/basic/publish.md +183 -0
- package/dsh-docs/user/develop/basic/publish.zh.md +183 -0
- package/dsh-docs/user/develop/basic/tool.md +52 -0
- package/dsh-docs/user/develop/basic/tool.zh.md +52 -0
- package/dsh-docs/user/develop/framework/events.md +143 -0
- package/dsh-docs/user/develop/framework/events.zh.md +143 -0
- package/dsh-docs/user/develop/framework/index.md +137 -0
- package/dsh-docs/user/develop/framework/index.zh.md +137 -0
- package/dsh-docs/user/develop/framework/service.md +148 -0
- package/dsh-docs/user/develop/framework/service.zh.md +150 -0
- package/dsh-docs/user/develop/practice/dynamic-cordis.md +15 -0
- package/dsh-docs/user/develop/practice/dynamic-cordis.zh.md +15 -0
- package/dsh-docs/user/develop/practice/index.md +155 -0
- package/dsh-docs/user/develop/practice/index.zh.md +155 -0
- package/dsh-docs/user/develop/practice/llm-adapter.md +189 -0
- package/dsh-docs/user/develop/practice/llm-adapter.zh.md +189 -0
- package/dsh-docs/user/guide/github-review.md +102 -0
- package/dsh-docs/user/guide/github-review.zh.md +102 -0
- package/dsh-docs/user/guide/index.md +30 -0
- package/dsh-docs/user/guide/index.zh.md +30 -0
- package/dsh-docs/user/guide/mcp-memory.md +101 -0
- package/dsh-docs/user/guide/mcp-memory.zh.md +101 -0
- package/dsh-docs/user/guide/network-proxy.md +85 -0
- package/dsh-docs/user/guide/network-proxy.zh.md +85 -0
- package/dsh-docs/user/guide/providers.md +190 -0
- package/dsh-docs/user/guide/providers.zh.md +190 -0
- package/dsh-docs/user/guide/python-sdk.md +150 -0
- package/dsh-docs/user/guide/python-sdk.zh.md +150 -0
- package/dsh-docs/user/guide/schedule.md +21 -0
- package/dsh-docs/user/guide/schedule.zh.md +21 -0
- package/dsh-docs/user/index.md +11 -0
- package/dsh-docs/user/index.zh.md +11 -0
- package/dsh-docs/web-styling.md +29 -0
- package/dsh-docs/web-styling.zh.md +29 -0
- package/eval-description.md +33 -0
- package/lib/client/index.js +327 -88
- package/lib/fs-aware/sandbox-plugin.d.ts +71 -0
- package/lib/fs-aware/sandbox-plugin.js +249 -0
- package/lib/index.d.ts +22 -22
- package/lib/index.js +3095 -3204
- package/lib/lsp-server-registry-DkaYmTwt.js +972 -0
- package/lib/lsp-server-registry-_hk-Wcia.js +3 -0
- package/lib/py-sdk-Chvy92MB.js +178 -0
- package/lib/py-sdk.d.ts +19 -2
- package/lib/py-sdk.js +2 -2
- package/lib/wrap-JFjcWwZf.js +747 -0
- package/package.json +9 -3
- package/url-schemes-instruction.md +22 -0
- package/control-prompt.md +0 -37
- package/docs/50_test-reports/v0.1.8d_artifacts/README.md +0 -138
- package/docs/50_test-reports/v0.1.8d_artifacts/code-mode-repl-only.observation.md +0 -74
- package/docs/50_test-reports/v0.1.8d_artifacts/dsh-session-session-4a293388-9ae1-474b-87a0-9e17bb556d94.jsonl +0 -3890
- package/docs/50_test-reports/v0.1.8d_artifacts/dsh-session-session-4a293388-9ae1-474b-87a0-9e17bb556d94.w-sample-0435.jsonl +0 -544
- package/docs/50_test-reports/v0.1.8d_artifacts/functions.json +0 -592
- package/docs/50_test-reports/v0.1.8d_artifacts/skills-catalog.snapshot.md +0 -30
- package/docs/50_test-reports/v0.1.8d_artifacts/tools-sdk.output-schemas.json +0 -1236
- package/docs/50_test-reports/v0.1.8d_artifacts/tools-sdk.python.txt +0 -592
- package/docs/50_test-reports/v0.1.8d_artifacts/tools-sdk.typescript.txt +0 -516
- package/docs/50_test-reports/v0.1.8d_artifacts/wire-vs-transcription.diff.md +0 -54
- package/docs/50_test-reports/v0.2.0b_artifacts/f2probe/Cargo.lock +0 -7
- package/docs/50_test-reports/v0.2.0b_artifacts/f2probe/Cargo.toml +0 -6
- package/docs/50_test-reports/v0.2.0b_artifacts/f2probe/src/bin/messy.rs +0 -8
- package/docs/50_test-reports/v0.2.0b_artifacts/f2probe/src/main.rs +0 -4
- package/docs/50_test-reports/v0.2.0b_artifacts/hashline-probe.md +0 -5
- package/docs/50_test-reports/v0.2.0b_artifacts/slowprobe/Cargo.lock +0 -7
- package/docs/50_test-reports/v0.2.0b_artifacts/slowprobe/Cargo.toml +0 -7
- package/docs/50_test-reports/v0.2.0b_artifacts/slowprobe/build.rs +0 -4
- package/docs/50_test-reports/v0.2.0b_artifacts/slowprobe/src/main.rs +0 -13
- package/docs/60_exploration-and-research/cordis-research.md +0 -350
- package/docs/60_exploration-and-research/dsh-web-profile-package-map.md +0 -186
- package/docs/60_exploration-and-research/dsh-web-ui-slot-system-research.md +0 -310
- package/docs/60_exploration-and-research/dsh-webui-strip-boundary-research.md +0 -300
- package/docs/60_exploration-and-research/ios-chat-app-bridge-research.md +0 -324
- package/docs/60_exploration-and-research/web-frontend-composability-research.md +0 -191
- package/docs/REPL-/345/267/245/345/205/267/350/260/203/347/224/250-/346/210/252/346/226/255/350/257/212/346/226/255.md +0 -110
- package/docs/adr/0001-bridge-tool-layer-not-service-layer.md +0 -14
- package/docs/adr/0002-masking-is-presentation-only.md +0 -15
- package/docs/plans/A2A-messaging-channel-test-archive.md +0 -256
- package/docs/plans/code-mode-vs-rlm-ipython-comparison.md +0 -137
- package/docs/plans/dashr-blueprint-review.md +0 -201
- package/docs/plans/dashr-blueprint.md +0 -561
- package/docs/plans/dashr-compaction-window-and-archive.md +0 -307
- package/docs/plans/dashr-profile-layer-feasibility.md +0 -367
- package/docs/plans/dashr-sandbox-escalation-semantics-gap.md +0 -171
- package/docs/plans/dashr-security-sandbox-analysis.md +0 -187
- package/docs/plans/dashr-surface-invariant-and-omp-imports.md +0 -97
- package/docs/plans/ipython-kernel-interactive-interface-test-report.md +0 -152
- package/docs/plans/kernel-refactoring/Dash-IPython-Control-Prompt-draft.md +0 -146
- package/docs/plans/kernel-refactoring/Dash-IPython-Control-Prompt-draft_v3.md +0 -50
- package/docs/plans/kernel-refactoring/Dash-IPython-Control-Prompt-draft_v4.md +0 -79
- package/docs/plans/kernel-refactoring/Dash-vs-PrimeAgent-systemprompt-toolcatalog-comparison.md +0 -138
- package/docs/plans/kernel-refactoring/RLM-system-prompt-injection-gap-report.md +0 -161
- package/docs/plans/kernel-refactoring/V0.1.5-development-plan.md +0 -109
- package/docs/plans/kernel-refactoring/actinoable-surface-to-llm-in-agent-runtime_dsh.md +0 -50
- package/docs/plans/kernel-refactoring/actinoable-surface-to-llm-in-agent-runtime_prime.md +0 -113
- package/docs/plans/recallable-compaction.md +0 -147
- package/docs/plans/spike-tag-repro.mjs +0 -102
- package/docs/plans/upstream-analysis.md +0 -128
- package/docs/v0.1.8-improved-/345/256/236/346/265/213/346/212/245/345/221/212.md +0 -142
- package/docs/v0.1.8-/345/256/236/346/265/213/346/212/245/345/221/212.md +0 -193
- package/docs/v0.1.8b-/345/256/236/346/265/213/346/212/245/345/221/212.md +0 -96
- package/docs/v0.1.8c-/345/256/236/346/265/213/346/212/245/345/221/212.md +0 -127
- package/docs/v0.1.8d-/345/256/236/346/265/213/346/212/245/345/221/212.md +0 -150
- package/docs/v0.1.8d_artifacts/README.md +0 -138
- package/docs/v0.1.8d_artifacts/code-mode-repl-only.observation.md +0 -74
- package/docs/v0.1.8d_artifacts/dsh-session-session-4a293388-9ae1-474b-87a0-9e17bb556d94.jsonl +0 -3890
- package/docs/v0.1.8d_artifacts/dsh-session-session-4a293388-9ae1-474b-87a0-9e17bb556d94.w-sample-0435.jsonl +0 -544
- package/docs/v0.1.8d_artifacts/functions.json +0 -592
- package/docs/v0.1.8d_artifacts/skills-catalog.snapshot.md +0 -30
- package/docs/v0.1.8d_artifacts/tools-sdk.output-schemas.json +0 -1236
- package/docs/v0.1.8d_artifacts/tools-sdk.python.txt +0 -592
- package/docs/v0.1.8d_artifacts/tools-sdk.typescript.txt +0 -516
- package/docs/v0.1.8d_artifacts/wire-vs-transcription.diff.md +0 -54
- package/docs/v0.1.8e-/345/256/236/346/265/213/346/212/245/345/221/212.md +0 -224
- package/docs/v0.1.9a-/345/256/236/346/265/213/346/212/245/345/221/212.md +0 -168
- package/docs/v0.2.0b-/345/256/236/346/265/213/346/212/245/345/221/212.md +0 -123
- package/docs/v0.2.0b_artifacts/f2probe/Cargo.lock +0 -7
- package/docs/v0.2.0b_artifacts/f2probe/Cargo.toml +0 -6
- package/docs/v0.2.0b_artifacts/f2probe/src/bin/messy.rs +0 -8
- package/docs/v0.2.0b_artifacts/f2probe/src/main.rs +0 -4
- package/docs/v0.2.0b_artifacts/hashline-probe.md +0 -5
- package/docs/v0.2.0b_artifacts/slowprobe/Cargo.lock +0 -7
- package/docs/v0.2.0b_artifacts/slowprobe/Cargo.toml +0 -7
- package/docs/v0.2.0b_artifacts/slowprobe/build.rs +0 -4
- package/docs/v0.2.0b_artifacts/slowprobe/src/main.rs +0 -13
- package/docs/v0.2.1-/345/256/236/346/265/213/346/212/245/345/221/212.md +0 -110
- package/docs/v0.2.1b-/345/256/236/346/265/213/346/212/245/345/221/212.md +0 -86
- package/docs/v0.2.1c-/345/256/236/346/265/213/346/212/245/345/221/212.md +0 -66
- package/lib/py-sdk-BCaOGYz7.d.ts +0 -125
- package/lib/py-sdk-CbgYiX8O.js +0 -691
|
@@ -1,310 +0,0 @@
|
|
|
1
|
-
# dsh Web UI 前端插件系统研究
|
|
2
|
-
|
|
3
|
-
> 记录:2026-08-31 · 一手核验:`~/workspaces/dsh-alpha/packages/client/` 源码 +
|
|
4
|
-
> `packages/extensions/cordis-client-runner/` + vendored `@deepseek-ai/*` 4.x 编译产物
|
|
5
|
-
> (`~/.dsh/profiles/node_modules/@deepseek-ai/`,220 包)。
|
|
6
|
-
> 本文是 `cordis-research.md`(Cordis 服务端侧)与 `web-frontend-composability-research.md`
|
|
7
|
-
> (Web 生态通用对照)的**dsh 实测侧**:回答"dsh 的 Web UI 到底是怎么把插件穿透到前端、又
|
|
8
|
-
> 怎么在 React 上渲染出来的"。
|
|
9
|
-
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
## 1. 一句话结论
|
|
13
|
-
|
|
14
|
-
**dsh 的 Web UI 不是"React 组件库",而是把 Cordis 原封不动地搬进了浏览器:每个
|
|
15
|
-
`dsh-client-ui-*` 包是"双半插件"(服务端空 `apply()` + 浏览器端真 `apply(ctx)`),组合靠一套
|
|
16
|
-
框架无关的**插槽注册表(SlotRegistry)**——一个靠 TypeScript `declare module` 声明合并出来的
|
|
17
|
-
类型化 `SlotMap` 定义所有插槽契约,React 只是挂在注册表上的**一个可替换渲染后端**,状态用
|
|
18
|
-
框架无关的 observable 喂给 `useSyncExternalStore`。**
|
|
19
|
-
|
|
20
|
-
判定:这与服务端 Cordis 是**同一哲学的两个投影**——服务端用 `inject`/`provide` 组合 *服务*,
|
|
21
|
-
前端用 `register`/`renderSlot` 组合 *组件*;两者都是"声明式 + 控制反转 + 免重启装卸"。
|
|
22
|
-
|
|
23
|
-
---
|
|
24
|
-
|
|
25
|
-
## 2. 双半插件(dual-half):一个包,两个编译目标
|
|
26
|
-
|
|
27
|
-
每个 `dsh-client-ui-*` 插件有两个入口文件,编译成两个目标:
|
|
28
|
-
|
|
29
|
-
**host 半**(服务端,空函数——只为让 Cordis Loader 有东西可加载):
|
|
30
|
-
|
|
31
|
-
```ts
|
|
32
|
-
// packages/client/ui-sidebar/src/index.ts
|
|
33
|
-
/** Host loader entry for the browser-only sidebar plugin. */
|
|
34
|
-
/** Provides no host-side behavior. */
|
|
35
|
-
export function apply(): void {}
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
**browser 半**(浏览器里真正干活):
|
|
39
|
-
|
|
40
|
-
```ts
|
|
41
|
-
// packages/client/ui-sidebar/src/client/index.ts
|
|
42
|
-
export const inject = ['slots', 'layout', 'uiWorkspace', 'locale']
|
|
43
|
-
|
|
44
|
-
export function apply(ctx: ClientContext): void {
|
|
45
|
-
const workspaceNavigation = ctx.get('uiWorkspace')
|
|
46
|
-
ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'ui-sidebar: dictionaries')
|
|
47
|
-
const injectProps = (): SidebarRootInjected => ({
|
|
48
|
-
startSession: (workspaceId) => workspaceNavigation.startSession(workspaceId),
|
|
49
|
-
toggleSidebar: () => ctx.layout.toggleSidebar(),
|
|
50
|
-
})
|
|
51
|
-
ctx.effect(
|
|
52
|
-
() => ctx.slots.register({ name: 'sidebar', children: {...}, inject: injectProps }, SidebarRoot),
|
|
53
|
-
'ui-sidebar: slot registration',
|
|
54
|
-
)
|
|
55
|
-
}
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
关键点:`client/index.ts` 的 `apply(ctx)` 里有 `inject` 数组(`['slots', 'layout', ...]`)和
|
|
59
|
-
`ctx.effect(...)`——**和服务端 Cordis 插件完全一样的写法**。它跑在浏览器里,是因为下面第 8 节
|
|
60
|
-
的 `dsh-cordis-client-runner` 在浏览器里又起了一套 Cordis。
|
|
61
|
-
|
|
62
|
-
判定:服务端"组合服务"和前端"组合 UI"用的是**同一套心智模型**,只是换了个宿主(Node 进程 →
|
|
63
|
-
浏览器页面)。
|
|
64
|
-
|
|
65
|
-
---
|
|
66
|
-
|
|
67
|
-
## 3. 组合 = Slot:框架无关的类型化插槽注册表
|
|
68
|
-
|
|
69
|
-
前端的组合**不是** React 的 props 钻孔,也不是 React Context,而是一个**纯插槽注册表**
|
|
70
|
-
(`SlotCore`,无 cordis、无 React):
|
|
71
|
-
|
|
72
|
-
```ts
|
|
73
|
-
// packages/client/ui-slots/src/index.ts
|
|
74
|
-
export interface SlotMap {} // 空接口,靠各插件 declare module 合并
|
|
75
|
-
export interface LocaleNamespaceMap {}
|
|
76
|
-
export type SlotKind = 'single' | 'list' | 'keyed' | 'chain'
|
|
77
|
-
export type SlotScope = 'root' | 'session-maybe' | 'session'
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
每个插件通过 **TypeScript 声明合并** 往 `SlotMap` 上"合并"进自己的插槽名,于是**类型层面就知道
|
|
81
|
-
每个插槽的契约**:
|
|
82
|
-
|
|
83
|
-
```ts
|
|
84
|
-
// packages/client/ui-sidebar/src/client/contract/slots.ts
|
|
85
|
-
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
86
|
-
interface SlotMap {
|
|
87
|
-
'sidebar.brand.mark': ...
|
|
88
|
-
'sidebar.brand.name': ...
|
|
89
|
-
'sidebar.workspaces': ...
|
|
90
|
-
'sidebar.settings': ...
|
|
91
|
-
'sidebar.footer.action': ...
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
这与服务端 Cordis 的 `declare module '@deepseek-ai/cordis' { interface Context { slots: ... } }`
|
|
97
|
-
是**同一个机制**(`ui-renderer` 就是用它把 `ctx.slots`、`ctx.uiRenderer` 合并进 cordis Context)。
|
|
98
|
-
|
|
99
|
-
组合是**一棵树**:owner 注册时声明 `children`(子槽),occupant 填充别人的槽:
|
|
100
|
-
|
|
101
|
-
```
|
|
102
|
-
root(内置,唯一的 ctx 级槽)
|
|
103
|
-
└─ layout 区域(ui-layout 拥有,声明 'sidebar' 等区域槽)
|
|
104
|
-
└─ sidebar 壳(ui-sidebar 注册)
|
|
105
|
-
├─ sidebar.workspaces ← ui-workspace 填充
|
|
106
|
-
├─ sidebar.settings ← ui-settings 填充
|
|
107
|
-
├─ sidebar.brand.mark ← ui-brand 填充
|
|
108
|
-
└─ sidebar.footer.action(list 槽,多插件追加)
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
判定:**"谁声明槽"和"谁填槽"是两个正交的插件集**,靠 `SlotMap` 的类型合并保证编译期契约匹配
|
|
112
|
-
——这是它比"字符串 key + `any` props"的普通插件系统(如 VS Code views)高明的地方。
|
|
113
|
-
|
|
114
|
-
---
|
|
115
|
-
|
|
116
|
-
## 4. 插槽的两个轴:基数(kind)与作用域(scope)
|
|
117
|
-
|
|
118
|
-
```ts
|
|
119
|
-
type SlotKind = 'single' | 'list' | 'keyed' | 'chain' // 单占位 / 有序列表 / 按 key 分发 / 选择器路由链
|
|
120
|
-
type SlotScope = 'root' | 'session-maybe' | 'session' // 全局 / 可选当前会话 / 严格绑定会话
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
- **kind** 决定一个槽能容纳几个 occupant、怎么分发(`single` 一个、`list` 按顺序叠加、`keyed`
|
|
124
|
-
按 key 分发、`chain` 用选择器决定路由)。
|
|
125
|
-
- **scope** 决定 occupant 是否/如何拿到当前 Session(`session` 槽会被注入 `sessionId` +
|
|
126
|
-
`SessionProvider` 座,`session-maybe` 在无会话时收到 `undefined`,`root` 不接触会话)。
|
|
127
|
-
|
|
128
|
-
判定:基数轴覆盖了 UI 扩展点的四种真实形态;作用域轴把"会话数据怎么流进 UI"做成了类型级约束
|
|
129
|
-
(`PropsRuntime` 按 scope 收窄),而不是靠运行时约定。
|
|
130
|
-
|
|
131
|
-
---
|
|
132
|
-
|
|
133
|
-
## 5. React 渲染:整个 App = 一个 `root` 槽
|
|
134
|
-
|
|
135
|
-
这是最反直觉的一步——**整个 React 树只有一个入口**:
|
|
136
|
-
|
|
137
|
-
```tsx
|
|
138
|
-
// packages/client/ui-renderer/src/client/app.tsx
|
|
139
|
-
export function buildRenderApp(deps): () => ReactNode {
|
|
140
|
-
const { ctx } = deps
|
|
141
|
-
return () => ctx.slots.renderSlot('root', {}) // ← 整个 app 就这一句
|
|
142
|
-
}
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
```ts
|
|
146
|
-
// packages/client/ui-renderer/src/client/index.ts
|
|
147
|
-
export function apply(ctx: Context): void {
|
|
148
|
-
const slots = new SlotRegistry(ctx)
|
|
149
|
-
slots.install(createSlotRenderer()) // ← 把 React 渲染器装进插槽注册表
|
|
150
|
-
ctx.reflect.provide('uiRenderer', {
|
|
151
|
-
mount: (container) => {
|
|
152
|
-
const root = mountApp(container, buildRenderApp({ ctx })) // createRoot / hydrateRoot
|
|
153
|
-
return () => root.unmount()
|
|
154
|
-
},
|
|
155
|
-
})
|
|
156
|
-
}
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
`SlotRegistry` 是 cordis 侧对 `SlotCore` 的包装;`createSlotRenderer()` 是**唯一一个 React 绑定**。
|
|
160
|
-
React 挂载后只渲染 `renderSlot('root')`,渲染器递归展开插槽树、找到每个槽的 occupant 渲染出来。
|
|
161
|
-
|
|
162
|
-
还有一段 boot 水合细节(`mountApp`):如果容器里已有 kernel 预渲染的 `[data-dsh-boot]` DOM,就走
|
|
163
|
-
`hydrateRoot` 保活;否则 `createRoot` + `flushSync` 首帧。这是"框架无关的 boot DOM"→"React 接管"的
|
|
164
|
-
交接。
|
|
165
|
-
|
|
166
|
-
判定:**插槽注册表和状态都是框架中立的;React 只是"当前安装的那个渲染器"。** 理论上换一个
|
|
167
|
-
渲染器(如 preact / solid)只换 `createSlotRenderer()`,插槽树和业务插件一行不用改。
|
|
168
|
-
|
|
169
|
-
---
|
|
170
|
-
|
|
171
|
-
## 6. 每个插槽组件的 props 是"组合"出来的
|
|
172
|
-
|
|
173
|
-
一个 slot 组件收到的 props 是五份的交集(`ComposedProps`):
|
|
174
|
-
|
|
175
|
-
| 份额 | 类型 | 来源 |
|
|
176
|
-
|---|---|---|
|
|
177
|
-
| **owner 分享** | `PropsRuntime`(`OwnerOf` + `KeyPropsOf` + scope 标准件) | 父级 `renderSlot` 调用点传的数据 |
|
|
178
|
-
| **render 分享** | `PropsRenderSlots<S>` | 子插槽的 `renderSlot` 函数,**静态收窄到声明的 `children`** |
|
|
179
|
-
| **store hooks** | `PropsStore` | 从 observable 源合成的 `use<Name>` 选择器 hook |
|
|
180
|
-
| **locale** | `PropsLocale` | `t` 翻译函数(按命名空间收窄 key) |
|
|
181
|
-
| **inject** | `InjectFace` | owner 注入的 `inject` 工厂(`hooks` 成员被转成 hook) |
|
|
182
|
-
|
|
183
|
-
侧栏的 `injectProps` 就是第 5 份的实例:把 `startSession`/`toggleSidebar` 通过 `inject` 工厂塞给
|
|
184
|
-
`SidebarRoot`,而 `SidebarRoot` 自己只消费 `PropsRenderSlots<'sidebar.brand.mark' | ...>` 去渲染
|
|
185
|
-
它声明的 5 个子槽。
|
|
186
|
-
|
|
187
|
-
判定:props 的每一份都有**编译期来源**(类型系统里能追到"谁给了什么"),不是运行时拼出来的
|
|
188
|
-
黑盒。这是它能"有求必应"又"不越权"的根基——owner 只拿到自己声明的 children 的 `renderSlot`,
|
|
189
|
-
occupant 只拿到 owner 声明的 `owner`/`inject` 分享。
|
|
190
|
-
|
|
191
|
-
---
|
|
192
|
-
|
|
193
|
-
## 7. 状态 = 框架无关的 observable → useSyncExternalStore
|
|
194
|
-
|
|
195
|
-
业务状态**不依赖 React**,是 `HostObservable<T>`(`getSnapshot` + `subscribe`)。React 绑定用
|
|
196
|
-
`useSyncExternalStore` 把它变成 hook:
|
|
197
|
-
|
|
198
|
-
```ts
|
|
199
|
-
// packages/client/ui-renderer/src/client/bindings.tsx
|
|
200
|
-
export function observableHook<T>(source: HostObservable<T>): SnapshotSelectorHook<T> { ... }
|
|
201
|
-
export function maybeObservableHook<T>(source: HostObservable<T> | undefined) { ... } // 缺席保持 Hook 调用顺序稳定
|
|
202
|
-
export function keyedObservableHook(source: KeyedStandardSource | undefined) { ... }
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
一个 store 的 snapshot 变成组件里注入的 `use<Name>(selector)` hook(`standardHookPropName` 把源名
|
|
206
|
-
`foo` 转成 `useFoo`)。`use-sync-external-store` 是为了在 React 18 里拿到并发安全的订阅。
|
|
207
|
-
|
|
208
|
-
判定:**状态层是框架中立的,React 是纯渲染绑定。** 这和第 5 节同构——插槽和状态都跟框架解耦,
|
|
209
|
-
所以"换渲染器"不是说说而已。
|
|
210
|
-
|
|
211
|
-
---
|
|
212
|
-
|
|
213
|
-
## 8. 浏览器里的 Cordis + RPC 传输
|
|
214
|
-
|
|
215
|
-
`dsh-cordis-client-runner`(`packages/extensions/cordis-client-runner/src/client/`)在**浏览器里再
|
|
216
|
-
起一套完整 Cordis**,逐个调每个 UI 插件的 `client/index.ts` 的 `apply(ctx)`。它带齐了 cordis 的
|
|
217
|
-
运行时件:`runtime.ts`、`providers.ts`、`evaluator.ts`、`guard.ts`、`timer.ts`、`slot-catalog.ts`、
|
|
218
|
-
`orchestrator.ts`(页面侧的 run 编排 / 审批 / 面板手势)。
|
|
219
|
-
|
|
220
|
-
浏览器 → 服务端的通信是 **WebSocket 上的 Typert RPC**:
|
|
221
|
-
|
|
222
|
-
| 包 | 角色 |
|
|
223
|
-
|---|---|
|
|
224
|
-
| `dsh-client-connection` | 认证 RPC 传输(`ws`),生命周期管理 |
|
|
225
|
-
| `dsh-api-gateway` | Typert Remote Host 分发器(`ws` + schemastery 校验) |
|
|
226
|
-
| `dsh-api-remotes` | 客户端 RPC 桩(BFF 组装,会话/工作区/设置等面) |
|
|
227
|
-
| `dsh-api-*-controller` | 服务端 BFF 后端(session/workspace/settings) |
|
|
228
|
-
|
|
229
|
-
判定:浏览器里的 Cordis 服务通过 `inject` 拿到的是**远程能力的本地代理**(`dsh-api-remotes` 桩),
|
|
230
|
-
而非直接 import 服务端实现。这条 RPC 边界就是"前端插件"和"后端服务"的分界——也是我们桥接层
|
|
231
|
-
(omp-webui)要替换数据源的那条缝。
|
|
232
|
-
|
|
233
|
-
---
|
|
234
|
-
|
|
235
|
-
## 9. 完整链路(一张图)
|
|
236
|
-
|
|
237
|
-
```mermaid
|
|
238
|
-
flowchart TD
|
|
239
|
-
subgraph Browser["浏览器(dsh-cordis-client-runner 再起一套 cordis)"]
|
|
240
|
-
R["ui-renderer<br/>SlotRegistry + createSlotRenderer + mount"]
|
|
241
|
-
L["ui-layout<br/>拥有 root 布局树,声明 'sidebar' 等区域槽"]
|
|
242
|
-
S["ui-sidebar<br/>注册 'sidebar' 槽 + 5 个子槽"]
|
|
243
|
-
W["ui-workspace / ui-settings<br/>填 sidebar.workspaces / sidebar.settings"]
|
|
244
|
-
C["ui-chat / ui-session / ui-conversation<br/>聊天区"]
|
|
245
|
-
T["client-connection(WS)+ api-remotes(RPC 桩)"]
|
|
246
|
-
R -->|"ctx.slots.renderSlot('root')"| L
|
|
247
|
-
L --> S --> W
|
|
248
|
-
end
|
|
249
|
-
subgraph Host["宿主(Node cordis)"]
|
|
250
|
-
G["dsh-api-gateway(typert 分发)"]
|
|
251
|
-
A["api-session/workspace/settings controller"]
|
|
252
|
-
D["dsh-session / dsh-llm / dsh-agent(核心,供数据)"]
|
|
253
|
-
G --> A --> D
|
|
254
|
-
end
|
|
255
|
-
T -->|"WebSocket Typert RPC"| G
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
---
|
|
259
|
-
|
|
260
|
-
## 10. 方法论提炼:为什么这么设计
|
|
261
|
-
|
|
262
|
-
把 dsh 前端这套机制抽象成三条方法论,与 Cordis 服务端一一对应:
|
|
263
|
-
|
|
264
|
-
1. **组合 = 类型化的注册表,不是字符串约定。** 服务端 `declare module '@deepseek-ai/cordis'`
|
|
265
|
-
合并 `Context`;前端 `declare module '@deepseek-ai/dsh-client-ui-slots'` 合并 `SlotMap`。插槽
|
|
266
|
-
契约是编译期检查的,不是文档口头约定。
|
|
267
|
-
2. **框架中立的内核 + 可替换的渲染后端。** `SlotCore`(无 cordis/React)+ observable(无 React)
|
|
268
|
-
是内核;`createSlotRenderer()` 是唯一 React 绑定。对应 Cordis 的"框架内核 + 插件树"。
|
|
269
|
-
3. **双半部署。** 一个插件包编译成 host 半(空 `apply()`)+ browser 半(真逻辑),由 cordis 的
|
|
270
|
-
`cordis-client-runner` 在两端各自加载。对应 Cordis 的"同一插件在两个运行时里各有一半"。
|
|
271
|
-
|
|
272
|
-
判定:这套东西的难点不在"能组合"(Web Components / MF 都能),而在**"依赖驱动的、反应式的、
|
|
273
|
-
类型安全的组合"**——`web-frontend-composability-research.md` §5 说 Web 生态缺的"反应式依赖激活",
|
|
274
|
-
dsh 前端是用 **cordis 本身**补上的(浏览器里再跑一个 cordis),而不是在 DOM 层重造。
|
|
275
|
-
|
|
276
|
-
---
|
|
277
|
-
|
|
278
|
-
## 11. 对 omp-webui 桥接层的意义
|
|
279
|
-
|
|
280
|
-
这份研究直接回答了我们前几轮纠结的问题:
|
|
281
|
-
|
|
282
|
-
- **"能不能只复用 UI、自己写 HTTP 服务器?"** —— 不能干净地做。UI 插件是 dual-half,它的
|
|
283
|
-
browser 半靠 `dsh-cordis-client-runner` 跑在浏览器 cordis 里、通过 `dsh-api-remotes` 的 RPC 桩
|
|
284
|
-
调服务端;UI 的"前端组件"和"后端服务"不是 REST 边界,是 Typert RPC 边界。要复用 UI 就得
|
|
285
|
-
把服务端 RPC 那半也搭起来。
|
|
286
|
-
- **"我们的桥接层到底替换了哪一段?"** —— 替换的是**数据源服务**(`dsh-session-persistence`
|
|
287
|
-
→ OMP 适配器、`dsh-agent-loop` → OMP provider、`dsh-agent-presets` → 单模式 roster),即第 8 节
|
|
288
|
-
RPC 链**服务端**那一侧的几个 provider。**前端插槽树、渲染器、RPC 协议一行没动。**
|
|
289
|
-
- **"YAML 组合"的设想本来就存在。** 服务端是 `cordis.patch.yml`(定义加载哪些插件),前端是
|
|
290
|
-
`SlotMap` + `register`/`renderSlot`(定义 UI 怎么组合)。我们要加 UI 面板,正确做法是**注册一个
|
|
291
|
-
槽的 occupant**(`ctx.slots.register(...)`),而不是去改渲染器或重写插槽机制。
|
|
292
|
-
|
|
293
|
-
---
|
|
294
|
-
|
|
295
|
-
## 来源
|
|
296
|
-
|
|
297
|
-
- dsh-alpha 源码(`~/workspaces/dsh-alpha/packages/`):
|
|
298
|
-
- `client/ui-sidebar/src/index.ts`(host 半空 `apply()`)、`client/ui-sidebar/src/client/index.ts`
|
|
299
|
-
(browser 半 `ctx.slots.register`)、`client/ui-sidebar/src/client/contract/slots.ts`(SlotMap 合并)
|
|
300
|
-
- `client/ui-slots/src/index.ts`(`SlotMap`/`SlotKind`/`SlotScope`/`SlotCore`)、
|
|
301
|
-
`client/ui-slots/src/renderer.ts`(框架中立契约 `SlotRendererHost`/`SlotRenderer`)
|
|
302
|
-
- `client/ui-renderer/src/client/app.tsx`(`renderSlot('root')`)、
|
|
303
|
-
`client/ui-renderer/src/client/index.ts`(`SlotRegistry` + `createSlotRenderer` + `mount`)、
|
|
304
|
-
`client/ui-renderer/src/client/bindings.tsx`(observable → `useSyncExternalStore`)
|
|
305
|
-
- `extensions/cordis-client-runner/src/client/orchestrator.ts`(浏览器 cordis 编排)
|
|
306
|
-
- vendored 编译产物:`~/.dsh/profiles/node_modules/@deepseek-ai/{dsh-web-app,dsh-web-frontend,
|
|
307
|
-
dsh-cordis-client-runner,dsh-client-connection,dsh-api-gateway,dsh-api-remotes,dsh-client-ui-renderer,
|
|
308
|
-
dsh-typert-protocol}/package.json`(description + peerDependencies 取证的依赖图)
|
|
309
|
-
- 关联研究:`cordis-research.md`(Cordis 服务端时空可组合性)、`web-frontend-composability-research.md`
|
|
310
|
-
(Web 生态通用对照,本文是其 dsh 实测侧)
|
|
@@ -1,300 +0,0 @@
|
|
|
1
|
-
# DSH Web UI 剥离边界研究:对接任意 Agent Runtime 的可行性评估
|
|
2
|
-
|
|
3
|
-
> 记录:2026-09-03 · 一手核验:`~/workspaces/dashr/upstream/deepseek-harness`(tag `dsh-v0.1.2-alpha.5`)
|
|
4
|
-
> 源码逐包阅读 + 4999 实例实际服务 HTML 抓取(`.scratch/dsh-index.html`,24,954 bytes)+ prod npm
|
|
5
|
-
> 工件核验。前置研究:`dsh-web-profile-package-map.md`(220 包测绘)、`dsh-web-ui-slot-system-research.md`
|
|
6
|
-
> (slot 机制)、`web-frontend-composability-research.md`(Web 生态对照)。
|
|
7
|
-
>
|
|
8
|
-
> **研究问题**:把 DSH 的 Web 前端剥离成通用 Web UI,对接其他任何 Agent 运行时——剥离到哪一层
|
|
9
|
-
> 最干净?方案一(源码级)vs 方案二(浏览器资产物理层)哪个更落地?
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## 0. 一句话结论
|
|
14
|
-
|
|
15
|
-
**"源码级 vs 物理层"是个伪分叉——两条路交付的是同一套浏览器工件(shell dist + 51 个插件
|
|
16
|
-
client bundle + boot graph),真正的工作量(≈70%)在两者都不触碰的部分:服务端 wire 面
|
|
17
|
-
(HTTP unary RPC + WebSocket 流复用 + 认证 + boot graph 注入)。因此正确的剥离边界不是
|
|
18
|
-
"源码 or 资产",而是:**
|
|
19
|
-
|
|
20
|
-
```
|
|
21
|
-
┌─ 浏览器侧(原样保留,零改动)─────────────────────────────────────┐
|
|
22
|
-
│ apps/web shell dist + 40 个 ui-* 插件 + client 基建 + boot kernel │
|
|
23
|
-
├─ 4 条 wire 契约(需要被"别的 runtime"实现或代理)────────────────┤
|
|
24
|
-
│ ① 静态资产(纯文件) ② boot graph 注入 ③ /api unary ④ WS 流复用 │
|
|
25
|
-
├─ 服务端适配层(唯一的新代码)───────────────────────────────────┤
|
|
26
|
-
│ ~13 个 TypertRemoteService 命名空间的适配实现(可裁剪到 ~4 个) │
|
|
27
|
-
└──────────────────────────────────────────────────────────────────┘
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
**推荐:方案一的收敛形态"1b —— npm 工件组合(UI-BFF)"**。上游 MIT 许可、每个 npm 包自带
|
|
31
|
-
预构建 `lib/client.js`、boot graph 由我方服务端生成(资产组合权在手里)、插件 roster 就是字段
|
|
32
|
-
披露旋钮。方案二(物理层)的正确形态会**退化为 1b 的采集通道**(从 npm 拿工件比从 CDP 抓更干净);
|
|
33
|
-
CDP 的正确角色是**契约侦察与版本 diff 的验证工具**,不是交付路径。
|
|
34
|
-
|
|
35
|
-
---
|
|
36
|
-
|
|
37
|
-
## 1. 现状测绘:DSH Web UI 到底由什么组成
|
|
38
|
-
|
|
39
|
-
### 1.1 交付链(源码实证,非推测)
|
|
40
|
-
|
|
41
|
-
```
|
|
42
|
-
apps/web (vite 壳, @deepseek-ai/dsh-web-frontend)
|
|
43
|
-
└─ index.html + src/main.ts (11 行): new AppWebEntry(#root).run()
|
|
44
|
-
└─ @deepseek-ai/dsh-client-web "Web boot kernel" (packages/client/web, 371 行)
|
|
45
|
-
├─ seed.ts: 静态模块表 = 仅 8 个平台词
|
|
46
|
-
│ react / react/jsx-runtime / react-dom / react-dom/client /
|
|
47
|
-
│ @deepseek-ai/cordis / dsh-client-store / dsh-client-ui-slots / dsh-client-ui-primitives
|
|
48
|
-
├─ boot.ts: 等 __DSH_BOOT_READY__ → 读 window.__ModuleLoader__ /
|
|
49
|
-
│ __DSH_BOOT__ / __DSH_TRANSPORT__ → 建模块系统 → 起浏览器侧 cordis
|
|
50
|
-
│ → cordis-plugin-loader 逐个装载 manifest.plugins → ctx.inject(['uiRenderer']) mount
|
|
51
|
-
└─ boot-page.ts: 框架无关 boot 进度页(插件失败可见)
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
每个 UI 插件是**双半包**:host 半空 `apply()`(可加载体),browser 半真逻辑(`lib/client.js`,
|
|
55
|
-
closure-factory 形,经 `/plugins/<pkg>/client.js&rev=<hash>` 按需物化)。浏览器里
|
|
56
|
-
`dsh-cordis-client-runner` 再起一套完整 cordis,40 个 `ui-*` 经 SlotRegistry 组合成整棵 React 树
|
|
57
|
-
(整树唯一入口 `renderSlot('root')`)。**React 只是"当前安装的渲染器",插槽/状态层框架中立。**
|
|
58
|
-
|
|
59
|
-
### 1.2 实际服务的物理页(4999 实例抓取)
|
|
60
|
-
|
|
61
|
-
24,954 bytes,结构惊人地薄:
|
|
62
|
-
|
|
63
|
-
| 分段 | 内容 | 大小 |
|
|
64
|
-
|---|---|---|
|
|
65
|
-
| `<base href="/">` + queue script | `window.__ModuleLoader__` 引导门面(inline) | ~1.5 KB |
|
|
66
|
-
| combo preload | `/plugins/??<47 个插件>/client.js&rev=…`(一次合并拉取) | URL ~4 KB |
|
|
67
|
-
| bootstrap script | `/plugins/??@deepseek-ai/dsh-client-modules/client.js&rev=…` | 单条 |
|
|
68
|
-
| **boot graph** | `globalThis.__DSH_BOOT__ = {rev, entries:[{id,url,rev,inject,immediately}×51]}` | ~15 KB |
|
|
69
|
-
| 原生 dist 头 | meta/title/`assets/index-*.js`(413KB)/`vendor-*.js`(723KB)/2 个 css | 原样 |
|
|
70
|
-
| body inline | 主题初始化脚本 + `__DSH_BOOT_READY__` resolver + `#root` | ~0.5 KB |
|
|
71
|
-
|
|
72
|
-
**51 个 client bundle 合计 3.94 MB(未压缩)**,最大头:ui-conversation 606KB、ui-trajectory
|
|
73
|
-
382KB、ui-chat 351KB、api-remotes 296KB、cordis-client-runner 228KB。npm 包全部自带预构建
|
|
74
|
-
`lib/client.js`(prod vendored 树实证:ui-trajectory 391,199 bytes,与源码树构建产物同量级)。
|
|
75
|
-
|
|
76
|
-
### 1.3 wire 面:浏览器 ↔ 服务端的全部契约(4 条)
|
|
77
|
-
|
|
78
|
-
| # | 面 | 协议 | 细节(源码锚点) |
|
|
79
|
-
|---|---|---|---|
|
|
80
|
-
| ① | 静态资产 | HTTP GET | `/plugins/??a/client.js,b/client.js&rev=…` 合并拉取;rev=内容 hash,immutable cache;非 index 资产**公开**(frontend-static: "Non-index assets stay public") |
|
|
81
|
-
| ② | boot graph + 注入 | index 渲染时 inline | `webserver/index-inject` 事件收集结构化行(kind: global/script/script-src/style/html),renderIndexInjections 渲进 index.html;`__DSH_BOOT__` 就是一行 `{kind:'global'}` |
|
|
82
|
-
| ③ | unary RPC | HTTP POST `/api/<ns>/<method>` | envelope `{type:'client-request', rpcId, method, payload:{args:[…]}}` → `{type:'server-response', rpcId, result:{ok:true,value}\|{ok:false,error:{code,message,details}}}`(client/connection/src/client/rpc.ts);body 上限 300MB |
|
|
83
|
-
| ④ | 流复用 | WebSocket `/api/remote.mux` | gateway 持有 WS mux(REMOTE_STREAM_MUX_PATH,stream-protocol.ts,心跳可配);`session/follow`、`session/control`、workspace 流、转发事件都走它;另有 worker-local 载体可替代 |
|
|
84
|
-
| + | 认证 | `?token=` 一次 → HMAC cookie | `dsh-auth-<authority>` 签名 cookie,按 authority 绑定 audience,24h(browser-auth.ts);trustedHosts 栅栏 alpha.5 起服务端配置化 |
|
|
85
|
-
|
|
86
|
-
**关键事实:没有任何 REST 资源面,也没有隐式 DOM 数据通道。** UI 的全部数据与动作都走 ③④
|
|
87
|
-
两条 RPC 面——这就是"另一个 runtime"要实现的全部。
|
|
88
|
-
|
|
89
|
-
### 1.4 数据模型:SessionEvent 日志(UI 的粮食,也是诊断价值的来源)
|
|
90
|
-
|
|
91
|
-
append-only、无损 JSON、seq 连续递增(`packages/core/session/src/types.ts`),插件可扩展:
|
|
92
|
-
|
|
93
|
-
| 事件 | 载荷 | UI 呈现 |
|
|
94
|
-
|---|---|---|
|
|
95
|
-
| `turn/start` `turn/end` | turn + 结束原因(error/max-tokens/interrupted 结构化) | 回合边界、失败标记 |
|
|
96
|
-
| `step/start` `step/end` | turn+step | 每步 = 一次模型调用 + 其工具执行 |
|
|
97
|
-
| `user/message` | UserMessage(source 区分人类输入/注入上下文/goal 续轮) | 用户气泡 |
|
|
98
|
-
| `assistant/chunk` | 原始 StreamChunk | **token 级回放保真**(打字机效果、chunk runs 打包分页) |
|
|
99
|
-
| `assistant/message` | 组装后 AssistantMessage + usage(TokenUsage)+ interrupted 标记 | 助手消息、用量统计 |
|
|
100
|
-
| `tool/call` | callId + name + **模型原始 arguments 字符串(未解析)** | 工具卡 |
|
|
101
|
-
| `tool/result` | ToolResultMessage + 可选 error{name,code} + 可选 meta(JSON) | 工具结果卡(含 fs diff 等) |
|
|
102
|
-
| `request/header` | **EpochHeader = {config, adapterDefaults?, system?, tools?}** | Trajectory 的 **System Prompt 标签页** + 工具清单 + 请求配置;缺失时有显式兜底文案(`record.systemPromptMissing: '本次请求没有系统提示词'`) |
|
|
103
|
-
| `request/context` | provider/model/contextWindow | 模型路由元数据 |
|
|
104
|
-
| `session/end-seed` | 空 | fork/resume 种子分界 |
|
|
105
|
-
|
|
106
|
-
**降级是设计内行为**(三条证据):① 未知事件带 `ignorable: true` 语义为"读者可安全跳过";
|
|
107
|
-
② `request/header` 缺失 → trajectory 显式渲染"本次请求没有系统提示词"占位;③ 插件缺席 → 槽位
|
|
108
|
-
渲染为空(patch 注释原文:"Absent a roster it renders nothing"、"Remove this entry to turn the
|
|
109
|
-
surface off; the tail hole renders empty")。**这正是用户看中的"字段缺失不崩溃"容错性的机制层根
|
|
110
|
-
据:事件子集可以任意裁剪,UI 按在场字段渲染。**
|
|
111
|
-
|
|
112
|
-
### 1.5 服务端 RPC 面:~13 个 TypertRemoteService 命名空间
|
|
113
|
-
|
|
114
|
-
endpoint 命名 = `<namespace>/<method>`,浏览器侧由 `api-remotes` 装配成 `ctx.remote.*`。全仓
|
|
115
|
-
`extends TypertRemoteService` 盘点(排除实验性):
|
|
116
|
-
|
|
117
|
-
| 命名空间 | 方法面(核心) | 服务端 inject 依赖(适配缝) | 必要性 |
|
|
118
|
-
|---|---|---|---|
|
|
119
|
-
| `session` | list/search/create/rename/fork/**prompt**/attachment/updateQueue/**cancel**/**page**/**follow**(流)/**control**(流)/selectModel/modelCatalog/openWorkspacePath + file-references/skill-catalog 子面 | sessions, sessionProjections, sessionQuery, agents, llm, attachments, workspaceRegistry, agentDefaultModel | **核心:聊天+历史+trajectory 的全部** |
|
|
120
|
-
| `workspace` | create/rename/delete/insertBefore/insertSessionBefore/archiveSession + 流 | workspaceRegistry | 侧栏工作区(可 stub) |
|
|
121
|
-
| `settings` + `credentials` | describe/get/set 等 7 方法 | settings-domains | 设置页(可 memory-stub;注意 describe mirror 在非 loopback 页 terminally unavailable 的既有缺口) |
|
|
122
|
-
| `llm` | listProviders/listConfigurableProviders/discoverModels | llm | 模型选择器(可最小 stub) |
|
|
123
|
-
| `presets` | roster | agent-presets | 无 roster → 不渲染 |
|
|
124
|
-
| `pluginInventory` | 目录只读投影 | loader entries | 插件页(可缺) |
|
|
125
|
-
| `goals` / `feedback` / `commands` / `subagents` / `dynamicCordis`(host-runner) | 各自小面 | 各服务 | 全部可缺(对应 UI 区块静默退化) |
|
|
126
|
-
|
|
127
|
-
**注意**:适配器不必实现这些 controller 类本身——controller 只是命名空间的"一种实现"。对接
|
|
128
|
-
其他 runtime 时直接以任意代码实现 endpoint 语义即可;schemastery 校验发生在 gateway 侧,但
|
|
129
|
-
envelope 是自描述 JSON。
|
|
130
|
-
|
|
131
|
-
### 1.6 组合面:roster = 披露旋钮
|
|
132
|
-
|
|
133
|
-
浏览器加载哪些插件完全由 boot graph 决定,boot graph 由 host 侧 loader 条目扫描
|
|
134
|
-
`dsh.client` 声明而来,而 loader 条目由 `cordis.patch.yml` 层序决定(bundles 列序 → profile →
|
|
135
|
-
home → `--patch`)。**因此"减少字段披露"有两级旋钮:**
|
|
136
|
-
|
|
137
|
-
1. **UI 级**:patch 行 `disabled: true`(如上游自带 `ui-schedule` 就是 disabled 出厂的)——
|
|
138
|
-
去掉 `ui-trajectory` 行 = 整个 trajectory 面消失;去掉 `ui-settings-*` = 设置页消失。
|
|
139
|
-
2. **数据级**:适配器不写 `request/header`/`assistant/chunk` 等事件 = 对应标签页/字段静默缺失。
|
|
140
|
-
|
|
141
|
-
甚至**在物理模式下 UI 扩展性仍然存活**:boot graph 由我方服务端生成,追加自有插件行(自己的
|
|
142
|
-
client.js + 槽位注册,lower priority 遮蔽官方组件)即可覆盖任意 UI 细节——dashr/better-sidebar
|
|
143
|
-
正是这样随插件发布 UI 的,机制对第三方开放。
|
|
144
|
-
|
|
145
|
-
---
|
|
146
|
-
|
|
147
|
-
## 2. 方案一(源码级剥离)评估
|
|
148
|
-
|
|
149
|
-
### 2.1 原样保留的部分(两条子路径共享)
|
|
150
|
-
|
|
151
|
-
- `apps/web` 壳 + `packages/client/web`(boot kernel)+ `packages/client/*` 全部 ui-*/基建 +
|
|
152
|
-
`packages/api/remotes`(浏览器半)+ `packages/typert/*` + `cordis-client-runner`。
|
|
153
|
-
- 这些包**已经高度自洽**:浏览器侧唯一的外部世界就是 1.3 的 4 条 wire 面。
|
|
154
|
-
|
|
155
|
-
### 2.2 需要替换/新写的部分
|
|
156
|
-
|
|
157
|
-
1. **wire 面载体**(若脱离 dsh 宿主):webserver(通用 node:http,无 harness 概念)、
|
|
158
|
-
frontend-static(通用 dist 服务)、auth、client-modules 的 host 半(boot graph 组合器 + /plugins
|
|
159
|
-
文件服务)。**注意 client-modules host 半与 cordis-plugin-loader 条目耦合**——若对接方宿主不跑
|
|
160
|
-
cordis,不装它,自己写一个静态 graph 组合器(本质是"读一份插件清单 JSON + 算 hash + 拼
|
|
161
|
-
entries",≈200 行;4999 实例的 graph 就是实证样板)。
|
|
162
|
-
2. **适配层**:1.5 表中裁剪后的命名空间实现(最小集 = `session` 的 8 个方法 + 2 个流 +
|
|
163
|
-
`llm.listProviders` stub + `workspace` 三方法)。
|
|
164
|
-
|
|
165
|
-
### 2.3 分寸:1a(全源 fork)vs 1b(npm 工件组合)
|
|
166
|
-
|
|
167
|
-
| 维度 | 1a:源码 fork | 1b:npm 工件组合(UI-BFF) |
|
|
168
|
-
|---|---|---|
|
|
169
|
-
| 获取 | clone monorepo,跑 pnpm+tsdown+tsdown.client 全工具链 | `npm i @deepseek-ai/dsh-client-ui-*`(每个包自带 lib/client.js)+ `@deepseek-ai/dsh-web-frontend` dist |
|
|
170
|
-
| 构建负担 | 269 projects,本机还需 2 个必须 patch(见 AGENTS.md) | **零构建**(shell dist 与 client bundle 都是发布产物) |
|
|
171
|
-
| 修改能力 | 任意改 UI 源码 | 不改上游 UI;靠 roster 裁剪 + 自有插件行遮蔽(§1.6) |
|
|
172
|
-
| 版本跟踪 | 每次 upstream 变更手动合并 | 改 package.json 版本号重装 |
|
|
173
|
-
| cordis 依赖 | 浏览器半自带 cordis(模块表平台词);host 半可全弃 | 同左;宿主侧只需自己选型的 BFF 服务 |
|
|
174
|
-
| 法律 | MIT(保留版权声明即可) | MIT 同 |
|
|
175
|
-
|
|
176
|
-
**判定:1b 是方案一的最优收敛形态。** 1a 只在"必须改上游 UI 组件内部"时才值得,而 slot 遮蔽
|
|
177
|
-
机制让绝大多数"改"都能以自有插件行完成。1b 的实质:**把 dsh 剥成一个纯 UI-BFF**——agent
|
|
178
|
-
runtime 在外面,BFF 只做 4 条 wire 面 + 适配器。
|
|
179
|
-
|
|
180
|
-
### 2.4 1b 的一个激进变体(可选,低优先):最小 cordis 宿主
|
|
181
|
-
|
|
182
|
-
不弃 host 半 cordis,而是跑一个**只挂载体插件的 cordis 宿主**(webserver + frontend-static +
|
|
183
|
-
client-modules + connection + gateway 原样复用,SessionController 等以自定义 cordis 插件替换
|
|
184
|
-
provider)。好处:wire 面 100% 原样、免复刻 WS mux;代价:引入 cordis loader 心智 + 上游这层
|
|
185
|
-
无稳定性承诺。**适合作为 PoC 对照,不建议作长期承诺层。**
|
|
186
|
-
|
|
187
|
-
---
|
|
188
|
-
|
|
189
|
-
## 3. 方案二(浏览器资产物理层剥离)评估
|
|
190
|
-
|
|
191
|
-
### 3.1 用户设想:CDP/DOM 分析 → 抓 HTML/JS/CSS 静态资产
|
|
192
|
-
|
|
193
|
-
**可行的部分**:资产确实干净可抓——index.html(含 boot graph)+ `/plugins/*` bundle +
|
|
194
|
-
`/assets/*`,全部静态文件,combo URL 就是清单。不含 source map 需求(client.js.map 随包发布,
|
|
195
|
-
npm 工件里就有)。
|
|
196
|
-
|
|
197
|
-
**不成立的部分**:抓到资产 ≠ 剥离完成。页面不是静态站,是"从服务端注入的 graph 引导的运行
|
|
198
|
-
时":没有 ③④ 两条 RPC 面,壳渲染到 boot 失败页(`web boot: … did not activate` /
|
|
199
|
-
auth 拒绝)。**物理层绕不开的工作量与方案一完全相同(服务端 wire 面 + 适配器)——而那才是
|
|
200
|
-
70% 的工作。** 换言之,方案二节省的只有"获取/构建资产"这一步,而这一步在 1b 里本来就已经
|
|
201
|
-
是零成本(npm 拉包)。
|
|
202
|
-
|
|
203
|
-
### 3.2 修正后的定位
|
|
204
|
-
|
|
205
|
-
| 用途 | 评价 |
|
|
206
|
-
|---|---|
|
|
207
|
-
| **交付路径**(物理剥离 UI 给别的 runtime) | ❌ 不推荐:与 1b 工作量相同但更糟——从实例抓的资产无版本锚(rev hash 换版即漂)、无 license 文件伴随、无 source map 归档、组合关系靠逆向 |
|
|
208
|
-
| **采集通道**(拿资产本身) | ✅ 但正确姿势是从 **npm 工件**采集(=1b),不是从 CDP;CDP 抓取仅在"验证某实例实际服务的组合"时有用 |
|
|
209
|
-
| **契约侦察**(经验性摸 wire 面) | ✅ 有价值:Network 面板可直接观察 envelope/流帧/认证流,是源码分析的交叉验证;本轮源码结论与之吻合 |
|
|
210
|
-
| **版本 diff**(upstream 升级影响面) | ✅ 有价值:两版实例各抓一份 boot graph,entries/inject 差分即 UI 组合变更面 |
|
|
211
|
-
|
|
212
|
-
**判定:方案二不是独立方案,是方案一(1b)的一个采集/验证通道。** 用户设想的"如果源码太复杂
|
|
213
|
-
就绕开源码"——实际源码复杂度 concentrated 在我们**本来就要丢掉的部分**(agent/session 核心),
|
|
214
|
-
浏览器侧源反而极薄(boot kernel 371 行 + 每插件独立小包),"必须绕开源码"的前提不成立。
|
|
215
|
-
|
|
216
|
-
---
|
|
217
|
-
|
|
218
|
-
## 4. 对接任意 runtime:具体路径与工作量
|
|
219
|
-
|
|
220
|
-
### 4.1 适配器要实现的 endpoint(最小可用集,建议 PoC 范围)
|
|
221
|
-
|
|
222
|
-
```
|
|
223
|
-
session/list → 会话列表(标题、mtime、cwd、origin 等 SessionSummary 字段,可稀疏)
|
|
224
|
-
session/create → 新会话(cwd 或 workspaceId)
|
|
225
|
-
session/prompt → 提交用户输入(附件引用可选)
|
|
226
|
-
session/cancel → 取消当前回合
|
|
227
|
-
session/page → 冷读历史(header + 事件 + chunk runs + projection baseline)
|
|
228
|
-
session/follow → 流:开场快照 + 无缝事件帧(活跃回合适时;冷会话 page 足够)
|
|
229
|
-
session/control → 流:活跃会话控制基线 + 替换帧(busy 状态、队列;无则可给最小帧)
|
|
230
|
-
llm/listProviders / listConfigurableProviders → 模型目录(可静态单条)
|
|
231
|
-
workspace/* → 侧栏工作区(可先固定单工作区)
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
### 4.2 数据映射(其他 runtime → SessionEvent)
|
|
235
|
-
|
|
236
|
-
| 其他 runtime 常见概念 | 映射到 | 缺失后果 |
|
|
237
|
-
|---|---|---|
|
|
238
|
-
| 用户消息 | `user/message` | —(必需) |
|
|
239
|
-
| 助手回复(整段) | `assistant/message`(无 chunk) | 无打字机效果,消息整段出现 |
|
|
240
|
-
| 流式 token | `assistant/chunk`(可选增强) | 缺 = 无 token 级回放 |
|
|
241
|
-
| 工具调用/结果 | `tool/call`(原始 arguments 字符串)+ `tool/result`(含 error 结构) | 缺 = 无工具卡 |
|
|
242
|
-
| system prompt / 工具清单 | `request/header.system` / `.tools` | 缺 = trajectory 无 System Prompt 标签(有显式占位文案) |
|
|
243
|
-
| 模型/上下文窗 | `request/context` | 缺 = 路由元数据不显示 |
|
|
244
|
-
| 回合失败/中断 | `turn/end.reason`(结构化 LlmFailure \| max-tokens \| interrupted) | 缺 = 回合无失败标记 |
|
|
245
|
-
| token 用量 | `assistant/message.usage` | 缺 = 无统计条 |
|
|
246
|
-
|
|
247
|
-
事件发射的时序契约:seq 单调连续、turn/step 包裹、surface 事件带 surfaceOp(append/replace)。
|
|
248
|
-
对接方不需要理解 cordis——**只需产出一个符合 discriminated-union 的 JSON 事件日志**。
|
|
249
|
-
|
|
250
|
-
### 4.3 工作量估算(粗)
|
|
251
|
-
|
|
252
|
-
| 块 | 规模 | 备注 |
|
|
253
|
-
|---|---|---|
|
|
254
|
-
| BFF 骨架(静态服务 + boot graph 组合器 + auth + /api 路由) | ~500–800 行 | 全部是薄胶水;WS mux 若不想复刻可先只做 unary + 轮询降级?——**不可**:`follow`/`control` 是流,follow 可用 page 轮询近似,control 建议复刻简化 mux 或借用 gateway 包 |
|
|
255
|
-
| session 适配器(含事件日志转换) | 视 runtime 复杂度,~300–1000 行 | 核心成本在事件模型映射 |
|
|
256
|
-
| 组合配置(roster patch) | ~100 行 YAML | 披露旋钮即在此 |
|
|
257
|
-
| 验证 | 壳冒烟(S7 式:boot graph → bundle URL 200 → 会话收发) | 已有成熟验证法 |
|
|
258
|
-
|
|
259
|
-
### 4.4 风险与开放问题
|
|
260
|
-
|
|
261
|
-
1. **版本不稳定(最大风险)**:`0.1.2-alpha.x`、`SESSION_FORMAT_VERSION=0`(源码注释明示
|
|
262
|
-
"no compatibility is implied, incompatible logs are rejected")。wire 面与事件词汇随版本可变。
|
|
263
|
-
缓解:锁精确版本;升级前跑 §3.2 的 boot-graph diff;适配器事件面尽量只发核心词汇。
|
|
264
|
-
2. **WS 流复用协议**未在本轮逐帧逆向(`stream-protocol.ts`);若走 1b+自写 BFF 需一次
|
|
265
|
-
帧格式侦察(源码在,量小)。或直接复用 `@deepseek-ai/dsh-api-gateway` 包(变体 2.4)。
|
|
266
|
-
3. **settings describe mirror 的非 loopback 缺口**:上游已知问题(skill web-ui.md §6),
|
|
267
|
-
Settings/Models 页在 remote 页面 terminally unavailable——对接方实例若非 loopback 托管,
|
|
268
|
-
设置面要么修(自有插件行补偿)要么 roster 裁掉。
|
|
269
|
-
4. **品牌/文案**:ui-brand-official、DSH 字样、manifest——对外复用需 roster 替换品牌槽或
|
|
270
|
-
接受原样(MIT 允许,但商标礼貌上应替换;`brand.mark`/`brand.name` 就是为此设计的槽)。
|
|
271
|
-
5. **HMR/preview 等附属面**(`/plugins/events`、worker preview)可整体不实现,不影响主链。
|
|
272
|
-
|
|
273
|
-
---
|
|
274
|
-
|
|
275
|
-
## 5. 裁决
|
|
276
|
-
|
|
277
|
-
1. **剥离边界**:浏览器半 + 4 条 wire 契约是"保留层";TypertRemoteService 实现是"替换层"。
|
|
278
|
-
方案一/二的真正分叉只在保留层的**获取与修改方式**。
|
|
279
|
-
2. **方案一(源码级)胜出,且应收敛为其 1b 形态**(npm 工件组合 + 自写 BFF + roster 组合)。
|
|
280
|
-
理由:零构建、版本可锚、MIT 干净、披露两级旋钮、UI 扩展不经 fork。
|
|
281
|
-
3. **方案二(物理层)不作为独立路线**:其收益(绕开源码)被事实否证——浏览器侧源码薄且
|
|
282
|
-
npm 工件本就预构建;其不可绕开的部分(服务端 wire 面)与方案一相同。CDP 保留两个辅助
|
|
283
|
-
角色:wire 契约的经验性验证、跨版本 boot-graph diff。
|
|
284
|
-
4. **PoC 建议(半天级)**:写死一份 boot graph(从 4999 抄)+ file server 服务 npm 拉的 51 个
|
|
285
|
-
bundle + 实现 `session/list|create|prompt|page` 四个 unary(无 WS,先只读+假发送)→ 浏览器
|
|
286
|
-
打开能看到会话列表与历史渲染,即证明边界正确。第二步补 `follow` 流与真 prompt。
|
|
287
|
-
|
|
288
|
-
## 来源
|
|
289
|
-
|
|
290
|
-
- 源码(alpha.5 checkout):`packages/client/web/{boot,seed,platform}.ts`、`packages/client/modules/src/index.ts`
|
|
291
|
-
(boot graph 组合 + /plugins 服务)、`packages/host/webserver/src/{index,injections}.ts`、
|
|
292
|
-
`packages/host/frontend-static/src/index.ts`、`packages/client/connection/src/{http-bridge,browser-auth}.ts`
|
|
293
|
-
+ `src/client/rpc.ts`(unary envelope)、`packages/api/gateway/src/index.ts` + `stream-protocol.ts`
|
|
294
|
-
(WS mux `/api/remote.mux`)、`packages/api/session-controller/src/index.ts`(@Remote 全量)、
|
|
295
|
-
`packages/api/remotes/src/client/index.ts`(浏览器装配)、`packages/core/session/src/types.ts`
|
|
296
|
-
(SessionEventMap 全量)、`packages/bundle/web-app/cordis.patch.yml`(roster 原文)
|
|
297
|
-
- 实例取证:4999 鉴权抓取 `.scratch/dsh-index.html`(boot graph 51 条、combo URL、注入行);
|
|
298
|
-
`~/.dsh/profiles/node_modules/@deepseek-ai/dsh-client-ui-trajectory/lib/client.js`(npm 工件含
|
|
299
|
-
预构建 bundle);51 bundle 体量盘点(3.94MB)
|
|
300
|
-
- 前置研究:本目录三篇(见文首);`.agents/skills/dsh-plugin-development/references/web-ui.md`
|