@caupulican/pi-adaptative 0.81.40 → 0.81.41

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 (406) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts.map +1 -1
  3. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js +1 -0
  4. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js.map +1 -1
  5. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.ts +1 -0
  6. package/dist/cli/args.d.ts +2 -0
  7. package/dist/cli/args.d.ts.map +1 -1
  8. package/dist/cli/args.js +22 -1
  9. package/dist/cli/args.js.map +1 -1
  10. package/dist/core/agent-paths.d.ts +6 -0
  11. package/dist/core/agent-paths.d.ts.map +1 -1
  12. package/dist/core/agent-paths.js +12 -0
  13. package/dist/core/agent-paths.js.map +1 -1
  14. package/dist/core/agent-session-contracts.d.ts +293 -0
  15. package/dist/core/agent-session-contracts.d.ts.map +1 -0
  16. package/dist/core/agent-session-contracts.js +26 -0
  17. package/dist/core/agent-session-contracts.js.map +1 -0
  18. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  19. package/dist/core/agent-session-runtime.js +3 -0
  20. package/dist/core/agent-session-runtime.js.map +1 -1
  21. package/dist/core/agent-session.d.ts +26 -405
  22. package/dist/core/agent-session.d.ts.map +1 -1
  23. package/dist/core/agent-session.js +86 -307
  24. package/dist/core/agent-session.js.map +1 -1
  25. package/dist/core/auth-storage.d.ts.map +1 -1
  26. package/dist/core/auth-storage.js +3 -1
  27. package/dist/core/auth-storage.js.map +1 -1
  28. package/dist/core/autonomy/lane-tool-surface.d.ts.map +1 -1
  29. package/dist/core/autonomy/lane-tool-surface.js +2 -1
  30. package/dist/core/autonomy/lane-tool-surface.js.map +1 -1
  31. package/dist/core/background-lane-controller.d.ts +3 -1
  32. package/dist/core/background-lane-controller.d.ts.map +1 -1
  33. package/dist/core/background-lane-controller.js +1 -0
  34. package/dist/core/background-lane-controller.js.map +1 -1
  35. package/dist/core/bedrock-sso-login.d.ts +16 -0
  36. package/dist/core/bedrock-sso-login.d.ts.map +1 -0
  37. package/dist/core/bedrock-sso-login.js +98 -0
  38. package/dist/core/bedrock-sso-login.js.map +1 -0
  39. package/dist/core/compaction-controller.d.ts.map +1 -1
  40. package/dist/core/compaction-controller.js +1 -1
  41. package/dist/core/compaction-controller.js.map +1 -1
  42. package/dist/core/compaction-support.d.ts +3 -8
  43. package/dist/core/compaction-support.d.ts.map +1 -1
  44. package/dist/core/compaction-support.js +3 -3
  45. package/dist/core/compaction-support.js.map +1 -1
  46. package/dist/core/context-pipeline.d.ts +1 -1
  47. package/dist/core/context-pipeline.d.ts.map +1 -1
  48. package/dist/core/context-pipeline.js +7 -33
  49. package/dist/core/context-pipeline.js.map +1 -1
  50. package/dist/core/cost/cost-summary.d.ts.map +1 -1
  51. package/dist/core/cost/cost-summary.js +5 -3
  52. package/dist/core/cost/cost-summary.js.map +1 -1
  53. package/dist/core/cost/daily-usage.d.ts.map +1 -1
  54. package/dist/core/cost/daily-usage.js +4 -5
  55. package/dist/core/cost/daily-usage.js.map +1 -1
  56. package/dist/core/default-tool-surface.d.ts.map +1 -1
  57. package/dist/core/default-tool-surface.js +1 -0
  58. package/dist/core/default-tool-surface.js.map +1 -1
  59. package/dist/core/extension-import-authority.d.ts +6 -0
  60. package/dist/core/extension-import-authority.d.ts.map +1 -0
  61. package/dist/core/extension-import-authority.js +10 -0
  62. package/dist/core/extension-import-authority.js.map +1 -0
  63. package/dist/core/extensions/loader.d.ts.map +1 -1
  64. package/dist/core/extensions/loader.js +2 -3
  65. package/dist/core/extensions/loader.js.map +1 -1
  66. package/dist/core/extensions/runner.d.ts +3 -0
  67. package/dist/core/extensions/runner.d.ts.map +1 -1
  68. package/dist/core/extensions/runner.js +14 -5
  69. package/dist/core/extensions/runner.js.map +1 -1
  70. package/dist/core/extensions/stale-context.d.ts +2 -0
  71. package/dist/core/extensions/stale-context.d.ts.map +1 -0
  72. package/dist/core/extensions/stale-context.js +2 -0
  73. package/dist/core/extensions/stale-context.js.map +1 -0
  74. package/dist/core/extensions/types.d.ts +8 -0
  75. package/dist/core/extensions/types.d.ts.map +1 -1
  76. package/dist/core/extensions/types.js.map +1 -1
  77. package/dist/core/foreground-recovery-controller.d.ts +1 -0
  78. package/dist/core/foreground-recovery-controller.d.ts.map +1 -1
  79. package/dist/core/foreground-recovery-controller.js +13 -13
  80. package/dist/core/foreground-recovery-controller.js.map +1 -1
  81. package/dist/core/goal-loop-controller.d.ts +14 -9
  82. package/dist/core/goal-loop-controller.d.ts.map +1 -1
  83. package/dist/core/goal-loop-controller.js +47 -75
  84. package/dist/core/goal-loop-controller.js.map +1 -1
  85. package/dist/core/goals/compact-goal-context.d.ts +11 -0
  86. package/dist/core/goals/compact-goal-context.d.ts.map +1 -0
  87. package/dist/core/goals/compact-goal-context.js +59 -0
  88. package/dist/core/goals/compact-goal-context.js.map +1 -0
  89. package/dist/core/goals/goal-acceptance.d.ts.map +1 -1
  90. package/dist/core/goals/goal-acceptance.js +2 -0
  91. package/dist/core/goals/goal-acceptance.js.map +1 -1
  92. package/dist/core/goals/goal-auto-continue-controller.d.ts +2 -1
  93. package/dist/core/goals/goal-auto-continue-controller.d.ts.map +1 -1
  94. package/dist/core/goals/goal-auto-continue-controller.js +5 -8
  95. package/dist/core/goals/goal-auto-continue-controller.js.map +1 -1
  96. package/dist/core/goals/goal-continuation-controller.d.ts +2 -2
  97. package/dist/core/goals/goal-continuation-controller.d.ts.map +1 -1
  98. package/dist/core/goals/goal-continuation-controller.js +42 -11
  99. package/dist/core/goals/goal-continuation-controller.js.map +1 -1
  100. package/dist/core/goals/goal-continuation-defaults.d.ts +4 -29
  101. package/dist/core/goals/goal-continuation-defaults.d.ts.map +1 -1
  102. package/dist/core/goals/goal-continuation-defaults.js +4 -32
  103. package/dist/core/goals/goal-continuation-defaults.js.map +1 -1
  104. package/dist/core/goals/goal-continuation-prompt.d.ts +8 -18
  105. package/dist/core/goals/goal-continuation-prompt.d.ts.map +1 -1
  106. package/dist/core/goals/goal-continuation-prompt.js +9 -179
  107. package/dist/core/goals/goal-continuation-prompt.js.map +1 -1
  108. package/dist/core/goals/goal-lifecycle.d.ts +35 -12
  109. package/dist/core/goals/goal-lifecycle.d.ts.map +1 -1
  110. package/dist/core/goals/goal-lifecycle.js +98 -13
  111. package/dist/core/goals/goal-lifecycle.js.map +1 -1
  112. package/dist/core/goals/goal-record.d.ts +17 -0
  113. package/dist/core/goals/goal-record.d.ts.map +1 -0
  114. package/dist/core/goals/goal-record.js +31 -0
  115. package/dist/core/goals/goal-record.js.map +1 -0
  116. package/dist/core/goals/goal-session-controller.d.ts +42 -0
  117. package/dist/core/goals/goal-session-controller.d.ts.map +1 -0
  118. package/dist/core/goals/goal-session-controller.js +128 -0
  119. package/dist/core/goals/goal-session-controller.js.map +1 -0
  120. package/dist/core/goals/goal-state.d.ts +45 -25
  121. package/dist/core/goals/goal-state.d.ts.map +1 -1
  122. package/dist/core/goals/goal-state.js +85 -15
  123. package/dist/core/goals/goal-state.js.map +1 -1
  124. package/dist/core/goals/goal-tool-core.d.ts +1 -4
  125. package/dist/core/goals/goal-tool-core.d.ts.map +1 -1
  126. package/dist/core/goals/goal-tool-core.js +49 -34
  127. package/dist/core/goals/goal-tool-core.js.map +1 -1
  128. package/dist/core/goals/session-goal-state.d.ts +18 -8
  129. package/dist/core/goals/session-goal-state.d.ts.map +1 -1
  130. package/dist/core/goals/session-goal-state.js +134 -11
  131. package/dist/core/goals/session-goal-state.js.map +1 -1
  132. package/dist/core/human-input-controller.d.ts +47 -0
  133. package/dist/core/human-input-controller.d.ts.map +1 -0
  134. package/dist/core/human-input-controller.js +181 -0
  135. package/dist/core/human-input-controller.js.map +1 -0
  136. package/dist/core/local-runtime-controller.d.ts +1 -1
  137. package/dist/core/local-runtime-controller.d.ts.map +1 -1
  138. package/dist/core/local-runtime-controller.js.map +1 -1
  139. package/dist/core/model-capability.d.ts +0 -19
  140. package/dist/core/model-capability.d.ts.map +1 -1
  141. package/dist/core/model-capability.js +0 -19
  142. package/dist/core/model-capability.js.map +1 -1
  143. package/dist/core/model-registry.d.ts +6 -1
  144. package/dist/core/model-registry.d.ts.map +1 -1
  145. package/dist/core/model-registry.js +13 -5
  146. package/dist/core/model-registry.js.map +1 -1
  147. package/dist/core/model-resolver.d.ts +16 -1
  148. package/dist/core/model-resolver.d.ts.map +1 -1
  149. package/dist/core/model-resolver.js +32 -16
  150. package/dist/core/model-resolver.js.map +1 -1
  151. package/dist/core/model-router-controller.d.ts +1 -1
  152. package/dist/core/model-router-controller.d.ts.map +1 -1
  153. package/dist/core/model-router-controller.js.map +1 -1
  154. package/dist/core/model-selection-controller.d.ts +1 -1
  155. package/dist/core/model-selection-controller.d.ts.map +1 -1
  156. package/dist/core/model-selection-controller.js.map +1 -1
  157. package/dist/core/orchestration/delegation-ledger.d.ts.map +1 -1
  158. package/dist/core/orchestration/delegation-ledger.js +3 -0
  159. package/dist/core/orchestration/delegation-ledger.js.map +1 -1
  160. package/dist/core/orchestration/work-state-projection.d.ts.map +1 -1
  161. package/dist/core/orchestration/work-state-projection.js +1 -1
  162. package/dist/core/orchestration/work-state-projection.js.map +1 -1
  163. package/dist/core/package-manager.d.ts.map +1 -1
  164. package/dist/core/package-manager.js +20 -3
  165. package/dist/core/package-manager.js.map +1 -1
  166. package/dist/core/profile-filter-controller.d.ts +8 -1
  167. package/dist/core/profile-filter-controller.d.ts.map +1 -1
  168. package/dist/core/profile-filter-controller.js +23 -5
  169. package/dist/core/profile-filter-controller.js.map +1 -1
  170. package/dist/core/prompt-templates.d.ts +1 -0
  171. package/dist/core/prompt-templates.d.ts.map +1 -1
  172. package/dist/core/prompt-templates.js +18 -29
  173. package/dist/core/prompt-templates.js.map +1 -1
  174. package/dist/core/reflection-controller.d.ts +1 -1
  175. package/dist/core/reflection-controller.d.ts.map +1 -1
  176. package/dist/core/reflection-controller.js +3 -1
  177. package/dist/core/reflection-controller.js.map +1 -1
  178. package/dist/core/request-auth.d.ts +7 -0
  179. package/dist/core/request-auth.d.ts.map +1 -0
  180. package/dist/core/request-auth.js +8 -0
  181. package/dist/core/request-auth.js.map +1 -0
  182. package/dist/core/resource-loader.d.ts.map +1 -1
  183. package/dist/core/resource-loader.js +16 -6
  184. package/dist/core/resource-loader.js.map +1 -1
  185. package/dist/core/risk-classifier.d.ts.map +1 -1
  186. package/dist/core/risk-classifier.js +8 -0
  187. package/dist/core/risk-classifier.js.map +1 -1
  188. package/dist/core/runtime-builder.d.ts +15 -3
  189. package/dist/core/runtime-builder.d.ts.map +1 -1
  190. package/dist/core/runtime-builder.js +132 -79
  191. package/dist/core/runtime-builder.js.map +1 -1
  192. package/dist/core/sdk.d.ts.map +1 -1
  193. package/dist/core/sdk.js +7 -1
  194. package/dist/core/sdk.js.map +1 -1
  195. package/dist/core/secrets/credential-exposure-guard.d.ts +9 -0
  196. package/dist/core/secrets/credential-exposure-guard.d.ts.map +1 -0
  197. package/dist/core/secrets/credential-exposure-guard.js +241 -0
  198. package/dist/core/secrets/credential-exposure-guard.js.map +1 -0
  199. package/dist/core/secrets/secret-dotenv.d.ts +27 -0
  200. package/dist/core/secrets/secret-dotenv.d.ts.map +1 -0
  201. package/dist/core/secrets/secret-dotenv.js +183 -0
  202. package/dist/core/secrets/secret-dotenv.js.map +1 -0
  203. package/dist/core/secrets/secret-vault-format.d.ts +112 -0
  204. package/dist/core/secrets/secret-vault-format.d.ts.map +1 -0
  205. package/dist/core/secrets/secret-vault-format.js +397 -0
  206. package/dist/core/secrets/secret-vault-format.js.map +1 -0
  207. package/dist/core/secrets/secret-vault.d.ts +72 -0
  208. package/dist/core/secrets/secret-vault.d.ts.map +1 -0
  209. package/dist/core/secrets/secret-vault.js +671 -0
  210. package/dist/core/secrets/secret-vault.js.map +1 -0
  211. package/dist/core/session-analytics.d.ts +4 -23
  212. package/dist/core/session-analytics.d.ts.map +1 -1
  213. package/dist/core/session-analytics.js +39 -69
  214. package/dist/core/session-analytics.js.map +1 -1
  215. package/dist/core/session-role.d.ts +5 -0
  216. package/dist/core/session-role.d.ts.map +1 -1
  217. package/dist/core/session-role.js +14 -1
  218. package/dist/core/session-role.js.map +1 -1
  219. package/dist/core/session-tree-navigator.d.ts +4 -6
  220. package/dist/core/session-tree-navigator.d.ts.map +1 -1
  221. package/dist/core/session-tree-navigator.js +4 -1
  222. package/dist/core/session-tree-navigator.js.map +1 -1
  223. package/dist/core/settings-manager.d.ts +1 -1
  224. package/dist/core/settings-manager.d.ts.map +1 -1
  225. package/dist/core/settings-manager.js +1 -1
  226. package/dist/core/settings-manager.js.map +1 -1
  227. package/dist/core/slash-commands.d.ts.map +1 -1
  228. package/dist/core/slash-commands.js +2 -2
  229. package/dist/core/slash-commands.js.map +1 -1
  230. package/dist/core/tool-capability-policy.d.ts.map +1 -1
  231. package/dist/core/tool-capability-policy.js +1 -0
  232. package/dist/core/tool-capability-policy.js.map +1 -1
  233. package/dist/core/tool-gate-controller.d.ts.map +1 -1
  234. package/dist/core/tool-gate-controller.js +8 -2
  235. package/dist/core/tool-gate-controller.js.map +1 -1
  236. package/dist/core/tool-protocol-controller.d.ts +2 -4
  237. package/dist/core/tool-protocol-controller.d.ts.map +1 -1
  238. package/dist/core/tool-protocol-controller.js.map +1 -1
  239. package/dist/core/tool-recovery-stats.d.ts +21 -1
  240. package/dist/core/tool-recovery-stats.d.ts.map +1 -1
  241. package/dist/core/tool-recovery-stats.js.map +1 -1
  242. package/dist/core/tools/bash.d.ts +5 -0
  243. package/dist/core/tools/bash.d.ts.map +1 -1
  244. package/dist/core/tools/bash.js +59 -5
  245. package/dist/core/tools/bash.js.map +1 -1
  246. package/dist/core/tools/delegate-status.d.ts.map +1 -1
  247. package/dist/core/tools/delegate-status.js +6 -7
  248. package/dist/core/tools/delegate-status.js.map +1 -1
  249. package/dist/core/tools/delegate.d.ts.map +1 -1
  250. package/dist/core/tools/delegate.js +6 -8
  251. package/dist/core/tools/delegate.js.map +1 -1
  252. package/dist/core/tools/git-filter.d.ts +1 -8
  253. package/dist/core/tools/git-filter.d.ts.map +1 -1
  254. package/dist/core/tools/git-filter.js +2 -63
  255. package/dist/core/tools/git-filter.js.map +1 -1
  256. package/dist/core/tools/goal.d.ts +5 -3
  257. package/dist/core/tools/goal.d.ts.map +1 -1
  258. package/dist/core/tools/goal.js +97 -19
  259. package/dist/core/tools/goal.js.map +1 -1
  260. package/dist/core/tools/index.d.ts +1 -0
  261. package/dist/core/tools/index.d.ts.map +1 -1
  262. package/dist/core/tools/index.js +1 -0
  263. package/dist/core/tools/index.js.map +1 -1
  264. package/dist/core/tools/orchestration-panel.d.ts +1 -4
  265. package/dist/core/tools/orchestration-panel.d.ts.map +1 -1
  266. package/dist/core/tools/orchestration-panel.js +0 -44
  267. package/dist/core/tools/orchestration-panel.js.map +1 -1
  268. package/dist/core/tools/output-accumulator.d.ts +11 -0
  269. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  270. package/dist/core/tools/output-accumulator.js +36 -3
  271. package/dist/core/tools/output-accumulator.js.map +1 -1
  272. package/dist/core/tools/python.d.ts +2 -0
  273. package/dist/core/tools/python.d.ts.map +1 -1
  274. package/dist/core/tools/python.js +3 -1
  275. package/dist/core/tools/python.js.map +1 -1
  276. package/dist/core/tools/read.d.ts.map +1 -1
  277. package/dist/core/tools/read.js +1 -1
  278. package/dist/core/tools/read.js.map +1 -1
  279. package/dist/core/tools/search-command-guard.d.ts +14 -0
  280. package/dist/core/tools/search-command-guard.d.ts.map +1 -0
  281. package/dist/core/tools/search-command-guard.js +333 -0
  282. package/dist/core/tools/search-command-guard.js.map +1 -0
  283. package/dist/core/tools/secret-store.d.ts +38 -0
  284. package/dist/core/tools/secret-store.d.ts.map +1 -0
  285. package/dist/core/tools/secret-store.js +412 -0
  286. package/dist/core/tools/secret-store.js.map +1 -0
  287. package/dist/core/tools/shell-command-parser.d.ts +16 -0
  288. package/dist/core/tools/shell-command-parser.d.ts.map +1 -0
  289. package/dist/core/tools/shell-command-parser.js +113 -0
  290. package/dist/core/tools/shell-command-parser.js.map +1 -0
  291. package/dist/core/tools/task-steps.d.ts.map +1 -1
  292. package/dist/core/tools/task-steps.js +4 -7
  293. package/dist/core/tools/task-steps.js.map +1 -1
  294. package/dist/core/util/atomic-file.d.ts +6 -2
  295. package/dist/core/util/atomic-file.d.ts.map +1 -1
  296. package/dist/core/util/atomic-file.js +4 -4
  297. package/dist/core/util/atomic-file.js.map +1 -1
  298. package/dist/index.d.ts +3 -2
  299. package/dist/index.d.ts.map +1 -1
  300. package/dist/index.js +2 -1
  301. package/dist/index.js.map +1 -1
  302. package/dist/main.d.ts.map +1 -1
  303. package/dist/main.js +25 -11
  304. package/dist/main.js.map +1 -1
  305. package/dist/modes/interactive/auth-dialogs-controller.d.ts +4 -0
  306. package/dist/modes/interactive/auth-dialogs-controller.d.ts.map +1 -1
  307. package/dist/modes/interactive/auth-dialogs-controller.js +60 -1
  308. package/dist/modes/interactive/auth-dialogs-controller.js.map +1 -1
  309. package/dist/modes/interactive/components/activity-lane.d.ts +55 -0
  310. package/dist/modes/interactive/components/activity-lane.d.ts.map +1 -0
  311. package/dist/modes/interactive/components/activity-lane.js +304 -0
  312. package/dist/modes/interactive/components/activity-lane.js.map +1 -0
  313. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  314. package/dist/modes/interactive/components/assistant-message.js +19 -10
  315. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  316. package/dist/modes/interactive/components/expandable-text.d.ts +12 -0
  317. package/dist/modes/interactive/components/expandable-text.d.ts.map +1 -0
  318. package/dist/modes/interactive/components/expandable-text.js +17 -0
  319. package/dist/modes/interactive/components/expandable-text.js.map +1 -0
  320. package/dist/modes/interactive/components/extension-editor.d.ts +15 -1
  321. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  322. package/dist/modes/interactive/components/extension-editor.js +30 -21
  323. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  324. package/dist/modes/interactive/components/extension-input.d.ts +1 -0
  325. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  326. package/dist/modes/interactive/components/extension-input.js +6 -1
  327. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  328. package/dist/modes/interactive/components/scoped-models-selector.d.ts +2 -2
  329. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  330. package/dist/modes/interactive/components/scoped-models-selector.js +23 -14
  331. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  332. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  333. package/dist/modes/interactive/components/settings-selector.js +4 -4
  334. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  335. package/dist/modes/interactive/components/tool-execution.d.ts +19 -11
  336. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  337. package/dist/modes/interactive/components/tool-execution.js +53 -20
  338. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  339. package/dist/modes/interactive/components/tool-group.d.ts.map +1 -1
  340. package/dist/modes/interactive/components/tool-group.js +3 -0
  341. package/dist/modes/interactive/components/tool-group.js.map +1 -1
  342. package/dist/modes/interactive/components/usage-action-selector.d.ts +16 -0
  343. package/dist/modes/interactive/components/usage-action-selector.d.ts.map +1 -0
  344. package/dist/modes/interactive/components/usage-action-selector.js +46 -0
  345. package/dist/modes/interactive/components/usage-action-selector.js.map +1 -0
  346. package/dist/modes/interactive/extension-ui-host.d.ts.map +1 -1
  347. package/dist/modes/interactive/extension-ui-host.js +1 -0
  348. package/dist/modes/interactive/extension-ui-host.js.map +1 -1
  349. package/dist/modes/interactive/external-editor.d.ts +15 -0
  350. package/dist/modes/interactive/external-editor.d.ts.map +1 -1
  351. package/dist/modes/interactive/external-editor.js +27 -19
  352. package/dist/modes/interactive/external-editor.js.map +1 -1
  353. package/dist/modes/interactive/history-reload-math.d.ts +6 -2
  354. package/dist/modes/interactive/history-reload-math.d.ts.map +1 -1
  355. package/dist/modes/interactive/history-reload-math.js +10 -5
  356. package/dist/modes/interactive/history-reload-math.js.map +1 -1
  357. package/dist/modes/interactive/interactive-event-controller.d.ts +74 -0
  358. package/dist/modes/interactive/interactive-event-controller.d.ts.map +1 -0
  359. package/dist/modes/interactive/interactive-event-controller.js +328 -0
  360. package/dist/modes/interactive/interactive-event-controller.js.map +1 -0
  361. package/dist/modes/interactive/interactive-mode.d.ts +20 -25
  362. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  363. package/dist/modes/interactive/interactive-mode.js +196 -608
  364. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  365. package/dist/modes/interactive/loaded-resources-view.d.ts +20 -0
  366. package/dist/modes/interactive/loaded-resources-view.d.ts.map +1 -0
  367. package/dist/modes/interactive/loaded-resources-view.js +147 -0
  368. package/dist/modes/interactive/loaded-resources-view.js.map +1 -0
  369. package/dist/modes/interactive/resource-display.d.ts.map +1 -1
  370. package/dist/modes/interactive/resource-display.js +8 -2
  371. package/dist/modes/interactive/resource-display.js.map +1 -1
  372. package/dist/modes/interactive/resource-shell-commands.d.ts +1 -5
  373. package/dist/modes/interactive/resource-shell-commands.d.ts.map +1 -1
  374. package/dist/modes/interactive/resource-shell-commands.js +0 -5
  375. package/dist/modes/interactive/resource-shell-commands.js.map +1 -1
  376. package/dist/modes/interactive/session-flow-commands.d.ts +10 -6
  377. package/dist/modes/interactive/session-flow-commands.d.ts.map +1 -1
  378. package/dist/modes/interactive/session-flow-commands.js +123 -70
  379. package/dist/modes/interactive/session-flow-commands.js.map +1 -1
  380. package/dist/modes/interactive/usage-commands.d.ts +34 -0
  381. package/dist/modes/interactive/usage-commands.d.ts.map +1 -0
  382. package/dist/modes/interactive/usage-commands.js +225 -0
  383. package/dist/modes/interactive/usage-commands.js.map +1 -0
  384. package/dist/utils/shell.d.ts.map +1 -1
  385. package/dist/utils/shell.js +5 -3
  386. package/dist/utils/shell.js.map +1 -1
  387. package/dist/utils/version-check.d.ts.map +1 -1
  388. package/dist/utils/version-check.js +3 -1
  389. package/dist/utils/version-check.js.map +1 -1
  390. package/docs/UI_POLISH_ORCHESTRATION.md +25 -31
  391. package/docs/UI_QUALITY_ORCHESTRATION.md +22 -24
  392. package/docs/providers.md +9 -1
  393. package/docs/ui-reference/README.md +6 -6
  394. package/docs/ui-reference/orchestration-after.txt +14 -7
  395. package/docs/ui-reference/orchestration-before.txt +12 -6
  396. package/docs/ui-reference/orchestration-reference.txt +15 -5
  397. package/docs/usage.md +9 -1
  398. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  399. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  400. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  401. package/examples/extensions/sandbox/package-lock.json +2 -2
  402. package/examples/extensions/sandbox/package.json +1 -1
  403. package/examples/extensions/with-deps/package-lock.json +2 -2
  404. package/examples/extensions/with-deps/package.json +1 -1
  405. package/npm-shrinkwrap.json +13 -13
  406. package/package.json +4 -4
