@agentex/agent 0.0.36 → 0.0.38

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 (38) hide show
  1. package/CHANGELOG.md +460 -0
  2. package/README.md +32 -7
  3. package/dist/index.d.ts +1 -1
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js.map +1 -1
  6. package/dist/providers/claude/parse.d.ts +3 -0
  7. package/dist/providers/claude/parse.d.ts.map +1 -1
  8. package/dist/providers/claude/parse.js +23 -1
  9. package/dist/providers/claude/parse.js.map +1 -1
  10. package/dist/providers/claude/session.d.ts +174 -4
  11. package/dist/providers/claude/session.d.ts.map +1 -1
  12. package/dist/providers/claude/session.js +541 -29
  13. package/dist/providers/claude/session.js.map +1 -1
  14. package/dist/providers/codex/execute.d.ts.map +1 -1
  15. package/dist/providers/codex/execute.js +3 -0
  16. package/dist/providers/codex/execute.js.map +1 -1
  17. package/dist/providers/codex/parse.d.ts +12 -1
  18. package/dist/providers/codex/parse.d.ts.map +1 -1
  19. package/dist/providers/codex/parse.js +21 -0
  20. package/dist/providers/codex/parse.js.map +1 -1
  21. package/dist/providers/codex/session.d.ts.map +1 -1
  22. package/dist/providers/codex/session.js +21 -1
  23. package/dist/providers/codex/session.js.map +1 -1
  24. package/dist/types.d.ts +95 -0
  25. package/dist/types.d.ts.map +1 -1
  26. package/dist/utils/instructions.d.ts +36 -12
  27. package/dist/utils/instructions.d.ts.map +1 -1
  28. package/dist/utils/instructions.js +104 -53
  29. package/dist/utils/instructions.js.map +1 -1
  30. package/package.json +1 -1
  31. package/src/index.ts +2 -0
  32. package/src/providers/claude/parse.ts +23 -1
  33. package/src/providers/claude/session.ts +556 -30
  34. package/src/providers/codex/execute.ts +3 -0
  35. package/src/providers/codex/parse.ts +25 -0
  36. package/src/providers/codex/session.ts +24 -1
  37. package/src/types.ts +97 -0
  38. package/src/utils/instructions.ts +152 -64
