@ckanner/flywheel 0.32.1 → 0.33.0

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.
Files changed (133) hide show
  1. package/CHANGELOG.md +10 -1
  2. package/README.md +7 -0
  3. package/README.zh-CN.md +5 -0
  4. package/THIRD_PARTY_NOTICES.md +42 -0
  5. package/bin/runtime.js +25 -31
  6. package/cordis.patch.yml +5 -0
  7. package/dist/bridge.mjs +421 -0
  8. package/dist/claude-code-pro-bridge.mjs +82 -0
  9. package/dist/claude-code-pro-worker.mjs +5 -0
  10. package/dist/client.js +4078 -0
  11. package/dist/codex-pro-bridge.mjs +75 -0
  12. package/dist/codex-pro-worker.mjs +5 -0
  13. package/dist/console-read.mjs +51 -0
  14. package/dist/control.mjs +218 -0
  15. package/dist/index.mjs +185 -0
  16. package/dist/installation.mjs +56 -0
  17. package/dist/machine-worker.mjs +241 -0
  18. package/dist/policy.mjs +91 -0
  19. package/dist/prewarm.mjs +136 -0
  20. package/dist/protocol.mjs +260 -0
  21. package/dist/task-association.mjs +127 -0
  22. package/dist/worker.mjs +52 -0
  23. package/dist/workspaces.mjs +42 -0
  24. package/docs/README.md +1 -1
  25. package/docs/README.zh-CN.md +1 -1
  26. package/docs/design.md +7 -4
  27. package/docs/en/configuration.md +1 -1
  28. package/docs/en/contributing.md +5 -6
  29. package/docs/en/flow-console.md +1 -1
  30. package/docs/en/getting-started.md +9 -2
  31. package/docs/en/releasing.md +132 -174
  32. package/docs/validation/2026-11-13-release-0.32.1.md +83 -0
  33. package/docs/validation/2026-11-14-single-package.md +60 -0
  34. package/docs/validation/README.md +2 -0
  35. package/docs/zh-CN/configuration.md +1 -1
  36. package/docs/zh-CN/contributing.md +4 -5
  37. package/docs/zh-CN/flow-console.md +1 -1
  38. package/docs/zh-CN/getting-started.md +7 -3
  39. package/docs/zh-CN/releasing.md +97 -81
  40. package/native/darwin-amd64/flywheel +0 -0
  41. package/native/darwin-arm64/flywheel +0 -0
  42. package/native/linux-amd64/flywheel +0 -0
  43. package/native/linux-arm64/flywheel +0 -0
  44. package/native/manifest.json +22 -0
  45. package/node_modules/dsh-subagent-codex-pro/CHANGELOG.md +403 -0
  46. package/node_modules/dsh-subagent-codex-pro/LICENSE +21 -0
  47. package/node_modules/dsh-subagent-codex-pro/README.md +557 -0
  48. package/node_modules/dsh-subagent-codex-pro/cordis.patch.yml +30 -0
  49. package/node_modules/dsh-subagent-codex-pro/docs/README.zh.md +355 -0
  50. package/node_modules/dsh-subagent-codex-pro/docs/machine-lifecycle-validation.md +65 -0
  51. package/node_modules/dsh-subagent-codex-pro/docs/machine-lifecycle.md +144 -0
  52. package/node_modules/dsh-subagent-codex-pro/docs/machine-lifecycle.zh.md +98 -0
  53. package/node_modules/dsh-subagent-codex-pro/docs/machine.md +194 -0
  54. package/node_modules/dsh-subagent-codex-pro/docs/orchestration.zh.md +86 -0
  55. package/node_modules/dsh-subagent-codex-pro/lib/codex-exec.js +68 -0
  56. package/node_modules/dsh-subagent-codex-pro/lib/codex-exec.js.map +1 -0
  57. package/node_modules/dsh-subagent-codex-pro/lib/dsh-types.js +15 -0
  58. package/node_modules/dsh-subagent-codex-pro/lib/dsh-types.js.map +1 -0
  59. package/node_modules/dsh-subagent-codex-pro/lib/index.js +830 -0
  60. package/node_modules/dsh-subagent-codex-pro/lib/index.js.map +1 -0
  61. package/node_modules/dsh-subagent-codex-pro/lib/jobs.js +35 -0
  62. package/node_modules/dsh-subagent-codex-pro/lib/jobs.js.map +1 -0
  63. package/node_modules/dsh-subagent-codex-pro/lib/jsonrpc.js +229 -0
  64. package/node_modules/dsh-subagent-codex-pro/lib/jsonrpc.js.map +1 -0
  65. package/node_modules/dsh-subagent-codex-pro/lib/machine-cli.js +101 -0
  66. package/node_modules/dsh-subagent-codex-pro/lib/machine-cli.js.map +1 -0
  67. package/node_modules/dsh-subagent-codex-pro/lib/machine-local.js +122 -0
  68. package/node_modules/dsh-subagent-codex-pro/lib/machine-local.js.map +1 -0
  69. package/node_modules/dsh-subagent-codex-pro/lib/machine-recovery.js +167 -0
  70. package/node_modules/dsh-subagent-codex-pro/lib/machine-recovery.js.map +1 -0
  71. package/node_modules/dsh-subagent-codex-pro/lib/machine-supervision.js +141 -0
  72. package/node_modules/dsh-subagent-codex-pro/lib/machine-supervision.js.map +1 -0
  73. package/node_modules/dsh-subagent-codex-pro/lib/machine-supervisor.js +128 -0
  74. package/node_modules/dsh-subagent-codex-pro/lib/machine-supervisor.js.map +1 -0
  75. package/node_modules/dsh-subagent-codex-pro/lib/machine.js +104 -0
  76. package/node_modules/dsh-subagent-codex-pro/lib/machine.js.map +1 -0
  77. package/node_modules/dsh-subagent-codex-pro/lib/process-guardian.js +156 -0
  78. package/node_modules/dsh-subagent-codex-pro/lib/process-guardian.js.map +1 -0
  79. package/node_modules/dsh-subagent-codex-pro/lib/run.js +842 -0
  80. package/node_modules/dsh-subagent-codex-pro/lib/run.js.map +1 -0
  81. package/node_modules/dsh-subagent-codex-pro/lib/structured.js +329 -0
  82. package/node_modules/dsh-subagent-codex-pro/lib/structured.js.map +1 -0
  83. package/node_modules/dsh-subagent-codex-pro/lib/tool.js +295 -0
  84. package/node_modules/dsh-subagent-codex-pro/lib/tool.js.map +1 -0
  85. package/node_modules/dsh-subagent-codex-pro/lib/types/codex-exec.d.ts +88 -0
  86. package/node_modules/dsh-subagent-codex-pro/lib/types/codex-exec.d.ts.map +1 -0
  87. package/node_modules/dsh-subagent-codex-pro/lib/types/dsh-types.d.ts +179 -0
  88. package/node_modules/dsh-subagent-codex-pro/lib/types/dsh-types.d.ts.map +1 -0
  89. package/node_modules/dsh-subagent-codex-pro/lib/types/index.d.ts +266 -0
  90. package/node_modules/dsh-subagent-codex-pro/lib/types/index.d.ts.map +1 -0
  91. package/node_modules/dsh-subagent-codex-pro/lib/types/jobs.d.ts +34 -0
  92. package/node_modules/dsh-subagent-codex-pro/lib/types/jobs.d.ts.map +1 -0
  93. package/node_modules/dsh-subagent-codex-pro/lib/types/jsonrpc.d.ts +113 -0
  94. package/node_modules/dsh-subagent-codex-pro/lib/types/jsonrpc.d.ts.map +1 -0
  95. package/node_modules/dsh-subagent-codex-pro/lib/types/machine-cli.d.ts +3 -0
  96. package/node_modules/dsh-subagent-codex-pro/lib/types/machine-cli.d.ts.map +1 -0
  97. package/node_modules/dsh-subagent-codex-pro/lib/types/machine-local.d.ts +4 -0
  98. package/node_modules/dsh-subagent-codex-pro/lib/types/machine-local.d.ts.map +1 -0
  99. package/node_modules/dsh-subagent-codex-pro/lib/types/machine-recovery.d.ts +53 -0
  100. package/node_modules/dsh-subagent-codex-pro/lib/types/machine-recovery.d.ts.map +1 -0
  101. package/node_modules/dsh-subagent-codex-pro/lib/types/machine-supervision.d.ts +8 -0
  102. package/node_modules/dsh-subagent-codex-pro/lib/types/machine-supervision.d.ts.map +1 -0
  103. package/node_modules/dsh-subagent-codex-pro/lib/types/machine-supervisor.d.ts +2 -0
  104. package/node_modules/dsh-subagent-codex-pro/lib/types/machine-supervisor.d.ts.map +1 -0
  105. package/node_modules/dsh-subagent-codex-pro/lib/types/machine.d.ts +70 -0
  106. package/node_modules/dsh-subagent-codex-pro/lib/types/machine.d.ts.map +1 -0
  107. package/node_modules/dsh-subagent-codex-pro/lib/types/process-guardian.d.ts +22 -0
  108. package/node_modules/dsh-subagent-codex-pro/lib/types/process-guardian.d.ts.map +1 -0
  109. package/node_modules/dsh-subagent-codex-pro/lib/types/run.d.ts +386 -0
  110. package/node_modules/dsh-subagent-codex-pro/lib/types/run.d.ts.map +1 -0
  111. package/node_modules/dsh-subagent-codex-pro/lib/types/structured.d.ts +35 -0
  112. package/node_modules/dsh-subagent-codex-pro/lib/types/structured.d.ts.map +1 -0
  113. package/node_modules/dsh-subagent-codex-pro/lib/types/tool.d.ts +107 -0
  114. package/node_modules/dsh-subagent-codex-pro/lib/types/tool.d.ts.map +1 -0
  115. package/node_modules/dsh-subagent-codex-pro/lib/types/usage.d.ts +131 -0
  116. package/node_modules/dsh-subagent-codex-pro/lib/types/usage.d.ts.map +1 -0
  117. package/node_modules/dsh-subagent-codex-pro/lib/types/wire.d.ts +321 -0
  118. package/node_modules/dsh-subagent-codex-pro/lib/types/wire.d.ts.map +1 -0
  119. package/node_modules/dsh-subagent-codex-pro/lib/usage.js +356 -0
  120. package/node_modules/dsh-subagent-codex-pro/lib/usage.js.map +1 -0
  121. package/node_modules/dsh-subagent-codex-pro/lib/wire.js +986 -0
  122. package/node_modules/dsh-subagent-codex-pro/lib/wire.js.map +1 -0
  123. package/node_modules/dsh-subagent-codex-pro/package.json +76 -0
  124. package/npm/install.js +59 -6
  125. package/package.json +74 -12
  126. package/plugins/dsh/LICENSE +21 -0
  127. package/plugins/dsh/PROTOCOL.md +607 -0
  128. package/plugins/dsh/README.en.md +4 -0
  129. package/plugins/dsh/README.md +342 -0
  130. package/plugins/dsh/README.zh-CN.md +279 -0
  131. package/plugins/dsh/THIRD_PARTY_NOTICES.md +42 -0
  132. package/plugins/dsh/vendor/README.md +17 -0
  133. package/plugins/dsh/vendor/codex-pro.json +16 -0
