@elie-laloum/outpost 6.0.1 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (463) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +3 -3
  3. package/SECURITY.md +9 -1
  4. package/dist/adapters/agents/antigravity-adapter.js +4 -2
  5. package/dist/adapters/agents/antigravity-adapter.js.map +1 -1
  6. package/dist/adapters/agents/antigravity-diagnostics.js +1 -1
  7. package/dist/adapters/agents/antigravity-diagnostics.js.map +1 -1
  8. package/dist/adapters/agents/antigravity-events.js +19 -10
  9. package/dist/adapters/agents/antigravity-events.js.map +1 -1
  10. package/dist/adapters/agents/antigravity-request.js +9 -1
  11. package/dist/adapters/agents/antigravity-request.js.map +1 -1
  12. package/dist/adapters/agents/antigravity.constants.d.ts +3 -0
  13. package/dist/adapters/agents/antigravity.constants.js +4 -0
  14. package/dist/adapters/agents/antigravity.constants.js.map +1 -0
  15. package/dist/adapters/agents/claude-events.js +52 -9
  16. package/dist/adapters/agents/claude-events.js.map +1 -1
  17. package/dist/adapters/agents/claude-request.js +2 -0
  18. package/dist/adapters/agents/claude-request.js.map +1 -1
  19. package/dist/adapters/agents/cli-diagnostics.d.ts +1 -1
  20. package/dist/adapters/agents/cli-diagnostics.js +15 -8
  21. package/dist/adapters/agents/cli-diagnostics.js.map +1 -1
  22. package/dist/adapters/agents/codex-events.js +28 -2
  23. package/dist/adapters/agents/codex-events.js.map +1 -1
  24. package/dist/adapters/agents/copilot-adapter.js +8 -2
  25. package/dist/adapters/agents/copilot-adapter.js.map +1 -1
  26. package/dist/adapters/agents/copilot-authentication.js +2 -1
  27. package/dist/adapters/agents/copilot-authentication.js.map +1 -1
  28. package/dist/adapters/agents/copilot-diagnostics.js +1 -1
  29. package/dist/adapters/agents/copilot-diagnostics.js.map +1 -1
  30. package/dist/adapters/agents/copilot-events.js +16 -0
  31. package/dist/adapters/agents/copilot-events.js.map +1 -1
  32. package/dist/adapters/agents/copilot-request.js +6 -1
  33. package/dist/adapters/agents/copilot-request.js.map +1 -1
  34. package/dist/adapters/agents/copilot-usage.d.ts +3 -0
  35. package/dist/adapters/agents/copilot-usage.js +19 -0
  36. package/dist/adapters/agents/copilot-usage.js.map +1 -0
  37. package/dist/adapters/agents/kimi-adapter.js +19 -3
  38. package/dist/adapters/agents/kimi-adapter.js.map +1 -1
  39. package/dist/adapters/agents/kimi-authentication.d.ts +2 -1
  40. package/dist/adapters/agents/kimi-authentication.js +41 -26
  41. package/dist/adapters/agents/kimi-authentication.js.map +1 -1
  42. package/dist/adapters/agents/kimi-diagnostics.d.ts +2 -1
  43. package/dist/adapters/agents/kimi-diagnostics.js +9 -1
  44. package/dist/adapters/agents/kimi-diagnostics.js.map +1 -1
  45. package/dist/adapters/agents/kimi-events.js +4 -0
  46. package/dist/adapters/agents/kimi-events.js.map +1 -1
  47. package/dist/adapters/agents/kimi-fork.d.ts +2 -0
  48. package/dist/adapters/agents/kimi-fork.js +11 -0
  49. package/dist/adapters/agents/kimi-fork.js.map +1 -0
  50. package/dist/adapters/agents/kimi-request.js +6 -1
  51. package/dist/adapters/agents/kimi-request.js.map +1 -1
  52. package/dist/adapters/agents/kimi-usage.d.ts +2 -0
  53. package/dist/adapters/agents/kimi-usage.js +7 -0
  54. package/dist/adapters/agents/kimi-usage.js.map +1 -0
  55. package/dist/adapters/agents/kimi.constants.d.ts +13 -0
  56. package/dist/adapters/agents/kimi.constants.js +14 -0
  57. package/dist/adapters/agents/kimi.constants.js.map +1 -0
  58. package/dist/adapters/agents/kimi.types.d.ts +1 -0
  59. package/dist/adapters/agents/kimi.types.js.map +1 -1
  60. package/dist/adapters/agents/protocol-fixtures.constants.js +15 -19
  61. package/dist/adapters/agents/protocol-fixtures.constants.js.map +1 -1
  62. package/dist/adapters/agents/session-usage.constants.d.ts +10 -0
  63. package/dist/adapters/agents/session-usage.constants.js +110 -0
  64. package/dist/adapters/agents/session-usage.constants.js.map +1 -0
  65. package/dist/adapters/agents/session-usage.d.ts +5 -0
  66. package/dist/adapters/agents/session-usage.js +45 -0
  67. package/dist/adapters/agents/session-usage.js.map +1 -0
  68. package/dist/adapters/agents/settings.types.d.ts +1 -0
  69. package/dist/adapters/agents/settings.types.js.map +1 -1
  70. package/dist/adapters/agents/tool-result.d.ts +2 -0
  71. package/dist/adapters/agents/tool-result.js +17 -0
  72. package/dist/adapters/agents/tool-result.js.map +1 -0
  73. package/dist/adapters/models/anthropic-response.js +3 -0
  74. package/dist/adapters/models/anthropic-response.js.map +1 -1
  75. package/dist/adapters/models/http-provider.js +6 -1
  76. package/dist/adapters/models/http-provider.js.map +1 -1
  77. package/dist/adapters/models/openai-responses.js +10 -0
  78. package/dist/adapters/models/openai-responses.js.map +1 -1
  79. package/dist/adapters/models/retry-after.d.ts +1 -0
  80. package/dist/adapters/models/retry-after.js +16 -0
  81. package/dist/adapters/models/retry-after.js.map +1 -0
  82. package/dist/application/activity-watchdog.js +1 -2
  83. package/dist/application/activity-watchdog.js.map +1 -1
  84. package/dist/application/agent-bootstrap.constants.js +1 -3
  85. package/dist/application/agent-bootstrap.constants.js.map +1 -1
  86. package/dist/application/agent-bootstrap.js +9 -3
  87. package/dist/application/agent-bootstrap.js.map +1 -1
  88. package/dist/application/agent-bootstrap.types.d.ts +1 -2
  89. package/dist/application/agent-bootstrap.types.js.map +1 -1
  90. package/dist/application/agent-output.js +74 -8
  91. package/dist/application/agent-output.js.map +1 -1
  92. package/dist/application/agent-request.d.ts +3 -0
  93. package/dist/application/agent-request.js +11 -0
  94. package/dist/application/agent-request.js.map +1 -0
  95. package/dist/application/agent-turn.js +74 -6
  96. package/dist/application/agent-turn.js.map +1 -1
  97. package/dist/application/agent-usage.d.ts +6 -0
  98. package/dist/application/agent-usage.js +57 -0
  99. package/dist/application/agent-usage.js.map +1 -0
  100. package/dist/application/attach.js +2 -0
  101. package/dist/application/attach.js.map +1 -1
  102. package/dist/application/custom-turn.js +44 -49
  103. package/dist/application/custom-turn.js.map +1 -1
  104. package/dist/application/dispatch-observation.d.ts +1 -1
  105. package/dist/application/dispatch-observation.js +141 -21
  106. package/dist/application/dispatch-observation.js.map +1 -1
  107. package/dist/application/dispatch-observation.types.d.ts +2 -0
  108. package/dist/application/dispatch-observation.types.js.map +1 -1
  109. package/dist/application/dispatch-validation.js +2 -0
  110. package/dist/application/dispatch-validation.js.map +1 -1
  111. package/dist/application/dispatch.js +1 -1
  112. package/dist/application/dispatch.js.map +1 -1
  113. package/dist/application/doctor-agent.constants.js +3 -0
  114. package/dist/application/doctor-agent.constants.js.map +1 -1
  115. package/dist/application/doctor-agent.js +6 -2
  116. package/dist/application/doctor-agent.js.map +1 -1
  117. package/dist/application/doctor.js +26 -6
  118. package/dist/application/doctor.js.map +1 -1
  119. package/dist/application/doctor.types.d.ts +1 -0
  120. package/dist/application/doctor.types.js.map +1 -1
  121. package/dist/application/execution.constants.d.ts +2 -0
  122. package/dist/application/execution.constants.js +2 -0
  123. package/dist/application/execution.constants.js.map +1 -1
  124. package/dist/application/execution.types.d.ts +8 -0
  125. package/dist/application/execution.types.js.map +1 -1
  126. package/dist/application/harness-budget.d.ts +3 -0
  127. package/dist/application/harness-budget.js +42 -0
  128. package/dist/application/harness-budget.js.map +1 -0
  129. package/dist/application/harness-budget.types.d.ts +5 -0
  130. package/dist/application/harness-budget.types.js +2 -0
  131. package/dist/application/harness-budget.types.js.map +1 -0
  132. package/dist/application/harness-hooks.js +34 -3
  133. package/dist/application/harness-hooks.js.map +1 -1
  134. package/dist/application/harness-loop.js +52 -24
  135. package/dist/application/harness-loop.js.map +1 -1
  136. package/dist/application/harness-model-provider.d.ts +3 -0
  137. package/dist/application/harness-model-provider.js +49 -0
  138. package/dist/application/harness-model-provider.js.map +1 -0
  139. package/dist/application/harness-model-provider.types.d.ts +10 -0
  140. package/dist/application/harness-model-provider.types.js +2 -0
  141. package/dist/application/harness-model-provider.types.js.map +1 -0
  142. package/dist/application/harness-subagent.d.ts +4 -0
  143. package/dist/application/harness-subagent.js +110 -0
  144. package/dist/application/harness-subagent.js.map +1 -0
  145. package/dist/application/harness.types.d.ts +11 -0
  146. package/dist/application/harness.types.js.map +1 -1
  147. package/dist/application/lifecycle-hooks.d.ts +1 -1
  148. package/dist/application/lifecycle-hooks.js +5 -4
  149. package/dist/application/lifecycle-hooks.js.map +1 -1
  150. package/dist/application/observed-lease.d.ts +3 -0
  151. package/dist/application/observed-lease.js +26 -0
  152. package/dist/application/observed-lease.js.map +1 -0
  153. package/dist/application/outpost.types.d.ts +3 -0
  154. package/dist/application/outpost.types.js.map +1 -1
  155. package/dist/application/output-lines.d.ts +4 -0
  156. package/dist/application/output-lines.js +28 -0
  157. package/dist/application/output-lines.js.map +1 -0
  158. package/dist/application/queue-worker.js +1 -1
  159. package/dist/application/queue-worker.js.map +1 -1
  160. package/dist/application/queue-worker.types.d.ts +1 -0
  161. package/dist/application/queue-worker.types.js.map +1 -1
  162. package/dist/application/queued-task.js +24 -5
  163. package/dist/application/queued-task.js.map +1 -1
  164. package/dist/application/recovery-archive.d.ts +3 -2
  165. package/dist/application/recovery-archive.js +9 -2
  166. package/dist/application/recovery-archive.js.map +1 -1
  167. package/dist/application/recovery-restore.d.ts +3 -2
  168. package/dist/application/recovery-restore.js +9 -2
  169. package/dist/application/recovery-restore.js.map +1 -1
  170. package/dist/application/recovery-retention.d.ts +3 -2
  171. package/dist/application/recovery-retention.js +9 -2
  172. package/dist/application/recovery-retention.js.map +1 -1
  173. package/dist/application/remote-workspace.js +5 -4
  174. package/dist/application/remote-workspace.js.map +1 -1
  175. package/dist/application/remote-workspace.types.d.ts +1 -0
  176. package/dist/application/remote-workspace.types.js.map +1 -1
  177. package/dist/application/sandbox-agents.js +11 -12
  178. package/dist/application/sandbox-agents.js.map +1 -1
  179. package/dist/application/sandbox-attach.js +12 -3
  180. package/dist/application/sandbox-attach.js.map +1 -1
  181. package/dist/application/sandbox-dispatch.js +13 -25
  182. package/dist/application/sandbox-dispatch.js.map +1 -1
  183. package/dist/application/sandbox-provision.js +15 -9
  184. package/dist/application/sandbox-provision.js.map +1 -1
  185. package/dist/application/sandbox-session.types.d.ts +2 -2
  186. package/dist/application/sandbox-session.types.js.map +1 -1
  187. package/dist/application/sandbox.js +13 -6
  188. package/dist/application/sandbox.js.map +1 -1
  189. package/dist/application/speculation-checkpoint.d.ts +6 -0
  190. package/dist/application/speculation-checkpoint.js +206 -0
  191. package/dist/application/speculation-checkpoint.js.map +1 -0
  192. package/dist/application/speculation-checkpoint.types.d.ts +24 -0
  193. package/dist/application/speculation-checkpoint.types.js +2 -0
  194. package/dist/application/speculation-checkpoint.types.js.map +1 -0
  195. package/dist/application/speculation-integration.constants.d.ts +4 -0
  196. package/dist/application/speculation-integration.constants.js +5 -0
  197. package/dist/application/speculation-integration.constants.js.map +1 -0
  198. package/dist/application/speculation-integration.d.ts +2 -0
  199. package/dist/application/speculation-integration.js +67 -0
  200. package/dist/application/speculation-integration.js.map +1 -0
  201. package/dist/application/speculation-resume.d.ts +4 -0
  202. package/dist/application/speculation-resume.js +71 -0
  203. package/dist/application/speculation-resume.js.map +1 -0
  204. package/dist/application/speculation-run.d.ts +4 -0
  205. package/dist/application/speculation-run.js +320 -0
  206. package/dist/application/speculation-run.js.map +1 -0
  207. package/dist/application/speculation-timeout.d.ts +1 -0
  208. package/dist/application/speculation-timeout.js +15 -0
  209. package/dist/application/speculation-timeout.js.map +1 -0
  210. package/dist/application/speculation.constants.d.ts +1 -0
  211. package/dist/application/speculation.constants.js +5 -1
  212. package/dist/application/speculation.constants.js.map +1 -1
  213. package/dist/application/speculation.js +41 -149
  214. package/dist/application/speculation.js.map +1 -1
  215. package/dist/application/speculation.types.d.ts +23 -0
  216. package/dist/application/speculation.types.js.map +1 -1
  217. package/dist/application/startup-recovery.js +13 -0
  218. package/dist/application/startup-recovery.js.map +1 -1
  219. package/dist/application/startup-recovery.types.d.ts +1 -0
  220. package/dist/application/startup-recovery.types.js.map +1 -1
  221. package/dist/application/stop-reason.d.ts +2 -0
  222. package/dist/application/stop-reason.js +21 -0
  223. package/dist/application/stop-reason.js.map +1 -0
  224. package/dist/application/stop-reason.types.d.ts +4 -0
  225. package/dist/application/stop-reason.types.js +2 -0
  226. package/dist/application/stop-reason.types.js.map +1 -0
  227. package/dist/application/task-observation.d.ts +3 -0
  228. package/dist/application/task-observation.js +22 -0
  229. package/dist/application/task-observation.js.map +1 -0
  230. package/dist/application/task-usage.js +5 -12
  231. package/dist/application/task-usage.js.map +1 -1
  232. package/dist/application/tasks.js +41 -16
  233. package/dist/application/tasks.js.map +1 -1
  234. package/dist/application/tool-execution.js +42 -19
  235. package/dist/application/tool-execution.js.map +1 -1
  236. package/dist/application/workspace.js +6 -4
  237. package/dist/application/workspace.js.map +1 -1
  238. package/dist/cli/doctor-command.js +1 -1
  239. package/dist/cli/doctor-command.js.map +1 -1
  240. package/dist/cli/main.js +2 -1
  241. package/dist/cli/main.js.map +1 -1
  242. package/dist/cli/scaffold.constants.js +3 -2
  243. package/dist/cli/scaffold.constants.js.map +1 -1
  244. package/dist/domain/agent-observation.d.ts +4 -0
  245. package/dist/domain/agent-observation.js +27 -0
  246. package/dist/domain/agent-observation.js.map +1 -0
  247. package/dist/domain/agent.types.d.ts +75 -3
  248. package/dist/domain/agent.types.js.map +1 -1
  249. package/dist/domain/harness.js +6 -0
  250. package/dist/domain/harness.js.map +1 -1
  251. package/dist/domain/harness.types.d.ts +2 -1
  252. package/dist/domain/harness.types.js.map +1 -1
  253. package/dist/domain/model.types.d.ts +8 -0
  254. package/dist/domain/model.types.js.map +1 -1
  255. package/dist/domain/observation.constants.d.ts +8 -0
  256. package/dist/domain/observation.constants.js +9 -0
  257. package/dist/domain/observation.constants.js.map +1 -0
  258. package/dist/domain/observation.d.ts +2 -0
  259. package/dist/domain/observation.js +190 -0
  260. package/dist/domain/observation.js.map +1 -0
  261. package/dist/domain/observation.types.d.ts +84 -0
  262. package/dist/domain/observation.types.js +2 -0
  263. package/dist/domain/observation.types.js.map +1 -0
  264. package/dist/domain/observed-operation.d.ts +2 -0
  265. package/dist/domain/observed-operation.js +30 -0
  266. package/dist/domain/observed-operation.js.map +1 -0
  267. package/dist/domain/sandbox.types.d.ts +2 -0
  268. package/dist/domain/sandbox.types.js.map +1 -1
  269. package/dist/domain/subagent.constants.d.ts +13 -0
  270. package/dist/domain/subagent.constants.js +9 -0
  271. package/dist/domain/subagent.constants.js.map +1 -0
  272. package/dist/domain/subagent.d.ts +4 -0
  273. package/dist/domain/subagent.js +28 -0
  274. package/dist/domain/subagent.js.map +1 -0
  275. package/dist/domain/subagent.types.d.ts +13 -0
  276. package/dist/domain/subagent.types.js +2 -0
  277. package/dist/domain/subagent.types.js.map +1 -0
  278. package/dist/domain/transcript.types.d.ts +2 -0
  279. package/dist/domain/transcript.types.js.map +1 -1
  280. package/dist/domain/usage.d.ts +1 -0
  281. package/dist/domain/usage.js +16 -0
  282. package/dist/domain/usage.js.map +1 -1
  283. package/dist/domain/workflow/budget.d.ts +7 -3
  284. package/dist/domain/workflow/budget.js +26 -0
  285. package/dist/domain/workflow/budget.js.map +1 -1
  286. package/dist/domain/workflow/budget.types.d.ts +1 -1
  287. package/dist/domain/workflow/budget.types.js.map +1 -1
  288. package/dist/domain/workflow/checkpoint-validation.js +7 -1
  289. package/dist/domain/workflow/checkpoint-validation.js.map +1 -1
  290. package/dist/domain/workflow/checkpoint.js +3 -0
  291. package/dist/domain/workflow/checkpoint.js.map +1 -1
  292. package/dist/domain/workflow/gate-validation.js +14 -1
  293. package/dist/domain/workflow/gate-validation.js.map +1 -1
  294. package/dist/domain/workflow/gates.d.ts +1 -1
  295. package/dist/domain/workflow/gates.js +52 -4
  296. package/dist/domain/workflow/gates.js.map +1 -1
  297. package/dist/domain/workflow/gates.types.d.ts +15 -1
  298. package/dist/domain/workflow/gates.types.js.map +1 -1
  299. package/dist/domain/workflow/idempotency.d.ts +1 -0
  300. package/dist/domain/workflow/idempotency.js +7 -0
  301. package/dist/domain/workflow/idempotency.js.map +1 -0
  302. package/dist/domain/workflow/retry.constants.d.ts +2 -0
  303. package/dist/domain/workflow/retry.constants.js +3 -0
  304. package/dist/domain/workflow/retry.constants.js.map +1 -0
  305. package/dist/domain/workflow/retry.d.ts +4 -0
  306. package/dist/domain/workflow/retry.js +49 -0
  307. package/dist/domain/workflow/retry.js.map +1 -0
  308. package/dist/domain/workflow/task-runner.js +9 -5
  309. package/dist/domain/workflow/task-runner.js.map +1 -1
  310. package/dist/domain/workflow/task.js +6 -6
  311. package/dist/domain/workflow/task.js.map +1 -1
  312. package/dist/domain/workflow/workflow-scheduler.js +110 -72
  313. package/dist/domain/workflow/workflow-scheduler.js.map +1 -1
  314. package/dist/domain/workflow/workflow-state.js +28 -12
  315. package/dist/domain/workflow/workflow-state.js.map +1 -1
  316. package/dist/domain/workflow.d.ts +1 -1
  317. package/dist/domain/workflow.js +1 -1
  318. package/dist/domain/workflow.js.map +1 -1
  319. package/dist/domain/workflow.types.d.ts +13 -2
  320. package/dist/domain/workflow.types.js.map +1 -1
  321. package/dist/index.d.ts +12 -3
  322. package/dist/index.js +6 -1
  323. package/dist/index.js.map +1 -1
  324. package/dist/infrastructure/conversations/capture.js +10 -0
  325. package/dist/infrastructure/conversations/capture.js.map +1 -1
  326. package/dist/infrastructure/conversations/harness-transcript.js +6 -0
  327. package/dist/infrastructure/conversations/harness-transcript.js.map +1 -1
  328. package/dist/infrastructure/conversations/harness-transcript.types.d.ts +2 -0
  329. package/dist/infrastructure/conversations/harness-transcript.types.js.map +1 -1
  330. package/dist/infrastructure/conversations/layout.js +2 -0
  331. package/dist/infrastructure/conversations/layout.js.map +1 -1
  332. package/dist/infrastructure/conversations/locate.js +7 -1
  333. package/dist/infrastructure/conversations/locate.js.map +1 -1
  334. package/dist/infrastructure/conversations/native-store.js +8 -1
  335. package/dist/infrastructure/conversations/native-store.js.map +1 -1
  336. package/dist/infrastructure/conversations/paths.js +3 -0
  337. package/dist/infrastructure/conversations/paths.js.map +1 -1
  338. package/dist/infrastructure/conversations/restore.js +7 -0
  339. package/dist/infrastructure/conversations/restore.js.map +1 -1
  340. package/dist/infrastructure/conversations/session-bundle.constants.d.ts +5 -0
  341. package/dist/infrastructure/conversations/session-bundle.constants.js +173 -0
  342. package/dist/infrastructure/conversations/session-bundle.constants.js.map +1 -0
  343. package/dist/infrastructure/conversations/session-bundle.d.ts +6 -0
  344. package/dist/infrastructure/conversations/session-bundle.js +98 -0
  345. package/dist/infrastructure/conversations/session-bundle.js.map +1 -0
  346. package/dist/infrastructure/conversations/session-bundle.types.d.ts +1 -0
  347. package/dist/infrastructure/conversations/session-bundle.types.js +2 -0
  348. package/dist/infrastructure/conversations/session-bundle.types.js.map +1 -0
  349. package/dist/infrastructure/conversations.js +4 -2
  350. package/dist/infrastructure/conversations.js.map +1 -1
  351. package/dist/infrastructure/conversations.types.d.ts +1 -1
  352. package/dist/infrastructure/conversations.types.js.map +1 -1
  353. package/dist/infrastructure/custom-reporter.js +32 -24
  354. package/dist/infrastructure/custom-reporter.js.map +1 -1
  355. package/dist/infrastructure/custom-reporter.types.d.ts +2 -0
  356. package/dist/infrastructure/custom-reporter.types.js.map +1 -1
  357. package/dist/infrastructure/git/workspace-lease.js +4 -3
  358. package/dist/infrastructure/git/workspace-lease.js.map +1 -1
  359. package/dist/infrastructure/git/workspace.js +7 -6
  360. package/dist/infrastructure/git/workspace.js.map +1 -1
  361. package/dist/infrastructure/git/workspace.types.d.ts +1 -0
  362. package/dist/infrastructure/git/workspace.types.js.map +1 -1
  363. package/dist/infrastructure/journal.constants.js +10 -1
  364. package/dist/infrastructure/journal.constants.js.map +1 -1
  365. package/dist/infrastructure/journal.d.ts +1 -1
  366. package/dist/infrastructure/journal.js +2 -2
  367. package/dist/infrastructure/journal.js.map +1 -1
  368. package/dist/infrastructure/journal.types.d.ts +2 -2
  369. package/dist/infrastructure/journal.types.js.map +1 -1
  370. package/dist/infrastructure/opentelemetry-dispatch.d.ts +3 -3
  371. package/dist/infrastructure/opentelemetry-dispatch.js +5 -4
  372. package/dist/infrastructure/opentelemetry-dispatch.js.map +1 -1
  373. package/dist/infrastructure/opentelemetry-observation.d.ts +5 -0
  374. package/dist/infrastructure/opentelemetry-observation.js +59 -0
  375. package/dist/infrastructure/opentelemetry-observation.js.map +1 -0
  376. package/dist/infrastructure/opentelemetry.js +15 -1
  377. package/dist/infrastructure/opentelemetry.js.map +1 -1
  378. package/dist/infrastructure/opentelemetry.types.d.ts +9 -1
  379. package/dist/infrastructure/opentelemetry.types.js.map +1 -1
  380. package/dist/infrastructure/reporter.d.ts +2 -2
  381. package/dist/infrastructure/reporter.js +5 -1
  382. package/dist/infrastructure/reporter.js.map +1 -1
  383. package/dist/infrastructure/s3-transport.constants.d.ts +2 -0
  384. package/dist/infrastructure/s3-transport.constants.js +3 -0
  385. package/dist/infrastructure/s3-transport.constants.js.map +1 -0
  386. package/dist/infrastructure/s3-transport.js +57 -3
  387. package/dist/infrastructure/s3-transport.js.map +1 -1
  388. package/dist/infrastructure/s3-transport.types.d.ts +1 -0
  389. package/dist/infrastructure/s3-transport.types.js.map +1 -1
  390. package/dist/infrastructure/speculation-store.constants.d.ts +3 -0
  391. package/dist/infrastructure/speculation-store.constants.js +2 -0
  392. package/dist/infrastructure/speculation-store.constants.js.map +1 -0
  393. package/dist/infrastructure/speculation-store.d.ts +4 -0
  394. package/dist/infrastructure/speculation-store.js +73 -0
  395. package/dist/infrastructure/speculation-store.js.map +1 -0
  396. package/dist/infrastructure/speculation-store.types.d.ts +12 -0
  397. package/dist/infrastructure/speculation-store.types.js +2 -0
  398. package/dist/infrastructure/speculation-store.types.js.map +1 -0
  399. package/dist/infrastructure/task-queue-bullmq-resources.js +3 -0
  400. package/dist/infrastructure/task-queue-bullmq-resources.js.map +1 -1
  401. package/dist/infrastructure/task-queue-http.js +29 -4
  402. package/dist/infrastructure/task-queue-http.js.map +1 -1
  403. package/dist/infrastructure/task-queue-http.types.d.ts +2 -2
  404. package/dist/infrastructure/task-queue-http.types.js.map +1 -1
  405. package/dist/infrastructure/transport-conversations.js +2 -0
  406. package/dist/infrastructure/transport-conversations.js.map +1 -1
  407. package/dist/infrastructure/transport-journal.d.ts +1 -1
  408. package/dist/infrastructure/transport-journal.js +8 -2
  409. package/dist/infrastructure/transport-journal.js.map +1 -1
  410. package/dist/infrastructure/workflow-decision-signature.constants.d.ts +4 -0
  411. package/dist/infrastructure/workflow-decision-signature.constants.js +5 -0
  412. package/dist/infrastructure/workflow-decision-signature.constants.js.map +1 -0
  413. package/dist/infrastructure/workflow-decision-signature.d.ts +4 -0
  414. package/dist/infrastructure/workflow-decision-signature.js +83 -0
  415. package/dist/infrastructure/workflow-decision-signature.js.map +1 -0
  416. package/dist/infrastructure/workflow-decision-signature.types.d.ts +16 -0
  417. package/dist/infrastructure/workflow-decision-signature.types.js +2 -0
  418. package/dist/infrastructure/workflow-decision-signature.types.js.map +1 -0
  419. package/dist/providers/antigravity-install.constants.d.ts +2 -0
  420. package/dist/providers/antigravity-install.constants.js +28 -0
  421. package/dist/providers/antigravity-install.constants.js.map +1 -0
  422. package/dist/providers/antigravity-install.d.ts +2 -0
  423. package/dist/providers/antigravity-install.js +29 -0
  424. package/dist/providers/antigravity-install.js.map +1 -0
  425. package/dist/providers/antigravity-install.types.d.ts +4 -0
  426. package/dist/providers/antigravity-install.types.js +2 -0
  427. package/dist/providers/antigravity-install.types.js.map +1 -0
  428. package/dist/providers/container-recovery.d.ts +4 -0
  429. package/dist/providers/container-recovery.js +28 -0
  430. package/dist/providers/container-recovery.js.map +1 -0
  431. package/dist/providers/container.js +8 -0
  432. package/dist/providers/container.js.map +1 -1
  433. package/dist/providers/daytona-network.constants.d.ts +5 -0
  434. package/dist/providers/daytona-network.constants.js +8 -0
  435. package/dist/providers/daytona-network.constants.js.map +1 -0
  436. package/dist/providers/daytona-network.d.ts +4 -0
  437. package/dist/providers/daytona-network.js +33 -0
  438. package/dist/providers/daytona-network.js.map +1 -0
  439. package/dist/providers/daytona.d.ts +1 -0
  440. package/dist/providers/daytona.js +9 -3
  441. package/dist/providers/daytona.js.map +1 -1
  442. package/dist/providers/daytona.types.d.ts +2 -0
  443. package/dist/providers/daytona.types.js.map +1 -1
  444. package/dist/providers/firecracker-command.js +1 -1
  445. package/dist/providers/firecracker-command.js.map +1 -1
  446. package/dist/providers/firecracker-jailer.constants.d.ts +9 -0
  447. package/dist/providers/firecracker-jailer.constants.js +10 -0
  448. package/dist/providers/firecracker-jailer.constants.js.map +1 -0
  449. package/dist/providers/firecracker-jailer.d.ts +4 -0
  450. package/dist/providers/firecracker-jailer.js +171 -0
  451. package/dist/providers/firecracker-jailer.js.map +1 -0
  452. package/dist/providers/firecracker-machine.js +30 -8
  453. package/dist/providers/firecracker-machine.js.map +1 -1
  454. package/dist/providers/firecracker.types.d.ts +16 -0
  455. package/dist/providers/firecracker.types.js.map +1 -1
  456. package/dist/providers/vercel-network.js +1 -1
  457. package/dist/providers/vercel-network.js.map +1 -1
  458. package/dist/providers/vercel.js +6 -3
  459. package/dist/providers/vercel.js.map +1 -1
  460. package/dist/providers/versions.constants.d.ts +1 -1
  461. package/dist/providers/versions.constants.js +1 -1
  462. package/dist/providers/versions.constants.js.map +1 -1
  463. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import { createHash } from "node:crypto";