package/CHANGELOG.md CHANGED
@@ -1,9 +1,195 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.0.38 — AGENTS.md is the workspace instruction file for every runtime
4
+
5
+ Claude Code reads `AGENTS.md` since 2.1.277, loaded exactly where `CLAUDE.md` would be, but only in a folder with no `CLAUDE.md`. A `CLAUDE.md`, a `CLAUDE.local.md`, or one in a parent folder hides `AGENTS.md` completely (verified against 2.1.281). Not yet on Bedrock, Vertex or Foundry.
6
+
7
+ ### Changed (breaking)
8
+
9
+ - **`installInstructions` writes `AGENTS.md` only by default.** Claude's workspace file is now `AGENTS.md`, like every other runtime. `CLAUDE.md` is Claude's native file, written only with `includeNativeFiles: true`, and then as a one-line `@AGENTS.md` pointer in the managed region instead of a second copy of the brief. A copy would have made anything the user writes in `AGENTS.md` invisible to Claude. Opt in for Claude Code before 2.1.277 or on a third-party API provider. `includeNativeFiles` still writes Gemini's `GEMINI.md` as a copy.
10
+ - **An existing workspace `CLAUDE.md` is reconciled** whenever `claude` is among the runtimes and the opt-in is off, because it would hide `AGENTS.md`: one holding nothing but this installer's managed region (for example the full brief 0.0.37 and earlier wrote) is deleted, and one the user wrote keeps their content and gains `@AGENTS.md` in the managed region. `managed: false` leaves it alone.
11
+ - **`removeInstructions` always checks native files** (`CLAUDE.md`, `GEMINI.md`), so an opt-in install is fully removable. It still only strips the managed region.
12
+
13
+ ### Added
14
+
15
+ - `InstructionStatus` gains `"removed"`, and `InstructionInstallResult` a `removed` count.
16
+ - `InstructionTarget.importsFile` marks a pointer file (`"AGENTS.md"` on an opt-in `CLAUDE.md`).
17
+
18
+ ### Migration
19
+
20
+ A host that relied on the default `CLAUDE.md` gets `AGENTS.md` only. Nothing else is needed on Claude Code 2.1.277+ with first-party auth: the next install deletes the old managed-only `CLAUDE.md`. Elsewhere, pass `includeNativeFiles: true`.
21
+
22
+ ## 0.0.37 — Turn liveness and background-task identity (Claude)
23
+
24
+ Claude Code starts turns by itself. When a background task finishes, the CLI
25
+ enqueues the notification as user input, which opens a fresh turn with no host
26
+ involvement. A host that tracks "is the agent working" from its own `send()`
27
+ cannot see those turns — `send()` already resolved — so the session reads as
28
+ finished while the agent is visibly working. Verified against Claude Code
29
+ 2.1.241, where one user message produced two `result` events with a
30
+ self-started turn between them.
31
+
32
+ ### Added
33
+
34
+ - **`turn_start` StreamEvent.** Pairs with `result`, which closes a turn.
35
+ Carries `trigger: "send" | "resume"` — `resume` meaning the provider opened
36
+ the turn on its own. Emitted for host-initiated turns too, so `turn_start` →
37
+ `result` describes turn liveness straight off the stream rather than by
38
+ inference from dispatch.
39
+
40
+ It deliberately does not name the background task behind a `resume`. Claude
41
+ delivers a task's result and opens the turn as two unlinked records, and with
42
+ several tasks in flight the pairing is not recoverable from the wire; every
43
+ attempt to infer it produced a plausible id that was sometimes wrong.
44
+ Correlate through `background_task.report` and `toolUseId`, which the
45
+ provider does state.
46
+
47
+ Attribution is exact, not inferred. A host message carries a uuid and a
48
+ provider-initiated continuation does not: every dequeued input with a uuid
49
+ emits `command_lifecycle` naming it, while the task-notification continuation
50
+ is enqueued without one. So a turn opened by a `started` naming an
51
+ outstanding message *is* that message's turn. A build that has never emitted
52
+ `command_lifecycle` falls back to the oldest unclaimed send; once one has
53
+ been seen, the fallback is disabled, because guessing there would mislabel
54
+ twice.
55
+
56
+ - **`turn_end` StreamEvent.** Every `turn_start` is followed by exactly one,
57
+ carrying the same `turnId` and a `reason`. `result` cannot serve as the close
58
+ signal on its own: a message the CLI cancels, discards, or refuses opens a
59
+ turn and produces no result, so a host pairing `turn_start` with `result`
60
+ would stay busy forever on those paths. `result` remains the outcome payload
61
+ and is ordered before the `turn_end` that follows it.
62
+
63
+ - **`background_task.report`.** The task's delivered output (`summary`,
64
+ `outputFile`, `usage`), present only on the event that hands the result
65
+ back. Claude emits *both* `task_updated` and `task_notification` for a single
66
+ completion; they are different records, not duplicates, and only the
67
+ notification carries the result. Collapsing them into one indistinguishable
68
+ `phase: "completed"` event made hosts render every finished task twice, once
69
+ with its report and once empty. A task that was stopped or killed delivered
70
+ nothing and carries no report. Codex applies the identical rule at every
71
+ emitter, so "one row per delivered result" holds across providers.
72
+
73
+ - **`background_task.toolUseId`.** The tool call that launched the task — the
74
+ same id Claude writes into a subagent's `meta.json`, and the only structured
75
+ task-to-tool_call link the wire provides. It was being discarded.
76
+
77
+ ### Changed
78
+
79
+ - Turn, command, and task state is now reduced from the ordered wire in one
80
+ place, rather than held in mutable fields updated across `await` boundaries.
81
+ Each turn's settlement batch is captured synchronously before any suspension
82
+ point, so a turn that opens while an earlier handler is still draining cannot
83
+ have its sends resolved by that handler — the failure that made two
84
+ back-to-back results resolve both callers with the first result.
85
+
86
+ - A turn owns a *set* of command uuids. The CLI coalesces: a host message
87
+ dequeued while a turn is running joins that turn instead of starting its own.
88
+ Modelling one command per turn left every coalesced message permanently
89
+ unsettled.
90
+
91
+ ### Fixed
92
+
93
+ - A background task's `taskType` and `description` survive its whole lifetime.
94
+ `task_started` is the only record that names them; the patches and the
95
+ completion notification that follow identify the task by id alone, so every
96
+ finished subagent normalized to `taskType: "unknown"` and hosts rendered
97
+ "Background task completed" for what was plainly a subagent. A completion for
98
+ a task the session never saw start still reports `unknown` rather than
99
+ guessing. The cache is bounded at 512 entries, oldest evicted.
100
+
101
+ - A detached subagent's own output no longer drives the parent session. Claude
102
+ streams a child's assistant text, thinking, and tool calls onto the parent
103
+ stream while the root turn is already over. Anything carrying
104
+ `parent_tool_use_id` is the child working, not the session: it does not open
105
+ a turn, does not move `session.state`, and a child's permission prompt no
106
+ longer parks the parent in `waiting_for_approval` with nothing able to clear
107
+ it.
108
+
109
+ - `session.state` and `turn_start`/`result` agree. A host turn took `thinking`
110
+ from `send()`; a provider-initiated one had nothing to set it, so `state`
111
+ read `idle` for the whole head of every resume turn while `turn_start` had
112
+ already fired.
113
+
114
+ - Turn settling is synchronous with the `result` line. The CLI can flush a
115
+ result and the next turn's opening line in one chunk; deferring the close
116
+ until the event chain drained swallowed the following `turn_start`, and
117
+ deferring the turn's send-resolvers with it let the next turn mistake them
118
+ for its own. The resolvers are appended to a settling list, never assigned
119
+ over — overwriting discarded the earlier turn's resolvers outright, hanging
120
+ that caller's `send()` and deadlocking `drain()` behind it.
121
+
122
+ - Background-task state is tracked from the wire, not from the delivery path.
123
+ It was maintained inside event dispatch, which only runs when a host
124
+ subscribed, so `session.state`, `drain()`, and turn attribution silently
125
+ degraded for a host that reads the session without an `onEvent` handler.
126
+
127
+ - A send resolves with its own turn. `_pendingResults` was a flat queue drained
128
+ by whatever `result` landed next, so a follow-up the CLI had merely queued
129
+ resolved against a turn that never contained it — the host then read
130
+ "finished" for a message still waiting to run. Each entry now carries its
131
+ command uuid and settles only when the turn that claimed it completes. A
132
+ terminal `command_lifecycle` settles a message the CLI retires without
133
+ running, which previously had nothing to settle it at all.
134
+
135
+ - `drain()` waits for provider-initiated turns and for running subagents.
136
+ `_inFlight` only tracks turns the host dispatched, so draining during the gap
137
+ between a root result and the resume turn that follows it — measured at 8-11
138
+ seconds live — SIGTERM'd the CLI and killed the child outright. Background
139
+ *processes* are deliberately excluded: a dev server started with
140
+ `run_in_background` may never exit, and the contract is "let the agent's work
141
+ settle", not "outlive whatever it launched". Bounded by a deadline so a
142
+ wedged turn cannot hang the drain.
143
+
144
+ It also holds across the gap between a task's result being delivered and the
145
+ resume turn it triggers — 24ms for a subagent, 71ms for a background process.
146
+ The task is no longer live by then, so waiting on live tasks alone left
147
+ `drain()` landing in that window and killing the very turn it was extended to
148
+ protect. The delivery record is the provider stating a turn is coming, so it
149
+ is used as one; the wait is released by the next turn to open or close.
150
+
151
+ - Turns opened by a command that ends in `refused`, `discarded`, or `cancelled`
152
+ are closed by that record. Those states never produce a `result`, so nothing
153
+ else would ever close them and the session pinned as working with no path
154
+ back.
155
+
156
+ - Wire lines arriving after `close()` are ignored, and `close()` rejects sends
157
+ still waiting on a turn instead of stranding the caller forever.
158
+
159
+ - `turn_start` carries the `eventId` of the line that opened it, and a minimal
160
+ `raw`. A resume turn is headed by `system/init`, whose payload runs to ~5KB
161
+ of tools, skills, plugins, and MCP config; echoing it whole made hosts that
162
+ persist `raw` pay that for every resume, twice.
163
+
164
+ ### Compatibility
165
+
166
+ - Additive at the type level. `turn_start` is a new event type — consumers with
167
+ exhaustive `switch` statements over `StreamEvent` will need a case or a
168
+ default. `report` and `toolUseId` are new required fields on
169
+ `background_task`; every in-tree provider sets them, and both are `null`
170
+ where the provider reports nothing.
171
+ - No behavior change for OpenCode, Cursor, or any other provider. Codex gains
172
+ `report`/`toolUseId` and is otherwise untouched; only the Claude provider
173
+ emits `turn_start`.
174
+
3
175
  ## 0.0.36 — OpenCode empty-turn follow-ups
