@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
package/CHANGELOG.md ADDED
@@ -0,0 +1,24 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@nathapp/nax-agent` are recorded here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). While the version is `0.x`, a minor
5
+ release may change the public API.
6
+
7
+ ## [0.1.0] - 2026-10-03
8
+
9
+ First published version. Extracted from nax, where it was the native agent.
10
+
11
+ ### Added
12
+
13
+ - The session contract, the native session adapter and `nativeComplete`, the tool set, permission
14
+ resolution, the OS sandbox, command-safety and the cost core, behind `@nathapp/nax-agent`.
15
+ - Process-wide slots: `setAgentLogger`, `configureCredentials`, and `setAgentRuntime` with a Node
16
+ default (`nodeRuntime`).
17
+ - Host ports: `runDeclaredCommand`, `ProtectedPathsPolicy`, `commandInterceptor`.
18
+ - `@nathapp/nax-agent/internal`, nax-only and outside semver.
19
+ - `api/nax-agent.api.txt`: the built public API, checked in CI.
20
+
21
+ ### Notes
22
+
23
+ - Requires Node.js >= 22.19.0. No Bun APIs ship in the package.
24
+ - `.` exports no `_`-prefixed name; test seams and reset hooks are on `./internal` only.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025-2026 William Khoo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,49 @@
1
+ # @nathapp/nax-agent
2
+
3
+ nax's native coding agent as a package: the session contract, the native session adapter and its turn loop over `@nathapp/nax-ai`, the tool set, permission resolution, the OS sandbox, command-safety and cost accounting.
4
+
5
+ > **Pre-1.0, not yet published.** `0.1.0` is the first planned version. Until `1.0` the API of `.` may change in any minor release. Pin an exact version.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @nathapp/nax-agent
11
+ ```
12
+
13
+ Requires **Node.js >= 22.19.0**. The package is ESM only and ships no Bun code: it runs on Node, and on Bun, with the default runtime.
14
+
15
+ ## Entry points
16
+
17
+ - **`@nathapp/nax-agent`** is the supported entry. Every export is named, and none starts with `_`. Its exact names are pinned in [`api/nax-agent.api.txt`](api/nax-agent.api.txt), which CI compares with the built declarations.
18
+ - **`@nathapp/nax-agent/internal`** is **nax-only and outside semver.** nax bundles this package and reaches below the public entry for shared helpers, `NaxError`, deep modules and the `_*Deps` test seams. Names, shapes and behaviour there can change in any release, patch included, and a change there is not a breaking change. Do not import it from another project.
19
+
20
+ ## Process-wide slots
21
+
22
+ The host installs these once, near startup. They are module-level, so they apply to everything in the process.
23
+
24
+ | Slot | Install | When unset |
25
+ |:-----|:--------|:-----------|
26
+ | Logger | `setAgentLogger(logger)` (`null` clears) | Logging is silent: `getLogger()` is a no-op logger and `getSafeLogger()` is `null`. |
27
+ | Credentials | `configureCredentials({ configDir, readAuthConfig })` | The first credential read throws `NaxError` with code `CREDENTIALS_NOT_CONFIGURED`. There is no default config directory. |
28
+ | Runtime | `setAgentRuntime(runtime)` (`null` clears) | `getAgentRuntime()` returns `nodeRuntime`, built on `node:child_process` and `node:fs`. |
29
+
30
+ `AgentRuntime` is the process and glob contract (`spawn`, `glob`, `globSync`). The Node default is complete; install your own only to change how the agent spawns processes or expands globs.
31
+
32
+ ## Ports the host supplies
33
+
34
+ Three pieces of host knowledge are passed in as data or functions, because the package cannot know them. Their behaviour when you omit them differs, so check each one.
35
+
36
+ - **`runDeclaredCommand`** runs a command your project declared (a test or lint command), never one the model wrote. If you do not supply it, the `RunCommand` tool answers `exit 1` with "no declared-command runner is configured for this session" and starts no process. It fails closed.
37
+ - **`ProtectedPathsPolicy`** names the paths you own and want kept away from the agent: git pathspecs the Git tool excludes from its default view, gitignore patterns `GitCommit` refuses to stage, the project state directory, the credential directory and the trust-store file the sandbox protects. If you do not supply it, the Git tool excludes nothing from its default view, and `GitCommit` fails closed: it refuses every path and stages nothing until the policy supplies a non-empty `gitIgnorePatterns` (an empty list refuses the same way). Supply it whenever the agent works in a directory that holds files you own. Building a sandboxed session requires it.
38
+ - **`commandInterceptor`** may rewrite a command before it runs (for example to prefix a wrapper binary). Rewrites are validated: an argv rewrite may only prefix the original argv with the provider's own binary, and a shell rewrite goes through the same narrowing. If you do not supply one, commands run unchanged. An interceptor that throws, or returns a rewrite that fails validation, is treated as a decline, and the original command runs.
39
+
40
+ ## Status and roadmap
41
+
42
+ The embedder-facing session API is still being designed, so `0.x` may reshape `.` with a minor bump. See [`CHANGELOG.md`](CHANGELOG.md).
43
+
44
+ Maintainers: see the [release procedure](https://github.com/nathapp-io/nax/blob/main/packages/nax-agent/RELEASING.md)
45
+ for the manual 0.1.0 publish and OTP step, trusted-publisher setup and subsequent tagged releases.
46
+
47
+ ## License
48
+
49
+ MIT
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Bash-specific grant resolution for `buildCodingToolSupport`.
3
+ *
4
+ * Extracted from coding-tool-support.ts, which sits at the 600-line source
5
+ * limit, so this stage's grant math -- and the explanatory comments that are
6
+ * load-bearing for reading the ADR-030 gating rule correctly -- have room to
7
+ * live without pushing the caller over the limit.
8
+ *
9
+ * Pure: no I/O, no `NaxError`. Decides nothing about the empty-root guard or
10
+ * the terminal `tools.length === 0` guard; both stay in coding-tool-support.ts,
11
+ * where the rest of the runtime is assembled.
12
+ */
13
+ import type { BashApprovalMode } from "#src/config/bash-approval";
14
+ import { type CodingToolName, type ToolGrant, type ToolPatternNarrowing } from "#src/tools/index";
15
+ export interface BashSupportResolution {
16
+ /**
17
+ * The grants `compileToolPolicy` should compile -- narrowed, and with the
18
+ * ADR-030 synthetic `Bash(*)` grant appended under `raw` when applicable.
19
+ */
20
+ readonly effectiveGrants: readonly ToolGrant[];
21
+ /** Whether the op should receive a Bash tool at all (the declaration ceiling). */
22
+ readonly allowBash: boolean;
23
+ /**
24
+ * The patterns the Bash tool's description should name -- the EFFECTIVE
25
+ * grant (post-synthetic), not the pre-synthetic human grant, so a `raw`
26
+ * stage with no human `Bash(...)` rule still names what it can actually
27
+ * run instead of the stale "no command forms are granted" (ADR-030 / F3).
28
+ * `createBashTool` ignores this entirely under `raw` (it has its own
29
+ * static raw description), so the distinction only matters for
30
+ * `gated`/`escalate`, where it is identical to the pre-synthetic grant --
31
+ * `raw` is the only mode that ever synthesizes one.
32
+ */
33
+ readonly bashDescriptionPatterns: readonly string[];
34
+ }
35
+ /**
36
+ * Resolve the Bash-specific half of a stage's compiled grants.
37
+ *
38
+ * `grants` is the RAW (pre-narrow) grant list, matching what
39
+ * `buildCodingToolSupport` used to pass into `narrowGrants` inline.
40
+ */
41
+ export declare function resolveBashSupport(args: {
42
+ declared: readonly CodingToolName[];
43
+ grants: readonly ToolGrant[];
44
+ toolPatterns?: ToolPatternNarrowing;
45
+ bashApproval: BashApprovalMode;
46
+ }): BashSupportResolution;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Bash-specific grant resolution for `buildCodingToolSupport`.
3
+ *
4
+ * Extracted from coding-tool-support.ts, which sits at the 600-line source
5
+ * limit, so this stage's grant math -- and the explanatory comments that are
6
+ * load-bearing for reading the ADR-030 gating rule correctly -- have room to
7
+ * live without pushing the caller over the limit.
8
+ *
9
+ * Pure: no I/O, no `NaxError`. Decides nothing about the empty-root guard or
10
+ * the terminal `tools.length === 0` guard; both stay in coding-tool-support.ts,
11
+ * where the rest of the runtime is assembled.
12
+ */
13
+ import { BASH_TOOL_NAME, narrowGrants, } from "#src/tools/index";
14
+ /**
15
+ * Resolve the Bash-specific half of a stage's compiled grants.
16
+ *
17
+ * `grants` is the RAW (pre-narrow) grant list, matching what
18
+ * `buildCodingToolSupport` used to pass into `narrowGrants` inline.
19
+ */
20
+ export function resolveBashSupport(args) {
21
+ // Narrowed, not raw: `narrowGrants` is what the POLICY compiles, so reading
22
+ // the raw list here would name forms in the tool's description that the
23
+ // policy then refuses -- the wasted turn the `patterns` option exists to
24
+ // prevent, inverted.
25
+ const narrowedGrants = narrowGrants(args.grants, args.toolPatterns);
26
+ const bashGrant = narrowedGrants.findLast((grant) => grant.tool === BASH_TOOL_NAME);
27
+ const allowBash = args.declared.includes(BASH_TOOL_NAME);
28
+ // ADR-030: `raw` changes GATING, not GRANTING — the Bash tool still has to be
29
+ // granted or `callTool` never reaches the policy. The grant is synthetic
30
+ // (no human wrote a `Bash(...)` rule) and is deliberately conditioned on the
31
+ // op having DECLARED Bash. That condition is what keeps review ops and the
32
+ // verifier shell-free under every mode: they declare no Bash, so no mode can
33
+ // hand them one. Never grant unconditionally here.
34
+ const syntheticGrant = args.bashApproval === "raw" && allowBash && bashGrant === undefined
35
+ ? { tool: BASH_TOOL_NAME, patterns: ["*"] }
36
+ : undefined;
37
+ const effectiveGrants = syntheticGrant !== undefined ? [...narrowedGrants, syntheticGrant] : narrowedGrants;
38
+ const effectiveBashGrant = bashGrant ?? syntheticGrant;
39
+ return {
40
+ effectiveGrants,
41
+ allowBash,
42
+ bashDescriptionPatterns: effectiveBashGrant?.patterns ?? [],
43
+ };
44
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * The session-local tools an operation declares: RunCommand (its declared
3
+ * commands and, when `Exec` is declared, its argv branch) and Bash.
4
+ *
5
+ * Extracted from coding-tool-support.ts to keep that file under its 600-line
6
+ * source limit ahead of the P4 sandbox wiring. A pure move: every comment that
7
+ * explains a field below travelled with it.
8
+ */
9
+ import type { BashApprovalMode } from "#src/config/bash-approval";
10
+ import type { QualityCommandSpec } from "#src/internal/command-spec/index";
11
+ import type { CommandLauncher } from "#src/sandbox/index";
12
+ import { type CodingTool, type DeclaredCommandRunner, type ToolGrant } from "#src/tools/index";
13
+ export interface DeclaredCommandToolsArgs {
14
+ readonly declaredCommands: ReadonlyMap<string, QualityCommandSpec>;
15
+ readonly allowExec: boolean;
16
+ readonly execGrant: ToolGrant | undefined;
17
+ readonly allowBash: boolean;
18
+ readonly bashDescriptionPatterns: readonly string[];
19
+ readonly bashApproval: BashApprovalMode;
20
+ /** A human can answer an escalated Bash command (ADR-030, amended for P4). */
21
+ readonly humanApproval?: boolean;
22
+ readonly root: string;
23
+ readonly repoRoot?: string;
24
+ readonly packageWorkdir?: string;
25
+ readonly commandCwd?: string;
26
+ readonly allowScripts?: boolean;
27
+ readonly packageName?: string;
28
+ readonly stripEnvVars?: readonly string[];
29
+ readonly shell?: string;
30
+ /** Port 7: runs declared commands; nax supplies `runQualityCommand`. */
31
+ readonly runDeclaredCommand?: DeclaredCommandRunner;
32
+ /** P4: how Bash and Exec-branch commands run; absent = direct spawn (tests). */
33
+ readonly launcher?: CommandLauncher;
34
+ }
35
+ export declare function buildDeclaredCommandTools(args: DeclaredCommandToolsArgs): CodingTool[];
@@ -0,0 +1,56 @@
1
+ import { createBashTool, createRunCommandTool, } from "#src/tools/index";
2
+ export function buildDeclaredCommandTools(args) {
3
+ return [
4
+ ...(args.declaredCommands.size > 0 || args.allowExec
5
+ ? [
6
+ createRunCommandTool(args.declaredCommands, {
7
+ stripEnvVars: args.stripEnvVars,
8
+ commandCwd: args.commandCwd ?? args.root,
9
+ runDeclaredCommand: args.runDeclaredCommand,
10
+ ...(args.allowExec
11
+ ? {
12
+ exec: {
13
+ repoRoot: args.repoRoot ?? args.root,
14
+ // Post-root-move: `args.root` is the repo root, so the
15
+ // fallback only matters for single-package repos where
16
+ // the two coincide (and for tests not threading
17
+ // `packageWorkdir`). Production always threads it via
18
+ // `commandCwd` plumbing in `resolveCodingToolSupport`
19
+ // (Task 10), which makes `effectiveTarget`'s
20
+ // `packageRelPath === ""` collapse impossible for a
21
+ // package story.
22
+ packageWorkdir: args.packageWorkdir ?? args.root,
23
+ allowScripts: args.allowScripts ?? false,
24
+ // The compiled grant, not BUILT_IN_EXEC_PATTERNS -- a
25
+ // project's own Exec(...) expression replaces that
26
+ // list rather than extending it (see the comment on
27
+ // BUILT_IN_EXEC_PATTERNS in src/config/permissions.ts).
28
+ // `allowExec` is true only when execGrant is defined,
29
+ // so this array is never actually empty at this call
30
+ // site; the fallback exists only for the type.
31
+ patterns: args.execGrant?.patterns ?? [],
32
+ ...(args.packageName !== undefined ? { packageName: args.packageName } : {}),
33
+ ...(args.launcher !== undefined ? { launcher: args.launcher } : {}),
34
+ },
35
+ }
36
+ : {}),
37
+ }),
38
+ ]
39
+ : []),
40
+ ...(args.allowBash
41
+ ? [
42
+ createBashTool({
43
+ ...(args.shell !== undefined ? { shell: args.shell } : {}),
44
+ ...(args.stripEnvVars !== undefined ? { stripEnvVars: args.stripEnvVars } : {}),
45
+ // The EFFECTIVE grant, so the description names what THIS
46
+ // stage may actually run, incl. the synthetic grant under
47
+ // `raw` (ADR-030 / F3) -- ignored under `raw` regardless.
48
+ patterns: args.bashDescriptionPatterns,
49
+ bashApproval: args.bashApproval,
50
+ ...(args.humanApproval === true ? { humanApproval: true } : {}),
51
+ ...(args.launcher !== undefined ? { launcher: args.launcher } : {}),
52
+ }),
53
+ ]
54
+ : []),
55
+ ];
56
+ }
@@ -0,0 +1,74 @@
1
+ import { homedir } from "node:os";
2
+ import type { SandboxConfig } from "#src/config/schemas-sandbox";
3
+ import { type CommandLauncher, defaultTempRoots, listCredentialFiles, listGitGuardFiles, listNaxEntries, probeSandboxOnce, resolveGitLayout, runTempRoots, sandboxBackendFor, strayCommonDirTripwire } from "#src/sandbox/index";
4
+ import type { ProtectedPathsPolicy } from "#src/tools/index";
5
+ export declare const _sessionSandboxDeps: {
6
+ backendFor: typeof sandboxBackendFor;
7
+ probe: typeof probeSandboxOnce;
8
+ gitLayout: typeof resolveGitLayout;
9
+ naxEntries: typeof listNaxEntries;
10
+ gitGuardFiles: typeof listGitGuardFiles;
11
+ commonDirTripwire: typeof strayCommonDirTripwire;
12
+ credentialFiles: typeof listCredentialFiles;
13
+ tempRoots: typeof defaultTempRoots;
14
+ homedir: typeof homedir;
15
+ platform: () => NodeJS.Platform;
16
+ /** US-002 — creates the session temp dir before the policy is built. */
17
+ mkdir: (path: string) => Promise<unknown>;
18
+ /** US-002 — the host temp dir, kept injectable so the policy choice is testable. */
19
+ tmpdir: () => string;
20
+ /** US-002 — the temp roots of one confined run, given its own root. */
21
+ runTempRoots: typeof runTempRoots;
22
+ };
23
+ export declare function resolveSessionSandbox(args: {
24
+ readonly config: SandboxConfig | undefined;
25
+ readonly root: string;
26
+ readonly outputDir?: string;
27
+ readonly needsLauncher: boolean;
28
+ readonly storyId?: string;
29
+ /** US-004 — per-session temp directory the launcher creates and exports as TMPDIR/TMP/TEMP. */
30
+ readonly tmpDir?: string;
31
+ /** US-002 — the run's own temp root, present whenever `tmpDir` is (dispatch-supplied). */
32
+ readonly runTmpRoot?: string;
33
+ /** Host-owned paths the policy denies (S1 spec port 6); nax passes `naxProtectedPaths()`. */
34
+ readonly protectedPaths: ProtectedPathsPolicy;
35
+ }): Promise<CommandLauncher>;
36
+ /** The compile-time policy refusal for `raw` (Task 8), or undefined. */
37
+ export declare function rawRefusalFor(launcher: CommandLauncher | undefined): string | undefined;
38
+ /**
39
+ * US-004: whether the session's sandbox confines temp writes to this run's own
40
+ * temp root.
41
+ *
42
+ * True exactly when the launcher is available AND says `sharedTmp: false` —
43
+ * the only state under which the command guard may skip the classifier for a
44
+ * temp-only command (`src/agents/coding-tool-support.ts` → `tempConfined` →
45
+ * `src/command-safety/guard.ts:185`). An available launcher without
46
+ * `sharedTmp`, an unavailable or disabled one, and no launcher at all all read
47
+ * as NOT confined.
48
+ *
49
+ * That is the RESOLVE-time answer, fixed when the launcher is built, and it is
50
+ * deliberately NOT the answer the policy narrows on. `SandboxPolicyInput.confined`
51
+ * ANDs it with whether the per-command session-dir `mkdir` succeeded
52
+ * (`src/sandbox/launcher.ts:194`), because the `export TMPDIR=…` prefix rides on
53
+ * that same mkdir. So a session whose dir fails to re-create reports `true` here
54
+ * while the policy for that ONE command is the unconflined one, `/tmp/claude`
55
+ * included — which means the guard's temp-only exemption can be claimed for a
56
+ * command that is not in fact confined. Deliberate, and documented on
57
+ * `SandboxPolicyInput.confined` (`src/sandbox/policy-builder.ts:41-64`); do not
58
+ * reconcile the two by making either follow the other.
59
+ */
60
+ export declare function isTempConfined(launcher: CommandLauncher | undefined): boolean;
61
+ /**
62
+ * US-002: the raw-screen options `compileToolPolicy` consumes, derived from the
63
+ * launcher's state.
64
+ *
65
+ * `rawBashRefusal` is exactly what `rawRefusalFor` returns (an unavailable
66
+ * launcher refuses every call). `sandboxWrapped: true` is added for an available
67
+ * launcher: the command really does run inside the OS sandbox, so the raw screen
68
+ * stops refusing a feature PRD the command only READS. A disabled launcher
69
+ * yields neither key.
70
+ */
71
+ export declare function rawScreenOptionsFor(launcher: CommandLauncher | undefined): {
72
+ rawBashRefusal?: string;
73
+ sandboxWrapped?: true;
74
+ };
@@ -0,0 +1,215 @@
1
+ /**
2
+ * The async half of P4's session wiring (spec 5.2, review finding 7).
3
+ *
4
+ * resolveCodingToolSupport is async and awaits this; buildCodingToolSupport is
5
+ * synchronous and on the hot dispatch path, so it only receives the result as
6
+ * data. Nothing here may be called from the sync path.
7
+ */
8
+ import { mkdir } from "node:fs/promises";
9
+ import { homedir, tmpdir } from "node:os";
10
+ import { errorMessage } from "#src/infra/errors";
11
+ import { getSafeLogger, NaxError } from "#src/infra/index";
12
+ import { approvalsPath } from "#src/permissions/index";
13
+ import { buildSandboxPolicy, createCommandLauncher, DISABLED_SANDBOX_STATE, defaultTempRoots, listCredentialFiles, listGitGuardFiles, listNaxEntries, probeSandboxOnce, rawBashRefusalReason, resolveGitLayout, runTempRoots, sandboxBackendFor, strayCommonDirTripwire, warnSandboxUnavailableOnce, } from "#src/sandbox/index";
14
+ export const _sessionSandboxDeps = {
15
+ backendFor: sandboxBackendFor,
16
+ probe: probeSandboxOnce,
17
+ gitLayout: resolveGitLayout,
18
+ naxEntries: listNaxEntries,
19
+ gitGuardFiles: listGitGuardFiles,
20
+ commonDirTripwire: strayCommonDirTripwire,
21
+ credentialFiles: listCredentialFiles,
22
+ tempRoots: defaultTempRoots,
23
+ homedir,
24
+ platform: () => process.platform,
25
+ /** US-002 — creates the session temp dir before the policy is built. */
26
+ mkdir: (path) => mkdir(path, { recursive: true }),
27
+ /** US-002 — the host temp dir, kept injectable so the policy choice is testable. */
28
+ tmpdir: () => tmpdir(),
29
+ /** US-002 — the temp roots of one confined run, given its own root. */
30
+ runTempRoots,
31
+ };
32
+ /**
33
+ * US-002: which temp roots a session's policy grants.
34
+ *
35
+ * Shared roots are today's behaviour and the fallback: the opt-out
36
+ * (`allowSharedTmp`), a session with no run root, and a failed directory
37
+ * creation all land there.
38
+ *
39
+ * Confinement needs both `runTmpRoot` and `tmpDir` — the session temp dir the
40
+ * launcher exports as TMPDIR is no more writable than `/tmp` is, so it has to
41
+ * be created here, BEFORE the policy that grants it. A creation failure fails
42
+ * OPEN to the shared roots: a session must never run with a TMPDIR its own
43
+ * sandbox cannot write.
44
+ */
45
+ async function sessionTempRoots(args) {
46
+ const { runTmpRoot, tmpDir } = args;
47
+ const shared = () => ({ tempRoots: _sessionSandboxDeps.tempRoots(), confined: false });
48
+ if (args.config.filesystem.allowSharedTmp || runTmpRoot === undefined || tmpDir === undefined)
49
+ return shared();
50
+ try {
51
+ await _sessionSandboxDeps.mkdir(tmpDir);
52
+ }
53
+ catch (err) {
54
+ getSafeLogger()?.warn("sandbox", "could not create the session temp dir — granting the shared temp roots", {
55
+ storyId: args.storyId ?? "_dispatch",
56
+ tmpDir,
57
+ error: errorMessage(err),
58
+ });
59
+ return shared();
60
+ }
61
+ return {
62
+ tempRoots: _sessionSandboxDeps.runTempRoots({ runTmpRoot, tmpdir: _sessionSandboxDeps.tmpdir() }),
63
+ confined: true,
64
+ };
65
+ }
66
+ export async function resolveSessionSandbox(args) {
67
+ const config = args.config;
68
+ if (config === undefined || !config.enabled || !args.needsLauncher) {
69
+ return createCommandLauncher({
70
+ state: DISABLED_SANDBOX_STATE,
71
+ ...(args.tmpDir !== undefined ? { tmpDir: args.tmpDir } : {}),
72
+ });
73
+ }
74
+ const backend = _sessionSandboxDeps.backendFor(config);
75
+ const probe = await _sessionSandboxDeps.probe(backend, args.storyId);
76
+ if (!probe.available) {
77
+ warnSandboxUnavailableOnce(probe.reason, args.storyId);
78
+ return createCommandLauncher({
79
+ state: { kind: "unavailable", backend: backend.name, reason: probe.reason },
80
+ ...(args.tmpDir !== undefined ? { tmpDir: args.tmpDir } : {}),
81
+ });
82
+ }
83
+ const git = await _sessionSandboxDeps.gitLayout(args.root);
84
+ const credentialFiles = await _sessionSandboxDeps.credentialFiles(args.protectedPaths.credentialDir);
85
+ const approvalsFile = args.outputDir !== undefined ? approvalsPath(args.outputDir) : undefined;
86
+ // Before the policy: the confined roots include the session temp dir itself.
87
+ const { tempRoots, confined } = await sessionTempRoots({
88
+ config,
89
+ storyId: args.storyId,
90
+ runTmpRoot: args.runTmpRoot,
91
+ tmpDir: args.tmpDir,
92
+ });
93
+ const policyFor = async (root, tmpDirInForce) => buildSandboxPolicy({
94
+ root,
95
+ git,
96
+ // Per build, like the .nax entries: a worktree added mid-run gets its denies too.
97
+ gitGuardFiles: await _sessionSandboxDeps.gitGuardFiles(git),
98
+ naxEntries: await _sessionSandboxDeps.naxEntries(root, args.protectedPaths.projectStateDir),
99
+ credentialFiles,
100
+ ...(approvalsFile !== undefined ? { approvalsFile } : {}),
101
+ // US-006: a command inside the sandbox must not be able to rewrite the
102
+ // trust store that decides whether repository code runs.
103
+ trustStoreFile: args.protectedPaths.trustStoreFile,
104
+ home: _sessionSandboxDeps.homedir(),
105
+ tempRoots,
106
+ // #2301: the RESOLVED confinement, not `config.filesystem.allowSharedTmp`.
107
+ // A session confines only when that opt-out is off, a run root AND a
108
+ // session dir were both supplied, and the dir was actually created.
109
+ // `allowSharedTmp: false` is therefore no evidence of confinement — it also
110
+ // holds when the session dir could not be created and when no run root was
111
+ // supplied, and reading the flag would deny a darwin session that is
112
+ // running on the shared roots.
113
+ //
114
+ // Narrowed by whether THIS command will actually get the session's
115
+ // `TMPDIR`. `createCommandLauncher` recreates the session dir before every
116
+ // run and drops the `export TMPDIR=…` prefix when that creation fails
117
+ // (src/sandbox/launcher.ts), and then srt's own forced `TMPDIR`
118
+ // (`/tmp/claude`, sandbox-utils.js:630) is what the child gets — denying it
119
+ // would leave the session with a TMPDIR its own sandbox refuses to write,
120
+ // the one posture SPEC-tmp-confinement.md:132 rules out.
121
+ confined: confined && tmpDirInForce,
122
+ platform: _sessionSandboxDeps.platform(),
123
+ config,
124
+ });
125
+ // Review #17: literal() refuses a glob character in any policy path, and the
126
+ // probe builds its own policy, so a repo path like `re[x]po` passed the probe
127
+ // and then failed every command. Build the policy once here instead.
128
+ // The old residual (a glob-named feature dir created mid-run failing every
129
+ // command) is gone: listNaxEntries skips glob-named `.nax` entries (nax#2260).
130
+ const policyError = await literalPolicyError(policyFor, args.root, confined);
131
+ if (policyError !== undefined) {
132
+ warnSandboxUnavailableOnce(policyError, args.storyId);
133
+ return createCommandLauncher({ state: { kind: "unavailable", backend: backend.name, reason: policyError } });
134
+ }
135
+ const afterWrapped = await _sessionSandboxDeps.commonDirTripwire(git, args.storyId);
136
+ const network = config.network.allowedDomains ?? "open"; // absent = open (spec S2)
137
+ return createCommandLauncher({
138
+ // `sharedTmp` is present only when confined: absent means the shared temp
139
+ // roots are writable, which is what every pre-US-002 launcher says.
140
+ state: { kind: "available", backend: backend.name, network, ...(confined ? { sharedTmp: false } : {}) },
141
+ backend,
142
+ policyFor,
143
+ ...(afterWrapped !== undefined ? { afterWrapped } : {}),
144
+ ...(args.tmpDir !== undefined ? { tmpDir: args.tmpDir } : {}),
145
+ });
146
+ }
147
+ /** The compile-time policy refusal for `raw` (Task 8), or undefined. */
148
+ export function rawRefusalFor(launcher) {
149
+ return launcher?.state.kind === "unavailable" ? rawBashRefusalReason(launcher.state.reason) : undefined;
150
+ }
151
+ /**
152
+ * US-004: whether the session's sandbox confines temp writes to this run's own
153
+ * temp root.
154
+ *
155
+ * True exactly when the launcher is available AND says `sharedTmp: false` —
156
+ * the only state under which the command guard may skip the classifier for a
157
+ * temp-only command (`src/agents/coding-tool-support.ts` → `tempConfined` →
158
+ * `src/command-safety/guard.ts:185`). An available launcher without
159
+ * `sharedTmp`, an unavailable or disabled one, and no launcher at all all read
160
+ * as NOT confined.
161
+ *
162
+ * That is the RESOLVE-time answer, fixed when the launcher is built, and it is
163
+ * deliberately NOT the answer the policy narrows on. `SandboxPolicyInput.confined`
164
+ * ANDs it with whether the per-command session-dir `mkdir` succeeded
165
+ * (`src/sandbox/launcher.ts:194`), because the `export TMPDIR=…` prefix rides on
166
+ * that same mkdir. So a session whose dir fails to re-create reports `true` here
167
+ * while the policy for that ONE command is the unconflined one, `/tmp/claude`
168
+ * included — which means the guard's temp-only exemption can be claimed for a
169
+ * command that is not in fact confined. Deliberate, and documented on
170
+ * `SandboxPolicyInput.confined` (`src/sandbox/policy-builder.ts:41-64`); do not
171
+ * reconcile the two by making either follow the other.
172
+ */
173
+ export function isTempConfined(launcher) {
174
+ return launcher?.state.kind === "available" && launcher.state.sharedTmp === false;
175
+ }
176
+ /**
177
+ * US-002: the raw-screen options `compileToolPolicy` consumes, derived from the
178
+ * launcher's state.
179
+ *
180
+ * `rawBashRefusal` is exactly what `rawRefusalFor` returns (an unavailable
181
+ * launcher refuses every call). `sandboxWrapped: true` is added for an available
182
+ * launcher: the command really does run inside the OS sandbox, so the raw screen
183
+ * stops refusing a feature PRD the command only READS. A disabled launcher
184
+ * yields neither key.
185
+ */
186
+ export function rawScreenOptionsFor(launcher) {
187
+ if (launcher?.state.kind === "available")
188
+ return { sandboxWrapped: true };
189
+ const rawBashRefusal = rawRefusalFor(launcher);
190
+ return rawBashRefusal !== undefined ? { rawBashRefusal } : {};
191
+ }
192
+ /**
193
+ * The compile-time policy refusal for `raw` (Task 8), or undefined.
194
+ *
195
+ * `resolvedConfinement` is the session's RESOLVE-time `confined`, not the
196
+ * per-launch `tmpDirInForce` this signature's second slot normally carries — a
197
+ * superset of it, since a launch can only narrow. That is deliberate: this probe
198
+ * exists to turn a glob refusal from `buildSandboxPolicy` into a session-level
199
+ * refusal, and the entries a narrower confinement differs by (#2301 — srt's
200
+ * `/tmp/claude` grant, present only when NOT confined) are fixed literals with no
201
+ * glob character. Passing the superset therefore exercises the strictest policy
202
+ * without risking a refusal a real launch would never hit.
203
+ */
204
+ async function literalPolicyError(policyFor, root, resolvedConfinement) {
205
+ try {
206
+ await policyFor(root, resolvedConfinement);
207
+ return undefined;
208
+ }
209
+ catch (err) {
210
+ if (err instanceof NaxError && err.code === "SANDBOX_POLICY_NOT_LITERAL") {
211
+ return `[sandbox] a path in the sandbox policy contains a glob character: ${String(err.context?.path ?? "")}`;
212
+ }
213
+ throw err;
214
+ }
215
+ }