sortie-dogs 0.13.8 → 0.13.10

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 (58) hide show
  1. package/.agents/skills/sortie-dogs/SKILL.md +59 -0
  2. package/.agents/skills/sortie-dogs/agents/openai.yaml +6 -0
  3. package/.agents/skills/sortie-dogs/sortie-dogs.version +1 -0
  4. package/README.md +240 -8
  5. package/dist/asset-version.d.ts +3 -2
  6. package/dist/asset-version.js +2 -1
  7. package/dist/cli/codex-mission.d.ts +7 -0
  8. package/dist/cli/codex-mission.js +124 -0
  9. package/dist/cli/main.js +96 -0
  10. package/dist/codex/app-server.d.ts +144 -0
  11. package/dist/codex/app-server.js +387 -0
  12. package/dist/codex/mission-session.d.ts +89 -0
  13. package/dist/codex/mission-session.js +622 -0
  14. package/dist/codex/mission-settlement.d.ts +53 -0
  15. package/dist/codex/mission-settlement.js +177 -0
  16. package/dist/codex/mission-shell.d.ts +8 -0
  17. package/dist/codex/mission-shell.js +22 -0
  18. package/dist/codex/mission-telemetry.d.ts +9 -0
  19. package/dist/codex/mission-telemetry.js +37 -0
  20. package/dist/codex/protected-evidence.d.ts +27 -0
  21. package/dist/codex/protected-evidence.js +77 -0
  22. package/dist/codex/run-mission.d.ts +28 -0
  23. package/dist/codex/run-mission.js +310 -0
  24. package/dist/codex/skill-assets.d.ts +2 -0
  25. package/dist/codex/skill-assets.js +27 -0
  26. package/dist/core/durable-scope-root.d.ts +2 -0
  27. package/dist/core/durable-scope-root.js +43 -0
  28. package/dist/core/goal-bound.d.ts +10 -0
  29. package/dist/core/goal-bound.js +5 -0
  30. package/dist/core/initialize.d.ts +2 -0
  31. package/dist/core/initialize.js +15 -0
  32. package/dist/core/observed-goal-evidence.d.ts +1 -1
  33. package/dist/core/operator-mission.d.ts +74 -1
  34. package/dist/core/operator-mission.js +139 -9
  35. package/dist/core/operator-runtime.d.ts +6 -0
  36. package/dist/core/operator-runtime.js +45 -1
  37. package/dist/core/validation-budget.d.ts +1 -0
  38. package/dist/core/worktree-scope.js +1 -1
  39. package/dist/index.d.ts +11 -1
  40. package/dist/index.js +6 -1
  41. package/dist/plugin/index.d.ts +3 -0
  42. package/dist/plugin/index.js +33 -62
  43. package/dist/plugin/mission-review.d.ts +10 -6
  44. package/dist/plugin/mission-review.js +31 -18
  45. package/dist/plugin/profiled.d.ts +2 -1
  46. package/dist/plugin/profiled.js +145 -39
  47. package/dist/plugin/run-metrics.d.ts +1 -1
  48. package/dist/plugin/run-metrics.js +17 -6
  49. package/dist/plugin/runtime-bridge.d.ts +4 -1
  50. package/dist/plugin/sortie-debrief.js +3 -0
  51. package/dist/plugin/tool-schema.d.ts +4 -0
  52. package/dist/plugin/tool-schema.js +58 -0
  53. package/dist/plugin/v2-session-history.d.ts +2 -0
  54. package/dist/plugin/v2-session-history.js +5 -0
  55. package/dist/plugin/v2.d.ts +1 -0
  56. package/dist/plugin/v2.js +5 -59
  57. package/dist/runtime-mission-assets.js +3 -1
  58. package/package.json +3 -2