4
176
 
5
177
  Follow-ups to the OpenCode empty-turn handling in 0.0.35.
6
178
 
179
+ ### Changed
180
+
181
+ - Turn, command, and task state is now reduced from the ordered wire in one
182
+ place, rather than held in mutable fields updated across `await` boundaries.
183
+ Each turn's settlement batch is captured synchronously before any suspension
184
+ point, so a turn that opens while an earlier handler is still draining cannot
185
+ have its sends resolved by that handler — the failure that made two
186
+ back-to-back results resolve both callers with the first result.
187
+
188
+ - A turn owns a *set* of command uuids. The CLI coalesces: a host message
189
+ dequeued while a turn is running joins that turn instead of starting its own.
190
+ Modelling one command per turn left every coalesced message permanently
191
+ unsettled.
192
+
7
193
  ### Fixed
8
194
 
9
195
  - The empty-turn classifier's "finished" guard now lives in `terminalOutcome`,
@@ -28,6 +214,26 @@ Follow-ups to the OpenCode empty-turn handling in 0.0.35.
28
214
  Codex's handling of the same action, rather than `agent_error` with a
29
215
  JSON-stringified error object.
30
216
 
217
+ - `session.state` no longer follows a detached child. The state machine set
218
+ `thinking` on any assistant line, including a subagent's, so `state` and
219
+ `turn_start`/`result` contradicted each other for the child's entire run —
220
+ measured at 7.6s live — with nothing to clear it if the child was stopped or
221
+ killed.
222
+ - `stream_event` opens a turn. Under `includePartialMessages` the whole
223
+ streamed reply arrived before `turn_start`, which reintroduced the reported
224
+ bug one layer down: output visible while the session still read as finished.
225
+ - A `send()` issued while a turn is settling is no longer classified as
226
+ `resume`. The trigger reads a counter of host messages still awaiting a
227
+ turn; the resolver list cannot answer that, because a turn's resolvers are
228
+ moved off it the moment its `result` is read.
229
+ - `_pendingResumeTaskId` is consumed only by the resume turn it explains. It
230
+ was cleared on every turn open, so a host send landing between a task's
231
+ delivery and its resume turn wiped the attribution.
232
+ - Turn state, the task-fact cache, and the unclaimed-send counter are all
233
+ reset when a session's pending work is rejected (exit, crash, close). A
234
+ `_turnOpen` left set would also suppress the `idle` fallback in
235
+ `handleResult` and pin a dead session as working with no path back.
236
+
31
237
  ### Compatibility
