@elie-laloum/outpost 2.0.0 → 3.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 (300) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/adapters/agents/claude-diagnostics.d.ts +1 -0
  3. package/dist/adapters/agents/claude-diagnostics.js +7 -0
  4. package/dist/adapters/agents/claude-diagnostics.js.map +1 -0
  5. package/dist/adapters/agents/cli-diagnostics.constants.d.ts +12 -0
  6. package/dist/adapters/agents/cli-diagnostics.constants.js +24 -0
  7. package/dist/adapters/agents/cli-diagnostics.constants.js.map +1 -0
  8. package/dist/adapters/agents/cli-diagnostics.d.ts +4 -0
  9. package/dist/adapters/agents/cli-diagnostics.js +14 -0
  10. package/dist/adapters/agents/cli-diagnostics.js.map +1 -0
  11. package/dist/adapters/agents/cli-diagnostics.types.d.ts +13 -0
  12. package/dist/adapters/agents/cli-diagnostics.types.js +2 -0
  13. package/dist/adapters/agents/cli-diagnostics.types.js.map +1 -0
  14. package/dist/adapters/agents/codex-diagnostics.d.ts +1 -0
  15. package/dist/adapters/agents/codex-diagnostics.js +7 -0
  16. package/dist/adapters/agents/codex-diagnostics.js.map +1 -0
  17. package/dist/adapters/agents/protocol-fixtures.constants.d.ts +2 -0
  18. package/dist/adapters/agents/protocol-fixtures.constants.js +68 -0
  19. package/dist/adapters/agents/protocol-fixtures.constants.js.map +1 -0
  20. package/dist/adapters/agents/protocol-fixtures.types.d.ts +6 -0
  21. package/dist/adapters/agents/protocol-fixtures.types.js +2 -0
  22. package/dist/adapters/agents/protocol-fixtures.types.js.map +1 -0
  23. package/dist/application/diagnostic-probe.d.ts +3 -0
  24. package/dist/application/diagnostic-probe.js +55 -0
  25. package/dist/application/diagnostic-probe.js.map +1 -0
  26. package/dist/application/doctor-agent.constants.d.ts +9 -0
  27. package/dist/application/doctor-agent.constants.js +8 -0
  28. package/dist/application/doctor-agent.constants.js.map +1 -0
  29. package/dist/application/doctor-agent.d.ts +3 -0
  30. package/dist/application/doctor-agent.js +53 -0
  31. package/dist/application/doctor-agent.js.map +1 -0
  32. package/dist/application/doctor-image.d.ts +3 -0
  33. package/dist/application/doctor-image.js +133 -0
  34. package/dist/application/doctor-image.js.map +1 -0
  35. package/dist/application/doctor-protocol.d.ts +3 -0
  36. package/dist/application/doctor-protocol.js +29 -0
  37. package/dist/application/doctor-protocol.js.map +1 -0
  38. package/dist/application/doctor-protocol.types.d.ts +10 -0
  39. package/dist/application/doctor-protocol.types.js +2 -0
  40. package/dist/application/doctor-protocol.types.js.map +1 -0
  41. package/dist/application/doctor-sandbox.constants.d.ts +5 -0
  42. package/dist/application/doctor-sandbox.constants.js +6 -0
  43. package/dist/application/doctor-sandbox.constants.js.map +1 -0
  44. package/dist/application/doctor-sandbox.d.ts +4 -0
  45. package/dist/application/doctor-sandbox.js +133 -0
  46. package/dist/application/doctor-sandbox.js.map +1 -0
  47. package/dist/application/doctor-sandbox.types.d.ts +23 -0
  48. package/dist/application/doctor-sandbox.types.js +2 -0
  49. package/dist/application/doctor-sandbox.types.js.map +1 -0
  50. package/dist/application/doctor-transfers.constants.d.ts +6 -0
  51. package/dist/application/doctor-transfers.constants.js +7 -0
  52. package/dist/application/doctor-transfers.constants.js.map +1 -0
  53. package/dist/application/doctor-transfers.d.ts +4 -0
  54. package/dist/application/doctor-transfers.js +88 -0
  55. package/dist/application/doctor-transfers.js.map +1 -0
  56. package/dist/application/doctor.constants.d.ts +9 -0
  57. package/dist/application/doctor.constants.js +15 -0
  58. package/dist/application/doctor.constants.js.map +1 -0
  59. package/dist/application/doctor.d.ts +3 -0
  60. package/dist/application/doctor.js +106 -0
  61. package/dist/application/doctor.js.map +1 -0
  62. package/dist/application/doctor.types.d.ts +39 -0
  63. package/dist/application/doctor.types.js +2 -0
  64. package/dist/application/doctor.types.js.map +1 -0
  65. package/dist/application/execution.js +1 -0
  66. package/dist/application/execution.js.map +1 -1
  67. package/dist/application/outpost.types.d.ts +2 -0
  68. package/dist/application/outpost.types.js.map +1 -1
  69. package/dist/application/recovery-checksum-capture.d.ts +2 -0
  70. package/dist/application/recovery-checksum-capture.js +32 -0
  71. package/dist/application/recovery-checksum-capture.js.map +1 -0
  72. package/dist/application/recovery-checksum-paths.d.ts +2 -0
  73. package/dist/application/recovery-checksum-paths.js +11 -0
  74. package/dist/application/recovery-checksum-paths.js.map +1 -0
  75. package/dist/application/recovery-checksums.constants.d.ts +5 -0
  76. package/dist/application/recovery-checksums.constants.js +6 -0
  77. package/dist/application/recovery-checksums.constants.js.map +1 -0
  78. package/dist/application/recovery-checksums.d.ts +3 -0
  79. package/dist/application/recovery-checksums.js +94 -0
  80. package/dist/application/recovery-checksums.js.map +1 -0
  81. package/dist/application/recovery-checksums.types.d.ts +17 -0
  82. package/dist/application/recovery-checksums.types.js +2 -0
  83. package/dist/application/recovery-checksums.types.js.map +1 -0
  84. package/dist/application/recovery-inspection.d.ts +2 -0
  85. package/dist/application/recovery-inspection.js +27 -0
  86. package/dist/application/recovery-inspection.js.map +1 -0
  87. package/dist/application/recovery-inspection.types.d.ts +15 -0
  88. package/dist/application/recovery-inspection.types.js +2 -0
  89. package/dist/application/recovery-inspection.types.js.map +1 -0
  90. package/dist/application/recovery-restorability.d.ts +2 -0
  91. package/dist/application/recovery-restorability.js +137 -0
  92. package/dist/application/recovery-restorability.js.map +1 -0
  93. package/dist/application/recovery-retention-policy.d.ts +2 -0
  94. package/dist/application/recovery-retention-policy.js +21 -0
  95. package/dist/application/recovery-retention-policy.js.map +1 -0
  96. package/dist/application/recovery-retention.constants.d.ts +3 -0
  97. package/dist/application/recovery-retention.constants.js +2 -0
  98. package/dist/application/recovery-retention.constants.js.map +1 -0
  99. package/dist/application/recovery-retention.d.ts +4 -0
  100. package/dist/application/recovery-retention.js +202 -0
  101. package/dist/application/recovery-retention.js.map +1 -0
  102. package/dist/application/recovery-retention.types.d.ts +52 -0
  103. package/dist/application/recovery-retention.types.js +2 -0
  104. package/dist/application/recovery-retention.types.js.map +1 -0
  105. package/dist/application/recovery-verification.constants.d.ts +5 -0
  106. package/dist/application/recovery-verification.constants.js +10 -0
  107. package/dist/application/recovery-verification.constants.js.map +1 -0
  108. package/dist/application/recovery-verification.d.ts +2 -0
  109. package/dist/application/recovery-verification.js +107 -0
  110. package/dist/application/recovery-verification.js.map +1 -0
  111. package/dist/application/recovery-verification.types.d.ts +26 -0
  112. package/dist/application/recovery-verification.types.js +2 -0
  113. package/dist/application/recovery-verification.types.js.map +1 -0
  114. package/dist/application/remote-apply.js +24 -6
  115. package/dist/application/remote-apply.js.map +1 -1
  116. package/dist/application/remote-backup.js +6 -2
  117. package/dist/application/remote-backup.js.map +1 -1
  118. package/dist/application/remote-download.js +36 -4
  119. package/dist/application/remote-download.js.map +1 -1
  120. package/dist/application/remote-validation.js +19 -0
  121. package/dist/application/remote-validation.js.map +1 -1
  122. package/dist/application/remote-workspace.constants.d.ts +3 -0
  123. package/dist/application/remote-workspace.constants.js +2 -0
  124. package/dist/application/remote-workspace.constants.js.map +1 -0
  125. package/dist/application/remote-workspace.js +6 -0
  126. package/dist/application/remote-workspace.js.map +1 -1
  127. package/dist/application/remote-workspace.types.d.ts +3 -1
  128. package/dist/application/remote-workspace.types.js.map +1 -1
  129. package/dist/application/sandbox.js +11 -0
  130. package/dist/application/sandbox.js.map +1 -1
  131. package/dist/application/task-usage.d.ts +4 -0
  132. package/dist/application/task-usage.js +41 -0
  133. package/dist/application/task-usage.js.map +1 -0
  134. package/dist/application/task-usage.types.d.ts +5 -0
  135. package/dist/application/task-usage.types.js +2 -0
  136. package/dist/application/task-usage.types.js.map +1 -0
  137. package/dist/application/tasks.js +23 -2
  138. package/dist/application/tasks.js.map +1 -1
  139. package/dist/cli/commands.js +4 -0
  140. package/dist/cli/commands.js.map +1 -1
  141. package/dist/cli/doctor-command.d.ts +3 -0
  142. package/dist/cli/doctor-command.js +38 -0
  143. package/dist/cli/doctor-command.js.map +1 -0
  144. package/dist/cli/main.constants.d.ts +28 -1
  145. package/dist/cli/main.constants.js +15 -0
  146. package/dist/cli/main.constants.js.map +1 -1
  147. package/dist/cli/recovery-command.d.ts +2 -0
  148. package/dist/cli/recovery-command.js +69 -0
  149. package/dist/cli/recovery-command.js.map +1 -0
  150. package/dist/cli/recovery-prune-command.d.ts +2 -0
  151. package/dist/cli/recovery-prune-command.js +34 -0
  152. package/dist/cli/recovery-prune-command.js.map +1 -0
  153. package/dist/cli/recovery-verify-command.d.ts +2 -0
  154. package/dist/cli/recovery-verify-command.js +43 -0
  155. package/dist/cli/recovery-verify-command.js.map +1 -0
  156. package/dist/domain/ports.d.ts +1 -1
  157. package/dist/domain/ports.js.map +1 -1
  158. package/dist/domain/sandbox.types.d.ts +12 -0
  159. package/dist/domain/sandbox.types.js.map +1 -1
  160. package/dist/domain/workflow/budget.constants.d.ts +1 -0
  161. package/dist/domain/workflow/budget.constants.js +7 -0
  162. package/dist/domain/workflow/budget.constants.js.map +1 -0
  163. package/dist/domain/workflow/budget.d.ts +9 -0
  164. package/dist/domain/workflow/budget.js +67 -0
  165. package/dist/domain/workflow/budget.js.map +1 -0
  166. package/dist/domain/workflow/budget.types.d.ts +15 -0
  167. package/dist/domain/workflow/budget.types.js +2 -0
  168. package/dist/domain/workflow/budget.types.js.map +1 -0
  169. package/dist/domain/workflow/task-runner.js +8 -1
  170. package/dist/domain/workflow/task-runner.js.map +1 -1
  171. package/dist/domain/workflow/workflow-scheduler.js +4 -2
  172. package/dist/domain/workflow/workflow-scheduler.js.map +1 -1
  173. package/dist/domain/workflow/workflow-state.js +29 -0
  174. package/dist/domain/workflow/workflow-state.js.map +1 -1
  175. package/dist/domain/workflow.d.ts +2 -0
  176. package/dist/domain/workflow.js +1 -0
  177. package/dist/domain/workflow.js.map +1 -1
  178. package/dist/domain/workflow.types.d.ts +10 -1
  179. package/dist/domain/workflow.types.js.map +1 -1
  180. package/dist/index.d.ts +12 -3
  181. package/dist/index.js +5 -1
  182. package/dist/index.js.map +1 -1
  183. package/dist/infrastructure/file-manifest.d.ts +6 -0
  184. package/dist/infrastructure/file-manifest.js +91 -0
  185. package/dist/infrastructure/file-manifest.js.map +1 -0
  186. package/dist/infrastructure/git/lock-inspection.constants.d.ts +4 -0
  187. package/dist/infrastructure/git/lock-inspection.constants.js +5 -0
  188. package/dist/infrastructure/git/lock-inspection.constants.js.map +1 -0
  189. package/dist/infrastructure/git/lock-inspection.d.ts +3 -0
  190. package/dist/infrastructure/git/lock-inspection.js +64 -0
  191. package/dist/infrastructure/git/lock-inspection.js.map +1 -0
  192. package/dist/infrastructure/git/lock-inspection.types.d.ts +27 -0
  193. package/dist/infrastructure/git/lock-inspection.types.js +2 -0
  194. package/dist/infrastructure/git/lock-inspection.types.js.map +1 -0
  195. package/dist/infrastructure/git/lock.d.ts +1 -0
  196. package/dist/infrastructure/git/lock.js +70 -29
  197. package/dist/infrastructure/git/lock.js.map +1 -1
  198. package/dist/infrastructure/git/process-identity.d.ts +3 -0
  199. package/dist/infrastructure/git/process-identity.js +73 -0
  200. package/dist/infrastructure/git/process-identity.js.map +1 -0
  201. package/dist/infrastructure/git/process-identity.types.d.ts +10 -0
  202. package/dist/infrastructure/git/process-identity.types.js +2 -0
  203. package/dist/infrastructure/git/process-identity.types.js.map +1 -0
  204. package/dist/infrastructure/git/verification-command.d.ts +1 -0
  205. package/dist/infrastructure/git/verification-command.js +36 -0
  206. package/dist/infrastructure/git/verification-command.js.map +1 -0
  207. package/dist/infrastructure/git/workspace-lease.js +1 -0
  208. package/dist/infrastructure/git/workspace-lease.js.map +1 -1
  209. package/dist/infrastructure/git/workspace.js +5 -1
  210. package/dist/infrastructure/git/workspace.js.map +1 -1
  211. package/dist/infrastructure/git/worktree-inspection.constants.d.ts +5 -0
  212. package/dist/infrastructure/git/worktree-inspection.constants.js +16 -0
  213. package/dist/infrastructure/git/worktree-inspection.constants.js.map +1 -0
  214. package/dist/infrastructure/git/worktree-inspection.d.ts +3 -0
  215. package/dist/infrastructure/git/worktree-inspection.js +120 -0
  216. package/dist/infrastructure/git/worktree-inspection.js.map +1 -0
  217. package/dist/infrastructure/git/worktree-inspection.types.d.ts +19 -0
  218. package/dist/infrastructure/git/worktree-inspection.types.js +2 -0
  219. package/dist/infrastructure/git/worktree-inspection.types.js.map +1 -0
  220. package/dist/infrastructure/inspection-file.constants.d.ts +1 -0
  221. package/dist/infrastructure/inspection-file.constants.js +5 -0
  222. package/dist/infrastructure/inspection-file.constants.js.map +1 -0
  223. package/dist/infrastructure/inspection-file.d.ts +1 -0
  224. package/dist/infrastructure/inspection-file.js +43 -0
  225. package/dist/infrastructure/inspection-file.js.map +1 -0
  226. package/dist/infrastructure/inspection-hash.constants.d.ts +1 -0
  227. package/dist/infrastructure/inspection-hash.constants.js +2 -0
  228. package/dist/infrastructure/inspection-hash.constants.js.map +1 -0
  229. package/dist/infrastructure/inspection-hash.d.ts +2 -0
  230. package/dist/infrastructure/inspection-hash.js +62 -0
  231. package/dist/infrastructure/inspection-hash.js.map +1 -0
  232. package/dist/infrastructure/inspection-hash.types.d.ts +5 -0
  233. package/dist/infrastructure/inspection-hash.types.js +2 -0
  234. package/dist/infrastructure/inspection-hash.types.js.map +1 -0
  235. package/dist/infrastructure/journal-retention.constants.d.ts +4 -0
  236. package/dist/infrastructure/journal-retention.constants.js +5 -0
  237. package/dist/infrastructure/journal-retention.constants.js.map +1 -0
  238. package/dist/infrastructure/journal-retention.d.ts +2 -0
  239. package/dist/infrastructure/journal-retention.js +51 -0
  240. package/dist/infrastructure/journal-retention.js.map +1 -0
  241. package/dist/infrastructure/journal.js +37 -13
  242. package/dist/infrastructure/journal.js.map +1 -1
  243. package/dist/infrastructure/opentelemetry.constants.d.ts +10 -0
  244. package/dist/infrastructure/opentelemetry.constants.js +11 -0
  245. package/dist/infrastructure/opentelemetry.constants.js.map +1 -0
  246. package/dist/infrastructure/opentelemetry.d.ts +3 -0
  247. package/dist/infrastructure/opentelemetry.js +131 -0
  248. package/dist/infrastructure/opentelemetry.js.map +1 -0
  249. package/dist/infrastructure/opentelemetry.types.d.ts +21 -0
  250. package/dist/infrastructure/opentelemetry.types.js +2 -0
  251. package/dist/infrastructure/opentelemetry.types.js.map +1 -0
  252. package/dist/infrastructure/storage-inventory.constants.d.ts +6 -0
  253. package/dist/infrastructure/storage-inventory.constants.js +11 -0
  254. package/dist/infrastructure/storage-inventory.constants.js.map +1 -0
  255. package/dist/infrastructure/storage-inventory.d.ts +2 -0
  256. package/dist/infrastructure/storage-inventory.js +123 -0
  257. package/dist/infrastructure/storage-inventory.js.map +1 -0
  258. package/dist/infrastructure/storage-inventory.types.d.ts +38 -0
  259. package/dist/infrastructure/storage-inventory.types.js +2 -0
  260. package/dist/infrastructure/storage-inventory.types.js.map +1 -0
  261. package/dist/infrastructure/transfer.js +12 -0
  262. package/dist/infrastructure/transfer.js.map +1 -1
  263. package/dist/providers/cloud.constants.d.ts +1 -0
  264. package/dist/providers/cloud.constants.js +1 -0
  265. package/dist/providers/cloud.constants.js.map +1 -1
  266. package/dist/providers/container-cache.constants.d.ts +11 -0
  267. package/dist/providers/container-cache.constants.js +9 -0
  268. package/dist/providers/container-cache.constants.js.map +1 -0
  269. package/dist/providers/container-cache.d.ts +4 -0
  270. package/dist/providers/container-cache.js +48 -0
  271. package/dist/providers/container-cache.js.map +1 -0
  272. package/dist/providers/container-cache.types.d.ts +8 -0
  273. package/dist/providers/container-cache.types.js +2 -0
  274. package/dist/providers/container-cache.types.js.map +1 -0
  275. package/dist/providers/container-plan.js +3 -1
  276. package/dist/providers/container-plan.js.map +1 -1
  277. package/dist/providers/container.js +31 -1
  278. package/dist/providers/container.js.map +1 -1
  279. package/dist/providers/container.types.d.ts +2 -0
  280. package/dist/providers/container.types.js.map +1 -1
  281. package/dist/providers/daytona-command.js +7 -4
  282. package/dist/providers/daytona-command.js.map +1 -1
  283. package/dist/providers/daytona.js +13 -4
  284. package/dist/providers/daytona.js.map +1 -1
  285. package/dist/providers/diagnostic-container.d.ts +4 -0
  286. package/dist/providers/diagnostic-container.js +15 -0
  287. package/dist/providers/diagnostic-container.js.map +1 -0
  288. package/dist/providers/docker.d.ts +1 -0
  289. package/dist/providers/docker.js.map +1 -1
  290. package/dist/providers/file-batches.constants.d.ts +10 -0
  291. package/dist/providers/file-batches.constants.js +57 -0
  292. package/dist/providers/file-batches.constants.js.map +1 -0
  293. package/dist/providers/file-batches.d.ts +2 -0
  294. package/dist/providers/file-batches.js +151 -0
  295. package/dist/providers/file-batches.js.map +1 -0
  296. package/dist/providers/podman.d.ts +1 -0
  297. package/dist/providers/podman.js.map +1 -1
  298. package/dist/providers/vercel.js +3 -1
  299. package/dist/providers/vercel.js.map +1 -1
  300. package/package.json +12 -1
