@gajae-code/coding-agent 0.11.7 → 0.11.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (213) hide show
  1. package/CHANGELOG.md +73 -1
  2. package/dist/types/cli/args.d.ts +0 -2
  3. package/dist/types/cli.d.ts +1 -0
  4. package/dist/types/config/keybindings.d.ts +33 -3
  5. package/dist/types/config/model-profile-activation.d.ts +4 -3
  6. package/dist/types/config/model-profile-contract.d.ts +38 -0
  7. package/dist/types/config/model-profiles.d.ts +2 -3
  8. package/dist/types/config/settings-schema.d.ts +15 -2
  9. package/dist/types/edit/modes/patch.d.ts +13 -0
  10. package/dist/types/edit/path-mutation-lock.d.ts +15 -0
  11. package/dist/types/eval/py/executor.d.ts +1 -1
  12. package/dist/types/eval/py/tool-bridge.d.ts +1 -2
  13. package/dist/types/gjc-runtime/deep-interview-ambiguity.d.ts +12 -5
  14. package/dist/types/gjc-runtime/deep-interview-draft.d.ts +8 -0
  15. package/dist/types/gjc-runtime/deep-interview-payload.d.ts +41 -0
  16. package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +32 -17
  17. package/dist/types/gjc-runtime/deep-interview-repair.d.ts +17 -0
  18. package/dist/types/gjc-runtime/deep-interview-state.d.ts +135 -4
  19. package/dist/types/gjc-runtime/repository-binding.d.ts +63 -0
  20. package/dist/types/gjc-runtime/state-writer.d.ts +44 -0
  21. package/dist/types/gjc-runtime/ultragoal-guard.d.ts +1 -0
  22. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +24 -0
  23. package/dist/types/gjc-runtime/workflow-manifest.d.ts +5 -3
  24. package/dist/types/main.d.ts +8 -0
  25. package/dist/types/modes/components/runtime-mcp-add-wizard.d.ts +2 -1
  26. package/dist/types/modes/components/tool-status-header.d.ts +3 -2
  27. package/dist/types/modes/components/welcome.d.ts +4 -0
  28. package/dist/types/modes/controllers/command-controller.d.ts +2 -0
  29. package/dist/types/modes/controllers/selector-controller.d.ts +2 -1
  30. package/dist/types/modes/interactive-mode.d.ts +5 -2
  31. package/dist/types/modes/prompt-action-autocomplete.d.ts +6 -1
  32. package/dist/types/modes/prompt-suggestion-controller.d.ts +35 -0
  33. package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +2 -2
  34. package/dist/types/modes/types.d.ts +3 -0
  35. package/dist/types/modes/utils/hotkeys-markdown.d.ts +2 -1
  36. package/dist/types/runtime-mcp/manager.d.ts +1 -1
  37. package/dist/types/runtime-mcp/oauth-flow.d.ts +0 -5
  38. package/dist/types/runtime-mcp/plugin-network-boundary.d.ts +14 -0
  39. package/dist/types/runtime-mcp/redaction.d.ts +2 -0
  40. package/dist/types/sdk/broker/broker.d.ts +2 -0
  41. package/dist/types/sdk/broker/lifecycle.d.ts +6 -0
  42. package/dist/types/sdk/bus/chat-daemon-control.d.ts +7 -1
  43. package/dist/types/sdk/bus/config-commands.d.ts +2 -2
  44. package/dist/types/sdk/bus/config.d.ts +2 -0
  45. package/dist/types/sdk/bus/conversation-store.d.ts +1 -0
  46. package/dist/types/sdk/bus/index.d.ts +25 -0
  47. package/dist/types/sdk/bus/notification-orchestration.d.ts +1 -0
  48. package/dist/types/sdk/bus/prompt-reconciliation.d.ts +105 -0
  49. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +15 -3
  50. package/dist/types/sdk/bus/telegram-daemon-control.d.ts +5 -1
  51. package/dist/types/sdk/bus/telegram-daemon.d.ts +128 -1
  52. package/dist/types/sdk/bus/telegram-reference.d.ts +2 -0
  53. package/dist/types/sdk/host/control/operations.d.ts +1 -1
  54. package/dist/types/sdk/host/host.d.ts +1 -1
  55. package/dist/types/sdk/host/query/handlers.d.ts +9 -0
  56. package/dist/types/sdk/index.d.ts +2 -0
  57. package/dist/types/sdk/prompt-status.d.ts +88 -0
  58. package/dist/types/sdk/session-directory.d.ts +1 -1
  59. package/dist/types/sdk/startup-capability.d.ts +3 -0
  60. package/dist/types/session/agent-session.d.ts +2 -0
  61. package/dist/types/session/internal/managed-session-scope.d.ts +22 -3
  62. package/dist/types/session/internal/managed-session-storage.d.ts +24 -4
  63. package/dist/types/session/internal/native-publish-outcome.d.ts +48 -0
  64. package/dist/types/session/session-manager.d.ts +5 -1
  65. package/dist/types/session/session-storage.d.ts +31 -0
  66. package/dist/types/skill-state/active-state.d.ts +4 -0
  67. package/dist/types/task/index.d.ts +3 -1
  68. package/dist/types/task/receipt.d.ts +2 -0
  69. package/dist/types/task/types.d.ts +94 -0
  70. package/dist/types/tools/ask.d.ts +454 -174
  71. package/dist/types/tools/image-gen.d.ts +47 -1
  72. package/dist/types/tools/index.d.ts +4 -0
  73. package/dist/types/utils/prompt-suggestion.d.ts +33 -0
  74. package/package.json +8 -8
  75. package/scripts/capture-platform-shortcut-labels-showcase.ts +342 -0
  76. package/scripts/dogfood-repository-binding.ts +209 -0
  77. package/scripts/generate-sdk-operation-inventory.ts +2 -0
  78. package/scripts/run-test-manifest.ts +4 -4
  79. package/src/cli/args.ts +2 -92
  80. package/src/cli/mcp-cli.ts +4 -21
  81. package/src/cli/notify-cli.ts +5 -38
  82. package/src/cli.ts +50 -0
  83. package/src/commands/deep-interview.ts +9 -4
  84. package/src/commands/sdk.ts +2 -2
  85. package/src/commit/agentic/index.ts +3 -3
  86. package/src/commit/map-reduce/index.ts +2 -2
  87. package/src/config/keybindings.ts +157 -24
  88. package/src/config/model-profile-activation.ts +7 -18
  89. package/src/config/model-profile-contract.ts +161 -0
  90. package/src/config/model-profiles.ts +2 -3
  91. package/src/config/model-registry.ts +11 -1
  92. package/src/config/settings-schema.ts +17 -2
  93. package/src/coordinator-mcp/model-preset.ts +21 -74
  94. package/src/defaults/gjc/skills/deep-interview/SKILL.md +80 -165
  95. package/src/defaults/gjc/skills/ralplan/SKILL.md +3 -1
  96. package/src/edit/index.ts +3 -6
  97. package/src/edit/modes/patch.ts +38 -1
  98. package/src/edit/modes/replace.ts +42 -0
  99. package/src/edit/path-mutation-lock.ts +112 -0
  100. package/src/eval/py/executor.ts +30 -11
  101. package/src/eval/py/prelude.py +2 -2
  102. package/src/eval/py/tool-bridge.ts +34 -18
  103. package/src/extensibility/gjc-plugins/runtime-adapters.ts +2 -1
  104. package/src/gjc-runtime/deep-interview-ambiguity.ts +68 -47
  105. package/src/gjc-runtime/deep-interview-draft.ts +842 -0
  106. package/src/gjc-runtime/deep-interview-payload.ts +262 -0
  107. package/src/gjc-runtime/deep-interview-recorder.ts +294 -226
  108. package/src/gjc-runtime/deep-interview-repair.ts +1674 -0
  109. package/src/gjc-runtime/deep-interview-runtime.ts +264 -103
  110. package/src/gjc-runtime/deep-interview-state.ts +916 -4
  111. package/src/gjc-runtime/launch-tmux.ts +1 -1
  112. package/src/gjc-runtime/managed-owner-supervisor.ts +83 -4
  113. package/src/gjc-runtime/ralplan-runtime.ts +78 -4
  114. package/src/gjc-runtime/repository-binding.ts +267 -0
  115. package/src/gjc-runtime/session-state-sidecar.ts +25 -9
  116. package/src/gjc-runtime/state-writer.ts +166 -2
  117. package/src/gjc-runtime/tmux-owner-isolation.ts +2 -1
  118. package/src/gjc-runtime/tmux-sessions.ts +45 -6
  119. package/src/gjc-runtime/ultragoal-guard.ts +5 -5
  120. package/src/gjc-runtime/ultragoal-runtime.ts +181 -19
  121. package/src/gjc-runtime/workflow-manifest.generated.json +386 -1
  122. package/src/gjc-runtime/workflow-manifest.ts +191 -5
  123. package/src/internal-urls/docs-index.generated.ts +8 -6
  124. package/src/internal-urls/local-protocol.ts +33 -16
  125. package/src/internal-urls/mcp-protocol.ts +73 -11
  126. package/src/main.ts +25 -10
  127. package/src/modes/DESIGN.md +5 -0
  128. package/src/modes/acp/acp-agent.ts +50 -16
  129. package/src/modes/components/model-selector.ts +42 -8
  130. package/src/modes/components/plan-preview-overlay.ts +1 -1
  131. package/src/modes/components/runtime-mcp-add-wizard.ts +5 -0
  132. package/src/modes/components/tool-status-header.ts +20 -4
  133. package/src/modes/components/welcome.ts +32 -20
  134. package/src/modes/controllers/command-controller.ts +97 -54
  135. package/src/modes/controllers/event-controller.ts +10 -0
  136. package/src/modes/controllers/input-controller.ts +7 -2
  137. package/src/modes/controllers/runtime-mcp-command-controller.ts +29 -6
  138. package/src/modes/controllers/selector-controller.ts +46 -54
  139. package/src/modes/interactive-mode.ts +70 -36
  140. package/src/modes/prompt-action-autocomplete.ts +32 -13
  141. package/src/modes/prompt-suggestion-controller.ts +96 -0
  142. package/src/modes/shared/agent-wire/workflow-gate-broker.ts +2 -2
  143. package/src/modes/types.ts +3 -0
  144. package/src/modes/utils/hotkeys-markdown.ts +64 -36
  145. package/src/modes/utils/ui-helpers.ts +5 -3
  146. package/src/prompts/agents/architect.md +0 -1
  147. package/src/prompts/agents/critic.md +0 -1
  148. package/src/prompts/system/prompt-suggestion-system.md +32 -0
  149. package/src/prompts/system/system-prompt.md +7 -4
  150. package/src/prompts/tools/cron.md +3 -1
  151. package/src/runtime-mcp/json-rpc.ts +7 -4
  152. package/src/runtime-mcp/manager.ts +51 -53
  153. package/src/runtime-mcp/oauth-flow.ts +0 -72
  154. package/src/runtime-mcp/plugin-network-boundary.ts +101 -0
  155. package/src/runtime-mcp/redaction.ts +30 -0
  156. package/src/runtime-mcp/transports/http.ts +13 -6
  157. package/src/sdk/broker/broker.ts +34 -20
  158. package/src/sdk/broker/lifecycle.ts +185 -36
  159. package/src/sdk/broker/session-index.ts +11 -1
  160. package/src/sdk/bus/chat-daemon-control.ts +20 -5
  161. package/src/sdk/bus/config-commands.ts +2 -2
  162. package/src/sdk/bus/config.ts +9 -1
  163. package/src/sdk/bus/conversation-store.ts +40 -6
  164. package/src/sdk/bus/index.ts +240 -65
  165. package/src/sdk/bus/lifecycle-commands.ts +47 -3
  166. package/src/sdk/bus/lifecycle-control-runtime.ts +11 -2
  167. package/src/sdk/bus/lifecycle-orchestrator.ts +32 -1
  168. package/src/sdk/bus/notification-orchestration.ts +12 -0
  169. package/src/sdk/bus/notification-service.ts +27 -2
  170. package/src/sdk/bus/prompt-reconciliation.ts +239 -0
  171. package/src/sdk/bus/recent-activity.ts +90 -26
  172. package/src/sdk/bus/telegram-daemon-contract.ts +15 -3
  173. package/src/sdk/bus/telegram-daemon-control.ts +145 -33
  174. package/src/sdk/bus/telegram-daemon.ts +853 -112
  175. package/src/sdk/bus/telegram-reference.ts +20 -2
  176. package/src/sdk/cli/session-cli.ts +15 -2
  177. package/src/sdk/host/control/dispatch.ts +1 -1
  178. package/src/sdk/host/control/operations.ts +1 -1
  179. package/src/sdk/host/host.ts +2 -6
  180. package/src/sdk/host/query/handlers.ts +70 -5
  181. package/src/sdk/index.ts +12 -0
  182. package/src/sdk/prompt-status.ts +97 -0
  183. package/src/sdk/protocol/operation-inventory.generated.json +47 -0
  184. package/src/sdk/protocol/operation-registry.ts +18 -4
  185. package/src/sdk/session-directory.ts +5 -1
  186. package/src/sdk/session.ts +2 -0
  187. package/src/sdk/startup-capability.ts +9 -1
  188. package/src/session/agent-session.ts +138 -5
  189. package/src/session/blob-store.ts +7 -2
  190. package/src/session/internal/managed-session-scope.ts +998 -133
  191. package/src/session/internal/managed-session-storage.ts +268 -203
  192. package/src/session/internal/native-publish-outcome.ts +266 -0
  193. package/src/session/session-manager.ts +406 -360
  194. package/src/session/session-storage.ts +151 -11
  195. package/src/skill-state/active-state.ts +10 -0
  196. package/src/task/executor.ts +13 -5
  197. package/src/task/gjc-command.ts +2 -2
  198. package/src/task/index.ts +121 -15
  199. package/src/task/receipt.ts +3 -0
  200. package/src/task/types.ts +34 -3
  201. package/src/tools/ask.ts +199 -88
  202. package/src/tools/ast-edit.ts +2 -2
  203. package/src/tools/bash-pty-selection.ts +2 -2
  204. package/src/tools/browser/screenshot-format.ts +6 -1
  205. package/src/tools/cron.ts +1 -1
  206. package/src/tools/image-gen.ts +178 -6
  207. package/src/tools/index.ts +4 -0
  208. package/src/tools/render-utils.ts +7 -1
  209. package/src/utils/edit-mode.ts +2 -2
  210. package/src/utils/prompt-suggestion.ts +265 -0
  211. package/src/utils/sixel.ts +3 -3
  212. package/src/web/insane/url-guard.ts +3 -1
  213. package/src/web/scrapers/docs-rs.ts +30 -5
