feat(workspace): open the workspace in local apps from the web UI (#3409)

Add the first-party open-in-app host and client packages with a localized Open In menu in the Web Session header.

Resolve installed applications on macOS, Windows, and Linux, launch workspace directories through platform-specific adapters, and remember the selected application.

Closes #1500.

Co-authored-by: ihsiang <ihsiang@deepseek.com>
This commit is contained in:
ihsiang
2026-09-07 17:58:11 +08:00
committed by GitHub
parent 9d93c57053
commit 9292dd8a2d
64 changed files with 5087 additions and 28 deletions
+2
View File
@@ -99,6 +99,8 @@ describe('client bundle purity gate', () => {
expect(resolveId('@deepseek-ai/dsh-token-meter/client')).toBeNull()
expect(() => resolveId('@deepseek-ai/dsh-token-meter')).toThrow(/purity/)
expect(() => resolveId('@deepseek-ai/dsh-token-meter/client/internal')).toThrow(/purity/)
expect(resolveId('@deepseek-ai/dsh-host-open-in-app/shared')).toBeNull()
expect(() => resolveId('@deepseek-ai/dsh-host-open-in-app')).toThrow(/purity/)
})
it('admits only the pure spill notice entry, not its Host policy', () => {
@@ -128,6 +128,8 @@ const SENTENCE_MODEL_EXPERIENCE: Readonly<Record<string, SentenceContract>> = {
'packages/webhook/webhook-github': { kind: 'indirect', reason: 'The adapter delegates model-visible text to matching rules and dsh-webhook.' },
'packages/host/frontend-static': { kind: 'none', reason: 'The SPA dist server answers browser asset requests and registers nothing model-facing.' },
'packages/host/plugin-inventory': { kind: 'none', reason: 'Host-side read-only Loader projection; registers nothing model-facing.' },
'packages/host/open-in-app': { kind: 'none', reason: 'Host routes opening desktop applications for a human; registers nothing model-facing.' },
'packages/client/ui-open-in-app': { kind: 'none', reason: 'Browser-side split button opening the workspace directory for a human; registers nothing model-facing.' },
'packages/bundle/base': { kind: 'indirect', reason: 'The bundle is a patch-list carrier; each inserted row\'s package owns its model-facing behavior.' },
'packages/bundle/headless': { kind: 'none', reason: 'The one-shot runner submits the task as an ordinary user message; prompts and tools belong to the composed base and headless bundles.' },
'packages/llm/llm': { kind: 'none', reason: 'The adapter registry forwards already-assembled requests unchanged.' },