@ckanner/dsh-plugin-flywheel 0.28.0 → 0.28.2

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/PROTOCOL.md CHANGED
@@ -18,7 +18,7 @@ Go 在工作目录启动 `flywheel-dsh-worker`,写入**一条** UTF-8 JSON 行
18
18
  | `maxTokens` | 正整数,每次原生模型请求的输出上限,传入 SDK initialize |
19
19
  | `timeoutMs` | 1–86,400,000,默认 1,800,000;涵盖权限准备、初始化、运行和关闭 |
20
20
 
21
- `permissionMode` 仅允许 `read-only`、`workspace-write`。未知字段一律拒绝。v1 不接受 `sessionId` / resume、附件、任意额外 CLI 参数和额外写目录;不进行隐式冷启动替代恢复。
21
+ `permissionMode` 允许 `read-only`、`workspace-write` 和显式 `danger-full-access`。未知字段一律拒绝。v1 不接受 `sessionId` / resume、附件、任意额外 CLI 参数和额外写目录;不进行隐式冷启动替代恢复。
22
22
 
23
23
  ## 运行参数
24
24
 
@@ -46,12 +46,12 @@ worker 用 `dsh --profile <profile> --patch <临时覆盖文件>` 启动 DSH。
46
46
  发出 ready 前必须依次满足:
47
47
 
48
48
  1. 官方 SDK `initialize` 返回 `deepseek-harness-sdk-runtime`,adapter 接受指定 provider/model/effort。
49
- 2. worker 策略插件经真实 `ctx.shell` 执行本地无副作用的 `:` 探针;退出码为 0 且报告 `sandbox.enforcement:full`。不可用或部分实施的沙箱拒绝通过。
49
+ 2. worker 策略插件经真实 `ctx.shell` 执行本地无副作用的 `:` 探针;退出码为 0、模式匹配且未被拒绝。受限模式还须报告 `sandbox.enforcement:full`,不可用或部分实施的沙箱拒绝通过;明确完全权限时记录 `confinedShell:false` 并省略 enforcement,不伪造 OS 强制。
50
50
  3. `session/working-directory/get` 创建全新的 Session,返回实际 cwd。
51
51
  4. Session 的 `sandbox/mode`、`approval/policy` 被固定,`ctx.sandboxPolicy.resolve()` 与 `ctx.approval.effectivePolicy()` 的实际读值形成 `flywheel/policy` 事件。
52
- 5. worker 比对 policy 事件的 cwd、mode、`never` 和 full confinement。
52
+ 5. worker 比对 policy 事件的 cwd、mode、`never` 及对应权限证据:受限模式为完整强制,完全权限为明确无 OS 限制。
53
53
 
54
- 任一项缺失,不发送 `session/prompt`。`never` 在 rc.5 的含义是自动拒绝需要批准的提权操作;它不会授予无限权限。
54
+ 任一项缺失,不发送 `session/prompt`。`never` 控制交互审批,不单独扩大访问范围;必须同时显式选择 `danger-full-access` 才请求完全权限。既有静态拒绝或外部权限不足仍按真实失败处理。
55
55
 
56
56
  ### event:可审计的原始持久事件
57
57
 
@@ -99,7 +99,7 @@ Go 的 `DSHArgs.Doctor` 使用这个入口;为保持 v1 必填 `prompt` 的 ad
99
99
  {"type":"start","protocol":1,"requestId":"call-123","cwd":"/absolute/worktree","model":"gpt-6.1-sol","reasoningEffort":"high","permissionMode":"workspace-write","prompt":"执行冻结工作单元","timeoutMs":1800000}