package/CHANGELOG.md CHANGED
@@ -2,22 +2,84 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.11.9] - 2026-07-24
6
+
7
+ ### Fixed
8
+
9
+ - Alibaba Token Plan canonical first-event timeouts now surface without session retry/fallback replay and are not internally retried by auto-compaction, preventing repeated provider usage (#3026).
10
+
11
+ - Telegram notification topics now fence malformed successful `createForumTopic` responses per session endpoint, preventing repeated ambiguous topic creation while keeping explicit Bot API failures retryable.
12
+ - Windows managed-session resume no longer reports `durability_failed` when Bun rejects `fsync` on the read-only descriptor used to revalidate an existing canonical binding; Windows now uses an owner-writable descriptor for that durability fence while retaining no-follow and pre/post identity/content checks.
13
+ - SDK daemon CLI end-to-end tests now drain spawned child stdout and stderr concurrently with process exit, preventing CI pipe teardown races from replacing the product exit contract with SIGPIPE status 141 (#3024).
14
+ - Interactive launch bootstrap is now suppressed for parser-accepted `--print=`, `--help=`, and `--version=` equals forms, keeping non-interactive output free of the warming-workspace preamble on TTYs.
15
+ - Managed legacy-session artifact migration now accepts up to 50,000 files, processes copy work in bounded batches, and reports capacity exhaustion separately from unsafe artifact topology (#2935).
16
+ - Kimi Code first-event timeouts now surface after the provider's continuous first-event wait instead of replaying the full request from zero.
17
+
18
+ - Rejected subagent schema payloads now retain their complete structured data in canonical output artifacts; inline results remain bounded while `agent://` output stays lossless (#2894).
19
+ - Managed legacy-session artifact migration now validates Windows directory roots from the native tree snapshot, tolerates only lazy metadata on plain Windows directories, and replays both clean and cleanup-pending detaches while retaining fail-closed receipt validation. Canonical binding durability sync uses a writable no-follow handle on Windows NTFS stacks that reject `FlushFileBuffers` on read-only handles (#3015, #2913).
20
+ ## [0.11.8] - 2026-07-23
21
+ ### Added
22
+
23
+ - Keybinding configuration now keeps portable canonical text while runtime shortcut labels render platform-native, including concise MacBook glyphs in inline surfaces and glyph-plus-text accessibility labels in `/hotkeys` and `/help`; `/hotkeys` remains authoritative for effective remapped bindings.
24
+
25
+ ### Added
26
+
27
+ - Plans and delegated tasks carry an authoritative repository binding (`gjc.repository_binding.v1`). Ultragoal/ralplan stamp identity at creation; task lanes stamp omitted bindings from session cwd **before** agent discovery; ralplan stage writes and handoff re-entry enforce the seed binding; declared paths must stay under the bound root; task receipts include the resolved identity; linked isolation worktrees must match the source repository (#2901).
28
+
29
+ ### Fixed
30
+
31
+ - Runtime MCP OAuth credentials are now bound to their authorized server origin and token endpoint, reject redirecting refresh responses, and fail closed when legacy or changed configuration lacks an exact match.
32
+ - `/share` now keeps full-session HTML in owner-private unpredictable staging until the share handler or `gh gist create` process has fully stopped; cancelling a blocked gist upload terminates and awaits that process before reporting cancellation and removing the export.
33
+ - MCP diagnostics now redact opaque endpoint paths, user information, query values, and fragments without changing outbound requests, and parse-failure logs omit response bodies that could echo request secrets.
34
+ - Telegram notification daemon self-heals degraded on-disk state: permanently missing scan roots are pruned (so one deleted worktree no longer disables orphan-topic cleanup), and retained exact-unlink transition/placeholder artifacts are reaped on ownership acquire and each scan. `gjc daemon reload` can recover without manual filesystem surgery (#2956).
35
+ - On macOS, resuming a managed session no longer fails with `identity_mismatch` when the first write-append open changes only file `ctime` (e.g. APFS write-provenance / `com.apple.provenance`). `appendSync` allows a single bounded re-capture + retry when `dev`/`ino`/`size`/`mtime`/SHA-256 remain unchanged, and still rejects real content races and repeated ctime transitions (#2944).
36
+ - Interactive `/resume` / `AgentSession.switchSession()` now awaits verified managed `local://` legacy-root migration for the newly selected session before post-commit lifecycle proceeds, matching cold-start `createAgentSession()` readiness from #2797 so synchronous `local://` resolution no longer fails with "legacy migration must complete before path resolution" after a mid-session switch (#2925).
37
+ - Concurrent edits to the same file path are serialized through a path-scoped mutation lock (in-process always; durable cross-process lock on the real filesystem). Disjoint concurrent `applyPatch` / replace mutations no longer silently overwrite each other, and a commit-time content check rejects writers that observe a mid-flight change (#2900).
38
+ - Concurrent edits to the same file path are serialized through a path-scoped mutation lock (in-process always; durable cross-process lock on the real filesystem). Disjoint concurrent `applyPatch` / replace mutations no longer silently overwrite each other, and a commit-time content check rejects writers that observe a mid-flight change. The production `executePatchSingle` / `LspFileSystem` path explicitly enables the durable lock rather than inferring it from FileSystem object identity (#2900).
39
+ - Lean notification verbosity no longer floods remote clients with intermediate tool-turn `turn_stream` frames. Under `/lean`, the latest assistant answer is deferred until `agent_end` (idle); ask lead-ins still flush immediately before inline buttons, and `/verbose` keeps per-turn streaming (including opt-in live frames) (#2863).
40
+ - Ultragoal `complete-goals` no longer reports contradictory next actions when every incomplete story is `blocked` or `review_blocked`. Text and JSON now agree on `next-action=resolve-blockers` with blocked goal IDs/status; failed-only schedules surface `retry-failed`; `execute-goal` always includes a `goal_id` (#2903).
41
+ - Bound each Python tool bridge bearer capability to one active session registration, reject non-canonical or empty bearer credentials before lookup, and rotate authority whenever a retained session replaces its kernel.
42
+ - Deep Interview now scopes provider-facing `ask` metadata to the persisted workflow stage, including after durable session resume: Round 0 advertises only the locked `intent_contract` branch, later rounds advertise ordinary and `intent_review` branches, foreign workflow gates cannot seed recorder state, and wire-valid empty positive-round reviews reach canonical Zod diagnostics while malformed authority remains fail-closed.
43
+ - Bounded docs.rs rustdoc downloads, legacy cache reads, and gzip expansion before parsing or caching; transport-level content encoding is disabled and rejected so Bun cannot decompress outside the explicit output guard.
44
+
45
+ ### Added
46
+
47
+ - Added SDK v3 prompt reconciliation through `turn.prompt_status` with caller-supplied `clientRef` correlation, bounded live-session lifecycle retention, reconnect-safe lookup, and explicit ordered non-replay semantics for `turn.prompt` (#2930).
48
+ - Added `models.profiles.list` discovery of the effective built-in plus `models.yml` profile catalog, exact-ID pre-spawn validation that reloads host configuration for each lifecycle request, and structured `unknown_model_profile` / `model_profile_registry_error` details across lifecycle startup failures (#2931).
49
+
5
50
  ## [0.11.7] - 2026-07-22
6
51
  ### Added
7
52
 
8
53
  - `/btw` now opens an ephemeral multi-turn side chat: plain text continues the side thread until Esc returns to the main chat, while visible text-only context stays outside the main transcript and session observability/debug hooks and is scrubbed synchronously on close or abort.
9
54
  - Added `statusLine.showActionHints` (default: `true`) to hide contextual action hints while retaining configured status-line segments.
10
55
  - `skill_discovery` empty results now carry a `notice` when discovery config caused the emptiness — naming the exact disabled setting (`skills.enabled`, `skills.enablePiProject`, or `skills.enablePiUser`) and the `gjc config set` command to enable it. Previously a disabled config was indistinguishable from "no skills exist", silently hiding freshly written user/project skills.
56
+ - `generate_image` now supports Alibaba Bailian (Token Plan) `wan2.7-image` as an image provider: set `providers.image` to `alibaba` (or let auto-detect find `ALIBABA_TOKEN_PLAN_API_KEY` / a registered `alibaba-token-plan` key), override the model with `providers.imageModel` (e.g. `wan2.7-image-pro`). Short-lived OSS result URLs are downloaded immediately, and image editing works via input images.
11
57
 
12
58
  ### Fixed
59
+ - Telegram `/session_recent` now retries one concurrently appended managed transcript and omits only candidates that remain unstable, preserving independently verified recent-session rows.
60
+ - Repeated byte-identical stale SDK broker locks no longer cause startup to loop when a prior tombstone exists.
61
+ - ACP session close now rotates idempotency keys for resumed attachment generations while retaining the same key across terminally uncertain close retries.
62
+ - ConversationStore now tolerates only unsupported Windows parent-directory durability errors after preserving temporary-file fsync and atomic rename.
63
+ - Ralplan no longer re-asks for execution approval when the user already explicitly named `ultragoal` or `team` in the current turn; that naming is the consent.
64
+ - Interactive Windows startup now stays keyboard-ready with large session histories and native multiplexers by showing an interactive-only bootstrap before the first TUI start, deferring bounded recent-session discovery until afterward, and reducing psmux frame pressure while preserving the three-second animation and update checks.
13
65
 
66
+ - Cron guidance now routes silent recurring polling and event-driven PR/CI watchers to `monitor`, because every cron firing starts a normal assistant turn and prompt wording cannot reliably suppress its response.
14
67
  - Ordinary `ask` calls now normalize a provider-emitted `deepInterview: null` placeholder instead of misclassifying it as malformed Round-0 intent recovery data and rejecting it before coercion.
68
+ - SDK event replay authorization now refreshes the negotiated capability cache synchronously from the native-sanitized replay snapshot before host filtering, preserving initial and repeated-hello capability updates without trusting client frame claims.
69
+
70
+ - Plugin-bundle HTTP and SSE MCP requests now bind every connection to a validated public address and revalidate bounded redirects before following them.
71
+ - Deep Interview now exposes stage-specific provider-facing `ask` metadata: Round 0 advertises only the locked `intent_contract` branch, while later rounds advertise ordinary and `intent_review` branches, preventing strict-schema constraint stripping from making an invalid empty Round 0 review selectable.
72
+ - Deep Interview now exposes stage-specific provider-facing `ask` metadata, including after durable session resume: Round 0 advertises only the locked `intent_contract` branch, while later rounds advertise ordinary and `intent_review` branches. Remaining strict-schema constraints that providers cannot express fail closed with bounded corrective guidance instead of an opaque retry loop.
73
+ - Deep Interview now exposes stage-specific provider-facing `ask` metadata, including after durable session resume: Round 0 advertises only the locked `intent_contract` branch, while later rounds advertise ordinary and `intent_review` branches. Foreign workflow gates can no longer seed Deep Interview recorder state, and remaining strict-schema constraints that providers cannot express fail closed with bounded corrective guidance instead of an opaque retry loop.
15
74
  - Documented that custom OpenAI-compatible models omit vision by default: when `input` is unset, GJC treats the model as text-only and strips images with `[image omitted: model does not support vision]`. Vision backends must set `input: [text, image]` in `models.yml`.
16
75
  - Restored `/models` preset landing navigation after the Image Generation row and made compaction/pruning regression fixtures use an explicit 200K context boundary instead of a mutable provider descriptor default.
17
76
  - Fixed Windows legacy session artifact migration by using native directory identity size, a traversable detached-path alias, and writable file handles for final durability sync.
18
77
  - `gjc setup credentials` now auto-imports only OAuth credentials with a finite expiry strictly in the future. Expired or malformed-expiry discoveries remain visible as non-importable records, and existing imported credentials remain recoverable through `/login`.
19
78
  - Resumed managed sessions now complete the verified legacy `local://` artifact migration before synchronous path resolution, preserving legacy scratch files instead of failing startup with a migration-order error.
20
79
  - Corrected Telegram's uncertain lifecycle guidance so create, close, and resume commands describe their own possible outcome; close and resume no longer display the create-only duplicate-start warning.
80
+ - Telegram ask notifications now preserve the authoritative recommended choice from native asks and workflow gates, marking that option as `(Recommended)` in the message body without changing button indices or submitted answers.
81
+ - Telegram `/session_close` now fails closed when tmux disappearance cannot be confirmed, and publishes the managed owner verdict before locked terminal-state preservation so normal close finalization is not delayed behind that state path.
82
+ - Managed publication now fails closed on malformed, committed, or mutation-unknown native outcomes: it never retries or cleans a destination, and preserves bounded atomic-unavailable/durability diagnostics through managed startup (#2804).
21
83
 
22
84
  ## [0.11.5] - 2026-07-20
23
85
  ### Fixed
@@ -38,12 +100,14 @@
38
100
  - Shell environment snapshots now use one process-private temporary root with exclusive private files, trusted cache validation, and whole-root shutdown cleanup instead of a predictable shared directory.
39
101
  - Python kernel startup now materializes its bundled runner in one process-private temporary directory with exclusive file creation instead of consulting a predictable shared cache path.
40
102
  - SSH command construction and discovery now reject malformed destinations with unsafe prefixes or control characters while preserving normal host, address, username, and alias forms.
103
+ - Bounded MCP resource URI and template matching now skips oversized templates and uses deterministic literal-segment matching instead of dynamically constructed regular expressions.
41
104
  - Fixed the `subagent` tool's `resume` action silently swallowing manager failures. Resume outcomes other than `context_unavailable`/`not_found` (`no_runner`, `resume_failed`, `owner_shutdown_in_progress`, …) were dropped and the stale terminal subagent snapshot was returned as if the resume had succeeded, so ralplan's re-review loop believed the persisted Planner had resumed when it had not and never fell back correctly. The resume action now surfaces every non-ok reason (matching the `steer` branch), and the task resume runner marks a resumed subprocess that aborted or exited non-zero as a `failed` job (carrying its rendered failure summary) instead of reporting it `completed`.
42
105
  - Daemon timeout flags now reject missing, malformed, non-positive, fractional, whitespace-containing, and unsafe integer values before daemon command side effects instead of partially parsing them.
43
106
  - Hardened standalone HTML session exports so session identifiers, provider/model labels, and embedded raster images remain confined to their intended HTML contexts; malformed image payloads are omitted.
44
107
  - Restored legacy `gjc coordinator-mcp` and root `gjc --team --team-size <n>` routing to their native MCP and team commands, with strict team-size validation that prevents malformed legacy flags from selecting team lifecycle actions.
45
108
  - Fixed the `subagent` tool's `resume` action silently swallowing manager failures. Resume outcomes other than `context_unavailable`/`not_found` (`no_runner`, `resume_failed`, `owner_shutdown_in_progress`, …) were dropped and the stale terminal subagent snapshot was returned as if the resume had succeeded, so ralplan's re-review loop believed the persisted Planner had resumed when it had not and never fell back correctly. The resume action now surfaces every non-ok reason (matching the `steer` branch), and the task resume runner marks a resumed subprocess that aborted or exited non-zero as a `failed` job (preserving its error text) instead of reporting it `completed`.
46
109
  - OpenRouter image generation now retrieves provider-returned HTTP(S) images only through connection-bound public-address validation, revalidates bounded redirects, and enforces image content-type and byte limits before buffering.
110
+ - Fixed session resume crashing with `TypeError: undefined is not an object (evaluating 'usage.input')`, and hardened both usage-aggregation paths against silent total corruption, when a persisted transcript contained a parseable-but-malformed assistant or `task` tool-result entry — as produced by torn concurrent multi-writer / NFS appends. `parseSessionEntries` accepts any parseable JSON, so a corrupt `usage` could be absent, `{}` (NaN totals), numeric strings (`"0" + "10"` → `"010"`), negative (silently reducing totals), a present-but-null/incomplete `premiumRequests`/`cost`, a non-record `cost` (e.g. an array), or cumulatively overflow to `Infinity`. Both the resume (`#buildIndex`) and runtime append (`#appendEntry`) paths now route through one shared validator that requires every usage bucket and `cost.total` to be finite non-negative numbers (defaulting only truly-absent `premiumRequests`/`cost`, and rejecting present-but-null/incomplete fields rather than zeroing them) and rejects any record that would overflow cumulative totals, skipping and reporting the malformed record instead of poisoning every `getUsageStatistics()` consumer.
47
111
  - Fixed the `subagent` tool's `resume` failing immediately for a persisted ralplan Planner. A subagent that finishes by calling `yield` (or is torn down right after a tool executes) left the saved session ending on an assistant `toolCall` with no matching `toolResult`; replaying that history on resume produced an invalid provider request (a `tool_use` not followed by a `tool_result`) that failed the resumed turn at once. Resumed transcripts now reconcile any trailing unpaired tool call with a synthesized placeholder result before the first resumed prompt. Additionally, a failed/no-op resume leg no longer overwrites the prior run's success output artifact with an empty file.
48
112
  - Fixed persisted subagent resumes being rejected before session reconstruction with `Session is inside managed storage but is not an authorized managed candidate`. Child session files intentionally live inside their parent session's artifact directory and are not top-level resume-picker candidates; the task resume path now explicitly opens the exact internally registered child session directory while retaining strict candidate validation for user-selected managed sessions.
49
113
  - Managed session resume scans now read only a bounded no-follow header prefix from foreign workspace transcripts, while fully recapturing and revalidating owned candidates before granting migration, receipt, or deletion authority.
@@ -87,6 +151,10 @@
87
151
  ### Changed
88
152
  - The `read` tool is now receipt-by-default: bare and unparseable reads return a bounded receipt (≤50 lines / 10 KiB) with a re-read-with-selector footer only when truncated, `:raw` stays pure verbatim up to a max(2 MiB, spill threshold) ceiling, structural summaries cap unit-granularly at 20 KiB while preserving elision and source-recovery footers, and directories are byte/line capped and never spill. Only an explicit full-content selector (`:raw` or an explicit range) with real content is spill-eligible. Subagent previews now enforce a real byte/code-point cap via per-shape render budgets plus a shape-aware artifact-eligibility tag enforced centrally in output-meta.
89
153
 
154
+
155
+ ### Fixed
156
+ - Ultragoal objective ownership no longer treats arbitrary strings that merely mention `goals.json`/`ledger.jsonl` as Ultragoal-owned; only the exact default aggregate objective qualifies for the known-objective path.
157
+
90
158
  ### Fixed
91
159
  - Workflow-state handoff no longer self-locks the active-state cache, so a same-turn skill handoff (e.g. ultragoal → ralplan) completes instead of stalling behind a lock the handoff itself still holds (#2638).
92
160
  - SDK host shutdown now retries a failed broker unregister instead of short-circuiting with a stale broker-index entry, while retained startup-cleanup owner-release failures remain isolated from the red extension-error path (#2625).
@@ -120,6 +188,7 @@
120
188
  ### Fixed
121
189
  - Repository LSP configuration can no longer define process-affecting server behavior: project files may control declarative matching, activation, and capabilities, but cannot set launch fields, initialization options, or opaque server settings. Trusted canonical user configuration outside the project retains those overrides; project-controlled plugin roots and the quarantined `--plugin-dir` surface cannot inject them. Automatic discovery uses trusted external executables and rejects repository-owned lexical paths as well as symlink-resolved project binaries; status uses the session cwd as its lspmux trust root. `GJC_DISABLE_LSPMUX=1` is the canonical opt-out and `PI_DISABLE_LSPMUX=1` is a supported compatibility alias; either truthy value disables lspmux probing and wrapping.
122
190
  - Palette slash commands now run only from an empty composer; drafts are never touched.
191
+ - Individual default and named-role model assignments now keep the model selector open for consecutive choices, while batch assignments retain their existing close-on-success behavior.
123
192
  - Aborting a session without an enabled active goal no longer suppresses the first reminder when a goal is activated later; active-goal abort suppression is one-shot, goal-owned, and clears across inactive or replacement-goal transitions (#2436).
124
193
  - Palette slash submissions no longer clear or rewrite composer text, cursor state, history, or pending images created while an asynchronous input hook is awaiting; canonical keyboard submission cleanup remains unchanged (#2441).
125
194
  - Dead browser-tab recovery now expires descriptors without releasing replacement, revived, or differently owned tabs, while exactly-once teardown closes stale targets and releases browser holds without refcount underflow (#2437).
@@ -145,6 +214,9 @@
145
214
  ### Fixed
146
215
  - Connected MCP server instructions now remain untrusted user-role data instead of entering the cached system prompt; hostile file paths, working directories, and workspace-tree metadata are structurally encoded, and volatile project context is removed from durable session history between requests.
147
216
  - Restored the strict G002 public-surface quarantine by removing the default README advertisement for the private coordinator MCP runtime.
217
+ ### Added
218
+
219
+ - Added opt-in prompt suggestions (Claude Code-style ghost-text autocomplete): with the `promptSuggestions` setting enabled, a smol-model prediction of your likely next prompt renders as dim ghost text in the empty composer after each agent turn; Tab accepts it, typing dismisses it, and a new turn clears it. Predictions are heuristically gated (silence on evaluative/meta/agent-voice/overlong output) and never generated while the composer has text or a turn is streaming.
148
220
 
149
221
  ## [0.11.1] - 2026-07-16
150
222
 
@@ -214,11 +286,11 @@
214
286
 
215
287
  ## [0.10.1] - 2026-07-13
216
288
 
289
+ - Deep-interview bundled guidance now uses the typed native setup, topology, answer-recovery, round-result, selective inspection, and sanity-check commands for normal workflow state changes. Generic `gjc state` remains limited to documented compatibility/recovery handoff paths; ambiguity, receipts, revisions, topology persistence, and diagnosis/repair remain runtime-owned.
217
290
  ### Added
218
291
 
219
292
  - Added an owner-proof idle session reaper and `gjc_coordinator_stop_session` for ephemeral (delegate-created) coordinator sessions. Termination goes exclusively through the canonical SDK broker `session.close` lifecycle (durable process identity verified before close) — never a raw `process.kill` or tmux control. The reaper re-validates ephemeral and no-active-turn state at close time under the same per-session mutation lock as delegate reuse, and purges coordinator metadata only after SDK closure is verified, retaining it when closure cannot be confirmed (#2080).
220
293
 
221
- - Added an owner-proof idle session reaper and `gjc_coordinator_stop_session` for ephemeral (delegate-created) coordinator sessions. Termination goes exclusively through the owner-proof `forceCloseGjcTmuxSession` path (pid, native session id, owner generation, server key, and start time all verified before SIGTERM) — never a raw `process.kill`. The reaper binds each close to the persisted runtime-state file, re-validates ephemeral and no-active-turn at kill time under the same per-session mutation lock as delegate reuse, and purges state only on verified termination (#2080).
222
294
  - SDK clients can now pass an explicit thinking level to `model.set`, atomically applying the effective model and thinking level to the active session and the machine-global default for future sessions, while project policy and resumed session history retain precedence.
223
295
  - Context-usage tokens/% now use provider-reported usage as the single source of truth on every surface. `AgentSession.getContextUsage()` returns a source-tagged snapshot (`source: "provider_anchor" | "heuristic" | "unknown"`), and the status-line `context_pct` segment, inline model percentage, and `/context` totals consume that snapshot instead of recomputing an independent heuristic sum — so footer, status line, `/context`, ACP, and RPC can no longer disagree about the same session state. Heuristic estimation now applies only when no provider anchor exists (session start, aborted/error-only turns), and that fallback now includes the fixed system-prompt/tool/skill context it previously omitted. The pre-prompt compaction estimate honors the latest-compaction boundary (never anchors on stale pre-compaction usage totals), unknown post-compaction usage stays unknown (status line renders `?`; ACP omits the `usage_update` instead of reporting `used: 0`), and `/context` labels its total by provenance with a reconciliation line when the estimated category composition diverges from the provider-reported total.
224
296
  - Post-durable default-model-selection failures now expose a stable SDK error with bounded `restored`, `partial`, or `unknown` rollback state; preflight and validation errors remain unchanged.
@@ -52,5 +52,3 @@ export interface Args {
52
52
  authBootstrap?: true;
53
53
  }
54
54
  export declare function parseArgs(args: string[]): Args;
55
- export declare function getExtraHelpText(): string;
56
- export declare function printHelp(): void;
@@ -6,6 +6,7 @@
6
6
  import "@gajae-code/utils/postmortem";
7
7
  import { Command, type CommandEntry } from "@gajae-code/utils/cli";
8
8
  export declare const commands: CommandEntry[];
9
+ export declare function interactiveBootstrapText(argv: readonly string[], stdinIsTTY?: boolean, stdoutIsTTY?: boolean): string | undefined;
9
10
  export declare class RootHelpCommand extends Command {
10
11
  static description: string;
11
12
  static hidden: boolean;
@@ -378,6 +378,10 @@ declare function migrateKeybindingsConfigFile(agentDir: string): void;
378
378
  export declare class KeybindingsManager extends TuiKeybindingsManager {
379
379
  #private;
380
380
  constructor(userBindings?: KeybindingsConfig, configPath?: string);
381
+ /**
382
+ * Replace user bindings only after canonical grammar validation.
383
+ */
384
+ setUserBindings(userBindings: KeybindingsConfig): void;
381
385
  /**
382
386
  * Create from config file at agentDir/keybindings.json.
383
387
  */
@@ -386,6 +390,11 @@ export declare class KeybindingsManager extends TuiKeybindingsManager {
386
390
  * Create an in-memory keybindings manager without file persistence.
387
391
  */
388
392
  static inMemory(userBindings?: KeybindingsConfig): KeybindingsManager;
393
+ /**
394
+ * Set the default display context used by composed surfaces that do not
395
+ * supply an explicit context.
396
+ */
397
+ setDisplayContext(context: KeyDisplayContext): void;
389
398
  /**
390
399
  * Reload keybindings from the config file.
391
400
  */
@@ -397,9 +406,30 @@ export declare class KeybindingsManager extends TuiKeybindingsManager {
397
406
  /**
398
407
  * Get display string for a keybinding (e.g., "ctrl+c/escape").
399
408
  */
400
- getDisplayString(keybinding: Keybinding): string;
409
+ getDisplayString(keybinding: Keybinding, context?: KeyDisplayContext): string;
410
+ /**
411
+ * Get an accessibility-oriented display string for help surfaces.
412
+ * Darwin chords include both the concise glyphs and expanded key names.
413
+ */
414
+ getAccessibleDisplayString(keybinding: Keybinding, context?: KeyDisplayContext): string;
415
+ /**
416
+ * Format a fixed key chord using this manager's display context.
417
+ */
418
+ formatKeyHint(key: string): string;
419
+ /**
420
+ * Format a fixed key chord for accessibility-oriented help surfaces.
421
+ */
422
+ formatAccessibleKeyHint(key: string): string;
423
+ }
424
+ /**
425
+ * Key hint formatting utilities for UI labels.
426
+ */
427
+ export interface KeyDisplayContext {
428
+ platform: NodeJS.Platform;
401
429
  }
402
- export declare function formatKeyHint(key: KeyId): string;
403
- export declare function formatKeyHints(keys: KeyId | KeyId[]): string;
430
+ export declare function formatKeyHint(key: string, context?: KeyDisplayContext): string;
431
+ export declare function formatAccessibleKeyHint(key: string, context?: KeyDisplayContext): string;
432
+ export declare function formatKeyHints(keys: string | readonly string[], context?: KeyDisplayContext): string;
433
+ export declare function formatAccessibleKeyHints(keys: string | readonly string[], context?: KeyDisplayContext): string;
404
434
  export type { Keybinding, KeybindingsConfig, KeyId };
405
435
  export { migrateKeybindingsConfigFile };
@@ -1,6 +1,7 @@
1
1
  import { ThinkingLevel } from "@gajae-code/agent-core";
2
2
  import type { Api, Model } from "@gajae-code/ai";
3
3
  import type { AgentSession } from "../session/agent-session";
4
+ export { resolveModelProfileName } from "./model-profile-contract";
4
5
  import { type GjcModelAssignmentTargetId, type ModelRegistry } from "./model-registry";
5
6
  import { type ModelSelectorValue } from "./model-selector-value";
6
7
  import type { Settings } from "./settings";
@@ -17,7 +18,9 @@ type ModelProfileActivationSession = Pick<AgentSession, "model" | "thinkingLevel
17
18
  };
18
19
  export interface PrepareModelProfileActivationOptions {
19
20
  session: ModelProfileActivationSession;
20
- modelRegistry: Pick<ModelRegistry, "getModelProfile" | "getModelProfiles" | "getAvailableModelProfileNames" | "getApiKeyForProvider" | "getAll" | "resolveCanonicalModel" | "getCanonicalVariants" | "getCanonicalId">;
21
+ modelRegistry: Pick<ModelRegistry, "getModelProfile" | "getModelProfiles" | "getAvailableModelProfileNames" | "getApiKeyForProvider" | "getAll" | "resolveCanonicalModel" | "getCanonicalVariants" | "getCanonicalId"> & {
22
+ getError?: ModelRegistry["getError"];
23
+ };
21
24
  settings: Pick<Settings, "get">;
22
25
  profileName: string;
23
26
  }
@@ -78,7 +81,6 @@ export declare class ModelProfileCredentialError extends Error {
78
81
  constructor(profileLabel: string, providers: readonly string[]);
79
82
  }
80
83
  export declare function formatModelProfileCredentialError(profileLabel: string, providers: readonly string[]): string;
81
- export declare function resolveModelProfileName(profileName: string, profiles: ReadonlyMap<string, unknown>): string;
82
84
  export declare function prepareModelProfileActivation(options: PrepareModelProfileActivationOptions): Promise<PreparedModelProfileActivation>;
83
85
  export declare function applyPreparedModelProfileActivation(prepared: PreparedModelProfileActivation, options?: ApplyModelProfileActivationOptions): Promise<void>;
84
86
  export interface MaterializeModelProfileForDeletionResult {
@@ -99,4 +101,3 @@ export declare function restoreMaterializedModelProfileForDeletion(options: {
99
101
  snapshot: MaterializeModelProfileForDeletionResult;
100
102
  }): Promise<void>;
101
103
  export declare function activateModelProfile(options: PrepareModelProfileActivationOptions, applyOptions?: ApplyModelProfileActivationOptions): Promise<void>;
102
- export {};
@@ -0,0 +1,38 @@
1
+ import { type ModelProfileDefinition } from "./model-profiles";
2
+ export declare const MODEL_PROFILE_DISCOVERY_QUERY = "models.profiles.list";
3
+ export declare const MODEL_PROFILE_ERROR_DETAIL_MAX_BYTES = 2048;
4
+ export interface ModelProfileCatalogItem {
5
+ id: string;
6
+ displayName: string;
7
+ source: "builtin" | "configured";
8
+ }
9
+ export interface UnknownModelProfileDetails {
10
+ requestedProfile: string;
11
+ availableProfiles: string[];
12
+ discoveryQuery: typeof MODEL_PROFILE_DISCOVERY_QUERY;
13
+ }
14
+ export interface ModelProfileRegistryErrorDetails {
15
+ requestedProfile?: string;
16
+ availableProfiles: [];
17
+ discoveryQuery: typeof MODEL_PROFILE_DISCOVERY_QUERY;
18
+ }
19
+ export type ModelProfileErrorDetails = UnknownModelProfileDetails | ModelProfileRegistryErrorDetails;
20
+ export type ModelProfileErrorCode = "unknown_model_profile" | "model_profile_registry_error";
21
+ export declare class UnknownModelProfileError extends Error {
22
+ readonly code: "unknown_model_profile";
23
+ readonly details: UnknownModelProfileDetails;
24
+ constructor(requestedProfile: string, profiles: ReadonlyMap<string, unknown>);
25
+ }
26
+ export declare class ModelProfileRegistryError extends Error {
27
+ readonly code: "model_profile_registry_error";
28
+ readonly details: ModelProfileRegistryErrorDetails;
29
+ constructor(requestedProfile?: string);
30
+ }
31
+ export declare function resolveModelProfileName(profileName: string, profiles: ReadonlyMap<string, unknown>): string;
32
+ export declare function validateModelProfileName(profileName: string, profiles: ReadonlyMap<string, unknown>, registryError?: unknown): string;
33
+ export declare function projectModelProfileCatalog(profiles: ReadonlyMap<string, ModelProfileDefinition>, registryError?: unknown): ModelProfileCatalogItem[];
34
+ export declare function isModelProfileError(value: unknown): value is {
35
+ code: ModelProfileErrorCode;
36
+ message: string;
37
+ details: ModelProfileErrorDetails;
38
+ };
@@ -1,7 +1,6 @@
1
- import type { GjcModelAssignmentTargetId } from "./model-registry";
2
1
  import { type ModelSelectorValue } from "./model-selector-value";
3
- import type { ModelsConfig } from "./models-config-schema";
4
- export type ModelProfileRole = GjcModelAssignmentTargetId;
2
+ import type { GJC_MODEL_ASSIGNMENT_TARGET_IDS, ModelsConfig } from "./models-config-schema";
3
+ export type ModelProfileRole = (typeof GJC_MODEL_ASSIGNMENT_TARGET_IDS)[number];
5
4
  export interface ModelProfileDefinition {
6
5
  name: string;
7
6
  requiredProviders: string[];
@@ -1561,6 +1561,15 @@ export declare const SETTINGS_SCHEMA: {
1561
1561
  readonly description: "Suggest emojis from `:name:` shortcodes and expand text emoticons like `:D` or `:-)`";
1562
1562
  };
1563
1563
  };
1564
+ readonly promptSuggestions: {
1565
+ readonly type: "boolean";
1566
+ readonly default: false;
1567
+ readonly ui: {
1568
+ readonly tab: "interaction";
1569
+ readonly label: "Prompt Suggestions";
1570
+ readonly description: "Predict your likely next prompt after each turn (smol-model call) and show it as ghost text; Tab accepts";
1571
+ };
1572
+ };
1564
1573
  readonly "startup.quiet": {
1565
1574
  readonly type: "boolean";
1566
1575
  readonly default: false;
@@ -3786,7 +3795,7 @@ export declare const SETTINGS_SCHEMA: {
3786
3795
  };
3787
3796
  readonly "providers.image": {
3788
3797
  readonly type: "enum";
3789
- readonly values: readonly ["auto", "openai", "gemini", "openrouter", "antigravity", "custom"];
3798
+ readonly values: readonly ["auto", "openai", "gemini", "openrouter", "antigravity", "alibaba", "custom"];
3790
3799
  readonly default: "auto";
3791
3800
  readonly ui: {
3792
3801
  readonly tab: "providers";
@@ -3795,7 +3804,7 @@ export declare const SETTINGS_SCHEMA: {
3795
3804
  readonly options: readonly [{
3796
3805
  readonly value: "auto";
3797
3806
  readonly label: "Auto";
3798
- readonly description: "Priority: GPT model image tool > Antigravity > OpenRouter > Gemini";
3807
+ readonly description: "Priority: GPT model image tool > Antigravity > OpenRouter > Gemini > Alibaba";
3799
3808
  }, {
3800
3809
  readonly value: "openai";
3801
3810
  readonly label: "OpenAI";
@@ -3812,6 +3821,10 @@ export declare const SETTINGS_SCHEMA: {
3812
3821
  readonly value: "antigravity";
3813
3822
  readonly label: "Antigravity";
3814
3823
  readonly description: "Requires login with google-antigravity";
3824
+ }, {
3825
+ readonly value: "alibaba";
3826
+ readonly label: "Alibaba Bailian";
3827
+ readonly description: "Requires ALIBABA_TOKEN_PLAN_API_KEY (wan2.7-image via Token Plan)";
3815
3828
  }, {
3816
3829
  readonly value: "custom";
3817
3830
  readonly label: "Custom";
@@ -41,11 +41,24 @@ export interface ApplyPatchOptions {
41
41
  fuzzyThreshold?: number;
42
42
  allowFuzzy?: boolean;
43
43
  fs?: FileSystem;
44
+ /**
45
+ * When false, skip durable cross-process file locks (in-process path mutex
46
+ * still serializes). Defaults to true only for the real `defaultFileSystem`
47
+ * (or when `fs` is omitted). Disk-backed adapters that are not
48
+ * `defaultFileSystem` (notably production `LspFileSystem` via
49
+ * `executePatchSingle`) MUST pass `crossProcessLock: true` explicitly —
50
+ * object identity is not a durable-lock capability probe.
51
+ */
52
+ crossProcessLock?: boolean;
44
53
  }
45
54
  /** Default filesystem implementation using Bun APIs */
46
55
  export declare const defaultFileSystem: FileSystem;
47
56
  /**
48
57
  * Apply a patch operation to the filesystem.
58
+ *
59
+ * Concurrent mutations of the same absolute path are serialized (in-process always;
60
+ * cross-process file lock when using the real filesystem) so disjoint concurrent
61
+ * edits cannot silently overwrite each other (#2900).
49
62
  */
50
63
  export declare function applyPatch(input: PatchInput, options: ApplyPatchOptions): Promise<ApplyPatchResult>;
51
64
  /**
@@ -0,0 +1,15 @@
1
+ import { type FileLockOptions } from "../config/file-lock";
2
+ export type EditPathMutationOptions = {
3
+ /**
4
+ * When true (default), also acquire a durable cross-process file lock.
5
+ * Disable for injectible/in-memory filesystem tests that do not touch disk.
6
+ */
7
+ crossProcess?: boolean;
8
+ fileLock?: FileLockOptions;
9
+ };
10
+ /**
11
+ * Run `fn` while holding exclusive mutation rights for every absolute path.
12
+ * Paths are locked in lexicographic order to avoid deadlocks on multi-path ops
13
+ * (e.g. rename source + destination).
14
+ */
15
+ export declare function withEditPathMutation<T>(absolutePaths: readonly string[], fn: () => Promise<T>, options?: EditPathMutationOptions): Promise<T>;
@@ -50,7 +50,7 @@ export interface PythonExecutorOptions {
50
50
  /** @internal Bridge endpoint info, set by `executePython` before delegating. */
51
51
  bridge?: {
52
52
  url: string;
53
- token: string;
53
+ capability: string;
54
54
  };
55
55
  }
56
56
  export interface PythonKernelExecutor {
@@ -7,7 +7,6 @@ export interface PyToolBridgeEntry {
7
7
  }
8
8
  export interface PyToolBridgeInfo {
9
9
  url: string;
10
- token: string;
11
10
  }
12
11
  /** Starts the bridge server lazily and returns its connection info. */
13
12
  export declare function ensurePyToolBridge(): Promise<PyToolBridgeInfo>;
@@ -15,6 +14,6 @@ export declare function ensurePyToolBridge(): Promise<PyToolBridgeInfo>;
15
14
  * Register a tool session for the duration of one execution. The returned
16
15
  * function MUST be called to remove the entry once execution finishes.
17
16
  */
18
- export declare function registerPyToolBridge(sessionId: string, entry: PyToolBridgeEntry): () => void;
17
+ export declare function registerPyToolBridge(sessionId: string, capability: string, entry: PyToolBridgeEntry): () => void;
19
18
  /** Stop the bridge and clear registrations. Test-only / shutdown helper. */
20
19
  export declare function disposePyToolBridge(): Promise<void>;
@@ -9,15 +9,13 @@ export interface AmbiguityClampResult {
9
9
  effective: number;
10
10
  clamped: boolean;
11
11
  }
12
- /** Compute the deterministic floor from the inner deep-interview `state` object. */
12
+ /** Compute the deterministic floor from integer units of persisted evidence. */
13
13
  export declare function computeAmbiguityFloor(inner: unknown): AmbiguityFloorBreakdown;
14
14
  /** Clamp an LLM-reported ambiguity to the deterministic floor: `max(reported, floor)`. */
15
15
  export declare function clampReportedAmbiguity(reported: number, floor: number): AmbiguityClampResult;
16
16
  /**
17
- * Mark every established fact recorded in `retractedRound` as disputed. This is the
18
- * mechanical contradiction signal for answer retraction: when the user replaces an
19
- * already-scored answer (A -> B pivot), the facts that answer established can no
20
- * longer be trusted, so they raise the floor until re-confirmed or superseded.
17
+ * Legacy pure utility for migrations and explicit repair flows. The recorder does
18
+ * not dispute facts when an answer is retracted: scored evidence is immutable.
21
19
  * Returns new arrays/objects; never mutates the input.
22
20
  */
23
21
  export declare function disputeFactsFromRetractedRound(facts: readonly unknown[], retractedRound: number): {
@@ -37,3 +35,12 @@ export interface AppliedAmbiguityFloor {
37
35
  * (state CLI write/reconcile, recorder) applies this immediately before persisting.
38
36
  */
39
37
  export declare function applyAmbiguityFloorToEnvelope(value: unknown): AppliedAmbiguityFloor;
38
+ export type DeepInterviewAmbiguityMilestone = "initial" | "progress" | "refined" | "ready";
39
+ export declare function deriveAmbiguityMilestone(effectiveUnits: number, thresholdUnits: number): DeepInterviewAmbiguityMilestone;
40
+ export declare function scoreToUnits(score: number): number;
41
+ export declare function weightedAmbiguityUnits(scores: {
42
+ goal: number;
43
+ constraints: number;
44
+ criteria: number;
45
+ context?: number;
46
+ }, type: "greenfield" | "brownfield"): number;
@@ -0,0 +1,8 @@
1
+ import { type DeepInterviewDraftKind } from "./deep-interview-payload";
2
+ export interface DeepInterviewDraftResult {
3
+ status: number;
4
+ stdout?: string;
5
+ stderr?: string;
6
+ }
7
+ export declare function runDeepInterviewDraftCommand(input: readonly string[], cwd: string): Promise<DeepInterviewDraftResult>;
8
+ export declare function runDeepInterviewDraftInternalConsumeCommand(draftId: string, expectedDraftRevision: number, kind: DeepInterviewDraftKind, cwd: string): Promise<DeepInterviewDraftResult>;
@@ -0,0 +1,41 @@
1
+ import type { DeepInterviewRoundResultV1 } from "./deep-interview-state";
2
+ export declare const DEEP_INTERVIEW_DRAFT_KINDS: readonly ["initialize-context", "confirm-topology", "record-answer", "apply-round-result"];
3
+ export type DeepInterviewDraftKind = (typeof DEEP_INTERVIEW_DRAFT_KINDS)[number];
4
+ export type DeepInterviewDraftPayload = Record<string, unknown>;
5
+ export type DraftScalarType = "string" | "id" | "text" | "score" | "number" | "safe-int" | "boolean" | "enum";
6
+ export interface DraftLeafDescriptor {
7
+ kind: "leaf";
8
+ type: DraftScalarType;
9
+ nullable?: boolean;
10
+ maxBytes?: number;
11
+ values?: readonly string[];
12
+ optional?: boolean;
13
+ dynamicMapValue?: boolean;
14
+ }
15
+ export interface DraftObjectDescriptor {
16
+ kind: "object";
17
+ fields: Record<string, DraftDescriptor>;
18
+ optional?: boolean;
19
+ dynamicMapValue?: boolean;
20
+ dynamicValue?: DraftLeafDescriptor;
21
+ }
22
+ export interface DraftArrayDescriptor {
23
+ kind: "array";
24
+ item: DraftLeafDescriptor | DraftObjectDescriptor;
25
+ maxItems: number;
26
+ optional?: boolean;
27
+ }
28
+ export type DraftDescriptor = DraftLeafDescriptor | DraftObjectDescriptor | DraftArrayDescriptor;
29
+ export declare function deepInterviewDraftSchema(kind: DeepInterviewDraftKind): DraftObjectDescriptor;
30
+ /** Shared strict payload decoders used by compatibility JSON and CLI-owned drafts. */
31
+ export declare function decodeInitializeContextPayload(payload: unknown): Record<string, unknown>;
32
+ export declare function decodeConfirmTopologyPayload(payload: unknown): Record<string, unknown>;
33
+ export declare function decodeRecordAnswerPayload(payload: unknown): {
34
+ question: string;
35
+ answer: {
36
+ selected_options: string[];
37
+ custom_input: string | null;
38
+ };
39
+ };
40
+ export declare function decodeApplyRoundResultPayload(payload: unknown, state: Record<string, unknown>): DeepInterviewRoundResultV1;
41
+ export declare function validateDraftPayload(kind: DeepInterviewDraftKind, payload: unknown, state?: Record<string, unknown>): void;
@@ -1,4 +1,4 @@
1
- import { type DeepInterviewEstablishedFact, type DeepInterviewIntentItem, type DeepInterviewIntentSubstitution, type DeepInterviewRoundRecord, type DeepInterviewStateEnvelope, type DeepInterviewTriggerMetadata } from "./deep-interview-state";
1
+ import { type DeepInterviewEstablishedFact, type DeepInterviewIntentItem, type DeepInterviewIntentSubstitution, type DeepInterviewRoundRecord, type DeepInterviewRoundResultV1, type DeepInterviewStateEnvelope, type DeepInterviewTriggerMetadata } from "./deep-interview-state";
2
2
  export * from "./deep-interview-ambiguity";
3
3
  export * from "./deep-interview-state";
4
4
  /**
@@ -40,6 +40,8 @@ export interface DeepInterviewScoringInput {
40
40
  scores: Record<string, number>;
41
41
  ambiguity: number;
42
42
  triggers?: DeepInterviewTriggerMetadata[];
43
+ /** Complete native round result for typed callers. */
44
+ roundResult?: DeepInterviewRoundResultV1;
43
45
  }
44
46
  export type AppendOrMergeAction = "created" | "noop" | "replaced";
45
47
  export interface AppendOrMergeResult {
@@ -67,11 +69,9 @@ export interface TransitionValidationResult {
67
69
  }
68
70
  export declare function buildAnswerShell(input: DeepInterviewAnswerInput, now?: string): DeepInterviewRoundRecord;
69
71
  /**
70
- * Append-or-merge by `round_key`. Exactly one record per key:
71
- * - no existing record -> append (`created`);
72
- * - identical question_hash + answer_hash -> deterministic no-op (`noop`);
73
- * - same key, different hashes -> deterministic replacement of the prior shell
74
- * (`replaced`); the prior answer for that key is superseded and lifecycle resets.
72
+ * Append-or-merge by `round_key`. An answer is a no-op only when its complete
73
+ * canonical shell identity matches; a scored record is immutable evidence and
74
+ * cannot be replaced by a late answer.
75
75
  */
76
76
  export declare function appendOrMergeRound(rounds: readonly DeepInterviewRoundRecord[], shell: DeepInterviewRoundRecord): AppendOrMergeResult;
77
77
  /**
@@ -94,28 +94,43 @@ export declare function ensureDeepInterviewStateShape(value: unknown): DeepInter
94
94
  export declare function projectCompactState(value: unknown, options?: {
95
95
  lastN?: number;
96
96
  }): DeepInterviewCompactState;
97
+ interface RecorderMutationOptions {
98
+ sessionId?: string;
99
+ expectedRevision?: number;
100
+ }
101
+ export interface DeepInterviewPostCommitWarning {
102
+ code: "DI_POST_COMMIT_AUDIT_FAILED" | "DI_POST_COMMIT_ACTIVITY_FAILED" | "DI_POST_COMMIT_HUD_FAILED";
103
+ message: string;
104
+ }
105
+ export declare function runDeepInterviewPostCommitEffects(options: {
106
+ cwd: string;
107
+ statePath: string;
108
+ sessionId: string;
109
+ envelope: Record<string, unknown>;
110
+ revision: number;
111
+ writer: string;
112
+ auditWarnings?: readonly {
113
+ code: "DI_POST_COMMIT_AUDIT_FAILED";
114
+ message: string;
115
+ }[];
116
+ }): Promise<DeepInterviewPostCommitWarning[]>;
97
117
  /** Refresh the best-effort HUD cache from persisted deep-interview state. */
98
118
  export declare function syncDeepInterviewRecorderHud(cwd: string, statePath: string, sessionId: string | undefined): Promise<void>;
99
119
  /**
100
120
  * Record an `answered` shell for one round (append-or-merge by durable key).
101
121
  *
102
- * Retraction dynamics: replacing an already-`scored` answer is a mechanical
103
- * contradiction signal (the user pivoted). The facts that round established are
104
- * marked disputed, which raises the deterministic ambiguity floor immediately —
105
- * without waiting for the LLM scorer to self-report a trigger.
122
+ * Replacing an already-scored answer is rejected with
123
+ * `DI_ANSWER_LIFECYCLE_CONFLICT`; scored evidence is immutable.
106
124
  */
107
- export declare function appendOrMergeDeepInterviewRound(cwd: string, statePath: string, input: DeepInterviewAnswerInput, options?: {
108
- sessionId?: string;
109
- }): Promise<{
125
+ export declare function appendOrMergeDeepInterviewRound(cwd: string, statePath: string, input: DeepInterviewAnswerInput, options?: RecorderMutationOptions): Promise<{
110
126
  action: AppendOrMergeAction;
111
127
  record: DeepInterviewRoundRecord;
112
- disputedFactIds?: string[];
128
+ warnings: DeepInterviewPostCommitWarning[];
113
129
  }>;
114
130
  /** Merge scoring output into the same round record, transitioning to `scored`. */
115
- export declare function enrichDeepInterviewRoundScoring(cwd: string, statePath: string, input: DeepInterviewScoringInput, options?: {
116
- sessionId?: string;
117
- }): Promise<{
131
+ export declare function enrichDeepInterviewRoundScoring(cwd: string, statePath: string, input: DeepInterviewScoringInput, options?: RecorderMutationOptions): Promise<{
118
132
  record: DeepInterviewRoundRecord;
133
+ warnings: DeepInterviewPostCommitWarning[];
119
134
  }>;
120
135
  /** Compact projection so callers read a slice instead of the full transcript. */
121
136
  export declare function readDeepInterviewStateCompact(statePath: string, options?: {
@@ -0,0 +1,17 @@
1
+ import { type DeepInterviewRoundResultV1 } from "./deep-interview-state";
2
+ export interface DeepInterviewRepairResult {
3
+ status: number;
4
+ stdout?: string;
5
+ stderr?: string;
6
+ }
7
+ export declare const DEEP_INTERVIEW_REPAIR_VERBS: readonly ["initialize-context", "confirm-topology", "record-answer", "apply-round-result", "inspect", "sanity-check"];
8
+ export type DeepInterviewRepairVerb = (typeof DEEP_INTERVIEW_REPAIR_VERBS)[number];
9
+ export declare function isDeepInterviewRepairVerb(value: string): value is DeepInterviewRepairVerb;
10
+ export declare function decodeDeepInterviewAnswerJson(value: unknown): {
11
+ selected_options: string[];
12
+ custom_input: string | null;
13
+ };
14
+ export declare function decodeDeepInterviewRoundResultJson(value: unknown, state: Record<string, unknown>): DeepInterviewRoundResultV1;
15
+ export declare function decodeDeepInterviewSetupJson(value: unknown): Record<string, unknown>;
16
+ export declare function decodeDeepInterviewTopologyJson(value: unknown): Record<string, unknown>;
17
+ export declare function runDeepInterviewRepairCommand(args: readonly string[], cwd: string): Promise<DeepInterviewRepairResult>;