@ckanner/flywheel 0.22.1 → 0.27.3

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.
@@ -0,0 +1,126 @@
1
+ # 模型 profiles、阶段绑定与预检
2
+
3
+ Flywheel 在启动时加载一份完整配置,再把模型 profile 展开成每个阶段的实际绑定。模型选择是显式配置,不由另一个模型替你决定;修改配置后需要重新启动引擎。
4
+
5
+ ## 1. 配置来源
6
+
7
+ 发现顺序为任务目录、项目 Git 根目录、全局文件、内嵌默认表,选择第一个存在的完整文件。全局默认路径为 `~/.config/flywheel/flywheel.config.json`;`FLYWHEEL_CONFIG` 可覆盖全局文件路径,但不能越过已经存在的任务/项目配置。当前不通过 `XDG_CONFIG_HOME` 改变该默认路径。
8
+
9
+ 高优先级文件不可读、JSON 无效或符号链接失效时直接报错,不悄悄使用其他账号或模型配置。不同文件的 profiles、loops、routes、channels 不逐字段合并。
10
+
11
+ ```sh
12
+ flywheel config inspect --cwd /repo --task-dir /repo/docs/task --json
13
+ ```
14
+
15
+ 输出 `source`、`scope`、物理 `cwd/taskDir` 和按阶段排列的 `bindings`。`scope` 为 task/project/global/embedded。它只解析配置,不物化全局文件,不读取账号 token,不启动模型,也不创建任务状态。省略任务时只从项目及更低层发现配置,不会误读运行命令所在的另一个目录。
16
+
17
+ 展示值包含 Flywheel 已确定的 driver 默认:DSH/Codex/Kimi 的空 thinking 为 high,pi/omp/zcode 为 max;Kimi/Codex/Zcode 的空 model 使用各自 driver 常量。pi/omp 未指定模型时仍留空,表示 Flywheel 不能从配置确定它。`residentSession` 只有 Plan+Kimi+明确启用时为 true,不把其他阶段忽略的请求显示为已生效。
18
+
19
+ ## 2. 四个概念各负责什么
20
+
21
+ | 字段 | 含义 | 示例 |
22
+ |---|---|---|
23
+ | `harness` | 实际工具循环与进程后端 | `dsh`、`kimi`、`codex` |
24
+ | `provider` | DSH SDK 已注册的 LLM adapter ID;仅 DSH 使用 | `deepseek-official`、`chatgpt` |
25
+ | `channel` | 配置中的凭证/后备/计量渠道名称 | `deepseek-sdk`、`chatgpt-sdk`、`kimi-subscription` |
26
+ | `profile` | 当前 Flywheel 配置内的一组模型字段引用 | `flash`、`gpt-review`、`kimi` |
27
+
28
+ Flywheel 的 model profile 与 DSH 的 `sdk`/`desktop` profile 是两件事。前者复用模型定义,后者决定宿主实际加载的插件和授权配置。channel 别名本身不会切换 DSH 账号;给同一个 provider 起两个 channel 名称不等于拥有两份独立订阅或额度。
29
+
30
+ DSH 的实际 provider 按 `binding.provider` → `channels[channel].provider` → 旧 `channel` 名解析。前两者都明确配置而不相等时拒绝加载。兼容旧内联配置的最后一项只适用于 DSH;Codex 和 Kimi 使用自己的 CLI 登录状态,不接受一个会被静默忽略的 provider。
31
+
32
+ ## 3. 从完整示例开始
33
+
34
+ 查看默认内联表或可复用 profiles 表:
35
+
36
+ ```sh
37
+ flywheel template flywheel.config.example.json
38
+ flywheel template flywheel.profiles.example.json
39
+ ```
40
+
41
+ 确认目标没有需要保留的配置后,选择其中一份导出到项目根。已有配置先备份并审阅差异,避免 shell 重定向覆盖它。下面只是解释结构的片段;完整可用起点在第二份模板中:
42
+
43
+ ```json
44
+ {
45
+ "profiles": {
46
+ "flash": {
47
+ "harness": "dsh",
48
+ "provider": "deepseek-official",
49
+ "channel": "deepseek-sdk",
50
+ "model": "deepseek-flash",
51
+ "thinking": "high"
52
+ },
53
+ "gpt": {
54
+ "harness": "dsh",
55
+ "provider": "chatgpt",
56
+ "channel": "chatgpt-sdk",
57
+ "model": "gpt-6.1-sol",
58
+ "thinking": "high"
59
+ }
60
+ },
61
+ "loops": {
62
+ "review": { "profile": "gpt" },
63
+ "judge": { "profile": "gpt", "model": "gpt-6-astra" },
64
+ "intake": { "profile": "flash", "thinking": "low" }
65
+ },
66
+ "routes": {
67
+ "default": { "profile": "flash" }
68
+ },
69
+ "channels": {
70
+ "deepseek-sdk": { "harness": "dsh", "provider": "deepseek-official", "env-key": null },
71
+ "chatgpt-sdk": { "harness": "dsh", "provider": "chatgpt", "env-key": null }
72
+ }
73
+ }
74
+ ```
75
+
76
+ 这些模型名沿用本仓库的初始绑定,能否使用仍由实际账号和 adapter 决定。读取配置、看到模型名称、adapter 接受参数都不等于账号已获授权。DeepSeek 默认仅 Flash;profiles 不引入自动跨渠道付费回退。
77
+
78
+ ### 覆盖与错误规则
79
+
80
+ | 情况 | 行为 |
81
+ |---|---|
82
+ | 阶段省略某字段 | 继承所引用 profile 的字段 |
83
+ | 阶段显式写 `model`/`channel`/`thinking` 等 | 只覆盖该阶段,不修改共享 profile 或其他阶段 |
84
+ | `thinking: ""` | 使用对应 harness 的现有默认 effort,不重新继承 profile |
85
+ | `resident-session: false` | 明确关闭该阶段的恢复请求;不会丢失为缺省值 |
86
+ | `judge-panel: null` | 关闭第二意见,保持默认行为 |
87
+ | profile 定义缺 `harness/model/channel`,或这些字段为空/null/纯空白 | 加载失败 |
88
+ | profile 不存在、未知字段、错拼阶段名、不支持的 harness | 加载失败,不静默回落 |
89
+ | profile 再引用另一个 profile | 不支持继承链;加载失败 |
90
+ | `_note`、`_note_*` | 允许配置对象中的说明文字,不进入执行绑定 |
91
+
92
+ `resident-session` 是阶段策略,不能放进 profile。当前只有 Kimi 的 Plan 可恢复历史,且必须匹配实际 harness/model/channel/cwd/thinking;profile 名改了而实际值没变,不影响身份。其他执行、评审和 SDK 调用仍是新会话。
93
+
94
+ 旧内联绑定保留原有缺省行为,不强制迁移。`env-key: null`、`retry.jitter: 0`、`worktree.enabled: false` 等已有合法零值继续支持。显式切换 harness 或 channel 时,要一起核对继承的 provider;必要时用 `provider: ""` 清除显式值,再按新 channel 解析,不能保留另一个 adapter 的 ID。
95
+
96
+ ## 4. 后备渠道与记录
97
+
98
+ `channels[channel].fallback` 仍是人工配置的有界后备链,只有既有错误分类/重试策略允许时才使用。切换后依据新渠道重新选择 provider 和模型;不会继续沿用原渠道的 provider。后备渠道省略 harness 时继承当前 harness,不回到链起点的后端。
99
+
100
+ 指标分别保存 `harness`、`provider`、`channel`、`model`。provider 来自 driver 可确认的结果,未知时为 null;channel 继续描述配置渠道。usage 和美元成本未报告时保持 unknown,订阅不会被当成已知零成本。profiles 不改变计费规则,也不会绕过 hard budget。
101
+
102
+ ## 5. 预检范围和结果
103
+
104
+ ```sh
105
+ flywheel doctor --cwd /repo --json
106
+ flywheel doctor --cwd /repo --task-dir /repo/docs/task --json
107
+ flywheel doctor --cwd /repo --task-dir /repo/docs/task --probe --json
108
+ ```
109
+
110
+ 没有任务时检查全部配置绑定。有任务时校验 Spec/packet,仅把 Plan、Review、Judge、已启用的第二意见和实际 packet 路由列为必需;其他绑定显示 skipped。任务尚未生成 packet 时检查默认执行路由并提示规划后复查。mock driver 跳过真实工具检查,不冒充模型已验证。
111
+
112
+ 预检可提前运行,正式 `run`/`control start` 仍需至少一个已准备并审阅的合法 packet;没有 packet 的 warn 不表示引擎已经能从空任务开始。绑定中的 permissionMode 表示阶段要求,实际实施能力还取决于 harness,尤其 Kimi CLI 不能据此宣称拥有 OS 沙箱。
113
+
114
+ 本地检查确认命令可用、版本响应可靠,以及声明的环境变量存在且非空,不显示变量值。`--probe` 才启动 DSH worker 验证 adapter 接受配置、cwd、完整沙箱、approval policy 和 SDK 正常关闭。相同 provider、channel、model、effort、cwd 和权限的探测去重;不同账号别名或读写权限不能相互代替。整体验证预算 40 秒,另留进程清理窗口。
115
+
116
+ | 状态 | 解释 |
117
+ |---|---|
118
+ | `pass` | 本项已取得对应证据;只对该项有效 |
119
+ | `fail` | 存在阻断项,整体 `ok:false` 且退出码 1 |
120
+ | `warn` | 限制或规划前状态,需要结合实际任务理解 |
121
+ | `unknown` | 未验证,例如账号授权、额度与真实模型服务能力 |
122
+ | `skipped` | 非必需绑定、mock、重复探测或前置检查失败等 |
123
+
124
+ 任何 probe 都不发送 `session/prompt`、不运行 L1/L2/L3、不写 Flywheel 状态或创建工作树;SDK 初始化可能访问 provider 目录并产生自己的会话/缓存文件。只读指 Flywheel 配置与任务状态,不表示整个宿主文件系统绝对无写入。
125
+
126
+ 桌面面板、`/flywheel` 和 `flywheel_control` 共用 `control config|doctor`,可省略 taskDir;只有 doctor 支持 `probe:true`。诊断阻断与传输失败分开显示。桌面使用的 PATH/profile/环境可能与终端不同,安装后应在面板里再检查一次。
@@ -0,0 +1,138 @@
1
+ #!/usr/bin/env bash
2
+ # Prepare a new, self-contained Flywheel demo. No model call or Git commit.
3
+ set -eu
4
+
5
+ if [ "$#" -ne 1 ]; then
6
+ printf '%s\n' 'usage: bash create-first-task.sh /absolute/path/to/new-demo-directory' >&2
7
+ exit 1
8
+ fi
9
+ demo_dir=$1
10
+ case "$demo_dir" in
11
+ /*) ;;
12
+ *) printf '%s\n' 'demo directory must be an absolute path' >&2; exit 1 ;;
13
+ esac
14
+ if [ -e "$demo_dir" ] || [ -L "$demo_dir" ]; then
15
+ printf '%s\n' 'demo directory already exists; choose a new path' >&2
16
+ exit 1
17
+ fi
18
+ flywheel_bin=${FLYWHEEL_BIN:-flywheel}
19
+ config_json=$("$flywheel_bin" template flywheel.config.example.json)
20
+
21
+ mkdir -p "$demo_dir/acceptance" "$demo_dir/docs/add"
22
+ cat > "$demo_dir/go.mod" <<'EOF'
23
+ module example.local/flywheel-demo
24
+
25
+ go 1.27.0
26
+ EOF
27
+ cat > "$demo_dir/sum.go" <<'EOF'
28
+ package demo
29
+
30
+ // Add returns the sum of two integers. The task starts with a deliberate stub.
31
+ func Add(a, b int) int { return 0 }
32
+ EOF
33
+ cat > "$demo_dir/acceptance/sum_test.go" <<'EOF'
34
+ package acceptance
35
+
36
+ import (
37
+ "testing"
38
+
39
+ demo "example.local/flywheel-demo"
40
+ )
41
+
42
+ func TestAddAcceptance(t *testing.T) {
43
+ for _, tc := range []struct{ a, b, want int }{
44
+ {2, 3, 5}, {-2, -3, -5}, {-4, 4, 0}, {0, 7, 7},
45
+ } {
46
+ if got := demo.Add(tc.a, tc.b); got != tc.want {
47
+ t.Errorf("Add(%d, %d) = %d; want %d", tc.a, tc.b, got, tc.want)
48
+ }
49
+ }
50
+ }
51
+ EOF
52
+ cat > "$demo_dir/.gitignore" <<'EOF'
53
+ /coverage.out
54
+ EOF
55
+ cat > "$demo_dir/docs/add/.gitignore" <<'EOF'
56
+ orchestrator.log
57
+ orchestrator.pid
58
+ metrics.jsonl
59
+ .state.lock
60
+ .run.lock
61
+ .stop-request
62
+ .control/
63
+ EOF
64
+ cat > "$demo_dir/docs/add/spec.md" <<'EOF'
65
+ ---
66
+ spec-version: 1
67
+ title: First Flywheel task
68
+ goal: Implement Add and meaningful unit tests in a small Go repository.
69
+ non-goals: [CLI, networking, dependencies, overflow policy beyond Go integer addition]
70
+ milestones:
71
+ - id: M-01
72
+ title: Addition and tests
73
+ gate: Unit tests, coverage, and frozen acceptance pass.
74
+ requirements:
75
+ - id: R-01
76
+ title: Add returns a + b for positive, negative, and zero inputs
77
+ milestone: M-01
78
+ verification: go test ./acceptance
79
+ - id: R-02
80
+ title: Ordinary unit tests assert results and cover every function statement
81
+ milestone: M-01
82
+ verification: go test -coverprofile=coverage.out . and the coverage gate
83
+ ---
84
+
85
+ # First Flywheel task
86
+
87
+ Only implement `sum.go` and add `sum_test.go`. The acceptance package is frozen.
88
+ Keep all dependency, contract, and verification settings unchanged.
89
+
90
+ ## Acceptance dry-run evidence
91
+
92
+ Before approving this contract, run each L1 command from the packet and record
93
+ its exact command, exit status, and a short output summary here. Initial failure
94
+ is expected because Add deliberately returns zero and ordinary tests are absent.
95
+ Do not replace these observations with claimed model-run or Mac-run results.
96
+ EOF
97
+ cat > "$demo_dir/docs/add/task-packet-M01-T01.md" <<'EOF'
98
+ ---
99
+ packet-id: M01-T01
100
+ contract-version: 1
101
+ goal: Implement Add and ordinary unit tests without changing frozen acceptance.
102
+ requirements: [R-01, R-02]
103
+ route: default
104
+ needs-live-credentials: false
105
+ context-files: [sum.go, acceptance/sum_test.go, docs/add/spec.md]
106
+ cache-scope: [docs/add/spec.md]
107
+ boundaries:
108
+ must-not-touch: [acceptance/, go.mod, .gitignore]
109
+ max-files: 2
110
+ acceptance:
111
+ L1:
112
+ - {cmd: "go test ./...", expect: "exit 0"}
113
+ - cmd: >-
114
+ go test -coverprofile=coverage.out . &&
115
+ go tool cover -func=coverage.out |
116
+ awk '$NF != "100.0%" && $NF != "100%" { bad=1 } END { exit bad }'
117
+ expect: exit 0
118
+ L2:
119
+ - {cmd: "go test ./acceptance", expect: "exit 0"}
120
+ review-rubric: |
121
+ Pass only when Add implements integer addition, tests assert actual results,
122
+ frozen acceptance is unchanged, and no unrelated functionality was added.
123
+ A green coverage number alone is insufficient.
124
+ escalation: {max-retries: 3, on-fail: inbox}
125
+ done-report-format:
126
+ requirements-covered: []
127
+ changed-files: []
128
+ commands-run: []
129
+ failures: []
130
+ ---
131
+
132
+ Implement sum.go and sum_test.go only. Do not alter the specification,
133
+ configuration, frozen acceptance, or the coverage threshold.
134
+ Write the required done-report to the exact path provided by the engine prompt.
135
+ EOF
136
+ printf '%s\n' "$config_json" > "$demo_dir/flywheel.config.json"
137
+ printf 'Prepared %s\n' "$demo_dir"
138
+ printf '%s\n' 'Next: inspect the files, initialize Git, dry-run the acceptance commands, review the contract, then start Flywheel.'
@@ -0,0 +1,347 @@
1
+ # Mac 安装与首个 Flywheel 任务
2
+
3
+ 本文适用于 **Flywheel 0.27.3 及以后的完整 npm 发行版**,覆盖 npm 一条命令安装 CLI、worker、DSH 插件与 skills,到配置、启动、观察、停止和恢复一个小任务。DSH 接口目标是已核对的 **Mac 桌面 0.2.1-rc.5**。真实桌面、Seatbelt 和账号调用仍需在自己的 Mac 验收,CI 不能代替这些检查。
4
+
5
+ 安装前用 `npm view @ckanner/flywheel version` 确认 registry 的 latest 已更新到所需版本;源码合并或 GitHub Release 不代表 npm 已发行。旧 0.22.1 没有本教程使用的安装与 DSH 接口,当前发行状态见[发行记录](releasing.md#3-失败恢复)。
6
+
7
+ ## 目录
8
+
9
+ 1. [准备运行环境](#1-准备运行环境)
10
+ 2. [一条命令安装](#2-一条命令安装)
11
+ 3. [桌面入口和 SDK 配置](#3-桌面入口和-sdk-配置)
12
+ 4. [配置模型与 skills](#4-配置模型与-skills)
13
+ 5. [运行无推理检查](#5-运行无推理检查)
14
+ 6. [准备首个小任务](#6-准备首个小任务)
15
+ 7. [启动、观察、停止与恢复](#7-启动观察停止与恢复)
16
+ 8. [升级、排错与卸载](#8-升级排错与卸载)
17
+ 9. [开发与备用构建](#9-开发与备用构建)
18
+
19
+ ## 1. 准备运行环境
20
+
21
+ | 依赖 | 用途与检查 |
22
+ |---|---|
23
+ | Git,已配置提交身份 | Flywheel 使用 worktree 和本地提交交付;执行 `git --version` |
24
+ | Node.js 22 或更高,npm | 安装 Flywheel 并运行 CLI 启动器/DSH worker;执行 `node --version`、`npm --version` |
25
+ | DSH Mac 桌面及其安装的 `dsh` 命令 | 在 About 核对具体版本;执行 `command -v dsh`、`dsh --version` |
26
+ | 已登录的 Kimi CLI | 默认 Plan、frontend、Garden 使用它;执行 `kimi --version`、`kimi --help` |
27
+ | 已登录的 Codex CLI | `hard` 执行路由使用它;执行 `codex --version` |
28
+ | SDK profile 的 DeepSeek 和 ChatGPT provider | 默认实现/评审使用;配置与授权见下一节 |
29
+ | Go 1.27 或更高 | 仅本文的 Go 示例和源码构建需要;npm 安装 Flywheel 不需要 Go 工具链 |
30
+
31
+ 安装器的前提是已有 Node/npm 和桌面 DSH;模型渠道可在安装后补齐。CLI 的登录和安装使用各自正式流程。Kimi 订阅、ChatGPT 订阅和 DeepSeek API 是三条独立渠道;安装 Flywheel 不会替这些工具登录、复制凭证或替换桌面程序。只运行默认小任务时不会使用 `hard` 路由,但所选 Plan、Execute、Review、Judge 均需要可用。
32
+
33
+ ## 2. 一条命令安装
34
+
35
+ 在能找到现有桌面 `dsh` 的终端运行:
36
+
37
+ ```sh
38
+ npx -y @ckanner/flywheel@latest install
39
+ ```
40
+
41
+ 给 Agent 使用时,可以直接采用输出单个 JSON 文档的形式:
42
+
43
+ ```sh
44
+ npx -y @ckanner/flywheel@latest install --json
45
+ ```
46
+
47
+ 两条命令选择一种即可。安装器按顺序完成:
48
+
49
+ 1. 把本次安装器的精确版本装到 npm 全局目录,解析适合本机的 Go 平台包和同版本 DSH worker,核对 CLI 版本。
50
+ 2. 从 Go 二进制安装全部 10 个 skills;全局配置不存在时生成默认配置,已有配置保留。
51
+ 3. 写入 GUI 启动器和安装记录,使用绝对 Node/CLI 路径。
52
+ 4. 通过现有桌面 `dsh` 注册精确版本的 Flywheel 插件,并通过 `plugin list` 验证安装结果。
53
+ 5. 执行不带 `--probe` 的本地 `doctor`,汇总工具、配置及目录检查结果。
54
+
55
+ 结果的 `ok` 与 `ready` 含义不同:**`ok:true` 表示软件安装完成,`ready:true` 表示本次本地 doctor 没有阻断项**。缺 Kimi/Codex 时允许 `ok:true, ready:false`,退出码仍为 0,具体缺项保留在 `diagnostic.checks`。这不代表账号已登录或真实推理通过;`authentication` 保持 `unknown`。安装步骤失败、取消、超时或诊断协议损坏则是安装失败,保留已经完成的步骤,修正原因后重跑。
56
+
57
+ ### 安装参数
58
+
59
+ | 参数 | 作用 |
60
+ |---|---|
61
+ | `--prefix PATH` | npm 全局安装 prefix;默认使用 `npm prefix --global` |
62
+ | `--project PATH` | 把 skills 装到已存在项目的 `.agents/skills`,并在该项目做预检;CLI 仍按全局安装处理 |
63
+ | `--dsh-bin PATH` | 指定现有桌面 `dsh` 命令;默认依次使用 `FLYWHEEL_DSH_BIN` 与 PATH |
64
+ | `--profile NAME` | DSH 插件目标 profile;默认 `desktop`,与 worker 的 SDK profile 是两回事 |
65
+ | `--no-dsh` | 明确只安装 CLI、worker、共享 skills 和启动记录,跳过桌面插件注册 |
66
+ | `--no-global` | 配置当前已持久安装的包,不再执行 npm 全局安装;不应用来把临时 npx 缓存当作永久入口 |
67
+ | `--timeout-ms N` | 每个外部安装步骤的时限,默认 600000 毫秒,允许 100–1800000;取消/终止另有有界清理窗口 |
68
+ | `--json` | 只向 stdout 输出一个结构化安装结果,适合 Agent 自动处理 |
69
+
70
+ 如果系统全局目录不可写,可以使用用户目录,并按实际位置指定桌面命令:
71
+
72
+ ```sh
73
+ npx -y @ckanner/flywheel@latest install --prefix "$HOME/.local" --dsh-bin /absolute/path/to/dsh
74
+ export PATH="$HOME/.local/bin:$PATH"
75
+ flywheel version
76
+ ```
77
+
78
+ 将实际 prefix 的 `bin` 加入自己的 shell 配置后,后续终端也能直接使用 `flywheel`。GUI 通过自动生成的绝对路径入口启动,不依赖这条临时 `export`。不要为修复 prefix 权限问题盲目以 root 运行整个安装器;它需要写入当前使用者的 skills 与桌面 profile。
79
+
80
+ ### 已经使用普通 npm 全局安装
81
+
82
+ 普通 `npm install --global @ckanner/flywheel` 只放置包文件,不运行修改用户目录的 postinstall。随后显式完成配置:
83
+
84
+ ```sh
85
+ flywheel setup --no-global
86
+ ```
87
+
88
+ `install` 与 `setup` 支持相同参数;不加 `--no-global` 时两者都会确保本次精确版本的全局包已安装。选择 `--ignore-scripts` 不会破坏 Go/worker 的包内分发;显式 `setup` 仍需已有 DSH 及其插件安装所需的 registry 访问。安装器不会在后台下载或更新其他 harness。
89
+
90
+ ## 3. 桌面入口和 SDK 配置
91
+
92
+ 安装器已经调用正式接口 `dsh plugin --profile desktop add --save-exact --ignore-scripts @ckanner/dsh-plugin-flywheel@<本次精确版本>`,随后通过 `list` 核对版本。无需再分别安装 worker 或手动选择压缩包。该命令必须来自桌面安装;独立 npm DSH CLI 不能管理保留的 `desktop` profile。按照宿主提示重新载入,在会话输入区底部查找 **Flywheel** 按钮。
93
+
94
+ ### 原生 SDK profile
95
+
96
+ worker 默认使用独立的 `sdk` profile。桌面已安装 provider,不代表 SDK profile 也已加载或授权。DeepSeek 使用 `deepseek-official` provider;GPT 原生路径需在 SDK profile 中配置 ChatGPT adapter,例如本轮核对的版本:
97
+
98
+ ```sh
99
+ dsh plugin --profile sdk add dsh-plugin-chatgpt@0.1.17
100
+ ```
101
+
102
+ 随后按该 provider 的文档在对应 profile 完成授权,并保持一致的 `DSH_HOME`。不需要把凭证复制到任务契约或 Git。此处不把 `subagent_codex_pro` 当成原生 LLM provider;困难任务继续走独立 Codex CLI。
103
+
104
+ ### Mac GUI 的自动入口
105
+
106
+ 安装器在 `~/.config/flywheel/` 下生成 `npm-launcher` 和 `installation.json`。launcher 使用绝对 Node/CLI 路径,记录安装时已核对的 DSH 入口,并保留工具的绝对 PATH 目录;不会把临时 npx 缓存路径当成正式工具目录。npm CLI 启动器再解析与自身版本一致的 worker。
107
+
108
+ 桌面插件在没有显式 `flywheelBinary` 配置时自动读取这份记录,核对 launcher 的普通文件类型、可执行位和 SHA-256 后启动。**不需要自己写启动脚本或改 `cordis.patch.yml`。** 已有显式配置优先,安装器不会覆盖;若要采用自动入口,先审阅旧配置再自行移除该覆盖项。记录不存在时沿用 PATH 查找;已有记录损坏或 launcher 被修改时报告错误,不静默切换另一份引擎。
109
+
110
+ 更换 Node 版本、移动全局 prefix、安装新的 Kimi/Codex 或补齐验收工具后,在这些工具均可见的终端运行 `flywheel setup --no-global`,必要时加原来的 `--prefix`/`--dsh-bin`,再按宿主提示重新载入。launcher 的用户修改会被保护,处理方法见升级章节。工具 PATH 应包含 Node、所选 CLI 和项目验收所需的 Go/其他工具。不要猜测 `.app/Contents/...` 的内部路径。权限及 worker 环境变量见[插件文档](../plugins/dsh/README.md)。
111
+
112
+ ## 4. 配置模型与 skills
113
+
114
+ 配置优先级是:**任务目录 → 项目根 → 全局 → 二进制内嵌模板**,选择第一个完整文件,不逐字段合并。默认全局路径是 `~/.config/flywheel/flywheel.config.json`;`FLYWHEEL_CONFIG` 只替换全局路径,不能越过已有任务/项目文件。
115
+
116
+ 查看当前二进制的配置:
117
+
118
+ ```sh
119
+ flywheel template flywheel.config.example.json
120
+ ```
121
+
122
+ 为一个项目采用新默认表时,在确认没有需保留的同名配置后,从目标仓库根导出:
123
+
124
+ ```sh
125
+ flywheel template flywheel.config.example.json > flywheel.config.json
126
+ ```
127
+
128
+ `loops` 配置 Plan/Review/Judge 等阶段,`routes` 配置 Execute 的 default/frontend/hard,`channels` 描述账号渠道;`drivers` 只选择 `real` 或 `mock`。默认模型表见 [项目 README](../README.md#3-当前默认路由)。DSH 的 `provider` 必须是 SDK 实际注册的 ID;`channel` 可使用自己的渠道名称。旧配置不写 provider 时继续使用 channel 作为 provider ID。Flash 的 effort 是 `off/low/high/max`,没有 `medium`。
129
+
130
+ 需要集中修改模型时,查看另一份完整示例:
131
+
132
+ ```sh
133
+ flywheel template flywheel.profiles.example.json
134
+ ```
135
+
136
+ 它把模型定义放进 `profiles`,如 `loops.review: {"profile":"gpt-review"}`;阶段可显式覆盖 model/thinking/channel 等字段。两个配置示例选一个作为起点,不要让任务文件只写部分 profiles、再期待与项目文件自动合并。profile 不是 DSH profile;渠道别名也不会自动切换账号。完整字段、覆盖规则和迁移示例见[配置指南](configuration.md)。
137
+
138
+ 编辑后先查看实际解析结果,确认没有被更高优先级文件遮住:
139
+
140
+ ```sh
141
+ flywheel config inspect --cwd /absolute/path/to/target-repo --json
142
+ ```
143
+
144
+ 验收命令使用受限环境,而不是继承模型进程的全部变量。若项目需要自定义 `GOCACHE`、`GOPATH` 等工具配置,在 `verify.env-allowlist` 中列出所需变量名,并确保它们在引擎启动环境中有值;只记录变量名,不把密钥内容写入配置。
145
+
146
+ ### 查看或补装 skills
147
+
148
+ 一条命令安装已经包含全部 10 个 skills,默认在 `~/.agents/skills`;使用它们仍是可选的,桌面面板和 CLI 可以独立工作。需要另外安装到目标项目时运行:
149
+
150
+ ```sh
151
+ flywheel install-skills --project /absolute/path/to/target-repo --json
152
+ flywheel skills list
153
+ flywheel skills read flywheel-run
154
+ ```
155
+
156
+ 安装输出会给出 `.agents/skills` 的准确位置。按宿主支持的发现规则启用目录,不能从文件已复制推断 DSH/Kimi 已自动发现。也可直接使用 Go CLI。
157
+
158
+ 快照的 `.flywheel-snapshot` 清单记录文件内容 hash、类型与模式。重跑会跳过相同内容,更新未被修改的自有快照;用户修改、新增/删除文件、链接、未标记目录或损坏清单会保留并报告冲突。每个 skill 独立采用暂存、rename 和失败回滚,不会覆盖手工修改。旧纯文本标记只有在整个目录与当前内嵌内容相同时才能安全迁移。`--force` 只用于 `--link` 开发模式,不能绕过默认保护。安装会在全局配置缺失时创建它,但不会改写已有配置。
159
+
160
+ ## 5. 运行无推理检查
161
+
162
+ 在实际目标仓库中执行:
163
+
164
+ ```sh
165
+ flywheel doctor --cwd "$PWD" --json
166
+ flywheel doctor --cwd "$PWD" --probe --json
167
+ ```
168
+
169
+ 需要核对桌面的自动入口时,可把命令开头的 `flywheel` 换成 `"$HOME/.config/flywheel/npm-launcher"`;最后仍应在桌面面板内复验,因为 GUI 的其余环境可能不同。
170
+
171
+ 第一条只查有效配置、本地命令版本、目录及已声明环境变量;不会检查凭证文件、发送模型 prompt 或运行 packet 验收。第二条对选中的 DSH 绑定做 SDK 初始化、cwd/沙箱握手及正常关闭;provider 初始化可能联网查询目录,但**没有推理请求**。两者都不创建 Flywheel 状态、运行锁、worktree 或全局配置。
172
+
173
+ 结果按 pass/fail/warn/unknown/skipped 展示;有 fail 时退出码 1,JSON 仍完整可读。即使 `ok:true`,unknown 的账号授权、订阅额度与实际推理仍未验证。Kimi/Codex 在这里只检查命令,不会自动登录或试调用。DSH 同一账号、模型、effort、目录和权限只探测一次,总预算 40 秒另加清理窗口;超时后明确失败。
174
+
175
+ 未指定任务时检查全部配置绑定,可能包括首个任务用不到的 Codex hard 路由。准备好任务后可把范围缩小为所需的 Plan/Execute route/Review/Judge(以及显式启用的 judge-panel):
176
+
177
+ ```sh
178
+ flywheel doctor --cwd "$PWD" --task-dir docs/add --probe --json
179
+ ```
180
+
181
+ 尚无 packet 时按规划前状态预检默认执行路由,规划后应再检查。坏契约会报告阻断项,不能用探测通过代替 schema 校验。若 cwd、权限、provider 或沙箱检查失败,先修正相应配置,不把权限改成 full access 绕过。桌面面板也提供“查看配置/检查环境/SDK 无推理探测”,使用同一个 CLI 后端;GUI 与终端环境不同的问题应在面板内复验。
182
+
183
+ 这允许在准备契约时提前排查安装,但正式启动仍需至少一个已审阅的合法 packet。完成下一节的小任务准备后,再运行带 `--task-dir` 的检查。
184
+
185
+ ## 6. 准备首个小任务
186
+
187
+ 首次建议使用单独的小仓库,便于分清安装问题和业务代码问题。npm 包附带的准备脚本会创建一个 Go 加法函数任务:初始实现故意错误,执行者需修复实现并补普通单测;独立 acceptance 测试不可修改。本示例需要 Go 1.27 或更高。
188
+
189
+ ```sh
190
+ FLYWHEEL_PACKAGE="$(npm root --global)/@ckanner/flywheel"
191
+ bash "$FLYWHEEL_PACKAGE/docs/examples/create-first-task.sh" "$HOME/flywheel-demo"
192
+ cd "$HOME/flywheel-demo"
193
+ git init
194
+ ```
195
+
196
+ 如果安装时使用了自定义 prefix,用 `npm root --global --prefix "$HOME/.local"` 等实际 prefix 定位包目录;不需要克隆源码。
197
+
198
+ 脚本要求目标目录不存在,只写示例文件并读取本机 `flywheel template`;它不调用模型,也不自动提交。若 Flywheel 不在 PATH,可在调用脚本时设置 `FLYWHEEL_BIN=/absolute/path/to/flywheel`。
199
+
200
+ 生成的关键文件:
201
+
202
+ | 文件 | 用途 |
203
+ |---|---|
204
+ | `sum.go` | 待实现的函数 |
205
+ | `acceptance/sum_test.go` | 冻结验收,禁止 executor 改动 |
206
+ | `docs/add/spec.md` | 两条需求与一个里程碑 |
207
+ | `docs/add/task-packet-M01-T01.md` | default 路由、写入边界、L1/L2 和评审要求 |
208
+ | `flywheel.config.json` | 从实际二进制导出的项目完整配置 |
209
+ | `.gitignore`、任务目录 `.gitignore` | 排除 coverage 和易变运行文件,保留状态/报告 |
210
+
211
+ 先逐条运行 packet 中的 L1:
212
+
213
+ ```sh
214
+ go test ./...
215
+ go test -coverprofile=coverage.out . &&
216
+ go tool cover -func=coverage.out |
217
+ awk '$NF != "100.0%" && $NF != "100%" { bad=1 } END { exit bad }'
218
+ ```
219
+
220
+ 初始失败是预期结果。把实际退出码和输出摘要写入 `spec.md` 的 dry-run evidence;不要填未经运行的结果。审阅需求、命令、配置和冻结边界后,将准备好的初始任务提交:
221
+
222
+ ```sh
223
+ git add go.mod sum.go acceptance .gitignore flywheel.config.json docs/add
224
+ git commit -m "docs: prepare first flywheel task"
225
+ ```
226
+
227
+ Git 提交身份必须已经按自己的设置配置。此时不应创建 `state.json`,它由引擎初始化。coverage 输出已被忽略,所以验收运行不会把生成物误判为候选代码漂移。
228
+
229
+ 对于已有业务仓库,可以通过 `flywheel-new` 生成并审阅契约,或者用 `flywheel template --list` 查看模板后手工准备。示例 auth 模板不是通用可运行任务,其中路径和验收命令必须改为真实项目的命令。不要照抄后直接启动。
230
+
231
+ ## 7. 启动、观察、停止与恢复
232
+
233
+ 以下从目标仓库根运行,且会使用真实配置调用模型:
234
+
235
+ ```sh
236
+ flywheel control start --task-dir "$PWD/docs/add" --cwd "$PWD"
237
+ flywheel control status --task-dir "$PWD/docs/add" --cwd "$PWD"
238
+ ```
239
+
240
+ `ok: true` 只表示控制操作成功;`running` 表示引擎运行状态,最终任务结果看 `state.status`。启动 readiness 超时后先刷新状态和看日志,不重复启动。也可以在 DSH 输入区的 Flywheel 面板填入同样两个绝对路径,先查看配置和检查环境,再点击“启动/刷新状态/停止”。面板区分未初始化、已完成、暂停、停止和升级;修改路径会清除旧视图,但不会停止旧任务。
241
+
242
+ 需要人工在 Review 前检查结果时,使用前台监督模式;它与后台 start 二选一:
243
+
244
+ ```sh
245
+ flywheel run docs/add --pause-before review
246
+ ```
247
+
248
+ `control start` 当前不接受 `--pause-before`。`--only execute` 会运行 Execute 子环及 L1,直至通过或遇到失败出口;它不是一次模型调用。`--only review` 只返回评审裁决,不会自动跨到 Plan 修订。单环命令详见各内嵌 skill。
249
+
250
+ 观察人话摘要和日志:
251
+
252
+ ```sh
253
+ flywheel status docs/add
254
+ tail -n 80 docs/add/orchestrator.log
255
+ git log -5 --oneline
256
+ ```
257
+
258
+ 停止与恢复:
259
+
260
+ ```sh
261
+ flywheel control stop --task-dir "$PWD/docs/add" --cwd "$PWD"
262
+ flywheel control start --task-dir "$PWD/docs/add" --cwd "$PWD"
263
+ ```
264
+
265
+ 仅在确认上次停止/暂停、检查并处理实际错误后恢复。恢复会重新核对契约和候选证据;不要手改 `state.json`,不要因为想重试就删报告、工作区或运行锁。`stopped` 表示引擎生命周期结束,已记录的清理错误仍需处理,不能据此断言任意逃逸进程都已清理。
266
+
267
+ 首次实机验收应确认:任务 completed、需求都被覆盖、冻结验收没改、报告与独立评审存在、代码已在本地 Git 保存/合并、停止恢复符合预期;同时记录真实模型、延迟和用量。模型自报“完成”和 `control` 的 `ok` 都不能代替这些结果。
268
+
269
+ ## 8. 升级、排错与卸载
270
+
271
+ ### 升级或修复安装
272
+
273
+ 先显式停止活动任务并确认停止结果,保存配置和定制 skills,再运行与首装相同的命令:
274
+
275
+ ```sh
276
+ npx -y @ckanner/flywheel@latest install
277
+ ```
278
+
279
+ 自定义 prefix、项目 skills 或 DSH 入口时保留原参数。想固定某个已发布版本,可把 `@latest` 换成该精确版本,例如在 registry 确认 0.27.3 已发布后使用 `@0.27.3`;安装器始终为 CLI、平台包、worker 和桌面插件选择本次安装器的同一版本。已安装包的配置修复可用 `flywheel setup --no-global`,它不会将 CLI 升级到别的版本。
280
+
281
+ 安装后对照新模板审阅需要迁移的配置,按宿主提示重新载入,运行 doctor,再用小任务验证。已有配置不会自动覆盖;特别检查任务级文件是否遮住了刚修改的项目或全局设置。安装不是跨 npm、DSH 与全部 skills 的单个事务:失败时报告已完成步骤,不擅自回退包管理器或删除用户文件。修正原因后重跑会重新核对版本与内容。
282
+
283
+ ### skills 或 launcher 冲突
284
+
285
+ 遇到内容冲突时,不要删整个 `.agents`、配置目录或修改 hash 清单来绕过校验。根据失败报告定位具体文件,先备份,再对照当前模板审阅差异。需要保留的定制可整理到另外命名的个人/项目 skill;确认后将**具体冲突目录**移到备份位置,重跑 `setup --no-global` 或对应范围的 `install-skills --json` 生成官方快照。旧版本纯文本标记不能证明目录未被修改,因此内容与新快照不一致时也需要这样处理。
286
+
287
+ launcher 被手工修改时,先备份修改。希望采用自动入口,可以将该 launcher 移到备份位置后重跑 setup;希望继续自定义,则在桌面配置中显式指定自己的 `flywheelBinary`。不要手改 `installation.json` 的 SHA-256 把未知内容标成安装器生成。若提示安装锁存在,先确认另一个安装进程是否仍在运行;只有确认进程已结束后才处理报告中的残留锁。
288
+
289
+ ### 常见问题
290
+
291
+ | 现象 | 先检查什么 |
292
+ |---|---|
293
+ | 没有 `install` 或 `control` 命令 | `npm view @ckanner/flywheel version` 与 `flywheel version`;是否仍是旧 0.22.1,PATH 或显式 `flywheelBinary` 是否指向旧版本 |
294
+ | 安装 `ok:true`,但 `ready:false` | 安装已完成;按 `diagnostic.checks` 补齐当前配置需要的 CLI、目录或环境变量,再运行 doctor |
295
+ | npm 全局目录权限错误 | 使用自己可写的 `--prefix`,并把对应 `bin` 加入 shell PATH |
296
+ | desktop profile 被拒绝 | `--dsh-bin` 是否指向桌面安装的命令,而非单独 npm 安装的 DSH CLI |
297
+ | 桌面找不到 worker/kimi/codex | 查看 `installation.json` 对应的自动 launcher、显式 `flywheelBinary` 和工具 PATH;工具变化后重跑 setup,终端 export 不会改变已有桌面进程 |
298
+ | launcher 缺失或 hash 不符 | 保存用户修改,修复持久 npm 安装后重跑 setup;不手改安装记录绕过校验 |
299
+ | SDK provider 未注册/未登录 | 独立 sdk profile、`DSH_HOME`、provider ID、对应 profile 的正常授权 |
300
+ | doctor 拒绝权限或沙箱 | 实际 DSH 版本与 Seatbelt/fs fence;不要改 full access 绕过 |
301
+ | 命令在终端通过、引擎内失败 | 检查验收输出、PATH、工具缓存权限和 `verify.env-allowlist`;不要把模型全部凭证注入验收 |
302
+ | 改了模型却没有生效 | 任务/项目/全局的完整文件优先级,随后重启任务引擎 |
303
+ | profile 不存在或字段拼错 | 对照配置模板检查当前优先级文件;profiles 只在该完整配置内查找,不跨文件合并,诊断不回显可能含凭据的原始字段值 |
304
+ | 改 channel 后账号没切换 | channel 是计量/配置别名;实际账号仍由 SDK profile/provider 的授权决定 |
305
+ | doctor 有 unknown 或 skipped | unknown 不等于通过,skipped 可能是非任务路由、mock 或没有请求 SDK probe |
306
+ | 费用显示未知 | 渠道未提供 cost/usage;unknown 不是免费,hard token budget 可能停止 |
307
+ | 启动超时但日志继续增长 | 先用 control status 观察就绪状态,不重复启动第二个引擎 |
308
+ | L1 在 exit 0 后仍拒绝 | 检查候选漂移、输出截断、超时/取消或进程收尾错误 |
309
+ | 提交/合并/持久化检查失败 | 检查保留 worktree、hook 和 Git 差异,修复原因后恢复,不强制清理 |
310
+ | skills 安装拒绝已有目录 | 查看具体冲突;可能是用户修改、未标记目录、损坏清单或旧标记。按上面的备份恢复流程处理,`--force` 不绕过默认保护 |
311
+
312
+ ### 卸载
313
+
314
+ 先通过 Flywheel 面板或 `flywheel control stop` 停止活动任务并确认结果,再在 DSH 的插件管理入口从所用 profile 移除 `@ckanner/dsh-plugin-flywheel`,按宿主提示重新载入。最后卸载全局 npm 包:
315
+
316
+ ```sh
317
+ npm uninstall --global @ckanner/flywheel
318
+ ```
319
+
320
+ 使用自定义 prefix 时为卸载命令加上同一个 `--prefix`。Flywheel 没有隐式卸载清理脚本:npm 卸载不会删除用户的任务账本、worktree、配置、skills 或安装记录,也不会卸载 DSH、Kimi、Codex 或账号凭证。保留这些文件便于恢复;需要清理时,由用户按实际安装报告逐项审阅所属文件,特别保留自己的修改,不批量删除整个 `~/.agents` 或 `~/.config`。桌面插件应先移除,避免遗留入口继续调用已卸载的 CLI。
321
+
322
+ 引擎只管理本地 Git 交付,不自动 push 或合并远端 PR。分支保护、远端 CI、发布和实际账号权限仍由所用仓库/服务处理。完整证据与实机边界见 [验证记录](validation/2026-11-01-results.md)。
323
+
324
+ ## 9. 开发与备用构建
325
+
326
+ 以下用于贡献代码、检查未发布分支或离线备份;普通用户使用 npm 安装。需要 Git、Go 1.27 或更高、Node.js 22 或更高:
327
+
328
+ ```sh
329
+ git clone https://github.com/ckanner/flywheel.git
330
+ cd flywheel
331
+ git log -1 --oneline
332
+ go build -o ./bin/flywheel ./cmd/flywheel
333
+ npm --prefix plugins/dsh ci --ignore-scripts
334
+ npm --prefix plugins/dsh run check
335
+ make quality-gate
336
+ npm test
337
+ npm run build:npm
338
+ FLYWHEEL_NPM_PACKAGES_DIR=dist-npm npm run test:install
339
+ ```
340
+
341
+ 普通 `go build` 的版本可能显示 `dev`。`build:npm` 在隔离目录先构建 worker,再为 macOS/Linux 的 arm64/x64 打包四个平台包、meta 包和 DSH 插件,共六个同版本 npm 包;输出在 `dist-npm/`,同时保存候选文件清单与校验值。构建不能悄悄改写仓库内的版本或复用旧 worker。`test:install` 用这些真实 tarball 和隔离的本地 registry/用户目录测试安装;DSH 命令是协议桩,不触碰自己的桌面 profile 或模型账号。
342
+
343
+ Actions artifact 和本地 tarball 是构建/审查产物,不代表 npm 已发布,也不是已签名、公证的 Mac 安装程序。备用分发时必须保留同版本依赖,并选择正确平台;单独拿一个 meta tarball 不能证明所有可选平台依赖已在离线缓存。普通 npm 安装完成且依赖齐全后,CLI 与内嵌 skills 不需要下载源码;首次包获取、DSH 插件注册和实际模型调用各自仍有网络需求。
344
+
345
+ 开发者可使用 `flywheel install-skills --link` 链接源码中的 skills;这是明确的开发模式,不是发布安装流程。源码、独立 Go 二进制或自定义 worker 的接入见[插件文档](../plugins/dsh/README.md),不得将本机协议桩通过写成用户 Mac 或真实账号通过。
346
+
347
+ 维护者发布到 npm 的认证配置、六包顺序和失败恢复见[发行指南](releasing.md)。普通安装者不需要 npm 发布权限,也不需要配置 GitHub OIDC。