@@ -0,0 +1,98 @@
1
+ # 结构化生命周期与只读恢复(lifecycle 1)
2
+
3
+ 本契约在 **0.9.0 未发布源码候选**中实现。公开
4
+ `dsh-subagent-codex-pro/machine` 结果协议仍为 1;lifecycle 是另行版本化的
5
+ JavaScript 能力。单 JSON 输入的 CLI 与原 DSH Host/tool 输出保持原有方式。
6
+
7
+ ## 显式启用
8
+
9
+ `runMachine(request, options)` 新增 `onLifecycle(event)` 与
10
+ `recoveryDirectory`。回调是程序持久化确认:Go 等调用者原子保存并 fsync 自己的
11
+ 检查点之后才 resolve,失败则 reject;它不增加用户审批步骤。恢复目录必须是
12
+ 现存物理父目录下的**全新绝对路径**,不是别名、符号链接或已有目录。每次 engine
13
+ invocation 使用自己的路径,不能按 thread ID 反复复用。目录存在会拒绝执行,
14
+ 不会读取其中的 requestId 后自动重放。
15
+
16
+ 任一选项启用后,独立进程组中的 machine supervisor 持有 native runner 与最终
17
+ 持久化职责,先建立 IPC lifeline,再开始工作。调用者或其整个进程组被强杀时,
18
+ supervisor 拒绝正在等待的 ACK,取消原调用,等已有 Codex guardian 收束 native
19
+ 进程组后保存实际回执。关闭进程本身不证明模型任务成功。
20
+
21
+ ```js
22
+ import { runMachine, recoverMachine } from 'dsh-subagent-codex-pro/machine'
23
+ const receipt = await runMachine(request, {
24
+ recoveryDirectory,
25
+ signal: controller.signal,
26
+ onLifecycle: event => engine.persistCheckpointAndFsync(event),
27
+ })
28
+ // 重启后使用自己已经保存的明确 runId;不扫描“最近一次”历史。
29
+ const recovered = await recoverMachine({
30
+ protocol: 1, requestId: request.requestId,
31
+ runId: savedCheckpoint.runId, recoveryDirectory,
32
+ })
33
+ ```
34
+
35
+ `MACHINE_LIFECYCLE_VERSION=1`;公开 capability 为 `{version:1,
36
+ durableJournal:true, readOnlyRecovery:true, threadReadyBeforeDispatch:true}`。
37
+ 能力声明不等于当前账号、历史或机器已通过真实验收。
38
+
39
+ ## 事件与证据强度
40
+
41
+ 每个事件含 `lifecycleVersion:1`、`type:'lifecycle'`、`requestId`、`runId`、
42
+ 从 1 连续递增的 `sequence`、`event`、`threadId`、`turnId`、`persistent`、
43
+ `configuration`、`dispatch`、`outcome`、`cleanupConfirmed`。
44
+ `persistent` 表示请求的历史模式,不能证明空 thread 已有可恢复 rollout。
45
+ 配置对象保留真实 start/resume 来源、请求与有效配置、完整 sandbox policy 和
46
+ 匹配结果。新 thread 的 `ephemeral` 必须由后端显式布尔值证明并与请求匹配;
47
+ resume 则必须被接受且有效 overrides 匹配。历史默认 effort 不冒充本 turn 的实际值。
48
+
49
+ | 事件 | 实际含义 |
50
+ | --- | --- |
51
+ | `thread-ready` | thread 与有效配置已核对,新 turn 尚未发送;等待调用者持久化 ACK。 |
52
+ | `dispatch-intent` | 准备提交这一明确 turn,仍未发送;等待 ACK。 |
53
+ | `dispatch-possible` | 在实际写入 turn 请求前保存并等待 ACK;发送与确认之间仍可能不确定。 |
54
+ | `turn-accepted` | 匹配的 turn/start 响应给出本次 turn ID;只是接受,不是完成。 |
55
+ | `terminal` | native 结果与清理事实已形成;请求 journal 时,完整原始回执已先 fsync。 |
56
+ | `cleanup-confirmed` | 只有实际确认 native 清理后才发;调用者可保存原调用的候选/guard/报告证据再 ACK。 |
57
+
58
+ 终态通知在 native 收尾后交付,不声称更早的流式 terminal。两个终态事件携带同一
59
+ 最终事实。原成功回执保存后,即使终态通知或 ACK 丢失,也不会把已完成的 native
60
+ 调用改写成 cancelled。启动失败可以没有 thread-ready 而直接交付失败终态。
61
+
62
+ `execution.dispatch` 与事件分别表达 not-dispatched、possible、accepted。
63
+ possible 屏障拒绝时,即使测试观察到请求尚未写出,也保留 possible,不能靠错误
64
+ 文本认领“零消耗/可重试”。进程清理完成不使 unknown 业务结果变成成功。
65
+ 原调用 deadline 仍限制 native 启动和前置屏障;supervisor admission 及每次 ACK
66
+ 另有 10 秒上限。调用者断开会立即拒绝 pending waiter,不会让清理无限等回调。
67
+
68
+ ## 持久化与只读核对
69
+
70
+ supervisor 独占创建 0700 目录;0600 记录写入独占临时文件,fsync 后原子 rename,
71
+ 再 fsync 目录。新建目录的父目录也 fsync。记录有精确 request/run 身份和 SHA-256
72
+ 完整性校验;它是运行证据,不写 Go 的 state、预算或候选决策。
73
+
74
+ `recoverMachine` 只读取调用者给定且身份匹配的一个 journal。它不启动 CLI、不发
75
+ 网络请求、不 resume、不查账号历史、不杀进程、不写文件、不重跑模型。必须给出
76
+ 已知 runId;PID 是否存在不能证明进程所有权、清理或成功。
77
+
78
+ | status | 可以得出的结论 |
79
+ | --- | --- |
80
+ | terminal | 返回原始完整 receipt。仍须检查配置、业务结果、独立 cleanup 与用量;它可能是失败或 unknown。 |
81
+ | pending | journal 身份正确,但没有持久化终态;不证明 owner 还活着、turn 仍运行或重放安全。 |
82
+ | unknown | 缺失、不可读、损坏或身份不匹配;不猜派发和清理事实。 |
83
+
84
+ 最新 `lifecycle` 在交付调用者**之前**落盘,所以它存在不证明 Go 已 ACK。只有 Go
85
+ 自己的检查点能证明原清理边界的 candidate/guard/报告已保存;缺少这个证据时,
86
+ 可以核对原消耗,不能重启后重采当前工作区当作旧验证。调用者死亡后通常可读到
87
+ supervisor 后续回执;若 supervisor 也在回执落盘前死亡,guardian 可能完成物理
88
+ 清理,但结果仍必须保持未知。未知 runId、双 supervisor 丢失、逃离进程组或断电
89
+ 超出 fsync 保证,都不构成 exactly-once。requestId 只是关联标识,不是幂等键。
90
+
91
+ 调用者负责保留期限与删除:先完成一次且仅一次的状态应用/计量并满足审计期限,
92
+ 再清理证据。不得通过删 journal 绕过 unknown。插件不自动扫历史或后台删档。
93
+ 环境凭证不会被复制到记录中;原始模型输出可能包含用户敏感内容,仍须按任务的
94
+ 私有证据和保留策略处理。
95
+
96
+ 离线测试使用真实子进程验证 ACK、拒绝、损坏、独占、只读、整组 SIGKILL、终态
97
+ 通知丢失及真实安装包入口;没有把这些测试冒充真实账号、缓存、质量或费用测量。
98
+ 详见[验收记录](machine-lifecycle-validation.md)。
@@ -0,0 +1,194 @@
1
+ # Machine API and CLI (protocol 1)
2
+
3
+ Version 0.8.0 introduced a public entry for orchestrators that need the complete outcome
4
+ without a DSH parent Agent. It uses the same app-server runner, configuration
5
+ checks, usage tracker and process guardian as the DSH provider and tool.
6
+
7
+ The **0.9.0 unreleased source candidate** adds [typed lifecycle and read-only
8
+ recovery](machine-lifecycle.md) ([中文](machine-lifecycle.zh.md)). The result protocol
9
+ remains 1. The single-document CLI remains terminal-only; durable ACKs use the
10
+ JavaScript API. Existing DSH callers do not opt into this additional supervisor.
11
+
12
+ ## Install and inspect
13
+
14
+ After 0.8.0 is published:
15
+
16
+ ```sh
17
+ npm install dsh-subagent-codex-pro@0.8.0
18
+ npx --no-install codex-pro-machine --capabilities
19
+ ```
20
+
21
+ For a source checkout, build and pack it, then install that tarball in a
22
+ separate test project. A checkout is not evidence that npm has this version.
23
+ Node 22.18+ is required. The Codex executable and its normal authentication must
24
+ already be available; this package neither installs Codex nor copies credentials.
25
+ Use an absolute command path when a desktop process has a different PATH.
26
+
27
+ `--capabilities` and `--version` are offline and do not spawn Codex. The package
28
+ exports `dsh-subagent-codex-pro/machine`; importing private source files is not a
29
+ supported integration.
30
+
31
+ ## One request, one receipt
32
+
33
+ Write a single JSON document to stdin and close stdin:
34
+
35
+ ```json
36
+ {
37
+ "protocol": 1,
38
+ "requestId": "task-42-attempt-1",
39
+ "prompt": "Implement the approved task in this worktree and write its required report.",
40
+ "cwd": "/absolute/path/to/task-worktree",
41
+ "model": "gpt-6.1-sol",
42
+ "effort": "high",
43
+ "permissionMode": "workspace-write",
44
+ "timeoutMs": 600000
45
+ }
46
+ ```
47
+
48
+ ```sh
49
+ npx --no-install codex-pro-machine --json < request.json > receipt.json
50
+ ```
51
+
52
+ The required fields are protocol, requestId, prompt, cwd, model, effort and
53
+ permissionMode. Machine calls always name their model and permission explicitly.
54
+ Optional fields are command, timeoutMs, maxOutputBytes, threadMode, threadId,
55
+ images and outputSchema. Unknown fields fail before a process starts. The CLI
56
+ limits the entire request to 1 MiB. The runner limits stdout and diagnostic bytes
57
+ to 32 MiB by default; exceeding the configured positive maxOutputBytes stops the
58
+ run and sets execution.truncated instead of accepting a partial answer.
59
+
60
+ Permissions are read-only, workspace-write (approvalPolicy=never), or the
61
+ explicit dangerously-bypass-approvals-and-sandbox mode. The machine API does not
62
+ accept ambiguous legacy never/approve-for-me modes. Cwd is a directory, not proof
63
+ of a sandbox: inspect the complete returned sandboxPolicy, including writable
64
+ roots and network settings, against the caller's requirements.
65
+
66
+ The default thread is ephemeral. A resumed thread must be persistent; threadId
67
+ never silently changes to a new thread after failure. Execute and independent review must have separate role histories. The owning
68
+ orchestrator may explicitly resume each role within its scope. Orchestrators
69
+ own retries, compatibility, durable task state and current-candidate validation.
70
+
71
+ The CLI prints exactly one JSON object on stdout. App-server diagnostics may go
72
+ to stderr. Exit 0 means a completed turn and confirmed cleanup; exit 1 means a
73
+ failed run or a consumer that closed stdout; exit 2 an invalid input envelope.
74
+ 130/143 can accompany the result-shaped cancellation receipt when a signal is
75
+ observed during the run, or the `type: error` envelope when the signal arrives
76
+ before a request/run exists (for example while reading stdin). Inspect the
77
+ envelope; do not infer success from a text message or exit code alone.
78
+
79
+ ## JavaScript API
80
+
81
+ ```js
82
+ import { runMachine } from 'dsh-subagent-codex-pro/machine'
83
+
84
+ const controller = new AbortController()
85
+ const receipt = await runMachine(request, { signal: controller.signal })
86
+ if (!receipt.ok) {
87
+ // Preserve the receipt and report failure to the owning orchestrator.
88
+ }
89
+ ```
90
+
91
+ `parseMachineRequest` validates untrusted input. `runMachine` rejects invalid
92
+ input with MachineInputError; ordinary run failures preserve receipts. A failed
93
+ supervisor or journal can reject without a terminal handoff: callers must recover
94
+ known durable evidence and otherwise remain blocked. Options may supply a trusted
95
+ env override, onProgress, awaitable onLifecycle, and a new recoveryDirectory; environment values and prompts
96
+ are never copied into the receipt's requested-configuration fields.
97
+
98
+ ## Receipt contract
99
+
100
+ The envelope contains protocol=1, type=result, caller requestId, a per-attempt
101
+ runId, ok, requested, outcome or failure, costUSD=null and costStatus=unknown.
102
+ An invalid CLI input instead produces type=error with INVALID_REQUEST/INPUT_ERROR
103
+ and exit 2. It is not a started run.
104
+
105
+ | Field | Meaning |
106
+ |---|---|
107
+ | outcome.output / structured | Unmodified model text and separately validated JSON; no persistent-thread marker appended |
108
+ | outcome.configuration | requested/effective, source, missing fields, mismatches, matched and full observed sandboxPolicy |
109
+ | outcome.turnConfiguration | Requested effort and whether turn/start accepted it; effectiveEffort stays null because the protocol does not echo it |
110
+ | outcome.execution | run/thread/turn IDs, timestamps, elapsed duration, direct-child/driver pid (the installed Codex launcher may have a native server child), mirrored exit/signal, supervisor facts, timeout/cancel/truncation/spawn/failure facts |
111
+ | outcome.approvalDiagnostic | Bounded package-generated unattended approval/sandbox note; never raw server output or task text |
112
+ | outcome.cleanup | Confirmation of the owned process range's disappearance, with a reason when unconfirmed |
113
+ | outcome.usage | complete/partial/unknown; attributable run delta and thread totals, never summed cumulative snapshots |
114
+ | outcome.rateLimits | Account limits, separate from token usage and cost |
115
+ | failure | Startup stage/category plus available execution/configuration/usage/cleanup observations |
116
+
117
+ Missing observations remain null/unknown. A malformed usage event, counter
118
+ rollback or uncertain baseline prevents a complete usage claim. Subscription
119
+ authentication does not establish a dollar price or unlimited quota.
120
+
121
+ ## Cancellation and process ownership
122
+
123
+ On POSIX the caller starts a guardian as a new process-group leader with an IPC
124
+ lifeline established during spawn. Codex and its ordinary descendants share
125
+ that group; they do not inherit the lifeline. The live caller owns normal
126
+ cleanup and checks that the group is gone. A live caller's SIGTERM/SIGINT stops
127
+ the guardian as soon as the app-server exits, so clean runs do not wait out the
128
+ full dispose grace. If the caller dies, including SIGKILL, IPC disconnect makes
129
+ the guardian retain the full grace and terminate its own group. There is no
130
+ later PID-registration window, name-based kill or ancestor-group kill.
131
+
132
+ The receipt distinguishes the direct child/driver process from its supervisor.
133
+ The installed Codex launcher may spawn the native app-server as its own child;
134
+ the reported exit/signal are mirrored launcher facts, not a claim that the
135
+ native server is the same PID. A successful turn may be followed by an
136
+ intentional TERM/KILL to close a long-lived app-server. execution.terminationRequested records that cleanup action; it is
137
+ not a caller cancellation. If the last escalation prevents an actual Codex exit
138
+ message from arriving, its exitCode/signal remain null even if the group is gone.
139
+ No supervisor exit is rewritten as a Codex exit 0. An unconfirmed cleanup cannot
140
+ produce a successful outcome, and DSH dispose rejects it.
141
+
142
+ If the caller cannot signal or confirm its group, it releases its own pipes and
143
+ IPC lifeline after the cleanup deadline so a failed run does not keep the caller
144
+ alive indefinitely. The guardian can then attempt its independent cleanup. The
145
+ receipt retains cleanup.confirmed=false and unknown process facts; that later
146
+ attempt is not evidence that the original cleanup succeeded.
147
+
148
+ A signal error also does not invalidate a later independent absence check.
149
+ Darwin can return EPERM while a group still exists but its members are being
150
+ reaped; the [XNU implementation](https://github.com/apple-oss-distributions/xnu/blob/f6217f891ac0bb64f3d375211650a4c1ff8ca1ea/bsd/kern/kern_sig.c#L1675-L1721)
151
+ filters zombie members. EPERM remains unknown and is retried within the same
152
+ cleanup budget. Only a later ESRCH confirms the owned group is gone.
153
+
154
+ Machine execution requires POSIX and rejects Windows before spawning Codex;
155
+ capabilities reports supported=false there. Processes that deliberately escape
156
+ with a new session/group require a stronger external containment boundary. The
157
+ legacy Windows Host adapter controls a direct process and reports owned-process;
158
+ it must not be advertised as the POSIX group guarantee. Without lifecycle/journal options, a killed caller cannot write a final receipt.
159
+ With them, the independent machine supervisor can finish native cleanup and save
160
+ the actual receipt. Losing that supervisor too can still leave unknown facts;
161
+ read-only recovery never guesses them from a PID or starts a replacement turn.
162
+
163
+ ## DSH and Flywheel compatibility
164
+
165
+ The DSH adapter follows the rc.5 Host result contract: output, structured,
166
+ diagnostic and stopReason. Its diagnostic is bounded metadata, not raw server
167
+ output. Host capabilities are agentOptions, agentPreset=false, outputSchema and
168
+ depthLimit=false. Unsupported provider/maxTokens overrides fail explicitly.
169
+ Host job results remain strings. These narrow Host shapes do not carry the full
170
+ machine receipt; use this public entry when that receipt is required.
171
+
172
+ DSH Mac rc.5's SDK has no external-subagent/start RPC. Host startActivation needs
173
+ a real live parent Agent. An orchestrator should call this machine entry instead
174
+ of inventing a parent or treating codex-pro as a DSH LLM provider.
175
+
176
+ The original 0.8.0 integration baseline was Flywheel 0.27.3. A downstream consumer must implement a
177
+ separate driver, pass the worktree/model/effort/permission/deadline/request ID,
178
+ validate the receipt and sandbox policy, preserve unknown usage and physical
179
+ facts, and retain Go ownership of reports, tests, retries, commits and budgets.
180
+ Changing a provider string alone does not implement that consumer.
181
+
182
+ ## Verification and source baselines
183
+
184
+ The default tests are offline and use real scripted child processes. CI covers
185
+ Ubuntu/macOS with Node 22/24, then installs an actual npm tarball and tests the
186
+ public export, installed CLI and compiled guardian. Live model tests require
187
+ CODEX_SUBAGENT_LIVE=1. The 0.8.0 live app-server cases pass on Codex 0.165.0;
188
+ this is not a claim that the user's DSH Desktop profile has loaded the package.
189
+
190
+ - [DSH rc.5 Host types](https://github.com/deepseek-ai/deepseek-harness/blob/b830ec950faba0a46dda564be3e2d854afed94f1/packages/subagent/subagent/src/types.ts)
191
+ - [DSH rc.5 SDK requests](https://github.com/deepseek-ai/deepseek-harness/blob/b830ec950faba0a46dda564be3e2d854afed94f1/packages/sdk/protocol/src/types.ts)
192
+ - [Codex 0.166 ThreadStartResponse](https://github.com/openai/codex/blob/rust-v0.166.0/codex-rs/app-server-protocol/schema/typescript/v2/ThreadStartResponse.ts)
193
+ - [Codex 0.166 TurnStartResponse](https://github.com/openai/codex/blob/rust-v0.166.0/codex-rs/app-server-protocol/schema/typescript/v2/TurnStartResponse.ts)
194
+ - [Codex app-server documentation](https://learn.chatgpt.com/docs/app-server)
@@ -0,0 +1,86 @@
1
+ # Flywheel 接入、需求准备与 Git 交付
2
+
3
+ 本文区分插件能力与下游流程。0.8.0 提供 machine API/CLI;当前 0.9.0 源码候选
4
+ 新增[可等待检查点与只读恢复](machine-lifecycle.zh.md)。原始接入分析的下游基线是
5
+ Flywheel 0.27.3;当前 Flywheel 的 driver、范围会话与恢复能力以其对应 PR 为准。
6
+ 安装本插件本身不修改下游绑定,也不证明下游已经使用新能力。
7
+ 本仓库 PR 不会替下游修改路由、推送业务代码、合并 main 或发布产品。
8
+
9
+ ## 建议的接入方式
10
+
11
+ Go 引擎 → codex-pro-machine → 本包运行核心 → Codex app-server。
12
+
13
+ DSH 桌面仍是任务控制面,Go 持有任务状态、重试、预算、worktree、验收和 Git
14
+ 交付。完整 Codex harness 由本包复用。复杂实现和需要 Codex 工具链的审查适合
15
+ 这条通路;DSH 原生 Flash/GPT 路线仍可保留,不需要统一改成 Codex。
16
+
17
+ SDK rc.5 没有 external-subagent/start;Host 的 startActivation 要求真实父 Agent。
18
+ 为调用 Codex 再启动一个父模型会增加一次模型循环,也不自动补足运行收据。
19
+ 正式 machine 入口可以避免这个依赖,同时保留 requested/effective、usage、
20
+ 取消、进程终态和清理证据。具体协议、失败行为与限制见 [machine.md](machine.md)。
21
+
22
+ 下游必须实际实现 driver/worker、配置绑定、无推理诊断和跨进程回归,才能宣布
23
+ 已经接通。它应校验协议版本、request/run 关联、实际sandbox policy及完成事实,
24
+ 不能只判断 exit 0。正常 turn 后关闭长驻 app-server 的信号与调用方取消须分别处理。
25
+
26
+ ## 需求准备选什么模型
27
+
28
+ 这里是工程建议,不是经过本项目实测的模型排名:
29
+
30
+ | 场景 | 建议起点 | 原因 |
31
+ |---|---|---|
32
+ | 跨模块、架构约束多或需求不清楚 | GPT-6 Astra / high | 需求范围、接口和验收错误会传递到所有执行单元,优先投入判断与推理 |
33
+ | 范围清楚的日常功能或修复 | GPT-6.1 Sol / high | 在代码理解、约束梳理与响应成本之间取折中 |
34
+ | 单文件、小改动、已有清晰验收 | 当前 Flash 或 Sol 的常用配置 | 先验证是否足够,避免所有小任务都承担最高推理开销 |
35
+
36
+ 初始 flywheel-new skill 使用宿主当前会话模型,不会自动切换到 loops.plan。
37
+ 先在 DSH 选择支持工具调用的实际 provider/model;只选它实际支持的思考等级。
38
+ 需求冻结后的运行中 Plan 仍按 Flywheel 配置,可以继续使用 Kimi CLI/high。
39
+ 复杂需求可以让一个不同模型只读评审 Spec、边界和验收矩阵,但不默认反复多模型会审。
40
+
41
+ high 是建议基线。xhigh/max 应由代表性任务的质量增益、时间和额度决定,不能
42
+ 仅凭“更高”就视为更优。API 支持某个等级,不等于当前 DSH adapter 暴露了它。
43
+ 账户实际可用模型以本人的模型目录和授权为准;订阅额度也不等于无限调用。
44
+
45
+ 依据:[OpenAI 模型指南](https://developers.openai.com/api/docs/guides/latest-model)、
46
+ [reasoning 与部署检查](https://developers.openai.com/api/docs/guides/deployment-checklist)。
47
+
48
+ ## Worktree 与 PR 的建议时机
49
+
50
+ 1. 从最新目标分支创建一个任务 feature branch 和独立 worktree。一个可独立
51
+ 交付的任务或里程碑对应一个 PR,避免每个内部 packet 都生成一个零碎 PR。
52
+ 2. 在这个 worktree 中调研并准备 Spec/packets,审阅范围、测试和保护边界。
53
+ 已有有意义的提交后尽早开 Draft PR,让变更可见并启动远端 CI。
54
+ 3. 让 Flywheel 的 cwd 指向该 feature worktree。它内部的 packet worktree
55
+ 提交汇回这个 feature branch;本地“主 checkout”不应被误解为 main 分支。
56
+ 4. 持续保存和推送可审查的检查点。全部 L1/L2/L3、独立评审与 Git 持久化完成,
57
+ 并且远端 CI 对应当前提交通过后,再将 PR 标记 Ready。
58
+ 5. 默认保留最终合并决策。用户已明确授权该任务自动合并时,可以启用 GitHub
59
+ auto-merge,让 required checks/reviews 和分支保护决定真正的合并时机。
60
+ 多人频繁合并的仓库可用 merge queue;工作流需要支持 merge_group 事件。
61
+ 6. 合并后核对目标分支 CI;发布/部署有自己的门禁与授权,不由本地 completed
62
+ 状态隐式触发。
63
+
64
+ worktree 解决工作区与 index 相互干扰,不是权限沙箱;仍要设置执行边界。
65
+ Draft、Ready、Merged、Published 是不同状态。模型说完成、某次测试绿灯、
66
+ Flywheel 的 local completed,都不能直接充当“允许合并 main”的判断。
67
+
68
+ 你提到的 [mattpocock/skills](https://github.com/mattpocock/skills) 也可以作为
69
+ 准备和审查方法的参考:当前 `to-spec` 整理已知需求与测试边界,`to-tickets`
70
+ 按可独立验证的端到端行为拆分任务并明确依赖,`implement-spec` 使用 integration
71
+ branch、独立 worktree 和 Draft PR。Flywheel 可以吸收这些方法;运行时状态与
72
+ 提交仍由 Go 持有,避免同时引入第二套编排状态机。
73
+
74
+ 依据:
75
+
76
+ - [Git worktree](https://git-scm.com/docs/git-worktree)
77
+ - [GitHub Draft PR](https://docs.github.com/en/pull-requests/reference/pull-requests)
78
+ - [GitHub auto-merge](https://docs.github.com/en/pull-requests/how-tos/merge-and-close-pull-requests/automatically-merging-a-pull-request)
79
+ - [受保护分支](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches)
80
+
81
+ ## 覆盖率与真实验收
82
+
83
+ 要求100%覆盖率时,应在项目实际测试工具里配置门禁,并写进任务包的L1命令。
84
+ 覆盖率数值不能证明断言正确,还要审查边界案例、错误路径、集成与用户流程。
85
+ 冻结验收不能由执行者削弱;真实模型、账号、桌面UI与系统沙箱的验证独立记录,
86
+ 不能用fake app-server、DOM测试或CI runner代替用户机器结果。
@@ -0,0 +1,68 @@
1
+ /**
2
+ * The `codex exec` command line, built and run.
3
+ *
4
+ * This module is deliberately free of harness types: the whole probe rests on
5
+ * whether a plugin can register a subagent provider at all, so the part that
6
+ * talks to Codex stays independently testable. It also keeps the plugin free of
7
+ * runtime dependencies — the failure mode we are looking for is the provider
8
+ * chain, not module resolution.
9
+ *
10
+ * @module dsh-subagent-codex-pro/codex-exec
11
+ */
12
+ /**
13
+ * Build the argv for one run.
14
+ *
15
+ * The prompt goes on stdin (`-`) rather than argv: delegated prompts are long and
16
+ * routinely contain quotes, newlines, and shell metacharacters.
17
+ *
18
+ * @param options - the run's inputs.
19
+ * @returns the argv to spawn, without the program name.
20
+ */
21
+ export function buildCodexExecArgv(options) {
22
+ const argv = ['exec', '-C', options.cwd, '--skip-git-repo-check'];
23
+ if (options.model !== undefined && options.model !== '')
24
+ argv.push('-m', options.model);
25
+ if (options.reasoningEffort !== undefined && options.reasoningEffort !== '') {
26
+ // `-c` overrides a `config.toml` value for this run only, which is how a
27
+ // per-call effort reaches the CLI without touching the user's configuration.
28
+ argv.push('-c', `model_reasoning_effort=${options.reasoningEffort}`);
29
+ }
30
+ if (options.bypassApprovals === true)
31
+ argv.push('--dangerously-bypass-approvals-and-sandbox');
32
+ else if (options.sandbox !== undefined)
33
+ argv.push('-s', options.sandbox);
34
+ argv.push('-o', options.outputFile, '-');
35
+ return argv;
36
+ }
37
+ /**
38
+ * Run one `codex exec` and collect its final message.
39
+ *
40
+ * @param command - the Codex executable.
41
+ * @param options - the run's inputs, plus the output file to read back.
42
+ * @param spawn - the spawn implementation to use.
43
+ * @param readOutput - reads the output file; returns `undefined` when absent.
44
+ * @returns the child's answer and status.
45
+ */
46
+ export async function runCodexExec(command, options, spawn, readOutput) {
47
+ const argv = buildCodexExecArgv(options);
48
+ const child = spawn(command, argv, {
49
+ cwd: options.cwd,
50
+ env: { ...process.env, ...options.env },
51
+ stdio: ['pipe', 'pipe', 'pipe'],
52
+ });
53
+ let stdout = '';
54
+ let stderr = '';
55
+ child.stdout?.on('data', (chunk) => { stdout += chunk.toString('utf8'); });
56
+ child.stderr?.on('data', (chunk) => { stderr += chunk.toString('utf8'); });
57
+ child.stdin?.end(options.prompt);
58
+ const code = await new Promise((resolve, reject) => {
59
+ child.on('error', reject);
60
+ child.on('close', resolve);
61
+ });
62
+ // The output file is the authoritative answer; stdout carries progress lines
63
+ // and is only a fallback when the CLI wrote no file.
64
+ const fromFile = readOutput(options.outputFile);
65
+ const text = fromFile !== undefined && fromFile !== '' ? fromFile : stdout;
66
+ return { text, code, stderr };
67
+ }
68
+ //# sourceMappingURL=codex-exec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-exec.js","sourceRoot":"","sources":["../src/codex-exec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAwCH;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAyB;IAC1D,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,EAAE,uBAAuB,CAAC,CAAA;IACjE,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO,CAAC,KAAK,KAAK,EAAE;QAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,CAAA;IACvF,IAAI,OAAO,CAAC,eAAe,KAAK,SAAS,IAAI,OAAO,CAAC,eAAe,KAAK,EAAE,EAAE,CAAC;QAC5E,yEAAyE;QACzE,6EAA6E;QAC7E,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,0BAA0B,OAAO,CAAC,eAAe,EAAE,CAAC,CAAA;IACtE,CAAC;IACD,IAAI,OAAO,CAAC,eAAe,KAAK,IAAI;QAAE,IAAI,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAA;SACxF,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS;QAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;IACxE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAA;IACxC,OAAO,IAAI,CAAA;AACb,CAAC;AAkBD;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,OAAe,EACf,OAAyB,EACzB,KAAgB,EAChB,UAAgD;IAEhD,MAAM,IAAI,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAA;IACxC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE;QACjC,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE;QACvC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;KAChC,CAAC,CAAA;IACF,IAAI,MAAM,GAAG,EAAE,CAAA;IACf,IAAI,MAAM,GAAG,EAAE,CAAA;IACf,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,GAAG,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA,CAAC,CAAC,CAAC,CAAA;IACzE,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,GAAG,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA,CAAC,CAAC,CAAC,CAAA;IACzE,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;IAEhC,MAAM,IAAI,GAAG,MAAM,IAAI,OAAO,CAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAChE,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;QACzB,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;IAC5B,CAAC,CAAC,CAAA;IAEF,6EAA6E;IAC7E,qDAAqD;IACrD,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;IAC/C,MAAM,IAAI,GAAG,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAA;IAC1E,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;AAC/B,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * The harness shapes this probe needs, declared locally.
3
+ *
4
+ * The plugin imports nothing from `@deepseek-ai/*` at runtime — that is a
5
+ * deliberate property, so a failure can only mean the wiring and never module
6
+ * resolution. These are structural types mirroring the harness contracts; they
7
+ * are erased at build time.
8
+ *
9
+ * The tool registration shape mirrors what the LCU plugin does, which is the
10
+ * proven path for a plugin that registers its own model-facing tools.
11
+ *
12
+ * @module dsh-subagent-codex-pro/dsh-types
13
+ */
14
+ export {};
15
+ //# sourceMappingURL=dsh-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dsh-types.js","sourceRoot":"","sources":["../src/dsh-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG"}