@caupulican/pi-adaptative 0.81.42 → 0.81.43

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 (1406) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/bun/cli.d.ts.map +1 -1
  3. package/dist/bun/cli.js.map +1 -1
  4. package/dist/bun/register-bedrock.d.ts.map +1 -1
  5. package/dist/bun/restore-sandbox-env.d.ts.map +1 -1
  6. package/dist/bun/restore-sandbox-env.js.map +1 -1
  7. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts.map +1 -1
  8. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js.map +1 -1
  9. package/dist/bundled-resources/extensions/tmux-agent-manager/index.d.ts.map +1 -1
  10. package/dist/bundled-resources/extensions/tmux-agent-manager/index.js +52 -49
  11. package/dist/bundled-resources/extensions/tmux-agent-manager/index.js.map +1 -1
  12. package/dist/bundled-resources/extensions/tmux-agent-manager/index.ts +62 -57
  13. package/dist/bundled-resources/prompts/skillify.md +1 -1
  14. package/dist/bundled-resources/runtimes/pi-shell-engine/commands/fs.py +16 -19
  15. package/dist/bundled-resources/runtimes/pi-shell-engine/commands/search.py +12 -26
  16. package/dist/bundled-resources/runtimes/pi-shell-engine/commands/strings.py +15 -121
  17. package/dist/bundled-resources/runtimes/pi-shell-engine/commands/text.py +52 -79
  18. package/dist/bundled-resources/runtimes/pi-shell-engine/escapes.py +70 -0
  19. package/dist/bundled-resources/runtimes/pi-shell-engine/exec.py +110 -61
  20. package/dist/bundled-resources/runtimes/pi-shell-engine/main.py +106 -23
  21. package/dist/bundled-resources/runtimes/pi-shell-engine/paths.py +10 -0
  22. package/dist/bundled-resources/runtimes/pi-shell-engine/proc.py +12 -4
  23. package/dist/bundled-resources/runtimes/pi-shell-engine/shell_args.py +22 -0
  24. package/dist/bundled-resources/runtimes/pi-shell-engine/state.py +9 -2
  25. package/dist/bundled-resources/runtimes/pi-shell-engine/tokens.py +129 -259
  26. package/dist/bundled-resources/skills/authorized-web-security-audit/SKILL.md +187 -0
  27. package/dist/bundled-resources/skills/authorized-web-security-audit/references/assessment-contract.md +92 -0
  28. package/dist/bundled-resources/skills/deduplicate-by-evidence/SKILL.md +134 -0
  29. package/dist/bundled-resources/skills/evidence-gated-tdd/SKILL.md +93 -0
  30. package/dist/bundled-resources/skills/evidence-gated-tdd/references/evidence-model.md +27 -0
  31. package/dist/bundled-resources/skills/evidence-gated-tdd/references/security-scanners.md +24 -0
  32. package/dist/bundled-resources/skills/harness-self-adaptation/SKILL.md +4 -2
  33. package/dist/bundled-resources/skills/secure-agent-tool-surfaces/SKILL.md +217 -0
  34. package/dist/bundled-resources/skills/secure-agent-tool-surfaces/references/defensive-exploit-catalogue.md +175 -0
  35. package/dist/bundled-resources/skills/secure-agent-tool-surfaces/references/tool-boundary-checklist.md +87 -0
  36. package/dist/bundled-resources/skills/skill-architect/SKILL.md +2 -2
  37. package/dist/bundled-resources/skills/skill-creator/SKILL.md +188 -0
  38. package/dist/bundled-resources/skills/skill-creator/references/pi-skill-contract.md +73 -0
  39. package/dist/bundled-resources/skills/skill-creator/scripts/init-skill.mjs +142 -0
  40. package/dist/bundled-resources/skills/skill-creator/scripts/validate-skill.mjs +122 -0
  41. package/dist/cli/args.d.ts.map +1 -1
  42. package/dist/cli/args.js.map +1 -1
  43. package/dist/cli/config-selector.d.ts.map +1 -1
  44. package/dist/cli/config-selector.js.map +1 -1
  45. package/dist/cli/file-processor.d.ts.map +1 -1
  46. package/dist/cli/file-processor.js +8 -8
  47. package/dist/cli/file-processor.js.map +1 -1
  48. package/dist/cli/initial-message.d.ts +1 -1
  49. package/dist/cli/initial-message.d.ts.map +1 -1
  50. package/dist/cli/initial-message.js.map +1 -1
  51. package/dist/cli/list-models.d.ts.map +1 -1
  52. package/dist/cli/list-models.js.map +1 -1
  53. package/dist/cli/piped-stdin.d.ts +4 -0
  54. package/dist/cli/piped-stdin.d.ts.map +1 -0
  55. package/dist/cli/piped-stdin.js +13 -0
  56. package/dist/cli/piped-stdin.js.map +1 -0
  57. package/dist/cli/session-picker.d.ts.map +1 -1
  58. package/dist/cli/session-picker.js.map +1 -1
  59. package/dist/cli.d.ts.map +1 -1
  60. package/dist/cli.js.map +1 -1
  61. package/dist/config.d.ts.map +1 -1
  62. package/dist/config.js +9 -14
  63. package/dist/config.js.map +1 -1
  64. package/dist/core/agent-directory-layout.d.ts.map +1 -1
  65. package/dist/core/agent-directory-layout.js.map +1 -1
  66. package/dist/core/agent-paths.d.ts.map +1 -1
  67. package/dist/core/agent-paths.js.map +1 -1
  68. package/dist/core/agent-session-contracts.d.ts +5 -9
  69. package/dist/core/agent-session-contracts.d.ts.map +1 -1
  70. package/dist/core/agent-session-contracts.js +1 -12
  71. package/dist/core/agent-session-contracts.js.map +1 -1
  72. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  73. package/dist/core/agent-session-runtime.js +10 -25
  74. package/dist/core/agent-session-runtime.js.map +1 -1
  75. package/dist/core/agent-session-services.d.ts.map +1 -1
  76. package/dist/core/agent-session-services.js.map +1 -1
  77. package/dist/core/agent-session.d.ts +24 -1
  78. package/dist/core/agent-session.d.ts.map +1 -1
  79. package/dist/core/agent-session.js +210 -237
  80. package/dist/core/agent-session.js.map +1 -1
  81. package/dist/core/auth-guidance.d.ts.map +1 -1
  82. package/dist/core/auth-guidance.js.map +1 -1
  83. package/dist/core/auth-storage.d.ts +4 -1
  84. package/dist/core/auth-storage.d.ts.map +1 -1
  85. package/dist/core/auth-storage.js +13 -39
  86. package/dist/core/auth-storage.js.map +1 -1
  87. package/dist/core/autonomy/approval-gate.d.ts.map +1 -1
  88. package/dist/core/autonomy/approval-gate.js.map +1 -1
  89. package/dist/core/autonomy/bounded-completion.d.ts.map +1 -1
  90. package/dist/core/autonomy/bounded-completion.js.map +1 -1
  91. package/dist/core/autonomy/contracts.d.ts.map +1 -1
  92. package/dist/core/autonomy/envelope-enforcement.d.ts.map +1 -1
  93. package/dist/core/autonomy/envelope-enforcement.js.map +1 -1
  94. package/dist/core/autonomy/evidence-finding-projection.d.ts +11 -0
  95. package/dist/core/autonomy/evidence-finding-projection.d.ts.map +1 -0
  96. package/dist/core/autonomy/evidence-finding-projection.js +37 -0
  97. package/dist/core/autonomy/evidence-finding-projection.js.map +1 -0
  98. package/dist/core/autonomy/foreground-envelope.d.ts.map +1 -1
  99. package/dist/core/autonomy/foreground-envelope.js.map +1 -1
  100. package/dist/core/autonomy/gates.d.ts.map +1 -1
  101. package/dist/core/autonomy/gates.js.map +1 -1
  102. package/dist/core/autonomy/lane-private-paths.d.ts.map +1 -1
  103. package/dist/core/autonomy/lane-private-paths.js.map +1 -1
  104. package/dist/core/autonomy/lane-tool-surface.d.ts.map +1 -1
  105. package/dist/core/autonomy/lane-tool-surface.js.map +1 -1
  106. package/dist/core/autonomy/lane-tracker.d.ts.map +1 -1
  107. package/dist/core/autonomy/lane-tracker.js +2 -3
  108. package/dist/core/autonomy/lane-tracker.js.map +1 -1
  109. package/dist/core/autonomy/path-scope.d.ts.map +1 -1
  110. package/dist/core/autonomy/path-scope.js.map +1 -1
  111. package/dist/core/autonomy/risk-assessment.d.ts.map +1 -1
  112. package/dist/core/autonomy/session-lane-record.d.ts.map +1 -1
  113. package/dist/core/autonomy/session-lane-record.js.map +1 -1
  114. package/dist/core/autonomy/status.d.ts.map +1 -1
  115. package/dist/core/autonomy/status.js.map +1 -1
  116. package/dist/core/autonomy/subagent-prompt.d.ts.map +1 -1
  117. package/dist/core/autonomy/subagent-prompt.js.map +1 -1
  118. package/dist/core/autonomy/telemetry-events.d.ts.map +1 -1
  119. package/dist/core/autonomy/telemetry-events.js.map +1 -1
  120. package/dist/core/autonomy-telemetry.d.ts.map +1 -1
  121. package/dist/core/autonomy-telemetry.js +2 -4
  122. package/dist/core/autonomy-telemetry.js.map +1 -1
  123. package/dist/core/background-lane-controller.d.ts.map +1 -1
  124. package/dist/core/background-lane-controller.js +2 -15
  125. package/dist/core/background-lane-controller.js.map +1 -1
  126. package/dist/core/background-tool-task-controller.d.ts +88 -0
  127. package/dist/core/background-tool-task-controller.d.ts.map +1 -0
  128. package/dist/core/background-tool-task-controller.js +470 -0
  129. package/dist/core/background-tool-task-controller.js.map +1 -0
  130. package/dist/core/bash-execution-controller.d.ts +1 -0
  131. package/dist/core/bash-execution-controller.d.ts.map +1 -1
  132. package/dist/core/bash-execution-controller.js +5 -4
  133. package/dist/core/bash-execution-controller.js.map +1 -1
  134. package/dist/core/bash-executor.d.ts.map +1 -1
  135. package/dist/core/bash-executor.js.map +1 -1
  136. package/dist/core/bedrock-sso-login.d.ts.map +1 -1
  137. package/dist/core/bedrock-sso-login.js.map +1 -1
  138. package/dist/core/billing-failover-controller.d.ts.map +1 -1
  139. package/dist/core/billing-failover-controller.js +3 -3
  140. package/dist/core/billing-failover-controller.js.map +1 -1
  141. package/dist/core/billing-failover.d.ts.map +1 -1
  142. package/dist/core/billing-failover.js.map +1 -1
  143. package/dist/core/capability-contract.d.ts.map +1 -1
  144. package/dist/core/catalog-manager.d.ts.map +1 -1
  145. package/dist/core/catalog-manager.js +0 -0
  146. package/dist/core/catalog-manager.js.map +1 -1
  147. package/dist/core/compaction-controller.d.ts +2 -0
  148. package/dist/core/compaction-controller.d.ts.map +1 -1
  149. package/dist/core/compaction-controller.js +21 -8
  150. package/dist/core/compaction-controller.js.map +1 -1
  151. package/dist/core/compaction-support.d.ts +8 -0
  152. package/dist/core/compaction-support.d.ts.map +1 -1
  153. package/dist/core/compaction-support.js +0 -2
  154. package/dist/core/compaction-support.js.map +1 -1
  155. package/dist/core/context/artifact-retrieval.d.ts.map +1 -1
  156. package/dist/core/context/artifact-retrieval.js.map +1 -1
  157. package/dist/core/context/brain-curator.d.ts.map +1 -1
  158. package/dist/core/context/brain-curator.js +14 -33
  159. package/dist/core/context/brain-curator.js.map +1 -1
  160. package/dist/core/context/context-artifacts.d.ts.map +1 -1
  161. package/dist/core/context/context-artifacts.js +16 -24
  162. package/dist/core/context/context-artifacts.js.map +1 -1
  163. package/dist/core/context/context-audit.d.ts.map +1 -1
  164. package/dist/core/context/context-audit.js +3 -17
  165. package/dist/core/context/context-audit.js.map +1 -1
  166. package/dist/core/context/context-composition.d.ts.map +1 -1
  167. package/dist/core/context/context-composition.js.map +1 -1
  168. package/dist/core/context/context-item.d.ts.map +1 -1
  169. package/dist/core/context/context-item.js.map +1 -1
  170. package/dist/core/context/context-prompt-enforcement.d.ts.map +1 -1
  171. package/dist/core/context/context-prompt-enforcement.js +3 -16
  172. package/dist/core/context/context-prompt-enforcement.js.map +1 -1
  173. package/dist/core/context/context-prompt-policy.d.ts.map +1 -1
  174. package/dist/core/context/context-prompt-policy.js.map +1 -1
  175. package/dist/core/context/context-retention.d.ts.map +1 -1
  176. package/dist/core/context/context-retention.js.map +1 -1
  177. package/dist/core/context/context-store-retention.d.ts.map +1 -1
  178. package/dist/core/context/context-store-retention.js.map +1 -1
  179. package/dist/core/context/context-store.d.ts.map +1 -1
  180. package/dist/core/context/context-store.js.map +1 -1
  181. package/dist/core/context/context-tool-result.d.ts +4 -0
  182. package/dist/core/context/context-tool-result.d.ts.map +1 -0
  183. package/dist/core/context/context-tool-result.js +15 -0
  184. package/dist/core/context/context-tool-result.js.map +1 -0
  185. package/dist/core/context/current-work-memory.d.ts.map +1 -1
  186. package/dist/core/context/current-work-memory.js.map +1 -1
  187. package/dist/core/context/file-store-memory-provider.d.ts.map +1 -1
  188. package/dist/core/context/file-store-memory-provider.js +7 -28
  189. package/dist/core/context/file-store-memory-provider.js.map +1 -1
  190. package/dist/core/context/local-memory-search.d.ts +11 -0
  191. package/dist/core/context/local-memory-search.d.ts.map +1 -0
  192. package/dist/core/context/local-memory-search.js +37 -0
  193. package/dist/core/context/local-memory-search.js.map +1 -0
  194. package/dist/core/context/long-term-memory-trigger.d.ts.map +1 -1
  195. package/dist/core/context/long-term-memory-trigger.js.map +1 -1
  196. package/dist/core/context/memory-diagnostics.d.ts.map +1 -1
  197. package/dist/core/context/memory-diagnostics.js.map +1 -1
  198. package/dist/core/context/memory-index-store.d.ts.map +1 -1
  199. package/dist/core/context/memory-index-store.js.map +1 -1
  200. package/dist/core/context/memory-prompt-block.d.ts.map +1 -1
  201. package/dist/core/context/memory-prompt-block.js.map +1 -1
  202. package/dist/core/context/memory-prompt-budget.d.ts.map +1 -1
  203. package/dist/core/context/memory-prompt-budget.js.map +1 -1
  204. package/dist/core/context/memory-provider-contract.d.ts.map +1 -1
  205. package/dist/core/context/memory-provider-contract.js.map +1 -1
  206. package/dist/core/context/memory-retrieval.d.ts.map +1 -1
  207. package/dist/core/context/memory-retrieval.js.map +1 -1
  208. package/dist/core/context/memory-tier-composer.d.ts.map +1 -1
  209. package/dist/core/context/memory-tier-composer.js.map +1 -1
  210. package/dist/core/context/message-text.d.ts +7 -0
  211. package/dist/core/context/message-text.d.ts.map +1 -0
  212. package/dist/core/context/message-text.js +68 -0
  213. package/dist/core/context/message-text.js.map +1 -0
  214. package/dist/core/context/okf-memory-provider.d.ts.map +1 -1
  215. package/dist/core/context/okf-memory-provider.js +4 -30
  216. package/dist/core/context/okf-memory-provider.js.map +1 -1
  217. package/dist/core/context/okf-memory.d.ts.map +1 -1
  218. package/dist/core/context/okf-memory.js.map +1 -1
  219. package/dist/core/context/policy-engine.d.ts.map +1 -1
  220. package/dist/core/context/policy-engine.js.map +1 -1
  221. package/dist/core/context/policy-types.d.ts.map +1 -1
  222. package/dist/core/context/sqlite-runtime-index.d.ts.map +1 -1
  223. package/dist/core/context/sqlite-runtime-index.js.map +1 -1
  224. package/dist/core/context/storage-authority.d.ts.map +1 -1
  225. package/dist/core/context/tool-output-packer.d.ts.map +1 -1
  226. package/dist/core/context/tool-output-packer.js.map +1 -1
  227. package/dist/core/context-gc.d.ts.map +1 -1
  228. package/dist/core/context-gc.js +14 -21
  229. package/dist/core/context-gc.js.map +1 -1
  230. package/dist/core/context-pipeline.d.ts +1 -3
  231. package/dist/core/context-pipeline.d.ts.map +1 -1
  232. package/dist/core/context-pipeline.js +64 -145
  233. package/dist/core/context-pipeline.js.map +1 -1
  234. package/dist/core/cost/cost-summary.d.ts.map +1 -1
  235. package/dist/core/cost/cost-summary.js.map +1 -1
  236. package/dist/core/cost/daily-usage.d.ts.map +1 -1
  237. package/dist/core/cost/daily-usage.js.map +1 -1
  238. package/dist/core/cost/session-usage.d.ts.map +1 -1
  239. package/dist/core/cost/session-usage.js.map +1 -1
  240. package/dist/core/cost-guard.d.ts.map +1 -1
  241. package/dist/core/cost-guard.js.map +1 -1
  242. package/dist/core/default-tool-surface.d.ts.map +1 -1
  243. package/dist/core/default-tool-surface.js +1 -0
  244. package/dist/core/default-tool-surface.js.map +1 -1
  245. package/dist/core/defaults.d.ts.map +1 -1
  246. package/dist/core/delegation/managed-lane-controller.d.ts.map +1 -1
  247. package/dist/core/delegation/managed-lane-controller.js +2 -6
  248. package/dist/core/delegation/managed-lane-controller.js.map +1 -1
  249. package/dist/core/delegation/session-worker-claim.d.ts.map +1 -1
  250. package/dist/core/delegation/session-worker-claim.js.map +1 -1
  251. package/dist/core/delegation/worker-action-journal.d.ts.map +1 -1
  252. package/dist/core/delegation/worker-action-journal.js +0 -4
  253. package/dist/core/delegation/worker-action-journal.js.map +1 -1
  254. package/dist/core/delegation/worker-actions.d.ts.map +1 -1
  255. package/dist/core/delegation/worker-actions.js.map +1 -1
  256. package/dist/core/delegation/worker-agent-control-coordinator.d.ts +1 -0
  257. package/dist/core/delegation/worker-agent-control-coordinator.d.ts.map +1 -1
  258. package/dist/core/delegation/worker-agent-control-coordinator.js +13 -15
  259. package/dist/core/delegation/worker-agent-control-coordinator.js.map +1 -1
  260. package/dist/core/delegation/worker-agent-control.d.ts.map +1 -1
  261. package/dist/core/delegation/worker-agent-control.js +1 -4
  262. package/dist/core/delegation/worker-agent-control.js.map +1 -1
  263. package/dist/core/delegation/worker-attempt-executor.d.ts.map +1 -1
  264. package/dist/core/delegation/worker-attempt-executor.js.map +1 -1
  265. package/dist/core/delegation/worker-claim.d.ts.map +1 -1
  266. package/dist/core/delegation/worker-claim.js.map +1 -1
  267. package/dist/core/delegation/worker-conversation-store.d.ts.map +1 -1
  268. package/dist/core/delegation/worker-conversation-store.js +0 -2
  269. package/dist/core/delegation/worker-conversation-store.js.map +1 -1
  270. package/dist/core/delegation/worker-delegation-controller.d.ts.map +1 -1
  271. package/dist/core/delegation/worker-delegation-controller.js +5 -14
  272. package/dist/core/delegation/worker-delegation-controller.js.map +1 -1
  273. package/dist/core/delegation/worker-delegation-request.d.ts.map +1 -1
  274. package/dist/core/delegation/worker-dispatch-scheduler.d.ts.map +1 -1
  275. package/dist/core/delegation/worker-dispatch-scheduler.js +5 -6
  276. package/dist/core/delegation/worker-dispatch-scheduler.js.map +1 -1
  277. package/dist/core/delegation/worker-execution-policy.d.ts.map +1 -1
  278. package/dist/core/delegation/worker-execution-policy.js.map +1 -1
  279. package/dist/core/delegation/worker-lane-projection.d.ts.map +1 -1
  280. package/dist/core/delegation/worker-lane-projection.js.map +1 -1
  281. package/dist/core/delegation/worker-lifecycle.d.ts.map +1 -1
  282. package/dist/core/delegation/worker-lifecycle.js +0 -3
  283. package/dist/core/delegation/worker-lifecycle.js.map +1 -1
  284. package/dist/core/delegation/worker-notification-coordinator.d.ts.map +1 -1
  285. package/dist/core/delegation/worker-notification-coordinator.js +4 -5
  286. package/dist/core/delegation/worker-notification-coordinator.js.map +1 -1
  287. package/dist/core/delegation/worker-process-owner.d.ts.map +1 -1
  288. package/dist/core/delegation/worker-process-owner.js.map +1 -1
  289. package/dist/core/delegation/worker-profile-resolver.d.ts.map +1 -1
  290. package/dist/core/delegation/worker-profile-resolver.js +1 -2
  291. package/dist/core/delegation/worker-profile-resolver.js.map +1 -1
  292. package/dist/core/delegation/worker-recovery-coordinator.d.ts.map +1 -1
  293. package/dist/core/delegation/worker-recovery-coordinator.js +3 -4
  294. package/dist/core/delegation/worker-recovery-coordinator.js.map +1 -1
  295. package/dist/core/delegation/worker-resource-catalog.d.ts.map +1 -1
  296. package/dist/core/delegation/worker-resource-catalog.js.map +1 -1
  297. package/dist/core/delegation/worker-resource-materializer.d.ts.map +1 -1
  298. package/dist/core/delegation/worker-resource-materializer.js +1 -4
  299. package/dist/core/delegation/worker-resource-materializer.js.map +1 -1
  300. package/dist/core/delegation/worker-runner.d.ts +2 -4
  301. package/dist/core/delegation/worker-runner.d.ts.map +1 -1
  302. package/dist/core/delegation/worker-runner.js +6 -18
  303. package/dist/core/delegation/worker-runner.js.map +1 -1
  304. package/dist/core/delegation/worker-task-label.d.ts.map +1 -1
  305. package/dist/core/delegation/worker-task-label.js.map +1 -1
  306. package/dist/core/delegation/worker-terminal-finalizer.d.ts.map +1 -1
  307. package/dist/core/delegation/worker-terminal-finalizer.js.map +1 -1
  308. package/dist/core/delegation/worker-write-reservation-coordinator.d.ts.map +1 -1
  309. package/dist/core/delegation/worker-write-reservation-coordinator.js +1 -4
  310. package/dist/core/delegation/worker-write-reservation-coordinator.js.map +1 -1
  311. package/dist/core/delegation/worker-write-reservation.d.ts.map +1 -1
  312. package/dist/core/delegation/worker-write-reservation.js +0 -2
  313. package/dist/core/delegation/worker-write-reservation.js.map +1 -1
  314. package/dist/core/diagnostics.d.ts.map +1 -1
  315. package/dist/core/doctor.d.ts.map +1 -1
  316. package/dist/core/doctor.js.map +1 -1
  317. package/dist/core/event-bus.d.ts.map +1 -1
  318. package/dist/core/event-bus.js.map +1 -1
  319. package/dist/core/exec.d.ts.map +1 -1
  320. package/dist/core/exec.js +26 -7
  321. package/dist/core/exec.js.map +1 -1
  322. package/dist/core/export-html/ansi-to-html.d.ts.map +1 -1
  323. package/dist/core/export-html/ansi-to-html.js +21 -74
  324. package/dist/core/export-html/ansi-to-html.js.map +1 -1
  325. package/dist/core/export-html/index.d.ts.map +1 -1
  326. package/dist/core/export-html/index.js +4 -0
  327. package/dist/core/export-html/index.js.map +1 -1
  328. package/dist/core/export-html/session-tree-foundations.d.mts +67 -0
  329. package/dist/core/export-html/session-tree-foundations.mjs +313 -0
  330. package/dist/core/export-html/template.css +14 -41
  331. package/dist/core/export-html/template.html +3 -1
  332. package/dist/core/export-html/template.js +26 -435
  333. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  334. package/dist/core/export-html/tool-renderer.js.map +1 -1
  335. package/dist/core/extension-import-authority.d.ts.map +1 -1
  336. package/dist/core/extension-import-authority.js.map +1 -1
  337. package/dist/core/extension-metadata.d.ts.map +1 -1
  338. package/dist/core/extension-metadata.js.map +1 -1
  339. package/dist/core/extensions/builtin.d.ts +17 -0
  340. package/dist/core/extensions/builtin.d.ts.map +1 -1
  341. package/dist/core/extensions/builtin.js +18 -54
  342. package/dist/core/extensions/builtin.js.map +1 -1
  343. package/dist/core/extensions/entry-resolution.d.ts +3 -0
  344. package/dist/core/extensions/entry-resolution.d.ts.map +1 -0
  345. package/dist/core/extensions/entry-resolution.js +17 -0
  346. package/dist/core/extensions/entry-resolution.js.map +1 -0
  347. package/dist/core/extensions/index.d.ts.map +1 -1
  348. package/dist/core/extensions/loader.d.ts.map +1 -1
  349. package/dist/core/extensions/loader.js +76 -21
  350. package/dist/core/extensions/loader.js.map +1 -1
  351. package/dist/core/extensions/runner.d.ts +2 -0
  352. package/dist/core/extensions/runner.d.ts.map +1 -1
  353. package/dist/core/extensions/runner.js +41 -112
  354. package/dist/core/extensions/runner.js.map +1 -1
  355. package/dist/core/extensions/stale-context.d.ts.map +1 -1
  356. package/dist/core/extensions/storage.d.ts.map +1 -1
  357. package/dist/core/extensions/storage.js.map +1 -1
  358. package/dist/core/extensions/types.d.ts.map +1 -1
  359. package/dist/core/extensions/types.js.map +1 -1
  360. package/dist/core/extensions/wrapper.d.ts.map +1 -1
  361. package/dist/core/extensions/wrapper.js.map +1 -1
  362. package/dist/core/failure-corpus.d.ts.map +1 -1
  363. package/dist/core/failure-corpus.js +2 -5
  364. package/dist/core/failure-corpus.js.map +1 -1
  365. package/dist/core/footer-data-provider.d.ts.map +1 -1
  366. package/dist/core/footer-data-provider.js +27 -33
  367. package/dist/core/footer-data-provider.js.map +1 -1
  368. package/dist/core/foreground-recovery-controller.d.ts.map +1 -1
  369. package/dist/core/foreground-recovery-controller.js +0 -4
  370. package/dist/core/foreground-recovery-controller.js.map +1 -1
  371. package/dist/core/gateways/channel-provider.d.ts.map +1 -1
  372. package/dist/core/gateways/channel-provider.js +7 -5
  373. package/dist/core/gateways/channel-provider.js.map +1 -1
  374. package/dist/core/goal-loop-controller.d.ts.map +1 -1
  375. package/dist/core/goal-loop-controller.js +0 -1
  376. package/dist/core/goal-loop-controller.js.map +1 -1
  377. package/dist/core/goals/compact-goal-context.d.ts.map +1 -1
  378. package/dist/core/goals/compact-goal-context.js +2 -4
  379. package/dist/core/goals/compact-goal-context.js.map +1 -1
  380. package/dist/core/goals/goal-acceptance.d.ts.map +1 -1
  381. package/dist/core/goals/goal-acceptance.js.map +1 -1
  382. package/dist/core/goals/goal-auto-continue-controller.d.ts.map +1 -1
  383. package/dist/core/goals/goal-auto-continue-controller.js +1 -3
  384. package/dist/core/goals/goal-auto-continue-controller.js.map +1 -1
  385. package/dist/core/goals/goal-continuation-controller.d.ts.map +1 -1
  386. package/dist/core/goals/goal-continuation-controller.js.map +1 -1
  387. package/dist/core/goals/goal-continuation-defaults.d.ts.map +1 -1
  388. package/dist/core/goals/goal-continuation-prompt.d.ts.map +1 -1
  389. package/dist/core/goals/goal-continuation-prompt.js.map +1 -1
  390. package/dist/core/goals/goal-lifecycle.d.ts.map +1 -1
  391. package/dist/core/goals/goal-lifecycle.js.map +1 -1
  392. package/dist/core/goals/goal-record.d.ts.map +1 -1
  393. package/dist/core/goals/goal-record.js.map +1 -1
  394. package/dist/core/goals/goal-runtime-snapshot.d.ts.map +1 -1
  395. package/dist/core/goals/goal-runtime-snapshot.js.map +1 -1
  396. package/dist/core/goals/goal-session-controller.d.ts +15 -0
  397. package/dist/core/goals/goal-session-controller.d.ts.map +1 -1
  398. package/dist/core/goals/goal-session-controller.js +27 -3
  399. package/dist/core/goals/goal-session-controller.js.map +1 -1
  400. package/dist/core/goals/goal-state.d.ts.map +1 -1
  401. package/dist/core/goals/goal-state.js +35 -51
  402. package/dist/core/goals/goal-state.js.map +1 -1
  403. package/dist/core/goals/goal-tool-core.d.ts.map +1 -1
  404. package/dist/core/goals/goal-tool-core.js.map +1 -1
  405. package/dist/core/goals/natural-language-goal.d.ts +9 -0
  406. package/dist/core/goals/natural-language-goal.d.ts.map +1 -0
  407. package/dist/core/goals/natural-language-goal.js +23 -0
  408. package/dist/core/goals/natural-language-goal.js.map +1 -0
  409. package/dist/core/goals/session-goal-state.d.ts.map +1 -1
  410. package/dist/core/goals/session-goal-state.js.map +1 -1
  411. package/dist/core/http-dispatcher.d.ts.map +1 -1
  412. package/dist/core/http-dispatcher.js.map +1 -1
  413. package/dist/core/human-input-controller.d.ts.map +1 -1
  414. package/dist/core/human-input-controller.js +2 -3
  415. package/dist/core/human-input-controller.js.map +1 -1
  416. package/dist/core/human-input.d.ts.map +1 -1
  417. package/dist/core/human-input.js.map +1 -1
  418. package/dist/core/improvement-loop.d.ts.map +1 -1
  419. package/dist/core/improvement-loop.js +11 -11
  420. package/dist/core/improvement-loop.js.map +1 -1
  421. package/dist/core/index.d.ts.map +1 -1
  422. package/dist/core/install-telemetry.d.ts.map +1 -1
  423. package/dist/core/install-telemetry.js.map +1 -1
  424. package/dist/core/isolated-text-completion.d.ts +17 -0
  425. package/dist/core/isolated-text-completion.d.ts.map +1 -0
  426. package/dist/core/isolated-text-completion.js +15 -0
  427. package/dist/core/isolated-text-completion.js.map +1 -0
  428. package/dist/core/keybindings.d.ts +47 -2
  429. package/dist/core/keybindings.d.ts.map +1 -1
  430. package/dist/core/keybindings.js +12 -1
  431. package/dist/core/keybindings.js.map +1 -1
  432. package/dist/core/learning/learning-audit.d.ts.map +1 -1
  433. package/dist/core/learning/learning-audit.js.map +1 -1
  434. package/dist/core/learning/learning-gate.d.ts.map +1 -1
  435. package/dist/core/learning/learning-gate.js.map +1 -1
  436. package/dist/core/learning/observation-store.d.ts.map +1 -1
  437. package/dist/core/learning/observation-store.js +0 -2
  438. package/dist/core/learning/observation-store.js.map +1 -1
  439. package/dist/core/learning/reflection-engine.d.ts +1 -1
  440. package/dist/core/learning/reflection-engine.d.ts.map +1 -1
  441. package/dist/core/learning/reflection-engine.js +3 -0
  442. package/dist/core/learning/reflection-engine.js.map +1 -1
  443. package/dist/core/learning/reflection-turn-analysis.d.ts +20 -0
  444. package/dist/core/learning/reflection-turn-analysis.d.ts.map +1 -0
  445. package/dist/core/learning/reflection-turn-analysis.js +136 -0
  446. package/dist/core/learning/reflection-turn-analysis.js.map +1 -0
  447. package/dist/core/learning/session-learning-decision.d.ts.map +1 -1
  448. package/dist/core/learning/session-learning-decision.js.map +1 -1
  449. package/dist/core/learning/skill-curator.d.ts.map +1 -1
  450. package/dist/core/learning/skill-curator.js +0 -3
  451. package/dist/core/learning/skill-curator.js.map +1 -1
  452. package/dist/core/local-runtime-controller.d.ts +39 -0
  453. package/dist/core/local-runtime-controller.d.ts.map +1 -1
  454. package/dist/core/local-runtime-controller.js +41 -62
  455. package/dist/core/local-runtime-controller.js.map +1 -1
  456. package/dist/core/memory/effectiveness-tracker.d.ts.map +1 -1
  457. package/dist/core/memory/effectiveness-tracker.js +4 -2
  458. package/dist/core/memory/effectiveness-tracker.js.map +1 -1
  459. package/dist/core/memory/memory-manager.d.ts.map +1 -1
  460. package/dist/core/memory/memory-manager.js +7 -7
  461. package/dist/core/memory/memory-manager.js.map +1 -1
  462. package/dist/core/memory/memory-provider.d.ts.map +1 -1
  463. package/dist/core/memory/providers/file-store.d.ts +7 -0
  464. package/dist/core/memory/providers/file-store.d.ts.map +1 -1
  465. package/dist/core/memory/providers/file-store.js +48 -13
  466. package/dist/core/memory/providers/file-store.js.map +1 -1
  467. package/dist/core/memory/providers/transcript-recall-worker-protocol.d.ts +47 -0
  468. package/dist/core/memory/providers/transcript-recall-worker-protocol.d.ts.map +1 -0
  469. package/dist/core/memory/providers/transcript-recall-worker-protocol.js +50 -0
  470. package/dist/core/memory/providers/transcript-recall-worker-protocol.js.map +1 -0
  471. package/dist/core/memory/providers/transcript-recall-worker.d.ts +2 -0
  472. package/dist/core/memory/providers/transcript-recall-worker.d.ts.map +1 -0
  473. package/dist/core/memory/providers/transcript-recall-worker.js +143 -0
  474. package/dist/core/memory/providers/transcript-recall-worker.js.map +1 -0
  475. package/dist/core/memory/providers/transcript-recall.d.ts +24 -13
  476. package/dist/core/memory/providers/transcript-recall.d.ts.map +1 -1
  477. package/dist/core/memory/providers/transcript-recall.js +143 -141
  478. package/dist/core/memory/providers/transcript-recall.js.map +1 -1
  479. package/dist/core/memory/providers/user-memory-archive.d.ts +39 -0
  480. package/dist/core/memory/providers/user-memory-archive.d.ts.map +1 -0
  481. package/dist/core/memory/providers/user-memory-archive.js +258 -0
  482. package/dist/core/memory/providers/user-memory-archive.js.map +1 -0
  483. package/dist/core/memory/transcript-index.d.ts.map +1 -1
  484. package/dist/core/memory/transcript-index.js +1 -1
  485. package/dist/core/memory/transcript-index.js.map +1 -1
  486. package/dist/core/memory-controller.d.ts +9 -0
  487. package/dist/core/memory-controller.d.ts.map +1 -1
  488. package/dist/core/memory-controller.js +57 -16
  489. package/dist/core/memory-controller.js.map +1 -1
  490. package/dist/core/model-capability.d.ts.map +1 -1
  491. package/dist/core/model-capability.js.map +1 -1
  492. package/dist/core/model-output-json.d.ts +10 -0
  493. package/dist/core/model-output-json.d.ts.map +1 -0
  494. package/dist/core/model-output-json.js +43 -0
  495. package/dist/core/model-output-json.js.map +1 -0
  496. package/dist/core/model-registry.d.ts +8 -8
  497. package/dist/core/model-registry.d.ts.map +1 -1
  498. package/dist/core/model-registry.js +29 -52
  499. package/dist/core/model-registry.js.map +1 -1
  500. package/dist/core/model-resolver.d.ts.map +1 -1
  501. package/dist/core/model-resolver.js +1 -1
  502. package/dist/core/model-resolver.js.map +1 -1
  503. package/dist/core/model-router/config-diagnostics.d.ts.map +1 -1
  504. package/dist/core/model-router/config-diagnostics.js.map +1 -1
  505. package/dist/core/model-router/executor-route.d.ts.map +1 -1
  506. package/dist/core/model-router/executor-route.js.map +1 -1
  507. package/dist/core/model-router/fitness-gate.d.ts.map +1 -1
  508. package/dist/core/model-router/fitness-gate.js.map +1 -1
  509. package/dist/core/model-router/intent-classifier.d.ts.map +1 -1
  510. package/dist/core/model-router/route-judge.d.ts.map +1 -1
  511. package/dist/core/model-router/route-judge.js +18 -36
  512. package/dist/core/model-router/route-judge.js.map +1 -1
  513. package/dist/core/model-router/session-buffer.d.ts.map +1 -1
  514. package/dist/core/model-router/session-buffer.js.map +1 -1
  515. package/dist/core/model-router/status.d.ts.map +1 -1
  516. package/dist/core/model-router/status.js.map +1 -1
  517. package/dist/core/model-router/tool-escalation.d.ts.map +1 -1
  518. package/dist/core/model-router/tool-escalation.js.map +1 -1
  519. package/dist/core/model-router-controller.d.ts +1 -0
  520. package/dist/core/model-router-controller.d.ts.map +1 -1
  521. package/dist/core/model-router-controller.js +25 -56
  522. package/dist/core/model-router-controller.js.map +1 -1
  523. package/dist/core/model-selection-controller.d.ts +10 -0
  524. package/dist/core/model-selection-controller.d.ts.map +1 -1
  525. package/dist/core/model-selection-controller.js +0 -1
  526. package/dist/core/model-selection-controller.js.map +1 -1
  527. package/dist/core/model-tool-protocol.d.ts.map +1 -1
  528. package/dist/core/model-tool-protocol.js.map +1 -1
  529. package/dist/core/models/adaptation-store.d.ts.map +1 -1
  530. package/dist/core/models/adaptation-store.js +0 -1
  531. package/dist/core/models/adaptation-store.js.map +1 -1
  532. package/dist/core/models/context-sizing.d.ts.map +1 -1
  533. package/dist/core/models/context-sizing.js.map +1 -1
  534. package/dist/core/models/default-model-suggestions.d.ts.map +1 -1
  535. package/dist/core/models/default-model-suggestions.js.map +1 -1
  536. package/dist/core/models/fitness-store.d.ts.map +1 -1
  537. package/dist/core/models/fitness-store.js +0 -1
  538. package/dist/core/models/fitness-store.js.map +1 -1
  539. package/dist/core/models/host-state-store.d.ts.map +1 -1
  540. package/dist/core/models/host-state-store.js +1 -6
  541. package/dist/core/models/host-state-store.js.map +1 -1
  542. package/dist/core/models/llamacpp-runtime.d.ts +4 -19
  543. package/dist/core/models/llamacpp-runtime.d.ts.map +1 -1
  544. package/dist/core/models/llamacpp-runtime.js +32 -136
  545. package/dist/core/models/llamacpp-runtime.js.map +1 -1
  546. package/dist/core/models/local-registration.d.ts.map +1 -1
  547. package/dist/core/models/local-registration.js +82 -115
  548. package/dist/core/models/local-registration.js.map +1 -1
  549. package/dist/core/models/local-runtime.d.ts +12 -18
  550. package/dist/core/models/local-runtime.d.ts.map +1 -1
  551. package/dist/core/models/local-runtime.js +60 -204
  552. package/dist/core/models/local-runtime.js.map +1 -1
  553. package/dist/core/models/model-endpoint.d.ts.map +1 -1
  554. package/dist/core/models/model-endpoint.js.map +1 -1
  555. package/dist/core/models/model-ref.d.ts.map +1 -1
  556. package/dist/core/models/model-ref.js.map +1 -1
  557. package/dist/core/models/needle-runtime.d.ts +7 -3
  558. package/dist/core/models/needle-runtime.d.ts.map +1 -1
  559. package/dist/core/models/needle-runtime.js +16 -92
  560. package/dist/core/models/needle-runtime.js.map +1 -1
  561. package/dist/core/models/perf-profile.d.ts +1 -1
  562. package/dist/core/models/perf-profile.d.ts.map +1 -1
  563. package/dist/core/models/perf-profile.js +6 -13
  564. package/dist/core/models/perf-profile.js.map +1 -1
  565. package/dist/core/models/prism-llamacpp-lifecycle.d.ts.map +1 -1
  566. package/dist/core/models/prism-llamacpp-lifecycle.js.map +1 -1
  567. package/dist/core/models/runtime-arbiter.d.ts.map +1 -1
  568. package/dist/core/models/runtime-arbiter.js +3 -15
  569. package/dist/core/models/runtime-arbiter.js.map +1 -1
  570. package/dist/core/models/runtime-process.d.ts +100 -0
  571. package/dist/core/models/runtime-process.d.ts.map +1 -0
  572. package/dist/core/models/runtime-process.js +183 -0
  573. package/dist/core/models/runtime-process.js.map +1 -0
  574. package/dist/core/orchestration/agent-resume.d.ts.map +1 -1
  575. package/dist/core/orchestration/agent-resume.js.map +1 -1
  576. package/dist/core/orchestration/attempt-usage.d.ts.map +1 -1
  577. package/dist/core/orchestration/attempt-usage.js.map +1 -1
  578. package/dist/core/orchestration/capability-gateway.d.ts.map +1 -1
  579. package/dist/core/orchestration/capability-gateway.js +0 -14
  580. package/dist/core/orchestration/capability-gateway.js.map +1 -1
  581. package/dist/core/orchestration/contracts.d.ts.map +1 -1
  582. package/dist/core/orchestration/contracts.js.map +1 -1
  583. package/dist/core/orchestration/delegation-ledger.d.ts.map +1 -1
  584. package/dist/core/orchestration/delegation-ledger.js +0 -2
  585. package/dist/core/orchestration/delegation-ledger.js.map +1 -1
  586. package/dist/core/orchestration/event-store.d.ts.map +1 -1
  587. package/dist/core/orchestration/event-store.js +1 -14
  588. package/dist/core/orchestration/event-store.js.map +1 -1
  589. package/dist/core/orchestration/lane-tool-manifests.d.ts.map +1 -1
  590. package/dist/core/orchestration/lane-tool-manifests.js.map +1 -1
  591. package/dist/core/orchestration/model-binding.d.ts.map +1 -1
  592. package/dist/core/orchestration/model-binding.js.map +1 -1
  593. package/dist/core/orchestration/policy-compiler.d.ts.map +1 -1
  594. package/dist/core/orchestration/policy-compiler.js +0 -3
  595. package/dist/core/orchestration/policy-compiler.js.map +1 -1
  596. package/dist/core/orchestration/policy-gate.d.ts.map +1 -1
  597. package/dist/core/orchestration/policy-gate.js +0 -2
  598. package/dist/core/orchestration/policy-gate.js.map +1 -1
  599. package/dist/core/orchestration/profile-registry.d.ts.map +1 -1
  600. package/dist/core/orchestration/profile-registry.js +1 -1
  601. package/dist/core/orchestration/profile-registry.js.map +1 -1
  602. package/dist/core/orchestration/profile-store.d.ts.map +1 -1
  603. package/dist/core/orchestration/profile-store.js +0 -3
  604. package/dist/core/orchestration/profile-store.js.map +1 -1
  605. package/dist/core/orchestration/risk-budget.d.ts.map +1 -1
  606. package/dist/core/orchestration/risk-budget.js.map +1 -1
  607. package/dist/core/orchestration/task-runtime.d.ts +1 -0
  608. package/dist/core/orchestration/task-runtime.d.ts.map +1 -1
  609. package/dist/core/orchestration/task-runtime.js +27 -42
  610. package/dist/core/orchestration/task-runtime.js.map +1 -1
  611. package/dist/core/orchestration/work-state-projection.d.ts.map +1 -1
  612. package/dist/core/orchestration/work-state-projection.js.map +1 -1
  613. package/dist/core/orchestration/worker-execution-contract.d.ts.map +1 -1
  614. package/dist/core/orchestration/worker-execution-contract.js.map +1 -1
  615. package/dist/core/orchestration/worker-result-adapter.d.ts.map +1 -1
  616. package/dist/core/orchestration/worker-result-adapter.js.map +1 -1
  617. package/dist/core/output-guard.d.ts.map +1 -1
  618. package/dist/core/output-guard.js.map +1 -1
  619. package/dist/core/package-manager.d.ts +3 -0
  620. package/dist/core/package-manager.d.ts.map +1 -1
  621. package/dist/core/package-manager.js +88 -353
  622. package/dist/core/package-manager.js.map +1 -1
  623. package/dist/core/process-identity.d.ts.map +1 -1
  624. package/dist/core/process-identity.js.map +1 -1
  625. package/dist/core/process-liveness.d.ts +3 -0
  626. package/dist/core/process-liveness.d.ts.map +1 -0
  627. package/dist/core/process-liveness.js +17 -0
  628. package/dist/core/process-liveness.js.map +1 -0
  629. package/dist/core/process-matrix/codes.d.ts.map +1 -1
  630. package/dist/core/process-matrix/resume-launcher.d.ts.map +1 -1
  631. package/dist/core/process-matrix/resume-launcher.js.map +1 -1
  632. package/dist/core/process-matrix/runtime.d.ts.map +1 -1
  633. package/dist/core/process-matrix/runtime.js.map +1 -1
  634. package/dist/core/process-matrix/store.d.ts.map +1 -1
  635. package/dist/core/process-matrix/store.js.map +1 -1
  636. package/dist/core/process-matrix/supervisor.d.ts.map +1 -1
  637. package/dist/core/process-matrix/supervisor.js.map +1 -1
  638. package/dist/core/profile-filter-controller.d.ts.map +1 -1
  639. package/dist/core/profile-filter-controller.js +7 -8
  640. package/dist/core/profile-filter-controller.js.map +1 -1
  641. package/dist/core/profile-registry.d.ts.map +1 -1
  642. package/dist/core/profile-registry.js +1 -2
  643. package/dist/core/profile-registry.js.map +1 -1
  644. package/dist/core/profile-resource-selection.d.ts.map +1 -1
  645. package/dist/core/profile-resource-selection.js +18 -59
  646. package/dist/core/profile-resource-selection.js.map +1 -1
  647. package/dist/core/prompt-markup.d.ts +3 -0
  648. package/dist/core/prompt-markup.d.ts.map +1 -0
  649. package/dist/core/prompt-markup.js +7 -0
  650. package/dist/core/prompt-markup.js.map +1 -0
  651. package/dist/core/prompt-templates.d.ts.map +1 -1
  652. package/dist/core/prompt-templates.js +13 -39
  653. package/dist/core/prompt-templates.js.map +1 -1
  654. package/dist/core/provider-display-names.d.ts.map +1 -1
  655. package/dist/core/python-runtime.d.ts.map +1 -1
  656. package/dist/core/python-runtime.js.map +1 -1
  657. package/dist/core/reflection-controller.d.ts +22 -1
  658. package/dist/core/reflection-controller.d.ts.map +1 -1
  659. package/dist/core/reflection-controller.js +143 -25
  660. package/dist/core/reflection-controller.js.map +1 -1
  661. package/dist/core/reload-blockers.d.ts +2 -1
  662. package/dist/core/reload-blockers.d.ts.map +1 -1
  663. package/dist/core/reload-blockers.js +4 -14
  664. package/dist/core/reload-blockers.js.map +1 -1
  665. package/dist/core/request-auth.d.ts.map +1 -1
  666. package/dist/core/request-auth.js.map +1 -1
  667. package/dist/core/research/automata-provider.d.ts.map +1 -1
  668. package/dist/core/research/automata-provider.js.map +1 -1
  669. package/dist/core/research/evidence-bundle.d.ts.map +1 -1
  670. package/dist/core/research/evidence-bundle.js.map +1 -1
  671. package/dist/core/research/lane-model-resolver.d.ts.map +1 -1
  672. package/dist/core/research/lane-model-resolver.js +0 -1
  673. package/dist/core/research/lane-model-resolver.js.map +1 -1
  674. package/dist/core/research/model-fitness-controller.d.ts.map +1 -1
  675. package/dist/core/research/model-fitness-controller.js +17 -33
  676. package/dist/core/research/model-fitness-controller.js.map +1 -1
  677. package/dist/core/research/model-fitness.d.ts.map +1 -1
  678. package/dist/core/research/model-fitness.js +4 -25
  679. package/dist/core/research/model-fitness.js.map +1 -1
  680. package/dist/core/research/research-gate.d.ts.map +1 -1
  681. package/dist/core/research/research-gate.js.map +1 -1
  682. package/dist/core/research/research-lane-controller.d.ts.map +1 -1
  683. package/dist/core/research/research-lane-controller.js +5 -10
  684. package/dist/core/research/research-lane-controller.js.map +1 -1
  685. package/dist/core/research/research-runner.d.ts +2 -4
  686. package/dist/core/research/research-runner.d.ts.map +1 -1
  687. package/dist/core/research/research-runner.js +17 -48
  688. package/dist/core/research/research-runner.js.map +1 -1
  689. package/dist/core/research/session-evidence-bundle.d.ts.map +1 -1
  690. package/dist/core/research/session-evidence-bundle.js.map +1 -1
  691. package/dist/core/research/workspace-collector.d.ts.map +1 -1
  692. package/dist/core/research/workspace-collector.js.map +1 -1
  693. package/dist/core/resolve-config-value.d.ts.map +1 -1
  694. package/dist/core/resolve-config-value.js.map +1 -1
  695. package/dist/core/resource-ignore.d.ts +6 -0
  696. package/dist/core/resource-ignore.d.ts.map +1 -0
  697. package/dist/core/resource-ignore.js +44 -0
  698. package/dist/core/resource-ignore.js.map +1 -0
  699. package/dist/core/resource-loader.d.ts +0 -1
  700. package/dist/core/resource-loader.d.ts.map +1 -1
  701. package/dist/core/resource-loader.js +52 -187
  702. package/dist/core/resource-loader.js.map +1 -1
  703. package/dist/core/resource-profile-blocks.d.ts +3 -1
  704. package/dist/core/resource-profile-blocks.d.ts.map +1 -1
  705. package/dist/core/resource-profile-blocks.js +8 -5
  706. package/dist/core/resource-profile-blocks.js.map +1 -1
  707. package/dist/core/resource-profile-equality.d.ts.map +1 -1
  708. package/dist/core/resource-profile-equality.js.map +1 -1
  709. package/dist/core/resource-traversal.d.ts +43 -0
  710. package/dist/core/resource-traversal.d.ts.map +1 -0
  711. package/dist/core/resource-traversal.js +84 -0
  712. package/dist/core/resource-traversal.js.map +1 -0
  713. package/dist/core/risk-classifier.d.ts.map +1 -1
  714. package/dist/core/risk-classifier.js.map +1 -1
  715. package/dist/core/runtime-builder.d.ts +4 -1
  716. package/dist/core/runtime-builder.d.ts.map +1 -1
  717. package/dist/core/runtime-builder.js +25 -50
  718. package/dist/core/runtime-builder.js.map +1 -1
  719. package/dist/core/scout-controller.d.ts.map +1 -1
  720. package/dist/core/scout-controller.js +0 -1
  721. package/dist/core/scout-controller.js.map +1 -1
  722. package/dist/core/sdk.d.ts.map +1 -1
  723. package/dist/core/sdk.js.map +1 -1
  724. package/dist/core/secrets/credential-exposure-guard.d.ts.map +1 -1
  725. package/dist/core/secrets/credential-exposure-guard.js +70 -44
  726. package/dist/core/secrets/credential-exposure-guard.js.map +1 -1
  727. package/dist/core/secrets/secret-dotenv.d.ts.map +1 -1
  728. package/dist/core/secrets/secret-dotenv.js +0 -1
  729. package/dist/core/secrets/secret-dotenv.js.map +1 -1
  730. package/dist/core/secrets/secret-vault-format.d.ts.map +1 -1
  731. package/dist/core/secrets/secret-vault-format.js +0 -1
  732. package/dist/core/secrets/secret-vault-format.js.map +1 -1
  733. package/dist/core/secrets/secret-vault.d.ts.map +1 -1
  734. package/dist/core/secrets/secret-vault.js +2 -10
  735. package/dist/core/secrets/secret-vault.js.map +1 -1
  736. package/dist/core/security/secret-text.d.ts.map +1 -1
  737. package/dist/core/security/secret-text.js.map +1 -1
  738. package/dist/core/security/untrusted-boundary.d.ts.map +1 -1
  739. package/dist/core/security/untrusted-boundary.js.map +1 -1
  740. package/dist/core/session-analytics.d.ts.map +1 -1
  741. package/dist/core/session-analytics.js +18 -50
  742. package/dist/core/session-analytics.js.map +1 -1
  743. package/dist/core/session-artifact-bundle.d.ts.map +1 -1
  744. package/dist/core/session-artifact-bundle.js.map +1 -1
  745. package/dist/core/session-cwd.d.ts.map +1 -1
  746. package/dist/core/session-cwd.js +0 -1
  747. package/dist/core/session-cwd.js.map +1 -1
  748. package/dist/core/session-entry-index.d.ts +8 -0
  749. package/dist/core/session-entry-index.d.ts.map +1 -0
  750. package/dist/core/session-entry-index.js +16 -0
  751. package/dist/core/session-entry-index.js.map +1 -0
  752. package/dist/core/session-image-store.d.ts.map +1 -1
  753. package/dist/core/session-image-store.js +0 -3
  754. package/dist/core/session-image-store.js.map +1 -1
  755. package/dist/core/session-jsonl-writer.d.ts +3 -0
  756. package/dist/core/session-jsonl-writer.d.ts.map +1 -0
  757. package/dist/core/session-jsonl-writer.js +38 -0
  758. package/dist/core/session-jsonl-writer.js.map +1 -0
  759. package/dist/core/session-manager-factory.d.ts.map +1 -1
  760. package/dist/core/session-manager-factory.js.map +1 -1
  761. package/dist/core/session-role.d.ts.map +1 -1
  762. package/dist/core/session-role.js.map +1 -1
  763. package/dist/core/session-snapshot.d.ts.map +1 -1
  764. package/dist/core/session-snapshot.js.map +1 -1
  765. package/dist/core/session-supervision-runtime.d.ts.map +1 -1
  766. package/dist/core/session-supervision-runtime.js +1 -4
  767. package/dist/core/session-supervision-runtime.js.map +1 -1
  768. package/dist/core/session-tree-navigator.d.ts.map +1 -1
  769. package/dist/core/session-tree-navigator.js +0 -1
  770. package/dist/core/session-tree-navigator.js.map +1 -1
  771. package/dist/core/settings-manager.d.ts +2 -1
  772. package/dist/core/settings-manager.d.ts.map +1 -1
  773. package/dist/core/settings-manager.js +64 -162
  774. package/dist/core/settings-manager.js.map +1 -1
  775. package/dist/core/skill-block.d.mts +8 -0
  776. package/dist/core/skill-block.mjs +52 -0
  777. package/dist/core/skill-discovery.d.ts +5 -0
  778. package/dist/core/skill-discovery.d.ts.map +1 -0
  779. package/dist/core/skill-discovery.js +34 -0
  780. package/dist/core/skill-discovery.js.map +1 -0
  781. package/dist/core/skills.d.ts.map +1 -1
  782. package/dist/core/skills.js +23 -159
  783. package/dist/core/skills.js.map +1 -1
  784. package/dist/core/slash-commands.d.ts.map +1 -1
  785. package/dist/core/source-info.d.ts.map +1 -1
  786. package/dist/core/source-info.js.map +1 -1
  787. package/dist/core/spawned-usage.d.ts +21 -0
  788. package/dist/core/spawned-usage.d.ts.map +1 -0
  789. package/dist/core/spawned-usage.js +29 -0
  790. package/dist/core/spawned-usage.js.map +1 -0
  791. package/dist/core/system-prompt-builder.d.ts +4 -0
  792. package/dist/core/system-prompt-builder.d.ts.map +1 -1
  793. package/dist/core/system-prompt-builder.js +15 -8
  794. package/dist/core/system-prompt-builder.js.map +1 -1
  795. package/dist/core/system-prompt.d.ts.map +1 -1
  796. package/dist/core/system-prompt.js +52 -35
  797. package/dist/core/system-prompt.js.map +1 -1
  798. package/dist/core/tasks/session-task-state.d.ts.map +1 -1
  799. package/dist/core/tasks/session-task-state.js.map +1 -1
  800. package/dist/core/tasks/task-command.d.ts.map +1 -1
  801. package/dist/core/tasks/task-command.js.map +1 -1
  802. package/dist/core/tasks/task-contract-monitor.d.ts.map +1 -1
  803. package/dist/core/tasks/task-contract-monitor.js.map +1 -1
  804. package/dist/core/tasks/task-projection.d.ts.map +1 -1
  805. package/dist/core/tasks/task-projection.js.map +1 -1
  806. package/dist/core/tasks/task-state.d.ts.map +1 -1
  807. package/dist/core/tasks/task-state.js.map +1 -1
  808. package/dist/core/text-preview.d.ts +4 -0
  809. package/dist/core/text-preview.d.ts.map +1 -0
  810. package/dist/core/text-preview.js +33 -0
  811. package/dist/core/text-preview.js.map +1 -0
  812. package/dist/core/timings.d.ts.map +1 -1
  813. package/dist/core/timings.js.map +1 -1
  814. package/dist/core/tool-capability-policy.d.ts.map +1 -1
  815. package/dist/core/tool-capability-policy.js.map +1 -1
  816. package/dist/core/tool-gate-controller.d.ts.map +1 -1
  817. package/dist/core/tool-gate-controller.js +86 -87
  818. package/dist/core/tool-gate-controller.js.map +1 -1
  819. package/dist/core/tool-protocol-controller.d.ts +4 -1
  820. package/dist/core/tool-protocol-controller.d.ts.map +1 -1
  821. package/dist/core/tool-protocol-controller.js +19 -23
  822. package/dist/core/tool-protocol-controller.js.map +1 -1
  823. package/dist/core/tool-recovery-log-records.d.ts.map +1 -1
  824. package/dist/core/tool-recovery-log-records.js.map +1 -1
  825. package/dist/core/tool-recovery-log-worker.d.ts.map +1 -1
  826. package/dist/core/tool-recovery-log-worker.js.map +1 -1
  827. package/dist/core/tool-recovery-logger.d.ts.map +1 -1
  828. package/dist/core/tool-recovery-logger.js +12 -24
  829. package/dist/core/tool-recovery-logger.js.map +1 -1
  830. package/dist/core/tool-recovery-stats.d.ts.map +1 -1
  831. package/dist/core/tool-recovery-stats.js +16 -22
  832. package/dist/core/tool-recovery-stats.js.map +1 -1
  833. package/dist/core/tool-repair-health.d.ts.map +1 -1
  834. package/dist/core/tool-repair-health.js.map +1 -1
  835. package/dist/core/tool-repair-settings.d.ts.map +1 -1
  836. package/dist/core/tool-repair-settings.js.map +1 -1
  837. package/dist/core/tool-selection/expected-utility.d.ts.map +1 -1
  838. package/dist/core/tool-selection/expected-utility.js.map +1 -1
  839. package/dist/core/tool-selection/promotion.d.ts.map +1 -1
  840. package/dist/core/tool-selection/promotion.js.map +1 -1
  841. package/dist/core/tool-selection/tool-performance-store.d.ts +2 -0
  842. package/dist/core/tool-selection/tool-performance-store.d.ts.map +1 -1
  843. package/dist/core/tool-selection/tool-performance-store.js +49 -7
  844. package/dist/core/tool-selection/tool-performance-store.js.map +1 -1
  845. package/dist/core/tool-selection/tool-phase-timing.d.ts +19 -0
  846. package/dist/core/tool-selection/tool-phase-timing.d.ts.map +1 -0
  847. package/dist/core/tool-selection/tool-phase-timing.js +63 -0
  848. package/dist/core/tool-selection/tool-phase-timing.js.map +1 -0
  849. package/dist/core/tool-selection/tool-selection-controller.d.ts +2 -5
  850. package/dist/core/tool-selection/tool-selection-controller.d.ts.map +1 -1
  851. package/dist/core/tool-selection/tool-selection-controller.js +50 -30
  852. package/dist/core/tool-selection/tool-selection-controller.js.map +1 -1
  853. package/dist/core/toolkit/reflex-interpreter.d.ts +16 -0
  854. package/dist/core/toolkit/reflex-interpreter.d.ts.map +1 -1
  855. package/dist/core/toolkit/reflex-interpreter.js +21 -0
  856. package/dist/core/toolkit/reflex-interpreter.js.map +1 -1
  857. package/dist/core/toolkit/script-registry.d.ts.map +1 -1
  858. package/dist/core/toolkit/script-registry.js.map +1 -1
  859. package/dist/core/toolkit/script-runner.d.ts.map +1 -1
  860. package/dist/core/toolkit/script-runner.js.map +1 -1
  861. package/dist/core/tools/artifact-retrieve.d.ts.map +1 -1
  862. package/dist/core/tools/artifact-retrieve.js.map +1 -1
  863. package/dist/core/tools/ask-question.d.ts +2 -3
  864. package/dist/core/tools/ask-question.d.ts.map +1 -1
  865. package/dist/core/tools/ask-question.js +14 -40
  866. package/dist/core/tools/ask-question.js.map +1 -1
  867. package/dist/core/tools/bash.d.ts +2 -0
  868. package/dist/core/tools/bash.d.ts.map +1 -1
  869. package/dist/core/tools/bash.js +83 -30
  870. package/dist/core/tools/bash.js.map +1 -1
  871. package/dist/core/tools/context-scout.d.ts.map +1 -1
  872. package/dist/core/tools/context-scout.js.map +1 -1
  873. package/dist/core/tools/delegate-status.d.ts.map +1 -1
  874. package/dist/core/tools/delegate-status.js +9 -7
  875. package/dist/core/tools/delegate-status.js.map +1 -1
  876. package/dist/core/tools/delegate.d.ts.map +1 -1
  877. package/dist/core/tools/delegate.js +6 -6
  878. package/dist/core/tools/delegate.js.map +1 -1
  879. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  880. package/dist/core/tools/edit-diff.js.map +1 -1
  881. package/dist/core/tools/edit.d.ts.map +1 -1
  882. package/dist/core/tools/edit.js.map +1 -1
  883. package/dist/core/tools/extensionify.d.ts.map +1 -1
  884. package/dist/core/tools/extensionify.js.map +1 -1
  885. package/dist/core/tools/fff-search-backend.d.ts +19 -0
  886. package/dist/core/tools/fff-search-backend.d.ts.map +1 -1
  887. package/dist/core/tools/fff-search-backend.js +28 -2
  888. package/dist/core/tools/fff-search-backend.js.map +1 -1
  889. package/dist/core/tools/file-encoding-policy.d.ts.map +1 -1
  890. package/dist/core/tools/file-encoding-policy.js.map +1 -1
  891. package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
  892. package/dist/core/tools/file-mutation-queue.js.map +1 -1
  893. package/dist/core/tools/find.d.ts +1 -1
  894. package/dist/core/tools/find.d.ts.map +1 -1
  895. package/dist/core/tools/find.js +44 -108
  896. package/dist/core/tools/find.js.map +1 -1
  897. package/dist/core/tools/git-filter.d.ts.map +1 -1
  898. package/dist/core/tools/git-filter.js.map +1 -1
  899. package/dist/core/tools/goal.d.ts.map +1 -1
  900. package/dist/core/tools/goal.js +7 -7
  901. package/dist/core/tools/goal.js.map +1 -1
  902. package/dist/core/tools/grep.d.ts +1 -1
  903. package/dist/core/tools/grep.d.ts.map +1 -1
  904. package/dist/core/tools/grep.js +42 -102
  905. package/dist/core/tools/grep.js.map +1 -1
  906. package/dist/core/tools/index.d.ts.map +1 -1
  907. package/dist/core/tools/index.js.map +1 -1
  908. package/dist/core/tools/ls.d.ts.map +1 -1
  909. package/dist/core/tools/ls.js +20 -36
  910. package/dist/core/tools/ls.js.map +1 -1
  911. package/dist/core/tools/model-fitness.d.ts.map +1 -1
  912. package/dist/core/tools/model-fitness.js.map +1 -1
  913. package/dist/core/tools/orchestration-panel.d.ts +5 -0
  914. package/dist/core/tools/orchestration-panel.d.ts.map +1 -1
  915. package/dist/core/tools/orchestration-panel.js +5 -5
  916. package/dist/core/tools/orchestration-panel.js.map +1 -1
  917. package/dist/core/tools/output-accumulator.d.ts +2 -0
  918. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  919. package/dist/core/tools/output-accumulator.js +24 -36
  920. package/dist/core/tools/output-accumulator.js.map +1 -1
  921. package/dist/core/tools/path-utils.d.ts.map +1 -1
  922. package/dist/core/tools/path-utils.js.map +1 -1
  923. package/dist/core/tools/persistent-process-coordinator.d.ts +31 -0
  924. package/dist/core/tools/persistent-process-coordinator.d.ts.map +1 -0
  925. package/dist/core/tools/persistent-process-coordinator.js +123 -0
  926. package/dist/core/tools/persistent-process-coordinator.js.map +1 -0
  927. package/dist/core/tools/python.d.ts.map +1 -1
  928. package/dist/core/tools/python.js.map +1 -1
  929. package/dist/core/tools/read.d.ts.map +1 -1
  930. package/dist/core/tools/read.js +14 -13
  931. package/dist/core/tools/read.js.map +1 -1
  932. package/dist/core/tools/render-utils.d.ts +29 -0
  933. package/dist/core/tools/render-utils.d.ts.map +1 -1
  934. package/dist/core/tools/render-utils.js +31 -1
  935. package/dist/core/tools/render-utils.js.map +1 -1
  936. package/dist/core/tools/run-process.d.ts.map +1 -1
  937. package/dist/core/tools/run-process.js.map +1 -1
  938. package/dist/core/tools/run-toolkit-script.d.ts.map +1 -1
  939. package/dist/core/tools/run-toolkit-script.js.map +1 -1
  940. package/dist/core/tools/search-command-guard.d.ts +10 -0
  941. package/dist/core/tools/search-command-guard.d.ts.map +1 -1
  942. package/dist/core/tools/search-command-guard.js +118 -31
  943. package/dist/core/tools/search-command-guard.js.map +1 -1
  944. package/dist/core/tools/search-router.d.ts.map +1 -1
  945. package/dist/core/tools/search-router.js.map +1 -1
  946. package/dist/core/tools/search-tool-runtime.d.ts +19 -0
  947. package/dist/core/tools/search-tool-runtime.d.ts.map +1 -0
  948. package/dist/core/tools/search-tool-runtime.js +12 -0
  949. package/dist/core/tools/search-tool-runtime.js.map +1 -0
  950. package/dist/core/tools/secret-store.d.ts.map +1 -1
  951. package/dist/core/tools/secret-store.js.map +1 -1
  952. package/dist/core/tools/shell-command-parser.d.ts.map +1 -1
  953. package/dist/core/tools/shell-command-parser.js.map +1 -1
  954. package/dist/core/tools/shell-contract-router.d.ts.map +1 -1
  955. package/dist/core/tools/shell-contract-router.js +4 -1
  956. package/dist/core/tools/shell-contract-router.js.map +1 -1
  957. package/dist/core/tools/shell-execution-session.d.ts +4 -0
  958. package/dist/core/tools/shell-execution-session.d.ts.map +1 -0
  959. package/dist/core/tools/shell-execution-session.js +11 -0
  960. package/dist/core/tools/shell-execution-session.js.map +1 -0
  961. package/dist/core/tools/shell-output-projection.d.ts +49 -0
  962. package/dist/core/tools/shell-output-projection.d.ts.map +1 -0
  963. package/dist/core/tools/shell-output-projection.js +381 -0
  964. package/dist/core/tools/shell-output-projection.js.map +1 -0
  965. package/dist/core/tools/shell-session.d.ts +2 -13
  966. package/dist/core/tools/shell-session.d.ts.map +1 -1
  967. package/dist/core/tools/shell-session.js +36 -136
  968. package/dist/core/tools/shell-session.js.map +1 -1
  969. package/dist/core/tools/skill-audit.d.ts.map +1 -1
  970. package/dist/core/tools/skill-audit.js.map +1 -1
  971. package/dist/core/tools/skillify.d.ts.map +1 -1
  972. package/dist/core/tools/skillify.js.map +1 -1
  973. package/dist/core/tools/task-steps.d.ts +8 -8
  974. package/dist/core/tools/task-steps.d.ts.map +1 -1
  975. package/dist/core/tools/task-steps.js +17 -18
  976. package/dist/core/tools/task-steps.js.map +1 -1
  977. package/dist/core/tools/tmux-dispatch.d.ts.map +1 -1
  978. package/dist/core/tools/tmux-dispatch.js.map +1 -1
  979. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  980. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  981. package/dist/core/tools/tool-task.d.ts +23 -0
  982. package/dist/core/tools/tool-task.d.ts.map +1 -0
  983. package/dist/core/tools/tool-task.js +93 -0
  984. package/dist/core/tools/tool-task.js.map +1 -0
  985. package/dist/core/tools/windows-shell-engine.d.ts +17 -11
  986. package/dist/core/tools/windows-shell-engine.d.ts.map +1 -1
  987. package/dist/core/tools/windows-shell-engine.js +339 -117
  988. package/dist/core/tools/windows-shell-engine.js.map +1 -1
  989. package/dist/core/tools/windows-shell-state.d.ts.map +1 -1
  990. package/dist/core/tools/windows-shell-state.js.map +1 -1
  991. package/dist/core/tools/worktree-sync.d.ts.map +1 -1
  992. package/dist/core/tools/worktree-sync.js +8 -12
  993. package/dist/core/tools/worktree-sync.js.map +1 -1
  994. package/dist/core/tools/write.d.ts.map +1 -1
  995. package/dist/core/tools/write.js +0 -1
  996. package/dist/core/tools/write.js.map +1 -1
  997. package/dist/core/trust-manager.d.ts.map +1 -1
  998. package/dist/core/trust-manager.js +7 -40
  999. package/dist/core/trust-manager.js.map +1 -1
  1000. package/dist/core/util/atomic-file.d.ts +19 -0
  1001. package/dist/core/util/atomic-file.d.ts.map +1 -1
  1002. package/dist/core/util/atomic-file.js +50 -15
  1003. package/dist/core/util/atomic-file.js.map +1 -1
  1004. package/dist/core/util/bounded-file.d.ts.map +1 -1
  1005. package/dist/core/util/bounded-file.js.map +1 -1
  1006. package/dist/core/util/bounded-jsonl.d.ts.map +1 -1
  1007. package/dist/core/util/bounded-jsonl.js +2 -9
  1008. package/dist/core/util/bounded-jsonl.js.map +1 -1
  1009. package/dist/core/util/bounded-value.d.ts.map +1 -1
  1010. package/dist/core/util/bounded-value.js.map +1 -1
  1011. package/dist/core/util/json-size.d.ts +3 -0
  1012. package/dist/core/util/json-size.d.ts.map +1 -0
  1013. package/dist/core/util/json-size.js +95 -0
  1014. package/dist/core/util/json-size.js.map +1 -0
  1015. package/dist/core/util/minimatch-cache.d.ts.map +1 -1
  1016. package/dist/core/util/minimatch-cache.js.map +1 -1
  1017. package/dist/core/util/value-guards.d.ts.map +1 -1
  1018. package/dist/core/util/value-guards.js.map +1 -1
  1019. package/dist/core/worktree-sync/codes.d.ts.map +1 -1
  1020. package/dist/core/worktree-sync/git-engine.d.ts.map +1 -1
  1021. package/dist/core/worktree-sync/git-engine.js +20 -36
  1022. package/dist/core/worktree-sync/git-engine.js.map +1 -1
  1023. package/dist/core/worktree-sync/lane-gate.d.ts.map +1 -1
  1024. package/dist/core/worktree-sync/lane-gate.js +1 -4
  1025. package/dist/core/worktree-sync/lane-gate.js.map +1 -1
  1026. package/dist/core/worktree-sync/runtime.d.ts.map +1 -1
  1027. package/dist/core/worktree-sync/runtime.js.map +1 -1
  1028. package/dist/core/worktree-sync/store.d.ts.map +1 -1
  1029. package/dist/core/worktree-sync/store.js.map +1 -1
  1030. package/dist/core/worktree-sync/watcher.d.ts.map +1 -1
  1031. package/dist/core/worktree-sync/watcher.js.map +1 -1
  1032. package/dist/index.d.ts.map +1 -1
  1033. package/dist/index.js.map +1 -1
  1034. package/dist/main.d.ts.map +1 -1
  1035. package/dist/main.js +10 -32
  1036. package/dist/main.js.map +1 -1
  1037. package/dist/migrations.d.ts.map +1 -1
  1038. package/dist/migrations.js +6 -19
  1039. package/dist/migrations.js.map +1 -1
  1040. package/dist/modes/index.d.ts.map +1 -1
  1041. package/dist/modes/interactive/auth-dialogs-controller.d.ts +3 -0
  1042. package/dist/modes/interactive/auth-dialogs-controller.d.ts.map +1 -1
  1043. package/dist/modes/interactive/auth-dialogs-controller.js +96 -132
  1044. package/dist/modes/interactive/auth-dialogs-controller.js.map +1 -1
  1045. package/dist/modes/interactive/auto-learn-controller.d.ts +1 -31
  1046. package/dist/modes/interactive/auto-learn-controller.d.ts.map +1 -1
  1047. package/dist/modes/interactive/auto-learn-controller.js +86 -307
  1048. package/dist/modes/interactive/auto-learn-controller.js.map +1 -1
  1049. package/dist/modes/interactive/autocomplete-provider.d.ts.map +1 -1
  1050. package/dist/modes/interactive/autocomplete-provider.js.map +1 -1
  1051. package/dist/modes/interactive/autonomy-commands.d.ts.map +1 -1
  1052. package/dist/modes/interactive/autonomy-commands.js +2 -8
  1053. package/dist/modes/interactive/autonomy-commands.js.map +1 -1
  1054. package/dist/modes/interactive/clipboard-input.d.ts +5 -1
  1055. package/dist/modes/interactive/clipboard-input.d.ts.map +1 -1
  1056. package/dist/modes/interactive/clipboard-input.js +17 -0
  1057. package/dist/modes/interactive/clipboard-input.js.map +1 -1
  1058. package/dist/modes/interactive/compaction-queue.d.ts.map +1 -1
  1059. package/dist/modes/interactive/compaction-queue.js +13 -18
  1060. package/dist/modes/interactive/compaction-queue.js.map +1 -1
  1061. package/dist/modes/interactive/components/activity-lane.d.ts.map +1 -1
  1062. package/dist/modes/interactive/components/activity-lane.js +6 -10
  1063. package/dist/modes/interactive/components/activity-lane.js.map +1 -1
  1064. package/dist/modes/interactive/components/armin.d.ts +1 -0
  1065. package/dist/modes/interactive/components/armin.d.ts.map +1 -1
  1066. package/dist/modes/interactive/components/armin.js +10 -21
  1067. package/dist/modes/interactive/components/armin.js.map +1 -1
  1068. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  1069. package/dist/modes/interactive/components/assistant-message.js +1 -6
  1070. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  1071. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  1072. package/dist/modes/interactive/components/bash-execution.js +4 -9
  1073. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  1074. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
  1075. package/dist/modes/interactive/components/bordered-loader.js +0 -3
  1076. package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
  1077. package/dist/modes/interactive/components/branch-summary-message.d.ts +3 -8
  1078. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  1079. package/dist/modes/interactive/components/branch-summary-message.js +13 -35
  1080. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  1081. package/dist/modes/interactive/components/compaction-summary-message.d.ts +3 -8
  1082. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  1083. package/dist/modes/interactive/components/compaction-summary-message.js +14 -36
  1084. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  1085. package/dist/modes/interactive/components/config-selector.d.ts +1 -0
  1086. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  1087. package/dist/modes/interactive/components/config-selector.js +20 -43
  1088. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  1089. package/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -1
  1090. package/dist/modes/interactive/components/countdown-timer.js +0 -5
  1091. package/dist/modes/interactive/components/countdown-timer.js.map +1 -1
  1092. package/dist/modes/interactive/components/custom-editor.d.ts +2 -0
  1093. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  1094. package/dist/modes/interactive/components/custom-editor.js +4 -8
  1095. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  1096. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  1097. package/dist/modes/interactive/components/custom-message.js +1 -6
  1098. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  1099. package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -1
  1100. package/dist/modes/interactive/components/daxnuts.js +6 -8
  1101. package/dist/modes/interactive/components/daxnuts.js.map +1 -1
  1102. package/dist/modes/interactive/components/diff.d.ts.map +1 -1
  1103. package/dist/modes/interactive/components/diff.js.map +1 -1
  1104. package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
  1105. package/dist/modes/interactive/components/dynamic-border.js +0 -1
  1106. package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
  1107. package/dist/modes/interactive/components/earendil-announcement.d.ts.map +1 -1
  1108. package/dist/modes/interactive/components/earendil-announcement.js.map +1 -1
  1109. package/dist/modes/interactive/components/expandable-markdown-message.d.ts +21 -0
  1110. package/dist/modes/interactive/components/expandable-markdown-message.d.ts.map +1 -0
  1111. package/dist/modes/interactive/components/expandable-markdown-message.js +48 -0
  1112. package/dist/modes/interactive/components/expandable-markdown-message.js.map +1 -0
  1113. package/dist/modes/interactive/components/expandable-text.d.ts.map +1 -1
  1114. package/dist/modes/interactive/components/expandable-text.js +0 -2
  1115. package/dist/modes/interactive/components/expandable-text.js.map +1 -1
  1116. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  1117. package/dist/modes/interactive/components/extension-editor.js +1 -9
  1118. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  1119. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  1120. package/dist/modes/interactive/components/extension-input.js +2 -8
  1121. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  1122. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  1123. package/dist/modes/interactive/components/extension-selector.js +5 -20
  1124. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  1125. package/dist/modes/interactive/components/fitness-role-selector.d.ts.map +1 -1
  1126. package/dist/modes/interactive/components/fitness-role-selector.js +0 -1
  1127. package/dist/modes/interactive/components/fitness-role-selector.js.map +1 -1
  1128. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  1129. package/dist/modes/interactive/components/footer.js +1 -5
  1130. package/dist/modes/interactive/components/footer.js.map +1 -1
  1131. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  1132. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  1133. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  1134. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  1135. package/dist/modes/interactive/components/login-dialog.js +4 -10
  1136. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  1137. package/dist/modes/interactive/components/model-selector.d.ts +2 -2
  1138. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  1139. package/dist/modes/interactive/components/model-selector.js +21 -44
  1140. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  1141. package/dist/modes/interactive/components/model-suggestion-selector.d.ts.map +1 -1
  1142. package/dist/modes/interactive/components/model-suggestion-selector.js +0 -1
  1143. package/dist/modes/interactive/components/model-suggestion-selector.js.map +1 -1
  1144. package/dist/modes/interactive/components/oauth-selector.d.ts +1 -1
  1145. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  1146. package/dist/modes/interactive/components/oauth-selector.js +16 -32
  1147. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  1148. package/dist/modes/interactive/components/profile-resource-editor.d.ts +3 -4
  1149. package/dist/modes/interactive/components/profile-resource-editor.d.ts.map +1 -1
  1150. package/dist/modes/interactive/components/profile-resource-editor.js +34 -93
  1151. package/dist/modes/interactive/components/profile-resource-editor.js.map +1 -1
  1152. package/dist/modes/interactive/components/profile-selector.d.ts.map +1 -1
  1153. package/dist/modes/interactive/components/profile-selector.js +0 -1
  1154. package/dist/modes/interactive/components/profile-selector.js.map +1 -1
  1155. package/dist/modes/interactive/components/scoped-models-selector.d.ts +3 -4
  1156. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  1157. package/dist/modes/interactive/components/scoped-models-selector.js +34 -79
  1158. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  1159. package/dist/modes/interactive/components/selector-list.d.ts +63 -0
  1160. package/dist/modes/interactive/components/selector-list.d.ts.map +1 -0
  1161. package/dist/modes/interactive/components/selector-list.js +186 -0
  1162. package/dist/modes/interactive/components/selector-list.js.map +1 -0
  1163. package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
  1164. package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
  1165. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  1166. package/dist/modes/interactive/components/session-selector.js +34 -59
  1167. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  1168. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  1169. package/dist/modes/interactive/components/settings-selector.js +40 -138
  1170. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  1171. package/dist/modes/interactive/components/show-images-selector.d.ts +2 -4
  1172. package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
  1173. package/dist/modes/interactive/components/show-images-selector.js +9 -28
  1174. package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
  1175. package/dist/modes/interactive/components/skill-invocation-message.d.ts +3 -8
  1176. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  1177. package/dist/modes/interactive/components/skill-invocation-message.js +12 -40
  1178. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  1179. package/dist/modes/interactive/components/theme-selector.d.ts +2 -5
  1180. package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
  1181. package/dist/modes/interactive/components/theme-selector.js +11 -37
  1182. package/dist/modes/interactive/components/theme-selector.js.map +1 -1
  1183. package/dist/modes/interactive/components/thinking-selector.d.ts +2 -4
  1184. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  1185. package/dist/modes/interactive/components/thinking-selector.js +9 -31
  1186. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  1187. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  1188. package/dist/modes/interactive/components/tool-execution.js +9 -28
  1189. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  1190. package/dist/modes/interactive/components/tool-group.d.ts.map +1 -1
  1191. package/dist/modes/interactive/components/tool-group.js +2 -3
  1192. package/dist/modes/interactive/components/tool-group.js.map +1 -1
  1193. package/dist/modes/interactive/components/tool-panel-registry.d.ts.map +1 -1
  1194. package/dist/modes/interactive/components/tool-panel-registry.js +5 -3
  1195. package/dist/modes/interactive/components/tool-panel-registry.js.map +1 -1
  1196. package/dist/modes/interactive/components/tool-title.d.ts.map +1 -1
  1197. package/dist/modes/interactive/components/tool-title.js +0 -4
  1198. package/dist/modes/interactive/components/tool-title.js.map +1 -1
  1199. package/dist/modes/interactive/components/transcript-pager.d.ts +26 -0
  1200. package/dist/modes/interactive/components/transcript-pager.d.ts.map +1 -0
  1201. package/dist/modes/interactive/components/transcript-pager.js +81 -0
  1202. package/dist/modes/interactive/components/transcript-pager.js.map +1 -0
  1203. package/dist/modes/interactive/components/tree-selector.d.ts +1 -12
  1204. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  1205. package/dist/modes/interactive/components/tree-selector.js +42 -402
  1206. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  1207. package/dist/modes/interactive/components/trust-selector.d.ts.map +1 -1
  1208. package/dist/modes/interactive/components/trust-selector.js +4 -16
  1209. package/dist/modes/interactive/components/trust-selector.js.map +1 -1
  1210. package/dist/modes/interactive/components/usage-action-selector.d.ts.map +1 -1
  1211. package/dist/modes/interactive/components/usage-action-selector.js +2 -10
  1212. package/dist/modes/interactive/components/usage-action-selector.js.map +1 -1
  1213. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
  1214. package/dist/modes/interactive/components/user-message-selector.js +3 -6
  1215. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  1216. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  1217. package/dist/modes/interactive/components/user-message.js +0 -1
  1218. package/dist/modes/interactive/components/user-message.js.map +1 -1
  1219. package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -1
  1220. package/dist/modes/interactive/components/visual-truncate.js.map +1 -1
  1221. package/dist/modes/interactive/config-backup.d.ts.map +1 -1
  1222. package/dist/modes/interactive/config-backup.js.map +1 -1
  1223. package/dist/modes/interactive/editor-overlay-host.d.ts.map +1 -1
  1224. package/dist/modes/interactive/editor-overlay-host.js +0 -3
  1225. package/dist/modes/interactive/editor-overlay-host.js.map +1 -1
  1226. package/dist/modes/interactive/extension-ui-host.d.ts +2 -0
  1227. package/dist/modes/interactive/extension-ui-host.d.ts.map +1 -1
  1228. package/dist/modes/interactive/extension-ui-host.js +51 -72
  1229. package/dist/modes/interactive/extension-ui-host.js.map +1 -1
  1230. package/dist/modes/interactive/external-editor.d.ts.map +1 -1
  1231. package/dist/modes/interactive/external-editor.js +2 -15
  1232. package/dist/modes/interactive/external-editor.js.map +1 -1
  1233. package/dist/modes/interactive/history-reload-math.d.ts.map +1 -1
  1234. package/dist/modes/interactive/history-reload-math.js.map +1 -1
  1235. package/dist/modes/interactive/interactive-event-controller.d.ts.map +1 -1
  1236. package/dist/modes/interactive/interactive-event-controller.js +23 -16
  1237. package/dist/modes/interactive/interactive-event-controller.js.map +1 -1
  1238. package/dist/modes/interactive/interactive-mode.d.ts +13 -4
  1239. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  1240. package/dist/modes/interactive/interactive-mode.js +123 -204
  1241. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  1242. package/dist/modes/interactive/interactive-selection-prompts.d.ts +20 -0
  1243. package/dist/modes/interactive/interactive-selection-prompts.d.ts.map +1 -0
  1244. package/dist/modes/interactive/interactive-selection-prompts.js +43 -0
  1245. package/dist/modes/interactive/interactive-selection-prompts.js.map +1 -0
  1246. package/dist/modes/interactive/key-handlers.d.ts +2 -1
  1247. package/dist/modes/interactive/key-handlers.d.ts.map +1 -1
  1248. package/dist/modes/interactive/key-handlers.js +4 -2
  1249. package/dist/modes/interactive/key-handlers.js.map +1 -1
  1250. package/dist/modes/interactive/loaded-resources-view.d.ts.map +1 -1
  1251. package/dist/modes/interactive/loaded-resources-view.js.map +1 -1
  1252. package/dist/modes/interactive/local-model-commands.d.ts.map +1 -1
  1253. package/dist/modes/interactive/local-model-commands.js +4 -9
  1254. package/dist/modes/interactive/local-model-commands.js.map +1 -1
  1255. package/dist/modes/interactive/model-fitness-presentation.d.ts +21 -0
  1256. package/dist/modes/interactive/model-fitness-presentation.d.ts.map +1 -0
  1257. package/dist/modes/interactive/model-fitness-presentation.js +13 -0
  1258. package/dist/modes/interactive/model-fitness-presentation.js.map +1 -0
  1259. package/dist/modes/interactive/profile-menu-controller.d.ts +2 -0
  1260. package/dist/modes/interactive/profile-menu-controller.d.ts.map +1 -1
  1261. package/dist/modes/interactive/profile-menu-controller.js +79 -171
  1262. package/dist/modes/interactive/profile-menu-controller.js.map +1 -1
  1263. package/dist/modes/interactive/report-commands.d.ts +2 -0
  1264. package/dist/modes/interactive/report-commands.d.ts.map +1 -1
  1265. package/dist/modes/interactive/report-commands.js +12 -6
  1266. package/dist/modes/interactive/report-commands.js.map +1 -1
  1267. package/dist/modes/interactive/resource-display.d.ts.map +1 -1
  1268. package/dist/modes/interactive/resource-display.js.map +1 -1
  1269. package/dist/modes/interactive/resource-shell-commands.d.ts.map +1 -1
  1270. package/dist/modes/interactive/resource-shell-commands.js +6 -23
  1271. package/dist/modes/interactive/resource-shell-commands.js.map +1 -1
  1272. package/dist/modes/interactive/session-flow-commands.d.ts.map +1 -1
  1273. package/dist/modes/interactive/session-flow-commands.js +21 -25
  1274. package/dist/modes/interactive/session-flow-commands.js.map +1 -1
  1275. package/dist/modes/interactive/session-io-commands.d.ts.map +1 -1
  1276. package/dist/modes/interactive/session-io-commands.js.map +1 -1
  1277. package/dist/modes/interactive/session-replacement-errors.d.ts.map +1 -1
  1278. package/dist/modes/interactive/session-replacement-errors.js.map +1 -1
  1279. package/dist/modes/interactive/settings-selector-flow.d.ts.map +1 -1
  1280. package/dist/modes/interactive/settings-selector-flow.js.map +1 -1
  1281. package/dist/modes/interactive/signal-lifecycle.d.ts.map +1 -1
  1282. package/dist/modes/interactive/signal-lifecycle.js.map +1 -1
  1283. package/dist/modes/interactive/startup-checks.d.ts.map +1 -1
  1284. package/dist/modes/interactive/startup-checks.js +12 -8
  1285. package/dist/modes/interactive/startup-checks.js.map +1 -1
  1286. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  1287. package/dist/modes/interactive/theme/theme.js +10 -76
  1288. package/dist/modes/interactive/theme/theme.js.map +1 -1
  1289. package/dist/modes/interactive/usage-commands.d.ts.map +1 -1
  1290. package/dist/modes/interactive/usage-commands.js.map +1 -1
  1291. package/dist/modes/print-mode.d.ts.map +1 -1
  1292. package/dist/modes/print-mode.js +5 -22
  1293. package/dist/modes/print-mode.js.map +1 -1
  1294. package/dist/modes/rpc/jsonl.d.ts.map +1 -1
  1295. package/dist/modes/rpc/jsonl.js +1 -1
  1296. package/dist/modes/rpc/jsonl.js.map +1 -1
  1297. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  1298. package/dist/modes/rpc/rpc-client.js +7 -8
  1299. package/dist/modes/rpc/rpc-client.js.map +1 -1
  1300. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  1301. package/dist/modes/rpc/rpc-mode.js +5 -20
  1302. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  1303. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  1304. package/dist/modes/rpc/rpc-types.js.map +1 -1
  1305. package/dist/modes/termination-signals.d.ts +4 -0
  1306. package/dist/modes/termination-signals.d.ts.map +1 -0
  1307. package/dist/modes/termination-signals.js +21 -0
  1308. package/dist/modes/termination-signals.js.map +1 -0
  1309. package/dist/package-manager-cli.d.ts.map +1 -1
  1310. package/dist/package-manager-cli.js.map +1 -1
  1311. package/dist/utils/ansi-colors.d.ts +5 -0
  1312. package/dist/utils/ansi-colors.d.ts.map +1 -0
  1313. package/dist/utils/ansi-colors.js +38 -0
  1314. package/dist/utils/ansi-colors.js.map +1 -0
  1315. package/dist/utils/ansi.d.ts.map +1 -1
  1316. package/dist/utils/ansi.js.map +1 -1
  1317. package/dist/utils/changelog.d.ts.map +1 -1
  1318. package/dist/utils/changelog.js.map +1 -1
  1319. package/dist/utils/child-process.d.ts.map +1 -1
  1320. package/dist/utils/child-process.js.map +1 -1
  1321. package/dist/utils/clipboard-image.d.ts.map +1 -1
  1322. package/dist/utils/clipboard-image.js.map +1 -1
  1323. package/dist/utils/clipboard-native.d.ts.map +1 -1
  1324. package/dist/utils/clipboard-native.js.map +1 -1
  1325. package/dist/utils/clipboard.d.ts.map +1 -1
  1326. package/dist/utils/clipboard.js.map +1 -1
  1327. package/dist/utils/deprecation.d.ts.map +1 -1
  1328. package/dist/utils/deprecation.js.map +1 -1
  1329. package/dist/utils/exif-orientation.d.ts.map +1 -1
  1330. package/dist/utils/exif-orientation.js.map +1 -1
  1331. package/dist/utils/external-editor-command.d.ts.map +1 -1
  1332. package/dist/utils/external-editor-command.js.map +1 -1
  1333. package/dist/utils/frontmatter.d.ts.map +1 -1
  1334. package/dist/utils/frontmatter.js.map +1 -1
  1335. package/dist/utils/fs-watch.d.ts.map +1 -1
  1336. package/dist/utils/fs-watch.js.map +1 -1
  1337. package/dist/utils/git.d.ts.map +1 -1
  1338. package/dist/utils/git.js +20 -28
  1339. package/dist/utils/git.js.map +1 -1
  1340. package/dist/utils/highlight-js-languages.d.ts.map +1 -1
  1341. package/dist/utils/html.d.ts.map +1 -1
  1342. package/dist/utils/html.js.map +1 -1
  1343. package/dist/utils/image-convert.d.ts.map +1 -1
  1344. package/dist/utils/image-convert.js.map +1 -1
  1345. package/dist/utils/image-resize-core.d.ts.map +1 -1
  1346. package/dist/utils/image-resize-core.js.map +1 -1
  1347. package/dist/utils/image-resize-worker.d.ts.map +1 -1
  1348. package/dist/utils/image-resize-worker.js.map +1 -1
  1349. package/dist/utils/image-resize.d.ts.map +1 -1
  1350. package/dist/utils/image-resize.js.map +1 -1
  1351. package/dist/utils/json.d.ts.map +1 -1
  1352. package/dist/utils/json.js.map +1 -1
  1353. package/dist/utils/mime.d.ts.map +1 -1
  1354. package/dist/utils/mime.js.map +1 -1
  1355. package/dist/utils/open-browser.d.ts.map +1 -1
  1356. package/dist/utils/open-browser.js.map +1 -1
  1357. package/dist/utils/paths.d.ts.map +1 -1
  1358. package/dist/utils/paths.js.map +1 -1
  1359. package/dist/utils/photon.d.ts.map +1 -1
  1360. package/dist/utils/photon.js.map +1 -1
  1361. package/dist/utils/pi-user-agent.d.ts.map +1 -1
  1362. package/dist/utils/pi-user-agent.js.map +1 -1
  1363. package/dist/utils/platform.d.ts.map +1 -1
  1364. package/dist/utils/platform.js.map +1 -1
  1365. package/dist/utils/process-memory.d.ts.map +1 -1
  1366. package/dist/utils/process-memory.js.map +1 -1
  1367. package/dist/utils/safe-write-stream.d.ts.map +1 -1
  1368. package/dist/utils/safe-write-stream.js.map +1 -1
  1369. package/dist/utils/shell.d.ts.map +1 -1
  1370. package/dist/utils/shell.js.map +1 -1
  1371. package/dist/utils/sleep.d.ts.map +1 -1
  1372. package/dist/utils/sleep.js +2 -15
  1373. package/dist/utils/sleep.js.map +1 -1
  1374. package/dist/utils/stdin-events.d.ts +8 -0
  1375. package/dist/utils/stdin-events.d.ts.map +1 -0
  1376. package/dist/utils/stdin-events.js +19 -0
  1377. package/dist/utils/stdin-events.js.map +1 -0
  1378. package/dist/utils/syntax-highlight.d.ts.map +1 -1
  1379. package/dist/utils/syntax-highlight.js +20 -13
  1380. package/dist/utils/syntax-highlight.js.map +1 -1
  1381. package/dist/utils/tools-manager.d.ts.map +1 -1
  1382. package/dist/utils/tools-manager.js.map +1 -1
  1383. package/dist/utils/version-check.d.ts.map +1 -1
  1384. package/dist/utils/version-check.js.map +1 -1
  1385. package/dist/utils/windows-self-update.d.ts.map +1 -1
  1386. package/dist/utils/windows-self-update.js.map +1 -1
  1387. package/dist/utils/work-directory.d.ts.map +1 -1
  1388. package/dist/utils/work-directory.js.map +1 -1
  1389. package/docs/compaction.md +11 -3
  1390. package/docs/sessions.md +6 -0
  1391. package/docs/settings.md +1 -1
  1392. package/docs/windows.md +26 -1
  1393. package/docs/work-directory.md +9 -1
  1394. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  1395. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  1396. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  1397. package/examples/extensions/sandbox/package-lock.json +2 -2
  1398. package/examples/extensions/sandbox/package.json +1 -1
  1399. package/examples/extensions/with-deps/package-lock.json +2 -2
  1400. package/examples/extensions/with-deps/package.json +1 -1
  1401. package/npm-shrinkwrap.json +16 -16
  1402. package/package.json +10 -10
  1403. package/dist/utils/streaming-lines.d.ts +0 -20
  1404. package/dist/utils/streaming-lines.d.ts.map +0 -1
  1405. package/dist/utils/streaming-lines.js +0 -79
  1406. package/dist/utils/streaming-lines.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"trust-manager.d.ts","sourceRoot":"","sources":["../../src/core/trust-manager.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,oBAAoB,GAAG,OAAO,GAAG,IAAI,CAAC;AAyFlD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CA2B1D;AAED,qBAAa,iBAAiB;IAC7B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAU;IAEnC,YAAY,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,EAI7D;IAED,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,oBAAoB,CAiBrC;IAED,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,oBAAoB,GAAG,IAAI,CAarD;CACD","sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport lockfile from \"proper-lockfile\";\nimport { CONFIG_DIR_NAME } from \"../config.ts\";\nimport { canonicalizePath, resolvePath } from \"../utils/paths.ts\";\nimport { stateFile } from \"./agent-paths.ts\";\nimport { isWorkerSession } from \"./session-role.ts\";\n\nexport type ProjectTrustDecision = boolean | null;\n\ntype TrustFile = Record<string, boolean | null | undefined>;\n\nconst CONTEXT_FILE_NAMES = [\"AGENTS.md\", \"AGENTS.MD\", \"CLAUDE.md\", \"CLAUDE.MD\", \"GEMINI.md\", \"GEMINI.MD\"];\n\nfunction normalizeCwd(cwd: string): string {\n\treturn canonicalizePath(resolvePath(cwd));\n}\n\nfunction readTrustFile(path: string): TrustFile | undefined {\n\tif (!existsSync(path)) {\n\t\treturn {};\n\t}\n\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(readFileSync(path, \"utf-8\"));\n\t} catch {\n\t\treturn undefined;\n\t}\n\n\tif (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n\t\tthrow new Error(`Invalid trust store ${path}: expected an object`);\n\t}\n\n\tconst data: TrustFile = {};\n\tfor (const [key, value] of Object.entries(parsed)) {\n\t\tif (value !== true && value !== false && value !== null) {\n\t\t\tthrow new Error(`Invalid trust store ${path}: value for ${JSON.stringify(key)} must be true, false, or null`);\n\t\t}\n\t\tdata[key] = value;\n\t}\n\treturn data;\n}\n\nfunction writeTrustFile(path: string, data: TrustFile): void {\n\tconst sorted: TrustFile = {};\n\tfor (const key of Object.keys(data).sort()) {\n\t\tconst value = data[key];\n\t\tif (value === true || value === false || value === null) {\n\t\t\tsorted[key] = value;\n\t\t}\n\t}\n\tmkdirSync(dirname(path), { recursive: true });\n\twriteFileSync(path, `${JSON.stringify(sorted, null, 2)}\\n`, \"utf-8\");\n}\n\nfunction acquireTrustLockSync(path: string): () => void {\n\tconst trustDir = dirname(path);\n\tmkdirSync(trustDir, { recursive: true });\n\tconst maxAttempts = 10;\n\tconst delayMs = 20;\n\tlet lastError: unknown;\n\n\tfor (let attempt = 1; attempt <= maxAttempts; attempt++) {\n\t\ttry {\n\t\t\treturn lockfile.lockSync(trustDir, { realpath: false, lockfilePath: `${path}.lock` });\n\t\t} catch (error) {\n\t\t\tconst code =\n\t\t\t\ttypeof error === \"object\" && error !== null && \"code\" in error\n\t\t\t\t\t? String((error as { code?: unknown }).code)\n\t\t\t\t\t: undefined;\n\t\t\tif (code !== \"ELOCKED\" || attempt === maxAttempts) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tlastError = error;\n\t\t\tconst start = Date.now();\n\t\t\twhile (Date.now() - start < delayMs) {\n\t\t\t\t// Sleep synchronously to avoid changing trust store callers to async.\n\t\t\t}\n\t\t}\n\t}\n\n\tif (lastError instanceof Error) {\n\t\tthrow lastError;\n\t}\n\tthrow new Error(\"Failed to acquire trust store lock\");\n}\n\nfunction withTrustFileLock<T>(path: string, fn: () => T): T {\n\tconst release = acquireTrustLockSync(path);\n\ttry {\n\t\treturn fn();\n\t} finally {\n\t\trelease();\n\t}\n}\n\nexport function hasProjectTrustInputs(cwd: string): boolean {\n\tlet currentDir = resolvePath(cwd);\n\tif (existsSync(join(currentDir, CONFIG_DIR_NAME))) {\n\t\treturn true;\n\t}\n\n\tconst root = resolve(\"/\");\n\twhile (true) {\n\t\tfor (const filename of CONTEXT_FILE_NAMES) {\n\t\t\tif (existsSync(join(currentDir, filename))) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\tif (existsSync(join(currentDir, \".agents\", \"skills\"))) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (currentDir === root) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst parentDir = resolve(currentDir, \"..\");\n\t\tif (parentDir === currentDir) {\n\t\t\treturn false;\n\t\t}\n\t\tcurrentDir = parentDir;\n\t}\n}\n\nexport class ProjectTrustStore {\n\tprivate trustPath: string;\n\tprivate readonly readOnly: boolean;\n\n\tconstructor(agentDir: string, options?: { readOnly?: boolean }) {\n\t\t// Machine-persisted trust decisions -- state/, not the agentDir root.\n\t\tthis.trustPath = stateFile(resolvePath(agentDir), \"trust.json\");\n\t\tthis.readOnly = options?.readOnly ?? isWorkerSession();\n\t}\n\n\tget(cwd: string): ProjectTrustDecision {\n\t\tif (this.readOnly) {\n\t\t\t// Zero-footprint (worker session): a lock-free read -- no lockfile, no state dir ever\n\t\t\t// created just from reading trust. A torn read (concurrent writer mid-rewrite) reads as\n\t\t\t// invalid JSON, which `readTrustFile` reports as `undefined`, and fails safe to untrusted\n\t\t\t// (null) below, never a crash.\n\t\t\tconst data = readTrustFile(this.trustPath);\n\t\t\tif (!data) return null;\n\t\t\tconst value = data[normalizeCwd(cwd)];\n\t\t\treturn value === true || value === false ? value : null;\n\t\t}\n\t\treturn withTrustFileLock(this.trustPath, () => {\n\t\t\tconst data = readTrustFile(this.trustPath);\n\t\t\tif (!data) return null;\n\t\t\tconst value = data[normalizeCwd(cwd)];\n\t\t\treturn value === true || value === false ? value : null;\n\t\t});\n\t}\n\n\tset(cwd: string, decision: ProjectTrustDecision): void {\n\t\tif (this.readOnly) return;\n\t\twithTrustFileLock(this.trustPath, () => {\n\t\t\tconst data = readTrustFile(this.trustPath);\n\t\t\tif (!data) return;\n\t\t\tconst key = normalizeCwd(cwd);\n\t\t\tif (decision === null) {\n\t\t\t\tdelete data[key];\n\t\t\t} else {\n\t\t\t\tdata[key] = decision;\n\t\t\t}\n\t\t\twriteTrustFile(this.trustPath, data);\n\t\t});\n\t}\n}\n"]}
