mixdog 0.9.63 → 0.9.65

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 (408) 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/turn-snapshot.mjs +184 -0
  187. package/src/runtime/shared/update-checker.mjs +1 -1
  188. package/src/runtime/shared/user-cwd.mjs +3 -3
  189. package/src/runtime/shared/user-data-guard.mjs +4 -4
  190. package/src/runtime/shared/workspace-router.mjs +5 -5
  191. package/src/session-runtime/config-helpers.mjs +2 -3
  192. package/src/session-runtime/config-lifecycle.mjs +1 -1
  193. package/src/session-runtime/hitch-profile.mjs +1 -1
  194. package/src/session-runtime/lifecycle-api.mjs +6 -4
  195. package/src/session-runtime/model-recency.mjs +5 -5
  196. package/src/session-runtime/plugin-mcp.mjs +1 -1
  197. package/src/session-runtime/provider-request-snapshot.mjs +338 -0
  198. package/src/session-runtime/runtime-core.mjs +4 -0
  199. package/src/session-runtime/session-text.mjs +4 -4
  200. package/src/session-runtime/session-turn-api.mjs +7 -0
  201. package/src/session-runtime/tool-catalog-schema.mjs +197 -0
  202. package/src/session-runtime/tool-catalog.mjs +6 -483
  203. package/src/session-runtime/tool-defs.mjs +1 -1
  204. package/src/standalone/agent-task-status.mjs +1 -1
  205. package/src/standalone/agent-tool/helpers.mjs +2 -2
  206. package/src/standalone/channel-admin.mjs +4 -4
  207. package/src/standalone/explore-tool.mjs +3 -3
  208. package/src/standalone/hook-bus/config.mjs +1 -1
  209. package/src/standalone/hook-bus/constants.mjs +1 -1
  210. package/src/standalone/hook-bus/rules.mjs +1 -1
  211. package/src/standalone/projects.mjs +1 -1
  212. package/src/standalone/provider-admin.mjs +2 -2
  213. package/src/tui/App.jsx +1 -1
  214. package/src/tui/app/app-format.mjs +2 -2
  215. package/src/tui/app/clipboard.mjs +3 -3
  216. package/src/tui/app/input-parsers.mjs +1 -1
  217. package/src/tui/app/text-layout.mjs +1 -1
  218. package/src/tui/app/transcript-row-estimate.mjs +360 -0
  219. package/src/tui/app/transcript-window.mjs +5 -347
  220. package/src/tui/app/use-mouse-input.mjs +1 -1
  221. package/src/tui/app/use-prompt-handlers.mjs +1 -1
  222. package/src/tui/components/tool-execution/surface-detail.mjs +9 -9
  223. package/src/tui/components/tool-execution/text-format.mjs +2 -2
  224. package/src/tui/components/tool-output-format.mjs +7 -7
  225. package/src/tui/display-width.mjs +4 -4
  226. package/src/tui/dist/index.mjs +187 -99
  227. package/src/tui/engine/agent-envelope.mjs +5 -5
  228. package/src/tui/engine/live-share.mjs +100 -0
  229. package/src/tui/engine/notification-plan.mjs +1 -1
  230. package/src/tui/engine/queue-helpers.mjs +3 -3
  231. package/src/tui/engine/render-timing.mjs +4 -5
  232. package/src/tui/engine/session-api-ext.mjs +6 -3
  233. package/src/tui/engine/tool-result-status.mjs +5 -5
  234. package/src/tui/engine/tool-result-text.mjs +1 -1
  235. package/src/tui/engine/transcript-spill.mjs +585 -0
  236. package/src/tui/engine/tui-steering-persist.mjs +1 -1
  237. package/src/tui/engine.mjs +29 -474
  238. package/src/tui/lib/voice-setup.mjs +1 -1
  239. package/src/tui/markdown/format-token.mjs +1 -1
  240. package/src/tui/markdown/render-ansi.mjs +1 -1
  241. package/src/tui/markdown/table-layout.mjs +4 -4
  242. package/src/tui/paste-attachments.mjs +1 -1
  243. package/src/tui/prompt-history-store.mjs +3 -3
  244. package/src/tui/statusline-ansi-bridge.mjs +2 -2
  245. package/src/tui/theme.mjs +1 -1
  246. package/src/tui/transcript-tool-failures.mjs +2 -2
  247. package/src/ui/ansi.mjs +0 -9
  248. package/src/ui/statusline-format.mjs +2 -4
  249. package/scripts/_bench-cwc.json +0 -20
  250. package/scripts/_jitter-fuzz.jsx +0 -42
  251. package/scripts/_jitter-fuzz2.jsx +0 -30
  252. package/scripts/_jitter-probe.jsx +0 -35
  253. package/scripts/_jp2.jsx +0 -16
  254. package/scripts/_smoke_wd.mjs +0 -7
  255. package/scripts/abort-recovery-test.mjs +0 -175
  256. package/scripts/agent-dispatch-abort-compose-test.mjs +0 -31
  257. package/scripts/agent-live-arg-guard-smoke.mjs +0 -20
  258. package/scripts/agent-live-path-suffix-smoke.mjs +0 -34
  259. package/scripts/agent-live-toolcall-args-smoke.mjs +0 -45
  260. package/scripts/agent-loop-policy-test.mjs +0 -37
  261. package/scripts/agent-model-liveness-test.mjs +0 -763
  262. package/scripts/agent-parallel-smoke.mjs +0 -435
  263. package/scripts/agent-route-batch-test.mjs +0 -40
  264. package/scripts/agent-tag-reuse-smoke.mjs +0 -441
  265. package/scripts/agent-terminal-reap-test.mjs +0 -252
  266. package/scripts/agent-trace-io-test.mjs +0 -133
  267. package/scripts/ansi-color-capability-test.mjs +0 -90
  268. package/scripts/anthropic-admission-retry-integration-test.mjs +0 -119
  269. package/scripts/anthropic-maxtokens-test.mjs +0 -119
  270. package/scripts/anthropic-oauth-refresh-race-test.mjs +0 -397
  271. package/scripts/anthropic-transport-policy-test.mjs +0 -726
  272. package/scripts/apply-patch-edit-smoke.mjs +0 -71
  273. package/scripts/arg-guard-test.mjs +0 -93
  274. package/scripts/async-notify-settlement-test.mjs +0 -99
  275. package/scripts/atomic-lock-tryonce-test.mjs +0 -125
  276. package/scripts/background-task-meta-smoke.mjs +0 -38
  277. package/scripts/bench-run.mjs +0 -508
  278. package/scripts/boot-smoke.mjs +0 -137
  279. package/scripts/build-runtime-windows.ps1 +0 -242
  280. package/scripts/channel-daemon-smoke.mjs +0 -1103
  281. package/scripts/code-graph-aggregate-cwd-test.mjs +0 -158
  282. package/scripts/code-graph-disk-hit-test.mjs +0 -290
  283. package/scripts/code-graph-dispatch-test.mjs +0 -96
  284. package/scripts/code-graph-root-federation-test.mjs +0 -273
  285. package/scripts/compact-active-turn-test.mjs +0 -68
  286. package/scripts/compact-file-reattach-test.mjs +0 -88
  287. package/scripts/compact-pressure-test.mjs +0 -788
  288. package/scripts/compact-prior-context-flatten-test.mjs +0 -252
  289. package/scripts/compact-recall-digest-test.mjs +0 -57
  290. package/scripts/compact-smoke.mjs +0 -1017
  291. package/scripts/compact-trigger-migration-smoke.mjs +0 -261
  292. package/scripts/compacted-placeholder-scrub-test.mjs +0 -63
  293. package/scripts/context-mcp-metering-test.mjs +0 -1406
  294. package/scripts/debounced-skills-async-save-test.mjs +0 -57
  295. package/scripts/deferred-tool-loading-test.mjs +0 -250
  296. package/scripts/desktop-session-bridge-test.mjs +0 -1013
  297. package/scripts/dispatch-persist-recovery-test.mjs +0 -141
  298. package/scripts/embedding-worker-exit-test.mjs +0 -76
  299. package/scripts/execution-completion-dedup-test.mjs +0 -205
  300. package/scripts/execution-pending-resume-kick-test.mjs +0 -151
  301. package/scripts/execution-resume-esc-integration-test.mjs +0 -176
  302. package/scripts/explore-bench-tmp.mjs +0 -36
  303. package/scripts/explore-bench.mjs +0 -248
  304. package/scripts/explore-prompt-policy-test.mjs +0 -256
  305. package/scripts/explore-timeout-cancel-test.mjs +0 -345
  306. package/scripts/find-fuzzy-hidden-test.mjs +0 -267
  307. package/scripts/forwarder-rebind-tail-test.mjs +0 -67
  308. package/scripts/freevar-smoke.mjs +0 -98
  309. package/scripts/gemini-provider-test.mjs +0 -1448
  310. package/scripts/generate-oc-icons.mjs +0 -11
  311. package/scripts/grok-oauth-refresh-race-test.mjs +0 -273
  312. package/scripts/headless-pristine-execution-test.mjs +0 -614
  313. package/scripts/hook-bus-test.mjs +0 -552
  314. package/scripts/ingest-pure-conversation-smoke.mjs +0 -175
  315. package/scripts/internal-comms-bench-test.mjs +0 -226
  316. package/scripts/internal-comms-bench.mjs +0 -853
  317. package/scripts/internal-comms-smoke.mjs +0 -277
  318. package/scripts/internal-tools-normalization-test.mjs +0 -62
  319. package/scripts/interrupted-turn-history-test.mjs +0 -399
  320. package/scripts/lead-workflow-smoke.mjs +0 -592
  321. package/scripts/lifecycle-api-test.mjs +0 -137
  322. package/scripts/live-share-test.mjs +0 -148
  323. package/scripts/live-worker-smoke.mjs +0 -333
  324. package/scripts/log-writer-guard-smoke.mjs +0 -131
  325. package/scripts/maintenance-default-routes-test.mjs +0 -164
  326. package/scripts/max-output-recovery-persist-test.mjs +0 -81
  327. package/scripts/max-output-recovery-test.mjs +0 -368
  328. package/scripts/mcp-client-normalization-test.mjs +0 -45
  329. package/scripts/mcp-grace-deferred-test.mjs +0 -225
  330. package/scripts/memory-core-input-test.mjs +0 -167
  331. package/scripts/memory-cycle-routing-test.mjs +0 -111
  332. package/scripts/memory-meta-concurrency-test.mjs +0 -20
  333. package/scripts/memory-pg-recovery-test.mjs +0 -59
  334. package/scripts/memory-rule-contract-test.mjs +0 -93
  335. package/scripts/model-list-sanitize-test.mjs +0 -37
  336. package/scripts/mouse-tracking-restore-smoke.mjs +0 -107
  337. package/scripts/native-edit-wire-test.mjs +0 -152
  338. package/scripts/notify-completion-mirror-test.mjs +0 -73
  339. package/scripts/openai-oauth-refresh-race-test.mjs +0 -120
  340. package/scripts/openai-oauth-ws-1006-retry-test.mjs +0 -954
  341. package/scripts/openai-ws-early-settle-test.mjs +0 -216
  342. package/scripts/output-style-bench.mjs +0 -292
  343. package/scripts/output-style-smoke.mjs +0 -145
  344. package/scripts/parent-abort-link-test.mjs +0 -90
  345. package/scripts/patch-binary-cache-test.mjs +0 -181
  346. package/scripts/path-suffix-test.mjs +0 -57
  347. package/scripts/pending-completion-drop-test.mjs +0 -239
  348. package/scripts/pending-messages-lock-nonblocking-test.mjs +0 -62
  349. package/scripts/pretool-ask-runtime-test.mjs +0 -54
  350. package/scripts/process-lifecycle-test.mjs +0 -461
  351. package/scripts/prompt-immediate-render-test.mjs +0 -89
  352. package/scripts/prompt-input-parity-test.mjs +0 -145
  353. package/scripts/provider-admission-scheduler-test.mjs +0 -681
  354. package/scripts/provider-contract-test.mjs +0 -632
  355. package/scripts/provider-stream-stall-test.mjs +0 -276
  356. package/scripts/provider-toolcall-test.mjs +0 -3063
  357. package/scripts/reactive-compact-persist-smoke.mjs +0 -203
  358. package/scripts/recall-bench.mjs +0 -359
  359. package/scripts/resource-admission-test.mjs +0 -792
  360. package/scripts/result-classification-test.mjs +0 -75
  361. package/scripts/rg-runner-test.mjs +0 -240
  362. package/scripts/routing-corpus-test.mjs +0 -349
  363. package/scripts/sanitize-tool-pairs-test.mjs +0 -260
  364. package/scripts/session-bench-cache-break-test.mjs +0 -102
  365. package/scripts/session-bench.mjs +0 -1708
  366. package/scripts/session-context-bench.mjs +0 -344
  367. package/scripts/session-heartbeat-lifecycle-test.mjs +0 -68
  368. package/scripts/session-ingest-compaction-smoke.mjs +0 -279
  369. package/scripts/session-ingest-smoke.mjs +0 -177
  370. package/scripts/session-orphan-sweep-test.mjs +0 -109
  371. package/scripts/set-effort-config-test.mjs +0 -41
  372. package/scripts/shell-failure-diagnostics-test.mjs +0 -280
  373. package/scripts/shell-hardening-test.mjs +0 -209
  374. package/scripts/shell-jobs-windows-hide-test.mjs +0 -164
  375. package/scripts/ship-mode-test.mjs +0 -98
  376. package/scripts/smoke-loop-failure-summary-test.mjs +0 -38
  377. package/scripts/smoke-loop-failure-summary.mjs +0 -16
  378. package/scripts/smoke-loop-report.mjs +0 -221
  379. package/scripts/smoke-loop.mjs +0 -202
  380. package/scripts/smoke-runtime-negative.ps1 +0 -106
  381. package/scripts/statusline-quota-hysteresis-test.mjs +0 -62
  382. package/scripts/steering-drain-buckets-test.mjs +0 -467
  383. package/scripts/steering-fold-provenance-test.mjs +0 -71
  384. package/scripts/streaming-tail-window-test.mjs +0 -175
  385. package/scripts/submit-commandbusy-race-test.mjs +0 -257
  386. package/scripts/task-bench.mjs +0 -205
  387. package/scripts/terminal-bench-isolation-guards-test.mjs +0 -102
  388. package/scripts/termio-input-smoke.mjs +0 -199
  389. package/scripts/tool-result-hook-test.mjs +0 -48
  390. package/scripts/tool-smoke.mjs +0 -2453
  391. package/scripts/tool-tui-presentation-test.mjs +0 -286
  392. package/scripts/toolcall-args-test.mjs +0 -239
  393. package/scripts/tui-ambiguous-width-test.mjs +0 -113
  394. package/scripts/tui-background-failure-smoke.mjs +0 -73
  395. package/scripts/tui-perf-run.ps1 +0 -26
  396. package/scripts/tui-render-smoke.mjs +0 -90
  397. package/scripts/tui-runtime-load-bench-entry.jsx +0 -608
  398. package/scripts/tui-runtime-load-bench.mjs +0 -50
  399. package/scripts/tui-store-frame-batch-test.mjs +0 -99
  400. package/scripts/tui-transcript-jitter-harness-entry.jsx +0 -383
  401. package/scripts/tui-transcript-perf-test.mjs +0 -934
  402. package/scripts/usage-metrics-epoch-smoke.mjs +0 -114
  403. package/scripts/verify-release-assets-test.mjs +0 -281
  404. package/scripts/web-fetch-routing-test.mjs +0 -158
  405. package/scripts/webhook-smoke.mjs +0 -201
  406. package/scripts/windows-hide-spawn-options-test.mjs +0 -19
  407. package/scripts/worker-notify-rejection-test.mjs +0 -51
  408. package/scripts/write-backpressure-test.mjs +0 -147
