@gajae-code/coding-agent 0.18.10 → 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 +295 -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
@@ -132,7 +132,7 @@ import {
132
132
  syntheticModelInputError,
133
133
  syntheticNamespaceCollision,
134
134
  } from "../model-profile-model";
135
- import { flushWorktreeOnPromptDeadline } from "../prompt-deadline-flush";
135
+ import { autosaveWorktreeOnPromptDeadline, deadlineFlushSuppressed } from "../prompt-deadline-flush";
136
136
  import {
137
137
  createPromptDeadlineLease,
138
138
  isAttributableProgressEventType,
@@ -2659,6 +2659,10 @@ function sdkControlSurface(
2659
2659
  // the session-wide preflight seam must not be invoked while another
2660
2660
  // connection's active preflight could be cancelled by it (review P1).
2661
2661
  noOtherConnectionPreflights?: () => boolean,
2662
+ // True only for an operator terminal abort that the broker control route already
2663
+ // authorized (`TerminalAbortInput.operator`, which a public SDK caller cannot grant):
2664
+ // it addresses the session's active turn, not the requesting connection's own prompt.
2665
+ operatorAuthorized?: boolean,
2662
2666
  ) => Promise<
2663
2667
  | {
2664
2668
  ok: true;
@@ -3178,6 +3182,9 @@ function sdkControlSurface(
3178
3182
  // invoking it (review thread P1).
3179
3183
  () =>
3180
3184
  ![...pendingPreflightCancellations.values()].some(entry => entry.connectionId !== requesterConnectionId),
3185
+ // Broker-authorized operator authority is the one case where the abort
3186
+ // addresses a turn another connection submitted (see the parameter note).
3187
+ input.operator === true,
3181
3188
  );
3182
3189
  // Preflight cancellation happens ONLY for a NEWLY ADMITTED abort,
3183
3190
  // after the durable admission/replay decision inside
@@ -4281,6 +4288,34 @@ export function boundedCorrelatedAgentEndFrame(frame: Record<string, unknown>):
4281
4288
  };
4282
4289
  }
4283
4290
 