@@ -0,0 +1,59 @@
1
+ ---
2
+ name: sortie-dogs
3
+ description: Run a task through the installed Sortie-dogs Codex Mission adapter when the user explicitly invokes $sortie-dogs. Preserve the existing Mission ledger and keep OpenCode configuration separate.
4
+ ---
5
+
6
+ # Sortie-dogs
7
+
8
+ Treat the user's text accompanying `$sortie-dogs` as the Mission request. If no task was supplied, ask for it and stop.
9
+
10
+ ## Boundaries
11
+
12
+ - Use the reviewed, locally installed `sortie-dogs` package. Never install or update a package, use `@latest`, publish, or switch authentication as part of invocation.
13
+ - Require the existing Codex CLI ChatGPT authentication. Do not use an API key or metered API fallback.
14
+ - Do not run `sortie-dogs init`; that command configures OpenCode. This skill uses only `sortie-dogs codex ...` and never edits `.opencode`.
15
+ - Do not create another ledger. The Codex adapter must reuse Sortie's existing Mission state, protected evidence, and scope leases.
16
+ - After starting a child Mission, observe it; do not edit the same project concurrently from the parent Codex chat.
17
+ - Preserve the user's authority boundaries. Invocation does not authorize push, publication, dependency installation, broader permissions, or unrelated changes.
18
+
19
+ ## Resolve the local entrypoint
20
+
21
+ Prefer `npx --no-install sortie-dogs` when the current project has the package installed. In the Sortie-dogs source repository itself, use `node dist/cli/main.js` after the repository's normal build when needed. Do not resolve a missing command from the network.
22
+
23
+ Check the selected entrypoint with `<entrypoint> codex --help` before starting work. If the packaged command lacks `codex mission` and `codex run`, report that the installed candidate is too old.
24
+
25
+ ## Choose one route
26
+
27
+ Use the natural-language Mission route on POSIX and Windows:
28
+
29
+ ```text
30
+ <entrypoint> codex mission --project-root <repository-root> --prompt <exact-user-request>
31
+ ```
32
+
33
+ Forward `--model`, `--effort`, or `--permissions` only when the user selected those values. Never silently widen the native permission profile. If an existing Mission is reported, resume only its exact root with `--resume`; do not launch replacement work.
34
+
35
+ Leave `--model` unset to retain role-specific defaults: Sol 6.1 Operator/Coordinator/Reviewer and Luna-fast Worker. The Codex adapter maps the shared Luna-fast alias to native `gpt-6-luna` plus the `priority` (Fast) service tier; it does not alter OpenCode defaults. Fast consumes subscription limits faster than Standard; no metered API fallback is allowed.
36
+
37
+ On Windows the same Mission command resolves existing PowerShell 7 automatically. Add `--trusted-pwsh <absolute-pwsh.exe>` only when an exact existing executable needs to be selected; do not add a separate shell preflight or approval step.
38
+
39
+ The compatibility tool named `bash` executes PowerShell commands on Windows and POSIX bash on POSIX. Do not supply POSIX commands to the Windows shell. Shell and file commands still use the configured native permissions, or an explicitly integrated host executor. A sandbox startup failure is not a validation failure or success: preserve the failed execution and report the environment blocker; do not widen permissions or stop unrelated Codex processes.
40
+
41
+ Use the manifest-bound `codex run` route only for an explicitly selected single-task manifest workflow. It is not the full multi-role Mission route:
42
+
43
+ 1. Read repository instructions and inspect only enough to identify bounded project-relative read scope, write scope, and meaningful validation commands.
44
+ 2. Create one temporary manifest under `.sortie-dogs/codex-skill/` with `version`, `task_id`, `read`, `write`, and non-empty `validation`. Reject external or uncertain write scope instead of broadening it.
45
+ 3. On Windows the manifest workflow needs the exact PowerShell executable for command-envelope observation. Resolve it with `(Get-Command pwsh.exe -ErrorAction Stop).Source`, then invoke:
46
+
47
+ ```text
48
+ <entrypoint> codex run --project-root <repository-root> --manifest <temporary-manifest> --prompt <exact-user-request> --trusted-pwsh <resolved-pwsh.exe>
49
+ ```
50
+
51
+ 4. Remove only the temporary manifest created by this invocation after the command reaches a terminal result. Preserve `.git/sortie-dogs` evidence and any other state.
52
+
53
+ If no defensible validation or bounded write scope can be derived, explain the missing contract and stop without starting Codex.
54
+
55
+ ## Completion
56
+
57
+ Treat only Mission acceptance or manifest settlement `succeeded` with admitted validation evidence as success. A completed native turn, model prose, or validation exit zero without admitted evidence is not completion.
58
+
59
+ Report the route, terminal status, root/thread identity, validation evidence count, changed paths, and any explicit remaining boundary. Subscription monetary cost is unavailable unless the host supplies it; never fabricate one.
@@ -0,0 +1,6 @@
1
+ interface:
2
+ display_name: "Sortie-dogs"
3
+ short_description: "Run a verified Sortie Mission through Codex"
4
+ default_prompt: "Use $sortie-dogs to execute and verify this task through the existing Mission workflow."
5
+ policy:
6
+ allow_implicit_invocation: false
@@ -0,0 +1 @@
1
+ 0.13.10-codex-skill-v2
package/README.md CHANGED
@@ -35,10 +35,10 @@ implementation, validation, review, and model routing.
35
35
  Guides: [日本語](docs/guide-ja.md) · [简体中文](docs/guide-zh-CN.md) ·
36
36
  [Testing](docs/testing.md) · [CLI testing](docs/cli-testing.md)
37
37
 
