@lannguyensi/harness 0.63.0 → 1.0.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 (702) hide show
  1. package/CHANGELOG.md +90 -0
  2. package/README.md +46 -42
  3. package/dist/cli/add/index.js +17 -21
  4. package/dist/cli/add/index.js.map +1 -1
  5. package/dist/cli/adopt/derive.d.ts +2 -2
  6. package/dist/cli/adopt/derive.js +2 -19
  7. package/dist/cli/adopt/derive.js.map +1 -1
  8. package/dist/cli/adopt/index.d.ts +1 -1
  9. package/dist/cli/adopt/index.js +1 -12
  10. package/dist/cli/adopt/index.js.map +1 -1
  11. package/dist/cli/apply/apply.d.ts +20 -35
  12. package/dist/cli/apply/apply.js +61 -136
  13. package/dist/cli/apply/apply.js.map +1 -1
  14. package/dist/cli/apply/generate-codex-config.js +10 -58
  15. package/dist/cli/apply/generate-codex-config.js.map +1 -1
  16. package/dist/cli/apply/generate-memory-index.js +1 -2
  17. package/dist/cli/apply/generate-memory-index.js.map +1 -1
  18. package/dist/cli/apply/generate-opencode-config.d.ts +2 -10
  19. package/dist/cli/apply/generate-opencode-config.js +74 -113
  20. package/dist/cli/apply/generate-opencode-config.js.map +1 -1
  21. package/dist/cli/apply/generate-settings.d.ts +11 -64
  22. package/dist/cli/apply/generate-settings.js +27 -132
  23. package/dist/cli/apply/generate-settings.js.map +1 -1
  24. package/dist/cli/apply/index.d.ts +1 -1
  25. package/dist/cli/apply/index.js +1 -1
  26. package/dist/cli/apply/index.js.map +1 -1
  27. package/dist/cli/apply/install-codex-config.d.ts +153 -1
  28. package/dist/cli/apply/install-codex-config.js +445 -70
  29. package/dist/cli/apply/install-codex-config.js.map +1 -1
  30. package/dist/cli/apply/next-steps.d.ts +7 -0
  31. package/dist/cli/apply/next-steps.js +13 -1
  32. package/dist/cli/apply/next-steps.js.map +1 -1
  33. package/dist/cli/bounded-stdin.d.ts +0 -23
  34. package/dist/cli/bounded-stdin.js +2 -49
  35. package/dist/cli/bounded-stdin.js.map +1 -1
  36. package/dist/cli/describe.d.ts +1 -1
  37. package/dist/cli/describe.js +0 -3
  38. package/dist/cli/describe.js.map +1 -1
  39. package/dist/cli/diff/engine.d.ts +0 -11
  40. package/dist/cli/diff/engine.js +1 -17
  41. package/dist/cli/diff/engine.js.map +1 -1
  42. package/dist/cli/diff/index.js +14 -25
  43. package/dist/cli/diff/index.js.map +1 -1
  44. package/dist/cli/doctor/claude-mcp.d.ts +4 -19
  45. package/dist/cli/doctor/claude-mcp.js +11 -22
  46. package/dist/cli/doctor/claude-mcp.js.map +1 -1
  47. package/dist/cli/doctor/codex.d.ts +12 -14
  48. package/dist/cli/doctor/codex.js +31 -144
  49. package/dist/cli/doctor/codex.js.map +1 -1
  50. package/dist/cli/doctor/format.js +23 -338
  51. package/dist/cli/doctor/format.js.map +1 -1
  52. package/dist/cli/doctor/hook-liveness.d.ts +56 -0
  53. package/dist/cli/doctor/hook-liveness.js +455 -0
  54. package/dist/cli/doctor/hook-liveness.js.map +1 -0
  55. package/dist/cli/doctor/index.d.ts +13 -87
  56. package/dist/cli/doctor/index.js +57 -705
  57. package/dist/cli/doctor/index.js.map +1 -1
  58. package/dist/cli/doctor/opencode.d.ts +2 -1
  59. package/dist/cli/doctor/opencode.js.map +1 -1
  60. package/dist/cli/doctor/types.d.ts +21 -378
  61. package/dist/cli/doctor/types.js.map +1 -1
  62. package/dist/cli/drain-stdio.d.ts +31 -0
  63. package/dist/cli/drain-stdio.js +76 -0
  64. package/dist/cli/drain-stdio.js.map +1 -0
  65. package/dist/cli/export.d.ts +3 -1
  66. package/dist/cli/export.js +7 -16
  67. package/dist/cli/export.js.map +1 -1
  68. package/dist/cli/gate/codex-disable.d.ts +29 -0
  69. package/dist/cli/gate/codex-disable.js +195 -0
  70. package/dist/cli/gate/codex-disable.js.map +1 -0
  71. package/dist/cli/gate/codex-enable.d.ts +41 -0
  72. package/dist/cli/gate/codex-enable.js +127 -0
  73. package/dist/cli/gate/codex-enable.js.map +1 -0
  74. package/dist/cli/gate/codex-snapshot.d.ts +208 -0
  75. package/dist/cli/gate/codex-snapshot.js +402 -0
  76. package/dist/cli/gate/codex-snapshot.js.map +1 -0
  77. package/dist/cli/gate/disable.d.ts +9 -0
  78. package/dist/cli/gate/disable.js +263 -28
  79. package/dist/cli/gate/disable.js.map +1 -1
  80. package/dist/cli/gate/enable.d.ts +26 -6
  81. package/dist/cli/gate/enable.js +152 -80
  82. package/dist/cli/gate/enable.js.map +1 -1
  83. package/dist/cli/gate/link-chain.d.ts +53 -0
  84. package/dist/cli/gate/link-chain.js +122 -0
  85. package/dist/cli/gate/link-chain.js.map +1 -0
  86. package/dist/cli/gate/snapshot.d.ts +289 -12
  87. package/dist/cli/gate/snapshot.js +481 -22
  88. package/dist/cli/gate/snapshot.js.map +1 -1
  89. package/dist/cli/index.d.ts +0 -9
  90. package/dist/cli/index.js +15 -2607
  91. package/dist/cli/index.js.map +1 -1
  92. package/dist/cli/init/composer.d.ts +3 -6
  93. package/dist/cli/init/composer.js +6 -370
  94. package/dist/cli/init/composer.js.map +1 -1
  95. package/dist/cli/init/dependencies.d.ts +1 -2
  96. package/dist/cli/init/dependencies.js +4 -80
  97. package/dist/cli/init/dependencies.js.map +1 -1
  98. package/dist/cli/init/detect.js +5 -4
  99. package/dist/cli/init/detect.js.map +1 -1
  100. package/dist/cli/init/interactive.d.ts +1 -23
  101. package/dist/cli/init/interactive.js +33 -247
  102. package/dist/cli/init/interactive.js.map +1 -1
  103. package/dist/cli/init/profiles.d.ts +2 -2
  104. package/dist/cli/init/profiles.js +51 -243
  105. package/dist/cli/init/profiles.js.map +1 -1
  106. package/dist/cli/init/templates.d.ts +2 -37
  107. package/dist/cli/init/templates.js +25 -1237
  108. package/dist/cli/init/templates.js.map +1 -1
  109. package/dist/cli/list.d.ts +1 -1
  110. package/dist/cli/list.js +1 -38
  111. package/dist/cli/list.js.map +1 -1
  112. package/dist/cli/loader.d.ts +15 -1
  113. package/dist/cli/loader.js +56 -39
  114. package/dist/cli/loader.js.map +1 -1
  115. package/dist/cli/main.js +7 -2
  116. package/dist/cli/main.js.map +1 -1
  117. package/dist/cli/migrate-home/index.js +2 -2
  118. package/dist/cli/migrate-home/index.js.map +1 -1
  119. package/dist/cli/pack/add.js +1 -1
  120. package/dist/cli/pack/add.js.map +1 -1
  121. package/dist/cli/pack/hook-bootstrap.d.ts +5 -164
  122. package/dist/cli/pack/hook-bootstrap.js +15 -291
  123. package/dist/cli/pack/hook-bootstrap.js.map +1 -1
  124. package/dist/cli/pack/hook-branch-protection.d.ts +28 -21
  125. package/dist/cli/pack/hook-branch-protection.js +365 -340
  126. package/dist/cli/pack/hook-branch-protection.js.map +1 -1
  127. package/dist/cli/pack/index.d.ts +0 -1
  128. package/dist/cli/pack/index.js +0 -1
  129. package/dist/cli/pack/index.js.map +1 -1
  130. package/dist/cli/pack/list.js +1 -6
  131. package/dist/cli/pack/list.js.map +1 -1
  132. package/dist/cli/pack/mutate.d.ts +7 -9
  133. package/dist/cli/pack/mutate.js +6 -9
  134. package/dist/cli/pack/mutate.js.map +1 -1
  135. package/dist/cli/pack/reseed.d.ts +2 -2
  136. package/dist/cli/pack/reseed.js +16 -22
  137. package/dist/cli/pack/reseed.js.map +1 -1
  138. package/dist/cli/register-gate-group.d.ts +5 -0
  139. package/dist/cli/register-gate-group.js +348 -0
  140. package/dist/cli/register-gate-group.js.map +1 -0
  141. package/dist/cli/register-inspect-group.d.ts +6 -0
  142. package/dist/cli/register-inspect-group.js +189 -0
  143. package/dist/cli/register-inspect-group.js.map +1 -0
  144. package/dist/cli/register-operator-lifecycle.d.ts +5 -0
  145. package/dist/cli/register-operator-lifecycle.js +20 -0
  146. package/dist/cli/register-operator-lifecycle.js.map +1 -0
  147. package/dist/cli/register-pack-group.d.ts +5 -0
  148. package/dist/cli/register-pack-group.js +134 -0
  149. package/dist/cli/register-pack-group.js.map +1 -0
  150. package/dist/cli/register-setup-group.d.ts +5 -0
  151. package/dist/cli/register-setup-group.js +495 -0
  152. package/dist/cli/register-setup-group.js.map +1 -0
  153. package/dist/cli/remove/index.d.ts +0 -14
  154. package/dist/cli/remove/index.js +2 -115
  155. package/dist/cli/remove/index.js.map +1 -1
  156. package/dist/cli/remove/mutate.d.ts +0 -2
  157. package/dist/cli/remove/mutate.js +1 -19
  158. package/dist/cli/remove/mutate.js.map +1 -1
  159. package/dist/cli/remove/register.d.ts +5 -0
  160. package/dist/cli/remove/register.js +25 -0
  161. package/dist/cli/remove/register.js.map +1 -0
  162. package/dist/cli/shell-quote.d.ts +7 -0
  163. package/dist/cli/shell-quote.js +17 -0
  164. package/dist/cli/shell-quote.js.map +1 -0
  165. package/dist/cli/uninstall/index.d.ts +4 -2
  166. package/dist/cli/uninstall/index.js +15 -7
  167. package/dist/cli/uninstall/index.js.map +1 -1
  168. package/dist/cli/uninstall/register.d.ts +5 -0
  169. package/dist/cli/uninstall/register.js +171 -0
  170. package/dist/cli/uninstall/register.js.map +1 -0
  171. package/dist/cli/uninstall/snapshot.d.ts +15 -0
  172. package/dist/cli/uninstall/snapshot.js +38 -0
  173. package/dist/cli/uninstall/snapshot.js.map +1 -1
  174. package/dist/cli/validate/checks.d.ts +0 -77
  175. package/dist/cli/validate/checks.js +3 -1049
  176. package/dist/cli/validate/checks.js.map +1 -1
  177. package/dist/cli/validate/index.js +19 -15
  178. package/dist/cli/validate/index.js.map +1 -1
  179. package/dist/index.d.ts +0 -3
  180. package/dist/index.js +0 -3
  181. package/dist/index.js.map +1 -1
  182. package/dist/io/claude-mcp.d.ts +1 -1
  183. package/dist/io/claude-mcp.js +27 -14
  184. package/dist/io/claude-mcp.js.map +1 -1
  185. package/dist/io/harness-lock.js +2 -2
  186. package/dist/io/harness-lock.js.map +1 -1
  187. package/dist/io/lock.d.ts +0 -26
  188. package/dist/io/lock.js +10 -27
  189. package/dist/io/lock.js.map +1 -1
  190. package/dist/io/merge-settings.js +6 -4
  191. package/dist/io/merge-settings.js.map +1 -1
  192. package/dist/io/project-name.d.ts +22 -39
  193. package/dist/io/project-name.js +25 -42
  194. package/dist/io/project-name.js.map +1 -1
  195. package/dist/io/read-regular-file.d.ts +103 -40
  196. package/dist/io/read-regular-file.js +196 -35
  197. package/dist/io/read-regular-file.js.map +1 -1
  198. package/dist/io/restart-hints.js +3 -6
  199. package/dist/io/restart-hints.js.map +1 -1
  200. package/dist/io/version-compare.d.ts +1 -3
  201. package/dist/io/version-compare.js +1 -3
  202. package/dist/io/version-compare.js.map +1 -1
  203. package/dist/io/write-regular-file.d.ts +30 -0
  204. package/dist/io/write-regular-file.js +85 -0
  205. package/dist/io/write-regular-file.js.map +1 -0
  206. package/dist/overrides/index.d.ts +1 -0
  207. package/dist/overrides/index.js +1 -0
  208. package/dist/overrides/index.js.map +1 -1
  209. package/dist/overrides/merge-layers.d.ts +43 -0
  210. package/dist/overrides/merge-layers.js +76 -0
  211. package/dist/overrides/merge-layers.js.map +1 -0
  212. package/dist/overrides/merge.d.ts +16 -0
  213. package/dist/overrides/merge.js +21 -8
  214. package/dist/overrides/merge.js.map +1 -1
  215. package/dist/policy-packs/builtin/branch-protection-runtime.d.ts +4 -69
  216. package/dist/policy-packs/builtin/branch-protection-runtime.js +12 -84
  217. package/dist/policy-packs/builtin/branch-protection-runtime.js.map +1 -1
  218. package/dist/policy-packs/builtin/branch-protection.d.ts +7 -30
  219. package/dist/policy-packs/builtin/branch-protection.js +56 -89
  220. package/dist/policy-packs/builtin/branch-protection.js.map +1 -1
  221. package/dist/policy-packs/config-check.d.ts +7 -5
  222. package/dist/policy-packs/config-check.js +2 -2
  223. package/dist/policy-packs/config-check.js.map +1 -1
  224. package/dist/policy-packs/expand.d.ts +1 -3
  225. package/dist/policy-packs/expand.js +5 -42
  226. package/dist/policy-packs/expand.js.map +1 -1
  227. package/dist/policy-packs/index.d.ts +3 -3
  228. package/dist/policy-packs/index.js +2 -2
  229. package/dist/policy-packs/index.js.map +1 -1
  230. package/dist/policy-packs/registry.d.ts +9 -38
  231. package/dist/policy-packs/registry.js +5 -65
  232. package/dist/policy-packs/registry.js.map +1 -1
  233. package/dist/policy-packs/runtime.d.ts +0 -4
  234. package/dist/policy-packs/runtime.js +9 -22
  235. package/dist/policy-packs/runtime.js.map +1 -1
  236. package/dist/policy-packs/types.d.ts +0 -19
  237. package/dist/policy-packs/ux-compare.d.ts +1 -11
  238. package/dist/policy-packs/ux-compare.js +6 -42
  239. package/dist/policy-packs/ux-compare.js.map +1 -1
  240. package/dist/policy-packs/ux-drift-check.d.ts +5 -5
  241. package/dist/policy-packs/ux-drift-check.js +17 -22
  242. package/dist/policy-packs/ux-drift-check.js.map +1 -1
  243. package/dist/policy-packs/version-check.d.ts +5 -26
  244. package/dist/policy-packs/version-check.js +19 -74
  245. package/dist/policy-packs/version-check.js.map +1 -1
  246. package/dist/probes/memory.d.ts +1 -1
  247. package/dist/probes/memory.js +1 -1
  248. package/dist/probes/memory.js.map +1 -1
  249. package/dist/runtime/agent-facing.d.ts +9 -0
  250. package/dist/runtime/agent-facing.js +28 -14
  251. package/dist/runtime/agent-facing.js.map +1 -1
  252. package/dist/runtime/bounded-text.d.ts +15 -0
  253. package/dist/runtime/bounded-text.js +27 -0
  254. package/dist/runtime/bounded-text.js.map +1 -0
  255. package/dist/runtime/git-branch.d.ts +125 -0
  256. package/dist/runtime/git-branch.js +381 -0
  257. package/dist/runtime/git-branch.js.map +1 -0
  258. package/dist/runtime/hermetic-spawn-guard.d.ts +2 -2
  259. package/dist/runtime/hermetic-spawn-guard.js +24 -34
  260. package/dist/runtime/hermetic-spawn-guard.js.map +1 -1
  261. package/dist/runtime/home-dir.js +3 -2
  262. package/dist/runtime/home-dir.js.map +1 -1
  263. package/dist/runtime/tool-name-aliases.d.ts +0 -6
  264. package/dist/runtime/tool-name-aliases.js +5 -18
  265. package/dist/runtime/tool-name-aliases.js.map +1 -1
  266. package/dist/schema/grounding.d.ts +7 -54
  267. package/dist/schema/grounding.js +10 -12
  268. package/dist/schema/grounding.js.map +1 -1
  269. package/dist/schema/hooks.d.ts +39 -136
  270. package/dist/schema/hooks.js +3 -6
  271. package/dist/schema/hooks.js.map +1 -1
  272. package/dist/schema/index.d.ts +114 -3828
  273. package/dist/schema/index.js +41 -80
  274. package/dist/schema/index.js.map +1 -1
  275. package/dist/schema/memory.d.ts +54 -131
  276. package/dist/schema/memory.js +2 -2
  277. package/dist/schema/memory.js.map +1 -1
  278. package/dist/schema/policy-packs.d.ts +3 -45
  279. package/dist/schema/policy-packs.js +7 -13
  280. package/dist/schema/policy-packs.js.map +1 -1
  281. package/dist/schema/policy-ux.d.ts +7 -0
  282. package/dist/schema/policy-ux.js +18 -0
  283. package/dist/schema/policy-ux.js.map +1 -0
  284. package/dist/schema/removed-keys.d.ts +185 -0
  285. package/dist/schema/removed-keys.js +531 -0
  286. package/dist/schema/removed-keys.js.map +1 -0
  287. package/dist/schema/tools.d.ts +30 -268
  288. package/dist/schema/tools.js +4 -4
  289. package/dist/schema/tools.js.map +1 -1
  290. package/package.json +5 -16
  291. package/dist/cli/approve/branch-protection.d.ts +0 -69
  292. package/dist/cli/approve/branch-protection.js +0 -144
  293. package/dist/cli/approve/branch-protection.js.map +0 -1
  294. package/dist/cli/approve/risk.d.ts +0 -112
  295. package/dist/cli/approve/risk.js +0 -197
  296. package/dist/cli/approve/risk.js.map +0 -1
  297. package/dist/cli/approve/stdin-report.d.ts +0 -57
  298. package/dist/cli/approve/stdin-report.js +0 -145
  299. package/dist/cli/approve/stdin-report.js.map +0 -1
  300. package/dist/cli/approve/understanding.d.ts +0 -410
  301. package/dist/cli/approve/understanding.js +0 -996
  302. package/dist/cli/approve/understanding.js.map +0 -1
  303. package/dist/cli/audit.d.ts +0 -80
  304. package/dist/cli/audit.js +0 -252
  305. package/dist/cli/audit.js.map +0 -1
  306. package/dist/cli/delegate/index.d.ts +0 -76
  307. package/dist/cli/delegate/index.js +0 -443
  308. package/dist/cli/delegate/index.js.map +0 -1
  309. package/dist/cli/doctor/auto-approve-mode.d.ts +0 -37
  310. package/dist/cli/doctor/auto-approve-mode.js +0 -80
  311. package/dist/cli/doctor/auto-approve-mode.js.map +0 -1
  312. package/dist/cli/doctor/bypass-without-auto-approve.d.ts +0 -38
  313. package/dist/cli/doctor/bypass-without-auto-approve.js +0 -95
  314. package/dist/cli/doctor/bypass-without-auto-approve.js.map +0 -1
  315. package/dist/cli/doctor/codex-config-drift.d.ts +0 -28
  316. package/dist/cli/doctor/codex-config-drift.js +0 -240
  317. package/dist/cli/doctor/codex-config-drift.js.map +0 -1
  318. package/dist/cli/doctor/rogue-ledger.d.ts +0 -53
  319. package/dist/cli/doctor/rogue-ledger.js +0 -153
  320. package/dist/cli/doctor/rogue-ledger.js.map +0 -1
  321. package/dist/cli/doctor/session-start-preflight-setup-version.d.ts +0 -83
  322. package/dist/cli/doctor/session-start-preflight-setup-version.js +0 -114
  323. package/dist/cli/doctor/session-start-preflight-setup-version.js.map +0 -1
  324. package/dist/cli/doctor/settings-drift.d.ts +0 -25
  325. package/dist/cli/doctor/settings-drift.js +0 -213
  326. package/dist/cli/doctor/settings-drift.js.map +0 -1
  327. package/dist/cli/doctor/toolchain-parity.d.ts +0 -63
  328. package/dist/cli/doctor/toolchain-parity.js +0 -154
  329. package/dist/cli/doctor/toolchain-parity.js.map +0 -1
  330. package/dist/cli/doctor/ug-auto-approvals.d.ts +0 -40
  331. package/dist/cli/doctor/ug-auto-approvals.js +0 -91
  332. package/dist/cli/doctor/ug-auto-approvals.js.map +0 -1
  333. package/dist/cli/doctor/ug-delegations.d.ts +0 -26
  334. package/dist/cli/doctor/ug-delegations.js +0 -121
  335. package/dist/cli/doctor/ug-delegations.js.map +0 -1
  336. package/dist/cli/doctor/ug-inflight.d.ts +0 -35
  337. package/dist/cli/doctor/ug-inflight.js +0 -57
  338. package/dist/cli/doctor/ug-inflight.js.map +0 -1
  339. package/dist/cli/doctor/understanding-mode-env.d.ts +0 -51
  340. package/dist/cli/doctor/understanding-mode-env.js +0 -98
  341. package/dist/cli/doctor/understanding-mode-env.js.map +0 -1
  342. package/dist/cli/dry-run.d.ts +0 -46
  343. package/dist/cli/dry-run.js +0 -250
  344. package/dist/cli/dry-run.js.map +0 -1
  345. package/dist/cli/event-input.d.ts +0 -28
  346. package/dist/cli/event-input.js +0 -73
  347. package/dist/cli/event-input.js.map +0 -1
  348. package/dist/cli/explain-action.d.ts +0 -20
  349. package/dist/cli/explain-action.js +0 -27
  350. package/dist/cli/explain-action.js.map +0 -1
  351. package/dist/cli/explain-policy.d.ts +0 -135
  352. package/dist/cli/explain-policy.js +0 -266
  353. package/dist/cli/explain-policy.js.map +0 -1
  354. package/dist/cli/explain.d.ts +0 -31
  355. package/dist/cli/explain.js +0 -159
  356. package/dist/cli/explain.js.map +0 -1
  357. package/dist/cli/gc/index.d.ts +0 -63
  358. package/dist/cli/gc/index.js +0 -566
  359. package/dist/cli/gc/index.js.map +0 -1
  360. package/dist/cli/pack/approve-escape.d.ts +0 -19
  361. package/dist/cli/pack/approve-escape.js +0 -190
  362. package/dist/cli/pack/approve-escape.js.map +0 -1
  363. package/dist/cli/pack/auto-approve-path.d.ts +0 -146
  364. package/dist/cli/pack/auto-approve-path.js +0 -462
  365. package/dist/cli/pack/auto-approve-path.js.map +0 -1
  366. package/dist/cli/pack/hook-codex-post-tool-use.d.ts +0 -25
  367. package/dist/cli/pack/hook-codex-post-tool-use.js +0 -160
  368. package/dist/cli/pack/hook-codex-post-tool-use.js.map +0 -1
  369. package/dist/cli/pack/hook-codex-pre-tool-use.d.ts +0 -48
  370. package/dist/cli/pack/hook-codex-pre-tool-use.js +0 -474
  371. package/dist/cli/pack/hook-codex-pre-tool-use.js.map +0 -1
  372. package/dist/cli/pack/hook-codex-stop.d.ts +0 -35
  373. package/dist/cli/pack/hook-codex-stop.js +0 -329
  374. package/dist/cli/pack/hook-codex-stop.js.map +0 -1
  375. package/dist/cli/pack/hook-codex-user-prompt-submit.d.ts +0 -24
  376. package/dist/cli/pack/hook-codex-user-prompt-submit.js +0 -93
  377. package/dist/cli/pack/hook-codex-user-prompt-submit.js.map +0 -1
  378. package/dist/cli/pack/hook-post-merge-gate-record.d.ts +0 -37
  379. package/dist/cli/pack/hook-post-merge-gate-record.js +0 -190
  380. package/dist/cli/pack/hook-post-merge-gate-record.js.map +0 -1
  381. package/dist/cli/pack/hook-post-merge-gate.d.ts +0 -34
  382. package/dist/cli/pack/hook-post-merge-gate.js +0 -277
  383. package/dist/cli/pack/hook-post-merge-gate.js.map +0 -1
  384. package/dist/cli/pack/hook-post-tool-use.d.ts +0 -45
  385. package/dist/cli/pack/hook-post-tool-use.js +0 -137
  386. package/dist/cli/pack/hook-post-tool-use.js.map +0 -1
  387. package/dist/cli/pack/hook-pre-tool-use.d.ts +0 -92
  388. package/dist/cli/pack/hook-pre-tool-use.js +0 -1328
  389. package/dist/cli/pack/hook-pre-tool-use.js.map +0 -1
  390. package/dist/cli/pack/hook-runtime-reality.d.ts +0 -63
  391. package/dist/cli/pack/hook-runtime-reality.js +0 -210
  392. package/dist/cli/pack/hook-runtime-reality.js.map +0 -1
  393. package/dist/cli/pack/hook-solution-acceptance-writeguard.d.ts +0 -32
  394. package/dist/cli/pack/hook-solution-acceptance-writeguard.js +0 -337
  395. package/dist/cli/pack/hook-solution-acceptance-writeguard.js.map +0 -1
  396. package/dist/cli/pack/hook-solution-acceptance.d.ts +0 -157
  397. package/dist/cli/pack/hook-solution-acceptance.js +0 -530
  398. package/dist/cli/pack/hook-solution-acceptance.js.map +0 -1
  399. package/dist/cli/pack/hook-stay-in-scope.d.ts +0 -37
  400. package/dist/cli/pack/hook-stay-in-scope.js +0 -128
  401. package/dist/cli/pack/hook-stay-in-scope.js.map +0 -1
  402. package/dist/cli/pack/hook-subagent-start.d.ts +0 -23
  403. package/dist/cli/pack/hook-subagent-start.js +0 -88
  404. package/dist/cli/pack/hook-subagent-start.js.map +0 -1
  405. package/dist/cli/pack/hook-subagent-stop.d.ts +0 -19
  406. package/dist/cli/pack/hook-subagent-stop.js +0 -41
  407. package/dist/cli/pack/hook-subagent-stop.js.map +0 -1
  408. package/dist/cli/pack/hook-track-active-claim.d.ts +0 -27
  409. package/dist/cli/pack/hook-track-active-claim.js +0 -275
  410. package/dist/cli/pack/hook-track-active-claim.js.map +0 -1
  411. package/dist/cli/pack/transcript-report-scan.d.ts +0 -71
  412. package/dist/cli/pack/transcript-report-scan.js +0 -359
  413. package/dist/cli/pack/transcript-report-scan.js.map +0 -1
  414. package/dist/cli/pack/understanding-report-schema-hint.d.ts +0 -26
  415. package/dist/cli/pack/understanding-report-schema-hint.js +0 -120
  416. package/dist/cli/pack/understanding-report-schema-hint.js.map +0 -1
  417. package/dist/cli/pack/upgrade.d.ts +0 -32
  418. package/dist/cli/pack/upgrade.js +0 -273
  419. package/dist/cli/pack/upgrade.js.map +0 -1
  420. package/dist/cli/pause/index.d.ts +0 -113
  421. package/dist/cli/pause/index.js +0 -251
  422. package/dist/cli/pause/index.js.map +0 -1
  423. package/dist/cli/pause-check.d.ts +0 -22
  424. package/dist/cli/pause-check.js +0 -54
  425. package/dist/cli/pause-check.js.map +0 -1
  426. package/dist/cli/policy/intercept.d.ts +0 -233
  427. package/dist/cli/policy/intercept.js +0 -1020
  428. package/dist/cli/policy/intercept.js.map +0 -1
  429. package/dist/cli/policy/risk-envelope-enrichment.d.ts +0 -40
  430. package/dist/cli/policy/risk-envelope-enrichment.js +0 -108
  431. package/dist/cli/policy/risk-envelope-enrichment.js.map +0 -1
  432. package/dist/cli/record/index.d.ts +0 -81
  433. package/dist/cli/record/index.js +0 -348
  434. package/dist/cli/record/index.js.map +0 -1
  435. package/dist/cli/resolve-env.d.ts +0 -32
  436. package/dist/cli/resolve-env.js +0 -47
  437. package/dist/cli/resolve-env.js.map +0 -1
  438. package/dist/cli/session-export/index.d.ts +0 -46
  439. package/dist/cli/session-export/index.js +0 -169
  440. package/dist/cli/session-export/index.js.map +0 -1
  441. package/dist/cli/session-export/redact.d.ts +0 -22
  442. package/dist/cli/session-export/redact.js +0 -47
  443. package/dist/cli/session-export/redact.js.map +0 -1
  444. package/dist/cli/session-export/transcript.d.ts +0 -24
  445. package/dist/cli/session-export/transcript.js +0 -164
  446. package/dist/cli/session-export/transcript.js.map +0 -1
  447. package/dist/cli/session-start/branch-check.d.ts +0 -18
  448. package/dist/cli/session-start/branch-check.js +0 -140
  449. package/dist/cli/session-start/branch-check.js.map +0 -1
  450. package/dist/cli/session-start/index.d.ts +0 -121
  451. package/dist/cli/session-start/index.js +0 -591
  452. package/dist/cli/session-start/index.js.map +0 -1
  453. package/dist/cli/session-start/shared-options.d.ts +0 -103
  454. package/dist/cli/session-start/shared-options.js +0 -107
  455. package/dist/cli/session-start/shared-options.js.map +0 -1
  456. package/dist/cli/session-start/stale-base-check.d.ts +0 -46
  457. package/dist/cli/session-start/stale-base-check.js +0 -352
  458. package/dist/cli/session-start/stale-base-check.js.map +0 -1
  459. package/dist/cli/session-start/toolchain-parity.d.ts +0 -267
  460. package/dist/cli/session-start/toolchain-parity.js +0 -797
  461. package/dist/cli/session-start/toolchain-parity.js.map +0 -1
  462. package/dist/cli/smoke/assertions.d.ts +0 -46
  463. package/dist/cli/smoke/assertions.js +0 -170
  464. package/dist/cli/smoke/assertions.js.map +0 -1
  465. package/dist/cli/smoke/index.d.ts +0 -76
  466. package/dist/cli/smoke/index.js +0 -245
  467. package/dist/cli/smoke/index.js.map +0 -1
  468. package/dist/cli/smoke/runner.d.ts +0 -55
  469. package/dist/cli/smoke/runner.js +0 -134
  470. package/dist/cli/smoke/runner.js.map +0 -1
  471. package/dist/cli/smoke/stream-parser.d.ts +0 -65
  472. package/dist/cli/smoke/stream-parser.js +0 -115
  473. package/dist/cli/smoke/stream-parser.js.map +0 -1
  474. package/dist/cli/test-risk.d.ts +0 -26
  475. package/dist/cli/test-risk.js +0 -34
  476. package/dist/cli/test-risk.js.map +0 -1
  477. package/dist/io/display-path.d.ts +0 -11
  478. package/dist/io/display-path.js +0 -29
  479. package/dist/io/display-path.js.map +0 -1
  480. package/dist/io/duration.d.ts +0 -5
  481. package/dist/io/duration.js +0 -50
  482. package/dist/io/duration.js.map +0 -1
  483. package/dist/io/extract.d.ts +0 -79
  484. package/dist/io/extract.js +0 -226
  485. package/dist/io/extract.js.map +0 -1
  486. package/dist/io/ledger-record.d.ts +0 -83
  487. package/dist/io/ledger-record.js +0 -301
  488. package/dist/io/ledger-record.js.map +0 -1
  489. package/dist/io/read-json-dir-entries.d.ts +0 -36
  490. package/dist/io/read-json-dir-entries.js +0 -48
  491. package/dist/io/read-json-dir-entries.js.map +0 -1
  492. package/dist/io/safe-json-parse.d.ts +0 -5
  493. package/dist/io/safe-json-parse.js +0 -21
  494. package/dist/io/safe-json-parse.js.map +0 -1
  495. package/dist/policies/index.d.ts +0 -5
  496. package/dist/policies/index.js +0 -6
  497. package/dist/policies/index.js.map +0 -1
  498. package/dist/policies/ledger-client.d.ts +0 -113
  499. package/dist/policies/ledger-client.js +0 -500
  500. package/dist/policies/ledger-client.js.map +0 -1
  501. package/dist/policies/producers.d.ts +0 -12
  502. package/dist/policies/producers.js +0 -61
  503. package/dist/policies/producers.js.map +0 -1
  504. package/dist/policies/requires.d.ts +0 -75
  505. package/dist/policies/requires.js +0 -240
  506. package/dist/policies/requires.js.map +0 -1
  507. package/dist/policies/timestamp.d.ts +0 -14
  508. package/dist/policies/timestamp.js +0 -36
  509. package/dist/policies/timestamp.js.map +0 -1
  510. package/dist/policy-packs/builtin/permission-profiles.d.ts +0 -11
  511. package/dist/policy-packs/builtin/permission-profiles.js +0 -74
  512. package/dist/policy-packs/builtin/permission-profiles.js.map +0 -1
  513. package/dist/policy-packs/builtin/post-merge-gate-runtime.d.ts +0 -286
  514. package/dist/policy-packs/builtin/post-merge-gate-runtime.js +0 -397
  515. package/dist/policy-packs/builtin/post-merge-gate-runtime.js.map +0 -1
  516. package/dist/policy-packs/builtin/post-merge-gate.d.ts +0 -56
  517. package/dist/policy-packs/builtin/post-merge-gate.js +0 -347
  518. package/dist/policy-packs/builtin/post-merge-gate.js.map +0 -1
  519. package/dist/policy-packs/builtin/solution-acceptance-reconnect.d.ts +0 -50
  520. package/dist/policy-packs/builtin/solution-acceptance-reconnect.js +0 -151
  521. package/dist/policy-packs/builtin/solution-acceptance-reconnect.js.map +0 -1
  522. package/dist/policy-packs/builtin/solution-acceptance-runtime.d.ts +0 -323
  523. package/dist/policy-packs/builtin/solution-acceptance-runtime.js +0 -672
  524. package/dist/policy-packs/builtin/solution-acceptance-runtime.js.map +0 -1
  525. package/dist/policy-packs/builtin/solution-acceptance.d.ts +0 -45
  526. package/dist/policy-packs/builtin/solution-acceptance.js +0 -226
  527. package/dist/policy-packs/builtin/solution-acceptance.js.map +0 -1
  528. package/dist/policy-packs/builtin/understanding-before-execution/active-claim.d.ts +0 -25
  529. package/dist/policy-packs/builtin/understanding-before-execution/active-claim.js +0 -94
  530. package/dist/policy-packs/builtin/understanding-before-execution/active-claim.js.map +0 -1
  531. package/dist/policy-packs/builtin/understanding-before-execution/auto-approve-default.d.ts +0 -35
  532. package/dist/policy-packs/builtin/understanding-before-execution/auto-approve-default.js +0 -86
  533. package/dist/policy-packs/builtin/understanding-before-execution/auto-approve-default.js.map +0 -1
  534. package/dist/policy-packs/builtin/understanding-before-execution/auto-approve.d.ts +0 -210
  535. package/dist/policy-packs/builtin/understanding-before-execution/auto-approve.js +0 -361
  536. package/dist/policy-packs/builtin/understanding-before-execution/auto-approve.js.map +0 -1
  537. package/dist/policy-packs/builtin/understanding-before-execution/delegation-markers.d.ts +0 -304
  538. package/dist/policy-packs/builtin/understanding-before-execution/delegation-markers.js +0 -734
  539. package/dist/policy-packs/builtin/understanding-before-execution/delegation-markers.js.map +0 -1
  540. package/dist/policy-packs/builtin/understanding-before-execution/expiry-reason.d.ts +0 -36
  541. package/dist/policy-packs/builtin/understanding-before-execution/expiry-reason.js +0 -73
  542. package/dist/policy-packs/builtin/understanding-before-execution/expiry-reason.js.map +0 -1
  543. package/dist/policy-packs/builtin/understanding-before-execution/index.d.ts +0 -19
  544. package/dist/policy-packs/builtin/understanding-before-execution/index.js +0 -83
  545. package/dist/policy-packs/builtin/understanding-before-execution/index.js.map +0 -1
  546. package/dist/policy-packs/builtin/understanding-before-execution/inflight-records.d.ts +0 -135
  547. package/dist/policy-packs/builtin/understanding-before-execution/inflight-records.js +0 -618
  548. package/dist/policy-packs/builtin/understanding-before-execution/inflight-records.js.map +0 -1
  549. package/dist/policy-packs/builtin/understanding-before-execution/ledger.d.ts +0 -25
  550. package/dist/policy-packs/builtin/understanding-before-execution/ledger.js +0 -56
  551. package/dist/policy-packs/builtin/understanding-before-execution/ledger.js.map +0 -1
  552. package/dist/policy-packs/builtin/understanding-before-execution/lifecycle.d.ts +0 -20
  553. package/dist/policy-packs/builtin/understanding-before-execution/lifecycle.js +0 -93
  554. package/dist/policy-packs/builtin/understanding-before-execution/lifecycle.js.map +0 -1
  555. package/dist/policy-packs/builtin/understanding-before-execution/markers.d.ts +0 -126
  556. package/dist/policy-packs/builtin/understanding-before-execution/markers.js +0 -245
  557. package/dist/policy-packs/builtin/understanding-before-execution/markers.js.map +0 -1
  558. package/dist/policy-packs/builtin/understanding-before-execution/measured-permission-modes.d.ts +0 -29
  559. package/dist/policy-packs/builtin/understanding-before-execution/measured-permission-modes.js +0 -82
  560. package/dist/policy-packs/builtin/understanding-before-execution/measured-permission-modes.js.map +0 -1
  561. package/dist/policy-packs/builtin/understanding-before-execution/permission-mode-observations.d.ts +0 -71
  562. package/dist/policy-packs/builtin/understanding-before-execution/permission-mode-observations.js +0 -175
  563. package/dist/policy-packs/builtin/understanding-before-execution/permission-mode-observations.js.map +0 -1
  564. package/dist/policy-packs/builtin/understanding-before-execution/persisted-reports.d.ts +0 -620
  565. package/dist/policy-packs/builtin/understanding-before-execution/persisted-reports.js +0 -1047
  566. package/dist/policy-packs/builtin/understanding-before-execution/persisted-reports.js.map +0 -1
  567. package/dist/policy-packs/builtin/understanding-before-execution/post-tool-use-boundary.d.ts +0 -128
  568. package/dist/policy-packs/builtin/understanding-before-execution/post-tool-use-boundary.js +0 -213
  569. package/dist/policy-packs/builtin/understanding-before-execution/post-tool-use-boundary.js.map +0 -1
  570. package/dist/policy-packs/builtin/understanding-before-execution/stay-in-scope-config.d.ts +0 -129
  571. package/dist/policy-packs/builtin/understanding-before-execution/stay-in-scope-config.js +0 -166
  572. package/dist/policy-packs/builtin/understanding-before-execution/stay-in-scope-config.js.map +0 -1
  573. package/dist/policy-packs/builtin/understanding-before-execution/task-markers.d.ts +0 -164
  574. package/dist/policy-packs/builtin/understanding-before-execution/task-markers.js +0 -275
  575. package/dist/policy-packs/builtin/understanding-before-execution/task-markers.js.map +0 -1
  576. package/dist/policy-packs/builtin/understanding-before-execution-runtime.d.ts +0 -1
  577. package/dist/policy-packs/builtin/understanding-before-execution-runtime.js +0 -10
  578. package/dist/policy-packs/builtin/understanding-before-execution-runtime.js.map +0 -1
  579. package/dist/policy-packs/builtin/understanding-before-execution.d.ts +0 -526
  580. package/dist/policy-packs/builtin/understanding-before-execution.js +0 -1074
  581. package/dist/policy-packs/builtin/understanding-before-execution.js.map +0 -1
  582. package/dist/policy-packs/permission-translator.d.ts +0 -9
  583. package/dist/policy-packs/permission-translator.js +0 -76
  584. package/dist/policy-packs/permission-translator.js.map +0 -1
  585. package/dist/runtime/action-envelope.d.ts +0 -64
  586. package/dist/runtime/action-envelope.js +0 -46
  587. package/dist/runtime/action-envelope.js.map +0 -1
  588. package/dist/runtime/approval-signing.d.ts +0 -111
  589. package/dist/runtime/approval-signing.js +0 -384
  590. package/dist/runtime/approval-signing.js.map +0 -1
  591. package/dist/runtime/bash-match-facts.d.ts +0 -60
  592. package/dist/runtime/bash-match-facts.js +0 -196
  593. package/dist/runtime/bash-match-facts.js.map +0 -1
  594. package/dist/runtime/bash-match-registry.d.ts +0 -112
  595. package/dist/runtime/bash-match-registry.js +0 -406
  596. package/dist/runtime/bash-match-registry.js.map +0 -1
  597. package/dist/runtime/bash-prefix-parse.d.ts +0 -31
  598. package/dist/runtime/bash-prefix-parse.js +0 -576
  599. package/dist/runtime/bash-prefix-parse.js.map +0 -1
  600. package/dist/runtime/command-normalize.d.ts +0 -658
  601. package/dist/runtime/command-normalize.js +0 -2410
  602. package/dist/runtime/command-normalize.js.map +0 -1
  603. package/dist/runtime/deletion-target-resolve.d.ts +0 -28
  604. package/dist/runtime/deletion-target-resolve.js +0 -1078
  605. package/dist/runtime/deletion-target-resolve.js.map +0 -1
  606. package/dist/runtime/destructive-shell-floor.d.ts +0 -19
  607. package/dist/runtime/destructive-shell-floor.js +0 -611
  608. package/dist/runtime/destructive-shell-floor.js.map +0 -1
  609. package/dist/runtime/environment-resolver.d.ts +0 -36
  610. package/dist/runtime/environment-resolver.js +0 -138
  611. package/dist/runtime/environment-resolver.js.map +0 -1
  612. package/dist/runtime/git-context.d.ts +0 -201
  613. package/dist/runtime/git-context.js +0 -422
  614. package/dist/runtime/git-context.js.map +0 -1
  615. package/dist/runtime/index.d.ts +0 -12
  616. package/dist/runtime/index.js +0 -13
  617. package/dist/runtime/index.js.map +0 -1
  618. package/dist/runtime/intercept.d.ts +0 -494
  619. package/dist/runtime/intercept.js +0 -1313
  620. package/dist/runtime/intercept.js.map +0 -1
  621. package/dist/runtime/kube-context.d.ts +0 -16
  622. package/dist/runtime/kube-context.js +0 -63
  623. package/dist/runtime/kube-context.js.map +0 -1
  624. package/dist/runtime/kubectl-target-parse.d.ts +0 -31
  625. package/dist/runtime/kubectl-target-parse.js +0 -249
  626. package/dist/runtime/kubectl-target-parse.js.map +0 -1
  627. package/dist/runtime/ledger-add.d.ts +0 -16
  628. package/dist/runtime/ledger-add.js +0 -150
  629. package/dist/runtime/ledger-add.js.map +0 -1
  630. package/dist/runtime/ledger-writer.d.ts +0 -27
  631. package/dist/runtime/ledger-writer.js +0 -46
  632. package/dist/runtime/ledger-writer.js.map +0 -1
  633. package/dist/runtime/pause-sentinel.d.ts +0 -60
  634. package/dist/runtime/pause-sentinel.js +0 -156
  635. package/dist/runtime/pause-sentinel.js.map +0 -1
  636. package/dist/runtime/pending-approval.d.ts +0 -23
  637. package/dist/runtime/pending-approval.js +0 -67
  638. package/dist/runtime/pending-approval.js.map +0 -1
  639. package/dist/runtime/read-only-bash.d.ts +0 -141
  640. package/dist/runtime/read-only-bash.js +0 -2204
  641. package/dist/runtime/read-only-bash.js.map +0 -1
  642. package/dist/runtime/recovery-git-commit.d.ts +0 -22
  643. package/dist/runtime/recovery-git-commit.js +0 -284
  644. package/dist/runtime/recovery-git-commit.js.map +0 -1
  645. package/dist/runtime/reject-malformed-session-id.d.ts +0 -8
  646. package/dist/runtime/reject-malformed-session-id.js +0 -16
  647. package/dist/runtime/reject-malformed-session-id.js.map +0 -1
  648. package/dist/runtime/risk-classifier.d.ts +0 -38
  649. package/dist/runtime/risk-classifier.js +0 -311
  650. package/dist/runtime/risk-classifier.js.map +0 -1
  651. package/dist/runtime/session-id.d.ts +0 -113
  652. package/dist/runtime/session-id.js +0 -193
  653. package/dist/runtime/session-id.js.map +0 -1
  654. package/dist/runtime/shell-word.d.ts +0 -62
  655. package/dist/runtime/shell-word.js +0 -410
  656. package/dist/runtime/shell-word.js.map +0 -1
  657. package/dist/runtime/task-providers/agent-tasks.d.ts +0 -103
  658. package/dist/runtime/task-providers/agent-tasks.js +0 -245
  659. package/dist/runtime/task-providers/agent-tasks.js.map +0 -1
  660. package/dist/runtime/when-eval.d.ts +0 -62
  661. package/dist/runtime/when-eval.js +0 -212
  662. package/dist/runtime/when-eval.js.map +0 -1
  663. package/dist/runtime/workflow-policies.d.ts +0 -207
  664. package/dist/runtime/workflow-policies.js +0 -596
  665. package/dist/runtime/workflow-policies.js.map +0 -1
  666. package/dist/schema/audit.d.ts +0 -71
  667. package/dist/schema/audit.js +0 -32
  668. package/dist/schema/audit.js.map +0 -1
  669. package/dist/schema/doctor.d.ts +0 -25
  670. package/dist/schema/doctor.js +0 -23
  671. package/dist/schema/doctor.js.map +0 -1
  672. package/dist/schema/environments.d.ts +0 -215
  673. package/dist/schema/environments.js +0 -101
  674. package/dist/schema/environments.js.map +0 -1
  675. package/dist/schema/extract.d.ts +0 -9
  676. package/dist/schema/extract.js +0 -86
  677. package/dist/schema/extract.js.map +0 -1
  678. package/dist/schema/permission-profiles.d.ts +0 -2292
  679. package/dist/schema/permission-profiles.js +0 -60
  680. package/dist/schema/permission-profiles.js.map +0 -1
  681. package/dist/schema/policies.d.ts +0 -974
  682. package/dist/schema/policies.js +0 -298
  683. package/dist/schema/policies.js.map +0 -1
  684. package/dist/schema/requires.d.ts +0 -131
  685. package/dist/schema/requires.js +0 -88
  686. package/dist/schema/requires.js.map +0 -1
  687. package/dist/schema/risk.d.ts +0 -144
  688. package/dist/schema/risk.js +0 -194
  689. package/dist/schema/risk.js.map +0 -1
  690. package/dist/schema/session-start-preflight.d.ts +0 -10
  691. package/dist/schema/session-start-preflight.js +0 -106
  692. package/dist/schema/session-start-preflight.js.map +0 -1
  693. package/dist/schema/stale-base-check.d.ts +0 -18
  694. package/dist/schema/stale-base-check.js +0 -37
  695. package/dist/schema/stale-base-check.js.map +0 -1
  696. package/dist/schema/toolchain-parity.d.ts +0 -21
  697. package/dist/schema/toolchain-parity.js +0 -48
  698. package/dist/schema/toolchain-parity.js.map +0 -1
  699. package/dist/schema/workflows.d.ts +0 -519
  700. package/dist/schema/workflows.js +0 -81
  701. package/dist/schema/workflows.js.map +0 -1
  702. package/scripts/runtime-reality-docker-probe.mjs +0 -71