100
100
  ```
101
101
 
102
- 只接受这些字段;不接受 provider、resume、threadId、额外写目录、任意 CLI 参数或危险权限模式。requestId 非空且最多 256 字符;cwd 为绝对路径,Go 先规范化成物理目录。model/reasoningEffort/prompt 必须是非空文本,permissionMode 仅 read-only/workspace-write。timeoutMs 显式值必须为 1–2,147,483,647 的安全整数,省略使用上游 600,000 毫秒;worker 不接受通过 0 关闭期限。Go 传递有效 wall deadline 和 high 默认 thinking;worker 将 reasoningEffort 映射到 machine 的 effort,固定 threadMode=ephemeral、command=`FLYWHEEL_CODEX_BIN` 或 `codex`,不恢复旧线程。
102
+ 只接受这些字段;不接受 provider、resume、threadId、额外写目录、任意 CLI 参数或未知权限模式。requestId 非空且最多 256 字符;cwd 为绝对路径,Go 先规范化成物理目录。model/reasoningEffort/prompt 必须是非空文本,permissionMode 为 read-only/workspace-write/danger-full-access;最后一项在 Node adapter 边界映射为 machine API 的 `dangerously-bypass-approvals-and-sandbox`,Go 同时核对映射后的 requested 字段和 canonical 生效模式。timeoutMs 显式值必须为 1–2,147,483,647 的安全整数,省略使用上游 600,000 毫秒;worker 不接受通过 0 关闭期限。Go 传递有效 wall deadline 和 high 默认 thinking;worker 将 reasoningEffort 映射到 machine 的 effort,固定 threadMode=ephemeral、command=`FLYWHEEL_CODEX_BIN` 或 `codex`,不恢复旧线程。
103
103
 
104
104
  **这里与 DSH worker 的 EOF 语义不同:Go 写入一行后保持 stdin 开放。** stdin 是父进程的存活连接;未完成前 EOF、读取错误或第二条非空输入触发 AbortSignal,并等待插件有界清理。不能用 `echo … | worker` 的关闭 stdin 行为冒充正常调用。运行请求首行等待上限 10 秒;请求最多 1 MiB,machine 原始输出上限 1 MiB,序列化 progress 累计最多 1 MiB,完整终态帧最多 8 MiB。超限明确失败,不能裁掉回执后判成功。
105
105
 
@@ -119,7 +119,7 @@ Go 的 `DSHArgs.Doctor` 使用这个入口;为保持 v1 必填 `prompt` 的 ad
119
119
 
120
120
  启动前不能获得 machine receipt 时为 null。运行已开始则即使失败也保留完整 receipt;`error` 非 null、重复/丢失 result、尾部垃圾、请求身份或 adapter 版本不符都不能成功。本通道没有 DSH `ready` 帧,不能据此虚构运行前完整沙箱握手或实际 effort 回显。
121
121
 
122
- Go 同时校验外层 worker 物理终态和插件 receipt:请求及 run/thread/turn 身份、模型、cwd、approval=never、实际沙箱模式、完整 sandboxPolicy、stopReason、cleanup 与执行事实。workspaceWrite 的显式 writableRoots 必须处于工作区内,networkAccess 必须明确 false;Codex 标准临时目录标记保留,不宣称只能写 cwd。插件 0.8.0 只在 turn 前检查模式等基本配置;完整策略是返回后的交付资格检查,**不能阻止自定义 Codex 配置已经允许的访问**。
122
+ Go 同时校验外层 worker 物理终态和插件 receipt:请求及 run/thread/turn 身份、模型、cwd、approval=never、实际沙箱模式、完整 sandboxPolicy、stopReason、cleanup 与执行事实。受限模式的 workspaceWrite 显式 writableRoots 必须处于工作区内,networkAccess 必须明确 false;显式完全权限要求 `sandbox:danger-full-access` 与精确的 `{type:"dangerFullAccess"}` policy,不要求不存在的受限模式字段;Codex 标准临时目录标记保留,不宣称只能写 cwd。插件 0.8.0 只在 turn 前检查模式等基本配置;完整策略是返回后的交付资格检查,**不能阻止自定义 Codex 配置已经允许的访问**。
123
123
 
124
124
  effort 的证据只可为 turn/start 请求接受,保留 `effectiveEffort:null`。usage 使用 `run` 增量,不能把 threadTotal 当成本次消耗;只有 complete 才记入可知预算,partial/unknown 原样存入 receipt 并增加未知调用计数。cached input/reasoning output 是总 input/output 的子项,不重复累加。订阅 costUSD 保持 null、costStatus 保持 unknown。receipt 没有实际 provider 时保持未知,不根据 channel 发明 provider。
125
125
 
@@ -160,6 +160,33 @@ Go doctor 同时检查 Node 与 Codex 命令。包导入成功不证明账号、
160
160
 
161
161
  config/doctor 的 Go CLI 将 SIGTERM/SIGINT 转为 context 取消,等待 watchdog 收尾后才退出。控制调用取消或超过窗口时,host 先发 SIGTERM,诊断动作再留 20 秒让 Go 完成分阶段清理,仍未退出才 SIGKILL;取消始终报告控制失败,即使迟到结果成功也不覆盖它。start/status/stop 保持原控制进程的 500ms 收尾,后台引擎停止仍走独立 stop 协议。
162
162
 
163
+ ### DSH 命令失败与是否派发
164
+
165
+ `/flywheel` 的 DSH command 结果仍使用 `kind:"success"` 或 `kind:"error"`。成功结果的 `text` 是上述 Go control JSON,包括具有合法诊断报告的 doctor 失败。新的 host 将所有 command 失败包装为以下独立 JSON,放在 `kind:"error"` 的 `text` 中;这不是 Go stdout envelope,也不改变 worker JSONL 或模型工具的异常接口:
166
+
167
+ ```json
168
+ {"protocol":1,"type":"flywheel-control-error","action":"start","dispatch":"not-dispatched","message":"taskDir must be an existing directory"}
169
+ ```
170
+
171
+ | 字段 | 语义 |
172
+ |---|---|
173
+ | `protocol`、`type` | 固定为 `1` 和 `flywheel-control-error`,用于区分命令失败与引擎结果 |
174
+ | `action` | 可读取的请求 action 字符串;解析失败或没有字符串 action 时为 `null`;界面必须与自己的在途请求匹配 |
175
+ | `dispatch` | `not-dispatched` 表示宿主证明本次请求没有启动 Go 控制进程;否则为 `unknown` |
176
+ | `message` | 给用户诊断的错误文本,本身不证明进程是否启动,也不能作为另一个 envelope 递归解析 |
177
+
178
+ 只有参数/目录等派发前校验失败、派发前取消,以及进程创建失败且没有成功启动的证据,才能返回 `not-dispatched`。进入控制进程后出现的非零退出、超时、取消、坏 JSON 或任务身份不符都不能取得这项证明,即使错误文本包含相同 JSON。host 对普通错误同样增加外层 envelope,只把原始错误放入 `message`,避免进程返回的文字冒充宿主确认。
179
+
180
+ 界面只有在版本、类型、action、dispatch 和 message 都符合契约时才使用宿主证明。未知协议、旧 host 的纯文本错误、DSH 传输失败或丢失响应均保持 `unknown`。启动/停止的 `unknown` 结果必须先成功查询原任务状态,再决定后续变更;不得自动重试。已确认未派发的拒绝会显示原因,用户可以修正输入或环境后重新提交。一次未派发的状态查询也不能解除更早启动/停止留下的未确认结果。
181
+
182
+ host 在调用 Go 前把任务和仓库目录规范化为真实路径,并校验引擎返回的任务身份。界面不能把用户输入的符号链接、`..`、尾部斜杠或 Mac `/var` 与 `/private/var` 的文本差异当作引擎身份错误;响应接纳依赖 host 的路径校验和当前请求关联。
183
+
184
+ ### 浏览器查看状态的边界
185
+
186
+ 浏览器端遵循[外部 plain-JS 插件实践](https://github.com/deepseek-ai/deepseek-harness/blob/b830ec950faba0a46dda564be3e2d854afed94f1/packages/preset/agent-preset/skills/cordis-plugin-development/references/practices.md),不运行时导入 Harness Client 包。插件自有的 store handle 只通过公开的 `spec`/`create()` 结构交给槽位注册;每个实例提供 `actions`、`getSnapshot()`、`subscribe()` 和 `clearPersisted()`,由宿主负责会话作用域、实例缓存与 hooks 绑定。当前没有持久化配置,`clearPersisted()` 不删除任何任务文件。
187
+
188
+ 异步控制层另有插件自有 observable,快照在未变化时保持同一身份,经 `inject.hooks` 交给宿主绑定;React 组件不自行订阅,不读取 ctx 或原始服务对象。路径草稿与控制快照只是查看缓存,不成为任务账本,也不写入新的 DSH 会话事件。模型可见的命令和工具结果仍由宿主原有记录机制处理。此查看契约不改变 Go control 协议、worker JSONL 或后台任务的停止语义。
189
+
163
190
  ## npm 安装报告与桌面入口
164
191
 
165
192
  以下是 Node 安装器的独立契约,不与 worker JSONL、Go control envelope 或任务 `state.json` 混用。入口为 `npx -y @ckanner/flywheel@latest install` 或已安装包的 `flywheel setup`;二者共用参数与行为。普通 npm 包安装没有修改用户目录的 postinstall,只有显式 install/setup 执行 skills、安装记录和 DSH profile 配置。
package/README.en.md CHANGED
@@ -7,17 +7,23 @@ provides its DSH SDK and Codex Pro workers. The engine owns task state, budgets,
7
7
  verification, Git delivery, and process lifecycles. The desktop is a control and
8
8
  observation interface; it does not need a parent model session to keep a task alive.
9
9
 
10
- This guide describes the **Flywheel 0.28.0** interfaces. Source availability does
10
+ This guide describes the **Flywheel 0.28.2** interfaces. Source availability does
11
11
  not mean that npm `latest` already contains them. Check the registry version and
12
12
  the [release guide](https://github.com/ckanner/flywheel/blob/main/docs/en/releasing.md) before installing. The desktop
13
13
  compatibility baseline is **DSH Mac 0.2.1-rc.5**, not a claim that every DSH build
14
14
  or provider adapter is compatible.
15
15
 
16
+ **Flywheel 0.28.1 introduces the native conversation view.** Version `0.28.0`
17
+ uses the composer popup. Upgrade the CLI and desktop plugin to the same new
18
+ version; merging source does not update an installed plugin.
19
+
20
+ Subscription preset migration and `permissions.mode` are available from **0.28.2**. Upgrades preserve existing configuration; only an explicit migration backs it up and updates model bindings and permissions.
21
+
16
22
  ## Components
17
23
 
18
24
  | Component | Responsibility |
19
25
  |---|---|
20
- | Flywheel panel | Inspect configuration, run local checks, and start, observe, or stop a task |
26
+ | Flywheel conversation view | A native view alongside Chat and Trajectory for task progress, intervention, configuration, checks, and explicit start/refresh/stop |
21
27
  | `/flywheel` command | Invoke the Go control interface from an explicit desktop command |
22
28
  | `flywheel_control` tool | Expose the same control operations to the host model |
23
29
  | `flywheel-dsh-worker` | Run one native model session through an independent DSH SDK profile |
@@ -27,6 +33,11 @@ The plugin has no separate task database and does not write `state.json`.
27
33
  Kimi CLI, Codex Pro, and the explicit legacy Codex CLI path have separate Go
28
34
  drivers. A DSH LLM provider and an external agent tool are different interfaces.
29
35
 
36
+ The view answers which stage is running, what needs attention, which models are
37
+ configured, and how to stop or recover the task. Requirement discussion, contract
38
+ preparation, and ordinary conversation stay in DSH's chat and skills. Flywheel
39
+ does not replace the host's composer, model selector, trajectory, or right sidebar.
40
+
30
41
  ## Install the complete application
31
42
 
32
43
  You need **Node.js 22.18.0 or later**, npm, and the existing DSH Mac desktop with
@@ -151,10 +162,16 @@ actual inference result. Keep `warn`, `unknown`, and `skipped` distinct from
151
162
 
152
163
  ## Use the desktop controls
153
164
 
154
- Open the **Flywheel** panel below the DSH session input. Select the absolute
155
- task worktree path as the repository directory and the task directory inside
156
- that same worktree. Prepare and review the contracts first; the panel does not
157
- turn an empty directory into a complete task plan.
165
+ Open a DSH session and choose **Flywheel** in the native view bar alongside
166
+ Chat and Trajectory. If the entry is not directly visible, check that bar's
167
+ More menu. Ask the chat assistant to prepare and review the task using
168
+ `flywheel-new`; it reports the actual paths. **Task files directory** contains
169
+ the task description and acceptance files, for example
170
+ `/Users/me/project/docs/fix-login`. **Project directory (optional)** can stay
171
+ blank to use the current DSH session directory; specify the matching project
172
+ worktree when the task lives elsewhere. Configuration and diagnostic actions
173
+ can also leave the task directory blank. These are project paths, not plugin
174
+ installation paths.
158
175
 
159
176
  The panel, `/flywheel`, and `flywheel_control` share these Go operations:
160
177
 
@@ -171,6 +188,86 @@ engine; closing the panel or desktop is not a stop request. Refresh status to
171
188
  observe it, and use `stop` to request shutdown. `ok: true` describes a successful
172
189
  control operation; task completion is recorded in `state.status`.
173
190
 
191
+ Opening the view starts no task or probe. It reads on explicit actions, without
192
+ automatic polling or task discovery. To observe a task started through another
193
+ entry point, select its task directory and refresh. Effective configuration comes
194
+ from the engine's selected file; installing the plugin or changing DSH's chat
195
+ model does not migrate that configuration.
196
+
197
+ **Check installation and configuration** performs local checks without starting
198
+ the SDK. **Check DSH connection** additionally starts a temporary SDK process,
199
+ checks its configuration, directory and permissions, and closes it. Use these
200
+ when installing, upgrading or troubleshooting; they are not required before
201
+ every task. Neither sends an inference prompt or proves account access, quota
202
+ or actual model response capability.
203
+
204
+ ### View, request, and task lifetimes
205
+
206
+ Task and repository drafts and fetched snapshots are retained separately for
207
+ each DSH session across Chat/Trajectory/Flywheel view switches while the host
208
+ retains that session binding. They are not a task database or durable storage
209
+ across binding release, plugin reload, or desktop restart. Only one control
210
+ request is pending per session. Start/stop locks the directory fields while
211
+ waiting. A read-only request allows path edits, but stays pending until its reply
212
+ settles and rejects late results for the previous selection. Hiding a view does
213
+ not make a pending operation complete.
214
+
215
+ Task state is the last successful snapshot with its refresh time, not a live
216
+ monitor. Failed reads retain valid prior content and show the failure. A lost,
217
+ timed-out, or disconnected start/stop response means the outcome is **unconfirmed**;
218
+ it does not prove that nothing started or that a task stopped. Refresh the same
219
+ task first and inspect its log when needed before deciding how to recover.
220
+ Until a successful status refresh reconciles that task, the view keeps the
221
+ uncertainty visible and disables further starts and stops. It never automatically
222
+ retries a start or stop.
223
+
224
+ A missing directory or a control process that cannot be created is recoverable
225
+ after correcting the input or environment only when the host supplies structured
226
+ evidence that the request was not dispatched. An ordinary error, connection loss,
227
+ or error-message text cannot establish that fact or dismiss an unconfirmed outcome.
228
+ The `/flywheel` command's error `text` uses the JSON discriminator
229
+ `type:"flywheel-control-error"`; its fields and compatibility behavior are defined
230
+ in the [command failure protocol](PROTOCOL.md#dsh-命令失败与是否派发) (Chinese).
231
+
232
+ Switching views, closing the session page, removing the plugin, or exiting DSH
233
+ does not stop the independent Go task. Request an explicit stop and await engine
234
+ confirmation. DSH's trajectory retains its own parent-session command and tool
235
+ events. Complete SDK, Kimi, and Codex Pro worker histories are not automatically
236
+ merged into that trajectory or presented as native DSH background tasks.
237
+
238
+ ### Host UI contract
239
+
240
+ The client uses `ctx.slots.inject()` and a distinct `id: flywheel` in the
241
+ `conversation.view` list. The host owns session scope and view navigation. Chat,
242
+ Trajectory, the composer, and the right sidebar keep their existing entries;
243
+ Flywheel neither shadows them nor draws a separate floating sidebar or composer
244
+ popup. Long paths, model details, and errors wrap or scroll inside the view.
245
+
246
+ As an external plain-JS plugin, the browser module imports only shared React at
247
+ runtime. It does not import `ui-primitives`, `client-store`, or another Harness
248
+ Client package. The plugin owns its buttons, inputs, viewing-state store handle,
249
+ and observable; the host manages registered session instances and binds their
250
+ read hooks. Locale comes through the injected service. Controls follow the
251
+ checked host markup and interactions, consume semantic color aliases, inherit
252
+ the host font, and mount compiled CSS Modules through the React view.
253
+
254
+ The baseline is the exact source snapshot `b830ec950faba0a46dda564be3e2d854afed94f1`,
255
+ which declares version `0.2.1-rc.5`: [external plugin practices](https://github.com/deepseek-ai/deepseek-harness/blob/b830ec950faba0a46dda564be3e2d854afed94f1/packages/preset/agent-preset/skills/cordis-plugin-development/references/practices.md),
256
+ [UI guidance](https://github.com/deepseek-ai/deepseek-harness/blob/b830ec950faba0a46dda564be3e2d854afed94f1/.agents/skills/dsh-client-ui-ux/SKILL.md),
257
+ [layout](https://github.com/deepseek-ai/deepseek-harness/blob/b830ec950faba0a46dda564be3e2d854afed94f1/packages/client/ui-layout/README.md),
258
+ [conversation slots](https://github.com/deepseek-ai/deepseek-harness/blob/b830ec950faba0a46dda564be3e2d854afed94f1/packages/client/ui-conversation/src/client/contract/slots.ts),
259
+ and [slot lifecycle](https://github.com/deepseek-ai/deepseek-harness/blob/b830ec950faba0a46dda564be3e2d854afed94f1/docs/subsystems/slots.md).
260
+ The view sits within Conversation's existing header and content geometry; it
261
+ does not change global window-chrome clearance. Source-contract inspection does
262
+ not establish a live Mac desktop pass.
263
+
264
+ Offline UI checks execute the built plugin's own controls, store handle, and
265
+ observable with React and jsdom. Component fixtures adapt slot bindings and
266
+ Remote; a separate check uses the published rc.5 renderer, slots, and Cordis to
267
+ exercise registration, session generations, declaration collapse/restoration,
268
+ and disposal. These checks do not establish real browser geometry or Mac
269
+ window behavior.
270
+
174
271
  Use one task integration worktree for preparation, planning, milestone
175
272
  verification, and the eventual PR. The engine manages packet worktrees for
176
273
  execution, L1, and review. A successful packet is merged into the branch of the
@@ -180,16 +277,40 @@ GitHub PRs, merge remote PRs, or publish packages. See the
180
277
 
181
278
  ## Permissions and lifecycle boundaries
182
279
 
183
- The DSH worker requests `read-only` or `workspace-write`, fixes approvals to
184
- `never`, and verifies the effective SDK policy before sending the task prompt.
185
- On the checked Mac host, the DSH sandbox uses its Seatbelt runner and filesystem
186
- fence. Workspace writes include DSH's permitted temporary area; this is not a
187
- network-isolation guarantee. Missing or incomplete enforcement is a failure,
188
- not a reason to switch to unrestricted access.
280
+ Desktop integration and worker policy have different scopes. The worker's
281
+ temporary overlay applies only to its independent **SDK process**; it does not
282
+ edit the desktop profile or remove the desktop's plugins, skills, tools, or UI.
283
+ Conversely, desktop installation and sign-in do not prove that the SDK profile
284
+ loads and authorizes the same capabilities. Verify each selected harness through
285
+ its own configuration and supported authorization flow.
286
+
287
+ The DSH worker supports `read-only`, `workspace-write`, and explicit
288
+ `danger-full-access`, with approvals fixed to `never`. New subscription presets
289
+ select `permissions.mode:full-access` for every stage; Kimi print retains native
290
+ auto behavior. Existing files without this setting retain role-based access
291
+ until explicitly migrated. The actual SDK policy is checked before prompting.
292
+ Restricted modes use the checked Mac Seatbelt runner and filesystem fence;
293
+ workspace writes include DSH's permitted temporary area. Explicit full access
294
+ is recorded without claiming OS confinement. Host static denials, account
295
+ restrictions, and operating-system permissions remain in effect.
296
+
297
+ The SDK overlay disables worker-owned delegation, workflow/goal drivers, model
298
+ titles, and automatic model compaction so the Go owner can bound work and
299
+ account for model calls. It also currently disables the whole `tool-web` package,
300
+ including both `web_search` and `web_fetch`. This is a conservative policy,
301
+ not a claim that every DSH web operation requires a model: the official
302
+ [web tool](https://github.com/deepseek-ai/deepseek-harness/blob/fcc0ad462172522aaf5c93a7b2e01f6b9f0b0159/packages/web/tool-web/README.md)
303
+ configures search and fetch independently, while the
304
+ [DeepSeek search backend](https://github.com/deepseek-ai/deepseek-harness/blob/fcc0ad462172522aaf5c93a7b2e01f6b9f0b0159/packages/web/web-search-deepseek/README.md)
305
+ does use an auxiliary model request. Full access changes the host access policy;
306
+ these tool and auxiliary-model restrictions still apply.
307
+ Restoring retrieval or [automatic compaction](https://github.com/deepseek-ai/deepseek-harness/blob/fcc0ad462172522aaf5c93a7b2e01f6b9f0b0159/packages/compaction/compaction-basic/README.md)
308
+ requires a separate check of accounting, budgets, cancellation, and directory
309
+ ownership; the view's location does not establish those guarantees.
189
310
 
190
311
  Codex Pro uses fresh ephemeral calls and checks the model, directory, approval
191
312
  policy, and sandbox mode before execution. In version 0.8.0, the full
192
- `sandboxPolicy` reaches Flywheel only in the returned receipt. Flywheel rejects
313
+ `sandboxPolicy` reaches Flywheel only in the returned receipt. In restricted modes, Flywheel rejects
193
314
  delivery when that policy permits unexpected writable roots or network access,
194
315
  but **this check happens after execution and cannot undo access already
195
316
  permitted by custom Codex configuration**. It is not a complete pre-execution
package/README.md CHANGED
@@ -6,11 +6,15 @@
6
6
 
7
7
  完整的 npm 安装、SDK 配置到首个任务流程见 [Mac 入门教程](../../docs/getting-started.md),适用于 Flywheel **0.28.0 及以后的完整 npm 发行版**。安装前用 `npm view @ckanner/flywheel version` 确认 registry 的 latest 已更新到所需版本;源码合并或 GitHub Release 不代表 npm 已发行。旧 0.22.1 没有本教程使用的安装与 DSH 接口,当前发行状态见[发行记录](../../docs/releasing.md#3-失败恢复)。
8
8
 
9
+ **Flywheel 0.28.1 引入原生会话视图**;0.28.0 仍使用输入区底部弹层。需要升级 CLI 与桌面插件到同一新版本,源码合并不会自动更新已安装的插件。
10
+
11
+ 订阅预设迁移命令和 `permissions.mode` 从 **0.28.2** 开始提供。升级保留已有配置;只有用户明确应用迁移时才备份并更新模型与权限。
12
+
9
13
  ## 提供什么
10
14
 
11
15
  | 部分 | 行为 |
12
16
  |---|---|
13
- | 桌面面板 | 会话输入框底部的 **Flywheel** 按钮;配置查看、环境检查、SDK 无推理探测、启动/刷新/停止;显示全部工作单元、逐项诊断与未知计量 |
17
+ | 桌面会话视图 | 与“对话/轨迹”并列的 **Flywheel** 视图;查看任务进度和待处理事项、检查模型配置与环境、启动/刷新/停止已有任务 |
14
18
  | `/flywheel` | 人工 slash command,通过已有 DSH commands Remote 调用 Go CLI;不会将控制指令交给模型执行 |
15
19
  | `flywheel_control` | 模型工具,复用同一个校验与 CLI 控制路径;后台 start 很快返回,stop 等待引擎确认 |
16
20
  | `flywheel-dsh-worker` | 独立 Node 进程,通过官方 `dsh --profile sdk` stdio JSON-RPC 执行一个原生模型会话 |
@@ -19,6 +23,8 @@
19
23
 
20
24
  插件没有自己的任务数据库,不直接读写 `state.json`。桌面退出不会让后台 Go 任务失去父智能体;Go 拥有 worker 生命周期。原生 SDK 入口只接收已注册的 LLM adapter provider;`subagent_codex_pro`、Kimi ACP、Teams 都不是此接口的 provider。Kimi CLI、Codex Pro machine API 和旧显式 Codex CLI 使用各自 Go driver;Codex Pro 复用同一插件 runner,不经过 DSH 父模型或工具名转发。
21
25
 
26
+ 这个视图用于回答“任务运行到了哪一步、哪里需要处理、使用哪些模型,以及如何停止或恢复”。需求讨论、编写契约和一般对话继续使用 DSH 的对话与 skills;Flywheel 不提供另一套聊天界面,也不接管 DSH 的模型选择器、输入框、轨迹或右侧栏。
27
+
22
28
  ## 一条命令安装到自己的 Mac
23
29
 
24
30
  已有 Node.js 22.18.0 或更高、npm 和 DSH Mac 桌面后,先确认 About、桌面安装的 `dsh --version` 与实际运行入口,再运行:
@@ -80,7 +86,7 @@ reasoningEffort = off | low | high | max
80
86
 
81
87
  npm 启动器自动解析并注入 `FLYWHEEL_CODEX_PRO_WORKER`。独立 Go 二进制默认从 PATH 查找 `flywheel-codex-pro-worker`,源码开发可显式设为构建后的 `dist/codex-pro-worker.js`。`FLYWHEEL_CODEX_BIN` 可指定底层 Codex 可执行程序,默认 `codex`;`CODEX_HOME` 沿用用户选择的配置/登录目录。Go 会将这些运行必需项交给插件,不把凭证复制到配置、契约或 Git。
82
88
 
83
- 新调用固定使用 ephemeral 会话和 `read-only`/`workspace-write`,approval 为 never。插件运行前核对模型、cwd 和权限模式;完整 sandboxPolicy 由 Flywheel 在返回后审查,允许 Codex 标准临时目录、拒绝工作区外额外 roots 与网络启用。0.8.0 尚无公开的运行前完整策略 guard,事后拒绝交付不能阻止先前的访问;可信 Codex 配置仍是本机运行前提。
89
+ 新调用使用 ephemeral 会话,权限由 `permissions.mode` 决定,approval 为 never。role-based 选择 `read-only`/`workspace-write`;full-access 请求 `danger-full-access`。插件运行前核对模型、cwd 和权限模式,完整 sandboxPolicy 由 Flywheel 在返回后审查。受限模式允许 Codex 标准临时目录、拒绝工作区外额外 roots 与网络启用;完全权限则核对 `dangerFullAccess` 策略,不声称 OS 隔离。0.8.0 尚无公开的运行前完整策略 guard,事后拒绝交付不能阻止先前的访问;可信 Codex 配置仍是本机运行前提。
84
90
 
85
91
  完整 machine receipt 写入指标,保留 accepted effort、未知 effectiveEffort、usage 完整性与进程终态。插件正常收尾可能主动 TERM/KILL app-server,其物理 exit code 可以为空;Flywheel 只有在完整终态证明任务完成、清理已确认且外层 worker 干净退出时才能继续。取消、超时、截断、启动或清理失败均阻止成功。Go 为此 worker 预留至少 10 秒终止宽限,避免截断插件内部清理。
86
92
 
@@ -117,7 +123,7 @@ node --input-type=module -e 'console.log(JSON.stringify({type:"start",protocol:1
117
123
 
118
124
  ## 桌面使用
119
125
 
120
- 打开一个 DSH 会话,点击输入区底部的 **Flywheel**,填写已准备并审阅契约的任务目录,例如 `/repo/docs/my-task`。仓库目录默认取当前 DSH 会话的起始目录,也可填明确的绝对路径。按钮只执行以下 Go JSON 控制接口:
126
+ 打开一个 DSH 会话,在顶部“对话/轨迹”所在的视图栏选择 **Flywheel**。入口由 DSH 的原生视图栏管理;若未直接显示,检查该栏的更多视图入口。先在“对话”中让助手按 `flywheel-new` 准备任务说明与验收清单,审阅后由助手给出实际路径。“任务资料目录”就是这些文件所在的目录,例如 `/Users/me/project/docs/fix-login`,不是插件安装目录。“项目目录(可选)”默认取当前 DSH 会话目录,可留空;任务在另一份 worktree 时填对应的项目路径,例如 `/Users/me/project`。只看配置或做检查时,任务资料目录也可留空。按钮只执行以下 Go JSON 控制接口:
121
127
 
122
128
  ```sh
