@nathapp/nax-agent 0.1.0

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 (398) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/LICENSE +21 -0
  3. package/README.md +49 -0
  4. package/dist/coding-tools/coding-tool-bash.d.ts +46 -0
  5. package/dist/coding-tools/coding-tool-bash.js +44 -0
  6. package/dist/coding-tools/coding-tool-extras.d.ts +35 -0
  7. package/dist/coding-tools/coding-tool-extras.js +56 -0
  8. package/dist/coding-tools/coding-tool-sandbox.d.ts +74 -0
  9. package/dist/coding-tools/coding-tool-sandbox.js +215 -0
  10. package/dist/coding-tools/coding-tool-support.d.ts +132 -0
  11. package/dist/coding-tools/coding-tool-support.js +159 -0
  12. package/dist/coding-tools/universal-coding-tools.d.ts +11 -0
  13. package/dist/coding-tools/universal-coding-tools.js +5 -0
  14. package/dist/command-interceptor/index.d.ts +55 -0
  15. package/dist/command-interceptor/index.js +60 -0
  16. package/dist/command-interceptor/shell.d.ts +36 -0
  17. package/dist/command-interceptor/shell.js +137 -0
  18. package/dist/command-safety/build.d.ts +19 -0
  19. package/dist/command-safety/build.js +47 -0
  20. package/dist/command-safety/guard.d.ts +32 -0
  21. package/dist/command-safety/guard.js +179 -0
  22. package/dist/command-safety/identifiers.d.ts +24 -0
  23. package/dist/command-safety/identifiers.js +20 -0
  24. package/dist/command-safety/index.d.ts +17 -0
  25. package/dist/command-safety/index.js +11 -0
  26. package/dist/command-safety/questions.d.ts +19 -0
  27. package/dist/command-safety/questions.js +60 -0
  28. package/dist/command-safety/row.d.ts +2 -0
  29. package/dist/command-safety/row.js +14 -0
  30. package/dist/command-safety/rule-scorer.d.ts +9 -0
  31. package/dist/command-safety/rule-scorer.js +391 -0
  32. package/dist/command-safety/shadow.d.ts +33 -0
  33. package/dist/command-safety/shadow.js +188 -0
  34. package/dist/command-safety/systemone-client.d.ts +16 -0
  35. package/dist/command-safety/systemone-client.js +92 -0
  36. package/dist/command-safety/tap.d.ts +37 -0
  37. package/dist/command-safety/tap.js +77 -0
  38. package/dist/command-safety/temp-only.d.ts +6 -0
  39. package/dist/command-safety/temp-only.js +215 -0
  40. package/dist/command-safety/tmp-write.d.ts +2 -0
  41. package/dist/command-safety/tmp-write.js +112 -0
  42. package/dist/command-safety/types.d.ts +185 -0
  43. package/dist/command-safety/types.js +21 -0
  44. package/dist/config/bash-approval.d.ts +33 -0
  45. package/dist/config/bash-approval.js +30 -0
  46. package/dist/config/catalog-overrides.d.ts +94 -0
  47. package/dist/config/catalog-overrides.js +7 -0
  48. package/dist/config/native-agent/index.d.ts +8 -0
  49. package/dist/config/native-agent/index.js +8 -0
  50. package/dist/config/schemas-sandbox.d.ts +31 -0
  51. package/dist/config/schemas-sandbox.js +45 -0
  52. package/dist/cost/core/index.d.ts +8 -0
  53. package/dist/cost/core/index.js +7 -0
  54. package/dist/cost/estimate.d.ts +34 -0
  55. package/dist/cost/estimate.js +65 -0
  56. package/dist/cost/model-spec.d.ts +28 -0
  57. package/dist/cost/model-spec.js +29 -0
  58. package/dist/cost/standard-types.d.ts +9 -0
  59. package/dist/cost/standard-types.js +1 -0
  60. package/dist/cost/usage-math.d.ts +18 -0
  61. package/dist/cost/usage-math.js +46 -0
  62. package/dist/index.d.ts +26 -0
  63. package/dist/index.js +21 -0
  64. package/dist/infra/agent-logger.d.ts +22 -0
  65. package/dist/infra/agent-logger.js +19 -0
  66. package/dist/infra/credentials-config.d.ts +20 -0
  67. package/dist/infra/credentials-config.js +15 -0
  68. package/dist/infra/errors.d.ts +9 -0
  69. package/dist/infra/errors.js +11 -0
  70. package/dist/infra/index.d.ts +7 -0
  71. package/dist/infra/index.js +7 -0
  72. package/dist/infra/nax-error.d.ts +10 -0
  73. package/dist/infra/nax-error.js +16 -0
  74. package/dist/infra/spin-breaker/hash.d.ts +2 -0
  75. package/dist/infra/spin-breaker/hash.js +5 -0
  76. package/dist/infra/spin-breaker/index.d.ts +120 -0
  77. package/dist/infra/spin-breaker/index.js +340 -0
  78. package/dist/internal/agent-output-env.d.ts +44 -0
  79. package/dist/internal/agent-output-env.js +57 -0
  80. package/dist/internal/argv-exec.d.ts +58 -0
  81. package/dist/internal/argv-exec.js +224 -0
  82. package/dist/internal/bounded-io.d.ts +24 -0
  83. package/dist/internal/bounded-io.js +51 -0
  84. package/dist/internal/command-spec/index.d.ts +29 -0
  85. package/dist/internal/command-spec/index.js +36 -0
  86. package/dist/internal/describe-value-type.d.ts +8 -0
  87. package/dist/internal/describe-value-type.js +14 -0
  88. package/dist/internal/exec-framing.d.ts +18 -0
  89. package/dist/internal/exec-framing.js +22 -0
  90. package/dist/internal/file-lock.d.ts +91 -0
  91. package/dist/internal/file-lock.js +212 -0
  92. package/dist/internal/file-size.d.ts +2 -0
  93. package/dist/internal/file-size.js +12 -0
  94. package/dist/internal/git-add.d.ts +43 -0
  95. package/dist/internal/git-add.js +59 -0
  96. package/dist/internal/git-env.d.ts +59 -0
  97. package/dist/internal/git-env.js +93 -0
  98. package/dist/internal/git-exec.d.ts +58 -0
  99. package/dist/internal/git-exec.js +115 -0
  100. package/dist/internal/path-file-lock.d.ts +23 -0
  101. package/dist/internal/path-file-lock.js +25 -0
  102. package/dist/internal/process-alive.d.ts +42 -0
  103. package/dist/internal/process-alive.js +56 -0
  104. package/dist/internal/process-kill.d.ts +27 -0
  105. package/dist/internal/process-kill.js +54 -0
  106. package/dist/internal/realpath.d.ts +29 -0
  107. package/dist/internal/realpath.js +52 -0
  108. package/dist/internal/redact.d.ts +40 -0
  109. package/dist/internal/redact.js +161 -0
  110. package/dist/internal/shell-quote.d.ts +2 -0
  111. package/dist/internal/shell-quote.js +4 -0
  112. package/dist/internal/sort.d.ts +20 -0
  113. package/dist/internal/sort.js +20 -0
  114. package/dist/internal/strip-control-chars.d.ts +19 -0
  115. package/dist/internal/strip-control-chars.js +38 -0
  116. package/dist/internal/thenable.d.ts +10 -0
  117. package/dist/internal/thenable.js +15 -0
  118. package/dist/internal.d.ts +91 -0
  119. package/dist/internal.js +91 -0
  120. package/dist/native/adapter-deps.d.ts +46 -0
  121. package/dist/native/adapter-deps.js +43 -0
  122. package/dist/native/auth-types.d.ts +70 -0
  123. package/dist/native/auth-types.js +13 -0
  124. package/dist/native/auth.d.ts +133 -0
  125. package/dist/native/auth.js +362 -0
  126. package/dist/native/client.d.ts +50 -0
  127. package/dist/native/client.js +174 -0
  128. package/dist/native/complete.d.ts +33 -0
  129. package/dist/native/complete.js +88 -0
  130. package/dist/native/credentials/chained-store.d.ts +30 -0
  131. package/dist/native/credentials/chained-store.js +68 -0
  132. package/dist/native/credentials/change-guard.d.ts +51 -0
  133. package/dist/native/credentials/change-guard.js +136 -0
  134. package/dist/native/credentials/exec-source.d.ts +50 -0
  135. package/dist/native/credentials/exec-source.js +222 -0
  136. package/dist/native/credentials/fingerprint.d.ts +26 -0
  137. package/dist/native/credentials/fingerprint.js +174 -0
  138. package/dist/native/credentials/helper-process.d.ts +79 -0
  139. package/dist/native/credentials/helper-process.js +259 -0
  140. package/dist/native/credentials/helper-protocol.d.ts +36 -0
  141. package/dist/native/credentials/helper-protocol.js +79 -0
  142. package/dist/native/credentials/index.d.ts +60 -0
  143. package/dist/native/credentials/index.js +184 -0
  144. package/dist/native/errors.d.ts +34 -0
  145. package/dist/native/errors.js +109 -0
  146. package/dist/native/index.d.ts +25 -0
  147. package/dist/native/index.js +23 -0
  148. package/dist/native/model-resolver.d.ts +57 -0
  149. package/dist/native/model-resolver.js +73 -0
  150. package/dist/native/models.d.ts +116 -0
  151. package/dist/native/models.js +183 -0
  152. package/dist/native/session/ask-human.d.ts +15 -0
  153. package/dist/native/session/ask-human.js +22 -0
  154. package/dist/native/session/compaction.d.ts +94 -0
  155. package/dist/native/session/compaction.js +170 -0
  156. package/dist/native/session/handle-invalid-tool-call.d.ts +111 -0
  157. package/dist/native/session/handle-invalid-tool-call.js +159 -0
  158. package/dist/native/session/loop-events/cache-boundary.d.ts +11 -0
  159. package/dist/native/session/loop-events/cache-boundary.js +29 -0
  160. package/dist/native/session/loop-events/external-handler.d.ts +38 -0
  161. package/dist/native/session/loop-events/external-handler.js +193 -0
  162. package/dist/native/session/loop-events/index.d.ts +16 -0
  163. package/dist/native/session/loop-events/index.js +15 -0
  164. package/dist/native/session/loop-events/payload-guard.d.ts +9 -0
  165. package/dist/native/session/loop-events/payload-guard.js +31 -0
  166. package/dist/native/session/loop-events/registry.d.ts +84 -0
  167. package/dist/native/session/loop-events/registry.js +305 -0
  168. package/dist/native/session/loop-events/types.d.ts +251 -0
  169. package/dist/native/session/loop-events/types.js +14 -0
  170. package/dist/native/session/loop-handlers.d.ts +73 -0
  171. package/dist/native/session/loop-handlers.js +137 -0
  172. package/dist/native/session/nudge.d.ts +29 -0
  173. package/dist/native/session/nudge.js +35 -0
  174. package/dist/native/session/rate-provenance.d.ts +17 -0
  175. package/dist/native/session/rate-provenance.js +39 -0
  176. package/dist/native/session/session.d.ts +139 -0
  177. package/dist/native/session/session.js +208 -0
  178. package/dist/native/session/tool-input-exemplar.d.ts +2 -0
  179. package/dist/native/session/tool-input-exemplar.js +66 -0
  180. package/dist/native/session/tool-input-validation.d.ts +15 -0
  181. package/dist/native/session/tool-input-validation.js +146 -0
  182. package/dist/native/session/tool-mapping.d.ts +18 -0
  183. package/dist/native/session/tool-mapping.js +27 -0
  184. package/dist/native/session/tool-result.d.ts +37 -0
  185. package/dist/native/session/tool-result.js +25 -0
  186. package/dist/native/session/transcript-store.d.ts +77 -0
  187. package/dist/native/session/transcript-store.js +200 -0
  188. package/dist/native/session/truncation-handler.d.ts +47 -0
  189. package/dist/native/session/truncation-handler.js +83 -0
  190. package/dist/native/session/turn-accumulator.d.ts +45 -0
  191. package/dist/native/session/turn-accumulator.js +67 -0
  192. package/dist/native/session/turn-ask-human.d.ts +23 -0
  193. package/dist/native/session/turn-ask-human.js +41 -0
  194. package/dist/native/session/turn-compaction-step.d.ts +74 -0
  195. package/dist/native/session/turn-compaction-step.js +128 -0
  196. package/dist/native/session/turn-complete-step.d.ts +77 -0
  197. package/dist/native/session/turn-complete-step.js +159 -0
  198. package/dist/native/session/turn-end-event.d.ts +3 -0
  199. package/dist/native/session/turn-end-event.js +17 -0
  200. package/dist/native/session/turn-events.d.ts +63 -0
  201. package/dist/native/session/turn-events.js +48 -0
  202. package/dist/native/session/turn-loop-round-trip.d.ts +116 -0
  203. package/dist/native/session/turn-loop-round-trip.js +318 -0
  204. package/dist/native/session/turn-loop.d.ts +23 -0
  205. package/dist/native/session/turn-loop.js +250 -0
  206. package/dist/native/session/turn-result.d.ts +39 -0
  207. package/dist/native/session/turn-result.js +64 -0
  208. package/dist/native/session/turn-retry.d.ts +120 -0
  209. package/dist/native/session/turn-retry.js +182 -0
  210. package/dist/native/session/turn-tool-batch.d.ts +61 -0
  211. package/dist/native/session/turn-tool-batch.js +259 -0
  212. package/dist/native/session/turn-types.d.ts +164 -0
  213. package/dist/native/session/turn-types.js +36 -0
  214. package/dist/native/session-adapter.d.ts +56 -0
  215. package/dist/native/session-adapter.js +369 -0
  216. package/dist/native/session-affinity.d.ts +36 -0
  217. package/dist/native/session-affinity.js +43 -0
  218. package/dist/native/tier-providers.d.ts +18 -0
  219. package/dist/native/tier-providers.js +20 -0
  220. package/dist/permissions/approval-audit.d.ts +10 -0
  221. package/dist/permissions/approval-audit.js +22 -0
  222. package/dist/permissions/approvals-link.d.ts +20 -0
  223. package/dist/permissions/approvals-link.js +62 -0
  224. package/dist/permissions/approvals-store.d.ts +168 -0
  225. package/dist/permissions/approvals-store.js +259 -0
  226. package/dist/permissions/approvals-taint.d.ts +33 -0
  227. package/dist/permissions/approvals-taint.js +138 -0
  228. package/dist/permissions/ask-chain.d.ts +69 -0
  229. package/dist/permissions/ask-chain.js +32 -0
  230. package/dist/permissions/ask.d.ts +23 -0
  231. package/dist/permissions/ask.js +25 -0
  232. package/dist/permissions/bash-lex.d.ts +59 -0
  233. package/dist/permissions/bash-lex.js +279 -0
  234. package/dist/permissions/grammar.d.ts +12 -0
  235. package/dist/permissions/grammar.js +24 -0
  236. package/dist/permissions/index.d.ts +11 -0
  237. package/dist/permissions/index.js +9 -0
  238. package/dist/permissions/secret-spans.d.ts +19 -0
  239. package/dist/permissions/secret-spans.js +88 -0
  240. package/dist/permissions/types.d.ts +85 -0
  241. package/dist/permissions/types.js +1 -0
  242. package/dist/runtime/index.d.ts +3 -0
  243. package/dist/runtime/index.js +2 -0
  244. package/dist/runtime/node-glob.d.ts +3 -0
  245. package/dist/runtime/node-glob.js +83 -0
  246. package/dist/runtime/node-runtime.d.ts +3 -0
  247. package/dist/runtime/node-runtime.js +126 -0
  248. package/dist/runtime/slot.d.ts +11 -0
  249. package/dist/runtime/slot.js +17 -0
  250. package/dist/runtime/types.d.ts +51 -0
  251. package/dist/runtime/types.js +1 -0
  252. package/dist/runtime/which.d.ts +8 -0
  253. package/dist/runtime/which.js +32 -0
  254. package/dist/sandbox/argv-quote.d.ts +11 -0
  255. package/dist/sandbox/argv-quote.js +13 -0
  256. package/dist/sandbox/defaults.d.ts +27 -0
  257. package/dist/sandbox/defaults.js +47 -0
  258. package/dist/sandbox/git-guards.d.ts +64 -0
  259. package/dist/sandbox/git-guards.js +161 -0
  260. package/dist/sandbox/index.d.ts +11 -0
  261. package/dist/sandbox/index.js +10 -0
  262. package/dist/sandbox/launcher.d.ts +37 -0
  263. package/dist/sandbox/launcher.js +160 -0
  264. package/dist/sandbox/messages.d.ts +17 -0
  265. package/dist/sandbox/messages.js +46 -0
  266. package/dist/sandbox/policy-builder.d.ts +44 -0
  267. package/dist/sandbox/policy-builder.js +149 -0
  268. package/dist/sandbox/policy-inputs.d.ts +53 -0
  269. package/dist/sandbox/policy-inputs.js +76 -0
  270. package/dist/sandbox/probe.d.ts +8 -0
  271. package/dist/sandbox/probe.js +66 -0
  272. package/dist/sandbox/registry.d.ts +17 -0
  273. package/dist/sandbox/registry.js +57 -0
  274. package/dist/sandbox/session-tmp.d.ts +20 -0
  275. package/dist/sandbox/session-tmp.js +95 -0
  276. package/dist/sandbox/srt-backend.d.ts +21 -0
  277. package/dist/sandbox/srt-backend.js +99 -0
  278. package/dist/sandbox/types.d.ts +102 -0
  279. package/dist/sandbox/types.js +1 -0
  280. package/dist/session/adapter-failure.d.ts +60 -0
  281. package/dist/session/adapter-failure.js +11 -0
  282. package/dist/session/agent-stream-events.d.ts +103 -0
  283. package/dist/session/agent-stream-events.js +6 -0
  284. package/dist/session/interaction-handler.d.ts +53 -0
  285. package/dist/session/interaction-handler.js +2 -0
  286. package/dist/session/no-op-interaction-handler.d.ts +9 -0
  287. package/dist/session/no-op-interaction-handler.js +11 -0
  288. package/dist/session/protocol-types.d.ts +12 -0
  289. package/dist/session/protocol-types.js +1 -0
  290. package/dist/session/session-types.d.ts +456 -0
  291. package/dist/session/session-types.js +64 -0
  292. package/dist/session/tool-descriptor.d.ts +23 -0
  293. package/dist/session/tool-descriptor.js +5 -0
  294. package/dist/session/turn-deadline.d.ts +17 -0
  295. package/dist/session/turn-deadline.js +23 -0
  296. package/dist/tools/ask-request.d.ts +35 -0
  297. package/dist/tools/ask-request.js +57 -0
  298. package/dist/tools/bash-cwd.d.ts +82 -0
  299. package/dist/tools/bash-cwd.js +55 -0
  300. package/dist/tools/bash.d.ts +69 -0
  301. package/dist/tools/bash.js +283 -0
  302. package/dist/tools/delete.d.ts +57 -0
  303. package/dist/tools/delete.js +154 -0
  304. package/dist/tools/denial-redirect.d.ts +42 -0
  305. package/dist/tools/denial-redirect.js +266 -0
  306. package/dist/tools/deny-paths.d.ts +35 -0
  307. package/dist/tools/deny-paths.js +76 -0
  308. package/dist/tools/edit-region.d.ts +50 -0
  309. package/dist/tools/edit-region.js +90 -0
  310. package/dist/tools/edit.d.ts +25 -0
  311. package/dist/tools/edit.js +114 -0
  312. package/dist/tools/exec-allowlist-text.d.ts +18 -0
  313. package/dist/tools/exec-allowlist-text.js +24 -0
  314. package/dist/tools/exec-guard.d.ts +69 -0
  315. package/dist/tools/exec-guard.js +151 -0
  316. package/dist/tools/git-commit.d.ts +59 -0
  317. package/dist/tools/git-commit.js +220 -0
  318. package/dist/tools/git-flags/index.d.ts +10 -0
  319. package/dist/tools/git-flags/index.js +10 -0
  320. package/dist/tools/git.d.ts +88 -0
  321. package/dist/tools/git.js +397 -0
  322. package/dist/tools/glob.d.ts +29 -0
  323. package/dist/tools/glob.js +153 -0
  324. package/dist/tools/grep.d.ts +21 -0
  325. package/dist/tools/grep.js +162 -0
  326. package/dist/tools/index.d.ts +36 -0
  327. package/dist/tools/index.js +28 -0
  328. package/dist/tools/narrow-grants.d.ts +19 -0
  329. package/dist/tools/narrow-grants.js +54 -0
  330. package/dist/tools/nax-owned-writes.d.ts +135 -0
  331. package/dist/tools/nax-owned-writes.js +259 -0
  332. package/dist/tools/package-managers-table.d.ts +146 -0
  333. package/dist/tools/package-managers-table.js +325 -0
  334. package/dist/tools/package-managers-types.d.ts +36 -0
  335. package/dist/tools/package-managers-types.js +6 -0
  336. package/dist/tools/package-managers.d.ts +85 -0
  337. package/dist/tools/package-managers.js +391 -0
  338. package/dist/tools/path-list.d.ts +38 -0
  339. package/dist/tools/path-list.js +62 -0
  340. package/dist/tools/policy-bash-raw.d.ts +19 -0
  341. package/dist/tools/policy-bash-raw.js +210 -0
  342. package/dist/tools/policy-bash.d.ts +64 -0
  343. package/dist/tools/policy-bash.js +232 -0
  344. package/dist/tools/policy-command-branch.d.ts +32 -0
  345. package/dist/tools/policy-command-branch.js +63 -0
  346. package/dist/tools/policy-input.d.ts +2 -0
  347. package/dist/tools/policy-input.js +10 -0
  348. package/dist/tools/policy-match.d.ts +75 -0
  349. package/dist/tools/policy-match.js +117 -0
  350. package/dist/tools/policy-paths-branch.d.ts +97 -0
  351. package/dist/tools/policy-paths-branch.js +314 -0
  352. package/dist/tools/policy.d.ts +65 -0
  353. package/dist/tools/policy.js +232 -0
  354. package/dist/tools/protected-paths.d.ts +26 -0
  355. package/dist/tools/protected-paths.js +8 -0
  356. package/dist/tools/provider-adapt.d.ts +4 -0
  357. package/dist/tools/provider-adapt.js +32 -0
  358. package/dist/tools/provider-advertise.d.ts +39 -0
  359. package/dist/tools/provider-advertise.js +50 -0
  360. package/dist/tools/provider-grants.d.ts +36 -0
  361. package/dist/tools/provider-grants.js +72 -0
  362. package/dist/tools/provider-sanitize.d.ts +19 -0
  363. package/dist/tools/provider-sanitize.js +53 -0
  364. package/dist/tools/provider-types.d.ts +41 -0
  365. package/dist/tools/provider-types.js +26 -0
  366. package/dist/tools/read-continuation.d.ts +147 -0
  367. package/dist/tools/read-continuation.js +176 -0
  368. package/dist/tools/read-file.d.ts +32 -0
  369. package/dist/tools/read-file.js +85 -0
  370. package/dist/tools/read.d.ts +25 -0
  371. package/dist/tools/read.js +182 -0
  372. package/dist/tools/registry.d.ts +125 -0
  373. package/dist/tools/registry.js +67 -0
  374. package/dist/tools/request-capability.d.ts +13 -0
  375. package/dist/tools/request-capability.js +23 -0
  376. package/dist/tools/run-command-exec.d.ts +14 -0
  377. package/dist/tools/run-command-exec.js +161 -0
  378. package/dist/tools/run-command.d.ts +107 -0
  379. package/dist/tools/run-command.js +398 -0
  380. package/dist/tools/runtime-calltool.d.ts +146 -0
  381. package/dist/tools/runtime-calltool.js +223 -0
  382. package/dist/tools/runtime.d.ts +149 -0
  383. package/dist/tools/runtime.js +345 -0
  384. package/dist/tools/scratchpad.d.ts +20 -0
  385. package/dist/tools/scratchpad.js +197 -0
  386. package/dist/tools/spill.d.ts +81 -0
  387. package/dist/tools/spill.js +251 -0
  388. package/dist/tools/tool-audit.d.ts +171 -0
  389. package/dist/tools/tool-audit.js +183 -0
  390. package/dist/tools/truncate.d.ts +98 -0
  391. package/dist/tools/truncate.js +297 -0
  392. package/dist/tools/types.d.ts +145 -0
  393. package/dist/tools/types.js +24 -0
  394. package/dist/tools/verb-denial-argv-hint.d.ts +35 -0
  395. package/dist/tools/verb-denial-argv-hint.js +40 -0
  396. package/dist/tools/write.d.ts +9 -0
  397. package/dist/tools/write.js +45 -0
  398. package/package.json +54 -0
