@gajae-code/coding-agent 0.15.1-nightly.20260823084028.32692335596.g28e375925cf5 → 0.15.2

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 (230) hide show
  1. package/CHANGELOG.md +78 -2
  2. package/dist/types/capability/index.d.ts +2 -0
  3. package/dist/types/capability/types.d.ts +7 -5
  4. package/dist/types/cli/github-release.d.ts +47 -0
  5. package/dist/types/cli/setup-cli.d.ts +4 -0
  6. package/dist/types/cli/update-cli.d.ts +18 -4
  7. package/dist/types/commands/setup.d.ts +12 -0
  8. package/dist/types/config/autorouting-tier-map.d.ts +3 -0
  9. package/dist/types/config/file-lock.d.ts +3 -1
  10. package/dist/types/config/machine-identity.d.ts +19 -0
  11. package/dist/types/config/model-registry.d.ts +1 -1
  12. package/dist/types/config/model-resolver.d.ts +4 -3
  13. package/dist/types/config/models-config-schema.d.ts +4 -0
  14. package/dist/types/config/settings-schema.d.ts +22 -5
  15. package/dist/types/config/settings.d.ts +2 -0
  16. package/dist/types/coordinator-mcp/codex-handoff.d.ts +3 -0
  17. package/dist/types/coordinator-mcp/codex-wake-publisher.d.ts +9 -1
  18. package/dist/types/coordinator-mcp/policy.d.ts +13 -0
  19. package/dist/types/coordinator-mcp/question-gate-codec.d.ts +11 -2
  20. package/dist/types/coordinator-mcp/question-state.d.ts +193 -14
  21. package/dist/types/coordinator-mcp/server.d.ts +41 -23
  22. package/dist/types/discovery/index.d.ts +1 -1
  23. package/dist/types/eval/py/executor.d.ts +3 -0
  24. package/dist/types/eval/py/kernel.d.ts +3 -1
  25. package/dist/types/exec/bash-executor.d.ts +3 -1
  26. package/dist/types/extensibility/custom-tools/types.d.ts +1 -1
  27. package/dist/types/extensibility/extensions/runner.d.ts +3 -1
  28. package/dist/types/extensibility/extensions/types.d.ts +49 -5
  29. package/dist/types/extensibility/gjc-plugins/lifecycle.d.ts +17 -1
  30. package/dist/types/extensibility/gjc-plugins/registry.d.ts +13 -0
  31. package/dist/types/extensibility/gjc-plugins/types.d.ts +7 -1
  32. package/dist/types/extensibility/plugins/manager.d.ts +8 -0
  33. package/dist/types/extensibility/plugins/marketplace/manager.d.ts +14 -1
  34. package/dist/types/extensibility/shared-events.d.ts +3 -1
  35. package/dist/types/extensibility/skills.d.ts +2 -0
  36. package/dist/types/gjc-runtime/coordinator-sidecar-bootstrap-worker.d.ts +1 -0
  37. package/dist/types/gjc-runtime/launch-tmux.d.ts +6 -0
  38. package/dist/types/gjc-runtime/launch-worktree.d.ts +1 -0
  39. package/dist/types/gjc-runtime/session-state-lock.d.ts +16 -0
  40. package/dist/types/gjc-runtime/session-state-sidecar.d.ts +7 -0
  41. package/dist/types/gjc-runtime/windows-powershell-command.d.ts +7 -1
  42. package/dist/types/modes/acp/acp-event-mapper.d.ts +1 -1
  43. package/dist/types/modes/components/frictionless-onboarding-selector.d.ts +28 -0
  44. package/dist/types/modes/components/gajae-pet-widget.d.ts +2 -1
  45. package/dist/types/modes/components/iterm-pet-transport.d.ts +1 -0
  46. package/dist/types/modes/components/pet-capability.d.ts +4 -1
  47. package/dist/types/modes/controllers/selector-controller.d.ts +1 -0
  48. package/dist/types/modes/interactive-mode.d.ts +3 -4
  49. package/dist/types/modes/types.d.ts +10 -12
  50. package/dist/types/modes/ui-language.d.ts +35 -0
  51. package/dist/types/runtime-mcp/config.d.ts +3 -0
  52. package/dist/types/sdk/acp/adapter.d.ts +7 -0
  53. package/dist/types/sdk/broker/broker.d.ts +2 -0
  54. package/dist/types/sdk/broker/lifecycle.d.ts +23 -3
  55. package/dist/types/sdk/broker/session-index.d.ts +37 -1
  56. package/dist/types/sdk/broker/transport.d.ts +1 -1
  57. package/dist/types/sdk/bus/config.d.ts +0 -1
  58. package/dist/types/sdk/bus/engine.d.ts +0 -1
  59. package/dist/types/sdk/bus/helpers.d.ts +0 -1
  60. package/dist/types/sdk/bus/index.d.ts +1 -3
  61. package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +8 -1
  62. package/dist/types/sdk/bus/reconciliation-store.d.ts +4 -0
  63. package/dist/types/sdk/bus/telegram-daemon-cli.d.ts +2 -0
  64. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +1 -1
  65. package/dist/types/sdk/bus/telegram-daemon.d.ts +4 -15
  66. package/dist/types/sdk/bus/telegram-reference.d.ts +10 -1
  67. package/dist/types/sdk/host/session-runtime.d.ts +10 -1
  68. package/dist/types/sdk/lifecycle/service.d.ts +17 -9
  69. package/dist/types/sdk/prompt-deadline-lease.d.ts +2 -0
  70. package/dist/types/sdk/prompt-deadline-manager.d.ts +15 -0
  71. package/dist/types/sdk/router/session-router.d.ts +35 -0
  72. package/dist/types/sdk/session.d.ts +1 -1
  73. package/dist/types/session/agent-session.d.ts +9 -2
  74. package/dist/types/session/agent-storage.d.ts +5 -2
  75. package/dist/types/session-import/provider-service.d.ts +10 -1
  76. package/dist/types/setup/frictionless-onboarding.d.ts +77 -0
  77. package/dist/types/setup/hermes-setup.d.ts +30 -2
  78. package/dist/types/ssh/ssh-executor.d.ts +3 -0
  79. package/dist/types/tools/ask.d.ts +0 -8
  80. package/dist/types/tools/auto-generated-guard.d.ts +5 -2
  81. package/dist/types/tools/bash-interactive.d.ts +2 -0
  82. package/dist/types/tools/context.d.ts +7 -2
  83. package/dist/types/tools/image-gen.d.ts +4 -4
  84. package/dist/types/tools/python.d.ts +3 -0
  85. package/dist/types/utils/herdr-pane.d.ts +11 -1
  86. package/dist/types/web/search/index.d.ts +32 -4
  87. package/dist/types/web/search/provider.d.ts +5 -2
  88. package/dist/types/web/search/providers/base.d.ts +19 -1
  89. package/dist/types/web/search/providers/exa.d.ts +3 -2
  90. package/dist/types/web/search/providers/searxng.d.ts +6 -3
  91. package/dist/types/web/search/providers/utils.d.ts +5 -1
  92. package/package.json +7 -7
  93. package/scripts/compile-args.ts +2 -0
  94. package/scripts/generate-sdk-operation-inventory.ts +3 -0
  95. package/scripts/generate-tool-catalog.ts +2 -1
  96. package/scripts/verify-gjc-sdk-canonicalization.ts +6 -0
  97. package/src/capability/index.ts +13 -2
  98. package/src/capability/types.ts +7 -5
  99. package/src/cli/github-release.ts +235 -0
  100. package/src/cli/plugin-cli.ts +90 -18
  101. package/src/cli/setup-cli.ts +59 -5
  102. package/src/cli/skills-cli.ts +23 -19
  103. package/src/cli/update-cli.ts +447 -130
  104. package/src/commands/sdk.ts +59 -36
  105. package/src/commands/setup.ts +23 -2
  106. package/src/config/autorouting-tier-map.ts +1 -0
  107. package/src/config/file-lock.ts +27 -5
  108. package/src/config/machine-identity.ts +177 -0
  109. package/src/config/model-profiles.ts +31 -31
  110. package/src/config/model-registry.ts +121 -49
  111. package/src/config/model-resolver.ts +9 -4
  112. package/src/config/models-config-schema.ts +1 -1
  113. package/src/config/settings-schema.ts +19 -5
  114. package/src/config/settings.ts +39 -9
  115. package/src/coordinator-mcp/codex-handoff.ts +56 -7
  116. package/src/coordinator-mcp/codex-wake-publisher.ts +80 -7
  117. package/src/coordinator-mcp/event-webhook.ts +6 -2
  118. package/src/coordinator-mcp/policy.ts +83 -3
  119. package/src/coordinator-mcp/question-gate-codec.ts +82 -4
  120. package/src/coordinator-mcp/question-state.ts +1899 -247
  121. package/src/coordinator-mcp/server.ts +4513 -1046
  122. package/src/defaults/gjc/skills/autoresearch/SKILL.md +22 -3
  123. package/src/defaults/gjc/skills/deep-interview/SKILL.md +1 -1
  124. package/src/discovery/builtin.ts +12 -16
  125. package/src/discovery/index.ts +1 -0
  126. package/src/discovery/opencode.ts +11 -8
  127. package/src/edit/modes/patch.ts +1 -1
  128. package/src/eval/py/executor.ts +53 -6
  129. package/src/eval/py/index.ts +2 -1
  130. package/src/eval/py/kernel.ts +7 -2
  131. package/src/exec/bash-executor.ts +3 -1
  132. package/src/extensibility/custom-tools/types.ts +1 -1
  133. package/src/extensibility/extensions/loader.ts +2 -1
  134. package/src/extensibility/extensions/runner.ts +6 -0
  135. package/src/extensibility/extensions/types.ts +126 -3
  136. package/src/extensibility/gjc-plugins/lifecycle.ts +90 -14
  137. package/src/extensibility/gjc-plugins/registry.ts +20 -0
  138. package/src/extensibility/gjc-plugins/types.ts +8 -0
  139. package/src/extensibility/plugins/manager.ts +11 -0
  140. package/src/extensibility/plugins/marketplace/manager.ts +31 -4
  141. package/src/extensibility/shared-events.ts +3 -1
  142. package/src/extensibility/skills.ts +8 -1
  143. package/src/gjc-runtime/coordinator-sidecar-bootstrap-worker.ts +50 -0
  144. package/src/gjc-runtime/launch-tmux.ts +222 -13
  145. package/src/gjc-runtime/launch-worktree.ts +132 -0
  146. package/src/gjc-runtime/session-state-lock.ts +302 -51
  147. package/src/gjc-runtime/session-state-sidecar.ts +149 -21
  148. package/src/gjc-runtime/tmux-sessions.ts +5 -13
  149. package/src/gjc-runtime/windows-powershell-command.ts +8 -0
  150. package/src/hashline/execute.ts +2 -2
  151. package/src/internal-urls/docs-index.generated.ts +15 -13
  152. package/src/main.ts +60 -21
  153. package/src/modes/acp/acp-agent.ts +90 -45
  154. package/src/modes/acp/acp-event-mapper.ts +22 -0
  155. package/src/modes/components/frictionless-onboarding-selector.ts +268 -0
  156. package/src/modes/components/gajae-pet-widget.ts +102 -7
  157. package/src/modes/components/iterm-pet-transport.ts +9 -3
  158. package/src/modes/components/pet-capability.ts +8 -2
  159. package/src/modes/components/settings-selector.ts +66 -23
  160. package/src/modes/controllers/command-controller.ts +3 -3
  161. package/src/modes/controllers/event-controller.ts +4 -3
  162. package/src/modes/controllers/extension-ui-controller.ts +2 -0
  163. package/src/modes/controllers/input-controller.ts +1 -1
  164. package/src/modes/controllers/selector-controller.ts +98 -10
  165. package/src/modes/interactive-mode.ts +17 -14
  166. package/src/modes/shared/agent-wire/event-contract.ts +1 -0
  167. package/src/modes/shared/agent-wire/event-envelope.ts +1 -0
  168. package/src/modes/shared/agent-wire/event-observation.ts +9 -0
  169. package/src/modes/types.ts +11 -4
  170. package/src/modes/ui-language.ts +94 -0
  171. package/src/runtime-mcp/config.ts +4 -0
  172. package/src/sdk/acp/adapter.ts +153 -12
  173. package/src/sdk/broker/broker.ts +38 -4
  174. package/src/sdk/broker/lifecycle.ts +453 -70
  175. package/src/sdk/broker/runtime.ts +40 -1
  176. package/src/sdk/broker/session-index.ts +232 -1
  177. package/src/sdk/broker/transport.ts +1 -3
  178. package/src/sdk/bus/chat-daemon-control.ts +2 -2
  179. package/src/sdk/bus/chat-daemon-runtime.ts +0 -2
  180. package/src/sdk/bus/config.ts +1 -4
  181. package/src/sdk/bus/engine.ts +1 -5
  182. package/src/sdk/bus/helpers.ts +1 -1
  183. package/src/sdk/bus/inbound-reaction-ordering.ts +12 -9
  184. package/src/sdk/bus/index.ts +23 -8
  185. package/src/sdk/bus/kind-aware-reconciliation.ts +96 -14
  186. package/src/sdk/bus/reconciliation-store.ts +38 -8
  187. package/src/sdk/bus/telegram-daemon-cli.ts +12 -1
  188. package/src/sdk/bus/telegram-daemon-contract.ts +1 -1
  189. package/src/sdk/bus/telegram-daemon.ts +73 -85
  190. package/src/sdk/bus/telegram-reference.ts +14 -3
  191. package/src/sdk/cli/session-cli.ts +229 -21
  192. package/src/sdk/client/client.ts +12 -1
  193. package/src/sdk/host/reverse-leases.ts +7 -0
  194. package/src/sdk/host/session-runtime.test.ts +1650 -31
  195. package/src/sdk/host/session-runtime.ts +1042 -91
  196. package/src/sdk/lifecycle/service.ts +22 -12
  197. package/src/sdk/models.ts +5 -3
  198. package/src/sdk/prompt-deadline-lease.ts +13 -2
  199. package/src/sdk/prompt-deadline-manager.ts +292 -8
  200. package/src/sdk/protocol/operation-inventory.generated.json +22 -0
  201. package/src/sdk/router/session-router.ts +163 -3
  202. package/src/sdk/session.ts +106 -27
  203. package/src/session/agent-session.ts +388 -104
  204. package/src/session/agent-storage.ts +9 -5
  205. package/src/session/contribution-prep.ts +2 -2
  206. package/src/session-import/provider-service.ts +31 -3
  207. package/src/setup/frictionless-onboarding.ts +769 -0
  208. package/src/setup/hermes/templates/operator-instructions.v1.md +21 -3
  209. package/src/setup/hermes-setup.ts +483 -81
  210. package/src/slash-commands/builtin-registry.ts +55 -0
  211. package/src/ssh/ssh-executor.ts +3 -1
  212. package/src/tools/ask.ts +0 -9
  213. package/src/tools/auto-generated-guard.ts +17 -5
  214. package/src/tools/bash-interactive.ts +2 -1
  215. package/src/tools/bash.ts +4 -0
  216. package/src/tools/context.ts +6 -2
  217. package/src/tools/descriptors.ts +1 -0
  218. package/src/tools/image-gen.ts +5 -6
  219. package/src/tools/index.ts +8 -1
  220. package/src/tools/python.ts +5 -0
  221. package/src/tools/ssh.ts +2 -1
  222. package/src/tools/vim.ts +2 -2
  223. package/src/tools/write.ts +1 -1
  224. package/src/utils/herdr-pane.ts +240 -5
  225. package/src/web/search/index.ts +157 -38
  226. package/src/web/search/provider.ts +51 -9
  227. package/src/web/search/providers/base.ts +21 -1
  228. package/src/web/search/providers/exa.ts +8 -6
  229. package/src/web/search/providers/searxng.ts +64 -21
  230. package/src/web/search/providers/utils.ts +25 -7
