@gajae-code/coding-agent 0.15.4 → 0.15.6

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 (174) hide show
  1. package/CHANGELOG.md +46 -2
  2. package/dist/types/async/job-manager.d.ts +83 -0
  3. package/dist/types/cli/auth-gateway-cli.d.ts +17 -0
  4. package/dist/types/cli/model-presets-cli.d.ts +9 -0
  5. package/dist/types/cli/update-cli.d.ts +27 -5
  6. package/dist/types/commands/auth-gateway.d.ts +3 -0
  7. package/dist/types/commands/gc.d.ts +13 -0
  8. package/dist/types/commands/model-presets.d.ts +21 -0
  9. package/dist/types/config/autorouting-tier-map.d.ts +99 -0
  10. package/dist/types/config/file-lock.d.ts +49 -2
  11. package/dist/types/config/internal/model-preset-registry-test-state.d.ts +4 -0
  12. package/dist/types/config/internal/model-preset-registry-test-support.d.ts +3 -0
  13. package/dist/types/config/keybindings.d.ts +3 -2
  14. package/dist/types/config/model-preset-registry.d.ts +368 -0
  15. package/dist/types/config/model-profile-activation.d.ts +39 -0
  16. package/dist/types/config/model-profiles.d.ts +5 -3
  17. package/dist/types/config/model-registry.d.ts +11 -5
  18. package/dist/types/config/settings-schema.d.ts +9 -0
  19. package/dist/types/coordinator-mcp/model-preset.d.ts +7 -5
  20. package/dist/types/coordinator-mcp/projection-scan.d.ts +46 -0
  21. package/dist/types/extensibility/extensions/types.d.ts +4 -4
  22. package/dist/types/extensibility/shared-events.d.ts +2 -0
  23. package/dist/types/gjc-runtime/empty-delete-gc.d.ts +58 -0
  24. package/dist/types/gjc-runtime/gc-runtime.d.ts +2 -0
  25. package/dist/types/gjc-runtime/session-state-lock.d.ts +35 -6
  26. package/dist/types/gjc-runtime/session-state-sidecar.d.ts +6 -0
  27. package/dist/types/index.d.ts +1 -0
  28. package/dist/types/main.d.ts +3 -1
  29. package/dist/types/modes/components/jobs-overlay-model.d.ts +4 -2
  30. package/dist/types/modes/jobs-observer.d.ts +36 -0
  31. package/dist/types/sdk/broker/broker.d.ts +3 -0
  32. package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +3 -0
  33. package/dist/types/sdk/bus/prompt-reconciliation.d.ts +4 -0
  34. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +8 -1
  35. package/dist/types/sdk/cli/session-cli.d.ts +42 -1
  36. package/dist/types/sdk/client/discovery.d.ts +1 -0
  37. package/dist/types/sdk/host/host.d.ts +2 -0
  38. package/dist/types/sdk/host/model-pin.d.ts +7 -2
  39. package/dist/types/sdk/host/sdk-run-capability.d.ts +1 -0
  40. package/dist/types/sdk/host/session-runtime.d.ts +19 -1
  41. package/dist/types/sdk/prompt-deadline-manager.d.ts +11 -1
  42. package/dist/types/sdk/protocol/adapter-validation.d.ts +2 -0
  43. package/dist/types/sdk/router/session-router.d.ts +9 -0
  44. package/dist/types/session/account-inventory.d.ts +1 -0
  45. package/dist/types/session/agent-session.d.ts +19 -5
  46. package/dist/types/session/fold-coordinator.d.ts +201 -0
  47. package/dist/types/session/internal/managed-session-storage.d.ts +4 -3
  48. package/dist/types/session/sdk-run-capability-internal.d.ts +7 -0
  49. package/dist/types/session/sdk-run-capability.d.ts +2 -0
  50. package/dist/types/telemetry/control.d.ts +11 -0
  51. package/dist/types/telemetry/events.d.ts +20 -0
  52. package/dist/types/telemetry/index.d.ts +3 -0
  53. package/dist/types/telemetry/transport.d.ts +22 -0
  54. package/dist/types/tools/bash-interactive.d.ts +23 -0
  55. package/dist/types/tools/index.d.ts +6 -5
  56. package/dist/types/tools/path-utils.d.ts +5 -6
  57. package/dist/types/tools/tmux-self-injection-guard.d.ts +15 -0
  58. package/dist/types/web/search/providers/base.d.ts +9 -4
  59. package/dist/types/web/search/providers/xai.d.ts +2 -1
  60. package/dist/types/web/search/types.d.ts +14 -0
  61. package/package.json +10 -7
  62. package/scripts/generate-hotkeys-docs.ts +4 -0
  63. package/scripts/generate-sdk-operation-inventory.ts +3 -3
  64. package/src/async/job-manager.ts +671 -39
  65. package/src/cli/auth-broker-cli.ts +40 -12
  66. package/src/cli/auth-gateway-cli.ts +273 -97
  67. package/src/cli/config-cli.ts +2 -2
  68. package/src/cli/fast-help.ts +3 -0
  69. package/src/cli/model-presets-cli.ts +100 -0
  70. package/src/cli/update-cli.ts +142 -6
  71. package/src/cli.ts +6 -2
  72. package/src/commands/auth-gateway.ts +12 -8
  73. package/src/commands/gc.ts +19 -0
  74. package/src/commands/model-presets.ts +24 -0
  75. package/src/commands/sdk.ts +5 -0
  76. package/src/config/autorouting-tier-map.ts +33 -0
  77. package/src/config/file-lock-gc.ts +9 -4
  78. package/src/config/file-lock.ts +775 -59
  79. package/src/config/internal/model-preset-registry-test-state.ts +28 -0
  80. package/src/config/internal/model-preset-registry-test-support.ts +11 -0
  81. package/src/config/keybindings.ts +6 -2
  82. package/src/config/model-preset-registry.ts +2799 -0
  83. package/src/config/model-profile-activation.ts +115 -28
  84. package/src/config/model-profile-contract.ts +4 -1
  85. package/src/config/model-profiles.ts +56 -14
  86. package/src/config/model-registry.ts +1028 -123
  87. package/src/config/settings-schema.ts +11 -0
  88. package/src/config/settings.ts +6 -1
  89. package/src/coordinator-mcp/model-preset.ts +32 -17
  90. package/src/coordinator-mcp/policy.ts +1 -1
  91. package/src/coordinator-mcp/projection-scan.ts +571 -0
  92. package/src/coordinator-mcp/server.ts +19 -24
  93. package/src/coordinator-mcp/session-reaper.ts +9 -3
  94. package/src/extensibility/extensions/loader.ts +0 -1
  95. package/src/extensibility/extensions/types.ts +4 -2
  96. package/src/extensibility/gjc-plugins/runtime-adapters.ts +1 -0
  97. package/src/extensibility/shared-events.ts +2 -0
  98. package/src/gjc-runtime/empty-delete-gc.ts +301 -0
  99. package/src/gjc-runtime/gc-render.ts +29 -0
  100. package/src/gjc-runtime/gc-runtime.ts +174 -11
  101. package/src/gjc-runtime/launch-worktree.ts +44 -7
  102. package/src/gjc-runtime/ralplan-runtime.ts +14 -1
  103. package/src/gjc-runtime/session-state-lock.ts +1242 -141
  104. package/src/gjc-runtime/session-state-sidecar.ts +76 -3
  105. package/src/gjc-runtime/tmux-sessions.ts +145 -48
  106. package/src/index.ts +1 -0
  107. package/src/internal-urls/docs-index.generated.ts +14 -13
  108. package/src/lsp/config.ts +4 -3
  109. package/src/lsp/path-trust.ts +12 -6
  110. package/src/main.ts +9 -2
  111. package/src/modes/acp/acp-agent.ts +11 -5
  112. package/src/modes/components/jobs-overlay-model.ts +99 -16
  113. package/src/modes/components/model-selector.ts +158 -18
  114. package/src/modes/components/status-line/segments.ts +6 -1
  115. package/src/modes/controllers/extension-ui-controller.ts +1 -1
  116. package/src/modes/controllers/input-controller.ts +23 -6
  117. package/src/modes/interactive-mode.ts +14 -1
  118. package/src/modes/jobs-observer.ts +149 -16
  119. package/src/modes/prompt-action-autocomplete.ts +26 -47
  120. package/src/modes/runtime-init.ts +1 -1
  121. package/src/modes/utils/injected-user-submission.ts +15 -1
  122. package/src/prompts/tools/bash.md +2 -2
  123. package/src/prompts/tools/fold-receipt.md +3 -0
  124. package/src/prompts/tools/job.md +1 -1
  125. package/src/sdk/acp/adapter.ts +17 -2
  126. package/src/sdk/broker/broker.ts +48 -21
  127. package/src/sdk/broker/lifecycle.ts +32 -6
  128. package/src/sdk/bus/chat-daemon-control.ts +2 -2
  129. package/src/sdk/bus/chat-daemon-runtime.ts +11 -1
  130. package/src/sdk/bus/kind-aware-reconciliation.ts +46 -8
  131. package/src/sdk/bus/prompt-reconciliation.ts +33 -6
  132. package/src/sdk/bus/slack-conversation.ts +5 -1
  133. package/src/sdk/bus/telegram-daemon-contract.ts +8 -1
  134. package/src/sdk/cli/session-cli.ts +161 -5
  135. package/src/sdk/client/discovery.ts +3 -1
  136. package/src/sdk/host/control/dispatch.ts +3 -0
  137. package/src/sdk/host/host.ts +7 -0
  138. package/src/sdk/host/model-pin.ts +185 -25
  139. package/src/sdk/host/sdk-run-capability.ts +1 -0
  140. package/src/sdk/host/session-runtime.test.ts +1240 -107
  141. package/src/sdk/host/session-runtime.ts +1029 -115
  142. package/src/sdk/prompt-deadline-manager.ts +16 -1
  143. package/src/sdk/protocol/adapter-validation.ts +27 -0
  144. package/src/sdk/protocol/operation-inventory.generated.json +2 -2
  145. package/src/sdk/protocol/operation-registry.ts +4 -1
  146. package/src/sdk/router/session-router.ts +297 -111
  147. package/src/sdk/session.ts +83 -12
  148. package/src/session/account-inventory.ts +27 -11
  149. package/src/session/agent-session.ts +887 -95
  150. package/src/session/fold-coordinator.ts +433 -0
  151. package/src/session/internal/managed-session-storage.ts +64 -26
  152. package/src/session/sdk-run-capability-internal.ts +15 -0
  153. package/src/session/sdk-run-capability.ts +2 -0
  154. package/src/session/session-manager.ts +29 -10
  155. package/src/setup/provider-presets.json +1 -1
  156. package/src/slash-commands/helpers/credential-switch.ts +6 -1
  157. package/src/task/executor.ts +19 -3
  158. package/src/telemetry/control.ts +26 -0
  159. package/src/telemetry/events.ts +142 -0
  160. package/src/telemetry/index.ts +3 -0
  161. package/src/telemetry/transport.ts +87 -0
  162. package/src/tools/bash-interactive.ts +182 -85
  163. package/src/tools/bash.ts +786 -67
  164. package/src/tools/index.ts +7 -5
  165. package/src/tools/path-utils.ts +77 -29
  166. package/src/tools/tmux-self-injection-guard.ts +359 -0
  167. package/src/tools/tool-catalog.generated.ts +1 -1
  168. package/src/web/search/provider.ts +120 -11
  169. package/src/web/search/providers/anthropic.ts +89 -17
  170. package/src/web/search/providers/base.ts +9 -4
  171. package/src/web/search/providers/gemini.ts +87 -15
  172. package/src/web/search/providers/openai-compatible.ts +23 -8
  173. package/src/web/search/providers/xai.ts +98 -12
  174. package/src/web/search/types.ts +16 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,50 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.15.6] - 2026-08-30
