@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,84 @@
1
+ /**
2
+ * The native session's in-process loop event seam (nax#2151, US-002).
3
+ *
4
+ * Typed function registrations, not an extension of `src/hooks/`: those events
5
+ * fire around a story, shell out with a 5s timeout, and cannot carry a
6
+ * rewritten tool result. Two events exist because two have real consumers
7
+ * today — invalid-call repair and the spin breaker on `before_tool`, and the
8
+ * truncation policy on `after_tool`.
9
+ *
10
+ * The dispatcher enforces four rules rather than leaving them to handler
11
+ * authors, because those rules are what let a future event be added without
12
+ * redesigning the seam:
13
+ *
14
+ * 1. Results are partial patches, never mutations. A handler returns only what
15
+ * it wants changed and the dispatcher merges. Payloads carry the live
16
+ * message array, readonly-TYPED only — mutation is not prevented at
17
+ * runtime; what §3 enforces mechanically is history REWRITING across the
18
+ * cache boundary, not object immutability.
19
+ * 2. Handlers chain, each seeing the previous handler's output, in
20
+ * registration order.
21
+ * 3. A throwing handler is logged at warn and skipped — it never fails the
22
+ * turn for its own defect. A rejected promise counts as a throw (spec
23
+ * 4.2): the await sits inside the try, so a handler whose promise rejects
24
+ * is logged-and-skipped identically to one that throws — a bare try/catch
25
+ * catches only the throw.
26
+ * 4. No handler may rewrite history. Measured prompt-cache hit rate on the
27
+ * native path is 96.7%, and Anthropic-style caching is prefix-matched, so
28
+ * rewriting anything early in the array re-bills every downstream turn at
29
+ * input rather than cacheRead — roughly 5x more expensive, not cheaper.
30
+ * `after_tool` is safe by construction: it shapes a result before the
31
+ * result enters the array. Across the full event set that safety is no
32
+ * longer left to construction — the cache-boundary checker (spec 4.7, §3)
33
+ * enforces it mechanically.
34
+ */
35
+ import type { BeforeToolOutcome, HandlerOf, LoopEvent, PatchOf, PayloadOf } from "./types.ts";
36
+ export interface LoopEventRegistry {
37
+ register<E extends LoopEvent>(event: E, handler: HandlerOf<E>): void;
38
+ dispatch<E extends LoopEvent>(event: E, payload: PayloadOf<E>): Promise<PatchOf<E>>;
39
+ }
40
+ /**
41
+ * The event names, at runtime (US-001).
42
+ *
43
+ * A plugin's registration is validated against this set before it is staged,
44
+ * because an event name arriving from a plugin is `unknown` until then. The
45
+ * list is read off `PATCHABLE_FIELDS` rather than written out again: that map
46
+ * is pinned to `LoopEvent` in both directions — a missing event fails the
47
+ * `satisfies` clause, an extra one fails the field map's exhaustiveness pin —
48
+ * so its keys are the event set, and a second hand-written copy cannot drift
49
+ * out of step with the type.
50
+ */
51
+ export declare const LOOP_EVENTS: readonly LoopEvent[];
52
+ /**
53
+ * US-002: is this a well-formed `before_tool` outcome?
54
+ *
55
+ * A plugin module is plain JavaScript and can answer anything at all — a
56
+ * string, `null`, an array, or an object whose `kind` is not a decision. What
57
+ * makes an answer an outcome is its SHAPE, not merely its object-ness, so the
58
+ * dispatcher and `wrapExternalHandler` ask this one question rather than each
59
+ * holding a half of it.
60
+ *
61
+ * This checks the `kind` only. The dispatcher also calls it on built-in
62
+ * handlers, whose return type already guarantees the kind's payload, so
63
+ * requiring the payload here would reject a built-in that a mutable test
64
+ * fixture handed an out-of-type value. The untrusted boundary — a plugin's
65
+ * answer — additionally needs the payload and is checked by
66
+ * `isCompleteBeforeToolOutcome`.
67
+ */
68
+ export declare function isBeforeToolOutcome(value: unknown): value is BeforeToolOutcome;
69
+ /**
70
+ * Is this a plugin answer that carries everything its `kind` promises? A
71
+ * `kind` alone is not enough: `block`/`terminate` must carry the `content` the
72
+ * loop records as the call's result, and `nudge` must carry the `text` it
73
+ * appends. A plugin answering `{ kind: "block" }` with nothing to say would
74
+ * otherwise reach the transcript builder as `content: undefined`, and a
75
+ * textless `nudge` would be silently downgraded to `allow` — so both are
76
+ * malformed, exactly like a `kind` that is not a decision.
77
+ */
78
+ export declare function isCompleteBeforeToolOutcome(value: unknown): value is BeforeToolOutcome;
79
+ /**
80
+ * Registration order is the chain order within each event; events are
81
+ * independent chains. The built-ins register on the same registry the loop
82
+ * dispatches from (see ./loop-handlers for their per-turn lifetime).
83
+ */
84
+ export declare function createLoopEventRegistry(): LoopEventRegistry;
@@ -0,0 +1,305 @@
1
+ /**
2
+ * The native session's in-process loop event seam (nax#2151, US-002).
3
+ *
4
+ * Typed function registrations, not an extension of `src/hooks/`: those events
5
+ * fire around a story, shell out with a 5s timeout, and cannot carry a
6
+ * rewritten tool result. Two events exist because two have real consumers
7
+ * today — invalid-call repair and the spin breaker on `before_tool`, and the
8
+ * truncation policy on `after_tool`.
9
+ *
10
+ * The dispatcher enforces four rules rather than leaving them to handler
11
+ * authors, because those rules are what let a future event be added without
12
+ * redesigning the seam:
13
+ *
14
+ * 1. Results are partial patches, never mutations. A handler returns only what
15
+ * it wants changed and the dispatcher merges. Payloads carry the live
16
+ * message array, readonly-TYPED only — mutation is not prevented at
17
+ * runtime; what §3 enforces mechanically is history REWRITING across the
18
+ * cache boundary, not object immutability.
19
+ * 2. Handlers chain, each seeing the previous handler's output, in
20
+ * registration order.
21
+ * 3. A throwing handler is logged at warn and skipped — it never fails the
22
+ * turn for its own defect. A rejected promise counts as a throw (spec
23
+ * 4.2): the await sits inside the try, so a handler whose promise rejects
24
+ * is logged-and-skipped identically to one that throws — a bare try/catch
25
+ * catches only the throw.
26
+ * 4. No handler may rewrite history. Measured prompt-cache hit rate on the
27
+ * native path is 96.7%, and Anthropic-style caching is prefix-matched, so
28
+ * rewriting anything early in the array re-bills every downstream turn at
29
+ * input rather than cacheRead — roughly 5x more expensive, not cheaper.
30
+ * `after_tool` is safe by construction: it shapes a result before the
31
+ * result enters the array. Across the full event set that safety is no
32
+ * longer left to construction — the cache-boundary checker (spec 4.7, §3)
33
+ * enforces it mechanically.
34
+ */
35
+ import { errorMessage } from "#src/infra/errors";
36
+ import { getSafeLogger } from "#src/infra/index";
37
+ import { isThenable } from "#src/internal/thenable";
38
+ import { restoreMutated, snapshotArrays } from "./payload-guard.js";
39
+ /**
40
+ * The fields each event's patch type declares, keyed by event. Only these are
41
+ * read off a handler's return, so a handler that bypasses the type cannot
42
+ * surface a non-patchable field. Two compile-time pins keep this map aligned
43
+ * with the patch types in `./types`, in both directions:
44
+ *
45
+ * - the `satisfies` pins every event to an entry whose members are valid
46
+ * patch keys for that event;
47
+ * - `_patchableFieldsExhaustive` below pins the converse — every patch key
48
+ * appears under its own event.
49
+ *
50
+ * Together: a patch field must appear here, or typecheck fails — either
51
+ * because the entry is invalid, or because the field was added to a patch
52
+ * type without an entry. The second direction is the load-bearing one: an
53
+ * unlisted field compiles fine on the type and would be silently stripped by
54
+ * `pickPatchFields`, which is exactly the failure this map exists to make
55
+ * impossible.
56
+ */
57
+ const PATCHABLE_FIELDS = {
58
+ // A decision, not a field patch — chained in dispatchBeforeTool below.
59
+ before_tool: [],
60
+ after_tool: ["content", "isError"],
61
+ before_turn: ["seed", "history"],
62
+ transform_context: ["messages"],
63
+ before_request: ["options"],
64
+ after_response: ["text", "toolCalls", "thinking"],
65
+ before_compaction: ["decline", "summary"],
66
+ before_turn_end: ["followUp"],
67
+ };
68
+ /**
69
+ * The event names, at runtime (US-001).
70
+ *
71
+ * A plugin's registration is validated against this set before it is staged,
72
+ * because an event name arriving from a plugin is `unknown` until then. The
73
+ * list is read off `PATCHABLE_FIELDS` rather than written out again: that map
74
+ * is pinned to `LoopEvent` in both directions — a missing event fails the
75
+ * `satisfies` clause, an extra one fails the field map's exhaustiveness pin —
76
+ * so its keys are the event set, and a second hand-written copy cannot drift
77
+ * out of step with the type.
78
+ */
79
+ export const LOOP_EVENTS = Object.freeze(Object.keys(PATCHABLE_FIELDS));
80
+ /**
81
+ * Only the patchable fields are read, so a handler that returns a
82
+ * denied-bearing object (bypassing the type) cannot surface one — the same
83
+ * defence keeps `usage` off an `after_response` patch, and every other event's
84
+ * surfaced-only fields out of its patch.
85
+ */
86
+ function pickPatchFields(returned, fields) {
87
+ if (typeof returned !== "object" || returned === null)
88
+ return {};
89
+ const source = returned;
90
+ const picked = {};
91
+ for (const field of fields) {
92
+ const value = source[field];
93
+ if (value !== undefined)
94
+ picked[field] = value;
95
+ }
96
+ return picked;
97
+ }
98
+ /** The four kinds that make a `before_tool` answer an outcome, and nothing else. */
99
+ const BEFORE_TOOL_KINDS = ["allow", "nudge", "block", "terminate"];
100
+ /**
101
+ * US-002: is this a well-formed `before_tool` outcome?
102
+ *
103
+ * A plugin module is plain JavaScript and can answer anything at all — a
104
+ * string, `null`, an array, or an object whose `kind` is not a decision. What
105
+ * makes an answer an outcome is its SHAPE, not merely its object-ness, so the
106
+ * dispatcher and `wrapExternalHandler` ask this one question rather than each
107
+ * holding a half of it.
108
+ *
109
+ * This checks the `kind` only. The dispatcher also calls it on built-in
110
+ * handlers, whose return type already guarantees the kind's payload, so
111
+ * requiring the payload here would reject a built-in that a mutable test
112
+ * fixture handed an out-of-type value. The untrusted boundary — a plugin's
113
+ * answer — additionally needs the payload and is checked by
114
+ * `isCompleteBeforeToolOutcome`.
115
+ */
116
+ export function isBeforeToolOutcome(value) {
117
+ if (typeof value !== "object" || value === null)
118
+ return false;
119
+ const kind = value.kind;
120
+ return typeof kind === "string" && BEFORE_TOOL_KINDS.includes(kind);
121
+ }
122
+ /**
123
+ * Is this a plugin answer that carries everything its `kind` promises? A
124
+ * `kind` alone is not enough: `block`/`terminate` must carry the `content` the
125
+ * loop records as the call's result, and `nudge` must carry the `text` it
126
+ * appends. A plugin answering `{ kind: "block" }` with nothing to say would
127
+ * otherwise reach the transcript builder as `content: undefined`, and a
128
+ * textless `nudge` would be silently downgraded to `allow` — so both are
129
+ * malformed, exactly like a `kind` that is not a decision.
130
+ */
131
+ export function isCompleteBeforeToolOutcome(value) {
132
+ if (!isBeforeToolOutcome(value))
133
+ return false;
134
+ const outcome = value;
135
+ if (value.kind === "block" || value.kind === "terminate")
136
+ return typeof outcome.content === "string";
137
+ if (value.kind === "nudge")
138
+ return typeof outcome.text === "string";
139
+ return true;
140
+ }
141
+ /**
142
+ * A handler's answer arrives typed, but its `kind` may be missing or invented,
143
+ * and reading `kind` off such an answer is a dereference the dispatcher must
144
+ * not do: it would throw out of a seam whose whole contract is that it never
145
+ * fails the turn, and it would do so OUTSIDE the handler's try (US-002).
146
+ */
147
+ function asOutcome(returned, tool) {
148
+ if (isBeforeToolOutcome(returned))
149
+ return returned;
150
+ getSafeLogger()?.warn("native-loop-events", "before_tool handler answered no valid outcome; treating it as allow", {
151
+ tool,
152
+ });
153
+ return { kind: "allow" };
154
+ }
155
+ /**
156
+ * Registration order is the chain order. `block` and `terminate` are a single
157
+ * decision, not a chained one: they short-circuit, because the outcome is the
158
+ * dispatcher's verdict and a later handler must not be able to veto it.
159
+ *
160
+ * `before_tool` is the one event whose patch is a DECISION, not a field patch,
161
+ * so it does not share the merge chain: an empty chain must still yield a
162
+ * verdict (`allow`, exactly as the pre-map dispatcher returned), and the thing
163
+ * a later handler sees is the accumulated input rewrite inside the call, not a
164
+ * merged payload.
165
+ */
166
+ async function dispatchBeforeTool(handlers, payload) {
167
+ const { call, tools } = payload;
168
+ let input;
169
+ let nudgeText;
170
+ for (const [index, handler] of handlers.entries()) {
171
+ let returned;
172
+ const snapshot = snapshotArrays({ tools });
173
+ try {
174
+ // Each handler sees the previous handler's output, so an `allow`
175
+ // rewrite is what the next one judges — and what the loop runs.
176
+ //
177
+ // Invoke synchronously and await ONLY a real thenable. The two built-in
178
+ // handlers ahead of the plugin entries answer synchronously; awaiting
179
+ // them would yield a microtask before a plugin wrapper is invoked, and
180
+ // its abort subscription is installed when it is called. An abort
181
+ // landing in that gap would then be missed and a never-settling plugin
182
+ // handler would run to its deadline instead of blocking promptly
183
+ // (nax#2151 US-003). A thenable is still awaited inside the try, so a
184
+ // rejection is caught exactly like a throw (spec 4.2).
185
+ const candidate = handler({
186
+ call: { ...call, input: input ?? call.input },
187
+ tools,
188
+ });
189
+ returned = isThenable(candidate) ? await candidate : candidate;
190
+ }
191
+ catch (err) {
192
+ getSafeLogger()?.warn("native-loop-events", "before_tool handler threw; skipping it", {
193
+ tool: call.name,
194
+ error: errorMessage(err),
195
+ });
196
+ continue;
197
+ }
198
+ finally {
199
+ restoreMutated(snapshot, "before_tool", index);
200
+ }
201
+ const outcome = asOutcome(returned, call.name);
202
+ if (outcome.kind === "block" || outcome.kind === "terminate")
203
+ return outcome;
204
+ if (outcome.kind === "nudge")
205
+ nudgeText = outcome.text;
206
+ if (outcome.input !== undefined)
207
+ input = outcome.input;
208
+ }
209
+ // The nudge carries the accumulated rewrite: a nudged call still runs, so
210
+ // dropping the rewrite would run the model's uncorrected input. The
211
+ // built-in chain produces this pair — the invalid-call repair strips a
212
+ // `null` optional, then the spin breaker nudges a repeat of it (nax#2200).
213
+ if (nudgeText !== undefined) {
214
+ return input === undefined ? { kind: "nudge", text: nudgeText } : { kind: "nudge", text: nudgeText, input };
215
+ }
216
+ return input === undefined ? { kind: "allow" } : { kind: "allow", input };
217
+ }
218
+ /**
219
+ * The seven field-patch events. Serial `for`, each handler awaited INSIDE the
220
+ * try (spec 4.2), patches accumulated in registration order, each handler
221
+ * seeing the previous one's output as the payload it is handed.
222
+ */
223
+ async function dispatchChain(event, handlers, payload) {
224
+ if (handlers.length === 0) {
225
+ // The empty fast path returns BEFORE touching the payload — never clone:
226
+ // transform_context fires before every request against a 200k+ token
227
+ // array, and cloning for an empty chain would make every request
228
+ // allocate a full copy for nothing (spec 4.4).
229
+ return {};
230
+ }
231
+ const fields = PATCHABLE_FIELDS[event];
232
+ let current = payload;
233
+ let accumulated = {};
234
+ for (const [index, handler] of handlers.entries()) {
235
+ const snapshot = snapshotArrays(current);
236
+ let returned;
237
+ try {
238
+ // The await sits inside the try, so a rejected promise is caught
239
+ // exactly like a throw (spec 4.2).
240
+ returned = await handler(current);
241
+ }
242
+ catch (err) {
243
+ // When the payload carries a tool name (after_tool does), the warn
244
+ // names the tool the failing handler was shaping — the context the
245
+ // first-argument dispatcher carried as `tool: call.name` before the
246
+ // single-payload signature replaced it.
247
+ const { toolName } = payload;
248
+ getSafeLogger()?.warn("native-loop-events", `${event} handler threw; skipping it`, {
249
+ event,
250
+ ...(toolName !== undefined ? { tool: toolName } : {}),
251
+ error: errorMessage(err),
252
+ });
253
+ continue;
254
+ }
255
+ finally {
256
+ restoreMutated(snapshot, event, index);
257
+ }
258
+ const picked = pickPatchFields(returned, fields);
259
+ if (Object.keys(picked).length > 0) {
260
+ // `before_request.options` is itself a partial patch. Preserve fields
261
+ // supplied by earlier handlers so independently registered policy hooks
262
+ // compose (for example, one can set temperature while another disables
263
+ // thinking for a retry).
264
+ const merged = event === "before_request" && typeof picked.options === "object" && picked.options !== null
265
+ ? { ...picked, options: { ...current.options, ...picked.options } }
266
+ : picked;
267
+ accumulated = { ...accumulated, ...merged };
268
+ // Only patch-declared fields ever overwrite anything, so the next
269
+ // handler sees the previous handler's output and nothing else moved.
270
+ current = { ...current, ...merged };
271
+ }
272
+ }
273
+ // Sound: `accumulated` holds only fields PATCHABLE_FIELDS declares for this
274
+ // event, which is exactly what PatchOf<E> declares.
275
+ return accumulated;
276
+ }
277
+ /**
278
+ * Registration order is the chain order within each event; events are
279
+ * independent chains. The built-ins register on the same registry the loop
280
+ * dispatches from (see ./loop-handlers for their per-turn lifetime).
281
+ */
282
+ export function createLoopEventRegistry() {
283
+ const byEvent = new Map();
284
+ return {
285
+ register(event, handler) {
286
+ // Erase E for storage: the map keys by event, and dispatch only ever
287
+ // calls a handler back with the payload type it registered for, so the
288
+ // widening loses nothing at the call sites.
289
+ const erased = handler;
290
+ const handlers = byEvent.get(event);
291
+ if (handlers === undefined) {
292
+ byEvent.set(event, [erased]);
293
+ return;
294
+ }
295
+ handlers.push(erased);
296
+ },
297
+ async dispatch(event, payload) {
298
+ const handlers = byEvent.get(event) ?? [];
299
+ if (event === "before_tool") {
300
+ return dispatchBeforeTool(handlers, payload);
301
+ }
302
+ return dispatchChain(event, handlers, payload);
303
+ },
304
+ };
305
+ }
@@ -0,0 +1,251 @@
1
+ /**
2
+ * The native session's loop-event map (nax#2151, P3).
3
+ *
4
+ * pi's `before_run`/`before_run_end` are `before_turn`/`before_turn_end` here:
5
+ * `runNativeTurn` is ONE TURN, while a nax "run" holds many stories each
6
+ * holding many turns, and `src/hooks/` already fires genuine run-level events.
7
+ * Keeping the vocabularies disjoint is the same reasoning ADR-030's D11 applied
8
+ * to the bash mode axis.
9
+ *
10
+ * `before_payload`, `before_drive` and `before_navigation` are deliberately
11
+ * absent: the payload is built inside nax-ai behind the import boundary, and
12
+ * nax has no branch navigation.
13
+ */
14
+ import type { ThinkingBlock, ToolCall, ToolDefinition } from "@nathapp/nax-ai";
15
+ import type { TokenUsage } from "#src/cost/standard-types";
16
+ import type { TranscriptMessage as NativeTranscriptMessage } from "../compaction.ts";
17
+ import type { DenialInfo } from "../tool-result.ts";
18
+ export type LoopEvent = "before_tool" | "after_tool" | "before_turn" | "transform_context" | "before_request" | "after_response" | "before_compaction" | "before_turn_end";
19
+ export interface BeforeToolPayload {
20
+ readonly call: ToolCall;
21
+ readonly tools: readonly ToolDefinition[];
22
+ }
23
+ /**
24
+ * `before_tool` outcomes:
25
+ *
26
+ * - `allow` optionally rewrites the tool's input; later handlers see the
27
+ * rewrite, and the loop records it in the transcript and invokes the tool
28
+ * with it.
29
+ * - `nudge` still invokes the tool, and prefixes its result with the handler's
30
+ * text. `input` carries any `allow` rewrite accumulated earlier in the chain,
31
+ * so a nudge never drops a correction — the null-optional strip ahead of the
32
+ * spin breaker is the built-in pair (nax#2200).
33
+ * - `block` answers without invoking the tool. `input` optionally carries the
34
+ * input the transcript should record instead, which is how the invalid-call
35
+ * repair keeps the rejected value out of history (nax#2047) — recording the
36
+ * model's call minus that property, never a fabricated one (nax#2200).
37
+ * - `terminate` answers every outstanding call in the current batch — the spin
38
+ * breaker's stop is a batch-level outcome, not a per-call one, and a batch
39
+ * left with an unanswered `tool_call` is rejected by strict providers.
40
+ */
41
+ export type BeforeToolOutcome = {
42
+ kind: "allow";
43
+ input?: Record<string, unknown>;
44
+ } | {
45
+ kind: "nudge";
46
+ text: string;
47
+ input?: Record<string, unknown>;
48
+ } | {
49
+ kind: "block";
50
+ content: string;
51
+ isError?: boolean;
52
+ input?: Record<string, unknown>;
53
+ } | {
54
+ kind: "terminate";
55
+ content: string;
56
+ isError?: boolean;
57
+ };
58
+ /**
59
+ * What an `after_tool` handler may change. Deliberately partial: a handler
60
+ * returns only the fields it wants patched.
61
+ *
62
+ * `denied` is NOT patchable — a refused Write is not a crashed Write (ADR-029
63
+ * s5), and letting a handler flip that erases a distinction the model is meant
64
+ * to act on.
65
+ */
66
+ export type AfterToolPatch = {
67
+ content?: string;
68
+ isError?: boolean;
69
+ };
70
+ export interface AfterToolPayload {
71
+ readonly content: string;
72
+ readonly isError?: boolean;
73
+ /** Surfaced to handlers, never writable by them. */
74
+ readonly denied?: DenialInfo;
75
+ /** The name of the tool call the result answers, from the dispatched call. */
76
+ readonly toolName?: string;
77
+ /** The provider tool-call id the result answers, from the dispatched call. */
78
+ readonly callId?: string;
79
+ /**
80
+ * Present when `before_tool` produced a nudge that will be PREPENDED to the
81
+ * surviving content. The model-facing truncation handler spends these bytes
82
+ * out of the result's own budget (`nudgeOverheadBytes`), so the ceiling
83
+ * stays unconditional — without them a nudged result would exceed
84
+ * `MODEL_MAX_BYTES` by exactly the nudge's width.
85
+ */
86
+ readonly nudgeText?: string;
87
+ }
88
+ /** `before_turn` — fires once as a turn starts, after the transcript loads. */
89
+ export interface BeforeTurnPayload {
90
+ readonly prompt: string;
91
+ /** The loaded transcript. Readonly: only a boundary rewrite may touch it. */
92
+ readonly history: readonly NativeTranscriptMessage[];
93
+ readonly sessionName: string;
94
+ /** Dispatcher-computed (spec 3.4). A handler may never assert a boundary. */
95
+ readonly boundary: boolean;
96
+ }
97
+ export interface BeforeTurnPatch {
98
+ /** The seed messages being appended now. */
99
+ readonly seed?: readonly NativeTranscriptMessage[];
100
+ /** Honoured ONLY when payload.boundary is true (spec 3.2, 6.1). */
101
+ readonly history?: readonly NativeTranscriptMessage[];
102
+ }
103
+ /** `transform_context` — fires before every provider request attempt. */
104
+ export interface TransformContextPayload {
105
+ readonly messages: readonly NativeTranscriptMessage[];
106
+ readonly tools: readonly ToolDefinition[];
107
+ readonly model?: string;
108
+ readonly anchorIndex?: number;
109
+ readonly boundary: boolean;
110
+ }
111
+ export interface TransformContextPatch {
112
+ readonly messages?: readonly NativeTranscriptMessage[];
113
+ }
114
+ /** `before_request` — per request ATTEMPT, including transport retries. */
115
+ export interface BeforeRequestPayload {
116
+ readonly model?: string;
117
+ readonly roundTrip: number;
118
+ /** 1 for the first attempt, 2..n inside retryTransportFault. */
119
+ readonly attempt: number;
120
+ readonly options: CompleteCallOptions;
121
+ }
122
+ export interface BeforeRequestPatch {
123
+ readonly options?: Partial<CompleteCallOptions>;
124
+ }
125
+ /**
126
+ * The per-call options bag added to TurnDeps.complete in Task 4 (spec 6.3).
127
+ * Minimal and additive by ruling: P6's extraction inherits one optional
128
+ * parameter, not a new concept.
129
+ */
130
+ export interface CompleteCallOptions {
131
+ readonly thinking?: boolean;
132
+ readonly temperature?: number;
133
+ }
134
+ /** `after_response` — fires on a settled assistant message. */
135
+ export interface AfterResponsePayload {
136
+ readonly text: string;
137
+ readonly toolCalls?: readonly ToolCall[];
138
+ readonly thinking?: readonly ThinkingBlock[];
139
+ /** Surfaced, NEVER patchable: billing truth is not a handler's to rewrite. */
140
+ readonly usage: TokenUsage;
141
+ readonly costUsd: number;
142
+ readonly roundTrip: number;
143
+ }
144
+ export interface AfterResponsePatch {
145
+ readonly text?: string;
146
+ readonly toolCalls?: readonly ToolCall[];
147
+ readonly thinking?: readonly ThinkingBlock[];
148
+ }
149
+ /** `before_compaction` — fires in both the proactive and overflow branches. */
150
+ export interface BeforeCompactionPayload {
151
+ readonly reason: "proactive" | "overflow";
152
+ readonly toSummarize: readonly NativeTranscriptMessage[];
153
+ readonly previousSummary?: string;
154
+ readonly estimatedTokens: number;
155
+ }
156
+ export interface BeforeCompactionPatch {
157
+ /** Honoured when reason is "proactive", IGNORED + logged when "overflow". */
158
+ readonly decline?: boolean;
159
+ /** A replacement summary, skipping the summarizer call. */
160
+ readonly summary?: string;
161
+ }
162
+ /** `before_turn_end` — fires before the final saveTranscript. */
163
+ export interface BeforeTurnEndPayload {
164
+ readonly messages: readonly NativeTranscriptMessage[];
165
+ readonly roundTrips: number;
166
+ /**
167
+ * How the turn ended. "completed" includes a stop (spin, invalid-call budget,
168
+ * deadline) -- see `stopped`. "aborted" means the turn signal fired (caller,
169
+ * idle watchdog or whole-turn deadline); "errored" is any other throw.
170
+ * On "aborted"/"errored" the result is ignored (review #20).
171
+ */
172
+ readonly ended: "completed" | "aborted" | "errored";
173
+ /** True when the turn ended by a STOP; followUp is not offered then. */
174
+ readonly stopped: boolean;
175
+ readonly followUpsSoFar: number;
176
+ }
177
+ export interface BeforeTurnEndPatch {
178
+ /** Re-enters the loop with another user turn. Capped; see registry.ts. */
179
+ readonly followUp?: string;
180
+ }
181
+ export interface LoopEventMap {
182
+ before_tool: {
183
+ payload: BeforeToolPayload;
184
+ patch: BeforeToolOutcome;
185
+ };
186
+ after_tool: {
187
+ payload: AfterToolPayload;
188
+ patch: AfterToolPatch;
189
+ };
190
+ before_turn: {
191
+ payload: BeforeTurnPayload;
192
+ patch: BeforeTurnPatch;
193
+ };
194
+ transform_context: {
195
+ payload: TransformContextPayload;
196
+ patch: TransformContextPatch;
197
+ };
198
+ before_request: {
199
+ payload: BeforeRequestPayload;
200
+ patch: BeforeRequestPatch;
201
+ };
202
+ after_response: {
203
+ payload: AfterResponsePayload;
204
+ patch: AfterResponsePatch;
205
+ };
206
+ before_compaction: {
207
+ payload: BeforeCompactionPayload;
208
+ patch: BeforeCompactionPatch;
209
+ };
210
+ before_turn_end: {
211
+ payload: BeforeTurnEndPayload;
212
+ patch: BeforeTurnEndPatch;
213
+ };
214
+ }
215
+ export type PayloadOf<E extends LoopEvent> = LoopEventMap[E]["payload"];
216
+ export type PatchOf<E extends LoopEvent> = LoopEventMap[E]["patch"];
217
+ export type HandlerOf<E extends LoopEvent> = (payload: PayloadOf<E>) => PatchOf<E> | Promise<PatchOf<E>>;
218
+ /**
219
+ * The read-only facts a plugin handler is handed alongside its payload.
220
+ *
221
+ * Owned by the coding-agent side on purpose: a plugin imports these types, and
222
+ * native code never imports the plugin system. Everything here is a fact about
223
+ * the session the handler is running in — there is deliberately no abort, no UI
224
+ * and no config access, so a plugin scopes itself by reading this at runtime
225
+ * rather than by declaring filters.
226
+ */
227
+ export interface LoopHandlerContext {
228
+ readonly sessionName: string;
229
+ readonly role?: string;
230
+ readonly storyId?: string;
231
+ readonly feature?: string;
232
+ readonly workdir?: string;
233
+ readonly model?: string;
234
+ readonly provider?: string;
235
+ }
236
+ /**
237
+ * A plugin's handler for one event: same payload and patch as a built-in,
238
+ * plus the context, and `undefined` is a valid "no patch" answer.
239
+ */
240
+ export type ExternalHandlerOf<E extends LoopEvent> = (payload: PayloadOf<E>, ctx: LoopHandlerContext) => PatchOf<E> | undefined | Promise<PatchOf<E> | undefined>;
241
+ /** One staged registration: which plugin it came from, its event, its handler. */
242
+ export interface LoopHandlerEntry {
243
+ readonly plugin: string;
244
+ readonly event: LoopEvent;
245
+ readonly handler: ExternalHandlerOf<LoopEvent>;
246
+ }
247
+ /**
248
+ * Every plugin-contributed handler for a run, in install order. The registry
249
+ * returns this frozen, and an empty set is the normal case.
250
+ */
251
+ export type LoopHandlerSet = readonly LoopHandlerEntry[];
@@ -0,0 +1,14 @@
1
+ /**
2
+ * The native session's loop-event map (nax#2151, P3).
3
+ *
4
+ * pi's `before_run`/`before_run_end` are `before_turn`/`before_turn_end` here:
5
+ * `runNativeTurn` is ONE TURN, while a nax "run" holds many stories each
6
+ * holding many turns, and `src/hooks/` already fires genuine run-level events.
7
+ * Keeping the vocabularies disjoint is the same reasoning ADR-030's D11 applied
8
+ * to the bash mode axis.
9
+ *
10
+ * `before_payload`, `before_drive` and `before_navigation` are deliberately
11
+ * absent: the payload is built inside nax-ai behind the import boundary, and
12
+ * nax has no branch navigation.
13
+ */
14
+ export {};