@gajae-code/coding-agent 0.18.11 → 0.18.12

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 (270) hide show
  1. package/CHANGELOG.md +293 -0
  2. package/dist/types/async/job-manager.d.ts +7 -3
  3. package/dist/types/async/result-formatting.d.ts +2 -0
  4. package/dist/types/autoresearch/git.d.ts +1 -1
  5. package/dist/types/capability/fs.d.ts +2 -2
  6. package/dist/types/cli/accounts-cli.d.ts +2 -2
  7. package/dist/types/cli/doctor/install-repairs.d.ts +4 -1
  8. package/dist/types/cli/install-activation.d.ts +10 -4
  9. package/dist/types/cli/public-command-errors.d.ts +1 -0
  10. package/dist/types/cli/update-cli.d.ts +14 -1
  11. package/dist/types/cli-ordinary.d.ts +2 -2
  12. package/dist/types/commands/accounts.d.ts +2 -1
  13. package/dist/types/commands/migrate.d.ts +1 -1
  14. package/dist/types/commands/sdk.d.ts +5 -0
  15. package/dist/types/commit/changelog/index.d.ts +1 -0
  16. package/dist/types/config/autorouting-tier-map.d.ts +30 -0
  17. package/dist/types/config/config-hot-reload-trust.d.ts +12 -0
  18. package/dist/types/config/config-hot-reload.d.ts +39 -0
  19. package/dist/types/config/file-lock.d.ts +8 -1
  20. package/dist/types/config/model-discovery-manager.d.ts +2 -0
  21. package/dist/types/config/model-profile-activation.d.ts +62 -6
  22. package/dist/types/config/model-registry.d.ts +56 -5
  23. package/dist/types/config/model-resolver.d.ts +2 -0
  24. package/dist/types/config/models-config-schema.d.ts +10 -0
  25. package/dist/types/config/settings-schema.d.ts +46 -3
  26. package/dist/types/config/settings.d.ts +33 -1
  27. package/dist/types/dap/config.d.ts +8 -4
  28. package/dist/types/debug/system-info.d.ts +6 -1
  29. package/dist/types/discovery/mcp-compat.d.ts +3 -1
  30. package/dist/types/edit/modes/patch.d.ts +5 -0
  31. package/dist/types/edit/modes/replace.d.ts +3 -0
  32. package/dist/types/exec/bash-executor.d.ts +12 -0
  33. package/dist/types/gjc-runtime/managed-owner-admission.d.ts +3 -0
  34. package/dist/types/gjc-runtime/session-state-lock.d.ts +2 -0
  35. package/dist/types/gjc-runtime/state-runtime.d.ts +0 -2
  36. package/dist/types/migrate/adapters/codex.d.ts +2 -1
  37. package/dist/types/migrate/adapters/index.d.ts +10 -1
  38. package/dist/types/migrate/executor.d.ts +3 -1
  39. package/dist/types/migrate/types.d.ts +15 -3
  40. package/dist/types/modes/components/settings-selector.d.ts +6 -0
  41. package/dist/types/modes/controllers/selector-controller.d.ts +2 -0
  42. package/dist/types/modes/theme/theme.d.ts +1 -0
  43. package/dist/types/runtime-mcp/content-limits.d.ts +4 -0
  44. package/dist/types/runtime-mcp/manager.d.ts +7 -0
  45. package/dist/types/runtime-mcp/plugin-mcp-name-filter.d.ts +22 -0
  46. package/dist/types/runtime-mcp/tool-bridge.d.ts +4 -0
  47. package/dist/types/sdk/broker/broker-exit.d.ts +2 -2
  48. package/dist/types/sdk/broker/broker.d.ts +7 -1
  49. package/dist/types/sdk/broker/daemon-entry.d.ts +11 -1
  50. package/dist/types/sdk/broker/doctor-restart.d.ts +1 -1
  51. package/dist/types/sdk/broker/ensure.d.ts +136 -7
  52. package/dist/types/sdk/broker/hop.d.ts +36 -0
  53. package/dist/types/sdk/broker/lifecycle-ledger.d.ts +18 -10
  54. package/dist/types/sdk/broker/lock-host-identity.d.ts +5 -0
  55. package/dist/types/sdk/broker/session-index.d.ts +4 -1
  56. package/dist/types/sdk/bus/chat-command-policy.d.ts +2 -1
  57. package/dist/types/sdk/bus/index.d.ts +23 -0
  58. package/dist/types/sdk/bus/reconciliation-store.d.ts +10 -0
  59. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +3 -1
  60. package/dist/types/sdk/cli/session-cli.d.ts +0 -1
  61. package/dist/types/sdk/host/session-runtime.d.ts +32 -0
  62. package/dist/types/sdk/prompt-deadline-flush.d.ts +42 -4
  63. package/dist/types/sdk/prompt-deadline-manager.d.ts +2 -0
  64. package/dist/types/sdk/protocol/adapter-validation.d.ts +10 -4
  65. package/dist/types/sdk/reconciliation-extensions.d.ts +1 -1
  66. package/dist/types/sdk/session-list.d.ts +1 -1
  67. package/dist/types/session/agent-session.d.ts +58 -2
  68. package/dist/types/session/internal/managed-session-scope.d.ts +2 -2
  69. package/dist/types/session/internal/managed-session-storage.d.ts +1 -1
  70. package/dist/types/session/internal/native-publish-outcome.d.ts +1 -1
  71. package/dist/types/session/messages.d.ts +5 -1
  72. package/dist/types/session/session-manager.d.ts +13 -3
  73. package/dist/types/session/startup-auth-config.d.ts +24 -2
  74. package/dist/types/session/streaming-output.d.ts +11 -0
  75. package/dist/types/session/terminal-abort.d.ts +3 -1
  76. package/dist/types/session-import/service.d.ts +1 -1
  77. package/dist/types/skill-state/workflow-mutation-guard.d.ts +7 -3
  78. package/dist/types/slash-commands/helpers/provider-auth-status.d.ts +8 -0
  79. package/dist/types/task/executor.d.ts +19 -2
  80. package/dist/types/tools/ast-edit-write-path.d.ts +10 -0
  81. package/dist/types/tools/atomic-file-write.d.ts +9 -7
  82. package/dist/types/tools/bash-allowed-prefixes.d.ts +11 -0
  83. package/dist/types/tools/descriptors.d.ts +2 -0
  84. package/dist/types/tools/fetch.d.ts +1 -1
  85. package/dist/types/tools/index.d.ts +2 -0
  86. package/dist/types/tools/python.d.ts +1 -1
  87. package/dist/types/tools/report-issue.d.ts +41 -0
  88. package/dist/types/tools/subagent.d.ts +23 -0
  89. package/dist/types/web/scrapers/types.d.ts +8 -1
  90. package/dist/types/web/search/providers/insane.d.ts +7 -1
  91. package/dist/types/web/search/providers/searxng.d.ts +5 -0
  92. package/package.json +8 -8
  93. package/scripts/build-binary.ts +2 -1
  94. package/scripts/capture-subagent-compact-panel-showcase.ts +105 -0
  95. package/scripts/generate-docs-index.ts +8 -1
  96. package/scripts/generate-sdk-operation-inventory.ts +22 -4
  97. package/src/async/job-manager.ts +356 -56
  98. package/src/async/result-formatting.ts +40 -0
  99. package/src/autoresearch/git.ts +9 -2
  100. package/src/autoresearch/prompts/prompt-setup.md +1 -1
  101. package/src/capability/fs.ts +27 -19
  102. package/src/capability/index.ts +2 -2
  103. package/src/cli/accounts-cli.ts +176 -8
  104. package/src/cli/auth-broker-cli.ts +21 -11
  105. package/src/cli/doctor/install-repairs.ts +35 -5
  106. package/src/cli/fast-help.ts +1 -1
  107. package/src/cli/install-activation.ts +47 -4
  108. package/src/cli/migrate-cli.ts +7 -5
  109. package/src/cli/public-command-errors.ts +4 -0
  110. package/src/cli/root-flags.ts +2 -2
  111. package/src/cli/stats-cli.ts +9 -5
  112. package/src/cli/update-cli.ts +224 -7
  113. package/src/cli-ordinary.ts +7 -2
  114. package/src/commands/accounts.ts +10 -5
  115. package/src/commands/migrate.ts +3 -3
  116. package/src/commands/sdk.ts +199 -42
  117. package/src/commands/ultragoal.ts +16 -8
  118. package/src/commit/changelog/index.ts +39 -1
  119. package/src/commit/message.ts +10 -3
  120. package/src/config/autorouting-tier-map.ts +30 -0
  121. package/src/config/config-hot-reload-trust.ts +148 -0
  122. package/src/config/config-hot-reload.ts +734 -0
  123. package/src/config/file-lock.ts +216 -56
  124. package/src/config/model-bindings-applier.ts +85 -47
  125. package/src/config/model-discovery-manager.ts +10 -0
  126. package/src/config/model-profile-activation.ts +716 -113
  127. package/src/config/model-registry.ts +1334 -158
  128. package/src/config/model-resolver.ts +3 -1
  129. package/src/config/models-config-schema.ts +6 -0
  130. package/src/config/settings-schema.ts +60 -3
  131. package/src/config/settings.ts +458 -24
  132. package/src/coordinator-mcp/policy.ts +26 -1
  133. package/src/crash/sanitize.ts +4 -0
  134. package/src/customization/import.ts +3 -1
  135. package/src/dap/config.ts +31 -11
  136. package/src/dap/defaults.json +1 -1
  137. package/src/debug/crash-diagnostics.ts +2 -1
  138. package/src/debug/report-bundle.ts +19 -0
  139. package/src/debug/system-info.ts +8 -3
  140. package/src/defaults/gjc/extensions/grok-cli-vendor/src/shared/base-url.ts +21 -7
  141. package/src/discovery/agents-md.ts +1 -1
  142. package/src/discovery/helpers.ts +1 -2
  143. package/src/discovery/mcp-compat.ts +120 -17
  144. package/src/edit/apply-patch/index.ts +12 -1
  145. package/src/edit/index.ts +13 -17
  146. package/src/edit/modes/patch.ts +187 -8
  147. package/src/edit/modes/replace.ts +136 -0
  148. package/src/eval/js/context-manager.ts +29 -3
  149. package/src/eval/js/worker-entry.ts +51 -18
  150. package/src/eval/py/executor.ts +14 -4
  151. package/src/eval/py/runner.py +144 -5
  152. package/src/exec/bash-executor.ts +81 -4
  153. package/src/exec/bash-shell-guardian.ts +4 -1
  154. package/src/exec/bash-shell-supervisor.ts +8 -4
  155. package/src/exec/isolated-shell.ts +5 -1
  156. package/src/export/html/index.ts +46 -6
  157. package/src/extensibility/custom-tools/wrapper.ts +3 -1
  158. package/src/extensibility/extensions/loader.ts +8 -1
  159. package/src/extensibility/plugins/marketplace/fetcher.ts +2 -2
  160. package/src/gjc-runtime/gc-runtime.ts +33 -6
  161. package/src/gjc-runtime/launch-tmux.ts +7 -2
  162. package/src/gjc-runtime/launch-worktree.test.ts +148 -0
  163. package/src/gjc-runtime/launch-worktree.ts +101 -14
  164. package/src/gjc-runtime/managed-owner-admission.ts +46 -2
  165. package/src/gjc-runtime/session-resolution.ts +38 -6
  166. package/src/gjc-runtime/session-state-lock.ts +59 -14
  167. package/src/gjc-runtime/state-runtime.ts +23 -19
  168. package/src/hooks/native-skill-hook.ts +14 -11
  169. package/src/internal-urls/docs-index.generated.ts +14 -13
  170. package/src/internal-urls/local-protocol.ts +142 -8
  171. package/src/lsp/index.ts +29 -0
  172. package/src/lsp/workspace-path.ts +23 -0
  173. package/src/migrate/action-planner.ts +57 -0
  174. package/src/migrate/adapters/claude-code.ts +23 -4
  175. package/src/migrate/adapters/codex.ts +22 -4
  176. package/src/migrate/adapters/index.ts +22 -4
  177. package/src/migrate/adapters/opencode.ts +6 -1
  178. package/src/migrate/executor.ts +84 -7
  179. package/src/migrate/report.ts +19 -2
  180. package/src/migrate/types.ts +14 -4
  181. package/src/modes/DESIGN.md +51 -0
  182. package/src/modes/acp/permission-mode.ts +18 -1
  183. package/src/modes/components/assistant-message.ts +55 -1
  184. package/src/modes/components/settings-selector.ts +103 -37
  185. package/src/modes/controllers/command-controller.ts +38 -2
  186. package/src/modes/controllers/plan-mode-controller.ts +17 -7
  187. package/src/modes/controllers/selector-controller.ts +62 -6
  188. package/src/modes/interactive-mode.ts +68 -0
  189. package/src/modes/theme/theme.ts +15 -0
  190. package/src/prompts/tools/debug.md +1 -1
  191. package/src/prompts/tools/read.md +1 -1
  192. package/src/prompts/tools/report-issue.md +13 -0
  193. package/src/prompts/tools/task.md +1 -1
  194. package/src/runtime-credential-selector.ts +2 -2
  195. package/src/runtime-mcp/content-limits.ts +7 -0
  196. package/src/runtime-mcp/manager-pool.test.ts +5 -4
  197. package/src/runtime-mcp/manager.ts +32 -0
  198. package/src/runtime-mcp/oauth-flow.ts +32 -6
  199. package/src/runtime-mcp/plugin-mcp-name-filter.ts +62 -0
  200. package/src/runtime-mcp/render.ts +16 -1
  201. package/src/runtime-mcp/tool-bridge.ts +126 -17
  202. package/src/sdk/broker/broker-exit.ts +8 -5
  203. package/src/sdk/broker/broker.ts +342 -82
  204. package/src/sdk/broker/daemon-entry.ts +338 -116
  205. package/src/sdk/broker/doctor-restart.ts +2 -1
  206. package/src/sdk/broker/ensure.ts +1143 -265
  207. package/src/sdk/broker/hop.ts +274 -0
  208. package/src/sdk/broker/lifecycle-ledger.ts +35 -11
  209. package/src/sdk/broker/lock-host-identity.ts +29 -0
  210. package/src/sdk/broker/session-index.ts +62 -12
  211. package/src/sdk/bus/chat-command-policy.ts +16 -3
  212. package/src/sdk/bus/index.ts +52 -21
  213. package/src/sdk/bus/reconciliation-store.ts +201 -8
  214. package/src/sdk/bus/telegram-daemon-contract.ts +3 -1
  215. package/src/sdk/cli/session-cli.ts +21 -6
  216. package/src/sdk/host/session-runtime.test.ts +118 -23
  217. package/src/sdk/host/session-runtime.ts +352 -47
  218. package/src/sdk/lifecycle/service.ts +1 -0
  219. package/src/sdk/prompt-deadline-flush.ts +78 -5
  220. package/src/sdk/prompt-deadline-manager.ts +68 -14
  221. package/src/sdk/protocol/adapter-validation.ts +53 -11
  222. package/src/sdk/protocol/operation-inventory.generated.json +101 -2
  223. package/src/sdk/reconciliation-extensions.ts +1 -0
  224. package/src/sdk/session-list.ts +1 -0
  225. package/src/sdk/session.ts +114 -61
  226. package/src/session/agent-session.ts +1043 -81
  227. package/src/session/internal/managed-session-scope.ts +126 -39
  228. package/src/session/internal/managed-session-storage.ts +14 -11
  229. package/src/session/internal/native-publish-outcome.ts +5 -1
  230. package/src/session/messages.ts +47 -6
  231. package/src/session/session-manager.ts +236 -14
  232. package/src/session/startup-auth-config.ts +116 -8
  233. package/src/session/streaming-output.ts +262 -4
  234. package/src/session/terminal-abort.ts +14 -2
  235. package/src/session-import/service.ts +1 -0
  236. package/src/skill-state/workflow-mutation-guard.ts +491 -32
  237. package/src/slash-commands/builtin-registry.ts +15 -3
  238. package/src/slash-commands/helpers/credential-switch.ts +10 -5
  239. package/src/slash-commands/helpers/provider-auth-status.ts +456 -0
  240. package/src/task/executor.ts +103 -12
  241. package/src/task/index.ts +389 -175
  242. package/src/tools/ast-edit-write-path.ts +64 -0
  243. package/src/tools/ast-edit.ts +18 -1
  244. package/src/tools/atomic-file-write.ts +46 -15
  245. package/src/tools/auto-generated-guard.ts +3 -0
  246. package/src/tools/bash-allowed-prefixes.ts +153 -5
  247. package/src/tools/bash-interactive.ts +14 -2
  248. package/src/tools/bash.ts +14 -0
  249. package/src/tools/debug.ts +7 -6
  250. package/src/tools/descriptors.test.ts +44 -0
  251. package/src/tools/descriptors.ts +34 -2
  252. package/src/tools/fetch.ts +3 -2
  253. package/src/tools/index.ts +2 -0
  254. package/src/tools/output-meta.ts +23 -2
  255. package/src/tools/python.ts +1 -1
  256. package/src/tools/read.ts +17 -35
  257. package/src/tools/report-issue.ts +184 -0
  258. package/src/tools/subagent-render.ts +114 -12
  259. package/src/tools/subagent.ts +108 -1
  260. package/src/tools/todo-write.ts +41 -3
  261. package/src/tools/tool-catalog.generated.ts +31 -3
  262. package/src/tools/write.ts +35 -3
  263. package/src/utils/commit-message-generator.ts +9 -2
  264. package/src/utils/file-mentions.ts +29 -1
  265. package/src/utils/title-generator.ts +7 -2
  266. package/src/web/scrapers/index.ts +3 -1
  267. package/src/web/scrapers/types.ts +8 -0
  268. package/src/web/scrapers/youtube.ts +3 -2
  269. package/src/web/search/providers/insane.ts +91 -28
  270. package/src/web/search/providers/searxng.ts +62 -10