6
+
7
+ - Auth metadata remains session-only when a compatibility registry has auth storage but no owner accessor, preventing an unscoped OAuth account lookup from attributing a registry-scoped API-key request to the wrong account.
8
+
9
+ - Every prompt no longer throws inside the session metadata resolver when the model registry does not implement `getAuthStorageOwner`. `80bbc96192` added the lookup as a required call in the resolver that runs on every prompt, but `buildSessionMetadata` takes `owner?: object` and 65 test files construct `AgentSession` with a deliberately minimal `modelRegistry` stub, so the resolver raised `TypeError: this.#modelRegistry.getAuthStorageOwner is not a function`. The throw stranded session admission, which then reported the misleading `Agent session admission is busy due to same-session reentrancy` on every following prompt, so a single missing method surfaced as ~45 failures and 5-second timeouts across six CI test shards in ten unrelated suites (IRC roster delivery, `respondAsBackground` visibility, deferred shell publication, coordinator activity labels, and others). The two optional-argument resolver call sites are now optional calls, matching the existing defensive convention in `account-inventory.ts`; the auth-credential call sites (`resolveOAuthPinTarget`, `invalidateCredentialMatching`, `markUsageLimitReached`) deliberately keep the strict call because they genuinely require a real registry owner and passing `undefined` there would change credential ownership scoping.
10
+ - SDK prompt controls now reject empty and whitespace-only text before client correlation, turn allocation, transcript mutation, or provider activity across CLI, MCP, ACP, and direct session controls; multiline and Unicode prompts remain valid. (#5059)
11
+ - Added disabled-by-default privacy-preserving update telemetry with a versioned allowlist, random local UUIDv4 install ID, bounded nonblocking HTTPS transport, explicit `telemetry.enabled` control, and the `GJC_DISABLE_TELEMETRY` emergency kill switch. Events never include prompts, argv, paths, environment, secrets, account/model/provider/repository identity, arbitrary errors, hostname, username, machine ID, or IP-derived identity. (#5046)
12
+ - A running foreground command can now be folded into a background job with the fold chord (default `Alt+Shift+B`, plus `Cmd+B` on macOS; remappable via `app.tool.backgroundFold`). The turn ends as a clean stop-after-result rather than an abort, and the folded job's completion automatically wakes a fresh turn carrying a receipt — the command's output, a retrieval handle, and the original request — so the interrupted task is finished instead of abandoned. All three command surfaces fold — managed non-PTY bash, editor/ACP client-terminal commands, and PTY-mode commands — and a folded command is never killed or restarted by folding (a folded PTY continues output-only, so it stops accepting input). Folded jobs keep their original deadlines, folded work is visible in the status line and jobs overlay with its delivery state, completions arriving close together merge into one wake turn, and `task`/`subagent` waits are deliberately not foldable. The previous `Ctrl+B` default could never work: `Ctrl+B` is already `tui.editor.cursorLeft` (and is tmux's default prefix), so the keypress fell through to cursor movement whenever nothing was foldable.
13
+ - Background job results are no longer silently lost in two pre-existing cases that also affected plain `async: true` bash. A job id with a queued or in-flight delivery is no longer recycled, which previously gave the pending delivery a mismatched generation and discarded it before it was ever delivered; and a delivery callback that fails after its job record was evicted is now retried, with a retry-cap failure recorded as visibly failed instead of vanishing with no dead letter.
14
+ - Fixed `AsyncJobManager.dispose()` ordering: it marked itself disposed before running owner cleanups, and the delivery loop is inert once disposed, so a failure an owner cleanup settled could never be drained. Registration is now closed by its own flag, which keeps cleanups from registering fresh work without disabling delivery.
15
+ - ACP prompt terminal publication no longer waits behind post-prompt worker integration or recovery work. SDK prompts pass the correlated `agent_end` boundary through immediately, while the existing bounded integration drain continues independently, preventing streamed turns from remaining pending until `sdk.promptDeadlineMs` when owned subagent work lingers. (#5030)
16
+
17
+ ### Fixed
18
+
19
+ - Session resume no longer spends minutes in a CPU-hot 5ms loop when `runtime-state.json.lock` contains corrupt or unprovenanced debris. Session-state acquisition now uses a two-second monotonic wall-time budget with capped exponential backoff and typed exact-path diagnostics; stale malformed records are reclaimed only when their local host provenance and dead PID are proved, old empty legacy lock directories are removed only through exact tree identity, and live, foreign, or replacement owners remain fail-closed. (#5062)
20
+
21
+ - `gjc sdk session tail` no longer rejects the host's `event_replay_result` control frame when its response position includes `generation` and `lastSeq` but no event `seq`; replay metadata is kept out of the event-ring tail while malformed event positions remain fail-closed. (#5055)
22
+
23
+ - Coordinator no longer treats native exact-unlink placeholders (empty `.gjc-delete-*.json`) as live projection JSON. Directory scans skip dotfiles before open; truncated canonical projections remain parse candidates and fail closed, while the parse cap applies only after filtering debris. Session-state lock reclaim reuses one quarantine name per acquire cycle and removes a verified-empty leftover at that name before exchange — deletion is the native identity-bound `exactUnlinkDirect`, so a replacement planted at the reserved name is refused instead of deleted. `gjc gc --empty-delete-receipts --root/--manifest` validates every operand before any store can prune, reports or prunes only operator-supplied empty receipts matching the strict UUID namespace (inode identity + symlink-root reject; no hardcoded host paths), and surfaces native retained recovery paths and discovery failures as report errors. Receipt discovery is fail-closed under concurrent cleanup: a candidate that vanishes between `readdir` and `lstat` is recorded as a `skipped`/`raced` row instead of silently shrinking the report.
24
+
25
+ - Fold control operations now report success only after the foreground fold transaction commits, while rejected fold requests follow the existing warning path; cleanup-triggered delivery failures remain eligible for bounded retry and visible dead-letter recording during manager disposal, and folded jobs expose read-only detail rows in the jobs overlay.
26
+ - Generic file-lock release now retries transient Windows sharing denials and quarantines a verified self-owned lock when deletion remains unavailable, using an in-process acquisition generation rather than reclaiming every live lock with the same PID. Terminal `agent_end` publication remains independent of coordinator sidecar persistence, and a repeated interactive exit escalates through bounded postmortem cleanup. (#4943)
27
+
28
+ - A one-shot `gjc sdk` command no longer idles for five seconds after its response is written. `SessionRouter` bounded four waits with `Bun.sleep` inside `Promise.race`; the race settles on the winner but does not cancel the loser, and a pending `Bun.sleep` keeps the event loop alive, so work that finished in milliseconds still owed the rest of the budget before the process could exit. `gjc sdk session list` wrote its result at 0.50s and exited at 5.51s. The startup attach budget, shutdown timeout, bounded notification work, and replay backoff now use the existing `cancellableSleep` helper with an `AbortController` cancelled once the race settles, and the reconcile interval is unref'd so a Router started without a matching `stop()` does not hold a host proce…
29
+
30
+ ## [0.15.5] - 2026-08-29
31
+
32
+ - Bash now blocks tmux input commands that resolve to the agent's own pane before spawning the shell, including direct pane targets, session aliases, explicit socket forms, shell wrappers, and inspected script indirection. Read-only inspection and cross-session orchestration remain available, while blocked input cannot reach the transcript as a user turn. (#5039)
33
+ - Saved-session staged model-selection appends now re-authenticate metadata-only drift on the same managed transcript object using its unchanged inode, link count, length, and content digest. A changed successor still fails closed, so native Windows persistence no longer turns routine timestamp updates into `managed_append_identity_mismatch` setup failures.
34
+ - The GLM tiers now spend `zai/glm-5.3-flash` on the high-volume lanes and keep judgment roles on `zai/glm-5.3`: `glm-eco` moves default, executor, and planner to `glm-5.3-flash:low` (critic and architect stay `glm-5.3:high`), `glm-medium` swaps only the executor to `glm-5.3-flash:low`, and `glm-pro` swaps the executor to `glm-5.3-flash:high`. GLM-5.3-Flash also joins the bundled `zai` catalog with GLM-5.3's text contract pinned in `applyGeneratedModelPolicy` (1M context, 128K output, always-on `low`/`high`/`max` reasoning effort), because models.dev currently lists it with null limits and a catalog regeneration would otherwise degrade it to the unknown-window fallback; it is skip-listed in the autorouting tier map as not yet curated.
35
+ - A content-free generic OpenAI Responses capacity overload no longer ends the turn under the default retry configuration. OpenAI reports it inside an HTTP 200 terminal envelope (`response.failed`, or `response.completed` with a `failed` status), so the turn surfaced `server_is_overloaded: …` and went idle for a failure the provider says to retry. The bare-default admission now also accepts that exact typed code, read only from transport facts and never from prose: the failed attempt must be on the `openai-responses` API, carry `openaiErrorCode` and `providerCode` equal to `server_is_overloaded` (matched case-sensitively) and no other transport fact (no status, no retained retry header, no second typed code, no error kind, no request size, first-event timing, endpoint class, or provider retry ceiling), and carry no assistant text, thinking, or tool call. Under bare defaults, an overload that follows observable work earlier in the same run is still terminal, `retry.enabled: false` still surfaces immediately, and the Codex and Anthropic overload admissions are unchanged. (#5018)
36
+ - A metadata-only touch of the managed transcript file (AV scanning, indexing, backup sync — anything that bumps `mtimeNs`/`ctimeNs` without changing bytes) no longer crashes an interactive session with an unhandled `managed_append_identity_mismatch` rejection. `appendExpectedIdentitySync` compared only `dev`/`ino`/`size`/`mtimeNs`/`ctimeNs` against the persisted expectation, so a present-but-drifted predecessor was rethrown as a genuine successor and killed the process at the next prompt. The append receipt now carries the content digest the append path already computes (`append_managed` binds `sha256` to the final identity), `#captureManagedPersistIdentity` persists that descriptor-bound digest with the expectation, and a mismatching expectation is re-authenticated: identical bytes on the same unlinked file object with an unchanged link count refresh the expectation and proceed, while a changed inode, length, link count, or digest keeps failing closed so a concurrent successor is never overwritten. Regression-tested with two consecutive drifts, an intact successor guarantee, and an interactive input-loop containment test. (#4892)
37
+ - Behavior change: this overload is now treated as a bounded provider-overload replay under explicit `retry.*` settings as well. It previously fell into the unbounded transient-prose retry class (its message matches `overloaded`), so a configured session retried it without limit; it now stops at `retry.maxRetries` with the existing capped exponential backoff, the same bound bare defaults use. (#5018)
38
+ - Managed fallback behavior is preserved for the typed Responses overload: the new transport facts do not change the agent loop's managed transaction handling or the managed chain's retry/advance policy for this failure (the `server` classification remains a session-side classifier only). (#5018)
39
+ - A single refused notification publication no longer kills a live session's chat mirroring for the rest of that session. `SessionRouter.#dispatchNotificationFrame` treated any rejection from the provider hook as terminal and called `#detachNotification(attached, "cancelled")`, which latches `notificationCancelled` on the `AttachedSession`; only a new attachment clears that latch, and a session that keeps running never gets one. The Telegram daemon throws exactly such a per-frame rejection from `#failPublicationPreSend` (for example `Telegram publication rejected before send: trusted attachment lease is stale`) when its topic or attachment lease momentarily fails `#leaseAllows` while another session attaches or detaches, so one transient authority flip permanently silenced that session's topic while every other session kept delivering — the user-visible symptom being Telegram that "works sometimes". Measured on one install over a single day: 20 such rejections across 20 distinct sessions, exactly one each, and 19 of the 20 never emitted another notification frame afterwards (their topic lease heartbeat stopped one to five seconds after the rejection, because the detach removed the endpoint from the daemon). Dispatch now tolerates a bounded run of consecutive local failures before conceding, mirroring `DELIVERY_ATTEMPT_LIMIT` on the ordered-delivery path in the same file: the refused frame is still dropped (the provider has already settled that publication as rejected on its own side), the next delivered frame resets the run, and a provider that never accepts anything is still cancelled after the limit. The `NOTIFICATION_WORK_TIMEOUT` path is deliberately unchanged — a hung provider is a different failure class and keeps its immediate detach — and core attachment authority, replay, lease renewal, and every other detach reason (`removed`, `replaced`, `replaced_same_generation`) are untouched.
40
+ - `gjc update` now recognizes an already verified standalone binary during package-manager shim migration, avoiding repeated downloads and post-update work while clearly explaining the required PATH ordering.
41
+
42
+ - GJC-managed launch worktrees now default to `<repo>/.worktrees/<slug>` instead of a `<repo>.gajae-code-worktrees` sibling beside the checkout, keeping each repository's isolated branches in one predictable local folder. Launch fails with an actionable diagnostic unless an in-repository bucket is ignored by Git, preventing nested worktrees from polluting the source checkout; external `GJC_WORKTREE_DIR` buckets and already registered sibling worktrees are unchanged.
43
+ - Launch worktree reuse now revalidates Git-registered paths before adoption and reports locked or replaced stale entries instead of running Git commands in an unavailable or occupied directory; coordinator policy and Stream Deck project grouping use the repository-local default while retaining legacy sibling-path recognition.
44
+
45
+ ### Fixed
46
+
47
+ - A one-shot `gjc sdk` command no longer idles for five seconds after its response is written. `SessionRouter` bounded four waits with `Bun.sleep` inside `Promise.race`; the race settles on the winner but does not cancel the loser, and a pending `Bun.sleep` keeps the event loop alive, so work that finished in milliseconds still owed the rest of the budget before the process could exit. `gjc sdk session list` wrote its result at 0.50s and exited at 5.51s. The startup attach budget, shutdown timeout, bounded notification work, and replay backoff now use the existing `cancellableSleep` helper with an `AbortController` cancelled once the race settles, and the reconcile interval is unref'd so a Router started without a matching `stop()` does not hold a host process open. The same command now exits at 1.65s, and every command routed through `withRouter` (`session.list`, `session.create`, `session.delete`, `session.fork`, `turn.prompt`, `turn.result`, `queue.*`, `compaction.*`) is affected.
48
+
5
49
  ## [0.15.4] - 2026-08-29
6
50
 
7
51
  - The `ask` tool now rejects empty or whitespace-only custom answers on every local and remote input path. Remote invalid answers receive a visible explanation and are retried at most three times with an event-loop yield between attempts before the ask is cancelled; local empty custom input is never returned as a valid answer. (#5001)
@@ -41,6 +85,7 @@
41
85
  - Foreground activity animation now uses layout-only TUI repaints, avoiding repeated reconstruction of unchanged transcript content during long sessions.
42
86
  - Notification adapters can now opt into one live representation per native effect: adapters that accept a positioned event are excluded from its matching raw fan-out, while ordinary direct SDK and raw-only legacy subscribers retain their existing delivery. Telegram opts in, preventing turn output, tool activity, and reasoning summaries from rendering twice after #4570; acknowledged terminal shutdown delivery is unchanged.
43
87
  - Lean notifications no longer replay a retained completion receipt at idle when identical text was already delivered immediately before an autonomous `ask`; distinct receipts and other settlement windows remain preserved.
88
+ - SDK prompts now publish a bounded structured terminal failure when a provider immediately returns HTTP 402 or 429. The accepted receipt remains non-terminal until the correlated `agent_end`, while `turn.result`/`turn.prompt_status` no longer strand the prompt as `in_flight`; replacement turns remain independently abortable and recoverable. (#4941)
44
89
 
45
90
  ## [0.15.2] - 2026-08-25
46
91
 
@@ -49,7 +94,6 @@
49
94
  - Version 0.15.1 was tagged but never published: release automation failed while deriving release notes, before any package reached npm. Everything listed under `## [0.15.1]` below ships in this release.
50
95
 
51
96
  ## [0.15.1] - 2026-08-25
52
-
53
97
  ### Added
54
98
 
55
99
  - Added `/language [en|ko]`, the interactive slash command for the persisted `ui.language` selection. Without arguments it reports the current language; with a canonical code, locale tag (`en-US`, `ko-KR`), endonym (`한국어`), English name, or common aliases (`eng`, `kr`, `kor`) it persists the canonical `en`/`ko` value through settings and confirms in the selected language. An unsupported value is rejected with the available list and changes nothing. See `docs/ui-language.md`.
@@ -634,7 +678,7 @@
634
678
  ### Added
635
679
 
636
680
  - The SDK `models.list/current` (Q10) catalog now lists model profiles as synthetic `gajae-code/<profile>` entries (e.g. `gajae-code/codex-eco`), and selecting one through `model.set` (or the ACP Model picker) activates the profile for the live session only; global persistence remains the explicit `gjc --mpreset <name> --default` or TUI default-selection path. ACP/SDK clients such as Paseo can therefore offer presets like ordinary models; only availability-filtered profiles are advertised, the reserved `gajae-code` namespace fails closed on collision, and `config.patch` serializes with profile activation through the session admission boundary.
637
- - Added first-class `cline-pass` and `commandcode-goat` provider presets with documented API endpoints, environment-variable credentials, non-hardcoded live model discovery from models.dev and the Command Code Provider API, and prefix-based Claude routing.
681
+ - Added first-class `cline-pass` and `commandcode-goat` provider presets with documented API endpoints, environment-variable credentials, non-hardcoded live model discovery from models.dev and the Command Code Provider API; Command Code models stay on its documented OpenAI-compatible transport regardless of model name.
638
682
  - Registered the `jetbrains-junie` provider in the famous-provider ordering and the `JUNIE_API_KEY` credential help so JetBrains AI (Junie) Claude models surface in `/model`, `--list-models` and `gjc --help` alongside the other first-class providers (#3626).
639
683
  - Added lease-backed MCP connection pooling with typed recovery, shared HTTP/SSE sessions, per-lease callback demultiplexing, and authorization binding scopes that keep credential secrets out of pool keys.
640
684
  - Added plugin registry v2 as the single execution authority for plugin tools, subskills, and prompt appendices, with digest verification at final use.
@@ -21,6 +21,12 @@ export interface AsyncJob {
21
21
  setupFailureSummary?: string;
22
22
  /** Safe, bounded summary of a terminal local (non-provider) failure kind. */
23
23
  localErrorSummary?: LocalErrorSummary;
24
+ /** Compact delivery-failure marker retained while the job row remains live. */
25
+ deliveryFailure?: {
26
+ attempt: number;
27
+ lastError?: string;
28
+ recordedAt: number;
29
+ };
24
30
  metadata?: AsyncJobMetadata;
25
31
  /**
26
32
  * Registry id of the agent that registered the job (e.g. "0-Main",
@@ -38,6 +44,8 @@ export interface AsyncJob {
38
44
  */
39
45
  export declare function jobElapsedMs(job: Pick<AsyncJob, "startTime" | "endTime">, now?: number): number;
40
46
  export interface AsyncJobMetadata {
47
+ /** Set once a foreground wait has been folded, so surfacing can show folded work. */
48
+ backgrounded?: boolean;
41
49
  subagent?: {
42
50
  id: string;
43
51
  agent: string;
@@ -170,11 +178,50 @@ export interface AsyncJobManagerOptions {
170
178
  onJobComplete: (jobId: string, text: string, job?: AsyncJob) => void | Promise<void>;
171
179
  maxRunningJobs?: number;
172
180
  retentionMs?: number;
181
+ maxDeadLetterOverflowOwners?: number;
182
+ }
183
+ export interface AsyncJobAdmission {
184
+ readonly manager: AsyncJobManager;
173
185
  }
174
186
  export interface AsyncJobDisposeDiagnostics {
175
187
  stuckJobIds: string[];
176
188
  deliveriesDrained: boolean;
177
189
  }
190
+ /** Per-job public delivery classification. Exactly one value per terminal job. */
191
+ export type JobDeliveryState = "pending" | "delivered" | "failed-visible";
192
+ /** One job as projected by {@link AsyncJobManager.getJobsSnapshot}. */
193
+ export interface AsyncJobSnapshotEntry {
194
+ id: string;
195
+ kind: string;
196
+ label: string;
197
+ status: AsyncJob["status"];
198
+ generation: string;
199
+ backgrounded: boolean;
200
+ deliveryState: JobDeliveryState;
201
+ }
202
+ /** Scalar delivery-failure evidence that may outlive its AsyncJob record. */
203
+ export interface DeadLetteredJobSnapshotEntry {
204
+ jobId: string;
205
+ generation: string;
206
+ ownerId?: string;
207
+ /** Whether the failed delivery originated from a backgrounded job. */
208
+ backgrounded?: boolean;
209
+ attempt: number;
210
+ lastError?: string;
211
+ recordedAt: number;
212
+ }
213
+ /**
214
+ * One atomic projection of job + delivery state.
215
+ *
216
+ * Computed in a single synchronous pass with no interleaved awaits so it cannot
217
+ * tear, and consumed verbatim: a UI that re-derives delivery classification from
218
+ * separate getters can disagree with this and produce a job that is in no public
219
+ * state at all.
220
+ */
221
+ export interface AsyncJobsSnapshot {
222
+ jobs: AsyncJobSnapshotEntry[];
223
+ deadLettered: DeadLetteredJobSnapshotEntry[];
224
+ }
178
225
  export interface AsyncJobDeliveryState {
179
226
  queued: number;
180
227
  delivering: boolean;
@@ -209,6 +256,8 @@ export interface AsyncJobRegisterOptions {
209
256
  metadata?: AsyncJobMetadata;
210
257
  onProgress?: (text: string, details?: Record<string, unknown>) => void | Promise<void>;
211
258
  lifecycle?: AsyncJobLifecycleCleanup;
259
+ /** Reserved capacity consumed atomically by this registration. */
260
+ admissionToken?: AsyncJobAdmission;
212
261
  }
213
262
  /**
214
263
  * Filter applied to job query/cancel APIs. With `ownerId`, results are
@@ -411,6 +460,10 @@ export declare class AsyncJobManager {
411
460
  */
412
461
  getJobPromise(id: string, generation: string): Promise<void> | undefined;
413
462
  getRunningJobs(filter?: AsyncJobFilter): AsyncJob[];
463
+ /** Whether a new running job can be admitted without starting side effects. */
464
+ hasCapacity(filter?: AsyncJobFilter): boolean;
465
+ reserveCapacity(): AsyncJobAdmission;
466
+ releaseCapacity(token: AsyncJobAdmission): void;
414
467
  getRecentJobs(limit?: number, filter?: AsyncJobFilter): AsyncJob[];
415
468
  getAllJobs(filter?: AsyncJobFilter): AsyncJob[];
416
469
  /**
@@ -450,6 +503,18 @@ export declare class AsyncJobManager {
450
503
  /** Run producer cleanups, then perform the legacy destructive subagent purge. */
451
504
  runOwnerCleanups(filter?: AsyncJobFilter): void;
452
505
  getDeliveryState(filter?: AsyncJobFilter): AsyncJobDeliveryState;
506
+ /**
507
+ * One synchronous pass over jobs plus delivery state.
508
+ *
509
+ * Every returned job carries exactly one {@link JobDeliveryState}, and
510
+ * dead-lettered evidence is included even when its record is already gone, so
511
+ * no terminal job can end up invisible to the UI.
512
+ */
513
+ getJobsSnapshot(filter?: AsyncJobFilter): AsyncJobsSnapshot;
514
+ retainParkedDelivery(job: AsyncJob, text: string): void;
515
+ retainDeliveryClaim(job: AsyncJob): void;
516
+ releaseDeliveryClaim(generation: string): void;
517
+ clearParkedDelivery(generation: string): void;
453
518
  hasPendingDeliveries(filter?: AsyncJobFilter): boolean;
454
519
  watchJobGenerations(jobIds: string[]): AsyncJobWatchHandle;
455
520
  watchJobs(jobIds: string[]): number;
@@ -460,6 +525,19 @@ export declare class AsyncJobManager {
460
525
  * matching agent registered; with no filter, cancels every running job
461
526
  * (used by `dispose()` to nuke the manager's state).
462
527
  */
528
+ /**
529
+ * Synchronously fail a running job AND enqueue its delivery, exactly once.
530
+ *
531
+ * An externally owned wait -- an ACP client terminal, say -- can fail while its
532
+ * owner is being torn down. `cancel()` is the wrong tool there: it marks the job
533
+ * cancelled, and the cancelled path deliberately enqueues NO delivery, so the
534
+ * failure would never become visible to anyone. This is the single transition
535
+ * that both fails the job and delivers that failure in one synchronous block, so
536
+ * it cannot lose the race against disposal.
537
+ */
538
+ failNow(jobId: string, generation: string, errorText: string, options?: {
539
+ abort?: boolean;
540
+ }): boolean;
463
541
  cancelAll(filter?: AsyncJobFilter): void;
464
542
  waitForOwnerInFlightDeliveries(ownerId: string, options?: {
465
543
  timeoutMs?: number;
@@ -468,6 +546,11 @@ export declare class AsyncJobManager {
468
546
  timeoutMs?: number;
469
547
  }): Promise<boolean>;
470
548
  getLastDisposeDiagnostics(): AsyncJobDisposeDiagnostics;
549
+ /**
550
+ * Mark a running job as backgrounded (folded out of its foreground call).
551
+ * Read by getJobsSnapshot so folded work stays visible; safe to call twice.
552
+ */
553
+ markBackgrounded(jobId: string, generation: string): boolean;
471
554
  waitForAll(): Promise<void>;
472
555
  drainDeliveries(options?: {
473
556
  timeoutMs?: number;
@@ -1,9 +1,11 @@
1
+ import { type AuthCredentialSnapshot, type CredentialHealthResult } from "@gajae-code/ai/core";
1
2
  export type AuthGatewayAction = "serve" | "token" | "status" | "check";
2
3
  export interface AuthGatewayCommandArgs {
3
4
  action: AuthGatewayAction;
4
5
  flags: {
5
6
  json?: boolean;
6
7
  bind?: string;
8
+ provider?: string;
7
9
  regenerate?: boolean;
8
10
  /**
9
11
  * Disable bearer-token auth on inbound requests. Useful when the gateway
@@ -14,5 +16,20 @@ export interface AuthGatewayCommandArgs {
14
16
  };
15
17
  }
16
18
  declare const ACTIONS: readonly AuthGatewayAction[];
19
+ export declare function resolveAuthGatewayReadiness(input: {
20
+ noAuth: boolean;
21
+ tokenPresent: boolean;
22
+ credentialCount: number;
23
+ modelCount: number;
24
+ }): {
25
+ ready: boolean;
26
+ reason: "token_missing" | "provider_credential_missing" | "provider_catalog_empty" | null;
27
+ };
28
+ export declare function normalizeProviderScope(provider: string | undefined): string | undefined;
29
+ export declare function filterCredentialCheckResults(results: readonly CredentialHealthResult[], provider: string | undefined): CredentialHealthResult[];
30
+ export declare function redactBrokerUrl(rawUrl: string): string;
31
+ export declare function hasEnabledProviderCredential(snapshot: Pick<AuthCredentialSnapshot, "credentials">, provider: string): boolean;
32
+ export declare function matchesProviderCredential(entry: AuthCredentialSnapshot["credentials"][number], apiKey: string): boolean;
33
+ export declare function assertEnabledProviderCredential(snapshot: Pick<AuthCredentialSnapshot, "credentials">, provider: string): void;
17
34
  export declare function runAuthGatewayCommand(cmd: AuthGatewayCommandArgs): Promise<void>;
18
35
  export { ACTIONS as AUTH_GATEWAY_ACTIONS };
@@ -0,0 +1,9 @@
1
+ export declare const MODEL_PRESETS_ACTIONS: readonly ["status", "refresh", "rollback", "pin", "unpin", "disable", "enable"];
2
+ export type ModelPresetsAction = (typeof MODEL_PRESETS_ACTIONS)[number];
3
+ export interface ModelPresetsCommandArgs {
4
+ action: ModelPresetsAction;
5
+ revision?: string;
6
+ json?: boolean;
7
+ agentDir?: string;
8
+ }
9
+ export declare function runModelPresetsCommand(args: ModelPresetsCommandArgs): Promise<void>;
@@ -1,6 +1,7 @@
1
1
  import { Settings } from "../config/settings";
2
2
  import { type UpdateChannel } from "../config/update-channel";
3
3
  import { type NotificationProvider } from "../sdk/bus/config";
4
+ import type { TelemetryDetails, TelemetryEventName } from "../telemetry";
4
5
  import { type GithubReleaseLookupOptions } from "./github-release";
5
6
  export interface UpdateCommandOptions {
6
7
  force: boolean;
@@ -53,6 +54,11 @@ export type PackageManagerTarget = {
53
54
  manager: "npm";
54
55
  packageName: string;
55
56
  };
57
+ type MigrationUpdateTarget = {
58
+ method: "migrate";
59
+ path: string;
60
+ previousPath?: string;
61
+ };
56
62
  export type UpdateTarget = {
57
63
  method: "bun";
58
64
  } | {
@@ -61,11 +67,7 @@ export type UpdateTarget = {
61
67
  } | {
62
68
  method: "binary";
63
69
  path: string;
64
- } | {
65
- method: "migrate";
66
- path: string;
67
- previousPath?: string;
68
- };
70
+ } | MigrationUpdateTarget;
69
71
  type PathPlatform = NodeJS.Platform;
70
72
  type PackageExists = (packageName: string, packageRoot: string) => boolean;
71
73
  export declare function resolveUpdateMethodForTest(ompPath: string, bunBinDir: string | undefined): "bun" | "npm" | "binary";
@@ -85,6 +87,24 @@ export declare function resolveGjcPathForTest(options: {
85
87
  whichPath: string | undefined;
86
88
  }): string | undefined;
87
89
  export declare function parseReportedVersionForTest(output: string): string | undefined;
90
+ interface MigrationTargetVerificationOptions {
91
+ runtimePath: string;
92
+ verifyChecksum: () => Promise<void>;
93
+ verifyRuntime: () => Promise<InstalledVersionVerification>;
94
+ }
95
+ interface MigrationChecksumOptions {
96
+ tag: string;
97
+ assetName: string;
98
+ filePath: string;
99
+ }
100
+ type MigrationChecksumVerifier = (options: MigrationChecksumOptions) => Promise<unknown>;
101
+ export declare function verifyMigrationTargetForTest(options: MigrationTargetVerificationOptions): Promise<InstalledVersionVerification>;
102
+ export declare function verifyMigrationTargetAdapterForTest(options: {
103
+ release: Pick<ReleaseInfo, "tag" | "version">;
104
+ runtimePath: string;
105
+ verifyChecksum: MigrationChecksumVerifier;
106
+ verifyRuntime: (expectedVersion: string, runtimePath: string) => Promise<InstalledVersionVerification>;
107
+ }): Promise<InstalledVersionVerification>;
88
108
  export declare function formatBinaryDownloadFailureMessageForTest(binaryName: string, url: string, status: string | number, platform?: NodeJS.Platform, registryNote?: string): string;
89
109
  export declare function buildReleaseBinaryUrlForTest(version: string, platform?: NodeJS.Platform, arch?: string): string;
90
110
  export declare function formatManualUpdateInstructionsForTest(platform?: NodeJS.Platform): string;
@@ -123,6 +143,7 @@ export declare function runBinaryUpdateFlow(targetPath: string, url: string, exp
123
143
  export interface UpdateCommandDependencies {
124
144
  getLatestRelease?: (options?: LatestReleaseLookupOptions) => Promise<ReleaseInfo>;
125
145
  resolveUpdateTarget?: () => Promise<UpdateTarget>;
146
+ verifyMigrationTarget?: (release: ReleaseInfo, runtimePath: string) => Promise<InstalledVersionVerification>;
126
147
  performUpdate?: (target: UpdateTarget, expectedVersion: string, registry?: string) => Promise<InstalledVersionVerification | undefined>;
127
148
  refreshInstalledDefaultSkills?: () => Promise<void>;
128
149
  settings?: () => Promise<Settings>;
@@ -130,6 +151,7 @@ export interface UpdateCommandDependencies {
130
151
  restartDaemon?: (settings: Settings) => Promise<void>;
131
152
  recoverNotifications?: (settings: Settings) => Promise<void>;
132
153
  runPostUpdateRecovery?: (runtimePath: string) => Promise<void>;
154
+ recordTelemetryEvent?: (event: TelemetryEventName, details: TelemetryDetails) => unknown;
133
155
  exit?: (code: number) => never;
134
156
  }
135
157
  export type PostUpdateRecoverySpawn = (argv: string[]) => Promise<number>;
@@ -20,6 +20,9 @@ export default class AuthGateway extends Command {
20
20
  description: string;
21
21
  char: string;
22
22
  };
23
+ provider: import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
24
+ description: string;
25
+ };
23
26
  regenerate: import("@gajae-code/utils/cli").FlagDescriptor<"boolean"> & {
24
27
  description: string;
25
28
  };
@@ -2,6 +2,7 @@ import { Command } from "@gajae-code/utils/cli";
2
2
  export default class Gc extends Command {
3
3
  static description: string;
4
4
  static strict: boolean;
5
+ static delegateHelp: boolean;
5
6
  static flags: {
6
7
  json: import("@gajae-code/utils/cli").FlagDescriptor<"boolean"> & {
7
8
  char: string;
@@ -28,6 +29,18 @@ export default class Gc extends Command {
28
29
  description: string;
29
30
  default: boolean;
30
31
  };
32
+ "empty-delete-receipts": import("@gajae-code/utils/cli").FlagDescriptor<"boolean"> & {
33
+ description: string;
34
+ default: boolean;
35
+ };
36
+ root: import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
37
+ description: string;
38
+ multiple: true;
39
+ };
40
+ manifest: import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
41
+ description: string;
42
+ multiple: true;
43
+ };
31
44
  };
32
45
  static examples: string[];
33
46
  run(): Promise<void>;
@@ -0,0 +1,21 @@
1
+ import { Command } from "@gajae-code/utils/cli";
2
+ export default class ModelPresets extends Command {
3
+ static description: string;
4
+ static args: {
5
+ action: import("@gajae-code/utils/cli").ArgDescriptor & {
6
+ description: string;
7
+ required: false;
8
+ options: readonly ["status", "refresh", "rollback", "pin", "unpin", "disable", "enable"];
9
+ };
10
+ revision: import("@gajae-code/utils/cli").ArgDescriptor & {
11
+ description: string;
12
+ required: false;
13
+ };
14
+ };
15
+ static flags: {
16
+ json: import("@gajae-code/utils/cli").FlagDescriptor<"boolean"> & {
17
+ description: string;
18
+ };
19
+ };
20
+ run(): Promise<void>;
21
+ }
@@ -250,6 +250,9 @@ export declare const TIER_MAP_SKIP_LIST: {
250
250
  readonly "zai/glm-5.3": {
251
251
  readonly rationale: "post-rebase catalog addition from dev; not yet curated";
252
252
  };
253
+ readonly "zai/glm-5.3-flash": {
254
+ readonly rationale: "post-feature catalog addition; not yet curated";
255
+ };
253
256
  readonly "cursor/gemini-3.7-flash-high": {
254
257
  readonly rationale: "post-rebase catalog addition from dev; not yet curated";
255
258
  };
@@ -16818,6 +16821,102 @@ export declare const TIER_MAP_SKIP_LIST: {
16818
16821
  readonly baseline: true;
16819
16822
  readonly rationale: "pre-feature baseline; not yet curated";
16820
16823
  };
16824
+ readonly "kiro/auto": {
16825
+ readonly rationale: "Kiro API-key catalog addition; not yet curated";
16826
+ };
16827
+ readonly "kiro/claude-haiku-4-5": {
16828
+ readonly rationale: "Kiro API-key catalog addition; not yet curated";
16829
+ };
16830
+ readonly "kiro/claude-haiku-4.5": {
16831
+ readonly rationale: "Kiro API-key catalog addition; not yet curated";
16832
+ };
16833
+ readonly "kiro/claude-opus-4-5": {
16834
+ readonly rationale: "Kiro API-key catalog addition; not yet curated";
16835
+ };
16836
+ readonly "kiro/claude-opus-4-6": {
16837
+ readonly rationale: "Kiro API-key catalog addition; not yet curated";
16838
+ };
16839
+ readonly "kiro/claude-opus-4-7": {
16840
+ readonly rationale: "Kiro API-key catalog addition; not yet curated";
16841
+ };
16842
+ readonly "kiro/claude-opus-4-8": {
16843
+ readonly rationale: "Kiro API-key catalog addition; not yet curated";
16844
+ };
16845
+ readonly "kiro/claude-opus-4.5": {
16846
+ readonly rationale: "Kiro API-key catalog addition; not yet curated";
16847
+ };
16848
+ readonly "kiro/claude-opus-4.6": {
16849
+ readonly rationale: "Kiro API-key catalog addition; not yet curated";
16850
+ };
16851
+ readonly "kiro/claude-opus-4.7": {
16852
+ readonly rationale: "Kiro API-key catalog addition; not yet curated";
16853
+ };
16854
+ readonly "kiro/claude-opus-4.8": {
16855
+ readonly rationale: "Kiro API-key catalog addition; not yet curated";
16856
+ };
16857
+ readonly "kiro/claude-opus-5": {
16858
+ readonly rationale: "Kiro API-key catalog addition; not yet curated";
16859
+ };
16860
+ readonly "kiro/claude-sonnet-4": {
16861
+ readonly rationale: "Kiro API-key catalog addition; not yet curated";
16862
+ };
16863
+ readonly "kiro/claude-sonnet-4-5": {
16864
+ readonly rationale: "Kiro API-key catalog addition; not yet curated";
16865
+ };
16866
+ readonly "kiro/claude-sonnet-4-6": {
16867
+ readonly rationale: "Kiro API-key catalog addition; not yet curated";
16868
+ };
16869
+ readonly "kiro/claude-sonnet-4.5": {
16870
+ readonly rationale: "Kiro API-key catalog addition; not yet curated";
16871
+ };
16872
+ readonly "kiro/claude-sonnet-4.6": {
16873
+ readonly rationale: "Kiro API-key catalog addition; not yet curated";
16874
+ };
16875
+ readonly "kiro/claude-sonnet-5": {
16876
+ readonly rationale: "Kiro API-key catalog addition; not yet curated";
16877
+ };
16878
+ readonly "kiro/deepseek-3-2": {
16879
+ readonly rationale: "Kiro API-key catalog addition; not yet curated";
16880
+ };
16881
+ readonly "kiro/deepseek-3.2": {
16882
+ readonly rationale: "Kiro API-key catalog addition; not yet curated";
16883
+ };
16884
+ readonly "kiro/glm-5": {
16885
+ readonly rationale: "Kiro API-key catalog addition; not yet curated";
16886
+ };
16887
+ readonly "kiro/gpt-5-6-luna": {
16888
+ readonly rationale: "Kiro API-key catalog addition; not yet curated";
16889
+ };
16890
+ readonly "kiro/gpt-5-6-sol": {
16891
+ readonly rationale: "Kiro API-key catalog addition; not yet curated";
16892
+ };
16893
+ readonly "kiro/gpt-5-6-terra": {
16894
+ readonly rationale: "Kiro API-key catalog addition; not yet curated";
16895
+ };
16896
+ readonly "kiro/gpt-5.6-luna": {
16897
+ readonly rationale: "Kiro API-key catalog addition; not yet curated";
16898
+ };
16899
+ readonly "kiro/gpt-5.6-sol": {
16900
+ readonly rationale: "Kiro API-key catalog addition; not yet curated";
16901
+ };
16902
+ readonly "kiro/gpt-5.6-terra": {
16903
+ readonly rationale: "Kiro API-key catalog addition; not yet curated";
16904
+ };
16905
+ readonly "kiro/minimax-m2-1": {
16906
+ readonly rationale: "Kiro API-key catalog addition; not yet curated";
16907
+ };
16908
+ readonly "kiro/minimax-m2-5": {
16909
+ readonly rationale: "Kiro API-key catalog addition; not yet curated";
16910
+ };
16911
+ readonly "kiro/minimax-m2.1": {
16912
+ readonly rationale: "Kiro API-key catalog addition; not yet curated";
16913
+ };
16914
+ readonly "kiro/minimax-m2.5": {
16915
+ readonly rationale: "Kiro API-key catalog addition; not yet curated";
16916
+ };
16917
+ readonly "kiro/qwen3-coder-next": {
16918
+ readonly rationale: "Kiro API-key catalog addition; not yet curated";
16919
+ };
16821
16920
  };
16822
16921
  export declare const CURATED_TIER_MAP: AutoroutingCuratedTierMap;
16823
16922
  /** Canonical JSON uses sorted object keys and preserves array order. */
@@ -1,3 +1,4 @@
1
+ import type { NativeDirectoryTreeResult, NativeExactUnlinkResult } from "@gajae-code/natives";
1
2
  export interface FileLockOptions {
2
3
  staleMs?: number;
3
4
  retries?: number;
@@ -9,8 +10,12 @@ export interface FileLockOptions {
9
10
  /** Previous local host identities accepted only when deciding stale-owner reclamation. */
10
11
  previousOwnerHostIds?: readonly string[];
11
12
  }
13
+ /** Release retries cover transient Windows/Dropbox handle denial without extending the lock indefinitely. */
14
+ export declare const FILE_LOCK_RELEASE_RETRY_ATTEMPTS = 5;
15
+ export declare const FILE_LOCK_RELEASE_RETRY_DELAY_MS = 10;
12
16
  export declare const FileLockTestHooks: {
13
17
  afterParentMkdir?: (lockPath: string) => void | Promise<void>;
18
+ nativeQuarantineBindings?: () => NativeFileLockBindings;
14
19
  };
15
20
  /**
16
21
  * Returns the OS-provided process start timestamp for PID-reuse detection.
@@ -25,16 +30,46 @@ export declare const FileLockTestHooks: {
25
30
  */
26
31
  export declare function processStartTime(pid: number): string | null;
27
32
  /** @internal */
33
+ export interface FileLockGcObservation {
34
+ info: FileLockOwnerToken;
35
+ bytes: string;
36
+ identity: GenericFileLockDirIdentity;
37
+ }
38
+ /** Capture owner bytes and the identity proving those exact bytes came from this tree. */
39
+ export declare function readFileLockObservationForGc(lockDir: string): Promise<FileLockGcObservation | null>;
40
+ /** @internal */
28
41
  export declare function readFileLockInfoForGc(lockDir: string): Promise<FileLockOwnerToken | null>;
29
42
  /** Owner identity stamped into a `<file>.lock/info` record. */
30
43
  export interface FileLockOwnerToken {
31
44
  pid: number;
32
45
  start_time?: string;
46
+ /** Encoding marker for the canonical UTC process-start identity. */
47
+ start_time_format?: string;
33
48
  owner_host_id?: string;
49
+ /** Unique acquisition generation, present on locks created by this runtime. */
50
+ owner_token?: string;
34
51
  timestamp: number;
35
52
  }
36
53
  /** Outcome of a guarded lock-dir removal attempt (`removeFileLockDirForGc`). */
37
- export type FileLockGcRemoval = "removed" | "owner_changed" | "missing";
54
+ export type FileLockGcRemoval = "removed" | "owner_changed" | "missing" | "cleanup_failed";
55
+ /** Identity evidence carried by the generic stale verdict into a later removal. */
56
+ export interface GenericFileLockDirIdentity {
57
+ rootDev: string;
58
+ rootIno: string;
59
+ infoDev: string;
60
+ infoIno: string;
61
+ infoNlink: string;
62
+ infoSize: string;
63
+ infoMtimeNs: string;
64
+ infoCtimeNs: string;
65
+ infoSha256: string;
66
+ }
67
+ export type GenericFileLockDirStaleVerdict = {
68
+ stale: false;
69
+ } | {
70
+ stale: true;
71
+ identity: GenericFileLockDirIdentity;
72
+ };
38
73
  /**
39
74
  * @internal
40
75
  * Fail-closed removal of a lock dir whose owner is expected to be dead or
@@ -52,7 +87,7 @@ export type FileLockGcRemoval = "removed" | "owner_changed" | "missing";
52
87
  * directory, so the residual read->unlink window cannot be fully eliminated,
53
88
  * but the reclaim-after-stale scenario the issue describes is now guarded.
54
89
  */
55
- export declare function removeFileLockDirForGc(lockDir: string, expected: FileLockOwnerToken): Promise<FileLockGcRemoval>;
90
+ export declare function removeFileLockDirForGc(lockDir: string, expected: FileLockOwnerToken, preVerdictIdentity?: GenericFileLockDirIdentity): Promise<FileLockGcRemoval>;
56
91
  /**
57
92
  * @internal
58
93
  * READ-ONLY verdict on an EXISTING generic `<file>.lock/` directory that another lock
@@ -71,6 +106,17 @@ export declare function removeFileLockDirForGc(lockDir: string, expected: FileLo
71
106
  * the object is no longer the one that was judged.
72
107
  */
73
108
  export declare function genericFileLockDirIsStale(lockDir: string, staleMs: number, ownerHostId?: string): Promise<boolean>;
109
+ /**
110
+ * Render a generic stale verdict together with the root and owner-file identity that
111
+ * verdict actually observed. A caller that removes the directory must require a later
112
+ * native snapshot to carry this same identity; a snapshot taken only after a clone was
113
+ * installed is not authority for the stale verdict.
114
+ */
115
+ export declare function genericFileLockDirStaleVerdict(lockDir: string, staleMs: number, ownerHostId?: string): Promise<GenericFileLockDirStaleVerdict>;
116
+ type NativeFileLockBindings = {
117
+ snapshotDirectoryTree(lockPath: string): NativeDirectoryTreeResult;
118
+ exactRemoveDirectoryTree(lockPath: string, snapshot: NonNullable<NativeDirectoryTreeResult["snapshot"]>): NativeExactUnlinkResult;
119
+ };
74
120
  /**
75
121
  * Serializes all contenders, including callers in the same process. Because this
76
122
  * API exposes no ownership token, recursive acquisition is indistinguishable
@@ -78,3 +124,4 @@ export declare function genericFileLockDirIsStale(lockDir: string, staleMs: numb
78
124
  * that fact through its own `lockHeld` path instead of acquiring it again.
79
125
  */
80
126
  export declare function withFileLock<T>(filePath: string, fn: () => Promise<T>, options?: FileLockOptions): Promise<T>;
127
+ export {};
@@ -0,0 +1,4 @@
1
+ import type { ModelPresetRegistryTrustedKey } from "../model-preset-registry";
2
+ export declare function getModelPresetRegistryTestTrustedKeys(agentDir: string): ReadonlyMap<string, ModelPresetRegistryTrustedKey> | undefined;
3
+ export declare function modelPresetRegistryTestUrlsAllowed(agentDir: string): boolean;
4
+ export declare function runWithModelPresetRegistryTestTrust<T>(agentDir: string, trustedKeys: ReadonlyMap<string, ModelPresetRegistryTrustedKey>, operation: () => T): T;
@@ -0,0 +1,3 @@
1
+ import type { ModelPresetRegistryTrustedKey } from "../model-preset-registry";
2
+ /** Runs one test operation with scoped trust. This module is denied by package exports. */
3
+ export declare function withModelPresetRegistryTestTrust<T>(agentDir: string, trustedKeys: ReadonlyMap<string, ModelPresetRegistryTrustedKey>, operation: () => T): T;