mixdog 0.9.62 → 0.9.64

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 (403) hide show
  1. package/README.md +3 -0
  2. package/package.json +9 -2
  3. package/scripts/code-graph-description-contract.mjs +3 -3
  4. package/scripts/verify-release-assets.mjs +2 -2
  5. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +11 -14
  6. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +6 -6
  7. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -2
  8. package/src/runtime/agent/orchestrator/agent-trace-format.mjs +1 -0
  9. package/src/runtime/agent/orchestrator/config.mjs +19 -124
  10. package/src/runtime/agent/orchestrator/context/collect.mjs +6 -6
  11. package/src/runtime/agent/orchestrator/dispatch-persist.mjs +2 -2
  12. package/src/runtime/agent/orchestrator/internal-agents.mjs +2 -2
  13. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +1 -1
  14. package/src/runtime/agent/orchestrator/mcp/client.mjs +4 -4
  15. package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +2 -2
  16. package/src/runtime/agent/orchestrator/providers/anthropic-betas.mjs +4 -4
  17. package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +2 -2
  18. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +4 -4
  19. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +333 -0
  20. package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +2 -2
  21. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +4 -4
  22. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +1 -1
  23. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +3 -277
  24. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +2 -2
  25. package/src/runtime/agent/orchestrator/providers/custom-tool-wire.mjs +1 -1
  26. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +2 -2
  27. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +6 -6
  28. package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +196 -0
  29. package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +460 -0
  30. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +14 -593
  31. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +1 -1
  32. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +1 -1
  33. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +1 -1
  34. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +4 -4
  35. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +2 -2
  36. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +5 -280
  37. package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +357 -0
  38. package/src/runtime/agent/orchestrator/providers/openai-ws-headers.mjs +216 -0
  39. package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +2 -188
  40. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +2 -2
  41. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +2 -2
  42. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +1 -1
  43. package/src/runtime/agent/orchestrator/providers/provider-catalog-cache.mjs +1 -1
  44. package/src/runtime/agent/orchestrator/providers/registry.mjs +1 -1
  45. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +2 -2
  46. package/src/runtime/agent/orchestrator/providers/statusline-route-meta.mjs +1 -1
  47. package/src/runtime/agent/orchestrator/session/cache/prefetch-cache.mjs +1 -1
  48. package/src/runtime/agent/orchestrator/session/cache/scoped-cache.mjs +3 -3
  49. package/src/runtime/agent/orchestrator/session/compact/budget.mjs +2 -2
  50. package/src/runtime/agent/orchestrator/session/compact/file-reattach.mjs +2 -2
  51. package/src/runtime/agent/orchestrator/session/compact/summary-schema.mjs +1 -1
  52. package/src/runtime/agent/orchestrator/session/compact/summary.mjs +1 -1
  53. package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +2 -2
  54. package/src/runtime/agent/orchestrator/session/context-utils.mjs +4 -4
  55. package/src/runtime/agent/orchestrator/session/loop/deferred-call-through.mjs +1 -1
  56. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +17 -0
  57. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +1 -1
  58. package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +18 -26
  59. package/src/runtime/agent/orchestrator/session/loop/termination.mjs +1 -1
  60. package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +3 -3
  61. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +1 -0
  62. package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +1 -1
  63. package/src/runtime/agent/orchestrator/session/manager/delivered-completions.mjs +1 -1
  64. package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +1 -1
  65. package/src/runtime/agent/orchestrator/session/store/live-state.mjs +49 -0
  66. package/src/runtime/agent/orchestrator/session/store/load-cache.mjs +49 -0
  67. package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +260 -0
  68. package/src/runtime/agent/orchestrator/session/store/serialize.mjs +72 -0
  69. package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +163 -0
  70. package/src/runtime/agent/orchestrator/session/store/write-guards.mjs +1 -1
  71. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +1 -1
  72. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +4 -1
  73. package/src/runtime/agent/orchestrator/session/store.mjs +9 -561
  74. package/src/runtime/agent/orchestrator/session/tool-envelope.mjs +1 -1
  75. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +2 -2
  76. package/src/runtime/agent/orchestrator/stall-policy.mjs +11 -11
  77. package/src/runtime/agent/orchestrator/tools/bash-policy-scan.mjs +1 -1
  78. package/src/runtime/agent/orchestrator/tools/bash-session.mjs +2 -2
  79. package/src/runtime/agent/orchestrator/tools/builtin/advisory-lock.mjs +1 -1
  80. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +2 -2
  81. package/src/runtime/agent/orchestrator/tools/builtin/atomic-write.mjs +1 -1
  82. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +2 -154
  83. package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +1 -1
  84. package/src/runtime/agent/orchestrator/tools/builtin/cwd-utils.mjs +1 -1
  85. package/src/runtime/agent/orchestrator/tools/builtin/fs-reachability.mjs +1 -1
  86. package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +1 -1
  87. package/src/runtime/agent/orchestrator/tools/builtin/glob-walk.mjs +1 -1
  88. package/src/runtime/agent/orchestrator/tools/builtin/path-locks.mjs +1 -1
  89. package/src/runtime/agent/orchestrator/tools/builtin/path-utils.mjs +1 -1
  90. package/src/runtime/agent/orchestrator/tools/builtin/read-args.mjs +2 -2
  91. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +2 -3
  92. package/src/runtime/agent/orchestrator/tools/builtin/read-image-resize.mjs +4 -4
  93. package/src/runtime/agent/orchestrator/tools/builtin/read-open.mjs +1 -1
  94. package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +1 -1
  95. package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +2 -2
  96. package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +5 -5
  97. package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +1 -1
  98. package/src/runtime/agent/orchestrator/tools/builtin/shell-job-paths.mjs +2 -2
  99. package/src/runtime/agent/orchestrator/tools/builtin/shell-job-process.mjs +2 -2
  100. package/src/runtime/agent/orchestrator/tools/builtin/shell-job-spawn.mjs +519 -0
  101. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +5 -449
  102. package/src/runtime/agent/orchestrator/tools/builtin/snapshot-helpers.mjs +1 -1
  103. package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +212 -0
  104. package/src/runtime/agent/orchestrator/tools/builtin.mjs +1 -1
  105. package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +1 -7
  106. package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +9 -36
  107. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +15 -3
  108. package/src/runtime/agent/orchestrator/tools/code-graph/search-references.mjs +429 -0
  109. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +2 -395
  110. package/src/runtime/agent/orchestrator/tools/code-graph/symbol-index.mjs +2 -2
  111. package/src/runtime/agent/orchestrator/tools/code-graph/text-mask.mjs +1 -1
  112. package/src/runtime/agent/orchestrator/tools/code-graph/trusted-roots.mjs +1 -1
  113. package/src/runtime/agent/orchestrator/tools/code-graph-prewarm-worker.mjs +1 -1
  114. package/src/runtime/agent/orchestrator/tools/code-graph-state.mjs +3 -3
  115. package/src/runtime/agent/orchestrator/tools/mutation-planner.mjs +5 -5
  116. package/src/runtime/agent/orchestrator/tools/next-call-utils.mjs +1 -1
  117. package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +1 -1
  118. package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +7 -7
  119. package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +72 -9
  120. package/src/runtime/agent/orchestrator/tools/patch/parsing.mjs +4 -4
  121. package/src/runtime/agent/orchestrator/tools/patch/paths.mjs +1 -1
  122. package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +1 -1
  123. package/src/runtime/agent/orchestrator/tools/patch-tool-defs.mjs +4 -4
  124. package/src/runtime/agent/orchestrator/tools/patch.mjs +1 -1
  125. package/src/runtime/agent/orchestrator/tools/result-compression.mjs +3 -3
  126. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +2 -444
  127. package/src/runtime/agent/orchestrator/tools/shell-exec-output.mjs +505 -0
  128. package/src/runtime/agent/orchestrator/tools/shell-exec-policy.mjs +2 -2
  129. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +1 -1
  130. package/src/runtime/channels/lib/backend-dispatch.mjs +20 -5
  131. package/src/runtime/channels/lib/scheduler.mjs +1 -1
  132. package/src/runtime/channels/lib/telegram-format.mjs +1 -1
  133. package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +4 -4
  134. package/src/runtime/channels/tool-defs.mjs +2 -3
  135. package/src/runtime/memory/index.mjs +1 -5
  136. package/src/runtime/memory/lib/core-memory-candidates.mjs +357 -0
  137. package/src/runtime/memory/lib/core-memory-store.mjs +7 -357
  138. package/src/runtime/memory/lib/cycle-signatures.mjs +1 -1
  139. package/src/runtime/memory/lib/embedding-model-config.mjs +1 -1
  140. package/src/runtime/memory/lib/embedding-provider.mjs +1 -5
  141. package/src/runtime/memory/lib/embedding-worker.mjs +1 -5
  142. package/src/runtime/memory/lib/ko-morph.mjs +2 -2
  143. package/src/runtime/memory/lib/memory-config-flags.mjs +2 -5
  144. package/src/runtime/memory/lib/memory-cycle-requests.mjs +3 -7
  145. package/src/runtime/memory/lib/memory-cycle1.mjs +4 -8
  146. package/src/runtime/memory/lib/memory-cycle2-gate.mjs +1 -1
  147. package/src/runtime/memory/lib/memory-cycle2-mutations.mjs +1 -1
  148. package/src/runtime/memory/lib/memory-cycle2-shared.mjs +2 -5
  149. package/src/runtime/memory/lib/memory-cycle3.mjs +1 -5
  150. package/src/runtime/memory/lib/memory-embed.mjs +2 -6
  151. package/src/runtime/memory/lib/memory-log.mjs +8 -0
  152. package/src/runtime/memory/lib/memory-ops-policy.mjs +4 -8
  153. package/src/runtime/memory/lib/memory-recall-scope-filter.mjs +1 -1
  154. package/src/runtime/memory/lib/memory-recall-store.mjs +2 -193
  155. package/src/runtime/memory/lib/memory-score.mjs +1 -1
  156. package/src/runtime/memory/lib/memory-text-utils.mjs +2 -2
  157. package/src/runtime/memory/lib/memory.mjs +2 -6
  158. package/src/runtime/memory/lib/pg/adapter.mjs +2 -6
  159. package/src/runtime/memory/lib/pg/process.mjs +1 -5
  160. package/src/runtime/memory/lib/pg/supervisor.mjs +1 -5
  161. package/src/runtime/memory/lib/recall-format.mjs +2 -2
  162. package/src/runtime/memory/lib/recall-scoring.mjs +195 -0
  163. package/src/runtime/memory/lib/runtime-fetcher.mjs +1 -5
  164. package/src/runtime/memory/lib/trace-store.mjs +2 -6
  165. package/src/runtime/search/lib/http-fetch.mjs +6 -6
  166. package/src/runtime/search/lib/web-tools.mjs +2 -2
  167. package/src/runtime/shared/buffered-appender.mjs +1 -1
  168. package/src/runtime/shared/child-guardian.mjs +1 -1
  169. package/src/runtime/shared/child-spawn-gate.mjs +1 -1
  170. package/src/runtime/shared/config.mjs +4 -4
  171. package/src/runtime/shared/launcher-control.mjs +9 -10
  172. package/src/runtime/shared/llm/index.mjs +5 -20
  173. package/src/runtime/shared/markdown-frontmatter.mjs +1 -1
  174. package/src/runtime/shared/memory-snapshot.mjs +4 -4
  175. package/src/runtime/shared/pristine-execution.mjs +1 -1
  176. package/src/runtime/shared/process-lifecycle.mjs +0 -1
  177. package/src/runtime/shared/process-shutdown.mjs +1 -1
  178. package/src/runtime/shared/resource-admission.mjs +2 -2
  179. package/src/runtime/shared/schedule-session-run.mjs +1 -1
  180. package/src/runtime/shared/schedules-db.mjs +1 -1
  181. package/src/runtime/shared/service-discovery.mjs +2 -2
  182. package/src/runtime/shared/staged-update.mjs +6 -6
  183. package/src/runtime/shared/tool-execution-contract.mjs +1 -1
  184. package/src/runtime/shared/tool-primitives.mjs +1 -1
  185. package/src/runtime/shared/tool-surface.mjs +2 -2
  186. package/src/runtime/shared/update-checker.mjs +1 -1
  187. package/src/runtime/shared/user-cwd.mjs +3 -3
  188. package/src/runtime/shared/user-data-guard.mjs +4 -4
  189. package/src/runtime/shared/workspace-router.mjs +5 -5
  190. package/src/session-runtime/config-helpers.mjs +2 -3
  191. package/src/session-runtime/config-lifecycle.mjs +1 -1
  192. package/src/session-runtime/hitch-profile.mjs +1 -1
  193. package/src/session-runtime/lifecycle-api.mjs +6 -4
  194. package/src/session-runtime/model-recency.mjs +5 -5
  195. package/src/session-runtime/plugin-mcp.mjs +1 -1
  196. package/src/session-runtime/provider-request-snapshot.mjs +338 -0
  197. package/src/session-runtime/session-text.mjs +4 -4
  198. package/src/session-runtime/tool-catalog-schema.mjs +197 -0
  199. package/src/session-runtime/tool-catalog.mjs +6 -483
  200. package/src/session-runtime/tool-defs.mjs +1 -1
  201. package/src/standalone/agent-task-status.mjs +1 -1
  202. package/src/standalone/agent-tool/helpers.mjs +2 -2
  203. package/src/standalone/channel-admin.mjs +4 -4
  204. package/src/standalone/explore-tool.mjs +3 -3
  205. package/src/standalone/hook-bus/config.mjs +1 -1
  206. package/src/standalone/hook-bus/constants.mjs +1 -1
  207. package/src/standalone/hook-bus/rules.mjs +1 -1
  208. package/src/standalone/projects.mjs +1 -1
  209. package/src/standalone/provider-admin.mjs +2 -2
  210. package/src/tui/app/app-format.mjs +2 -2
  211. package/src/tui/app/clipboard.mjs +3 -3
  212. package/src/tui/app/input-parsers.mjs +1 -1
  213. package/src/tui/app/text-layout.mjs +1 -1
  214. package/src/tui/app/transcript-row-estimate.mjs +360 -0
  215. package/src/tui/app/transcript-window.mjs +5 -347
  216. package/src/tui/app/use-mouse-input.mjs +1 -1
  217. package/src/tui/app/use-prompt-handlers.mjs +1 -1
  218. package/src/tui/components/tool-execution/surface-detail.mjs +9 -9
  219. package/src/tui/components/tool-execution/text-format.mjs +2 -2
  220. package/src/tui/components/tool-output-format.mjs +7 -7
  221. package/src/tui/display-width.mjs +4 -4
  222. package/src/tui/dist/index.mjs +63 -97
  223. package/src/tui/engine/agent-envelope.mjs +5 -5
  224. package/src/tui/engine/notification-plan.mjs +1 -1
  225. package/src/tui/engine/queue-helpers.mjs +3 -3
  226. package/src/tui/engine/render-timing.mjs +4 -5
  227. package/src/tui/engine/session-api-ext.mjs +3 -3
  228. package/src/tui/engine/tool-result-status.mjs +5 -5
  229. package/src/tui/engine/tool-result-text.mjs +1 -1
  230. package/src/tui/engine/transcript-spill.mjs +585 -0
  231. package/src/tui/engine/tui-steering-persist.mjs +1 -1
  232. package/src/tui/engine.mjs +2 -474
  233. package/src/tui/lib/voice-setup.mjs +1 -1
  234. package/src/tui/markdown/format-token.mjs +1 -1
  235. package/src/tui/markdown/render-ansi.mjs +1 -1
  236. package/src/tui/markdown/table-layout.mjs +4 -4
  237. package/src/tui/paste-attachments.mjs +1 -1
  238. package/src/tui/prompt-history-store.mjs +3 -3
  239. package/src/tui/statusline-ansi-bridge.mjs +2 -2
  240. package/src/tui/theme.mjs +1 -1
  241. package/src/tui/transcript-tool-failures.mjs +2 -2
  242. package/src/ui/ansi.mjs +0 -9
  243. package/src/ui/statusline-format.mjs +2 -4
  244. package/scripts/_bench-cwc.json +0 -20
  245. package/scripts/_jitter-fuzz.jsx +0 -42
  246. package/scripts/_jitter-fuzz2.jsx +0 -30
  247. package/scripts/_jitter-probe.jsx +0 -35
  248. package/scripts/_jp2.jsx +0 -16
  249. package/scripts/_smoke_wd.mjs +0 -7
  250. package/scripts/abort-recovery-test.mjs +0 -175
  251. package/scripts/agent-dispatch-abort-compose-test.mjs +0 -31
  252. package/scripts/agent-live-arg-guard-smoke.mjs +0 -20
  253. package/scripts/agent-live-path-suffix-smoke.mjs +0 -34
  254. package/scripts/agent-live-toolcall-args-smoke.mjs +0 -45
  255. package/scripts/agent-loop-policy-test.mjs +0 -37
  256. package/scripts/agent-model-liveness-test.mjs +0 -763
  257. package/scripts/agent-parallel-smoke.mjs +0 -435
  258. package/scripts/agent-route-batch-test.mjs +0 -40
  259. package/scripts/agent-tag-reuse-smoke.mjs +0 -441
  260. package/scripts/agent-terminal-reap-test.mjs +0 -252
  261. package/scripts/agent-trace-io-test.mjs +0 -133
  262. package/scripts/ansi-color-capability-test.mjs +0 -90
  263. package/scripts/anthropic-admission-retry-integration-test.mjs +0 -119
  264. package/scripts/anthropic-maxtokens-test.mjs +0 -119
  265. package/scripts/anthropic-oauth-refresh-race-test.mjs +0 -397
  266. package/scripts/anthropic-transport-policy-test.mjs +0 -726
  267. package/scripts/apply-patch-edit-smoke.mjs +0 -71
  268. package/scripts/arg-guard-test.mjs +0 -93
  269. package/scripts/async-notify-settlement-test.mjs +0 -99
  270. package/scripts/atomic-lock-tryonce-test.mjs +0 -125
  271. package/scripts/background-task-meta-smoke.mjs +0 -38
  272. package/scripts/bench-run.mjs +0 -508
  273. package/scripts/boot-smoke.mjs +0 -137
  274. package/scripts/build-runtime-windows.ps1 +0 -242
  275. package/scripts/channel-daemon-smoke.mjs +0 -1103
  276. package/scripts/code-graph-aggregate-cwd-test.mjs +0 -158
  277. package/scripts/code-graph-disk-hit-test.mjs +0 -290
  278. package/scripts/code-graph-dispatch-test.mjs +0 -96
  279. package/scripts/code-graph-root-federation-test.mjs +0 -273
  280. package/scripts/compact-active-turn-test.mjs +0 -68
  281. package/scripts/compact-file-reattach-test.mjs +0 -88
  282. package/scripts/compact-pressure-test.mjs +0 -788
  283. package/scripts/compact-prior-context-flatten-test.mjs +0 -252
  284. package/scripts/compact-recall-digest-test.mjs +0 -57
  285. package/scripts/compact-smoke.mjs +0 -1017
  286. package/scripts/compact-trigger-migration-smoke.mjs +0 -261
  287. package/scripts/compacted-placeholder-scrub-test.mjs +0 -63
  288. package/scripts/context-mcp-metering-test.mjs +0 -1406
  289. package/scripts/debounced-skills-async-save-test.mjs +0 -57
  290. package/scripts/deferred-tool-loading-test.mjs +0 -250
  291. package/scripts/desktop-session-bridge-test.mjs +0 -1013
  292. package/scripts/dispatch-persist-recovery-test.mjs +0 -141
  293. package/scripts/embedding-worker-exit-test.mjs +0 -76
  294. package/scripts/execution-completion-dedup-test.mjs +0 -205
  295. package/scripts/execution-pending-resume-kick-test.mjs +0 -151
  296. package/scripts/execution-resume-esc-integration-test.mjs +0 -176
  297. package/scripts/explore-bench-tmp.mjs +0 -36
  298. package/scripts/explore-bench.mjs +0 -248
  299. package/scripts/explore-prompt-policy-test.mjs +0 -256
  300. package/scripts/explore-timeout-cancel-test.mjs +0 -345
  301. package/scripts/find-fuzzy-hidden-test.mjs +0 -267
  302. package/scripts/forwarder-rebind-tail-test.mjs +0 -67
  303. package/scripts/freevar-smoke.mjs +0 -98
  304. package/scripts/gemini-provider-test.mjs +0 -1448
  305. package/scripts/generate-oc-icons.mjs +0 -11
  306. package/scripts/grok-oauth-refresh-race-test.mjs +0 -273
  307. package/scripts/headless-pristine-execution-test.mjs +0 -614
  308. package/scripts/hook-bus-test.mjs +0 -552
  309. package/scripts/ingest-pure-conversation-smoke.mjs +0 -175
  310. package/scripts/internal-comms-bench-test.mjs +0 -226
  311. package/scripts/internal-comms-bench.mjs +0 -853
  312. package/scripts/internal-comms-smoke.mjs +0 -277
  313. package/scripts/internal-tools-normalization-test.mjs +0 -62
  314. package/scripts/interrupted-turn-history-test.mjs +0 -399
  315. package/scripts/lead-workflow-smoke.mjs +0 -592
  316. package/scripts/lifecycle-api-test.mjs +0 -137
  317. package/scripts/live-share-test.mjs +0 -148
  318. package/scripts/live-worker-smoke.mjs +0 -333
  319. package/scripts/log-writer-guard-smoke.mjs +0 -131
  320. package/scripts/maintenance-default-routes-test.mjs +0 -164
  321. package/scripts/max-output-recovery-persist-test.mjs +0 -81
  322. package/scripts/max-output-recovery-test.mjs +0 -368
  323. package/scripts/mcp-client-normalization-test.mjs +0 -45
  324. package/scripts/mcp-grace-deferred-test.mjs +0 -225
  325. package/scripts/memory-core-input-test.mjs +0 -167
  326. package/scripts/memory-cycle-routing-test.mjs +0 -111
  327. package/scripts/memory-meta-concurrency-test.mjs +0 -20
  328. package/scripts/memory-pg-recovery-test.mjs +0 -59
  329. package/scripts/memory-rule-contract-test.mjs +0 -93
  330. package/scripts/model-list-sanitize-test.mjs +0 -37
  331. package/scripts/mouse-tracking-restore-smoke.mjs +0 -107
  332. package/scripts/native-edit-wire-test.mjs +0 -152
  333. package/scripts/notify-completion-mirror-test.mjs +0 -73
  334. package/scripts/openai-oauth-refresh-race-test.mjs +0 -120
  335. package/scripts/openai-oauth-ws-1006-retry-test.mjs +0 -954
  336. package/scripts/openai-ws-early-settle-test.mjs +0 -216
  337. package/scripts/output-style-bench.mjs +0 -292
  338. package/scripts/output-style-smoke.mjs +0 -145
  339. package/scripts/parent-abort-link-test.mjs +0 -90
  340. package/scripts/patch-binary-cache-test.mjs +0 -181
  341. package/scripts/path-suffix-test.mjs +0 -57
  342. package/scripts/pending-completion-drop-test.mjs +0 -239
  343. package/scripts/pending-messages-lock-nonblocking-test.mjs +0 -62
  344. package/scripts/pretool-ask-runtime-test.mjs +0 -54
  345. package/scripts/process-lifecycle-test.mjs +0 -461
  346. package/scripts/prompt-immediate-render-test.mjs +0 -89
  347. package/scripts/prompt-input-parity-test.mjs +0 -145
  348. package/scripts/provider-admission-scheduler-test.mjs +0 -681
  349. package/scripts/provider-contract-test.mjs +0 -632
  350. package/scripts/provider-stream-stall-test.mjs +0 -276
  351. package/scripts/provider-toolcall-test.mjs +0 -3063
  352. package/scripts/reactive-compact-persist-smoke.mjs +0 -203
  353. package/scripts/recall-bench.mjs +0 -359
  354. package/scripts/resource-admission-test.mjs +0 -792
  355. package/scripts/result-classification-test.mjs +0 -75
  356. package/scripts/rg-runner-test.mjs +0 -240
  357. package/scripts/routing-corpus-test.mjs +0 -349
  358. package/scripts/sanitize-tool-pairs-test.mjs +0 -260
  359. package/scripts/session-bench-cache-break-test.mjs +0 -102
  360. package/scripts/session-bench.mjs +0 -1708
  361. package/scripts/session-context-bench.mjs +0 -344
  362. package/scripts/session-heartbeat-lifecycle-test.mjs +0 -68
  363. package/scripts/session-ingest-compaction-smoke.mjs +0 -279
  364. package/scripts/session-ingest-smoke.mjs +0 -177
  365. package/scripts/session-orphan-sweep-test.mjs +0 -109
  366. package/scripts/set-effort-config-test.mjs +0 -41
  367. package/scripts/shell-failure-diagnostics-test.mjs +0 -280
  368. package/scripts/shell-hardening-test.mjs +0 -209
  369. package/scripts/shell-jobs-windows-hide-test.mjs +0 -164
  370. package/scripts/ship-mode-test.mjs +0 -98
  371. package/scripts/smoke-loop-failure-summary-test.mjs +0 -38
  372. package/scripts/smoke-loop-failure-summary.mjs +0 -16
  373. package/scripts/smoke-loop-report.mjs +0 -221
  374. package/scripts/smoke-loop.mjs +0 -202
  375. package/scripts/smoke-runtime-negative.ps1 +0 -106
  376. package/scripts/statusline-quota-hysteresis-test.mjs +0 -62
  377. package/scripts/steering-drain-buckets-test.mjs +0 -467
  378. package/scripts/steering-fold-provenance-test.mjs +0 -71
  379. package/scripts/streaming-tail-window-test.mjs +0 -175
  380. package/scripts/submit-commandbusy-race-test.mjs +0 -257
  381. package/scripts/task-bench.mjs +0 -205
  382. package/scripts/terminal-bench-isolation-guards-test.mjs +0 -102
  383. package/scripts/termio-input-smoke.mjs +0 -199
  384. package/scripts/tool-result-hook-test.mjs +0 -48
  385. package/scripts/tool-smoke.mjs +0 -2453
  386. package/scripts/tool-tui-presentation-test.mjs +0 -286
  387. package/scripts/toolcall-args-test.mjs +0 -239
  388. package/scripts/tui-ambiguous-width-test.mjs +0 -113
  389. package/scripts/tui-background-failure-smoke.mjs +0 -73
  390. package/scripts/tui-perf-run.ps1 +0 -26
  391. package/scripts/tui-render-smoke.mjs +0 -90
  392. package/scripts/tui-runtime-load-bench-entry.jsx +0 -608
  393. package/scripts/tui-runtime-load-bench.mjs +0 -50
  394. package/scripts/tui-store-frame-batch-test.mjs +0 -99
  395. package/scripts/tui-transcript-jitter-harness-entry.jsx +0 -383
  396. package/scripts/tui-transcript-perf-test.mjs +0 -934
  397. package/scripts/usage-metrics-epoch-smoke.mjs +0 -114
  398. package/scripts/verify-release-assets-test.mjs +0 -281
  399. package/scripts/web-fetch-routing-test.mjs +0 -158
  400. package/scripts/webhook-smoke.mjs +0 -201
  401. package/scripts/windows-hide-spawn-options-test.mjs +0 -19
  402. package/scripts/worker-notify-rejection-test.mjs +0 -51
  403. package/scripts/write-backpressure-test.mjs +0 -147
