dsh-edge 0.2.0 → 0.3.0-alpha.1
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/README.i18n.yaml +2 -2
- package/README.md +11 -8
- package/README.zh.md +11 -8
- package/THIRD_PARTY_NOTICES.md +447 -348
- package/dist/assets/{index-BNMwCG9c.css → index-C6eRlFa6.css} +1 -1
- package/dist/assets/{index-CA9Bpko5.js → index-ClqxG24t.js} +35 -35
- package/dist/index.html +3 -3
- package/dist/plugins/@deepseek-ai/dsh-api-gateway/client.js +84 -55
- package/dist/plugins/@deepseek-ai/dsh-client-connection/client.js +10 -6
- package/dist/plugins/@deepseek-ai/dsh-client-runtime/client.js +15 -6
- package/dist/plugins/@deepseek-ai/dsh-client-ui-attachment/client.js +782 -0
- package/dist/plugins/@deepseek-ai/dsh-client-ui-conversation/client.js +188 -72
- package/dist/plugins/@deepseek-ai/dsh-client-ui-permission-presets/client.js +46 -13
- package/dist/plugins/@deepseek-ai/dsh-client-ui-sidebar/client.js +1 -1
- package/dist/plugins/@deepseek-ai/dsh-client-ui-subagent/client.js +287 -128
- package/dist/plugins/@deepseek-ai/dsh-client-ui-user-questions/client.js +46 -9
- package/dist/plugins/@deepseek-ai/dsh-client-ui-workspace/client.js +26 -0
- package/package.json +25 -22
- package/scripts/cli.mjs +3 -0
- package/scripts/install.d.mts +25 -0
- package/scripts/install.mjs +185 -6
- package/scripts/legal-files.mjs +5 -1
- package/scripts/wrangler-config-core.mjs +28 -0
- package/scripts/wrangler-config.d.mts +1 -0
- package/worker/direct/index.js +1021 -991
- package/worker/isolated/index.js +677 -647
package/README.i18n.yaml
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
# last confirmed-consistent state. Both languages carry equal authority.
|
|
3
3
|
# After editing either side, update both and re-record every pair with:
|
|
4
4
|
# pnpm run doc-pairs -- --write
|
|
5
|
-
README.md:
|
|
6
|
-
README.zh.md:
|
|
5
|
+
README.md: 8f0179678a006d175cbb9207577f78654bc9ca69
|
|
6
|
+
README.zh.md: f69246647c123e8633138a5032c5556724ab2d22
|
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ The checked-in Wrangler configuration exposes two deployment targets from the sa
|
|
|
10
10
|
|
|
11
11
|
The runtime runs persistent conversations through the upstream Cordis-composed `ReactLoopAgent`, `AgentRegistry`, `LlmRuntime`, `ToolRuntime`, `SystemPrompt`, `SessionStore`, and `SessionPersistence`. Edge code only binds a request-scoped DeepSeek adapter and maps one native DSH `bash` tool definition onto Cloudflare Computer. Durable Object SQLite implements the upstream persistence backend contract; `PersistenceCoordinator` still owns write-behind, revisions, resume preparation, and crash recovery. Model history is projected from canonical events rather than persisted separately.
|
|
12
12
|
|
|
13
|
-
The browser is the upstream Web shell and upstream client-plugin bundles. A build-time assembler derives the browser roster from the upstream base and Web bundle configs, injects the standard `window.__DSH_BOOT__` graph, and publishes the result as Cloudflare static assets. The Durable Object implements the supported upstream `ApiProxy` methods through the standard HTTP carrier and supplies the two upstream downlinks as hibernatable WebSockets. Edge excludes client plugins whose host domains are absent instead of forking their UI code; this includes session-log export until its server endpoint exists. A small Edge-owned login shell protects the upstream UI and protocol without changing either one. Optional local-host plugins remain unavailable.
|
|
13
|
+
The browser is the upstream Web shell and upstream client-plugin bundles. A build-time assembler derives the browser roster from the upstream base and Web bundle configs, injects the standard `window.__DSH_BOOT__` graph, and publishes the result as Cloudflare static assets. The Durable Object implements the supported upstream `ApiProxy` methods through the standard HTTP carrier and supplies the two upstream downlinks as hibernatable WebSockets. The upstream image composer, gallery, lightbox, attachment wire contract, and DeepSeek serializer are reused unchanged; the storage seam selects private R2 for new permanent deployments and bounded Durable Object storage for temporary deployments. Edge excludes client plugins whose host domains are absent instead of forking their UI code; this includes session-log export until its server endpoint exists. A small Edge-owned login shell protects the upstream UI and protocol without changing either one. Optional local-host plugins remain unavailable.
|
|
14
14
|
|
|
15
15
|
## Run locally
|
|
16
16
|
|
|
@@ -99,7 +99,7 @@ This reference separates code that runs natively in Workers, code adapted at an
|
|
|
99
99
|
| Workspace registry | Storage-domain global state plus `WorkspaceRecord` rows | Native backend adaptation | Keep the upstream global and record value shapes, including manual session order and archive membership, but map their physical keys and atomic writes to Durable Object storage. Edge constrains the registry to the one native `/workspace` VFS; rename, delete, recreation, and session reordering retain the upstream RPC and Host-frame semantics. |
|
|
100
100
|
| Existing Web UI | Runtime-loaded shell and `dsh.client` plugin graph | Reused with generic composition fallbacks | Assemble the upstream shell and supported upstream client bundles as Worker assets. Shared slot-occupancy rules hide actions whose provider is absent; Cloudflare serves ordinary assets directly, while `/`, `/login`, and `/api/*` enter the Worker for owner access control. The assembled asset policy prevents every direct or SPA-fallback shell alias from being framed. |
|
|
101
101
|
| Other tools | Web Search, filesystem editor tools, MCP, skills, workflows, jobs, and subagents | Search ported; others not ported | Reuse upstream DeepSeek Web Search with its 30-second tool-call timeout. Add the remaining tools individually against Worker-compatible capabilities; do not advertise unavailable host behavior. |
|
|
102
|
-
| Attachments | Local attachment storage
|
|
102
|
+
| Attachments | Local attachment storage, upstream image references, composer, gallery, lightbox, and provider conversion | Adapted at the native storage seam | Reuse upstream `AttachmentStore`, admission, protocol, authorization, UI, and DeepSeek conversion unchanged. Store immutable PNG/JPEG bytes under their SHA-256 identities in private R2 for new permanent deployments or in a 64 MiB, 512 KiB-chunked DO fallback for temporary deployments; session events retain only upstream refs. The first backend is pinned per owner instance so claiming or upgrading cannot strand existing references. |
|
|
103
103
|
| Authentication and tenancy | Local trusted-user boundary | Single-owner adaptation | Require one high-entropy Worker secret, exchange it for a signed 30-day HttpOnly `SameSite=Strict` cookie, and route every accepted request to one fixed owner object. This intentionally provides no registration, user database, roles, or multi-tenant routing. |
|
|
104
104
|
|
|
105
105
|
The browser request path is:
|
|
@@ -109,12 +109,15 @@ Cloudflare static assets -> upstream Web shell + client plugin graph
|
|
|
109
109
|
-> POST /api/session.create through the upstream HTTP carrier
|
|
110
110
|
-> host/workspace-changed + session/subscribed over Durable Object WebSockets
|
|
111
111
|
-> POST /api/session.prompt with the client rpcId
|
|
112
|
+
-> upstream image admission validates and stores immutable bytes in private R2
|
|
113
|
+
-> canonical session events retain upstream sha256 attachment refs only
|
|
112
114
|
-> AgentRegistry live lookup or resume
|
|
113
115
|
-> sessionPersistence.prepare through PersistenceCoordinator on cold resume
|
|
114
116
|
-> ReactLoopAgent.followup(queue) or ReactLoopAgent.steer(steer)
|
|
115
117
|
-> pre-step admission gate waits for the sessions.flush durability barrier
|
|
116
118
|
-> session/queue snapshots publish live and replay on mux reconnect
|
|
117
119
|
-> turn-scoped DeepSeekAdapter configuration selected by sessionId
|
|
120
|
+
-> upstream attachment resolver reads and verifies authorized backend bytes
|
|
118
121
|
-> upstream LlmRuntime + ReactLoopAgent stream/event pipeline
|
|
119
122
|
-> upstream ToolRuntime native bash or web_search call
|
|
120
123
|
-> upstream WebRuntime + DeepSeek native search provider for web_search
|
|
@@ -128,7 +131,7 @@ Cloudflare static assets -> upstream Web shell + client plugin graph
|
|
|
128
131
|
-> upstream Web runtime reconciles and renders the canonical events
|
|
129
132
|
```
|
|
130
133
|
|
|
131
|
-
The local integration check uses an SSE stand-in and the real Wrangler, Durable Object SQLite, the default direct Computer workspace backend, static asset service, HTTP carrier, and WebSockets. It verifies owner login, API and WebSocket cookie enforcement, rejection of legacy instance selectors, disabled direct-shell networking, the upstream session create/list/history/search/prompt/rename/fork flow; queue edit, removal, and promotion to steering; workspace create/list/rename/delete/session reorder/archive; the corresponding live and reconnect baselines and Host frames; real browser boot and UI-issued workspace rename, turn, content search, branch, and archive actions; automatic return to login when the browser session expires; conversation continuity, event replay, two-step bash and Web Search tool exchanges, and restoration after a Wrangler restart. A focused failure test proves that a post-enqueue durability failure blocks model use without reporting the already-woken prompt as rejected. Committed model-visible and ARIA goldens pin the tool transcripts and the assembled upstream Web client through the Edge HTTP/WebSocket protocol. A live DeepSeek call requires the developer's own key and is intentionally not part of the repository test suite.
|
|
134
|
+
The local integration check uses an SSE stand-in and the real Wrangler, Durable Object SQLite, local R2, the default direct Computer workspace backend, static asset service, HTTP carrier, and WebSockets. Direct mode exercises the temporary DO attachment backend while Isolated mode exercises private R2. It verifies owner login, API and WebSocket cookie enforcement, rejection of legacy instance selectors, disabled direct-shell networking, the upstream session create/list/history/search/prompt/rename/fork flow; an image prompt through the upstream composer/protocol/provider path; authorized attachment reads, cross-session rejection, fork reuse, and attachment persistence after restart; queue edit, removal, and promotion to steering; workspace create/list/rename/delete/session reorder/archive; the corresponding live and reconnect baselines and Host frames; real browser boot and UI-issued workspace rename, image turn, content search, branch, and archive actions; automatic return to login when the browser session expires; conversation continuity, event replay, two-step bash and Web Search tool exchanges, and restoration after a Wrangler restart. A focused failure test proves that a post-enqueue durability failure blocks model use without reporting the already-woken prompt as rejected. Committed model-visible and ARIA goldens pin the tool transcripts and the assembled upstream Web client through the Edge HTTP/WebSocket protocol. A live DeepSeek call requires the developer's own key and is intentionally not part of the repository test suite.
|
|
132
135
|
|
|
133
136
|
## API-key boundary
|
|
134
137
|
|
|
@@ -152,7 +155,7 @@ Run the stable installer without cloning this repository:
|
|
|
152
155
|
npx dsh-edge install
|
|
153
156
|
```
|
|
154
157
|
|
|
155
|
-
This resolves through npm's `latest` channel. Use `npx dsh-edge@next install`
|
|
158
|
+
This resolves through npm's `latest` channel. Use `npx dsh-edge@next install` to test the current 0.3 prerelease with upstream model selection and image prompts.
|
|
156
159
|
|
|
157
160
|
Upgrade an existing named Worker with the same runtime choice. The deployment keeps its Durable Object data; because Cloudflare secrets are write-only, the upgrade asks for the owner access key and DeepSeek API key again and replaces their active values:
|
|
158
161
|
|
|
@@ -164,7 +167,7 @@ npx dsh-edge upgrade
|
|
|
164
167
|
|
|
165
168
|
If the installed version is a 0.2 alpha, promote it to the stable channel once with `npx dsh-edge@latest upgrade`; prerelease deployments otherwise remain on `next`. The Edge settings page derives the channel from the installed version and copies the matching command.
|
|
166
169
|
|
|
167
|
-
The installer asks for the runtime before the account. The recommended `Free — Direct Shell` mode works on Workers Free and can use a detected Cloudflare account, open Cloudflare sign-in or registration, or create a temporary account without login. `Isolated — Dynamic Worker` requires Workers Paid and therefore offers only a detected or newly authenticated account. Cloudflare does not expose a reliable local entitlement check for Worker Loader, so an isolated install lets Cloudflare authorize the upload and turns a rejection into a choice between enabling Workers Paid and using direct mode.
|
|
170
|
+
The installer asks for the runtime before the account. The recommended `Free — Direct Shell` mode works on Workers Free and can use a detected Cloudflare account, open Cloudflare sign-in or registration, or create a temporary account without login. `Isolated — Dynamic Worker` requires Workers Paid and therefore offers only a detected or newly authenticated account. Cloudflare does not expose a reliable local entitlement check for Worker Loader, so an isolated install lets Cloudflare authorize the upload and turns a rejection into a choice between enabling Workers Paid and using direct mode. For a new permanent account installation, the installer creates or reuses a private `<worker-name>-attachments` R2 bucket and writes only its binding to the generated private Wrangler config. It never deletes the bucket on deployment failure. R2 must be enabled for the selected account; otherwise the installer provides the activation/retry path. Temporary accounts use a 64 MiB Durable Object attachment backend and support the same upstream image UI. Claiming preserves that backend and its existing image history; automatic migration to R2 is not implemented. Each new deployment records an explicit attachment-storage marker. Before updating an existing Worker, the installer inspects every active version, preserves the marked R2-or-DO choice, initializes an unmarked pre-attachment release on private R2, and refuses a mixed rollout rather than guessing.
|
|
168
171
|
|
|
169
172
|
The remaining prompts select a Worker name, generate or accept the owner access key, collect the DeepSeek API key through hidden input, and show a final cost summary. A temporary-account install also asks the user to accept Cloudflare's Terms of Service and Privacy Policy explicitly. An existing Worker is never overwritten without confirmation. The installer passes both credentials through a mode-`0600` temporary secrets file and gives Wrangler only an allowlisted runtime environment plus the Cloudflare authentication selected for that command; unrelated ambient keys, tokens, passwords, secrets, and Node injection options do not reach the child. It removes the secret file after the command and discovers the resulting URL from Wrangler's structured output. Deployment output is hidden behind one progress indicator by default; add `--verbose` to either command to inspect Wrangler diagnostics.
|
|
170
173
|
|
|
@@ -184,7 +187,7 @@ pnpm --filter dsh-edge example:install
|
|
|
184
187
|
- `GET /login` renders the Edge-owned owner form; `POST /api/auth/login` exchanges the configured access key for a signed cookie, `GET /api/auth/session` reports cookie validity, and `POST /api/auth/logout` clears it.
|
|
185
188
|
- `GET /api/events.mux` and `GET /api/events.host` upgrade to the upstream downlink WebSockets. The Durable Object serializes each socket's channel and verified owner-session expiry as its hibernation attachment, closes it at that expiry through an alarm, and reconstructs canonical sessions plus retained blank headers from Durable Object SQL. The mux stream publishes a complete `session/queue` snapshot after each committed inbox splice and sends pending live inbox baselines when a client reconnects.
|
|
186
189
|
- `POST /api/commands/list` implements the upstream generated-Remote envelope with an empty catalog because the Edge preset registers no human commands.
|
|
187
|
-
- `GET /api/health` returns the public package-and-mode release identifier and validates owner authentication, the deployment-scoped DeepSeek credential, model and transport choices, and the command-timeout policy before reporting the runtime components as ready. It does not call the provider, Durable Object, VFS, or shell.
|
|
190
|
+
- `GET /api/health` returns the public package-and-mode release identifier and configured attachment default (`private-r2` or `temporary-do`), and validates owner authentication, the deployment-scoped DeepSeek credential, model and transport choices, and the command-timeout policy before reporting the runtime components as ready. It does not call the provider, Durable Object, R2, VFS, or shell. The authenticated agent-preset projection reports the actual backend pinned by the owner Durable Object and the temporary storage cap.
|
|
188
191
|
- `PUT /api/workspace/file?path=/workspace/...` writes a UTF-8 file.
|
|
189
192
|
- `GET /api/workspace/file?path=/workspace/...` reads a UTF-8 file.
|
|
190
193
|
- `DELETE /api/workspace/file?path=/workspace/...` removes a file.
|
|
@@ -195,6 +198,6 @@ pnpm --filter dsh-edge example:install
|
|
|
195
198
|
- `GET /api/sessions/:sessionId/events?after=...&limit=...` replays a bounded event page and returns continuation headers.
|
|
196
199
|
- `POST /api/sessions/:sessionId/cancel` aborts the active turn owned by the current Durable Object process.
|
|
197
200
|
|
|
198
|
-
Upstream session creation and fork return `workspace-attach-failed` with the published session and Workspace ids when publication succeeds but Workspace attachment fails; the diagnostic creation route returns the same code plus its complete created session. Prompt and queue-edit text share the same 64 KiB semantic limit
|
|
201
|
+
Upstream session creation and fork return `workspace-attach-failed` with the published session and Workspace ids when publication succeeds but Workspace attachment fails; the diagnostic creation route returns the same code plus its complete created session. Prompt and queue-edit text share the same 64 KiB semantic limit. Their RPC carrier accepts up to 10 MiB so a projected 7 MiB raw-image batch still fits after base64 and envelope overhead. Because the Edge composition has no directory-flow provider, the upstream browser hides Delete on its sole Workspace and exposes it again whenever restoration remains possible.
|
|
199
202
|
|
|
200
|
-
The API limits text files to 1 MiB, commands to 16 KiB, user messages to 64 KiB, and retained shell stdout plus stderr to 64 KiB; these are UTF-8 byte limits. Request bodies are consumed incrementally before parsing or forwarding: session creation accepts at most 8 KiB of JSON, workspace execution 128 KiB, and message-bearing turn or queue-update RPCs
|
|
203
|
+
The API limits text files to 1 MiB, commands to 16 KiB, user messages to 64 KiB, and retained shell stdout plus stderr to 64 KiB; these are UTF-8 byte limits. Both attachment backends accept PNG and JPEG only, at most 4 images per message, 3.5 MiB per image, 7 MiB total, 40 million pixels, and 2,000 pixels per side; admission fully decodes the declared raster format before writing. Request bodies are consumed incrementally before parsing or forwarding: session creation accepts at most 8 KiB of JSON, workspace execution 128 KiB, and message-bearing turn or queue-update RPCs 10 MiB, while file uploads enforce their 1 MiB bound during consumption and reject malformed UTF-8. Once a body exceeds its route limit, later chunks are drained without being retained and the route returns 413. File reads first check VFS metadata, then collect the opened raw byte stream through the same 1 MiB cap, closing the growth race between `stat()` and `readFile()` without retaining an unbounded value. The runtime requests interruption when combined shell output crosses the retention bound and does not accumulate later output. Command status reports cancellation only when the adapter requested interruption, independently of the shell exit code; `timedOut` separately records deadline expiry. Failed initial session persistence discards the retained unmaterialized batch before disposing the newly published upstream agent handle, so teardown cannot later commit a session whose create request returned an error. A lazy blank session retains only its upstream header until the first canonical event; that materialization removes the retained header in the same SQL transaction. Each turn owns one upstream handle and disposes it after the stream completes, so previously accessed conversations do not remain resident for the Durable Object lifetime. Deployment settings resolve before the process-local owner claim. An upstream protocol prompt returns accepted and publishes running state only after its inbox event crosses `SessionStore.flush()`; later streamed events cross the same barrier before WebSocket or SSE delivery. Queue edits, removals, and steering promotion use the synchronous live-inbox mutation as their acceptance point; `PersistenceCoordinator` owns subsequent write-behind or retirement retry, so a later storage attempt cannot turn an accepted mutation into a rejected response. Session rename follows the same upstream metadata contract: the synchronous title append is its acceptance point for both active and cold sessions. Workspace global state and records use the upstream logical schemas under Edge-specific physical keys; DO transactions atomically pair record and registry-order changes, while a process-local chain serializes workspace mutations. Committed rename, delete, recreation, session reorder, attachment, and archive changes publish the matching upstream Host frames, and `workspace.list` restores their complete baseline after restart. A process-local owner rejects a concurrent turn, and cancel calls the native agent cancellation path. On the next cold resume, upstream interrupted-turn repair closes an open persisted tail and canonical `session/end-seed` markers preserve lifecycle boundaries. Replay checks session absence separately so persistence corruption or SQL failures are not collapsed into 404, reads only one bounded SQL page rather than the full suffix, and caps the encoded response. `PersistenceCoordinator.readValidatedPage()` performs identity, format, legacy-shape, and event-vocabulary validation on every page without adding Edge pagination to the public persistence service. If legacy normalization needs earlier messages, it rereads only one prefix through the same byte-bounded loader and refuses the page when that required prefix does not fit. Cold browser history selects its message boundary in SQL and loads only the resulting contiguous range under fixed event and stored-byte ceilings. Session listing queries one bounded canonical header/title summary page; detail reads its durable canonical point summary or retained blank header, while turn existence checks use point queries instead of listing headers or projecting a complete log. Effective model, system prompt, adapter defaults, and tools are recorded in standard `request/header` events. The request-scoped adapter uses the validated deployment reasoning and output policies. Workspace paths must stay below `/workspace/`.
|
package/README.zh.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
该运行时通过上游 Cordis 组合的 `ReactLoopAgent`、`AgentRegistry`、`LlmRuntime`、`ToolRuntime`、`SystemPrompt`、`SessionStore` 和 `SessionPersistence` 运行持久对话。Edge 代码只绑定请求作用域的 DeepSeek 适配器,并把一个原生 DSH `bash` 工具定义映射到 Cloudflare Computer。Durable Object SQLite 实现上游持久化后端约定,write-behind、revision、恢复准备和崩溃恢复仍由 `PersistenceCoordinator` 负责。模型历史从 canonical 事件投影,不再单独持久化。
|
|
12
12
|
|
|
13
|
-
浏览器直接使用上游 Web shell 和上游客户端插件包。构建期 assembler 根据上游 base 与 Web 组合包配置推导浏览器 roster,注入标准 `window.__DSH_BOOT__` graph,并把结果发布为 Cloudflare 静态资源。Durable Object 通过标准 HTTP carrier 实现受支持的上游 `ApiProxy` 方法,并以支持休眠的 WebSocket 提供两条上游 downlink。Edge 会排除缺少对应 host domain 的客户端插件,而不会 fork 其 UI 代码;在服务端 endpoint 可用前,session log export 也属于排除项。一个很小的 Edge 登录外壳会保护上游 UI 与协议,不修改两者本身。可选的本地 host 插件仍不可用。
|
|
13
|
+
浏览器直接使用上游 Web shell 和上游客户端插件包。构建期 assembler 根据上游 base 与 Web 组合包配置推导浏览器 roster,注入标准 `window.__DSH_BOOT__` graph,并把结果发布为 Cloudflare 静态资源。Durable Object 通过标准 HTTP carrier 实现受支持的上游 `ApiProxy` 方法,并以支持休眠的 WebSocket 提供两条上游 downlink。上游图片 composer、gallery、lightbox、attachment wire contract 与 DeepSeek serializer 保持原样复用;storage seam 会为新的永久部署选择私有 R2,为临时部署选择有界 Durable Object storage。Edge 会排除缺少对应 host domain 的客户端插件,而不会 fork 其 UI 代码;在服务端 endpoint 可用前,session log export 也属于排除项。一个很小的 Edge 登录外壳会保护上游 UI 与协议,不修改两者本身。可选的本地 host 插件仍不可用。
|
|
14
14
|
|
|
15
15
|
## 本地运行
|
|
16
16
|
|
|
@@ -99,7 +99,7 @@ Session listing 同样有界:`GET /api/sessions?after=SESSION_ID&limit=COUNT`
|
|
|
99
99
|
| Workspace registry | Storage-domain global state 加 `WorkspaceRecord` rows | 原生 backend 适配 | 保持上游 global 和 record value shape,包括手动 session 顺序与 archive membership;仅把物理 key 和原子写入映射到 Durable Object storage。Edge 把 registry 限制为一个原生 `/workspace` VFS;rename、delete、recreate 与 session reorder 保持上游 RPC 和 Host-frame 语义。 |
|
|
100
100
|
| Existing Web UI | 运行时加载的 shell 和 `dsh.client` 插件 graph | 复用并采用通用 composition fallback | 把上游 shell 和受支持的上游客户端包组装成 Worker 静态资源;共享的 slot occupancy 规则会隐藏缺少 provider 的 action。Cloudflare 直接提供普通资源,`/`、`/login` 与 `/api/*` 则进入 Worker 执行 owner access control。组装后的 asset policy 会阻止所有直接或 SPA-fallback shell alias 被嵌入 frame。 |
|
|
101
101
|
| Other tools | Web Search、filesystem editor tools、MCP、skills、workflows、jobs 和 subagents | Search 已移植;其他未移植 | 复用上游 DeepSeek Web Search 及其 30 秒 tool-call timeout。逐个针对 Worker-compatible capabilities 增加其余工具,不宣称不可用的 host 行为。 |
|
|
102
|
-
| Attachments | 本地 attachment storage
|
|
102
|
+
| Attachments | 本地 attachment storage、上游 image reference、composer、gallery、lightbox 与 provider conversion | 在原生 storage seam 上适配 | 原样复用上游 `AttachmentStore`、admission、协议、授权、UI 与 DeepSeek conversion。PNG/JPEG 不可变字节按 SHA-256 identity 存入新永久部署的私有 R2,或存入临时部署 64 MiB、按 512 KiB 分块的 DO fallback;session event 只保留上游 ref。每个 owner instance 首次选择的 backend 会被固定,认领或升级不会让既有引用失联。 |
|
|
103
103
|
| Authentication and tenancy | 本地 trusted-user boundary | 单 owner 适配 | 要求一个高熵 Worker secret,把它交换为带签名、有效期 30 天的 HttpOnly `SameSite=Strict` cookie,并把所有已接纳请求路由到一个固定 owner object。这里刻意不提供注册、用户数据库、角色或多租户路由。 |
|
|
104
104
|
|
|
105
105
|
浏览器请求路径是:
|
|
@@ -109,12 +109,15 @@ Cloudflare static assets -> upstream Web shell + client plugin graph
|
|
|
109
109
|
-> POST /api/session.create through the upstream HTTP carrier
|
|
110
110
|
-> host/workspace-changed + session/subscribed over Durable Object WebSockets
|
|
111
111
|
-> POST /api/session.prompt with the client rpcId
|
|
112
|
+
-> 上游图片 admission 校验图片,并把不可变字节存入私有 R2
|
|
113
|
+
-> canonical session event 只保留上游 sha256 attachment ref
|
|
112
114
|
-> AgentRegistry live lookup or resume
|
|
113
115
|
-> sessionPersistence.prepare through PersistenceCoordinator on cold resume
|
|
114
116
|
-> ReactLoopAgent.followup(queue) or ReactLoopAgent.steer(steer)
|
|
115
117
|
-> pre-step admission gate waits for the sessions.flush durability barrier
|
|
116
118
|
-> session/queue snapshots publish live and replay on mux reconnect
|
|
117
119
|
-> turn-scoped DeepSeekAdapter configuration selected by sessionId
|
|
120
|
+
-> 上游 attachment resolver 读取并校验已授权的 backend 字节
|
|
118
121
|
-> upstream LlmRuntime + ReactLoopAgent stream/event pipeline
|
|
119
122
|
-> upstream ToolRuntime native bash or web_search call
|
|
120
123
|
-> upstream WebRuntime + DeepSeek native search provider for web_search
|
|
@@ -128,7 +131,7 @@ Cloudflare static assets -> upstream Web shell + client plugin graph
|
|
|
128
131
|
-> upstream Web runtime reconciles and renders the canonical events
|
|
129
132
|
```
|
|
130
133
|
|
|
131
|
-
本地集成检查使用 SSE stand-in 以及真实的 Wrangler、Durable Object SQLite、默认 direct Computer workspace backend、静态资源服务、HTTP carrier 和 WebSocket。它验证 owner 登录、API 与 WebSocket cookie enforcement、拒绝旧 instance selector、direct shell 网络被禁用、上游 session create/list/history/search/prompt/rename/fork
|
|
134
|
+
本地集成检查使用 SSE stand-in 以及真实的 Wrangler、Durable Object SQLite、本地 R2、默认 direct Computer workspace backend、静态资源服务、HTTP carrier 和 WebSocket。Direct 模式会覆盖临时 DO attachment backend,Isolated 模式则覆盖私有 R2。它验证 owner 登录、API 与 WebSocket cookie enforcement、拒绝旧 instance selector、direct shell 网络被禁用、上游 session create/list/history/search/prompt/rename/fork;经上游 composer/协议/provider 路径完成图片 prompt;已授权附件读取、跨 session 拒绝、fork 复用,以及重启后的附件持久性;queue edit、remove 与提升为 steering;workspace create/list/rename/delete/session reorder/archive;对应的实时与重连 baseline 和 Host frame;真实浏览器启动及由 UI 发起的 workspace rename、图片 turn、内容搜索、branch 与 archive 操作;浏览器 session 过期后自动返回登录页;跨 turn 对话连续性、event 重放、两步 bash 与 Web Search tool 交互,以及 Wrangler 重启后的恢复。一项聚焦的故障测试证明,入队后的持久化失败会阻止模型调用,同时不会把已经唤醒 Agent 的 prompt 报告为拒绝。提交到仓库的 model-visible 与 ARIA golden 会固定 tool transcript 以及组装后的上游 Web client 通过 Edge HTTP/WebSocket 协议呈现的结果。真实 DeepSeek 调用需要开发者自己的 key,因此不会纳入仓库测试套件。
|
|
132
135
|
|
|
133
136
|
## API key 边界
|
|
134
137
|
|
|
@@ -152,7 +155,7 @@ Cloudflare static assets -> upstream Web shell + client plugin graph
|
|
|
152
155
|
npx dsh-edge install
|
|
153
156
|
```
|
|
154
157
|
|
|
155
|
-
该命令通过 npm `latest`
|
|
158
|
+
该命令通过 npm `latest` 渠道解析。使用 `npx dsh-edge@next install` 可以测试当前包含上游模型选择与图片 prompt 的 0.3 预发布版本。
|
|
156
159
|
|
|
157
160
|
选择相同 runtime 并输入现有 Worker 名称即可升级。部署会保留 Durable Object 数据;由于 Cloudflare secret 只能写入而不能读取,升级会再次要求 owner access key 与 DeepSeek API key,并用输入值替换当前生效值:
|
|
158
161
|
|
|
@@ -164,7 +167,7 @@ npx dsh-edge upgrade
|
|
|
164
167
|
|
|
165
168
|
如果当前安装的是 0.2 alpha,需要执行一次 `npx dsh-edge@latest upgrade` 晋级到稳定渠道;其他预发布部署仍跟随 `next`。Edge 设置页会根据已安装版本推导渠道,并复制匹配的命令。
|
|
166
169
|
|
|
167
|
-
安装器会先询问运行时,再询问账户。推荐的 `Free — Direct Shell` 模式可在 Workers Free 上运行,并可使用检测到的 Cloudflare 账户、打开 Cloudflare 登录或注册,也可在不登录的情况下创建临时账户。`Isolated — Dynamic Worker` 需要 Workers Paid,因此只提供已检测到或新认证的账户。Cloudflare 没有提供可靠的本地 Worker Loader entitlement 检查;isolated 安装会由 Cloudflare 对上传进行授权,并在被拒绝时提示启用 Workers Paid 或改用 direct
|
|
170
|
+
安装器会先询问运行时,再询问账户。推荐的 `Free — Direct Shell` 模式可在 Workers Free 上运行,并可使用检测到的 Cloudflare 账户、打开 Cloudflare 登录或注册,也可在不登录的情况下创建临时账户。`Isolated — Dynamic Worker` 需要 Workers Paid,因此只提供已检测到或新认证的账户。Cloudflare 没有提供可靠的本地 Worker Loader entitlement 检查;isolated 安装会由 Cloudflare 对上传进行授权,并在被拒绝时提示启用 Workers Paid 或改用 direct 模式。对于新的永久账户安装,安装器会创建或复用私有 `<worker-name>-attachments` R2 bucket,并只把 binding 写入生成的私有 Wrangler 配置;部署失败时绝不会删除 bucket。所选账户必须已启用 R2,否则安装器会给出启用与重试路径。临时账户使用 64 MiB Durable Object attachment backend,并支持相同的上游图片 UI。认领会保留这个 backend 与已有图片历史;自动迁移到 R2 尚未实现。每个新部署都会记录明确的 attachment-storage marker。在更新已有 Worker 前,安装器会检查所有 active version,保留 marker 指定的 R2 或 DO 选择;没有 marker 的旧版 pre-attachment 部署会按永久 R2 初始化;若 rollout 混用两种 backend,则会拒绝猜测并要求先完成 rollout。
|
|
168
171
|
|
|
169
172
|
后续提示会选择 Worker 名称、生成或接收 owner access key、通过隐藏输入收集 DeepSeek API key,并显示最终费用摘要。临时账户安装还会要求用户明确接受 Cloudflare 服务条款与隐私政策。安装器绝不会在未经确认时覆盖现有 Worker。两项 credential 会通过权限模式为 `0600` 的临时 secret 文件传给 Wrangler;Wrangler 子进程只会收到 allowlist 内的运行时环境变量和当前命令选中的 Cloudflare authentication,其他 ambient key、token、password、secret 与 Node 注入选项不会进入子进程。命令结束后临时 secret 文件会被删除,安装器从 Wrangler 结构化输出中取得最终 URL。默认情况下,部署输出会收敛到一个进度提示;在任一命令后添加 `--verbose` 可以查看 Wrangler 诊断。
|
|
170
173
|
|
|
@@ -184,7 +187,7 @@ pnpm --filter dsh-edge example:install
|
|
|
184
187
|
- `GET /login` 渲染 Edge 持有的 owner form;`POST /api/auth/login` 用已配置的 access key 换取 signed cookie,`GET /api/auth/session` 报告 cookie 是否有效,`POST /api/auth/logout` 清除 cookie。
|
|
185
188
|
- `GET /api/events.mux` 和 `GET /api/events.host` 会升级为上游 downlink WebSocket。Durable Object 会把每个 socket 的 channel 与已验证 owner session 过期时间序列化为 hibernation attachment,通过 alarm 在该时间关闭连接,并从 Durable Object SQL 重建 canonical session 与 retained blank header。每次 inbox splice 提交后,mux stream 都会发布完整的 `session/queue` snapshot;客户端重连时还会发送 live inbox 的待处理 baseline。
|
|
186
189
|
- `POST /api/commands/list` 使用上游 generated-Remote envelope 返回空 catalog,因为 Edge preset 没有注册 human command。
|
|
187
|
-
- `GET /api/health` 会返回公开的 package-and-mode release identifier
|
|
190
|
+
- `GET /api/health` 会返回公开的 package-and-mode release identifier 与配置的附件默认值(`private-r2` 或 `temporary-do`),并先验证 owner authentication、部署级 DeepSeek 凭据、模型与传输配置,以及命令超时策略,再报告运行时组件已就绪。它不会调用提供方、Durable Object、R2、VFS 或 shell。认证后的 agent-preset projection 会报告 owner Durable Object 实际固定的 backend 与临时存储上限。
|
|
188
191
|
- `PUT /api/workspace/file?path=/workspace/...` 写入 UTF-8 文件。
|
|
189
192
|
- `GET /api/workspace/file?path=/workspace/...` 读取 UTF-8 文件。
|
|
190
193
|
- `DELETE /api/workspace/file?path=/workspace/...` 删除文件。
|
|
@@ -195,6 +198,6 @@ pnpm --filter dsh-edge example:install
|
|
|
195
198
|
- `GET /api/sessions/:sessionId/events?after=...&limit=...` 重放一个有界 event page,并返回 continuation headers。
|
|
196
199
|
- `POST /api/sessions/:sessionId/cancel` 终止当前 Durable Object 进程持有的 active turn。
|
|
197
200
|
|
|
198
|
-
上游 Session 创建与 fork 在发布成功但 Workspace attachment 失败时返回 `workspace-attach-failed`,并携带已发布的 session 与 Workspace id;诊断创建路由会返回相同 code 及完整的已创建 session。Prompt 和 queue-edit 文本共用 64 KiB
|
|
201
|
+
上游 Session 创建与 fork 在发布成功但 Workspace attachment 失败时返回 `workspace-attach-failed`,并携带已发布的 session 与 Workspace id;诊断创建路由会返回相同 code 及完整的已创建 session。Prompt 和 queue-edit 文本共用 64 KiB 语义上限。其 RPC 载体最多接受 10 MiB,从而让 7 MiB 原始图片批次在 base64 与 envelope 膨胀后仍可装入。Edge 组合没有目录流 provider,因此上游浏览器会在仅剩一个 Workspace 时隐藏 Delete,并在仍有恢复路径时重新显示。
|
|
199
202
|
|
|
200
|
-
API 将文本文件限制为 1 MiB、命令限制为 16 KiB、用户消息限制为 64 KiB,并将保留的 shell stdout 与 stderr 总量限制为 64 KiB;这些均为 UTF-8
|
|
203
|
+
API 将文本文件限制为 1 MiB、命令限制为 16 KiB、用户消息限制为 64 KiB,并将保留的 shell stdout 与 stderr 总量限制为 64 KiB;这些均为 UTF-8 字节限制。两种 attachment backend 都只接受 PNG 与 JPEG:每条消息最多 4 张、每张最多 3.5 MiB、合计最多 7 MiB、最多 4,000 万像素,且单边不超过 2,000 像素;写入前会完整解码声明的 raster 格式。Request body 会在解析或转发前增量消费:创建 session 的 JSON 上限为 8 KiB、workspace execution 为 128 KiB、承载消息的 turn 或 queue-update RPC 为 10 MiB,文件上传也会在消费过程中执行其 1 MiB 上限,并拒绝非法 UTF-8。Body 一旦越过路由上限,后续 chunk 只会排空而不会继续保留,路由最终返回 413。读取文件时会先检查 VFS metadata,再通过相同的 1 MiB 上限收集实际打开的原始 byte stream,从而关闭 `stat()` 与 `readFile()` 之间的增长竞态,且不会保留无界值。组合输出越界时,runtime 会请求中断 shell execution,并停止累积后续输出。只有 adapter 实际请求过中断时,命令状态才会报告 cancellation;这一状态与 shell exit code 独立,`timedOut` 则单独记录 deadline expiry。首次 session 持久化失败时,会先丢弃保留但尚未物化的 batch,再 dispose 新发布的上游 agent handle,因此 teardown 无法在创建请求返回错误后又提交该 session。Lazy blank session 在首个 canonical event 前只保留其上游 header;物化该 event 的同一个 SQL transaction 会删除 retained header。每个 turn 持有一个上游 handle,并在 stream 完成后 dispose,避免曾访问的对话在 Durable Object 整个生命周期内常驻内存。部署 settings 会在声明进程内 owner 前解析。上游 protocol prompt 只有在其 inbox event 跨过 `SessionStore.flush()` 后才返回 accepted 并发布 running state;后续 streamed event 也会先跨过同一个 barrier,再通过 WebSocket 或 SSE 发送。Queue edit、remove 与 steering promotion 以同步 live-inbox mutation 作为接纳点;后续 write-behind 或 retirement retry 由 `PersistenceCoordinator` 负责,因此后续存储尝试不能把已接纳的 mutation 变成被拒绝的响应。Session rename 遵循相同的上游 metadata contract:对于 active 与 cold session,同步追加 title 即为接纳点。Workspace global state 与 record 在 Edge-specific physical key 下使用上游逻辑 schema;DO transaction 原子组合 record 与 registry order 变更,进程内 chain 则串行化 workspace mutation。已提交的 rename、delete、recreate、session reorder、attachment 和 archive 变更会发布对应的上游 Host frame,`workspace.list` 会在重启后恢复完整 baseline。进程内 owner 会拒绝并发 turn,cancel 调用原生 agent cancellation path。下次冷恢复时,上游 interrupted-turn repair 会关闭开放的持久 event tail,canonical `session/end-seed` marker 会保留生命周期边界。Replay 会独立确认 session 是否不存在,因此 persistence corruption 或 SQL failure 不会被折叠成 404;它只读取一个有界 SQL page,而不是完整 suffix,并限制编码后的 response。`PersistenceCoordinator.readValidatedPage()` 会对每个 page 执行 identity、format、legacy-shape 和 event-vocabulary 校验,而不把 Edge pagination 加入公共 persistence service。如果 legacy normalization 需要更早的 message,它只会通过同一个受字节约束的 loader 重读一个 prefix;必要 prefix 无法装入预算时会拒绝该 page。冷浏览器 history 会在 SQL 中选择消息边界,并仅在固定事件数与存储字节上限内加载所得连续区间。Session listing 查询一个有界的 canonical header/title summary page;detail 读取持久化的 canonical point summary 或 retained blank header,turn existence check 则使用 point query,不会列出全部 headers 或投影完整 log。实际 model、system prompt、adapter defaults 和 tools 写入标准 `request/header` 事件。Request-scoped adapter 使用已校验的部署级 reasoning 与输出策略。workspace 路径必须位于 `/workspace/` 下。
|