1
+ {"version":3,"file":"trust-manager.d.ts","sourceRoot":"","sources":["../../src/core/trust-manager.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,oBAAoB,GAAG,OAAO,GAAG,IAAI,CAAC;AAwDlD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CA2B1D;AAED,qBAAa,iBAAiB;IAC7B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAU;IAEnC,YAAY,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,EAI7D;IAED,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,oBAAoB,CAgBrC;IAED,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,oBAAoB,GAAG,IAAI,CAarD;CACD"}
@@ -1,10 +1,10 @@
1
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
- import { dirname, join, resolve } from "node:path";
3
- import lockfile from "proper-lockfile";
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { join, resolve } from "node:path";
4
3
  import { CONFIG_DIR_NAME } from "../config.js";
5
4
  import { canonicalizePath, resolvePath } from "../utils/paths.js";
6
5
  import { stateFile } from "./agent-paths.js";
7
6
  import { isWorkerSession } from "./session-role.js";
7
+ import { acquireFileLockSync, LOW_LATENCY_FILE_LOCK_OPTIONS, writeFileAtomicSync } from "./util/atomic-file.js";
8
8
  const CONTEXT_FILE_NAMES = ["AGENTS.md", "AGENTS.MD", "CLAUDE.md", "CLAUDE.MD", "GEMINI.md", "GEMINI.MD"];
9
9
  function normalizeCwd(cwd) {
10
10
  return canonicalizePath(resolvePath(cwd));
@@ -40,40 +40,10 @@ function writeTrustFile(path, data) {
40
40
  sorted[key] = value;
41
41
  }
42
42
  }
43
- mkdirSync(dirname(path), { recursive: true });
44
- writeFileSync(path, `${JSON.stringify(sorted, null, 2)}\n`, "utf-8");
45
- }
46
- function acquireTrustLockSync(path) {
47
- const trustDir = dirname(path);
48
- mkdirSync(trustDir, { recursive: true });
49
- const maxAttempts = 10;
50
- const delayMs = 20;
51
- let lastError;
52
- for (let attempt = 1; attempt <= maxAttempts; attempt++) {
53
- try {
54
- return lockfile.lockSync(trustDir, { realpath: false, lockfilePath: `${path}.lock` });
55
- }
56
- catch (error) {
57
- const code = typeof error === "object" && error !== null && "code" in error
58
- ? String(error.code)
59
- : undefined;
60
- if (code !== "ELOCKED" || attempt === maxAttempts) {
61
- throw error;
62
- }
63
- lastError = error;
64
- const start = Date.now();
65
- while (Date.now() - start < delayMs) {
66
- // Sleep synchronously to avoid changing trust store callers to async.
67
- }
68
- }
69
- }
70
- if (lastError instanceof Error) {
71
- throw lastError;
72
- }
73
- throw new Error("Failed to acquire trust store lock");
43
+ writeFileAtomicSync(path, `${JSON.stringify(sorted, null, 2)}\n`);
74
44
  }