@@ -0,0 +1,72 @@
1
+ import { type SecretBindingResolution, type SecretEnvDestinationState, type SecretMaterializationResult, type SecretProfileSummary, type SecretRemovalResult, type SecretVariableValue, type SecretVaultOptions } from "./secret-vault-format.ts";
2
+ export type { SecretBindingResolution, SecretBindingSummary, SecretEnvDestinationState, SecretMaterializationResult, SecretProfileSummary, SecretRemovalResult, SecretVariableValue, SecretVaultErrorCode, SecretVaultOptions, } from "./secret-vault-format.ts";
3
+ export { MAX_BINDINGS_PER_PROFILE, MAX_VARIABLES_PER_PROFILE, SECRET_DESCRIPTION_MAX_CHARS, SECRET_PRINTABLE_METADATA_PATTERN, SECRET_PROFILE_ID_MAX_CHARS, SECRET_PROFILE_ID_PATTERN, SECRET_VARIABLE_NAME_MAX_CHARS, SECRET_VARIABLE_NAME_PATTERN, SecretVaultError, } from "./secret-vault-format.ts";
4
+ /**
5
+ * Encrypted generic credential vault. Only the derived key is retained in memory, until this
6
+ * process explicitly locks the vault or exits. The native model-facing tool receives summaries,
7
+ * never decrypted values or materialization paths.
8
+ */
9
+ export declare class SecretVault {
10
+ readonly vaultPath: string;
11
+ readonly materializedDir: string;
12
+ private readonly rootDir;
13
+ private readonly scryptN;
14
+ private readonly now;
15
+ private readonly onEnvironmentChanged;
16
+ private cachedKey;
17
+ private cachedKdf;
18
+ private cachedProfiles;
19
+ private readonly activeProfilesByWorkspace;
20
+ constructor(options: SecretVaultOptions);
21
+ static forAgentDir(agentDir: string): SecretVault;
22
+ get isUnlocked(): boolean;
23
+ exists(): Promise<boolean>;
24
+ lock(): void;
25
+ /** Environment for the nearest explicitly activated profile covering cwd. */
26
+ getEnvironmentForCwd(cwd: string): NodeJS.ProcessEnv;
27
+ hasEnvironmentForCwd(cwd: string): boolean;
28
+ /** Remove exact unlocked vault values and high-confidence credential shapes from model-facing text. */
29
+ redactSensitiveText(text: string): string;
30
+ initialize(passphrase: string): Promise<void>;
31
+ unlock(passphrase: string): Promise<void>;
32
+ listProfiles(): Promise<SecretProfileSummary[]>;
33
+ upsertProfile(profile: string, description: string | undefined, values: readonly SecretVariableValue[]): Promise<SecretProfileSummary>;
34
+ replaceProfileDocument(profile: string, description: string | undefined, document: string, binding?: {
35
+ workspace: string;
36
+ envFile: string;
37
+ }): Promise<SecretProfileSummary>;
38
+ getProfileDocument(profile: string): Promise<string | undefined>;
39
+ readOwnerDotenv(destination: string): Promise<string>;
40
+ removeProfile(profile: string, variableNames?: readonly string[]): Promise<SecretRemovalResult>;
41
+ getManagedEnvPath(profile: string): string;
42
+ resolveBindingTarget(workspace: string, envFile: string): {
43
+ workspace: string;
44
+ envFile: string;
45
+ destination: string;
46
+ };
47
+ resolveBindingForWorkspace(cwd: string, profile?: string): Promise<SecretBindingResolution>;
48
+ inspectEnvDestination(destination: string, profile: string): Promise<SecretEnvDestinationState>;
49
+ materializeEnv(profile: string, destination: string, options?: {
50
+ activationWorkspace?: string;
51
+ allowReplaceUnmanaged?: boolean;
52
+ expectedUnmanagedContent?: string;
53
+ managed?: boolean;
54
+ }): Promise<SecretMaterializationResult>;
55
+ private storeProfileDocument;
56
+ private assertReplaceableDestination;
57
+ private assertBoundDestinationParent;
58
+ private assertDestination;
59
+ private replaceCachedKey;
60
+ private clearSecretCache;
61
+ private deactivateProfile;
62
+ private notifyEnvironmentChanged;
63
+ private activeEnvironmentFingerprint;
64
+ private refreshSecretCache;
65
+ private resolveCachedProfile;
66
+ private requireUnlocked;
67
+ private withPayload;
68
+ private writeEnvelope;
69
+ private removeBoundMaterializations;
70
+ private removeManagedMaterialization;
71
+ }
72
+ //# sourceMappingURL=secret-vault.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secret-vault.d.ts","sourceRoot":"","sources":["../../../src/core/secrets/secret-vault.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { constants, promises as fs, type Stats } from \"node:fs\";\nimport { dirname, isAbsolute, join, relative, resolve, sep } from \"node:path\";\nimport { managedSecretEnvDir, secretsDir, secretVaultFile } from \"../agent-paths.ts\";\nimport { redactKnownSecrets } from \"../security/secret-text.ts\";\nimport { withFileLock, writeFileAtomic } from \"../util/atomic-file.ts\";\nimport { MAX_DOTENV_DOCUMENT_BYTES, parseDotenvDocument } from \"./secret-dotenv.ts\";\nimport {\n\tassertPassphrase,\n\tcreateVaultKdf,\n\tDEFAULT_SCRYPT_N,\n\tdecryptPayload,\n\tderiveKey,\n\tMANAGED_ENV_HEADER_PREFIX,\n\tMAX_BINDINGS_PER_PROFILE,\n\tMAX_PROFILES,\n\tMAX_VARIABLES_PER_PROFILE,\n\tMAX_VAULT_FILE_BYTES,\n\tparseEnvelope,\n\tprofileSummary,\n\ttype SecretBindingResolution,\n\ttype SecretBindingSummary,\n\ttype SecretEnvDestinationState,\n\ttype SecretMaterializationResult,\n\ttype SecretProfileSummary,\n\ttype SecretRemovalResult,\n\ttype SecretVariableValue,\n\tSecretVaultError,\n\ttype SecretVaultOptions,\n\tsameKdf,\n\tscrubPayload,\n\tserializeEnvelope,\n\tserializeVariableValues,\n\tVAULT_MARKER,\n\ttype VaultKdf,\n\ttype VaultPayload,\n\tvalidateBindingEnvFile,\n\tvalidateBindingWorkspace,\n\tvalidateDescription,\n\tvalidateDotenvProfileDocument,\n\tvalidateProfileId,\n\tvalidateScryptN,\n\tvalidateSecretValue,\n\tvalidateVariableName,\n} from \"./secret-vault-format.ts\";\n\nexport type {\n\tSecretBindingResolution,\n\tSecretBindingSummary,\n\tSecretEnvDestinationState,\n\tSecretMaterializationResult,\n\tSecretProfileSummary,\n\tSecretRemovalResult,\n\tSecretVariableValue,\n\tSecretVaultErrorCode,\n\tSecretVaultOptions,\n} from \"./secret-vault-format.ts\";\nexport {\n\tMAX_BINDINGS_PER_PROFILE,\n\tMAX_VARIABLES_PER_PROFILE,\n\tSECRET_DESCRIPTION_MAX_CHARS,\n\tSECRET_PRINTABLE_METADATA_PATTERN,\n\tSECRET_PROFILE_ID_MAX_CHARS,\n\tSECRET_PROFILE_ID_PATTERN,\n\tSECRET_VARIABLE_NAME_MAX_CHARS,\n\tSECRET_VARIABLE_NAME_PATTERN,\n\tSecretVaultError,\n} from \"./secret-vault-format.ts\";\n\nfunction nodeErrorCode(error: unknown): string | undefined {\n\treturn typeof error === \"object\" && error !== null && \"code\" in error && typeof error.code === \"string\"\n\t\t? error.code\n\t\t: undefined;\n}\n\nasync function lstatIfExists(path: string): Promise<Stats | undefined> {\n\ttry {\n\t\treturn await fs.lstat(path);\n\t} catch (error) {\n\t\tif (nodeErrorCode(error) === \"ENOENT\") return undefined;\n\t\tthrow error;\n\t}\n}\n\nasync function readBoundedRegularFile(\n\tfilePath: string,\n\tmaxBytes: number,\n\tlabel: \"Secret vault\" | \"Dotenv file\",\n): Promise<string> {\n\tconst before = await fs.lstat(filePath);\n\tif (before.isSymbolicLink()) throw new SecretVaultError(\"symlink_refused\", `${label} symlinks are refused.`);\n\tif (!before.isFile()) {\n\t\tthrow new SecretVaultError(\n\t\t\tlabel === \"Secret vault\" ? \"vault_corrupt\" : \"destination_invalid\",\n\t\t\t`${label} path is not a regular file.`,\n\t\t);\n\t}\n\tif (before.size > maxBytes) {\n\t\tthrow new SecretVaultError(\n\t\t\tlabel === \"Secret vault\" ? \"vault_too_large\" : \"invalid_dotenv\",\n\t\t\t`${label} exceeds its ${label === \"Secret vault\" ? \"4 MiB\" : \"512 KiB\"} limit.`,\n\t\t);\n\t}\n\tconst handle = await fs.open(filePath, constants.O_RDONLY);\n\ttry {\n\t\tconst opened = await handle.stat();\n\t\tif ((before.dev !== opened.dev || before.ino !== opened.ino) && before.ino !== 0 && opened.ino !== 0) {\n\t\t\tthrow new SecretVaultError(\"symlink_refused\", \"Secret vault changed while it was being opened.\");\n\t\t}\n\t\tconst output = Buffer.alloc(Math.min(maxBytes + 1, before.size + 1));\n\t\tlet offset = 0;\n\t\twhile (offset < output.byteLength) {\n\t\t\tconst { bytesRead } = await handle.read(output, offset, output.byteLength - offset, null);\n\t\t\tif (bytesRead === 0) break;\n\t\t\toffset += bytesRead;\n\t\t}\n\t\tif (offset > before.size || offset > maxBytes) {\n\t\t\toutput.fill(0);\n\t\t\tthrow new SecretVaultError(\n\t\t\t\tlabel === \"Secret vault\" ? \"vault_too_large\" : \"invalid_dotenv\",\n\t\t\t\t`${label} grew beyond its limit while being read.`,\n\t\t\t);\n\t\t}\n\t\tconst text = output.toString(\"utf8\", 0, offset);\n\t\toutput.fill(0);\n\t\treturn text;\n\t} finally {\n\t\tawait handle.close();\n\t}\n}\n\nasync function readBoundedFile(filePath: string): Promise<string> {\n\treturn readBoundedRegularFile(filePath, MAX_VAULT_FILE_BYTES, \"Secret vault\");\n}\n\nasync function readFilePrefix(filePath: string, maxBytes: number): Promise<string> {\n\tconst handle = await fs.open(filePath, constants.O_RDONLY);\n\ttry {\n\t\tconst output = Buffer.alloc(maxBytes);\n\t\tconst { bytesRead } = await handle.read(output, 0, output.byteLength, 0);\n\t\tconst text = output.toString(\"utf8\", 0, bytesRead);\n\t\toutput.fill(0);\n\t\treturn text;\n\t} finally {\n\t\tawait handle.close();\n\t}\n}\n\nasync function ensurePrivateDirectory(path: string): Promise<void> {\n\tconst existing = await lstatIfExists(path);\n\tif (existing?.isSymbolicLink()) {\n\t\tthrow new SecretVaultError(\"symlink_refused\", \"Secret storage directory symlinks are refused.\");\n\t}\n\tif (existing && !existing.isDirectory()) {\n\t\tthrow new SecretVaultError(\"destination_invalid\", \"Secret storage path is not a directory.\");\n\t}\n\tawait fs.mkdir(path, { recursive: true, mode: 0o700 });\n\tif (process.platform !== \"win32\") await fs.chmod(path, 0o700);\n}\n\nasync function enforcePrivateFileMode(path: string): Promise<void> {\n\tif (process.platform !== \"win32\") await fs.chmod(path, 0o600);\n}\n\ninterface CachedSecretVariable {\n\tname: string;\n\tvalue: string;\n}\n\ninterface CachedSecretProfile {\n\tprofile: string;\n\tbindings: SecretBindingSummary[];\n\tvariables: CachedSecretVariable[];\n}\n\nfunction isPathInside(root: string, target: string): boolean {\n\tconst fromRoot = relative(root, target);\n\treturn fromRoot === \"\" || (!fromRoot.startsWith(`..${sep}`) && fromRoot !== \"..\" && !isAbsolute(fromRoot));\n}\n\nfunction escapeRegExp(value: string): string {\n\treturn value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\n/**\n * Encrypted generic credential vault. Only the derived key is retained in memory, until this\n * process explicitly locks the vault or exits. The native model-facing tool receives summaries,\n * never decrypted values or materialization paths.\n */\nexport class SecretVault {\n\treadonly vaultPath: string;\n\treadonly materializedDir: string;\n\tprivate readonly rootDir: string;\n\tprivate readonly scryptN: number;\n\tprivate readonly now: () => Date;\n\tprivate readonly onEnvironmentChanged: (() => void) | undefined;\n\tprivate cachedKey: Buffer | undefined;\n\tprivate cachedKdf: VaultKdf | undefined;\n\tprivate cachedProfiles: CachedSecretProfile[] = [];\n\tprivate readonly activeProfilesByWorkspace = new Map<string, string>();\n\n\tconstructor(options: SecretVaultOptions) {\n\t\tthis.rootDir = secretsDir(options.agentDir);\n\t\tthis.vaultPath = secretVaultFile(options.agentDir);\n\t\tthis.materializedDir = managedSecretEnvDir(options.agentDir);\n\t\tthis.scryptN = validateScryptN(options.scryptN ?? DEFAULT_SCRYPT_N);\n\t\tthis.now = options.now ?? (() => new Date());\n\t\tthis.onEnvironmentChanged = options.onEnvironmentChanged;\n\t}\n\n\tstatic forAgentDir(agentDir: string): SecretVault {\n\t\treturn new SecretVault({ agentDir });\n\t}\n\n\tget isUnlocked(): boolean {\n\t\treturn this.cachedKey !== undefined;\n\t}\n\n\tasync exists(): Promise<boolean> {\n\t\tconst existing = await lstatIfExists(this.vaultPath);\n\t\tif (existing?.isSymbolicLink()) {\n\t\t\tthrow new SecretVaultError(\"symlink_refused\", \"Secret vault symlinks are refused.\");\n\t\t}\n\t\treturn existing !== undefined;\n\t}\n\n\tlock(): void {\n\t\tthis.cachedKey?.fill(0);\n\t\tthis.cachedKey = undefined;\n\t\tthis.cachedKdf = undefined;\n\t\tthis.clearSecretCache();\n\t\tthis.activeProfilesByWorkspace.clear();\n\t\tthis.notifyEnvironmentChanged();\n\t}\n\n\t/** Environment for the nearest explicitly activated profile covering cwd. */\n\tgetEnvironmentForCwd(cwd: string): NodeJS.ProcessEnv {\n\t\tconst match = this.resolveCachedProfile(cwd);\n\t\tif (!match) return {};\n\t\treturn Object.fromEntries(match.profile.variables.map((variable) => [variable.name, variable.value]));\n\t}\n\n\thasEnvironmentForCwd(cwd: string): boolean {\n\t\treturn this.resolveCachedProfile(cwd) !== undefined;\n\t}\n\n\t/** Remove exact unlocked vault values and high-confidence credential shapes from model-facing text. */\n\tredactSensitiveText(text: string): string {\n\t\tlet redacted = redactKnownSecrets(text);\n\t\tconst values = [\n\t\t\t...new Set(\n\t\t\t\tthis.cachedProfiles\n\t\t\t\t\t.flatMap((profile) => profile.variables.map((variable) => variable.value))\n\t\t\t\t\t.filter(Boolean),\n\t\t\t),\n\t\t].sort((left, right) => right.length - left.length);\n\t\tfor (const value of values) {\n\t\t\tif (value.length >= 4) {\n\t\t\t\tredacted = redacted.split(value).join(\"[REDACTED]\");\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst bounded = new RegExp(`(^|[\\\\s=:;,])${escapeRegExp(value)}(?=$|[\\\\s,;])`, \"g\");\n\t\t\tredacted = redacted.replace(bounded, (_match, prefix: string) => `${prefix}[REDACTED]`);\n\t\t}\n\t\treturn redacted;\n\t}\n\n\tasync initialize(passphrase: string): Promise<void> {\n\t\tassertPassphrase(passphrase, true);\n\t\tawait ensurePrivateDirectory(this.rootDir);\n\t\tawait withFileLock(this.vaultPath, async () => {\n\t\t\tif (await lstatIfExists(this.vaultPath)) {\n\t\t\t\tthrow new SecretVaultError(\"already_initialized\", \"Secret vault is already initialized.\");\n\t\t\t}\n\t\t\tconst kdf = createVaultKdf(this.scryptN);\n\t\t\tconst key = await deriveKey(passphrase, kdf);\n\t\t\tconst payload: VaultPayload = { marker: VAULT_MARKER, profiles: [] };\n\t\t\ttry {\n\t\t\t\tawait this.writeEnvelope(kdf, payload, key);\n\t\t\t\tthis.replaceCachedKey(key, kdf);\n\t\t\t} catch (error) {\n\t\t\t\tkey.fill(0);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t});\n\t}\n\n\tasync unlock(passphrase: string): Promise<void> {\n\t\tassertPassphrase(passphrase, false);\n\t\tif (!(await this.exists())) throw new SecretVaultError(\"not_initialized\", \"Secret vault is not initialized.\");\n\t\tconst envelope = parseEnvelope(await readBoundedFile(this.vaultPath));\n\t\tconst key = await deriveKey(passphrase, envelope.kdf);\n\t\tlet payload: VaultPayload | undefined;\n\t\ttry {\n\t\t\tconst environmentBefore = this.activeEnvironmentFingerprint();\n\t\t\tpayload = decryptPayload(envelope.payload, key);\n\t\t\tthis.replaceCachedKey(key, envelope.kdf);\n\t\t\tthis.refreshSecretCache(payload);\n\t\t\tif (environmentBefore !== this.activeEnvironmentFingerprint()) this.notifyEnvironmentChanged();\n\t\t} catch (error) {\n\t\t\tkey.fill(0);\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\tif (payload) scrubPayload(payload);\n\t\t}\n\t}\n\n\tasync listProfiles(): Promise<SecretProfileSummary[]> {\n\t\treturn this.withPayload((payload) => payload.profiles.map(profileSummary), false);\n\t}\n\n\tasync upsertProfile(\n\t\tprofile: string,\n\t\tdescription: string | undefined,\n\t\tvalues: readonly SecretVariableValue[],\n\t): Promise<SecretProfileSummary> {\n\t\tif (values.length === 0) {\n\t\t\tthrow new SecretVaultError(\"invalid_variable\", \"At least one environment variable is required.\");\n\t\t}\n\t\tconst seenNames = new Set<string>();\n\t\tconst normalizedValues = values.map((entry) => {\n\t\t\tconst name = validateVariableName(entry.name);\n\t\t\tif (seenNames.has(name)) {\n\t\t\t\tthrow new SecretVaultError(\"invalid_variable\", `Environment variable ${name} is duplicated.`);\n\t\t\t}\n\t\t\tseenNames.add(name);\n\t\t\treturn { name, value: validateSecretValue(entry.value) };\n\t\t});\n\t\treturn this.storeProfileDocument(\n\t\t\tprofile,\n\t\t\tdescription,\n\t\t\tserializeVariableValues(normalizedValues),\n\t\t\tundefined,\n\t\t\ttrue,\n\t\t);\n\t}\n\n\tasync replaceProfileDocument(\n\t\tprofile: string,\n\t\tdescription: string | undefined,\n\t\tdocument: string,\n\t\tbinding?: { workspace: string; envFile: string },\n\t): Promise<SecretProfileSummary> {\n\t\treturn this.storeProfileDocument(profile, description, document, binding, false);\n\t}\n\n\tasync getProfileDocument(profile: string): Promise<string | undefined> {\n\t\tconst normalizedProfile = validateProfileId(profile);\n\t\treturn this.withPayload(\n\t\t\t(payload) => payload.profiles.find((candidate) => candidate.profile === normalizedProfile)?.dotenv,\n\t\t\tfalse,\n\t\t);\n\t}\n\n\tasync readOwnerDotenv(destination: string): Promise<string> {\n\t\tthis.assertDestination(destination);\n\t\treturn readBoundedRegularFile(destination, MAX_DOTENV_DOCUMENT_BYTES, \"Dotenv file\");\n\t}\n\n\tasync removeProfile(profile: string, variableNames?: readonly string[]): Promise<SecretRemovalResult> {\n\t\tconst normalizedProfile = validateProfileId(profile);\n\t\tconst normalizedNames = variableNames?.map(validateVariableName);\n\t\tif (normalizedNames && new Set(normalizedNames).size !== normalizedNames.length) {\n\t\t\tthrow new SecretVaultError(\"invalid_variable\", \"Environment variable removals are duplicated.\");\n\t\t}\n\t\tlet managedMaterializationRemoved = false;\n\t\tlet boundMaterializationsRemoved = 0;\n\t\tconst result = await this.withPayload(async (payload) => {\n\t\t\tconst index = payload.profiles.findIndex((candidate) => candidate.profile === normalizedProfile);\n\t\t\tconst record = payload.profiles[index];\n\t\t\tif (!record) throw new SecretVaultError(\"profile_missing\", \"Secret profile does not exist.\");\n\t\t\tconst variables = validateDotenvProfileDocument(record.dotenv).variables;\n\t\t\tlet removedProfile: boolean;\n\t\t\tlet removedVariableNames: string[];\n\t\t\tlet remaining: SecretVariableValue[] = [];\n\t\t\tif (normalizedNames === undefined) {\n\t\t\t\tremovedProfile = true;\n\t\t\t\tremovedVariableNames = variables.map((variable) => variable.name);\n\t\t\t} else {\n\t\t\t\tif (normalizedNames.length === 0) {\n\t\t\t\t\tthrow new SecretVaultError(\"invalid_variable\", \"Select at least one environment variable to remove.\");\n\t\t\t\t}\n\t\t\t\tconst requested = new Set(normalizedNames);\n\t\t\t\tremovedVariableNames = variables\n\t\t\t\t\t.filter((variable) => requested.has(variable.name))\n\t\t\t\t\t.map((variable) => variable.name);\n\t\t\t\tif (removedVariableNames.length !== requested.size) {\n\t\t\t\t\tthrow new SecretVaultError(\n\t\t\t\t\t\t\"invalid_variable\",\n\t\t\t\t\t\t\"One or more requested environment variables do not exist.\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tremaining = variables.filter((variable) => !requested.has(variable.name));\n\t\t\t\tremovedProfile = remaining.length === 0;\n\t\t\t}\n\n\t\t\t// Validate the complete mutation before removing any recoverable materialization.\n\t\t\tmanagedMaterializationRemoved = await this.removeManagedMaterialization(normalizedProfile);\n\t\t\tboundMaterializationsRemoved = await this.removeBoundMaterializations(record);\n\t\t\tif (removedProfile) payload.profiles.splice(index, 1);\n\t\t\telse {\n\t\t\t\trecord.dotenv = serializeVariableValues(remaining);\n\t\t\t\trecord.updatedAt = this.now().toISOString();\n\t\t\t}\n\t\t\treturn { removedProfile, removedVariableNames };\n\t\t}, true);\n\t\tthis.deactivateProfile(normalizedProfile);\n\t\treturn {\n\t\t\tprofile: normalizedProfile,\n\t\t\t...result,\n\t\t\tmanagedMaterializationRemoved,\n\t\t\tboundMaterializationsRemoved,\n\t\t};\n\t}\n\n\tgetManagedEnvPath(profile: string): string {\n\t\treturn join(this.materializedDir, `${validateProfileId(profile)}.env`);\n\t}\n\n\tresolveBindingTarget(\n\t\tworkspace: string,\n\t\tenvFile: string,\n\t): {\n\t\tworkspace: string;\n\t\tenvFile: string;\n\t\tdestination: string;\n\t} {\n\t\tconst normalizedWorkspace = validateBindingWorkspace(resolve(workspace));\n\t\tconst normalizedEnvFile = validateBindingEnvFile(envFile);\n\t\tconst destination = resolve(normalizedWorkspace, normalizedEnvFile);\n\t\tif (!isPathInside(normalizedWorkspace, destination)) {\n\t\t\tthrow new SecretVaultError(\"destination_invalid\", \"Credential target must stay inside its workspace.\");\n\t\t}\n\t\treturn { workspace: normalizedWorkspace, envFile: normalizedEnvFile, destination };\n\t}\n\n\tasync resolveBindingForWorkspace(cwd: string, profile?: string): Promise<SecretBindingResolution> {\n\t\tconst normalizedCwd = resolve(cwd);\n\t\tconst normalizedProfile = profile === undefined ? undefined : validateProfileId(profile);\n\t\treturn this.withPayload((payload) => {\n\t\t\tconst matches = payload.profiles.flatMap((candidate) => {\n\t\t\t\tif (normalizedProfile !== undefined && candidate.profile !== normalizedProfile) return [];\n\t\t\t\tconst binding = candidate.bindings\n\t\t\t\t\t.filter((entry) => isPathInside(entry.workspace, normalizedCwd))\n\t\t\t\t\t.sort((left, right) => right.workspace.length - left.workspace.length)[0];\n\t\t\t\tif (!binding) return [];\n\t\t\t\treturn [{ candidate, binding }];\n\t\t\t});\n\t\t\tif (matches.length === 0) {\n\t\t\t\tthrow new SecretVaultError(\n\t\t\t\t\t\"binding_missing\",\n\t\t\t\t\tnormalizedProfile\n\t\t\t\t\t\t? `Secret profile ${normalizedProfile} is not bound to this workspace.`\n\t\t\t\t\t\t: \"No secret profile is bound to this workspace.\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst longestRoot = Math.max(...matches.map((match) => match.binding.workspace.length));\n\t\t\tconst nearest = matches.filter((match) => match.binding.workspace.length === longestRoot);\n\t\t\tlet selected = nearest[0];\n\t\t\tif (nearest.length > 1) {\n\t\t\t\tconst active = nearest.find(\n\t\t\t\t\t(match) => this.activeProfilesByWorkspace.get(match.binding.workspace) === match.candidate.profile,\n\t\t\t\t);\n\t\t\t\tif (!active) {\n\t\t\t\t\tthrow new SecretVaultError(\n\t\t\t\t\t\t\"ambiguous_binding\",\n\t\t\t\t\t\t\"Multiple secret profiles apply to this workspace; select one by profile name.\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tselected = active;\n\t\t\t}\n\t\t\tconst parsed = validateDotenvProfileDocument(selected.candidate.dotenv);\n\t\t\treturn {\n\t\t\t\tprofile: selected.candidate.profile,\n\t\t\t\t...selected.binding,\n\t\t\t\tdestination: resolve(selected.binding.workspace, selected.binding.envFile),\n\t\t\t\tvariableNames: parsed.variables.map((variable) => variable.name),\n\t\t\t};\n\t\t}, false);\n\t}\n\n\tasync inspectEnvDestination(destination: string, profile: string): Promise<SecretEnvDestinationState> {\n\t\tvalidateProfileId(profile);\n\t\tthis.assertDestination(destination);\n\t\tconst existing = await lstatIfExists(destination);\n\t\tif (!existing) return \"missing\";\n\t\tif (existing.isSymbolicLink()) {\n\t\t\tthrow new SecretVaultError(\"symlink_refused\", \"Secret dotenv destination symlinks are refused.\");\n\t\t}\n\t\tif (!existing.isFile()) {\n\t\t\tthrow new SecretVaultError(\"destination_invalid\", \"Secret dotenv destination is not a regular file.\");\n\t\t}\n\t\tconst firstLine = (await readFilePrefix(destination, 512)).split(/\\r?\\n/, 1)[0] ?? \"\";\n\t\tif (firstLine === `${MANAGED_ENV_HEADER_PREFIX}${profile}`) return \"managed-profile\";\n\t\tif (firstLine.startsWith(MANAGED_ENV_HEADER_PREFIX)) return \"managed-other\";\n\t\treturn \"unmanaged\";\n\t}\n\n\tasync materializeEnv(\n\t\tprofile: string,\n\t\tdestination: string,\n\t\toptions: {\n\t\t\tactivationWorkspace?: string;\n\t\t\tallowReplaceUnmanaged?: boolean;\n\t\t\texpectedUnmanagedContent?: string;\n\t\t\tmanaged?: boolean;\n\t\t} = {},\n\t): Promise<SecretMaterializationResult> {\n\t\tconst normalizedProfile = validateProfileId(profile);\n\t\tthis.assertDestination(destination);\n\t\tconst previousState = await this.inspectEnvDestination(destination, normalizedProfile);\n\t\tawait this.assertReplaceableDestination(destination, previousState, options);\n\t\tif (options.managed) {\n\t\t\tif (resolve(destination) !== resolve(this.getManagedEnvPath(normalizedProfile))) {\n\t\t\t\tthrow new SecretVaultError(\"destination_invalid\", \"Managed dotenv destination is not canonical.\");\n\t\t\t}\n\t\t\tawait ensurePrivateDirectory(this.materializedDir);\n\t\t} else {\n\t\t\tconst parent = await lstatIfExists(dirname(destination));\n\t\t\tif (!parent?.isDirectory()) {\n\t\t\t\tthrow new SecretVaultError(\"destination_invalid\", \"Dotenv destination directory does not exist.\");\n\t\t\t}\n\t\t}\n\t\treturn this.withPayload(async (payload) => {\n\t\t\tconst record = payload.profiles.find((candidate) => candidate.profile === normalizedProfile);\n\t\t\tif (!record) throw new SecretVaultError(\"profile_missing\", \"Secret profile does not exist.\");\n\t\t\tconst binding = record.bindings.find(\n\t\t\t\t(candidate) => resolve(candidate.workspace, candidate.envFile) === resolve(destination),\n\t\t\t);\n\t\t\tconst activationCwd = options.activationWorkspace ? resolve(options.activationWorkspace) : undefined;\n\t\t\tconst activationBinding = activationCwd\n\t\t\t\t? record.bindings\n\t\t\t\t\t\t.filter((candidate) => isPathInside(candidate.workspace, activationCwd))\n\t\t\t\t\t\t.sort((left, right) => right.workspace.length - left.workspace.length)[0]\n\t\t\t\t: binding;\n\t\t\tif (activationCwd && !activationBinding) {\n\t\t\t\tthrow new SecretVaultError(\n\t\t\t\t\t\"binding_missing\",\n\t\t\t\t\t`Secret profile ${normalizedProfile} is not bound to this workspace.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (binding && !options.managed) await this.assertBoundDestinationParent(binding, destination);\n\t\t\tconst currentState = await this.inspectEnvDestination(destination, normalizedProfile);\n\t\t\tawait this.assertReplaceableDestination(destination, currentState, options);\n\t\t\tconst variableNames = validateDotenvProfileDocument(record.dotenv).variables.map((variable) => variable.name);\n\t\t\tconst body = record.dotenv.endsWith(\"\\n\") ? record.dotenv : `${record.dotenv}\\n`;\n\t\t\tlet dotenv = `${MANAGED_ENV_HEADER_PREFIX}${normalizedProfile}\\n# Generated by Pi. Do not edit, inspect, source as shell code, or commit.\\n${body}`;\n\t\t\ttry {\n\t\t\t\tawait writeFileAtomic(destination, dotenv, { mode: 0o600 });\n\t\t\t\tawait enforcePrivateFileMode(destination);\n\t\t\t\tif (activationBinding) {\n\t\t\t\t\tthis.activeProfilesByWorkspace.set(activationBinding.workspace, normalizedProfile);\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tdotenv = \"\";\n\t\t\t}\n\t\t\treturn { profile: normalizedProfile, variableNames, previousState: currentState };\n\t\t}, false);\n\t}\n\n\tprivate async storeProfileDocument(\n\t\tprofile: string,\n\t\tdescription: string | undefined,\n\t\tdocument: string,\n\t\tbinding: { workspace: string; envFile: string } | undefined,\n\t\tmerge: boolean,\n\t): Promise<SecretProfileSummary> {\n\t\tconst normalizedProfile = validateProfileId(profile);\n\t\tconst normalizedDescription = validateDescription(description);\n\t\tconst parsedDocument = validateDotenvProfileDocument(document);\n\t\tconst target = binding ? this.resolveBindingTarget(binding.workspace, binding.envFile) : undefined;\n\t\tconst normalizedBinding = target ? { workspace: target.workspace, envFile: target.envFile } : undefined;\n\n\t\tconst summary = await this.withPayload(async (payload) => {\n\t\t\tlet record = payload.profiles.find((candidate) => candidate.profile === normalizedProfile);\n\t\t\tconst timestamp = this.now().toISOString();\n\t\t\tif (!record && payload.profiles.length >= MAX_PROFILES) {\n\t\t\t\tthrow new SecretVaultError(\"profile_limit\", `Secret vault supports at most ${MAX_PROFILES} profiles.`);\n\t\t\t}\n\t\t\tconst nextBindings = record?.bindings.map((entry) => ({ ...entry })) ?? [];\n\t\t\tif (normalizedBinding) {\n\t\t\t\tconst next = { ...normalizedBinding, updatedAt: timestamp };\n\t\t\t\tconst existingIndex = nextBindings.findIndex((entry) => entry.workspace === normalizedBinding.workspace);\n\t\t\t\tif (existingIndex === -1) nextBindings.push(next);\n\t\t\t\telse nextBindings[existingIndex] = next;\n\t\t\t\tif (nextBindings.length > MAX_BINDINGS_PER_PROFILE) {\n\t\t\t\t\tthrow new SecretVaultError(\n\t\t\t\t\t\t\"profile_limit\",\n\t\t\t\t\t\t`A secret profile supports at most ${MAX_BINDINGS_PER_PROFILE} workspace bindings.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet nextDocument = parsedDocument.document;\n\t\t\tif (merge && record) {\n\t\t\t\tconst merged = new Map(\n\t\t\t\t\tvalidateDotenvProfileDocument(record.dotenv).variables.map((variable) => [\n\t\t\t\t\t\tvariable.name,\n\t\t\t\t\t\tvariable.value,\n\t\t\t\t\t]),\n\t\t\t\t);\n\t\t\t\tfor (const variable of parsedDocument.variables) merged.set(variable.name, variable.value);\n\t\t\t\tif (merged.size > MAX_VARIABLES_PER_PROFILE) {\n\t\t\t\t\tthrow new SecretVaultError(\n\t\t\t\t\t\t\"variable_limit\",\n\t\t\t\t\t\t`A secret profile supports at most ${MAX_VARIABLES_PER_PROFILE} variables.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tnextDocument = serializeVariableValues([...merged].map(([name, value]) => ({ name, value })));\n\t\t\t}\n\n\t\t\tif (record) {\n\t\t\t\tawait this.removeManagedMaterialization(normalizedProfile);\n\t\t\t\tawait this.removeBoundMaterializations(record);\n\t\t\t} else {\n\t\t\t\trecord = {\n\t\t\t\t\tprofile: normalizedProfile,\n\t\t\t\t\tcreatedAt: timestamp,\n\t\t\t\t\tupdatedAt: timestamp,\n\t\t\t\t\tdotenv: nextDocument,\n\t\t\t\t\tbindings: [],\n\t\t\t\t};\n\t\t\t\tpayload.profiles.push(record);\n\t\t\t}\n\t\t\tif (normalizedDescription !== undefined) record.description = normalizedDescription;\n\t\t\trecord.dotenv = nextDocument;\n\t\t\trecord.bindings = nextBindings.sort(\n\t\t\t\t(left, right) => left.workspace.localeCompare(right.workspace) || left.envFile.localeCompare(right.envFile),\n\t\t\t);\n\t\t\trecord.updatedAt = timestamp;\n\t\t\tpayload.profiles.sort((left, right) => left.profile.localeCompare(right.profile));\n\t\t\treturn profileSummary(record);\n\t\t}, true);\n\t\tthis.deactivateProfile(normalizedProfile);\n\t\treturn summary;\n\t}\n\n\tprivate async assertReplaceableDestination(\n\t\tdestination: string,\n\t\tstate: SecretEnvDestinationState,\n\t\toptions: { allowReplaceUnmanaged?: boolean; expectedUnmanagedContent?: string },\n\t): Promise<void> {\n\t\tif (state === \"managed-other\") {\n\t\t\tthrow new SecretVaultError(\n\t\t\t\t\"destination_conflict\",\n\t\t\t\t\"Destination already contains a file managed for another secret profile.\",\n\t\t\t);\n\t\t}\n\t\tif (state !== \"unmanaged\") return;\n\t\tif (!options.allowReplaceUnmanaged || options.expectedUnmanagedContent === undefined) {\n\t\t\tthrow new SecretVaultError(\n\t\t\t\t\"destination_conflict\",\n\t\t\t\t\"Destination already contains an unmanaged file that was not reviewed for replacement.\",\n\t\t\t);\n\t\t}\n\t\tif ((await this.readOwnerDotenv(destination)) !== options.expectedUnmanagedContent) {\n\t\t\tthrow new SecretVaultError(\n\t\t\t\t\"destination_conflict\",\n\t\t\t\t\"The reviewed dotenv file changed before replacement and was preserved.\",\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate async assertBoundDestinationParent(binding: SecretBindingSummary, destination: string): Promise<void> {\n\t\ttry {\n\t\t\tconst [workspace, parent] = await Promise.all([\n\t\t\t\tfs.realpath(binding.workspace),\n\t\t\t\tfs.realpath(dirname(destination)),\n\t\t\t]);\n\t\t\tif (isPathInside(workspace, parent)) return;\n\t\t} catch {\n\t\t\t// Collapse filesystem detail so a model-facing failure cannot disclose unrelated paths.\n\t\t}\n\t\tthrow new SecretVaultError(\n\t\t\t\"destination_invalid\",\n\t\t\t\"Credential destination resolves outside its bound workspace or cannot be verified.\",\n\t\t);\n\t}\n\n\tprivate assertDestination(destination: string): void {\n\t\tif (!isAbsolute(destination) || resolve(destination) === resolve(this.vaultPath)) {\n\t\t\tthrow new SecretVaultError(\n\t\t\t\t\"destination_invalid\",\n\t\t\t\t\"Secret dotenv destination must be an absolute non-vault path.\",\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate replaceCachedKey(key: Buffer, kdf: VaultKdf): void {\n\t\tthis.cachedKey?.fill(0);\n\t\tthis.cachedKey = key;\n\t\tthis.cachedKdf = { ...kdf };\n\t}\n\n\tprivate clearSecretCache(): void {\n\t\tfor (const profile of this.cachedProfiles) {\n\t\t\tfor (const variable of profile.variables) variable.value = \"\";\n\t\t}\n\t\tthis.cachedProfiles = [];\n\t}\n\n\tprivate deactivateProfile(profile: string): void {\n\t\tlet changed = false;\n\t\tfor (const [workspace, activeProfile] of this.activeProfilesByWorkspace) {\n\t\t\tif (activeProfile !== profile) continue;\n\t\t\tthis.activeProfilesByWorkspace.delete(workspace);\n\t\t\tchanged = true;\n\t\t}\n\t\tconst cached = this.cachedProfiles.find((candidate) => candidate.profile === profile);\n\t\tif (cached) {\n\t\t\tfor (const variable of cached.variables) variable.value = \"\";\n\t\t\tcached.variables = [];\n\t\t}\n\t\tif (changed) this.notifyEnvironmentChanged();\n\t}\n\n\tprivate notifyEnvironmentChanged(): void {\n\t\ttry {\n\t\t\tthis.onEnvironmentChanged?.();\n\t\t} catch {\n\t\t\t// Credential state changes remain authoritative even if host cleanup is best-effort.\n\t\t}\n\t}\n\n\tprivate activeEnvironmentFingerprint(): string {\n\t\tconst hash = createHash(\"sha256\");\n\t\tfor (const profile of this.cachedProfiles) {\n\t\t\tconst activeBindings = profile.bindings\n\t\t\t\t.filter((binding) => this.activeProfilesByWorkspace.get(binding.workspace) === profile.profile)\n\t\t\t\t.sort((left, right) => left.workspace.localeCompare(right.workspace));\n\t\t\tif (activeBindings.length === 0) continue;\n\t\t\thash.update(`${profile.profile.length}:${profile.profile}`);\n\t\t\tfor (const binding of activeBindings) hash.update(`${binding.workspace.length}:${binding.workspace}`);\n\t\t\tfor (const variable of profile.variables) {\n\t\t\t\thash.update(`${variable.name.length}:${variable.name}${variable.value.length}:${variable.value}`);\n\t\t\t}\n\t\t}\n\t\treturn hash.digest(\"hex\");\n\t}\n\n\tprivate refreshSecretCache(payload: VaultPayload): void {\n\t\tthis.clearSecretCache();\n\t\tthis.cachedProfiles = payload.profiles.map((profile) => ({\n\t\t\tprofile: profile.profile,\n\t\t\tbindings: profile.bindings.map((binding) => ({ ...binding })),\n\t\t\tvariables: profile.bindings.some(\n\t\t\t\t(binding) => this.activeProfilesByWorkspace.get(binding.workspace) === profile.profile,\n\t\t\t)\n\t\t\t\t? parseDotenvDocument(profile.dotenv).variables.map((variable) => ({ ...variable }))\n\t\t\t\t: [],\n\t\t}));\n\t\tfor (const [workspace, profile] of this.activeProfilesByWorkspace) {\n\t\t\tconst stillBound = this.cachedProfiles.some(\n\t\t\t\t(candidate) =>\n\t\t\t\t\tcandidate.profile === profile && candidate.bindings.some((binding) => binding.workspace === workspace),\n\t\t\t);\n\t\t\tif (!stillBound) this.activeProfilesByWorkspace.delete(workspace);\n\t\t}\n\t}\n\n\tprivate resolveCachedProfile(\n\t\tcwd: string,\n\t): { profile: CachedSecretProfile; binding: SecretBindingSummary } | undefined {\n\t\tconst resolvedCwd = resolve(cwd);\n\t\treturn this.cachedProfiles\n\t\t\t.flatMap((profile) => {\n\t\t\t\tconst binding = profile.bindings\n\t\t\t\t\t.filter((candidate) => isPathInside(candidate.workspace, resolvedCwd))\n\t\t\t\t\t.sort((left, right) => right.workspace.length - left.workspace.length)[0];\n\t\t\t\treturn binding ? [{ profile, binding }] : [];\n\t\t\t})\n\t\t\t.filter((match) => this.activeProfilesByWorkspace.get(match.binding.workspace) === match.profile.profile)\n\t\t\t.sort((left, right) => right.binding.workspace.length - left.binding.workspace.length)[0];\n\t}\n\n\tprivate requireUnlocked(): { key: Buffer; kdf: VaultKdf } {\n\t\tif (!this.cachedKey || !this.cachedKdf) {\n\t\t\tthrow new SecretVaultError(\"not_unlocked\", \"Secret vault is locked.\");\n\t\t}\n\t\treturn { key: this.cachedKey, kdf: this.cachedKdf };\n\t}\n\n\tprivate async withPayload<T>(operation: (payload: VaultPayload) => T | Promise<T>, write: boolean): Promise<T> {\n\t\treturn withFileLock(this.vaultPath, async () => {\n\t\t\tconst environmentBefore = this.activeEnvironmentFingerprint();\n\t\t\tconst { key, kdf } = this.requireUnlocked();\n\t\t\tif (!(await lstatIfExists(this.vaultPath))) {\n\t\t\t\tthrow new SecretVaultError(\"not_initialized\", \"Secret vault is not initialized.\");\n\t\t\t}\n\t\t\tconst envelope = parseEnvelope(await readBoundedFile(this.vaultPath));\n\t\t\tif (!sameKdf(kdf, envelope.kdf)) {\n\t\t\t\tthis.lock();\n\t\t\t\tthrow new SecretVaultError(\"unlock_failed\", \"Secret vault changed and must be unlocked again.\");\n\t\t\t}\n\t\t\tconst payload = decryptPayload(envelope.payload, key);\n\t\t\ttry {\n\t\t\t\tconst result = await operation(payload);\n\t\t\t\tif (write) await this.writeEnvelope(kdf, payload, key);\n\t\t\t\tthis.refreshSecretCache(payload);\n\t\t\t\tif (environmentBefore !== this.activeEnvironmentFingerprint()) this.notifyEnvironmentChanged();\n\t\t\t\treturn result;\n\t\t\t} finally {\n\t\t\t\tscrubPayload(payload);\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate async writeEnvelope(kdf: VaultKdf, payload: VaultPayload, key: Buffer): Promise<void> {\n\t\tlet serialized = serializeEnvelope(kdf, payload, key);\n\t\ttry {\n\t\t\tawait writeFileAtomic(this.vaultPath, serialized, { mode: 0o600 });\n\t\t\tawait enforcePrivateFileMode(this.vaultPath);\n\t\t} finally {\n\t\t\tserialized = \"\";\n\t\t}\n\t}\n\n\tprivate async removeBoundMaterializations(record: {\n\t\tprofile: string;\n\t\tbindings: SecretBindingSummary[];\n\t}): Promise<number> {\n\t\tlet removed = 0;\n\t\tfor (const binding of record.bindings) {\n\t\t\tconst destination = resolve(binding.workspace, binding.envFile);\n\t\t\tconst existing = await lstatIfExists(destination);\n\t\t\tif (!existing) continue;\n\t\t\tconst state = await this.inspectEnvDestination(destination, record.profile);\n\t\t\tif (state !== \"managed-profile\") continue;\n\t\t\tawait fs.unlink(destination);\n\t\t\tremoved++;\n\t\t}\n\t\treturn removed;\n\t}\n\n\tprivate async removeManagedMaterialization(profile: string): Promise<boolean> {\n\t\tconst path = this.getManagedEnvPath(profile);\n\t\tconst existing = await lstatIfExists(path);\n\t\tif (!existing) return false;\n\t\tif (existing.isSymbolicLink()) {\n\t\t\tthrow new SecretVaultError(\"symlink_refused\", \"Managed dotenv symlinks are refused.\");\n\t\t}\n\t\tif (!existing.isFile()) {\n\t\t\tthrow new SecretVaultError(\"destination_invalid\", \"Managed dotenv path is not a regular file.\");\n\t\t}\n\t\tconst state = await this.inspectEnvDestination(path, profile);\n\t\tif (state !== \"managed-profile\") return false;\n\t\tawait fs.unlink(path);\n\t\treturn true;\n\t}\n}\n"]}