@ckanner/flywheel 0.32.1 → 0.33.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -1
- package/README.md +7 -0
- package/README.zh-CN.md +5 -0
- package/THIRD_PARTY_NOTICES.md +42 -0
- package/bin/runtime.js +25 -31
- package/cordis.patch.yml +5 -0
- package/dist/bridge.mjs +421 -0
- package/dist/claude-code-pro-bridge.mjs +82 -0
- package/dist/claude-code-pro-worker.mjs +5 -0
- package/dist/client.js +4140 -0
- package/dist/codex-pro-bridge.mjs +75 -0
- package/dist/codex-pro-worker.mjs +5 -0
- package/dist/console-read.mjs +51 -0
- package/dist/control.mjs +218 -0
- package/dist/index.mjs +185 -0
- package/dist/installation.mjs +56 -0
- package/dist/machine-worker.mjs +241 -0
- package/dist/policy.mjs +91 -0
- package/dist/prewarm.mjs +136 -0
- package/dist/protocol.mjs +260 -0
- package/dist/task-association.mjs +127 -0
- package/dist/worker.mjs +52 -0
- package/dist/workspaces.mjs +42 -0
- package/docs/README.md +1 -1
- package/docs/README.zh-CN.md +1 -1
- package/docs/design.md +8 -5
- package/docs/en/configuration.md +1 -1
- package/docs/en/contributing.md +5 -6
- package/docs/en/flow-console.md +2 -2
- package/docs/en/getting-started.md +9 -2
- package/docs/en/releasing.md +132 -174
- package/docs/validation/2026-11-13-release-0.32.1.md +83 -0
- package/docs/validation/2026-11-14-release-0.33.0.md +49 -0
- package/docs/validation/2026-11-14-single-package.md +60 -0
- package/docs/validation/README.md +3 -0
- package/docs/zh-CN/configuration.md +1 -1
- package/docs/zh-CN/contributing.md +4 -5
- package/docs/zh-CN/flow-console.md +2 -2
- package/docs/zh-CN/getting-started.md +7 -3
- package/docs/zh-CN/releasing.md +97 -81
- package/native/darwin-amd64/flywheel +0 -0
- package/native/darwin-arm64/flywheel +0 -0
- package/native/linux-amd64/flywheel +0 -0
- package/native/linux-arm64/flywheel +0 -0
- package/native/manifest.json +22 -0
- package/node_modules/dsh-subagent-codex-pro/CHANGELOG.md +403 -0
- package/node_modules/dsh-subagent-codex-pro/LICENSE +21 -0
- package/node_modules/dsh-subagent-codex-pro/README.md +557 -0
- package/node_modules/dsh-subagent-codex-pro/cordis.patch.yml +30 -0
- package/node_modules/dsh-subagent-codex-pro/docs/README.zh.md +355 -0
- package/node_modules/dsh-subagent-codex-pro/docs/machine-lifecycle-validation.md +65 -0
- package/node_modules/dsh-subagent-codex-pro/docs/machine-lifecycle.md +144 -0
- package/node_modules/dsh-subagent-codex-pro/docs/machine-lifecycle.zh.md +98 -0
- package/node_modules/dsh-subagent-codex-pro/docs/machine.md +194 -0
- package/node_modules/dsh-subagent-codex-pro/docs/orchestration.zh.md +86 -0
- package/node_modules/dsh-subagent-codex-pro/lib/codex-exec.js +68 -0
- package/node_modules/dsh-subagent-codex-pro/lib/codex-exec.js.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/dsh-types.js +15 -0
- package/node_modules/dsh-subagent-codex-pro/lib/dsh-types.js.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/index.js +830 -0
- package/node_modules/dsh-subagent-codex-pro/lib/index.js.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/jobs.js +35 -0
- package/node_modules/dsh-subagent-codex-pro/lib/jobs.js.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/jsonrpc.js +229 -0
- package/node_modules/dsh-subagent-codex-pro/lib/jsonrpc.js.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/machine-cli.js +101 -0
- package/node_modules/dsh-subagent-codex-pro/lib/machine-cli.js.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/machine-local.js +122 -0
- package/node_modules/dsh-subagent-codex-pro/lib/machine-local.js.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/machine-recovery.js +167 -0
- package/node_modules/dsh-subagent-codex-pro/lib/machine-recovery.js.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/machine-supervision.js +141 -0
- package/node_modules/dsh-subagent-codex-pro/lib/machine-supervision.js.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/machine-supervisor.js +128 -0
- package/node_modules/dsh-subagent-codex-pro/lib/machine-supervisor.js.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/machine.js +104 -0
- package/node_modules/dsh-subagent-codex-pro/lib/machine.js.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/process-guardian.js +156 -0
- package/node_modules/dsh-subagent-codex-pro/lib/process-guardian.js.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/run.js +842 -0
- package/node_modules/dsh-subagent-codex-pro/lib/run.js.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/structured.js +329 -0
- package/node_modules/dsh-subagent-codex-pro/lib/structured.js.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/tool.js +295 -0
- package/node_modules/dsh-subagent-codex-pro/lib/tool.js.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/codex-exec.d.ts +88 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/codex-exec.d.ts.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/dsh-types.d.ts +179 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/dsh-types.d.ts.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/index.d.ts +266 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/index.d.ts.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/jobs.d.ts +34 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/jobs.d.ts.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/jsonrpc.d.ts +113 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/jsonrpc.d.ts.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/machine-cli.d.ts +3 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/machine-cli.d.ts.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/machine-local.d.ts +4 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/machine-local.d.ts.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/machine-recovery.d.ts +53 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/machine-recovery.d.ts.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/machine-supervision.d.ts +8 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/machine-supervision.d.ts.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/machine-supervisor.d.ts +2 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/machine-supervisor.d.ts.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/machine.d.ts +70 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/machine.d.ts.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/process-guardian.d.ts +22 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/process-guardian.d.ts.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/run.d.ts +386 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/run.d.ts.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/structured.d.ts +35 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/structured.d.ts.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/tool.d.ts +107 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/tool.d.ts.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/usage.d.ts +131 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/usage.d.ts.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/wire.d.ts +321 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/wire.d.ts.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/usage.js +356 -0
- package/node_modules/dsh-subagent-codex-pro/lib/usage.js.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/wire.js +986 -0
- package/node_modules/dsh-subagent-codex-pro/lib/wire.js.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/package.json +76 -0
- package/npm/install.js +59 -6
- package/package.json +74 -12
- package/plugins/dsh/LICENSE +21 -0
- package/plugins/dsh/PROTOCOL.md +609 -0
- package/plugins/dsh/README.en.md +4 -0
- package/plugins/dsh/README.md +342 -0
- package/plugins/dsh/README.zh-CN.md +279 -0
- package/plugins/dsh/THIRD_PARTY_NOTICES.md +42 -0
- package/plugins/dsh/vendor/README.md +17 -0
- package/plugins/dsh/vendor/codex-pro.json +16 -0
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.9.0 (source candidate, unreleased)
|
|
4
|
+
|
|
5
|
+
- Add lifecycle v1 with awaited configuration-checked thread-ready, dispatch-intent,
|
|
6
|
+
dispatch-possible and turn-accepted checkpoints. A failed ACK cannot silently
|
|
7
|
+
continue a turn; the possible-send window remains explicitly ambiguous.
|
|
8
|
+
- Add a separately grouped machine supervisor for opted-in lifecycle/journal
|
|
9
|
+
calls. Caller death aborts native work and persists the original complete
|
|
10
|
+
receipt; a lost terminal notification never rewrites a completed run as cancelled.
|
|
11
|
+
- Add exclusive private, atomic and fsynced invocation journals plus a read-only
|
|
12
|
+
recoverMachine entry. Missing/corrupt evidence remains unknown, not a retry.
|
|
13
|
+
- Record typed execution.dispatch without inferring model execution from a PID,
|
|
14
|
+
progress text, a thread ID, or cleanup success. Require explicit boolean
|
|
15
|
+
persistence evidence on thread/start.
|
|
16
|
+
- Exercise real checkpoint rejection, caller process-group SIGKILL, original
|
|
17
|
+
receipt recovery and built-package lifecycle paths with offline app-server
|
|
18
|
+
fixtures. No new live-account or installed desktop acceptance is claimed.
|
|
19
|
+
|
|
20
|
+
## 0.8.0
|
|
21
|
+
|
|
22
|
+
Released 2026-11-03.
|
|
23
|
+
|
|
24
|
+
- Add the public protocol-1 machine API and single-request CLI, preserving run identity, actual process facts, configuration and usage completeness without changing DSH Host result shapes.
|
|
25
|
+
- Supervise POSIX Codex groups with an IPC-lifeline guardian so caller death triggers bounded cleanup; never substitute supervisor exit for the actual Codex exit. A live caller's normal stop now exits the guardian as soon as the app-server is gone instead of paying the full dispose grace; caller-death cleanup keeps the full grace.
|
|
26
|
+
- Confirm cleanup from a final independent absence probe, retaining unknown status for EPERM while allowing a later ESRCH to resolve a Darwin exit race.
|
|
27
|
+
- Reject missing or conflicting effective configuration before sending a task. Preserve full sandbox policy and request-only effort evidence.
|
|
28
|
+
- Default to workspace-write + never; full access remains explicit and tool overrides cannot expand configured permissions.
|
|
29
|
+
- Align DSH rc.5 capabilities, reject unsupported provider/maxTokens overrides, and reject dispose when cleanup is unconfirmed.
|
|
30
|
+
- Correct malformed, early, foreign-turn and resumed token-usage accounting; unknown counters and costs are not zero. A resumed thread's historical replay is adopted even when it arrives after turn/start; a different-turn snapshot after live current-turn usage remains unattributed.
|
|
31
|
+
- Add Ubuntu/macOS Node22/24 CI, real packed-package/public-entry tests, migration notes and Flywheel/PR workflow documentation.
|
|
32
|
+
- Accept the protocol-defaulted `cacheWriteInputTokens`, preserve bounded approval diagnostics, gate the model-facing permission enum to the configured policy, handle CLI EPIPE, and retain startup failure causes in machine receipts.
|
|
33
|
+
- Real Codex 0.165 app-server live cases pass 4/4 (including resume/usage replay); real DSH Desktop smoke is not claimed.
|
|
34
|
+
|
|
35
|
+
## 0.7.0
|
|
36
|
+
|
|
37
|
+
Adapter reliability and observability hardening. Released 2026-11-01. The
|
|
38
|
+
user's global Codex login/config is untouched.
|
|
39
|
+
|
|
40
|
+
- **One deadline for the whole delegation.** A single derived abort signal now
|
|
41
|
+
covers `initialize`, `thread/start`/`thread/resume`, `thread/name/set`, and the
|
|
42
|
+
turn. Startup hangs can no longer outlive `runTimeoutMs`; `0` still disables
|
|
43
|
+
the deadline. Timeout, caller cancellation, protocol failure, and process exit
|
|
44
|
+
are classified distinctly, settlement occurs once, and teardown is idempotent.
|
|
45
|
+
An auto-resume retry inherits the original absolute deadline instead of a
|
|
46
|
+
fresh full timeout.
|
|
47
|
+
- **Resume applies requested configuration.** On the 0.165 protocol,
|
|
48
|
+
`thread/resume` sends explicit model, cwd, and permission overrides and checks
|
|
49
|
+
the response's effective `model`, `cwd`, `approvalPolicy`, `approvalsReviewer`,
|
|
50
|
+
and `sandbox`. A mismatch fails an explicit resume; a remembered session
|
|
51
|
+
thread with incompatible configuration is replaced by a new thread under the
|
|
52
|
+
same deadline. `thread/start` no longer sends `reasoningEffort`, which is not
|
|
53
|
+
in the 0.165/0.166 start parameters; thinking remains a per-turn `effort`.
|
|
54
|
+
- **Read-only review mode.** Added `read-only` (`approvalPolicy: never`,
|
|
55
|
+
`sandbox: read-only`), available in configuration and per-call as
|
|
56
|
+
`permission_mode`. `never` remains only "do not prompt"; the default
|
|
57
|
+
write-capable mode is unchanged.
|
|
58
|
+
- **Token usage and rate limits.** `thread/tokenUsage/updated` is folded from
|
|
59
|
+
thread-cumulative snapshots into a run delta: resume replays are baselines,
|
|
60
|
+
duplicates/out-of-order snapshots never add, missing baselines are `unknown`
|
|
61
|
+
rather than zero, and observed usage survives failure/timeout/cancel.
|
|
62
|
+
`account/rateLimits/updated` is stored separately from token usage and is
|
|
63
|
+
never merged into it.
|
|
64
|
+
- **Result envelope separated.** Final text, structured result, thread id,
|
|
65
|
+
usage, configuration, diagnostics, cleanup, and schema errors are distinct
|
|
66
|
+
fields on the internal outcome. A schema-constrained answer stays pure JSON:
|
|
67
|
+
the persistent-thread marker is not appended to it, and parse/schema
|
|
68
|
+
verification is fail-closed. The DSH provider/tool/job contracts are
|
|
69
|
+
unchanged; they carry no usage field, so usage/rate limits are reported in
|
|
70
|
+
the outcome and diagnostic log rather than invented host fields.
|
|
71
|
+
- **Provable process cleanup.** POSIX children are process-group leaders;
|
|
72
|
+
teardown signals the group, escalates to `SIGKILL` after a separate grace, and
|
|
73
|
+
verifies the group is gone. Unconfirmed cleanup is reported, including for
|
|
74
|
+
descendants that ignore `SIGTERM`; there is no global `killall`.
|
|
75
|
+
- **Tests and docs.** Added fake-app-server lifecycle tests, usage-accounting
|
|
76
|
+
tests, structured-verification tests, resume-override tests, result-marker
|
|
77
|
+
tests, and permission-forwarding tests. Updated README and Chinese README to
|
|
78
|
+
match the 0.165 baseline and to separate offline, real-Codex, and real-DSH
|
|
79
|
+
desktop validation. Validation baseline: installed Codex 0.165.0; live
|
|
80
|
+
app-server cases 4/4 passed and the `codex exec` live case passed; official
|
|
81
|
+
0.166.0 schemas reviewed, no 0.166 runtime executed; real DSH desktop smoke
|
|
82
|
+
still not run.
|
|
83
|
+
|
|
84
|
+
## 0.6.4
|
|
85
|
+
|
|
86
|
+
Tests only; the shipped runtime is unchanged.
|
|
87
|
+
|
|
88
|
+
The live suite still read `delegateOnce` as if it returned the answer string, but
|
|
89
|
+
the function has returned `{ text, threadId, images }` since persistent threads
|
|
90
|
+
landed. Both live cases therefore failed their assertion even though the real
|
|
91
|
+
app-server turn had answered correctly; they now read `outcome.text`.
|
|
92
|
+
|
|
93
|
+
Verified against `@openai/codex` 0.164.0: the hermetic suite passes, and both
|
|
94
|
+
live cases complete a real turn (model + reasoning effort, and the defaults).
|
|
95
|
+
The 0.164.0 app-server protocol keeps every message phase and server request
|
|
96
|
+
this wire handles; it only adds optional `TurnStartParams` fields
|
|
97
|
+
(`parentTurnId`, `rootTurnId`) and two notifications this provider ignores.
|
|
98
|
+
|
|
99
|
+
## 0.6.3
|
|
100
|
+
|
|
101
|
+
A missing Codex executable now fails one delegation instead of the Host.
|
|
102
|
+
|
|
103
|
+
`spawn codex` reports `ENOENT` when the executable is not on the Host's `PATH`
|
|
104
|
+
— for example after a Node version switch through a version manager drops the
|
|
105
|
+
global npm install. The run failed correctly, but the process-cleanup path
|
|
106
|
+
attached its termination-timer cleanup with a bare `finally()` on the
|
|
107
|
+
already-rejected exit promise. That derived rejection was unhandled, and the
|
|
108
|
+
Host's global unhandled-rejection handler escalates it to a fatal load failure:
|
|
109
|
+
DSH Desktop exited instead of returning the delegation error, taking every
|
|
110
|
+
running session with it. Cleanup now handles both settlements, so the only
|
|
111
|
+
observable result is a failed run with its diagnostic.
|
|
112
|
+
|
|
113
|
+
Add a regression test: a delegation whose executable is missing rejects
|
|
114
|
+
without leaving an unhandled rejection behind.
|
|
115
|
+
|
|
116
|
+
The README now records how to point `command` at an absolute executable for a
|
|
117
|
+
Host whose launch-time `PATH` does not carry the global install.
|
|
118
|
+
|
|
119
|
+
## 0.6.2
|
|
120
|
+
|
|
121
|
+
Compatibility with DSH 0.2.1's subagent seam and the Codex app-server it drives.
|
|
122
|
+
|
|
123
|
+
- Accept the `partial_answer` agent-message phase. It is retained as a fallback answer and selection stays
|
|
124
|
+
final → partial → unphased, matching the official provider as of DSH 0.2.1. A turn that emitted only a partial
|
|
125
|
+
answer no longer fails with `unknown agent message phase "partial_answer"`.
|
|
126
|
+
- Use the working directory the shared subagent service selected (`request.cwd`) when one is supplied, falling
|
|
127
|
+
back to the parent session's directory. Provider-row and workflow dispatch now honour it; this plugin's own
|
|
128
|
+
tool path is unchanged because it already resolves the directory itself.
|
|
129
|
+
- Document the changed official activation model: since DSH 0.2.1 the official `subagent_codex` is a global Host
|
|
130
|
+
tool, and this plugin's per-Agent registration shadows it for the configured presets rather than a per-preset
|
|
131
|
+
disabled row switching it off. A same-scope duplicate still collides, so the profile must not enable a
|
|
132
|
+
same-name `tool-subagent` row beside this provider.
|
|
133
|
+
|
|
134
|
+
## 0.6.1
|
|
135
|
+
|
|
136
|
+
The deadline is now a parameter, so a prompt can set it.
|
|
137
|
+
|
|
138
|
+
`timeout_ms` overrides the configured `runTimeoutMs` for one delegation, and `0` means no deadline at all. The
|
|
139
|
+
default was already a plugin setting, which made it usable only by editing a profile and restarting — plugin
|
|
140
|
+
configuration is not hot-reloaded, and a model cannot pass a value that no parameter declares. Now the routine
|
|
141
|
+
that needs tens of minutes and the lookup that needs seconds can be told apart by the model itself, in the same
|
|
142
|
+
turn, without a restart.
|
|
143
|
+
|
|
144
|
+
`0` is forwarded rather than treated as "unset": asking for no deadline is a different request from asking for
|
|
145
|
+
the configured one.
|
|
146
|
+
|
|
147
|
+
The README now records how a profile overrides this package's row. The loader replaces the whole `config` map
|
|
148
|
+
rather than merging it — read out of `applyEntryPatches`, which assigns each top-level field in turn, `config`
|
|
149
|
+
being one of them — so overriding `runTimeoutMs` without restating `presets` mounts a row that matches no
|
|
150
|
+
preset and therefore serves no session. The failure is silent, the log line names the presets actually received,
|
|
151
|
+
and both READMEs now carry the wrong and right shapes side by side.
|
|
152
|
+
|
|
153
|
+
Also corrects a contradiction in the capabilities table: `outputSchema` was listed as ✅ and, three rows later,
|
|
154
|
+
still inside the ❌ row left over from 0.6.0. The three refusals that remain — `maxDepth`, persona, `toolFilter`
|
|
155
|
+
— are now described as not applicable rather than not implemented, with the reason: a Codex delegation is a
|
|
156
|
+
leaf with no DSH child to cap, its tools are Codex's own rather than this harness's, and a persona is a system
|
|
157
|
+
instruction for a child agent where this one already takes the task in `prompt`.
|
|
158
|
+
|
|
159
|
+
## 0.6.0
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
The answer can now be made machine-readable, and the capability table stops understating what this provider can
|
|
163
|
+
do.
|
|
164
|
+
|
|
165
|
+
`output_schema` hands Codex a JSON Schema its final answer must conform to, so a later step reads the answer
|
|
166
|
+
instead of parsing prose and hoping. The schema must be object-rooted, the same rule the harness applies to a
|
|
167
|
+
schema it passes a provider. The app-server enforces it: a measured run returned
|
|
168
|
+
`{"verdict":"pass","reason":"…","count":2}` with no extra keys and every required one present. The answer still
|
|
169
|
+
arrives as text, and that text is JSON.
|
|
170
|
+
|
|
171
|
+
It is sent on the **turn**: the same field on `thread/start` is accepted and then silently ignored — measured
|
|
172
|
+
both ways, and the thread-level form produced prose. Another silent-ignore, like a missing `localImage` path.
|
|
173
|
+
|
|
174
|
+
`capabilities.outputSchema` is now `true` rather than `false`, because it is now honored: a schema the harness
|
|
175
|
+
puts on a `tool-subagent` row reaches Codex, and the answer is parsed so the caller receives `structured`
|
|
176
|
+
alongside the text. Declaring it while ignoring it would have been worse than the old `false`.
|
|
177
|
+
|
|
178
|
+
The `apply` diagnostic line now names the version, so a restart's log says which build is loaded. It previously
|
|
179
|
+
could not tell two releases apart: 0.3.3 and 0.4.0 logged identically.
|
|
180
|
+
|
|
181
|
+
## 0.5.0
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
Pictures now travel both ways. `images` hands Codex pictures alongside the task:
|
|
185
|
+
|
|
186
|
+
```js
|
|
187
|
+
tools.subagent_codex({ description: "Match this design", prompt: "…", images: ["/tmp/design.png"] })
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Each path must be absolute, must exist, and must be a file, and the call fails before anything is spawned
|
|
191
|
+
otherwise. That check is load-bearing rather than decorative: **the app-server silently ignores a `localImage`
|
|
192
|
+
path that does not exist** — measured, with the turn completing normally and not one error item — so an
|
|
193
|
+
unchecked typo would produce a delegation that quietly lacks the picture its task was about.
|
|
194
|
+
|
|
195
|
+
The pictures go out as the app-server's `localImage` variant, which the error messages themselves identified as
|
|
196
|
+
one of `text`, `image`, `localImage`, `audio`, `localAudio`. Its `image` variant wants an `ImageReference` this
|
|
197
|
+
plugin cannot construct — both `{type:'image', data, mimeType}` and a `data:` URL are rejected with
|
|
198
|
+
`did not match any variant of untagged enum ImageReference` — so a host path is not a workaround but the form
|
|
199
|
+
that needs no encoding at all.
|
|
200
|
+
|
|
201
|
+
A delegation prompt remains text. An image block arriving there is refused with a message naming the `images`
|
|
202
|
+
parameter instead of the old flat refusal, because the harness can put an image in a prompt but a tool call's
|
|
203
|
+
arguments are JSON and the model has no bytes to put in them.
|
|
204
|
+
|
|
205
|
+
Verified live: a delegation whose prompt never mentioned a path, given one image, answered "Settings, Models" —
|
|
206
|
+
the two words on it.
|
|
207
|
+
|
|
208
|
+
## 0.4.0
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
A delegation can run in a directory of its own.
|
|
212
|
+
|
|
213
|
+
`cwd` names an absolute path the run should use instead of the session's working directory — the shape a
|
|
214
|
+
post-deploy smoke test needs, where the run may write its artifacts but the repository must stay clean.
|
|
215
|
+
|
|
216
|
+
The path must be absolute, must exist, and must be a directory; anything else is refused with a message naming
|
|
217
|
+
the problem, rather than a run that quietly happens somewhere unexpected. It is a working directory and not a
|
|
218
|
+
sandbox boundary: what a run may touch remains the permission mode's decision.
|
|
219
|
+
|
|
220
|
+
Naming a directory also starts a fresh Codex thread, because a thread belongs to the directory it was created
|
|
221
|
+
in — continuing one elsewhere would be continuing a conversation about different files. `cwd` is therefore
|
|
222
|
+
incompatible with `threadMode: session`'s reuse, and the log says which directory each run used.
|
|
223
|
+
|
|
224
|
+
Requested while retiring a skill whose two jobs this plugin now covers: dispatching to Codex, and getting
|
|
225
|
+
screenshots back — which the skill could not do, and which is why its instructions required artifacts to land on
|
|
226
|
+
disk instead.
|
|
227
|
+
|
|
228
|
+
## 0.3.3
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
A delegation now has a deadline, because one without it is invisible when it stalls.
|
|
232
|
+
|
|
233
|
+
`runTimeoutMs` bounds one whole delegation, defaulting to ten minutes and disabled by `0`. When the deadline
|
|
234
|
+
passes, the run is cancelled, the child process is torn down, and the result carries
|
|
235
|
+
`codex-pro: the delegation exceeded its 600000 ms deadline and was cancelled` rather than nothing at all.
|
|
236
|
+
|
|
237
|
+
The harness's own vocabulary has no `timeout` stop reason, so the provider path reports a cancelled run as
|
|
238
|
+
`aborted` while the diagnostic carries the reason; this plugin's own tool reports `timeout` and formats the
|
|
239
|
+
message itself.
|
|
240
|
+
|
|
241
|
+
Found in a real session: a screenshot delegation had been running for seven minutes at 0% CPU with one
|
|
242
|
+
established connection to a local proxy, no rollout written, and nothing anywhere in the log to say so. The
|
|
243
|
+
proxy turned out to be healthy — the stall was in the streaming request — which is precisely why the deadline
|
|
244
|
+
matters more than the diagnosis: whatever the cause, the wait now ends with a reason.
|
|
245
|
+
|
|
246
|
+
Verified live: a three-second deadline cancelled a run at 3.1 s, returned the diagnostic, and left no child
|
|
247
|
+
process behind.
|
|
248
|
+
|
|
249
|
+
## 0.3.2
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
A background delegation no longer loses its images.
|
|
253
|
+
|
|
254
|
+
`run_in_background` returns a job id, and everything read back through `job_output` is text by contract, so the
|
|
255
|
+
image blocks a foreground call returns were simply dropped — silently, and with no trace of where the picture
|
|
256
|
+
went. A screenshot taken by a background delegation is still a file on this host, so the text now names it:
|
|
257
|
+
`[1 image: /Users/…/shot.png]`. A foreground call is unchanged and still delivers the image itself; `render` no
|
|
258
|
+
longer repeats the count, because the text already carries it.
|
|
259
|
+
|
|
260
|
+
Found by looking at a real session rather than at the code: a screenshot delegation had been started in the
|
|
261
|
+
background, and there was no path in the answer it would eventually produce.
|
|
262
|
+
|
|
263
|
+
## 0.3.1
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
The image guard was too strict, and it would have hidden the feature it was added for.
|
|
267
|
+
|
|
268
|
+
0.3.0 refused an image whenever the calling route did not **report** `image` among its input modalities, and it
|
|
269
|
+
failed closed: a route it could not resolve was treated as a route that cannot take images. The default
|
|
270
|
+
`deepseek-flash` entry declares `['text', 'image']`, so a session that could display screenshots would instead
|
|
271
|
+
have been told `[image not delivered: …]` for every one of them.
|
|
272
|
+
|
|
273
|
+
The rule is now the harness's own — an image is refused only when the route **declares** modalities and `image`
|
|
274
|
+
is not among them — and an unresolvable route delivers the image rather than withholding it. The route lookup
|
|
275
|
+
also gained the fallback `dsh-plugin-lcu` uses, so a session header without a model still resolves.
|
|
276
|
+
|
|
277
|
+
The rule is a pure function, `routeRefusesImages`, so the boundary is covered by tests instead of by whichever
|
|
278
|
+
session happens to be running.
|
|
279
|
+
|
|
280
|
+
## 0.3.0
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
Images a delegation produces now come back.
|
|
284
|
+
|
|
285
|
+
The app-server reports them two ways and both are captured. `imageView` names a file on this host — the bytes
|
|
286
|
+
are never inlined, because the host that asked for the work is expected to read the file itself — while a
|
|
287
|
+
computer-use screenshot arrives as an image content block inside an MCP tool result. The plugin reads or decodes
|
|
288
|
+
whichever it gets, hands the bytes to the harness's attachment store, and returns image blocks beside the text,
|
|
289
|
+
so the model sees a picture instead of a description of one.
|
|
290
|
+
|
|
291
|
+
An image is only delivered when the calling Agent's model route reports `image` among its input modalities, the
|
|
292
|
+
same guard `dsh-plugin-lcu` applies to its screenshots. Everything else — no store, an unreadable file, over
|
|
293
|
+
20 MB, an unsupported type, a route that cannot take images — becomes a text note. None of it can fail the
|
|
294
|
+
delegation: the answer the run produced always survives.
|
|
295
|
+
|
|
296
|
+
Verified against a real app-server through this package's own code: asked to open a file by path, Codex read the
|
|
297
|
+
providers listed on the screenshot aloud, and the run reported one captured image with its host path.
|
|
298
|
+
|
|
299
|
+
Sending images *in* is not implemented. The protocol accepts `input_image`, `local_image`, `image_url` and
|
|
300
|
+
audio, but this tool still sends text only; naming a path in the prompt remains the working route, and both
|
|
301
|
+
READMEs now document what each side actually supports.
|
|
302
|
+
|
|
303
|
+
## 0.2.2
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
**`session` mode no longer collides with itself.** A thread carries one turn at a time, so two delegations sent
|
|
307
|
+
together from one session both reached for the remembered thread and the app-server refused the second with
|
|
308
|
+
`thread-store conflict: … already has an active writer`. The plugin now tracks which threads its Agent is
|
|
309
|
+
delegating in and checks before it starts: a remembered thread in use is skipped, the call gets a thread of its
|
|
310
|
+
own, and the skip is logged. Parallel work keeps running, and the mode falls back to `persistent` — which is
|
|
311
|
+
what that shape of work needs anyway — instead of failing and retrying.
|
|
312
|
+
|
|
313
|
+
The decision is a pure function, `chooseThread`, so it is covered by tests rather than by an app-server. An id
|
|
314
|
+
the caller passed explicitly is never skipped: continuing that thread was the request, and running somewhere
|
|
315
|
+
else would answer a different question.
|
|
316
|
+
|
|
317
|
+
## 0.2.1
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
`apply` now records the thread mode and the originator, so the log says which lifetime is in force without
|
|
321
|
+
anyone reading the profile to find out.
|
|
322
|
+
|
|
323
|
+
**The session-mode retry is narrowed to the failure it was meant for.** It wrapped every delegation, so a turn
|
|
324
|
+
that failed for its own reasons was retried as a fresh thread — paying for the same work twice and hiding the
|
|
325
|
+
real failure behind a second attempt. It now applies only to a resume the app-server refused.
|
|
326
|
+
|
|
327
|
+
**A concurrency limit, measured rather than assumed.** Two delegations sent at once to one thread collide: the
|
|
328
|
+
app-server answers `thread-store conflict: … already has an active writer` and the second fails, while
|
|
329
|
+
`ephemeral` runs the same pair independently. `session` is therefore the wrong mode for parallel work, and both
|
|
330
|
+
READMEs now say so.
|
|
331
|
+
|
|
332
|
+
## 0.2.0
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
A delegation can now outlive its run.
|
|
336
|
+
|
|
337
|
+
**Thread lifetime is a choice, not a constant.** Every delegation used to open an ephemeral thread, which the
|
|
338
|
+
app-server deletes when the connection ends — nothing to list, nothing to continue. `threadMode` now has three
|
|
339
|
+
settings: `ephemeral` keeps that behaviour and stays the default; `persistent` gives each delegation a durable
|
|
340
|
+
thread; `session` reuses one durable thread for the whole Agent session, so ten delegations leave one thread
|
|
341
|
+
rather than ten and each call after the first continues the same conversation.
|
|
342
|
+
|
|
343
|
+
**A durable thread is one the Codex CLI and the Codex application can see.** Verified against a real
|
|
344
|
+
app-server: the thread is written to `~/.codex/sessions/`, appears in `thread/list`, and can be continued with
|
|
345
|
+
`thread/resume`. The application's own list is the narrow part — its client filters by a single hardcoded
|
|
346
|
+
originator value, `Codex Desktop`, so `originator` exists to set that and defaults to the value that works.
|
|
347
|
+
Overriding it trades application visibility for an honest name; the CLI lists the thread either way.
|
|
348
|
+
|
|
349
|
+
**Threads are named, because the originator cannot say where they came from.** A thread from this provider has
|
|
350
|
+
to claim to be `Codex Desktop` to be listed at all, so `thread/name/set` carries the identification instead:
|
|
351
|
+
a persistent thread is named `DSH · <the call's description>`, which is what a person sees in the list.
|
|
352
|
+
|
|
353
|
+
**The model can control it per call.** The tool gained `thread_mode` and `thread_id`, and a persistent result
|
|
354
|
+
ends with the thread's id so a follow-up call can continue it. Resuming ignores `model` and `reasoning_effort`:
|
|
355
|
+
both are `thread/start` parameters and a resumed thread keeps the ones it was created with, while the per-turn
|
|
356
|
+
`effort` still applies.
|
|
357
|
+
|
|
358
|
+
**Why it is worth the change beyond convenience:** a resumed thread keeps the same prompt prefix, so the
|
|
359
|
+
endpoint's cache keeps hitting — measured on the Codex side at 93–99% of input tokens, against 0% for the same
|
|
360
|
+
work driven through a plan-usage route that refuses every cache control.
|
|
361
|
+
|
|
362
|
+
A thread with no turn yet is not resumable — the app-server answers `no rollout found` — so a thread becomes
|
|
363
|
+
continuable only after its first completed turn. A remembered session thread that has gone is replaced with a
|
|
364
|
+
fresh one; an id the caller passed explicitly is reported as a failure instead, because continuing it was the
|
|
365
|
+
whole request.
|
|
366
|
+
|
|
367
|
+
## 0.1.1
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
Documentation and packaging; no behaviour change.
|
|
371
|
+
|
|
372
|
+
The published `files` list named only `lib` and the patch, so an installed copy shipped **no licence and no
|
|
373
|
+
readme** — npm's own defaults covered neither once `files` was set. It now carries the licence, the readme, this
|
|
374
|
+
changelog and the Chinese page.
|
|
375
|
+
|
|
376
|
+
Joins a closing sentence that a blank line had split in two, and removes a `helper` entry from `files` that
|
|
377
|
+
named a directory this package does not have.
|
|
378
|
+
|
|
379
|
+
## 0.1.0
|
|
380
|
+
|
|
381
|
+
First release.
|
|
382
|
+
|
|
383
|
+
**A Codex delegation that can carry a model and a reasoning effort per call** — the two things
|
|
384
|
+
`@deepseek-ai/dsh-subagent-codex` cannot express. The Codex protocol supports both
|
|
385
|
+
(`ThreadStartParams.reasoningEffort`, `TurnStartParams.effort`); the official provider never sends them, and its
|
|
386
|
+
schema exposes neither, so a caller told to use a specific model and thinking level has nowhere to put either.
|
|
387
|
+
|
|
388
|
+
**Execution is a port of the official app-server adapter** (`src/wire.ts`, `src/run.ts`) — the initialize
|
|
389
|
+
handshake, the ephemeral thread, thread/turn association including notifications that arrive before
|
|
390
|
+
`turn/start` returns, unattended approval decisions, and terminal-answer selection — with `reasoningEffort` added
|
|
391
|
+
to `thread/start` and `effort` added to `turn/start`. The two literals appear nowhere in the official adapter.
|
|
392
|
+
|
|
393
|
+
**The tool is registered by this plugin itself**, on `agent/created`, into that Agent's own context, which keeps
|
|
394
|
+
the harness's preset-row machinery out of the path. Because the tool name is fixed, the official
|
|
395
|
+
`tool-subagent-codex` row stays disabled in those presets: two rows registering the same name in one scope
|
|
396
|
+
collide, and the second registration throws while its tool silently never appears.
|
|
397
|
+
|
|
398
|
+
**Defaults are deliberately absent.** What the call names is what runs; when it names neither, the choice stays
|
|
399
|
+
with Codex's own `~/.codex/config.toml`. The Host's `subagent-model-selection` setting is not consulted — it
|
|
400
|
+
governs a DSH catalog route billed as tokens, not a Codex model id under the CLI's own subscription.
|
|
401
|
+
|
|
402
|
+
**Background runs report progress.** `run_in_background` appends the child's completed commands, file changes,
|
|
403
|
+
and `commentary` messages to the job's output ring, so `job_output` shows how a long delegation is going.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ckanner
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|