@@ -33,46 +33,37 @@
33
33
  * to occupy and against it carrying control characters anywhere
34
34
  * downstream.
35
35
  *
36
- * WHAT A REJECTION LOOKS LIKE. `deriveProjectName` (`src/runtime/git-
37
- * context.ts`) validates its own return value at every exit, so a
38
- * checkout directory whose basename contains a control character now
39
- * takes the same path a `".."` basename already took: the helper returns
40
- * `null`, no project override layer is looked up for that repository,
41
- * and the base/machine value applies unchanged. There is no error and no
42
- * warning; the operator sees the host-wide value instead of a per-repo
43
- * one (`harness doctor`'s setup-version finding then carries
44
- * `projectName: null` and renders no `(project: X)` suffix). An explicit
45
- * `--project` carrying a control character is instead reported:
36
+ * WHAT A REJECTION LOOKS LIKE. An explicit `--project` carrying a control
37
+ * character or a path-escaping shape is reported, not silently used:
46
38
  * `resolvePaths` resolves no project layer for it, and
47
39
  * `substituteProject` (`src/probes/memory.ts`) degrades to the "no
48
40
  * project supplied" branch, which `harness doctor` surfaces as its
49
41
  * rejected-`--project` warn line.
50
42
  *
51
- * Exported (task c88461c1, review round 3 residual; task `1c4eb3ea`
52
- * of the batch-44 follow-up run) so `resolvePaths` (`src/cli/loader.ts`)
53
- * can apply the SAME guard at its own `path.join` sink, defense in
54
- * depth: this function already rejects an unsafe name at every
55
- * `deriveProjectName` exit, but an `opts.project` reaching
56
- * `resolvePaths`' OWN sink from anywhere else (a caller building
57
- * `LoaderOptions` by hand, a future producer) had no equivalent check
58
- * of its own until now. Applied a THIRD time at `substituteProject`'s
59
- * own sink (`src/probes/memory.ts`, task `e904f25a`): an invalid name
60
- * there degrades to the "no project supplied" branch instead of being
61
- * interpolated into the `{project}` placeholder. Applied a FOURTH time
62
- * at `buildLockEntries`' own sink (`src/io/harness-lock.ts`, task
63
- * `b5e6ccb0`): an invalid name there skips the templated directory's
64
- * lock entry instead of the raw value being interpolated into the path
65
- * this function stats, hashes and writes into `harness.lock`.
43
+ * Exported (task c88461c1; task `1c4eb3ea` of the batch-44 follow-up run)
44
+ * so `resolvePaths` (`src/cli/loader.ts`) can apply the SAME guard at
45
+ * its own `path.join` sink, defense in depth: an `opts.project`
46
+ * reaching `resolvePaths` from anywhere (the explicit `--project`
47
+ * flag, a caller building `LoaderOptions` by hand, a future producer)
48
+ * is checked there. Applied a SECOND time at
49
+ * `substituteProject`'s own sink (`src/probes/memory.ts`, task
50
+ * `e904f25a`): an invalid name there degrades to the "no project
51
+ * supplied" branch instead of being interpolated into the `{project}`
52
+ * placeholder. Applied a THIRD time at `buildLockEntries`' own sink
53
+ * (`src/io/harness-lock.ts`, task `b5e6ccb0`): an invalid name there
54
+ * skips the templated directory's lock entry instead of the raw value
55
+ * being interpolated into the path this function stats, hashes and
56
+ * writes into `harness.lock`.
66
57
  * `resolvePaths`, `substituteProject` and `buildLockEntries` are now all