32
238
 
33
239
  - The incomplete-turn note is emitted as `type: "assistant"` (the only surface a
@@ -39,6 +245,20 @@ Follow-ups to the OpenCode empty-turn handling in 0.0.35.
39
245
 
40
246
  ## 0.0.35 — Codex turn-boundary correctness and model discovery
41
247
 
248
+ ### Changed
249
+
250
+ - Turn, command, and task state is now reduced from the ordered wire in one
251
+ place, rather than held in mutable fields updated across `await` boundaries.
252
+ Each turn's settlement batch is captured synchronously before any suspension
253
+ point, so a turn that opens while an earlier handler is still draining cannot
254
+ have its sends resolved by that handler — the failure that made two
255
+ back-to-back results resolve both callers with the first result.
256
+
257
+ - A turn owns a *set* of command uuids. The CLI coalesces: a host message
258
+ dequeued while a turn is running joins that turn instead of starting its own.
259
+ Modelling one command per turn left every coalesced message permanently
260
+ unsettled.
261
+
42
262
  ### Fixed
43
263
 
44
264
  - A Codex `send()` issued while the previous turn's result was still being
@@ -183,6 +403,26 @@ Follow-ups to the OpenCode empty-turn handling in 0.0.35.
183
403
  contract test now checks both directions so a provider cannot declare
184
404
  discovery it does not implement, or implement discovery it does not declare.
185
405
 
406
+ - `session.state` no longer follows a detached child. The state machine set
407
+ `thinking` on any assistant line, including a subagent's, so `state` and
408
+ `turn_start`/`result` contradicted each other for the child's entire run —
409
+ measured at 7.6s live — with nothing to clear it if the child was stopped or
410
+ killed.
411
+ - `stream_event` opens a turn. Under `includePartialMessages` the whole
412
+ streamed reply arrived before `turn_start`, which reintroduced the reported
413
+ bug one layer down: output visible while the session still read as finished.
414
+ - A `send()` issued while a turn is settling is no longer classified as
415
+ `resume`. The trigger reads a counter of host messages still awaiting a
416
+ turn; the resolver list cannot answer that, because a turn's resolvers are
417
+ moved off it the moment its `result` is read.
418
+ - `_pendingResumeTaskId` is consumed only by the resume turn it explains. It
419
+ was cleared on every turn open, so a host send landing between a task's
420
+ delivery and its resume turn wiped the attribution.
421
+ - Turn state, the task-fact cache, and the unclaimed-send counter are all
422
+ reset when a session's pending work is rejected (exit, crash, close). A
423
+ `_turnOpen` left set would also suppress the `idle` fallback in
424
+ `handleResult` and pin a dead session as working with no path back.
425
+
186
426
  ### Compatibility
187
427
 
188
428
  - Discovery is curated-list-plus-validation for Claude, not enumeration. A tier
@@ -229,6 +469,20 @@ Follow-ups to the OpenCode empty-turn handling in 0.0.35.
229
469
 
230
470
  ## 0.0.34 - Codex collaboration task lifecycle
231
471
 
472
+ ### Changed
473
+
474
+ - Turn, command, and task state is now reduced from the ordered wire in one
475
+ place, rather than held in mutable fields updated across `await` boundaries.
476
+ Each turn's settlement batch is captured synchronously before any suspension
477
+ point, so a turn that opens while an earlier handler is still draining cannot
478
+ have its sends resolved by that handler — the failure that made two
479
+ back-to-back results resolve both callers with the first result.
480
+
481
+ - A turn owns a *set* of command uuids. The CLI coalesces: a host message
482
+ dequeued while a turn is running joins that turn instead of starting its own.
483
+ Modelling one command per turn left every coalesced message permanently
484
+ unsettled.
485
+
232
486
  ### Fixed
233
487
 
234
488
  - Codex 0.144 collaboration tool calls now register spawned child threads as
@@ -241,6 +495,26 @@ Follow-ups to the OpenCode empty-turn handling in 0.0.35.
241
495
  child-thread, and reconciliation signals. Session shutdown also closes any
242
496
  still-active child lifecycle instead of leaving a permanent running state.
243
497
 
498
+ - `session.state` no longer follows a detached child. The state machine set
499
+ `thinking` on any assistant line, including a subagent's, so `state` and
500
+ `turn_start`/`result` contradicted each other for the child's entire run —
501
+ measured at 7.6s live — with nothing to clear it if the child was stopped or
502
+ killed.
503
+ - `stream_event` opens a turn. Under `includePartialMessages` the whole
504
+ streamed reply arrived before `turn_start`, which reintroduced the reported
505
+ bug one layer down: output visible while the session still read as finished.
506
+ - A `send()` issued while a turn is settling is no longer classified as
507
+ `resume`. The trigger reads a counter of host messages still awaiting a
508
+ turn; the resolver list cannot answer that, because a turn's resolvers are
509
+ moved off it the moment its `result` is read.
510
+ - `_pendingResumeTaskId` is consumed only by the resume turn it explains. It
511
+ was cleared on every turn open, so a host send landing between a task's
512
+ delivery and its resume turn wiped the attribution.
513
+ - Turn state, the task-fact cache, and the unclaimed-send counter are all
514
+ reset when a session's pending work is rejected (exit, crash, close). A
515
+ `_turnOpen` left set would also suppress the `idle` fallback in
516
+ `handleResult` and pin a dead session as working with no path back.
517
+
244
518
  ### Compatibility
245
519
 
246
520
  - The change is isolated to Codex collaboration events. Claude and the other
@@ -264,6 +538,20 @@ Follow-ups to the OpenCode empty-turn handling in 0.0.35.
264
538
  `getClaudeTaskDetails()` remains available for Claude-native fields and
265
539
  accepts legacy `unknown` task events from older agentex versions.
266
540
 
541
+ ### Changed
542
+
543
+ - Turn, command, and task state is now reduced from the ordered wire in one
544
+ place, rather than held in mutable fields updated across `await` boundaries.
545
+ Each turn's settlement batch is captured synchronously before any suspension
546
+ point, so a turn that opens while an earlier handler is still draining cannot
547
+ have its sends resolved by that handler — the failure that made two
548
+ back-to-back results resolve both callers with the first result.
549
+
550
+ - A turn owns a *set* of command uuids. The CLI coalesces: a host message
551
+ dequeued while a turn is running joins that turn instead of starting its own.
552
+ Modelling one command per turn left every coalesced message permanently
553
+ unsettled.
554
+
267
555
  ### Fixed
268
556
 
269
557
  - Codex live sessions now track the active root turn and interrupt it with the
@@ -277,6 +565,26 @@ Follow-ups to the OpenCode empty-turn handling in 0.0.35.
277
565
  as `aborted`. Interrupt RPC errors propagate to the caller so hosts can show a
278
566
  failed Stop action instead of reporting false success.
279
567
 
568
+ - `session.state` no longer follows a detached child. The state machine set
569
+ `thinking` on any assistant line, including a subagent's, so `state` and
570
+ `turn_start`/`result` contradicted each other for the child's entire run —
571
+ measured at 7.6s live — with nothing to clear it if the child was stopped or
572
+ killed.
573
+ - `stream_event` opens a turn. Under `includePartialMessages` the whole
574
+ streamed reply arrived before `turn_start`, which reintroduced the reported
575
+ bug one layer down: output visible while the session still read as finished.
576
+ - A `send()` issued while a turn is settling is no longer classified as
577
+ `resume`. The trigger reads a counter of host messages still awaiting a
578
+ turn; the resolver list cannot answer that, because a turn's resolvers are
579
+ moved off it the moment its `result` is read.
580
+ - `_pendingResumeTaskId` is consumed only by the resume turn it explains. It
581
+ was cleared on every turn open, so a host send landing between a task's
582
+ delivery and its resume turn wiped the attribution.
583
+ - Turn state, the task-fact cache, and the unclaimed-send counter are all
584
+ reset when a session's pending work is rejected (exit, crash, close). A
585
+ `_turnOpen` left set would also suppress the `idle` fallback in
586
+ `handleResult` and pin a dead session as working with no path back.
587
+
280
588
  ### Compatibility
281
589
 
282
590
  - Timeout and AbortSignal cancellation remain best-effort and preserve their
@@ -286,6 +594,20 @@ Follow-ups to the OpenCode empty-turn handling in 0.0.35.
286
594
 
287
595
  ## 0.0.32 — Codex root-thread completion isolation
288
596
 
597
+ ### Changed
598
+
599
+ - Turn, command, and task state is now reduced from the ordered wire in one
600
+ place, rather than held in mutable fields updated across `await` boundaries.
601
+ Each turn's settlement batch is captured synchronously before any suspension
602
+ point, so a turn that opens while an earlier handler is still draining cannot
603
+ have its sends resolved by that handler — the failure that made two
604
+ back-to-back results resolve both callers with the first result.
605
+
606
+ - A turn owns a *set* of command uuids. The CLI coalesces: a host message
607
+ dequeued while a turn is running joins that turn instead of starting its own.
608
+ Modelling one command per turn left every coalesced message permanently
609
+ unsettled.
610
+
289
611
  ### Fixed
290
612
 
291
613
  - Codex live sessions now pin their root thread and ignore notifications from
@@ -302,6 +624,26 @@ Follow-ups to the OpenCode empty-turn handling in 0.0.35.
302
624
  - Live Codex event identity prefers the event's own thread scope while retaining
303
625
  the pinned root id as a compatibility fallback for older unscoped events.
304
626
 
627
+ - `session.state` no longer follows a detached child. The state machine set
628
+ `thinking` on any assistant line, including a subagent's, so `state` and
629
+ `turn_start`/`result` contradicted each other for the child's entire run —
630
+ measured at 7.6s live — with nothing to clear it if the child was stopped or
631
+ killed.
632
+ - `stream_event` opens a turn. Under `includePartialMessages` the whole
633
+ streamed reply arrived before `turn_start`, which reintroduced the reported
634
+ bug one layer down: output visible while the session still read as finished.
635
+ - A `send()` issued while a turn is settling is no longer classified as
636
+ `resume`. The trigger reads a counter of host messages still awaiting a
637
+ turn; the resolver list cannot answer that, because a turn's resolvers are
638
+ moved off it the moment its `result` is read.
639
+ - `_pendingResumeTaskId` is consumed only by the resume turn it explains. It
640
+ was cleared on every turn open, so a host send landing between a task's
641
+ delivery and its resume turn wiped the attribution.
642
+ - Turn state, the task-fact cache, and the unclaimed-send counter are all
643
+ reset when a session's pending work is rejected (exit, crash, close). A
644
+ `_turnOpen` left set would also suppress the `idle` fallback in
645
+ `handleResult` and pin a dead session as working with no path back.
646
+
305
647
  ### Compatibility
306
648
 
307
649
  - Unscoped global Codex notifications continue to flow through. The documented
@@ -355,6 +697,20 @@ Follow-ups to the OpenCode empty-turn handling in 0.0.35.
355
697
 
356
698
  ## 0.0.30 — Complete Claude and Codex host capabilities
357
699
 
700
+ ### Changed
701
+
702
+ - Turn, command, and task state is now reduced from the ordered wire in one
703
+ place, rather than held in mutable fields updated across `await` boundaries.
704
+ Each turn's settlement batch is captured synchronously before any suspension
705
+ point, so a turn that opens while an earlier handler is still draining cannot
706
+ have its sends resolved by that handler — the failure that made two
707
+ back-to-back results resolve both callers with the first result.
708
+
709
+ - A turn owns a *set* of command uuids. The CLI coalesces: a host message
710
+ dequeued while a turn is running joins that turn instead of starting its own.
711
+ Modelling one command per turn left every coalesced message permanently
712
+ unsettled.
713
+
358
714
  ### Fixed
359
715
 
360
716
  - Claude and Codex now declare the resumability, permission, question, and
@@ -489,6 +845,26 @@ remain source-compatible.
489
845
  - Codex endpoint header names are emitted as quoted TOML path segments, so
490
846
  valid names containing dots cannot become nested configuration keys.
491
847
 
848
+ - `session.state` no longer follows a detached child. The state machine set
849
+ `thinking` on any assistant line, including a subagent's, so `state` and
850
+ `turn_start`/`result` contradicted each other for the child's entire run —
851
+ measured at 7.6s live — with nothing to clear it if the child was stopped or
852
+ killed.
853
+ - `stream_event` opens a turn. Under `includePartialMessages` the whole
854
+ streamed reply arrived before `turn_start`, which reintroduced the reported
855
+ bug one layer down: output visible while the session still read as finished.
856
+ - A `send()` issued while a turn is settling is no longer classified as
857
+ `resume`. The trigger reads a counter of host messages still awaiting a
858
+ turn; the resolver list cannot answer that, because a turn's resolvers are
859
+ moved off it the moment its `result` is read.
860
+ - `_pendingResumeTaskId` is consumed only by the resume turn it explains. It
861
+ was cleared on every turn open, so a host send landing between a task's
862
+ delivery and its resume turn wiped the attribution.
863
+ - Turn state, the task-fact cache, and the unclaimed-send counter are all
864
+ reset when a session's pending work is rejected (exit, crash, close). A
865
+ `_turnOpen` left set would also suppress the `idle` fallback in
866
+ `handleResult` and pin a dead session as working with no path back.
867
+
492
868
  ### Compatibility and limits
493
869
 
494
870
  - OpenCode 1.3.2 is the release-tested server schema. Safe disconnect uses
@@ -505,6 +881,20 @@ remain source-compatible.
505
881
 
506
882
  ## 0.0.27 — Codex session reasoning effort
507
883
 
884
+ ### Changed
885
+
886
+ - Turn, command, and task state is now reduced from the ordered wire in one
887
+ place, rather than held in mutable fields updated across `await` boundaries.
888
+ Each turn's settlement batch is captured synchronously before any suspension
889
+ point, so a turn that opens while an earlier handler is still draining cannot
890
+ have its sends resolved by that handler — the failure that made two
891
+ back-to-back results resolve both callers with the first result.
892
+
893
+ - A turn owns a *set* of command uuids. The CLI coalesces: a host message
894
+ dequeued while a turn is running joins that turn instead of starting its own.
895
+ Modelling one command per turn left every coalesced message permanently
896
+ unsettled.
897
+
508
898
  ### Fixed
509
899
 
510
900
  - **Codex session reasoning effort.** Multi-turn Codex sessions now forward
@@ -630,6 +1020,20 @@ invisible to callers. `getProvider` stays synchronous; only heavy modules
630
1020
  The loader defaults to the built-in `acpProvider`; `registerAcpFactory` stays
631
1021
  exported and honored as an override hook.
632
1022
 
1023
+ ### Changed
1024
+
1025
+ - Turn, command, and task state is now reduced from the ordered wire in one
1026
+ place, rather than held in mutable fields updated across `await` boundaries.
1027
+ Each turn's settlement batch is captured synchronously before any suspension
1028
+ point, so a turn that opens while an earlier handler is still draining cannot
1029
+ have its sends resolved by that handler — the failure that made two
1030
+ back-to-back results resolve both callers with the first result.
1031
+
1032
+ - A turn owns a *set* of command uuids. The CLI coalesces: a host message
1033
+ dequeued while a turn is running joins that turn instead of starting its own.
1034
+ Modelling one command per turn left every coalesced message permanently
1035
+ unsettled.
1036
+
633
1037
  ### Fixed
634
1038
 
635
1039
  - **TDZ crash on direct provider import.** `import("@agentex/agent/providers/gemini")`
@@ -693,6 +1097,20 @@ A session-scoped **goal** primitive. Attach a durable objective and the library
693
1097
  - **`GoalController` + reconstruction helpers**, exported for hosts: `goalStateFromEvent`, `latestGoalFromEvents`, `normalizeClaudeGoalAttachment`, `normalizeCodexGoalStatus`, `normalizeCodexGoalRecord`, `createDefaultSentinel`, `parseAssessment`, `isTerminalGoalStatus`, `EMULATED_GOAL_CAPABILITY`, `GOAL_OBJECTIVE_MAX`, `CODEX_GOAL_TOOLS`, plus the `GoalState` / `GoalStatus` / `GoalOptions` / `GoalSentinel` / `SetGoalResult` / `ClearGoalResult` types.
694
1098
  - **Native observability + resume.** Claude writes `goal_status` only to the on-disk transcript (never live stdout), so a native goal session tails its transcript to surface `active`→`met` and restores an unmet goal on `--resume`. Codex rehydrates a durable goal on resume via `thread/goal/get`. Both confirmed live.
695
1099
 
1100
+ ### Changed
1101
+
1102
+ - Turn, command, and task state is now reduced from the ordered wire in one
1103
+ place, rather than held in mutable fields updated across `await` boundaries.
1104
+ Each turn's settlement batch is captured synchronously before any suspension
1105
+ point, so a turn that opens while an earlier handler is still draining cannot
1106
+ have its sends resolved by that handler — the failure that made two
1107
+ back-to-back results resolve both callers with the first result.
1108
+
1109
+ - A turn owns a *set* of command uuids. The CLI coalesces: a host message
1110
+ dequeued while a turn is running joins that turn instead of starting its own.
1111
+ Modelling one command per turn left every coalesced message permanently
1112
+ unsettled.
1113
+
696
1114
  ### Fixed
697
1115
 
698
1116
  - **Codex failed turns are no longer reported as success.** codex 0.130 signals failure via `turn/completed` with `turn.status: "failed"` (carrying `turn.error.message`), not only `turn/failed` — agentex hardcoded `isError:false`, so a failed turn (e.g. a 4xx from the model API) looked `completed`. The parser + session now detect the failed status and the trailing `error` notification, reporting `status:"failed"` with the error text. Verified live.
@@ -724,6 +1142,20 @@ Additive. The instruction-file twin of `installSkills`: install an orientation b
724
1142
 
725
1143
  Driven by consumer feedback from an embedding host wiring an orchestrator onto agentex sessions. All additive — except the MCP fix, which replaces behavior that never worked in any published version.
726
1144
 
1145
+ ### Changed
1146
+
1147
+ - Turn, command, and task state is now reduced from the ordered wire in one
1148
+ place, rather than held in mutable fields updated across `await` boundaries.
1149
+ Each turn's settlement batch is captured synchronously before any suspension
1150
+ point, so a turn that opens while an earlier handler is still draining cannot
1151
+ have its sends resolved by that handler — the failure that made two
1152
+ back-to-back results resolve both callers with the first result.
1153
+
1154
+ - A turn owns a *set* of command uuids. The CLI coalesces: a host message
1155
+ dequeued while a turn is running joins that turn instead of starting its own.
1156
+ Modelling one command per turn left every coalesced message permanently
1157
+ unsettled.
1158
+
727
1159
  ### Fixed
728
1160
 
729
1161
  - **`config.mcpServers` actually attaches MCP servers now.** It previously emitted `--mcp-server <name> -- <command>…` — a flag that does not exist in Claude Code 2.x — so any run/session setting the field died instantly with `error: unknown option '--mcp-server'` (verified against claude 2.1.165; the field has never worked in any published version, so there is no behavior to migrate from). The config is now staged as a **mode-0600 JSON file** in a temp dir and passed via the real `--mcp-config <path>`, cleaned up with the run/session (including spawn-failure paths). Secrets never touch argv — http `headers` (bearer tokens) live only in the 0600 file; argv is world-readable via `ps`.
@@ -759,6 +1191,20 @@ A three-tier provider architecture (deep-native · ACP · bespoke). The ACP tier
759
1191
  - **Codex collaboration modes.** `codexProvider.listModes()` discovers Codex's collaboration modes via `collaborationMode/list`; `config.modeId` applies a chosen mode to a fresh `thread/start` (a resumed thread keeps its original mode). `capabilities.modes` is now `true` for Codex.
760
1192
  - **Codex structured questions.** The app-server `requestUserInput` (and legacy `tool/requestUserInput`) server→client request is now bridged to `onUserInputRequest` as an `AskUserQuestion`, with answers mapped back into Codex's `{ answers: { [id]: { answers: [] } } }` shape — Codex sessions can answer questions headlessly.
761
1193
 
1194
+ ### Changed
1195
+
1196
+ - Turn, command, and task state is now reduced from the ordered wire in one
1197
+ place, rather than held in mutable fields updated across `await` boundaries.
1198
+ Each turn's settlement batch is captured synchronously before any suspension
1199
+ point, so a turn that opens while an earlier handler is still draining cannot
1200
+ have its sends resolved by that handler — the failure that made two
1201
+ back-to-back results resolve both callers with the first result.
1202
+
1203
+ - A turn owns a *set* of command uuids. The CLI coalesces: a host message
1204
+ dequeued while a turn is running joins that turn instead of starting its own.
1205
+ Modelling one command per turn left every coalesced message permanently
1206
+ unsettled.
1207
+
762
1208
  ### Fixed
763
1209
 
764
1210
  - **Codex tool-approval response shape.** Command/file approval requests are now answered with `{ decision: "accept" | "decline" }` (Codex's actual app-server contract) instead of `{ approved: boolean }`, which the app-server did not honor. Tool-permission gating in Codex sessions now works headlessly.
@@ -796,6 +1242,20 @@ Scheduled / fire-and-forget session runs needed three things the SDK pushed onto
796
1242
 
797
1243
  - **`SendHandle`, `SendOptions`, `CancelResult`** are now exported from the package entry point (previously only the `AgentSession` interface was).
798
1244
 
1245
+ ### Changed
1246
+
1247
+ - Turn, command, and task state is now reduced from the ordered wire in one
1248
+ place, rather than held in mutable fields updated across `await` boundaries.
1249
+ Each turn's settlement batch is captured synchronously before any suspension
1250
+ point, so a turn that opens while an earlier handler is still draining cannot
1251
+ have its sends resolved by that handler — the failure that made two
1252
+ back-to-back results resolve both callers with the first result.
1253
+
1254
+ - A turn owns a *set* of command uuids. The CLI coalesces: a host message
1255
+ dequeued while a turn is running joins that turn instead of starting its own.
1256
+ Modelling one command per turn left every coalesced message permanently
1257
+ unsettled.
1258
+
799
1259
  ### Fixed
800
1260
 
801
1261
  - **Session `close()` now honors `ProviderConfig.graceSec`** for the SIGTERM → SIGKILL window (was hardcoded to 5s, ignoring the config field that `execute()` already respected). `drain()` uses the same configurable grace.