38
- **Current release: [v0.13.8](https://github.com/zufall-upon/Sortie-dogs/releases/tag/v0.13.8)**
39
- ([release notes](docs/release-v0.13.8.md)). The default Mission runtime retains the `v010`
38
+ **Current release: [v0.13.10](https://github.com/zufall-upon/Sortie-dogs/releases/tag/v0.13.10)**
39
+ ([release notes](docs/release-v0.13.10.md)). The default Mission runtime retains the `v010`
40
40
  profile, command and configuration names for compatibility; these names do not mean v0.10 is installed.
41
- The current asset marker is `0.13.8-native-binding-v1`.
41
+ The current asset marker is `0.13.10-codex-windows-v1`.
42
42
 
43
43
  ## SWE-bench Lite: 170/300 (56.67%)
44
44
 
@@ -48,7 +48,7 @@ The fixed **Sortie-dogs v0.12.24** harness resolved **170 of 300 SWE-bench Lite
48
48
 
49
49
  The single official 300-instance report and frozen predictions are hash-bound in the report. Confirmed inference expense was **$162.99**; a separate **$34.60** of usage has unknown pricing and is held against the campaign cap, **not** counted as known expense. Leaderboard registration and maintainer acceptance are separate from this official local evaluation.
50
50
 
51
- Historical scores below belong to their fixed candidates, not v0.13.8. SWE-bench is a separate,
51
+ Historical scores below belong to their fixed candidates, not v0.13.10. SWE-bench is a separate,
52
52
  optional measurement rather than a mandatory release gate.
53
53
 
54
54
  > **Beta:** v0.13.x is still stabilizing. Runtime behavior,
@@ -56,7 +56,217 @@ optional measurement rather than a mandatory release gate.
56
56
 
57
57
  ## Quick start
58
58
 
59
- Requirements: Node.js 22.6 or newer, npm, and OpenCode V2.
59
+ ### Codex host adapter (experimental)
60
+
61
+ Choose this route for Codex; OpenCode is not required and **do not run `sortie-dogs init` for it**.
62
+ Use Node.js 22.6 or newer and an existing Codex CLI with ChatGPT authentication. Ubuntu validation
63
+ used Node.js 22.22.1 and Codex 0.160.1. Sortie neither installs Codex nor starts a login flow, copies
64
+ credentials, or creates a second host configuration. Mission execution refuses non-ChatGPT auth.
65
+
66
+ The Codex Mission adapter and explicit skill are included in v0.13.10. Install the release in the
67
+ target project and inspect the entrypoint before running a prompt:
68
+
69
+ ```sh
70
+ npm install --save-dev sortie-dogs@0.13.10
71
+ npx --no-install sortie-dogs codex init .
72
+ npx --no-install sortie-dogs codex mission --help
73
+ ```
74
+
75
+ For an unpublished development candidate, a maintainer with checkout dependencies already present
76
+ can produce a local tarball with `npm pack` (build included) and install that tarball instead.
77
+ This does not publish it. Use the same installed version for the CLI and SDK below.
78
+ `codex init` installs only `.agents/skills/sortie-dogs`; it does not create or edit `.opencode`.
79
+ It refuses to overwrite a skill whose ownership cannot be established.
80
+
81
+ After restarting Codex or opening the project in a new chat, invoke the installed skill explicitly:
82
+
83
+ ```text
84
+ $sortie-dogs Implement and verify the requested change
85
+ ```
86
+
87
+ `$sortie-dogs` is the current direct Skills syntax. Codex does not expose arbitrary custom commands
88
+ as exact `/sortie-dogs` slash commands; `/skills` opens the skill picker. The skill is intentionally
89
+ explicit-only so child Codex Mission turns cannot invoke another Sortie Mission recursively.
90
+ On POSIX and Windows it selects the natural-language, multi-role Mission route below.
91
+ Windows uses existing PowerShell 7; it does not route natural-language Missions through the
92
+ single-task `codex run` manifest workflow. That workflow remains available when explicitly selected
93
+ and retains its post-execution observation boundary, not a pre-execution guard.
94
+
95
+ Sortie-dogs also exports a host adapter for the official Codex app-server stdio protocol. This is
96
+ separate from selecting an OpenAI model through OpenCode: OpenCode model routing still uses the
97
+ OpenCode host, while `CodexAppServerHost` starts and observes native Codex threads and turns.
98
+
99
+ ```ts
100
+ import { CodexAppServerHost, createCodexAppServerTransport } from "sortie-dogs";
101
+
102
+ const transport = createCodexAppServerTransport({ executable: "codex" });
103
+ const host = new CodexAppServerHost(transport);
104
+ const threadID = await host.startThread({ cwd: process.cwd(), ephemeral: true });
105
+ const result = await host.runTurn(threadID, "Implement the admitted unit.", {
106
+ cwd: process.cwd(),
107
+ approvalPolicy: "unlessTrusted",
108
+ sandboxPolicy: {
109
+ type: "workspaceWrite",
110
+ writableRoots: [process.cwd()],
111
+ networkAccess: false,
112
+ },
113
+ });
114
+ await host.close();
115
+ ```
116
+
117
+ The adapter reuses Sortie's host-neutral core instead of copying its goal, acceptance, evidence, or
118
+ ledger implementation. It exposes completed Codex items as authoritative observations, supports
119
+ exact persisted-thread resume and turn interruption (ephemeral threads have no resumable rollout), and declines command/file approvals unless the caller
120
+ provides an approval handler. Permission-subset requests receive an empty grant unless the caller
121
+ connects `permissionsApproval`; approved responses are limited to the native request. Unsupported
122
+ server-initiated requests fail closed.
123
+
124
+ For the existing Operator → Coordinator → Worker → Reviewer Mission workflow, use:
125
+
126
+ ```sh
127
+ npx --no-install sortie-dogs codex mission --prompt "Implement and review the requested change"
128
+ ```
129
+
130
+ The equivalent public SDK entrypoint is:
131
+
132
+ ```ts
133
+ import { CodexMissionSession } from "sortie-dogs";
134
+
135
+ const mission = await CodexMissionSession.create({
136
+ projectRoot: process.cwd(),
137
+ // Leave model/effort unset to preserve packaged role defaults.
138
+ // model: "gpt-6.1-sol", effort: "medium", // Explicit override for every role.
139
+ // trustedPowerShellExecutable: "C:/Program Files/PowerShell/7/pwsh.exe", // Windows, optional.
140
+ // resumeThreadID: "saved-root-thread-id", // Continue the same Mission when needed.
141
+ });
142
+ try {
143
+ const result = await mission.run("Implement and review the requested change");
144
+ console.log(JSON.stringify(result));
145
+ process.exitCode = result.accepted ? 0 : 1;
146
+ } finally {
147
+ await mission.close();
148
+ }
149
+ ```
150
+
151
+ This route uses `CodexMissionSession` and the existing Mission tools, correction grants,
152
+ validation evidence, and final Operator acceptance. It runs saved native Codex threads with existing
153
+ ChatGPT authentication; it does not import OpenCode settings or introduce a second Mission ledger.
154
+ Commands run through `/bin/bash` on POSIX or existing `pwsh.exe -NoProfile -NonInteractive -Command`
155
+ on Windows, using the native app-server's configured permissions. The compatibility tool remains
156
+ named `bash`, but its Windows input must be PowerShell syntax. Windows callers can pin an absolute
157
+ PowerShell 7 path with SDK `trustedPowerShellExecutable` or CLI `--trusted-pwsh`.
158
+ Packaged roles retain Sol 6.1/xhigh for Operator, Coordinator and Reviewer. The shared Luna-fast/max
159
+ Worker alias maps only in Codex to native `gpt-6-luna`/max plus `serviceTier: "priority"` (Fast).
160
+ OpenCode routing is unchanged. Fast uses subscription limits faster than Standard; no metered API
161
+ fallback is introduced. CLI progress exposes each role's native model, effort and separate service tier.
162
+ Sortie does not
163
+ replace them with a fixed repository-only or network-disabled policy, change host configuration, or select
164
+ full access. Thread turns retain native thread permissions; standalone `command/exec` uses the server's
165
+ configured policy, not a thread's temporary grants. A parent application's in-memory approval is not
166
+ automatically transferred to a separately launched app-server.
167
+ Windows recovery can reclaim a killed adapter only when its recorded Windows PID is absent.
168
+ A live/reused PID, access denial, legacy owner without platform identity, or unresolved native
169
+ execution remains unknown; no command is replayed. Sandbox startup errors must be resolved at the
170
+ native host, not by silently widening Sortie's permissions or stopping unrelated Codex processes.
171
+ SDK hosts can forward native command/file approval requests through `approval` and permission-subset
172
+ requests through `permissionsApproval`. The native host remains responsible for deciding and enforcing
173
+ the grant. The CLI reports approval requests but has no interactive approval bridge; without a connected
174
+ host callback, no grant is returned. `command/exec` has no thread-scoped approval API, so inheriting the
175
+ configured policy does not add an escalation path for these standalone commands.
176
+ Use SDK `permissions` or CLI `--permissions <native-profile>` only to explicitly select an existing
177
+ native profile for thread start/resume and standalone commands. Omission retains native defaults,
178
+ which may be read-only. Invalid or disallowed profiles fail through the native server without fallback;
179
+ no configuration file is changed. Low-level `CodexAppServerHost` callers must opt into
180
+ `experimentalApi: true` for profile APIs; Mission sessions already negotiate that capability. Progress reports the effective native profile, sandbox and approval
181
+ routing. This selection does not configure a delegated parent-host executor's own permissions.
182
+ See [Ubuntu acceptance evidence and remaining work](docs/codex-mission-acceptance-20261006.md).
183
+
184
+ For a parent application with an existing approval-aware executor, pass the optional SDK
185
+ `executeCommand` callback. It receives the exact post-hook argv, cwd, timeout, thread/turn/call identity,
186
+ and an AbortSignal for bash/read/write operations. The parent owns approval and execution; Sortie does
187
+ not infer a grant from prompt text or create another permission store. Return `completed` only after
188
+ execution ends, with the real integer exitCode, stdout and stderr. Approval alone is not a result.
189
+ `denied` and `not-started` explicitly mean nothing ran and create no validation exit. `interrupted`,
190
+ `unknown`, exceptions and invalid results retain unknown execution and stop resends. The host owns
191
+ command timeout enforcement; Sortie does not add a separate deadline to its approval interaction.
192
+ Closing the adapter signals cancellation; late callback results cannot establish validation, and the
193
+ host must reconcile any still-running process. Omission keeps native `command/exec`; a connected
194
+ executor never falls back to native execution after rejection or failure. Existing Mission before/after
195
+ hooks, command identity and validation acceptance remain shared. CLI progress identifies the selected
196
+ executor; the CLI itself does not attach a parent executor.
197
+ The bash tool accepts `workdir` (absolute or relative to the project root). The shared hooks and both
198
+ executors use that directory; progress and receipts include the effective cwd. A successful command in
199
+ another directory does not satisfy a validation declared for the project root.
200
+
201
+ Packaged role models and reasoning levels apply by default. `--model` and `--effort` explicitly
202
+ override all roles; SDK callers can use `roleModels` for individual roles. Unsupported native model
203
+ names fail rather than silently selecting another model. Availability depends on the signed-in account.
204
+
205
+ Use `--resume <root-thread-id>` to continue a saved Mission root. Without it, a single unfinished Codex
206
+ Mission in this repository is selected automatically; multiple unfinished roots require an explicit
207
+ selection. Resume restores native messages and tool evidence, including child sessions. Completed native
208
+ receipts feed the existing reservation reconciliation without replaying tool execution. A new Task stopped
209
+ before child binding can be recovered when the exact terminal parent thread/turn/call/input matches and
210
+ the prior adapter is closed or its Linux process identity proves it is gone. The host retains that proof in
211
+ the existing Mission and reconciles the reservation before another model prompt; repeated recovery does
212
+ not settle it again. Concurrent recovery claims are serialized.
213
+
214
+ A newly created ordinary Worker also saves its exact dispatch binding before the child prompt is sent.
215
+ If its parent Task result is lost, recovery can match that binding to the child's single, fully loaded,
216
+ completed native turn. The initial recovery path supports leaf Workers only: later turns, nested Tasks,
217
+ untracked native children, missing bindings and ambiguous identities remain unknown. Recovery restores
218
+ execution completion for the existing settlement path; missing validation evidence is a process defect,
219
+ not an invented PASS. It does not rerun the implementation. Continue with only the work or validation
220
+ still needed for normal Operator acceptance.
221
+
222
+ SIGINT/SIGTERM closes the adapter and exits 130/143. Bound children without an exact completed dispatch,
223
+ and commands sent without a saved terminal receipt, remain unknown and are not resent. App-server exit
224
+ does not prove an external command has stopped. Linux process-death checks do not prove external writer
225
+ quiescence either; other platforms require a clean adapter close for automatic prelaunch recovery.
226
+ Inspect the original executor before recovery; do not delete Mission state to force a retry.
227
+ Per-session usage is native thread cumulative usage (including earlier turns), not a Mission total;
228
+ monetary cost is unavailable and reported as `null`.
229
+ The existing Mission report uses observed per-turn token deltas and execution times. Cache and reasoning
230
+ subtotals are counted once. Its pre-terminal snapshot excludes final-answer generation, while final JSON
231
+ retains native thread totals. Terminal accounting observations survive cold reload in the existing Mission;
232
+ missing baselines remain unavailable. Native turn aggregates do not establish model-request counts, API
233
+ costs or remaining subscription allowance, so these values are not inferred.
234
+ CLI exit 0 means Operator acceptance; exit 1 means incomplete work or an execution error; exit 2
235
+ means invalid arguments. A native turn completing alone is not acceptance.
236
+ The CLI writes bounded progress records to stderr: tool start/completion, commands and exit codes,
237
+ replan reasons, next actions, child identity, and public model commentary. Final JSON remains on stdout.
238
+
239
+ For a manifest-bound mission, use the SDK `runCodexMission(...)` or the CLI:
240
+
241
+ ```sh
242
+ sortie-dogs codex run --manifest operation-manifest.json --prompt "Implement the requested change"
243
+ ```
244
+
245
+ The operation manifest remains required. The mission runner reuses Sortie's existing goal ledger,
246
+ protected evidence capture, settlement, and repository-wide scope leases. It does not emulate
247
+ OpenCode plugin hooks, install Codex assets, switch models implicitly, or copy/import/modify OpenCode
248
+ settings and sessions. Codex command and file events are post-execution observations, not a claimed
249
+ pre-execution write guard. The stdio transport is the supported initial integration; experimental
250
+ WebSocket transport is intentionally out of scope.
251
+
252
+ The manifest-run CLI handles SIGINT/SIGTERM by requesting interruption and cleaning up its
253
+ app-server (exit 130/143). SDK callers can pass an `AbortSignal` as `signal`. Before
254
+ turn dispatch, cancellation settles the reservation and releases its lease. After
255
+ dispatch, app-server exit or an interrupt acknowledgement does not prove that an
256
+ externally hosted command stopped. Cancellation or transport loss therefore preserves
257
+ the active goal/reservation as an unknown outcome and stops lease heartbeats without
258
+ claiming completion. SIGKILL can leave the same unresolved state.
259
+
260
+ Lease expiry alone does not authorize a retry: subsequent Codex missions refuse with
261
+ `codex-mission-outcome-unknown:no-resend` and the ledger path, including across
262
+ stable/v010 profiles. Inspect the prior worker and ledger before recovery; do not
263
+ delete the ledger or automatically resend the prompt. This is a Codex admission
264
+ check; it does not establish quiescence of external command executors.
265
+
266
+ ### OpenCode plugin
267
+
268
+ Requirements: Node.js 22.6 or newer, npm, and OpenCode V2. These installation and `init` steps
269
+ configure the OpenCode route; they are not prerequisites for the Codex route above.
60
270
 
61
271
  Run these commands in the target project:
62
272
 
@@ -93,6 +303,28 @@ existing local bridge loads enforcement and model routing. OpenCode can reload w
93
303
  but replacing an installed dependency may require a full restart. A new chat session alone does not
94
304
  prove the newly installed plugin is loaded.
95
305
 
306
+ ## v0.13.10 runtime updates
307
+
308
+ PR #169 connects natural-language Windows Codex Missions to the same multi-role lifecycle using
309
+ existing PowerShell 7, preserves command failure exits and native resume settings, and maps the
310
+ Luna-fast Worker alias to native Luna/max with the separate priority tier. Directory reads list
311
+ direct entries instead of requiring filename guesses. OpenCode model settings and native permission
312
+ profiles remain unchanged. PR #168 provides one host-aware Anko runner, reuses unchanged setup,
313
+ removes mandatory paid diagnostic probes, and preserves prior attempts, unknown usage and service
314
+ evidence. Its recorded v0.13.9 Anko completion and PR #169's Windows Codex host-executor completion
315
+ are historical fixed-candidate observations, not new v0.13.10 benchmark or native sandbox results.
316
+ See [release notes](docs/release-v0.13.10.md).
317
+
318
+ ## v0.13.9 runtime updates (retained)
319
+
320
+ PRs #163–#166 connect native Codex sessions to the existing Mission lifecycle, add the explicit
321
+ `$sortie-dogs` skill and `codex init`, restore operation Reviewer correction within existing write
322
+ scope, and reconcile native terminal observations without reviving completed work from delayed events.
323
+ Codex settings and authentication remain separate from OpenCode. Real Ubuntu Codex acceptance
324
+ evidence and host-specific limits remain in [the acceptance record](docs/codex-mission-acceptance-20261006.md);
325
+ they are not a new all-host or performance benchmark. Release CLI proof observes actual OpenCode
326
+ Worker startup and model identity only, not Mission completion. See [release notes](docs/release-v0.13.9.md).
327
+
96
328
  ## v0.13.8 runtime updates
97
329
 
98
330
  PR #161 captures native validation bindings through the readable resolved target of a Windows
@@ -448,7 +680,7 @@ register stable and `v010` from the same package installation path in one host.
448
680
  Project-local installation is recommended. To expose the current Mission assets globally:
449
681
 
450
682
  ```sh
451
- npm install --global sortie-dogs@0.13.8
683
+ npm install --global sortie-dogs@0.13.10
452
684
  sortie-dogs init --global --profile v010
453
685
  ```
454
686
 
@@ -460,7 +692,7 @@ can resolve a **separate dependency** under that config root. Updating npm-globa
460
692
  it. For that layout, also install the same release at the actual config root, then rerun global init:
461
693
 
462
694
  ```sh
463
- npm install --prefix "$HOME/.config/opencode" sortie-dogs@0.13.8
695
+ npm install --prefix "$HOME/.config/opencode" sortie-dogs@0.13.10
464
696
  sortie-dogs init --global --profile v010
465
697
  ```
466
698
 
@@ -483,7 +715,7 @@ version, preserves user configuration, and stops safely on unknown ownership or
483
715
  conflicting files.
484
716
 
485
717
  Align any exact version pin or separate bridge dependency with the intended release too. An installed
486
- marker of `0.13.8-native-binding-v1` identifies the assets; it does not prove an already-running
718
+ marker of `0.13.10-codex-windows-v1` identifies the assets; it does not prove an already-running
487
719
  OpenCode process has reloaded the plugin.
488
720
 
489
721
  There is no supported uninstall command. Remove the npm dependency separately,
@@ -3,5 +3,6 @@
3
3
  * installed project marker without importing every asset body.
4
4
  */
5
5
  export declare const RUNTIME_ASSET_VERSION = "0.3.89-completion-proof-v1";
6
- export declare const V010_RUNTIME_ASSET_VERSION = "0.13.8-native-binding-v1";
7
- export type RuntimeAssetVersion = typeof RUNTIME_ASSET_VERSION | typeof V010_RUNTIME_ASSET_VERSION;
6
+ export declare const V010_RUNTIME_ASSET_VERSION = "0.13.10-codex-windows-v1";
7
+ export declare const CODEX_SKILL_ASSET_VERSION = "0.13.10-codex-skill-v2";
8
+ export type RuntimeAssetVersion = typeof RUNTIME_ASSET_VERSION | typeof V010_RUNTIME_ASSET_VERSION | typeof CODEX_SKILL_ASSET_VERSION;
@@ -3,4 +3,5 @@
3
3
  * installed project marker without importing every asset body.
4
4
  */
5
5
  export const RUNTIME_ASSET_VERSION = "0.3.89-completion-proof-v1";
6
- export const V010_RUNTIME_ASSET_VERSION = "0.13.8-native-binding-v1";
6
+ export const V010_RUNTIME_ASSET_VERSION = "0.13.10-codex-windows-v1";
7
+ export const CODEX_SKILL_ASSET_VERSION = "0.13.10-codex-skill-v2";
@@ -0,0 +1,7 @@
1
+ import type { CodexTurnEvent } from "../codex/app-server.js";
2
+ export declare const CODEX_MISSION_USAGE = "Usage: sortie-dogs codex mission --prompt <text>\n [--resume <root-thread-id>] [--project-root <path>] [--executable <codex>] [--model <model>] [--effort <effort>] [--permissions <native-profile>] [--trusted-pwsh <absolute-pwsh.exe>]\n\nRuns the existing Mission Operator, Coordinator, Worker and Reviewer through Codex.\n--model and --effort explicitly override all roles; otherwise packaged role defaults apply.\n--permissions explicitly selects an existing native profile; omission retains native defaults.\nWindows uses existing PowerShell 7; --trusted-pwsh pins its absolute executable path.\nThe packaged Luna-fast worker maps to native gpt-6-luna with the priority (Fast) service tier.\nUses existing ChatGPT authentication and native Codex permissions.";
3
+ export declare function runCodexMissionCommand(argv: readonly string[]): Promise<number>;
4
+ /** Bounded user-facing progress; do not dump control packets or hidden reasoning. */
5
+ export declare function codexMissionProgress(event: CodexTurnEvent & {
6
+ threadId: string;
7
+ }): Record<string, unknown> | undefined;
@@ -0,0 +1,124 @@
1
+ import { CodexMissionSession } from "../codex/mission-session.js";
2
+ export const CODEX_MISSION_USAGE = `Usage: sortie-dogs codex mission --prompt <text>
3
+ [--resume <root-thread-id>] [--project-root <path>] [--executable <codex>] [--model <model>] [--effort <effort>] [--permissions <native-profile>] [--trusted-pwsh <absolute-pwsh.exe>]
4
+
5
+ Runs the existing Mission Operator, Coordinator, Worker and Reviewer through Codex.
6
+ --model and --effort explicitly override all roles; otherwise packaged role defaults apply.
7
+ --permissions explicitly selects an existing native profile; omission retains native defaults.
8
+ Windows uses existing PowerShell 7; --trusted-pwsh pins its absolute executable path.
9
+ The packaged Luna-fast worker maps to native gpt-6-luna with the priority (Fast) service tier.
10
+ Uses existing ChatGPT authentication and native Codex permissions.`;
11
+ export async function runCodexMissionCommand(argv) {
12
+ if (argv.length === 1 && argv[0] === "--help") {
13
+ process.stdout.write(`${CODEX_MISSION_USAGE}\n`);
14
+ return 0;
15
+ }
16
+ const values = new Map();
17
+ const allowed = new Set(["--prompt", "--resume", "--project-root", "--executable", "--model", "--effort", "--permissions", "--trusted-pwsh"]);
18
+ for (let index = 0; index < argv.length; index += 2) {
19
+ const key = argv[index], value = argv[index + 1];
20
+ if (!key || !allowed.has(key) || !value || value.startsWith("--") || values.has(key)) {
21
+ process.stderr.write(`${CODEX_MISSION_USAGE}\n`);
22
+ return 2;
23
+ }
24
+ values.set(key, value);
25
+ }
26
+ const prompt = values.get("--prompt");
27
+ if (!prompt) {
28
+ process.stderr.write(`${CODEX_MISSION_USAGE}\n`);
29
+ return 2;
30
+ }
31
+ let adapter;
32
+ let signalExit;
33
+ const stop = (exit) => { signalExit ??= exit; void adapter?.close().catch(() => undefined); };
34
+ const onTerm = () => stop(143), onInt = () => stop(130);
35
+ process.on("SIGTERM", onTerm);
36
+ process.on("SIGINT", onInt);
37
+ try {
38
+ adapter = await CodexMissionSession.create({ projectRoot: values.get("--project-root") ?? process.cwd(),
39
+ resumeThreadID: values.get("--resume"), permissions: values.get("--permissions"), executable: values.get("--executable"), model: values.get("--model"), effort: values.get("--effort"),
40
+ trustedPowerShellExecutable: values.get("--trusted-pwsh"), onEvent: event => {
41
+ const progress = codexMissionProgress(event);
42
+ if (progress)
43
+ process.stderr.write(`${JSON.stringify(progress)}\n`);
44
+ } });
45
+ if (signalExit)
46
+ return signalExit;
47
+ const result = await adapter.run(prompt);
48
+ process.stdout.write(`${JSON.stringify({ status: result.accepted ? "succeeded" : "incomplete", root_session_id: result.rootSessionID,
49
+ thread_id: result.turn.threadID, turn_id: result.turn.turnID, native_status: result.turn.status,
50
+ response: result.turn.finalResponse, sessions: result.sessions, cost: null })}\n`);
51
+ return signalExit ?? (result.accepted ? 0 : 1);
52
+ }
53
+ catch (error) {
54
+ process.stderr.write(`${error instanceof Error ? error.message : "codex-mission-failed"}\n`);
55
+ return signalExit ?? 1;
56
+ }
57
+ finally {
58
+ try {
59
+ await adapter?.close();
60
+ }
61
+ finally {
62
+ process.off("SIGTERM", onTerm);
63
+ process.off("SIGINT", onInt);
64
+ }
65
+ }
66
+ }
67
+ /** Bounded user-facing progress; do not dump control packets or hidden reasoning. */
68
+ export function codexMissionProgress(event) {
69
+ if (event.method === "sortie/modelRoute")
70
+ return { thread_id: event.threadId, phase: "model-route", agent: event.params.agent, model: event.params.model,
71
+ effort: event.params.effort, service_tier: event.params.serviceTier };
72
+ if (event.method === "sortie/permissions")
73
+ return { thread_id: event.threadId, phase: "permissions", requested_profile: event.params.requestedProfile,
74
+ effective_profile: event.params.profile, sandbox: event.params.sandbox, network_access: event.params.networkAccess,
75
+ approval_policy: event.params.approvalPolicy, approvals_reviewer: event.params.approvalsReviewer,
76
+ command_executor: event.params.commandExecutor };
77
+ if (event.method === "sortie/commandExecution")
78
+ return { thread_id: event.threadId, turn_id: event.params.turnId, call_id: event.params.callId,
79
+ tool: event.params.tool, executor: event.params.executor, cwd: event.params.cwd, phase: event.params.status,
80
+ detail: typeof event.params.reason === "string" ? event.params.reason.slice(0, 1600) : undefined };
81
+ if (["item/commandExecution/requestApproval", "item/fileChange/requestApproval", "item/permissions/requestApproval"].includes(event.method))
82
+ return { thread_id: event.threadId, turn_id: event.params.turnId, phase: "approval-required", method: event.method,
83
+ reason: typeof event.params.reason === "string" ? event.params.reason.slice(0, 1600) : undefined,
84
+ command: typeof event.params.command === "string" ? event.params.command.slice(0, 1600) : undefined,
85
+ item_id: event.params.itemId, host_approval_available: event.params.hostApprovalAvailable === true,
86
+ next_action: event.params.hostApprovalAvailable === true ? "Await the host approval decision." :
87
+ "No host approval callback is connected; this request receives no grant. Use a host-integrated SDK client for approval." };
88
+ if (!["item/started", "item/completed"].includes(event.method))
89
+ return;
90
+ const item = event.params.item;
91
+ if (event.method === "item/completed" && item?.type === "agentMessage" && item.phase === "commentary" && typeof item.text === "string")
92
+ return { thread_id: event.threadId, turn_id: event.params.turnId, phase: "commentary", text: item.text.slice(0, 1600) };
93
+ if (item?.type !== "dynamicToolCall")
94
+ return;
95
+ const record = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
96
+ const bounded = (value) => typeof value === "string" ? value.slice(0, 1600) : undefined;
97
+ const args = record(item.arguments) ? item.arguments : {};
98
+ let receipt = {};
99
+ const contents = Array.isArray(item.contentItems) ? item.contentItems : [];
100
+ const text = contents.find(part => record(part) && part.type === "inputText")?.text;
101
+ try {
102
+ const parsed = JSON.parse(String(text));
103
+ if (record(parsed))
104
+ receipt = parsed;
105
+ }
106
+ catch { /* Plain native failure. */ }
107
+ if (typeof receipt.output === "string") {
108
+ try {
109
+ const nested = JSON.parse(receipt.output);
110
+ if (record(nested))
111
+ receipt = { ...nested, ...receipt };
112
+ }
113
+ catch { /* Ordinary command output. */ }
114
+ }
115
+ const metadata = record(receipt.metadata) ? receipt.metadata : {};
116
+ return { thread_id: event.threadId, turn_id: event.params.turnId, tool: item.tool,
117
+ phase: event.method === "item/started" ? "started" : "completed", status: item.status, success: item.success,
118
+ command: bounded(args.command), workdir: bounded(args.workdir), cwd: bounded(metadata.cwd), reason: bounded(args.reason),
119
+ agent: bounded(args.subagent_type), description: bounded(args.description), child_session_id: bounded(metadata.sessionId),
120
+ outcome: bounded(receipt.status), exit: metadata.exit, executor: metadata.executor,
121
+ next_action: bounded(receipt.next_action),
122
+ summary: bounded(args.summary ?? receipt.summary),
123
+ detail: bounded(receipt.reason ?? receipt.error ?? (item.success === false ? text : undefined)) };
124
+ }
package/dist/cli/main.js CHANGED
@@ -32,6 +32,19 @@ const USAGE = `Usage: sortie-dogs lint <handoff.json> [<handoff.json> ...]
32
32
  const INIT_USAGE = `Usage: sortie-dogs init [project-root] [--profile stable|v010]
33
33
  sortie-dogs init --global [--profile stable|v010]
34
34
  This beta package defaults to the v010 profile.`;
35
+ const CODEX_USAGE = `Natural-language Mission: sortie-dogs codex mission --prompt <text> (mission --help for options)
36
+
37
+ Install the direct Codex skill: sortie-dogs codex init [project-root]
38
+
39
+ Usage: sortie-dogs codex run --manifest <operation-manifest.json> --prompt <text>
40
+ [--project-root <path>] [--executable <codex>] [--model <model>] [--effort <effort>]
41
+ [--trusted-pwsh <absolute-pwsh.exe>] [--profile stable|v010]
42
+
43
+ The operation manifest is required. This command reuses Sortie's goal ledger and
44
+ scope leases; it does not import or modify OpenCode settings or sessions.`;
45
+ const CODEX_INIT_USAGE = `Usage: sortie-dogs codex init [project-root]
46
+
47
+ Installs the explicit $sortie-dogs skill under .agents/skills without modifying OpenCode settings.`;
35
48
  class InputFailure extends Error {
36
49
  safeMessage;
37
50
  constructor(safeMessage) {
@@ -225,6 +238,89 @@ function render(output, format) {
225
238
  return output.map(({ file, pointer, code, severity, message }) => `${file} ${neutralizeTextControlCharacters(pointer || "/")} ${code} ${severity} ${neutralizeTextControlCharacters(message)}\n`).join("");
226
239
  }
227
240
  export async function run(argv) {
241
+ if (argv[0] === "codex") {
242
+ if (argv[1] === "init") {
243
+ if (argv[2] === "--help" && argv.length === 3) {
244
+ process.stdout.write(`${CODEX_INIT_USAGE}\n`);
245
+ return 0;
246
+ }
247
+ if (argv.length > 3 || argv[2]?.startsWith("-")) {
248
+ process.stderr.write(`${CODEX_INIT_USAGE}\n`);
249
+ return 2;
250
+ }
251
+ try {
252
+ const initialized = await initializer.initializeCodexSkill(argv[2]);
253
+ process.stdout.write(initialized.status === "installed"
254
+ ? `Installed the $sortie-dogs Codex skill (${initialized.version}).\n`
255
+ : `The $sortie-dogs Codex skill (${initialized.version}) is already installed.\n`);
256
+ return 0;
257
+ }
258
+ catch (error) {
259
+ process.stderr.write(`${error instanceof Error ? error.message : "codex-skill-init-failed"}\n`);
260
+ return 1;
261
+ }
262
+ }
263
+ if (argv[1] === "mission")
264
+ return (await import("./codex-mission.js")).runCodexMissionCommand(argv.slice(2));
265
+ if (argv.length === 3 && argv[1] === "run" && argv[2] === "--help") {
266
+ process.stdout.write(`${CODEX_USAGE}\n`);
267
+ return 0;
268
+ }
269
+ if (argv[1] === "--help" && argv.length === 2) {
270
+ process.stdout.write(`${CODEX_USAGE}\n`);
271
+ return 0;
272
+ }
273
+ if (argv[1] !== "run") {
274
+ process.stderr.write(`${CODEX_USAGE}\n`);
275
+ return 2;
276
+ }
277
+ const values = new Map();
278
+ const allowed = new Set(["--manifest", "--prompt", "--project-root", "--executable", "--model", "--effort", "--trusted-pwsh", "--profile"]);
279
+ for (let index = 2; index < argv.length; index += 2) {
280
+ const key = argv[index], value = argv[index + 1];
281
+ if (!key || !allowed.has(key) || value === undefined || value.startsWith("--") || values.has(key)) {
282
+ process.stderr.write(`${CODEX_USAGE}\n`);
283
+ return 2;
284
+ }
285
+ values.set(key, value);
286
+ }
287
+ const manifest = values.get("--manifest"), prompt = values.get("--prompt"), profile = values.get("--profile") ?? "stable";
288
+ if (!manifest || !prompt || !["stable", "v010"].includes(profile)) {
289
+ process.stderr.write(`${CODEX_USAGE}\n`);
290
+ return 2;
291
+ }
292
+ const cancellation = new AbortController();
293
+ let signalExit;
294
+ const onTerm = () => { signalExit ??= 143; cancellation.abort(); };
295
+ const onInt = () => { signalExit ??= 130; cancellation.abort(); };
296
+ process.on("SIGTERM", onTerm);
297
+ process.on("SIGINT", onInt);
298
+ try {
299
+ const runner = await import("../codex/run-mission.js");
300
+ const profiles = await import("../core/runtime-profile.js");
301
+ const result = await runner.runCodexMission({ signal: cancellation.signal, projectRoot: values.get("--project-root") ?? process.cwd(), manifestPath: manifest,
302
+ prompt, ...(values.get("--executable") ? { executable: values.get("--executable") } : {}),
303
+ ...(values.get("--model") ? { model: values.get("--model") } : {}),
304
+ ...(values.get("--effort") ? { effort: values.get("--effort") } : {}),
305
+ ...(values.get("--trusted-pwsh") ? { trustedPowerShellExecutable: values.get("--trusted-pwsh") } : {}),
306
+ profile: profile === "stable" ? profiles.STABLE_RUNTIME_PROFILE : profiles.V010_RUNTIME_PROFILE });
307
+ process.stdout.write(`${JSON.stringify({ status: result.settlement.disposition, root_session_id: result.rootSessionID,
308
+ thread_id: result.validation.threadID, turn_id: result.validation.turnID, ledger_path: result.ledgerPath,
309
+ evidence: result.settlement.evidence.length,
310
+ validation_commands: result.validation.items.filter(item => item.type === "commandExecution").map(item => ({
311
+ command: item.command, status: item.status, exit_code: item.exitCode,
312
+ })) })}\n`);
313
+ return signalExit ?? (result.settlement.disposition === "succeeded" ? 0 : 1);
314
+ }
315
+ catch (error) {
316
+ process.stderr.write(`${error instanceof Error ? error.message : "codex-mission-failed"}\n`);
317
+ return signalExit ?? 1;
318
+ }
319
+ finally {
320
+ process.off("SIGTERM", onTerm);
321
+ process.off("SIGINT", onInt);
322
+ }
323
+ }
228
324
  if (argv[0] === "init") {
229
325
  if (argv[1] === "--help" && argv.length === 2) {
230
326
  process.stdout.write(`${INIT_USAGE}\n`);