@@ -4,6 +4,12 @@ outpost init [--yes] [--agent codex|claude] [--provider docker|podman|vercel|day
4
4
  [--manager npm|pnpm|yarn|bun] [--model NAME] [--install] [--build] [--image NAME] [--directory PATH] [--repository PATH]
5
5
  outpost image build|remove [--engine docker|podman] [--file PATH] [--image NAME] [--uid ID] [--gid ID]
6
6
 
7
+ outpost doctor [--provider docker|podman|local|vercel|daytona] [--agent codex|claude] [--image NAME] [--json]
8
+
9
+ outpost recovery inspect [--repository PATH] [--max-entries NUMBER] [--git] [--locks] [--json]
10
+ outpost recovery verify --directory TRANSFER_PATH [--checksums] [--max-bytes NUMBER] [--restorability --repository PATH] [--json]
11
+ outpost recovery prune --policy FILE [--repository PATH] [--apply] [--json]
12
+
7
13
  Node.js 24+ and Git are required. Run generated scripts with Node.js.
8
14
  Initialization writes run.ts and project files directly into --directory (default: current directory).
9
15
  --repository selects the target Git repository; relative paths are resolved from the workflow directory.
@@ -13,6 +19,15 @@ export const cliOptions = {
13
19
  yes: { type: "boolean", short: "y" },
14
20
  install: { type: "boolean" },
15
21
  build: { type: "boolean" },
22
+ json: { type: "boolean" },
23
+ git: { type: "boolean" },
24
+ locks: { type: "boolean" },
25
+ restorability: { type: "boolean" },
26
+ apply: { type: "boolean" },
27
+ policy: { type: "string" },
28
+ checksums: { type: "boolean" },
29
+ "max-bytes": { type: "string" },
30
+ "max-entries": { type: "string" },
16
31
  agent: { type: "string" },
17
32
  provider: { type: "string" },
18
33
  manager: { type: "string" },
@@ -1 +1 @@
1
- {"version":3,"file":"main.constants.js","sourceRoot":"","sources":["../../src/cli/main.constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,IAAI,GAAG;;;;;;;;;CASnB,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE;IACrC,GAAG,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE;IACpC,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;IAC5B,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;IAC1B,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IACzB,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IAC5B,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IAC3B,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IACzB,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IAC7B,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IAC9B,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IACxB,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IACzB,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IACvB,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;CACf,CAAC;AAEX,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,CAAC,OAAO,EAAE,sBAAsB,EAAE,OAAO,CAAC;IAC1C,CAAC,UAAU,EAAE,8CAA8C,EAAE,QAAQ,CAAC;CAC9D,CAAC","sourcesContent":["export const help = `Outpost — sandboxed coding agents and workflows\n\noutpost init [--yes] [--agent codex|claude] [--provider docker|podman|vercel|daytona|local]\n [--manager npm|pnpm|yarn|bun] [--model NAME] [--install] [--build] [--image NAME] [--directory PATH] [--repository PATH]\noutpost image build|remove [--engine docker|podman] [--file PATH] [--image NAME] [--uid ID] [--gid ID]\n\nNode.js 24+ and Git are required. Run generated scripts with Node.js.\nInitialization writes run.ts and project files directly into --directory (default: current directory).\n--repository selects the target Git repository; relative paths are resolved from the workflow directory.\n`;\n\nexport const cliOptions = {\n help: { type: \"boolean\", short: \"h\" },\n yes: { type: \"boolean\", short: \"y\" },\n install: { type: \"boolean\" },\n build: { type: \"boolean\" },\n agent: { type: \"string\" },\n provider: { type: \"string\" },\n manager: { type: \"string\" },\n model: { type: \"string\" },\n directory: { type: \"string\" },\n repository: { type: \"string\" },\n engine: { type: \"string\" },\n file: { type: \"string\" },\n image: { type: \"string\" },\n uid: { type: \"string\" },\n gid: { type: \"string\" },\n} as const;\n\nexport const initializationQuestions = [\n [\"agent\", \"Agent (codex/claude)\", \"codex\"],\n [\"provider\", \"Sandbox (docker/podman/vercel/daytona/local)\", \"docker\"],\n] as const;\n"]}
1
+ {"version":3,"file":"main.constants.js","sourceRoot":"","sources":["../../src/cli/main.constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,IAAI,GAAG;;;;;;;;;;;;;;;CAenB,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE;IACrC,GAAG,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE;IACpC,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;IAC5B,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;IAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;IACzB,GAAG,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;IACxB,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;IAC1B,aAAa,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;IAClC,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;IAC1B,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IAC1B,SAAS,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;IAC9B,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IAC/B,aAAa,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IACjC,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IACzB,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IAC5B,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IAC3B,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IACzB,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IAC7B,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IAC9B,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IACxB,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IACzB,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IACvB,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;CACf,CAAC;AAEX,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,CAAC,OAAO,EAAE,sBAAsB,EAAE,OAAO,CAAC;IAC1C,CAAC,UAAU,EAAE,8CAA8C,EAAE,QAAQ,CAAC;CAC9D,CAAC","sourcesContent":["export const help = `Outpost — sandboxed coding agents and workflows\n\noutpost init [--yes] [--agent codex|claude] [--provider docker|podman|vercel|daytona|local]\n [--manager npm|pnpm|yarn|bun] [--model NAME] [--install] [--build] [--image NAME] [--directory PATH] [--repository PATH]\noutpost image build|remove [--engine docker|podman] [--file PATH] [--image NAME] [--uid ID] [--gid ID]\n\noutpost doctor [--provider docker|podman|local|vercel|daytona] [--agent codex|claude] [--image NAME] [--json]\n\noutpost recovery inspect [--repository PATH] [--max-entries NUMBER] [--git] [--locks] [--json]\noutpost recovery verify --directory TRANSFER_PATH [--checksums] [--max-bytes NUMBER] [--restorability --repository PATH] [--json]\noutpost recovery prune --policy FILE [--repository PATH] [--apply] [--json]\n\nNode.js 24+ and Git are required. Run generated scripts with Node.js.\nInitialization writes run.ts and project files directly into --directory (default: current directory).\n--repository selects the target Git repository; relative paths are resolved from the workflow directory.\n`;\n\nexport const cliOptions = {\n help: { type: \"boolean\", short: \"h\" },\n yes: { type: \"boolean\", short: \"y\" },\n install: { type: \"boolean\" },\n build: { type: \"boolean\" },\n json: { type: \"boolean\" },\n git: { type: \"boolean\" },\n locks: { type: \"boolean\" },\n restorability: { type: \"boolean\" },\n apply: { type: \"boolean\" },\n policy: { type: \"string\" },\n checksums: { type: \"boolean\" },\n \"max-bytes\": { type: \"string\" },\n \"max-entries\": { type: \"string\" },\n agent: { type: \"string\" },\n provider: { type: \"string\" },\n manager: { type: \"string\" },\n model: { type: \"string\" },\n directory: { type: \"string\" },\n repository: { type: \"string\" },\n engine: { type: \"string\" },\n file: { type: \"string\" },\n image: { type: \"string\" },\n uid: { type: \"string\" },\n gid: { type: \"string\" },\n} as const;\n\nexport const initializationQuestions = [\n [\"agent\", \"Agent (codex/claude)\", \"codex\"],\n [\"provider\", \"Sandbox (docker/podman/vercel/daytona/local)\", \"docker\"],\n] as const;\n"]}
@@ -0,0 +1,2 @@
1
+ import type { CliInvocation } from "./main.types.ts";
2
+ export declare function recoveryCommand({ values, positionals, }: CliInvocation): Promise<void>;
@@ -0,0 +1,69 @@
1
+ import { recoveryPruneCommand } from "./recovery-prune-command.js";
2
+ import { recoveryVerifyCommand } from "./recovery-verify-command.js";
3
+ import { inspectRecovery } from "../application/recovery-inspection.js";
4
+ import { invariant, positive } from "../domain/errors.js";
5
+ export async function recoveryCommand({ values, positionals, }) {
6
+ if (positionals[1] === "prune")
7
+ return recoveryPruneCommand({ values, positionals });
8
+ if (positionals[1] === "verify")
9
+ return recoveryVerifyCommand({ values, positionals });
10
+ invariant(positionals.length === 2 && positionals[1] === "inspect", "Usage: outpost recovery inspect [--repository PATH] [--max-entries NUMBER] [--git] [--locks] [--json]");
11
+ for (const key of Object.keys(values))
12
+ invariant(["repository", "max-entries", "git", "locks", "json"].includes(key), `Unsupported recovery option: --${key}`);
13
+ const maxEntries = values["max-entries"] === undefined
14
+ ? undefined
15
+ : positive(Number(values["max-entries"]), "max-entries");
16
+ const report = await inspectRecovery({
17
+ ...(values.repository !== undefined
18
+ ? { repository: values.repository }
19
+ : {}),
20
+ ...(maxEntries !== undefined ? { maxEntries } : {}),
21
+ ...(values.git ? { git: true } : {}),
22
+ ...(values.locks ? { locks: true } : {}),
23
+ });
24
+ if (values.json)
25
+ process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
26
+ else {
27
+ process.stdout.write(`Outpost recovery inspection — ${JSON.stringify(report.repository)}\n`);
28
+ for (const category of report.categories) {
29
+ process.stdout.write(`${category.name}: ${category.entries.length} listed entries\n`);
30
+ for (const entry of category.entries)
31
+ process.stdout.write(` ${JSON.stringify(entry.name)} | ${entry.kind} | ${entry.bytes} bytes | ${entry.files} files | ${entry.symlinks} symlinks | ${entry.modifiedAt ?? "unknown time"} | ${entry.complete ? "complete" : "partial"}\n`);
32
+ }
33
+ if (report.git) {
34
+ process.stdout.write(`Workspace Git inspection: ${report.git.complete ? "complete for listed entries" : "partial"}\n`);
35
+ for (const workspace of report.git.workspaces) {
36
+ const detail = workspace.state === "registered"
37
+ ? `${workspace.branch === null ? "detached HEAD" : JSON.stringify(workspace.branch)} | ${workspace.dirty ? "dirty" : "clean"} | ${workspace.head}${workspace.locked ? " | Git locked" : ""}`
38
+ : workspace.state;
39
+ process.stdout.write(` ${JSON.stringify(workspace.name)} | ${detail}\n`);
40
+ }
41
+ for (const issue of report.git.issues)
42
+ process.stdout.write(`[PARTIAL] ${issue.code}: ${JSON.stringify(issue.path)}\n`);
43
+ process.stdout.write("Git status excludes ignored files. Clean does not mean safe to delete.\n");
44
+ }
45
+ if (report.locks) {
46
+ process.stdout.write(`Lock PID inspection (local host): ${report.locks.complete ? "complete for listed entries" : "partial"}\n`);
47
+ for (const lock of report.locks.entries) {
48
+ const pid = "pid" in lock ? ` | PID ${lock.pid}` : "";
49
+ const reason = "reason" in lock ? ` | ${lock.reason}` : "";
50
+ process.stdout.write(` ${JSON.stringify(lock.name)} | ${lock.state}${pid}${reason}${lock.ownership ? ` | ownership ${lock.ownership.status}: ${lock.ownership.reason}` : ""}\n`);
51
+ }
52
+ for (const issue of report.locks.issues)
53
+ process.stdout.write(`[PARTIAL] ${issue.code}: ${JSON.stringify(issue.path)}\n`);
54
+ process.stdout.write("PID presence does not prove lock ownership; PID absence does not authorize deletion.\n");
55
+ }
56
+ for (const issue of report.issues)
57
+ process.stdout.write(`[PARTIAL] ${issue.code}: ${JSON.stringify(issue.path)}\n`);
58
+ process.stdout.write(`Total observed: ${report.usage.bytes} bytes in ${report.usage.files} files; ${report.scannedEntries}/${report.maxEntries} entries scanned.\n`);
59
+ process.stdout.write(`${report.complete ? "Inventory complete." : "Inventory incomplete; totals are partial."} File sizes are logical bytes; symlink targets are excluded.\n`);
60
+ process.stdout.write(report.git || report.locks
61
+ ? "Activity and recovery integrity are unverified. No raw file contents were displayed or files removed.\n"
62
+ : "Activity and recovery integrity are unverified. No files were read for content or removed.\n");
63
+ }
64
+ if (!report.complete ||
65
+ report.git?.complete === false ||
66
+ report.locks?.complete === false)
67
+ process.exitCode = 1;
68
+ }
69
+ //# sourceMappingURL=recovery-command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recovery-command.js","sourceRoot":"","sources":["../../src/cli/recovery-command.ts"],"names":[],"mappings":"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","sourcesContent":["import { recoveryPruneCommand } from \"./recovery-prune-command.ts\";\nimport { recoveryVerifyCommand } from \"./recovery-verify-command.ts\";\nimport { inspectRecovery } from \"../application/recovery-inspection.ts\";\nimport { invariant, positive } from \"../domain/errors.ts\";\nimport type { CliInvocation } from \"./main.types.ts\";\n\nexport async function recoveryCommand({\n values,\n positionals,\n}: CliInvocation): Promise<void> {\n if (positionals[1] === \"prune\")\n return recoveryPruneCommand({ values, positionals });\n if (positionals[1] === \"verify\")\n return recoveryVerifyCommand({ values, positionals });\n invariant(\n positionals.length === 2 && positionals[1] === \"inspect\",\n \"Usage: outpost recovery inspect [--repository PATH] [--max-entries NUMBER] [--git] [--locks] [--json]\",\n );\n for (const key of Object.keys(values))\n invariant(\n [\"repository\", \"max-entries\", \"git\", \"locks\", \"json\"].includes(key),\n `Unsupported recovery option: --${key}`,\n );\n const maxEntries =\n values[\"max-entries\"] === undefined\n ? undefined\n : positive(Number(values[\"max-entries\"]), \"max-entries\");\n const report = await inspectRecovery({\n ...(values.repository !== undefined\n ? { repository: values.repository }\n : {}),\n ...(maxEntries !== undefined ? { maxEntries } : {}),\n ...(values.git ? { git: true } : {}),\n ...(values.locks ? { locks: true } : {}),\n });\n if (values.json) process.stdout.write(`${JSON.stringify(report, null, 2)}\\n`);\n else {\n process.stdout.write(\n `Outpost recovery inspection — ${JSON.stringify(report.repository)}\\n`,\n );\n for (const category of report.categories) {\n process.stdout.write(\n `${category.name}: ${category.entries.length} listed entries\\n`,\n );\n for (const entry of category.entries)\n process.stdout.write(\n ` ${JSON.stringify(entry.name)} | ${entry.kind} | ${entry.bytes} bytes | ${entry.files} files | ${entry.symlinks} symlinks | ${entry.modifiedAt ?? \"unknown time\"} | ${entry.complete ? \"complete\" : \"partial\"}\\n`,\n );\n }\n if (report.git) {\n process.stdout.write(\n `Workspace Git inspection: ${report.git.complete ? \"complete for listed entries\" : \"partial\"}\\n`,\n );\n for (const workspace of report.git.workspaces) {\n const detail =\n workspace.state === \"registered\"\n ? `${workspace.branch === null ? \"detached HEAD\" : JSON.stringify(workspace.branch)} | ${workspace.dirty ? \"dirty\" : \"clean\"} | ${workspace.head}${workspace.locked ? \" | Git locked\" : \"\"}`\n : workspace.state;\n process.stdout.write(\n ` ${JSON.stringify(workspace.name)} | ${detail}\\n`,\n );\n }\n for (const issue of report.git.issues)\n process.stdout.write(\n `[PARTIAL] ${issue.code}: ${JSON.stringify(issue.path)}\\n`,\n );\n process.stdout.write(\n \"Git status excludes ignored files. Clean does not mean safe to delete.\\n\",\n );\n }\n if (report.locks) {\n process.stdout.write(\n `Lock PID inspection (local host): ${report.locks.complete ? \"complete for listed entries\" : \"partial\"}\\n`,\n );\n for (const lock of report.locks.entries) {\n const pid = \"pid\" in lock ? ` | PID ${lock.pid}` : \"\";\n const reason = \"reason\" in lock ? ` | ${lock.reason}` : \"\";\n process.stdout.write(\n ` ${JSON.stringify(lock.name)} | ${lock.state}${pid}${reason}${lock.ownership ? ` | ownership ${lock.ownership.status}: ${lock.ownership.reason}` : \"\"}\\n`,\n );\n }\n for (const issue of report.locks.issues)\n process.stdout.write(\n `[PARTIAL] ${issue.code}: ${JSON.stringify(issue.path)}\\n`,\n );\n process.stdout.write(\n \"PID presence does not prove lock ownership; PID absence does not authorize deletion.\\n\",\n );\n }\n for (const issue of report.issues)\n process.stdout.write(\n `[PARTIAL] ${issue.code}: ${JSON.stringify(issue.path)}\\n`,\n );\n process.stdout.write(\n `Total observed: ${report.usage.bytes} bytes in ${report.usage.files} files; ${report.scannedEntries}/${report.maxEntries} entries scanned.\\n`,\n );\n process.stdout.write(\n `${report.complete ? \"Inventory complete.\" : \"Inventory incomplete; totals are partial.\"} File sizes are logical bytes; symlink targets are excluded.\\n`,\n );\n process.stdout.write(\n report.git || report.locks\n ? \"Activity and recovery integrity are unverified. No raw file contents were displayed or files removed.\\n\"\n : \"Activity and recovery integrity are unverified. No files were read for content or removed.\\n\",\n );\n }\n if (\n !report.complete ||\n report.git?.complete === false ||\n report.locks?.complete === false\n )\n process.exitCode = 1;\n}\n"]}
@@ -0,0 +1,2 @@
1
+ import type { CliInvocation } from "./main.types.ts";
2
+ export declare function recoveryPruneCommand({ values, positionals, }: CliInvocation): Promise<void>;
@@ -0,0 +1,34 @@
1
+ import { recoveryRetentionLimits } from "../application/recovery-retention.constants.js";
2
+ import { planRecoveryRetention, pruneRecoveryRetention, } from "../application/recovery-retention.js";
3
+ import { retentionPolicy } from "../application/recovery-retention-policy.js";
4
+ import { invariant } from "../domain/errors.js";
5
+ import { readInspectionFile } from "../infrastructure/inspection-file.js";
6
+ import { resolve } from "node:path";
7
+ export async function recoveryPruneCommand({ values, positionals, }) {
8
+ invariant(positionals.length === 2 && !!values.policy, "Usage: outpost recovery prune --policy FILE [--repository PATH] [--apply] [--json]");
9
+ for (const key of Object.keys(values))
10
+ invariant(["policy", "repository", "apply", "json"].includes(key), `Unsupported recovery prune option: --${key}`);
11
+ const policy = JSON.parse((await readInspectionFile(resolve(values.policy), recoveryRetentionLimits.maxPolicyBytes)).toString("utf8"));
12
+ retentionPolicy(policy);
13
+ const plan = await planRecoveryRetention({
14
+ policy,
15
+ ...(values.repository ? { repository: values.repository } : {}),
16
+ });
17
+ const result = values.apply ? await pruneRecoveryRetention(plan) : undefined;
18
+ const after = result?.after ?? plan;
19
+ if (values.json)
20
+ process.stdout.write(`${JSON.stringify({ dryRun: !values.apply, plan, ...(result ? { result } : {}) }, null, 2)}\n`);
21
+ else {
22
+ process.stdout.write(`Outpost retention ${values.apply ? "apply" : "dry run"} — ${JSON.stringify(plan.repository)}\n`);
23
+ for (const entry of plan.entries)
24
+ process.stdout.write(`${entry.eligible ? "CANDIDATE" : "RETAIN"} ${JSON.stringify(entry.path)} | ${entry.reason} | ${entry.bytes} bytes\n`);
25
+ for (const path of result?.removed ?? [])
26
+ process.stdout.write(`REMOVED ${JSON.stringify(path)}\n`);
27
+ for (const entry of result?.retained ?? [])
28
+ process.stdout.write(`RETAIN ${JSON.stringify(entry.path)} | ${entry.reason}\n`);
29
+ process.stdout.write(`Observed ${after.usageBytes} logical bytes; projected ${after.projectedBytes}; projected quota ${after.quota}. Branches and recovery artifacts are retained.\n`);
30
+ }
31
+ if (!after.complete || after.quota !== "within" || result?.retained.length)
32
+ process.exitCode = 1;
33
+ }
34
+ //# sourceMappingURL=recovery-prune-command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recovery-prune-command.js","sourceRoot":"","sources":["../../src/cli/recovery-prune-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,gDAAgD,CAAC;AACzF,OAAO,EACL,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,6CAA6C,CAAC;AAC9E,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAC1E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,EACzC,MAAM,EACN,WAAW,GACG;IACd,SAAS,CACP,WAAW,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,MAAM,EAC3C,oFAAoF,CACrF,CAAC;IACF,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;QACnC,SAAS,CACP,CAAC,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,EACvD,wCAAwC,GAAG,EAAE,CAC9C,CAAC;IACJ,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAChC,CACE,MAAM,kBAAkB,CACtB,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EACtB,uBAAuB,CAAC,cAAc,CACvC,CACF,CAAC,QAAQ,CAAC,MAAM,CAAC,CACnB,CAAC;IACF,eAAe,CAAC,MAAM,CAAC,CAAC;IACxB,MAAM,IAAI,GAAG,MAAM,qBAAqB,CAAC;QACvC,MAAM;QACN,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAChE,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,sBAAsB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC7E,MAAM,KAAK,GAAG,MAAM,EAAE,KAAK,IAAI,IAAI,CAAC;IACpC,IAAI,MAAM,CAAC,IAAI;QACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAC/F,CAAC;SACC,CAAC;QACJ,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,qBAAqB,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CACjG,CAAC;QACF,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO;YAC9B,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,IAAI,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,MAAM,MAAM,KAAK,CAAC,KAAK,UAAU,CACtH,CAAC;QACJ,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,OAAO,IAAI,EAAE;YACtC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5D,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,QAAQ,IAAI,EAAE;YACxC,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,UAAU,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,MAAM,IAAI,CAC3D,CAAC;QACJ,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,YAAY,KAAK,CAAC,UAAU,6BAA6B,KAAK,CAAC,cAAc,qBAAqB,KAAK,CAAC,KAAK,mDAAmD,CACjK,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,KAAK,KAAK,QAAQ,IAAI,MAAM,EAAE,QAAQ,CAAC,MAAM;QACxE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACzB,CAAC","sourcesContent":["import { recoveryRetentionLimits } from \"../application/recovery-retention.constants.ts\";\nimport {\n planRecoveryRetention,\n pruneRecoveryRetention,\n} from \"../application/recovery-retention.ts\";\nimport { retentionPolicy } from \"../application/recovery-retention-policy.ts\";\nimport { invariant } from \"../domain/errors.ts\";\nimport { readInspectionFile } from \"../infrastructure/inspection-file.ts\";\nimport { resolve } from \"node:path\";\nimport type { CliInvocation } from \"./main.types.ts\";\n\nexport async function recoveryPruneCommand({\n values,\n positionals,\n}: CliInvocation): Promise<void> {\n invariant(\n positionals.length === 2 && !!values.policy,\n \"Usage: outpost recovery prune --policy FILE [--repository PATH] [--apply] [--json]\",\n );\n for (const key of Object.keys(values))\n invariant(\n [\"policy\", \"repository\", \"apply\", \"json\"].includes(key),\n `Unsupported recovery prune option: --${key}`,\n );\n const policy: unknown = JSON.parse(\n (\n await readInspectionFile(\n resolve(values.policy),\n recoveryRetentionLimits.maxPolicyBytes,\n )\n ).toString(\"utf8\"),\n );\n retentionPolicy(policy);\n const plan = await planRecoveryRetention({\n policy,\n ...(values.repository ? { repository: values.repository } : {}),\n });\n const result = values.apply ? await pruneRecoveryRetention(plan) : undefined;\n const after = result?.after ?? plan;\n if (values.json)\n process.stdout.write(\n `${JSON.stringify({ dryRun: !values.apply, plan, ...(result ? { result } : {}) }, null, 2)}\\n`,\n );\n else {\n process.stdout.write(\n `Outpost retention ${values.apply ? \"apply\" : \"dry run\"} — ${JSON.stringify(plan.repository)}\\n`,\n );\n for (const entry of plan.entries)\n process.stdout.write(\n `${entry.eligible ? \"CANDIDATE\" : \"RETAIN\"} ${JSON.stringify(entry.path)} | ${entry.reason} | ${entry.bytes} bytes\\n`,\n );\n for (const path of result?.removed ?? [])\n process.stdout.write(`REMOVED ${JSON.stringify(path)}\\n`);\n for (const entry of result?.retained ?? [])\n process.stdout.write(\n `RETAIN ${JSON.stringify(entry.path)} | ${entry.reason}\\n`,\n );\n process.stdout.write(\n `Observed ${after.usageBytes} logical bytes; projected ${after.projectedBytes}; projected quota ${after.quota}. Branches and recovery artifacts are retained.\\n`,\n );\n }\n if (!after.complete || after.quota !== \"within\" || result?.retained.length)\n process.exitCode = 1;\n}\n"]}
@@ -0,0 +1,2 @@
1
+ import type { CliInvocation } from "./main.types.ts";
2
+ export declare function recoveryVerifyCommand({ values, positionals, }: CliInvocation): Promise<void>;
@@ -0,0 +1,43 @@
1
+ import { verifyRecoveryTransfer } from "../application/recovery-verification.js";
2
+ import { invariant, positive } from "../domain/errors.js";
3
+ export async function recoveryVerifyCommand({ values, positionals, }) {
4
+ invariant(positionals.length === 2 && !!values.directory, "Usage: outpost recovery verify --directory TRANSFER_PATH [--checksums] [--max-bytes NUMBER] [--restorability --repository PATH] [--json]");
5
+ for (const key of Object.keys(values))
6
+ invariant([
7
+ "directory",
8
+ "checksums",
9
+ "max-bytes",
10
+ "json",
11
+ "restorability",
12
+ "repository",
13
+ ].includes(key), `Unsupported recovery verify option: --${key}`);
14
+ invariant(values["max-bytes"] === undefined || values.checksums, "--max-bytes requires --checksums");
15
+ invariant(!values.repository || values.restorability, "--repository requires --restorability");
16
+ const report = await verifyRecoveryTransfer(values.directory, {
17
+ ...(values.restorability ? { restorability: true } : {}),
18
+ ...(values.repository ? { repository: values.repository } : {}),
19
+ ...(values.checksums ? { checksums: true } : {}),
20
+ ...(values["max-bytes"] !== undefined
21
+ ? { maxBytes: positive(Number(values["max-bytes"]), "max-bytes") }
22
+ : {}),
23
+ });
24
+ if (values.json)
25
+ process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
26
+ else {
27
+ process.stdout.write(`Outpost recovery structure verification — ${JSON.stringify(report.directory)}\n`);
28
+ for (const check of report.checks)
29
+ process.stdout.write(`[${check.status.toUpperCase()}] ${check.code}: ${JSON.stringify(check.path)}\n`);
30
+ process.stdout.write(`${report.complete ? "Requested transfer checks passed." : "Transfer checks failed or are incomplete."}\n`);
31
+ if (values.restorability)
32
+ process.stdout.write("Restorability scope: commit objects, bundle validity and three transfer patches applied independently in a temporary clone. Payload restoration, original staging/worktree consistency, session patches, submodules and external dependencies are outside this scope. Target repository unchanged.\n");
33
+ if (values.checksums) {
34
+ process.stdout.write(`Checksums: ${report.integrity}; ${report.checksums?.bytesChecked ?? 0} bytes checked.\n`);
35
+ process.stdout.write("Checksums compare against an unsigned manifest. Activity and full restoration remain unverified. No files were changed.\n");
36
+ }
37
+ if (!values.checksums && !values.restorability)
38
+ process.stdout.write("Patch and bundle contents, commit availability, activity and restorability are unverified. No files were changed.\n");
39
+ }
40
+ if (!report.complete)
41
+ process.exitCode = 1;
42
+ }
43
+ //# sourceMappingURL=recovery-verify-command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recovery-verify-command.js","sourceRoot":"","sources":["../../src/cli/recovery-verify-command.ts"],"names":[],"mappings":"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","sourcesContent":["import { verifyRecoveryTransfer } from \"../application/recovery-verification.ts\";\nimport { invariant, positive } from \"../domain/errors.ts\";\nimport type { CliInvocation } from \"./main.types.ts\";\n\nexport async function recoveryVerifyCommand({\n values,\n positionals,\n}: CliInvocation): Promise<void> {\n invariant(\n positionals.length === 2 && !!values.directory,\n \"Usage: outpost recovery verify --directory TRANSFER_PATH [--checksums] [--max-bytes NUMBER] [--restorability --repository PATH] [--json]\",\n );\n for (const key of Object.keys(values))\n invariant(\n [\n \"directory\",\n \"checksums\",\n \"max-bytes\",\n \"json\",\n \"restorability\",\n \"repository\",\n ].includes(key),\n `Unsupported recovery verify option: --${key}`,\n );\n invariant(\n values[\"max-bytes\"] === undefined || values.checksums,\n \"--max-bytes requires --checksums\",\n );\n invariant(\n !values.repository || values.restorability,\n \"--repository requires --restorability\",\n );\n const report = await verifyRecoveryTransfer(values.directory, {\n ...(values.restorability ? { restorability: true } : {}),\n ...(values.repository ? { repository: values.repository } : {}),\n ...(values.checksums ? { checksums: true } : {}),\n ...(values[\"max-bytes\"] !== undefined\n ? { maxBytes: positive(Number(values[\"max-bytes\"]), \"max-bytes\") }\n : {}),\n });\n if (values.json) process.stdout.write(`${JSON.stringify(report, null, 2)}\\n`);\n else {\n process.stdout.write(\n `Outpost recovery structure verification — ${JSON.stringify(report.directory)}\\n`,\n );\n for (const check of report.checks)\n process.stdout.write(\n `[${check.status.toUpperCase()}] ${check.code}: ${JSON.stringify(check.path)}\\n`,\n );\n process.stdout.write(\n `${report.complete ? \"Requested transfer checks passed.\" : \"Transfer checks failed or are incomplete.\"}\\n`,\n );\n if (values.restorability)\n process.stdout.write(\n \"Restorability scope: commit objects, bundle validity and three transfer patches applied independently in a temporary clone. Payload restoration, original staging/worktree consistency, session patches, submodules and external dependencies are outside this scope. Target repository unchanged.\\n\",\n );\n if (values.checksums) {\n process.stdout.write(\n `Checksums: ${report.integrity}; ${report.checksums?.bytesChecked ?? 0} bytes checked.\\n`,\n );\n process.stdout.write(\n \"Checksums compare against an unsigned manifest. Activity and full restoration remain unverified. No files were changed.\\n\",\n );\n }\n if (!values.checksums && !values.restorability)\n process.stdout.write(\n \"Patch and bundle contents, commit availability, activity and restorability are unverified. No files were changed.\\n\",\n );\n }\n if (!report.complete) process.exitCode = 1;\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  export type { AgentAdapter, AgentEvent, AgentInput, AgentObservation, Usage, } from "./agent.types.ts";
2
2
  export type { Channel, Command, CommandResult, Variables, } from "./command.types.ts";
3
3
  export type { ConversationContext, ConversationRecord, ConversationStore, } from "./conversation.types.ts";
4
- export type { SandboxContext, SandboxLease, SandboxProvider, TransferOptions, Volume, } from "./sandbox.types.ts";
4
+ export type { FileManifestEntry, FileTransfers, SandboxContext, SandboxLease, SandboxProvider, TransferOptions, Volume, } from "./sandbox.types.ts";
5
5
  export type { BranchPolicy, Commit, Disposal, LifecycleHooks, StageLimits, WorkspaceRecord, } from "./workspace.types.ts";
@@ -1 +1 @@
1
- {"version":3,"file":"ports.js","sourceRoot":"","sources":["../../src/domain/ports.ts"],"names":[],"mappings":"","sourcesContent":["export type {\n AgentAdapter,\n AgentEvent,\n AgentInput,\n AgentObservation,\n Usage,\n} from \"./agent.types.ts\";\nexport type {\n Channel,\n Command,\n CommandResult,\n Variables,\n} from \"./command.types.ts\";\nexport type {\n ConversationContext,\n ConversationRecord,\n ConversationStore,\n} from \"./conversation.types.ts\";\nexport type {\n SandboxContext,\n SandboxLease,\n SandboxProvider,\n TransferOptions,\n Volume,\n} from \"./sandbox.types.ts\";\nexport type {\n BranchPolicy,\n Commit,\n Disposal,\n LifecycleHooks,\n StageLimits,\n WorkspaceRecord,\n} from \"./workspace.types.ts\";\n"]}
1
+ {"version":3,"file":"ports.js","sourceRoot":"","sources":["../../src/domain/ports.ts"],"names":[],"mappings":"","sourcesContent":["export type {\n AgentAdapter,\n AgentEvent,\n AgentInput,\n AgentObservation,\n Usage,\n} from \"./agent.types.ts\";\nexport type {\n Channel,\n Command,\n CommandResult,\n Variables,\n} from \"./command.types.ts\";\nexport type {\n ConversationContext,\n ConversationRecord,\n ConversationStore,\n} from \"./conversation.types.ts\";\nexport type {\n FileManifestEntry,\n FileTransfers,\n SandboxContext,\n SandboxLease,\n SandboxProvider,\n TransferOptions,\n Volume,\n} from \"./sandbox.types.ts\";\nexport type {\n BranchPolicy,\n Commit,\n Disposal,\n LifecycleHooks,\n StageLimits,\n WorkspaceRecord,\n} from \"./workspace.types.ts\";\n"]}
@@ -15,7 +15,19 @@ export interface TransferOptions {
15
15
  readonly signal?: AbortSignal;
16
16
  readonly deadlineMs?: number;
17
17
  }
18
+ export interface FileManifestEntry {
19
+ readonly path: string;
20
+ readonly kind: "file" | "link";
21
+ readonly mode: number;
22
+ readonly size: number;
23
+ readonly sha256: string;
24
+ }
25
+ export interface FileTransfers {
26
+ manifest(source: string, paths: readonly string[], options?: TransferOptions): Promise<readonly FileManifestEntry[]>;
27
+ downloadBatch(source: string, entries: readonly FileManifestEntry[], destination: string, options?: TransferOptions): Promise<void>;
28
+ }
18
29
  export interface SandboxLease {
30
+ readonly fileTransfers?: FileTransfers;
19
31
  readonly root: string;
20
32
  readonly home: string;
21
33
  invoke(command: Command): Promise<CommandResult>;
@@ -1 +1 @@
1
- {"version":3,"file":"sandbox.types.js","sourceRoot":"","sources":["../../src/domain/sandbox.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Command, CommandResult, Variables } from \"./command.types.ts\";\n\nexport interface Volume {\n readonly source: string;\n readonly target: string;\n readonly readOnly?: boolean;\n}\n\nexport interface SandboxContext {\n readonly repository: string;\n readonly directory: string;\n readonly gitDirectories: readonly string[];\n readonly variables: Variables;\n readonly signal?: AbortSignal;\n}\n\nexport interface TransferOptions {\n readonly signal?: AbortSignal;\n readonly deadlineMs?: number;\n}\n\nexport interface SandboxLease {\n readonly root: string;\n readonly home: string;\n invoke(command: Command): Promise<CommandResult>;\n upload(\n source: string,\n destination: string,\n options?: TransferOptions,\n ): Promise<void>;\n download(\n source: string,\n destination: string,\n options?: TransferOptions,\n ): Promise<void>;\n release(): Promise<void>;\n}\n\nexport interface SandboxProvider {\n readonly name: string;\n readonly placement: \"mounted\" | \"remote\" | \"host\";\n readonly variables?: Variables;\n acquire(context: SandboxContext): Promise<SandboxLease>;\n}\n"]}
1
+ {"version":3,"file":"sandbox.types.js","sourceRoot":"","sources":["../../src/domain/sandbox.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Command, CommandResult, Variables } from \"./command.types.ts\";\n\nexport interface Volume {\n readonly source: string;\n readonly target: string;\n readonly readOnly?: boolean;\n}\n\nexport interface SandboxContext {\n readonly repository: string;\n readonly directory: string;\n readonly gitDirectories: readonly string[];\n readonly variables: Variables;\n readonly signal?: AbortSignal;\n}\n\nexport interface TransferOptions {\n readonly signal?: AbortSignal;\n readonly deadlineMs?: number;\n}\n\nexport interface FileManifestEntry {\n readonly path: string;\n readonly kind: \"file\" | \"link\";\n readonly mode: number;\n readonly size: number;\n readonly sha256: string;\n}\n\nexport interface FileTransfers {\n manifest(\n source: string,\n paths: readonly string[],\n options?: TransferOptions,\n ): Promise<readonly FileManifestEntry[]>;\n downloadBatch(\n source: string,\n entries: readonly FileManifestEntry[],\n destination: string,\n options?: TransferOptions,\n ): Promise<void>;\n}\n\nexport interface SandboxLease {\n readonly fileTransfers?: FileTransfers;\n readonly root: string;\n readonly home: string;\n invoke(command: Command): Promise<CommandResult>;\n upload(\n source: string,\n destination: string,\n options?: TransferOptions,\n ): Promise<void>;\n download(\n source: string,\n destination: string,\n options?: TransferOptions,\n ): Promise<void>;\n release(): Promise<void>;\n}\n\nexport interface SandboxProvider {\n readonly name: string;\n readonly placement: \"mounted\" | \"remote\" | \"host\";\n readonly variables?: Variables;\n acquire(context: SandboxContext): Promise<SandboxLease>;\n}\n"]}
@@ -0,0 +1 @@
1
+ export declare const usageDimensions: readonly ["input", "cached", "cacheCreated", "output"];
@@ -0,0 +1,7 @@
1
+ export const usageDimensions = [
2
+ "input",
3
+ "cached",
4
+ "cacheCreated",
5
+ "output",
6
+ ];
7
+ //# sourceMappingURL=budget.constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budget.constants.js","sourceRoot":"","sources":["../../../src/domain/workflow/budget.constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,OAAO;IACP,QAAQ;IACR,cAAc;IACd,QAAQ;CACA,CAAC","sourcesContent":["export const usageDimensions = [\n \"input\",\n \"cached\",\n \"cacheCreated\",\n \"output\",\n] as const;\n"]}
@@ -0,0 +1,9 @@
1
+ import type { Usage } from "../agent.types.ts";
2
+ import type { WorkflowAccounting, WorkflowBudget } from "./budget.types.ts";
3
+ export declare class WorkflowBudgetExceeded extends Error {
4
+ readonly dimension: "attempts" | keyof Usage;
5
+ readonly limit: number;
6
+ readonly observed: number;
7
+ constructor(dimension: "attempts" | keyof Usage, limit: number, observed: number);
8
+ }
9
+ export declare function workflowAccounting(budget: WorkflowBudget | undefined, exhaust: (error: WorkflowBudgetExceeded) => void): WorkflowAccounting;
@@ -0,0 +1,67 @@
1
+ import { addUsage } from "../usage.js";
2
+ import { usageDimensions } from "./budget.constants.js";
3
+ export class WorkflowBudgetExceeded extends Error {
4
+ dimension;
5
+ limit;
6
+ observed;
7
+ constructor(dimension, limit, observed) {
8
+ super(`Workflow budget exhausted: ${dimension} limit ${limit}, observed ${observed}`);
9
+ this.name = "WorkflowBudgetExceeded";
10
+ this.dimension = dimension;
11
+ this.limit = limit;
12
+ this.observed = observed;
13
+ }
14
+ }
15
+ export function workflowAccounting(budget, exhaust) {
16
+ for (const [key, value] of Object.entries({
17
+ attempts: budget?.attempts,
18
+ ...budget?.usage,
19
+ })) {
20
+ if (value !== undefined && (!Number.isSafeInteger(value) || value < 0))
21
+ throw new Error(`Workflow budget ${key} must be a nonnegative safe integer`);
22
+ }
23
+ let attempts = 0;
24
+ let tokens = { input: 0, cached: 0, output: 0 };
25
+ let exhausted = false;
26
+ let usageExhausted = false;
27
+ function fail(dimension, limit, observed) {
28
+ const error = new WorkflowBudgetExceeded(dimension, limit, observed);
29
+ if (!exhausted || (dimension !== "attempts" && !usageExhausted)) {
30
+ exhausted = true;
31
+ if (dimension !== "attempts")
32
+ usageExhausted = true;
33
+ exhaust(error);
34
+ }
35
+ return error;
36
+ }
37
+ return {
38
+ get exhausted() {
39
+ return exhausted;
40
+ },
41
+ admit() {
42
+ if (budget?.attempts !== undefined && attempts >= budget.attempts)
43
+ throw fail("attempts", budget.attempts, attempts);
44
+ for (const dimension of usageDimensions) {
45
+ const limit = budget?.usage?.[dimension];
46
+ if (limit !== undefined && (tokens[dimension] ?? 0) >= limit)
47
+ throw fail(dimension, limit, tokens[dimension] ?? 0);
48
+ }
49
+ attempts++;
50
+ },
51
+ report(usage) {
52
+ for (const dimension of usageDimensions) {
53
+ const value = usage[dimension] ?? 0;
54
+ if (!Number.isSafeInteger(value) || value < 0)
55
+ throw new Error(`Reported usage ${dimension} must be a nonnegative safe integer`);
56
+ }
57
+ tokens = addUsage(tokens, usage);
58
+ for (const dimension of usageDimensions) {
59
+ const limit = budget?.usage?.[dimension];
60
+ if (limit !== undefined && (tokens[dimension] ?? 0) >= limit)
61
+ fail(dimension, limit, tokens[dimension] ?? 0);
62
+ }
63
+ },
64
+ snapshot: () => Object.freeze({ attempts, tokens: Object.freeze({ ...tokens }) }),
65
+ };
66
+ }
67
+ //# sourceMappingURL=budget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budget.js","sourceRoot":"","sources":["../../../src/domain/workflow/budget.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Usage } from \"../agent.types.ts\";\nimport { addUsage } from \"../usage.ts\";\nimport { usageDimensions } from \"./budget.constants.ts\";\nimport type { WorkflowAccounting, WorkflowBudget } from \"./budget.types.ts\";\n\nexport class WorkflowBudgetExceeded extends Error {\n readonly dimension: \"attempts\" | keyof Usage;\n readonly limit: number;\n readonly observed: number;\n constructor(\n dimension: \"attempts\" | keyof Usage,\n limit: number,\n observed: number,\n ) {\n super(\n `Workflow budget exhausted: ${dimension} limit ${limit}, observed ${observed}`,\n );\n this.name = \"WorkflowBudgetExceeded\";\n this.dimension = dimension;\n this.limit = limit;\n this.observed = observed;\n }\n}\n\nexport function workflowAccounting(\n budget: WorkflowBudget | undefined,\n exhaust: (error: WorkflowBudgetExceeded) => void,\n): WorkflowAccounting {\n for (const [key, value] of Object.entries({\n attempts: budget?.attempts,\n ...budget?.usage,\n })) {\n if (value !== undefined && (!Number.isSafeInteger(value) || value < 0))\n throw new Error(\n `Workflow budget ${key} must be a nonnegative safe integer`,\n );\n }\n let attempts = 0;\n let tokens: Usage = { input: 0, cached: 0, output: 0 };\n let exhausted = false;\n let usageExhausted = false;\n function fail(\n dimension: \"attempts\" | keyof Usage,\n limit: number,\n observed: number,\n ): WorkflowBudgetExceeded {\n const error = new WorkflowBudgetExceeded(dimension, limit, observed);\n if (!exhausted || (dimension !== \"attempts\" && !usageExhausted)) {\n exhausted = true;\n if (dimension !== \"attempts\") usageExhausted = true;\n exhaust(error);\n }\n return error;\n }\n return {\n get exhausted() {\n return exhausted;\n },\n admit() {\n if (budget?.attempts !== undefined && attempts >= budget.attempts)\n throw fail(\"attempts\", budget.attempts, attempts);\n for (const dimension of usageDimensions) {\n const limit = budget?.usage?.[dimension];\n if (limit !== undefined && (tokens[dimension] ?? 0) >= limit)\n throw fail(dimension, limit, tokens[dimension] ?? 0);\n }\n attempts++;\n },\n report(usage) {\n for (const dimension of usageDimensions) {\n const value = usage[dimension] ?? 0;\n if (!Number.isSafeInteger(value) || value < 0)\n throw new Error(\n `Reported usage ${dimension} must be a nonnegative safe integer`,\n );\n }\n tokens = addUsage(tokens, usage);\n for (const dimension of usageDimensions) {\n const limit = budget?.usage?.[dimension];\n if (limit !== undefined && (tokens[dimension] ?? 0) >= limit)\n fail(dimension, limit, tokens[dimension] ?? 0);\n }\n },\n snapshot: () =>\n Object.freeze({ attempts, tokens: Object.freeze({ ...tokens }) }),\n };\n}\n"]}
@@ -0,0 +1,15 @@
1
+ import type { Usage } from "../agent.types.ts";
2
+ export interface WorkflowBudget {
3
+ readonly attempts?: number;
4
+ readonly usage?: Partial<Usage>;
5
+ }
6
+ export interface WorkflowUsage {
7
+ readonly attempts: number;
8
+ readonly tokens: Usage;
9
+ }
10
+ export interface WorkflowAccounting {
11
+ readonly exhausted: boolean;
12
+ admit(): void;
13
+ report(usage: Usage): void;
14
+ snapshot(): WorkflowUsage;
15
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=budget.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budget.types.js","sourceRoot":"","sources":["../../../src/domain/workflow/budget.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Usage } from \"../agent.types.ts\";\n\nexport interface WorkflowBudget {\n readonly attempts?: number;\n readonly usage?: Partial<Usage>;\n}\n\nexport interface WorkflowUsage {\n readonly attempts: number;\n readonly tokens: Usage;\n}\n\nexport interface WorkflowAccounting {\n readonly exhausted: boolean;\n admit(): void;\n report(usage: Usage): void;\n snapshot(): WorkflowUsage;\n}\n"]}
@@ -1,3 +1,4 @@
1
+ import { WorkflowBudgetExceeded } from "./budget.js";
1
2
  import { setTimeout as delay } from "node:timers/promises";
2
3
  export async function runTask(item, runtime) {
3
4
  const { record, signal, context, emit, finish, values, errors, options, stop, } = runtime;
@@ -15,13 +16,16 @@ export async function runTask(item, runtime) {
15
16
  const limit = item.retry?.attempts ?? 1;
16
17
  for (let attempt = 1; attempt <= limit; attempt++) {
17
18
  signal.throwIfAborted();
19
+ runtime.accounting.admit();
18
20
  state.attempts = attempt;
21
+ emit({ type: "attempt", key: item.key, attempt });
19
22
  const deadline = new AbortController();
20
23
  const timer = item.timeoutMs === undefined
21
24
  ? undefined
22
25
  : setTimeout(() => deadline.abort(new Error(`${item.key} timed out`)), item.timeoutMs);
23
26
  const taskSignal = AbortSignal.any([signal, deadline.signal]);
24
27
  try {
28
+ taskSignal.throwIfAborted();
25
29
  const value = await item.perform(context(item, attempt, taskSignal));
26
30
  taskSignal.throwIfAborted();
27
31
  values.set(item, value);
@@ -29,6 +33,7 @@ export async function runTask(item, runtime) {
29
33
  return;
30
34
  }
31
35
  catch (error) {
36
+ runtime.closeAttempt(item);
32
37
  if (signal.aborted ||
33
38
  attempt === limit ||
34
39
  item.retry?.accepts?.(error, attempt) === false)
@@ -36,6 +41,7 @@ export async function runTask(item, runtime) {
36
41
  emit({ type: "retry", key: item.key, attempt });
37
42
  }
38
43
  finally {
44
+ runtime.closeAttempt(item);
39
45
  clearTimeout(timer);
40
46
  }
41
47
  await delay(item.retry?.delayMs ?? 0, undefined, { signal });
@@ -43,7 +49,8 @@ export async function runTask(item, runtime) {
43
49
  }
44
50
  catch (error) {
45
51
  state.error = error instanceof Error ? error.message : String(error);
46
- if (signal.aborted)
52
+ if (signal.aborted ||
53
+ (error instanceof WorkflowBudgetExceeded && runtime.accounting.exhausted))
47
54
  finish(item, "cancelled");
48
55
  else {
49
56
  errors.push(error);
@@ -1 +1 @@
1
- {"version":3,"file":"task-runner.js","sourceRoot":"","sources":["../../../src/domain/workflow/task-runner.ts"],"names":[],"mappings":"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","sourcesContent":["import { setTimeout as delay } from \"node:timers/promises\";\nimport type { Task, WorkflowExecutionState } from \"../workflow.types.ts\";\n\nexport async function runTask(\n item: Task,\n runtime: WorkflowExecutionState,\n): Promise<void> {\n const {\n record,\n signal,\n context,\n emit,\n finish,\n values,\n errors,\n options,\n stop,\n } = runtime;\n const state = record(item);\n state.status = \"active\";\n state.startedAt = new Date().toISOString();\n emit({ type: \"task\", key: item.key, status: \"active\", attempt: 0 });\n try {\n signal.throwIfAborted();\n if (item.condition && !(await item.condition(context(item, 0, signal)))) {\n signal.throwIfAborted();\n finish(item, \"skipped\");\n return;\n }\n const limit = item.retry?.attempts ?? 1;\n for (let attempt = 1; attempt <= limit; attempt++) {\n signal.throwIfAborted();\n state.attempts = attempt;\n const deadline = new AbortController();\n const timer =\n item.timeoutMs === undefined\n ? undefined\n : setTimeout(\n () => deadline.abort(new Error(`${item.key} timed out`)),\n item.timeoutMs,\n );\n const taskSignal = AbortSignal.any([signal, deadline.signal]);\n try {\n const value = await item.perform(context(item, attempt, taskSignal));\n taskSignal.throwIfAborted();\n values.set(item, value);\n finish(item, \"done\");\n return;\n } catch (error) {\n if (\n signal.aborted ||\n attempt === limit ||\n item.retry?.accepts?.(error, attempt) === false\n )\n throw error;\n emit({ type: \"retry\", key: item.key, attempt });\n } finally {\n clearTimeout(timer);\n }\n await delay(item.retry?.delayMs ?? 0, undefined, { signal });\n }\n } catch (error) {\n state.error = error instanceof Error ? error.message : String(error);\n if (signal.aborted) finish(item, \"cancelled\");\n else {\n errors.push(error);\n finish(item, \"failed\");\n if (options.stopOnError !== false) stop.abort(error);\n }\n }\n}\n"]}
1
+ {"version":3,"file":"task-runner.js","sourceRoot":"","sources":["../../../src/domain/workflow/task-runner.ts"],"names":[],"mappings":"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","sourcesContent":["import { WorkflowBudgetExceeded } from \"./budget.ts\";\nimport { setTimeout as delay } from \"node:timers/promises\";\nimport type { Task, WorkflowExecutionState } from \"../workflow.types.ts\";\n\nexport async function runTask(\n item: Task,\n runtime: WorkflowExecutionState,\n): Promise<void> {\n const {\n record,\n signal,\n context,\n emit,\n finish,\n values,\n errors,\n options,\n stop,\n } = runtime;\n const state = record(item);\n state.status = \"active\";\n state.startedAt = new Date().toISOString();\n emit({ type: \"task\", key: item.key, status: \"active\", attempt: 0 });\n try {\n signal.throwIfAborted();\n if (item.condition && !(await item.condition(context(item, 0, signal)))) {\n signal.throwIfAborted();\n finish(item, \"skipped\");\n return;\n }\n const limit = item.retry?.attempts ?? 1;\n for (let attempt = 1; attempt <= limit; attempt++) {\n signal.throwIfAborted();\n runtime.accounting.admit();\n state.attempts = attempt;\n emit({ type: \"attempt\", key: item.key, attempt });\n const deadline = new AbortController();\n const timer =\n item.timeoutMs === undefined\n ? undefined\n : setTimeout(\n () => deadline.abort(new Error(`${item.key} timed out`)),\n item.timeoutMs,\n );\n const taskSignal = AbortSignal.any([signal, deadline.signal]);\n try {\n taskSignal.throwIfAborted();\n const value = await item.perform(context(item, attempt, taskSignal));\n taskSignal.throwIfAborted();\n values.set(item, value);\n finish(item, \"done\");\n return;\n } catch (error) {\n runtime.closeAttempt(item);\n if (\n signal.aborted ||\n attempt === limit ||\n item.retry?.accepts?.(error, attempt) === false\n )\n throw error;\n emit({ type: \"retry\", key: item.key, attempt });\n } finally {\n runtime.closeAttempt(item);\n clearTimeout(timer);\n }\n await delay(item.retry?.delayMs ?? 0, undefined, { signal });\n }\n } catch (error) {\n state.error = error instanceof Error ? error.message : String(error);\n if (\n signal.aborted ||\n (error instanceof WorkflowBudgetExceeded && runtime.accounting.exhausted)\n )\n finish(item, \"cancelled\");\n else {\n errors.push(error);\n finish(item, \"failed\");\n if (options.stopOnError !== false) stop.abort(error);\n }\n }\n}\n"]}
@@ -8,13 +8,14 @@ export async function schedule(name, tasks, options) {
8
8
  const state = workflowState(name, tasks, options);
9
9
  const { executionId, signal, values, records, errors, observerErrors, record, emit, finish, } = state;
10
10
  const active = new Map();
11
+ const started = Date.now();
11
12
  emit({ type: "start" });
12
13
  while (true) {
13
14
  let changed = false;
14
15
  for (const item of tasks) {
15
16
  if (record(item).status !== "waiting")
16
17
  continue;
17
- if (signal.aborted) {
18
+ if (signal.aborted || state.accounting.exhausted) {
18
19
  finish(item, "cancelled");
19
20
  changed = true;
20
21
  continue;
@@ -48,11 +49,12 @@ export async function schedule(name, tasks, options) {
48
49
  : errors.length
49
50
  ? "failed"
50
51
  : "done";
51
- emit({ type: "finish" });
52
+ emit({ type: "finish", status, durationMs: Date.now() - started });
52
53
  const result = Object.freeze({
53
54
  executionId,
54
55
  name,
55
56
  status,
57
+ usage: state.accounting.snapshot(),
56
58
  tasks: Object.freeze([...records.values()].map((value) => Object.freeze({ ...value }))),
57
59
  errors: Object.freeze(errors),
58
60
  observerErrors: Object.freeze(observerErrors),
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-scheduler.js","sourceRoot":"","sources":["../../../src/domain/workflow/workflow-scheduler.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n Task,\n WorkflowOptions,\n WorkflowResult,\n} from \"../workflow.types.ts\";\nimport { WorkflowFailure } from \"./failure.ts\";\nimport { runTask } from \"./task-runner.ts\";\nimport { positive } from \"./validation.ts\";\nimport { workflowState } from \"./workflow-state.ts\";\n\nexport async function schedule(\n name: string,\n tasks: readonly Task[],\n options: WorkflowOptions,\n): Promise<WorkflowResult> {\n const concurrency = options.concurrency ?? 1;\n positive(concurrency, \"concurrency\");\n const state = workflowState(name, tasks, options);\n const {\n executionId,\n signal,\n values,\n records,\n errors,\n observerErrors,\n record,\n emit,\n finish,\n } = state;\n const active = new Map<Task, Promise<void>>();\n emit({ type: \"start\" });\n while (true) {\n let changed = false;\n for (const item of tasks) {\n if (record(item).status !== \"waiting\") continue;\n if (signal.aborted) {\n finish(item, \"cancelled\");\n changed = true;\n continue;\n }\n const dependencies = item.after.map(\n (dependency) => record(dependency).status,\n );\n if (\n dependencies.some((status) =>\n [\"failed\", \"skipped\", \"cancelled\"].includes(status),\n )\n ) {\n finish(item, \"skipped\");\n changed = true;\n continue;\n }\n if (\n active.size >= concurrency ||\n !dependencies.every((status) => status === \"done\")\n )\n continue;\n const running = runTask(item, state).finally(() => {\n active.delete(item);\n });\n active.set(item, running);\n changed = true;\n }\n if (active.size) {\n await Promise.race(active.values());\n continue;\n }\n if (!changed) break;\n }\n if (options.signal?.aborted) errors.push(options.signal.reason);\n const status = options.signal?.aborted\n ? \"cancelled\"\n : errors.length\n ? \"failed\"\n : \"done\";\n emit({ type: \"finish\" });\n const result: WorkflowResult = Object.freeze({\n executionId,\n name,\n status,\n tasks: Object.freeze(\n [...records.values()].map((value) => Object.freeze({ ...value })),\n ),\n errors: Object.freeze(errors),\n observerErrors: Object.freeze(observerErrors),\n value<T>(item: Task<T>): T {\n if (!values.has(item))\n throw new Error(\n `${item.key} has no successful value in this execution`,\n );\n return values.get(item) as T;\n },\n unwrap() {\n if (status !== \"done\") throw new WorkflowFailure(result);\n },\n });\n return result;\n}\n"]}
1
+ {"version":3,"file":"workflow-scheduler.js","sourceRoot":"","sources":["../../../src/domain/workflow/workflow-scheduler.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,IAAY,EACZ,KAAsB,EACtB,OAAwB;IAExB,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,CAAC,CAAC;IAC7C,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IACrC,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IAClD,MAAM,EACJ,WAAW,EACX,MAAM,EACN,MAAM,EACN,OAAO,EACP,MAAM,EACN,cAAc,EACd,MAAM,EACN,IAAI,EACJ,MAAM,GACP,GAAG,KAAK,CAAC;IACV,MAAM,MAAM,GAAG,IAAI,GAAG,EAAuB,CAAC;IAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC3B,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IACxB,OAAO,IAAI,EAAE,CAAC;QACZ,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS;gBAAE,SAAS;YAChD,IAAI,MAAM,CAAC,OAAO,IAAI,KAAK,CAAC,UAAU,CAAC,SAAS,EAAE,CAAC;gBACjD,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;gBAC1B,OAAO,GAAG,IAAI,CAAC;gBACf,SAAS;YACX,CAAC;YACD,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CACjC,CAAC,UAAU,EAAE,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,MAAM,CAC1C,CAAC;YACF,IACE,YAAY,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAC3B,CAAC,QAAQ,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CACpD,EACD,CAAC;gBACD,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;gBACxB,OAAO,GAAG,IAAI,CAAC;gBACf,SAAS;YACX,CAAC;YACD,IACE,MAAM,CAAC,IAAI,IAAI,WAAW;gBAC1B,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,KAAK,MAAM,CAAC;gBAElD,SAAS;YACX,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE;gBAChD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACtB,CAAC,CAAC,CAAC;YACH,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAC1B,OAAO,GAAG,IAAI,CAAC;QACjB,CAAC;QACD,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;YAChB,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;YACpC,SAAS;QACX,CAAC;QACD,IAAI,CAAC,OAAO;YAAE,MAAM;IACtB,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,EAAE,OAAO;QAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAChE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,OAAO;QACpC,CAAC,CAAC,WAAW;QACb,CAAC,CAAC,MAAM,CAAC,MAAM;YACb,CAAC,CAAC,QAAQ;YACV,CAAC,CAAC,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;IACnE,MAAM,MAAM,GAAmB,MAAM,CAAC,MAAM,CAAC;QAC3C,WAAW;QACX,IAAI;QACJ,MAAM;QACN,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,QAAQ,EAAE;QAClC,KAAK,EAAE,MAAM,CAAC,MAAM,CAClB,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC,CAClE;QACD,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;QAC7B,cAAc,EAAE,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC;QAC7C,KAAK,CAAI,IAAa;YACpB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;gBACnB,MAAM,IAAI,KAAK,CACb,GAAG,IAAI,CAAC,GAAG,4CAA4C,CACxD,CAAC;YACJ,OAAO,MAAM,CAAC,GAAG,CAAC,IAAI,CAAM,CAAC;QAC/B,CAAC;QACD,MAAM;YACJ,IAAI,MAAM,KAAK,MAAM;gBAAE,MAAM,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC;QAC3D,CAAC;KACF,CAAC,CAAC;IACH,OAAO,MAAM,CAAC;AAChB,CAAC","sourcesContent":["import type {\n Task,\n WorkflowOptions,\n WorkflowResult,\n} from \"../workflow.types.ts\";\nimport { WorkflowFailure } from \"./failure.ts\";\nimport { runTask } from \"./task-runner.ts\";\nimport { positive } from \"./validation.ts\";\nimport { workflowState } from \"./workflow-state.ts\";\n\nexport async function schedule(\n name: string,\n tasks: readonly Task[],\n options: WorkflowOptions,\n): Promise<WorkflowResult> {\n const concurrency = options.concurrency ?? 1;\n positive(concurrency, \"concurrency\");\n const state = workflowState(name, tasks, options);\n const {\n executionId,\n signal,\n values,\n records,\n errors,\n observerErrors,\n record,\n emit,\n finish,\n } = state;\n const active = new Map<Task, Promise<void>>();\n const started = Date.now();\n emit({ type: \"start\" });\n while (true) {\n let changed = false;\n for (const item of tasks) {\n if (record(item).status !== \"waiting\") continue;\n if (signal.aborted || state.accounting.exhausted) {\n finish(item, \"cancelled\");\n changed = true;\n continue;\n }\n const dependencies = item.after.map(\n (dependency) => record(dependency).status,\n );\n if (\n dependencies.some((status) =>\n [\"failed\", \"skipped\", \"cancelled\"].includes(status),\n )\n ) {\n finish(item, \"skipped\");\n changed = true;\n continue;\n }\n if (\n active.size >= concurrency ||\n !dependencies.every((status) => status === \"done\")\n )\n continue;\n const running = runTask(item, state).finally(() => {\n active.delete(item);\n });\n active.set(item, running);\n changed = true;\n }\n if (active.size) {\n await Promise.race(active.values());\n continue;\n }\n if (!changed) break;\n }\n if (options.signal?.aborted) errors.push(options.signal.reason);\n const status = options.signal?.aborted\n ? \"cancelled\"\n : errors.length\n ? \"failed\"\n : \"done\";\n emit({ type: \"finish\", status, durationMs: Date.now() - started });\n const result: WorkflowResult = Object.freeze({\n executionId,\n name,\n status,\n usage: state.accounting.snapshot(),\n tasks: Object.freeze(\n [...records.values()].map((value) => Object.freeze({ ...value })),\n ),\n errors: Object.freeze(errors),\n observerErrors: Object.freeze(observerErrors),\n value<T>(item: Task<T>): T {\n if (!values.has(item))\n throw new Error(\n `${item.key} has no successful value in this execution`,\n );\n return values.get(item) as T;\n },\n unwrap() {\n if (status !== \"done\") throw new WorkflowFailure(result);\n },\n });\n return result;\n}\n"]}