sortie-dogs 0.13.7 → 0.13.9
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/.agents/skills/sortie-dogs/SKILL.md +53 -0
- package/.agents/skills/sortie-dogs/agents/openai.yaml +6 -0
- package/.agents/skills/sortie-dogs/sortie-dogs.version +1 -0
- package/README.md +227 -9
- package/dist/asset-version.d.ts +3 -2
- package/dist/asset-version.js +2 -1
- package/dist/cli/codex-mission.d.ts +7 -0
- package/dist/cli/codex-mission.js +118 -0
- package/dist/cli/main.js +96 -0
- package/dist/codex/app-server.d.ts +135 -0
- package/dist/codex/app-server.js +366 -0
- package/dist/codex/mission-session.d.ts +86 -0
- package/dist/codex/mission-session.js +598 -0
- package/dist/codex/mission-settlement.d.ts +53 -0
- package/dist/codex/mission-settlement.js +176 -0
- package/dist/codex/mission-telemetry.d.ts +9 -0
- package/dist/codex/mission-telemetry.js +37 -0
- package/dist/codex/protected-evidence.d.ts +27 -0
- package/dist/codex/protected-evidence.js +77 -0
- package/dist/codex/run-mission.d.ts +28 -0
- package/dist/codex/run-mission.js +310 -0
- package/dist/codex/skill-assets.d.ts +2 -0
- package/dist/codex/skill-assets.js +27 -0
- package/dist/core/durable-scope-root.d.ts +2 -0
- package/dist/core/durable-scope-root.js +43 -0
- package/dist/core/goal-bound.d.ts +10 -0
- package/dist/core/goal-bound.js +5 -0
- package/dist/core/initialize.d.ts +2 -0
- package/dist/core/initialize.js +15 -0
- package/dist/core/observed-goal-evidence.d.ts +1 -1
- package/dist/core/operator-mission.d.ts +73 -1
- package/dist/core/operator-mission.js +124 -9
- package/dist/core/operator-runtime.d.ts +6 -0
- package/dist/core/operator-runtime.js +45 -1
- package/dist/core/validation-budget.d.ts +1 -0
- package/dist/core/worktree-scope.js +1 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +6 -1
- package/dist/plugin/index.d.ts +3 -0
- package/dist/plugin/index.js +33 -62
- package/dist/plugin/mission-review.d.ts +10 -6
- package/dist/plugin/mission-review.js +31 -18
- package/dist/plugin/profiled.d.ts +2 -1
- package/dist/plugin/profiled.js +145 -39
- package/dist/plugin/protected-snapshot.js +13 -10
- package/dist/plugin/run-metrics.d.ts +1 -1
- package/dist/plugin/run-metrics.js +17 -6
- package/dist/plugin/runtime-bridge.d.ts +4 -1
- package/dist/plugin/sortie-debrief.js +3 -0
- package/dist/plugin/tool-schema.d.ts +4 -0
- package/dist/plugin/tool-schema.js +58 -0
- package/dist/plugin/v2-session-history.d.ts +2 -0
- package/dist/plugin/v2-session-history.js +5 -0
- package/dist/plugin/v2.d.ts +1 -0
- package/dist/plugin/v2.js +5 -59
- package/dist/runtime-mission-assets.js +3 -1
- package/package.json +3 -2
|
@@ -0,0 +1,53 @@
|
|
|
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
|
+
On a POSIX host with `/bin/bash`, use the natural-language Mission route:
|
|
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
|
+
On Windows, use the manifest-bound route until the full Mission shell path supports Windows natively:
|
|
36
|
+
|
|
37
|
+
1. Read repository instructions and inspect only enough to identify bounded project-relative read scope, write scope, and meaningful validation commands.
|
|
38
|
+
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.
|
|
39
|
+
3. Resolve the exact PowerShell executable with `(Get-Command pwsh.exe -ErrorAction Stop).Source`. Invoke:
|
|
40
|
+
|
|
41
|
+
```text
|
|
42
|
+
<entrypoint> codex run --project-root <repository-root> --manifest <temporary-manifest> --prompt <exact-user-request> --trusted-pwsh <resolved-pwsh.exe>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
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.
|
|
46
|
+
|
|
47
|
+
If no defensible validation or bounded write scope can be derived, explain the missing contract and stop without starting Codex.
|
|
48
|
+
|
|
49
|
+
## Completion
|
|
50
|
+
|
|
51
|
+
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.
|
|
52
|
+
|
|
53
|
+
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 @@
|
|
|
1
|
+
0.13.9-codex-skill-v1
|
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.
|
|
39
|
-
([release notes](docs/release-v0.13.
|
|
38
|
+
**Current release: [v0.13.9](https://github.com/zufall-upon/Sortie-dogs/releases/tag/v0.13.9)**
|
|
39
|
+
([release notes](docs/release-v0.13.9.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.
|
|
41
|
+
The current asset marker is `0.13.9-codex-operation-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.
|
|
51
|
+
Historical scores below belong to their fixed candidates, not v0.13.9. 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,203 @@ optional measurement rather than a mandatory release gate.
|
|
|
56
56
|
|
|
57
57
|
## Quick start
|
|
58
58
|
|
|
59
|
-
|
|
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.9. 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.9
|
|
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 it selects the natural-language Mission route below. On Windows it derives a bounded
|
|
91
|
+
operation manifest and uses `codex run`, which retains the documented post-execution observation
|
|
92
|
+
boundary instead of claiming a pre-execution guard.
|
|
93
|
+
|
|
94
|
+
Sortie-dogs also exports a host adapter for the official Codex app-server stdio protocol. This is
|
|
95
|
+
separate from selecting an OpenAI model through OpenCode: OpenCode model routing still uses the
|
|
96
|
+
OpenCode host, while `CodexAppServerHost` starts and observes native Codex threads and turns.
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
import { CodexAppServerHost, createCodexAppServerTransport } from "sortie-dogs";
|
|
100
|
+
|
|
101
|
+
const transport = createCodexAppServerTransport({ executable: "codex" });
|
|
102
|
+
const host = new CodexAppServerHost(transport);
|
|
103
|
+
const threadID = await host.startThread({ cwd: process.cwd(), ephemeral: true });
|
|
104
|
+
const result = await host.runTurn(threadID, "Implement the admitted unit.", {
|
|
105
|
+
cwd: process.cwd(),
|
|
106
|
+
approvalPolicy: "unlessTrusted",
|
|
107
|
+
sandboxPolicy: {
|
|
108
|
+
type: "workspaceWrite",
|
|
109
|
+
writableRoots: [process.cwd()],
|
|
110
|
+
networkAccess: false,
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
await host.close();
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
The adapter reuses Sortie's host-neutral core instead of copying its goal, acceptance, evidence, or
|
|
117
|
+
ledger implementation. It exposes completed Codex items as authoritative observations, supports
|
|
118
|
+
exact persisted-thread resume and turn interruption (ephemeral threads have no resumable rollout), and declines command/file approvals unless the caller
|
|
119
|
+
provides an approval handler. Permission-subset requests receive an empty grant unless the caller
|
|
120
|
+
connects `permissionsApproval`; approved responses are limited to the native request. Unsupported
|
|
121
|
+
server-initiated requests fail closed.
|
|
122
|
+
|
|
123
|
+
For the existing Operator → Coordinator → Worker → Reviewer Mission workflow, use:
|
|
124
|
+
|
|
125
|
+
```sh
|
|
126
|
+
npx --no-install sortie-dogs codex mission --prompt "Implement and review the requested change" --model gpt-6.1-sol --effort medium
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
The equivalent public SDK entrypoint is:
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
import { CodexMissionSession } from "sortie-dogs";
|
|
133
|
+
|
|
134
|
+
const mission = await CodexMissionSession.create({
|
|
135
|
+
projectRoot: process.cwd(),
|
|
136
|
+
model: "gpt-6.1-sol", // Choose a model available to the existing signed-in account.
|
|
137
|
+
effort: "medium",
|
|
138
|
+
// resumeThreadID: "saved-root-thread-id", // Continue the same Mission when needed.
|
|
139
|
+
});
|
|
140
|
+
try {
|
|
141
|
+
const result = await mission.run("Implement and review the requested change");
|
|
142
|
+
console.log(JSON.stringify(result));
|
|
143
|
+
process.exitCode = result.accepted ? 0 : 1;
|
|
144
|
+
} finally {
|
|
145
|
+
await mission.close();
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
This Linux-first route uses `CodexMissionSession` and the existing Mission tools, correction grants,
|
|
150
|
+
validation evidence, and final Operator acceptance. It runs saved native Codex threads with existing
|
|
151
|
+
ChatGPT authentication; it does not import OpenCode settings or introduce a second Mission ledger.
|
|
152
|
+
Commands run through `/bin/bash` using the native app-server's configured permissions. Sortie does not
|
|
153
|
+
replace them with a fixed repository-only or network-disabled policy, change host configuration, or select
|
|
154
|
+
full access. Thread turns retain native thread permissions; standalone `command/exec` uses the server's
|
|
155
|
+
configured policy, not a thread's temporary grants. A parent application's in-memory approval is not
|
|
156
|
+
automatically transferred to a separately launched app-server.
|
|
157
|
+
SDK hosts can forward native command/file approval requests through `approval` and permission-subset
|
|
158
|
+
requests through `permissionsApproval`. The native host remains responsible for deciding and enforcing
|
|
159
|
+
the grant. The CLI reports approval requests but has no interactive approval bridge; without a connected
|
|
160
|
+
host callback, no grant is returned. `command/exec` has no thread-scoped approval API, so inheriting the
|
|
161
|
+
configured policy does not add an escalation path for these standalone commands.
|
|
162
|
+
Use SDK `permissions` or CLI `--permissions <native-profile>` only to explicitly select an existing
|
|
163
|
+
native profile for thread start/resume and standalone commands. Omission retains native defaults,
|
|
164
|
+
which may be read-only. Invalid or disallowed profiles fail through the native server without fallback;
|
|
165
|
+
no configuration file is changed. Low-level `CodexAppServerHost` callers must opt into
|
|
166
|
+
`experimentalApi: true` for profile APIs; Mission sessions already negotiate that capability. Progress reports the effective native profile, sandbox and approval
|
|
167
|
+
routing. This selection does not configure a delegated parent-host executor's own permissions.
|
|
168
|
+
See [Ubuntu acceptance evidence and remaining work](docs/codex-mission-acceptance-20261006.md).
|
|
169
|
+
|
|
170
|
+
For a parent application with an existing approval-aware executor, pass the optional SDK
|
|
171
|
+
`executeCommand` callback. It receives the exact post-hook argv, cwd, timeout, thread/turn/call identity,
|
|
172
|
+
and an AbortSignal for bash/read/write operations. The parent owns approval and execution; Sortie does
|
|
173
|
+
not infer a grant from prompt text or create another permission store. Return `completed` only after
|
|
174
|
+
execution ends, with the real integer exitCode, stdout and stderr. Approval alone is not a result.
|
|
175
|
+
`denied` and `not-started` explicitly mean nothing ran and create no validation exit. `interrupted`,
|
|
176
|
+
`unknown`, exceptions and invalid results retain unknown execution and stop resends. The host owns
|
|
177
|
+
command timeout enforcement; Sortie does not add a separate deadline to its approval interaction.
|
|
178
|
+
Closing the adapter signals cancellation; late callback results cannot establish validation, and the
|
|
179
|
+
host must reconcile any still-running process. Omission keeps native `command/exec`; a connected
|
|
180
|
+
executor never falls back to native execution after rejection or failure. Existing Mission before/after
|
|
181
|
+
hooks, command identity and validation acceptance remain shared. CLI progress identifies the selected
|
|
182
|
+
executor; the CLI itself does not attach a parent executor.
|
|
183
|
+
The bash tool accepts `workdir` (absolute or relative to the project root). The shared hooks and both
|
|
184
|
+
executors use that directory; progress and receipts include the effective cwd. A successful command in
|
|
185
|
+
another directory does not satisfy a validation declared for the project root.
|
|
186
|
+
|
|
187
|
+
Packaged role models and reasoning levels apply by default. `--model` and `--effort` explicitly
|
|
188
|
+
override all roles; SDK callers can use `roleModels` for individual roles. Unsupported native model
|
|
189
|
+
names fail rather than silently selecting another model. Availability depends on the signed-in account.
|
|
190
|
+
|
|
191
|
+
Use `--resume <root-thread-id>` to continue a saved Mission root. Without it, a single unfinished Codex
|
|
192
|
+
Mission in this repository is selected automatically; multiple unfinished roots require an explicit
|
|
193
|
+
selection. Resume restores native messages and tool evidence, including child sessions. Completed native
|
|
194
|
+
receipts feed the existing reservation reconciliation without replaying tool execution. A new Task stopped
|
|
195
|
+
before child binding can be recovered when the exact terminal parent thread/turn/call/input matches and
|
|
196
|
+
the prior adapter is closed or its Linux process identity proves it is gone. The host retains that proof in
|
|
197
|
+
the existing Mission and reconciles the reservation before another model prompt; repeated recovery does
|
|
198
|
+
not settle it again. Concurrent recovery claims are serialized.
|
|
199
|
+
|
|
200
|
+
A newly created ordinary Worker also saves its exact dispatch binding before the child prompt is sent.
|
|
201
|
+
If its parent Task result is lost, recovery can match that binding to the child's single, fully loaded,
|
|
202
|
+
completed native turn. The initial recovery path supports leaf Workers only: later turns, nested Tasks,
|
|
203
|
+
untracked native children, missing bindings and ambiguous identities remain unknown. Recovery restores
|
|
204
|
+
execution completion for the existing settlement path; missing validation evidence is a process defect,
|
|
205
|
+
not an invented PASS. It does not rerun the implementation. Continue with only the work or validation
|
|
206
|
+
still needed for normal Operator acceptance.
|
|
207
|
+
|
|
208
|
+
SIGINT/SIGTERM closes the adapter and exits 130/143. Bound children without an exact completed dispatch,
|
|
209
|
+
and commands sent without a saved terminal receipt, remain unknown and are not resent. App-server exit
|
|
210
|
+
does not prove an external command has stopped. Linux process-death checks do not prove external writer
|
|
211
|
+
quiescence either; other platforms require a clean adapter close for automatic prelaunch recovery.
|
|
212
|
+
Inspect the original executor before recovery; do not delete Mission state to force a retry.
|
|
213
|
+
Per-session usage is native thread cumulative usage (including earlier turns), not a Mission total;
|
|
214
|
+
monetary cost is unavailable and reported as `null`.
|
|
215
|
+
The existing Mission report uses observed per-turn token deltas and execution times. Cache and reasoning
|
|
216
|
+
subtotals are counted once. Its pre-terminal snapshot excludes final-answer generation, while final JSON
|
|
217
|
+
retains native thread totals. Terminal accounting observations survive cold reload in the existing Mission;
|
|
218
|
+
missing baselines remain unavailable. Native turn aggregates do not establish model-request counts, API
|
|
219
|
+
costs or remaining subscription allowance, so these values are not inferred.
|
|
220
|
+
CLI exit 0 means Operator acceptance; exit 1 means incomplete work or an execution error; exit 2
|
|
221
|
+
means invalid arguments. A native turn completing alone is not acceptance.
|
|
222
|
+
The CLI writes bounded progress records to stderr: tool start/completion, commands and exit codes,
|
|
223
|
+
replan reasons, next actions, child identity, and public model commentary. Final JSON remains on stdout.
|
|
224
|
+
|
|
225
|
+
For a manifest-bound mission, use the SDK `runCodexMission(...)` or the CLI:
|
|
226
|
+
|
|
227
|
+
```sh
|
|
228
|
+
sortie-dogs codex run --manifest operation-manifest.json --prompt "Implement the requested change"
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
The operation manifest remains required. The mission runner reuses Sortie's existing goal ledger,
|
|
232
|
+
protected evidence capture, settlement, and repository-wide scope leases. It does not emulate
|
|
233
|
+
OpenCode plugin hooks, install Codex assets, switch models implicitly, or copy/import/modify OpenCode
|
|
234
|
+
settings and sessions. Codex command and file events are post-execution observations, not a claimed
|
|
235
|
+
pre-execution write guard. The stdio transport is the supported initial integration; experimental
|
|
236
|
+
WebSocket transport is intentionally out of scope.
|
|
237
|
+
|
|
238
|
+
The manifest-run CLI handles SIGINT/SIGTERM by requesting interruption and cleaning up its
|
|
239
|
+
app-server (exit 130/143). SDK callers can pass an `AbortSignal` as `signal`. Before
|
|
240
|
+
turn dispatch, cancellation settles the reservation and releases its lease. After
|
|
241
|
+
dispatch, app-server exit or an interrupt acknowledgement does not prove that an
|
|
242
|
+
externally hosted command stopped. Cancellation or transport loss therefore preserves
|
|
243
|
+
the active goal/reservation as an unknown outcome and stops lease heartbeats without
|
|
244
|
+
claiming completion. SIGKILL can leave the same unresolved state.
|
|
245
|
+
|
|
246
|
+
Lease expiry alone does not authorize a retry: subsequent Codex missions refuse with
|
|
247
|
+
`codex-mission-outcome-unknown:no-resend` and the ledger path, including across
|
|
248
|
+
stable/v010 profiles. Inspect the prior worker and ledger before recovery; do not
|
|
249
|
+
delete the ledger or automatically resend the prompt. This is a Codex admission
|
|
250
|
+
check; it does not establish quiescence of external command executors.
|
|
251
|
+
|
|
252
|
+
### OpenCode plugin
|
|
253
|
+
|
|
254
|
+
Requirements: Node.js 22.6 or newer, npm, and OpenCode V2. These installation and `init` steps
|
|
255
|
+
configure the OpenCode route; they are not prerequisites for the Codex route above.
|
|
60
256
|
|
|
61
257
|
Run these commands in the target project:
|
|
62
258
|
|
|
@@ -93,7 +289,29 @@ existing local bridge loads enforcement and model routing. OpenCode can reload w
|
|
|
93
289
|
but replacing an installed dependency may require a full restart. A new chat session alone does not
|
|
94
290
|
prove the newly installed plugin is loaded.
|
|
95
291
|
|
|
96
|
-
## v0.13.
|
|
292
|
+
## v0.13.9 runtime updates
|
|
293
|
+
|
|
294
|
+
PRs #163–#166 connect native Codex sessions to the existing Mission lifecycle, add the explicit
|
|
295
|
+
`$sortie-dogs` skill and `codex init`, restore operation Reviewer correction within existing write
|
|
296
|
+
scope, and reconcile native terminal observations without reviving completed work from delayed events.
|
|
297
|
+
Codex settings and authentication remain separate from OpenCode. Real Ubuntu Codex acceptance
|
|
298
|
+
evidence and host-specific limits remain in [the acceptance record](docs/codex-mission-acceptance-20261006.md);
|
|
299
|
+
they are not a new all-host or performance benchmark. Release CLI proof observes actual OpenCode
|
|
300
|
+
Worker startup and model identity only, not Mission completion. See [release notes](docs/release-v0.13.9.md).
|
|
301
|
+
|
|
302
|
+
## v0.13.8 runtime updates
|
|
303
|
+
|
|
304
|
+
PR #161 captures native validation bindings through the readable resolved target of a Windows
|
|
305
|
+
directory junction instead of enumerating its failing logical alias. Logical evidence labels,
|
|
306
|
+
link identity and complete target bytes remain bound; unchanged readable junctions retain their
|
|
307
|
+
evidence identity. External-link/cycle handling, actual source/output freshness and Review remain
|
|
308
|
+
unchanged. No new approval, permissions or model changes. The PR's isolated native Windows fixture
|
|
309
|
+
reached independent Review PASS and accepted completion after resuming the same Mission, without
|
|
310
|
+
rerunning its successful check; this does not claim original product recovery or uninterrupted
|
|
311
|
+
single-turn completion. Release receipts: `_testenv/releases/0.13.8/`;
|
|
312
|
+
see [release notes](docs/release-v0.13.8.md).
|
|
313
|
+
|
|
314
|
+
## v0.13.7 runtime updates (retained)
|
|
97
315
|
|
|
98
316
|
PRs #158/#159 prevent late write-only reports from falsely invalidating bound non-generating
|
|
99
317
|
native checks, while preserving actual source/output freshness, failed checks and legacy recipes.
|
|
@@ -436,7 +654,7 @@ register stable and `v010` from the same package installation path in one host.
|
|
|
436
654
|
Project-local installation is recommended. To expose the current Mission assets globally:
|
|
437
655
|
|
|
438
656
|
```sh
|
|
439
|
-
npm install --global sortie-dogs@0.13.
|
|
657
|
+
npm install --global sortie-dogs@0.13.9
|
|
440
658
|
sortie-dogs init --global --profile v010
|
|
441
659
|
```
|
|
442
660
|
|
|
@@ -448,7 +666,7 @@ can resolve a **separate dependency** under that config root. Updating npm-globa
|
|
|
448
666
|
it. For that layout, also install the same release at the actual config root, then rerun global init:
|
|
449
667
|
|
|
450
668
|
```sh
|
|
451
|
-
npm install --prefix "$HOME/.config/opencode" sortie-dogs@0.13.
|
|
669
|
+
npm install --prefix "$HOME/.config/opencode" sortie-dogs@0.13.9
|
|
452
670
|
sortie-dogs init --global --profile v010
|
|
453
671
|
```
|
|
454
672
|
|
|
@@ -471,7 +689,7 @@ version, preserves user configuration, and stops safely on unknown ownership or
|
|
|
471
689
|
conflicting files.
|
|
472
690
|
|
|
473
691
|
Align any exact version pin or separate bridge dependency with the intended release too. An installed
|
|
474
|
-
marker of `0.13.
|
|
692
|
+
marker of `0.13.9-codex-operation-v1` identifies the assets; it does not prove an already-running
|
|
475
693
|
OpenCode process has reloaded the plugin.
|
|
476
694
|
|
|
477
695
|
There is no supported uninstall command. Remove the npm dependency separately,
|
package/dist/asset-version.d.ts
CHANGED
|
@@ -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.
|
|
7
|
-
export
|
|
6
|
+
export declare const V010_RUNTIME_ASSET_VERSION = "0.13.9-codex-operation-v1";
|
|
7
|
+
export declare const CODEX_SKILL_ASSET_VERSION = "0.13.9-codex-skill-v1";
|
|
8
|
+
export type RuntimeAssetVersion = typeof RUNTIME_ASSET_VERSION | typeof V010_RUNTIME_ASSET_VERSION | typeof CODEX_SKILL_ASSET_VERSION;
|
package/dist/asset-version.js
CHANGED
|
@@ -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.
|
|
6
|
+
export const V010_RUNTIME_ASSET_VERSION = "0.13.9-codex-operation-v1";
|
|
7
|
+
export const CODEX_SKILL_ASSET_VERSION = "0.13.9-codex-skill-v1";
|
|
@@ -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>]\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.\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,118 @@
|
|
|
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>]
|
|
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
|
+
Uses existing ChatGPT authentication and native Codex permissions.`;
|
|
9
|
+
export async function runCodexMissionCommand(argv) {
|
|
10
|
+
if (argv.length === 1 && argv[0] === "--help") {
|
|
11
|
+
process.stdout.write(`${CODEX_MISSION_USAGE}\n`);
|
|
12
|
+
return 0;
|
|
13
|
+
}
|
|
14
|
+
const values = new Map();
|
|
15
|
+
const allowed = new Set(["--prompt", "--resume", "--project-root", "--executable", "--model", "--effort", "--permissions"]);
|
|
16
|
+
for (let index = 0; index < argv.length; index += 2) {
|
|
17
|
+
const key = argv[index], value = argv[index + 1];
|
|
18
|
+
if (!key || !allowed.has(key) || !value || value.startsWith("--") || values.has(key)) {
|
|
19
|
+
process.stderr.write(`${CODEX_MISSION_USAGE}\n`);
|
|
20
|
+
return 2;
|
|
21
|
+
}
|
|
22
|
+
values.set(key, value);
|
|
23
|
+
}
|
|
24
|
+
const prompt = values.get("--prompt");
|
|
25
|
+
if (!prompt) {
|
|
26
|
+
process.stderr.write(`${CODEX_MISSION_USAGE}\n`);
|
|
27
|
+
return 2;
|
|
28
|
+
}
|
|
29
|
+
let adapter;
|
|
30
|
+
let signalExit;
|
|
31
|
+
const stop = (exit) => { signalExit ??= exit; void adapter?.close().catch(() => undefined); };
|
|
32
|
+
const onTerm = () => stop(143), onInt = () => stop(130);
|
|
33
|
+
process.on("SIGTERM", onTerm);
|
|
34
|
+
process.on("SIGINT", onInt);
|
|
35
|
+
try {
|
|
36
|
+
adapter = await CodexMissionSession.create({ projectRoot: values.get("--project-root") ?? process.cwd(),
|
|
37
|
+
resumeThreadID: values.get("--resume"), permissions: values.get("--permissions"), executable: values.get("--executable"), model: values.get("--model"), effort: values.get("--effort"), onEvent: event => {
|
|
38
|
+
const progress = codexMissionProgress(event);
|
|
39
|
+
if (progress)
|
|
40
|
+
process.stderr.write(`${JSON.stringify(progress)}\n`);
|
|
41
|
+
} });
|
|
42
|
+
if (signalExit)
|
|
43
|
+
return signalExit;
|
|
44
|
+
const result = await adapter.run(prompt);
|
|
45
|
+
process.stdout.write(`${JSON.stringify({ status: result.accepted ? "succeeded" : "incomplete", root_session_id: result.rootSessionID,
|
|
46
|
+
thread_id: result.turn.threadID, turn_id: result.turn.turnID, native_status: result.turn.status,
|
|
47
|
+
response: result.turn.finalResponse, sessions: result.sessions, cost: null })}\n`);
|
|
48
|
+
return signalExit ?? (result.accepted ? 0 : 1);
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
process.stderr.write(`${error instanceof Error ? error.message : "codex-mission-failed"}\n`);
|
|
52
|
+
return signalExit ?? 1;
|
|
53
|
+
}
|
|
54
|
+
finally {
|
|
55
|
+
try {
|
|
56
|
+
await adapter?.close();
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
process.off("SIGTERM", onTerm);
|
|
60
|
+
process.off("SIGINT", onInt);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/** Bounded user-facing progress; do not dump control packets or hidden reasoning. */
|
|
65
|
+
export function codexMissionProgress(event) {
|
|
66
|
+
if (event.method === "sortie/permissions")
|
|
67
|
+
return { thread_id: event.threadId, phase: "permissions", requested_profile: event.params.requestedProfile,
|
|
68
|
+
effective_profile: event.params.profile, sandbox: event.params.sandbox, network_access: event.params.networkAccess,
|
|
69
|
+
approval_policy: event.params.approvalPolicy, approvals_reviewer: event.params.approvalsReviewer,
|
|
70
|
+
command_executor: event.params.commandExecutor };
|
|
71
|
+
if (event.method === "sortie/commandExecution")
|
|
72
|
+
return { thread_id: event.threadId, turn_id: event.params.turnId, call_id: event.params.callId,
|
|
73
|
+
tool: event.params.tool, executor: event.params.executor, cwd: event.params.cwd, phase: event.params.status,
|
|
74
|
+
detail: typeof event.params.reason === "string" ? event.params.reason.slice(0, 1600) : undefined };
|
|
75
|
+
if (["item/commandExecution/requestApproval", "item/fileChange/requestApproval", "item/permissions/requestApproval"].includes(event.method))
|
|
76
|
+
return { thread_id: event.threadId, turn_id: event.params.turnId, phase: "approval-required", method: event.method,
|
|
77
|
+
reason: typeof event.params.reason === "string" ? event.params.reason.slice(0, 1600) : undefined,
|
|
78
|
+
command: typeof event.params.command === "string" ? event.params.command.slice(0, 1600) : undefined,
|
|
79
|
+
item_id: event.params.itemId, host_approval_available: event.params.hostApprovalAvailable === true,
|
|
80
|
+
next_action: event.params.hostApprovalAvailable === true ? "Await the host approval decision." :
|
|
81
|
+
"No host approval callback is connected; this request receives no grant. Use a host-integrated SDK client for approval." };
|
|
82
|
+
if (!["item/started", "item/completed"].includes(event.method))
|
|
83
|
+
return;
|
|
84
|
+
const item = event.params.item;
|
|
85
|
+
if (event.method === "item/completed" && item?.type === "agentMessage" && item.phase === "commentary" && typeof item.text === "string")
|
|
86
|
+
return { thread_id: event.threadId, turn_id: event.params.turnId, phase: "commentary", text: item.text.slice(0, 1600) };
|
|
87
|
+
if (item?.type !== "dynamicToolCall")
|
|
88
|
+
return;
|
|
89
|
+
const record = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
90
|
+
const bounded = (value) => typeof value === "string" ? value.slice(0, 1600) : undefined;
|
|
91
|
+
const args = record(item.arguments) ? item.arguments : {};
|
|
92
|
+
let receipt = {};
|
|
93
|
+
const contents = Array.isArray(item.contentItems) ? item.contentItems : [];
|
|
94
|
+
const text = contents.find(part => record(part) && part.type === "inputText")?.text;
|
|
95
|
+
try {
|
|
96
|
+
const parsed = JSON.parse(String(text));
|
|
97
|
+
if (record(parsed))
|
|
98
|
+
receipt = parsed;
|
|
99
|
+
}
|
|
100
|
+
catch { /* Plain native failure. */ }
|
|
101
|
+
if (typeof receipt.output === "string") {
|
|
102
|
+
try {
|
|
103
|
+
const nested = JSON.parse(receipt.output);
|
|
104
|
+
if (record(nested))
|
|
105
|
+
receipt = { ...nested, ...receipt };
|
|
106
|
+
}
|
|
107
|
+
catch { /* Ordinary command output. */ }
|
|
108
|
+
}
|
|
109
|
+
const metadata = record(receipt.metadata) ? receipt.metadata : {};
|
|
110
|
+
return { thread_id: event.threadId, turn_id: event.params.turnId, tool: item.tool,
|
|
111
|
+
phase: event.method === "item/started" ? "started" : "completed", status: item.status, success: item.success,
|
|
112
|
+
command: bounded(args.command), workdir: bounded(args.workdir), cwd: bounded(metadata.cwd), reason: bounded(args.reason),
|
|
113
|
+
agent: bounded(args.subagent_type), description: bounded(args.description), child_session_id: bounded(metadata.sessionId),
|
|
114
|
+
outcome: bounded(receipt.status), exit: metadata.exit, executor: metadata.executor,
|
|
115
|
+
next_action: bounded(receipt.next_action),
|
|
116
|
+
summary: bounded(args.summary ?? receipt.summary),
|
|
117
|
+
detail: bounded(receipt.reason ?? receipt.error ?? (item.success === false ? text : undefined)) };
|
|
118
|
+
}
|
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`);
|