4291
+ /** Connection-scoped identity of a queued prompt submission an abort may address. */
4292
+ export interface TerminalAbortSubmissionScope {
4293
+ connectionId?: string;
4294
+ terminal: boolean;
4295
+ }
4296
+
4297
+ /**
4298
+ * Whether a terminal abort addresses this prompt submission.
4299
+ *
4300
+ * An ordinary abort is scoped to the requesting connection's own prompt: `connectionId`
4301
+ * identifies the connection that submitted it, and a submission that already reached a
4302
+ * terminal state is never addressed. Broker-authorized operator authority
4303
+ * (`TerminalAbortInput.operator`, granted only through the broker control route) is the
4304
+ * documented exception — "operator authority changes only connection ownership, never
4305
+ * those settlement proofs" — so it addresses the session's submission even when another
4306
+ * connection submitted it. Without that override every operator abort issued over a
4307
+ * second connection (the SDK client case, where each request is its own connection)
4308
+ * reported no_active_turn while the turn was still running.
4309
+ */
4310
+ export function terminalAbortAddressesSubmission(input: {
4311
+ connectionId: string | undefined;
4312
+ operatorAuthorized: boolean;
4313
+ submission: TerminalAbortSubmissionScope;
4314
+ }): boolean {
4315
+ if (input.submission.terminal) return false;
4316
+ return input.operatorAuthorized || input.submission.connectionId === input.connectionId;
4317
+ }
4318
+
4284
4319
  export function createNotificationsExtension(
4285
4320
  api: ExtensionAPI,
4286
4321
  options: {
@@ -6408,21 +6443,12 @@ export function createNotificationsExtension(
6408
6443
  if (
6409
6444
  winner.kind === "failed" &&
6410
6445
  winner.code === "prompt_deadline_exceeded" &&
6411
- settings?.get("sdk.flushWorktreeOnDeadline") !== false
6446
+ !deadlineFlushSuppressed(settings)
6412
6447
  ) {
6413
- // `has` is true only for a value the user actually wrote, so this
6414
- // separates an explicit opt-in from the schema default. The flush only
6415
- // honours the default inside a linked worktree the session owns.
6416
- const configured = settings?.get("sdk.flushWorktreeOnDeadline");
6417
- const hasExplicitSetting =
6418
- typeof settings?.has === "function"
6419
- ? settings.has("sdk.flushWorktreeOnDeadline")
6420
- : configured === true;
6421
- const explicitOptIn = hasExplicitSetting === true && configured === true;
6448
+ // Same opt-in as the session runtime: user/global config or a runtime
6449
+ // override, never a project `.gjc` file or the schema default.
6422
6450
  await runBoundedDeadlineFlush(signal =>
6423
- flushWorktreeOnPromptDeadline(ctx.cwd, {
6424
- agentDir: settings?.getAgentDir(),
6425
- explicitOptIn,
6451
+ autosaveWorktreeOnPromptDeadline(ctx.cwd, settings, {
6426
6452
  isCurrent: () =>
6427
6453
  deadlineAttemptStatus(promptSubmissionKey(correlation), submission, deadlineAttempt) ===
6428
6454
  "current",
@@ -6736,7 +6762,14 @@ export function createNotificationsExtension(
6736
6762
  }
6737
6763
  return { aborted: true, disposition: "cancelled" as const };
6738
6764
  },
6739
- async (connectionId, scope, idempotencyKey, preflightCancel, noOtherConnectionPreflights) => {
6765
+ async (
6766
+ connectionId,
6767
+ scope,
6768
+ idempotencyKey,
6769
+ preflightCancel,
6770
+ noOtherConnectionPreflights,
6771
+ operatorAuthorized = false,
6772
+ ) => {
6740
6773
  // Capture the steering snapshot at ADMISSION (before the durable
6741
6774
  // marker transaction): client steering admitted while the abort
6742
6775
  // is in flight classifies as post-snapshot and is preserved at
@@ -7098,9 +7131,9 @@ export function createNotificationsExtension(
7098
7131
  return "failed";
7099
7132
  }
7100
7133
  };
7101
- let active = [...promptSubmissions.entries()].find(
7102
- ([, submission]) => submission.connectionId === connectionId && !submission.terminal,
7103
- );
7134
+ const addresses = (submission: TerminalAbortSubmissionScope): boolean =>
7135
+ terminalAbortAddressesSubmission({ connectionId, operatorAuthorized, submission });
7136
+ let active = [...promptSubmissions.entries()].find(([, submission]) => addresses(submission));
7104
7137
  if (!active) {
7105
7138
  // DURABLY reserve the key even for a no-active-turn abort: the
7106
7139
  // generic idempotency cache is in-memory only, so after restart
@@ -7130,9 +7163,7 @@ export function createNotificationsExtension(
7130
7163
  // and the durable no-effect row would block a same-key retry from
7131
7164
  // stopping it — fall through to the pre-run / active fencing path
7132
7165
  // when a submission now exists (review thread P1).
7133
- active = [...promptSubmissions.entries()].find(
7134
- ([, submission]) => submission.connectionId === connectionId && !submission.terminal,
7135
- );
7166
+ active = [...promptSubmissions.entries()].find(([, submission]) => addresses(submission));
7136
7167
  if (!active) {
7137
7168
  // Close the remaining acceptance race: cancel the requester's
7138
7169
  // preflights HERE, in the same synchronous region as the
@@ -670,11 +670,22 @@ export interface ReconciliationStore {
670
670
  delete(): Promise<void>;
671
671
  }
672
672
 
673
+ export interface ReconciliationStoreInstrumentationEvent {
674
+ at: number;
675
+ phase: "enqueued" | "started" | "completed" | "failed";
676
+ operation?: string;
677
+ substep?: string;
678
+ error?: string;
679
+ /** Detailed information about lock acquisition, promise identity, db state, etc. */
680
+ detail?: string;
681
+ }
682
+
673
683
  export function createReconciliationStore(options: {
674
684
  sessionFile: string | null | undefined;
675
685
  sessionId: string;
676
686
  fs?: ReconciliationStoreFs;
677
687
  now?: () => number;
688
+ onInstrumentationForTests?: (event: ReconciliationStoreInstrumentationEvent) => void;
678
689
  }): ReconciliationStore {
679
690
  const fileFs = options.fs ?? nodeFs;
680
691
  const now = options.now ?? Date.now;
@@ -701,20 +712,56 @@ export function createReconciliationStore(options: {
701
712
  const directory = path.dirname(filePath);
702
713
  let temporary: string | undefined;
703
714
  try {
715
+ try {
716
+ options.onInstrumentationForTests?.({ at: Date.now(), phase: "started", substep: "mkdir" });
717
+ } catch {}
704
718
  await fileFs.mkdir(directory, { recursive: true, mode: 0o700 });
719
+ try {
720
+ options.onInstrumentationForTests?.({ at: Date.now(), phase: "completed", substep: "mkdir" });
721
+ } catch {}
705
722
  temporary = `${filePath}.${process.pid}.${Date.now()}.${randomUUID()}.tmp`;
723
+ try {
724
+ options.onInstrumentationForTests?.({ at: Date.now(), phase: "started", substep: "writeFile" });
725
+ } catch {}
706
726
  await fileFs.writeFile(temporary, `${JSON.stringify(document)}\n`, { mode: 0o600 });
707
727
  try {
728
+ options.onInstrumentationForTests?.({ at: Date.now(), phase: "completed", substep: "writeFile" });
729
+ } catch {}
730
+ try {
731
+ try {
732
+ options.onInstrumentationForTests?.({ at: Date.now(), phase: "started", substep: "open" });
733
+ } catch {}
708
734
  const handle = await fileFs.open(temporary, "r+");
709
735
  try {
736
+ options.onInstrumentationForTests?.({ at: Date.now(), phase: "completed", substep: "open" });
737
+ } catch {}
738
+ try {
739
+ try {
740
+ options.onInstrumentationForTests?.({ at: Date.now(), phase: "started", substep: "sync" });
741
+ } catch {}
710
742
  await handle.sync();
743
+ try {
744
+ options.onInstrumentationForTests?.({ at: Date.now(), phase: "completed", substep: "sync" });
745
+ } catch {}
711
746
  } finally {
747
+ try {
748
+ options.onInstrumentationForTests?.({ at: Date.now(), phase: "started", substep: "close" });
749
+ } catch {}
712
750
  await handle.close();
751
+ try {
752
+ options.onInstrumentationForTests?.({ at: Date.now(), phase: "completed", substep: "close" });
753
+ } catch {}
713
754
  }
714
755
  } catch {
715
756
  // fsync optional on some fs seams
716
757
  }
758
+ try {
759
+ options.onInstrumentationForTests?.({ at: Date.now(), phase: "started", substep: "rename" });
760
+ } catch {}
717
761
  await fileFs.rename(temporary, filePath);
762
+ try {
763
+ options.onInstrumentationForTests?.({ at: Date.now(), phase: "completed", substep: "rename" });
764
+ } catch {}
718
765
  } catch (error) {
719
766
  // Every persistence-path failure (mkdir included) is evidence a drained
720
767
  // window must surface, never silently treat as quiescent (#4743).
@@ -723,6 +770,9 @@ export function createReconciliationStore(options: {
723
770
  code: "reconciliation_persist_failed",
724
771
  });
725
772
  unreportedPersistFailures.push(coded);
773
+ try {
774
+ options.onInstrumentationForTests?.({ at: Date.now(), phase: "failed", error: coded.message });
775
+ } catch {}
726
776
  throw coded;
727
777
  }
728
778
  };
@@ -795,7 +845,26 @@ export function createReconciliationStore(options: {
795
845
  const transact = async (
796
846
  mutator: (records: DurableReconciliationRecord[]) => DurableReconciliationRecord[],
797
847
  ): Promise<void> => {
848
+ const promiseId = `reconcil-transact-${randomUUID().slice(0, 8)}`;
849
+ const enqueueTime = Date.now();
798
850
  const run = async () => {
851
+ const lockWaitMs = Date.now() - enqueueTime;
852
+ try {
853
+ options.onInstrumentationForTests?.({
854
+ at: enqueueTime,
855
+ phase: "enqueued",
856
+ operation: "transact",
857
+ detail: `promise=${promiseId}`,
858
+ });
859
+ } catch {}
860
+ try {
861
+ options.onInstrumentationForTests?.({
862
+ at: Date.now(),
863
+ phase: "started",
864
+ operation: "transact",
865
+ detail: `promise=${promiseId} lock-wait=${lockWaitMs}ms`,
866
+ });
867
+ } catch {}
799
868
  const next = mutator(memory.map(r => ({ ...r })));
800
869
  await writeAtomic({
801
870
  version: RECONCILIATION_STORE_VERSION,
@@ -805,19 +874,55 @@ export function createReconciliationStore(options: {
805
874
  ...(terminalKeyMemory.length > 0 ? { evictedTerminalKeys: terminalKeyMemory } : {}),
806
875
  });
807
876
  memory = next;
877
+ try {
878
+ options.onInstrumentationForTests?.({
879
+ at: Date.now(),
880
+ phase: "completed",
881
+ operation: "transact",
882
+ detail: `promise=${promiseId}`,
883
+ });
884
+ } catch {}
808
885
  };
809
886
  const pending = chain.then(run, run);
810
- chain = pending.then(
887
+ const settled = pending.then(
811
888
  () => undefined,
812
889
  () => undefined,
813
890
  );
814
- await pending;
891
+ chain = settled;
892
+ try {
893
+ await pending;
894
+ } catch (error) {
895
+ try {
896
+ options.onInstrumentationForTests?.({
897
+ at: Date.now(),
898
+ phase: "failed",
899
+ operation: "transact",
900
+ detail: `promise=${promiseId} lock-wait=${Date.now() - enqueueTime}ms`,
901
+ error: error instanceof Error ? error.message : String(error),
902
+ });
903
+ } catch {}
904
+ throw error;
905
+ }
815
906
  };
816
907
 
817
908
  const transactTerminalScopes = async (
818
909
  mutator: (scopes: DurableTerminalScopeRecord[]) => DurableTerminalScopeRecord[],
819
910
  ): Promise<void> => {
820
911
  const run = async () => {
912
+ try {
913
+ options.onInstrumentationForTests?.({
914
+ at: Date.now(),
915
+ phase: "enqueued",
916
+ operation: "transactTerminalScopes",
917
+ });
918
+ } catch {}
919
+ try {
920
+ options.onInstrumentationForTests?.({
921
+ at: Date.now(),
922
+ phase: "started",
923
+ operation: "transactTerminalScopes",
924
+ });
925
+ } catch {}
821
926
  const next = mutator(terminalMemory.map(s => ({ ...s })));
822
927
  await writeAtomic({
823
928
  version: RECONCILIATION_STORE_VERSION,
@@ -827,13 +932,33 @@ export function createReconciliationStore(options: {
827
932
  ...(terminalKeyMemory.length > 0 ? { evictedTerminalKeys: terminalKeyMemory } : {}),
828
933
  });
829
934
  terminalMemory = next;
935
+ try {
936
+ options.onInstrumentationForTests?.({
937
+ at: Date.now(),
938
+ phase: "completed",
939
+ operation: "transactTerminalScopes",
940
+ });
941
+ } catch {}
830
942
  };
831
943
  const pending = chain.then(run, run);
832
- chain = pending.then(
944
+ const settled = pending.then(
833
945
  () => undefined,
834
946
  () => undefined,
835
947
  );
836
- await pending;
948
+ chain = settled;
949
+ try {
950
+ await pending;
951
+ } catch (error) {
952
+ try {
953
+ options.onInstrumentationForTests?.({
954
+ at: Date.now(),
955
+ phase: "failed",
956
+ operation: "transactTerminalScopes",
957
+ error: error instanceof Error ? error.message : String(error),
958
+ });
959
+ } catch {}
960
+ throw error;
961
+ }
837
962
  };
838
963
 
839
964
  const transactTerminalState = async (
@@ -843,6 +968,20 @@ export function createReconciliationStore(options: {
843
968
  },
844
969
  ): Promise<void> => {
845
970
  const run = async () => {
971
+ try {
972
+ options.onInstrumentationForTests?.({
973
+ at: Date.now(),
974
+ phase: "enqueued",
975
+ operation: "transactTerminalState",
976
+ });
977
+ } catch {}
978
+ try {
979
+ options.onInstrumentationForTests?.({
980
+ at: Date.now(),
981
+ phase: "started",
982
+ operation: "transactTerminalState",
983
+ });
984
+ } catch {}
846
985
  const next = mutator({
847
986
  scopes: terminalMemory.map(s => ({ ...s })),
848
987
  keys: terminalKeyMemory.map(k => ({ ...k })),
@@ -856,19 +995,53 @@ export function createReconciliationStore(options: {
856
995
  });
857
996
  terminalMemory = next.scopes;
858
997
  terminalKeyMemory = next.keys;
998
+ try {
999
+ options.onInstrumentationForTests?.({
1000
+ at: Date.now(),
1001
+ phase: "completed",
1002
+ operation: "transactTerminalState",
1003
+ });
1004
+ } catch {}
859
1005
  };
860
1006
  const pending = chain.then(run, run);
861
- chain = pending.then(
1007
+ const settled = pending.then(
862
1008
  () => undefined,
863
1009
  () => undefined,
864
1010
  );
865
- await pending;
1011
+ chain = settled;
1012
+ try {
1013
+ await pending;
1014
+ } catch (error) {
1015
+ try {
1016
+ options.onInstrumentationForTests?.({
1017
+ at: Date.now(),
1018
+ phase: "failed",
1019
+ operation: "transactTerminalState",
1020
+ error: error instanceof Error ? error.message : String(error),
1021
+ });
1022
+ } catch {}
1023
+ throw error;
1024
+ }
866
1025
  };
867
1026
 
868
1027
  const transactTerminalKeys = async (
869
1028
  mutator: (keys: EvictedTerminalKeyEntry[]) => EvictedTerminalKeyEntry[],
870
1029
  ): Promise<void> => {
871
1030
  const run = async () => {
1031
+ try {
1032
+ options.onInstrumentationForTests?.({
1033
+ at: Date.now(),
1034
+ phase: "enqueued",
1035
+ operation: "transactTerminalKeys",
1036
+ });
1037
+ } catch {}
1038
+ try {
1039
+ options.onInstrumentationForTests?.({
1040
+ at: Date.now(),
1041
+ phase: "started",
1042
+ operation: "transactTerminalKeys",
1043
+ });
1044
+ } catch {}
872
1045
  const next = mutator(terminalKeyMemory.map(k => ({ ...k })));
873
1046
  await writeAtomic({
874
1047
  version: RECONCILIATION_STORE_VERSION,
@@ -878,13 +1051,33 @@ export function createReconciliationStore(options: {
878
1051
  ...(next.length > 0 ? { evictedTerminalKeys: next } : {}),
879
1052
  });
880
1053
  terminalKeyMemory = next;
1054
+ try {
1055
+ options.onInstrumentationForTests?.({
1056
+ at: Date.now(),
1057
+ phase: "completed",
1058
+ operation: "transactTerminalKeys",
1059
+ });
1060
+ } catch {}
881
1061
  };
882
1062
  const pending = chain.then(run, run);
883
- chain = pending.then(
1063
+ const settled = pending.then(
884
1064
  () => undefined,
885
1065
  () => undefined,
886
1066
  );
887
- await pending;
1067
+ chain = settled;
1068
+ try {
1069
+ await pending;
1070
+ } catch (error) {
1071
+ try {
1072
+ options.onInstrumentationForTests?.({
1073
+ at: Date.now(),
1074
+ phase: "failed",
1075
+ operation: "transactTerminalKeys",
1076
+ error: error instanceof Error ? error.message : String(error),
1077
+ });
1078
+ } catch {}
1079
+ throw error;
1080
+ }
888
1081
  };
889
1082
 
890
1083
  const deleteStore = async (): Promise<void> => {
@@ -301,8 +301,10 @@ export const SDK_LIFECYCLE_ROUTER_PROTOCOL_VERSION = 1;
301
301
  * Generation 202 joins queued-removal terminal publication before ordinary
302
302
  * abort acknowledgement, replacing owners that still acknowledge cancellation
303
303
  * before its terminal record is durable.
304
+ * Generation 203 replaces owners that still treat a project `.gjc` file as an
305
+ * explicit deadline-autosave opt-in for a primary checkout.
304
306
  */
305
- export const DAEMON_GENERATION = 202;
307
+ export const DAEMON_GENERATION = 204;
306
308
 
307
309
  /**
308
310
  * Serving-compatibility boundary for daemon lifecycle requests. Epoch 7
@@ -258,17 +258,32 @@ function normalizeSessionFailure(error: unknown, args: SdkSessionCliArgs): Publi
258
258
  }
259
259
 
260
260
  /** Lifecycle terminality/retryability is not, by itself, proof of an effect outcome. */
261
+ /**
262
+ * Lifecycle codes the broker produces when it refuses the request payload itself. Input shape is
263
+ decided before the request can be dispatched, and an outcome the broker cannot establish comes
264
+ back as `terminal_uncertain` instead, so these codes never stand for an applied operation. They
265
+ still collapse into `operation_failed` below, which cannot say why the request was refused, so
266
+ the refusal class survives as one fixed diagnostic.
267
+ */
268
+ const LIFECYCLE_INPUT_REFUSAL_CODES = new Set(["invalid_input", "invalid_request"]);
269
+
261
270
  export function lifecyclePublicFailure(outcome: Extract<SessionLifecycleResult, { ok: false }>): PublicCommandFailure {
262
271
  const failure = sdkPublicFailure(outcome.error.code);
263
272
  // The service emits retryable protocol_error only when requestSent is explicitly false.
264
273
  const proof: PublicEffectProof =
265
274
  outcome.certainty === "retryable" && outcome.error.code === "protocol_error" ? "pre-send" : "unknown";
266
- // `operation_failed` cannot distinguish a conflict from any other failed operation, so
267
- // the conflict survives as one fixed diagnostic. The broker message itself is never
268
- // rendered: it may carry request keys, paths, or credentials, and its cause is not
269
- // decidable from the code alone.
275
+ // `operation_failed` cannot distinguish a conflict or an input refusal from any other failed
276
+ // operation, so each survives as one fixed diagnostic. The broker message itself is never
277
+ // rendered: it may carry request keys, paths, or credentials, and its cause is not decidable
278
+ // from the code alone.
279
+ let diagnostic: PublicCommandDiagnosticCode | undefined;
280
+ if (outcome.error.code === "idempotency_conflict") {
281
+ diagnostic = "lifecycle_idempotency_conflict";
282
+ } else if (LIFECYCLE_INPUT_REFUSAL_CODES.has(outcome.error.code)) {
283
+ diagnostic = "lifecycle_input_refused";
284
+ }
270
285
  const diagnostics: readonly PublicCommandDiagnosticCode[] | undefined =
271
- outcome.error.code === "idempotency_conflict" ? ["lifecycle_idempotency_conflict"] : undefined;
286
+ diagnostic === undefined ? undefined : [diagnostic];
272
287
  return new PublicCommandFailure({
273
288
  ...failure.input,
274
289
  ...(diagnostics === undefined ? {} : { diagnostics }),
@@ -2209,7 +2224,7 @@ async function runRawControl(
2209
2224
  input: JsonRecord,
2210
2225
  args: SdkSessionCliArgs,
2211
2226
  ): Promise<unknown> {
2212
- const invalid = validateAdapterControl(operation, input);
2227
+ const invalid = validateAdapterControl(operation, input, { allowUltrafastTier: true });
2213
2228
  if (invalid) throw new SdkSessionCliError(invalid.code, invalid.message, 2);
2214
2229
  await ensureBroker({ agentDir });
2215
2230
  const operatorRequest = operatorAbortBrokerRequest(sessionId, operation, input, args);