@gajae-code/coding-agent 0.12.11 → 0.12.13

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 (140) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/dist/types/cli/marketplace-hint.d.ts +28 -0
  3. package/dist/types/cli/notify-cli.d.ts +42 -1
  4. package/dist/types/cli/update-cli.d.ts +9 -3
  5. package/dist/types/cli.d.ts +10 -0
  6. package/dist/types/commands/notify.d.ts +6 -0
  7. package/dist/types/config/file-lock-gc.d.ts +13 -1
  8. package/dist/types/config/file-lock.d.ts +3 -0
  9. package/dist/types/config/model-registry.d.ts +6 -0
  10. package/dist/types/config/models-config-schema.d.ts +99 -0
  11. package/dist/types/coordinator/contract.d.ts +1 -1
  12. package/dist/types/coordinator-mcp/question-state.d.ts +3 -1
  13. package/dist/types/extensibility/extensions/index.d.ts +1 -0
  14. package/dist/types/extensibility/extensions/ouroboros-ooo-bridge.d.ts +13 -0
  15. package/dist/types/extensibility/extensions/prefix-command-bridge.d.ts +0 -1
  16. package/dist/types/extensibility/extensions/types.d.ts +2 -0
  17. package/dist/types/gjc-runtime/deep-interview-state.d.ts +14 -0
  18. package/dist/types/gjc-runtime/gc-runtime.d.ts +11 -0
  19. package/dist/types/main.d.ts +6 -2
  20. package/dist/types/modes/acp/acp-agent.d.ts +24 -1
  21. package/dist/types/modes/components/session-selector.d.ts +1 -1
  22. package/dist/types/modes/utils/host-status.d.ts +23 -0
  23. package/dist/types/runtime-mcp/types.d.ts +2 -0
  24. package/dist/types/sdk/broker/lifecycle.d.ts +12 -0
  25. package/dist/types/sdk/bus/chat-daemon-cli.d.ts +3 -0
  26. package/dist/types/sdk/bus/chat-daemon-command-channel.d.ts +244 -0
  27. package/dist/types/sdk/bus/chat-daemon-control.d.ts +11 -1
  28. package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +7 -0
  29. package/dist/types/sdk/bus/control-plane-frames.d.ts +43 -0
  30. package/dist/types/sdk/bus/conversation-store.d.ts +18 -0
  31. package/dist/types/sdk/bus/existing-thread-readiness.d.ts +71 -0
  32. package/dist/types/sdk/bus/html-format.d.ts +10 -0
  33. package/dist/types/sdk/bus/notification-service.d.ts +10 -0
  34. package/dist/types/sdk/bus/slack-daemon.d.ts +27 -0
  35. package/dist/types/sdk/bus/slack-live-provider.d.ts +11 -0
  36. package/dist/types/sdk/bus/slack-provider.d.ts +14 -0
  37. package/dist/types/sdk/bus/slack-thread-binding.d.ts +140 -0
  38. package/dist/types/sdk/bus/telegram-daemon-cli.d.ts +2 -0
  39. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +28 -7
  40. package/dist/types/sdk/bus/telegram-daemon.d.ts +119 -17
  41. package/dist/types/sdk/bus/telegram-reference.d.ts +20 -1
  42. package/dist/types/sdk/bus/topic-registry.d.ts +130 -85
  43. package/dist/types/sdk/host/host.d.ts +52 -0
  44. package/dist/types/sdk/lifecycle-session.d.ts +6 -0
  45. package/dist/types/sdk/session-activation.d.ts +41 -0
  46. package/dist/types/sdk/session.d.ts +18 -0
  47. package/dist/types/sdk/startup-capability.d.ts +8 -1
  48. package/dist/types/session/agent-session.d.ts +7 -2
  49. package/dist/types/session/artifacts.d.ts +2 -2
  50. package/dist/types/session/session-manager.d.ts +40 -6
  51. package/dist/types/tools/index.d.ts +15 -0
  52. package/dist/types/utils/npm-registry.d.ts +71 -0
  53. package/examples/extensions/README.md +38 -4
  54. package/examples/extensions/ooo-bridge.ts +15 -0
  55. package/package.json +8 -8
  56. package/scripts/generate-sdk-operation-inventory.ts +4 -0
  57. package/src/async/job-manager.ts +9 -2
  58. package/src/cli/fast-help.ts +1 -0
  59. package/src/cli/marketplace-hint.ts +39 -0
  60. package/src/cli/notify-cli.ts +226 -2
  61. package/src/cli/plugin-cli.ts +10 -0
  62. package/src/cli/update-cli.ts +90 -23
  63. package/src/cli.ts +23 -0
  64. package/src/commands/notify.ts +27 -3
  65. package/src/commands/sdk.ts +1 -0
  66. package/src/config/file-lock-gc.ts +65 -26
  67. package/src/config/file-lock.ts +61 -16
  68. package/src/config/model-profiles.ts +46 -30
  69. package/src/config/model-registry.ts +17 -5
  70. package/src/config/models-config-schema.ts +9 -4
  71. package/src/coordinator/contract.ts +1 -0
  72. package/src/coordinator-mcp/question-state.ts +2 -0
  73. package/src/coordinator-mcp/server.ts +358 -7
  74. package/src/defaults/gjc/skills/deep-interview/SKILL.md +1 -1
  75. package/src/defaults/gjc/skills/ultragoal/SKILL.md +2 -0
  76. package/src/extensibility/extensions/index.ts +1 -0
  77. package/src/extensibility/extensions/ouroboros-ooo-bridge.ts +235 -0
  78. package/src/extensibility/extensions/prefix-command-bridge.ts +4 -9
  79. package/src/extensibility/extensions/runner.ts +15 -2
  80. package/src/extensibility/extensions/types.ts +2 -0
  81. package/src/gjc-runtime/deep-interview-recorder.ts +9 -5
  82. package/src/gjc-runtime/deep-interview-state.ts +27 -3
  83. package/src/gjc-runtime/gc-render.ts +8 -1
  84. package/src/gjc-runtime/gc-runtime.ts +15 -1
  85. package/src/gjc-runtime/launch-tmux.ts +53 -1
  86. package/src/internal-urls/docs-index.generated.ts +14 -13
  87. package/src/main.ts +214 -70
  88. package/src/modes/DESIGN.md +8 -5
  89. package/src/modes/acp/acp-agent.ts +123 -7
  90. package/src/modes/components/footer.ts +10 -18
  91. package/src/modes/components/model-selector.ts +52 -5
  92. package/src/modes/components/session-selector.ts +26 -3
  93. package/src/modes/components/status-line/gh.ts +23 -2
  94. package/src/modes/controllers/event-controller.ts +3 -0
  95. package/src/modes/controllers/extension-ui-controller.ts +2 -0
  96. package/src/modes/controllers/input-controller.ts +11 -0
  97. package/src/modes/controllers/selector-controller.ts +8 -2
  98. package/src/modes/interactive-mode.ts +7 -1
  99. package/src/modes/print-mode.ts +10 -0
  100. package/src/modes/utils/host-status.ts +38 -0
  101. package/src/prompts/system/project-prompt.md +19 -0
  102. package/src/runtime-mcp/types.ts +2 -0
  103. package/src/sdk/broker/lifecycle.ts +60 -3
  104. package/src/sdk/bus/chat-daemon-cli.ts +42 -0
  105. package/src/sdk/bus/chat-daemon-command-channel.ts +921 -0
  106. package/src/sdk/bus/chat-daemon-control.ts +16 -3
  107. package/src/sdk/bus/chat-daemon-runtime.ts +257 -21
  108. package/src/sdk/bus/control-plane-frames.ts +51 -0
  109. package/src/sdk/bus/conversation-store.ts +29 -1
  110. package/src/sdk/bus/existing-thread-readiness.ts +155 -0
  111. package/src/sdk/bus/html-format.ts +19 -3
  112. package/src/sdk/bus/index.ts +91 -12
  113. package/src/sdk/bus/notification-service.ts +28 -1
  114. package/src/sdk/bus/rich-render.ts +3 -2
  115. package/src/sdk/bus/slack-daemon.ts +99 -4
  116. package/src/sdk/bus/slack-live-provider.ts +32 -2
  117. package/src/sdk/bus/slack-provider.ts +11 -0
  118. package/src/sdk/bus/slack-thread-binding.ts +641 -0
  119. package/src/sdk/bus/telegram-daemon-cli.ts +11 -0
  120. package/src/sdk/bus/telegram-daemon-contract.ts +28 -7
  121. package/src/sdk/bus/telegram-daemon.ts +2007 -509
  122. package/src/sdk/bus/telegram-reference.ts +114 -15
  123. package/src/sdk/bus/topic-registry.ts +674 -181
  124. package/src/sdk/host/host.ts +180 -1
  125. package/src/sdk/lifecycle-session.ts +8 -2
  126. package/src/sdk/protocol/operation-inventory.generated.json +22 -0
  127. package/src/sdk/session-activation.ts +127 -0
  128. package/src/sdk/session.ts +144 -29
  129. package/src/sdk/startup-capability.ts +10 -1
  130. package/src/session/agent-session.ts +220 -13
  131. package/src/session/artifacts.ts +56 -13
  132. package/src/session/internal/managed-session-storage.ts +228 -7
  133. package/src/session/session-manager.ts +225 -60
  134. package/src/setup/provider-presets.json +3 -3
  135. package/src/task/index.ts +92 -44
  136. package/src/thinking-metadata.ts +2 -1
  137. package/src/tools/ask.ts +10 -0
  138. package/src/tools/index.ts +15 -0
  139. package/src/tools/todo-write.ts +4 -4
  140. package/src/utils/npm-registry.ts +660 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,65 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.12.13] - 2026-08-06