123
129
  flywheel control status --task-dir /repo/docs/my-task --cwd /repo
@@ -133,27 +139,49 @@ flywheel control doctor --task-dir /repo/docs/my-task --cwd /repo --probe
133
139
  /flywheel {"action":"status","taskDir":"/repo/docs/my-task","cwd":"/repo"}
134
140
  ```
135
141
 
136
- 模型工具 `flywheel_control` 接受 `action`、`taskDir`、`cwd`,以及仅用于 doctor 的可选 `probe` 布尔值。config/doctor 可省 taskDir,cwd 可沿用会话目录;start/status/stop 必须指定任务。输入统一校验,使用 argv 调用,不拼接 shell 命令。面板只在点击时读取状态,不自动轮询,也不重新决定模型路由。
142
+ 模型工具 `flywheel_control` 接受 `action`、`taskDir`、`cwd`,以及仅用于 doctor 的可选 `probe` 布尔值。config/doctor 可省 taskDir,cwd 可沿用会话目录;start/status/stop 必须指定任务。输入统一校验,使用 argv 调用,不拼接 shell 命令。打开视图不会启动任务或探测;视图只在点击时读取状态,不自动轮询,也不自动发现其他入口启动的任务。查看已有任务时,选择同一任务目录再刷新。
143
+
144
+ “查看模型配置”展示实际配置来源、展开后的阶段绑定及 provider/channel/权限。“检查安装与配置”仅做本地预检,不启动 SDK;“检查 DSH 接入”额外临时启动 SDK、核对配置/目录/权限后退出。首次安装、升级或排障时按需使用,平时不必每次点击;两项都不向模型发送消息,也不验证账号、额度和实际回答能力。doctor 的合法退出码 1 会显示逐项诊断,超时、坏协议或不匹配的任务身份仍视为控制错误。`ok:true` 不代表账号、额度和真实推理通过。
145
+
146
+ 状态区区分未初始化、运行、已完成、暂停、停止、升级和预算停止;全部 packet 可见,不会只展示前几个。未知 usage/cost 明确保留,原始 JSON 默认折叠。配置显示引擎实际选择的文件及阶段绑定;已有用户配置不会因安装或切换 DSH 对话模型而自动迁移。
147
+
148
+ ### 视图、请求与任务的生命周期
149
+
150
+ 任务/仓库路径草稿和已取得的快照按 DSH 会话分别保留,在宿主仍保留该会话绑定时,切换“对话/轨迹/Flywheel”后可以继续使用;这不是任务数据库,也不保证在会话绑定释放、插件重载或桌面重启后继续保留。每个会话同一时刻只等待一个控制请求。启动/停止等待期间锁定目录输入;只读请求等待期间可以编辑路径,但仍等待已有请求返回,并忽略旧选择的迟到响应。切换视图不会把等待中的请求当成已经完成。
137
151
 
138
- “查看模型配置”展示配置来源、展开后的阶段绑定及 provider/channel;“检查环境”不启动 SDK,“SDK 无推理检查”显式启用 probe。doctor 的合法退出码 1 会显示逐项诊断,超时、坏协议或不匹配的任务身份仍视为控制错误。`ok:true` 不代表账号、额度和真实推理通过。
152
+ 任务状态是最近一次成功读取的快照,带有刷新时间,不能当作实时监控。读取失败时保留已有有效内容并显示失败;启动或停止的响应丢失、超时或断连表示**结果未确认**,不能推断任务没有启动或已经停止。结果未确认时,界面保留提示并禁止继续启动/停止,直到“刷新状态”成功核对该任务;必要时查看任务日志,再决定恢复。界面不会自动重试启动或停止。
139
153
 
140
- 状态区区分未初始化、运行、已完成、暂停、停止、升级和预算停止;全部 packet 可见,不会只展示前几个。未知 usage/cost 明确保留,原始 JSON 默认折叠。改任务/仓库路径会清空旧视图并忽略旧请求的迟到结果。关闭面板、卸载插件或退出桌面,不等于停止任务;重新打开后按“刷新状态”恢复观察,需停止时点“停止”。
154
+ 目录不存在或控制进程无法创建等情况,只有宿主结构化确认请求尚未执行,界面才允许修正输入或环境后再次提交。普通错误、断连或错误文字本身不构成这项确认,不能据此解除结果未确认状态。`/flywheel` 的失败 `text` 使用 `type:"flywheel-control-error"` 的 JSON 包装,字段和兼容行为见[命令失败协议](PROTOCOL.md#dsh-命令失败与是否派发)。
155
+
156
+ 切换视图、关闭会话页面、卸载插件或退出桌面,都不等于向后台 Go 任务发出停止请求。需要停止时显式点击“停止”并等待引擎确认;重新打开后刷新同一任务。DSH 的原生轨迹继续展示父会话已有的命令与工具记录;独立 SDK、Kimi、Codex Pro worker 的完整执行历史不会自动合并到父会话轨迹,也不会被伪装成 DSH 原生后台任务。
157
+
158
+ ### 宿主 UI 接入
159
+
160
+ 客户端通过 `ctx.slots.inject()` 和独立 `id: flywheel` 注册到 `conversation.view` 列表,使用宿主的会话作用域和视图切换。保留“对话/轨迹”原有条目、输入区和右侧栏;不注册覆盖它们的同名条目,不另外绘制悬浮侧栏或底部大弹层。长路径、模型信息和错误在视图内容区换行或局部滚动,不通过遮挡宿主控件来增加空间。
161
+
162
+ 作为外部 plain-JS 插件,浏览器模块只运行时导入共享 React,不导入 `ui-primitives`、`client-store` 或其他 Harness Client 包。插件自有按钮、输入框、查看状态 store handle 和 observable;宿主根据注册契约管理会话实例并提供读取 hooks,locale 通过注入服务取得。控件参照宿主结构和交互,颜色使用语义别名,字体继承宿主,编译后的 CSS Modules 样式随 React 视图挂载和卸载。这样匹配宿主界面,也避免绑定不稳定的 Client 模块值接口。
163
+
164
+ 依据固定为声明版本 `0.2.1-rc.5` 的源码快照 `b830ec950faba0a46dda564be3e2d854afed94f1`:[外部插件实践](https://github.com/deepseek-ai/deepseek-harness/blob/b830ec950faba0a46dda564be3e2d854afed94f1/packages/preset/agent-preset/skills/cordis-plugin-development/references/practices.md)、[UI 规范](https://github.com/deepseek-ai/deepseek-harness/blob/b830ec950faba0a46dda564be3e2d854afed94f1/.agents/skills/dsh-client-ui-ux/SKILL.md)、[布局说明](https://github.com/deepseek-ai/deepseek-harness/blob/b830ec950faba0a46dda564be3e2d854afed94f1/packages/client/ui-layout/README.md),以及[会话插槽契约](https://github.com/deepseek-ai/deepseek-harness/blob/b830ec950faba0a46dda564be3e2d854afed94f1/packages/client/ui-conversation/src/client/contract/slots.ts)和[插槽生命周期](https://github.com/deepseek-ai/deepseek-harness/blob/b830ec950faba0a46dda564be3e2d854afed94f1/docs/subsystems/slots.md)。视图使用 Conversation 已有标题栏和内容区,遵循其窗口边距,不修改全局窗口留白。源码契约核对不代替目标 Mac 桌面的实机验证。
141
165
 
142
166
  ## 权限、上下文与报告归档
143
167
 
144
168
  每个调用使用新的 SDK Session;provider/model/effort 在该进程中固定。v1 不支持 resume、图像/附件输入或 SDK 原生 output schema。文本与报告文件由 Go 的冻结合同和 JSON Schema 验收,不能把 SDK idle 当成验收完成。
145
169
 
146
- worker 只支持 `read-only` 与 `workspace-write`。Mac 上由 DSH 的 Seatbelt bash runner 和 native fs fence 执行权限。workspace-write 的写入范围是**实际工作目录加 DSH 规定的系统临时区**,并非额外目录列表,也不是网络隔离。策略插件将 approval 固定为 `never`,即拒绝提权。
170
+ worker 支持 `read-only`、`workspace-write` 和显式 `danger-full-access`。新订阅预设通过 `permissions.mode:full-access` 为全部阶段选择完全权限,approval 固定为 `never`;Kimi print 使用原生 auto,不逐步请求用户点击允许。已有文件缺省仍保留 role-based,需通过[配置迁移](../../docs/configuration.md#将旧配置切换到已有的三种资源)显式采用新方案。受限模式由 Mac 上 DSH 的 Seatbelt bash runner 和 native fs fence 执行,workspace-write 范围是**实际工作目录加 DSH 规定的系统临时区**。full-access 如实记录无 OS 沙箱限制;宿主静态拒绝、账号与操作系统权限不被绕过。
171
+
172
+ 执行报告仍先写到 worktree 内的任务报告路径,由 Go 校验后归档到主任务目录。权限模式来自明确配置,不能因为报告写入失败而暗中扩大它;任务边界、冻结验收和候选身份检查保持有效。
173
+
174
+ 默认覆盖会关闭 DSH 自主委派、workflow、goal 驱动、模型生成标题及自动模型压缩,避免在一个 Go 工作单元之外再启动辅助模型调用。需要压缩/继续执行时由 Go 显式决定下一次任务;超出上下文或输出 token 限制不会伪装成成功。SDK profile 应只装所需的可信 provider /工具,第三方 Host 插件本身是进程内代码,不能由本包替它提供任意代码隔离。
147
175
 
148
- 执行报告先写到 worktree 内的任务报告路径,由 Go 校验后归档到主任务目录。不得为报告写入而把整个任务目录或用户目录设成 full access。
176
+ 这份临时覆盖只用于每次独立启动的 **SDK worker 进程**,不修改桌面 profile,不卸载或隐藏桌面已有的插件、skills、对话工具及 UI。反过来,桌面已安装插件或已登录账号,也不证明 SDK profile 已加载并授权相同能力;应按对应 harness 的配置和正式授权流程核对。
149
177
 
150
- 默认覆盖会关闭 DSH 自主委派、workflow、goal 驱动、模型生成标题、web search 工具及自动模型压缩,避免在一个 Go 工作单元之外再启动辅助模型调用。需要压缩/继续执行时由 Go 显式决定下一次任务;超出上下文或输出 token 限制不会伪装成成功。SDK profile 应只装所需的可信 provider /工具,第三方 Host 插件本身是进程内代码,不能由本包替它提供任意代码隔离。
178
+ 当前覆盖禁用整个 `tool-web`,因此 SDK worker 的 `web_search` 和 `web_fetch` 都不可用。这是一项保守的运行策略,不是 DSH 所有网页操作必然调用模型:官方 [web 工具](https://github.com/deepseek-ai/deepseek-harness/blob/fcc0ad462172522aaf5c93a7b2e01f6b9f0b0159/packages/web/tool-web/README.md)支持分别配置搜索与抓取,[DeepSeek 搜索后端](https://github.com/deepseek-ai/deepseek-harness/blob/fcc0ad462172522aaf5c93a7b2e01f6b9f0b0159/packages/web/web-search-deepseek/README.md)才明确包含辅助模型调用。此次 UI 修复不变更 worker 策略;恢复检索或[自动压缩](https://github.com/deepseek-ai/deepseek-harness/blob/fcc0ad462172522aaf5c93a7b2e01f6b9f0b0159/packages/compaction/compaction-basic/README.md)等能力,需要另行验证调用计量、预算、取消和工作目录边界。
151
179
 
152
180
  ## 生命周期与可验证范围
153
181
 
154
182
  官方 rc.5 SDK 没有 per-turn cancel,所以使用每调用一个 SDK 进程。worker 请求 `shutdown` 并等待退出;SDK 自己排空其托管命令。Go 继续负责外层 deadline、取消及它拥有的进程组清扫。正常 SDK 关闭未被证明时结果失败,不能进入成功验收。Go 默认 5 秒 kill grace 应保留,以给 worker 清理窗口;不要配置短于桥接清理预算的值。
155
183
 
156
- 测试覆盖离线 worker 全生命周期与事件折叠;桌面 command/tool 入口一致;构建后的浏览器模块经 ModuleLoader/宿主 React/真实 DOM/Remote 的交互;Go 与 Node 的配置、诊断和失败契约;安装记录校验、用户配置优先及损坏入口拒绝。根目录的 npm 安装测试使用实际六包 tarball、隔离目录和 DSH 协议桩,验证完整安装流程。前轮还核对官方 npm rc.5 的真实 Host commands/tools 注册、SDK 初始化/关闭,以及当前 Linux 无可用沙箱时在 prompt 前 fail closed。具体运行结果见[验证记录](../../docs/validation/2026-11-01-results.md)。
184
+ 测试覆盖离线 worker 全生命周期与事件折叠;桌面 command/tool 入口一致;构建后的浏览器模块在 React 与 jsdom 中运行插件自有控件、store handle 和 observable。组件夹具适配槽位桥接和 Remote,另用已发布的 rc.5 renderer、slots 与 Cordis 检验真实注册、会话绑定、声明收起/恢复及卸载;这两类测试都不验证真实宿主几何布局。还覆盖 Go 与 Node 的配置、诊断和失败契约,以及安装记录校验、用户配置优先和损坏入口拒绝。根目录的 npm 安装测试使用实际六包 tarball、隔离目录和 DSH 协议桩,验证完整安装流程。前轮还核对官方 npm rc.5 的真实 Host commands/tools 注册、SDK 初始化/关闭,以及当前 Linux 无可用沙箱时在 prompt 前 fail closed。前轮运行结果见[验证记录](../../docs/validation/2026-11-01-results.md)。
157
185
 
158
186
  尚未在用户 Mac 实测:桌面安装和 UI 渲染、Seatbelt 探针、实际 Flash/GPT 推理、授权可见性及断电恢复。Linux 上的 CLI 加载成功不代替这些验证。不会将协议桩写成付费模型成功的证据。
159
187
 
@@ -0,0 +1,38 @@
1
+ # Third-party notices
2
+
3
+ ## DeepSeek Harness UI patterns
4
+
5
+ Flywheel's plugin-owned Button, Input, and ongoing StateDot treatments are
6
+ adapted from DeepSeek Harness at commit
7
+ `b830ec950faba0a46dda564be3e2d854afed94f1`:
8
+
9
+ - `packages/client/ui-primitives/src/Button.tsx` and its stylesheet
10
+ - `packages/client/ui-primitives/src/Input.tsx` and its stylesheet
11
+ - `packages/client/ui-primitives/src/StateDot.tsx` and its stylesheet
12
+
13
+ [Upstream source](https://github.com/deepseek-ai/deepseek-harness/tree/b830ec950faba0a46dda564be3e2d854afed94f1/packages/client/ui-primitives/src)
14
+
15
+ These adapted portions retain the upstream MIT license below. Other Flywheel
16
+ source remains under the repository's existing license.
17
+
18
+ MIT License
19
+
20
+ Copyright (c) 2026 DeepSeek
21
+
22
+ Permission is hereby granted, free of charge, to any person obtaining a copy
23
+ of this software and associated documentation files (the "Software"), to deal
24
+ in the Software without restriction, including without limitation the rights
25
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
26
+ copies of the Software, and to permit persons to whom the Software is
27
+ furnished to do so, subject to the following conditions:
28
+
29
+ The above copyright notice and this permission notice shall be included in all
30
+ copies or substantial portions of the Software.
31
+
32
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
36
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
38
+ SOFTWARE.