@@ -1,256 +0,0 @@
1
- #!/usr/bin/env node
2
- import test from 'node:test';
3
- import assert from 'node:assert/strict';
4
- import { readFileSync } from 'node:fs';
5
- import { buildExplorerPrompt } from '../src/standalone/explore-tool.mjs';
6
- import { EXPLORE_TOOL } from '../src/standalone/explore-tool.mjs';
7
- import { BUILTIN_TOOLS } from '../src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs';
8
- import { CODE_GRAPH_TOOL_DEFS } from '../src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs';
9
- import { TOOL_SEARCH_TOOL } from '../src/session-runtime/tool-defs.mjs';
10
- import { createEagerDispatcher } from '../src/runtime/agent/orchestrator/session/eager-dispatch.mjs';
11
- import { crossTurnSignature } from '../src/runtime/agent/orchestrator/session/loop/completion-guards.mjs';
12
- import {
13
- isEagerDispatchable,
14
- isToolCallDedupEligible,
15
- } from '../src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs';
16
- import { assertCodeGraphDescriptionContract } from './code-graph-description-contract.mjs';
17
-
18
- test('explore per-query prompt contains only escaped query XML', () => {
19
- const prompt = buildExplorerPrompt('display model usage show usage model_usage provider_usage session cache usage state');
20
- assert.equal(prompt, '<query>display model usage show usage model_usage provider_usage session cache usage state</query>');
21
- assert.doesNotMatch(prompt, /Reminder:|BUDGET|TURN 1|STOP and answer|verdicts|ratings|recommendations/i);
22
- assert.equal(buildExplorerPrompt('where is <agent> & status?'), '<query>where is &lt;agent&gt; &amp; status?</query>');
23
- });
24
-
25
- test('builtin route descriptions carry the shortest verified-path policy', () => {
26
- const byName = Object.fromEntries(BUILTIN_TOOLS.map((tool) => [tool.name, tool]));
27
- // Conditional find-first: only genuinely guessed fragments route through
28
- // find, and in the SAME turn — project root itself is a verified scope.
29
- assert.match(byName.grep.description, /project root counts as verified/i);
30
- assert.match(byName.grep.description, /guessed path fragment → find first/i);
31
- assert.match(byName.grep.description, /no path "\." \+ guessed src\/\*\*/i);
32
- assert.match(byName.glob.description, /project root is verified/i);
33
- assert.match(byName.glob.description, /Guessed root\/name → find first/i);
34
- assert.match(byName.find.description, /output paths are verified/i);
35
- assert.match(byName.read.description, /guessed path\/name → find first/i);
36
- assert.match(byName.read.description, /Batch paths\/regions as real arrays.*path\[\]/i);
37
- assert.match(byName.shell.description, /Shell\/write calls are serial/i);
38
- assert.doesNotMatch(byName.shell.description, /parallel calls/i);
39
- assert.match(byName.find.description, /lookup only for unknown partial paths\/names/i);
40
- assert.match(byName.find.description, /project root or already-verified roots/i);
41
- assert.doesNotMatch(byName.grep.description, /find for that fragment before any grep\/glob/i);
42
- assert.match(byName.grep.description, /nonzero content_with_context result resolves that search concept/i);
43
- assert.match(byName.grep.description, /Only zero\/error results may change tokens or scope/i);
44
- assert.match(`${byName.code_graph?.description || ''} ${CODE_GRAPH_TOOL_DEFS[0]?.inputSchema?.properties?.symbols?.description || ''}`, /multiple exact symbols use one symbols\[\] call/i);
45
- assert.match(CODE_GRAPH_TOOL_DEFS[0]?.description || '', /verified source files only/i);
46
- });
47
-
48
- test('shared tool policy routes facets without duplicate content acquisition', () => {
49
- const rule = readFileSync(new URL('../src/rules/shared/01-tool.md', import.meta.url), 'utf8');
50
- const policy = rule.replace(/\s+/g, ' ');
51
- assert.match(policy, /for each facet choose exactly one shortest locator route/i);
52
- assert.match(policy, /broad\/uncertain→\s*`explore`.*partial path\/name→\s*`find`.*verified root\+wildcard→\s*`glob`.*quoted\/non-identifier literal or regex→\s*`grep`.*exact code identifier\/relation→\s*`code_graph` before grep/i);
53
- assert.match(policy, /grep only for a requested literal occurrence or after graph zero\/error/i);
54
- assert.match(policy, /batch compatible targets/i);
55
- assert.match(policy, /parallelize distinct facets only, never alternative routes for one facet/i);
56
- assert.match(policy, /put independent read-only calls in one turn; they may run concurrently regardless of tool/i);
57
- assert.match(policy, /after locator results, collect all known candidate files\/regions before inspection/i);
58
- assert.match(policy, /batch compatible reads.*same-file regions.*in one `path\[\]` call and graph targets in arrays/i);
59
- assert.match(policy, /parallelize independent incompatible read-only inspections/i);
60
- assert.match(policy, /do not start a singleton while a known compatible candidate remains/i);
61
- assert.match(policy, /shell\/write calls are serial/i);
62
- assert.match(policy, /later turns are only for targets dependent on prior results or unresolved facets/i);
63
- assert.match(policy, /stop when evidence covers the deliverable/i);
64
- assert.match(policy, /sufficient contextual grep means no overlapping `read`/i);
65
- assert.match(policy, /files_with_matches.*count.*capped.*insufficient context.*inspect only missing content/i);
66
- assert.match(policy, /known file\/span→`read` directly without `grep`/i);
67
- assert.doesNotMatch(policy, /retrieval[^.]{0,120}\b(?:one|at most \d+)\s+(?:lookup|inspection|turn|call)/i);
68
- assert.doesNotMatch(policy, /\bput independent calls in one turn\b/i);
69
- assert.doesNotMatch(policy, /\b(?:all|every)\s+(?:independent\s+)?(?:calls|tool calls)\b[^.]{0,80}\bone turn\b/i);
70
- assert.doesNotMatch(policy, /\bone lookup\b[^.]{0,80}\bat most\b[^.]{0,40}\binspection\b/i);
71
- assert.doesNotMatch(policy, /all (?:independent )?(?:calls|tool calls|targets)[^.]{0,100}\bone (?:tool )?(?:message|call)/i);
72
- });
73
-
74
- test('explorer locator policy retains its compact behavioral contract', () => {
75
- const rule = readFileSync(new URL('../src/rules/agent/30-explorer.md', import.meta.url), 'utf8');
76
- const policy = rule.replace(/\s+/g, ' ');
77
- const required = [
78
- /Return only WHERE \(`path:line`\), never WHY[\s\S]*You ARE `explore`; never call it/i,
79
- /only grep\/find\/glob\/code_graph[\s\S]*`read` and `list` are forbidden/i,
80
- /Turn 1 \(`turn 1\/3`\) is the whole search[\s\S]*Split broad\/uncertain input into every known facet[\s\S]*one batch under the shared one-route contract[\s\S]*upstream producer\/derivation layer[\s\S]*SAME batch[\s\S]*Follow-up turns batch every unresolved facet in parallel[\s\S]*single-tool turn is allowed only when exactly one pre-anchor\/zero-hit facet remains/i,
81
- /broad grep use `output_mode:"files_with_matches"`[\s\S]*`content_with_context` with `head_limit` only on paths returned this session/i,
82
- /Each pattern is one identifier, camel\/snake variant, or concept synonym[\s\S]*never a prose phrase[\s\S]*Spaces and non-ASCII are allowed only in verbatim quoted error\/log literals[\s\S]*Translate other non-English queries to English identifiers/i,
83
- /Scope is session cwd[\s\S]*For unverified `src` paths, use `find` first[\s\S]*never guess or invent directories[\s\S]*`path:"\."` with guessed `src\/\*\*`[\s\S]*exact find-returned path[\s\S]*no earlier than turn 2[\s\S]*After zero hits, change tokens or scope, never wording or guessed paths/i,
84
- /anchor is a `path:line` containing a query token or synonym[\s\S]*code_graph hit[\s\S]*Generic terms without query specificity are zero[\s\S]*Never re-locate, reconfirm, or upgrade an anchor[\s\S]*path without `:line` is a pre-anchor and counts as zero/i,
85
- /After every result, stop and answer on any specific-token anchor[\s\S]*mark a weak anchor `\?`/i,
86
- /code-location query left only with pre-anchors[\s\S]*sole anchor-minting follow-up[\s\S]*one scoped `content_with_context` grep with `head_limit`[\s\S]*If it returns zero[\s\S]*changed tokens or scope[\s\S]*Never make a second minting hop or fabricate\/estimate a line/i,
87
- /at most 3 turns[\s\S]*label every tool message `turn N\/3`[\s\S]*normally use one batch and one answer[\s\S]*Turns 2–3 are allowed only when turn 1 has zero anchors/i,
88
- /first matching entry\/definition anchors a concept, value, or default[\s\S]*never trace its chain[\s\S]*explicit flow or default-resolution query[\s\S]*entry anchor but no resolved value[\s\S]*turn 2 for one resolving hop/i,
89
- /Answer in at most 3 lines[\s\S]*`path:line — symbol — short reason`[\s\S]*Copy every cited `path:line` verbatim[\s\S]*tool result in this session[\s\S]*never estimate, adjust, or recall/i,
90
- /Every code-location line requires `:line`[\s\S]*never return a bare filename or vague prose/i,
91
- /file\/dir-location query may return an exact verified path without `:line`/i,
92
- /Return `EXPLORATION_FAILED` only after spending the budget with zero anchors[\s\S]*prefer a weak anchor to a false miss/i,
93
- ];
94
- for (const behavior of required) assert.match(policy, behavior);
95
- assert.doesNotMatch(policy, /grep[^.]{0,120}\band\b[^.]{0,120}code_graph[^.]{0,120}\band\b[^.]{0,120}find/i);
96
- });
97
-
98
- test('canonical schemas advertise safe batching without changing tool shapes', () => {
99
- const graph = CODE_GRAPH_TOOL_DEFS[0];
100
- const patch = readFileSync(new URL('../src/runtime/agent/orchestrator/tools/patch-tool-defs.mjs', import.meta.url), 'utf8');
101
- const mode = graph?.inputSchema?.properties?.mode?.description || '';
102
- const description = graph?.description || '';
103
- const symbols = graph?.inputSchema?.properties?.symbols?.description || '';
104
- assert.doesNotThrow(() => assertCodeGraphDescriptionContract({
105
- description,
106
- modeDescription: mode,
107
- symbolsDescription: symbols,
108
- }));
109
- assert.deepEqual(graph?.inputSchema?.required, ['mode']);
110
- assert.equal(graph?.inputSchema?.properties?.file, undefined);
111
- assert.equal(graph?.inputSchema?.properties?.symbol, undefined);
112
- assert.match(patch, /one patch/i);
113
- assert.match(patch, /one file block per target/i);
114
- });
115
-
116
- test('code graph and eager-dispatch boundaries preserve runtime shape', () => {
117
- const schema = CODE_GRAPH_TOOL_DEFS[0]?.inputSchema?.properties || {};
118
- const fileModes = ['overview', 'imports', 'dependents', 'related', 'impact', 'symbols'];
119
- const symbolModes = ['symbols', 'find_symbol', 'symbol_search', 'search', 'references', 'callers', 'callees'];
120
- assert.deepEqual(new Set(schema.mode?.enum), new Set([...fileModes, ...symbolModes]));
121
- const assertBatchShape = (field) => {
122
- assert.equal(field?.anyOf?.length, 2);
123
- assert.deepEqual(field.anyOf.map((entry) => entry.type), ['string', 'array']);
124
- assert.equal(field.anyOf[1].items.type, 'string');
125
- assert.equal(field.anyOf[1].minItems, 1);
126
- };
127
- assertBatchShape(schema.files);
128
- assertBatchShape(schema.symbols);
129
- assert.equal(schema.file, undefined);
130
- assert.equal(schema.symbol, undefined);
131
- assert.equal(schema.language, undefined);
132
- const tools = [
133
- ...BUILTIN_TOOLS,
134
- { name: 'mcp_read', annotations: { readOnlyHint: true } },
135
- { name: 'mcp_write', annotations: { readOnlyHint: false } },
136
- ];
137
- assert.equal(isEagerDispatchable('read', tools), true);
138
- assert.equal(isEagerDispatchable('shell', tools), false);
139
- assert.equal(isEagerDispatchable('mcp_read', tools), true);
140
- assert.equal(isEagerDispatchable('mcp_write', tools), false);
141
- assert.equal(isToolCallDedupEligible('read', tools), true);
142
- assert.equal(isToolCallDedupEligible('mcp_read', tools), true);
143
- });
144
-
145
- test('same-batch load_tool and legacy tool_search repeats all execute eagerly', async () => {
146
- const tools = [...BUILTIN_TOOLS, TOOL_SEARCH_TOOL];
147
- assert.equal(isEagerDispatchable('load_tool', tools), true);
148
- assert.equal(isEagerDispatchable('tool_search', tools), true);
149
- assert.equal(isToolCallDedupEligible('load_tool', tools), false);
150
- assert.equal(isToolCallDedupEligible('tool_search', tools), false);
151
- assert.equal(isToolCallDedupEligible('read', tools), true);
152
-
153
- const args = { names: ['shell'] };
154
- const calls = [
155
- { id: 'load-1', name: 'load_tool', arguments: args },
156
- { id: 'load-2', name: 'load_tool', arguments: args },
157
- { id: 'legacy-1', name: 'tool_search', arguments: args },
158
- { id: 'legacy-2', name: 'tool_search', arguments: args },
159
- ];
160
- const executed = [];
161
- const crossTurnCalls = new Map([
162
- [crossTurnSignature('load_tool', args), { count: 1, firstIteration: 1 }],
163
- [crossTurnSignature('tool_search', args), { count: 1, firstIteration: 1 }],
164
- ]);
165
- const dispatcher = createEagerDispatcher({
166
- tools,
167
- cwd: process.cwd(),
168
- sessionId: null,
169
- sessionRef: {},
170
- signal: null,
171
- opts: {},
172
- crossTurnCalls,
173
- getIterations: () => 2,
174
- getNextIteration: () => 2,
175
- repeatFailLimit: 3,
176
- executeToolFn: async (name) => {
177
- executed.push(name);
178
- return '{}';
179
- },
180
- });
181
- dispatcher.startEagerRun(calls, 0, new Set());
182
- assert.equal(dispatcher.pending.size, 4);
183
- await Promise.all([...dispatcher.pending.values()].map((entry) => entry.promise));
184
- assert.deepEqual(executed, ['load_tool', 'load_tool', 'tool_search', 'tool_search']);
185
-
186
- const normalExecuted = [];
187
- const normalDispatcher = createEagerDispatcher({
188
- tools,
189
- cwd: process.cwd(),
190
- sessionId: null,
191
- sessionRef: {},
192
- signal: null,
193
- opts: {},
194
- crossTurnCalls: new Map(),
195
- getIterations: () => 1,
196
- getNextIteration: () => 1,
197
- repeatFailLimit: 3,
198
- executeToolFn: async (name) => {
199
- normalExecuted.push(name);
200
- return 'ok';
201
- },
202
- });
203
- normalDispatcher.startEagerRun([
204
- { id: 'read-1', name: 'read', arguments: { path: 'same.txt' } },
205
- { id: 'read-2', name: 'read', arguments: { path: 'same.txt' } },
206
- ], 0, new Set());
207
- await Promise.all([...normalDispatcher.pending.values()].map((entry) => entry.promise));
208
- assert.deepEqual(normalExecuted, ['read']);
209
- });
210
-
211
- test('code graph descriptions partition file and symbol targets', () => {
212
- const description = CODE_GRAPH_TOOL_DEFS[0]?.description || '';
213
- const mode = CODE_GRAPH_TOOL_DEFS[0]?.inputSchema?.properties?.mode?.description || '';
214
- assert.match(mode, /file modes=\{overview,imports,dependents,related,impact\}.*symbols with files.*files\[\].*file outline/i);
215
- assert.match(mode, /symbol modes=\{find_symbol,symbol_search,search,references,callers,callees\}.*fileless symbols.*symbol_search keywords/i);
216
- assert.match(description, /exact identifiers.*find_symbol\/references\/callers\/callees.*keywords.*symbol_search\/search/i);
217
- assert.match(description, /IDs→graph; literal\/zero→grep/i);
218
- assert.match(description, /unsupported target arrays.*omitted.*never silently mixed/i);
219
- assert.match(CODE_GRAPH_TOOL_DEFS[0]?.inputSchema?.properties?.files?.description || '', /supported targets only/i);
220
- assert.match(CODE_GRAPH_TOOL_DEFS[0]?.inputSchema?.properties?.symbols?.description || '', /exact identifiers.*keywords/i);
221
- const grep = Object.fromEntries(BUILTIN_TOOLS.map((tool) => [tool.name, tool])).grep;
222
- assert.match(grep.description, /quoted\/non-identifier literal or regex→grep/i);
223
- assert.doesNotMatch(grep.inputSchema.properties.pattern.description, /code_graph/i);
224
- });
225
-
226
- test('retrieval schemas require their primary arguments and preserve region paths', () => {
227
- const byName = Object.fromEntries(BUILTIN_TOOLS.map((tool) => [tool.name, tool]));
228
- const read = byName.read.inputSchema;
229
- assert.deepEqual(read.required, ['path']);
230
- const region = read.properties.path.anyOf[1].items.anyOf[1];
231
- assert.deepEqual(region.required, ['path']);
232
- assert.deepEqual(byName.grep.inputSchema.anyOf, [{ required: ['pattern'] }, { required: ['glob'] }]);
233
- assert.deepEqual(byName.grep.inputSchema.properties.output_mode.enum, ['content_with_context', 'files_with_matches', 'count']);
234
- const grepSchema = byName.grep.inputSchema;
235
- const valid = (value) => grepSchema.anyOf.some((branch) => branch.required.every((key) => Object.hasOwn(value, key)));
236
- assert.equal(valid({ pattern: 'x' }), true);
237
- assert.equal(valid({ glob: '*.mjs' }), true);
238
- assert.equal(valid({}), false);
239
- });
240
-
241
- test('grep scopes do not masquerade as read regions', () => {
242
- const pattern = Object.fromEntries(BUILTIN_TOOLS.map((tool) => [tool.name, tool])).grep.inputSchema.properties.pattern.description;
243
- assert.match(pattern, /path\[\] batches verified scopes only/i);
244
- assert.match(pattern, /file\/span reads use read path\[\] regions/i);
245
- assert.doesNotMatch(pattern, /known files\/spans use path\[\]/i);
246
- });
247
-
248
- test('explore freezes returned facets and avoids re-location', () => {
249
- assert.match(EXPLORE_TOOL.description, /freezes the LOCATION only/i);
250
- assert.match(EXPLORE_TOOL.description, /read\/code_graph detail inspection is valid when content was not returned/i);
251
- assert.match(EXPLORE_TOOL.description, /never re-locate it/i);
252
- assert.match(EXPLORE_TOOL.description, /search only unresolved facets/i);
253
- const rule = readFileSync(new URL('../src/rules/shared/01-tool.md', import.meta.url), 'utf8');
254
- assert.match(rule, /freezes the LOCATION only[\s\S]*read or[\s\S]*code_graph detail inspection is valid[\s\S]*never re-locate it/i);
255
- assert.match(rule, /nonzero[\s\S]*content_with_context[\s\S]*result resolves[\s\S]*act directly/i);
256
- });
@@ -1,345 +0,0 @@
1
- #!/usr/bin/env node
2
- // Regression test for explore-tool wall-clock timeout + cancellation cleanup:
3
- // - the default hard timeout is 60s (was 10min) and the
4
- // MIXDOG_EXPLORE_HARD_TIMEOUT_MS override (including 0 = disabled) is kept;
5
- // - a parent cancellation aborts every child compute AbortSignal immediately;
6
- // - the wall-clock hard timeout aborts the compute AbortSignal (not just the
7
- // race), so wedged compute tears down instead of running detached;
8
- // - a canceled/timed-out compute purges its poisoned cache entry so a later
9
- // call never awaits a dead promise and empties into "no tool output".
10
- import test from 'node:test';
11
- import assert from 'node:assert/strict';
12
- import { execFileSync } from 'node:child_process';
13
- import { readFileSync } from 'node:fs';
14
- import {
15
- EXPLORE_COMPUTE_HARD_TIMEOUT_MS,
16
- runExploreComputeWithAbort,
17
- runExploreCached,
18
- runExplore,
19
- exploreStaggerDelay,
20
- awaitExploreProviderReadyOrCancel,
21
- ensureExploreProviderReady,
22
- __exploreResultCacheForTest,
23
- } from '../src/standalone/explore-tool.mjs';
24
-
25
- const MODULE_URL = new URL('../src/standalone/explore-tool.mjs', import.meta.url).href;
26
-
27
- // A compute stub that rejects the moment its AbortSignal fires (mirrors a real
28
- // child dispatch tearing down on abort), and handles the already-aborted case.
29
- function abortAwareCompute(record) {
30
- return (signal) => new Promise((_resolve, reject) => {
31
- record?.(signal);
32
- if (signal.aborted) { reject(signal.reason || new Error('aborted')); return; }
33
- signal.addEventListener('abort', () => reject(signal.reason || new Error('aborted')), { once: true });
34
- });
35
- }
36
-
37
- function readHardTimeoutWithEnv(value) {
38
- const code = `import(${JSON.stringify(MODULE_URL)}).then((m) => process.stdout.write(String(m.EXPLORE_COMPUTE_HARD_TIMEOUT_MS)))`;
39
- return execFileSync(process.execPath, ['--input-type=module', '-e', code], {
40
- env: { ...process.env, MIXDOG_EXPLORE_HARD_TIMEOUT_MS: value },
41
- encoding: 'utf8',
42
- }).trim();
43
- }
44
-
45
- // The production hard-timeout timer is unref()'d (must never keep the host
46
- // process alive). In an otherwise-idle test that relies on that timer firing,
47
- // hold a ref'd timer so the event loop stays alive until the assertion settles.
48
- function keepEventLoopAlive(ms = 5_000) {
49
- const t = setTimeout(() => {}, ms);
50
- return () => clearTimeout(t);
51
- }
52
-
53
- test('default explore hard timeout is 60 seconds', () => {
54
- // Only meaningful when the override is unset (the CI/default environment).
55
- if (process.env.MIXDOG_EXPLORE_HARD_TIMEOUT_MS == null) {
56
- assert.equal(EXPLORE_COMPUTE_HARD_TIMEOUT_MS, 60_000);
57
- }
58
- });
59
-
60
- test('MIXDOG_EXPLORE_HARD_TIMEOUT_MS override is preserved (including 0 = disabled)', () => {
61
- assert.equal(readHardTimeoutWithEnv('1234'), '1234');
62
- assert.equal(readHardTimeoutWithEnv('0'), '0');
63
- assert.equal(readHardTimeoutWithEnv('90000'), '90000');
64
- });
65
-
66
- test('hard timeout aborts the compute AbortSignal', async () => {
67
- const release = keepEventLoopAlive();
68
- try {
69
- let received = null;
70
- const p = runExploreComputeWithAbort((signal) => {
71
- received = signal;
72
- return new Promise(() => {}); // never settles on its own
73
- }, null, 25);
74
- await assert.rejects(p, /timed out/);
75
- assert.ok(received, 'compute received a signal');
76
- assert.equal(received.aborted, true);
77
- } finally {
78
- release();
79
- }
80
- });
81
-
82
- test('parent cancellation aborts every child compute immediately', async () => {
83
- const parent = new AbortController();
84
- const seen = [];
85
- const p1 = runExploreComputeWithAbort(abortAwareCompute((s) => seen.push(s)), parent.signal, 10_000);
86
- const p2 = runExploreComputeWithAbort(abortAwareCompute((s) => seen.push(s)), parent.signal, 10_000);
87
- parent.abort(new Error('user pressed ESC'));
88
- await assert.rejects(p1);
89
- await assert.rejects(p2);
90
- assert.equal(seen.length, 2);
91
- assert.ok(seen.every((s) => s.aborted), 'both child signals aborted');
92
- });
93
-
94
- test('an already-aborted parent signal aborts the compute up front', async () => {
95
- const parent = new AbortController();
96
- parent.abort(new Error('already canceled'));
97
- let received = null;
98
- const p = runExploreComputeWithAbort(abortAwareCompute((s) => { received = s; }), parent.signal, 10_000);
99
- await assert.rejects(p);
100
- assert.ok(received.aborted, 'compute signal was already aborted');
101
- });
102
-
103
- test('a canceled compute purges its poisoned cache entry', async () => {
104
- // Force the result cache on so the in-flight promise is stored.
105
- process.env.MIXDOG_EXPLORE_RESULT_CACHE = '1';
106
- const cache = __exploreResultCacheForTest();
107
- cache.clear();
108
- const key = 'explore-cancel-poison-key';
109
- const parent = new AbortController();
110
- const promise = runExploreCached(key, abortAwareCompute(), parent.signal);
111
- // Pending promise cached while the compute is in flight.
112
- assert.equal(cache.has(key), true);
113
- parent.abort(new Error('cancel'));
114
- await assert.rejects(promise);
115
- // The poisoned pending entry must be gone so a later call recomputes fresh
116
- // instead of awaiting the dead promise.
117
- assert.equal(cache.has(key), false);
118
- });
119
-
120
- test('a wedged never-resolving shared compute is purged by its real hard-timeout timer and recomputed', async () => {
121
- process.env.MIXDOG_EXPLORE_RESULT_CACHE = '1';
122
- const cache = __exploreResultCacheForTest();
123
- cache.clear();
124
- const key = 'shared-hard-timeout-wedged';
125
- const seen = [];
126
- let calls = 0;
127
- const neverResolves = (signal) => { calls += 1; seen.push(signal); return new Promise(() => {}); };
128
- const release = keepEventLoopAlive();
129
- try {
130
- await assert.rejects(runExploreCached(key, neverResolves, null, 25), /timed out/);
131
- assert.equal(seen[0].aborted, true, 'the timer aborted the actual wedged compute');
132
- assert.equal(cache.has(key), false, 'timed-out pending entry was purged');
133
- assert.equal(await runExploreCached(key, () => { calls += 1; return Promise.resolve('fresh'); }, null, 100), 'fresh');
134
- assert.equal(calls, 2, 'a later caller recomputes rather than reusing the rejected promise');
135
- } finally {
136
- release();
137
- }
138
- });
139
-
140
- // A compute whose settlement the test controls, recording the AbortSignal it
141
- // received so shared-compute teardown can be asserted.
142
- function deferredCompute() {
143
- const handle = { signal: null, resolve: null, reject: null };
144
- handle.fn = (signal) => new Promise((resolve, reject) => {
145
- handle.signal = signal;
146
- handle.resolve = resolve;
147
- handle.reject = reject;
148
- });
149
- return handle;
150
- }
151
-
152
- test('parent cancellation rejects immediately even for a non-cooperative compute', async () => {
153
- // The compute IGNORES its AbortSignal (never settles on abort). Cancellation
154
- // must still reject the returned promise right away — not hang until the
155
- // wall-clock hard timeout.
156
- const parent = new AbortController();
157
- const p = runExploreComputeWithAbort(() => new Promise(() => {}), parent.signal, 10_000);
158
- const t0 = Date.now();
159
- parent.abort(new Error('user pressed ESC'));
160
- await assert.rejects(p);
161
- assert.ok(Date.now() - t0 < 500, 'rejected promptly, not after the hard timeout');
162
- });
163
-
164
- test('never-resolving compute is torn down by the hard timeout (real cleanup)', async () => {
165
- const release = keepEventLoopAlive();
166
- try {
167
- let received = null;
168
- const p = runExploreComputeWithAbort((signal) => {
169
- received = signal;
170
- return new Promise(() => {}); // never resolves, never observes abort
171
- }, null, 30);
172
- await assert.rejects(p, /timed out/);
173
- assert.equal(received.aborted, true, 'compute signal aborted on timeout');
174
- } finally {
175
- release();
176
- }
177
- });
178
-
179
- test('owner cancellation does not abort an unaffected later subscriber', async () => {
180
- process.env.MIXDOG_EXPLORE_RESULT_CACHE = '1';
181
- const cache = __exploreResultCacheForTest();
182
- cache.clear();
183
- const key = 'shared-owner-cancel';
184
- const dc = deferredCompute();
185
- const owner = new AbortController();
186
- const later = new AbortController();
187
- const ownerP = runExploreCached(key, dc.fn, owner.signal); // starts shared compute
188
- const laterP = runExploreCached(key, dc.fn, later.signal); // subscribes to the same compute
189
- owner.abort(new Error('owner ESC'));
190
- await assert.rejects(ownerP);
191
- // The shared compute must keep running for the still-active later subscriber.
192
- assert.equal(dc.signal.aborted, false, 'shared compute not aborted by owner cancel');
193
- assert.equal(cache.has(key), true);
194
- dc.resolve('src/x.mjs:1 — shared hit');
195
- assert.match(String(await laterP), /src\/x\.mjs:1/);
196
- });
197
-
198
- test('later subscriber cancellation releases itself without aborting the shared compute', async () => {
199
- process.env.MIXDOG_EXPLORE_RESULT_CACHE = '1';
200
- const cache = __exploreResultCacheForTest();
201
- cache.clear();
202
- const key = 'shared-later-cancel';
203
- const dc = deferredCompute();
204
- const owner = new AbortController();
205
- const later = new AbortController();
206
- const ownerP = runExploreCached(key, dc.fn, owner.signal);
207
- const laterP = runExploreCached(key, dc.fn, later.signal);
208
- later.abort(new Error('later ESC'));
209
- await assert.rejects(laterP);
210
- assert.equal(dc.signal.aborted, false, 'owner still waiting; compute alive');
211
- assert.equal(cache.has(key), true);
212
- dc.resolve('src/y.mjs:2 — owner result');
213
- assert.match(String(await ownerP), /src\/y\.mjs:2/);
214
- });
215
-
216
- test('all subscribers canceling aborts the shared compute and purges the cache', async () => {
217
- process.env.MIXDOG_EXPLORE_RESULT_CACHE = '1';
218
- const cache = __exploreResultCacheForTest();
219
- cache.clear();
220
- const key = 'shared-all-cancel';
221
- const dc = deferredCompute();
222
- const a = new AbortController();
223
- const b = new AbortController();
224
- const pa = runExploreCached(key, dc.fn, a.signal);
225
- const pb = runExploreCached(key, dc.fn, b.signal);
226
- a.abort(new Error('a ESC'));
227
- await assert.rejects(pa);
228
- assert.equal(cache.has(key), true, 'b still subscribed; compute retained');
229
- assert.equal(dc.signal.aborted, false);
230
- b.abort(new Error('b ESC'));
231
- await assert.rejects(pb);
232
- assert.equal(dc.signal.aborted, true, 'last subscriber gone; shared compute torn down');
233
- assert.equal(cache.has(key), false, 'purged so a future call recomputes');
234
- });
235
-
236
- test('a failed shared compute is purged so future calls recompute', async () => {
237
- process.env.MIXDOG_EXPLORE_RESULT_CACHE = '1';
238
- const cache = __exploreResultCacheForTest();
239
- cache.clear();
240
- const key = 'shared-recompute';
241
- let calls = 0;
242
- const compute = () => { calls += 1; return Promise.reject(new Error(`owner fail ${calls}`)); };
243
- await assert.rejects(runExploreCached(key, compute, null));
244
- assert.equal(cache.has(key), false);
245
- await assert.rejects(runExploreCached(key, compute, null));
246
- assert.equal(calls, 2, 'recomputed rather than deduping on the dead promise');
247
- });
248
-
249
- test('stagger delay is canceled before dispatch when the signal aborts', async () => {
250
- const ctrl = new AbortController();
251
- let dispatched = false;
252
- const p = exploreStaggerDelay(10_000, ctrl.signal).then(() => { dispatched = true; return 'DISPATCHED'; });
253
- ctrl.abort(new Error('cancel during stagger'));
254
- await assert.rejects(p);
255
- assert.equal(dispatched, false, 'child dispatch skipped after the stagger was canceled');
256
- });
257
-
258
- test('runtime-core forwards the caller signal into runExplore (plumbing)', () => {
259
- const src = readFileSync(new URL('../src/session-runtime/runtime-core.mjs', import.meta.url), 'utf8');
260
- const at = src.indexOf("name === 'explore'");
261
- assert.ok(at >= 0, 'explore branch present in runtime-core');
262
- const branch = src.slice(at, at + 1000);
263
- assert.match(branch, /return await runExplore\(/);
264
- assert.match(branch, /signal:\s*callerCtx\?\.signal\s*\|\|\s*session\?\.controller\?\.signal/);
265
- });
266
-
267
- test('runExplore short-circuits an already-canceled call without dispatching', async () => {
268
- const ctrl = new AbortController();
269
- ctrl.abort(new Error('canceled up front'));
270
- const res = await runExplore({ query: 'anything at all' }, { signal: ctrl.signal });
271
- assert.equal(res.isError, true);
272
- assert.match(res.content?.[0]?.text || '', /cancel/i);
273
- });
274
-
275
- test('explore provider warmup is canceled immediately when the caller aborts mid-init', async () => {
276
- const ctrl = new AbortController();
277
- const ready = new Promise(() => {}); // warmup wedged (never resolves)
278
- const t0 = Date.now();
279
- const p = awaitExploreProviderReadyOrCancel(ready, ctrl.signal);
280
- ctrl.abort(new Error('ESC during warmup'));
281
- const canceled = await p;
282
- assert.equal(canceled, true, 'reported canceled without waiting for warmup');
283
- assert.ok(Date.now() - t0 < 500, 'returned promptly, did not block on warmup');
284
- });
285
-
286
- test('explore provider warmup aborts the real pending initializer work', async () => {
287
- const ctrl = new AbortController();
288
- let initializerAborted = false;
289
- const pendingInit = (_providers, { signal }) => new Promise((_resolve, reject) => {
290
- signal.addEventListener('abort', () => {
291
- initializerAborted = true;
292
- reject(signal.reason);
293
- }, { once: true });
294
- });
295
- const ready = ensureExploreProviderReady({ providers: { fake: { enabled: true } } }, { provider: 'fake' }, ctrl.signal, pendingInit);
296
- const waited = awaitExploreProviderReadyOrCancel(ready, ctrl.signal);
297
- ctrl.abort(new Error('ESC during provider init'));
298
- assert.equal(await waited, true);
299
- assert.equal(initializerAborted, true, 'AbortSignal reached the pending initializer');
300
- });
301
-
302
- test('explore provider warmup resolves to not-canceled when the caller stays active', async () => {
303
- const canceled = await awaitExploreProviderReadyOrCancel(Promise.resolve(), new AbortController().signal);
304
- assert.equal(canceled, false, 'ready to dispatch');
305
- });
306
-
307
- test('explore provider warmup short-circuits an already-aborted caller before awaiting init', async () => {
308
- const ctrl = new AbortController();
309
- ctrl.abort(new Error('already canceled'));
310
- let awaited = false;
311
- const ready = Promise.resolve().then(() => { awaited = true; });
312
- const canceled = await awaitExploreProviderReadyOrCancel(ready, ctrl.signal);
313
- assert.equal(canceled, true, 'canceled without blocking on the warmup promise');
314
- });
315
-
316
- test('explore provider warmup propagates a genuine init failure (not a cancel)', async () => {
317
- const ctrl = new AbortController(); // never aborted
318
- const ready = Promise.reject(new Error('provider init failed'));
319
- await assert.rejects(awaitExploreProviderReadyOrCancel(ready, ctrl.signal), /init failed/);
320
- });
321
-
322
- test('a retired shared compute success write is identity-guarded (no stale overwrite)', async () => {
323
- process.env.MIXDOG_EXPLORE_RESULT_CACHE = '1';
324
- const cache = __exploreResultCacheForTest();
325
- cache.clear();
326
- const key = 'identity-guard-success';
327
- const dc = deferredCompute();
328
- const p = runExploreCached(key, dc.fn, null);
329
- p.catch(() => {});
330
- // The compute executor runs on a microtask; let it install dc.resolve.
331
- await new Promise((r) => setTimeout(r, 0));
332
- const oldEntry = cache.get(key);
333
- assert.ok(oldEntry?.promise, 'pending entry stored');
334
- assert.equal(typeof dc.resolve, 'function', 'compute executor ran');
335
- // Simulate the entry having been retired + replaced by a fresh one (e.g. a
336
- // TTL eviction/recompute) WITHOUT touching the old in-flight compute.
337
- const freshEntry = { ts: Date.now(), value: undefined, sentinel: true };
338
- cache.set(key, freshEntry);
339
- // The OLD compute now resolves successfully — its success handler must NOT
340
- // overwrite the fresh entry (identity guard on every eventual write).
341
- dc.resolve('src/stale.mjs:1 — retired winner');
342
- await p;
343
- await new Promise((r) => setTimeout(r, 0)); // flush the success microtask
344
- assert.equal(cache.get(key), freshEntry, 'retired success write was identity-guarded');
345
- });