1
+ import { taskIdempotencyKey } from "../domain/workflow/idempotency.js";
2
2
  import { setTimeout as delay } from "node:timers/promises";
3
3
  import { task } from "../domain/workflow.js";
4
4
  import { queueDefaultPollMs } from "../domain/task-queue.constants.js";
@@ -14,15 +14,18 @@ export function queuedTask(options) {
14
14
  ...definition,
15
15
  async perform(context) {
16
16
  context.signal.throwIfAborted();
17
- const id = createHash("sha256")
18
- .update(JSON.stringify([context.executionId, definition.key]))
19
- .digest("hex");
17
+ const id = taskIdempotencyKey(context.executionId, definition.key);
20
18
  let job = await queue.enqueue({
21
19
  id,
22
20
  handler,
23
21
  input: input(context),
24
22
  ...(deadline === undefined ? {} : { deadline }),
25
23
  });
24
+ context.observation?.emit("workflow", {
25
+ kind: "queue",
26
+ id,
27
+ status: "enqueued",
28
+ });
26
29
  try {
27
30
  while (job.status === "pending" || job.status === "active") {
28
31
  await delay(pollMs, undefined, { signal: context.signal });
@@ -30,6 +33,11 @@ export function queuedTask(options) {
30
33
  if (!latest)
31
34
  throw new Error("Queued workflow job disappeared");
32
35
  job = latest;
36
+ context.observation?.emit("workflow", {
37
+ kind: "queue",
38
+ id,
39
+ status: "polled",
40
+ });
33
41
  }
34
42
  if (job.result?.usage) {
35
43
  if (context.reportUsageOnce)
@@ -40,9 +48,20 @@ export function queuedTask(options) {
40
48
  if (job.status !== "done" || !job.result)
41
49
  throw new Error(job.result?.error ?? "Queued workflow job cancelled");
42
50
  context.signal.throwIfAborted();
43
- return decode(job.result.value);
51
+ const value = decode(job.result.value);
52
+ context.observation?.emit("workflow", {
53
+ kind: "queue",
54
+ id,
55
+ status: "completed",
56
+ });
57
+ return value;
44
58
  }
45
59
  catch (error) {
60
+ context.observation?.emit("workflow", {
61
+ kind: "queue",
62
+ id,
63
+ status: "failed",
64
+ });
46
65
  if (context.signal.aborted) {
47
66
  const latest = await queue.get(id);
48
67
  if (latest)
@@ -1 +1 @@
1
- {"version":3,"file":"queued-task.js","sourceRoot":"","sources":["../../src/application/queued-task.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { setTimeout as delay } from \"node:timers/promises\";\nimport { task } from \"../domain/workflow.ts\";\nimport { queueDefaultPollMs } from \"../domain/task-queue.constants.ts\";\nimport { queueNumber, queueString } from \"../domain/task-queue.ts\";\nimport type { Task } from \"../domain/workflow.types.ts\";\nimport type { QueuedTaskOptions } from \"./queued-task.types.ts\";\n\nexport function queuedTask<T>(options: QueuedTaskOptions<T>): Task<T> {\n const {\n queue,\n handler,\n input,\n decode,\n deadline,\n pollMs = queueDefaultPollMs,\n ...definition\n } = options;\n queueString(handler);\n if (!queueNumber(pollMs))\n throw new Error(\"Queue poll interval must be positive\");\n if (deadline !== undefined) queueNumber(deadline);\n return task({\n ...definition,\n async perform(context) {\n context.signal.throwIfAborted();\n const id = createHash(\"sha256\")\n .update(JSON.stringify([context.executionId, definition.key]))\n .digest(\"hex\");\n let job = await queue.enqueue({\n id,\n handler,\n input: input(context),\n ...(deadline === undefined ? {} : { deadline }),\n });\n try {\n while (job.status === \"pending\" || job.status === \"active\") {\n await delay(pollMs, undefined, { signal: context.signal });\n const latest = await queue.get(id);\n if (!latest) throw new Error(\"Queued workflow job disappeared\");\n job = latest;\n }\n if (job.result?.usage) {\n if (context.reportUsageOnce)\n context.reportUsageOnce(`queue:${id}`, job.result.usage);\n else context.reportUsage(job.result.usage);\n }\n if (job.status !== \"done\" || !job.result)\n throw new Error(job.result?.error ?? \"Queued workflow job cancelled\");\n context.signal.throwIfAborted();\n return decode(job.result.value);\n } catch (error) {\n if (context.signal.aborted) {\n const latest = await queue.get(id);\n if (latest) await queue.cancel(id, latest.fence);\n }\n throw error;\n }\n },\n });\n}\n"]}
1
+ {"version":3,"file":"queued-task.js","sourceRoot":"","sources":["../../src/application/queued-task.ts"],"names":[],"mappings":"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","sourcesContent":["import { taskIdempotencyKey } from \"../domain/workflow/idempotency.ts\";\nimport { setTimeout as delay } from \"node:timers/promises\";\nimport { task } from \"../domain/workflow.ts\";\nimport { queueDefaultPollMs } from \"../domain/task-queue.constants.ts\";\nimport { queueNumber, queueString } from \"../domain/task-queue.ts\";\nimport type { Task } from \"../domain/workflow.types.ts\";\nimport type { QueuedTaskOptions } from \"./queued-task.types.ts\";\n\nexport function queuedTask<T>(options: QueuedTaskOptions<T>): Task<T> {\n const {\n queue,\n handler,\n input,\n decode,\n deadline,\n pollMs = queueDefaultPollMs,\n ...definition\n } = options;\n queueString(handler);\n if (!queueNumber(pollMs))\n throw new Error(\"Queue poll interval must be positive\");\n if (deadline !== undefined) queueNumber(deadline);\n return task({\n ...definition,\n async perform(context) {\n context.signal.throwIfAborted();\n const id = taskIdempotencyKey(context.executionId, definition.key);\n let job = await queue.enqueue({\n id,\n handler,\n input: input(context),\n ...(deadline === undefined ? {} : { deadline }),\n });\n context.observation?.emit(\"workflow\", {\n kind: \"queue\",\n id,\n status: \"enqueued\",\n });\n try {\n while (job.status === \"pending\" || job.status === \"active\") {\n await delay(pollMs, undefined, { signal: context.signal });\n const latest = await queue.get(id);\n if (!latest) throw new Error(\"Queued workflow job disappeared\");\n job = latest;\n context.observation?.emit(\"workflow\", {\n kind: \"queue\",\n id,\n status: \"polled\",\n });\n }\n if (job.result?.usage) {\n if (context.reportUsageOnce)\n context.reportUsageOnce(`queue:${id}`, job.result.usage);\n else context.reportUsage(job.result.usage);\n }\n if (job.status !== \"done\" || !job.result)\n throw new Error(job.result?.error ?? \"Queued workflow job cancelled\");\n context.signal.throwIfAborted();\n const value = decode(job.result.value);\n context.observation?.emit(\"workflow\", {\n kind: \"queue\",\n id,\n status: \"completed\",\n });\n return value;\n } catch (error) {\n context.observation?.emit(\"workflow\", {\n kind: \"queue\",\n id,\n status: \"failed\",\n });\n if (context.signal.aborted) {\n const latest = await queue.get(id);\n if (latest) await queue.cancel(id, latest.fence);\n }\n throw error;\n }\n },\n });\n}\n"]}
@@ -1,4 +1,5 @@
1
+ import type { ObservationHub } from "../domain/observation.types.ts";
1
2
  import type { TransportReference } from "../domain/transport.types.ts";
2
3
  import type { RecoveryArchiveOptions, RecoveryArchiveRestoreOptions } from "./recovery-archive.types.ts";
3
- export declare function archiveRecovery(options: RecoveryArchiveOptions): Promise<TransportReference>;
4
- export declare function materializeRecoveryArchive(options: RecoveryArchiveRestoreOptions): Promise<string>;
4
+ export declare function archiveRecovery(options: RecoveryArchiveOptions, observation?: ObservationHub): Promise<TransportReference>;
5
+ export declare function materializeRecoveryArchive(options: RecoveryArchiveRestoreOptions, observation?: ObservationHub): Promise<string>;
@@ -1,3 +1,4 @@
1
+ import { observedOperation } from "../domain/observed-operation.js";
1
2
  import { randomUUID } from "node:crypto";
2
3
  import { archiveFiles, restoreArchiveFiles, } from "../infrastructure/transport-archive.js";
3
4
  import { snapshotRecoveryTransfer } from "./recovery-restore-snapshot.js";
@@ -5,7 +6,7 @@ import { recoveryChecksumPaths } from "./recovery-checksum-paths.js";
5
6
  import { recoveryChecksumDefaults } from "./recovery-checksums.constants.js";
6
7
  import { verifyRecoveryTransfer } from "./recovery-verification.js";
7
8
  import { invariant } from "../domain/errors.js";
8
- export async function archiveRecovery(options) {
9
+ async function archiveRecoveryOperation(options) {
9
10
  const snapshot = await snapshotRecoveryTransfer(options.directory, options.maxBytes);
10
11
  try {
11
12
  return await archiveFiles(options.transporter, snapshot.directory, [
@@ -17,7 +18,7 @@ export async function archiveRecovery(options) {
17
18
  await snapshot.dispose();
18
19
  }
19
20
  }
20
- export async function materializeRecoveryArchive(options) {
21
+ async function materializeRecoveryOperation(options) {
21
22
  await restoreArchiveFiles(options.transporter, options.reference, options.destination, options.maxBytes);
22
23
  const verified = await verifyRecoveryTransfer(options.destination, {
23
24
  checksums: true,
@@ -26,4 +27,10 @@ export async function materializeRecoveryArchive(options) {
26
27
  invariant(verified.complete && verified.integrity === "checksums-match", "Recovery archive integrity verification failed; destination retained");
27
28
  return options.destination;
28
29
  }
30
+ export function archiveRecovery(options, observation) {
31
+ return observedOperation(observation, "transfer", "recovery.archive", () => archiveRecoveryOperation(options));
32
+ }
33
+ export function materializeRecoveryArchive(options, observation) {
34
+ return observedOperation(observation, "transfer", "recovery.materialize", () => materializeRecoveryOperation(options));
35
+ }
29
36
  //# sourceMappingURL=recovery-archive.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"recovery-archive.js","sourceRoot":"","sources":["../../src/application/recovery-archive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EACL,YAAY,EACZ,mBAAmB,GACpB,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAC1E,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAC7E,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAMhD,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,OAA+B;IAE/B,MAAM,QAAQ,GAAG,MAAM,wBAAwB,CAC7C,OAAO,CAAC,SAAS,EACjB,OAAO,CAAC,QAAQ,CACjB,CAAC;IACF,IAAI,CAAC;QACH,OAAO,MAAM,YAAY,CACvB,OAAO,CAAC,WAAW,EACnB,QAAQ,CAAC,SAAS,EAClB;YACE,GAAG,qBAAqB,CAAC,QAAQ,CAAC,KAAK,CAAC;YACxC,wBAAwB,CAAC,QAAQ;SAClC,EACD,YAAY,UAAU,EAAE,EAAE,EAC1B,OAAO,CAAC,QAAQ,CACjB,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,MAAM,QAAQ,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,OAAsC;IAEtC,MAAM,mBAAmB,CACvB,OAAO,CAAC,WAAW,EACnB,OAAO,CAAC,SAAS,EACjB,OAAO,CAAC,WAAW,EACnB,OAAO,CAAC,QAAQ,CACjB,CAAC;IACF,MAAM,QAAQ,GAAG,MAAM,sBAAsB,CAAC,OAAO,CAAC,WAAW,EAAE;QACjE,SAAS,EAAE,IAAI;QACf,GAAG,CAAC,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC;KAC1E,CAAC,CAAC;IACH,SAAS,CACP,QAAQ,CAAC,QAAQ,IAAI,QAAQ,CAAC,SAAS,KAAK,iBAAiB,EAC7D,sEAAsE,CACvE,CAAC;IACF,OAAO,OAAO,CAAC,WAAW,CAAC;AAC7B,CAAC","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport type { TransportReference } from \"../domain/transport.types.ts\";\nimport {\n archiveFiles,\n restoreArchiveFiles,\n} from \"../infrastructure/transport-archive.ts\";\nimport { snapshotRecoveryTransfer } from \"./recovery-restore-snapshot.ts\";\nimport { recoveryChecksumPaths } from \"./recovery-checksum-paths.ts\";\nimport { recoveryChecksumDefaults } from \"./recovery-checksums.constants.ts\";\nimport { verifyRecoveryTransfer } from \"./recovery-verification.ts\";\nimport { invariant } from \"../domain/errors.ts\";\nimport type {\n RecoveryArchiveOptions,\n RecoveryArchiveRestoreOptions,\n} from \"./recovery-archive.types.ts\";\n\nexport async function archiveRecovery(\n options: RecoveryArchiveOptions,\n): Promise<TransportReference> {\n const snapshot = await snapshotRecoveryTransfer(\n options.directory,\n options.maxBytes,\n );\n try {\n return await archiveFiles(\n options.transporter,\n snapshot.directory,\n [\n ...recoveryChecksumPaths(snapshot.state),\n recoveryChecksumDefaults.filename,\n ],\n `recovery/${randomUUID()}`,\n options.maxBytes,\n );\n } finally {\n await snapshot.dispose();\n }\n}\n\nexport async function materializeRecoveryArchive(\n options: RecoveryArchiveRestoreOptions,\n): Promise<string> {\n await restoreArchiveFiles(\n options.transporter,\n options.reference,\n options.destination,\n options.maxBytes,\n );\n const verified = await verifyRecoveryTransfer(options.destination, {\n checksums: true,\n ...(options.maxBytes === undefined ? {} : { maxBytes: options.maxBytes }),\n });\n invariant(\n verified.complete && verified.integrity === \"checksums-match\",\n \"Recovery archive integrity verification failed; destination retained\",\n );\n return options.destination;\n}\n"]}
1
+ {"version":3,"file":"recovery-archive.js","sourceRoot":"","sources":["../../src/application/recovery-archive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EACL,YAAY,EACZ,mBAAmB,GACpB,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAC1E,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAC7E,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAMhD,KAAK,UAAU,wBAAwB,CACrC,OAA+B;IAE/B,MAAM,QAAQ,GAAG,MAAM,wBAAwB,CAC7C,OAAO,CAAC,SAAS,EACjB,OAAO,CAAC,QAAQ,CACjB,CAAC;IACF,IAAI,CAAC;QACH,OAAO,MAAM,YAAY,CACvB,OAAO,CAAC,WAAW,EACnB,QAAQ,CAAC,SAAS,EAClB;YACE,GAAG,qBAAqB,CAAC,QAAQ,CAAC,KAAK,CAAC;YACxC,wBAAwB,CAAC,QAAQ;SAClC,EACD,YAAY,UAAU,EAAE,EAAE,EAC1B,OAAO,CAAC,QAAQ,CACjB,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,MAAM,QAAQ,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;AACH,CAAC;AAED,KAAK,UAAU,4BAA4B,CACzC,OAAsC;IAEtC,MAAM,mBAAmB,CACvB,OAAO,CAAC,WAAW,EACnB,OAAO,CAAC,SAAS,EACjB,OAAO,CAAC,WAAW,EACnB,OAAO,CAAC,QAAQ,CACjB,CAAC;IACF,MAAM,QAAQ,GAAG,MAAM,sBAAsB,CAAC,OAAO,CAAC,WAAW,EAAE;QACjE,SAAS,EAAE,IAAI;QACf,GAAG,CAAC,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC;KAC1E,CAAC,CAAC;IACH,SAAS,CACP,QAAQ,CAAC,QAAQ,IAAI,QAAQ,CAAC,SAAS,KAAK,iBAAiB,EAC7D,sEAAsE,CACvE,CAAC;IACF,OAAO,OAAO,CAAC,WAAW,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,OAA+B,EAC/B,WAA4B;IAE5B,OAAO,iBAAiB,CAAC,WAAW,EAAE,UAAU,EAAE,kBAAkB,EAAE,GAAG,EAAE,CACzE,wBAAwB,CAAC,OAAO,CAAC,CAClC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,0BAA0B,CACxC,OAAsC,EACtC,WAA4B;IAE5B,OAAO,iBAAiB,CACtB,WAAW,EACX,UAAU,EACV,sBAAsB,EACtB,GAAG,EAAE,CAAC,4BAA4B,CAAC,OAAO,CAAC,CAC5C,CAAC;AACJ,CAAC","sourcesContent":["import { observedOperation } from \"../domain/observed-operation.ts\";\nimport type { ObservationHub } from \"../domain/observation.types.ts\";\nimport { randomUUID } from \"node:crypto\";\nimport type { TransportReference } from \"../domain/transport.types.ts\";\nimport {\n archiveFiles,\n restoreArchiveFiles,\n} from \"../infrastructure/transport-archive.ts\";\nimport { snapshotRecoveryTransfer } from \"./recovery-restore-snapshot.ts\";\nimport { recoveryChecksumPaths } from \"./recovery-checksum-paths.ts\";\nimport { recoveryChecksumDefaults } from \"./recovery-checksums.constants.ts\";\nimport { verifyRecoveryTransfer } from \"./recovery-verification.ts\";\nimport { invariant } from \"../domain/errors.ts\";\nimport type {\n RecoveryArchiveOptions,\n RecoveryArchiveRestoreOptions,\n} from \"./recovery-archive.types.ts\";\n\nasync function archiveRecoveryOperation(\n options: RecoveryArchiveOptions,\n): Promise<TransportReference> {\n const snapshot = await snapshotRecoveryTransfer(\n options.directory,\n options.maxBytes,\n );\n try {\n return await archiveFiles(\n options.transporter,\n snapshot.directory,\n [\n ...recoveryChecksumPaths(snapshot.state),\n recoveryChecksumDefaults.filename,\n ],\n `recovery/${randomUUID()}`,\n options.maxBytes,\n );\n } finally {\n await snapshot.dispose();\n }\n}\n\nasync function materializeRecoveryOperation(\n options: RecoveryArchiveRestoreOptions,\n): Promise<string> {\n await restoreArchiveFiles(\n options.transporter,\n options.reference,\n options.destination,\n options.maxBytes,\n );\n const verified = await verifyRecoveryTransfer(options.destination, {\n checksums: true,\n ...(options.maxBytes === undefined ? {} : { maxBytes: options.maxBytes }),\n });\n invariant(\n verified.complete && verified.integrity === \"checksums-match\",\n \"Recovery archive integrity verification failed; destination retained\",\n );\n return options.destination;\n}\n\nexport function archiveRecovery(\n options: RecoveryArchiveOptions,\n observation?: ObservationHub,\n): Promise<TransportReference> {\n return observedOperation(observation, \"transfer\", \"recovery.archive\", () =>\n archiveRecoveryOperation(options),\n );\n}\n\nexport function materializeRecoveryArchive(\n options: RecoveryArchiveRestoreOptions,\n observation?: ObservationHub,\n): Promise<string> {\n return observedOperation(\n observation,\n \"transfer\",\n \"recovery.materialize\",\n () => materializeRecoveryOperation(options),\n );\n}\n"]}
@@ -1,3 +1,4 @@
1
+ import type { ObservationHub } from "../domain/observation.types.ts";
1
2
  import type { RecoveryRestoreOptions, RecoveryRestorePlan, RecoveryRestoreResult } from "./recovery-restore.types.ts";
2
- export declare function planRecoveryRestore(options: RecoveryRestoreOptions): Promise<RecoveryRestorePlan>;
3
- export declare function restoreRecoveryTransfer(plan: RecoveryRestorePlan): Promise<RecoveryRestoreResult>;
3
+ export declare function planRecoveryRestore(options: RecoveryRestoreOptions, observation?: ObservationHub): Promise<RecoveryRestorePlan>;
4
+ export declare function restoreRecoveryTransfer(plan: RecoveryRestorePlan, observation?: ObservationHub): Promise<RecoveryRestoreResult>;
@@ -1,3 +1,4 @@
1
+ import { observedOperation } from "../domain/observed-operation.js";
1
2
  import { createHash } from "node:crypto";
2
3
  import { cp, lstat, mkdir } from "node:fs/promises";
3
4
  import { basename, dirname, join, resolve } from "node:path";
@@ -48,7 +49,7 @@ async function locations(options) {
48
49
  await absent(destination);
49
50
  return { repository, directory: transfer, destination };
50
51
  }
51
- export async function planRecoveryRestore(options) {
52
+ async function planRecoveryRestoreOperation(options) {
52
53
  const paths = await locations(options);
53
54
  const snapshot = await snapshotRecoveryTransfer(paths.directory, options.maxBytes);
54
55
  try {
@@ -84,7 +85,7 @@ async function applyPatch(checkout, patch, cached = false) {
84
85
  patch,
85
86
  ]);
86
87
  }
87
- export async function restoreRecoveryTransfer(plan) {
88
+ async function restoreRecoveryOperation(plan) {
88
89
  invariant(plan.fingerprint === planFingerprint(plan), "Recovery plan changed after planning");
89
90
  const paths = await locations(plan);
90
91
  invariant(paths.repository === plan.repository &&
@@ -158,4 +159,10 @@ export async function restoreRecoveryTransfer(plan) {
158
159
  await snapshot.dispose();
159
160
  }
160
161
  }
162
+ export function planRecoveryRestore(options, observation) {
163
+ return observedOperation(observation, "recovery", "restore.plan", () => planRecoveryRestoreOperation(options));
164
+ }
165
+ export function restoreRecoveryTransfer(plan, observation) {
166
+ return observedOperation(observation, "recovery", "restore.apply", () => restoreRecoveryOperation(plan));
167
+ }
161
168
  //# sourceMappingURL=recovery-restore.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"recovery-restore.js","sourceRoot":"","sources":["../../src/application/recovery-restore.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { cp, lstat, mkdir } from \"node:fs/promises\";\nimport { basename, dirname, join, resolve } from \"node:path\";\nimport { invariant, OutpostError } from \"../domain/errors.ts\";\nimport { directory, inside, safeDestination } from \"../infrastructure/files.ts\";\nimport { verificationGit as git } from \"../infrastructure/git/verification-command.ts\";\nimport { verifyRecoveryRestorability } from \"./recovery-restorability.ts\";\nimport { snapshotRecoveryTransfer } from \"./recovery-restore-snapshot.ts\";\nimport type {\n RecoveryRestoreOptions,\n RecoveryRestorePlan,\n RecoveryRestoreResult,\n} from \"./recovery-restore.types.ts\";\n\nfunction planFingerprint(\n plan: Omit<RecoveryRestorePlan, \"fingerprint\">,\n): string {\n return createHash(\"sha256\")\n .update(\n JSON.stringify([\n plan.directory,\n plan.repository,\n plan.destination,\n plan.side,\n plan.maxBytes ?? null,\n plan.manifestSha256,\n plan.commit,\n plan.payloads,\n plan.staging,\n ]),\n )\n .digest(\"hex\");\n}\n\nasync function absent(path: string): Promise<void> {\n const present = await lstat(path).then(\n () => true,\n (error: unknown) => {\n if (\n error &&\n typeof error === \"object\" &&\n \"code\" in error &&\n error.code === \"ENOENT\"\n )\n return false;\n throw error;\n },\n );\n invariant(!present, \"Recovery destination already exists\");\n}\n\nasync function locations(options: RecoveryRestoreOptions) {\n invariant(\n options.side === \"previous\" || options.side === \"incoming\",\n \"Recovery side must be previous or incoming\",\n );\n const repository = await directory(options.repository);\n const transfer = await directory(options.directory);\n const destination = join(\n await directory(dirname(resolve(options.destination))),\n basename(resolve(options.destination)),\n );\n const common = await directory(\n (\n await git(repository, [\n \"rev-parse\",\n \"--path-format=absolute\",\n \"--git-common-dir\",\n ])\n ).trim(),\n );\n invariant(\n !inside(repository, destination) &&\n !inside(transfer, destination) &&\n !inside(common, destination),\n \"Recovery destination must be outside the source repository, Git metadata and transfer\",\n );\n await absent(destination);\n return { repository, directory: transfer, destination };\n}\n\nexport async function planRecoveryRestore(\n options: RecoveryRestoreOptions,\n): Promise<RecoveryRestorePlan> {\n const paths = await locations(options);\n const snapshot = await snapshotRecoveryTransfer(\n paths.directory,\n options.maxBytes,\n );\n try {\n const checks = await verifyRecoveryRestorability(\n snapshot.directory,\n snapshot.state,\n paths.repository,\n );\n invariant(\n checks.every((check) => check.status === \"pass\"),\n \"Recovery Git restorability verification failed\",\n );\n const plan = {\n ...options,\n ...paths,\n manifestSha256: snapshot.manifestSha256,\n commit:\n options.side === \"previous\"\n ? snapshot.state.previous\n : snapshot.state.next,\n payloads:\n options.side === \"previous\"\n ? snapshot.state.previousExtras\n : snapshot.state.incoming,\n staging:\n options.side === \"previous\"\n ? (\"preserved\" as const)\n : (\"unavailable\" as const),\n };\n return { ...plan, fingerprint: planFingerprint(plan) };\n } finally {\n await snapshot.dispose();\n }\n}\n\nasync function applyPatch(\n checkout: string,\n patch: string,\n cached = false,\n): Promise<void> {\n if (!(await lstat(patch)).size) return;\n await git(checkout, [\n \"apply\",\n \"--binary\",\n ...(cached ? [\"--cached\"] : []),\n patch,\n ]);\n}\n\nexport async function restoreRecoveryTransfer(\n plan: RecoveryRestorePlan,\n): Promise<RecoveryRestoreResult> {\n invariant(\n plan.fingerprint === planFingerprint(plan),\n \"Recovery plan changed after planning\",\n );\n const paths = await locations(plan);\n invariant(\n paths.repository === plan.repository &&\n paths.directory === plan.directory &&\n paths.destination === plan.destination,\n \"Recovery plan paths changed after planning\",\n );\n const snapshot = await snapshotRecoveryTransfer(\n paths.directory,\n plan.maxBytes,\n );\n let owned = false;\n try {\n invariant(\n snapshot.manifestSha256 === plan.manifestSha256,\n \"Recovery transfer changed since planning\",\n );\n const commit =\n plan.side === \"previous\" ? snapshot.state.previous : snapshot.state.next;\n invariant(commit === plan.commit, \"Recovery plan commit changed\");\n const checks = await verifyRecoveryRestorability(\n snapshot.directory,\n snapshot.state,\n paths.repository,\n );\n invariant(\n checks.every((check) => check.status === \"pass\"),\n \"Recovery Git restorability verification failed\",\n );\n await mkdir(paths.destination, { mode: 0o700 });\n owned = true;\n await git(dirname(paths.destination), [\n \"clone\",\n \"--local\",\n \"--no-hardlinks\",\n \"--no-checkout\",\n \"--\",\n paths.repository,\n paths.destination,\n ]);\n await git(paths.destination, [\"remote\", \"remove\", \"origin\"]);\n if (snapshot.state.previous !== snapshot.state.next) {\n await git(paths.destination, [\n \"bundle\",\n \"verify\",\n join(snapshot.directory, \"commits.bundle\"),\n ]);\n await git(paths.destination, [\n \"bundle\",\n \"unbundle\",\n join(snapshot.directory, \"commits.bundle\"),\n ]);\n }\n await git(paths.destination, [\"checkout\", \"--detach\", commit]);\n await applyPatch(\n paths.destination,\n join(\n snapshot.directory,\n plan.side === \"previous\" ? \"previous.patch\" : \"remote.patch\",\n ),\n );\n if (plan.side === \"previous\")\n await applyPatch(\n paths.destination,\n join(snapshot.directory, \"previous-index.patch\"),\n true,\n );\n const entries =\n plan.side === \"previous\"\n ? snapshot.state.previousExtras\n : snapshot.state.incoming;\n const prefix = plan.side === \"previous\" ? \"previous-files\" : \"incoming\";\n for (const entry of entries) {\n const to = await safeDestination(paths.destination, entry);\n await absent(to);\n await mkdir(dirname(to), { recursive: true, mode: 0o700 });\n await cp(\n await safeDestination(snapshot.directory, `${prefix}/${entry}`),\n to,\n {\n dereference: false,\n verbatimSymlinks: true,\n force: false,\n errorOnExist: true,\n },\n );\n }\n return {\n directory: paths.destination,\n commit,\n side: plan.side,\n staging: plan.side === \"previous\" ? \"preserved\" : \"unavailable\",\n sourceRetained: true,\n };\n } catch (cause) {\n if (!owned) throw cause;\n throw new OutpostError(\n \"workspace\",\n \"Recovery restoration failed; source and partial destination retained\",\n { destination: paths.destination, transfer: paths.directory },\n cause,\n );\n } finally {\n await snapshot.dispose();\n }\n}\n"]}
1
+ {"version":3,"file":"recovery-restore.js","sourceRoot":"","sources":["../../src/application/recovery-restore.ts"],"names":[],"mappings":"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","sourcesContent":["import { observedOperation } from \"../domain/observed-operation.ts\";\nimport type { ObservationHub } from \"../domain/observation.types.ts\";\nimport { createHash } from \"node:crypto\";\nimport { cp, lstat, mkdir } from \"node:fs/promises\";\nimport { basename, dirname, join, resolve } from \"node:path\";\nimport { invariant, OutpostError } from \"../domain/errors.ts\";\nimport { directory, inside, safeDestination } from \"../infrastructure/files.ts\";\nimport { verificationGit as git } from \"../infrastructure/git/verification-command.ts\";\nimport { verifyRecoveryRestorability } from \"./recovery-restorability.ts\";\nimport { snapshotRecoveryTransfer } from \"./recovery-restore-snapshot.ts\";\nimport type {\n RecoveryRestoreOptions,\n RecoveryRestorePlan,\n RecoveryRestoreResult,\n} from \"./recovery-restore.types.ts\";\n\nfunction planFingerprint(\n plan: Omit<RecoveryRestorePlan, \"fingerprint\">,\n): string {\n return createHash(\"sha256\")\n .update(\n JSON.stringify([\n plan.directory,\n plan.repository,\n plan.destination,\n plan.side,\n plan.maxBytes ?? null,\n plan.manifestSha256,\n plan.commit,\n plan.payloads,\n plan.staging,\n ]),\n )\n .digest(\"hex\");\n}\n\nasync function absent(path: string): Promise<void> {\n const present = await lstat(path).then(\n () => true,\n (error: unknown) => {\n if (\n error &&\n typeof error === \"object\" &&\n \"code\" in error &&\n error.code === \"ENOENT\"\n )\n return false;\n throw error;\n },\n );\n invariant(!present, \"Recovery destination already exists\");\n}\n\nasync function locations(options: RecoveryRestoreOptions) {\n invariant(\n options.side === \"previous\" || options.side === \"incoming\",\n \"Recovery side must be previous or incoming\",\n );\n const repository = await directory(options.repository);\n const transfer = await directory(options.directory);\n const destination = join(\n await directory(dirname(resolve(options.destination))),\n basename(resolve(options.destination)),\n );\n const common = await directory(\n (\n await git(repository, [\n \"rev-parse\",\n \"--path-format=absolute\",\n \"--git-common-dir\",\n ])\n ).trim(),\n );\n invariant(\n !inside(repository, destination) &&\n !inside(transfer, destination) &&\n !inside(common, destination),\n \"Recovery destination must be outside the source repository, Git metadata and transfer\",\n );\n await absent(destination);\n return { repository, directory: transfer, destination };\n}\n\nasync function planRecoveryRestoreOperation(\n options: RecoveryRestoreOptions,\n): Promise<RecoveryRestorePlan> {\n const paths = await locations(options);\n const snapshot = await snapshotRecoveryTransfer(\n paths.directory,\n options.maxBytes,\n );\n try {\n const checks = await verifyRecoveryRestorability(\n snapshot.directory,\n snapshot.state,\n paths.repository,\n );\n invariant(\n checks.every((check) => check.status === \"pass\"),\n \"Recovery Git restorability verification failed\",\n );\n const plan = {\n ...options,\n ...paths,\n manifestSha256: snapshot.manifestSha256,\n commit:\n options.side === \"previous\"\n ? snapshot.state.previous\n : snapshot.state.next,\n payloads:\n options.side === \"previous\"\n ? snapshot.state.previousExtras\n : snapshot.state.incoming,\n staging:\n options.side === \"previous\"\n ? (\"preserved\" as const)\n : (\"unavailable\" as const),\n };\n return { ...plan, fingerprint: planFingerprint(plan) };\n } finally {\n await snapshot.dispose();\n }\n}\n\nasync function applyPatch(\n checkout: string,\n patch: string,\n cached = false,\n): Promise<void> {\n if (!(await lstat(patch)).size) return;\n await git(checkout, [\n \"apply\",\n \"--binary\",\n ...(cached ? [\"--cached\"] : []),\n patch,\n ]);\n}\n\nasync function restoreRecoveryOperation(\n plan: RecoveryRestorePlan,\n): Promise<RecoveryRestoreResult> {\n invariant(\n plan.fingerprint === planFingerprint(plan),\n \"Recovery plan changed after planning\",\n );\n const paths = await locations(plan);\n invariant(\n paths.repository === plan.repository &&\n paths.directory === plan.directory &&\n paths.destination === plan.destination,\n \"Recovery plan paths changed after planning\",\n );\n const snapshot = await snapshotRecoveryTransfer(\n paths.directory,\n plan.maxBytes,\n );\n let owned = false;\n try {\n invariant(\n snapshot.manifestSha256 === plan.manifestSha256,\n \"Recovery transfer changed since planning\",\n );\n const commit =\n plan.side === \"previous\" ? snapshot.state.previous : snapshot.state.next;\n invariant(commit === plan.commit, \"Recovery plan commit changed\");\n const checks = await verifyRecoveryRestorability(\n snapshot.directory,\n snapshot.state,\n paths.repository,\n );\n invariant(\n checks.every((check) => check.status === \"pass\"),\n \"Recovery Git restorability verification failed\",\n );\n await mkdir(paths.destination, { mode: 0o700 });\n owned = true;\n await git(dirname(paths.destination), [\n \"clone\",\n \"--local\",\n \"--no-hardlinks\",\n \"--no-checkout\",\n \"--\",\n paths.repository,\n paths.destination,\n ]);\n await git(paths.destination, [\"remote\", \"remove\", \"origin\"]);\n if (snapshot.state.previous !== snapshot.state.next) {\n await git(paths.destination, [\n \"bundle\",\n \"verify\",\n join(snapshot.directory, \"commits.bundle\"),\n ]);\n await git(paths.destination, [\n \"bundle\",\n \"unbundle\",\n join(snapshot.directory, \"commits.bundle\"),\n ]);\n }\n await git(paths.destination, [\"checkout\", \"--detach\", commit]);\n await applyPatch(\n paths.destination,\n join(\n snapshot.directory,\n plan.side === \"previous\" ? \"previous.patch\" : \"remote.patch\",\n ),\n );\n if (plan.side === \"previous\")\n await applyPatch(\n paths.destination,\n join(snapshot.directory, \"previous-index.patch\"),\n true,\n );\n const entries =\n plan.side === \"previous\"\n ? snapshot.state.previousExtras\n : snapshot.state.incoming;\n const prefix = plan.side === \"previous\" ? \"previous-files\" : \"incoming\";\n for (const entry of entries) {\n const to = await safeDestination(paths.destination, entry);\n await absent(to);\n await mkdir(dirname(to), { recursive: true, mode: 0o700 });\n await cp(\n await safeDestination(snapshot.directory, `${prefix}/${entry}`),\n to,\n {\n dereference: false,\n verbatimSymlinks: true,\n force: false,\n errorOnExist: true,\n },\n );\n }\n return {\n directory: paths.destination,\n commit,\n side: plan.side,\n staging: plan.side === \"previous\" ? \"preserved\" : \"unavailable\",\n sourceRetained: true,\n };\n } catch (cause) {\n if (!owned) throw cause;\n throw new OutpostError(\n \"workspace\",\n \"Recovery restoration failed; source and partial destination retained\",\n { destination: paths.destination, transfer: paths.directory },\n cause,\n );\n } finally {\n await snapshot.dispose();\n }\n}\n\nexport function planRecoveryRestore(\n options: RecoveryRestoreOptions,\n observation?: ObservationHub,\n): Promise<RecoveryRestorePlan> {\n return observedOperation(observation, \"recovery\", \"restore.plan\", () =>\n planRecoveryRestoreOperation(options),\n );\n}\n\nexport function restoreRecoveryTransfer(\n plan: RecoveryRestorePlan,\n observation?: ObservationHub,\n): Promise<RecoveryRestoreResult> {\n return observedOperation(observation, \"recovery\", \"restore.apply\", () =>\n restoreRecoveryOperation(plan),\n );\n}\n"]}
@@ -1,5 +1,6 @@
1
+ import type { ObservationHub } from "../domain/observation.types.ts";
1
2
  import type { TransportStoreOptions } from "../domain/transport.types.ts";
2
3
  import type { RecoveryPruneResult, RecoveryQuotaOptions, RecoveryRetentionOptions, RecoveryRetentionPlan } from "./recovery-retention.types.ts";
3
- export declare function planRecoveryRetention(options: RecoveryRetentionOptions): Promise<RecoveryRetentionPlan>;
4
- export declare function pruneRecoveryRetention(plan: RecoveryRetentionPlan, options?: TransportStoreOptions): Promise<RecoveryPruneResult>;
5
4
  export declare function assertRecoveryQuota(options: RecoveryQuotaOptions): Promise<void>;
5
+ export declare function planRecoveryRetention(options: RecoveryRetentionOptions, observation?: ObservationHub): Promise<RecoveryRetentionPlan>;
6
+ export declare function pruneRecoveryRetention(plan: RecoveryRetentionPlan, options?: TransportStoreOptions, observation?: ObservationHub): Promise<RecoveryPruneResult>;
@@ -1,3 +1,4 @@
1
+ import { observedOperation } from "../domain/observed-operation.js";
1
2
  import { planTransportRetention, pruneTransportRetention, } from "./transport-retention.js";
2
3
  import { lstat } from "node:fs/promises";
3
4
  import { join } from "node:path";
@@ -49,7 +50,7 @@ async function workspaceReason(entry, inspection) {
49
50
  }
50
51
  return "ELIGIBLE";
51
52
  }
52
- export async function planRecoveryRetention(options) {
53
+ async function planRetentionOperation(options) {
53
54
  if (options.transporter)
54
55
  return planTransportRetention(options);
55
56
  retentionPolicy(options.policy);
@@ -161,7 +162,7 @@ export async function planRecoveryRetention(options) {
161
162
  quota: !complete ? "unknown" : exceeded ? "exceeded" : "within",
162
163
  };
163
164
  }
164
- export async function pruneRecoveryRetention(plan, options) {
165
+ async function pruneRetentionOperation(plan, options) {
165
166
  if (plan.source === "transport") {
166
167
  invariant(options, "Transport retention requires its transporter");
167
168
  return pruneTransportRetention(plan, options);
@@ -253,4 +254,10 @@ export async function assertRecoveryQuota(options) {
253
254
  complete: inspection.complete,
254
255
  });
255
256
  }
257
+ export function planRecoveryRetention(options, observation) {
258
+ return observedOperation(observation, "recovery", "retention.plan", () => planRetentionOperation(options));
259
+ }
260
+ export function pruneRecoveryRetention(plan, options, observation) {
261
+ return observedOperation(observation, "recovery", "retention.prune", () => pruneRetentionOperation(plan, options));
262
+ }
256
263
  //# sourceMappingURL=recovery-retention.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"recovery-retention.js","sourceRoot":"","sources":["../../src/application/recovery-retention.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TransportStoreOptions } from \"../domain/transport.types.ts\";\nimport {\n planTransportRetention,\n pruneTransportRetention,\n} from \"./transport-retention.ts\";\nimport { lstat } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { repositoryTransport } from \"../infrastructure/repository-transport.ts\";\nimport { repositoryStorageDirectory } from \"../infrastructure/repository-transport.constants.ts\";\nimport { OutpostError, invariant } from \"../domain/errors.ts\";\nimport { git } from \"../infrastructure/git/command.ts\";\nimport { lock, lockPath } from \"../infrastructure/git/lock.ts\";\nimport type { StorageEntry } from \"../infrastructure/storage-inventory.types.ts\";\nimport type { RecoveryInspection } from \"./recovery-inspection.types.ts\";\nimport { inspectRecovery } from \"./recovery-inspection.ts\";\nimport { retentionPolicy } from \"./recovery-retention-policy.ts\";\nimport type {\n RecoveryPruneResult,\n RecoveryRetainedEntry,\n RecoveryQuotaOptions,\n RecoveryRetentionEntry,\n RecoveryRetentionOptions,\n RecoveryRetentionPlan,\n} from \"./recovery-retention.types.ts\";\n\nasync function workspaceReason(\n entry: StorageEntry,\n inspection: RecoveryInspection,\n): Promise<string> {\n if (inspection.resources?.complete === false)\n return \"RESOURCE_ACTIVITY_UNKNOWN\";\n if (\n inspection.resources?.entries.some(\n (resource) => resource.record?.workspace === entry.path,\n )\n )\n return \"RESOURCE_ACTIVITY_RECORDED\";\n const workspace = inspection.git?.workspaces.find(\n (value) => value.path === entry.path,\n );\n if (!workspace || workspace.state !== \"registered\")\n return \"WORKSPACE_UNREGISTERED_OR_UNKNOWN\";\n if (workspace.branch === null) return \"DETACHED_WORKSPACE\";\n if (workspace.dirty) return \"DIRTY_WORKSPACE\";\n if (workspace.locked) return \"GIT_LOCKED_WORKSPACE\";\n try {\n await lstat(lockPath(inspection.repository, workspace.branch));\n return \"OPERATION_LOCK_PRESENT\";\n } catch (error) {\n if (!(\n error &&\n typeof error === \"object\" &&\n \"code\" in error &&\n error.code === \"ENOENT\"\n ))\n return \"OWNERSHIP_UNKNOWN\";\n }\n try {\n const ignored = await git(entry.path, [\n \"ls-files\",\n \"--others\",\n \"--ignored\",\n \"--exclude-standard\",\n \"-z\",\n ]);\n if (ignored.length) return \"IGNORED_FILES\";\n } catch {\n return \"WORKSPACE_STATE_UNKNOWN\";\n }\n return \"ELIGIBLE\";\n}\n\nexport async function planRecoveryRetention(\n options: RecoveryRetentionOptions,\n): Promise<RecoveryRetentionPlan> {\n if (options.transporter) return planTransportRetention(options);\n retentionPolicy(options.policy);\n const policy = structuredClone(options.policy);\n const inspection = await inspectRecovery({\n ...options,\n git: true,\n locks: true,\n resources: true,\n });\n const entries: RecoveryRetentionEntry[] = [];\n const inspectedAt = new Date().toISOString();\n let complete = inspection.complete && inspection.git?.complete !== false;\n for (const category of inspection.categories) {\n for (const entry of category.entries) {\n let reason = \"RECOVERY_DATA_PROTECTED\";\n if (category.name === \"locks\") reason = \"OWNERSHIP_RECORD_PROTECTED\";\n if (category.name === \"logs\") reason = \"LOG_ACTIVITY_OR_CONTENT_UNKNOWN\";\n if (category.name === \"workspaces\") reason = \"SCOPE_NOT_SELECTED\";\n if (\n category.name === \"workspaces\" &&\n policy.scopes.includes(\"clean-workspaces\")\n )\n reason = await workspaceReason(entry, inspection);\n if (\n reason === \"ELIGIBLE\" &&\n (!entry.modifiedAt ||\n Date.parse(inspectedAt) - Date.parse(entry.modifiedAt) <\n policy.minAgeMs)\n )\n reason = \"RETENTION_AGE\";\n if (reason === \"ELIGIBLE\" && (!complete || !entry.complete))\n reason = \"INCOMPLETE_INVENTORY\";\n const workspace = inspection.git?.workspaces.find(\n (value) => value.path === entry.path,\n );\n entries.push({\n path: entry.path,\n category: category.name,\n bytes: entry.bytes,\n eligible: reason === \"ELIGIBLE\",\n reason,\n ...(entry.modifiedAt ? { modifiedAt: entry.modifiedAt } : {}),\n ...(workspace?.state === \"registered\" && workspace.branch\n ? { branch: workspace.branch, head: workspace.head }\n : {}),\n });\n }\n }\n const logs = await planTransportRetention({\n transporter: repositoryTransport(inspection.repository),\n policy: {\n version: 1,\n scopes: policy.scopes.filter((scope) => scope === \"closed-logs\"),\n minAgeMs: policy.minAgeMs,\n },\n ...(options.maxEntries === undefined\n ? {}\n : { maxEntries: options.maxEntries }),\n });\n for (const entry of logs.entries.filter(\n (entry) => entry.category === \"logs\",\n )) {\n let bytes = 0;\n for (const object of entry.objects ?? []) {\n try {\n bytes += (\n await lstat(\n join(\n inspection.repository,\n \".outpost\",\n repositoryStorageDirectory,\n \"objects\",\n `${object.key}.object`,\n ),\n )\n ).size;\n } catch {\n complete = false;\n }\n }\n const container = entries.findIndex(\n (value) =>\n value.category === \"storage\" &&\n value.path ===\n join(\n inspection.repository,\n \".outpost\",\n repositoryStorageDirectory,\n \"objects\",\n ),\n );\n const stored = entries[container];\n if (!stored || stored.bytes < bytes) complete = false;\n if (stored)\n entries[container] = {\n ...stored,\n bytes: Math.max(0, stored.bytes - bytes),\n };\n entries.push({ ...entry, bytes, eligible: entry.eligible && complete });\n }\n complete = complete && logs.complete;\n if (!complete) {\n for (let index = 0; index < entries.length; index++) {\n const entry = entries[index]!;\n if (entry.eligible)\n entries[index] = {\n ...entry,\n eligible: false,\n reason: \"INCOMPLETE_INVENTORY\",\n };\n }\n }\n const projectedBytes =\n inspection.usage.bytes -\n entries\n .filter((entry) => entry.eligible)\n .reduce((sum, entry) => sum + entry.bytes, 0);\n const workspaces = entries.filter(\n (entry) => entry.category === \"workspaces\" && !entry.eligible,\n ).length;\n const exceeded =\n (policy.maxBytes !== undefined && projectedBytes > policy.maxBytes) ||\n (policy.maxWorkspaces !== undefined && workspaces > policy.maxWorkspaces);\n return {\n repository: inspection.repository,\n policy,\n inspectedAt,\n inspection,\n entries,\n complete,\n usageBytes: inspection.usage.bytes,\n projectedBytes,\n quota: !complete ? \"unknown\" : exceeded ? \"exceeded\" : \"within\",\n };\n}\n\nexport async function pruneRecoveryRetention(\n plan: RecoveryRetentionPlan,\n options?: TransportStoreOptions,\n): Promise<RecoveryPruneResult> {\n if (plan.source === \"transport\") {\n invariant(options, \"Transport retention requires its transporter\");\n return pruneTransportRetention(plan, options);\n }\n invariant(!options, \"Local retention does not accept a transporter\");\n retentionPolicy(plan.policy);\n invariant(plan.complete, \"Cannot prune an incomplete retention plan\");\n const removed: string[] = [];\n const retained: RecoveryRetainedEntry[] = [];\n for (const candidate of plan.entries.filter((entry) => entry.eligible)) {\n const fresh = await planRecoveryRetention({\n repository: plan.repository,\n policy: plan.policy,\n });\n const entry = fresh.entries.find((value) => value.path === candidate.path);\n if (\n !entry?.eligible ||\n entry.head !== candidate.head ||\n entry.branch !== candidate.branch ||\n entry.bytes !== candidate.bytes ||\n entry.modifiedAt !== candidate.modifiedAt\n ) {\n retained.push({ path: candidate.path, reason: \"PLAN_CHANGED\" });\n continue;\n }\n try {\n if (entry.category === \"workspaces\" && entry.branch) {\n const release = await lock(plan.repository, entry.branch);\n try {\n const status = await git(entry.path, [\n \"status\",\n \"--porcelain=v1\",\n \"--ignored\",\n \"--untracked-files=all\",\n ]);\n invariant(!status.length, \"Workspace changed before pruning\");\n invariant(\n (await git(entry.path, [\"rev-parse\", \"HEAD\"])).trim() ===\n entry.head,\n \"Workspace HEAD changed before pruning\",\n );\n invariant(\n (\n await git(entry.path, [\"symbolic-ref\", \"--short\", \"HEAD\"])\n ).trim() === entry.branch,\n \"Workspace branch changed before pruning\",\n );\n await git(plan.repository, [\"worktree\", \"remove\", entry.path]);\n } finally {\n await release();\n }\n } else {\n const result = await pruneTransportRetention(\n {\n ...plan,\n source: \"transport\",\n policy: {\n version: 1,\n scopes: [\"closed-logs\"],\n minAgeMs: plan.policy.minAgeMs,\n },\n entries: [candidate],\n },\n { transporter: repositoryTransport(plan.repository) },\n );\n if (!result.removed.includes(entry.path)) {\n retained.push(...result.retained);\n continue;\n }\n }\n removed.push(entry.path);\n } catch {\n retained.push({\n path: candidate.path,\n reason: \"REVALIDATION_OR_REMOVAL_FAILED\",\n });\n }\n }\n return {\n removed,\n retained,\n after: await planRecoveryRetention({\n repository: plan.repository,\n policy: plan.policy,\n }),\n };\n}\n\nexport async function assertRecoveryQuota(\n options: RecoveryQuotaOptions,\n): Promise<void> {\n invariant(\n Number.isSafeInteger(options.maxBytes) && options.maxBytes >= 0,\n \"maxBytes must be a nonnegative integer\",\n );\n const reserve = options.reserveBytes ?? 0;\n invariant(\n Number.isSafeInteger(reserve) && reserve >= 0,\n \"reserveBytes must be a nonnegative integer\",\n );\n const inspection = await inspectRecovery(options);\n if (\n !inspection.complete ||\n inspection.usage.bytes + reserve > options.maxBytes\n )\n throw new OutpostError(\n \"workspace\",\n \"Outpost storage quota admission refused\",\n {\n usageBytes: inspection.usage.bytes,\n reserveBytes: reserve,\n maxBytes: options.maxBytes,\n complete: inspection.complete,\n },\n );\n}\n"]}
1
+ {"version":3,"file":"recovery-retention.js","sourceRoot":"","sources":["../../src/application/recovery-retention.ts"],"names":[],"mappings":"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","sourcesContent":["import { observedOperation } from \"../domain/observed-operation.ts\";\nimport type { ObservationHub } from \"../domain/observation.types.ts\";\nimport type { TransportStoreOptions } from \"../domain/transport.types.ts\";\nimport {\n planTransportRetention,\n pruneTransportRetention,\n} from \"./transport-retention.ts\";\nimport { lstat } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { repositoryTransport } from \"../infrastructure/repository-transport.ts\";\nimport { repositoryStorageDirectory } from \"../infrastructure/repository-transport.constants.ts\";\nimport { OutpostError, invariant } from \"../domain/errors.ts\";\nimport { git } from \"../infrastructure/git/command.ts\";\nimport { lock, lockPath } from \"../infrastructure/git/lock.ts\";\nimport type { StorageEntry } from \"../infrastructure/storage-inventory.types.ts\";\nimport type { RecoveryInspection } from \"./recovery-inspection.types.ts\";\nimport { inspectRecovery } from \"./recovery-inspection.ts\";\nimport { retentionPolicy } from \"./recovery-retention-policy.ts\";\nimport type {\n RecoveryPruneResult,\n RecoveryRetainedEntry,\n RecoveryQuotaOptions,\n RecoveryRetentionEntry,\n RecoveryRetentionOptions,\n RecoveryRetentionPlan,\n} from \"./recovery-retention.types.ts\";\n\nasync function workspaceReason(\n entry: StorageEntry,\n inspection: RecoveryInspection,\n): Promise<string> {\n if (inspection.resources?.complete === false)\n return \"RESOURCE_ACTIVITY_UNKNOWN\";\n if (\n inspection.resources?.entries.some(\n (resource) => resource.record?.workspace === entry.path,\n )\n )\n return \"RESOURCE_ACTIVITY_RECORDED\";\n const workspace = inspection.git?.workspaces.find(\n (value) => value.path === entry.path,\n );\n if (!workspace || workspace.state !== \"registered\")\n return \"WORKSPACE_UNREGISTERED_OR_UNKNOWN\";\n if (workspace.branch === null) return \"DETACHED_WORKSPACE\";\n if (workspace.dirty) return \"DIRTY_WORKSPACE\";\n if (workspace.locked) return \"GIT_LOCKED_WORKSPACE\";\n try {\n await lstat(lockPath(inspection.repository, workspace.branch));\n return \"OPERATION_LOCK_PRESENT\";\n } catch (error) {\n if (!(\n error &&\n typeof error === \"object\" &&\n \"code\" in error &&\n error.code === \"ENOENT\"\n ))\n return \"OWNERSHIP_UNKNOWN\";\n }\n try {\n const ignored = await git(entry.path, [\n \"ls-files\",\n \"--others\",\n \"--ignored\",\n \"--exclude-standard\",\n \"-z\",\n ]);\n if (ignored.length) return \"IGNORED_FILES\";\n } catch {\n return \"WORKSPACE_STATE_UNKNOWN\";\n }\n return \"ELIGIBLE\";\n}\n\nasync function planRetentionOperation(\n options: RecoveryRetentionOptions,\n): Promise<RecoveryRetentionPlan> {\n if (options.transporter) return planTransportRetention(options);\n retentionPolicy(options.policy);\n const policy = structuredClone(options.policy);\n const inspection = await inspectRecovery({\n ...options,\n git: true,\n locks: true,\n resources: true,\n });\n const entries: RecoveryRetentionEntry[] = [];\n const inspectedAt = new Date().toISOString();\n let complete = inspection.complete && inspection.git?.complete !== false;\n for (const category of inspection.categories) {\n for (const entry of category.entries) {\n let reason = \"RECOVERY_DATA_PROTECTED\";\n if (category.name === \"locks\") reason = \"OWNERSHIP_RECORD_PROTECTED\";\n if (category.name === \"logs\") reason = \"LOG_ACTIVITY_OR_CONTENT_UNKNOWN\";\n if (category.name === \"workspaces\") reason = \"SCOPE_NOT_SELECTED\";\n if (\n category.name === \"workspaces\" &&\n policy.scopes.includes(\"clean-workspaces\")\n )\n reason = await workspaceReason(entry, inspection);\n if (\n reason === \"ELIGIBLE\" &&\n (!entry.modifiedAt ||\n Date.parse(inspectedAt) - Date.parse(entry.modifiedAt) <\n policy.minAgeMs)\n )\n reason = \"RETENTION_AGE\";\n if (reason === \"ELIGIBLE\" && (!complete || !entry.complete))\n reason = \"INCOMPLETE_INVENTORY\";\n const workspace = inspection.git?.workspaces.find(\n (value) => value.path === entry.path,\n );\n entries.push({\n path: entry.path,\n category: category.name,\n bytes: entry.bytes,\n eligible: reason === \"ELIGIBLE\",\n reason,\n ...(entry.modifiedAt ? { modifiedAt: entry.modifiedAt } : {}),\n ...(workspace?.state === \"registered\" && workspace.branch\n ? { branch: workspace.branch, head: workspace.head }\n : {}),\n });\n }\n }\n const logs = await planTransportRetention({\n transporter: repositoryTransport(inspection.repository),\n policy: {\n version: 1,\n scopes: policy.scopes.filter((scope) => scope === \"closed-logs\"),\n minAgeMs: policy.minAgeMs,\n },\n ...(options.maxEntries === undefined\n ? {}\n : { maxEntries: options.maxEntries }),\n });\n for (const entry of logs.entries.filter(\n (entry) => entry.category === \"logs\",\n )) {\n let bytes = 0;\n for (const object of entry.objects ?? []) {\n try {\n bytes += (\n await lstat(\n join(\n inspection.repository,\n \".outpost\",\n repositoryStorageDirectory,\n \"objects\",\n `${object.key}.object`,\n ),\n )\n ).size;\n } catch {\n complete = false;\n }\n }\n const container = entries.findIndex(\n (value) =>\n value.category === \"storage\" &&\n value.path ===\n join(\n inspection.repository,\n \".outpost\",\n repositoryStorageDirectory,\n \"objects\",\n ),\n );\n const stored = entries[container];\n if (!stored || stored.bytes < bytes) complete = false;\n if (stored)\n entries[container] = {\n ...stored,\n bytes: Math.max(0, stored.bytes - bytes),\n };\n entries.push({ ...entry, bytes, eligible: entry.eligible && complete });\n }\n complete = complete && logs.complete;\n if (!complete) {\n for (let index = 0; index < entries.length; index++) {\n const entry = entries[index]!;\n if (entry.eligible)\n entries[index] = {\n ...entry,\n eligible: false,\n reason: \"INCOMPLETE_INVENTORY\",\n };\n }\n }\n const projectedBytes =\n inspection.usage.bytes -\n entries\n .filter((entry) => entry.eligible)\n .reduce((sum, entry) => sum + entry.bytes, 0);\n const workspaces = entries.filter(\n (entry) => entry.category === \"workspaces\" && !entry.eligible,\n ).length;\n const exceeded =\n (policy.maxBytes !== undefined && projectedBytes > policy.maxBytes) ||\n (policy.maxWorkspaces !== undefined && workspaces > policy.maxWorkspaces);\n return {\n repository: inspection.repository,\n policy,\n inspectedAt,\n inspection,\n entries,\n complete,\n usageBytes: inspection.usage.bytes,\n projectedBytes,\n quota: !complete ? \"unknown\" : exceeded ? \"exceeded\" : \"within\",\n };\n}\n\nasync function pruneRetentionOperation(\n plan: RecoveryRetentionPlan,\n options?: TransportStoreOptions,\n): Promise<RecoveryPruneResult> {\n if (plan.source === \"transport\") {\n invariant(options, \"Transport retention requires its transporter\");\n return pruneTransportRetention(plan, options);\n }\n invariant(!options, \"Local retention does not accept a transporter\");\n retentionPolicy(plan.policy);\n invariant(plan.complete, \"Cannot prune an incomplete retention plan\");\n const removed: string[] = [];\n const retained: RecoveryRetainedEntry[] = [];\n for (const candidate of plan.entries.filter((entry) => entry.eligible)) {\n const fresh = await planRecoveryRetention({\n repository: plan.repository,\n policy: plan.policy,\n });\n const entry = fresh.entries.find((value) => value.path === candidate.path);\n if (\n !entry?.eligible ||\n entry.head !== candidate.head ||\n entry.branch !== candidate.branch ||\n entry.bytes !== candidate.bytes ||\n entry.modifiedAt !== candidate.modifiedAt\n ) {\n retained.push({ path: candidate.path, reason: \"PLAN_CHANGED\" });\n continue;\n }\n try {\n if (entry.category === \"workspaces\" && entry.branch) {\n const release = await lock(plan.repository, entry.branch);\n try {\n const status = await git(entry.path, [\n \"status\",\n \"--porcelain=v1\",\n \"--ignored\",\n \"--untracked-files=all\",\n ]);\n invariant(!status.length, \"Workspace changed before pruning\");\n invariant(\n (await git(entry.path, [\"rev-parse\", \"HEAD\"])).trim() ===\n entry.head,\n \"Workspace HEAD changed before pruning\",\n );\n invariant(\n (\n await git(entry.path, [\"symbolic-ref\", \"--short\", \"HEAD\"])\n ).trim() === entry.branch,\n \"Workspace branch changed before pruning\",\n );\n await git(plan.repository, [\"worktree\", \"remove\", entry.path]);\n } finally {\n await release();\n }\n } else {\n const result = await pruneTransportRetention(\n {\n ...plan,\n source: \"transport\",\n policy: {\n version: 1,\n scopes: [\"closed-logs\"],\n minAgeMs: plan.policy.minAgeMs,\n },\n entries: [candidate],\n },\n { transporter: repositoryTransport(plan.repository) },\n );\n if (!result.removed.includes(entry.path)) {\n retained.push(...result.retained);\n continue;\n }\n }\n removed.push(entry.path);\n } catch {\n retained.push({\n path: candidate.path,\n reason: \"REVALIDATION_OR_REMOVAL_FAILED\",\n });\n }\n }\n return {\n removed,\n retained,\n after: await planRecoveryRetention({\n repository: plan.repository,\n policy: plan.policy,\n }),\n };\n}\n\nexport async function assertRecoveryQuota(\n options: RecoveryQuotaOptions,\n): Promise<void> {\n invariant(\n Number.isSafeInteger(options.maxBytes) && options.maxBytes >= 0,\n \"maxBytes must be a nonnegative integer\",\n );\n const reserve = options.reserveBytes ?? 0;\n invariant(\n Number.isSafeInteger(reserve) && reserve >= 0,\n \"reserveBytes must be a nonnegative integer\",\n );\n const inspection = await inspectRecovery(options);\n if (\n !inspection.complete ||\n inspection.usage.bytes + reserve > options.maxBytes\n )\n throw new OutpostError(\n \"workspace\",\n \"Outpost storage quota admission refused\",\n {\n usageBytes: inspection.usage.bytes,\n reserveBytes: reserve,\n maxBytes: options.maxBytes,\n complete: inspection.complete,\n },\n );\n}\n\nexport function planRecoveryRetention(\n options: RecoveryRetentionOptions,\n observation?: ObservationHub,\n): Promise<RecoveryRetentionPlan> {\n return observedOperation(observation, \"recovery\", \"retention.plan\", () =>\n planRetentionOperation(options),\n );\n}\n\nexport function pruneRecoveryRetention(\n plan: RecoveryRetentionPlan,\n options?: TransportStoreOptions,\n observation?: ObservationHub,\n): Promise<RecoveryPruneResult> {\n return observedOperation(observation, \"recovery\", \"retention.prune\", () =>\n pruneRetentionOperation(plan, options),\n );\n}\n"]}
@@ -1,3 +1,4 @@
1
+ import { observedOperation } from "../domain/observed-operation.js";
1
2
  import { randomUUID } from "node:crypto";
2
3
  import { mkdir, readFile, rm } from "node:fs/promises";
3
4
  import { join, posix } from "node:path";
@@ -103,10 +104,10 @@ export async function seedRemote(workspace, lease, options = {}) {
103
104
  const transfer = join(recovery, randomUUID());
104
105
  await mkdir(transfer, { recursive: true });
105
106
  try {
106
- const changes = await downloadChanges(context, synchronized, transfer);
107
- await validateChanges(context, changes, synchronized, expected, transfer);
108
- const backup = await backupHost(context, changes, synchronized, transfer);
109
- await applyChanges(context, changes, backup, synchronized, expected, transfer);
107
+ const changes = await observedOperation(options.observation, "transfer", "repository.download", async () => downloadChanges(context, synchronized, transfer));
108
+ await observedOperation(options.observation, "recovery", "changes.validate", async () => validateChanges(context, changes, synchronized, expected, transfer));
109
+ const backup = await observedOperation(options.observation, "recovery", "host.backup", async () => backupHost(context, changes, synchronized, transfer));
110
+ await observedOperation(options.observation, "git", "changes.apply", async () => applyChanges(context, changes, backup, synchronized, expected, transfer));
110
111
  context.transferred?.clear();
111
112
  for (const entry of changes.manifest ?? [])
112
113
  context.transferred?.set(entry.path, entry);
@@ -1 +1 @@
1
- {"version":3,"file":"remote-workspace.js","sourceRoot":"","sources":["../../src/application/remote-workspace.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { mkdir, readFile, rm } from \"node:fs/promises\";\nimport { join, posix } from \"node:path\";\nimport { OutpostError } from \"../domain/errors.ts\";\nimport type { SandboxLease } from \"../domain/sandbox.types.ts\";\nimport type { WorkspaceRecord } from \"../domain/workspace.types.ts\";\nimport { seedHistory } from \"./remote-history.ts\";\nimport { uploadFiles } from \"./remote-upload.ts\";\nimport { git } from \"../infrastructure/git/command.ts\";\nimport { gitDefaults } from \"../infrastructure/git/git.constants.ts\";\nimport { applyChanges } from \"./remote-apply.ts\";\nimport { backupHost } from \"./remote-backup.ts\";\nimport { downloadChanges } from \"./remote-download.ts\";\nimport { validateChanges } from \"./remote-validation.ts\";\nimport type {\n RemoteSync,\n RemoteSyncOptions,\n RemoteWorkspaceContext,\n} from \"./remote-workspace.types.ts\";\nimport { digest, extras } from \"./workspace-fingerprint.ts\";\n\nexport type {\n RemoteSync,\n RemoteSyncOptions,\n} from \"./remote-workspace.types.ts\";\n\nexport async function seedRemote(\n workspace: WorkspaceRecord,\n lease: SandboxLease,\n options: RemoteSyncOptions = {},\n): Promise<RemoteSync> {\n options.signal?.throwIfAborted();\n const recovery = join(\n workspace.repository,\n \".outpost\",\n \"recovery\",\n randomUUID(),\n );\n await mkdir(recovery, { recursive: true });\n const remoteBundle = posix.join(\n lease.root.replaceAll(\"\\\\\", \"/\"),\n \"..\",\n `outpost-${randomUUID()}.bundle`,\n );\n let initializing = true,\n failed = false;\n const run = async (args: readonly string[]) => {\n let result;\n for (let attempt = 0; attempt < 3; attempt++) {\n result = await lease.invoke({\n executable: \"git\",\n arguments: args,\n directory: lease.root,\n retain: gitDefaults.retainBytes,\n ...(initializing && options.signal ? { signal: options.signal } : {}),\n ...(options.limits?.gitMs ? { deadlineMs: options.limits.gitMs } : {}),\n });\n if (!initializing || result.status !== 126) break;\n }\n if (!result)\n throw new OutpostError(\"workspace\", \"Remote Git did not start\");\n if (result.status !== 0)\n throw new OutpostError(\"workspace\", \"Remote Git operation failed\", {\n ...result,\n recovery,\n });\n if (result.stdout.length >= gitDefaults.retainBytes)\n throw new OutpostError(\n \"workspace\",\n \"Remote Git output exceeds synchronization limit\",\n { recovery },\n );\n return result.stdout;\n };\n await run([\"init\"]);\n await run([\"config\", \"core.autocrlf\", \"false\"]);\n await seedHistory(workspace, lease, options, recovery, remoteBundle, run);\n for (const key of [\"user.name\", \"user.email\"] as const) {\n const fallback = key === \"user.name\" ? \"Outpost\" : \"outpost@localhost\";\n const value =\n (\n await git(workspace.repository, [\"config\", \"--get\", key]).catch(\n () => fallback,\n )\n ).trim() || fallback;\n await run([\"config\", key, value]);\n }\n const initialPatch = join(recovery, \"initial.patch\");\n await git(workspace.directory, [\n \"diff\",\n \"--binary\",\n \"HEAD\",\n `--output=${initialPatch}`,\n ]);\n const initialIndex = join(recovery, \"initial-index.patch\");\n await git(workspace.directory, [\n \"diff\",\n \"--cached\",\n \"--binary\",\n `--output=${initialIndex}`,\n ]);\n const protectedFiles = options.includeUncommitted\n ? []\n : [\n ...(\n await git(workspace.directory, [\"diff\", \"--name-only\", \"-z\", \"HEAD\"])\n )\n .split(\"\\0\")\n .filter(Boolean),\n ...(await extras(workspace.directory)),\n ];\n const originalHead = (\n await git(workspace.directory, [\"rev-parse\", \"HEAD\"])\n ).trim();\n if (options.includeUncommitted && (await readFile(initialPatch)).length) {\n await lease.upload(initialPatch, `${remoteBundle}.patch`);\n await run([\"apply\", \"--binary\", `${remoteBundle}.patch`]);\n }\n await uploadFiles(\n lease,\n workspace.directory,\n options.includeUncommitted ? await extras(workspace.directory) : [],\n { ...(options.signal ? { signal: options.signal } : {}) },\n );\n let synchronized = (await run([\"rev-parse\", \"HEAD\"])).trim();\n initializing = false;\n let expected = await digest(workspace.directory, recovery);\n const context: RemoteWorkspaceContext = {\n transferred: new Map(),\n workspace,\n lease,\n options,\n recovery,\n remoteBundle,\n run,\n protectedFiles,\n originalHead,\n initialPatch,\n initialIndex,\n };\n return {\n async close() {\n if (!failed) await rm(recovery, { recursive: true, force: true });\n },\n async pull() {\n const transfer = join(recovery, randomUUID());\n await mkdir(transfer, { recursive: true });\n try {\n const changes = await downloadChanges(context, synchronized, transfer);\n await validateChanges(\n context,\n changes,\n synchronized,\n expected,\n transfer,\n );\n const backup = await backupHost(\n context,\n changes,\n synchronized,\n transfer,\n );\n await applyChanges(\n context,\n changes,\n backup,\n synchronized,\n expected,\n transfer,\n );\n context.transferred?.clear();\n for (const entry of changes.manifest ?? [])\n context.transferred?.set(entry.path, entry);\n const { head } = changes;\n synchronized = head;\n expected = await digest(workspace.directory, recovery);\n await rm(transfer, { recursive: true, force: true });\n } catch (cause) {\n failed = true;\n throw new OutpostError(\n \"workspace\",\n \"Remote changes could not be fully synchronized; recovery files retained\",\n { recovery: transfer, directory: workspace.directory },\n cause,\n );\n }\n },\n };\n}\n"]}
1
+ {"version":3,"file":"remote-workspace.js","sourceRoot":"","sources":["../../src/application/remote-workspace.ts"],"names":[],"mappings":"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","sourcesContent":["import { observedOperation } from \"../domain/observed-operation.ts\";\nimport { randomUUID } from \"node:crypto\";\nimport { mkdir, readFile, rm } from \"node:fs/promises\";\nimport { join, posix } from \"node:path\";\nimport { OutpostError } from \"../domain/errors.ts\";\nimport type { SandboxLease } from \"../domain/sandbox.types.ts\";\nimport type { WorkspaceRecord } from \"../domain/workspace.types.ts\";\nimport { seedHistory } from \"./remote-history.ts\";\nimport { uploadFiles } from \"./remote-upload.ts\";\nimport { git } from \"../infrastructure/git/command.ts\";\nimport { gitDefaults } from \"../infrastructure/git/git.constants.ts\";\nimport { applyChanges } from \"./remote-apply.ts\";\nimport { backupHost } from \"./remote-backup.ts\";\nimport { downloadChanges } from \"./remote-download.ts\";\nimport { validateChanges } from \"./remote-validation.ts\";\nimport type {\n RemoteSync,\n RemoteSyncOptions,\n RemoteWorkspaceContext,\n} from \"./remote-workspace.types.ts\";\nimport { digest, extras } from \"./workspace-fingerprint.ts\";\n\nexport type {\n RemoteSync,\n RemoteSyncOptions,\n} from \"./remote-workspace.types.ts\";\n\nexport async function seedRemote(\n workspace: WorkspaceRecord,\n lease: SandboxLease,\n options: RemoteSyncOptions = {},\n): Promise<RemoteSync> {\n options.signal?.throwIfAborted();\n const recovery = join(\n workspace.repository,\n \".outpost\",\n \"recovery\",\n randomUUID(),\n );\n await mkdir(recovery, { recursive: true });\n const remoteBundle = posix.join(\n lease.root.replaceAll(\"\\\\\", \"/\"),\n \"..\",\n `outpost-${randomUUID()}.bundle`,\n );\n let initializing = true,\n failed = false;\n const run = async (args: readonly string[]) => {\n let result;\n for (let attempt = 0; attempt < 3; attempt++) {\n result = await lease.invoke({\n executable: \"git\",\n arguments: args,\n directory: lease.root,\n retain: gitDefaults.retainBytes,\n ...(initializing && options.signal ? { signal: options.signal } : {}),\n ...(options.limits?.gitMs ? { deadlineMs: options.limits.gitMs } : {}),\n });\n if (!initializing || result.status !== 126) break;\n }\n if (!result)\n throw new OutpostError(\"workspace\", \"Remote Git did not start\");\n if (result.status !== 0)\n throw new OutpostError(\"workspace\", \"Remote Git operation failed\", {\n ...result,\n recovery,\n });\n if (result.stdout.length >= gitDefaults.retainBytes)\n throw new OutpostError(\n \"workspace\",\n \"Remote Git output exceeds synchronization limit\",\n { recovery },\n );\n return result.stdout;\n };\n await run([\"init\"]);\n await run([\"config\", \"core.autocrlf\", \"false\"]);\n await seedHistory(workspace, lease, options, recovery, remoteBundle, run);\n for (const key of [\"user.name\", \"user.email\"] as const) {\n const fallback = key === \"user.name\" ? \"Outpost\" : \"outpost@localhost\";\n const value =\n (\n await git(workspace.repository, [\"config\", \"--get\", key]).catch(\n () => fallback,\n )\n ).trim() || fallback;\n await run([\"config\", key, value]);\n }\n const initialPatch = join(recovery, \"initial.patch\");\n await git(workspace.directory, [\n \"diff\",\n \"--binary\",\n \"HEAD\",\n `--output=${initialPatch}`,\n ]);\n const initialIndex = join(recovery, \"initial-index.patch\");\n await git(workspace.directory, [\n \"diff\",\n \"--cached\",\n \"--binary\",\n `--output=${initialIndex}`,\n ]);\n const protectedFiles = options.includeUncommitted\n ? []\n : [\n ...(\n await git(workspace.directory, [\"diff\", \"--name-only\", \"-z\", \"HEAD\"])\n )\n .split(\"\\0\")\n .filter(Boolean),\n ...(await extras(workspace.directory)),\n ];\n const originalHead = (\n await git(workspace.directory, [\"rev-parse\", \"HEAD\"])\n ).trim();\n if (options.includeUncommitted && (await readFile(initialPatch)).length) {\n await lease.upload(initialPatch, `${remoteBundle}.patch`);\n await run([\"apply\", \"--binary\", `${remoteBundle}.patch`]);\n }\n await uploadFiles(\n lease,\n workspace.directory,\n options.includeUncommitted ? await extras(workspace.directory) : [],\n { ...(options.signal ? { signal: options.signal } : {}) },\n );\n let synchronized = (await run([\"rev-parse\", \"HEAD\"])).trim();\n initializing = false;\n let expected = await digest(workspace.directory, recovery);\n const context: RemoteWorkspaceContext = {\n transferred: new Map(),\n workspace,\n lease,\n options,\n recovery,\n remoteBundle,\n run,\n protectedFiles,\n originalHead,\n initialPatch,\n initialIndex,\n };\n return {\n async close() {\n if (!failed) await rm(recovery, { recursive: true, force: true });\n },\n async pull() {\n const transfer = join(recovery, randomUUID());\n await mkdir(transfer, { recursive: true });\n try {\n const changes = await observedOperation(\n options.observation,\n \"transfer\",\n \"repository.download\",\n async () => downloadChanges(context, synchronized, transfer),\n );\n await observedOperation(\n options.observation,\n \"recovery\",\n \"changes.validate\",\n async () =>\n validateChanges(context, changes, synchronized, expected, transfer),\n );\n const backup = await observedOperation(\n options.observation,\n \"recovery\",\n \"host.backup\",\n async () => backupHost(context, changes, synchronized, transfer),\n );\n await observedOperation(\n options.observation,\n \"git\",\n \"changes.apply\",\n async () =>\n applyChanges(\n context,\n changes,\n backup,\n synchronized,\n expected,\n transfer,\n ),\n );\n context.transferred?.clear();\n for (const entry of changes.manifest ?? [])\n context.transferred?.set(entry.path, entry);\n const { head } = changes;\n synchronized = head;\n expected = await digest(workspace.directory, recovery);\n await rm(transfer, { recursive: true, force: true });\n } catch (cause) {\n failed = true;\n throw new OutpostError(\n \"workspace\",\n \"Remote changes could not be fully synchronized; recovery files retained\",\n { recovery: transfer, directory: workspace.directory },\n cause,\n );\n }\n },\n };\n}\n"]}
@@ -6,6 +6,7 @@ export interface RemoteSync {
6
6
  close(): Promise<void>;
7
7
  }
8
8
  export interface RemoteSyncOptions {
9
+ readonly observation?: import("../domain/observation.types.ts").ObservationHub;
9
10
  readonly recoveryTransport?: Transport;
10
11
  readonly includeUncommitted?: boolean;
11
12
  readonly signal?: AbortSignal;
@@ -1 +1 @@
1
- {"version":3,"file":"remote-workspace.types.js","sourceRoot":"","sources":["../../src/application/remote-workspace.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Transport } from \"../domain/transport.types.ts\";\nimport type {\n FileManifestEntry,\n SandboxLease,\n} from \"../domain/sandbox.types.ts\";\nimport type {\n StageLimits,\n WorkspaceRecord,\n} from \"../domain/workspace.types.ts\";\n\nexport interface RemoteSync {\n pull(): Promise<void>;\n close(): Promise<void>;\n}\n\nexport interface RemoteSyncOptions {\n readonly recoveryTransport?: Transport;\n readonly includeUncommitted?: boolean;\n readonly signal?: AbortSignal;\n readonly limits?: StageLimits;\n}\n\nexport interface RemoteWorkspaceContext {\n readonly transferred?: Map<string, FileManifestEntry>;\n readonly workspace: WorkspaceRecord;\n readonly lease: SandboxLease;\n readonly options: RemoteSyncOptions;\n readonly recovery: string;\n readonly remoteBundle: string;\n readonly run: (args: readonly string[]) => Promise<string>;\n readonly protectedFiles: readonly string[];\n readonly originalHead: string;\n readonly initialPatch: string;\n readonly initialIndex: string;\n}\nexport interface RemoteChanges {\n readonly manifest?: readonly FileManifestEntry[];\n readonly head: string;\n readonly patch: string;\n readonly incoming: readonly string[];\n}\nexport interface HostBackup {\n readonly previousPatch: string;\n readonly previousExtras: readonly string[];\n}\n"]}
1
+ {"version":3,"file":"remote-workspace.types.js","sourceRoot":"","sources":["../../src/application/remote-workspace.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Transport } from \"../domain/transport.types.ts\";\nimport type {\n FileManifestEntry,\n SandboxLease,\n} from \"../domain/sandbox.types.ts\";\nimport type {\n StageLimits,\n WorkspaceRecord,\n} from \"../domain/workspace.types.ts\";\n\nexport interface RemoteSync {\n pull(): Promise<void>;\n close(): Promise<void>;\n}\n\nexport interface RemoteSyncOptions {\n readonly observation?: import(\"../domain/observation.types.ts\").ObservationHub;\n readonly recoveryTransport?: Transport;\n readonly includeUncommitted?: boolean;\n readonly signal?: AbortSignal;\n readonly limits?: StageLimits;\n}\n\nexport interface RemoteWorkspaceContext {\n readonly transferred?: Map<string, FileManifestEntry>;\n readonly workspace: WorkspaceRecord;\n readonly lease: SandboxLease;\n readonly options: RemoteSyncOptions;\n readonly recovery: string;\n readonly remoteBundle: string;\n readonly run: (args: readonly string[]) => Promise<string>;\n readonly protectedFiles: readonly string[];\n readonly originalHead: string;\n readonly initialPatch: string;\n readonly initialIndex: string;\n}\nexport interface RemoteChanges {\n readonly manifest?: readonly FileManifestEntry[];\n readonly head: string;\n readonly patch: string;\n readonly incoming: readonly string[];\n}\nexport interface HostBackup {\n readonly previousPatch: string;\n readonly previousExtras: readonly string[];\n}\n"]}
@@ -1,3 +1,4 @@
1
+ import { observedOperation } from "../domain/observed-operation.js";
1
2
  import { invariant } from "../domain/errors.js";
2
3
  import { resolveVariables } from "../infrastructure/settings.js";
3
4
  import { authenticateAgent } from "./agent-authentication.js";
@@ -7,11 +8,11 @@ export function sandboxAgents(context) {
7
8
  const { options, sandboxProvider, workspace, runtime, prepared, staging } = context;
8
9
  const known = new Set();
9
10
  const authenticated = new Map();
10
- const selectAgent = async (selected, signal) => {
11
+ const selectAgent = async (selected, signal, observation = options.observation) => {
11
12
  invariant(selected, "Provide an agent on the sandbox or this operation");
12
13
  if (!prepared.has(selected))
13
14
  prepared.set(selected, sandboxProvider.placement === "remote" && options.bootstrap !== false
14
- ? await prepareAdapter(selected, runtime, signal)
15
+ ? await observedOperation(observation, "sandbox", "agent.bootstrap", async () => prepareAdapter(selected, runtime, signal))
15
16
  : selected);
16
17
  const variables = await resolveVariables(workspace.repository, selected.variables, sandboxProvider.variables);
17
18
  const adapter = prepared.get(selected);
@@ -19,7 +20,7 @@ export function sandboxAgents(context) {
19
20
  authenticated.get(adapter.name)?.adapter !== adapter)
20
21
  authenticated.set(adapter.name, {
21
22
  adapter,
22
- variables: await authenticateAgent(adapter, variables, runtime, sandboxProvider.placement, signal),
23
+ variables: await observedOperation(observation, "sandbox", "agent.authenticate", async () => authenticateAgent(adapter, variables, runtime, sandboxProvider.placement, signal)),
23
24
  });
24
25
  const credentials = adapter.kind === "cli" ? authenticated.get(adapter.name)?.variables : {};
25
26
  return {
@@ -37,20 +38,18 @@ export function sandboxAgents(context) {
37
38
  };
38
39
  };
39
40
  const conversationKey = (agent, id) => `${agent.storage?.name ?? agent.conversations ?? agent.name}:${id}`;
40
- const restore = async (id, agent) => {
41
+ const restore = async (id, agent, executionLease) => {
41
42
  if (known.has(conversationKey(agent, id)))
42
43
  return;
43
44
  const storage = storageFor(agent);
44
45
  invariant(storage, "This adapter does not support native conversations");
45
46
  const found = await storage.locate(id, workspace.repository, options.conversationHome);
46
- if (found.reference !== undefined ||
47
- sandboxProvider.placement !== "host" ||
48
- workspace.directory !== workspace.repository)
49
- await storage.restore(found, {
50
- repository: workspace.repository,
51
- sandbox: runtime,
52
- staging,
53
- });
47
+ await storage.restore(found, {
48
+ repository: workspace.repository,
49
+ sandbox: executionLease,
50
+ staging,
51
+ local: sandboxProvider.placement === "host",
52
+ });
54
53
  known.add(conversationKey(agent, id));
55
54
  };
56
55
  return {