67
58
  * guarded; one `{project}` sink is NOT: `generate-memory-index.ts`'s own
68
59
  * substitution still interpolates an operator-supplied `--project` value
69
60
  * into a path unvalidated, left unguarded (reached only via the explicit
70
- * CLI flag, not this module's derivation; see CHANGELOG.md for the
71
- * reservation/follow-up). That one call site calls this function
72
- * nowhere, so it inherits NOTHING from the control-character screen
73
- * above either: a caller reading this comment should not assume this
74
- * function guards every `{project}`-shaped sink in the codebase, for
75
- * path escapes or for control characters.
61
+ * `--project` CLI flag; see CHANGELOG.md for the reservation/follow-up).
62
+ * That one call site calls this function nowhere, so it inherits NOTHING
63
+ * from the control-character screen above either: a caller reading
64
+ * this comment should not assume this function guards every
65
+ * `{project}`-shaped sink in the codebase, for path escapes or for
66
+ * control characters.
76
67
  */
77
68
  export declare function isValidProjectName(name: string): boolean;
78
69
  /**
@@ -96,14 +87,6 @@ export declare function isValidProjectName(name: string): boolean;
96
87
  * field (`src/cli/list.ts`, and with it the text table derived from
97
88
  * it).
98
89
  *
99
- * The `session_start_preflight.setup` finding's `(project: X)` suffix is
100
- * also wrapped, as defense in depth rather than as an echo of a rejected
101
- * value: `harness doctor` sets that finding's `projectName` only when
102
- * `resolvePaths` actually resolved a project layer FILE, which requires
103
- * the name to have passed {@link isValidProjectName} first. The wrap
104
- * stays so a hand-built finding or a future producer cannot reintroduce
105
- * a forged line through that one call site.
106
- *
107
90
  * Strips (rather than escapes) every character in
108
91
  * {@link PROJECT_NAME_CONTROL_CHARS}. A name with no control character
109
92
  * (`..`, `a/b`, every ordinary shape) passes through unchanged. Report
@@ -10,9 +10,9 @@
10
10
  // documents for `src/policies/duration.ts`, `src/policies/extract.ts`,
11
11
  // `src/runtime/ledger-record.ts` and `src/runtime/expand-home.ts`: a
12
12
  // utility needed below its original layer moves down rather than the
13
- // importing layer's boundary being relaxed. `src/runtime/git-context.ts`
14
- // re-exports both names so every existing consumer that imports them from
15
- // `../runtime/git-context.js` keeps working unchanged.
13
+ // importing layer's boundary being relaxed. This module is the home of
14
+ // both helpers: every consumer imports them from `src/io/project-name.ts`
15
+ // directly.
16
16
  /**
17
17
  * Every C0 control character (U+0000 to U+001F, so NUL, LF, CR and ESC
18
18
  * among them), DEL (U+007F), and every C1 control character (U+0080 to
@@ -65,46 +65,37 @@ const PROJECT_NAME_CONTROL_CHARS_GLOBAL = new RegExp(PROJECT_NAME_CONTROL_CHARS.
65
65
  * to occupy and against it carrying control characters anywhere
66
66
  * downstream.
67
67
  *
68
- * WHAT A REJECTION LOOKS LIKE. `deriveProjectName` (`src/runtime/git-
69
- * context.ts`) validates its own return value at every exit, so a
70
- * checkout directory whose basename contains a control character now
71
- * takes the same path a `".."` basename already took: the helper returns
72
- * `null`, no project override layer is looked up for that repository,
73
- * and the base/machine value applies unchanged. There is no error and no
74
- * warning; the operator sees the host-wide value instead of a per-repo
75
- * one (`harness doctor`'s setup-version finding then carries
76
- * `projectName: null` and renders no `(project: X)` suffix). An explicit
77
- * `--project` carrying a control character is instead reported:
68
+ * WHAT A REJECTION LOOKS LIKE. An explicit `--project` carrying a control
69
+ * character or a path-escaping shape is reported, not silently used:
78
70
  * `resolvePaths` resolves no project layer for it, and
79
71
  * `substituteProject` (`src/probes/memory.ts`) degrades to the "no
80
72
  * project supplied" branch, which `harness doctor` surfaces as its
81
73
  * rejected-`--project` warn line.
82
74
  *
83
- * Exported (task c88461c1, review round 3 residual; task `1c4eb3ea`
84
- * of the batch-44 follow-up run) so `resolvePaths` (`src/cli/loader.ts`)
85
- * can apply the SAME guard at its own `path.join` sink, defense in
86
- * depth: this function already rejects an unsafe name at every
87
- * `deriveProjectName` exit, but an `opts.project` reaching
88
- * `resolvePaths`' OWN sink from anywhere else (a caller building
89
- * `LoaderOptions` by hand, a future producer) had no equivalent check
90
- * of its own until now. Applied a THIRD time at `substituteProject`'s
91
- * own sink (`src/probes/memory.ts`, task `e904f25a`): an invalid name
92
- * there degrades to the "no project supplied" branch instead of being
93
- * interpolated into the `{project}` placeholder. Applied a FOURTH time
94
- * at `buildLockEntries`' own sink (`src/io/harness-lock.ts`, task
95
- * `b5e6ccb0`): an invalid name there skips the templated directory's
96
- * lock entry instead of the raw value being interpolated into the path
97
- * this function stats, hashes and writes into `harness.lock`.
75
+ * Exported (task c88461c1; task `1c4eb3ea` of the batch-44 follow-up run)
76
+ * so `resolvePaths` (`src/cli/loader.ts`) can apply the SAME guard at
77
+ * its own `path.join` sink, defense in depth: an `opts.project`
78
+ * reaching `resolvePaths` from anywhere (the explicit `--project`
79
+ * flag, a caller building `LoaderOptions` by hand, a future producer)
80
+ * is checked there. Applied a SECOND time at
81
+ * `substituteProject`'s own sink (`src/probes/memory.ts`, task
82
+ * `e904f25a`): an invalid name there degrades to the "no project
83
+ * supplied" branch instead of being interpolated into the `{project}`
84
+ * placeholder. Applied a THIRD time at `buildLockEntries`' own sink
85
+ * (`src/io/harness-lock.ts`, task `b5e6ccb0`): an invalid name there
86
+ * skips the templated directory's lock entry instead of the raw value
87
+ * being interpolated into the path this function stats, hashes and
88
+ * writes into `harness.lock`.
98
89
  * `resolvePaths`, `substituteProject` and `buildLockEntries` are now all
99
90
  * guarded; one `{project}` sink is NOT: `generate-memory-index.ts`'s own
100
91
  * substitution still interpolates an operator-supplied `--project` value
101
92
  * into a path unvalidated, left unguarded (reached only via the explicit
102
- * CLI flag, not this module's derivation; see CHANGELOG.md for the
103
- * reservation/follow-up). That one call site calls this function
104
- * nowhere, so it inherits NOTHING from the control-character screen
105
- * above either: a caller reading this comment should not assume this
106
- * function guards every `{project}`-shaped sink in the codebase, for
107
- * path escapes or for control characters.
93
+ * `--project` CLI flag; see CHANGELOG.md for the reservation/follow-up).
94
+ * That one call site calls this function nowhere, so it inherits NOTHING
95
+ * from the control-character screen above either: a caller reading
96
+ * this comment should not assume this function guards every
97
+ * `{project}`-shaped sink in the codebase, for path escapes or for
98
+ * control characters.
108
99
  */