@@ -0,0 +1,340 @@
1
+ /**
2
+ * Repetition breaker for an agent turn.
3
+ *
4
+ * A verifier session ran 36 minutes re-running the same PASSING scoped test
5
+ * 622 times, emitted no verdict, and was ended by an operator (nax#2013). Every
6
+ * call was fast and exited 0, so there was no timeout, no error rate and no
7
+ * failing gate to trip; what distinguished it was repetition without progress
8
+ * — 622 calls across 2 distinct argv shapes and no file writes.
9
+ *
10
+ * Deliberately NOT a round-trip cap. That was removed twice on purpose
11
+ * (#1823/#1827/#1830, then #1819/#1820) and a session making 600 VARIED calls
12
+ * is working, not spinning. This counts only calls whose normalised shape was
13
+ * already seen.
14
+ *
15
+ * Transport-neutral and config-free by construction: it takes resolved
16
+ * settings, so `src/agents/native/` can consult it without reading NaxConfig
17
+ * (check:adapter-no-config-import).
18
+ */
19
+ import { getSafeLogger } from "#src/infra/index";
20
+ import { byCodePoint } from "#src/internal/sort";
21
+ import { stripControlChars } from "#src/internal/strip-control-chars";
22
+ import { digest64 } from "./hash.js";
23
+ export const DEFAULT_SPIN_BREAKER_SETTINGS = Object.freeze({
24
+ enabled: true,
25
+ nudgeAfterRepeats: 25,
26
+ maxNudges: 3,
27
+ stopAfterRepeats: 50,
28
+ recentKeyWindow: 64,
29
+ stopAfterSameKeyRepeats: 12,
30
+ stopAfterNoProgressSeconds: 900,
31
+ });
32
+ /** Beyond this, the key is hashed — one large input must not grow the key set without bound. */
33
+ const MAX_KEY_BYTES = 512;
34
+ /**
35
+ * nax#2017: repeats of one call that must accumulate before the time axis may
36
+ * end the turn. A deliberate module constant, not a setting — a run of two or
37
+ * three calls is not a spin, however long each one took.
38
+ */
39
+ const NO_PROGRESS_TIME_MIN_REPEATS = 5;
40
+ /** Deterministic regardless of property order, so a reordered input is the same call. */
41
+ function stableStringify(value) {
42
+ if (value === null || typeof value !== "object")
43
+ return JSON.stringify(value) ?? "null";
44
+ if (Array.isArray(value))
45
+ return `[${value.map(stableStringify).join(",")}]`;
46
+ const entries = Object.entries(value).sort((a, b) => byCodePoint(a[0], b[0]));
47
+ return `{${entries.map(([key, val]) => `${JSON.stringify(key)}:${stableStringify(val)}`).join(",")}}`;
48
+ }
49
+ /**
50
+ * Strips the tokens that differ between two byte-identical runs: elapsed
51
+ * times and clock timestamps (ANSI escapes are removed by
52
+ * `stripControlChars` first). Deliberately surgical rather than blanking
53
+ * every digit — "2 failed" -> "1 failed" is real progress and must survive
54
+ * normalisation, while "in 1.20s" -> "in 1.23s" must not.
55
+ *
56
+ * The single-letter `m`/`s` units are ambiguous with ordinary tokens
57
+ * (`file-2m.ts`, "expected 5 m"), so they are stripped only when the number
58
+ * is decimal (`1.2s`) or sits in a time context (`in`/`took`/`time`/
59
+ * `elapsed`/`duration`/`=`/`(`/`,`). `ms` and `min` are unambiguous and stay
60
+ * unconditional. The `ms|s|m|min` alternation is ordered so backtracking
61
+ * still reaches `min`.
62
+ */
63
+ const DURATION_OR_TIMESTAMP = /\b\d+\.\d+\s?(?:ms|s|m|min)\b|(?:\b(?:in|took|time|elapsed|duration)\s?|[=(,]\s?)\d+\s?[ms]\b|\b\d+(?:\.\d+)?\s?(?:ms|min)\b|\b\d{2}:\d{2}:\d{2}(?:\.\d+)?\b|\d{4}-\d{2}-\d{2}T[\d:.]+Z?/g;
64
+ function resultDigest(text) {
65
+ const normalised = stripControlChars(text).replace(DURATION_OR_TIMESTAMP, "").replace(/\s+/g, " ").trim();
66
+ return digest64(normalised);
67
+ }
68
+ /**
69
+ * Tool names are fixed identifiers (e.g. "Read", "RunCommand") that never
70
+ * contain a space, so concatenating on one never lets `toolName="a:b"` +
71
+ * `body="c"` collide with `toolName="a"` + `body="b:c"` the way a colon would.
72
+ */
73
+ const KEY_SEPARATOR = " ";
74
+ function callKey(toolName, input) {
75
+ const body = stableStringify(input);
76
+ const clipped = body.length > MAX_KEY_BYTES ? digest64(body) : body;
77
+ return `${toolName}${KEY_SEPARATOR}${clipped}`;
78
+ }
79
+ /**
80
+ * Nudge points are derived from the three knobs rather than configured
81
+ * separately: with 25/50/3 they fall at 25, 33 and 42, leaving the stop at 50.
82
+ */
83
+ function nudgePoints(settings) {
84
+ const span = settings.stopAfterRepeats - settings.nudgeAfterRepeats;
85
+ return Array.from({ length: settings.maxNudges }, (_unused, index) => Math.round(settings.nudgeAfterRepeats + (index * span) / settings.maxNudges));
86
+ }
87
+ const NUDGE_ESCALATION = [
88
+ "You have made {repeats} tool calls without issuing a new, distinct call. You are repeating work already done and the results are not changing. Stop re-running and produce your final answer now, in the exact format your instructions require.",
89
+ "You are still repeating the same calls ({repeats} with no new work). If you cannot conclude, say so explicitly in your final answer and stop — an explicit inability to conclude is a valid answer; repeating is not.",
90
+ "Final warning: {repeats} repeated calls with no progress. The next repeated call ends this session with no answer recorded. Produce your final answer now.",
91
+ ];
92
+ /**
93
+ * Answered to every outstanding call when the breaker first decides to end a
94
+ * turn (nax#2120). The stop used to break with the call unexecuted and
95
+ * unanswered, so the turn was classified `fail-spin` and retried on the
96
+ * timeout lane — a FRESH session at a reduced budget, discarding everything
97
+ * the turn had accumulated. One terminal round trip lets the model close out
98
+ * instead. NUDGE_ESCALATION's final warning is one step ahead of the hard
99
+ * end, not literally true: the first stop only warns (this notice) and only a
100
+ * further stop verdict ends the turn.
101
+ */
102
+ export const SPIN_TERMINAL_NOTICE = "[nax] This turn is ending: you repeated the same call with no change in its result. " +
103
+ "This call was not executed. Produce your final answer now, in the exact format your " +
104
+ "instructions require. Any further repeated call ends the turn with no answer recorded.";
105
+ const SPIN_RAW_BACKSTOP_TERMINAL_NOTICE = "[nax] This turn is ending: the same call reached the safety call limit even though its results changed. " +
106
+ "This call was not executed. Produce your final answer now, in the exact format your " +
107
+ "instructions require. Any further repeated call ends the turn with no answer recorded.";
108
+ /**
109
+ * nax#2017: the time axis fires on repetition alone — the ladder is spent on
110
+ * the repeat path, and AC1's own sequence never calls `noteResult` — so the
111
+ * generic notice would assert an unchanged result the breaker never observed.
112
+ * The same reasoning as the raw backstop's copy above: a stop message that
113
+ * claims the wrong diagnostic is worse than a blunter one.
114
+ */
115
+ const SPIN_NO_PROGRESS_TIME_TERMINAL_NOTICE = "[nax] This turn is ending: you have repeated calls for too long with no new, distinct call. " +
116
+ "This call was not executed. Produce your final answer now, in the exact format your " +
117
+ "instructions require. Any further repeated call ends the turn with no answer recorded.";
118
+ /**
119
+ * Exhaustive, so a future stop reason cannot silently inherit copy written for
120
+ * a different diagnostic.
121
+ */
122
+ const SPIN_TERMINAL_NOTICES = {
123
+ "repeat-run": SPIN_TERMINAL_NOTICE,
124
+ "same-key-cumulative": SPIN_TERMINAL_NOTICE,
125
+ "same-key-backstop": SPIN_RAW_BACKSTOP_TERMINAL_NOTICE,
126
+ "no-progress-time": SPIN_NO_PROGRESS_TIME_TERMINAL_NOTICE,
127
+ };
128
+ export function spinTerminalNotice(reason) {
129
+ return SPIN_TERMINAL_NOTICES[reason];
130
+ }
131
+ function nudgeText(nudgeNumber, repeats) {
132
+ const template = NUDGE_ESCALATION[Math.min(nudgeNumber, NUDGE_ESCALATION.length) - 1] ?? NUDGE_ESCALATION[0];
133
+ return (template ?? "").replace("{repeats}", String(repeats));
134
+ }
135
+ export function createSpinBreaker(settings, deps) {
136
+ const points = nudgePoints(settings);
137
+ /**
138
+ * nax#2017: injectable clock (milliseconds). The time axis needs a clock a
139
+ * test can drive; production takes the default (`Date.now`).
140
+ */
141
+ const now = deps?.now ?? Date.now;
142
+ // Insertion-ordered and capped: a Map's iteration order gives the eviction
143
+ // order for free, so the window needs no second structure. The value carries
144
+ // the cumulative count and the same-result run, so a re-issued key reads as
145
+ // a continuation of its prior state — but only for keys still in the window:
146
+ // an evicted key is gone, and the next sighting will start fresh at 1. That
147
+ // is the same windowing tradeoff `newKeyEvents` already documents, just on
148
+ // the count axis.
149
+ const recent = new Map();
150
+ let repeatsSinceProgress = 0;
151
+ let totalCalls = 0;
152
+ let newKeyEvents = 0;
153
+ let maxRepeatRun = 0;
154
+ let maxSameKeyRepeats = 0;
155
+ /** Session-cumulative; what `summary()` reports. Telemetry meaning unchanged. */
156
+ let nudges = 0;
157
+ /**
158
+ * nax#2017: the budget the ladder actually spends, restored by sustained new
159
+ * work rather than by any single new key. Sessions are long-lived (nax#2047),
160
+ * so a session-lifetime budget left a turn that had already spent its three
161
+ * nudges with no warning left at all.
162
+ */
163
+ let episodeNudges = 0;
164
+ /** `newKeyEvents` when the last nudge was built — the replenishment anchor. */
165
+ let newKeyEventsAtLastNudge = 0;
166
+ /** nax#2017: when a new call key was last seen; the time axis' origin. */
167
+ let lastProgressAt = now();
168
+ function remember(key) {
169
+ const record = { count: 1, sameResultRun: 0 };
170
+ recent.set(key, record);
171
+ newKeyEvents += 1;
172
+ if (recent.size > settings.recentKeyWindow) {
173
+ const oldest = recent.keys().next();
174
+ if (!oldest.done)
175
+ recent.delete(oldest.value);
176
+ }
177
+ return record;
178
+ }
179
+ function buildNudge(toolName, repeats) {
180
+ nudges += 1;
181
+ episodeNudges += 1;
182
+ newKeyEventsAtLastNudge = newKeyEvents;
183
+ getSafeLogger()?.warn("spin-breaker", "Repeated calls with no progress — nudging", {
184
+ tool: toolName,
185
+ repeats,
186
+ nudgeNumber: episodeNudges,
187
+ newKeyEvents,
188
+ });
189
+ return { action: "nudge", nudgeNumber: episodeNudges, repeats, text: nudgeText(episodeNudges, repeats) };
190
+ }
191
+ /**
192
+ * Reason-specific stop messages: the raw backstop fires precisely when the
193
+ * results ARE changing, so reusing the no-progress copy there would invert
194
+ * the one diagnostic that matters.
195
+ */
196
+ const stopMessage = {
197
+ "repeat-run": "Ending the turn — repeated calls with no progress",
198
+ "same-key-cumulative": "Ending the turn — the same call returned the same result too many times",
199
+ "same-key-backstop": "Ending the turn — the same call repeated too many times (raw backstop; results were changing)",
200
+ "no-progress-time": "Ending the turn — repeated calls with no new call for too long",
201
+ };
202
+ /**
203
+ * The raw per-key backstop: a cap on the cumulative count, and that count
204
+ * includes the call being judged — `remember` seeds a new key at 1. It is
205
+ * therefore checked on the key's FIRST occurrence too, in both branches,
206
+ * rather than only when the key is seen again. For every supported cap
207
+ * (`stopAfterRepeats` has a schema minimum of 3) the first occurrence sits
208
+ * below it and nothing changes; a degenerate cap of 1 stops on the first
209
+ * call rather than the second, and that is the only case where the two
210
+ * readings differ.
211
+ */
212
+ function backstopVerdict(record, toolName) {
213
+ if (settings.stopAfterSameKeyRepeats <= 0 || record.count < settings.stopAfterRepeats)
214
+ return undefined;
215
+ return stopOrNudge(toolName, record.count, "same-key-backstop", () => {
216
+ record.count = 0;
217
+ record.sameResultRun = 0;
218
+ });
219
+ }
220
+ /**
221
+ * nax#2120: the escalation ladder must always render before a kill. The
222
+ * nudge points are derived from `repeatsSinceProgress`, but the cumulative
223
+ * per-key check runs on a different counter, so for a loop over 1-2
224
+ * already-seen keys the first nudge point was unreachable by arithmetic
225
+ * and the turn was killed cold with `nudges: 0`.
226
+ *
227
+ * Deliberately NOT a config refinement: reachability depends on the loop's
228
+ * CYCLE LENGTH, not on the knobs, so no cross-field inequality can express
229
+ * it. Spending a nudge instead costs at most `maxNudges` extra calls before
230
+ * a genuine nax#2047 kill, and makes `nudges: 0` on a stop unreachable for
231
+ * every configuration.
232
+ *
233
+ * `onStop` runs only when the verdict is a real stop — the Task 1 evidence
234
+ * reset must not fire on a downgrade, or the threshold could never be
235
+ * reached twice and the loop would nudge forever.
236
+ *
237
+ * A real stop also consumes `repeatsSinceProgress`, symmetric with the
238
+ * per-key reset. The breaker is session-scoped by design (nax#2047), and
239
+ * the first stop is now reprieved by the turn loop (nax#2120 Task 4): if
240
+ * the run counter stayed latched at the threshold, the next turn would stop
241
+ * cold on its first or second repeated call. It must re-accumulate in full.
242
+ */
243
+ function stopOrNudge(toolName, repeats, reason, onStop) {
244
+ if (episodeNudges < settings.maxNudges)
245
+ return buildNudge(toolName, repeats);
246
+ onStop?.();
247
+ repeatsSinceProgress = 0;
248
+ // nax#2017: a real stop hands the next run a full ladder. The breaker is
249
+ // session-scoped (nax#2047), so a budget spent in one turn would otherwise
250
+ // deny every later turn its warnings — the shape this story exists to fix.
251
+ episodeNudges = 0;
252
+ getSafeLogger()?.error("spin-breaker", stopMessage[reason], {
253
+ tool: toolName,
254
+ repeats,
255
+ reason,
256
+ newKeyEvents,
257
+ totalCalls,
258
+ nudges,
259
+ });
260
+ return { action: "stop", repeats, reason };
261
+ }
262
+ return {
263
+ observe(toolName, input) {
264
+ if (!settings.enabled)
265
+ return { action: "allow" };
266
+ totalCalls += 1;
267
+ const key = callKey(toolName, input);
268
+ const existing = recent.get(key);
269
+ if (existing === undefined) {
270
+ const created = remember(key);
271
+ repeatsSinceProgress = 0;
272
+ // nax#2017: a new call key is progress on the time axis...
273
+ lastProgressAt = now();
274
+ // ...and sustained new work replenishes the episode's nudge budget.
275
+ // Deliberately NOT every new key: a laundering loop that interleaves
276
+ // one fresh key between repeats of a single call (nax#2047) would then
277
+ // restore its own budget forever and never stop.
278
+ if (newKeyEvents - newKeyEventsAtLastNudge >= settings.nudgeAfterRepeats)
279
+ episodeNudges = 0;
280
+ // Judged on its own first occurrence — see `backstopVerdict`.
281
+ const firstBackstop = backstopVerdict(created, toolName);
282
+ return firstBackstop ?? { action: "allow" };
283
+ }
284
+ const record = existing;
285
+ record.count += 1;
286
+ if (record.count > maxSameKeyRepeats)
287
+ maxSameKeyRepeats = record.count;
288
+ // nax#2120: the cumulative threshold runs on the RESULT axis. Same call
289
+ // + same result N times is a spin whatever interleaved; same call with
290
+ // a changing result is an edit -> test loop, which is work. The raw
291
+ // count is kept as a backstop for a call whose result is unique every
292
+ // time, or which never reaches `noteResult` (a throw; a DENIAL does
293
+ // reach it) — `stopAfterRepeats` bounds it without adding a knob. The
294
+ // backstop fires while results are changing, hence its own reason.
295
+ if (settings.stopAfterSameKeyRepeats > 0 && record.sameResultRun >= settings.stopAfterSameKeyRepeats) {
296
+ return stopOrNudge(toolName, record.sameResultRun, "same-key-cumulative", () => {
297
+ record.count = 0;
298
+ record.sameResultRun = 0;
299
+ });
300
+ }
301
+ const backstop = backstopVerdict(record, toolName);
302
+ if (backstop !== undefined)
303
+ return backstop;
304
+ repeatsSinceProgress += 1;
305
+ if (repeatsSinceProgress > maxRepeatRun)
306
+ maxRepeatRun = repeatsSinceProgress;
307
+ // nax#2017: the time axis. A repeated call that takes ~40 s each reaches
308
+ // the tool-call-only idle watchdog before the repeat thresholds, and the
309
+ // watchdog's cancel is classified `fail-stale` — a retry on the timeout
310
+ // lane, discarding the turn. Ending it here instead makes it `fail-spin`.
311
+ // Checked before the repeat-run threshold so a slow spin ends on time
312
+ // rather than on a count it may never reach.
313
+ if (settings.stopAfterNoProgressSeconds > 0 &&
314
+ repeatsSinceProgress >= NO_PROGRESS_TIME_MIN_REPEATS &&
315
+ now() - lastProgressAt >= settings.stopAfterNoProgressSeconds * 1000) {
316
+ return stopOrNudge(toolName, repeatsSinceProgress, "no-progress-time");
317
+ }
318
+ if (repeatsSinceProgress >= settings.stopAfterRepeats) {
319
+ return stopOrNudge(toolName, repeatsSinceProgress, "repeat-run");
320
+ }
321
+ const isNudgePoint = points.includes(repeatsSinceProgress);
322
+ if (isNudgePoint && episodeNudges < settings.maxNudges)
323
+ return buildNudge(toolName, repeatsSinceProgress);
324
+ return { action: "allow" };
325
+ },
326
+ noteResult(toolName, input, resultText) {
327
+ if (!settings.enabled)
328
+ return;
329
+ const record = recent.get(callKey(toolName, input));
330
+ if (record === undefined)
331
+ return;
332
+ const digest = resultDigest(resultText);
333
+ record.sameResultRun = record.digest === digest ? record.sameResultRun + 1 : 1;
334
+ record.digest = digest;
335
+ },
336
+ summary() {
337
+ return { totalCalls, newKeyEvents, maxRepeatRun, maxSameKeyRepeats, nudges };
338
+ },
339
+ };
340
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Agent-friendly output env for nax's own agent-facing spawn sites.
3
+ *
4
+ * `AGENT_OUTPUT_MARKERS` / `withAgentOutputEnv` are the rule the quality and
5
+ * verification runners already share; this module is where they live so the
6
+ * other spawn sites (Bash, RunCommand's Exec branch) can apply the identical
7
+ * rule instead of a second copy of it. `src/verification/executor.ts`
8
+ * re-exports both, so `src/quality/runner.ts` keeps importing them unchanged.
9
+ */
10
+ /**
11
+ * Env vars that tell an agent-aware test runner to emit failures-only output.
12
+ * `bun test` honours all three (https://bun.com/docs/test): failures keep their
13
+ * full code frame, diff and stack, and the summary line is preserved — only the
14
+ * per-test pass/skip/todo roll call is dropped.
15
+ *
16
+ * Exported so the quality runner applies the identical rule at its own spawn
17
+ * site; the two env paths must not drift.
18
+ */
19
+ export declare const AGENT_OUTPUT_MARKERS: readonly ["CLAUDECODE", "REPL_ID", "AGENT"];
20
+ /**
21
+ * Add `AGENT=1` unless a marker is already present or the caller stripped it.
22
+ */
23
+ export declare function withAgentOutputEnv(env: Record<string, string | undefined>, strippedVars?: readonly string[]): Record<string, string | undefined>;
24
+ /** Where marker presence is read from; tests replace it. */
25
+ export declare const _agentOutputEnvDeps: {
26
+ processEnv: () => Record<string, string | undefined>;
27
+ };
28
+ /**
29
+ * `{ AGENT: "1" }`, or undefined when a marker is already inherited or AGENT
30
+ * is stripped.
31
+ *
32
+ * The spawn sites here overlay a small record onto the child's inherited
33
+ * environment rather than normalizing a whole env, so "no overlay" has to be
34
+ * distinguishable from "an empty overlay": undefined means the caller passes
35
+ * no `env` key at all and the child inherits `process.env` untouched.
36
+ *
37
+ * Marker presence is read from the nax process environment — the SAME source
38
+ * `withAgentOutputEnv` reads from — so an inherited CLAUDECODE/REPL_ID speaks
39
+ * for itself, and a stripped AGENT stays stripped. Reading from the child's
40
+ * already-built env would not work: by the time the spawn site runs, the
41
+ * inherited env is what nax itself was launched under, and there is no second
42
+ * "real" source of truth to consult.
43
+ */
44
+ export declare function agentOutputOverlay(strippedVars: readonly string[]): Readonly<Record<string, string>> | undefined;
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Agent-friendly output env for nax's own agent-facing spawn sites.
3
+ *
4
+ * `AGENT_OUTPUT_MARKERS` / `withAgentOutputEnv` are the rule the quality and
5
+ * verification runners already share; this module is where they live so the
6
+ * other spawn sites (Bash, RunCommand's Exec branch) can apply the identical
7
+ * rule instead of a second copy of it. `src/verification/executor.ts`
8
+ * re-exports both, so `src/quality/runner.ts` keeps importing them unchanged.
9
+ */
10
+ /**
11
+ * Env vars that tell an agent-aware test runner to emit failures-only output.
12
+ * `bun test` honours all three (https://bun.com/docs/test): failures keep their
13
+ * full code frame, diff and stack, and the summary line is preserved — only the
14
+ * per-test pass/skip/todo roll call is dropped.
15
+ *
16
+ * Exported so the quality runner applies the identical rule at its own spawn
17
+ * site; the two env paths must not drift.
18
+ */
19
+ export const AGENT_OUTPUT_MARKERS = ["CLAUDECODE", "REPL_ID", "AGENT"];
20
+ /**
21
+ * Add `AGENT=1` unless a marker is already present or the caller stripped it.
22
+ */
23
+ export function withAgentOutputEnv(env, strippedVars = []) {
24
+ if (strippedVars.includes("AGENT"))
25
+ return env;
26
+ if (AGENT_OUTPUT_MARKERS.some((marker) => env[marker] !== undefined))
27
+ return env;
28
+ return { ...env, AGENT: "1" };
29
+ }
30
+ /** Where marker presence is read from; tests replace it. */
31
+ export const _agentOutputEnvDeps = {
32
+ processEnv: () => process.env,
33
+ };
34
+ /**
35
+ * `{ AGENT: "1" }`, or undefined when a marker is already inherited or AGENT
36
+ * is stripped.
37
+ *
38
+ * The spawn sites here overlay a small record onto the child's inherited
39
+ * environment rather than normalizing a whole env, so "no overlay" has to be
40
+ * distinguishable from "an empty overlay": undefined means the caller passes
41
+ * no `env` key at all and the child inherits `process.env` untouched.
42
+ *
43
+ * Marker presence is read from the nax process environment — the SAME source
44
+ * `withAgentOutputEnv` reads from — so an inherited CLAUDECODE/REPL_ID speaks
45
+ * for itself, and a stripped AGENT stays stripped. Reading from the child's
46
+ * already-built env would not work: by the time the spawn site runs, the
47
+ * inherited env is what nax itself was launched under, and there is no second
48
+ * "real" source of truth to consult.
49
+ */
50
+ export function agentOutputOverlay(strippedVars) {
51
+ if (strippedVars.includes("AGENT"))
52
+ return undefined;
53
+ const env = _agentOutputEnvDeps.processEnv();
54
+ if (AGENT_OUTPUT_MARKERS.some((marker) => env[marker] !== undefined))
55
+ return undefined;
56
+ return { AGENT: "1" };
57
+ }
@@ -0,0 +1,58 @@
1
+ import { killProcessGroup } from "./process-kill.ts";
2
+ export interface RunArgvOptions {
3
+ readonly argv: readonly string[];
4
+ readonly cwd: string;
5
+ readonly timeoutMs: number;
6
+ readonly stripEnvVars?: readonly string[];
7
+ /**
8
+ * Overlay applied on top of process.env, after stripping.
9
+ *
10
+ * Yarn 2+ has no --ignore-scripts option and honours the enableScripts
11
+ * setting instead, overridable per invocation by YARN_ENABLE_SCRIPTS. So the
12
+ * no-scripts mechanism is a flag for some managers and an environment
13
+ * variable for others, and both must be nax-supplied.
14
+ */
15
+ readonly env?: Readonly<Record<string, string>>;
16
+ /**
17
+ * When aborted, the process group is SIGKILLed, both readers are cancelled
18
+ * and the result resolves with `aborted: true`. US-001.
19
+ */
20
+ readonly signal?: AbortSignal;
21
+ }
22
+ export interface ArgvExecResult {
23
+ readonly exitCode: number;
24
+ readonly stdout: string;
25
+ readonly stderr: string;
26
+ readonly timedOut: boolean;
27
+ /** True when an abort killed the process group. Always set by runArgv. */
28
+ readonly aborted?: boolean;
29
+ /** True when background processes holding a stream were SIGKILLed on drain. Always set by runArgv. */
30
+ readonly orphansKilled?: boolean;
31
+ }
32
+ /**
33
+ * Time, in milliseconds, the readers are allowed to drain after `exited`
34
+ * before runArgv SIGKILLs the whole group and reports `orphansKilled`. US-001.
35
+ * Injectable for tests; not exposed as user configuration.
36
+ */
37
+ export declare const DRAIN_GRACE_MS = 500;
38
+ /** Injectable seam, mirroring _worktreeDependencyDeps. */
39
+ export declare const _argvExecDeps: {
40
+ spawn: (cmd: readonly string[], opts: import("#src/runtime/index").AgentSpawnOptions) => import("#src/runtime/index").AgentSpawnResult;
41
+ killProcessGroup: typeof killProcessGroup;
42
+ /**
43
+ * The post-exit drain grace (US-001). A real test can shrink it to keep the
44
+ * "background process holding the pipe" case under a second; production
45
+ * stays at the DRAIN_GRACE_MS constant.
46
+ */
47
+ drainGraceMs: number;
48
+ /**
49
+ * Injectable timer pair — lets the BUG-13 "hung install" test drive the
50
+ * timeout off a virtual clock instead of waiting the full 1s schema minimum.
51
+ * Mirrors `_heartbeatDeps` / `_idleWatchdogDeps` / `_authDeps`.
52
+ *
53
+ * @internal
54
+ */
55
+ setTimeout: (fn: () => void, ms: number) => unknown;
56
+ clearTimeout: (id: unknown) => void;
57
+ };
58
+ export declare function runArgv(options: RunArgvOptions): Promise<ArgvExecResult>;