6
+
7
+ ### Fixed
8
+ - ACP session configuration now emits the spec-defined `category` field on the Mode, Model, and Thinking select options (`mode`, `model`, `thought_level`), so standards-compliant ACP clients such as Paseo discover models, modes, and thinking levels instead of an empty model picker (#3922).
9
+ - The ACP session model catalog is now filtered to active providers via `providers.list/active`, falling back to the full catalog on older session hosts, so ACP clients no longer list models for providers without usable credentials (#3922).
10
+
11
+ - `todo_write` now rejects malformed raw arguments with bounded, authority-controlled correction codes instead of a generic rejection: unknown root keys, unknown operation-entry keys, done/drop entries without a task or phase target, and unknown init list-entry keys each surface a fixed message naming the accepted shape without echoing the offending input, while recoverable payloads keep the passthrough/coercion path and the existing ask-tool codes are untouched (#3916).
12
+ - The Alibaba Token Plan onboarding preset and `alibaba-token-plan-qwen-deepseek` profile now reference the provider-supported `qwen3.8-max` model id instead of `qwen-3.8-max`, preventing the built-in profile from selecting an HTTP 400 unsupported model (#3909).
13
+ - `/model` reasoning menu header now shows the highlighted reasoning level (not the model id), seeds the cursor from the role badge when re-editing the same model, and uses a provider-neutral label for `max` instead of "Opus maximum reasoning" (#3847).
14
+ - Resume listing now reverse-scans for buried but canonically valid `header_patch` titles, so a persisted manual title remains visible in the picker after later transcript growth instead of falling back to an empty/line-1 projection (#3633).
15
+ - Custom OpenAI-compatible models whose wire id is namespaced (for example `cline-pass/deepseek-v4-flash`) now inherit capability metadata from the bundled leaf model when `contextWindow` / `maxTokens` are omitted, instead of silently falling back to the generic 128K / 16K defaults. True unknown leaf ids still default; explicit limits remain authoritative (#3856).
16
+ - `gjc gc` file-lock discovery now budgets the walk **per lock root** and reports a hit entry cap as a **warning**, not a hard error. Truncating one root no longer skips the remaining roots, and a healthy run with only cap warnings exits `0` so scripts/cron/`&&` chains stay usable (#3852).
17
+
18
+ - `gjc models` is no longer treated as a free-form agent prompt. The mistaken subcommand spelling now routes to the existing `--list-models` listing path so a nested bash-tool invocation cannot recursively spawn unbounded GJC agents (#3857).
19
+ - Always-apply and rulebook rules are injected on the default system prompt path again. Discovery still loaded `.gjc/rules/`, `~/.gjc/agent/rules/`, and sticky `RULES.md`, but only `custom-system-prompt.md` rendered them, so normal sessions silently dropped the content while AGENTS.md in the same directory continued to work (#3859).
20
+ - Made Telegram reference-client capability diagnostics safe for TUI embedding.
21
+ - Custom `anthropic-messages` providers can now configure `compat.promptCacheMode` (`none`, `explicit`, or `automatic`) and `compat.supportsLongCacheRetention` at provider, model, and model-override levels. This makes the automatic Claude-family caching default safely overridable for compatible endpoints that require block-level cache markers or do not support 1-hour retention.
22
+ - A Telegram notification daemon whose reconciliation pass fails no longer exits. The pass persists through the shared topic authority, and a momentarily unavailable authority (lock contention or a rejected compare-and-set) rejected out of both the scan timer and the run loop into the process-level fatal handler, killing the owner. Every session topic was then left behind as an unarchived shell that answers nothing — including for sessions that were still live and lost their notifications. The pass now reports the failure and the next scan interval retries it; the queue-flush timer is guarded the same way.
23
+ - MiniMax M3 preset and profile ids canonicalized to `MiniMax-M3` (issue #3896): the `minimax` / `minimax-cn` onboarding presets and the `minimax-eco` / `minimax-medium` / `minimax-pro` builtin model profiles no longer reference the removed lowercase `minimax-m3` / `minimax-v3` first-class catalog ids.
24
+ - Deep-interview round identity and input caps are now Unicode-canonical. Question text, selected options, and custom input are canonicalized to NFC before hashing and persisting, so the same Korean answer arriving in decomposed form (macOS-sourced pastes and some IME/clipboard paths emit NFD) no longer produces a second `answer_hash` — the documented append-or-merge no-op holds, and intent-review approval evidence still matches the user's recorded answer. Free-text caps are measured on the NFC form, so decomposed Hangul is charged the same character budget as the identical composed text instead of 2–3 code points per syllable (#3871).
25
+ - Telegram notifications no longer disappear in a paired private chat whose bot has no Threaded Mode. Telegram answers `createForumTopic` there with `Bad Request: the chat is not a forum`, which was not recognized as a capability refusal, and the refusal verdict lived in caller-local flags — so every frame that joined the shared in-flight topic creation rethrew and its message (identity headers after `/resume`, asks, context updates) was dropped instead of being delivered flat. The rejection is now carried by typed errors that every awaiter of the same creation classifies identically, `the chat is not a forum` counts as a capability refusal, and a confirmed refusal is latched so later frames stop re-issuing a rejected `createForumTopic` per message.
26
+ - Slash commands now expand in non-interactive runs. `gjc -p "/init"` previously reached the model as the literal text `/init`, so no command body was injected, no file was written, and the model still answered as if the command had run. Print mode now loads the same bundled and file-based command list interactive mode uses before it prompts.
27
+ - `gjc plugin install <name>` now names the marketplaces that offer `<name>` when the npm resolution it falls back to fails, so a plugin name copied out of `gjc plugin discover` no longer dead-ends on a bare `install_failed`.
28
+ - A remote multi-select ask now shows what is already selected. The ask tool re-issues one remote request per toggle, but the request carried no selection state, so Telegram kept posting an identical prompt with no sign that option 1 had been picked — the checkbox rendering existed only for durable workflow gates. `AskAnswerRequest` now carries `multi` and the selected option labels, the notification bus publishes them as `selectedOptionIndices` with the `(N selected)` question prefix while keeping the ask tool's own Next/Done control, and pre-numbered options (deep interview) are renumbered once instead of rendering as `1. ☑ 1. …`.
29
+
30
+ ## [0.12.12] - 2026-08-05
31
+
32
+ ### Added
33
+
34
+ - Interactive turns now announce their state as an OSC 777 sequence (`notify;Terax;gjc;working|attention|finished`), so a hosting terminal can follow the agent without polling. Terminals that do not parse it discard it like any unknown OSC, and print/RPC mode stdout is untouched.
35
+ - Existing Slack threads can now be adopted through an opt-in prepare → bind → activate lifecycle. A prepared session (broker `readiness: "deferred"` / `gjc_coordinator_start_session` with `prepare_existing_thread`, or `GJC_NOTIFY_BIND_EXISTING_THREAD=1` for a manually started one) publishes discoverable endpoint authority while withholding readiness, so no stock root is claimed; `gjc notify bind-thread` then adopts the exact operator-supplied root through the running Slack daemon owner over a new per-request command channel — the CLI is never a direct mapping writer — and `gjc notify activate-thread` / `gjc_coordinator_activate_session` publishes the withheld readiness exactly once behind a gate that proves the daemon-owned mapping at that endpoint generation. Adoption posts zero replacement roots, is fenced on the exact session/generation/daemon-owner tuple, and is idempotent on exact retry. Every mapping mutation passes a two-sided final authority fence inside the store lock — authority is proven, commit authority is taken, and authority is proven again — so a session, endpoint generation, or daemon-owner tuple that rolls while commit authority is being taken leaves no mapping behind. `ChatDaemonRuntime` now drops internal control-plane frames (`session_prepared`, `event_replay_result`, `control_response`, `query_response`, `hello`) before any post, root, mapping, resume, close, or action mutation on both the live and replay paths, and correlates each delivered frame first: an event envelope, its `name`/`kind` aliases, and its payload are representations of one event, so disagreeing spellings, a duplicated `sessionId`/`generation` that is unequal or present-but-malformed, and a reserved lifecycle or control-plane identity carried on only one representation all make the frame inert before any mutation. Because the command channel proves correlation and never authorship, a reported `status:"ok"` that the durable conversation store does not corroborate is reported as `binding_outcome_unknown` instead of success; a storage failure raised after commit authority was granted — the mapping rename applies before its durability barrier — is reported as `binding_outcome_unknown` rather than as a definitive rejection an operator could retry against; and a timeout that wins the single-winner response claim is a definitive, mutation-free failure for that submission's race against a concurrent serve (not durable settlement across a crashed and resurrected daemon). Ordinary sessions keep the stock immediate ready/root behaviour.
36
+
37
+ ### Added
38
+
39
+ - Added a verified, copy-installable `ooo` bridge example: `ooo interview` renders Ouroboros MCP questions in GJC, serializes startup and follow-up answers by session ID, cancellation-fences late settlement, disposes state on GJC session changes and `/clear`, drops queued predecessor-generation starts, releases dead transports and controls, honors `OUROBOROS_CLI`, and loads dependency-free in compiled binaries (#3803).
40
+
41
+ ### Fixed
42
+
43
+ - Fixed deep-interview prompts exposing the literal argument placeholder.
44
+
45
+ - Automatic session retry now refuses to re-issue a request once the failed attempt carries observable assistant text, thinking, or tool-call content — including under explicit legacy `retry.*` settings. Content-free clean failures keep their existing bounded/unbounded policy; managed provisional discard, credential rotation, first-event timeout scope checks, and manual `/retry` are unchanged (#3791).
46
+ - Resuming a session whose transcript file is at or above the ~64 MiB managed-storage per-file bound no longer OOMs, stalls the process, or fails with a bare unhandled rejection. Resume/open now fail closed with a structured `oversized` reason (`SessionTranscriptOversizedError`) and recovery guidance before the full read/decode/parse path, instead of loading the entire file into memory. The bound matches the existing managed-artifact per-file limit and is not raised; sub-limit sessions resume unchanged (#3851).
47
+
48
+ - Parent sessions and their subagent trees now share one identity-authorized artifact manager across persistent and ephemeral operation. Non-persistent roots are retired on committed session transitions and terminal close, failed transitions retain predecessor ownership, and atomic numeric-ID claims prevent same-root managers from creating ambiguous artifact references (#3813).
49
+
50
+ - Telegram daemon restart now revokes every persisted callback alias before polling. Reconnecting sessions must replay a pending ask to receive fresh, owner-bound aliases; old controls remain stale, and their keyboards are best-effort terminalized when the original Telegram message id is available. Shutdown now fences new session messages and drains every admitted handler before final callback persistence and ownership release, preventing a successful send racing shutdown from publishing alias state after a successor takes ownership (#3727).
51
+ - Extension handler timeout signals now preserve lazy, live context accessors instead of eagerly snapshotting them. Model changes made through SDK controls are immediately visible to later context reads, and unused getters can no longer reject lifecycle emission before the runner's extension error boundary (#3817).
52
+ - Direct interactive launches inside tmux now bind automatic window renames to the originating pane's immutable pane/window identities and observed window index. If that binding changes before mutation, GJC preserves every window name instead of renaming whichever window became active (#3808).
53
+ - `gjc update` and the startup version check now resolve the npm registry from npm configuration — `npm_config_registry` or `BUN_CONFIG_REGISTRY` from the environment, a scoped `@scope:registry` key, and the user and machine-wide `.npmrc` files, including the credentials registered for that registry — instead of always querying `registry.npmjs.org`. On networks that mirror or block the public registry the check failed with an empty `Failed to fetch release info:` even though the install step, which already shells out to bun/npm and therefore honored the configured registry, would have succeeded. Repository-controlled configuration is excluded: a `.npmrc` in the current working directory is not read, the environment is read through `$credentialEnv`, and `npm_config_*` is ignored entirely when GJC is launched by an npm lifecycle, because npm synthesizes those variables from the project `.npmrc` with `${VAR}` already expanded. Credentials are never sent to a remote plaintext `http:` registry, including credentials embedded in the registry URL. Whichever manager will run the install decides Bun-vs-npm config priority, the machine-wide config path is derived from npm's own prefix rather than guessed, and keys inside an ini `[section]` are not treated as top-level config. A registry that is configured but unusable, and a config file that exists but cannot be read, fail loudly instead of silently falling back to the public registry; failures name the URL, the status, and the exact file or environment variable the registry came from — including the case where an intercepting proxy answers 200 with a non-JSON body — and credentials are stripped from a `https://user:pass@host` registry rather than printed with it. `bunfig.toml` is not read. (#3821)
54
+
55
+ ### Fixed
56
+
57
+ - Telegram `notify setup` activation works when `notifications/` is a directory symlink (multi-account shared notification dirs). Transition-lock release previously rejected intermediate directory reparse points, left `telegram-daemon.steal` behind, and failed with "provisional ownership could not be retired safely" while durable settings remained armed. Only intermediate directory components are resolved before native exact unlink; the final basename is rejoined so final-component file symlinks stay `reparse_point` under native `AT_SYMLINK_NOFOLLOW`, including TOCTOU replacement after JS preflight (#3761).
58
+ - A failed `notify setup` no longer reports "Unable to persist and activate Telegram notification settings" when the durable configuration already carries the attempted bot token, chat id, and enabled state. The wording now follows the stored configuration, so it can no longer contradict a follow-up `notify status`; an operator who reads the failure as "nothing was saved" would otherwise leave Telegram armed for a token another poller may own. A commit that was entered and then failed while the stored configuration is also unreadable is reported as undecided, pointing at `notify status`, instead of guessing either outcome (#3761).
59
+ - Continuing a large managed session on Darwin now batches stale OpenAI Responses replay-metadata patches into one transcript append instead of performing one identity-verified whole-file replacement per patch. Interactive startup also renders before exact MCP connection and explicit `--mpreset` activation, gates every provider turn until both are ready, and refreshes models online only after the UI is usable, preventing `gjc -c` from remaining at `GJC warming workspace` with sustained CPU, multi-gigabyte RSS growth, or avoidable network waits (#3793).
60
+ - Slack Web API requests now use form encoding instead of JSON, preventing thread reconciliation through `conversations.replies` from failing with `invalid_arguments`.
61
+
62
+ - Managed replacement cleanup now migrates version-one receipts from earlier releases and recovers canonical exchange placeholders left by interrupted cleanup, so a stale receipt cannot permanently block the next managed session mutation with `managed_replace_cleanup_receipt_invalid`.
63
+
5
64
  ## [0.12.11] - 2026-08-03
6
65
 
7
66
  ### Fixed
@@ -10,6 +69,7 @@
10
69
  - Managed session rewrites and authority-absent Darwin appends now use native identity-verified atomic replacement instead of deterministically failing with `managed_replace_exact_unavailable` or risking a torn JSONL tail; uncertain readable outcomes are re-fsynced and carried through ctime-bound strict adoption before recovery reports them durable. This unblocks Darwin compaction and session append durability when retained native authority is absent (#3742, #3760).
11
70
  - `todo_write` recovery reminders now distinguish rejected payloads from runtime aborts, preserve the available cause, and require durable state reconciliation instead of incorrectly telling the agent to change a valid payload (#3743, #3760).
12
71
  - Authority-absent Darwin `appendSync` regression coverage now exercises the replace-based race window (destination mutation during successor staging) instead of the retired in-place `O_APPEND` open path, and documents that ctime-only destination transitions are tolerated by exact replacement.
72
+ - The legacy interactive footer now uses the session manager's cumulative usage index, so completed task and subagent tokens, premium requests, and estimated costs are included exactly once instead of reporting only the parent agent's assistant messages.
13
73
 
14
74
  ## [0.12.10] - 2026-08-03
15
75
 
@@ -31,6 +91,9 @@
31
91
  - Dead-owner notification recovery now preserves a machine-readable transition block, marker-age diagnostics, and safe force-recovery guidance without weakening ownership proofs (#3762).
32
92
  - Detached SDK session hosts no longer outlive the broker that spawned them. A host whose broker died without teardown (crash, `SIGKILL`, restart without `--close-session-hosts`) previously stayed resident forever, holding its session's memory — hundreds of MB per orphan. Each host now polls the broker discovery publication and, after a bounded grace period with no live broker, disposes itself through the same graceful teardown a `SIGTERM` takes. A replacement broker resets the window, so hosts still survive ordinary broker restarts, and a transient discovery read failure is treated as ambiguity rather than proof of orphanhood.
33
93
  - Syntax highlighting now recognizes special filenames such as `CMakeLists.txt`, `Dockerfile.*`, `Makefile`, and `.env.*` before generic filename extensions.
94
+ ### Changed
95
+
96
+ - Updated the Cursor Eco, Medium, and Pro profiles from Composer 1.5 to distinct Composer 2.5 tiers: standard throughout for Eco, Fast on execution/review/design roles for Medium, and Fast throughout for Pro. Removed inert generic effort suffixes that the Cursor RPC could not transport.
34
97
 
35
98
  ## [0.12.8] - 2026-08-02
36
99
  ### Added
@@ -46,6 +109,9 @@
46
109
 
47
110
  - Windows automatic tmux resolution now selects `psmux` then `pmux` by canonical command order without rejecting distinct lower-priority aliases; it probes `tmux` only when neither named provider is available (#3725).
48
111
  - CI failure extraction now aggregates Bun failure and suite-error summaries across every test invocation in a job log instead of silently using only the first summary.
112
+ - The GitHub status-line lookup now binds terminal links to positive PR numbers and canonical matching HTTP(S) pull-request URLs, rejecting ambiguous or control-bearing targets.
113
+ - Fork-context subagents no longer inherit the parent's provider continuity identity. Each child session now presents its own `session_id`/`prompt_cache_key`, so concurrent subagent fleets stop colliding on session-owning upstream transports (`owner_busy` websocket-to-HTTP fallbacks) and keep per-worker cache affinity. Explicit `providerSessionId` overrides and serial same-session continuity are unchanged.
114
+ - Fork-context subagents no longer inherit the parent's provider continuity identity. Each child session now presents its own `session_id`/`prompt_cache_key`, so concurrent subagent fleets stop colliding on session-owning upstream transports (`owner_busy` websocket-to-HTTP fallbacks) and keep per-worker cache affinity. Because `providerSessionId` scopes sticky credential selection as well as prompt-cache affinity, each child also selects its provider credential independently instead of following the parent's sticky choice. Explicit `providerSessionId` overrides and serial same-session continuity are unchanged.
49
115
  - Ordinary `ask` selectors now bound long question premises and page through every premise row without skipping rows hidden by overflow indicators (#3675).
50
116
  - First-event timeout retries now require a typed, content-free failure from the current clean attempt scope, preventing prior or stale extension activity from suppressing or admitting a later request (#3553).
51
117
  - The issue-1979 Korean prose wrap test now cleans up inherited multiplexer env vars (`TMUX`, `TMUX_PANE`, etc.) so it deterministically exercises the plain-terminal render path regardless of the CI runner's terminal session (#1979).
@@ -146,6 +212,8 @@
146
212
 
147
213
  - User-created Telegram forum topics can now start a GJC session by selecting the home folder, choosing a verified recent work folder, or entering an explicit folder path. The selected topic is adopted by the new session without creating or deleting a separate Telegram topic.
148
214
  - The interactive terminal’s responsive IRC/todo work-lane contract now covers exact narrow/wide geometry, requested versus effective IRC visibility, direct-root pin ordering, todo lane bounds, remapped IRC toggles, and live composer shortcut hints.
215
+ - Managed-session startup now preserves bounded Windows ACL and identity failure classifications in path-redacted recovery guidance without broadening permissions, elevation, or unsafe fallback.
216
+ - Telegram topic synchronization now uses generation-CAS shared authority, durable pre-create claims, lease-fenced effects, bounded single-flight archive retries, and an isolated owner-backed validation-supergroup mode without deleting topics.
149
217
 
150
218
  ### Fixed
151
219
 
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Install-failure hints for marketplace-shaped plugin names.
3
+ *
4
+ * A bare spec (no `@marketplace`) is always classified as npm, so a user who
5
+ * copies a plugin name out of `plugin discover` gets an npm resolution failure
6
+ * with no hint that the same name is offered by a registered marketplace.
7
+ *
8
+ * Kept dependency-free — the marketplace barrel loads native addons — so this
9
+ * takes the narrow catalog surface it actually reads instead of the manager.
10
+ */
11
+ /** The catalog lookups this module needs; `MarketplaceManager` satisfies it. */
12
+ export interface MarketplaceCatalogLookup {
13
+ listMarketplaces(): Promise<ReadonlyArray<{
14
+ name: string;
15
+ }>>;
16
+ getPluginInfo(name: string, marketplace: string): Promise<unknown | null>;
17
+ }
18
+ /**
19
+ * A bare name carries no `@scope`, version specifier, or path separator, so it
20
+ * is the only install spec shape that is safe to echo back in an error.
21
+ */
22
+ export declare function isBareInstallName(spec: string): boolean;
23
+ /**
24
+ * Names of registered marketplaces whose catalog offers a plugin under exactly
25
+ * `name`. Only marketplace names are returned: they are user-chosen registry
26
+ * labels, never the plugin source, so they carry no credentials or home paths.
27
+ */
28
+ export declare function findMarketplacesOffering(catalogs: MarketplaceCatalogLookup, name: string): Promise<string[]>;
@@ -1,8 +1,10 @@
1
1
  import { Settings } from "../config/settings";
2
2
  import { type EnsureChatDaemonResult } from "../sdk/bus/chat-daemon-control";
3
+ import { type ActivatedPreparedSession } from "../sdk/bus/existing-thread-readiness";
4
+ import { type BoundSlackThread } from "../sdk/bus/slack-thread-binding";
3
5
  import { type EnsureTelegramDaemonDetailedResult } from "../sdk/bus/telegram-daemon";
4
6
  import { type TelegramSetupPreflight, type TelegramSetupTimers } from "../sdk/bus/telegram-setup";
5
- export type NotifyAction = "setup" | "status" | "health" | "test" | "recovery" | "daemon-internal";
7
+ export type NotifyAction = "setup" | "status" | "health" | "test" | "recovery" | "bind-thread" | "activate-thread" | "daemon-internal";
6
8
  export type NotifySetupProvider = "telegram" | "discord" | "slack";
7
9
  export interface NotifyCommandArgs {
8
10
  action: NotifyAction;
@@ -24,6 +26,8 @@ export interface NotifyCommandArgs {
24
26
  forceDaemonLock?: boolean;
25
27
  probe?: boolean;
26
28
  message?: string;
29
+ sessionId?: string;
30
+ threadTs?: string;
27
31
  }
28
32
  export interface NotifyCommandDeps {
29
33
  fetchImpl?: typeof fetch;
@@ -50,6 +54,15 @@ export interface NotifyCommandDeps {
50
54
  setupPidIncarnation?: (pid: number) => string | undefined;
51
55
  ensureProviderDaemon?: (provider: "discord" | "slack", settings: Settings) => Promise<EnsureChatDaemonResult>;
52
56
  ensureTelegramDaemon?: (settings: Settings) => Promise<EnsureTelegramDaemonDetailedResult>;
57
+ bindSlackThread?: (input: {
58
+ settings: Settings;
59
+ sessionId: string;
60
+ threadTs: string;
61
+ }) => Promise<BoundSlackThread>;
62
+ activatePreparedSession?: (input: {
63
+ settings: Settings;
64
+ sessionId: string;
65
+ }) => Promise<ActivatedPreparedSession>;
53
66
  }
54
67
  export declare function parseNotifyArgs(args: string[]): NotifyCommandArgs | undefined;
55
68
  export declare function runNotifyCommand(cmd: NotifyCommandArgs, deps?: NotifyCommandDeps): Promise<void>;
@@ -61,5 +74,33 @@ type TokenPromptInput = NodeJS.ReadStream & {
61
74
  };
62
75
  type TokenPromptOutput = Pick<NodeJS.WriteStream, "write">;
63
76
  export declare function promptForToken(input?: TokenPromptInput, output?: TokenPromptOutput): Promise<string>;
77
+ export interface BindThreadInvocation {
78
+ sessionId: string;
79
+ threadTs: string;
80
+ }
81
+ /**
82
+ * Enforce the exact `bind-thread` grammar at every entrypoint.
83
+ *
84
+ * The command accepts only a session and a root; a positional argument, an
85
+ * unrelated notify flag, or a target/credential input is a rejection rather than
86
+ * something silently ignored, so no other invocation shape can reach the
87
+ * binding authority.
88
+ */
89
+ export declare function assertStrictBindThreadInvocation(cmd: NotifyCommandArgs): BindThreadInvocation;
90
+ /** Confirmation carries identifiers only: no tokens, message bodies, or control secrets. */
91
+ export declare function formatBoundSlackThread(bound: BoundSlackThread): string;
92
+ export interface ActivateThreadInvocation {
93
+ sessionId: string;
94
+ }
95
+ /**
96
+ * Enforce the exact `activate-thread` grammar at every entrypoint.
97
+ *
98
+ * Activation names one prepared session and nothing else: the root it adopts is
99
+ * already the applied binding, so a supplied root, target, or credential is a
100
+ * rejection rather than something silently ignored.
101
+ */
102
+ export declare function assertStrictActivateThreadInvocation(cmd: NotifyCommandArgs): ActivateThreadInvocation;
103
+ /** Confirmation carries identifiers only: no endpoints, tokens, or thread content. */
104
+ export declare function formatActivatedSession(activated: ActivatedPreparedSession): string;
64
105
  export declare function printNotifyHelp(): void;
65
106
  export {};
@@ -1,6 +1,11 @@
1
+ import { type Installer, type NpmRegistryLookupOptions } from "../utils/npm-registry";
1
2
  interface ReleaseInfo {
2
3
  tag: string;
3
4
  version: string;
5
+ /** Registry the version came from. Release binaries still come from GitHub. */
6
+ registry: string;
7
+ /** Config problems that did not stop the lookup but changed its outcome. */
8
+ warnings: string[];
4
9
  }
5
10
  /** Result from running the installed binary and parsing its reported version. */
6
11
  export interface InstalledVersionVerification {
@@ -56,7 +61,8 @@ type PathPlatform = NodeJS.Platform;
56
61
  type PackageExists = (packageName: string, packageRoot: string) => boolean;
57
62
  export declare function resolveUpdateMethodForTest(ompPath: string, bunBinDir: string | undefined): "bun" | "npm" | "binary";
58
63
  export declare function resolveNpmManagedTargetForTest(ompPath: string, platform: PathPlatform, packageExists: PackageExists): PackageManagerTarget | undefined;
59
- export declare function formatBinaryDownloadFailureMessageForTest(binaryName: string, url: string, status: string | number, platform?: NodeJS.Platform): string;
64
+ export declare function getLatestReleaseForTest(options: NpmRegistryLookupOptions): Promise<ReleaseInfo>;
65
+ export declare function formatBinaryDownloadFailureMessageForTest(binaryName: string, url: string, status: string | number, platform?: NodeJS.Platform, registryNote?: string): string;
60
66
  export declare function buildReleaseBinaryUrlForTest(version: string, platform?: NodeJS.Platform, arch?: string): string;
61
67
  export declare function formatManualUpdateInstructionsForTest(platform?: NodeJS.Platform): string;
62
68
  export declare function formatVerificationFailureForTest(result: InstalledVersionVerification, expectedVersion: string): string;
@@ -91,9 +97,9 @@ export declare function runBinaryUpdateFlow(targetPath: string, url: string, exp
91
97
  * Run the update command.
92
98
  */
93
99
  export interface UpdateCommandDependencies {
94
- getLatestRelease?: () => Promise<ReleaseInfo>;
100
+ getLatestRelease?: (installer?: Installer) => Promise<ReleaseInfo>;
95
101
  resolveUpdateTarget?: () => Promise<UpdateTarget>;
96
- performUpdate?: (target: UpdateTarget, expectedVersion: string) => Promise<void>;
102
+ performUpdate?: (target: UpdateTarget, expectedVersion: string, registry?: string) => Promise<void>;
97
103
  refreshInstalledDefaultSkills?: () => Promise<void>;
98
104
  exit?: (code: number) => never;
99
105
  }
@@ -144,6 +144,16 @@ export declare class RootHelpCommand extends Command {
144
144
  }
145
145
  /** Normalize the sole `gjc resume` alias into the value-less launch intent. */
146
146
  export declare function normalizeResumeAlias(argv: readonly string[]): string[];
147
+ /**
148
+ * Map the common mistaken `models` subcommand spelling to non-agent listing.
149
+ *
150
+ * Agents frequently run `gjc models` from the bash tool expecting a catalog.
151
+ * Without this route, `models` was a positional launch prompt and nested agents
152
+ * re-invoked `gjc models`, spawning an unbounded process chain (#3857).
153
+ * Always rewrite to `launch --list-models` so the invocation exits after a
154
+ * bounded listing and never starts an interactive agent session.
155
+ */
156
+ export declare function routeModelsAlias(argv: readonly string[]): string[] | undefined;
147
157
  /** Apply the same default-launch routing used by runCli after root fast paths. */
148
158
  export declare function routeRootArgv(argv: readonly string[]): string[];
149
159
  /** Run the CLI with the given argv (no `process.argv` prefix). */
@@ -65,6 +65,12 @@ export default class Notify extends Command {
65
65
  message: import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
66
66
  description: string;
67
67
  };
68
+ "session-id": import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
69
+ description: string;
70
+ };
71
+ "thread-ts": import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
72
+ description: string;
73
+ };
68
74
  "owner-id": import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
69
75
  description: string;
70
76
  };
@@ -1,5 +1,17 @@
1
1
  /**
2
2
  * GC adapter for config file-locks (`<file>.lock` dirs holding `{pid, timestamp}`).
3
3
  */
4
- import type { GcStoreAdapter } from "../gjc-runtime/gc-runtime";
4
+ import type { GcCollectResult, GcContext, GcStoreAdapter } from "../gjc-runtime/gc-runtime";
5
+ /** Default per-root walk budget. Truncation is a warning, not a hard error. */
6
+ export declare const FILE_LOCK_GC_MAX_WALK_ENTRIES = 20000;
7
+ export interface FileLocksGcCollectOptions {
8
+ /** Override per-root entry budget (tests). Defaults to {@link FILE_LOCK_GC_MAX_WALK_ENTRIES}. */
9
+ maxWalkEntries?: number;
10
+ }
11
+ /**
12
+ * Discover + classify file-lock records. Each known lock root gets its own walk
13
+ * budget so truncating one root never skips the others. Caps surface as
14
+ * warnings (partial results), not hard discovery errors.
15
+ */
16
+ export declare function collectFileLocksForGc(ctx: GcContext, options?: FileLocksGcCollectOptions): Promise<GcCollectResult>;
5
17
  export declare const fileLocksGcAdapter: GcStoreAdapter;
@@ -2,6 +2,8 @@ export interface FileLockOptions {
2
2
  staleMs?: number;
3
3
  retries?: number;
4
4
  retryDelayMs?: number;
5
+ /** Stable host identity required to safely reclaim locks on a shared volume. */
6
+ ownerHostId?: string;
5
7
  }
6
8
  export declare const FileLockTestHooks: {
7
9
  afterParentMkdir?: (lockPath: string) => void | Promise<void>;
@@ -18,6 +20,7 @@ export declare function readFileLockInfoForGc(lockDir: string): Promise<FileLock
18
20
  export interface FileLockOwnerToken {
19
21
  pid: number;
20
22
  start_time?: string;
23
+ owner_host_id?: string;
21
24
  timestamp: number;
22
25
  }
23
26
  /** Outcome of a guarded lock-dir removal attempt (`removeFileLockDirForGc`). */
@@ -94,6 +94,8 @@ export declare const ModelsConfigFile: ConfigFile<{
94
94
  extraBody?: Record<string, unknown> | undefined;
95
95
  supportsStrictMode?: boolean | undefined;
96
96
  toolStrictMode?: "all_strict" | "none" | undefined;
97
+ supportsLongCacheRetention?: boolean | undefined;
98
+ promptCacheMode?: "automatic" | "explicit" | "none" | undefined;
97
99
  } | undefined;
98
100
  webSearch?: "auto" | "off" | "on" | undefined;
99
101
  authHeader?: boolean | undefined;
@@ -173,6 +175,8 @@ export declare const ModelsConfigFile: ConfigFile<{
173
175
  extraBody?: Record<string, unknown> | undefined;
174
176
  supportsStrictMode?: boolean | undefined;
175
177
  toolStrictMode?: "all_strict" | "none" | undefined;
178
+ supportsLongCacheRetention?: boolean | undefined;
179
+ promptCacheMode?: "automatic" | "explicit" | "none" | undefined;
176
180
  } | undefined;
177
181
  contextPromotionTarget?: string | undefined;
178
182
  wireModelId?: string | undefined;
@@ -247,6 +251,8 @@ export declare const ModelsConfigFile: ConfigFile<{
247
251
  extraBody?: Record<string, unknown> | undefined;
248
252
  supportsStrictMode?: boolean | undefined;
249
253
  toolStrictMode?: "all_strict" | "none" | undefined;
254
+ supportsLongCacheRetention?: boolean | undefined;
255
+ promptCacheMode?: "automatic" | "explicit" | "none" | undefined;
250
256
  } | undefined;
251
257
  contextPromotionTarget?: string | undefined;
252
258
  wireModelId?: string | undefined;
@@ -1,4 +1,73 @@
1
1
  import * as z from "zod/v4";
2
+ export declare const ModelCompatSchema: z.ZodObject<{
3
+ supportsStore: z.ZodOptional<z.ZodBoolean>;
4
+ supportsDeveloperRole: z.ZodOptional<z.ZodBoolean>;
5
+ sendSessionHeaders: z.ZodOptional<z.ZodBoolean>;
6
+ supportsMultipleSystemMessages: z.ZodOptional<z.ZodBoolean>;
7
+ supportsReasoningEffort: z.ZodOptional<z.ZodBoolean>;
8
+ reasoningEffortMap: z.ZodOptional<z.ZodObject<{
9
+ minimal: z.ZodOptional<z.ZodString>;
10
+ low: z.ZodOptional<z.ZodString>;
11
+ medium: z.ZodOptional<z.ZodString>;
12
+ high: z.ZodOptional<z.ZodString>;
13
+ xhigh: z.ZodOptional<z.ZodString>;
14
+ max: z.ZodOptional<z.ZodString>;
15
+ }, z.core.$strip>>;
16
+ maxTokensField: z.ZodOptional<z.ZodEnum<{
17
+ max_completion_tokens: "max_completion_tokens";
18
+ max_tokens: "max_tokens";
19
+ }>>;
20
+ supportsUsageInStreaming: z.ZodOptional<z.ZodBoolean>;
21
+ requiresToolResultName: z.ZodOptional<z.ZodBoolean>;
22
+ requiresMistralToolIds: z.ZodOptional<z.ZodBoolean>;
23
+ requiresAssistantAfterToolResult: z.ZodOptional<z.ZodBoolean>;
24
+ requiresThinkingAsText: z.ZodOptional<z.ZodBoolean>;
25
+ reasoningContentField: z.ZodOptional<z.ZodEnum<{
26
+ reasoning: "reasoning";
27
+ reasoning_content: "reasoning_content";
28
+ reasoning_text: "reasoning_text";
29
+ }>>;
30
+ requiresReasoningContentForToolCalls: z.ZodOptional<z.ZodBoolean>;
31
+ allowsSyntheticReasoningContentForToolCalls: z.ZodOptional<z.ZodBoolean>;
32
+ requiresAssistantContentForToolCalls: z.ZodOptional<z.ZodBoolean>;
33
+ supportsToolChoice: z.ZodOptional<z.ZodBoolean>;
34
+ supportsForcedToolChoice: z.ZodOptional<z.ZodBoolean>;
35
+ toolChoiceSupport: z.ZodOptional<z.ZodEnum<{
36
+ auto: "auto";
37
+ named: "named";
38
+ none: "none";
39
+ required: "required";
40
+ }>>;
41
+ disableReasoningOnForcedToolChoice: z.ZodOptional<z.ZodBoolean>;
42
+ disableReasoningOnToolChoice: z.ZodOptional<z.ZodBoolean>;
43
+ thinkingFormat: z.ZodOptional<z.ZodEnum<{
44
+ openai: "openai";
45
+ openrouter: "openrouter";
46
+ qwen: "qwen";
47
+ "qwen-chat-template": "qwen-chat-template";
48
+ zai: "zai";
49
+ }>>;
50
+ openRouterRouting: z.ZodOptional<z.ZodObject<{
51
+ only: z.ZodOptional<z.ZodArray<z.ZodString>>;
52
+ order: z.ZodOptional<z.ZodArray<z.ZodString>>;
53
+ }, z.core.$strip>>;
54
+ vercelGatewayRouting: z.ZodOptional<z.ZodObject<{
55
+ only: z.ZodOptional<z.ZodArray<z.ZodString>>;
56
+ order: z.ZodOptional<z.ZodArray<z.ZodString>>;
57
+ }, z.core.$strip>>;
58
+ extraBody: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
59
+ supportsStrictMode: z.ZodOptional<z.ZodBoolean>;
60
+ toolStrictMode: z.ZodOptional<z.ZodEnum<{
61
+ all_strict: "all_strict";
62
+ none: "none";
63
+ }>>;
64
+ supportsLongCacheRetention: z.ZodOptional<z.ZodBoolean>;
65
+ promptCacheMode: z.ZodOptional<z.ZodEnum<{
66
+ automatic: "automatic";
67
+ explicit: "explicit";
68
+ none: "none";
69
+ }>>;
70
+ }, z.core.$strip>;
2
71
  export declare const OpenAICompatSchema: z.ZodObject<{
3
72
  supportsStore: z.ZodOptional<z.ZodBoolean>;
4
73
  supportsDeveloperRole: z.ZodOptional<z.ZodBoolean>;
@@ -61,6 +130,12 @@ export declare const OpenAICompatSchema: z.ZodObject<{
61
130
  all_strict: "all_strict";
62
131
  none: "none";
63
132
  }>>;
133
+ supportsLongCacheRetention: z.ZodOptional<z.ZodBoolean>;
134
+ promptCacheMode: z.ZodOptional<z.ZodEnum<{
135
+ automatic: "automatic";
136
+ explicit: "explicit";
137
+ none: "none";
138
+ }>>;
64
139
  }, z.core.$strip>;
65
140
  export declare const GJC_MODEL_EFFORT_IDS: readonly ["minimal", "low", "medium", "high", "xhigh", "max"];
66
141
  export declare const GJC_MODEL_ASSIGNMENT_TARGET_IDS: readonly ["default", "executor", "architect", "planner", "critic"];
@@ -238,6 +313,12 @@ export declare const ModelOverrideSchema: z.ZodObject<{
238
313
  all_strict: "all_strict";
239
314
  none: "none";
240
315
  }>>;
316
+ supportsLongCacheRetention: z.ZodOptional<z.ZodBoolean>;
317
+ promptCacheMode: z.ZodOptional<z.ZodEnum<{
318
+ automatic: "automatic";
319
+ explicit: "explicit";
320
+ none: "none";
321
+ }>>;
241
322
  }, z.core.$strip>>;
242
323
  contextPromotionTarget: z.ZodOptional<z.ZodString>;
243
324
  wireModelId: z.ZodOptional<z.ZodString>;
@@ -352,6 +433,12 @@ export declare const ModelsConfigSchema: z.ZodObject<{
352
433
  all_strict: "all_strict";
353
434
  none: "none";
354
435
  }>>;
436
+ supportsLongCacheRetention: z.ZodOptional<z.ZodBoolean>;
437
+ promptCacheMode: z.ZodOptional<z.ZodEnum<{
438
+ automatic: "automatic";
439
+ explicit: "explicit";
440
+ none: "none";
441
+ }>>;
355
442
  }, z.core.$strip>>;
356
443
  webSearch: z.ZodOptional<z.ZodEnum<{
357
444
  auto: "auto";
@@ -519,6 +606,12 @@ export declare const ModelsConfigSchema: z.ZodObject<{
519
606
  all_strict: "all_strict";
520
607
  none: "none";
521
608
  }>>;
609
+ supportsLongCacheRetention: z.ZodOptional<z.ZodBoolean>;
610
+ promptCacheMode: z.ZodOptional<z.ZodEnum<{
611
+ automatic: "automatic";
612
+ explicit: "explicit";
613
+ none: "none";
614
+ }>>;
522
615
  }, z.core.$strip>>;
523
616
  contextPromotionTarget: z.ZodOptional<z.ZodString>;
524
617
  wireModelId: z.ZodOptional<z.ZodString>;
@@ -660,6 +753,12 @@ export declare const ModelsConfigSchema: z.ZodObject<{
660
753
  all_strict: "all_strict";
661
754
  none: "none";
662
755
  }>>;
756
+ supportsLongCacheRetention: z.ZodOptional<z.ZodBoolean>;
757
+ promptCacheMode: z.ZodOptional<z.ZodEnum<{
758
+ automatic: "automatic";
759
+ explicit: "explicit";
760
+ none: "none";
761
+ }>>;
663
762
  }, z.core.$strip>>;
664
763
  contextPromotionTarget: z.ZodOptional<z.ZodString>;
665
764
  wireModelId: z.ZodOptional<z.ZodString>;
@@ -1,4 +1,4 @@
1
1
  export declare const COORDINATOR_MCP_PROTOCOL_VERSION = "2024-11-05";
2
2
  export declare const COORDINATOR_MCP_SERVER_NAME = "gjc-coordinator-mcp";
3
- export declare const COORDINATOR_MCP_TOOL_NAMES: readonly ["gjc_coordinator_list_sessions", "gjc_coordinator_read_status", "gjc_coordinator_read_tail", "gjc_coordinator_list_questions", "gjc_coordinator_list_artifacts", "gjc_coordinator_read_artifact", "gjc_coordinator_read_coordination_status", "gjc_coordinator_watch_events", "gjc_coordinator_register_session", "gjc_coordinator_start_session", "gjc_coordinator_stop_session", "gjc_coordinator_send_prompt", "gjc_coordinator_submit_question_answer", "gjc_coordinator_read_turn", "gjc_coordinator_await_turn", "gjc_coordinator_report_status", "gjc_delegate_plan", "gjc_delegate_execute", "gjc_delegate_team"];
3
+ export declare const COORDINATOR_MCP_TOOL_NAMES: readonly ["gjc_coordinator_list_sessions", "gjc_coordinator_read_status", "gjc_coordinator_read_tail", "gjc_coordinator_list_questions", "gjc_coordinator_list_artifacts", "gjc_coordinator_read_artifact", "gjc_coordinator_read_coordination_status", "gjc_coordinator_watch_events", "gjc_coordinator_register_session", "gjc_coordinator_start_session", "gjc_coordinator_activate_session", "gjc_coordinator_stop_session", "gjc_coordinator_send_prompt", "gjc_coordinator_submit_question_answer", "gjc_coordinator_read_turn", "gjc_coordinator_await_turn", "gjc_coordinator_report_status", "gjc_delegate_plan", "gjc_delegate_execute", "gjc_delegate_team"];
4
4
  export type CoordinatorToolName = (typeof COORDINATOR_MCP_TOOL_NAMES)[number];
@@ -1,5 +1,7 @@
1
1
  import type { PrivateAskGateCodecV1, PublicReason } from "./question-gate-codec";
2
- export type CoordinatorSessionState = "booting" | "ready_for_input" | "running" | "needs_user_input" | "completed" | "errored" | "stale" | "unknown";
2
+ export type CoordinatorSessionState = "booting"
3
+ /** Live and endpoint-addressable, but withholding readiness until activation. */
4
+ | "prepared" | "ready_for_input" | "running" | "needs_user_input" | "completed" | "errored" | "stale" | "unknown";
3
5
  export interface CanonicalSessionSnapshotV1 {
4
6
  schema_version: 1;
5
7
  namespace_id: string;
@@ -3,6 +3,7 @@
3
3
  */
4
4
  export type { SlashCommandInfo, SlashCommandLocation, SlashCommandSource } from "../slash-commands";
5
5
  export { discoverAndLoadExtensions, ExtensionRuntimeNotInitializedError, loadExtensionFromFactory, loadExtensions, } from "./loader";
6
+ export * from "./ouroboros-ooo-bridge";
6
7
  export * from "./prefix-command-bridge";
7
8
  export * from "./runner";
8
9
  export * from "./types";
@@ -0,0 +1,13 @@
1
+ import { callTool, connectToServer, disconnectServer } from "../../runtime-mcp";
2
+ import type { ExtensionContext, InputEvent, InputEventResult } from "./types";
3
+ interface OuroborosOooBridgeOptions {
4
+ connect?: typeof connectToServer;
5
+ callTool?: typeof callTool;
6
+ disconnect?: typeof disconnectServer;
7
+ }
8
+ interface OuroborosOooBridgeHandler {
9
+ (event: InputEvent, ctx: ExtensionContext): Promise<InputEventResult>;
10
+ reset(): Promise<void>;
11
+ }
12
+ export declare function createOuroborosOooBridge(options?: OuroborosOooBridgeOptions): OuroborosOooBridgeHandler;
13
+ export {};
@@ -32,4 +32,3 @@ export interface ExactPrefixCommandBridgeOptions {
32
32
  * bridge while the child command runs.
33
33
  */
34
34
  export declare function createExactPrefixCommandBridge(options: ExactPrefixCommandBridgeOptions): (event: InputEvent, ctx: ExtensionContext) => Promise<InputEventResult>;
35
- export declare function createOuroborosOooBridge(): (event: InputEvent, ctx: ExtensionContext) => Promise<InputEventResult>;
@@ -239,6 +239,8 @@ export interface ExtensionContext {
239
239
  hasUI: boolean;
240
240
  /** Current working directory */
241
241
  cwd: string;
242
+ /** Aborted when the runner stops waiting for this handler, including handler timeout. */
243
+ signal?: AbortSignal;
242
244
  /** Session manager (read-only) */
243
245
  sessionManager: ReadonlySessionManager;
244
246
  /** Session classification supplied by the SDK for extension policy decisions. */
@@ -76,6 +76,18 @@ export interface DeepInterviewStateEnvelope {
76
76
  [key: string]: unknown;
77
77
  }
78
78
  export declare function hashContent(value: string): string;
79
+ /**
80
+ * Canonicalize interview prose to NFC.
81
+ *
82
+ * Hangul, unlike most Latin prose, routinely reaches the interview in both
83
+ * composed and decomposed form (macOS-sourced pastes and some IME/clipboard
84
+ * paths emit NFD), and the two forms are the same text for the user while
85
+ * being different JavaScript strings. Canonicalizing at the identity and
86
+ * length boundaries keeps one round per answer and keeps the character caps
87
+ * script-fair: decomposed Hangul otherwise costs two to three code points per
88
+ * syllable against the same budget.
89
+ */
90
+ export declare function canonicalizeDeepInterviewText(value: string): string;
79
91
  export declare function questionHash(questionText: string): string;
80
92
  export declare function answerHash(selectedOptions: string[] | undefined, customInput: string | undefined): string;
81
93
  /**
@@ -151,6 +163,8 @@ export declare function assertDeepInterviewStructuredResponseWithinLimit(value:
151
163
  /**
152
164
  * Assert a free-text input is within its size cap. Never inspects content for shell
153
165
  * metacharacters — free-text fields accept prose verbatim; this only bounds length.
166
+ * The cap is measured on the NFC form so decomposed Hangul is charged the same
167
+ * budget as the identical composed text.
154
168
  */
155
169
  export declare function assertDeepInterviewInputWithinLimit(value: string, max: number, fieldName?: string): void;
156
170
  /** Validate user-supplied deep-interview prose before an envelope is persisted. */
@@ -49,9 +49,17 @@ export interface GcError {
49
49
  scope: string;
50
50
  message: string;
51
51
  }
52
+ /** Non-fatal discovery partials (e.g. traversal caps). Does not affect exit code. */
53
+ export interface GcWarning {
54
+ store: GcStore;
55
+ scope: string;
56
+ message: string;
57
+ }
52
58
  export interface GcCollectResult {
53
59
  records: GcRecord[];
54
60
  errors: GcError[];
61
+ /** Optional partial-result notices; omitted by adapters that have none. */
62
+ warnings?: GcWarning[];
55
63
  }
56
64
  export interface GcPruneOutcome {
57
65
  removed: boolean;
@@ -108,6 +116,8 @@ export interface GcReport {
108
116
  stores: Record<GcStore, GcRecord[]>;
109
117
  counts: GcCounts;
110
118
  errors: GcError[];
119
+ /** Partial-result notices that do not fail the run (e.g. walk caps). */
120
+ warnings: GcWarning[];
111
121
  session_index?: GcSessionIndexHealth;
112
122
  }
113
123
  export interface GcRunResult {
@@ -134,6 +144,7 @@ export declare function collectGcReport(adapters: GcStoreAdapter[], ctx: GcConte
134
144
  * - usage/parse error => 2
135
145
  * - hard discovery errors => 1 (both modes)
136
146
  * - prune mode with a failed intended removal => 1
147
+ * - warnings alone never fail the run
137
148
  * - otherwise => 0
138
149
  */
139
150
  export declare function computeExitCode(report: GcReport): number;