@@ -18,6 +18,7 @@ import {
18
18
  getBackgroundTask,
19
19
  } from '../../../../shared/background-tasks.mjs';
20
20
  import { startChildGuardian } from '../../../../shared/child-guardian.mjs';
21
+ import { _startBackgroundShellJobImpl } from './shell-job-spawn.mjs';
21
22
  import { detachedSpawnOpts } from '../../../../shared/spawn-flags.mjs';
22
23
  import {
23
24
  getShellJobsDir,
@@ -133,7 +134,7 @@ export function killShellJob(jobId) {
133
134
  return { ...attachJobInsights(detail), killed: true };
134
135
  }
135
136
 
136
- function refreshShellJob(jobId) {
137
+ export function refreshShellJob(jobId) {
137
138
  const detail = readShellJobDetail(jobId);
138
139
  if (!detail) return null;
139
140
  if (detail.status !== 'running') return detail;
@@ -239,7 +240,7 @@ const SHELL_JOB_WATCH_GRACE_MS = 5000;
239
240
  // and fire immediately. The resolved timeout is already clamped at parse time
240
241
  // (bash-tool.mjs TIMER_MAX_MS), but sites that add grace to it can still exceed
241
242
  // the ceiling, so clamp the summed delay here too.
242
- const TIMER_MAX_MS = 2_147_483_647;
243
+ export const TIMER_MAX_MS = 2_147_483_647;
243
244
  // Registry of armed background-job watchers keyed by jobId. task wait
244
245
  // and `kill` actions already hold the completed outcome, so they cancel the
245
246
  // armed watcher here to prevent a double-notify when its next poll fires.
@@ -292,7 +293,7 @@ export function attachShellJobResourceLease(jobId, lease, { allowUnpersisted = f
292
293
  shellJobResourceLeases.set(jobId, lease);
293
294
  return true;
294
295
  }
295
- function releaseShellJobOwnershipWhenQuiescent(jobId, pid, {
296
+ export function releaseShellJobOwnershipWhenQuiescent(jobId, pid, {
296
297
  onConfirmed = null,
297
298
  allowLateLease = false,
298
299
  deferUntilRootExit = false,
@@ -324,7 +325,7 @@ function releaseShellJobOwnershipWhenQuiescent(jobId, pid, {
324
325
  }, { waitForRootExit: deferUntilRootExit });
325
326
  return true;
326
327
  }
327
- function trackChildUntilConfirmedExit(child, jobId, onConfirmed = null) {
328
+ export function trackChildUntilConfirmedExit(child, jobId, onConfirmed = null) {
328
329
  const pid = Number(child?.pid);
329
330
  if (!Number.isFinite(pid) || pid <= 0) return false;
330
331
  _installShellJobsExitHook();
@@ -752,448 +753,3 @@ function _armAdoptedJobCapPoll(jobId) {
752
753
  if (typeof tick.unref === 'function') tick.unref();
753
754
  return tick;
754
755
  }
755
-
756
- async function _startBackgroundShellJobImpl({
757
- command, timeoutMs, workDir, mergeStderr, spawnEnv, shell, shellArg, shellArgs,
758
- shellType, clientHostPid, spawnFn = spawn, writeDetailFn = writeShellJobDetail,
759
- rollbackTimeoutMs = 5000,
760
- }) {
761
- // Route ANY PowerShell shell to the PS wrapper, regardless of platform.
762
- // Gating on win32 sent shell:'powershell' on macOS/Linux down the POSIX
763
- // path below, which spawns `pwsh <wrapper>.sh` — pwsh then tries to run a
764
- // bash script. isPowerShellShell already matches pwsh/powershell by stem.
765
- if (isPowerShellShell(shell, shellType)) {
766
- return startBackgroundPowerShellJob({
767
- command, timeoutMs, workDir, mergeStderr, spawnEnv, shell, clientHostPid,
768
- spawnFn, writeDetailFn,
769
- });
770
- }
771
-
772
- // POSIX-shell wrapper path. On Windows this runs for shell:'bash' (Git
773
- // Bash): the previous hard rejection here was a policy choice, NOT a real
774
- // invariant — every piece of this path's plumbing is shell-neutral.
775
- // The wrapper uses `command -v timeout`, `if ... fi`, single-quote escape
776
- // and POSIX exit-code propagation, all of which Git Bash executes; output
777
- // and exit-code plumbing flows through the staged script's own
778
- // `exec > … 2> …` redirect plus `printf … > exitPath` / `touch donePath`
779
- // (filesystem ops, not shell features); and kill goes through
780
- // killProcessTree(), which on win32 uses `taskkill /pid /t /f` regardless
781
- // of which shell spawned the tree. So Git Bash background tasks cancel,
782
- // capture output, and report exit codes correctly.
783
- const jobId = `job_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
784
- const stdoutPath = shellJobStdoutPath(jobId);
785
- const stderrPath = shellJobStderrPath(jobId);
786
- const exitPath = shellJobExitPath(jobId);
787
- const donePath = shellJobDonePath(jobId);
788
- // timeoutMs <= 0 means unlimited (async omitted default): no kernel
789
- // `timeout` wrapper, no enforced marker — exec the inner shell directly.
790
- const enforceTimeout = Number(timeoutMs) > 0;
791
- const timeoutSeconds = enforceTimeout ? Math.max(1, Math.ceil(timeoutMs / 1000)) : 0;
792
- // P2 fix: wrap with POSIX `timeout` so the kernel terminates the process
793
- // at deadline even if the JS-side timer is interrupted. --preserve-status
794
- // keeps the user command's exit code on success; on timeout the wrapper
795
- // exits 124.
796
- // `timeout` ships with GNU coreutils on Linux. On macOS, Homebrew
797
- // coreutils installs it as `gtimeout` (the un-prefixed name is NOT created
798
- // by default), so the wrapper picks `timeout` if present else `gtimeout`.
799
- // When neither exists it falls through to the inner command (the parent
800
- // setTimeout still calls refreshShellJob to clean up).
801
- const userCmdQuoted = shellQuoteSingle(command);
802
- // P2 fix: invoke the resolved shell (not bash -c) so zsh / dash /
803
- // alternate shells run snapshot-aware commands correctly. Drop
804
- // --preserve-status so timeout returns 124 unambiguously, making
805
- // it trivial to distinguish a timeout (124) from a user-side
806
- // SIGTERM exit (143).
807
- const innerShellQ = shellQuoteSingle(shell);
808
- const innerArgs = Array.isArray(shellArgs) && shellArgs.length > 0 ? shellArgs : [shellArg];
809
- const innerArgsQ = innerArgs.filter((arg) => arg != null && String(arg).length > 0).map(shellQuoteSingle).join(' ');
810
- // Runtime enforcement proof: the wrapper touches <jobId>.enforced right
811
- // before exec'ing `timeout`, so the marker exists iff the timeout branch
812
- // actually ran under the wrapper's own env/cwd. A spawn-time probe can't
813
- // guarantee that (env is scrubbed, cwd differs) — see shellJobEnforcedPath.
814
- const enforcedPath = shellJobEnforcedPath(jobId);
815
- // Lifecycle ordering invariant: write the exit-code file FIRST and
816
- // `touch donePath` strictly AFTER. refreshShellJob() gates completion
817
- // on donePath existence and only then trusts the exit file — without
818
- // this strict ordering, readFileSync on a partially-flushed exit file
819
- // returned '' -> parseInt NaN -> exitCode null -> spurious 'failed'
820
- // status for processes that actually exited 0. `rm -- "$0"` removes
821
- // the staged wrapper .cmd.sh after donePath is published so a host
822
- // crash before this point still leaves the file for the sweep to GC.
823
- const _innerRun = `${innerShellQ} ${innerArgsQ} ${userCmdQuoted}`;
824
- const _execPart = enforceTimeout
825
- ? `if command -v timeout >/dev/null 2>&1; then _to=timeout; elif command -v gtimeout >/dev/null 2>&1; then _to=gtimeout; else _to=; fi; if [ -n "$_to" ]; then touch ${shellQuoteSingle(enforcedPath)}; "$_to" ${timeoutSeconds} ${_innerRun}; else ${_innerRun}; fi`
826
- : _innerRun;
827
- const wrapped = `{ ${_execPart}; rc=$?; printf '%s' "$rc" > ${shellQuoteSingle(exitPath)}; touch ${shellQuoteSingle(donePath)}; rm -- "$0" 2>/dev/null; exit $rc; }`;
828
- // Stage the wrapped command to a .sh and let the script open its own
829
- // output files via `exec > … 2> …`. The parent does NOT pass file
830
- // descriptors via stdio inheritance (`stdio: 'ignore'` for all three).
831
- //
832
- // Let the shell own redirects via `exec > ... 2> ...` inside the staged
833
- // script. The child remains referenced by this CLI process; detached here
834
- // is only used on POSIX to create a process group for tree-kill.
835
- const outRedirect = mergeStderr
836
- ? `> ${shellQuoteSingle(stdoutPath)} 2>&1`
837
- : `> ${shellQuoteSingle(stdoutPath)} 2> ${shellQuoteSingle(stderrPath)}`;
838
- const scriptBody = `#!/usr/bin/env bash\nexec ${outRedirect}\n${wrapped}\n`;
839
- const wrappedTempPath = `${exitPath}.cmd.sh`;
840
- try {
841
- writeFileSync(wrappedTempPath, scriptBody);
842
- } catch (e) {
843
- return { jobId, kind: 'bash', status: 'failed', error: `failed to stage shell background task: ${e?.message || e}` };
844
- }
845
- // R11: scrub loader/execution vars even though bash-tool.mjs already
846
- // scrubs upstream — defense-in-depth at the spawn site catches future
847
- // callers that build their own spawnEnv.
848
- let child;
849
- try {
850
- child = spawnFn(shell, [wrappedTempPath], {
851
- cwd: workDir,
852
- env: scrubLoaderVars(scrubProviderSecrets({ ...spawnEnv })),
853
- stdio: 'ignore',
854
- ...detachedSpawnOpts,
855
- });
856
- await awaitSpawnReady(child, 'POSIX background task');
857
- } catch (e) {
858
- try { unlinkSync(wrappedTempPath); } catch {}
859
- return { jobId, kind: 'bash', status: 'failed', error: `failed to spawn shell background task: ${e?.message || e}` };
860
- }
861
- const detail = {
862
- jobId,
863
- kind: 'bash',
864
- status: 'running',
865
- command,
866
- cwd: workDir,
867
- pid: child.pid,
868
- mergeStderr,
869
- timeoutMs,
870
- timeoutSeconds,
871
- stdoutPath,
872
- stderrPath: mergeStderr ? stdoutPath : stderrPath,
873
- exitPath,
874
- donePath,
875
- // Per-terminal session stamp (see resolveJobOwnerHostPid).
876
- ownerHostPid: resolveJobOwnerHostPid(clientHostPid),
877
- startedAt: new Date().toISOString(),
878
- };
879
- let terminal = false;
880
- let runtimeOwned = false;
881
- const onRuntimeError = (error) => {
882
- if (terminal) return;
883
- terminal = true;
884
- detail.status = 'failed';
885
- detail.terminationPending = true;
886
- detail.error = `shell background task process error: ${error?.message || error}`;
887
- detail.finishedAt = new Date().toISOString();
888
- try { writeDetailFn(detail); } catch {}
889
- if (runtimeOwned) void (async () => {
890
- const rollback = await rollbackSpawnedChild(child, { timeoutMs: rollbackTimeoutMs });
891
- if (rollback.confirmed) {
892
- releaseShellJobOwnershipWhenQuiescent(jobId, child.pid, {
893
- onConfirmed: () => {
894
- detail.terminationPending = false;
895
- try { writeDetailFn(detail); } catch {}
896
- },
897
- });
898
- } else {
899
- detail.error += `; termination unconfirmed after ${rollbackTimeoutMs}ms (process remains tracked)`;
900
- try { writeDetailFn(detail); } catch {}
901
- trackChildUntilConfirmedExit(child, jobId, () => {
902
- detail.terminationPending = false;
903
- try { writeDetailFn(detail); } catch {}
904
- });
905
- }
906
- })();
907
- };
908
- adoptSpawnErrorHandler(child, onRuntimeError);
909
- if (terminal) {
910
- const rollback = await rollbackSpawnedChild(child, { timeoutMs: rollbackTimeoutMs });
911
- detail.terminationPending = !rollback.confirmed;
912
- try { writeDetailFn(detail); } catch {}
913
- try { unlinkSync(wrappedTempPath); } catch {}
914
- return rollback.confirmed
915
- ? detail
916
- : {
917
- ...detail,
918
- rollbackPending: trackChildUntilConfirmedExit(child, jobId, () => {
919
- detail.terminationPending = false;
920
- try { writeDetailFn(detail); } catch {}
921
- }),
922
- error: `${detail.error}; termination unconfirmed after ${rollbackTimeoutMs}ms (process remains tracked)`,
923
- };
924
- }
925
- try {
926
- writeDetailFn(detail);
927
- } catch (e) {
928
- terminal = true;
929
- const rollback = await rollbackSpawnedChild(child, { timeoutMs: rollbackTimeoutMs });
930
- child.removeListener('error', onRuntimeError);
931
- discardSpawnErrorGuard(child);
932
- try { unlinkSync(wrappedTempPath); } catch {}
933
- const failure = { jobId, kind: 'bash', status: 'failed', error: `failed to persist shell background task: ${e?.message || e}` };
934
- if (!rollback.confirmed) {
935
- failure.rollbackPending = trackChildUntilConfirmedExit(child, jobId);
936
- failure.error += `; termination unconfirmed after ${rollbackTimeoutMs}ms (process remains tracked)`;
937
- }
938
- return failure;
939
- }
940
- startChildGuardian({
941
- childPid: child.pid,
942
- childGroupPid: child.pid,
943
- label: 'shell-job',
944
- });
945
- _installShellJobsExitHook();
946
- _registerLiveJobPid(child.pid, jobId);
947
- runtimeOwned = true;
948
- releaseShellJobOwnershipWhenQuiescent(jobId, child.pid, {
949
- allowLateLease: true,
950
- deferUntilRootExit: true,
951
- });
952
- // Deadline cleanup poke only when a timeout is enforced; an unlimited
953
- // (timeoutMs<=0) job has no deadline — completion is observed via the
954
- // fs.watch/poll watcher and refreshShellJob on task queries.
955
- if (enforceTimeout) {
956
- const timer = setTimeout(() => { refreshShellJob(jobId); }, Math.min(TIMER_MAX_MS, timeoutMs + 25));
957
- if (typeof timer.unref === 'function') timer.unref();
958
- }
959
- return detail;
960
- }
961
-
962
- async function startBackgroundPowerShellJob({
963
- command, timeoutMs, workDir, mergeStderr, spawnEnv, shell, clientHostPid,
964
- spawnFn = spawn, writeDetailFn = writeShellJobDetail, rollbackTimeoutMs = 5000,
965
- }) {
966
- const jobId = `job_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
967
- const stdoutPath = shellJobStdoutPath(jobId);
968
- const rawStderrPath = shellJobStderrPath(jobId);
969
- const exitPath = shellJobExitPath(jobId);
970
- const donePath = shellJobDonePath(jobId);
971
- const wrappedTempPath = `${exitPath}.cmd.ps1`;
972
- // Stage the USER command as its own .ps1 and run it via `-File` instead of
973
- // `-EncodedCommand <base64>`: the base64 token landed on the grandchild's
974
- // visible command line, which is a prime Defender obfuscation signature
975
- // (same family as the PowhidSubExec false positive). A file path on the
976
- // command line carries no such signature, and the payload stays opaque to
977
- // outer-shell quoting exactly as base64 did. UTF-8 BOM so Windows
978
- // PowerShell 5.1 doesn't misread non-ASCII as ANSI.
979
- // Trailer mirrors -Command/-EncodedCommand exit semantics (-File alone
980
- // does NOT propagate the last native command's exit code).
981
- const innerTempPath = `${exitPath}.user.ps1`;
982
- const innerScript = `\ufeff${command}\nif ($null -ne $LASTEXITCODE) { exit $LASTEXITCODE }\n`;
983
- const mergeLiteral = mergeStderr ? '$true' : '$false';
984
- const wrapper = [
985
- "$ErrorActionPreference = 'Continue'",
986
- '[Console]::OutputEncoding=[System.Text.Encoding]::UTF8',
987
- '$OutputEncoding=[System.Text.Encoding]::UTF8',
988
- '$exe = (Get-Process -Id $PID).Path',
989
- `$innerPath = ${psSingleQuote(innerTempPath)}`,
990
- `$stdoutPath = ${psSingleQuote(stdoutPath)}`,
991
- `$stderrPath = ${psSingleQuote(rawStderrPath)}`,
992
- `$exitPath = ${psSingleQuote(exitPath)}`,
993
- `$donePath = ${psSingleQuote(donePath)}`,
994
- `$mergeStderr = ${mergeLiteral}`,
995
- // 0 (or negative) = unlimited: the wrapper's `if ($timeoutMs -gt 0 ...`
996
- // guard falls through to a plain WaitForExit() with no deadline. Do NOT
997
- // floor to 1 — that would enforce a 1ms timeout on unlimited jobs.
998
- `$timeoutMs = ${Math.max(0, Math.floor(timeoutMs || 0))}`,
999
- '$code = 1',
1000
- 'try {',
1001
- // -ExecutionPolicy Bypass: unlike -EncodedCommand, -File is subject to
1002
- // the execution policy on Windows PowerShell; pwsh on macOS/Linux
1003
- // accepts the parameter as a no-op, so it is safe unconditionally.
1004
- " $argList = @('-NoLogo', '-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass', '-File', $innerPath)",
1005
- // Do not set WindowStyle: Hidden creates a separate transient conhost.
1006
- // On Windows, explicitly reuse the wrapper's CREATE_NO_WINDOW console.
1007
- // NoNewWindow is unavailable on non-Windows pwsh, so only add it for
1008
- // Windows (where $IsWindows is absent/null in Windows PowerShell 5.1).
1009
- ' $spArgs = @{ FilePath = $exe; ArgumentList = $argList; RedirectStandardOutput = $stdoutPath; RedirectStandardError = $stderrPath; PassThru = $true }',
1010
- ' if ($IsWindows -or $null -eq $IsWindows) { $spArgs[\'NoNewWindow\'] = $true }',
1011
- ' $p = Start-Process @spArgs',
1012
- ' if ($timeoutMs -gt 0 -and -not $p.WaitForExit($timeoutMs)) {',
1013
- // Kill the whole process TREE, not just the direct child: Start-Process
1014
- // launches an intermediate pwsh that spawns the user command, so
1015
- // Stop-Process on $p.Id alone orphans the grandchildren. On Windows use
1016
- // `taskkill /T /F` (tree-terminate); on macOS/Linux pwsh, fall back to
1017
- // Stop-Process (no taskkill there).
1018
- ' try {',
1019
- ' if ($IsWindows -or $null -eq $IsWindows) {',
1020
- ' & taskkill.exe /pid $p.Id /t /f 2>$null | Out-Null',
1021
- ' } else {',
1022
- ' try { Stop-Process -Id $p.Id -Force -ErrorAction SilentlyContinue } catch {}',
1023
- ' }',
1024
- ' } catch {}',
1025
- ' $code = 124',
1026
- ' } else {',
1027
- ' try { $p.WaitForExit() } catch {}',
1028
- ' $code = if ($null -ne $p.ExitCode) { [int]$p.ExitCode } else { 0 }',
1029
- ' }',
1030
- '} catch {',
1031
- ' try { Add-Content -LiteralPath $stderrPath -Value ($_ | Out-String) -Encoding utf8 } catch {}',
1032
- ' $code = 1',
1033
- '}',
1034
- 'if ($mergeStderr) {',
1035
- ' try {',
1036
- ' if (Test-Path -LiteralPath $stderrPath) {',
1037
- ' $err = Get-Content -LiteralPath $stderrPath -Raw -ErrorAction SilentlyContinue',
1038
- ' if ($err) { Add-Content -LiteralPath $stdoutPath -Value $err -Encoding utf8 }',
1039
- ' Remove-Item -LiteralPath $stderrPath -Force -ErrorAction SilentlyContinue',
1040
- ' }',
1041
- ' } catch {}',
1042
- '}',
1043
- 'try { Set-Content -LiteralPath $exitPath -Value ([string]$code) -NoNewline -Encoding ascii } catch {}',
1044
- 'try { Set-Content -LiteralPath $donePath -Value "" -NoNewline -Encoding ascii } catch {}',
1045
- 'try { Remove-Item -LiteralPath $innerPath -Force -ErrorAction SilentlyContinue } catch {}',
1046
- 'try { Remove-Item -LiteralPath $PSCommandPath -Force -ErrorAction SilentlyContinue } catch {}',
1047
- 'exit $code',
1048
- '',
1049
- ].join('\n');
1050
- try {
1051
- writeFileSync(wrappedTempPath, wrapper, 'utf-8');
1052
- writeFileSync(innerTempPath, innerScript, 'utf-8');
1053
- } catch (e) {
1054
- return { jobId, kind: 'bash', status: 'failed', error: `failed to stage PowerShell background task: ${e?.message || e}` };
1055
- }
1056
-
1057
- const shellStem = basename(String(shell || '')).toLowerCase().replace(/\.exe$/, '');
1058
- // No `-WindowStyle Hidden` CLI switch: windowsHide:true on the spawn below
1059
- // already gives CREATE_NO_WINDOW, and the visible command-line token trips
1060
- // Defender's hidden-PowerShell dropper signature (PowhidSubExec). The
1061
- // in-wrapper Start-Process uses Windows-only NoNewWindow to reuse this
1062
- // hidden console rather than creating a transient conhost window.
1063
- // `-ExecutionPolicy` only applies to Windows PowerShell; build per-platform.
1064
- const isWin = process.platform === 'win32';
1065
- const wrapperArgs = ['-NoLogo', '-NoProfile', '-NonInteractive'];
1066
- if (isWin && shellStem === 'powershell') wrapperArgs.push('-ExecutionPolicy', 'Bypass');
1067
- wrapperArgs.push('-File', wrappedTempPath);
1068
- // Spawn the staged wrapper directly. detached MUST be false on Windows:
1069
- // a native pwsh launched with detached:true + stdio:'ignore' exits
1070
- // immediately without running -File (verified — the detached child dies
1071
- // even while the parent stays alive; the non-detached child runs to
1072
- // completion). windowsHide:true gives CREATE_NO_WINDOW so no console
1073
- // window flashes on screen. The wrapper owns its own stdout/stderr file
1074
- // redirect (exec-equivalent Set-Content paths above), so stdio:'ignore'
1075
- // drops no output. The child remains referenced so it is owned by the CLI
1076
- // process; runtime.close()/exit hooks reap it instead of daemonizing it.
1077
- let child;
1078
- try {
1079
- child = spawnFn(shell, wrapperArgs, {
1080
- cwd: workDir,
1081
- env: scrubLoaderVars(scrubProviderSecrets({ ...spawnEnv })),
1082
- detached: false,
1083
- stdio: 'ignore',
1084
- windowsHide: true,
1085
- });
1086
- await awaitSpawnReady(child, 'PowerShell background task');
1087
- } catch (e) {
1088
- try { unlinkSync(wrappedTempPath); } catch {}
1089
- try { unlinkSync(innerTempPath); } catch {}
1090
- return { jobId, kind: 'bash', status: 'failed', error: `failed to spawn PowerShell background task: ${e?.message || e}` };
1091
- }
1092
- const childPid = child.pid;
1093
- if (!Number.isFinite(childPid) || childPid <= 0) {
1094
- return { jobId, kind: 'bash', status: 'failed', error: 'PowerShell background task spawn returned no pid' };
1095
- }
1096
- const detail = {
1097
- jobId,
1098
- kind: 'bash',
1099
- shellType: 'powershell',
1100
- status: 'running',
1101
- command,
1102
- cwd: workDir,
1103
- pid: childPid,
1104
- mergeStderr,
1105
- timeoutMs,
1106
- timeoutSeconds: Number(timeoutMs) > 0 ? Math.max(1, Math.ceil(timeoutMs / 1000)) : 0,
1107
- stdoutPath,
1108
- stderrPath: mergeStderr ? stdoutPath : rawStderrPath,
1109
- exitPath,
1110
- donePath,
1111
- // The PS wrapper enforces the deadline (WaitForExit($timeoutMs) →
1112
- // Stop-Process → 124) only when timeoutMs>0; an unlimited job waits
1113
- // with no deadline, so don't falsely claim enforcement.
1114
- timeoutEnforced: Number(timeoutMs) > 0,
1115
- // Per-terminal session stamp (see resolveJobOwnerHostPid).
1116
- ownerHostPid: resolveJobOwnerHostPid(clientHostPid),
1117
- startedAt: new Date().toISOString(),
1118
- };
1119
- let terminal = false;
1120
- let runtimeOwned = false;
1121
- const onRuntimeError = (error) => {
1122
- if (terminal) return;
1123
- terminal = true;
1124
- detail.status = 'failed';
1125
- detail.terminationPending = true;
1126
- detail.error = `PowerShell background task process error: ${error?.message || error}`;
1127
- detail.finishedAt = new Date().toISOString();
1128
- try { writeDetailFn(detail); } catch {}
1129
- if (runtimeOwned) void (async () => {
1130
- const rollback = await rollbackSpawnedChild(child, { timeoutMs: rollbackTimeoutMs });
1131
- if (rollback.confirmed) {
1132
- releaseShellJobOwnershipWhenQuiescent(jobId, childPid, {
1133
- onConfirmed: () => {
1134
- detail.terminationPending = false;
1135
- try { writeDetailFn(detail); } catch {}
1136
- },
1137
- });
1138
- } else {
1139
- detail.error += `; termination unconfirmed after ${rollbackTimeoutMs}ms (process remains tracked)`;
1140
- try { writeDetailFn(detail); } catch {}
1141
- trackChildUntilConfirmedExit(child, jobId, () => {
1142
- detail.terminationPending = false;
1143
- try { writeDetailFn(detail); } catch {}
1144
- });
1145
- }
1146
- })();
1147
- };
1148
- adoptSpawnErrorHandler(child, onRuntimeError);
1149
- if (terminal) {
1150
- const rollback = await rollbackSpawnedChild(child, { timeoutMs: rollbackTimeoutMs });
1151
- detail.terminationPending = !rollback.confirmed;
1152
- try { writeDetailFn(detail); } catch {}
1153
- try { unlinkSync(wrappedTempPath); } catch {}
1154
- try { unlinkSync(innerTempPath); } catch {}
1155
- return rollback.confirmed
1156
- ? detail
1157
- : {
1158
- ...detail,
1159
- rollbackPending: trackChildUntilConfirmedExit(child, jobId, () => {
1160
- detail.terminationPending = false;
1161
- try { writeDetailFn(detail); } catch {}
1162
- }),
1163
- error: `${detail.error}; termination unconfirmed after ${rollbackTimeoutMs}ms (process remains tracked)`,
1164
- };
1165
- }
1166
- try {
1167
- writeDetailFn(detail);
1168
- } catch (e) {
1169
- terminal = true;
1170
- const rollback = await rollbackSpawnedChild(child, { timeoutMs: rollbackTimeoutMs });
1171
- child.removeListener('error', onRuntimeError);
1172
- discardSpawnErrorGuard(child);
1173
- try { unlinkSync(wrappedTempPath); } catch {}
1174
- try { unlinkSync(innerTempPath); } catch {}
1175
- const failure = { jobId, kind: 'bash', status: 'failed', error: `failed to persist PowerShell background task: ${e?.message || e}` };
1176
- if (!rollback.confirmed) {
1177
- failure.rollbackPending = trackChildUntilConfirmedExit(child, jobId);
1178
- failure.error += `; termination unconfirmed after ${rollbackTimeoutMs}ms (process remains tracked)`;
1179
- }
1180
- return failure;
1181
- }
1182
- startChildGuardian({
1183
- childPid,
1184
- childGroupPid: childPid,
1185
- label: 'shell-job-powershell',
1186
- });
1187
- _installShellJobsExitHook();
1188
- _registerLiveJobPid(childPid, jobId);
1189
- runtimeOwned = true;
1190
- releaseShellJobOwnershipWhenQuiescent(jobId, childPid, {
1191
- allowLateLease: true,
1192
- deferUntilRootExit: true,
1193
- });
1194
- if (Number(timeoutMs) > 0) {
1195
- const timer = setTimeout(() => { refreshShellJob(jobId); }, Math.min(TIMER_MAX_MS, timeoutMs + 25));
1196
- if (typeof timer.unref === 'function') timer.unref();
1197
- }
1198
- return detail;
1199
- }
@@ -112,7 +112,7 @@ export function snapshotCoversFullFile(snapshot) {
112
112
  }
113
113
 
114
114
  /** Logical line count captured at read-time (wc-l compatible). Undefined if absent. */
115
- export function snapshotFileLineCount(snapshot) {
115
+ function snapshotFileLineCount(snapshot) {
116
116
  const n = snapshot?.fileLineCount;
117
117
  return Number.isFinite(n) && n >= 0 ? Math.trunc(n) : undefined;
118
118
  }