package/CHANGELOG.md CHANGED
@@ -2,29 +2,97 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
- ## [0.15.0] - 2026-08-22
5
+ ## [0.15.2] - 2026-08-25
6
+
7
+ ### Changed
8
+
9
+ - 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.
10
+
11
+ ## [0.15.1] - 2026-08-25
12
+
13
+ ### Added
14
+
15
+ - 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`.
16
+ - Added a persisted, owner-directed `ui.language` selector for human-facing settings chrome, with deterministic English fallback and an independently authored initial Korean catalog. Commands, flags, environment variables, canonical values, JSON, and other protocol output remain unchanged. Localization-boundary guidance was informed by the unofficial, unaffiliated MIT-licensed community patch [`yazzang-homelab/gajae-code-ko@aff1bfa`](https://github.com/yazzang-homelab/gajae-code-ko/commit/aff1bfa097789a8e2f13349da3c7f99b008d93b6). (#4919)
17
+ - Added frictionless interactive onboarding for unresolved users and `/tutorial`. GJC now performs bounded, local metadata discovery across known coding-agent roots, requires corroborating activity within 90 days before inferring a workflow, falls back to manual guidance when evidence is insufficient, persists only a derived profile and completion decision, discloses unavailable sources, and previews the guided migration result before a single explicit apply or experienced-user skip.
18
+ - vLLM servers are now discovered implicitly at `http://127.0.0.1:8000/v1`, the same zero-config UX as Ollama, LM Studio, and oMLX. The existing descriptor lane remains authoritative so implicit discovery does not race or replace authenticated/custom vLLM discovery evidence. Credentialless discovery is loopback-only; trusted shell/user-env `VLLM_BASE_URL` plus `VLLM_API_KEY`, or an explicit `models.yml` provider entry, supports remote servers. Adds `discovery.type: "vllm"`.
19
+ - SGLang servers are now discovered implicitly at `http://127.0.0.1:30000/v1`, the same zero-config UX as Ollama, LM Studio, oMLX, and vLLM. The existing descriptor lane remains authoritative so implicit discovery does not race or replace authenticated/custom SGLang discovery evidence. Credentialless discovery is loopback-only; trusted shell/user-env `SGLANG_BASE_URL` plus `SGLANG_API_KEY`, or an explicit `models.yml` provider entry, supports remote servers. Adds `discovery.type: "sglang"`.
20
+ - Standalone GitHub release binaries now publish `gajae-release-binaries-v1.json` and `gajae-release-binaries.sha256` so installers and `gjc update` can verify downloads.
21
+
22
+ ### Changed
23
+
24
+ - End-user install and `gjc update` are standalone-binary-first and do not require Bun. `scripts/install.sh` / `install.ps1` default to the current platform GitHub release (stable, `--channel nightly`, or `--ref <tag>`), never detect or download Bun, and keep `--source` as an explicit development path that requires an already-installed Bun. `gjc update` resolves channels from GitHub releases, atomically replaces a matching binary, migrates package-manager shims to a user binary path instead of overwriting them, and refuses to self-overwrite source checkouts or `dev:link` executables.
25
+ - The five `macOS Local (oMLX)` presets are retuned from same-machine throughput measurements (#4871). All presets now use one role-effort ladder — critic and architect `high`, planner `medium`, executor and default `low` — and pick each preset's model by measured local throughput: `fast` keeps the 4-bit and `balanced` the 8-bit Qwen 3.6 35B A3B MoE quants (93.5 / 71.1 tok/s measured), `quality` keeps the 8-bit MoE for default/executor/planner/architect and routes only the critic to the official dense `Qwen3.8-27B-8bit` checkpoint (public SWE-bench/agent scores still favor dense for criticism), and both `abliterated` presets move to the faster `Qwen3.8-27B-Uncensored-MLX-4bit` (19.8 tok/s measured, ahead of the Abliterated 4-bit/6-bit quants on every measured axis). Preset display names now state the measured throughput instead of the memory-tier hints.
26
+
27
+ ### Fixed
6
28
 
29
+ - Onboarding language detection (`/tutorial`, first-run onboarding) no longer misreads English or Korean transcripts as French, Spanish, or German. Word evidence for space-delimited languages is matched on token boundaries instead of substrings — `le`/`la`/`el` used to match inside `file`, `please`, `class`, and `help`, so plain English handed French a majority — Korean, Japanese, and Chinese are identified by script instead of particle substrings, script counts and word hits share one ranking so two Hangul or Han characters cannot override a clearly English transcript, a claimant script needs two characters before it may claim mixed han text so one stray Hangul or kana glyph cannot erase dominant han evidence, a language must lead the runner-up outright to beat the OS locale, and an explicit `ui.language` selection outranks both. `/language` also accepts locale tags such as `en-US` / `ko-KR` and now rejects hostile inputs that used to resolve to inherited object properties (`__proto__`, `constructor`) instead of canonical `en`/`ko`.
30
+ - `ask` question wording and option labels no longer use the post-resample U+2014 display-text exemption because accepted calls enter durable session history and deep-interview rounds; genuinely display-only tool fields retain the existing exemption (#4926).
31
+ - Gajae Pet now treats forwarded `LC_TERMINAL=iTerm2` and `TERM_PROGRAM=iTerm.app` values as probe hints over SSH, enabling iTerm2 only after an active OSC 1337 File-capability reply. Generic SSH, spoofed/noninteractive/CI environments, and unmanaged tmux/screen/zellij nesting remain on the text fallback; verified Kitty and Sixel keep precedence. (#4911)
32
+ - Interactive terminal completion now publishes the local `agent_end` boundary before waiting for the ordered coordinator sidecar write, so slow or lock-hostile WSL drvfs mounts cannot leave the foreground activity indicator and composer busy after a turn has completed. Coordinator persistence ordering and extension delivery remain unchanged. (#4741)
33
+ - One unresponsive session host can no longer own SDK Router startup. A host whose listener still accepts while its loop never serves answers nothing, and `SessionRouter.start()` awaited the initial attach pass, so startup cost the sum of every such session's request budget: measured at 40.7s of a 40.9s startup for a single spinning host, against the 10s budget `gjc sdk session list` gives startup — every SDK CLI call on that agent directory failed with `SDK session Router startup timed out` while eleven healthy sessions had attached in under 200ms combined. `start()` now bounds the initial pass (5s) and lets it finish in the background, and an attach replay whose frame was dispatched and left unanswered (`uncertain_after_send`) no longer runs the 3-retry ladder against a peer that cannot answer any of them. Per-request replay budgets are unchanged, so a host that is legitimately slow — settling a cancellation grace, for example — is not cut off; the periodic 2s reconcile keeps converging stragglers. Measured on the same workspace: startup 40.9s to 5.1s.
34
+
35
+ - Telegram polling no longer wedges behind a deleted private-chat `forum_topic_created` update. Definitive missing-topic `400` responses from the adoption picker now consume the stale update, remove only its matching pending-topic sidecar, and let the ordered poll offset advance; rate limits, network/server failures, authentication failures, and ambiguous responses remain retryable. (#4904)
36
+ - Quota and rate-limit exhaustion now keep AuthStorage's already-computed unblock instant on the terminal provider error as `retryable at <ISO-8601>`. All-row exhaustion still surfaces immediately with no wait and no extra retry loop (#4908).
37
+ - ACP sessions re-register reverse providers when a permission lease expires or the same client reattaches. Guarded tools no longer fail permanently with `no permission provider is connected` after the reverse-lease TTL/reclaim grace lapses on a still-living session (#4909).
38
+
39
+ - `gjc --worktree` now runs the declared Bun, npm, or pnpm frozen install in workspace launch worktrees instead of linking the origin checkout's `node_modules`. Workspace imports and install mutations are bound to the worktree's own lockfile and checkout, including reuse of worktrees carrying the legacy source-tree link (#4620).
40
+ - Custom OpenAI-compatible models now expose and send reasoning levels only when their transport capability is known or explicitly opted in. Arbitrary proxies no longer inherit a universal `reasoning_effort` assumption from `reasoning: true`; `compat.supportsReasoningEffort: false` keeps the selector, persisted effort controls, and outbound payload aligned, while bundled OpenRouter, OpenCode, Kilo, and other audited provider routes retain their existing reasoning controls (#4903).
41
+ - Late conventional MCP connections publish into the active session registry through an ordered, failure-isolated chain: concurrent late snapshots can no longer interleave a stale tool list, one failed publication no longer kills every later one, and mixed plugin + conventional sessions re-seal the fixed connection set once the last conventional server settles instead of staying reloadable.
42
+ - User skill discovery now follows the active `agentDir` profile, matching MCP and customization writers instead of silently reading the default home-relative profile. The bundled `deep-interview` trigger no longer claims explicit third-party Ouroboros commands.
43
+ - `gjc setup hermes` no longer hardcodes the Hermes MCP client timeouts. New `--timeout` / `--connect-timeout` flags (whole seconds, 1–3600, exit 2 on anything else) override the 180/60 defaults, and `--install` now preserves existing numeric `timeout` / `connect_timeout` values from a GJC-marked block per field when the flag is omitted — a hand-set `timeout: 900` survives re-installs instead of being reset to 180 (#4878). The managed setup signature no longer pins those two operator knobs (hand-tuning keeps the block managed and `--check` no longer flags timeout drift), and unmarked blocks keep the existing refusal and `--force` full-overwrite behavior. Docs/help now state these are host MCP client call budgets — not GJC turn deadlines and not the coordinator per-call caps (`watch_events` 30000 ms; `await_turn` 30 minutes). Upgrading a pre-#4878 install: a block still matching its stored signature is re-signed on the next `--install`; a hand-tuned legacy block is refused with a dedicated stale-signature error pointing at `--force` (which preserves the tuned values); `--profile-dir` targets holding an older operator-instructions render need one `--force` because that file's digest pins its exact content. Unpreservable values (non-numeric or out of range) fall back to defaults with an explicit warning instead of being written through.
44
+
45
+ - Bumped Telegram daemon durable authority to generation 176 after the SDK lifecycle changes modified protected broker declarations. Older generation-175 daemons are now unattachable by this host, preserving fail-closed discovery and launch ownership across rolling upgrades (#4668).
46
+ - Gajae Pet now stays reachable in tmux and image-protocol-free SSH clients through a bounded two-row text-cell rendering. The fallback derives conservative Block Elements from the active skin, uses truecolor when available and ANSI-256 otherwise, reserves no extra transcript rows, and retains the pixel renderer unchanged for supported Kitty, Sixel, and iTerm2 terminals (#4867).
47
+ - `gjc setup hermes --gjc-command` now accepts the full server command instead of always appending `mcp-serve coordinator` (#4877). Omitted or single-token values stay executable-only and render byte-identically to previous output (`gjc`, `/opt/gjc` + `args: [mcp-serve, coordinator]`); a multi-token value is the complete command, split quote-aware (single/double quotes, backslash escapes) into controller argv and rendered verbatim with nothing appended — `--gjc-command 'python3 /tmp/gjc-wrapper.py'` now emits `command: python3`, `args: [/tmp/gjc-wrapper.py]`, exactly the shape a wrapper that already execs `gjc mcp-serve coordinator` needs instead of the doubled argv tail it previously received. Unbalanced quotes are rejected with an explicit error; the value is tokenized, never shell-evaluated. Setup signatures are computed from the rendered block, so existing installs and idempotent re-installs remain valid.
48
+
49
+ - Corrected the session-state lock recovery contract documented for 0.15.0: valid dead regular state owners are reclaimed automatically, while foreign, unqualified, malformed owners and post-crash atomic transition directories remain fail-closed for explicit operator recovery.
50
+ - Python kernel reuse is once again keyed on the settings values that shape a kernel, not on `Settings` object identity. Binding built-in executors to session settings (#4826) made `scopedSessionId` suffix each kernel key with a per-instance counter, so two logical sessions in one process — which resolve the same shell configuration and therefore spawn byte-identical kernels — each started their own kernel, and disposing one shut down a kernel the other still owned. The scope is now a fingerprint of the resolved shell config (shell, args, environment), so equivalent settings share one retained kernel while genuinely different shell environments stay isolated.
51
+ - Flat Telegram private-chat idle markers now carry a short per-session tag (`🟢 Agent idle · <tag>`), because the flat fallback has no topic to identify which session went idle (#4855). Asks and threaded/topic delivery are unchanged, preserving the identity-once contract from #981; the tag is the last six characters of the session id and no full session id is ever rendered. The discarded `sessionTag` parameter threaded through `buildRedactedAction`, `notificationActionPayload`, and `NotificationPresentationEngine` — computed but never consumed anywhere — was removed.
52
+
53
+ ## [0.15.0] - 2026-08-22
7
54
 
8
55
  ### Added
9
56
 
57
+ - Added `router.SessionRouter.generationStatus(sessionId, endpointGeneration)`, a public credential-free exact-generation reconciliation predicate for managed SDK consumers. It returns deterministic `current`, positively evidenced `retired`, live-generation `replaced`, or fail-closed `unknown` results without exposing endpoint URL/token credentials, process IDs, locators, or private Broker payloads. Close/delete proof is durable across Router and Broker restart within the bounded session-index retention policy; unavailable/incomplete reconciliation, expired history, ambiguous authority, and detected generation reuse remain unknown (#4848).
58
+ - The bundled `autoresearch` skill now cooperatively drives missions through GJC goal mode: after spec or cold-intake persistence, the agent creates or resumes a matching inline goal so the continuation loop nudges the mission to a structured verdict receipt. Active or paused goals owned by another objective suppress creation and remain untouched; inconclusive means `status.disposition: "inconclusive"`, while only `status.disposition: "conclusive"` requests mission auto-clear after goal completion. Manual clear, handoff, and cancel require the agent to drop only the mission's own nonterminal goal when the runtime permits it; generic goal guards, aborts, and handoffs can leave state open, so failed steps are surfaced and retried on re-entry without rewriting completed goals as dropped. Verdict writes are append-only and not idempotent, so uncertain retries must inspect the latest receipt before issuing another verdict. Instruction-only: no runtime code, config keys, guards, or `ask` blocking.
10
59
  - Added an SDK `automationTools` option for host-owned `browser` and `computer` implementations. External automation retains built-in activation and provenance, receives the normal abort signal, works independently of the default browser/platform gates, and fails closed on custom, extension, or MCP name collisions (#4809).
11
60
  - Added opt-in Task autorouting that derives deterministic `fast`, `balanced`, and `strong` model tiers from declared provider priority. Tier generation is catalog-scoped and auth-independent, `/routing` opens the smart-routing setup panel, and bounded preflight evidence records candidate skips and acceptance outcomes.
12
61
 
13
62
  ### Changed
14
63
 
64
+ - `macos-omlx-quality` now routes every role through `omlx/Qwen3.6-35B-A3B-8bit` instead of the BF16 checkpoint, retaining the profile's higher reasoning-effort ladder while reducing the local model footprint and improving measured generation throughput on its M5 Max 128 GB target. The preset group label now uses the branded `macOS Local (oMLX)` casing throughout the public profile picker.
15
65
  - Upgrade note: restart the SDK broker after upgrading (`gjc sdk` callers pick this up automatically on the next launch; an already-running daemon does not). This release adds the `model.resolve` broker operation, and the broker discovery record carries no package-generation fence — a daemon left running from an earlier version keeps serving and answers the new operation with `unknown_operation`, so coordinator `model` pins (`gjc_coordinator_start_session`) fail until it is replaced. Verified against a live daemon: the failure is loud, no session is created, and one broker restart clears it.
16
66
  - Closed the remaining Sentry triage approval races: `gh` is resolved only from trusted system paths, acknowledgement rechecks and records under the creation lock, pending-create reconciliation uses a per-attempt nonce with compare-and-clear, and malformed timestamp suffixes fail ingestion before rendering. Regression coverage pins the retry/apply interleaving so a newer unresolved create cannot be cleared by an older `--retry-pending` request.
17
67
 
18
68
  - The SDK session index now self-repairs on append when it finds a corrupt suffix, instead of throwing `Cannot append to corrupt session index log` until an operator runs `gjc gc --repair-session-index`. The inline path reuses the same quarantine-backed repair (evidence preserved under `sessions/quarantine`, valid prefix republished), so a single poisoned row — e.g. a stale long-lived broker signing a `lifecycle_terminal` event against an outdated `indexSeq` — no longer wedges every subsequent session launch in that agent dir; the manual `gc` flag remains for non-converging damage.
19
69
  - Breaking: removed `task.autorouting.preset` and the autorouting preset layer. Preset-only autorouting configuration is inactive until tiers are generated from smart-routing setup; public routing contracts no longer expose preset/source fields, and routing notes contain tier, fallback, and resume components only.
20
70
  - Autorouting selectors now use one shared provider-qualified grammar and 256-character bound across runtime validation, generated tiers, routing evidence, and JSON Schema. Settings-derived tiers report provenance only when the provenance is valid; malformed provenance fails closed as hand-authored tiers.
71
+
72
+ ### Fixed
73
+
74
+ - Cleanly exiting foreground turns now settle on filesystems such as CephFS that reject Linux `renameat2` exchange/no-replace. State owners rewrite their identity-verified, machine-qualified records into reusable PID-1 compatibility tombstones, while transition ownership uses atomic `mkdir`/`rmdir` with a validated sidecar; no live release unlinks a pathname that a successor can race. Foreign, unqualified, malformed, and all post-crash state/transition owners remain fail-closed for explicit operator recovery.
75
+ - Telegram inbound reaction acks now stay serialized per update id when an earlier ack settles while a later one is still in flight. `InboundReactionSequencer` deleted the per-update chain unconditionally on settle, so a fast `accepted` ack settling dropped the tail an in-flight `consumed` transition had installed, and the next transition for that update chained onto a fresh promise and ran concurrently — letting a replayed queued marker race the terminal consumed marker the sequencer promises can never be overwritten. The chain delete is now identity-guarded, matching the router's other serialization tail-maps, and tombstone eviction tracks the maximum terminal update id so reverse-order effect completion cannot grow the retained map without bound.
76
+ - The Sentry triage approval store (`scripts/sentry-crash-issues.ts`) now works on Windows without weakening its local approval boundary. Windows store directories, files, and lock metadata receive and verify native protected owner-only DACLs bound to retained filesystem identities instead of relying on synthetic POSIX mode bits; reads use an identity-checked handle, so reparse or pathname substitution fails closed. Lock acquisition now publishes a fully initialized candidate through the native atomic no-replace rename primitive instead of classifying Windows `EPERM` from ordinary directory replacement, stale owners are displaced only after definitive process absence, and cleanup uses an exact native directory-tree snapshot so a successor lock cannot be removed through the stale-owner pathname.
77
+ - `Esc` abort with a cleanup budget now actually recovers the session when a provider stream ignores its abort signal. After the budget fired and the agent was force-aborted, the abort still awaited the aborted-turn drain, which waits on the wedged prompt's in-flight count — a count that only drops when the wedged `agent.prompt(...)` settles, which force-abort does not make happen. The abort therefore never released its unwind, and every later prompt, message, and abort waited on that unwind forever: a permanent input lockout announced as "forced session recovery". Forced recovery now abandons the exact prompts that were in flight when it fired (tracked by identity, since prompts overlap and do not settle FIFO): the aborted-turn drain and the agent_end defer/flush gates stop waiting on abandoned prompts, the forced terminal `agent_end` publishes instead of parking behind them, and an abandoned prompt that does settle later still cleans up after itself. A bounded abort that piggybacks on an earlier unbounded abort's unwind also no longer discards its own budget: it races the shared unwind and forces the same recovery on the first abort's behalf, so a user `Esc` issued while an extension- or tool-initiated abort is wedged can still recover the session.
78
+ - Terminal `agent_end` now retires the foreground `Working…` indicator even when the mutable session streaming flag settles late. The terminal event remains authoritative across later background-task refreshes, while the next `agent_start` re-enables normal streaming activity.
79
+ - Bash tool globs with a trailing separator (`pattern*/`) now match directories only, and literal components after a glob (`*/name`) now require the resulting path to exist, matching bash/POSIX pathname expansion. The vendored shell's expander appended post-glob literal components (including the empty component a trailing `/` splits into) without any filesystem check, so `LICENSE*/` matched the plain file `LICENSE`, `ls -d */` received file arguments and exited 1, `for d in */` iterated over files, and `*/absent` fabricated paths that were never on disk. Directory checks follow symlinks (matching bash `*/` semantics) while literal-suffix existence uses lstat (dangling symlinks still match); patterns whose last component is itself a glob are unchanged since their matches come from directory reads.
21
80
  - Workflow handoffs out of autoresearch now transit properly: `/skill:deep-interview`, `/skill:ralplan`, and `/skill:ultragoal` chain from any live autoresearch phase (`intake`/`research`/`verdict`), and ralplan's `final` phase chains via its manifest terminal states; ralplan/ultragoal live phases still require the explicit write-to-handoff step. `gjc autoresearch clear` remains the finalize-only exit.
81
+ - The coordinator idle reaper now judges idle eligibility against the durable WAL's turn activity watermark (`recovery.prompt_watermark_at`, falling back to the session's creation stamp for turn-less sessions) instead of the projection session-state stamp. Projection repair (and any failed close admission) rewrites that state file with a fresh `now` stamp, which reset the idle clock after every failed `session.close` and deferred the reaper's same-key retry by a full idle TTL. The reaper retry contract (`coordinator-reap:<session>:<incarnation>` key reuse) holds again, and an ephemeral session older than the TTL whose last turn completed recently is no longer reapable between turns; the projection stamp remains the fallback only for sessions whose WAL cannot be read. The `stop-session` and `send-prompt-concurrency` lifecycle suites were also re-based onto the post-#4731 durable layout (canonical WAL + namespaced projections; broker `session.create` mocks echo `coordinatorSidecarKeyId`), restoring them to the required CI set (#4835).
22
82
  - Breaking: autoresearch spec intake is now the explicit `intake` verb (`gjc autoresearch intake --spec <path>`; the bare `--spec` flag form still works). The ambiguous `handoff` verb token is rejected with disambiguation hints instead of silently becoming a cold-intake goal — workflow handoff lives at `/skill:<callee>` (or `gjc state autoresearch handoff --to <callee>`).
23
83
  - Subagents now start correctly on Bun 1.4 when extension tools provide custom renderers. `RegisteredToolAdapter` installs its renderer adapters before proxying the definition, avoiding a write through the proxy's getter-only property while preserving the no-renderer fallback path.
24
84
 
25
85
  ### Fixed
26
86
 
87
+ - Added a fail-closed recursive-deletion boundary to test preloads: recursive cleanup now derives the real home from the account database rather than mutable HOME/TMPDIR values, accepts the supported `/tmp` and `/var/tmp` fixture roots only when they are disjoint from that home, refuses roots, shallow or symlink-escaping targets and unowned paths, and determines Darwin case handling from filesystem evidence; HOME-sensitive fixtures use the safe cleanup contract and static scan, while runtime interception aborts unsafe Bun test processes without touching the target (#4794).
88
+ - `sdk session tail --until-idle` now reconciles retained replay and live lifecycle events that carry a `(generation, seq)` position by that canonical order instead of arrival order, so a retained terminal event from an earlier turn no longer completes a newer turn that is still active, and a terminal event observed live is no longer undone by replayed history arriving after it. Positioned event items are emitted canonically ahead of an arrival-ordered segment of events carrying no position; such an event stays visible but cannot supersede a positioned turn state, including for live Router frames without a publication position. Different lifecycle kinds claiming one `(generation, seq)` now fail closed with `protocol_error` instead of letting arrival order decide, and that conflict outranks an otherwise successful idle or close completion. A canonical position must be a pair of non-negative safe integers, checked on the raw replayed event-ring row before projection: a row stating either coordinate property must state both validly, so claiming one coordinate only, or a null, negative, fractional, non-finite, or unsafe-integer coordinate, fails closed with `protocol_error` rather than being silently treated as unpositioned. Only a row stating neither coordinate is unpositioned. Retained transcript entries now deduplicate independently of event-ring rows, so a transcript row projecting the same kind and position as a real event no longer suppresses that event's lifecycle or conflict evidence. `session status <sessionId> <opRef>` remains the lossless authority for a specific prompt operation; a bare live tail otherwise remains attached until its timeout unless the session closes.
89
+
90
+ - `gjc plugin uninstall --dry-run` no longer performs the uninstall it was asked to preview. `plugin.ts` parsed `--dry-run` but `handleUninstall` never received it, so a preview removed the plugin through all three uninstall paths and reported `Uninstalled` — most visibly `gjc plugin uninstall <name>@<marketplace> --scope user --dry-run --json`, which deregistered the plugin and deleted its cache. Preview is now a separate read-only API per path rather than an early return inside the mutating one, so under `--dry-run` the handler only ever reaches code that cannot write: `previewGjcBundleUninstall`, `MarketplaceManager.resolveUninstallTarget`, and `PluginManager.previewUninstall`. Each resolves and validates exactly what the real uninstall would act on — GJC registry entry and installed-root containment, marketplace target lookup with scope disambiguation and cache-path validation, npm package-name validation — so a preview refuses whatever the real uninstall refuses. The uninstall entry points keep their existing signatures and result shapes.
91
+ - A `gjc plugin uninstall --dry-run` for *any* target no longer migrates the GJC plugin registry. GJC-bundle classification runs before a target is selected, so it read the registry for every uninstall target — including npm and marketplace names that never reach the GJC path — through a migrating read that persists legacy-root discovery under the scope lock. With a legacy bundle present at `<cwd>/.gjc/gjc-plugins/<name>` (files on disk, no registry entry), a dry run for an unrelated npm name created and wrote `registry.json` in project scope. Preview classification now uses `readEffectiveRegistryUnpersisted`, which applies legacy discovery and entry migration in memory only: the preview still sees the same entries the real uninstall would act on, without persisting them and without taking the lock (acquiring it would itself create the scope root and a lockfile). Real uninstalls keep the migrating read.
92
+ - An unreadable (corrupt) GJC scope registry now makes `gjc plugin uninstall` fail closed for *any* target, dry-run or real. Classification previously skipped an unreadable scope as non-ownership and fell through to the marketplace/npm branches, so a corrupt registry that actually owned the requested name could preview — and the real command could then remove — a same-named marketplace or npm plugin the user never targeted. The refusal is a typed error naming the unreadable scope with a repair hint; nothing is removed while ownership is unknown. The exported mutating GJC uninstall API keeps its historical `invalid_target` result for a malformed registry; only the read-only preview surfaces the internal `registry_unreadable` signal the CLI fails closed on.
93
+ - `gjc plugin uninstall <name>@<marketplace> --json` now emits JSON instead of the human `✔ Uninstalled …` line, which the marketplace branch printed even in JSON mode.
27
94
  - Fixed long skill-HUD entries corrupting bottom-pinned TUI row accounting by emitting at most two independent width-bounded rows and preserving severity glyphs through narrow truncation.
95
+ - Image generation now receives the owning session's settings through direct, TUI, tmux, and coordinator/sub-session tool contexts, so `modelRoles.image` resolves for Codex image models without consulting mutable global state (#4826).
28
96
 
29
97
  - SDK `goal.list/get` no longer reports `resource_gone` when an in-flight session's live goal projection is temporarily unavailable. It recovers the latest authoritative goal mode state from the current session branch after runtime recreation or session replacement, while goal-less sessions return an explicit `no_active_goal` diagnostic instead of being confused with snapshot-store loss (#4824).
30
98
 
@@ -34,6 +102,8 @@
34
102
  - Queued SDK prompts now retain their dispatch-time ownership across selection fences instead of reclassifying from a contradictory later streaming snapshot. Fresh promotion, earlier follow-up ordering, and terminal-abort cancellation are reachable again, while `/btw` test fixtures now model the user-drainable queue count required by the current empty-submit contract.
35
103
  - Coordinator stop and idle-reap now initialize canonical namespace state before reading durable deletion recovery. Fresh or upgraded projection-only sessions were misreported as `state_corrupt` before the broker close was attempted, and completed deletion receipts were excluded from the idempotent missing-session lookup; both paths now preserve strict malformed-state rejection while allowing safe cleanup and replay.
36
104
  - Fixed provider safety-stop classification being lost before session persistence (#4777). The managed provider-envelope boundary now preserves only the allowlisted `provider_safety_stop` kind, typed safety stops remain terminal even with transport facts on a multi-model fallback chain, and the regression e2e test is selected both by the focused affected-path route and exactly one normal coding-agent shard.
105
+ - A forged `errorKind: "provider_safety_stop"` label can no longer suppress model fallback (#4777 review). Terminal safety-stop authority is now adapter-minted (module-scoped provenance set by the first-party anthropic/openai/google adapters when they parse a structured refusal) rather than carried on message data: the loop strips unauthenticated labels at the stream exit, the managed discard gate re-verifies identity, and transport facts never upgrade provenance, so a compromised provider that names the typed kind on an error envelope degrades to an ordinary fallback-eligible failure on every status (400 and 429 both keep advancing the chain). Authenticated envelopes remain single-dispatch terminal with the manual-switch hint intact, and persisted/reloaded sessions retain the legacy display classification without retaining live terminal authority, so restart/replay stays fail-closed.
106
+ - The provider safety-stop minting path is now package-private and capability-branded; public AI imports and structural custom-stream payloads cannot forge terminal authority. Trailing stream completion now sanitizes the final message before managed-shell rebuilding when no `done` or `error` event was emitted, preserving fallback for forged labels (#4777 review).
37
107
  - Retained-publication acquisition diagnostics now name the stage that actually refused instead of always claiming a failed open, and the native errno vocabulary is closed over the actionable `open(2)` refusal set (#4764). `nativeRetainedObstruction()` rendered every unmatched reason as "could not be opened", so a `broker.json` FIFO — which opens fine `O_RDWR | O_NOFOLLOW | O_NONBLOCK` and then refuses `read_to_end` with `WouldBlock` — was reported as an open failure that had in fact succeeded, `clone`/`metadata` refusals of already-open descriptors were reported as opens, and `unsupported-platform` read as an open error. The structured native reason now drives the prose: `errno-`/`io-` render as open refusals, `read-<kind>` as a read failure, `clone-`/`metadata[-kind]` as inspection failures of an already-open object, `unsupported-platform` as unimplemented authority, and any future reason falls back to a stable "withheld publication authority (reason)" sentence instead of misnaming the stage; the structured reason is preferred whenever the native message parses, so the observed-state fallback is never entered for a stage-named refusal. The Rust `errno_name()` vocabulary adds `EAGAIN`, `EMFILE`, `ENAMETOOLONG`, `ENFILE`, `ENOMEM`, `EOVERFLOW`, and `EPERM` alongside the existing six — descriptor exhaustion and LSM/seccomp denial no longer collapse to `UNKNOWN` — while every unlisted errno still renders as `UNKNOWN` and no errno number or OS string ever leaves the native layer.
38
108
  - `move_session` no longer lets a cwd transition commit inside an in-flight tool's execution (#4629). The previous fence re-checked the cwd generation and then yielded, so a move that started inside a tool's first `await` retargeted work already admitted against the launcher root: bash computed `commandCwd` from the live session cwd only after `expandInternalUrls`, running a root-A command in root B. Relative-path tools now hold a shared read lease on the session cwd for their whole execution (`SessionManager.runWithCwdReadLease`), and writers drain outstanding leases before committing, so the cwd observed at admission stays authoritative until the tool finishes. Announced writers also block newly arriving readers, so a stream of tool calls cannot starve a queued move, and async bash jobs stay bound to the cwd they were admitted for.
39
109
  - `move_session` re-roots the state the model is shown at the new cwd (#4629). The volatile per-turn message reported the post-move cwd while attaching the launch-bound workspace tree, and subagents launched at the live cwd inherited startup `contextFiles`, `skills`, and `workspaceTree` — pairing the new cwd with the retired root's files and project instructions, which drives wrong path selection rather than merely stale display. Project context files and skills are now re-discovered after a committed move, the workspace-tree service resolves the live cwd per scan instead of capturing the launch root, the cached tree is retired so the next turn re-scans, and the system prompt is rebuilt from the live cwd.
@@ -41,10 +111,12 @@
41
111
  - `move_session` now verifies process-cwd identity against the pinned directory handle (#4629). The no-follow handle was only ever `stat()`ed while the commit and `setProjectDir` resolved the target *name*, so a replacement after the last comparison escaped the validated descendant — the confinement the tool exists to enforce. Node exposes no `fchdir`, so the post-`chdir` cwd's inode identity is now compared against the pinned handle and the chdir is rolled back on mismatch.
42
112
  - Process-cwd authority is now an explicit claim rather than an inference (#4629). `move_session` decided it owned the process cwd when `process.cwd() === session.cwd`, which two sessions launched at the same root both satisfy, so rescoping one called process-global `setProjectDir`, `resetCapabilities`, `shutdownAllLspClients`, and plugin-cache clearing underneath its sibling — reaching real execution through consumers such as browser tab work. `SessionManager.claimProcessCwdOwnership` grants the claim to one live manager; a session without it moves its own cwd and leaves process-global state untouched.
43
113
  - Conventional MCP autoload now reads the user scope from the agent directory instead of a home-relative `<home>/.gjc/agent` path (#4767). Every writer and denylist reader already resolved user scope through `getMCPConfigPath("user")` (the agent directory), while native discovery derived it from the load context's home, so the two disagreed the moment an agent-directory profile was in play: `GJC_CODING_AGENT_DIR=<profile> gjc mcp add <name>` wrote `<profile>/mcp.json` and reported the server as loaded by ordinary sessions at startup, but startup read `~/.gjc/agent/mcp.json` — the profile's own registrations never loaded and the default profile's servers loaded into the profile instead. `loadAllMCPConfigs` accepts an `agentDir`, sessions created with their own `agentDir` pass it, and the `disabledServers` denylist follows the same scope, so discovery, `gjc mcp add`, the `/mcp` wizard, and `gjc customize doctor` all name one file. This also restores isolation for the MCP autoload suites, which established their temp user scope with `setAgentDir()`: after the trusted-home provenance rework their `os.homedir()` mock no longer reached discovery, so on a developer machine the red-team suite read the real `~/.gjc/agent/mcp.json` and in CI it found nothing.
114
+ - Accepted SDK prompt controls now receive a bounded zero-progress deadline at durable acceptance or promotion, renew every correlation attached to a shared run, fence expiry before late lifecycle adoption, and reconcile `agent_failed` through the typed extension event. The `goal.list/get` goal-less response remains an explicit `no_active_goal` diagnostic page; integrations using `onQueuedPromoted` must handle both `startsOwnRun` dispositions.
44
115
  - Immediate `turn.prompt` after `turn.abort` acknowledgement now starts exactly one successor turn instead of being silently consumed by aborted-turn teardown. Abort unwind no longer classifies the successor as steering into the dying loop, delayed `agent_end` is paired with the aborted invocation rather than the successor, and abort acknowledgement waits for that serialized terminal transition — no client-side sleep (#4749). Retention is bounded in the other direction too: abort stays terminal across overlapping aborts. Every abort request advances an abort-admission epoch synchronously, including one that shares an already in-flight unwind, so a prompt admitted between two aborts is refused as a cancelled preflight instead of refreshing its generation and starting work the user already aborted twice. An abort sharing another abort's unwind also applies its own request-scoped effects (preflight cancellation, and abort visibility so a later real abort is not silenced by an earlier `silent: true` abort). A prompt admitted after an abort settles still starts a normal successor turn.
45
116
  - Esc/Ctrl+C now recover a WSL/basic-terminal session whose busy indicator outlived its turn (#4741). Both the global interrupt/clear listener and the editor escape handler treated any mounted working loader as unconditionally cancellable work: after a completed turn left the loader mounted, every press ran a no-op abort, consumed the key, and reset the escape gestures, so the composer stayed `working [esc]`/`Fetching … [esc]` and Esc, Ctrl+C, and Ctrl+X never did anything (Ctrl+Z suspend/resume was the only escape). The loading branch now stops the stale indicator via the shared activity-indicator stop and lets the key fall through to idle semantics when there is no pending submission (including a started one still inside prompt preflight, exposed through the new `hasPendingSubmission()` context query), no queued steering/follow-up/compaction messages, and the session is neither streaming nor compacting; active work (streaming, queued messages, pending optimistic or started-preflight submission) still aborts exactly as before. Recovery gates on drainable queues only: the new `AgentSession.drainableQueuedMessageCount` counts exactly the steering and follow-up entries that `clearQueue()`/`popLastQueuedMessage()`/`getQueuedMessageEntries()` return, whereas the aggregate `queuedMessageCount` also counts hidden next-turn context that no key press can drain and that deliberately survives turn completion (a `todo_write` failure reminder queued with `deliverAs: "nextTurn"` and no `triggerTurn`) — gating on the aggregate left a permanently nonzero count that reproduced the same lockout while idle. Hidden next-turn ordering and delivery are unchanged; recovery neither clears nor delivers those entries. The same correction applies to the two adjacent gates whose handlers are also visible-queue-only: `app.message.sendNow` no longer advertises itself when only hidden context is queued (its only outcome was "No visible queued message to send"), and an empty submit while streaming no longer aborts the live turn to flush a queue that holds nothing drainable.
46
117
  - Bare-default Codex and Anthropic provider-overload retries now honor the configured retry ceiling instead of entering the unbounded transient path, and every replay still requires a clean retry scope after extension lifecycle handlers participate.
47
- - `gjc accounts` command errors no longer escape as uncaught exceptions in text mode. `accounts pin` resolves its target through `resolveOAuthPinTarget`, which throws a typed `OAuthCredentialSelectorError` for user-correctable selector problems (API-key rows, active overrides, disabled or missing accounts, ambiguity), and `runAccountsCommand` rendered `AccountsCommandError` only in `--json` mode — text mode rethrew everything, so even the command's own "Provider … is not configured; no pin was written" surfaced as a stack trace plus a `gjc-crash.log` entry. Selector failures now map to `AccountsCommandError` with the message preserved (so `--json` reports `accounts-error` instead of `internal-error`), and text mode prints one clean stderr line with exit code 1. The framework's `CliParseError` handling and the JSON machine contract (exactly one document, never stacks or secrets) are unchanged.
118
+ - `gjc accounts` command errors no longer escape as uncaught exceptions in text mode. `accounts pin` resolves its target through `resolveOAuthPinTarget`, which throws a typed `OAuthCredentialSelectorError` for user-correctable selector problems (API-key rows, active overrides, disabled or missing accounts, ambiguity), and `runAccountsCommand` rendered `AccountsCommandError` only in `--json` mode — text mode rethrew everything, so even the command's own "Provider … is not configured; no pin was written" surfaced as a stack trace plus a `gjc-crash.log` entry. Selector failures now map to `AccountsCommandError` with the message preserved (so `--json` reports `accounts-error` instead of `internal-error`), and text mode prints one clean stderr line with exit code 1 instead of an uncaught exception.
119
+ - Reverted the SDK broker package-generation fence (#4862 and its follow-ups). Broker discovery no longer refuses reuse, retires, or signals a live broker because its published `packageGeneration` / `packageVersion` / `installationIdentity` differ from the caller's, so `gjc sdk …`, ACP, and coordinator callers stop failing with `SDK broker package generation … does not match expected generation …`. An in-place upgrade needs the broker stopped once (`bun run restart:sdk-broker` from a source checkout, or stop the published `broker-internal` pid) instead of an automatic retirement handshake.
48
120
  - Fixed interactive steering stalling during post-prompt unwind when the terminal transcript message is a bash or Python execution; the auto-continue gate now treats all three terminal roles consistently and regression coverage pins delivery for assistant, bash, and Python tails (#4739).
49
121
  - Restored live subagent progress in the `subagent await` panel through a bounded public DTO. #4748 dropped the `progress` field believing it exposed model-generated deltas and tool output to the parent model; the renderer needs live status, tool names, output counts, fast mode, and retry state, but raw progress must not enter tool-result, ACP, or telemetry envelopes. The await signature now tracks only those approved fields and ignores countdown-only churn, so the panel updates without exposing model deltas, tool arguments, arbitrary output, or nested task payloads.
50
122
  - Dev CI no longer re-runs the entire code-validation matrix when a pull request body is edited. The verdict line lives in the PR body, so every review verdict update fired a `pull_request: edited` event; with `cancel-in-progress: true` that cancelled the run already validating the identical tree and re-queued the whole matrix against it. Cancelled runs surfaced as confusing downstream failures rather than clean cancellations -- a job would report `Artifact not found for name: dev-affected-plan-<run>` while that artifact existed and its producer had succeeded. `edited` stays in the trigger list because `pr-contract-bootstrap` must re-check the body, but it is now the only job that runs for it; every code-validation root carries an explicit guard and the remaining jobs inherit it through their dependency on a skipped plan.
@@ -98,6 +170,10 @@
98
170
  - Fixed an SDK broker that stops publishing while its process stays alive blocking every client permanently (#4704). The publication tick is a chain of awaited IO -- the machine-global session-index lock, the retained heartbeat write, the host checkpoint -- and a fence is only reachable from an observation that returned or an error that was thrown, so a stall that does neither armed neither the loss nor the ambiguity deadline. The broker then held its port and its lock with a published heartbeat aging far past its TTL, and peers refused to reclaim a lock whose owner pid is alive, so every `paseo run --provider gjc`, `gjc sdk`, and ACP launch failed with `Broker lock is held by a live owner (pid N)` until the process was killed by hand (observed: 13.6 hours, after a `session index "heartbeat checkpoint" still holds the index lock after 10s` warning that escalated to nothing). Liveness is now measured from the last *successful* publication rather than from being scheduled: a broker that has published nothing within `max(60s, heartbeatTtl * 4)` terminates itself as `lost-root`, so the dead-owner reclaim from #3963 hands the lock to its successor. The check runs before any await in the tick and on every tick even while an earlier one is still in flight, so a stalled chain cannot starve the path that ends it, and ticks no longer stack behind a stalled predecessor. The retained heartbeat's positional write and its `fsync` also moved off the JS thread onto the libuv blocking pool (`heartbeatAsync`/`syncAsync`, replacing the synchronous bindings): both are unbounded, and running them on the JS thread let a wedged filesystem stop the timers, signal handlers, and broker completion along with the write they were blocking -- a process that could not even notice it had stopped publishing. The retained handle is split accordingly, so shutdown is not merely moved behind the same stall: the single-writer lock is taken only on the pool, while `observe()` and `close()` need the descriptors rather than the write ordering and take a lock held for a pointer read alone. Closing therefore detaches immediately -- an unresolved worker keeps its own reference, observes the closed flag, and returns without committing a heartbeat against authority the owner has already given up -- so `lost-root` completion finishes and the lock stays reclaimable by the successor while the stalled write is still outstanding.
99
171
  - The per-turn project context now carries the host's local date, clock time, UTC offset, and IANA zone (`Today is 2026-08-19 (Wed), the local time is 21:04 UTC+09:00 (Asia/Seoul)`) instead of `new Date().toISOString().slice(0, 10)`. The agent previously received a bare UTC calendar date with no clock and no zone, so it reported every timestamp it read from files, logs, git, and APIs in UTC — forcing users outside UTC to convert by hand — and was a full day wrong for east-of-UTC users during their local morning (00:00–09:00 KST rendered as the previous date). The same block now instructs the agent to convert timestamps explicitly identified as UTC to that local zone while preserving timestamps that already include an offset or timezone. Rendering is derived from a single `Intl.DateTimeFormat` pass over one resolved zone, with deterministic UTC fallback for invalid clock values, so date, clock, offset, and zone can never disagree, and the vestigial UTC `date`/`dateTime` fields are dropped from the cached stable system prefix, which never rendered them. The zone follows runtime process configuration and may be influenced by project environment settings; it is display context, not trusted location evidence. Full IANA-zone output can reveal geographic information, and date/time overrides are accepted only in the strict derived formats used by deterministic tests.
100
172
 
173
+ ### Fixed
174
+
175
+ - A gjc session no longer disappears from Herdr's sidebar when the Herdr server is replaced under it. A server restart or `herdr update --handoff` starts with an empty agent registry, and the reporter deduplicates against the last state it sent, so a session waiting at its prompt stayed invisible until the user typed into it. The reporter now watches the pane's API socket — replacement rebinds the same path to a new inode — and re-reports its current state and last title when that happens.
176
+
101
177
  ## [0.14.2] - 2026-08-20
102
178
 
103
179
  ### Added
@@ -17,6 +17,8 @@ export declare function loadCapability<T>(capabilityId: string, options?: LoadOp
17
17
  * Call this once on startup to enable persistent provider state.
18
18
  */
19
19
  export declare function initializeWithSettings(activeSettings: Settings): void;
20
+ /** Remove a disposed session scope without disturbing a newer replacement. */
21
+ export declare function releaseSettingsScope(activeSettings: Settings): void;
20
22
  /** Disable a provider for the supplied session settings. */
21
23
  export declare function disableProvider(providerId: string, activeSettings?: Settings): void;
22
24
  /** Enable a provider for the supplied session settings. */
@@ -19,17 +19,19 @@ export interface LoadContext {
19
19
  * (`getAgentDir()`), which `--agent-dir`, `GJC_CODING_AGENT_DIR` and
20
20
  * `setAgentDir()` redirect away from `<home>/.gjc/agent`. `loadCapability`
21
21
  * always sets it; ad-hoc contexts built for path scanning may omit it, and
22
- * consumers then fall back to the same process-wide `getAgentDir()`.
22
+ * native providers then fall back to the home-relative default
23
+ * `<home>/<configDirName>/agent` (see `resolveUserAgentDir` in
24
+ * `discovery/builtin.ts`).
23
25
  *
24
26
  * A native surface whose write path targets the agent directory resolves its
25
- * user scope from here, or discovery reads a different file than the one the
26
- * writer produced: `gjc mcp add` (user scope) writes `getMCPConfigPath("user")`
27
- * under this directory. Surfaces whose writers are home-relative (skills) keep
28
- * resolving from `home`.
27
+ * user scope from here, or discovery reads a different file than the writer
28
+ * produced. This includes MCP registrations and user-installed skills.
29
29
  */
30
30
  userAgentDir?: string;
31
31
  /** Git repository root (directory containing .git), or null if not in a repo */
32
32
  repoRoot: string | null;
33
+ /** Owning session settings for provider policy decisions. */
34
+ settings?: Settings;
33
35
  }
34
36
  /**
35
37
  * Result from a provider's load function.
@@ -0,0 +1,47 @@
1
+ /**
2
+ * GitHub release lookup and checksum helpers for binary install/update.
3
+ * End-user updates resolve versions from GitHub, not the npm registry.
4
+ */
5
+ import type { UpdateChannel } from "../config/update-channel";
6
+ export declare const RELEASE_REPO = "Yeachan-Heo/gajae-code";
7
+ export declare const GITHUB_API_ORIGIN = "https://api.github.com";
8
+ export declare const GITHUB_RELEASE_DOWNLOAD_ORIGIN = "https://github.com/Yeachan-Heo/gajae-code/releases/download";
9
+ export declare const BINARY_SHA256_ASSET = "gajae-release-binaries.sha256";
10
+ export declare const BINARY_MANIFEST_ASSET = "gajae-release-binaries-v1.json";
11
+ export interface GithubReleaseInfo {
12
+ tag: string;
13
+ version: string;
14
+ channel: UpdateChannel;
15
+ htmlUrl?: string;
16
+ warnings: string[];
17
+ }
18
+ export type GithubFetch = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
19
+ export interface GithubReleaseLookupOptions {
20
+ channel?: UpdateChannel;
21
+ fetchImpl?: GithubFetch;
22
+ lookupEnv?: (name: string) => string | undefined;
23
+ apiOrigin?: string;
24
+ timeoutMs?: number;
25
+ useAmbientToken?: boolean;
26
+ }
27
+ export declare function isSafeReleaseTag(tag: string): boolean;
28
+ export declare function versionFromTag(tag: string): string;
29
+ export declare function githubReleaseHeaders(token: string | undefined): Record<string, string>;
30
+ export declare function fetchGithubChannelRelease(options?: GithubReleaseLookupOptions): Promise<GithubReleaseInfo>;
31
+ export declare function parseChecksumForAsset(text: string, assetName: string): string | undefined;
32
+ export declare function parseManifestChecksum(payload: unknown, assetName: string): string | undefined;
33
+ export declare function sha256Buffer(bytes: Uint8Array): string;
34
+ export declare function sha256File(filePath: string): Promise<string>;
35
+ export declare function fetchOptionalText(url: string, options?: {
36
+ fetchImpl?: GithubFetch;
37
+ lookupEnv?: (name: string) => string | undefined;
38
+ timeoutMs?: number;
39
+ }): Promise<string | undefined>;
40
+ export declare function verifyDownloadedBinaryChecksum(options: {
41
+ tag: string;
42
+ assetName: string;
43
+ filePath: string;
44
+ fetchImpl?: GithubFetch;
45
+ lookupEnv?: (name: string) => string | undefined;
46
+ downloadOrigin?: string;
47
+ }): Promise<"verified">;
@@ -29,13 +29,17 @@ export interface SetupCommandArgs {
29
29
  mpreset?: string;
30
30
  noWorktree?: boolean;
31
31
  worktreeName?: string;
32
+ requireWorktree?: boolean;
32
33
  stateRoot?: string;
34
+ codingAgentDir?: string;
33
35
  mutation?: string[];
34
36
  artifactByteCap?: string;
35
37
  serverKey?: string;
36
38
  gjcCommand?: string;
37
39
  target?: string;
38
40
  profileDir?: string;
41
+ timeout?: string;
42
+ connectTimeout?: string;
39
43
  yes?: boolean;
40
44
  dryRun?: boolean;
41
45
  keychain?: boolean;
@@ -1,7 +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 NpmRegistryLookupOptions } from "../utils/npm-registry";
4
+ import { type GithubReleaseLookupOptions } from "./github-release";
5
5
  export interface UpdateCommandOptions {
6
6
  force: boolean;
7
7
  check: boolean;
@@ -61,22 +61,35 @@ export type UpdateTarget = {
61
61
  } | {
62
62
  method: "binary";
63
63
  path: string;
64
+ } | {
65
+ method: "migrate";
66
+ path: string;
67
+ previousPath?: string;
64
68
  };
65
69
  type PathPlatform = NodeJS.Platform;
66
70
  type PackageExists = (packageName: string, packageRoot: string) => boolean;
67
71
  export declare function resolveUpdateMethodForTest(ompPath: string, bunBinDir: string | undefined): "bun" | "npm" | "binary";
68
72
  export declare function resolveNpmManagedTargetForTest(ompPath: string, platform: PathPlatform, packageExists: PackageExists): PackageManagerTarget | undefined;
69
- /** Lookup options for the release check: registry resolution plus the release channel. */
70
- export interface LatestReleaseLookupOptions extends NpmRegistryLookupOptions {
73
+ export declare function defaultUserBinaryPath(platform?: NodeJS.Platform, env?: NodeJS.ProcessEnv): string;
74
+ export declare function isProtectedSourcePathForTest(filePath: string): boolean;
75
+ export declare function defaultUserBinaryPathForTest(platform?: NodeJS.Platform, env?: NodeJS.ProcessEnv): string;
76
+ /** Lookup options for the GitHub release check. */
77
+ export interface LatestReleaseLookupOptions extends GithubReleaseLookupOptions {
71
78
  channel?: UpdateChannel;
72
79
  }
73
80
  export declare function getLatestReleaseForTest(options: LatestReleaseLookupOptions): Promise<ReleaseInfo>;
74
81
  export declare function compareVersionsForTest(a: string, b: string): number;
82
+ export declare function resolveGjcPathForTest(options: {
83
+ compiled: boolean;
84
+ execPath: string;
85
+ whichPath: string | undefined;
86
+ }): string | undefined;
75
87
  export declare function parseReportedVersionForTest(output: string): string | undefined;
76
88
  export declare function formatBinaryDownloadFailureMessageForTest(binaryName: string, url: string, status: string | number, platform?: NodeJS.Platform, registryNote?: string): string;
77
89
  export declare function buildReleaseBinaryUrlForTest(version: string, platform?: NodeJS.Platform, arch?: string): string;
78
90
  export declare function formatManualUpdateInstructionsForTest(platform?: NodeJS.Platform): string;
79
91
  export declare function formatVerificationFailureForTest(result: InstalledVersionVerification, expectedVersion: string): string;
92
+ export declare function recoverWindowsUpdateJournal(journalPath: string): Promise<void>;
80
93
  /**
81
94
  * Atomically replace the installed binary and roll back if version verification fails.
82
95
  */
@@ -133,7 +146,7 @@ export declare function runManagedNotifyRecovery(deps: Pick<UpdateCommandDepende
133
146
  /** How the update command should proceed after comparing versions. */
134
147
  export interface UpdateDecision {
135
148
  install: boolean;
136
- kind: "up-to-date" | "new-version" | "switch-back" | "force";
149
+ kind: "up-to-date" | "new-version" | "switch-back" | "force" | "migrate";
137
150
  }
138
151
  /**
139
152
  * Decide whether to install after comparing the channel's release with the
@@ -151,6 +164,7 @@ export declare function resolveUpdateDecision(options: {
151
164
  force: boolean;
152
165
  channel: UpdateChannel;
153
166
  currentVersion: string;
167
+ migrate?: boolean;
154
168
  }): UpdateDecision;
155
169
  export declare function runUpdateCommand(opts: UpdateCommandOptions, deps?: UpdateCommandDependencies): Promise<void>;
156
170
  /**
@@ -49,9 +49,15 @@ export default class Setup extends Command {
49
49
  "worktree-name": import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
50
50
  description: string;
51
51
  };
52
+ "require-worktree": import("@gajae-code/utils/cli").FlagDescriptor<"boolean"> & {
53
+ description: string;
54
+ };
52
55
  "state-root": import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
53
56
  description: string;
54
57
  };
58
+ "coding-agent-dir": import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
59
+ description: string;
60
+ };
55
61
  mutation: import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
56
62
  description: string;
57
63
  multiple: true;
@@ -71,6 +77,12 @@ export default class Setup extends Command {
71
77
  "profile-dir": import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
72
78
  description: string;
73
79
  };
80
+ timeout: import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
81
+ description: string;
82
+ };
83
+ "connect-timeout": import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
84
+ description: string;
85
+ };
74
86
  preset: import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
75
87
  description: string;
76
88
  };
@@ -727,6 +727,9 @@ export declare const TIER_MAP_SKIP_LIST: {
727
727
  readonly "kilo/sakana/sakana-namazu": {
728
728
  readonly rationale: "post-rebase catalog addition from dev; not yet curated";
729
729
  };
730
+ readonly "kilo/stealth/ox-alpha": {
731
+ readonly rationale: "newly pinned preview model; latency and quality rank are not yet curated";
732
+ };
730
733
  readonly "kilo/tencent/hy3:free": {
731
734
  readonly rationale: "post-rebase catalog addition from dev; not yet curated";
732
735
  };
@@ -6,6 +6,8 @@ export interface FileLockOptions {
6
6
  onAcquired?: () => void;
7
7
  /** Stable host identity required to safely reclaim locks on a shared volume. */
8
8
  ownerHostId?: string;
9
+ /** Previous local host identities accepted only when deciding stale-owner reclamation. */
10
+ previousOwnerHostIds?: readonly string[];
9
11
  }
10
12
  export declare const FileLockTestHooks: {
11
13
  afterParentMkdir?: (lockPath: string) => void | Promise<void>;
@@ -62,7 +64,7 @@ export declare function removeFileLockDirForGc(lockDir: string, expected: FileLo
62
64
  * remove the directory has to do it under an identity-bound primitive that refuses when
63
65
  * the object is no longer the one that was judged.
64
66
  */
65
- export declare function genericFileLockDirIsStale(lockDir: string, staleMs: number): Promise<boolean>;
67
+ export declare function genericFileLockDirIsStale(lockDir: string, staleMs: number, ownerHostId?: string): Promise<boolean>;
66
68
  /**
67
69
  * Serializes all contenders, including callers in the same process. Because this
68
70
  * API exposes no ownership token, recursive acquisition is indistinguishable
@@ -0,0 +1,19 @@
1
+ export interface MachineIdentityDeps {
2
+ platform?: NodeJS.Platform;
3
+ readFile?: (file: string) => Promise<string>;
4
+ runCommand?: (command: string, args: readonly string[]) => {
5
+ exitCode: number;
6
+ stdout: Uint8Array;
7
+ };
8
+ installationSecret?: string;
9
+ configRootDir?: string;
10
+ link?: (existingPath: string, newPath: string) => Promise<void>;
11
+ }
12
+ /** @internal */
13
+ export declare function parseWindowsMachineGuid(output: string): string | undefined;
14
+ /** @internal */
15
+ export declare function parseMacPlatformUuid(output: string): string | undefined;
16
+ /** Loads a verified machine-local identity without persisting the underlying machine ID. */
17
+ export declare function loadInstallationHostId(deps?: MachineIdentityDeps): Promise<string>;
18
+ /** @internal Recognizes owner records written before installation-keyed identities. */
19
+ export declare function loadLegacyInstallationHostId(deps?: MachineIdentityDeps): Promise<string>;
@@ -107,7 +107,7 @@ export declare const ModelsConfigFile: ConfigFile<{
107
107
  authHeader?: boolean | undefined;
108
108
  auth?: "apiKey" | "none" | "oauth" | undefined;
109
109
  discovery?: {
110
- type: "llama.cpp" | "lm-studio" | "models-dev" | "ollama" | "omlx" | "openai-models-list";
110
+ type: "llama.cpp" | "lm-studio" | "models-dev" | "ollama" | "omlx" | "openai-models-list" | "sglang" | "vllm";
111
111
  apiByModelPrefix?: Record<string, "anthropic-messages" | "openai-completions"> | undefined;
112
112
  modelsDevProvider?: string | undefined;
113
113
  } | undefined;
@@ -86,11 +86,12 @@ export declare function parseModelPattern(pattern: string, availableModels: Mode
86
86
  credentialSessionId?: string;
87
87
  aliasIntent?: "preset-equivalent" | "reject";
88
88
  }): ParsedModelResult;
89
+ export type ModelRoleSettings = Pick<Settings, "getModelRole">;
89
90
  /**
90
91
  * Expand a role alias like "pi/default" to the configured model string.
91
92
  */
92
- export declare function expandRoleAlias(value: string, settings?: Settings): string;
93
- export declare function resolveConfiguredModelPatterns(value: ModelSelectorValue | undefined, settings?: Settings): string[];
93
+ export declare function expandRoleAlias(value: string, settings?: ModelRoleSettings): string;
94
+ export declare function resolveConfiguredModelPatterns(value: ModelSelectorValue | undefined, settings?: ModelRoleSettings): string[];
94
95
  export interface AgentModelPatternResolutionOptions {
95
96
  settingsOverride?: ModelSelectorValue;
96
97
  agentModel?: ModelSelectorValue;
@@ -109,7 +110,7 @@ export interface ResolvedModelRoleValue {
109
110
  warning: string | undefined;
110
111
  }
111
112
  export declare function resolveModelRoleValue(roleValue: ModelSelectorValue | undefined, availableModels: Model<Api>[], options?: {
112
- settings?: Settings;
113
+ settings?: ModelRoleSettings;
113
114
  matchPreferences?: ModelMatchPreferences;
114
115
  modelRegistry?: CanonicalModelRegistry;
115
116
  sessionId?: string;
@@ -355,6 +355,8 @@ export declare const ProviderDiscoverySchema: z.ZodObject<{
355
355
  ollama: "ollama";
356
356
  omlx: "omlx";
357
357
  "openai-models-list": "openai-models-list";
358
+ sglang: "sglang";
359
+ vllm: "vllm";
358
360
  }>;
359
361
  apiByModelPrefix: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodEnum<{
360
362
  "anthropic-messages": "anthropic-messages";
@@ -478,6 +480,8 @@ export declare const ModelsConfigSchema: z.ZodObject<{
478
480
  ollama: "ollama";
479
481
  omlx: "omlx";
480
482
  "openai-models-list": "openai-models-list";
483
+ sglang: "sglang";
484
+ vllm: "vllm";
481
485
  }>;
482
486
  apiByModelPrefix: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodEnum<{
483
487
  "anthropic-messages": "anthropic-messages";
@@ -602,6 +602,23 @@ export declare const SETTINGS_SCHEMA: {
602
602
  readonly default: 10;
603
603
  readonly validate: (value: number) => boolean;
604
604
  };
605
+ readonly "ui.language": {
606
+ readonly type: "enum";
607
+ readonly values: readonly ["en", "ko"];
608
+ readonly default: "en";
609
+ readonly ui: {
610
+ readonly tab: "appearance";
611
+ readonly label: "Language";
612
+ readonly description: "Language for human-facing interactive UI text";
613
+ readonly options: readonly [{
614
+ readonly value: "en";
615
+ readonly label: "English";
616
+ }, {
617
+ readonly value: "ko";
618
+ readonly label: "Korean (한국어)";
619
+ }];
620
+ };
621
+ };
605
622
  readonly "theme.dark": {
606
623
  readonly type: "string";
607
624
  readonly default: "red-claw";
@@ -779,7 +796,7 @@ export declare const SETTINGS_SCHEMA: {
779
796
  readonly ui: {
780
797
  readonly tab: "appearance";
781
798
  readonly label: "Gajae Pet";
782
- readonly description: "Real-pixel pet living beside the composer (sixel/kitty terminals)";
799
+ readonly description: "Animated pet beside the composer (pixel graphics where supported; text cells elsewhere)";
783
800
  readonly options: readonly [{
784
801
  readonly value: "off";
785
802
  readonly label: "Off";
@@ -1686,7 +1703,7 @@ export declare const SETTINGS_SCHEMA: {
1686
1703
  readonly ui: {
1687
1704
  readonly tab: "interaction";
1688
1705
  readonly label: "Mouse Support";
1689
- readonly description: "Enable GJC session scrolling, drag-to-copy text selection, and overlay row selection with the mouse. Disabled by default to preserve native terminal or tmux scrollback and selection.";
1706
+ readonly description: "Enable GJC session scrolling, drag-to-copy text selection, double-click word and triple-click line selection, and overlay row selection with the mouse. Disabled by default to preserve native terminal or tmux scrollback and selection; while enabled, most terminals still reach their own selection with a modifier held (Option on macOS, Shift elsewhere), though that path copies only if the host terminal has its own copy-on-select enabled.";
1690
1707
  };
1691
1708
  };
1692
1709
  readonly steeringMode: {
@@ -1837,7 +1854,7 @@ export declare const SETTINGS_SCHEMA: {
1837
1854
  readonly ui: {
1838
1855
  readonly tab: "interaction";
1839
1856
  readonly label: "Check for Updates";
1840
- readonly description: "At interactive startup, notify of newer versions; never install. Use `gjc update` only for recognized Bun global, Windows npm, or bundled-installer binaries; source, linked, and unrecognized installs use their original method.";
1857
+ readonly description: "At interactive startup, notify of newer versions; never install. `gjc update` installs the matching GitHub release binary. Source, linked, and unrecognized installs stay on their original method.";
1841
1858
  };
1842
1859
  };
1843
1860
  readonly "startup.updateChannel": {
@@ -1851,11 +1868,11 @@ export declare const SETTINGS_SCHEMA: {
1851
1868
  readonly options: readonly [{
1852
1869
  readonly value: "stable";
1853
1870
  readonly label: "Stable";
1854
- readonly description: "Track stable releases (npm `latest` dist-tag)";
1871
+ readonly description: "Track stable GitHub releases";
1855
1872
  }, {
1856
1873
  readonly value: "nightly";
1857
1874
  readonly label: "Nightly";
1858
- readonly description: "Track nightly prereleases (npm `nightly` dist-tag)";
1875
+ readonly description: "Track nightly GitHub prereleases";
1859
1876
  }];
1860
1877
  };
1861
1878
  };
@@ -179,6 +179,8 @@ export declare class Settings implements NotificationSettingsReader {
179
179
  flushOrThrow(): Promise<void>;
180
180
  cloneForCwd(cwd: string): Promise<Settings>;
181
181
  getStorage(): AgentStorage | null;
182
+ /** Flush and close storage owned by an isolated settings scope. */
183
+ close(): Promise<void>;
182
184
  getCwd(): string;
183
185
  getAgentDir(): string;
184
186
  getPlansDirectory(): string;
@@ -1,3 +1,4 @@
1
+ import { type CodexTokenFileIdentity } from "./codex-wake-publisher";
1
2
  export declare const CODEX_WAKE_EVENT_KINDS: readonly ["question.opened", "turn.waiting_for_answer", "turn.completed", "turn.failed", "turn.cancelled", "turn.superseded"];
2
3
  export type CodexWakeEventKind = (typeof CODEX_WAKE_EVENT_KINDS)[number];
3
4
  export type CodexHandoffEndpoint = {
@@ -24,6 +25,7 @@ export interface CodexHandoffRegistrationV1 {
24
25
  thread_id: string;
25
26
  endpoint: CodexHandoffEndpoint;
26
27
  token_file: string | null;
28
+ token_file_identity: CodexTokenFileIdentity | null;
27
29
  registered_at: string;
28
30
  updated_at: string;
29
31
  origin?: CodexHandoffOriginV1;
@@ -55,6 +57,7 @@ export declare function registerCodexHandoff(namespaceDir: string, input: {
55
57
  thread_id: string;
56
58
  endpoint: CodexHandoffEndpoint;
57
59
  token_file?: string | null;
60
+ token_root?: string;
58
61
  origin?: unknown;
59
62
  }): Promise<CodexHandoffRegistrationV1>;
60
63
  export declare function readCodexHandoff(namespaceDir: string, workUnit: string): Promise<CodexHandoffRegistrationV1 | null>;