75
45
  function withTrustFileLock(path, fn) {
76
- const release = acquireTrustLockSync(path);
46
+ const release = acquireFileLockSync(path, LOW_LATENCY_FILE_LOCK_OPTIONS);
77
47
  try {
78
48
  return fn();
79
49
  }
@@ -107,8 +77,6 @@ export function hasProjectTrustInputs(cwd) {
107
77
  }
108
78
  }
109
79
  export class ProjectTrustStore {
110
- trustPath;
111
- readOnly;
112
80
  constructor(agentDir, options) {
113
81
  // Machine-persisted trust decisions -- state/, not the agentDir root.
114
82
  this.trustPath = stateFile(resolvePath(agentDir), "trust.json");
@@ -117,9 +85,8 @@ export class ProjectTrustStore {
117
85
  get(cwd) {
118
86
  if (this.readOnly) {
119
87
  // Zero-footprint (worker session): a lock-free read -- no lockfile, no state dir ever
120
- // created just from reading trust. A torn read (concurrent writer mid-rewrite) reads as
121
- // invalid JSON, which `readTrustFile` reports as `undefined`, and fails safe to untrusted
122
- // (null) below, never a crash.
88
+ // created just from reading trust. Writers publish by atomic rename, so a worker sees either
89
+ // the prior or next complete generation and still fails malformed input safe to untrusted.
123
90
  const data = readTrustFile(this.trustPath);
124
91
  if (!data)
125
92
  return null;
@@ -1 +1 @@
1
- {"version":3,"file":"trust-manager.js","sourceRoot":"","sources":["../../src/core/trust-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport lockfile from \"proper-lockfile\";\nimport { CONFIG_DIR_NAME } from \"../config.ts\";\nimport { canonicalizePath, resolvePath } from \"../utils/paths.ts\";\nimport { stateFile } from \"./agent-paths.ts\";\nimport { isWorkerSession } from \"./session-role.ts\";\n\nexport type ProjectTrustDecision = boolean | null;\n\ntype TrustFile = Record<string, boolean | null | undefined>;\n\nconst CONTEXT_FILE_NAMES = [\"AGENTS.md\", \"AGENTS.MD\", \"CLAUDE.md\", \"CLAUDE.MD\", \"GEMINI.md\", \"GEMINI.MD\"];\n\nfunction normalizeCwd(cwd: string): string {\n\treturn canonicalizePath(resolvePath(cwd));\n}\n\nfunction readTrustFile(path: string): TrustFile | undefined {\n\tif (!existsSync(path)) {\n\t\treturn {};\n\t}\n\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(readFileSync(path, \"utf-8\"));\n\t} catch {\n\t\treturn undefined;\n\t}\n\n\tif (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n\t\tthrow new Error(`Invalid trust store ${path}: expected an object`);\n\t}\n\n\tconst data: TrustFile = {};\n\tfor (const [key, value] of Object.entries(parsed)) {\n\t\tif (value !== true && value !== false && value !== null) {\n\t\t\tthrow new Error(`Invalid trust store ${path}: value for ${JSON.stringify(key)} must be true, false, or null`);\n\t\t}\n\t\tdata[key] = value;\n\t}\n\treturn data;\n}\n\nfunction writeTrustFile(path: string, data: TrustFile): void {\n\tconst sorted: TrustFile = {};\n\tfor (const key of Object.keys(data).sort()) {\n\t\tconst value = data[key];\n\t\tif (value === true || value === false || value === null) {\n\t\t\tsorted[key] = value;\n\t\t}\n\t}\n\tmkdirSync(dirname(path), { recursive: true });\n\twriteFileSync(path, `${JSON.stringify(sorted, null, 2)}\\n`, \"utf-8\");\n}\n\nfunction acquireTrustLockSync(path: string): () => void {\n\tconst trustDir = dirname(path);\n\tmkdirSync(trustDir, { recursive: true });\n\tconst maxAttempts = 10;\n\tconst delayMs = 20;\n\tlet lastError: unknown;\n\n\tfor (let attempt = 1; attempt <= maxAttempts; attempt++) {\n\t\ttry {\n\t\t\treturn lockfile.lockSync(trustDir, { realpath: false, lockfilePath: `${path}.lock` });\n\t\t} catch (error) {\n\t\t\tconst code =\n\t\t\t\ttypeof error === \"object\" && error !== null && \"code\" in error\n\t\t\t\t\t? String((error as { code?: unknown }).code)\n\t\t\t\t\t: undefined;\n\t\t\tif (code !== \"ELOCKED\" || attempt === maxAttempts) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tlastError = error;\n\t\t\tconst start = Date.now();\n\t\t\twhile (Date.now() - start < delayMs) {\n\t\t\t\t// Sleep synchronously to avoid changing trust store callers to async.\n\t\t\t}\n\t\t}\n\t}\n\n\tif (lastError instanceof Error) {\n\t\tthrow lastError;\n\t}\n\tthrow new Error(\"Failed to acquire trust store lock\");\n}\n\nfunction withTrustFileLock<T>(path: string, fn: () => T): T {\n\tconst release = acquireTrustLockSync(path);\n\ttry {\n\t\treturn fn();\n\t} finally {\n\t\trelease();\n\t}\n}\n\nexport function hasProjectTrustInputs(cwd: string): boolean {\n\tlet currentDir = resolvePath(cwd);\n\tif (existsSync(join(currentDir, CONFIG_DIR_NAME))) {\n\t\treturn true;\n\t}\n\n\tconst root = resolve(\"/\");\n\twhile (true) {\n\t\tfor (const filename of CONTEXT_FILE_NAMES) {\n\t\t\tif (existsSync(join(currentDir, filename))) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\tif (existsSync(join(currentDir, \".agents\", \"skills\"))) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (currentDir === root) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst parentDir = resolve(currentDir, \"..\");\n\t\tif (parentDir === currentDir) {\n\t\t\treturn false;\n\t\t}\n\t\tcurrentDir = parentDir;\n\t}\n}\n\nexport class ProjectTrustStore {\n\tprivate trustPath: string;\n\tprivate readonly readOnly: boolean;\n\n\tconstructor(agentDir: string, options?: { readOnly?: boolean }) {\n\t\t// Machine-persisted trust decisions -- state/, not the agentDir root.\n\t\tthis.trustPath = stateFile(resolvePath(agentDir), \"trust.json\");\n\t\tthis.readOnly = options?.readOnly ?? isWorkerSession();\n\t}\n\n\tget(cwd: string): ProjectTrustDecision {\n\t\tif (this.readOnly) {\n\t\t\t// Zero-footprint (worker session): a lock-free read -- no lockfile, no state dir ever\n\t\t\t// created just from reading trust. A torn read (concurrent writer mid-rewrite) reads as\n\t\t\t// invalid JSON, which `readTrustFile` reports as `undefined`, and fails safe to untrusted\n\t\t\t// (null) below, never a crash.\n\t\t\tconst data = readTrustFile(this.trustPath);\n\t\t\tif (!data) return null;\n\t\t\tconst value = data[normalizeCwd(cwd)];\n\t\t\treturn value === true || value === false ? value : null;\n\t\t}\n\t\treturn withTrustFileLock(this.trustPath, () => {\n\t\t\tconst data = readTrustFile(this.trustPath);\n\t\t\tif (!data) return null;\n\t\t\tconst value = data[normalizeCwd(cwd)];\n\t\t\treturn value === true || value === false ? value : null;\n\t\t});\n\t}\n\n\tset(cwd: string, decision: ProjectTrustDecision): void {\n\t\tif (this.readOnly) return;\n\t\twithTrustFileLock(this.trustPath, () => {\n\t\t\tconst data = readTrustFile(this.trustPath);\n\t\t\tif (!data) return;\n\t\t\tconst key = normalizeCwd(cwd);\n\t\t\tif (decision === null) {\n\t\t\t\tdelete data[key];\n\t\t\t} else {\n\t\t\t\tdata[key] = decision;\n\t\t\t}\n\t\t\twriteTrustFile(this.trustPath, data);\n\t\t});\n\t}\n}\n"]}
1
+ {"version":3,"file":"trust-manager.js","sourceRoot":"","sources":["../../src/core/trust-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,6BAA6B,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAMhH,MAAM,kBAAkB,GAAG,CAAC,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC;AAE1G,SAAS,YAAY,CAAC,GAAW;IAChC,OAAO,gBAAgB,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;AAC3C,CAAC;AAED,SAAS,aAAa,CAAC,IAAY;IAClC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACvB,OAAO,EAAE,CAAC;IACX,CAAC;IAED,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACJ,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IAClD,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAC;IAClB,CAAC;IAED,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5E,MAAM,IAAI,KAAK,CAAC,uBAAuB,IAAI,sBAAsB,CAAC,CAAC;IACpE,CAAC;IAED,MAAM,IAAI,GAAc,EAAE,CAAC;IAC3B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACnD,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACzD,MAAM,IAAI,KAAK,CAAC,uBAAuB,IAAI,eAAe,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC;QAC/G,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACnB,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC;AAED,SAAS,cAAc,CAAC,IAAY,EAAE,IAAe;IACpD,MAAM,MAAM,GAAc,EAAE,CAAC;IAC7B,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;QACxB,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACzD,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACrB,CAAC;IACF,CAAC;IACD,mBAAmB,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AACnE,CAAC;AAED,SAAS,iBAAiB,CAAI,IAAY,EAAE,EAAW;IACtD,MAAM,OAAO,GAAG,mBAAmB,CAAC,IAAI,EAAE,6BAA6B,CAAC,CAAC;IACzE,IAAI,CAAC;QACJ,OAAO,EAAE,EAAE,CAAC;IACb,CAAC;YAAS,CAAC;QACV,OAAO,EAAE,CAAC;IACX,CAAC;AACF,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,GAAW;IAChD,IAAI,UAAU,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,UAAU,CAAC,IAAI,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC,EAAE,CAAC;QACnD,OAAO,IAAI,CAAC;IACb,CAAC;IAED,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAC1B,OAAO,IAAI,EAAE,CAAC;QACb,KAAK,MAAM,QAAQ,IAAI,kBAAkB,EAAE,CAAC;YAC3C,IAAI,UAAU,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC;gBAC5C,OAAO,IAAI,CAAC;YACb,CAAC;QACF,CAAC;QACD,IAAI,UAAU,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC;YACvD,OAAO,IAAI,CAAC;QACb,CAAC;QAED,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;YACzB,OAAO,KAAK,CAAC;QACd,CAAC;QAED,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QAC5C,IAAI,SAAS,KAAK,UAAU,EAAE,CAAC;YAC9B,OAAO,KAAK,CAAC;QACd,CAAC;QACD,UAAU,GAAG,SAAS,CAAC;IACxB,CAAC;AACF,CAAC;AAED,MAAM,OAAO,iBAAiB;IAI7B,YAAY,QAAgB,EAAE,OAAgC;QAC7D,sEAAsE;QACtE,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAC,CAAC;QAChE,IAAI,CAAC,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,eAAe,EAAE,CAAC;IACxD,CAAC;IAED,GAAG,CAAC,GAAW;QACd,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,sFAAsF;YACtF,6FAA6F;YAC7F,2FAA2F;YAC3F,MAAM,IAAI,GAAG,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC3C,IAAI,CAAC,IAAI;gBAAE,OAAO,IAAI,CAAC;YACvB,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;YACtC,OAAO,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;QACzD,CAAC;QACD,OAAO,iBAAiB,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE;YAC7C,MAAM,IAAI,GAAG,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC3C,IAAI,CAAC,IAAI;gBAAE,OAAO,IAAI,CAAC;YACvB,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;YACtC,OAAO,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;QACzD,CAAC,CAAC,CAAC;IACJ,CAAC;IAED,GAAG,CAAC,GAAW,EAAE,QAA8B;QAC9C,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC1B,iBAAiB,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE;YACtC,MAAM,IAAI,GAAG,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC3C,IAAI,CAAC,IAAI;gBAAE,OAAO;YAClB,MAAM,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;YAC9B,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;gBACvB,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;YAClB,CAAC;iBAAM,CAAC;gBACP,IAAI,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC;YACtB,CAAC;YACD,cAAc,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;IACJ,CAAC;CACD","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport { CONFIG_DIR_NAME } from \"../config.ts\";\nimport { canonicalizePath, resolvePath } from \"../utils/paths.ts\";\nimport { stateFile } from \"./agent-paths.ts\";\nimport { isWorkerSession } from \"./session-role.ts\";\nimport { acquireFileLockSync, LOW_LATENCY_FILE_LOCK_OPTIONS, writeFileAtomicSync } from \"./util/atomic-file.ts\";\n\nexport type ProjectTrustDecision = boolean | null;\n\ntype TrustFile = Record<string, boolean | null | undefined>;\n\nconst CONTEXT_FILE_NAMES = [\"AGENTS.md\", \"AGENTS.MD\", \"CLAUDE.md\", \"CLAUDE.MD\", \"GEMINI.md\", \"GEMINI.MD\"];\n\nfunction normalizeCwd(cwd: string): string {\n\treturn canonicalizePath(resolvePath(cwd));\n}\n\nfunction readTrustFile(path: string): TrustFile | undefined {\n\tif (!existsSync(path)) {\n\t\treturn {};\n\t}\n\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(readFileSync(path, \"utf-8\"));\n\t} catch {\n\t\treturn undefined;\n\t}\n\n\tif (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n\t\tthrow new Error(`Invalid trust store ${path}: expected an object`);\n\t}\n\n\tconst data: TrustFile = {};\n\tfor (const [key, value] of Object.entries(parsed)) {\n\t\tif (value !== true && value !== false && value !== null) {\n\t\t\tthrow new Error(`Invalid trust store ${path}: value for ${JSON.stringify(key)} must be true, false, or null`);\n\t\t}\n\t\tdata[key] = value;\n\t}\n\treturn data;\n}\n\nfunction writeTrustFile(path: string, data: TrustFile): void {\n\tconst sorted: TrustFile = {};\n\tfor (const key of Object.keys(data).sort()) {\n\t\tconst value = data[key];\n\t\tif (value === true || value === false || value === null) {\n\t\t\tsorted[key] = value;\n\t\t}\n\t}\n\twriteFileAtomicSync(path, `${JSON.stringify(sorted, null, 2)}\\n`);\n}\n\nfunction withTrustFileLock<T>(path: string, fn: () => T): T {\n\tconst release = acquireFileLockSync(path, LOW_LATENCY_FILE_LOCK_OPTIONS);\n\ttry {\n\t\treturn fn();\n\t} finally {\n\t\trelease();\n\t}\n}\n\nexport function hasProjectTrustInputs(cwd: string): boolean {\n\tlet currentDir = resolvePath(cwd);\n\tif (existsSync(join(currentDir, CONFIG_DIR_NAME))) {\n\t\treturn true;\n\t}\n\n\tconst root = resolve(\"/\");\n\twhile (true) {\n\t\tfor (const filename of CONTEXT_FILE_NAMES) {\n\t\t\tif (existsSync(join(currentDir, filename))) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\tif (existsSync(join(currentDir, \".agents\", \"skills\"))) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (currentDir === root) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst parentDir = resolve(currentDir, \"..\");\n\t\tif (parentDir === currentDir) {\n\t\t\treturn false;\n\t\t}\n\t\tcurrentDir = parentDir;\n\t}\n}\n\nexport class ProjectTrustStore {\n\tprivate trustPath: string;\n\tprivate readonly readOnly: boolean;\n\n\tconstructor(agentDir: string, options?: { readOnly?: boolean }) {\n\t\t// Machine-persisted trust decisions -- state/, not the agentDir root.\n\t\tthis.trustPath = stateFile(resolvePath(agentDir), \"trust.json\");\n\t\tthis.readOnly = options?.readOnly ?? isWorkerSession();\n\t}\n\n\tget(cwd: string): ProjectTrustDecision {\n\t\tif (this.readOnly) {\n\t\t\t// Zero-footprint (worker session): a lock-free read -- no lockfile, no state dir ever\n\t\t\t// created just from reading trust. Writers publish by atomic rename, so a worker sees either\n\t\t\t// the prior or next complete generation and still fails malformed input safe to untrusted.\n\t\t\tconst data = readTrustFile(this.trustPath);\n\t\t\tif (!data) return null;\n\t\t\tconst value = data[normalizeCwd(cwd)];\n\t\t\treturn value === true || value === false ? value : null;\n\t\t}\n\t\treturn withTrustFileLock(this.trustPath, () => {\n\t\t\tconst data = readTrustFile(this.trustPath);\n\t\t\tif (!data) return null;\n\t\t\tconst value = data[normalizeCwd(cwd)];\n\t\t\treturn value === true || value === false ? value : null;\n\t\t});\n\t}\n\n\tset(cwd: string, decision: ProjectTrustDecision): void {\n\t\tif (this.readOnly) return;\n\t\twithTrustFileLock(this.trustPath, () => {\n\t\t\tconst data = readTrustFile(this.trustPath);\n\t\t\tif (!data) return;\n\t\t\tconst key = normalizeCwd(cwd);\n\t\t\tif (decision === null) {\n\t\t\t\tdelete data[key];\n\t\t\t} else {\n\t\t\t\tdata[key] = decision;\n\t\t\t}\n\t\t\twriteTrustFile(this.trustPath, data);\n\t\t});\n\t}\n}\n"]}
@@ -37,15 +37,34 @@ export interface AtomicFileLockOptions {
37
37
  * the existing execution model rather than introducing a new one.
38
38
  */
39
39
  retries?: number;
40
+ /** Initial delay between sync/async acquisition attempts; defaults to 25ms. */
41
+ minRetryDelayMs?: number;
42
+ /** Maximum delay between sync/async acquisition attempts; defaults to 500ms. */
43
+ maxRetryDelayMs?: number;
44
+ /** Retry-delay multiplier; defaults to 2. Set max=min for a fixed delay. */
45
+ retryFactor?: number;
40
46
  /** Resolve symlinks before locking (proper-lockfile `realpath`); false matches file-store.ts. */
41
47
  realpath?: boolean;
42
48
  /** Lock staleness window in ms (proper-lockfile `stale`); omitted = proper-lockfile's own default. */
43
49
  stale?: number;
50
+ /** Explicit proper-lockfile directory path; defaults to `${filePath}.lock`. */
51
+ lockfilePath?: string;
44
52
  }
45
53
  export interface AtomicFileWriteOptions {
46
54
  /** POSIX permission bits applied to the temporary file and inherited by the renamed destination. */
47
55
  mode?: number;
48
56
  }
57
+ /**
58
+ * Existing auth/settings/trust paths historically used 10 total attempts separated by 20ms. Keep
59
+ * that low-latency user-facing policy explicit while routing the mechanism through this module.
60
+ */
61
+ export declare const LOW_LATENCY_FILE_LOCK_OPTIONS: Readonly<AtomicFileLockOptions>;
62
+ /**
63
+ * Acquire a synchronous advisory file lock and return its release function. This is the shared
64
+ * mechanism for coordinators that must hold several locks in a deterministic order before entering
65
+ * one critical section; callers retain ownership of release ordering and release-error semantics.
66
+ */
67
+ export declare function acquireFileLockSync(filePath: string, options?: AtomicFileLockOptions): () => void;
49
68
  /**
50
69
  * Hold an exclusive advisory lock on `filePath` for the duration of `fn` (sync). Always releases,
51
70
  * including when `fn` throws.
@@ -1 +1 @@
1
- {"version":3,"file":"atomic-file.d.ts","sourceRoot":"","sources":["../../../src/core/util/atomic-file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAiEH,MAAM,WAAW,qBAAqB;IACrC;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iGAAiG;IACjG,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sGAAsG;IACtG,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,sBAAsB;IACtC,oGAAoG;IACpG,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AA2ED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,CAAC,CAcrG;AAED,0GAA0G;AAC1G,wBAAsB,YAAY,CAAC,CAAC,EACnC,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,EACxB,OAAO,CAAC,EAAE,qBAAqB,GAC7B,OAAO,CAAC,CAAC,CAAC,CAiBZ;AA6BD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,sBAAsB,GAAG,IAAI,CAY7G;AAED,wDAAwD;AACxD,wBAAsB,eAAe,CACpC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,sBAAsB,GAC9B,OAAO,CAAC,IAAI,CAAC,CAYf","sourcesContent":["/**\n * Shared atomic-file helper: a single lock+tmp+rename implementation reused by every\n * on-disk store that does a read-modify-write against a JSON/text file. Modeled on the pattern\n * already proven in `memory/providers/file-store.ts` (proper-lockfile advisory lock + write-tmp-\n * then-rename); before this helper existed the pattern was copy-pasted per store, and most copies\n * were missing either the lock, the atomic write, or both.\n *\n * Two call shapes:\n * - `withFileLock(Sync)` — hold an exclusive advisory lock across an arbitrary read-modify-write\n * callback. The lock spans BOTH the read and the write, closing the classic RMW race where two\n * writers each read the old content before either writes back.\n * - `writeFileAtomic(Sync)` — write-tmp-then-rename. Used INSIDE a `withFileLock` callback (or\n * standalone, for a pure overwrite that has no read step to race).\n *\n * Sync and async variants are both exported. Most existing stores expose a synchronous public API\n * called from hot, non-async paths (e.g. a per-token-stream perf sample), so the sync variant lets\n * them gain locking without forcing an async ripple through their callers; the async variant is for\n * call sites that are already async.\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport { promises as fsPromises, mkdirSync, renameSync, unlinkSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport lockfile from \"proper-lockfile\";\n\n/**\n * Bounded rename retry budget for the win32-only transient-rename handling below (see\n * {@link isTransientRenameErrorOnWin32}). Backoff doubles each attempt starting at\n * {@link RENAME_RETRY_MIN_TIMEOUT_MS} and capped at {@link RENAME_RETRY_MAX_TIMEOUT_MS}, mirroring\n * the doubling-backoff shape used for lock acquisition above. With {@link RENAME_RETRY_ATTEMPTS}\n * extra attempts (10, 20, 40, 80, ... capped at 200) the worst-case total wait is ~1.03s\n * (10+20+40+80+160+200+200+200+200 ~= 1110ms across 9 gaps), which comfortably covers the\n * millisecond-scale window Defender/the Windows Search indexer hold a freshly-written file open\n * without FILE_SHARE_DELETE before releasing it.\n */\nconst RENAME_RETRY_ATTEMPTS = 9;\nconst RENAME_RETRY_MIN_TIMEOUT_MS = 10;\nconst RENAME_RETRY_MAX_TIMEOUT_MS = 200;\n\n/**\n * On win32, antivirus (e.g. Windows Defender's real-time scanner) and the Windows Search indexer\n * routinely open a freshly-written file for a brief scan without `FILE_SHARE_DELETE`, which makes a\n * rename over/of that file fail transiently with EPERM/EACCES/EBUSY for a few milliseconds. This is\n * a well-documented platform semantic, not a bug in our write path — it's exactly why the\n * `graceful-fs` package ships its own win32 rename-retry wrapper. POSIX platforms never exhibit this\n * transient (a POSIX rename either succeeds or fails for a real, non-transient reason), so retry is\n * gated strictly to win32 to keep POSIX behavior byte-identical to a bare rename.\n */\nfunction isTransientRenameErrorOnWin32(err: unknown): boolean {\n\tif (process.platform !== \"win32\") return false;\n\tif (typeof err !== \"object\" || err === null) return false;\n\tconst code = (err as { code?: string }).code;\n\treturn code === \"EPERM\" || code === \"EACCES\" || code === \"EBUSY\";\n}\n\n/** Sync counterpart of the rename-retry policy; see {@link isTransientRenameErrorOnWin32}. */\nfunction renameSyncWithRetry(tmpPath: string, filePath: string): void {\n\tfor (let attempt = 0; attempt <= RENAME_RETRY_ATTEMPTS; attempt++) {\n\t\ttry {\n\t\t\trenameSync(tmpPath, filePath);\n\t\t\treturn;\n\t\t} catch (err) {\n\t\t\tif (!isTransientRenameErrorOnWin32(err) || attempt === RENAME_RETRY_ATTEMPTS) throw err;\n\t\t\tconst backoffMs = Math.min(RENAME_RETRY_MIN_TIMEOUT_MS * 2 ** attempt, RENAME_RETRY_MAX_TIMEOUT_MS);\n\t\t\tblockingSleepMs(backoffMs);\n\t\t}\n\t}\n}\n\n/** Async counterpart of the rename-retry policy; see {@link isTransientRenameErrorOnWin32}. */\nasync function renameWithRetry(tmpPath: string, filePath: string): Promise<void> {\n\tfor (let attempt = 0; attempt <= RENAME_RETRY_ATTEMPTS; attempt++) {\n\t\ttry {\n\t\t\tawait fsPromises.rename(tmpPath, filePath);\n\t\t\treturn;\n\t\t} catch (err) {\n\t\t\tif (!isTransientRenameErrorOnWin32(err) || attempt === RENAME_RETRY_ATTEMPTS) throw err;\n\t\t\tconst backoffMs = Math.min(RENAME_RETRY_MIN_TIMEOUT_MS * 2 ** attempt, RENAME_RETRY_MAX_TIMEOUT_MS);\n\t\t\tawait new Promise((resolve) => setTimeout(resolve, backoffMs));\n\t\t}\n\t}\n}\n\nexport interface AtomicFileLockOptions {\n\t/**\n\t * Bounded retry attempts while waiting for a lock already held elsewhere. Both variants use a\n\t * SHORT, capped backoff (see {@link RETRY_MIN_TIMEOUT_MS}/{@link RETRY_MAX_TIMEOUT_MS}) — these\n\t * stores' critical sections are sub-millisecond reads+writes of small JSON/text files, so\n\t * contention should clear in milliseconds, not the multi-second-to-31-second worst case\n\t * proper-lockfile's OWN default backoff produces for a bare numeric `retries` (its default\n\t * `minTimeout` is 1000ms with factor 2 — see node_modules/retry/lib/retry.js). Passing a bare\n\t * number straight through would turn brief contention into a multi-second stall on a hot path\n\t * (e.g. a per-token-stream perf sample), so both variants instead build an explicit short-backoff\n\t * `retry` options object.\n\t * - Async (`withFileLock`): forwarded as `{retries, minTimeout, maxTimeout}` to proper-lockfile.\n\t * - Sync (`withFileLockSync`): proper-lockfile's sync API REJECTS `retries > 0` outright (it\n\t * requires the whole acquire flow to be synchronous — see proper-lockfile/lib/adapter.js\n\t * `toSyncOptions`, which throws `ESYNC`). So the sync path implements its own bounded retry\n\t * around single `lockfile.lockSync` attempts, blocking briefly between them (Atomics.wait) —\n\t * callers are already fully synchronous fs code, so a short blocking wait on contention matches\n\t * the existing execution model rather than introducing a new one.\n\t */\n\tretries?: number;\n\t/** Resolve symlinks before locking (proper-lockfile `realpath`); false matches file-store.ts. */\n\trealpath?: boolean;\n\t/** Lock staleness window in ms (proper-lockfile `stale`); omitted = proper-lockfile's own default. */\n\tstale?: number;\n}\n\nexport interface AtomicFileWriteOptions {\n\t/** POSIX permission bits applied to the temporary file and inherited by the renamed destination. */\n\tmode?: number;\n}\n\nconst DEFAULT_RETRIES = 10;\nconst DEFAULT_REALPATH = false;\n/**\n * Capped doubling backoff shared by both variants — see {@link AtomicFileLockOptions.retries}.\n * With the current defaults (10 retries, 25ms floor, 500ms cap) the total worst-case contention\n * budget is ~3.3s (25+50+100+200+400+500+500+500+500+500), comfortably over the >= 2s floor this\n * needs to survive a loaded CI runner (e.g. the Windows CI mkdir/rmdir lock-directory churn under\n * two-real-OS-thread contention).\n */\nconst RETRY_MIN_TIMEOUT_MS = 25;\nconst RETRY_MAX_TIMEOUT_MS = 500;\nfunction ensureLockDirSync(filePath: string): void {\n\tmkdirSync(dirname(filePath), { recursive: true });\n}\n\nasync function ensureLockDir(filePath: string): Promise<void> {\n\tawait fsPromises.mkdir(dirname(filePath), { recursive: true });\n}\n\nfunction isLockedError(err: unknown): boolean {\n\tif (typeof err !== \"object\" || err === null) return false;\n\tconst code = (err as { code?: string }).code;\n\tif (code === \"ELOCKED\") return true;\n\t// On win32, mkdir-ing the lock directory can transiently surface EPERM (rather than the\n\t// expected EEXIST) when a previous incarnation of that directory is concurrently being\n\t// rmdir'd by the racing releaser — the mkdir lands mid-teardown and the OS reports \"operation\n\t// not permitted\" instead of \"already exists\". This is contention, not a real permissions\n\t// failure, so treat it identically to ELOCKED: retry with the existing backoff rather than\n\t// letting it escape as fatal. POSIX platforms don't exhibit this transient and keep surfacing\n\t// real EPERM (e.g. an actually unwritable directory) as fatal.\n\tif (code === \"EPERM\" && process.platform === \"win32\") return true;\n\treturn false;\n}\n\n/** Block the calling thread for `ms` without spinning the CPU (Atomics.wait on a private buffer). */\nfunction blockingSleepMs(ms: number): void {\n\tAtomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);\n}\n\n/**\n * Acquire a proper-lockfile sync lock with bounded retry on `ELOCKED` (proper-lockfile's sync API\n * itself forbids `retries > 0`; see {@link AtomicFileLockOptions.retries}).\n *\n * Backoff doubles each attempt (mirroring the `retry` module's own `factor: 2` default that the\n * async path gets for free from proper-lockfile), starting at {@link RETRY_MIN_TIMEOUT_MS} and\n * capped at {@link RETRY_MAX_TIMEOUT_MS}.\n *\n * This is budget PARITY between two implementations of the same lock-acquisition contract, not\n * flake-masking: `options.retries` (a count of RETRIES, i.e. attempts after the first) means the\n * same thing on both paths, so both must make `retries + 1` total acquisition attempts with the\n * same per-gap backoff schedule. The async path gets `retries + 1` attempts for free from the\n * `retry` module (it retries `options.retries` times after its initial attempt); the sync path\n * used to loop exactly `attempts` times total (one fewer gap, and one fewer attempt than the\n * async path for the same `retries` value), which under-budgeted it relative to its async sibling\n * and surfaced as spurious ELOCKED failures under real contention (e.g. two OS threads hammering\n * the same file, or mkdir/rmdir lock-directory churn on a loaded Windows CI runner).\n */\nfunction lockSyncWithRetry(filePath: string, options: AtomicFileLockOptions): () => void {\n\tconst attempts = Math.max(1, options.retries ?? DEFAULT_RETRIES) + 1;\n\tconst lockOptions = { realpath: options.realpath ?? DEFAULT_REALPATH, stale: options.stale };\n\tfor (let attempt = 1; attempt <= attempts; attempt++) {\n\t\ttry {\n\t\t\treturn lockfile.lockSync(filePath, lockOptions);\n\t\t} catch (err) {\n\t\t\tif (!isLockedError(err) || attempt === attempts) throw err;\n\t\t\tconst backoffMs = Math.min(RETRY_MIN_TIMEOUT_MS * 2 ** (attempt - 1), RETRY_MAX_TIMEOUT_MS);\n\t\t\tblockingSleepMs(backoffMs);\n\t\t}\n\t}\n\t// Unreachable (the loop always returns or throws), but keeps the function's return type honest.\n\tthrow new Error(`Failed to acquire lock for ${filePath}`);\n}\n\n/**\n * Hold an exclusive advisory lock on `filePath` for the duration of `fn` (sync). Always releases,\n * including when `fn` throws.\n */\nexport function withFileLockSync<T>(filePath: string, fn: () => T, options?: AtomicFileLockOptions): T {\n\tensureLockDirSync(filePath);\n\tconst release = lockSyncWithRetry(filePath, options ?? {});\n\ttry {\n\t\treturn fn();\n\t} finally {\n\t\t// A lock-cleanup failure must never mask fn()'s result (or replace fn()'s own thrown error) —\n\t\t// by this point fn() has already durably committed or failed on its own terms.\n\t\ttry {\n\t\t\trelease();\n\t\t} catch {\n\t\t\t// best-effort cleanup; a stale lock self-expires via proper-lockfile's `stale` window\n\t\t}\n\t}\n}\n\n/** Async counterpart of {@link withFileLockSync}. Always releases, including when `fn` throws/rejects. */\nexport async function withFileLock<T>(\n\tfilePath: string,\n\tfn: () => Promise<T> | T,\n\toptions?: AtomicFileLockOptions,\n): Promise<T> {\n\tawait ensureLockDir(filePath);\n\tconst release = await lockfile.lock(filePath, {\n\t\trealpath: options?.realpath ?? DEFAULT_REALPATH,\n\t\tretries: {\n\t\t\tretries: options?.retries ?? DEFAULT_RETRIES,\n\t\t\tminTimeout: RETRY_MIN_TIMEOUT_MS,\n\t\t\tmaxTimeout: RETRY_MAX_TIMEOUT_MS,\n\t\t},\n\t\tstale: options?.stale,\n\t});\n\ttry {\n\t\treturn await fn();\n\t} finally {\n\t\t// See {@link withFileLockSync} — cleanup failures must not mask fn()'s outcome.\n\t\tawait release().catch(() => {});\n\t}\n}\n\n/**\n * Write `content` to `filePath` via write-tmp-then-rename (sync); the rename is atomic on the same\n * filesystem, so a concurrent reader never observes a partially-written file. Does NOT itself lock —\n * call from inside {@link withFileLockSync} when the write follows a read that must not race another\n * writer's read+write; call standalone for an unconditional overwrite with no read step.\n */\nfunction temporaryPath(filePath: string): string {\n\treturn `${filePath}.${process.pid}.${randomUUID()}.tmp`;\n}\n\n/** Remove one invocation's temporary path without masking the original write/rename failure. */\nfunction removeTemporaryPathSync(tmpPath: string): void {\n\ttry {\n\t\tunlinkSync(tmpPath);\n\t} catch {\n\t\t// The rename may have consumed the path, or another failure may have prevented its creation.\n\t}\n}\n\nasync function removeTemporaryPath(tmpPath: string): Promise<void> {\n\ttry {\n\t\tawait fsPromises.unlink(tmpPath);\n\t} catch {\n\t\t// The rename may have consumed the path, or another failure may have prevented its creation.\n\t}\n}\n\nexport function writeFileAtomicSync(filePath: string, content: string, options?: AtomicFileWriteOptions): void {\n\tmkdirSync(dirname(filePath), { recursive: true });\n\tconst tmpPath = temporaryPath(filePath);\n\tlet renamed = false;\n\ttry {\n\t\t// `wx` makes a nonce collision harmless: never truncate another writer's temporary file.\n\t\twriteFileSync(tmpPath, content, { encoding: \"utf-8\", flag: \"wx\", mode: options?.mode });\n\t\trenameSyncWithRetry(tmpPath, filePath);\n\t\trenamed = true;\n\t} finally {\n\t\tif (!renamed) removeTemporaryPathSync(tmpPath);\n\t}\n}\n\n/** Async counterpart of {@link writeFileAtomicSync}. */\nexport async function writeFileAtomic(\n\tfilePath: string,\n\tcontent: string,\n\toptions?: AtomicFileWriteOptions,\n): Promise<void> {\n\tawait fsPromises.mkdir(dirname(filePath), { recursive: true });\n\tconst tmpPath = temporaryPath(filePath);\n\tlet renamed = false;\n\ttry {\n\t\t// `wx` makes a nonce collision harmless: never truncate another writer's temporary file.\n\t\tawait fsPromises.writeFile(tmpPath, content, { encoding: \"utf-8\", flag: \"wx\", mode: options?.mode });\n\t\tawait renameWithRetry(tmpPath, filePath);\n\t\trenamed = true;\n\t} finally {\n\t\tif (!renamed) await removeTemporaryPath(tmpPath);\n\t}\n}\n"]}
1
+ {"version":3,"file":"atomic-file.d.ts","sourceRoot":"","sources":["../../../src/core/util/atomic-file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAiEH,MAAM,WAAW,qBAAqB;IACrC;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gFAAgF;IAChF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,4EAA4E;IAC5E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iGAAiG;IACjG,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sGAAsG;IACtG,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+EAA+E;IAC/E,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,sBAAsB;IACtC,oGAAoG;IACpG,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAcD;;;GAGG;AACH,eAAO,MAAM,6BAA6B,EAAE,QAAQ,CAAC,qBAAqB,CAIxE,CAAC;AAmEH;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,qBAA0B,GAAG,MAAM,IAAI,CAkBrG;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,CAAC,CAarG;AAED,0GAA0G;AAC1G,wBAAsB,YAAY,CAAC,CAAC,EACnC,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,EACxB,OAAO,CAAC,EAAE,qBAAqB,GAC7B,OAAO,CAAC,CAAC,CAAC,CAmBZ;AA6BD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,sBAAsB,GAAG,IAAI,CAY7G;AAED,wDAAwD;AACxD,wBAAsB,eAAe,CACpC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,sBAAsB,GAC9B,OAAO,CAAC,IAAI,CAAC,CAYf"}
@@ -92,11 +92,23 @@ const DEFAULT_REALPATH = false;
92
92
  */
93
93
  const RETRY_MIN_TIMEOUT_MS = 25;
94
94
  const RETRY_MAX_TIMEOUT_MS = 500;
95
- function ensureLockDirSync(filePath) {
96
- mkdirSync(dirname(filePath), { recursive: true });
95
+ /**
96
+ * Existing auth/settings/trust paths historically used 10 total attempts separated by 20ms. Keep
97
+ * that low-latency user-facing policy explicit while routing the mechanism through this module.
98
+ */
99
+ export const LOW_LATENCY_FILE_LOCK_OPTIONS = Object.freeze({
100
+ retries: 9,
101
+ minRetryDelayMs: 20,
102
+ maxRetryDelayMs: 20,
103
+ });
104
+ function lockDirectory(filePath, lockfilePath) {
105
+ return dirname(lockfilePath ?? filePath);
97
106
  }
98
- async function ensureLockDir(filePath) {
99
- await fsPromises.mkdir(dirname(filePath), { recursive: true });
107
+ function ensureLockDirSync(filePath, lockfilePath) {
108
+ mkdirSync(lockDirectory(filePath, lockfilePath), { recursive: true });
109
+ }
110
+ async function ensureLockDir(filePath, lockfilePath) {
111
+ await fsPromises.mkdir(lockDirectory(filePath, lockfilePath), { recursive: true });
100
112
  }
101
113
  function isLockedError(err) {
102
114
  if (typeof err !== "object" || err === null)
@@ -137,9 +149,32 @@ function blockingSleepMs(ms) {
137
149
  * and surfaced as spurious ELOCKED failures under real contention (e.g. two OS threads hammering
138
150
  * the same file, or mkdir/rmdir lock-directory churn on a loaded Windows CI runner).
139
151
  */
140
- function lockSyncWithRetry(filePath, options) {
141
- const attempts = Math.max(1, options.retries ?? DEFAULT_RETRIES) + 1;
142
- const lockOptions = { realpath: options.realpath ?? DEFAULT_REALPATH, stale: options.stale };
152
+ function retryCount(options) {
153
+ const configured = options.retries ?? DEFAULT_RETRIES;
154
+ return Number.isFinite(configured) ? Math.max(0, Math.floor(configured)) : DEFAULT_RETRIES;
155
+ }
156
+ function retryDelayMs(options, attempt) {
157
+ const configuredMin = options.minRetryDelayMs ?? RETRY_MIN_TIMEOUT_MS;
158
+ const minDelay = Number.isFinite(configuredMin) ? Math.max(0, configuredMin) : RETRY_MIN_TIMEOUT_MS;
159
+ const configuredMax = options.maxRetryDelayMs ?? RETRY_MAX_TIMEOUT_MS;
160
+ const maxDelay = Number.isFinite(configuredMax) ? Math.max(minDelay, configuredMax) : RETRY_MAX_TIMEOUT_MS;
161
+ const configuredFactor = options.retryFactor ?? 2;
162
+ const factor = Number.isFinite(configuredFactor) ? Math.max(1, configuredFactor) : 2;
163
+ return Math.min(minDelay * factor ** (attempt - 1), maxDelay);
164
+ }
165
+ /**
166
+ * Acquire a synchronous advisory file lock and return its release function. This is the shared
167
+ * mechanism for coordinators that must hold several locks in a deterministic order before entering
168
+ * one critical section; callers retain ownership of release ordering and release-error semantics.
169
+ */
170
+ export function acquireFileLockSync(filePath, options = {}) {
171
+ ensureLockDirSync(filePath, options.lockfilePath);
172
+ const attempts = retryCount(options) + 1;
173
+ const lockOptions = {
174
+ lockfilePath: options.lockfilePath,
175
+ realpath: options.realpath ?? DEFAULT_REALPATH,
176
+ stale: options.stale,
177
+ };
143
178
  for (let attempt = 1; attempt <= attempts; attempt++) {
144
179
  try {
145
180
  return lockfile.lockSync(filePath, lockOptions);
@@ -147,8 +182,7 @@ function lockSyncWithRetry(filePath, options) {
147
182
  catch (err) {
148
183
  if (!isLockedError(err) || attempt === attempts)
149
184
  throw err;
150
- const backoffMs = Math.min(RETRY_MIN_TIMEOUT_MS * 2 ** (attempt - 1), RETRY_MAX_TIMEOUT_MS);
151
- blockingSleepMs(backoffMs);
185
+ blockingSleepMs(retryDelayMs(options, attempt));
152
186
  }
153
187
  }
154
188
  // Unreachable (the loop always returns or throws), but keeps the function's return type honest.
@@ -159,8 +193,7 @@ function lockSyncWithRetry(filePath, options) {
159
193
  * including when `fn` throws.
160
194
  */
161
195
  export function withFileLockSync(filePath, fn, options) {
162
- ensureLockDirSync(filePath);
163
- const release = lockSyncWithRetry(filePath, options ?? {});
196
+ const release = acquireFileLockSync(filePath, options);
164
197
  try {
165
198
  return fn();
166
199
  }
@@ -177,13 +210,15 @@ export function withFileLockSync(filePath, fn, options) {
177
210
  }
178
211
  /** Async counterpart of {@link withFileLockSync}. Always releases, including when `fn` throws/rejects. */
179
212
  export async function withFileLock(filePath, fn, options) {
180
- await ensureLockDir(filePath);
213
+ await ensureLockDir(filePath, options?.lockfilePath);
181
214
  const release = await lockfile.lock(filePath, {
215
+ lockfilePath: options?.lockfilePath,
182
216
  realpath: options?.realpath ?? DEFAULT_REALPATH,
183
217
  retries: {
184
- retries: options?.retries ?? DEFAULT_RETRIES,
185
- minTimeout: RETRY_MIN_TIMEOUT_MS,
186
- maxTimeout: RETRY_MAX_TIMEOUT_MS,
218
+ retries: retryCount(options ?? {}),
219
+ factor: options?.retryFactor ?? 2,
220
+ minTimeout: options?.minRetryDelayMs ?? RETRY_MIN_TIMEOUT_MS,
221
+ maxTimeout: options?.maxRetryDelayMs ?? RETRY_MAX_TIMEOUT_MS,
187
222
  },
188
223
  stale: options?.stale,
189
224
  });
@@ -1 +1 @@
1
- {"version":3,"file":"atomic-file.js","sourceRoot":"","sources":["../../../src/core/util/atomic-file.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared atomic-file helper: a single lock+tmp+rename implementation reused by every\n * on-disk store that does a read-modify-write against a JSON/text file. Modeled on the pattern\n * already proven in `memory/providers/file-store.ts` (proper-lockfile advisory lock + write-tmp-\n * then-rename); before this helper existed the pattern was copy-pasted per store, and most copies\n * were missing either the lock, the atomic write, or both.\n *\n * Two call shapes:\n * - `withFileLock(Sync)` — hold an exclusive advisory lock across an arbitrary read-modify-write\n * callback. The lock spans BOTH the read and the write, closing the classic RMW race where two\n * writers each read the old content before either writes back.\n * - `writeFileAtomic(Sync)` — write-tmp-then-rename. Used INSIDE a `withFileLock` callback (or\n * standalone, for a pure overwrite that has no read step to race).\n *\n * Sync and async variants are both exported. Most existing stores expose a synchronous public API\n * called from hot, non-async paths (e.g. a per-token-stream perf sample), so the sync variant lets\n * them gain locking without forcing an async ripple through their callers; the async variant is for\n * call sites that are already async.\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport { promises as fsPromises, mkdirSync, renameSync, unlinkSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport lockfile from \"proper-lockfile\";\n\n/**\n * Bounded rename retry budget for the win32-only transient-rename handling below (see\n * {@link isTransientRenameErrorOnWin32}). Backoff doubles each attempt starting at\n * {@link RENAME_RETRY_MIN_TIMEOUT_MS} and capped at {@link RENAME_RETRY_MAX_TIMEOUT_MS}, mirroring\n * the doubling-backoff shape used for lock acquisition above. With {@link RENAME_RETRY_ATTEMPTS}\n * extra attempts (10, 20, 40, 80, ... capped at 200) the worst-case total wait is ~1.03s\n * (10+20+40+80+160+200+200+200+200 ~= 1110ms across 9 gaps), which comfortably covers the\n * millisecond-scale window Defender/the Windows Search indexer hold a freshly-written file open\n * without FILE_SHARE_DELETE before releasing it.\n */\nconst RENAME_RETRY_ATTEMPTS = 9;\nconst RENAME_RETRY_MIN_TIMEOUT_MS = 10;\nconst RENAME_RETRY_MAX_TIMEOUT_MS = 200;\n\n/**\n * On win32, antivirus (e.g. Windows Defender's real-time scanner) and the Windows Search indexer\n * routinely open a freshly-written file for a brief scan without `FILE_SHARE_DELETE`, which makes a\n * rename over/of that file fail transiently with EPERM/EACCES/EBUSY for a few milliseconds. This is\n * a well-documented platform semantic, not a bug in our write path — it's exactly why the\n * `graceful-fs` package ships its own win32 rename-retry wrapper. POSIX platforms never exhibit this\n * transient (a POSIX rename either succeeds or fails for a real, non-transient reason), so retry is\n * gated strictly to win32 to keep POSIX behavior byte-identical to a bare rename.\n */\nfunction isTransientRenameErrorOnWin32(err: unknown): boolean {\n\tif (process.platform !== \"win32\") return false;\n\tif (typeof err !== \"object\" || err === null) return false;\n\tconst code = (err as { code?: string }).code;\n\treturn code === \"EPERM\" || code === \"EACCES\" || code === \"EBUSY\";\n}\n\n/** Sync counterpart of the rename-retry policy; see {@link isTransientRenameErrorOnWin32}. */\nfunction renameSyncWithRetry(tmpPath: string, filePath: string): void {\n\tfor (let attempt = 0; attempt <= RENAME_RETRY_ATTEMPTS; attempt++) {\n\t\ttry {\n\t\t\trenameSync(tmpPath, filePath);\n\t\t\treturn;\n\t\t} catch (err) {\n\t\t\tif (!isTransientRenameErrorOnWin32(err) || attempt === RENAME_RETRY_ATTEMPTS) throw err;\n\t\t\tconst backoffMs = Math.min(RENAME_RETRY_MIN_TIMEOUT_MS * 2 ** attempt, RENAME_RETRY_MAX_TIMEOUT_MS);\n\t\t\tblockingSleepMs(backoffMs);\n\t\t}\n\t}\n}\n\n/** Async counterpart of the rename-retry policy; see {@link isTransientRenameErrorOnWin32}. */\nasync function renameWithRetry(tmpPath: string, filePath: string): Promise<void> {\n\tfor (let attempt = 0; attempt <= RENAME_RETRY_ATTEMPTS; attempt++) {\n\t\ttry {\n\t\t\tawait fsPromises.rename(tmpPath, filePath);\n\t\t\treturn;\n\t\t} catch (err) {\n\t\t\tif (!isTransientRenameErrorOnWin32(err) || attempt === RENAME_RETRY_ATTEMPTS) throw err;\n\t\t\tconst backoffMs = Math.min(RENAME_RETRY_MIN_TIMEOUT_MS * 2 ** attempt, RENAME_RETRY_MAX_TIMEOUT_MS);\n\t\t\tawait new Promise((resolve) => setTimeout(resolve, backoffMs));\n\t\t}\n\t}\n}\n\nexport interface AtomicFileLockOptions {\n\t/**\n\t * Bounded retry attempts while waiting for a lock already held elsewhere. Both variants use a\n\t * SHORT, capped backoff (see {@link RETRY_MIN_TIMEOUT_MS}/{@link RETRY_MAX_TIMEOUT_MS}) — these\n\t * stores' critical sections are sub-millisecond reads+writes of small JSON/text files, so\n\t * contention should clear in milliseconds, not the multi-second-to-31-second worst case\n\t * proper-lockfile's OWN default backoff produces for a bare numeric `retries` (its default\n\t * `minTimeout` is 1000ms with factor 2 — see node_modules/retry/lib/retry.js). Passing a bare\n\t * number straight through would turn brief contention into a multi-second stall on a hot path\n\t * (e.g. a per-token-stream perf sample), so both variants instead build an explicit short-backoff\n\t * `retry` options object.\n\t * - Async (`withFileLock`): forwarded as `{retries, minTimeout, maxTimeout}` to proper-lockfile.\n\t * - Sync (`withFileLockSync`): proper-lockfile's sync API REJECTS `retries > 0` outright (it\n\t * requires the whole acquire flow to be synchronous — see proper-lockfile/lib/adapter.js\n\t * `toSyncOptions`, which throws `ESYNC`). So the sync path implements its own bounded retry\n\t * around single `lockfile.lockSync` attempts, blocking briefly between them (Atomics.wait) —\n\t * callers are already fully synchronous fs code, so a short blocking wait on contention matches\n\t * the existing execution model rather than introducing a new one.\n\t */\n\tretries?: number;\n\t/** Resolve symlinks before locking (proper-lockfile `realpath`); false matches file-store.ts. */\n\trealpath?: boolean;\n\t/** Lock staleness window in ms (proper-lockfile `stale`); omitted = proper-lockfile's own default. */\n\tstale?: number;\n}\n\nexport interface AtomicFileWriteOptions {\n\t/** POSIX permission bits applied to the temporary file and inherited by the renamed destination. */\n\tmode?: number;\n}\n\nconst DEFAULT_RETRIES = 10;\nconst DEFAULT_REALPATH = false;\n/**\n * Capped doubling backoff shared by both variants — see {@link AtomicFileLockOptions.retries}.\n * With the current defaults (10 retries, 25ms floor, 500ms cap) the total worst-case contention\n * budget is ~3.3s (25+50+100+200+400+500+500+500+500+500), comfortably over the >= 2s floor this\n * needs to survive a loaded CI runner (e.g. the Windows CI mkdir/rmdir lock-directory churn under\n * two-real-OS-thread contention).\n */\nconst RETRY_MIN_TIMEOUT_MS = 25;\nconst RETRY_MAX_TIMEOUT_MS = 500;\nfunction ensureLockDirSync(filePath: string): void {\n\tmkdirSync(dirname(filePath), { recursive: true });\n}\n\nasync function ensureLockDir(filePath: string): Promise<void> {\n\tawait fsPromises.mkdir(dirname(filePath), { recursive: true });\n}\n\nfunction isLockedError(err: unknown): boolean {\n\tif (typeof err !== \"object\" || err === null) return false;\n\tconst code = (err as { code?: string }).code;\n\tif (code === \"ELOCKED\") return true;\n\t// On win32, mkdir-ing the lock directory can transiently surface EPERM (rather than the\n\t// expected EEXIST) when a previous incarnation of that directory is concurrently being\n\t// rmdir'd by the racing releaser — the mkdir lands mid-teardown and the OS reports \"operation\n\t// not permitted\" instead of \"already exists\". This is contention, not a real permissions\n\t// failure, so treat it identically to ELOCKED: retry with the existing backoff rather than\n\t// letting it escape as fatal. POSIX platforms don't exhibit this transient and keep surfacing\n\t// real EPERM (e.g. an actually unwritable directory) as fatal.\n\tif (code === \"EPERM\" && process.platform === \"win32\") return true;\n\treturn false;\n}\n\n/** Block the calling thread for `ms` without spinning the CPU (Atomics.wait on a private buffer). */\nfunction blockingSleepMs(ms: number): void {\n\tAtomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);\n}\n\n/**\n * Acquire a proper-lockfile sync lock with bounded retry on `ELOCKED` (proper-lockfile's sync API\n * itself forbids `retries > 0`; see {@link AtomicFileLockOptions.retries}).\n *\n * Backoff doubles each attempt (mirroring the `retry` module's own `factor: 2` default that the\n * async path gets for free from proper-lockfile), starting at {@link RETRY_MIN_TIMEOUT_MS} and\n * capped at {@link RETRY_MAX_TIMEOUT_MS}.\n *\n * This is budget PARITY between two implementations of the same lock-acquisition contract, not\n * flake-masking: `options.retries` (a count of RETRIES, i.e. attempts after the first) means the\n * same thing on both paths, so both must make `retries + 1` total acquisition attempts with the\n * same per-gap backoff schedule. The async path gets `retries + 1` attempts for free from the\n * `retry` module (it retries `options.retries` times after its initial attempt); the sync path\n * used to loop exactly `attempts` times total (one fewer gap, and one fewer attempt than the\n * async path for the same `retries` value), which under-budgeted it relative to its async sibling\n * and surfaced as spurious ELOCKED failures under real contention (e.g. two OS threads hammering\n * the same file, or mkdir/rmdir lock-directory churn on a loaded Windows CI runner).\n */\nfunction lockSyncWithRetry(filePath: string, options: AtomicFileLockOptions): () => void {\n\tconst attempts = Math.max(1, options.retries ?? DEFAULT_RETRIES) + 1;\n\tconst lockOptions = { realpath: options.realpath ?? DEFAULT_REALPATH, stale: options.stale };\n\tfor (let attempt = 1; attempt <= attempts; attempt++) {\n\t\ttry {\n\t\t\treturn lockfile.lockSync(filePath, lockOptions);\n\t\t} catch (err) {\n\t\t\tif (!isLockedError(err) || attempt === attempts) throw err;\n\t\t\tconst backoffMs = Math.min(RETRY_MIN_TIMEOUT_MS * 2 ** (attempt - 1), RETRY_MAX_TIMEOUT_MS);\n\t\t\tblockingSleepMs(backoffMs);\n\t\t}\n\t}\n\t// Unreachable (the loop always returns or throws), but keeps the function's return type honest.\n\tthrow new Error(`Failed to acquire lock for ${filePath}`);\n}\n\n/**\n * Hold an exclusive advisory lock on `filePath` for the duration of `fn` (sync). Always releases,\n * including when `fn` throws.\n */\nexport function withFileLockSync<T>(filePath: string, fn: () => T, options?: AtomicFileLockOptions): T {\n\tensureLockDirSync(filePath);\n\tconst release = lockSyncWithRetry(filePath, options ?? {});\n\ttry {\n\t\treturn fn();\n\t} finally {\n\t\t// A lock-cleanup failure must never mask fn()'s result (or replace fn()'s own thrown error) —\n\t\t// by this point fn() has already durably committed or failed on its own terms.\n\t\ttry {\n\t\t\trelease();\n\t\t} catch {\n\t\t\t// best-effort cleanup; a stale lock self-expires via proper-lockfile's `stale` window\n\t\t}\n\t}\n}\n\n/** Async counterpart of {@link withFileLockSync}. Always releases, including when `fn` throws/rejects. */\nexport async function withFileLock<T>(\n\tfilePath: string,\n\tfn: () => Promise<T> | T,\n\toptions?: AtomicFileLockOptions,\n): Promise<T> {\n\tawait ensureLockDir(filePath);\n\tconst release = await lockfile.lock(filePath, {\n\t\trealpath: options?.realpath ?? DEFAULT_REALPATH,\n\t\tretries: {\n\t\t\tretries: options?.retries ?? DEFAULT_RETRIES,\n\t\t\tminTimeout: RETRY_MIN_TIMEOUT_MS,\n\t\t\tmaxTimeout: RETRY_MAX_TIMEOUT_MS,\n\t\t},\n\t\tstale: options?.stale,\n\t});\n\ttry {\n\t\treturn await fn();\n\t} finally {\n\t\t// See {@link withFileLockSync} — cleanup failures must not mask fn()'s outcome.\n\t\tawait release().catch(() => {});\n\t}\n}\n\n/**\n * Write `content` to `filePath` via write-tmp-then-rename (sync); the rename is atomic on the same\n * filesystem, so a concurrent reader never observes a partially-written file. Does NOT itself lock —\n * call from inside {@link withFileLockSync} when the write follows a read that must not race another\n * writer's read+write; call standalone for an unconditional overwrite with no read step.\n */\nfunction temporaryPath(filePath: string): string {\n\treturn `${filePath}.${process.pid}.${randomUUID()}.tmp`;\n}\n\n/** Remove one invocation's temporary path without masking the original write/rename failure. */\nfunction removeTemporaryPathSync(tmpPath: string): void {\n\ttry {\n\t\tunlinkSync(tmpPath);\n\t} catch {\n\t\t// The rename may have consumed the path, or another failure may have prevented its creation.\n\t}\n}\n\nasync function removeTemporaryPath(tmpPath: string): Promise<void> {\n\ttry {\n\t\tawait fsPromises.unlink(tmpPath);\n\t} catch {\n\t\t// The rename may have consumed the path, or another failure may have prevented its creation.\n\t}\n}\n\nexport function writeFileAtomicSync(filePath: string, content: string, options?: AtomicFileWriteOptions): void {\n\tmkdirSync(dirname(filePath), { recursive: true });\n\tconst tmpPath = temporaryPath(filePath);\n\tlet renamed = false;\n\ttry {\n\t\t// `wx` makes a nonce collision harmless: never truncate another writer's temporary file.\n\t\twriteFileSync(tmpPath, content, { encoding: \"utf-8\", flag: \"wx\", mode: options?.mode });\n\t\trenameSyncWithRetry(tmpPath, filePath);\n\t\trenamed = true;\n\t} finally {\n\t\tif (!renamed) removeTemporaryPathSync(tmpPath);\n\t}\n}\n\n/** Async counterpart of {@link writeFileAtomicSync}. */\nexport async function writeFileAtomic(\n\tfilePath: string,\n\tcontent: string,\n\toptions?: AtomicFileWriteOptions,\n): Promise<void> {\n\tawait fsPromises.mkdir(dirname(filePath), { recursive: true });\n\tconst tmpPath = temporaryPath(filePath);\n\tlet renamed = false;\n\ttry {\n\t\t// `wx` makes a nonce collision harmless: never truncate another writer's temporary file.\n\t\tawait fsPromises.writeFile(tmpPath, content, { encoding: \"utf-8\", flag: \"wx\", mode: options?.mode });\n\t\tawait renameWithRetry(tmpPath, filePath);\n\t\trenamed = true;\n\t} finally {\n\t\tif (!renamed) await removeTemporaryPath(tmpPath);\n\t}\n}\n"]}
1
+ {"version":3,"file":"atomic-file.js","sourceRoot":"","sources":["../../../src/core/util/atomic-file.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared atomic-file helper: a single lock+tmp+rename implementation reused by every\n * on-disk store that does a read-modify-write against a JSON/text file. Modeled on the pattern\n * already proven in `memory/providers/file-store.ts` (proper-lockfile advisory lock + write-tmp-\n * then-rename); before this helper existed the pattern was copy-pasted per store, and most copies\n * were missing either the lock, the atomic write, or both.\n *\n * Two call shapes:\n * - `withFileLock(Sync)` — hold an exclusive advisory lock across an arbitrary read-modify-write\n * callback. The lock spans BOTH the read and the write, closing the classic RMW race where two\n * writers each read the old content before either writes back.\n * - `writeFileAtomic(Sync)` — write-tmp-then-rename. Used INSIDE a `withFileLock` callback (or\n * standalone, for a pure overwrite that has no read step to race).\n *\n * Sync and async variants are both exported. Most existing stores expose a synchronous public API\n * called from hot, non-async paths (e.g. a per-token-stream perf sample), so the sync variant lets\n * them gain locking without forcing an async ripple through their callers; the async variant is for\n * call sites that are already async.\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport { promises as fsPromises, mkdirSync, renameSync, unlinkSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport lockfile from \"proper-lockfile\";\n\n/**\n * Bounded rename retry budget for the win32-only transient-rename handling below (see\n * {@link isTransientRenameErrorOnWin32}). Backoff doubles each attempt starting at\n * {@link RENAME_RETRY_MIN_TIMEOUT_MS} and capped at {@link RENAME_RETRY_MAX_TIMEOUT_MS}, mirroring\n * the doubling-backoff shape used for lock acquisition above. With {@link RENAME_RETRY_ATTEMPTS}\n * extra attempts (10, 20, 40, 80, ... capped at 200) the worst-case total wait is ~1.03s\n * (10+20+40+80+160+200+200+200+200 ~= 1110ms across 9 gaps), which comfortably covers the\n * millisecond-scale window Defender/the Windows Search indexer hold a freshly-written file open\n * without FILE_SHARE_DELETE before releasing it.\n */\nconst RENAME_RETRY_ATTEMPTS = 9;\nconst RENAME_RETRY_MIN_TIMEOUT_MS = 10;\nconst RENAME_RETRY_MAX_TIMEOUT_MS = 200;\n\n/**\n * On win32, antivirus (e.g. Windows Defender's real-time scanner) and the Windows Search indexer\n * routinely open a freshly-written file for a brief scan without `FILE_SHARE_DELETE`, which makes a\n * rename over/of that file fail transiently with EPERM/EACCES/EBUSY for a few milliseconds. This is\n * a well-documented platform semantic, not a bug in our write path — it's exactly why the\n * `graceful-fs` package ships its own win32 rename-retry wrapper. POSIX platforms never exhibit this\n * transient (a POSIX rename either succeeds or fails for a real, non-transient reason), so retry is\n * gated strictly to win32 to keep POSIX behavior byte-identical to a bare rename.\n */\nfunction isTransientRenameErrorOnWin32(err: unknown): boolean {\n\tif (process.platform !== \"win32\") return false;\n\tif (typeof err !== \"object\" || err === null) return false;\n\tconst code = (err as { code?: string }).code;\n\treturn code === \"EPERM\" || code === \"EACCES\" || code === \"EBUSY\";\n}\n\n/** Sync counterpart of the rename-retry policy; see {@link isTransientRenameErrorOnWin32}. */\nfunction renameSyncWithRetry(tmpPath: string, filePath: string): void {\n\tfor (let attempt = 0; attempt <= RENAME_RETRY_ATTEMPTS; attempt++) {\n\t\ttry {\n\t\t\trenameSync(tmpPath, filePath);\n\t\t\treturn;\n\t\t} catch (err) {\n\t\t\tif (!isTransientRenameErrorOnWin32(err) || attempt === RENAME_RETRY_ATTEMPTS) throw err;\n\t\t\tconst backoffMs = Math.min(RENAME_RETRY_MIN_TIMEOUT_MS * 2 ** attempt, RENAME_RETRY_MAX_TIMEOUT_MS);\n\t\t\tblockingSleepMs(backoffMs);\n\t\t}\n\t}\n}\n\n/** Async counterpart of the rename-retry policy; see {@link isTransientRenameErrorOnWin32}. */\nasync function renameWithRetry(tmpPath: string, filePath: string): Promise<void> {\n\tfor (let attempt = 0; attempt <= RENAME_RETRY_ATTEMPTS; attempt++) {\n\t\ttry {\n\t\t\tawait fsPromises.rename(tmpPath, filePath);\n\t\t\treturn;\n\t\t} catch (err) {\n\t\t\tif (!isTransientRenameErrorOnWin32(err) || attempt === RENAME_RETRY_ATTEMPTS) throw err;\n\t\t\tconst backoffMs = Math.min(RENAME_RETRY_MIN_TIMEOUT_MS * 2 ** attempt, RENAME_RETRY_MAX_TIMEOUT_MS);\n\t\t\tawait new Promise((resolve) => setTimeout(resolve, backoffMs));\n\t\t}\n\t}\n}\n\nexport interface AtomicFileLockOptions {\n\t/**\n\t * Bounded retry attempts while waiting for a lock already held elsewhere. Both variants use a\n\t * SHORT, capped backoff (see {@link RETRY_MIN_TIMEOUT_MS}/{@link RETRY_MAX_TIMEOUT_MS}) — these\n\t * stores' critical sections are sub-millisecond reads+writes of small JSON/text files, so\n\t * contention should clear in milliseconds, not the multi-second-to-31-second worst case\n\t * proper-lockfile's OWN default backoff produces for a bare numeric `retries` (its default\n\t * `minTimeout` is 1000ms with factor 2 — see node_modules/retry/lib/retry.js). Passing a bare\n\t * number straight through would turn brief contention into a multi-second stall on a hot path\n\t * (e.g. a per-token-stream perf sample), so both variants instead build an explicit short-backoff\n\t * `retry` options object.\n\t * - Async (`withFileLock`): forwarded as `{retries, minTimeout, maxTimeout}` to proper-lockfile.\n\t * - Sync (`withFileLockSync`): proper-lockfile's sync API REJECTS `retries > 0` outright (it\n\t * requires the whole acquire flow to be synchronous — see proper-lockfile/lib/adapter.js\n\t * `toSyncOptions`, which throws `ESYNC`). So the sync path implements its own bounded retry\n\t * around single `lockfile.lockSync` attempts, blocking briefly between them (Atomics.wait) —\n\t * callers are already fully synchronous fs code, so a short blocking wait on contention matches\n\t * the existing execution model rather than introducing a new one.\n\t */\n\tretries?: number;\n\t/** Initial delay between sync/async acquisition attempts; defaults to 25ms. */\n\tminRetryDelayMs?: number;\n\t/** Maximum delay between sync/async acquisition attempts; defaults to 500ms. */\n\tmaxRetryDelayMs?: number;\n\t/** Retry-delay multiplier; defaults to 2. Set max=min for a fixed delay. */\n\tretryFactor?: number;\n\t/** Resolve symlinks before locking (proper-lockfile `realpath`); false matches file-store.ts. */\n\trealpath?: boolean;\n\t/** Lock staleness window in ms (proper-lockfile `stale`); omitted = proper-lockfile's own default. */\n\tstale?: number;\n\t/** Explicit proper-lockfile directory path; defaults to `${filePath}.lock`. */\n\tlockfilePath?: string;\n}\n\nexport interface AtomicFileWriteOptions {\n\t/** POSIX permission bits applied to the temporary file and inherited by the renamed destination. */\n\tmode?: number;\n}\n\nconst DEFAULT_RETRIES = 10;\nconst DEFAULT_REALPATH = false;\n/**\n * Capped doubling backoff shared by both variants — see {@link AtomicFileLockOptions.retries}.\n * With the current defaults (10 retries, 25ms floor, 500ms cap) the total worst-case contention\n * budget is ~3.3s (25+50+100+200+400+500+500+500+500+500), comfortably over the >= 2s floor this\n * needs to survive a loaded CI runner (e.g. the Windows CI mkdir/rmdir lock-directory churn under\n * two-real-OS-thread contention).\n */\nconst RETRY_MIN_TIMEOUT_MS = 25;\nconst RETRY_MAX_TIMEOUT_MS = 500;\n\n/**\n * Existing auth/settings/trust paths historically used 10 total attempts separated by 20ms. Keep\n * that low-latency user-facing policy explicit while routing the mechanism through this module.\n */\nexport const LOW_LATENCY_FILE_LOCK_OPTIONS: Readonly<AtomicFileLockOptions> = Object.freeze({\n\tretries: 9,\n\tminRetryDelayMs: 20,\n\tmaxRetryDelayMs: 20,\n});\n\nfunction lockDirectory(filePath: string, lockfilePath?: string): string {\n\treturn dirname(lockfilePath ?? filePath);\n}\n\nfunction ensureLockDirSync(filePath: string, lockfilePath?: string): void {\n\tmkdirSync(lockDirectory(filePath, lockfilePath), { recursive: true });\n}\n\nasync function ensureLockDir(filePath: string, lockfilePath?: string): Promise<void> {\n\tawait fsPromises.mkdir(lockDirectory(filePath, lockfilePath), { recursive: true });\n}\n\nfunction isLockedError(err: unknown): boolean {\n\tif (typeof err !== \"object\" || err === null) return false;\n\tconst code = (err as { code?: string }).code;\n\tif (code === \"ELOCKED\") return true;\n\t// On win32, mkdir-ing the lock directory can transiently surface EPERM (rather than the\n\t// expected EEXIST) when a previous incarnation of that directory is concurrently being\n\t// rmdir'd by the racing releaser — the mkdir lands mid-teardown and the OS reports \"operation\n\t// not permitted\" instead of \"already exists\". This is contention, not a real permissions\n\t// failure, so treat it identically to ELOCKED: retry with the existing backoff rather than\n\t// letting it escape as fatal. POSIX platforms don't exhibit this transient and keep surfacing\n\t// real EPERM (e.g. an actually unwritable directory) as fatal.\n\tif (code === \"EPERM\" && process.platform === \"win32\") return true;\n\treturn false;\n}\n\n/** Block the calling thread for `ms` without spinning the CPU (Atomics.wait on a private buffer). */\nfunction blockingSleepMs(ms: number): void {\n\tAtomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);\n}\n\n/**\n * Acquire a proper-lockfile sync lock with bounded retry on `ELOCKED` (proper-lockfile's sync API\n * itself forbids `retries > 0`; see {@link AtomicFileLockOptions.retries}).\n *\n * Backoff doubles each attempt (mirroring the `retry` module's own `factor: 2` default that the\n * async path gets for free from proper-lockfile), starting at {@link RETRY_MIN_TIMEOUT_MS} and\n * capped at {@link RETRY_MAX_TIMEOUT_MS}.\n *\n * This is budget PARITY between two implementations of the same lock-acquisition contract, not\n * flake-masking: `options.retries` (a count of RETRIES, i.e. attempts after the first) means the\n * same thing on both paths, so both must make `retries + 1` total acquisition attempts with the\n * same per-gap backoff schedule. The async path gets `retries + 1` attempts for free from the\n * `retry` module (it retries `options.retries` times after its initial attempt); the sync path\n * used to loop exactly `attempts` times total (one fewer gap, and one fewer attempt than the\n * async path for the same `retries` value), which under-budgeted it relative to its async sibling\n * and surfaced as spurious ELOCKED failures under real contention (e.g. two OS threads hammering\n * the same file, or mkdir/rmdir lock-directory churn on a loaded Windows CI runner).\n */\nfunction retryCount(options: AtomicFileLockOptions): number {\n\tconst configured = options.retries ?? DEFAULT_RETRIES;\n\treturn Number.isFinite(configured) ? Math.max(0, Math.floor(configured)) : DEFAULT_RETRIES;\n}\n\nfunction retryDelayMs(options: AtomicFileLockOptions, attempt: number): number {\n\tconst configuredMin = options.minRetryDelayMs ?? RETRY_MIN_TIMEOUT_MS;\n\tconst minDelay = Number.isFinite(configuredMin) ? Math.max(0, configuredMin) : RETRY_MIN_TIMEOUT_MS;\n\tconst configuredMax = options.maxRetryDelayMs ?? RETRY_MAX_TIMEOUT_MS;\n\tconst maxDelay = Number.isFinite(configuredMax) ? Math.max(minDelay, configuredMax) : RETRY_MAX_TIMEOUT_MS;\n\tconst configuredFactor = options.retryFactor ?? 2;\n\tconst factor = Number.isFinite(configuredFactor) ? Math.max(1, configuredFactor) : 2;\n\treturn Math.min(minDelay * factor ** (attempt - 1), maxDelay);\n}\n\n/**\n * Acquire a synchronous advisory file lock and return its release function. This is the shared\n * mechanism for coordinators that must hold several locks in a deterministic order before entering\n * one critical section; callers retain ownership of release ordering and release-error semantics.\n */\nexport function acquireFileLockSync(filePath: string, options: AtomicFileLockOptions = {}): () => void {\n\tensureLockDirSync(filePath, options.lockfilePath);\n\tconst attempts = retryCount(options) + 1;\n\tconst lockOptions = {\n\t\tlockfilePath: options.lockfilePath,\n\t\trealpath: options.realpath ?? DEFAULT_REALPATH,\n\t\tstale: options.stale,\n\t};\n\tfor (let attempt = 1; attempt <= attempts; attempt++) {\n\t\ttry {\n\t\t\treturn lockfile.lockSync(filePath, lockOptions);\n\t\t} catch (err) {\n\t\t\tif (!isLockedError(err) || attempt === attempts) throw err;\n\t\t\tblockingSleepMs(retryDelayMs(options, attempt));\n\t\t}\n\t}\n\t// Unreachable (the loop always returns or throws), but keeps the function's return type honest.\n\tthrow new Error(`Failed to acquire lock for ${filePath}`);\n}\n\n/**\n * Hold an exclusive advisory lock on `filePath` for the duration of `fn` (sync). Always releases,\n * including when `fn` throws.\n */\nexport function withFileLockSync<T>(filePath: string, fn: () => T, options?: AtomicFileLockOptions): T {\n\tconst release = acquireFileLockSync(filePath, options);\n\ttry {\n\t\treturn fn();\n\t} finally {\n\t\t// A lock-cleanup failure must never mask fn()'s result (or replace fn()'s own thrown error) —\n\t\t// by this point fn() has already durably committed or failed on its own terms.\n\t\ttry {\n\t\t\trelease();\n\t\t} catch {\n\t\t\t// best-effort cleanup; a stale lock self-expires via proper-lockfile's `stale` window\n\t\t}\n\t}\n}\n\n/** Async counterpart of {@link withFileLockSync}. Always releases, including when `fn` throws/rejects. */\nexport async function withFileLock<T>(\n\tfilePath: string,\n\tfn: () => Promise<T> | T,\n\toptions?: AtomicFileLockOptions,\n): Promise<T> {\n\tawait ensureLockDir(filePath, options?.lockfilePath);\n\tconst release = await lockfile.lock(filePath, {\n\t\tlockfilePath: options?.lockfilePath,\n\t\trealpath: options?.realpath ?? DEFAULT_REALPATH,\n\t\tretries: {\n\t\t\tretries: retryCount(options ?? {}),\n\t\t\tfactor: options?.retryFactor ?? 2,\n\t\t\tminTimeout: options?.minRetryDelayMs ?? RETRY_MIN_TIMEOUT_MS,\n\t\t\tmaxTimeout: options?.maxRetryDelayMs ?? RETRY_MAX_TIMEOUT_MS,\n\t\t},\n\t\tstale: options?.stale,\n\t});\n\ttry {\n\t\treturn await fn();\n\t} finally {\n\t\t// See {@link withFileLockSync} — cleanup failures must not mask fn()'s outcome.\n\t\tawait release().catch(() => {});\n\t}\n}\n\n/**\n * Write `content` to `filePath` via write-tmp-then-rename (sync); the rename is atomic on the same\n * filesystem, so a concurrent reader never observes a partially-written file. Does NOT itself lock —\n * call from inside {@link withFileLockSync} when the write follows a read that must not race another\n * writer's read+write; call standalone for an unconditional overwrite with no read step.\n */\nfunction temporaryPath(filePath: string): string {\n\treturn `${filePath}.${process.pid}.${randomUUID()}.tmp`;\n}\n\n/** Remove one invocation's temporary path without masking the original write/rename failure. */\nfunction removeTemporaryPathSync(tmpPath: string): void {\n\ttry {\n\t\tunlinkSync(tmpPath);\n\t} catch {\n\t\t// The rename may have consumed the path, or another failure may have prevented its creation.\n\t}\n}\n\nasync function removeTemporaryPath(tmpPath: string): Promise<void> {\n\ttry {\n\t\tawait fsPromises.unlink(tmpPath);\n\t} catch {\n\t\t// The rename may have consumed the path, or another failure may have prevented its creation.\n\t}\n}\n\nexport function writeFileAtomicSync(filePath: string, content: string, options?: AtomicFileWriteOptions): void {\n\tmkdirSync(dirname(filePath), { recursive: true });\n\tconst tmpPath = temporaryPath(filePath);\n\tlet renamed = false;\n\ttry {\n\t\t// `wx` makes a nonce collision harmless: never truncate another writer's temporary file.\n\t\twriteFileSync(tmpPath, content, { encoding: \"utf-8\", flag: \"wx\", mode: options?.mode });\n\t\trenameSyncWithRetry(tmpPath, filePath);\n\t\trenamed = true;\n\t} finally {\n\t\tif (!renamed) removeTemporaryPathSync(tmpPath);\n\t}\n}\n\n/** Async counterpart of {@link writeFileAtomicSync}. */\nexport async function writeFileAtomic(\n\tfilePath: string,\n\tcontent: string,\n\toptions?: AtomicFileWriteOptions,\n): Promise<void> {\n\tawait fsPromises.mkdir(dirname(filePath), { recursive: true });\n\tconst tmpPath = temporaryPath(filePath);\n\tlet renamed = false;\n\ttry {\n\t\t// `wx` makes a nonce collision harmless: never truncate another writer's temporary file.\n\t\tawait fsPromises.writeFile(tmpPath, content, { encoding: \"utf-8\", flag: \"wx\", mode: options?.mode });\n\t\tawait renameWithRetry(tmpPath, filePath);\n\t\trenamed = true;\n\t} finally {\n\t\tif (!renamed) await removeTemporaryPath(tmpPath);\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"bounded-file.d.ts","sourceRoot":"","sources":["../../../src/core/util/bounded-file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyD,KAAK,KAAK,EAAE,MAAM,SAAS,CAAC;AAW5F,sGAAsG;AACtG,wBAAgB,eAAe,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAQlE;AAkBD,8FAA8F;AAC9F,wBAAgB,6BAA6B,CAAC,cAAc,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAc1G;AAED,uEAAuE;AACvE,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAiBjG;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CAAC,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAehH;AAED,4DAA4D;AAC5D,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAiB5G","sourcesContent":["import { closeSync, fstatSync, opendirSync, openSync, readSync, type Stats } from \"node:fs\";\nimport { type FileHandle, open as openAsync } from \"node:fs/promises\";\n\nconst READ_CHUNK_BYTES = 64 * 1024;\n\nfunction validateByteLimit(maxBytes: number): void {\n\tif (!Number.isSafeInteger(maxBytes) || maxBytes < 0) {\n\t\tthrow new TypeError(\"Bounded file reads require a non-negative safe-integer byte limit.\");\n\t}\n}\n\n/** Compare the filesystem identity and mutation-sensitive metadata captured around a bounded read. */\nexport function sameFileVersion(left: Stats, right: Stats): boolean {\n\treturn (\n\t\tleft.dev === right.dev &&\n\t\tleft.ino === right.ino &&\n\t\tleft.size === right.size &&\n\t\tleft.mtimeMs === right.mtimeMs &&\n\t\tleft.ctimeMs === right.ctimeMs\n\t);\n}\n\nasync function readFileHandleBounded(fileHandle: FileHandle, maxBytes: number): Promise<Buffer | undefined> {\n\tvalidateByteLimit(maxBytes);\n\tconst chunks: Buffer[] = [];\n\tlet totalBytes = 0;\n\twhile (totalBytes < maxBytes) {\n\t\tconst chunk = Buffer.allocUnsafe(Math.min(READ_CHUNK_BYTES, maxBytes - totalBytes));\n\t\tconst { bytesRead } = await fileHandle.read(chunk, 0, chunk.length, totalBytes);\n\t\tif (bytesRead === 0) return Buffer.concat(chunks, totalBytes);\n\t\tchunks.push(chunk.subarray(0, bytesRead));\n\t\ttotalBytes += bytesRead;\n\t}\n\tconst overflowProbe = Buffer.allocUnsafe(1);\n\tif ((await fileHandle.read(overflowProbe, 0, 1, totalBytes)).bytesRead > 0) return undefined;\n\treturn Buffer.concat(chunks, totalBytes);\n}\n\n/** Read at most `maxBytes`, then probe one byte so a growing file cannot escape the bound. */\nexport function readFileDescriptorBoundedSync(fileDescriptor: number, maxBytes: number): Buffer | undefined {\n\tvalidateByteLimit(maxBytes);\n\tconst chunks: Buffer[] = [];\n\tlet totalBytes = 0;\n\twhile (totalBytes < maxBytes) {\n\t\tconst chunk = Buffer.allocUnsafe(Math.min(READ_CHUNK_BYTES, maxBytes - totalBytes));\n\t\tconst bytesRead = readSync(fileDescriptor, chunk, 0, chunk.length, null);\n\t\tif (bytesRead === 0) return Buffer.concat(chunks, totalBytes);\n\t\tchunks.push(chunk.subarray(0, bytesRead));\n\t\ttotalBytes += bytesRead;\n\t}\n\tconst overflowProbe = Buffer.allocUnsafe(1);\n\tif (readSync(fileDescriptor, overflowProbe, 0, 1, null) > 0) return undefined;\n\treturn Buffer.concat(chunks, totalBytes);\n}\n\n/** Bounded, version-stable text read for small durable state files. */\nexport function readBoundedTextFileSync(filePath: string, maxBytes: number, label: string): string {\n\tvalidateByteLimit(maxBytes);\n\tconst fileDescriptor = openSync(filePath, \"r\");\n\ttry {\n\t\tconst before = fstatSync(fileDescriptor);\n\t\tif (!before.isFile()) throw new Error(`${label} is not a regular file.`);\n\t\tif (before.size > maxBytes) throw new Error(`${label} exceeds its byte limit.`);\n\t\tconst content = readFileDescriptorBoundedSync(fileDescriptor, maxBytes);\n\t\tif (!content) throw new Error(`${label} exceeds its byte limit.`);\n\t\tconst after = fstatSync(fileDescriptor);\n\t\tif (!sameFileVersion(before, after) || content.byteLength !== before.size) {\n\t\t\tthrow new Error(`${label} changed while it was being read.`);\n\t\t}\n\t\treturn content.toString(\"utf-8\");\n\t} finally {\n\t\tcloseSync(fileDescriptor);\n\t}\n}\n\n/**\n * Enumerate a managed directory incrementally. Unlike `readdirSync`, this never allocates an\n * unbounded entry array before the caller can reject a corrupt or hostile directory.\n */\nexport function readBoundedDirectoryNamesSync(directoryPath: string, maxEntries: number, label: string): string[] {\n\tif (!Number.isSafeInteger(maxEntries) || maxEntries < 1) {\n\t\tthrow new TypeError(\"Bounded directory reads require a positive safe-integer entry limit.\");\n\t}\n\tconst directory = opendirSync(directoryPath);\n\ttry {\n\t\tconst names: string[] = [];\n\t\tfor (let entry = directory.readSync(); entry; entry = directory.readSync()) {\n\t\t\tif (names.length === maxEntries) throw new Error(`${label} exceeds its entry limit.`);\n\t\t\tnames.push(entry.name);\n\t\t}\n\t\treturn names;\n\t} finally {\n\t\tdirectory.closeSync();\n\t}\n}\n\n/** Async counterpart of {@link readBoundedTextFileSync}. */\nexport async function readBoundedTextFile(filePath: string, maxBytes: number, label: string): Promise<string> {\n\tvalidateByteLimit(maxBytes);\n\tconst fileHandle = await openAsync(filePath, \"r\");\n\ttry {\n\t\tconst before = await fileHandle.stat();\n\t\tif (!before.isFile()) throw new Error(`${label} is not a regular file.`);\n\t\tif (before.size > maxBytes) throw new Error(`${label} exceeds its byte limit.`);\n\t\tconst content = await readFileHandleBounded(fileHandle, maxBytes);\n\t\tif (!content) throw new Error(`${label} exceeds its byte limit.`);\n\t\tconst after = await fileHandle.stat();\n\t\tif (!sameFileVersion(before, after) || content.byteLength !== before.size) {\n\t\t\tthrow new Error(`${label} changed while it was being read.`);\n\t\t}\n\t\treturn content.toString(\"utf-8\");\n\t} finally {\n\t\tawait fileHandle.close();\n\t}\n}\n"]}
1
+ {"version":3,"file":"bounded-file.d.ts","sourceRoot":"","sources":["../../../src/core/util/bounded-file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyD,KAAK,KAAK,EAAE,MAAM,SAAS,CAAC;AAW5F,sGAAsG;AACtG,wBAAgB,eAAe,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAQlE;AAkBD,8FAA8F;AAC9F,wBAAgB,6BAA6B,CAAC,cAAc,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAc1G;AAED,uEAAuE;AACvE,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAiBjG;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CAAC,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAehH;AAED,4DAA4D;AAC5D,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAiB5G"}
@@ -1 +1 @@
1
- {"version":3,"file":"bounded-file.js","sourceRoot":"","sources":["../../../src/core/util/bounded-file.ts"],"names":[],"mappings":"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","sourcesContent":["import { closeSync, fstatSync, opendirSync, openSync, readSync, type Stats } from \"node:fs\";\nimport { type FileHandle, open as openAsync } from \"node:fs/promises\";\n\nconst READ_CHUNK_BYTES = 64 * 1024;\n\nfunction validateByteLimit(maxBytes: number): void {\n\tif (!Number.isSafeInteger(maxBytes) || maxBytes < 0) {\n\t\tthrow new TypeError(\"Bounded file reads require a non-negative safe-integer byte limit.\");\n\t}\n}\n\n/** Compare the filesystem identity and mutation-sensitive metadata captured around a bounded read. */\nexport function sameFileVersion(left: Stats, right: Stats): boolean {\n\treturn (\n\t\tleft.dev === right.dev &&\n\t\tleft.ino === right.ino &&\n\t\tleft.size === right.size &&\n\t\tleft.mtimeMs === right.mtimeMs &&\n\t\tleft.ctimeMs === right.ctimeMs\n\t);\n}\n\nasync function readFileHandleBounded(fileHandle: FileHandle, maxBytes: number): Promise<Buffer | undefined> {\n\tvalidateByteLimit(maxBytes);\n\tconst chunks: Buffer[] = [];\n\tlet totalBytes = 0;\n\twhile (totalBytes < maxBytes) {\n\t\tconst chunk = Buffer.allocUnsafe(Math.min(READ_CHUNK_BYTES, maxBytes - totalBytes));\n\t\tconst { bytesRead } = await fileHandle.read(chunk, 0, chunk.length, totalBytes);\n\t\tif (bytesRead === 0) return Buffer.concat(chunks, totalBytes);\n\t\tchunks.push(chunk.subarray(0, bytesRead));\n\t\ttotalBytes += bytesRead;\n\t}\n\tconst overflowProbe = Buffer.allocUnsafe(1);\n\tif ((await fileHandle.read(overflowProbe, 0, 1, totalBytes)).bytesRead > 0) return undefined;\n\treturn Buffer.concat(chunks, totalBytes);\n}\n\n/** Read at most `maxBytes`, then probe one byte so a growing file cannot escape the bound. */\nexport function readFileDescriptorBoundedSync(fileDescriptor: number, maxBytes: number): Buffer | undefined {\n\tvalidateByteLimit(maxBytes);\n\tconst chunks: Buffer[] = [];\n\tlet totalBytes = 0;\n\twhile (totalBytes < maxBytes) {\n\t\tconst chunk = Buffer.allocUnsafe(Math.min(READ_CHUNK_BYTES, maxBytes - totalBytes));\n\t\tconst bytesRead = readSync(fileDescriptor, chunk, 0, chunk.length, null);\n\t\tif (bytesRead === 0) return Buffer.concat(chunks, totalBytes);\n\t\tchunks.push(chunk.subarray(0, bytesRead));\n\t\ttotalBytes += bytesRead;\n\t}\n\tconst overflowProbe = Buffer.allocUnsafe(1);\n\tif (readSync(fileDescriptor, overflowProbe, 0, 1, null) > 0) return undefined;\n\treturn Buffer.concat(chunks, totalBytes);\n}\n\n/** Bounded, version-stable text read for small durable state files. */\nexport function readBoundedTextFileSync(filePath: string, maxBytes: number, label: string): string {\n\tvalidateByteLimit(maxBytes);\n\tconst fileDescriptor = openSync(filePath, \"r\");\n\ttry {\n\t\tconst before = fstatSync(fileDescriptor);\n\t\tif (!before.isFile()) throw new Error(`${label} is not a regular file.`);\n\t\tif (before.size > maxBytes) throw new Error(`${label} exceeds its byte limit.`);\n\t\tconst content = readFileDescriptorBoundedSync(fileDescriptor, maxBytes);\n\t\tif (!content) throw new Error(`${label} exceeds its byte limit.`);\n\t\tconst after = fstatSync(fileDescriptor);\n\t\tif (!sameFileVersion(before, after) || content.byteLength !== before.size) {\n\t\t\tthrow new Error(`${label} changed while it was being read.`);\n\t\t}\n\t\treturn content.toString(\"utf-8\");\n\t} finally {\n\t\tcloseSync(fileDescriptor);\n\t}\n}\n\n/**\n * Enumerate a managed directory incrementally. Unlike `readdirSync`, this never allocates an\n * unbounded entry array before the caller can reject a corrupt or hostile directory.\n */\nexport function readBoundedDirectoryNamesSync(directoryPath: string, maxEntries: number, label: string): string[] {\n\tif (!Number.isSafeInteger(maxEntries) || maxEntries < 1) {\n\t\tthrow new TypeError(\"Bounded directory reads require a positive safe-integer entry limit.\");\n\t}\n\tconst directory = opendirSync(directoryPath);\n\ttry {\n\t\tconst names: string[] = [];\n\t\tfor (let entry = directory.readSync(); entry; entry = directory.readSync()) {\n\t\t\tif (names.length === maxEntries) throw new Error(`${label} exceeds its entry limit.`);\n\t\t\tnames.push(entry.name);\n\t\t}\n\t\treturn names;\n\t} finally {\n\t\tdirectory.closeSync();\n\t}\n}\n\n/** Async counterpart of {@link readBoundedTextFileSync}. */\nexport async function readBoundedTextFile(filePath: string, maxBytes: number, label: string): Promise<string> {\n\tvalidateByteLimit(maxBytes);\n\tconst fileHandle = await openAsync(filePath, \"r\");\n\ttry {\n\t\tconst before = await fileHandle.stat();\n\t\tif (!before.isFile()) throw new Error(`${label} is not a regular file.`);\n\t\tif (before.size > maxBytes) throw new Error(`${label} exceeds its byte limit.`);\n\t\tconst content = await readFileHandleBounded(fileHandle, maxBytes);\n\t\tif (!content) throw new Error(`${label} exceeds its byte limit.`);\n\t\tconst after = await fileHandle.stat();\n\t\tif (!sameFileVersion(before, after) || content.byteLength !== before.size) {\n\t\t\tthrow new Error(`${label} changed while it was being read.`);\n\t\t}\n\t\treturn content.toString(\"utf-8\");\n\t} finally {\n\t\tawait fileHandle.close();\n\t}\n}\n"]}
1
+ {"version":3,"file":"bounded-file.js","sourceRoot":"","sources":["../../../src/core/util/bounded-file.ts"],"names":[],"mappings":"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","sourcesContent":["import { closeSync, fstatSync, opendirSync, openSync, readSync, type Stats } from \"node:fs\";\nimport { type FileHandle, open as openAsync } from \"node:fs/promises\";\n\nconst READ_CHUNK_BYTES = 64 * 1024;\n\nfunction validateByteLimit(maxBytes: number): void {\n\tif (!Number.isSafeInteger(maxBytes) || maxBytes < 0) {\n\t\tthrow new TypeError(\"Bounded file reads require a non-negative safe-integer byte limit.\");\n\t}\n}\n\n/** Compare the filesystem identity and mutation-sensitive metadata captured around a bounded read. */\nexport function sameFileVersion(left: Stats, right: Stats): boolean {\n\treturn (\n\t\tleft.dev === right.dev &&\n\t\tleft.ino === right.ino &&\n\t\tleft.size === right.size &&\n\t\tleft.mtimeMs === right.mtimeMs &&\n\t\tleft.ctimeMs === right.ctimeMs\n\t);\n}\n\nasync function readFileHandleBounded(fileHandle: FileHandle, maxBytes: number): Promise<Buffer | undefined> {\n\tvalidateByteLimit(maxBytes);\n\tconst chunks: Buffer[] = [];\n\tlet totalBytes = 0;\n\twhile (totalBytes < maxBytes) {\n\t\tconst chunk = Buffer.allocUnsafe(Math.min(READ_CHUNK_BYTES, maxBytes - totalBytes));\n\t\tconst { bytesRead } = await fileHandle.read(chunk, 0, chunk.length, totalBytes);\n\t\tif (bytesRead === 0) return Buffer.concat(chunks, totalBytes);\n\t\tchunks.push(chunk.subarray(0, bytesRead));\n\t\ttotalBytes += bytesRead;\n\t}\n\tconst overflowProbe = Buffer.allocUnsafe(1);\n\tif ((await fileHandle.read(overflowProbe, 0, 1, totalBytes)).bytesRead > 0) return undefined;\n\treturn Buffer.concat(chunks, totalBytes);\n}\n\n/** Read at most `maxBytes`, then probe one byte so a growing file cannot escape the bound. */\nexport function readFileDescriptorBoundedSync(fileDescriptor: number, maxBytes: number): Buffer | undefined {\n\tvalidateByteLimit(maxBytes);\n\tconst chunks: Buffer[] = [];\n\tlet totalBytes = 0;\n\twhile (totalBytes < maxBytes) {\n\t\tconst chunk = Buffer.allocUnsafe(Math.min(READ_CHUNK_BYTES, maxBytes - totalBytes));\n\t\tconst bytesRead = readSync(fileDescriptor, chunk, 0, chunk.length, null);\n\t\tif (bytesRead === 0) return Buffer.concat(chunks, totalBytes);\n\t\tchunks.push(chunk.subarray(0, bytesRead));\n\t\ttotalBytes += bytesRead;\n\t}\n\tconst overflowProbe = Buffer.allocUnsafe(1);\n\tif (readSync(fileDescriptor, overflowProbe, 0, 1, null) > 0) return undefined;\n\treturn Buffer.concat(chunks, totalBytes);\n}\n\n/** Bounded, version-stable text read for small durable state files. */\nexport function readBoundedTextFileSync(filePath: string, maxBytes: number, label: string): string {\n\tvalidateByteLimit(maxBytes);\n\tconst fileDescriptor = openSync(filePath, \"r\");\n\ttry {\n\t\tconst before = fstatSync(fileDescriptor);\n\t\tif (!before.isFile()) throw new Error(`${label} is not a regular file.`);\n\t\tif (before.size > maxBytes) throw new Error(`${label} exceeds its byte limit.`);\n\t\tconst content = readFileDescriptorBoundedSync(fileDescriptor, maxBytes);\n\t\tif (!content) throw new Error(`${label} exceeds its byte limit.`);\n\t\tconst after = fstatSync(fileDescriptor);\n\t\tif (!sameFileVersion(before, after) || content.byteLength !== before.size) {\n\t\t\tthrow new Error(`${label} changed while it was being read.`);\n\t\t}\n\t\treturn content.toString(\"utf-8\");\n\t} finally {\n\t\tcloseSync(fileDescriptor);\n\t}\n}\n\n/**\n * Enumerate a managed directory incrementally. Unlike `readdirSync`, this never allocates an\n * unbounded entry array before the caller can reject a corrupt or hostile directory.\n */\nexport function readBoundedDirectoryNamesSync(directoryPath: string, maxEntries: number, label: string): string[] {\n\tif (!Number.isSafeInteger(maxEntries) || maxEntries < 1) {\n\t\tthrow new TypeError(\"Bounded directory reads require a positive safe-integer entry limit.\");\n\t}\n\tconst directory = opendirSync(directoryPath);\n\ttry {\n\t\tconst names: string[] = [];\n\t\tfor (let entry = directory.readSync(); entry; entry = directory.readSync()) {\n\t\t\tif (names.length === maxEntries) throw new Error(`${label} exceeds its entry limit.`);\n\t\t\tnames.push(entry.name);\n\t\t}\n\t\treturn names;\n\t} finally {\n\t\tdirectory.closeSync();\n\t}\n}\n\n/** Async counterpart of {@link readBoundedTextFileSync}. */\nexport async function readBoundedTextFile(filePath: string, maxBytes: number, label: string): Promise<string> {\n\tvalidateByteLimit(maxBytes);\n\tconst fileHandle = await openAsync(filePath, \"r\");\n\ttry {\n\t\tconst before = await fileHandle.stat();\n\t\tif (!before.isFile()) throw new Error(`${label} is not a regular file.`);\n\t\tif (before.size > maxBytes) throw new Error(`${label} exceeds its byte limit.`);\n\t\tconst content = await readFileHandleBounded(fileHandle, maxBytes);\n\t\tif (!content) throw new Error(`${label} exceeds its byte limit.`);\n\t\tconst after = await fileHandle.stat();\n\t\tif (!sameFileVersion(before, after) || content.byteLength !== before.size) {\n\t\t\tthrow new Error(`${label} changed while it was being read.`);\n\t\t}\n\t\treturn content.toString(\"utf-8\");\n\t} finally {\n\t\tawait fileHandle.close();\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"bounded-jsonl.d.ts","sourceRoot":"","sources":["../../../src/core/util/bounded-jsonl.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,kBAAkB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACnB;AA6GD,+FAA+F;AAC/F,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,kBAAkB,GAAG,IAAI,CAgC5G;AAED,8DAA8D;AAC9D,wBAAsB,qBAAqB,CAC1C,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,kBAAkB,GACxB,OAAO,CAAC,IAAI,CAAC,CA2Cf","sourcesContent":["import { appendFileSync, promises as fsPromises, type Stats, statSync } from \"node:fs\";\nimport { withFileLock, withFileLockSync, writeFileAtomic, writeFileAtomicSync } from \"./atomic-file.ts\";\nimport { readBoundedTextFile, readBoundedTextFileSync } from \"./bounded-file.ts\";\n\nexport interface BoundedJsonlLimits {\n\tmaxBytes: number;\n\ttargetBytes: number;\n\tmaxRecords: number;\n}\n\nconst asyncAppendTails = new Map<string, Promise<void>>();\nconst MAX_CACHED_FILES = 128;\n\ninterface JsonlFileState {\n\tstats: Stats;\n\trecordCount: number;\n}\n\nconst fileStates = new Map<string, JsonlFileState>();\n\nfunction sameFileState(left: Stats, right: Stats): boolean {\n\treturn (\n\t\tleft.dev === right.dev &&\n\t\tleft.ino === right.ino &&\n\t\tleft.size === right.size &&\n\t\tleft.mtimeMs === right.mtimeMs &&\n\t\tleft.ctimeMs === right.ctimeMs\n\t);\n}\n\nfunction cachedRecordCount(filePath: string, stats: Stats): number | undefined {\n\tconst cached = fileStates.get(filePath);\n\tif (!cached || !sameFileState(cached.stats, stats)) return undefined;\n\tfileStates.delete(filePath);\n\tfileStates.set(filePath, cached);\n\treturn cached.recordCount;\n}\n\nfunction rememberFileState(filePath: string, stats: Stats, recordCount: number): void {\n\tfileStates.delete(filePath);\n\tfileStates.set(filePath, { stats, recordCount });\n\twhile (fileStates.size > MAX_CACHED_FILES) {\n\t\tconst oldest = fileStates.keys().next().value;\n\t\tif (oldest === undefined) break;\n\t\tfileStates.delete(oldest);\n\t}\n}\n\nfunction recordCount(content: string): number {\n\tlet count = 0;\n\tfor (const line of content.split(\"\\n\")) {\n\t\tif (line.trim().length > 0) count++;\n\t}\n\treturn count;\n}\n\nfunction validateLimits(limits: BoundedJsonlLimits): void {\n\tif (\n\t\t!Number.isSafeInteger(limits.maxBytes) ||\n\t\t!Number.isSafeInteger(limits.targetBytes) ||\n\t\t!Number.isSafeInteger(limits.maxRecords) ||\n\t\tlimits.maxBytes <= 0 ||\n\t\tlimits.targetBytes <= 0 ||\n\t\tlimits.targetBytes > limits.maxBytes ||\n\t\tlimits.maxRecords <= 0\n\t) {\n\t\tthrow new TypeError(\"Bounded JSONL limits require positive integers and targetBytes <= maxBytes.\");\n\t}\n}\n\nfunction retainedContent(content: string, limits: BoundedJsonlLimits): string {\n\tconst lines = content.split(\"\\n\").filter((line) => line.trim().length > 0);\n\tconst retained: string[] = [];\n\tlet retainedBytes = 0;\n\tfor (let index = lines.length - 1; index >= 0 && retained.length < limits.maxRecords; index--) {\n\t\tconst line = lines[index]!;\n\t\tconst lineBytes = Buffer.byteLength(line, \"utf-8\") + 1;\n\t\tif (lineBytes > limits.maxBytes) continue;\n\t\tif (retained.length > 0 && retainedBytes + lineBytes > limits.targetBytes) break;\n\t\tretained.push(line);\n\t\tretainedBytes += lineBytes;\n\t\tif (retainedBytes >= limits.targetBytes) break;\n\t}\n\tretained.reverse();\n\treturn retained.length > 0 ? `${retained.join(\"\\n\")}\\n` : \"\";\n}\n\nfunction serializeLine(value: unknown): string {\n\tconst encoded = JSON.stringify(value);\n\tif (encoded === undefined) throw new TypeError(\"Bounded JSONL records must be JSON-serializable values.\");\n\treturn `${encoded}\\n`;\n}\n\nfunction assertLineFits(line: string, limits: BoundedJsonlLimits): number {\n\tconst bytes = Buffer.byteLength(line, \"utf-8\");\n\tif (bytes > limits.maxBytes) throw new Error(\"Bounded JSONL record exceeds maxBytes.\");\n\treturn bytes;\n}\n\nfunction existingStatsSync(filePath: string): Stats | undefined {\n\ttry {\n\t\treturn statSync(filePath);\n\t} catch (error) {\n\t\tif (typeof error === \"object\" && error !== null && \"code\" in error && error.code === \"ENOENT\") return undefined;\n\t\tthrow error;\n\t}\n}\n\nasync function existingStats(filePath: string): Promise<Stats | undefined> {\n\ttry {\n\t\treturn await fsPromises.stat(filePath);\n\t} catch (error) {\n\t\tif (typeof error === \"object\" && error !== null && \"code\" in error && error.code === \"ENOENT\") return undefined;\n\t\tthrow error;\n\t}\n}\n\n/** Append one JSON record and rotate to the newest low-water tail under one exclusive lock. */\nexport function appendBoundedJsonLineSync(filePath: string, value: unknown, limits: BoundedJsonlLimits): void {\n\tvalidateLimits(limits);\n\tconst line = serializeLine(value);\n\tconst lineBytes = assertLineFits(line, limits);\n\twithFileLockSync(filePath, () => {\n\t\ttry {\n\t\t\tconst before = existingStatsSync(filePath);\n\t\t\tif (!before || before.size > limits.maxBytes) {\n\t\t\t\twriteFileAtomicSync(filePath, line);\n\t\t\t\trememberFileState(filePath, statSync(filePath), 1);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tlet content: string | undefined;\n\t\t\tlet count = cachedRecordCount(filePath, before);\n\t\t\tif (count === undefined) {\n\t\t\t\tcontent = readBoundedTextFileSync(filePath, limits.maxBytes, \"Bounded JSONL file\");\n\t\t\t\tcount = recordCount(content);\n\t\t\t}\n\t\t\tif (before.size + lineBytes <= limits.maxBytes && count + 1 <= limits.maxRecords) {\n\t\t\t\tappendFileSync(filePath, line, \"utf-8\");\n\t\t\t\trememberFileState(filePath, statSync(filePath), count + 1);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcontent ??= readBoundedTextFileSync(filePath, limits.maxBytes, \"Bounded JSONL file\");\n\t\t\tconst retained = retainedContent(`${content}${line}`, limits);\n\t\t\twriteFileAtomicSync(filePath, retained);\n\t\t\trememberFileState(filePath, statSync(filePath), recordCount(retained));\n\t\t} catch (error) {\n\t\t\tfileStates.delete(filePath);\n\t\t\tthrow error;\n\t\t}\n\t});\n}\n\n/** Async counterpart of {@link appendBoundedJsonLineSync}. */\nexport async function appendBoundedJsonLine(\n\tfilePath: string,\n\tvalue: unknown,\n\tlimits: BoundedJsonlLimits,\n): Promise<void> {\n\tvalidateLimits(limits);\n\tconst line = serializeLine(value);\n\tconst lineBytes = assertLineFits(line, limits);\n\tconst previous = asyncAppendTails.get(filePath) ?? Promise.resolve();\n\tconst operation = previous\n\t\t.catch(() => undefined)\n\t\t.then(async () => {\n\t\t\tawait withFileLock(filePath, async () => {\n\t\t\t\ttry {\n\t\t\t\t\tconst before = await existingStats(filePath);\n\t\t\t\t\tif (!before || before.size > limits.maxBytes) {\n\t\t\t\t\t\tawait writeFileAtomic(filePath, line);\n\t\t\t\t\t\trememberFileState(filePath, await fsPromises.stat(filePath), 1);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tlet content: string | undefined;\n\t\t\t\t\tlet count = cachedRecordCount(filePath, before);\n\t\t\t\t\tif (count === undefined) {\n\t\t\t\t\t\tcontent = await readBoundedTextFile(filePath, limits.maxBytes, \"Bounded JSONL file\");\n\t\t\t\t\t\tcount = recordCount(content);\n\t\t\t\t\t}\n\t\t\t\t\tif (before.size + lineBytes <= limits.maxBytes && count + 1 <= limits.maxRecords) {\n\t\t\t\t\t\tawait fsPromises.appendFile(filePath, line, \"utf-8\");\n\t\t\t\t\t\trememberFileState(filePath, await fsPromises.stat(filePath), count + 1);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tcontent ??= await readBoundedTextFile(filePath, limits.maxBytes, \"Bounded JSONL file\");\n\t\t\t\t\tconst retained = retainedContent(`${content}${line}`, limits);\n\t\t\t\t\tawait writeFileAtomic(filePath, retained);\n\t\t\t\t\trememberFileState(filePath, await fsPromises.stat(filePath), recordCount(retained));\n\t\t\t\t} catch (error) {\n\t\t\t\t\tfileStates.delete(filePath);\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\tasyncAppendTails.set(filePath, operation);\n\ttry {\n\t\tawait operation;\n\t} finally {\n\t\tif (asyncAppendTails.get(filePath) === operation) asyncAppendTails.delete(filePath);\n\t}\n}\n"]}
1
+ {"version":3,"file":"bounded-jsonl.d.ts","sourceRoot":"","sources":["../../../src/core/util/bounded-jsonl.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,kBAAkB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACnB;AAmGD,+FAA+F;AAC/F,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,kBAAkB,GAAG,IAAI,CAgC5G;AAED,8DAA8D;AAC9D,wBAAsB,qBAAqB,CAC1C,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,kBAAkB,GACxB,OAAO,CAAC,IAAI,CAAC,CA2Cf"}
@@ -1,19 +1,12 @@
1
1
  import { appendFileSync, promises as fsPromises, statSync } from "node:fs";
2
2
  import { withFileLock, withFileLockSync, writeFileAtomic, writeFileAtomicSync } from "./atomic-file.js";
3
- import { readBoundedTextFile, readBoundedTextFileSync } from "./bounded-file.js";
3
+ import { readBoundedTextFile, readBoundedTextFileSync, sameFileVersion } from "./bounded-file.js";
4
4
  const asyncAppendTails = new Map();
5
5
  const MAX_CACHED_FILES = 128;
6
6
  const fileStates = new Map();
7
- function sameFileState(left, right) {
8
- return (left.dev === right.dev &&
9
- left.ino === right.ino &&
10
- left.size === right.size &&
11
- left.mtimeMs === right.mtimeMs &&
12
- left.ctimeMs === right.ctimeMs);
13
- }
14
7
  function cachedRecordCount(filePath, stats) {
15
8
  const cached = fileStates.get(filePath);
16
- if (!cached || !sameFileState(cached.stats, stats))
9
+ if (!cached || !sameFileVersion(cached.stats, stats))
17
10
  return undefined;
18
11
  fileStates.delete(filePath);
19
12
  fileStates.set(filePath, cached);