@@ -44,7 +44,8 @@
44
44
  * WHERE it runs. `sdk.flushWorktreeOnDeadline` still defaults to on, but the
45
45
  * implicit default applies only in a LINKED worktree (`gitDir !== commonDir`) —
46
46
  * what agent/paseo sessions run in, and the #5583 field report. In the user's
47
- * primary checkout an autosave needs an explicit opt-in.
47
+ * primary checkout an autosave needs an explicit opt-in from the user/global
48
+ * config or a runtime override. A project `.gjc` file is not that opt-in.
48
49
  */
49
50
 
50
51
  import * as fsp from "node:fs/promises";
@@ -66,9 +67,10 @@ export interface PromptDeadlineFlushOptions {
66
67
  /** Active session's agent directory, used to keep volatile broker state out of the WIP commit. */
67
68
  readonly agentDir?: string;
68
69
  /**
69
- * Whether the caller resolved `sdk.flushWorktreeOnDeadline` to `true` from a
70
- * value the user actually wrote, rather than from the schema default. Only an
71
- * explicit opt-in may autosave outside a linked worktree.
70
+ * Whether the caller resolved `sdk.flushWorktreeOnDeadline` to `true` from the
71
+ * user/global config or a runtime override, rather than from the schema
72
+ * default or a project `.gjc` file. Only that opt-in may autosave outside a
73
+ * linked worktree.
72
74
  */
73
75
  readonly explicitOptIn?: boolean;
74
76
  /**
@@ -162,6 +164,76 @@ function isLinkedWorktree(repository: git.GitRepository): boolean {
162
164
  return path.resolve(repository.gitDir) !== path.resolve(repository.commonDir);
163
165
  }
164
166
 
167
+ const DEADLINE_FLUSH_SETTING = "sdk.flushWorktreeOnDeadline";
168
+
169
+ /**
170
+ * The settings view both deadline hosts already hold. `get` is the merged value
171
+ * (global, then project, then runtime override, otherwise the schema default).
172
+ * `getGlobal` and `getOverride` are the layers a project file cannot write.
173
+ */
174
+ export interface DeadlineFlushSettings {
175
+ get(path: typeof DEADLINE_FLUSH_SETTING): unknown;
176
+ getAgentDir?(): string | undefined;
177
+ getGlobal?(path: typeof DEADLINE_FLUSH_SETTING): unknown;
178
+ getOverride?(path: typeof DEADLINE_FLUSH_SETTING): unknown;
179
+ }
180
+
181
+ /**
182
+ * True only when the user wrote `sdk.flushWorktreeOnDeadline: true` in a runtime
183
+ * override or the global config. The schema default and a project `.gjc` file
184
+ * do not count: `Settings.has()` sees the merged view, so a repo-shipped `true`
185
+ * would otherwise open the primary-checkout gate.
186
+ */
187
+ export function explicitDeadlineFlushOptIn(settings: DeadlineFlushSettings | undefined): boolean {
188
+ if (!settings) return false;
189
+ if (typeof settings.getOverride === "function") {
190
+ const override = settings.getOverride(DEADLINE_FLUSH_SETTING);
191
+ if (override !== undefined) return override === true;
192
+ }
193
+ if (typeof settings.getGlobal === "function") return settings.getGlobal(DEADLINE_FLUSH_SETTING) === true;
194
+ return false;
195
+ }
196
+
197
+ /**
198
+ * Whether this deadline must not autosave.
199
+ *
200
+ * A runtime override wins, then the user/global value. A project file cannot
201
+ * cancel either one. A project `false` still opts out when the user has not
202
+ * written the key.
203
+ */
204
+ export function deadlineFlushSuppressed(settings: DeadlineFlushSettings | undefined): boolean {
205
+ if (!settings) return false;
206
+ if (typeof settings.getOverride === "function") {
207
+ const override = settings.getOverride(DEADLINE_FLUSH_SETTING);
208
+ if (override === false) return true;
209
+ if (override === true) return false;
210
+ }
211
+ if (typeof settings.getGlobal === "function") {
212
+ const globalValue = settings.getGlobal(DEADLINE_FLUSH_SETTING);
213
+ if (globalValue === false) return true;
214
+ if (globalValue === true) return false;
215
+ }
216
+ return settings.get(DEADLINE_FLUSH_SETTING) === false;
217
+ }
218
+
219
+ /**
220
+ * Deadline-host entry for the worktree autosave. Both the session runtime and
221
+ * the notification bus call this so the opt-in decision cannot drift.
222
+ */
223
+ export async function autosaveWorktreeOnPromptDeadline(
224
+ cwd: string,
225
+ settings: DeadlineFlushSettings | undefined,
226
+ options?: { readonly isCurrent?: () => boolean; readonly signal?: AbortSignal },
227
+ ): Promise<PromptDeadlineFlushResult | undefined> {
228
+ if (deadlineFlushSuppressed(settings)) return undefined;
229
+ return flushWorktreeOnPromptDeadline(cwd, {
230
+ agentDir: settings?.getAgentDir?.(),
231
+ explicitOptIn: explicitDeadlineFlushOptIn(settings),
232
+ isCurrent: options?.isCurrent,
233
+ signal: options?.signal,
234
+ });
235
+ }
236
+
165
237
  /**
166
238
  * Commit any uncommitted work in the worktree owning `cwd`.
167
239
  *
@@ -195,7 +267,8 @@ export async function flushWorktreeOnPromptDeadline(
195
267
  if (!explicitOptIn && !isLinkedWorktree(repository)) {
196
268
  logger.debug(
197
269
  `sdk: prompt deadline worktree autosave skipped; ${worktreeRoot} is a primary checkout the session does ` +
198
- `not own. Set sdk.flushWorktreeOnDeadline to true to autosave here anyway.`,
270
+ `not own. Set sdk.flushWorktreeOnDeadline to true in the user config or a runtime override to ` +
271
+ `autosave here anyway.`,
199
272
  );
200
273
  return undefined;
201
274
  }
@@ -103,10 +103,18 @@ export class PromptDeadlineManager {
103
103
  readonly #uncertaintyRecoveryPending = new Set<string>();
104
104
  readonly #expiring = new Set<string>();
105
105
  readonly #deadlineAttempts = new Set<string>();
106
+ /**
107
+ * The next deadline came due while `#expire` was still inside an await
108
+ * (tool-boundary grace or the bounded flush). The in-flight pass owns the
109
+ * single-flight slot, so the timer callback only records the follow-up and
110
+ * `#onDeadline` runs it after this pass returns.
111
+ */
112
+ readonly #deadlineFollowUps = new Set<string>();
106
113
  readonly #pendingTerminalTransitions = new Set<string>();
107
114
  readonly #deadlineDeferredTerminalTransitions = new Set<string>();
108
115
  readonly #deadlineTerminalizationConfirmed = new Set<string>();
109
116
  readonly #terminalPublicationPending = new Map<string, SdkPromptTerminalOutcome>();
117
+ readonly #toolsStillPendingOnLastCheck = new Set<string>();
110
118
  readonly #deadlineStartCleanup = new Map<string, () => void>();
111
119
  readonly #pendingTerminalFailureReasons = new Map<
112
120
  string,
@@ -187,7 +195,11 @@ export class PromptDeadlineManager {
187
195
  }
188
196
 
189
197
  /** Run the durability hook under the shared bound; see `runBoundedDeadlineFlush`. */
190
- async #runDeadlineFlush(correlation: InvocationCorrelation, lease: PromptDeadlineLease): Promise<void> {
198
+ async #runDeadlineFlush(
199
+ correlation: InvocationCorrelation,
200
+ lease: PromptDeadlineLease,
201
+ generation: number,
202
+ ): Promise<void> {
191
203
  const hook = this.#onDeadlineExceeded;
192
204
  if (hook === undefined) return;
193
205
  const key = leaseKey(correlation);
@@ -195,7 +207,9 @@ export class PromptDeadlineManager {
195
207
  signal =>
196
208
  hook(correlation, signal, () => {
197
209
  const current = this.#leases.get(key);
198
- return current === lease && this.#now() >= promptDeadlineAt(current);
210
+ return (
211
+ current === lease && current.generation === generation && this.#now() >= promptDeadlineAt(current)
212
+ );
199
213
  }),
200
214
  this.#deadlineFlushTimeoutMs,
201
215
  );
@@ -239,12 +253,24 @@ export class PromptDeadlineManager {
239
253
  }
240
254
 
241
255
  async #onDeadline(key: string): Promise<void> {
242
- if (this.#deadlineAttempts.has(key)) return;
256
+ if (this.#deadlineAttempts.has(key)) {
257
+ this.#deadlineFollowUps.add(key);
258
+ return;
259
+ }
243
260
  this.#deadlineAttempts.add(key);
244
261
  try {
245
- await this.#expire(key);
262
+ do {
263
+ this.#deadlineFollowUps.delete(key);
264
+ await this.#expire(key);
265
+ } while (this.#deadlineFollowUps.has(key));
246
266
  } finally {
247
267
  this.#deadlineAttempts.delete(key);
268
+ if (this.#deadlineFollowUps.has(key)) {
269
+ this.#deadlineFollowUps.delete(key);
270
+ queueMicrotask(() => {
271
+ void this.#onDeadline(key);
272
+ });
273
+ }
248
274
  }
249
275
  }
250
276
 
@@ -385,7 +411,9 @@ export class PromptDeadlineManager {
385
411
  terminalization =
386
412
  (await this.#onDeadlineTerminalization?.(correlation, () => {
387
413
  const current = this.#leases.get(key);
388
- return current === lease && this.#now() >= promptDeadlineAt(current);
414
+ return (
415
+ current === lease && current.generation === generation && this.#now() >= promptDeadlineAt(current)
416
+ );
389
417
  })) ?? "settled";
390
418
  } catch {
391
419
  terminalization = "uncertain";
@@ -410,7 +438,7 @@ export class PromptDeadlineManager {
410
438
  // The claim above remains the durable pending marker throughout both
411
439
  // bounded operations, so restart recovery never reports unsaved work as
412
440
  // finished.
413
- await this.#runDeadlineFlush(correlation, lease);
441
+ await this.#runDeadlineFlush(correlation, lease, generation);
414
442
  // Fence again AFTER the flush (#5623 review round 2): progress can land
415
443
  // while the bounded git operation runs and renews the lease.
416
444
  if (this.#backOffIfSuperseded(key, lease, generation)) return;
@@ -532,14 +560,19 @@ export class PromptDeadlineManager {
532
560
  /**
533
561
  * After an awaited reconciliation call, verify the captured lease is still
534
562
  * authoritative. Fresh attributable progress during the await advances the
535
- * lease generation and its deadline; when superseded, cancel this expiry
536
- * instance (release the expiration fence, clear any retry budget, and
537
- * reschedule the deadline) and report it so the caller stops. A cleared or
538
- * re-accepted lease is stale by identity too.
563
+ * lease generation and its deadline. A tool-boundary wait or a flush can
564
+ * outlive that renewed lease, so a generation mismatch is stale even when
565
+ * the new deadline is already due — the time check alone would let this
566
+ * pass publish with the generation it captured, the publisher would refuse,
567
+ * and uncertainty recovery would refuse to re-anchor the same mismatch.
568
+ * Cancel this expiry instance (release the expiration fence, clear any
569
+ * retry budget, and reschedule the deadline) and report it so the caller
570
+ * stops. The follow-up expiry captures the current generation. A cleared
571
+ * or re-accepted lease is stale by identity too.
539
572
  */
540
- #backOffIfSuperseded(key: string, lease: PromptDeadlineLease, _generation: number): boolean {
573
+ #backOffIfSuperseded(key: string, lease: PromptDeadlineLease, generation: number): boolean {
541
574
  const current = this.#leases.get(key);
542
- if (current !== lease || this.#now() < promptDeadlineAt(current)) {
575
+ if (current !== lease || current.generation !== generation || this.#now() < promptDeadlineAt(current)) {
543
576
  this.#expiring.delete(key);
544
577
  this.#expiryRetries.delete(key);
545
578
  if (current) this.#schedule(key);
@@ -578,13 +611,32 @@ export class PromptDeadlineManager {
578
611
  this.clear(correlation);
579
612
  }
580
613
 
581
- #scheduleTerminalPublicationRetry(key: string): void {
614
+ #scheduleTerminalPublicationRetry(key: string, delayMs?: number): void {
582
615
  this.#clearTimer(key);
583
- const timer = setTimeout(() => void this.#onDeadline(key), UNCERTAINTY_RETRY_DELAY_MS);
616
+ // Use immediate retry (0ms) if tools were pending on last check;
617
+ // otherwise use normal retry delay. This allows quick detection when tools drain.
618
+ const effectiveDelayMs =
619
+ delayMs ?? (this.#toolsStillPendingOnLastCheck.has(key) ? 0 : UNCERTAINTY_RETRY_DELAY_MS);
620
+ const timer = setTimeout(() => void this.#onDeadline(key), effectiveDelayMs);
584
621
  (timer as unknown as { unref?: () => void }).unref?.();
585
622
  this.#timers.set(key, timer);
586
623
  }
587
624
 
625
+ /** Notify about termination check results to adjust retry strategy. */
626
+ notifyTerminationResult(
627
+ correlation: InvocationCorrelation,
628
+ _result: PromptDeadlineTerminalization,
629
+ reason: string,
630
+ ): void {
631
+ const key = leaseKey(correlation);
632
+ if (reason.includes("tools-still-pending")) {
633
+ this.#toolsStillPendingOnLastCheck.add(key);
634
+ } else {
635
+ // Tools have settled or are no longer relevant
636
+ this.#toolsStillPendingOnLastCheck.delete(key);
637
+ }
638
+ }
639
+
588
640
  #retry(key: string): void {
589
641
  const attempts = (this.#expiryRetries.get(key) ?? 0) + 1;
590
642
  this.#expiryRetries.set(key, attempts);
@@ -817,6 +869,7 @@ export class PromptDeadlineManager {
817
869
  this.#terminalPublicationPending.delete(key);
818
870
  this.#pendingTerminalFailureReasons.delete(key);
819
871
  this.#pendingTerminalEvidence.delete(key);
872
+ this.#toolsStillPendingOnLastCheck.delete(key);
820
873
  }
821
874
 
822
875
  clearAll(): void {
@@ -839,6 +892,7 @@ export class PromptDeadlineManager {
839
892
  this.#terminalPublicationPending.clear();
840
893
  this.#pendingTerminalFailureReasons.clear();
841
894
  this.#pendingTerminalEvidence.clear();
895
+ this.#toolsStillPendingOnLastCheck.clear();
842
896
  }
843
897
 
844
898
  /** For tests: current deadline or undefined if no lease. */
@@ -1,24 +1,57 @@
1
1
  const RELOAD_COMPONENTS = new Set(["config", "models", "skills", "extensions", "tools"]);
2
- const SERVICE_TIERS = new Set(["none", "auto", "default", "flex", "scale", "priority", "openai-only", "claude-only"]);
2
+ const SERVICE_TIERS = new Set([
3
+ "none",
4
+ "auto",
5
+ "default",
6
+ "flex",
7
+ "scale",
8
+ "priority",
9
+ "ultrafast",
10
+ "openai-only",
11
+ "claude-only",
12
+ ]);
3
13
 
4
14
  type Input = Record<string, unknown>;
5
15
 
6
16
  type SecretInputError = { code: "secret_field_forbidden"; message: string };
7
17
  const SECRET_FIELD = /(?:secret|token|password|credential|authorization|api[_-]?key)/i;
8
18
 
19
+ type UltrafastRestrictionError = { code: "ultrafast_tier_forbidden"; message: string };
20
+
21
+ function containsUltrafastServiceTier(value: unknown): boolean {
22
+ if (Array.isArray(value)) return value.some(containsUltrafastServiceTier);
23
+ if (!value || typeof value !== "object") return false;
24
+ return Object.entries(value as Record<string, unknown>).some(
25
+ ([key, nested]) =>
26
+ ((key === "serviceTier" || key.endsWith(".serviceTier")) && nested === "ultrafast") ||
27
+ containsUltrafastServiceTier(nested),
28
+ );
29
+ }
30
+
9
31
  function containsSecretField(value: unknown): boolean {
10
32
  if (Array.isArray(value)) return value.some(containsSecretField);
11
33
  if (!value || typeof value !== "object") return false;
12
34
  return Object.entries(value).some(([key, nested]) => SECRET_FIELD.test(key) || containsSecretField(nested));
13
35
  }
14
36
 
15
- /** Rejects secret-bearing config patches from model-facing adapter inputs. */
16
- export function validateAdapterSecretFields(operation: string, input: Input): SecretInputError | undefined {
17
- if (operation === "config.patch" && containsSecretField(input)) {
18
- return {
19
- code: "secret_field_forbidden",
20
- message: "config.patch secret fields are not available through this adapter.",
21
- };
37
+ /** Rejects secret-bearing and ultrafast-tier config patches from model-facing adapter inputs. */
38
+ export function validateAdapterSecretFields(
39
+ operation: string,
40
+ input: Input,
41
+ ): SecretInputError | UltrafastRestrictionError | undefined {
42
+ if (operation === "config.patch") {
43
+ if (containsSecretField(input)) {
44
+ return {
45
+ code: "secret_field_forbidden",
46
+ message: "config.patch secret fields are not available through this adapter.",
47
+ };
48
+ }
49
+ if (containsUltrafastServiceTier(input)) {
50
+ return {
51
+ code: "ultrafast_tier_forbidden",
52
+ message: "config.patch serviceTier ultrafast is restricted to trusted local sources.",
53
+ };
54
+ }
22
55
  }
23
56
  return undefined;
24
57
  }
@@ -53,8 +86,12 @@ export function validateRequiredPromptText(operation: string, input: Input): Ada
53
86
  return undefined;
54
87
  }
55
88
 
56
- /** Validates controls that adapters must reject before forwarding them to a host. */
57
- export function validateAdapterControl(operation: string, input: Input): AdapterValidationError | undefined {
89
+ /** Validates controls before forwarding them; adapters reject ultrafast unless explicitly trusted. */
90
+ export function validateAdapterControl(
91
+ operation: string,
92
+ input: Input,
93
+ options: { allowUltrafastTier?: boolean } = {},
94
+ ): AdapterValidationError | undefined {
58
95
  const promptError = validateRequiredPromptText(operation, input);
59
96
  if (promptError) return promptError;
60
97
  if (operation === "runtime.reload") {
@@ -68,7 +105,12 @@ export function validateAdapterControl(operation: string, input: Input): Adapter
68
105
  };
69
106
  }
70
107
  }
71
- if (operation === "service_tier.set" && (typeof input.tier !== "string" || !SERVICE_TIERS.has(input.tier))) {
108
+ if (
109
+ operation === "service_tier.set" &&
110
+ (typeof input.tier !== "string" ||
111
+ !SERVICE_TIERS.has(input.tier) ||
112
+ (input.tier === "ultrafast" && options.allowUltrafastTier !== true))
113
+ ) {
72
114
  return { code: "invalid_input", message: "service_tier.set tier is invalid." };
73
115
  }
74
116
  return undefined;
@@ -4502,6 +4502,17 @@
4502
4502
  "testIds": "not_applicable"
4503
4503
  }
4504
4504
  },
4505
+ {
4506
+ "sourceId": "agent_session:markProfileRoleOverrideManual",
4507
+ "sourceFile": "packages/coding-agent/src/session/agent-session.ts",
4508
+ "sourceKind": "agent_session",
4509
+ "decision": "exclude",
4510
+ "rationale": "internal profile role-layer ownership tracking after explicit user assignments; not a user-facing SDK control seam",
4511
+ "exclusionMetadata": {
4512
+ "adapterMappings": "not_applicable",
4513
+ "testIds": "not_applicable"
4514
+ }
4515
+ },
4505
4516
  {
4506
4517
  "sourceId": "agent_session:getActiveModelProfile",
4507
4518
  "sourceFile": "packages/coding-agent/src/session/agent-session.ts",
@@ -4518,7 +4529,7 @@
4518
4529
  "sourceFile": "packages/coding-agent/src/session/agent-session.ts",
4519
4530
  "sourceKind": "agent_session",
4520
4531
  "decision": "exclude",
4521
- "rationale": "internal session-scoped unavailable profile tracking; mutated by the session lifecycle on model-load failure, not a public SDK control seam",
4532
+ "rationale": "internal session-scoped startup-profile recovery marker, not a user-facing SDK control seam",
4522
4533
  "exclusionMetadata": {
4523
4534
  "adapterMappings": "not_applicable",
4524
4535
  "testIds": "not_applicable"
@@ -4529,7 +4540,7 @@
4529
4540
  "sourceFile": "packages/coding-agent/src/session/agent-session.ts",
4530
4541
  "sourceKind": "agent_session",
4531
4542
  "decision": "exclude",
4532
- "rationale": "internal session-scoped unavailable profile query for UI status rendering; not a public SDK operation",
4543
+ "rationale": "internal session-scoped startup-profile recovery status for UI rendering, not a public SDK operation",
4533
4544
  "exclusionMetadata": {
4534
4545
  "adapterMappings": "not_applicable",
4535
4546
  "testIds": "not_applicable"
@@ -4568,6 +4579,39 @@
4568
4579
  "testIds": "not_applicable"
4569
4580
  }
4570
4581
  },
4582
+ {
4583
+ "sourceId": "agent_session:getConfigurationPaths",
4584
+ "sourceFile": "packages/coding-agent/src/session/agent-session.ts",
4585
+ "sourceKind": "agent_session",
4586
+ "decision": "exclude",
4587
+ "rationale": "internal config hot-reload path identity projection, not a user-facing SDK control seam",
4588
+ "exclusionMetadata": {
4589
+ "adapterMappings": "not_applicable",
4590
+ "testIds": "not_applicable"
4591
+ }
4592
+ },
4593
+ {
4594
+ "sourceId": "agent_session:validateConfiguration",
4595
+ "sourceFile": "packages/coding-agent/src/session/agent-session.ts",
4596
+ "sourceKind": "agent_session",
4597
+ "decision": "exclude",
4598
+ "rationale": "internal read-only config hot-reload preflight, not an independent SDK operation",
4599
+ "exclusionMetadata": {
4600
+ "adapterMappings": "not_applicable",
4601
+ "testIds": "not_applicable"
4602
+ }
4603
+ },
4604
+ {
4605
+ "sourceId": "agent_session:reloadConfiguration",
4606
+ "sourceFile": "packages/coding-agent/src/session/agent-session.ts",
4607
+ "sourceKind": "agent_session",
4608
+ "decision": "exclude",
4609
+ "rationale": "internal transactional config hot-reload publication, not a user-facing SDK control seam",
4610
+ "exclusionMetadata": {
4611
+ "adapterMappings": "not_applicable",
4612
+ "testIds": "not_applicable"
4613
+ }
4614
+ },
4571
4615
  {
4572
4616
  "sourceId": "agent_session:syncEagerDelegation",
4573
4617
  "sourceFile": "packages/coding-agent/src/session/agent-session.ts",
@@ -4590,6 +4634,28 @@
4590
4634
  "testIds": "not_applicable"
4591
4635
  }
4592
4636
  },
4637
+ {
4638
+ "sourceId": "agent_session:getProfileInstalledOverrideState",
4639
+ "sourceFile": "packages/coding-agent/src/session/agent-session.ts",
4640
+ "sourceKind": "agent_session",
4641
+ "decision": "exclude",
4642
+ "rationale": "internal model-profile activation rollback snapshot, not a user-facing SDK control seam",
4643
+ "exclusionMetadata": {
4644
+ "adapterMappings": "not_applicable",
4645
+ "testIds": "not_applicable"
4646
+ }
4647
+ },
4648
+ {
4649
+ "sourceId": "agent_session:restoreProfileInstalledOverrideState",
4650
+ "sourceFile": "packages/coding-agent/src/session/agent-session.ts",
4651
+ "sourceKind": "agent_session",
4652
+ "decision": "exclude",
4653
+ "rationale": "internal model-profile activation rollback restoration, not a user-facing SDK control seam",
4654
+ "exclusionMetadata": {
4655
+ "adapterMappings": "not_applicable",
4656
+ "testIds": "not_applicable"
4657
+ }
4658
+ },
4593
4659
  {
4594
4660
  "sourceId": "agent_session:clearProfileInstalledOverrides",
4595
4661
  "sourceFile": "packages/coding-agent/src/session/agent-session.ts",
@@ -4828,6 +4894,39 @@
4828
4894
  "testIds": "not_applicable"
4829
4895
  }
4830
4896
  },
4897
+ {
4898
+ "sourceId": "agent_session:prepareModelSelectionForProfileActivation",
4899
+ "sourceFile": "packages/coding-agent/src/session/agent-session.ts",
4900
+ "sourceKind": "agent_session",
4901
+ "decision": "exclude",
4902
+ "rationale": "internal staged model-selection preparation for profile activation, not a user-facing SDK control seam",
4903
+ "exclusionMetadata": {
4904
+ "adapterMappings": "not_applicable",
4905
+ "testIds": "not_applicable"
4906
+ }
4907
+ },
4908
+ {
4909
+ "sourceId": "agent_session:commitPreparedProfileModelSelection",
4910
+ "sourceFile": "packages/coding-agent/src/session/agent-session.ts",
4911
+ "sourceKind": "agent_session",
4912
+ "decision": "exclude",
4913
+ "rationale": "internal model-selection commit for profile activation, not a user-facing SDK control seam",
4914
+ "exclusionMetadata": {
4915
+ "adapterMappings": "not_applicable",
4916
+ "testIds": "not_applicable"
4917
+ }
4918
+ },
4919
+ {
4920
+ "sourceId": "agent_session:finishPreparedProfileModelSelection",
4921
+ "sourceFile": "packages/coding-agent/src/session/agent-session.ts",
4922
+ "sourceKind": "agent_session",
4923
+ "decision": "exclude",
4924
+ "rationale": "internal post-commit model-selection refresh for profile activation, not a user-facing SDK control seam",
4925
+ "exclusionMetadata": {
4926
+ "adapterMappings": "not_applicable",
4927
+ "testIds": "not_applicable"
4928
+ }
4929
+ },
4831
4930
  {
4832
4931
  "sourceId": "agent_session:restoreModelSelectionForRollback",
4833
4932
  "sourceFile": "packages/coding-agent/src/session/agent-session.ts",
@@ -10,5 +10,6 @@ export {
10
10
  type DurableReconciliationRecord,
11
11
  type DurableSteerReconciliationRecord,
12
12
  type ReconciliationStore,
13
+ type ReconciliationStoreInstrumentationEvent,
13
14
  resolveReconciliationSessionFile,
14
15
  } from "./bus/reconciliation-store";
@@ -20,6 +20,7 @@ export const SESSION_LIST_SAVED_SESSION_OMISSION_DETAIL_CODES = [
20
20
  "managed_gc_journal_capacity_exceeded",
21
21
  "atomic_unavailable",
22
22
  "invalid_request",
23
+ "permission_denied",
23
24
  "durability_failed",
24
25
  "durability_not_provable",
25
26
  "capacity_exceeded",