109
100
  export function isValidProjectName(name) {
110
101
  if (name.length === 0)
@@ -136,14 +127,6 @@ export function isValidProjectName(name) {
136
127
  * field (`src/cli/list.ts`, and with it the text table derived from
137
128
  * it).
138
129
  *
139
- * The `session_start_preflight.setup` finding's `(project: X)` suffix is
140
- * also wrapped, as defense in depth rather than as an echo of a rejected
141
- * value: `harness doctor` sets that finding's `projectName` only when
142
- * `resolvePaths` actually resolved a project layer FILE, which requires
143
- * the name to have passed {@link isValidProjectName} first. The wrap
144
- * stays so a hand-built finding or a future producer cannot reintroduce
145
- * a forged line through that one call site.
146
- *
147
130
  * Strips (rather than escapes) every character in
148
131
  * {@link PROJECT_NAME_CONTROL_CHARS}. A name with no control character
149
132
  * (`..`, `a/b`, every ordinary shape) passes through unchanged. Report
@@ -1 +1 @@
1
- {"version":3,"file":"project-name.js","sourceRoot":"","sources":["../../src/io/project-name.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,yCAAyC;AACzC,EAAE;AACF,4EAA4E;AAC5E,uEAAuE;AACvE,2EAA2E;AAC3E,+DAA+D;AAC/D,wEAAwE;AACxE,wEAAwE;AACxE,uEAAuE;AACvE,qEAAqE;AACrE,qEAAqE;AACrE,yEAAyE;AACzE,0EAA0E;AAC1E,uDAAuD;AAEvD;;;;;;;GAOG;AACH,MAAM,0BAA0B,GAAG,8BAA8B,CAAC;AAElE;;;;;;GAMG;AACH,MAAM,iCAAiC,GAAG,IAAI,MAAM,CAAC,0BAA0B,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAE7F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2EG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACpC,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAChD,IAAI,0BAA0B,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACxD,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACrD,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,MAAM,UAAU,yBAAyB,CAAC,IAAY;IACpD,OAAO,IAAI,CAAC,OAAO,CAAC,iCAAiC,EAAE,EAAE,CAAC,CAAC;AAC7D,CAAC"}
1
+ {"version":3,"file":"project-name.js","sourceRoot":"","sources":["../../src/io/project-name.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,yCAAyC;AACzC,EAAE;AACF,4EAA4E;AAC5E,uEAAuE;AACvE,2EAA2E;AAC3E,+DAA+D;AAC/D,wEAAwE;AACxE,wEAAwE;AACxE,uEAAuE;AACvE,qEAAqE;AACrE,qEAAqE;AACrE,uEAAuE;AACvE,0EAA0E;AAC1E,YAAY;AAEZ;;;;;;;GAOG;AACH,MAAM,0BAA0B,GAAG,8BAA8B,CAAC;AAElE;;;;;;GAMG;AACH,MAAM,iCAAiC,GAAG,IAAI,MAAM,CAAC,0BAA0B,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAE7F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkEG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACpC,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAChD,IAAI,0BAA0B,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACxD,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACrD,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,UAAU,yBAAyB,CAAC,IAAY;IACpD,OAAO,IAAI,CAAC,OAAO,CAAC,iCAAiC,EAAE,EAAE,CAAC,CAAC;AAC7D,CAAC"}
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Result of a symlink-rejecting regular-file read. The kinds are deliberately
3
- * fine-grained because the gate readers need to keep their distinct deny
4
- * details (missing vs symlink vs not-regular) and one caller treats
5
- * exists-but-unreadable as "existence already satisfied the gate".
3
+ * fine-grained because the readers need to keep their distinct failure
4
+ * details (missing vs symlink vs not-regular); every caller treats
5
+ * `unreadable` (an oversized file included) as fail-closed.
6
6
  */
7
7
  export type RegularFileRead = {
8
8
  kind: "ok";
@@ -17,47 +17,110 @@ export type RegularFileRead = {
17
17
  kind: "unreadable";
18
18
  };
19
19
  /**
20
- * Result of a stat-only existence probe (see `probePathPresence`). No
21
- * `content`: this never reads the file, only classifies what lstat sees at
22
- * the path. `present` covers a symlink, a directory, or any other non-regular
23
- * node the caller wants to treat as "something is there" without yet reading
24
- * it or deciding whether it is a valid regular file.
20
+ * The most bytes a read returns by default. The current callers read small
21
+ * text records: the harness manifest and its override layers
22
+ * (`src/cli/loader.ts`) and, with a larger bound of their own, the Claude
23
+ * Code user-scope MCP registry (`src/io/claude-mcp.ts`). A file over the
24
+ * cap is refused as `unreadable` (fail-closed in every caller) before any
25
+ * byte is read: a sparse multi-gigabyte file at one of these paths
26
+ * otherwise makes the caller wait on bytes it never asked for, the same
27
+ * stall a FIFO used to cause.
25
28
  */
26
- export type PathPresence = {
27
- kind: "missing";
28
- } | {
29
- kind: "present";
30
- };
29
+ export declare const MAX_REGULAR_FILE_READ_BYTES: number;
30
+ /**
31
+ * Options of the readers below. They default to the strict read this module
32
+ * was built for (the 1 MiB cap, a symlink refused).
33
+ */
34
+ export interface BoundedReadOptions {
35
+ /**
36
+ * The most bytes the read returns; a file over it is refused as
37
+ * `unreadable` before any byte is read, exactly like the default cap.
38
+ * Defaults to {@link MAX_REGULAR_FILE_READ_BYTES}. A caller
39
+ * with a legitimately larger input (the Claude Code user registry) passes
40
+ * its own, larger bound and justifies
41
+ * it at the call site; there is deliberately no way to ask for no bound.
42
+ */
43
+ maxBytes?: number;
44
+ /**
45
+ * Follow a symbolic link at the path (the open drops `O_NOFOLLOW`). For a
46
+ * reader of a file the operator legitimately keeps behind a link
47
+ * (a dotfiles-managed manifest); it never weakens the
48
+ * rest: the type of the OPENED descriptor still decides, so a link to a
49
+ * FIFO, a device or a directory is `not-regular` and never blocks.
50
+ * Defaults to `false` (a link is refused as `symlink`).
51
+ */
52
+ followSymlinks?: boolean;
53
+ }
54
+ export type RegularFileBytesRead = {
55
+ kind: "ok";
56
+ bytes: Buffer;
57
+ } | Exclude<RegularFileRead, {
58
+ kind: "ok";
59
+ }>;
31
60
  /**
32
- * Read a marker/verdict file as utf8, refusing symlinks and non-regular
33
- * files. lstat (NOT stat): defense-in-depth against a symlink at the marker
34
- * path pointing at an arbitrary target the agent controls. In today's threat
35
- * model the agent has no Edit / Write / Bash path to plant such a symlink
36
- * (the same PreToolUse hook gates all three), but the gate contract is to
37
- * assume the agent is hostile, so the lstat reject is cheap insurance
61
+ * The one open-once, type-checked-on-the-descriptor, size-bounded read every
62
+ * by-path reader on a hook path stands on, returning raw bytes (a binary key
63
+ * file needs them, `readRegularFileBounded` decodes them). The cap and the
64
+ * symlink policy are options.
65
+ *
66
+ * The path is opened once, read-only, with `O_NOFOLLOW` (a symlink at the
67
+ * path is refused by the open itself) and `O_NONBLOCK` (opening a FIFO with
68
+ * no writer returns at once instead of waiting for one). The type of the
69
+ * OPENED descriptor then decides (`fstat`, never a separate stat of the
70
+ * path), and the content is read through that same descriptor, so nothing
71
+ * can be swapped in between a check and the read: a writer that replaces the
72
+ * file with a FIFO or a symlink after any earlier look gets `not-regular` /
73
+ * `symlink` back, not a read that blocks the hook past its budget (which the
74
+ * runtime treats as an allow). The descriptor is always closed. The size is
75
+ * bounded too: a file over the cap by `fstat` is refused as `unreadable`
76
+ * without a read, and the read itself stops one byte past the cap, so a file
77
+ * that grows after the `fstat` is bounded as well.
78
+ *
79
+ * Why refuse symlinks at all: defense-in-depth against a symlink at the
80
+ * path pointing at an arbitrary target the agent controls. The gate contract
81
+ * is to assume the agent is hostile, so the refusal is cheap insurance
38
82
  * (agent-tasks/d39f160e).
39
83
  *
40
- * This is THE shared implementation for every gate-marker read; a future
41
- * defensive fix belongs in `lstatOrNull`, above, and nowhere else. Its
42
- * lighter-weight sibling `probePathPresence`, below, shares this file for
43
- * the same reason: both stand on the same `lstatOrNull` helper, and a
44
- * caller that only needs to know "is anything there" before deciding
45
- * whether to pay for the full read (e.g. `verifyDelegation`'s
46
- * existence-before-path-hash check in
47
- * `src/policy-packs/builtin/understanding-before-execution/delegation-markers.ts`)
48
- * gets that from here instead of hand-rolling its own `lstatSync` try/catch.
84
+ * Platforms without `O_NOFOLLOW` (Windows): an `lstat` runs first and
85
+ * refuses a symlink or a non-regular node before the open, because the open
86
+ * alone would follow a link. That leaves the old lstat-to-open window on
87
+ * those platforms; there is no FIFO node on the filesystem there to swap in
88
+ * (named pipes live in a separate namespace), and `O_NONBLOCK` is a no-op
89
+ * flag that is simply left out. The descriptor type check still runs.
90
+ *
91
+ * A future defensive fix belongs here and in `classifyOpenFailure` /
92
+ * `lstatOrNull`, and nowhere else.
93
+ */
94
+ export declare function readRegularFileBytesBounded(filePath: string, opts?: BoundedReadOptions): RegularFileBytesRead;
95
+ /**
96
+ * {@link readRegularFileBytesBounded} decoded as utf8, for the by-path
97
+ * readers of a file a symlink at the path is acceptable for or a larger cap
98
+ * is justified (see {@link BoundedReadOptions}). Same five result kinds as
99
+ * {@link readRegularFileBytesBounded}; `missing` is the one a caller may
100
+ * treat as "legitimately absent", every other non-`ok` kind means something
101
+ * is at the path that must not be read as the file (a FIFO, a device, a
102
+ * directory, an oversized or unreadable file) and is fail-closed or
103
+ * explicitly reported by the caller.
104
+ */
105
+ export declare function readRegularFileBounded(filePath: string, opts?: BoundedReadOptions): RegularFileRead;
106
+ /**
107
+ * Thrown by {@link readTextFileBoundedOrThrow}. `code` is `ENOENT` for a
108
+ * path that is not there (so a caller's existing `ENOENT` branch keeps
109
+ * meaning "absent") and `E_<KIND>` (`E_SYMLINK`, `E_NOT_REGULAR`,
110
+ * `E_UNREADABLE`) for anything else, which never matches `ENOENT`.
49
111
  */
50
- export declare function readRegularFileRejectingSymlink(filePath: string): RegularFileRead;
112
+ export declare class BoundedReadError extends Error {
113
+ readonly code: string;
114
+ readonly kind: Exclude<RegularFileRead["kind"], "ok">;
115
+ constructor(filePath: string, kind: Exclude<RegularFileRead["kind"], "ok">);
116
+ }
51
117
  /**
52
- * Stat-only existence probe: "is anything there", nothing more. Uses the
53
- * same `lstatOrNull` helper (not `stat`) as `readRegularFileRejectingSymlink`
54
- * so a symlink or a directory answers `present`, not `missing`; this probe
55
- * cannot and does not classify WHAT is there (regular file, symlink,
56
- * directory), only whether lstat can see anything at all. A path lstat
57
- * cannot reach for any reason (absent, or unreachable: `EACCES`, `ENOTDIR`,
58
- * ...) comes back `missing`; lstat cannot distinguish those cases, so
59
- * neither does this probe. Callers that need the file-type distinction
60
- * (symlink vs directory vs regular) read the file instead, through
61
- * `readRegularFileRejectingSymlink`.
118
+ * {@link readRegularFileBounded} for the call sites that already wrap a
119
+ * `fs.readFileSync(path, "utf8")` in a try/catch (and, some of them, branch
120
+ * on `ENOENT`): the same bounded, non-blocking read, thrown as a
121
+ * {@link BoundedReadError} instead of returned, so the existing catch blocks
122
+ * keep their shape and every FIFO, device, directory or oversized file now
123
+ * lands in the catch block it would have reached on any other read error,
124
+ * rather than blocking the process.
62
125
  */
63
- export declare function probePathPresence(filePath: string): PathPresence;
126
+ export declare function readTextFileBoundedOrThrow(filePath: string, opts?: BoundedReadOptions): string;
@@ -1,11 +1,10 @@
1
1
  import * as fs from "node:fs";
2
2
  /**
3
- * The single `fs.lstatSync` call both exports below stand on. Returns `null`
3
+ * The single `fs.lstatSync` call the readers below stand on. Returns `null`
4
4
  * on any lstat failure (absent path, or unreachable for another reason:
5
5
  * `EACCES`, `ENOTDIR`, ...); lstat cannot distinguish those cases from each
6
- * other, so neither export tries to. A future defensive fix here (e.g.
7
- * closing the lstat/read race with `O_NOFOLLOW`, `ENOTDIR` handling) lands in
8
- * this one place and is inherited by both callers.
6
+ * other, so no caller tries to. A future defensive fix here
7
+ * (e.g. `ENOTDIR` handling) lands in this one place.
9
8
  */
10
9
  function lstatOrNull(filePath) {
11
10
  try {
@@ -16,25 +15,79 @@ function lstatOrNull(filePath) {
16
15
  }
17
16
  }
18
17
  /**
19
- * Read a marker/verdict file as utf8, refusing symlinks and non-regular
20
- * files. lstat (NOT stat): defense-in-depth against a symlink at the marker
21
- * path pointing at an arbitrary target the agent controls. In today's threat
22
- * model the agent has no Edit / Write / Bash path to plant such a symlink
23
- * (the same PreToolUse hook gates all three), but the gate contract is to
24
- * assume the agent is hostile, so the lstat reject is cheap insurance
25
- * (agent-tasks/d39f160e).
26
- *
27
- * This is THE shared implementation for every gate-marker read; a future
28
- * defensive fix belongs in `lstatOrNull`, above, and nowhere else. Its
29
- * lighter-weight sibling `probePathPresence`, below, shares this file for
30
- * the same reason: both stand on the same `lstatOrNull` helper, and a
31
- * caller that only needs to know "is anything there" before deciding
32
- * whether to pay for the full read (e.g. `verifyDelegation`'s
33
- * existence-before-path-hash check in
34
- * `src/policy-packs/builtin/understanding-before-execution/delegation-markers.ts`)
35
- * gets that from here instead of hand-rolling its own `lstatSync` try/catch.
18
+ * Open flags for the reads in this module. `O_NOFOLLOW` makes the open itself
19
+ * refuse a symbolic link at the final path component (`ELOOP`), so no
20
+ * earlier `lstat` is needed for a swap to race. `O_NONBLOCK` keeps an open
21
+ * of a FIFO with no writer from waiting for one: the open returns at once
22
+ * and the descriptor's type then refuses it. `O_NOFOLLOW` covers only the
23
+ * LAST path component; a symlinked parent directory is followed, as it was
24
+ * under the earlier lstat. `O_NOCTTY` is belt and braces for a tty node at
25
+ * the path. All three are POSIX-only flags; `fs.constants` leaves them
26
+ * `undefined` on Windows, where the code falls back to 0 (see
27
+ * `readRegularFileBytesBounded` for that fallback).
28
+ */
29
+ const O_NOFOLLOW = fs.constants.O_NOFOLLOW;
30
+ const O_NONBLOCK = fs.constants.O_NONBLOCK ?? 0;
31
+ /** A read here must never make a terminal the process's controlling one. */
32
+ const O_NOCTTY = fs.constants.O_NOCTTY ?? 0;
33
+ /**
34
+ * The most bytes a read returns by default. The current callers read small
35
+ * text records: the harness manifest and its override layers
36
+ * (`src/cli/loader.ts`) and, with a larger bound of their own, the Claude
37
+ * Code user-scope MCP registry (`src/io/claude-mcp.ts`). A file over the
38
+ * cap is refused as `unreadable` (fail-closed in every caller) before any
39
+ * byte is read: a sparse multi-gigabyte file at one of these paths
40
+ * otherwise makes the caller wait on bytes it never asked for, the same
41
+ * stall a FIFO used to cause.
42
+ */
43
+ export const MAX_REGULAR_FILE_READ_BYTES = 1024 * 1024;
44
+ const READ_CHUNK_BYTES = 64 * 1024;
45
+ /**
46
+ * Read the opened descriptor to EOF, never more than `maxBytes + 1` bytes: a
47
+ * file that grows after the `fstat` size check stays bounded too. Returns
48
+ * `null` when the file is over the cap. Any read error propagates to the
49
+ * caller.
50
+ */
51
+ function readDescriptorBounded(fd, maxBytes) {
52
+ const chunks = [];
53
+ let total = 0;
54
+ for (;;) {
55
+ const want = Math.min(READ_CHUNK_BYTES, maxBytes + 1 - total);
56
+ const chunk = Buffer.allocUnsafe(want);
57
+ const got = fs.readSync(fd, chunk, 0, want, null);
58
+ if (got === 0)
59
+ break;
60
+ total += got;
61
+ if (total > maxBytes)
62
+ return null;
63
+ chunks.push(got === want ? chunk : chunk.subarray(0, got));
64
+ }
65
+ return Buffer.concat(chunks);
66
+ }
67
+ /**
68
+ * Classify a failed open by what `lstat` sees at the path now, so the
69
+ * caller-visible kinds stay what they were when `lstat` came first: an
70
+ * unreachable path (absent, `ENOTDIR`, an unsearchable parent) is `missing`,
71
+ * a symlink (dangling included) is `symlink`, any other non-regular node is
72
+ * `not-regular`, and a regular file the open could not read (`EACCES`, ...)
73
+ * is `unreadable`. A path that raced into a different state between the
74
+ * failed open and this `lstat` still lands on one of the five kinds, never
75
+ * on `ok`.
36
76
  */
37
- export function readRegularFileRejectingSymlink(filePath) {
77
+ function classifyOpenFailure(filePath, followSymlinks = false) {
78
+ if (followSymlinks) {
79
+ // A link is followed by this read, so what matters is what it leads to:
80
+ // a dangling link (or an unreachable parent) is absent, exactly as a
81
+ // by-path read of it reports `ENOENT`; a link loop or an unreadable
82
+ // target is something there that cannot be read.
83
+ try {
84
+ return fs.statSync(filePath).isFile() ? { kind: "unreadable" } : { kind: "not-regular" };
85
+ }
86
+ catch (err) {
87
+ const code = err.code;
88
+ return code === "ENOENT" || code === "ENOTDIR" ? { kind: "missing" } : { kind: "unreadable" };
89
+ }
90
+ }
38
91
  const stat = lstatOrNull(filePath);
39
92
  if (stat === null)
40
93
  return { kind: "missing" };
@@ -42,26 +95,134 @@ export function readRegularFileRejectingSymlink(filePath) {
42
95
  return { kind: "symlink" };
43
96
  if (!stat.isFile())
44
97
  return { kind: "not-regular" };
98
+ return { kind: "unreadable" };
99
+ }
100
+ /**
101
+ * The one open-once, type-checked-on-the-descriptor, size-bounded read every
102
+ * by-path reader on a hook path stands on, returning raw bytes (a binary key
103
+ * file needs them, `readRegularFileBounded` decodes them). The cap and the
104
+ * symlink policy are options.
105
+ *
106
+ * The path is opened once, read-only, with `O_NOFOLLOW` (a symlink at the
107
+ * path is refused by the open itself) and `O_NONBLOCK` (opening a FIFO with
108
+ * no writer returns at once instead of waiting for one). The type of the
109
+ * OPENED descriptor then decides (`fstat`, never a separate stat of the
110
+ * path), and the content is read through that same descriptor, so nothing
111
+ * can be swapped in between a check and the read: a writer that replaces the
112
+ * file with a FIFO or a symlink after any earlier look gets `not-regular` /
113
+ * `symlink` back, not a read that blocks the hook past its budget (which the
114
+ * runtime treats as an allow). The descriptor is always closed. The size is
115
+ * bounded too: a file over the cap by `fstat` is refused as `unreadable`
116
+ * without a read, and the read itself stops one byte past the cap, so a file
117
+ * that grows after the `fstat` is bounded as well.
118
+ *
119
+ * Why refuse symlinks at all: defense-in-depth against a symlink at the
120
+ * path pointing at an arbitrary target the agent controls. The gate contract
121
+ * is to assume the agent is hostile, so the refusal is cheap insurance
122
+ * (agent-tasks/d39f160e).
123
+ *
124
+ * Platforms without `O_NOFOLLOW` (Windows): an `lstat` runs first and
125
+ * refuses a symlink or a non-regular node before the open, because the open
126
+ * alone would follow a link. That leaves the old lstat-to-open window on
127
+ * those platforms; there is no FIFO node on the filesystem there to swap in
128
+ * (named pipes live in a separate namespace), and `O_NONBLOCK` is a no-op
129
+ * flag that is simply left out. The descriptor type check still runs.
130
+ *
131
+ * A future defensive fix belongs here and in `classifyOpenFailure` /
132
+ * `lstatOrNull`, and nowhere else.
133
+ */
134
+ export function readRegularFileBytesBounded(filePath, opts = {}) {
135
+ const maxBytes = opts.maxBytes ?? MAX_REGULAR_FILE_READ_BYTES;
136
+ const noFollow = opts.followSymlinks !== true;
137
+ if (noFollow && O_NOFOLLOW === undefined) {
138
+ const stat = lstatOrNull(filePath);
139
+ if (stat === null)
140
+ return { kind: "missing" };
141
+ if (stat.isSymbolicLink())
142
+ return { kind: "symlink" };
143
+ if (!stat.isFile())
144
+ return { kind: "not-regular" };
145
+ }
146
+ let fd;
147
+ try {
148
+ fd = fs.openSync(filePath, fs.constants.O_RDONLY | (noFollow ? (O_NOFOLLOW ?? 0) : 0) | O_NONBLOCK | O_NOCTTY);
149
+ }
150
+ catch {
151
+ return classifyOpenFailure(filePath, !noFollow);
152
+ }
45
153
  try {
46
- return { kind: "ok", content: fs.readFileSync(filePath, "utf8") };
154
+ const st = fs.fstatSync(fd);
155
+ if (!st.isFile())
156
+ return { kind: "not-regular" };
157
+ if (st.size > maxBytes)
158
+ return { kind: "unreadable" };
159
+ const bytes = readDescriptorBounded(fd, maxBytes);
160
+ if (bytes === null)
161
+ return { kind: "unreadable" };
162
+ return { kind: "ok", bytes };
47
163
  }
48
164
  catch {
49
165
  return { kind: "unreadable" };
50
166
  }
167
+ finally {
168
+ try {
169
+ fs.closeSync(fd);
170
+ }
171
+ catch {
172
+ // Already gone; nothing left to release.
173
+ }
174
+ }
175
+ }
176
+ /**
177
+ * {@link readRegularFileBytesBounded} decoded as utf8, for the by-path
178
+ * readers of a file a symlink at the path is acceptable for or a larger cap
179
+ * is justified (see {@link BoundedReadOptions}). Same five result kinds as
180
+ * {@link readRegularFileBytesBounded}; `missing` is the one a caller may
181
+ * treat as "legitimately absent", every other non-`ok` kind means something
182
+ * is at the path that must not be read as the file (a FIFO, a device, a
183
+ * directory, an oversized or unreadable file) and is fail-closed or
184
+ * explicitly reported by the caller.
185
+ */
186
+ export function readRegularFileBounded(filePath, opts = {}) {
187
+ const read = readRegularFileBytesBounded(filePath, opts);
188
+ return read.kind === "ok" ? { kind: "ok", content: read.bytes.toString("utf8") } : read;
189
+ }
190
+ /**
191
+ * Thrown by {@link readTextFileBoundedOrThrow}. `code` is `ENOENT` for a
192
+ * path that is not there (so a caller's existing `ENOENT` branch keeps
193
+ * meaning "absent") and `E_<KIND>` (`E_SYMLINK`, `E_NOT_REGULAR`,
194
+ * `E_UNREADABLE`) for anything else, which never matches `ENOENT`.
195
+ */
196
+ export class BoundedReadError extends Error {
197
+ code;
198
+ kind;
199
+ constructor(filePath, kind) {
200
+ const code = kind === "missing" ? "ENOENT" : `E_${kind.toUpperCase().replace(/-/g, "_")}`;
201
+ super(`${code}: ${filePath} ${DESCRIBE_KIND[kind]}`);
202
+ this.name = "BoundedReadError";
203
+ this.code = code;
204
+ this.kind = kind;
205
+ }
51
206
  }
207
+ const DESCRIBE_KIND = {
208
+ missing: "does not exist",
209
+ symlink: "is a symbolic link (refused)",
210
+ "not-regular": "is not a regular file (refused without a read)",
211
+ unreadable: "is unreadable or larger than the read cap",
212
+ };
52
213
  /**
53
- * Stat-only existence probe: "is anything there", nothing more. Uses the
54
- * same `lstatOrNull` helper (not `stat`) as `readRegularFileRejectingSymlink`
55
- * so a symlink or a directory answers `present`, not `missing`; this probe
56
- * cannot and does not classify WHAT is there (regular file, symlink,
57
- * directory), only whether lstat can see anything at all. A path lstat
58
- * cannot reach for any reason (absent, or unreachable: `EACCES`, `ENOTDIR`,
59
- * ...) comes back `missing`; lstat cannot distinguish those cases, so
60
- * neither does this probe. Callers that need the file-type distinction
61
- * (symlink vs directory vs regular) read the file instead, through
62
- * `readRegularFileRejectingSymlink`.
214
+ * {@link readRegularFileBounded} for the call sites that already wrap a
215
+ * `fs.readFileSync(path, "utf8")` in a try/catch (and, some of them, branch
216
+ * on `ENOENT`): the same bounded, non-blocking read, thrown as a
217
+ * {@link BoundedReadError} instead of returned, so the existing catch blocks
218
+ * keep their shape and every FIFO, device, directory or oversized file now
219
+ * lands in the catch block it would have reached on any other read error,
220
+ * rather than blocking the process.
63
221
  */
64
- export function probePathPresence(filePath) {
65
- return lstatOrNull(filePath) === null ? { kind: "missing" } : { kind: "present" };
222
+ export function readTextFileBoundedOrThrow(filePath, opts = {}) {
223
+ const read = readRegularFileBounded(filePath, opts);
224
+ if (read.kind === "ok")
225
+ return read.content;
226
+ throw new BoundedReadError(filePath, read.kind);
66
227
  }
67
228
  //# sourceMappingURL=read-regular-file.js.map