open-multi-agent-kit 1.0.0 → 1.2.2

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 (622) hide show
  1. package/CHANGELOG.md +52 -1
  2. package/README.md +2 -2
  3. package/dist/approval-api.d.ts +5 -0
  4. package/dist/approval-api.d.ts.map +1 -0
  5. package/dist/approval-api.js +5 -0
  6. package/dist/approval-api.js.map +1 -0
  7. package/dist/cli/help.d.ts.map +1 -1
  8. package/dist/cli/help.js +1 -0
  9. package/dist/cli/help.js.map +1 -1
  10. package/dist/cli/session-picker.d.ts +2 -2
  11. package/dist/cli/session-picker.d.ts.map +1 -1
  12. package/dist/cli/session-picker.js.map +1 -1
  13. package/dist/commands/verified-run-cli.d.ts.map +1 -1
  14. package/dist/commands/verified-run-cli.js +69 -22
  15. package/dist/commands/verified-run-cli.js.map +1 -1
  16. package/dist/commands/verified-run-signal.d.ts +3 -0
  17. package/dist/commands/verified-run-signal.d.ts.map +1 -0
  18. package/dist/commands/verified-run-signal.js +15 -0
  19. package/dist/commands/verified-run-signal.js.map +1 -0
  20. package/dist/coordination/awareness.d.ts +32 -0
  21. package/dist/coordination/awareness.d.ts.map +1 -0
  22. package/dist/coordination/awareness.js +55 -0
  23. package/dist/coordination/awareness.js.map +1 -0
  24. package/dist/coordination/broker.d.ts +79 -0
  25. package/dist/coordination/broker.d.ts.map +1 -0
  26. package/dist/coordination/broker.js +202 -0
  27. package/dist/coordination/broker.js.map +1 -0
  28. package/dist/coordination/index.d.ts +16 -0
  29. package/dist/coordination/index.d.ts.map +1 -0
  30. package/dist/coordination/index.js +16 -0
  31. package/dist/coordination/index.js.map +1 -0
  32. package/dist/coordination/integration.d.ts +59 -0
  33. package/dist/coordination/integration.d.ts.map +1 -0
  34. package/dist/coordination/integration.js +126 -0
  35. package/dist/coordination/integration.js.map +1 -0
  36. package/dist/coordination/operation.d.ts +107 -0
  37. package/dist/coordination/operation.d.ts.map +1 -0
  38. package/dist/coordination/operation.js +231 -0
  39. package/dist/coordination/operation.js.map +1 -0
  40. package/dist/coordination/resource.d.ts +33 -0
  41. package/dist/coordination/resource.d.ts.map +1 -0
  42. package/dist/coordination/resource.js +95 -0
  43. package/dist/coordination/resource.js.map +1 -0
  44. package/dist/coordination/session.d.ts +74 -0
  45. package/dist/coordination/session.d.ts.map +1 -0
  46. package/dist/coordination/session.js +143 -0
  47. package/dist/coordination/session.js.map +1 -0
  48. package/dist/coordination/types.d.ts +68 -0
  49. package/dist/coordination/types.d.ts.map +1 -0
  50. package/dist/coordination/types.js +26 -0
  51. package/dist/coordination/types.js.map +1 -0
  52. package/dist/core/adaptorch-bridge.d.ts +1 -1
  53. package/dist/core/adaptorch-bridge.d.ts.map +1 -1
  54. package/dist/core/adaptorch-bridge.js +1 -1
  55. package/dist/core/adaptorch-bridge.js.map +1 -1
  56. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  57. package/dist/core/agent-session-runtime.js +16 -16
  58. package/dist/core/agent-session-runtime.js.map +1 -1
  59. package/dist/core/agent-session.d.ts.map +1 -1
  60. package/dist/core/agent-session.js +35 -15
  61. package/dist/core/agent-session.js.map +1 -1
  62. package/dist/core/canonical-json.d.ts +3 -0
  63. package/dist/core/canonical-json.d.ts.map +1 -0
  64. package/dist/core/canonical-json.js +20 -0
  65. package/dist/core/canonical-json.js.map +1 -0
  66. package/dist/core/compaction/compaction.d.ts +7 -3
  67. package/dist/core/compaction/compaction.d.ts.map +1 -1
  68. package/dist/core/compaction/compaction.js +14 -29
  69. package/dist/core/compaction/compaction.js.map +1 -1
  70. package/dist/core/compaction/control-state.d.ts +41 -0
  71. package/dist/core/compaction/control-state.d.ts.map +1 -0
  72. package/dist/core/compaction/control-state.js +85 -0
  73. package/dist/core/compaction/control-state.js.map +1 -0
  74. package/dist/core/compaction/fallback.d.ts +71 -0
  75. package/dist/core/compaction/fallback.d.ts.map +1 -0
  76. package/dist/core/compaction/fallback.js +118 -0
  77. package/dist/core/compaction/fallback.js.map +1 -0
  78. package/dist/core/compaction/index.d.ts +2 -0
  79. package/dist/core/compaction/index.d.ts.map +1 -1
  80. package/dist/core/compaction/index.js +2 -0
  81. package/dist/core/compaction/index.js.map +1 -1
  82. package/dist/core/compaction/model-failover.d.ts +21 -0
  83. package/dist/core/compaction/model-failover.d.ts.map +1 -0
  84. package/dist/core/compaction/model-failover.js +46 -0
  85. package/dist/core/compaction/model-failover.js.map +1 -0
  86. package/dist/core/compaction/session-summary.d.ts +21 -0
  87. package/dist/core/compaction/session-summary.d.ts.map +1 -0
  88. package/dist/core/compaction/session-summary.js +27 -0
  89. package/dist/core/compaction/session-summary.js.map +1 -0
  90. package/dist/core/context-budget-headroom-candidates.d.ts +16 -1
  91. package/dist/core/context-budget-headroom-candidates.d.ts.map +1 -1
  92. package/dist/core/context-budget-headroom-candidates.js +31 -13
  93. package/dist/core/context-budget-headroom-candidates.js.map +1 -1
  94. package/dist/core/context-budget-headroom-types.d.ts +7 -1
  95. package/dist/core/context-budget-headroom-types.d.ts.map +1 -1
  96. package/dist/core/context-budget-headroom-types.js +0 -1
  97. package/dist/core/context-budget-headroom-types.js.map +1 -1
  98. package/dist/core/context-budget-headroom.d.ts +10 -0
  99. package/dist/core/context-budget-headroom.d.ts.map +1 -1
  100. package/dist/core/context-budget-headroom.js +11 -2
  101. package/dist/core/context-budget-headroom.js.map +1 -1
  102. package/dist/core/context-budget-v2-global-pass.d.ts +21 -0
  103. package/dist/core/context-budget-v2-global-pass.d.ts.map +1 -0
  104. package/dist/core/context-budget-v2-global-pass.js +203 -0
  105. package/dist/core/context-budget-v2-global-pass.js.map +1 -0
  106. package/dist/core/context-budget-v2-planned-items.d.ts +12 -0
  107. package/dist/core/context-budget-v2-planned-items.d.ts.map +1 -1
  108. package/dist/core/context-budget-v2-planned-items.js +21 -2
  109. package/dist/core/context-budget-v2-planned-items.js.map +1 -1
  110. package/dist/core/context-budget-v2-planner.d.ts.map +1 -1
  111. package/dist/core/context-budget-v2-planner.js +18 -19
  112. package/dist/core/context-budget-v2-planner.js.map +1 -1
  113. package/dist/core/context-budget-v2-scoring.d.ts +7 -1
  114. package/dist/core/context-budget-v2-scoring.d.ts.map +1 -1
  115. package/dist/core/context-budget-v2-scoring.js.map +1 -1
  116. package/dist/core/context-budget-v2-selection.d.ts +3 -0
  117. package/dist/core/context-budget-v2-selection.d.ts.map +1 -1
  118. package/dist/core/context-budget-v2-selection.js +6 -2
  119. package/dist/core/context-budget-v2-selection.js.map +1 -1
  120. package/dist/core/context-budget-v2-types.d.ts +6 -1
  121. package/dist/core/context-budget-v2-types.d.ts.map +1 -1
  122. package/dist/core/context-budget-v2-types.js +6 -1
  123. package/dist/core/context-budget-v2-types.js.map +1 -1
  124. package/dist/core/export-html/template.js +14 -0
  125. package/dist/core/extensions/index.d.ts +1 -1
  126. package/dist/core/extensions/index.d.ts.map +1 -1
  127. package/dist/core/extensions/index.js.map +1 -1
  128. package/dist/core/extensions/session-lifecycle-types.d.ts +14 -0
  129. package/dist/core/extensions/session-lifecycle-types.d.ts.map +1 -0
  130. package/dist/core/extensions/session-lifecycle-types.js +2 -0
  131. package/dist/core/extensions/session-lifecycle-types.js.map +1 -0
  132. package/dist/core/extensions/types.d.ts +4 -9
  133. package/dist/core/extensions/types.d.ts.map +1 -1
  134. package/dist/core/extensions/types.js.map +1 -1
  135. package/dist/core/http-dispatcher.d.ts.map +1 -1
  136. package/dist/core/http-dispatcher.js +10 -1
  137. package/dist/core/http-dispatcher.js.map +1 -1
  138. package/dist/core/keybindings.d.ts.map +1 -1
  139. package/dist/core/keybindings.js +3 -6
  140. package/dist/core/keybindings.js.map +1 -1
  141. package/dist/core/legacy-resource-policy.d.ts +7 -0
  142. package/dist/core/legacy-resource-policy.d.ts.map +1 -0
  143. package/dist/core/legacy-resource-policy.js +9 -0
  144. package/dist/core/legacy-resource-policy.js.map +1 -0
  145. package/dist/core/mcp/config.d.ts.map +1 -1
  146. package/dist/core/mcp/config.js +17 -3
  147. package/dist/core/mcp/config.js.map +1 -1
  148. package/dist/core/mcp/connection-queue.d.ts +12 -0
  149. package/dist/core/mcp/connection-queue.d.ts.map +1 -0
  150. package/dist/core/mcp/connection-queue.js +46 -0
  151. package/dist/core/mcp/connection-queue.js.map +1 -0
  152. package/dist/core/mcp/manager-runtime.d.ts +55 -0
  153. package/dist/core/mcp/manager-runtime.d.ts.map +1 -0
  154. package/dist/core/mcp/manager-runtime.js +66 -0
  155. package/dist/core/mcp/manager-runtime.js.map +1 -0
  156. package/dist/core/mcp/manager.d.ts +12 -68
  157. package/dist/core/mcp/manager.d.ts.map +1 -1
  158. package/dist/core/mcp/manager.js +33 -113
  159. package/dist/core/mcp/manager.js.map +1 -1
  160. package/dist/core/mcp/protocol.d.ts.map +1 -1
  161. package/dist/core/mcp/protocol.js +70 -40
  162. package/dist/core/mcp/protocol.js.map +1 -1
  163. package/dist/core/package-manager.d.ts +4 -0
  164. package/dist/core/package-manager.d.ts.map +1 -1
  165. package/dist/core/package-manager.js +59 -129
  166. package/dist/core/package-manager.js.map +1 -1
  167. package/dist/core/package-resource-patterns.d.ts +7 -0
  168. package/dist/core/package-resource-patterns.d.ts.map +1 -0
  169. package/dist/core/package-resource-patterns.js +99 -0
  170. package/dist/core/package-resource-patterns.js.map +1 -0
  171. package/dist/core/provider-default-models.d.ts +1 -0
  172. package/dist/core/provider-default-models.d.ts.map +1 -1
  173. package/dist/core/provider-default-models.js +1 -0
  174. package/dist/core/provider-default-models.js.map +1 -1
  175. package/dist/core/provider-display-names.d.ts.map +1 -1
  176. package/dist/core/provider-display-names.js +1 -0
  177. package/dist/core/provider-display-names.js.map +1 -1
  178. package/dist/core/provider-resilience.d.ts +9 -0
  179. package/dist/core/provider-resilience.d.ts.map +1 -1
  180. package/dist/core/provider-resilience.js +15 -0
  181. package/dist/core/provider-resilience.js.map +1 -1
  182. package/dist/core/reasoning-router-resolver.d.ts +7 -0
  183. package/dist/core/reasoning-router-resolver.d.ts.map +1 -1
  184. package/dist/core/reasoning-router-resolver.js +21 -3
  185. package/dist/core/reasoning-router-resolver.js.map +1 -1
  186. package/dist/core/reasoning-router-v4.d.ts +13 -7
  187. package/dist/core/reasoning-router-v4.d.ts.map +1 -1
  188. package/dist/core/reasoning-router-v4.js +8 -5
  189. package/dist/core/reasoning-router-v4.js.map +1 -1
  190. package/dist/core/resource-loader.d.ts.map +1 -1
  191. package/dist/core/resource-loader.js +4 -8
  192. package/dist/core/resource-loader.js.map +1 -1
  193. package/dist/core/run-execution-api.d.ts +8 -1
  194. package/dist/core/run-execution-api.d.ts.map +1 -1
  195. package/dist/core/run-execution-api.js +4 -0
  196. package/dist/core/run-execution-api.js.map +1 -1
  197. package/dist/core/run-journal.d.ts +1 -2
  198. package/dist/core/run-journal.d.ts.map +1 -1
  199. package/dist/core/run-journal.js +2 -19
  200. package/dist/core/run-journal.js.map +1 -1
  201. package/dist/core/session-compaction-service.d.ts +15 -0
  202. package/dist/core/session-compaction-service.d.ts.map +1 -1
  203. package/dist/core/session-compaction-service.js +17 -4
  204. package/dist/core/session-compaction-service.js.map +1 -1
  205. package/dist/core/session-listing.d.ts +51 -0
  206. package/dist/core/session-listing.d.ts.map +1 -0
  207. package/dist/core/session-listing.js +111 -0
  208. package/dist/core/session-listing.js.map +1 -0
  209. package/dist/core/session-manager.d.ts +12 -37
  210. package/dist/core/session-manager.d.ts.map +1 -1
  211. package/dist/core/session-manager.js +12 -118
  212. package/dist/core/session-manager.js.map +1 -1
  213. package/dist/core/session-message-text.d.ts +5 -0
  214. package/dist/core/session-message-text.d.ts.map +1 -0
  215. package/dist/core/session-message-text.js +9 -0
  216. package/dist/core/session-message-text.js.map +1 -0
  217. package/dist/core/skills-catalog-cache.d.ts +2 -0
  218. package/dist/core/skills-catalog-cache.d.ts.map +1 -1
  219. package/dist/core/skills-catalog-cache.js +71 -17
  220. package/dist/core/skills-catalog-cache.js.map +1 -1
  221. package/dist/core/todo-runtime-state.d.ts +12 -0
  222. package/dist/core/todo-runtime-state.d.ts.map +1 -1
  223. package/dist/core/todo-runtime-state.js +23 -0
  224. package/dist/core/todo-runtime-state.js.map +1 -1
  225. package/dist/core/tools/read.d.ts.map +1 -1
  226. package/dist/core/tools/read.js +1 -1
  227. package/dist/core/tools/read.js.map +1 -1
  228. package/dist/core/verified-run/authority-clock.d.ts +3 -0
  229. package/dist/core/verified-run/authority-clock.d.ts.map +1 -0
  230. package/dist/core/verified-run/authority-clock.js +25 -0
  231. package/dist/core/verified-run/authority-clock.js.map +1 -0
  232. package/dist/core/verified-run/authority-errors.d.ts +10 -0
  233. package/dist/core/verified-run/authority-errors.d.ts.map +1 -0
  234. package/dist/core/verified-run/authority-errors.js +17 -0
  235. package/dist/core/verified-run/authority-errors.js.map +1 -0
  236. package/dist/core/verified-run/authority-events.d.ts +126 -0
  237. package/dist/core/verified-run/authority-events.d.ts.map +1 -0
  238. package/dist/core/verified-run/authority-events.js +482 -0
  239. package/dist/core/verified-run/authority-events.js.map +1 -0
  240. package/dist/core/verified-run/authority-journal.d.ts +27 -0
  241. package/dist/core/verified-run/authority-journal.d.ts.map +1 -0
  242. package/dist/core/verified-run/authority-journal.js +83 -0
  243. package/dist/core/verified-run/authority-journal.js.map +1 -0
  244. package/dist/core/verified-run/authority-meaning.d.ts +13 -0
  245. package/dist/core/verified-run/authority-meaning.d.ts.map +1 -0
  246. package/dist/core/verified-run/authority-meaning.js +40 -0
  247. package/dist/core/verified-run/authority-meaning.js.map +1 -0
  248. package/dist/core/verified-run/authority-runtime.d.ts +82 -0
  249. package/dist/core/verified-run/authority-runtime.d.ts.map +1 -0
  250. package/dist/core/verified-run/authority-runtime.js +169 -0
  251. package/dist/core/verified-run/authority-runtime.js.map +1 -0
  252. package/dist/core/verified-run/authority-store.d.ts +204 -0
  253. package/dist/core/verified-run/authority-store.d.ts.map +1 -0
  254. package/dist/core/verified-run/authority-store.js +852 -0
  255. package/dist/core/verified-run/authority-store.js.map +1 -0
  256. package/dist/core/verified-run/broker.d.ts +8 -1
  257. package/dist/core/verified-run/broker.d.ts.map +1 -1
  258. package/dist/core/verified-run/broker.js +94 -90
  259. package/dist/core/verified-run/broker.js.map +1 -1
  260. package/dist/core/verified-run/candidate-policy.d.ts +10 -0
  261. package/dist/core/verified-run/candidate-policy.d.ts.map +1 -0
  262. package/dist/core/verified-run/candidate-policy.js +33 -0
  263. package/dist/core/verified-run/candidate-policy.js.map +1 -0
  264. package/dist/core/verified-run/candidate.d.ts.map +1 -1
  265. package/dist/core/verified-run/candidate.js +5 -10
  266. package/dist/core/verified-run/candidate.js.map +1 -1
  267. package/dist/core/verified-run/coordinator.d.ts +35 -17
  268. package/dist/core/verified-run/coordinator.d.ts.map +1 -1
  269. package/dist/core/verified-run/coordinator.js +111 -57
  270. package/dist/core/verified-run/coordinator.js.map +1 -1
  271. package/dist/core/verified-run/dag-phase.d.ts.map +1 -1
  272. package/dist/core/verified-run/dag-phase.js +1 -1
  273. package/dist/core/verified-run/dag-phase.js.map +1 -1
  274. package/dist/core/verified-run/dag-recovery.d.ts +5 -1
  275. package/dist/core/verified-run/dag-recovery.d.ts.map +1 -1
  276. package/dist/core/verified-run/dag-recovery.js +10 -4
  277. package/dist/core/verified-run/dag-recovery.js.map +1 -1
  278. package/dist/core/verified-run/event-parser.d.ts.map +1 -1
  279. package/dist/core/verified-run/event-parser.js +33 -0
  280. package/dist/core/verified-run/event-parser.js.map +1 -1
  281. package/dist/core/verified-run/evidence-read-projection.d.ts +4 -0
  282. package/dist/core/verified-run/evidence-read-projection.d.ts.map +1 -0
  283. package/dist/core/verified-run/evidence-read-projection.js +27 -0
  284. package/dist/core/verified-run/evidence-read-projection.js.map +1 -0
  285. package/dist/core/verified-run/evidence.d.ts +12 -1
  286. package/dist/core/verified-run/evidence.d.ts.map +1 -1
  287. package/dist/core/verified-run/evidence.js +51 -2
  288. package/dist/core/verified-run/evidence.js.map +1 -1
  289. package/dist/core/verified-run/git-candidate-preflight.d.ts +4 -0
  290. package/dist/core/verified-run/git-candidate-preflight.d.ts.map +1 -0
  291. package/dist/core/verified-run/git-candidate-preflight.js +34 -0
  292. package/dist/core/verified-run/git-candidate-preflight.js.map +1 -0
  293. package/dist/core/verified-run/git-effect-supervisor.d.ts +24 -0
  294. package/dist/core/verified-run/git-effect-supervisor.d.ts.map +1 -0
  295. package/dist/core/verified-run/git-effect-supervisor.js +174 -0
  296. package/dist/core/verified-run/git-effect-supervisor.js.map +1 -0
  297. package/dist/core/verified-run/git-execution.d.ts +27 -0
  298. package/dist/core/verified-run/git-execution.d.ts.map +1 -0
  299. package/dist/core/verified-run/git-execution.js +118 -0
  300. package/dist/core/verified-run/git-execution.js.map +1 -0
  301. package/dist/core/verified-run/git-plumbing.d.ts +37 -0
  302. package/dist/core/verified-run/git-plumbing.d.ts.map +1 -0
  303. package/dist/core/verified-run/git-plumbing.js +171 -0
  304. package/dist/core/verified-run/git-plumbing.js.map +1 -0
  305. package/dist/core/verified-run/git-publication-worker.d.ts +2 -0
  306. package/dist/core/verified-run/git-publication-worker.d.ts.map +1 -0
  307. package/dist/core/verified-run/git-publication-worker.js +54 -0
  308. package/dist/core/verified-run/git-publication-worker.js.map +1 -0
  309. package/dist/core/verified-run/git-sandbox-layout.d.ts +4 -0
  310. package/dist/core/verified-run/git-sandbox-layout.d.ts.map +1 -0
  311. package/dist/core/verified-run/git-sandbox-layout.js +29 -0
  312. package/dist/core/verified-run/git-sandbox-layout.js.map +1 -0
  313. package/dist/core/verified-run/git-worker-protocol.d.ts +19 -0
  314. package/dist/core/verified-run/git-worker-protocol.d.ts.map +1 -0
  315. package/dist/core/verified-run/git-worker-protocol.js +109 -0
  316. package/dist/core/verified-run/git-worker-protocol.js.map +1 -0
  317. package/dist/core/verified-run/git-worker-runtime.d.ts +19 -0
  318. package/dist/core/verified-run/git-worker-runtime.d.ts.map +1 -0
  319. package/dist/core/verified-run/git-worker-runtime.js +74 -0
  320. package/dist/core/verified-run/git-worker-runtime.js.map +1 -0
  321. package/dist/core/verified-run/journal.d.ts +2 -3
  322. package/dist/core/verified-run/journal.d.ts.map +1 -1
  323. package/dist/core/verified-run/journal.js.map +1 -1
  324. package/dist/core/verified-run/namespace-identity.d.ts.map +1 -1
  325. package/dist/core/verified-run/namespace-identity.js +1 -1
  326. package/dist/core/verified-run/namespace-identity.js.map +1 -1
  327. package/dist/core/verified-run/owned-execution.d.ts +10 -1
  328. package/dist/core/verified-run/owned-execution.d.ts.map +1 -1
  329. package/dist/core/verified-run/owned-execution.js +124 -31
  330. package/dist/core/verified-run/owned-execution.js.map +1 -1
  331. package/dist/core/verified-run/phase-context.d.ts +2 -0
  332. package/dist/core/verified-run/phase-context.d.ts.map +1 -1
  333. package/dist/core/verified-run/phase-context.js.map +1 -1
  334. package/dist/core/verified-run/projection.d.ts.map +1 -1
  335. package/dist/core/verified-run/projection.js +51 -1
  336. package/dist/core/verified-run/projection.js.map +1 -1
  337. package/dist/core/verified-run/publish-preflight.d.ts +12 -0
  338. package/dist/core/verified-run/publish-preflight.d.ts.map +1 -0
  339. package/dist/core/verified-run/publish-preflight.js +38 -0
  340. package/dist/core/verified-run/publish-preflight.js.map +1 -0
  341. package/dist/core/verified-run/publish-start.d.ts +5 -0
  342. package/dist/core/verified-run/publish-start.d.ts.map +1 -0
  343. package/dist/core/verified-run/publish-start.js +7 -0
  344. package/dist/core/verified-run/publish-start.js.map +1 -0
  345. package/dist/core/verified-run/recovery-projection.d.ts.map +1 -1
  346. package/dist/core/verified-run/recovery-projection.js +5 -0
  347. package/dist/core/verified-run/recovery-projection.js.map +1 -1
  348. package/dist/core/verified-run/recovery.d.ts +5 -1
  349. package/dist/core/verified-run/recovery.d.ts.map +1 -1
  350. package/dist/core/verified-run/recovery.js +10 -4
  351. package/dist/core/verified-run/recovery.js.map +1 -1
  352. package/dist/core/verified-run/run-plan.d.ts +17 -0
  353. package/dist/core/verified-run/run-plan.d.ts.map +1 -0
  354. package/dist/core/verified-run/run-plan.js +18 -0
  355. package/dist/core/verified-run/run-plan.js.map +1 -0
  356. package/dist/core/verified-run/run-publish-owned.d.ts +6 -0
  357. package/dist/core/verified-run/run-publish-owned.d.ts.map +1 -0
  358. package/dist/core/verified-run/run-publish-owned.js +199 -0
  359. package/dist/core/verified-run/run-publish-owned.js.map +1 -0
  360. package/dist/core/verified-run/run-publish.d.ts +19 -0
  361. package/dist/core/verified-run/run-publish.d.ts.map +1 -0
  362. package/dist/core/verified-run/run-publish.js +210 -0
  363. package/dist/core/verified-run/run-publish.js.map +1 -0
  364. package/dist/core/verified-run/run-status-owned.d.ts +4 -0
  365. package/dist/core/verified-run/run-status-owned.d.ts.map +1 -0
  366. package/dist/core/verified-run/run-status-owned.js +14 -0
  367. package/dist/core/verified-run/run-status-owned.js.map +1 -0
  368. package/dist/core/verified-run/run-status.d.ts +133 -0
  369. package/dist/core/verified-run/run-status.d.ts.map +1 -0
  370. package/dist/core/verified-run/run-status.js +193 -0
  371. package/dist/core/verified-run/run-status.js.map +1 -0
  372. package/dist/core/verified-run/run-types.d.ts +31 -0
  373. package/dist/core/verified-run/run-types.d.ts.map +1 -1
  374. package/dist/core/verified-run/run-types.js.map +1 -1
  375. package/dist/core/verified-run/storage.d.ts.map +1 -1
  376. package/dist/core/verified-run/storage.js +1 -1
  377. package/dist/core/verified-run/storage.js.map +1 -1
  378. package/dist/core/verified-run/supervisor-adapter.d.ts +77 -0
  379. package/dist/core/verified-run/supervisor-adapter.d.ts.map +1 -0
  380. package/dist/core/verified-run/supervisor-adapter.js +164 -0
  381. package/dist/core/verified-run/supervisor-adapter.js.map +1 -0
  382. package/dist/core/verified-run/verification-phase.d.ts.map +1 -1
  383. package/dist/core/verified-run/verification-phase.js +1 -1
  384. package/dist/core/verified-run/verification-phase.js.map +1 -1
  385. package/dist/core/verified-run/writer-phase.d.ts.map +1 -1
  386. package/dist/core/verified-run/writer-phase.js +1 -0
  387. package/dist/core/verified-run/writer-phase.js.map +1 -1
  388. package/dist/core/verified-run/writer-recovery.d.ts +2 -0
  389. package/dist/core/verified-run/writer-recovery.d.ts.map +1 -1
  390. package/dist/core/verified-run/writer-recovery.js +1 -0
  391. package/dist/core/verified-run/writer-recovery.js.map +1 -1
  392. package/dist/core/workload-shard-execution-types.d.ts +4 -1
  393. package/dist/core/workload-shard-execution-types.d.ts.map +1 -1
  394. package/dist/core/workload-shard-execution-types.js.map +1 -1
  395. package/dist/core/workload-shard-executor.d.ts +2 -2
  396. package/dist/core/workload-shard-executor.d.ts.map +1 -1
  397. package/dist/core/workload-shard-executor.js +16 -37
  398. package/dist/core/workload-shard-executor.js.map +1 -1
  399. package/dist/core/workload-shard-frontier.d.ts +5 -0
  400. package/dist/core/workload-shard-frontier.d.ts.map +1 -0
  401. package/dist/core/workload-shard-frontier.js +47 -0
  402. package/dist/core/workload-shard-frontier.js.map +1 -0
  403. package/dist/core/workload-shard-runner.d.ts.map +1 -1
  404. package/dist/core/workload-shard-runner.js +28 -17
  405. package/dist/core/workload-shard-runner.js.map +1 -1
  406. package/dist/index.d.ts +4 -5
  407. package/dist/index.d.ts.map +1 -1
  408. package/dist/index.js +3 -4
  409. package/dist/index.js.map +1 -1
  410. package/dist/main.d.ts.map +1 -1
  411. package/dist/main.js +2 -1
  412. package/dist/main.js.map +1 -1
  413. package/dist/metacognition/bridge-result.d.ts +148 -0
  414. package/dist/metacognition/bridge-result.d.ts.map +1 -0
  415. package/dist/metacognition/bridge-result.js +46 -0
  416. package/dist/metacognition/bridge-result.js.map +1 -0
  417. package/dist/metacognition/calibration-selective.d.ts +78 -0
  418. package/dist/metacognition/calibration-selective.d.ts.map +1 -0
  419. package/dist/metacognition/calibration-selective.js +167 -0
  420. package/dist/metacognition/calibration-selective.js.map +1 -0
  421. package/dist/metacognition/calibration.d.ts +62 -0
  422. package/dist/metacognition/calibration.d.ts.map +1 -0
  423. package/dist/metacognition/calibration.js +122 -0
  424. package/dist/metacognition/calibration.js.map +1 -0
  425. package/dist/metacognition/checkpoint.d.ts +60 -0
  426. package/dist/metacognition/checkpoint.d.ts.map +1 -0
  427. package/dist/metacognition/checkpoint.js +57 -0
  428. package/dist/metacognition/checkpoint.js.map +1 -0
  429. package/dist/metacognition/context7.d.ts +48 -0
  430. package/dist/metacognition/context7.d.ts.map +1 -0
  431. package/dist/metacognition/context7.js +154 -0
  432. package/dist/metacognition/context7.js.map +1 -0
  433. package/dist/metacognition/decision.d.ts +44 -0
  434. package/dist/metacognition/decision.d.ts.map +1 -0
  435. package/dist/metacognition/decision.js +111 -0
  436. package/dist/metacognition/decision.js.map +1 -0
  437. package/dist/metacognition/evaluation.d.ts +73 -0
  438. package/dist/metacognition/evaluation.d.ts.map +1 -0
  439. package/dist/metacognition/evaluation.js +97 -0
  440. package/dist/metacognition/evaluation.js.map +1 -0
  441. package/dist/metacognition/index.d.ts +32 -0
  442. package/dist/metacognition/index.d.ts.map +1 -0
  443. package/dist/metacognition/index.js +32 -0
  444. package/dist/metacognition/index.js.map +1 -0
  445. package/dist/metacognition/knowledge-action.d.ts +43 -0
  446. package/dist/metacognition/knowledge-action.d.ts.map +1 -0
  447. package/dist/metacognition/knowledge-action.js +60 -0
  448. package/dist/metacognition/knowledge-action.js.map +1 -0
  449. package/dist/metacognition/knowledge.d.ts +84 -0
  450. package/dist/metacognition/knowledge.d.ts.map +1 -0
  451. package/dist/metacognition/knowledge.js +165 -0
  452. package/dist/metacognition/knowledge.js.map +1 -0
  453. package/dist/metacognition/obligations.d.ts +82 -0
  454. package/dist/metacognition/obligations.d.ts.map +1 -0
  455. package/dist/metacognition/obligations.js +139 -0
  456. package/dist/metacognition/obligations.js.map +1 -0
  457. package/dist/metacognition/observation-validity.d.ts +83 -0
  458. package/dist/metacognition/observation-validity.d.ts.map +1 -0
  459. package/dist/metacognition/observation-validity.js +118 -0
  460. package/dist/metacognition/observation-validity.js.map +1 -0
  461. package/dist/metacognition/observe.d.ts +45 -0
  462. package/dist/metacognition/observe.d.ts.map +1 -0
  463. package/dist/metacognition/observe.js +59 -0
  464. package/dist/metacognition/observe.js.map +1 -0
  465. package/dist/metacognition/policy.d.ts +53 -0
  466. package/dist/metacognition/policy.d.ts.map +1 -0
  467. package/dist/metacognition/policy.js +155 -0
  468. package/dist/metacognition/policy.js.map +1 -0
  469. package/dist/metacognition/predictions.d.ts +78 -0
  470. package/dist/metacognition/predictions.d.ts.map +1 -0
  471. package/dist/metacognition/predictions.js +181 -0
  472. package/dist/metacognition/predictions.js.map +1 -0
  473. package/dist/metacognition/retrieval.d.ts +53 -0
  474. package/dist/metacognition/retrieval.d.ts.map +1 -0
  475. package/dist/metacognition/retrieval.js +170 -0
  476. package/dist/metacognition/retrieval.js.map +1 -0
  477. package/dist/metacognition/risk.d.ts +48 -0
  478. package/dist/metacognition/risk.d.ts.map +1 -0
  479. package/dist/metacognition/risk.js +179 -0
  480. package/dist/metacognition/risk.js.map +1 -0
  481. package/dist/metacognition/route-economics.d.ts +95 -0
  482. package/dist/metacognition/route-economics.d.ts.map +1 -0
  483. package/dist/metacognition/route-economics.js +110 -0
  484. package/dist/metacognition/route-economics.js.map +1 -0
  485. package/dist/metacognition/runtime-bridge.d.ts +81 -0
  486. package/dist/metacognition/runtime-bridge.d.ts.map +1 -0
  487. package/dist/metacognition/runtime-bridge.js +458 -0
  488. package/dist/metacognition/runtime-bridge.js.map +1 -0
  489. package/dist/metacognition/skills.d.ts +42 -0
  490. package/dist/metacognition/skills.d.ts.map +1 -0
  491. package/dist/metacognition/skills.js +220 -0
  492. package/dist/metacognition/skills.js.map +1 -0
  493. package/dist/metacognition/state.d.ts +110 -0
  494. package/dist/metacognition/state.d.ts.map +1 -0
  495. package/dist/metacognition/state.js +52 -0
  496. package/dist/metacognition/state.js.map +1 -0
  497. package/dist/metacognition/validation.d.ts +19 -0
  498. package/dist/metacognition/validation.d.ts.map +1 -0
  499. package/dist/metacognition/validation.js +58 -0
  500. package/dist/metacognition/validation.js.map +1 -0
  501. package/dist/metacognition/verification.d.ts +93 -0
  502. package/dist/metacognition/verification.d.ts.map +1 -0
  503. package/dist/metacognition/verification.js +132 -0
  504. package/dist/metacognition/verification.js.map +1 -0
  505. package/dist/metacognition/verifier.d.ts +49 -0
  506. package/dist/metacognition/verifier.d.ts.map +1 -0
  507. package/dist/metacognition/verifier.js +88 -0
  508. package/dist/metacognition/verifier.js.map +1 -0
  509. package/dist/modes/interactive/components/assistant-message.d.ts +2 -0
  510. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  511. package/dist/modes/interactive/components/assistant-message.js +42 -26
  512. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  513. package/dist/modes/interactive/components/chat-container.d.ts +7 -0
  514. package/dist/modes/interactive/components/chat-container.d.ts.map +1 -0
  515. package/dist/modes/interactive/components/chat-container.js +14 -0
  516. package/dist/modes/interactive/components/chat-container.js.map +1 -0
  517. package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
  518. package/dist/modes/interactive/components/dynamic-border.js +4 -2
  519. package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
  520. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  521. package/dist/modes/interactive/components/login-dialog.js +0 -1
  522. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  523. package/dist/modes/interactive/components/session-selector-async-search.d.ts +33 -0
  524. package/dist/modes/interactive/components/session-selector-async-search.d.ts.map +1 -0
  525. package/dist/modes/interactive/components/session-selector-async-search.js +109 -0
  526. package/dist/modes/interactive/components/session-selector-async-search.js.map +1 -0
  527. package/dist/modes/interactive/components/session-selector-loaders.d.ts +6 -0
  528. package/dist/modes/interactive/components/session-selector-loaders.d.ts.map +1 -0
  529. package/dist/modes/interactive/components/session-selector-loaders.js +9 -0
  530. package/dist/modes/interactive/components/session-selector-loaders.js.map +1 -0
  531. package/dist/modes/interactive/components/session-selector-search.d.ts +1 -1
  532. package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
  533. package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
  534. package/dist/modes/interactive/components/session-selector-tree.d.ts +16 -0
  535. package/dist/modes/interactive/components/session-selector-tree.d.ts.map +1 -0
  536. package/dist/modes/interactive/components/session-selector-tree.js +46 -0
  537. package/dist/modes/interactive/components/session-selector-tree.js.map +1 -0
  538. package/dist/modes/interactive/components/session-selector.d.ts +6 -1
  539. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  540. package/dist/modes/interactive/components/session-selector.js +36 -76
  541. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  542. package/dist/modes/interactive/components/tool-execution-images.d.ts +32 -0
  543. package/dist/modes/interactive/components/tool-execution-images.d.ts.map +1 -0
  544. package/dist/modes/interactive/components/tool-execution-images.js +144 -0
  545. package/dist/modes/interactive/components/tool-execution-images.js.map +1 -0
  546. package/dist/modes/interactive/components/tool-execution.d.ts +3 -4
  547. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  548. package/dist/modes/interactive/components/tool-execution.js +22 -71
  549. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  550. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  551. package/dist/modes/interactive/interactive-mode.js +7 -9
  552. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  553. package/dist/modes/interactive/tui-diagnostics.d.ts +8 -4
  554. package/dist/modes/interactive/tui-diagnostics.d.ts.map +1 -1
  555. package/dist/modes/interactive/tui-diagnostics.js +35 -1
  556. package/dist/modes/interactive/tui-diagnostics.js.map +1 -1
  557. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  558. package/dist/modes/rpc/rpc-mode.js +14 -17
  559. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  560. package/dist/modes/rpc/rpc-response.d.ts +5 -0
  561. package/dist/modes/rpc/rpc-response.d.ts.map +1 -0
  562. package/dist/modes/rpc/rpc-response.js +17 -0
  563. package/dist/modes/rpc/rpc-response.js.map +1 -0
  564. package/dist/observation/identity.d.ts +14 -0
  565. package/dist/observation/identity.d.ts.map +1 -0
  566. package/dist/observation/identity.js +29 -0
  567. package/dist/observation/identity.js.map +1 -0
  568. package/dist/observation/index.d.ts +13 -0
  569. package/dist/observation/index.d.ts.map +1 -0
  570. package/dist/observation/index.js +13 -0
  571. package/dist/observation/index.js.map +1 -0
  572. package/dist/observation/observe-mode.d.ts +46 -0
  573. package/dist/observation/observe-mode.d.ts.map +1 -0
  574. package/dist/observation/observe-mode.js +83 -0
  575. package/dist/observation/observe-mode.js.map +1 -0
  576. package/dist/observation/store.d.ts +53 -0
  577. package/dist/observation/store.d.ts.map +1 -0
  578. package/dist/observation/store.js +126 -0
  579. package/dist/observation/store.js.map +1 -0
  580. package/dist/observation/types.d.ts +72 -0
  581. package/dist/observation/types.d.ts.map +1 -0
  582. package/dist/observation/types.js +9 -0
  583. package/dist/observation/types.js.map +1 -0
  584. package/dist/observation/view.d.ts +39 -0
  585. package/dist/observation/view.d.ts.map +1 -0
  586. package/dist/observation/view.js +173 -0
  587. package/dist/observation/view.js.map +1 -0
  588. package/dist/utils/exif-orientation.d.ts.map +1 -1
  589. package/dist/utils/exif-orientation.js +2 -3
  590. package/dist/utils/exif-orientation.js.map +1 -1
  591. package/dist/utils/tools-manager.d.ts.map +1 -1
  592. package/dist/utils/tools-manager.js +3 -5
  593. package/dist/utils/tools-manager.js.map +1 -1
  594. package/docs/adaptorch-preview-spec.md +7 -7
  595. package/docs/atomic-commit-planning.md +69 -0
  596. package/docs/compaction.md +26 -1
  597. package/docs/extensions.md +14 -0
  598. package/docs/mcp.md +22 -0
  599. package/docs/metacognition.md +130 -0
  600. package/docs/model-catalog-refresh.md +218 -1
  601. package/docs/models.md +1 -1
  602. package/docs/providers.md +53 -0
  603. package/docs/runtime-algorithms.md +156 -7
  604. package/docs/session-format.md +8 -0
  605. package/docs/sessions.md +19 -0
  606. package/docs/skills.md +19 -0
  607. package/docs/terminal-setup.md +15 -0
  608. package/docs/tui.md +41 -0
  609. package/docs/verified-run-safety.md +75 -0
  610. package/examples/extensions/custom-provider-anthropic/index.ts +1 -1
  611. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  612. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  613. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  614. package/examples/extensions/doom-overlay/wad-finder.ts +7 -3
  615. package/examples/extensions/gondolin/package-lock.json +2 -2
  616. package/examples/extensions/gondolin/package.json +1 -1
  617. package/examples/extensions/sandbox/package-lock.json +2 -2
  618. package/examples/extensions/sandbox/package.json +1 -1
  619. package/examples/extensions/with-deps/package-lock.json +2 -2
  620. package/examples/extensions/with-deps/package.json +1 -1
  621. package/npm-shrinkwrap.json +18 -18
  622. package/package.json +6 -8
@@ -0,0 +1,118 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { chmodSync, lstatSync, mkdtempSync, readdirSync, rmSync } from "node:fs";
3
+ import { devNull, tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import { performance } from "node:perf_hooks";
6
+ import { VerifiedRunError } from "./storage.js";
7
+ const COMMAND_TIMEOUT_MS = 30_000;
8
+ const MAX_OUTPUT_BYTES = 16 * 1024 * 1024;
9
+ const ENV_NAMES = ["PATH", "SystemRoot", "SYSTEMROOT", "WINDIR", "TMPDIR", "TEMP", "TMP"];
10
+ export class GitOperationBudget {
11
+ deadline;
12
+ clock;
13
+ signal;
14
+ counts = new Map();
15
+ constructor(options = {}) {
16
+ const timeout = options.timeoutMs ?? COMMAND_TIMEOUT_MS;
17
+ if (!Number.isFinite(timeout) || timeout <= 0)
18
+ throw new VerifiedRunError("deadline");
19
+ this.clock = options.clock ?? (() => performance.now());
20
+ this.deadline = this.clock() + timeout;
21
+ this.signal = options.signal;
22
+ }
23
+ remaining() {
24
+ return Math.min(COMMAND_TIMEOUT_MS, this.remainingWorkMs());
25
+ }
26
+ remainingWorkMs() {
27
+ if (this.signal?.aborted)
28
+ throw new VerifiedRunError("cancelled");
29
+ const remaining = this.deadline - this.clock();
30
+ if (!(remaining > 0))
31
+ throw new VerifiedRunError("deadline");
32
+ return Math.max(1, Math.ceil(remaining));
33
+ }
34
+ record(command) {
35
+ this.counts.set(command, (this.counts.get(command) ?? 0) + 1);
36
+ }
37
+ get commandCounts() {
38
+ return Object.freeze(Object.fromEntries(this.counts));
39
+ }
40
+ }
41
+ export function assertPrivateEmptyHooks(path) {
42
+ const stat = lstatSync(path);
43
+ if (!stat.isDirectory() ||
44
+ stat.isSymbolicLink() ||
45
+ (stat.mode & 0o777) !== 0o700 ||
46
+ (process.getuid && stat.uid !== process.getuid()) ||
47
+ readdirSync(path).length !== 0)
48
+ throw new VerifiedRunError("git_hooks_boundary");
49
+ }
50
+ function gitEnvironment(write) {
51
+ const env = {};
52
+ for (const name of ENV_NAMES)
53
+ if (process.env[name] !== undefined)
54
+ env[name] = process.env[name];
55
+ return {
56
+ ...env,
57
+ GIT_CONFIG_NOSYSTEM: "1",
58
+ GIT_CONFIG_GLOBAL: devNull,
59
+ GIT_CONFIG_COUNT: "0",
60
+ GIT_TERMINAL_PROMPT: "0",
61
+ GIT_NO_REPLACE_OBJECTS: "1",
62
+ GIT_OPTIONAL_LOCKS: write ? "1" : "0",
63
+ LC_ALL: "C",
64
+ GIT_AUTHOR_NAME: "OMK verified-run",
65
+ GIT_AUTHOR_EMAIL: "omk-verified-run@localhost",
66
+ GIT_AUTHOR_DATE: "2000-01-01T00:00:00Z",
67
+ GIT_COMMITTER_NAME: "OMK verified-run",
68
+ GIT_COMMITTER_EMAIL: "omk-verified-run@localhost",
69
+ GIT_COMMITTER_DATE: "2000-01-01T00:00:00Z",
70
+ };
71
+ }
72
+ /** A private hooks directory belongs to this synchronous child, never to a predictable shared path. */
73
+ export function runGit(root, args, options = {}) {
74
+ const budget = options.budget ?? new GitOperationBudget();
75
+ budget.remaining();
76
+ const hooks = mkdtempSync(join(tmpdir(), "omk-verified-git-"));
77
+ try {
78
+ chmodSync(hooks, 0o700);
79
+ assertPrivateEmptyHooks(hooks);
80
+ const isolated = [
81
+ "-c",
82
+ `core.hooksPath=${hooks}`,
83
+ "-c",
84
+ "core.fsmonitor=false",
85
+ "-c",
86
+ "gc.auto=0",
87
+ "-c",
88
+ "maintenance.auto=false",
89
+ "-c",
90
+ "commit.gpgsign=false",
91
+ "-C",
92
+ root,
93
+ ...args,
94
+ ];
95
+ const timeout = budget.remaining();
96
+ budget.record(args[0] ?? "unknown");
97
+ const result = spawnSync("git", isolated, {
98
+ env: gitEnvironment(options.write === true),
99
+ maxBuffer: MAX_OUTPUT_BYTES,
100
+ timeout,
101
+ killSignal: "SIGKILL",
102
+ stdio: [options.input === undefined ? "ignore" : "pipe", "pipe", "pipe"],
103
+ input: options.input,
104
+ windowsHide: true,
105
+ });
106
+ if (result.error !== undefined)
107
+ throw new VerifiedRunError(options.write ? "git_outcome_unknown" : "git_plumbing");
108
+ const allowed = options.allowedExitCodes ?? [0];
109
+ if (result.status === null || !allowed.includes(result.status))
110
+ throw new VerifiedRunError("git_plumbing");
111
+ return { status: result.status, stdout: result.stdout };
112
+ }
113
+ finally {
114
+ // spawnSync has observed the direct child's exit, including SIGKILL on timeout.
115
+ rmSync(hooks, { recursive: true, force: true });
116
+ }
117
+ }
118
+ //# sourceMappingURL=git-execution.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-execution.js","sourceRoot":"","sources":["../../../src/core/verified-run/git-execution.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawnSync } from \"node:child_process\";\nimport { chmodSync, lstatSync, mkdtempSync, readdirSync, rmSync } from \"node:fs\";\nimport { devNull, tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { performance } from \"node:perf_hooks\";\nimport { VerifiedRunError } from \"./storage.ts\";\n\nconst COMMAND_TIMEOUT_MS = 30_000;\nconst MAX_OUTPUT_BYTES = 16 * 1024 * 1024;\nconst ENV_NAMES = [\"PATH\", \"SystemRoot\", \"SYSTEMROOT\", \"WINDIR\", \"TMPDIR\", \"TEMP\", \"TMP\"];\n\nexport class GitOperationBudget {\n\tprivate readonly deadline: number;\n\tprivate readonly clock: () => number;\n\tprivate readonly signal: AbortSignal | undefined;\n\tprivate readonly counts = new Map<string, number>();\n\tconstructor(options: { timeoutMs?: number; signal?: AbortSignal; clock?: () => number } = {}) {\n\t\tconst timeout = options.timeoutMs ?? COMMAND_TIMEOUT_MS;\n\t\tif (!Number.isFinite(timeout) || timeout <= 0) throw new VerifiedRunError(\"deadline\");\n\t\tthis.clock = options.clock ?? (() => performance.now());\n\t\tthis.deadline = this.clock() + timeout;\n\t\tthis.signal = options.signal;\n\t}\n\tremaining(): number {\n\t\treturn Math.min(COMMAND_TIMEOUT_MS, this.remainingWorkMs());\n\t}\n\tremainingWorkMs(): number {\n\t\tif (this.signal?.aborted) throw new VerifiedRunError(\"cancelled\");\n\t\tconst remaining = this.deadline - this.clock();\n\t\tif (!(remaining > 0)) throw new VerifiedRunError(\"deadline\");\n\t\treturn Math.max(1, Math.ceil(remaining));\n\t}\n\trecord(command: string): void {\n\t\tthis.counts.set(command, (this.counts.get(command) ?? 0) + 1);\n\t}\n\tget commandCounts(): Readonly<Record<string, number>> {\n\t\treturn Object.freeze(Object.fromEntries(this.counts));\n\t}\n}\n\nexport function assertPrivateEmptyHooks(path: string): void {\n\tconst stat = lstatSync(path);\n\tif (\n\t\t!stat.isDirectory() ||\n\t\tstat.isSymbolicLink() ||\n\t\t(stat.mode & 0o777) !== 0o700 ||\n\t\t(process.getuid && stat.uid !== process.getuid()) ||\n\t\treaddirSync(path).length !== 0\n\t)\n\t\tthrow new VerifiedRunError(\"git_hooks_boundary\");\n}\n\nfunction gitEnvironment(write: boolean): NodeJS.ProcessEnv {\n\tconst env: NodeJS.ProcessEnv = {};\n\tfor (const name of ENV_NAMES) if (process.env[name] !== undefined) env[name] = process.env[name];\n\treturn {\n\t\t...env,\n\t\tGIT_CONFIG_NOSYSTEM: \"1\",\n\t\tGIT_CONFIG_GLOBAL: devNull,\n\t\tGIT_CONFIG_COUNT: \"0\",\n\t\tGIT_TERMINAL_PROMPT: \"0\",\n\t\tGIT_NO_REPLACE_OBJECTS: \"1\",\n\t\tGIT_OPTIONAL_LOCKS: write ? \"1\" : \"0\",\n\t\tLC_ALL: \"C\",\n\t\tGIT_AUTHOR_NAME: \"OMK verified-run\",\n\t\tGIT_AUTHOR_EMAIL: \"omk-verified-run@localhost\",\n\t\tGIT_AUTHOR_DATE: \"2000-01-01T00:00:00Z\",\n\t\tGIT_COMMITTER_NAME: \"OMK verified-run\",\n\t\tGIT_COMMITTER_EMAIL: \"omk-verified-run@localhost\",\n\t\tGIT_COMMITTER_DATE: \"2000-01-01T00:00:00Z\",\n\t};\n}\n\n/** A private hooks directory belongs to this synchronous child, never to a predictable shared path. */\nexport function runGit(\n\troot: string,\n\targs: readonly string[],\n\toptions: { write?: boolean; input?: Buffer; allowedExitCodes?: readonly number[]; budget?: GitOperationBudget } = {},\n): { status: number; stdout: Buffer } {\n\tconst budget = options.budget ?? new GitOperationBudget();\n\tbudget.remaining();\n\tconst hooks = mkdtempSync(join(tmpdir(), \"omk-verified-git-\"));\n\ttry {\n\t\tchmodSync(hooks, 0o700);\n\t\tassertPrivateEmptyHooks(hooks);\n\t\tconst isolated = [\n\t\t\t\"-c\",\n\t\t\t`core.hooksPath=${hooks}`,\n\t\t\t\"-c\",\n\t\t\t\"core.fsmonitor=false\",\n\t\t\t\"-c\",\n\t\t\t\"gc.auto=0\",\n\t\t\t\"-c\",\n\t\t\t\"maintenance.auto=false\",\n\t\t\t\"-c\",\n\t\t\t\"commit.gpgsign=false\",\n\t\t\t\"-C\",\n\t\t\troot,\n\t\t\t...args,\n\t\t];\n\t\tconst timeout = budget.remaining();\n\t\tbudget.record(args[0] ?? \"unknown\");\n\t\tconst result = spawnSync(\"git\", isolated, {\n\t\t\tenv: gitEnvironment(options.write === true),\n\t\t\tmaxBuffer: MAX_OUTPUT_BYTES,\n\t\t\ttimeout,\n\t\t\tkillSignal: \"SIGKILL\",\n\t\t\tstdio: [options.input === undefined ? \"ignore\" : \"pipe\", \"pipe\", \"pipe\"],\n\t\t\tinput: options.input,\n\t\t\twindowsHide: true,\n\t\t});\n\t\tif (result.error !== undefined)\n\t\t\tthrow new VerifiedRunError(options.write ? \"git_outcome_unknown\" : \"git_plumbing\");\n\t\tconst allowed = options.allowedExitCodes ?? [0];\n\t\tif (result.status === null || !allowed.includes(result.status)) throw new VerifiedRunError(\"git_plumbing\");\n\t\treturn { status: result.status, stdout: result.stdout };\n\t} finally {\n\t\t// spawnSync has observed the direct child's exit, including SIGKILL on timeout.\n\t\trmSync(hooks, { recursive: true, force: true });\n\t}\n}\n"]}
@@ -0,0 +1,37 @@
1
+ import type { CandidateManifest } from "./candidate.ts";
2
+ import { GitOperationBudget } from "./git-execution.ts";
3
+ /** The single authoritative publication point; moved only by one old-OID CAS. */
4
+ export declare const OMK_ACCEPTED_REF = "refs/omk/accepted";
5
+ /**
6
+ * Fail closed unless `root` is exactly the git work-tree top level. Publishing is
7
+ * defined for a repository root only; subdirectory workspaces stay unsupported.
8
+ */
9
+ export declare function assertGitWorkspaceRoot(root: string, budget?: GitOperationBudget): void;
10
+ /** `sha1` or `sha256`; determines the zero OID length used for unborn-ref CAS. */
11
+ export declare function repoObjectFormat(root: string, budget?: GitOperationBudget): "sha1" | "sha256";
12
+ export declare function zeroOid(format: "sha1" | "sha256"): string;
13
+ /** Current commit OID of `ref`, or null when the ref does not resolve. */
14
+ export declare function resolveRef(root: string, ref: string, budget?: GitOperationBudget): string | null;
15
+ export declare function objectExists(root: string, oid: string, budget?: GitOperationBudget): boolean;
16
+ export interface SealCandidateInput {
17
+ readonly manifest: CandidateManifest;
18
+ readonly contents: ReadonlyMap<string, Buffer>;
19
+ readonly parentOid: string;
20
+ readonly zeroOid: string;
21
+ readonly runId: string;
22
+ readonly candidateDigest: string;
23
+ readonly receiptDigest: string;
24
+ }
25
+ /**
26
+ * Seal the stored candidate bytes into a deterministic commit: same manifest,
27
+ * parent and binding fields always produce the same OID, so a replayed publish
28
+ * never creates a second object identity for the same candidate.
29
+ */
30
+ export declare function sealCandidateCommit(root: string, input: SealCandidateInput, budget?: GitOperationBudget): string;
31
+ export declare class GitRefCasError extends Error {
32
+ readonly ref: string;
33
+ constructor(ref: string);
34
+ }
35
+ /** One old-OID compare-and-swap on a single ref. Throws GitRefCasError on any rejection; callers re-resolve to classify. */
36
+ export declare function casRef(root: string, ref: string, newOid: string, expectedOldOid: string, budget?: GitOperationBudget): void;
37
+ //# sourceMappingURL=git-plumbing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-plumbing.d.ts","sourceRoot":"","sources":["../../../src/core/verified-run/git-plumbing.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExD,OAAO,EAAE,kBAAkB,EAAU,MAAM,oBAAoB,CAAC;AAGhE,iFAAiF;AACjF,eAAO,MAAM,gBAAgB,sBAAsB,CAAC;AAUpD;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAStF;AAED,kFAAkF;AAClF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,kBAAkB,GAAG,MAAM,GAAG,QAAQ,CAI7F;AAED,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,MAAM,CAEzD;AAED,0EAA0E;AAC1E,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,kBAAkB,GAAG,MAAM,GAAG,IAAI,CAMhG;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAE5F;AA+FD,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IACrC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAC/B;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAClC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,kBAAkB,EACzB,MAAM,qBAA2B,GAC/B,MAAM,CAYR;AAED,qBAAa,cAAe,SAAQ,KAAK;IACxC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,YAAY,GAAG,EAAE,MAAM,EAItB;CACD;AAED,4HAA4H;AAC5H,wBAAgB,MAAM,CACrB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,EACtB,MAAM,qBAA2B,GAC/B,IAAI,CAQN","sourcesContent":["import { realpathSync } from \"node:fs\";\nimport type { CandidateManifest } from \"./candidate.ts\";\nimport { preflightGitCandidate } from \"./git-candidate-preflight.ts\";\nimport { GitOperationBudget, runGit } from \"./git-execution.ts\";\nimport { digestObject, VerifiedRunError } from \"./storage.ts\";\n\n/** The single authoritative publication point; moved only by one old-OID CAS. */\nexport const OMK_ACCEPTED_REF = \"refs/omk/accepted\";\n/** Full SHA-1 or SHA-256 git object names. */\nconst GIT_OID_HEX = /^(?:[0-9a-f]{40}|[0-9a-f]{64})$/;\n\nfunction oidOf(stdout: Buffer): string {\n\tconst oid = stdout.toString(\"utf8\").trim();\n\tif (!GIT_OID_HEX.test(oid)) throw new VerifiedRunError(\"git_plumbing\");\n\treturn oid;\n}\n\n/**\n * Fail closed unless `root` is exactly the git work-tree top level. Publishing is\n * defined for a repository root only; subdirectory workspaces stay unsupported.\n */\nexport function assertGitWorkspaceRoot(root: string, budget?: GitOperationBudget): void {\n\tlet toplevel = \"\";\n\ttry {\n\t\ttoplevel = runGit(root, [\"rev-parse\", \"--show-toplevel\"], { budget }).stdout.toString(\"utf8\").replace(/\\n$/, \"\");\n\t} catch (error) {\n\t\tif (error instanceof VerifiedRunError && error.code === \"git_plumbing\") throw new VerifiedRunError(\"unsupported\");\n\t\tthrow error;\n\t}\n\tif (!toplevel || realpathSync(toplevel) !== realpathSync(root)) throw new VerifiedRunError(\"unsupported\");\n}\n\n/** `sha1` or `sha256`; determines the zero OID length used for unborn-ref CAS. */\nexport function repoObjectFormat(root: string, budget?: GitOperationBudget): \"sha1\" | \"sha256\" {\n\tconst format = runGit(root, [\"rev-parse\", \"--show-object-format\"], { budget }).stdout.toString(\"utf8\").trim();\n\tif (format !== \"sha1\" && format !== \"sha256\") throw new VerifiedRunError(\"git_plumbing\");\n\treturn format;\n}\n\nexport function zeroOid(format: \"sha1\" | \"sha256\"): string {\n\treturn \"0\".repeat(format === \"sha1\" ? 40 : 64);\n}\n\n/** Current commit OID of `ref`, or null when the ref does not resolve. */\nexport function resolveRef(root: string, ref: string, budget?: GitOperationBudget): string | null {\n\tconst result = runGit(root, [\"rev-parse\", \"--verify\", \"--quiet\", `${ref}^{commit}`], {\n\t\tallowedExitCodes: [0, 1],\n\t\tbudget,\n\t});\n\treturn result.status === 0 ? oidOf(result.stdout) : null;\n}\n\nexport function objectExists(root: string, oid: string, budget?: GitOperationBudget): boolean {\n\treturn runGit(root, [\"cat-file\", \"-e\", `${oid}^{commit}`], { allowedExitCodes: [0, 1], budget }).status === 0;\n}\n\nfunction treeSortKey(name: string, directory: boolean): Buffer {\n\treturn Buffer.from(directory ? `${name}/` : name, \"utf8\");\n}\n\n/** Git trees only distinguish non-executable `100644` from executable `100755`. */\nfunction gitFileMode(mode: number): \"100644\" | \"100755\" {\n\tconst executable = (mode & 0o111) !== 0;\n\tif (executable ? mode !== 0o755 : mode !== 0o644) throw new VerifiedRunError(\"mode_unrepresentable\");\n\treturn executable ? \"100755\" : \"100644\";\n}\n\n/** Rebuild the manifest's exact directory hierarchy with `git mktree`; only regular files exist in candidates. */\nfunction buildTree(\n\troot: string,\n\tmanifest: CandidateManifest,\n\tcontents: ReadonlyMap<string, Buffer>,\n\tbudget: GitOperationBudget,\n): string {\n\tconst blobOids = new Map<string, string>();\n\tfor (const file of manifest.files) {\n\t\tif (blobOids.has(file.digest)) continue;\n\t\tconst bytes = contents.get(file.digest);\n\t\tif (!bytes || bytes.length !== file.size) throw new VerifiedRunError(\"integrity\");\n\t\tblobOids.set(\n\t\t\tfile.digest,\n\t\t\toidOf(runGit(root, [\"hash-object\", \"-w\", \"--stdin\"], { write: true, input: bytes, budget }).stdout),\n\t\t);\n\t}\n\tconst children = new Map<string, { files: CandidateManifest[\"files\"][number][]; dirs: string[] }>();\n\tchildren.set(\"\", { files: [], dirs: [] });\n\tfor (const directory of manifest.directories) children.set(directory, { files: [], dirs: [] });\n\tfor (const file of manifest.files) {\n\t\tconst parent = file.path.includes(\"/\") ? file.path.slice(0, file.path.lastIndexOf(\"/\")) : \"\";\n\t\tchildren.get(parent)?.files.push(file);\n\t}\n\tfor (const directory of manifest.directories) {\n\t\tconst parent = directory.includes(\"/\") ? directory.slice(0, directory.lastIndexOf(\"/\")) : \"\";\n\t\tchildren.get(parent)?.dirs.push(directory);\n\t}\n\tconst treeOids = new Map<string, string>();\n\tconst ordered = [...manifest.directories].sort((left, right) => right.length - left.length);\n\tfor (const directory of ordered) {\n\t\tconst entries = children.get(directory);\n\t\tif (!entries) throw new VerifiedRunError(\"integrity\");\n\t\ttreeOids.set(directory, mintTree(root, entries, treeOids, blobOids, budget));\n\t}\n\tconst top = children.get(\"\");\n\tif (!top) throw new VerifiedRunError(\"integrity\");\n\tconst tree = mintTree(root, top, treeOids, blobOids, budget);\n\tconst expected = [\n\t\t...manifest.files.map((file) => `${gitFileMode(file.mode)} blob ${blobOids.get(file.digest)}\\t${file.path}`),\n\t\t...manifest.directories.map((path) => `040000 tree ${treeOids.get(path)}\\t${path}`),\n\t].sort();\n\tconst output = runGit(root, [\"ls-tree\", \"-r\", \"-t\", \"-z\", tree], { budget }).stdout.toString(\"utf8\");\n\tconst observed = output.split(\"\\0\").filter(Boolean).sort();\n\tif (expected.length !== observed.length || expected.some((entry, i) => entry !== observed[i]))\n\t\tthrow new VerifiedRunError(\"integrity\");\n\treturn tree;\n}\n\nfunction mintTree(\n\troot: string,\n\tentries: { files: CandidateManifest[\"files\"][number][]; dirs: string[] },\n\ttreeOids: ReadonlyMap<string, string>,\n\tblobOids: ReadonlyMap<string, string>,\n\tbudget: GitOperationBudget,\n): string {\n\tconst lines: { key: Buffer; line: string }[] = [];\n\tfor (const file of entries.files) {\n\t\tconst name = file.path.slice(file.path.lastIndexOf(\"/\") + 1);\n\t\tconst oid = blobOids.get(file.digest);\n\t\tif (!oid) throw new VerifiedRunError(\"integrity\");\n\t\tlines.push({\n\t\t\tkey: treeSortKey(name, false),\n\t\t\tline: `${gitFileMode(file.mode)} blob ${oid}\\t${name}`,\n\t\t});\n\t}\n\tfor (const directory of entries.dirs) {\n\t\tconst name = directory.slice(directory.lastIndexOf(\"/\") + 1);\n\t\tconst oid = treeOids.get(directory);\n\t\tif (!oid) throw new VerifiedRunError(\"integrity\");\n\t\tlines.push({ key: treeSortKey(name, true), line: `040000 tree ${oid}\\t${name}` });\n\t}\n\tlines.sort((left, right) => Buffer.compare(left.key, right.key));\n\treturn oidOf(\n\t\trunGit(root, [\"mktree\", \"-z\"], {\n\t\t\tbudget,\n\t\t\twrite: true,\n\t\t\tinput: Buffer.from(lines.map((entry) => `${entry.line}\\0`).join(\"\"), \"utf8\"),\n\t\t}).stdout,\n\t);\n}\n\nexport interface SealCandidateInput {\n\treadonly manifest: CandidateManifest;\n\treadonly contents: ReadonlyMap<string, Buffer>;\n\treadonly parentOid: string;\n\treadonly zeroOid: string;\n\treadonly runId: string;\n\treadonly candidateDigest: string;\n\treadonly receiptDigest: string;\n}\n\n/**\n * Seal the stored candidate bytes into a deterministic commit: same manifest,\n * parent and binding fields always produce the same OID, so a replayed publish\n * never creates a second object identity for the same candidate.\n */\nexport function sealCandidateCommit(\n\troot: string,\n\tinput: SealCandidateInput,\n\tbudget = new GitOperationBudget(),\n): string {\n\tbudget.remaining();\n\tpreflightGitCandidate(input.manifest, input.contents);\n\tif (digestObject(input.manifest) !== input.candidateDigest) throw new VerifiedRunError(\"integrity\");\n\tconst tree = buildTree(root, input.manifest, input.contents, budget);\n\tconst args = [\"commit-tree\", tree];\n\tif (input.parentOid !== input.zeroOid) args.push(\"-p\", input.parentOid);\n\targs.push(\n\t\t\"-m\",\n\t\t`omk: verified candidate\\n\\nrun: ${input.runId}\\ncandidate: ${input.candidateDigest}\\nreceipt: ${input.receiptDigest}\\n`,\n\t);\n\treturn oidOf(runGit(root, args, { write: true, budget }).stdout);\n}\n\nexport class GitRefCasError extends Error {\n\treadonly ref: string;\n\tconstructor(ref: string) {\n\t\tsuper(`git update-ref rejected ${ref}`);\n\t\tthis.name = \"GitRefCasError\";\n\t\tthis.ref = ref;\n\t}\n}\n\n/** One old-OID compare-and-swap on a single ref. Throws GitRefCasError on any rejection; callers re-resolve to classify. */\nexport function casRef(\n\troot: string,\n\tref: string,\n\tnewOid: string,\n\texpectedOldOid: string,\n\tbudget = new GitOperationBudget(),\n): void {\n\tbudget.remaining();\n\ttry {\n\t\trunGit(root, [\"update-ref\", ref, newOid, expectedOldOid], { write: true, budget });\n\t} catch (error) {\n\t\tif (error instanceof VerifiedRunError && error.code === \"git_plumbing\") throw new GitRefCasError(ref);\n\t\tthrow error;\n\t}\n}\n"]}
@@ -0,0 +1,171 @@
1
+ import { realpathSync } from "node:fs";
2
+ import { preflightGitCandidate } from "./git-candidate-preflight.js";
3
+ import { GitOperationBudget, runGit } from "./git-execution.js";
4
+ import { digestObject, VerifiedRunError } from "./storage.js";
5
+ /** The single authoritative publication point; moved only by one old-OID CAS. */
6
+ export const OMK_ACCEPTED_REF = "refs/omk/accepted";
7
+ /** Full SHA-1 or SHA-256 git object names. */
8
+ const GIT_OID_HEX = /^(?:[0-9a-f]{40}|[0-9a-f]{64})$/;
9
+ function oidOf(stdout) {
10
+ const oid = stdout.toString("utf8").trim();
11
+ if (!GIT_OID_HEX.test(oid))
12
+ throw new VerifiedRunError("git_plumbing");
13
+ return oid;
14
+ }
15
+ /**
16
+ * Fail closed unless `root` is exactly the git work-tree top level. Publishing is
17
+ * defined for a repository root only; subdirectory workspaces stay unsupported.
18
+ */
19
+ export function assertGitWorkspaceRoot(root, budget) {
20
+ let toplevel = "";
21
+ try {
22
+ toplevel = runGit(root, ["rev-parse", "--show-toplevel"], { budget }).stdout.toString("utf8").replace(/\n$/, "");
23
+ }
24
+ catch (error) {
25
+ if (error instanceof VerifiedRunError && error.code === "git_plumbing")
26
+ throw new VerifiedRunError("unsupported");
27
+ throw error;
28
+ }
29
+ if (!toplevel || realpathSync(toplevel) !== realpathSync(root))
30
+ throw new VerifiedRunError("unsupported");
31
+ }
32
+ /** `sha1` or `sha256`; determines the zero OID length used for unborn-ref CAS. */
33
+ export function repoObjectFormat(root, budget) {
34
+ const format = runGit(root, ["rev-parse", "--show-object-format"], { budget }).stdout.toString("utf8").trim();
35
+ if (format !== "sha1" && format !== "sha256")
36
+ throw new VerifiedRunError("git_plumbing");
37
+ return format;
38
+ }
39
+ export function zeroOid(format) {
40
+ return "0".repeat(format === "sha1" ? 40 : 64);
41
+ }
42
+ /** Current commit OID of `ref`, or null when the ref does not resolve. */
43
+ export function resolveRef(root, ref, budget) {
44
+ const result = runGit(root, ["rev-parse", "--verify", "--quiet", `${ref}^{commit}`], {
45
+ allowedExitCodes: [0, 1],
46
+ budget,
47
+ });
48
+ return result.status === 0 ? oidOf(result.stdout) : null;
49
+ }
50
+ export function objectExists(root, oid, budget) {
51
+ return runGit(root, ["cat-file", "-e", `${oid}^{commit}`], { allowedExitCodes: [0, 1], budget }).status === 0;
52
+ }
53
+ function treeSortKey(name, directory) {
54
+ return Buffer.from(directory ? `${name}/` : name, "utf8");
55
+ }
56
+ /** Git trees only distinguish non-executable `100644` from executable `100755`. */
57
+ function gitFileMode(mode) {
58
+ const executable = (mode & 0o111) !== 0;
59
+ if (executable ? mode !== 0o755 : mode !== 0o644)
60
+ throw new VerifiedRunError("mode_unrepresentable");
61
+ return executable ? "100755" : "100644";
62
+ }
63
+ /** Rebuild the manifest's exact directory hierarchy with `git mktree`; only regular files exist in candidates. */
64
+ function buildTree(root, manifest, contents, budget) {
65
+ const blobOids = new Map();
66
+ for (const file of manifest.files) {
67
+ if (blobOids.has(file.digest))
68
+ continue;
69
+ const bytes = contents.get(file.digest);
70
+ if (!bytes || bytes.length !== file.size)
71
+ throw new VerifiedRunError("integrity");
72
+ blobOids.set(file.digest, oidOf(runGit(root, ["hash-object", "-w", "--stdin"], { write: true, input: bytes, budget }).stdout));
73
+ }
74
+ const children = new Map();
75
+ children.set("", { files: [], dirs: [] });
76
+ for (const directory of manifest.directories)
77
+ children.set(directory, { files: [], dirs: [] });
78
+ for (const file of manifest.files) {
79
+ const parent = file.path.includes("/") ? file.path.slice(0, file.path.lastIndexOf("/")) : "";
80
+ children.get(parent)?.files.push(file);
81
+ }
82
+ for (const directory of manifest.directories) {
83
+ const parent = directory.includes("/") ? directory.slice(0, directory.lastIndexOf("/")) : "";
84
+ children.get(parent)?.dirs.push(directory);
85
+ }
86
+ const treeOids = new Map();
87
+ const ordered = [...manifest.directories].sort((left, right) => right.length - left.length);
88
+ for (const directory of ordered) {
89
+ const entries = children.get(directory);
90
+ if (!entries)
91
+ throw new VerifiedRunError("integrity");
92
+ treeOids.set(directory, mintTree(root, entries, treeOids, blobOids, budget));
93
+ }
94
+ const top = children.get("");
95
+ if (!top)
96
+ throw new VerifiedRunError("integrity");
97
+ const tree = mintTree(root, top, treeOids, blobOids, budget);
98
+ const expected = [
99
+ ...manifest.files.map((file) => `${gitFileMode(file.mode)} blob ${blobOids.get(file.digest)}\t${file.path}`),
100
+ ...manifest.directories.map((path) => `040000 tree ${treeOids.get(path)}\t${path}`),
101
+ ].sort();
102
+ const output = runGit(root, ["ls-tree", "-r", "-t", "-z", tree], { budget }).stdout.toString("utf8");
103
+ const observed = output.split("\0").filter(Boolean).sort();
104
+ if (expected.length !== observed.length || expected.some((entry, i) => entry !== observed[i]))
105
+ throw new VerifiedRunError("integrity");
106
+ return tree;
107
+ }
108
+ function mintTree(root, entries, treeOids, blobOids, budget) {
109
+ const lines = [];
110
+ for (const file of entries.files) {
111
+ const name = file.path.slice(file.path.lastIndexOf("/") + 1);
112
+ const oid = blobOids.get(file.digest);
113
+ if (!oid)
114
+ throw new VerifiedRunError("integrity");
115
+ lines.push({
116
+ key: treeSortKey(name, false),
117
+ line: `${gitFileMode(file.mode)} blob ${oid}\t${name}`,
118
+ });
119
+ }
120
+ for (const directory of entries.dirs) {
121
+ const name = directory.slice(directory.lastIndexOf("/") + 1);
122
+ const oid = treeOids.get(directory);
123
+ if (!oid)
124
+ throw new VerifiedRunError("integrity");
125
+ lines.push({ key: treeSortKey(name, true), line: `040000 tree ${oid}\t${name}` });
126
+ }
127
+ lines.sort((left, right) => Buffer.compare(left.key, right.key));
128
+ return oidOf(runGit(root, ["mktree", "-z"], {
129
+ budget,
130
+ write: true,
131
+ input: Buffer.from(lines.map((entry) => `${entry.line}\0`).join(""), "utf8"),
132
+ }).stdout);
133
+ }
134
+ /**
135
+ * Seal the stored candidate bytes into a deterministic commit: same manifest,
136
+ * parent and binding fields always produce the same OID, so a replayed publish
137
+ * never creates a second object identity for the same candidate.
138
+ */
139
+ export function sealCandidateCommit(root, input, budget = new GitOperationBudget()) {
140
+ budget.remaining();
141
+ preflightGitCandidate(input.manifest, input.contents);
142
+ if (digestObject(input.manifest) !== input.candidateDigest)
143
+ throw new VerifiedRunError("integrity");
144
+ const tree = buildTree(root, input.manifest, input.contents, budget);
145
+ const args = ["commit-tree", tree];
146
+ if (input.parentOid !== input.zeroOid)
147
+ args.push("-p", input.parentOid);
148
+ args.push("-m", `omk: verified candidate\n\nrun: ${input.runId}\ncandidate: ${input.candidateDigest}\nreceipt: ${input.receiptDigest}\n`);
149
+ return oidOf(runGit(root, args, { write: true, budget }).stdout);
150
+ }
151
+ export class GitRefCasError extends Error {
152
+ ref;
153
+ constructor(ref) {
154
+ super(`git update-ref rejected ${ref}`);
155
+ this.name = "GitRefCasError";
156
+ this.ref = ref;
157
+ }
158
+ }
159
+ /** One old-OID compare-and-swap on a single ref. Throws GitRefCasError on any rejection; callers re-resolve to classify. */
160
+ export function casRef(root, ref, newOid, expectedOldOid, budget = new GitOperationBudget()) {
161
+ budget.remaining();
162
+ try {
163
+ runGit(root, ["update-ref", ref, newOid, expectedOldOid], { write: true, budget });
164
+ }
165
+ catch (error) {
166
+ if (error instanceof VerifiedRunError && error.code === "git_plumbing")
167
+ throw new GitRefCasError(ref);
168
+ throw error;
169
+ }
170
+ }
171
+ //# sourceMappingURL=git-plumbing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-plumbing.js","sourceRoot":"","sources":["../../../src/core/verified-run/git-plumbing.ts"],"names":[],"mappings":"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","sourcesContent":["import { realpathSync } from \"node:fs\";\nimport type { CandidateManifest } from \"./candidate.ts\";\nimport { preflightGitCandidate } from \"./git-candidate-preflight.ts\";\nimport { GitOperationBudget, runGit } from \"./git-execution.ts\";\nimport { digestObject, VerifiedRunError } from \"./storage.ts\";\n\n/** The single authoritative publication point; moved only by one old-OID CAS. */\nexport const OMK_ACCEPTED_REF = \"refs/omk/accepted\";\n/** Full SHA-1 or SHA-256 git object names. */\nconst GIT_OID_HEX = /^(?:[0-9a-f]{40}|[0-9a-f]{64})$/;\n\nfunction oidOf(stdout: Buffer): string {\n\tconst oid = stdout.toString(\"utf8\").trim();\n\tif (!GIT_OID_HEX.test(oid)) throw new VerifiedRunError(\"git_plumbing\");\n\treturn oid;\n}\n\n/**\n * Fail closed unless `root` is exactly the git work-tree top level. Publishing is\n * defined for a repository root only; subdirectory workspaces stay unsupported.\n */\nexport function assertGitWorkspaceRoot(root: string, budget?: GitOperationBudget): void {\n\tlet toplevel = \"\";\n\ttry {\n\t\ttoplevel = runGit(root, [\"rev-parse\", \"--show-toplevel\"], { budget }).stdout.toString(\"utf8\").replace(/\\n$/, \"\");\n\t} catch (error) {\n\t\tif (error instanceof VerifiedRunError && error.code === \"git_plumbing\") throw new VerifiedRunError(\"unsupported\");\n\t\tthrow error;\n\t}\n\tif (!toplevel || realpathSync(toplevel) !== realpathSync(root)) throw new VerifiedRunError(\"unsupported\");\n}\n\n/** `sha1` or `sha256`; determines the zero OID length used for unborn-ref CAS. */\nexport function repoObjectFormat(root: string, budget?: GitOperationBudget): \"sha1\" | \"sha256\" {\n\tconst format = runGit(root, [\"rev-parse\", \"--show-object-format\"], { budget }).stdout.toString(\"utf8\").trim();\n\tif (format !== \"sha1\" && format !== \"sha256\") throw new VerifiedRunError(\"git_plumbing\");\n\treturn format;\n}\n\nexport function zeroOid(format: \"sha1\" | \"sha256\"): string {\n\treturn \"0\".repeat(format === \"sha1\" ? 40 : 64);\n}\n\n/** Current commit OID of `ref`, or null when the ref does not resolve. */\nexport function resolveRef(root: string, ref: string, budget?: GitOperationBudget): string | null {\n\tconst result = runGit(root, [\"rev-parse\", \"--verify\", \"--quiet\", `${ref}^{commit}`], {\n\t\tallowedExitCodes: [0, 1],\n\t\tbudget,\n\t});\n\treturn result.status === 0 ? oidOf(result.stdout) : null;\n}\n\nexport function objectExists(root: string, oid: string, budget?: GitOperationBudget): boolean {\n\treturn runGit(root, [\"cat-file\", \"-e\", `${oid}^{commit}`], { allowedExitCodes: [0, 1], budget }).status === 0;\n}\n\nfunction treeSortKey(name: string, directory: boolean): Buffer {\n\treturn Buffer.from(directory ? `${name}/` : name, \"utf8\");\n}\n\n/** Git trees only distinguish non-executable `100644` from executable `100755`. */\nfunction gitFileMode(mode: number): \"100644\" | \"100755\" {\n\tconst executable = (mode & 0o111) !== 0;\n\tif (executable ? mode !== 0o755 : mode !== 0o644) throw new VerifiedRunError(\"mode_unrepresentable\");\n\treturn executable ? \"100755\" : \"100644\";\n}\n\n/** Rebuild the manifest's exact directory hierarchy with `git mktree`; only regular files exist in candidates. */\nfunction buildTree(\n\troot: string,\n\tmanifest: CandidateManifest,\n\tcontents: ReadonlyMap<string, Buffer>,\n\tbudget: GitOperationBudget,\n): string {\n\tconst blobOids = new Map<string, string>();\n\tfor (const file of manifest.files) {\n\t\tif (blobOids.has(file.digest)) continue;\n\t\tconst bytes = contents.get(file.digest);\n\t\tif (!bytes || bytes.length !== file.size) throw new VerifiedRunError(\"integrity\");\n\t\tblobOids.set(\n\t\t\tfile.digest,\n\t\t\toidOf(runGit(root, [\"hash-object\", \"-w\", \"--stdin\"], { write: true, input: bytes, budget }).stdout),\n\t\t);\n\t}\n\tconst children = new Map<string, { files: CandidateManifest[\"files\"][number][]; dirs: string[] }>();\n\tchildren.set(\"\", { files: [], dirs: [] });\n\tfor (const directory of manifest.directories) children.set(directory, { files: [], dirs: [] });\n\tfor (const file of manifest.files) {\n\t\tconst parent = file.path.includes(\"/\") ? file.path.slice(0, file.path.lastIndexOf(\"/\")) : \"\";\n\t\tchildren.get(parent)?.files.push(file);\n\t}\n\tfor (const directory of manifest.directories) {\n\t\tconst parent = directory.includes(\"/\") ? directory.slice(0, directory.lastIndexOf(\"/\")) : \"\";\n\t\tchildren.get(parent)?.dirs.push(directory);\n\t}\n\tconst treeOids = new Map<string, string>();\n\tconst ordered = [...manifest.directories].sort((left, right) => right.length - left.length);\n\tfor (const directory of ordered) {\n\t\tconst entries = children.get(directory);\n\t\tif (!entries) throw new VerifiedRunError(\"integrity\");\n\t\ttreeOids.set(directory, mintTree(root, entries, treeOids, blobOids, budget));\n\t}\n\tconst top = children.get(\"\");\n\tif (!top) throw new VerifiedRunError(\"integrity\");\n\tconst tree = mintTree(root, top, treeOids, blobOids, budget);\n\tconst expected = [\n\t\t...manifest.files.map((file) => `${gitFileMode(file.mode)} blob ${blobOids.get(file.digest)}\\t${file.path}`),\n\t\t...manifest.directories.map((path) => `040000 tree ${treeOids.get(path)}\\t${path}`),\n\t].sort();\n\tconst output = runGit(root, [\"ls-tree\", \"-r\", \"-t\", \"-z\", tree], { budget }).stdout.toString(\"utf8\");\n\tconst observed = output.split(\"\\0\").filter(Boolean).sort();\n\tif (expected.length !== observed.length || expected.some((entry, i) => entry !== observed[i]))\n\t\tthrow new VerifiedRunError(\"integrity\");\n\treturn tree;\n}\n\nfunction mintTree(\n\troot: string,\n\tentries: { files: CandidateManifest[\"files\"][number][]; dirs: string[] },\n\ttreeOids: ReadonlyMap<string, string>,\n\tblobOids: ReadonlyMap<string, string>,\n\tbudget: GitOperationBudget,\n): string {\n\tconst lines: { key: Buffer; line: string }[] = [];\n\tfor (const file of entries.files) {\n\t\tconst name = file.path.slice(file.path.lastIndexOf(\"/\") + 1);\n\t\tconst oid = blobOids.get(file.digest);\n\t\tif (!oid) throw new VerifiedRunError(\"integrity\");\n\t\tlines.push({\n\t\t\tkey: treeSortKey(name, false),\n\t\t\tline: `${gitFileMode(file.mode)} blob ${oid}\\t${name}`,\n\t\t});\n\t}\n\tfor (const directory of entries.dirs) {\n\t\tconst name = directory.slice(directory.lastIndexOf(\"/\") + 1);\n\t\tconst oid = treeOids.get(directory);\n\t\tif (!oid) throw new VerifiedRunError(\"integrity\");\n\t\tlines.push({ key: treeSortKey(name, true), line: `040000 tree ${oid}\\t${name}` });\n\t}\n\tlines.sort((left, right) => Buffer.compare(left.key, right.key));\n\treturn oidOf(\n\t\trunGit(root, [\"mktree\", \"-z\"], {\n\t\t\tbudget,\n\t\t\twrite: true,\n\t\t\tinput: Buffer.from(lines.map((entry) => `${entry.line}\\0`).join(\"\"), \"utf8\"),\n\t\t}).stdout,\n\t);\n}\n\nexport interface SealCandidateInput {\n\treadonly manifest: CandidateManifest;\n\treadonly contents: ReadonlyMap<string, Buffer>;\n\treadonly parentOid: string;\n\treadonly zeroOid: string;\n\treadonly runId: string;\n\treadonly candidateDigest: string;\n\treadonly receiptDigest: string;\n}\n\n/**\n * Seal the stored candidate bytes into a deterministic commit: same manifest,\n * parent and binding fields always produce the same OID, so a replayed publish\n * never creates a second object identity for the same candidate.\n */\nexport function sealCandidateCommit(\n\troot: string,\n\tinput: SealCandidateInput,\n\tbudget = new GitOperationBudget(),\n): string {\n\tbudget.remaining();\n\tpreflightGitCandidate(input.manifest, input.contents);\n\tif (digestObject(input.manifest) !== input.candidateDigest) throw new VerifiedRunError(\"integrity\");\n\tconst tree = buildTree(root, input.manifest, input.contents, budget);\n\tconst args = [\"commit-tree\", tree];\n\tif (input.parentOid !== input.zeroOid) args.push(\"-p\", input.parentOid);\n\targs.push(\n\t\t\"-m\",\n\t\t`omk: verified candidate\\n\\nrun: ${input.runId}\\ncandidate: ${input.candidateDigest}\\nreceipt: ${input.receiptDigest}\\n`,\n\t);\n\treturn oidOf(runGit(root, args, { write: true, budget }).stdout);\n}\n\nexport class GitRefCasError extends Error {\n\treadonly ref: string;\n\tconstructor(ref: string) {\n\t\tsuper(`git update-ref rejected ${ref}`);\n\t\tthis.name = \"GitRefCasError\";\n\t\tthis.ref = ref;\n\t}\n}\n\n/** One old-OID compare-and-swap on a single ref. Throws GitRefCasError on any rejection; callers re-resolve to classify. */\nexport function casRef(\n\troot: string,\n\tref: string,\n\tnewOid: string,\n\texpectedOldOid: string,\n\tbudget = new GitOperationBudget(),\n): void {\n\tbudget.remaining();\n\ttry {\n\t\trunGit(root, [\"update-ref\", ref, newOid, expectedOldOid], { write: true, budget });\n\t} catch (error) {\n\t\tif (error instanceof VerifiedRunError && error.code === \"git_plumbing\") throw new GitRefCasError(ref);\n\t\tthrow error;\n\t}\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=git-publication-worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-publication-worker.d.ts","sourceRoot":"","sources":["../../../src/core/verified-run/git-publication-worker.ts"],"names":[],"mappings":"","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { setTimeout as delay } from \"node:timers/promises\";\nimport { GitOperationBudget } from \"./git-execution.ts\";\nimport { casRef, GitRefCasError, OMK_ACCEPTED_REF, resolveRef, sealCandidateCommit } from \"./git-plumbing.ts\";\nimport { readGitNotice, readGitRequest, readGitStartGate, writeGitControl } from \"./git-worker-protocol.ts\";\nimport { VerifiedRunError } from \"./storage.ts\";\n\nasync function waitFor(path: string, budget: GitOperationBudget): Promise<void> {\n\twhile (!existsSync(path)) {\n\t\tbudget.remaining();\n\t\tawait delay(5);\n\t}\n\tbudget.remaining();\n}\n\n/** Fixed trusted worker. Request bytes are data; no plugin, model or tool discovery is performed. */\nasync function main(): Promise<void> {\n\tconst path = process.argv[2];\n\tif (!path || !/^\\/workspace\\/\\.git\\/omk-publish-[A-Za-z0-9_-]+\\/request\\.json$/.test(path))\n\t\tthrow new VerifiedRunError(\"git_worker_protocol\");\n\tconst stage = dirname(path);\n\tconst request = readGitRequest(path);\n\tconst remaining = Number((BigInt(request.deadlineNs) - process.hrtime.bigint()) / 1_000_000n);\n\tconst budget = new GitOperationBudget({ timeoutMs: Math.min(request.timeoutMs, remaining) });\n\tconst candidateOid = sealCandidateCommit(\"/workspace\", request.input, budget);\n\twriteGitControl(join(stage, \"prepared.json\"), { kind: \"prepared\", candidateOid });\n\tawait waitFor(join(stage, \"cas-go.json\"), budget);\n\tconst go = readGitStartGate(join(stage, \"cas-go.json\"));\n\tif (go.kind !== \"prepared\" || go.candidateOid !== candidateOid) throw new VerifiedRunError(\"git_worker_protocol\");\n\tlet kind: \"committed\" | \"ref-rejected\" = \"committed\";\n\ttry {\n\t\tcasRef(\"/workspace\", OMK_ACCEPTED_REF, candidateOid, request.input.parentOid, budget);\n\t} catch (error) {\n\t\tif (!(error instanceof GitRefCasError)) throw error;\n\t\tif (resolveRef(\"/workspace\", OMK_ACCEPTED_REF) !== candidateOid) kind = \"ref-rejected\";\n\t}\n\twriteGitControl(join(stage, \"result.json\"), { kind, candidateOid });\n\t// Keep the namespace owned while the host observes CAS and persists its result.\n\tawait waitFor(join(stage, \"finish.json\"), budget);\n\tconst finish = readGitNotice(join(stage, \"finish.json\"));\n\tif (finish.kind !== kind || finish.candidateOid !== candidateOid) throw new VerifiedRunError(\"git_worker_protocol\");\n}\n\ntry {\n\tawait main();\n} catch {\n\tprocess.stderr.write(\"git_worker_failed\\n\");\n\tprocess.exitCode = 1;\n}\n"]}
@@ -0,0 +1,54 @@
1
+ import { existsSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ import { setTimeout as delay } from "node:timers/promises";
4
+ import { GitOperationBudget } from "./git-execution.js";
5
+ import { casRef, GitRefCasError, OMK_ACCEPTED_REF, resolveRef, sealCandidateCommit } from "./git-plumbing.js";
6
+ import { readGitNotice, readGitRequest, readGitStartGate, writeGitControl } from "./git-worker-protocol.js";
7
+ import { VerifiedRunError } from "./storage.js";
8
+ async function waitFor(path, budget) {
9
+ while (!existsSync(path)) {
10
+ budget.remaining();
11
+ await delay(5);
12
+ }
13
+ budget.remaining();
14
+ }
15
+ /** Fixed trusted worker. Request bytes are data; no plugin, model or tool discovery is performed. */
16
+ async function main() {
17
+ const path = process.argv[2];
18
+ if (!path || !/^\/workspace\/\.git\/omk-publish-[A-Za-z0-9_-]+\/request\.json$/.test(path))
19
+ throw new VerifiedRunError("git_worker_protocol");
20
+ const stage = dirname(path);
21
+ const request = readGitRequest(path);
22
+ const remaining = Number((BigInt(request.deadlineNs) - process.hrtime.bigint()) / 1000000n);
23
+ const budget = new GitOperationBudget({ timeoutMs: Math.min(request.timeoutMs, remaining) });
24
+ const candidateOid = sealCandidateCommit("/workspace", request.input, budget);
25
+ writeGitControl(join(stage, "prepared.json"), { kind: "prepared", candidateOid });
26
+ await waitFor(join(stage, "cas-go.json"), budget);
27
+ const go = readGitStartGate(join(stage, "cas-go.json"));
28
+ if (go.kind !== "prepared" || go.candidateOid !== candidateOid)
29
+ throw new VerifiedRunError("git_worker_protocol");
30
+ let kind = "committed";
31
+ try {
32
+ casRef("/workspace", OMK_ACCEPTED_REF, candidateOid, request.input.parentOid, budget);
33
+ }
34
+ catch (error) {
35
+ if (!(error instanceof GitRefCasError))
36
+ throw error;
37
+ if (resolveRef("/workspace", OMK_ACCEPTED_REF) !== candidateOid)
38
+ kind = "ref-rejected";
39
+ }
40
+ writeGitControl(join(stage, "result.json"), { kind, candidateOid });
41
+ // Keep the namespace owned while the host observes CAS and persists its result.
42
+ await waitFor(join(stage, "finish.json"), budget);
43
+ const finish = readGitNotice(join(stage, "finish.json"));
44
+ if (finish.kind !== kind || finish.candidateOid !== candidateOid)
45
+ throw new VerifiedRunError("git_worker_protocol");
46
+ }
47
+ try {
48
+ await main();
49
+ }
50
+ catch {
51
+ process.stderr.write("git_worker_failed\n");
52
+ process.exitCode = 1;
53
+ }
54
+ //# sourceMappingURL=git-publication-worker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-publication-worker.js","sourceRoot":"","sources":["../../../src/core/verified-run/git-publication-worker.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { setTimeout as delay } from \"node:timers/promises\";\nimport { GitOperationBudget } from \"./git-execution.ts\";\nimport { casRef, GitRefCasError, OMK_ACCEPTED_REF, resolveRef, sealCandidateCommit } from \"./git-plumbing.ts\";\nimport { readGitNotice, readGitRequest, readGitStartGate, writeGitControl } from \"./git-worker-protocol.ts\";\nimport { VerifiedRunError } from \"./storage.ts\";\n\nasync function waitFor(path: string, budget: GitOperationBudget): Promise<void> {\n\twhile (!existsSync(path)) {\n\t\tbudget.remaining();\n\t\tawait delay(5);\n\t}\n\tbudget.remaining();\n}\n\n/** Fixed trusted worker. Request bytes are data; no plugin, model or tool discovery is performed. */\nasync function main(): Promise<void> {\n\tconst path = process.argv[2];\n\tif (!path || !/^\\/workspace\\/\\.git\\/omk-publish-[A-Za-z0-9_-]+\\/request\\.json$/.test(path))\n\t\tthrow new VerifiedRunError(\"git_worker_protocol\");\n\tconst stage = dirname(path);\n\tconst request = readGitRequest(path);\n\tconst remaining = Number((BigInt(request.deadlineNs) - process.hrtime.bigint()) / 1_000_000n);\n\tconst budget = new GitOperationBudget({ timeoutMs: Math.min(request.timeoutMs, remaining) });\n\tconst candidateOid = sealCandidateCommit(\"/workspace\", request.input, budget);\n\twriteGitControl(join(stage, \"prepared.json\"), { kind: \"prepared\", candidateOid });\n\tawait waitFor(join(stage, \"cas-go.json\"), budget);\n\tconst go = readGitStartGate(join(stage, \"cas-go.json\"));\n\tif (go.kind !== \"prepared\" || go.candidateOid !== candidateOid) throw new VerifiedRunError(\"git_worker_protocol\");\n\tlet kind: \"committed\" | \"ref-rejected\" = \"committed\";\n\ttry {\n\t\tcasRef(\"/workspace\", OMK_ACCEPTED_REF, candidateOid, request.input.parentOid, budget);\n\t} catch (error) {\n\t\tif (!(error instanceof GitRefCasError)) throw error;\n\t\tif (resolveRef(\"/workspace\", OMK_ACCEPTED_REF) !== candidateOid) kind = \"ref-rejected\";\n\t}\n\twriteGitControl(join(stage, \"result.json\"), { kind, candidateOid });\n\t// Keep the namespace owned while the host observes CAS and persists its result.\n\tawait waitFor(join(stage, \"finish.json\"), budget);\n\tconst finish = readGitNotice(join(stage, \"finish.json\"));\n\tif (finish.kind !== kind || finish.candidateOid !== candidateOid) throw new VerifiedRunError(\"git_worker_protocol\");\n}\n\ntry {\n\tawait main();\n} catch {\n\tprocess.stderr.write(\"git_worker_failed\\n\");\n\tprocess.exitCode = 1;\n}\n"]}
@@ -0,0 +1,4 @@
1
+ /** The initial owned publisher supports a real .git directory, not external worktree aliases. */
2
+ export declare function ownedGitDirectory(workspace: string): string;
3
+ export declare function ownedGitMounts(workspace: string): readonly string[];
4
+ //# sourceMappingURL=git-sandbox-layout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-sandbox-layout.d.ts","sourceRoot":"","sources":["../../../src/core/verified-run/git-sandbox-layout.ts"],"names":[],"mappings":"AAIA,iGAAiG;AACjG,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAW3D;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CASnE","sourcesContent":["import { lstatSync, realpathSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport { VerifiedRunError } from \"./storage.ts\";\n\n/** The initial owned publisher supports a real .git directory, not external worktree aliases. */\nexport function ownedGitDirectory(workspace: string): string {\n\tconst path = join(realpathSync(workspace), \".git\");\n\ttry {\n\t\tconst stat = lstatSync(path);\n\t\tif (!stat.isDirectory() || stat.isSymbolicLink() || realpathSync(path) !== resolve(path))\n\t\t\tthrow new VerifiedRunError(\"unsupported_git_layout\");\n\t\treturn path;\n\t} catch (error) {\n\t\tif (error instanceof VerifiedRunError) throw error;\n\t\tthrow new VerifiedRunError(\"unsupported_git_layout\");\n\t}\n}\n\nexport function ownedGitMounts(workspace: string): readonly string[] {\n\treturn [\n\t\t\"--bind\",\n\t\townedGitDirectory(workspace),\n\t\t\"/workspace/.git\",\n\t\t\"--ro-bind\",\n\t\trealpathSync(process.execPath),\n\t\t\"/omk-node\",\n\t];\n}\n"]}
@@ -0,0 +1,29 @@
1
+ import { lstatSync, realpathSync } from "node:fs";
2
+ import { join, resolve } from "node:path";
3
+ import { VerifiedRunError } from "./storage.js";
4
+ /** The initial owned publisher supports a real .git directory, not external worktree aliases. */
5
+ export function ownedGitDirectory(workspace) {
6
+ const path = join(realpathSync(workspace), ".git");
7
+ try {
8
+ const stat = lstatSync(path);
9
+ if (!stat.isDirectory() || stat.isSymbolicLink() || realpathSync(path) !== resolve(path))
10
+ throw new VerifiedRunError("unsupported_git_layout");
11
+ return path;
12
+ }
13
+ catch (error) {
14
+ if (error instanceof VerifiedRunError)
15
+ throw error;
16
+ throw new VerifiedRunError("unsupported_git_layout");
17
+ }
18
+ }
19
+ export function ownedGitMounts(workspace) {
20
+ return [
21
+ "--bind",
22
+ ownedGitDirectory(workspace),
23
+ "/workspace/.git",
24
+ "--ro-bind",
25
+ realpathSync(process.execPath),
26
+ "/omk-node",
27
+ ];
28
+ }
29
+ //# sourceMappingURL=git-sandbox-layout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-sandbox-layout.js","sourceRoot":"","sources":["../../../src/core/verified-run/git-sandbox-layout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,iGAAiG;AACjG,MAAM,UAAU,iBAAiB,CAAC,SAAiB,EAAU;IAC5D,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC,CAAC;IACnD,IAAI,CAAC;QACJ,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QAC7B,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,IAAI,CAAC,cAAc,EAAE,IAAI,YAAY,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC;YACvF,MAAM,IAAI,gBAAgB,CAAC,wBAAwB,CAAC,CAAC;QACtD,OAAO,IAAI,CAAC;IACb,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,IAAI,KAAK,YAAY,gBAAgB;YAAE,MAAM,KAAK,CAAC;QACnD,MAAM,IAAI,gBAAgB,CAAC,wBAAwB,CAAC,CAAC;IACtD,CAAC;AAAA,CACD;AAED,MAAM,UAAU,cAAc,CAAC,SAAiB,EAAqB;IACpE,OAAO;QACN,QAAQ;QACR,iBAAiB,CAAC,SAAS,CAAC;QAC5B,iBAAiB;QACjB,WAAW;QACX,YAAY,CAAC,OAAO,CAAC,QAAQ,CAAC;QAC9B,WAAW;KACX,CAAC;AAAA,CACF","sourcesContent":["import { lstatSync, realpathSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport { VerifiedRunError } from \"./storage.ts\";\n\n/** The initial owned publisher supports a real .git directory, not external worktree aliases. */\nexport function ownedGitDirectory(workspace: string): string {\n\tconst path = join(realpathSync(workspace), \".git\");\n\ttry {\n\t\tconst stat = lstatSync(path);\n\t\tif (!stat.isDirectory() || stat.isSymbolicLink() || realpathSync(path) !== resolve(path))\n\t\t\tthrow new VerifiedRunError(\"unsupported_git_layout\");\n\t\treturn path;\n\t} catch (error) {\n\t\tif (error instanceof VerifiedRunError) throw error;\n\t\tthrow new VerifiedRunError(\"unsupported_git_layout\");\n\t}\n}\n\nexport function ownedGitMounts(workspace: string): readonly string[] {\n\treturn [\n\t\t\"--bind\",\n\t\townedGitDirectory(workspace),\n\t\t\"/workspace/.git\",\n\t\t\"--ro-bind\",\n\t\trealpathSync(process.execPath),\n\t\t\"/omk-node\",\n\t];\n}\n"]}
@@ -0,0 +1,19 @@
1
+ import type { SealCandidateInput } from "./git-plumbing.ts";
2
+ export interface GitWorkerRequest {
3
+ readonly input: SealCandidateInput;
4
+ readonly timeoutMs: number;
5
+ /** Linux CLOCK_MONOTONIC deadline, shared across the host and its PID namespace. */
6
+ readonly deadlineNs: string;
7
+ }
8
+ export interface GitWorkerNotice {
9
+ readonly kind: "prepared" | "committed" | "ref-rejected";
10
+ readonly candidateOid: string;
11
+ }
12
+ export declare function writeGitControl(path: string, value: unknown): void;
13
+ export declare function serializeGitRequest(request: GitWorkerRequest): unknown;
14
+ export declare function readGitRequest(path: string): GitWorkerRequest;
15
+ export declare function readGitStartGate(path: string): GitWorkerNotice & {
16
+ readonly authorizationDeadline: number;
17
+ };
18
+ export declare function readGitNotice(path: string): GitWorkerNotice;
19
+ //# sourceMappingURL=git-worker-protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-worker-protocol.d.ts","sourceRoot":"","sources":["../../../src/core/verified-run/git-worker-protocol.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAG5D,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAC;IACnC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,oFAAoF;IACpF,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC5B;AACD,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,WAAW,GAAG,cAAc,CAAC;IACzD,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC9B;AAaD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAKlE;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAQtE;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAyD7D;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG;IAAE,QAAQ,CAAC,qBAAqB,EAAE,MAAM,CAAA;CAAE,CAc3G;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAK3D","sourcesContent":["import { renameSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { fsyncDirectorySync } from \"../durable-file-io.ts\";\nimport type { CandidateFile, CandidateManifest } from \"./candidate.ts\";\nimport { preflightGitCandidate } from \"./git-candidate-preflight.ts\";\nimport type { SealCandidateInput } from \"./git-plumbing.ts\";\nimport { digestObject, publishObject, readJson, VerifiedRunError } from \"./storage.ts\";\n\nexport interface GitWorkerRequest {\n\treadonly input: SealCandidateInput;\n\treadonly timeoutMs: number;\n\t/** Linux CLOCK_MONOTONIC deadline, shared across the host and its PID namespace. */\n\treadonly deadlineNs: string;\n}\nexport interface GitWorkerNotice {\n\treadonly kind: \"prepared\" | \"committed\" | \"ref-rejected\";\n\treadonly candidateOid: string;\n}\n\nfunction object(value: unknown): Record<string, unknown> {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) throw new VerifiedRunError(\"git_worker_protocol\");\n\treturn value as Record<string, unknown>;\n}\nfunction text(value: unknown, pattern: RegExp): string {\n\tif (typeof value !== \"string\" || !pattern.test(value)) throw new VerifiedRunError(\"git_worker_protocol\");\n\treturn value;\n}\nconst DIGEST = /^[a-f0-9]{64}$/;\nconst OID = /^(?:[a-f0-9]{40}|[a-f0-9]{64})$/;\n\nexport function writeGitControl(path: string, value: unknown): void {\n\tconst temporary = `${path}.tmp`;\n\tpublishObject(temporary, value);\n\trenameSync(temporary, path);\n\tfsyncDirectorySync(dirname(path));\n}\n\nexport function serializeGitRequest(request: GitWorkerRequest): unknown {\n\treturn {\n\t\tversion: 1,\n\t\t...request.input,\n\t\tcontents: [...request.input.contents].map(([digest, bytes]) => ({ digest, bytes: bytes.toString(\"base64\") })),\n\t\ttimeoutMs: request.timeoutMs,\n\t\tdeadlineNs: request.deadlineNs,\n\t};\n}\n\nexport function readGitRequest(path: string): GitWorkerRequest {\n\tconst raw = object(readJson(path, 128 * 1024 * 1024));\n\tif (\n\t\traw.version !== 1 ||\n\t\ttypeof raw.timeoutMs !== \"number\" ||\n\t\t!Number.isSafeInteger(raw.timeoutMs) ||\n\t\traw.timeoutMs <= 0 ||\n\t\traw.timeoutMs > 60_000\n\t)\n\t\tthrow new VerifiedRunError(\"git_worker_protocol\");\n\tconst manifest = object(raw.manifest);\n\tif (\n\t\tmanifest.version !== 1 ||\n\t\t!Array.isArray(manifest.files) ||\n\t\t!Array.isArray(manifest.directories) ||\n\t\t!Array.isArray(raw.contents)\n\t)\n\t\tthrow new VerifiedRunError(\"git_worker_protocol\");\n\tconst directories = manifest.directories.map((entry: unknown) => text(entry, /^.{1,4096}$/u));\n\tconst files: CandidateFile[] = manifest.files.map((entry: unknown) => {\n\t\tconst file = object(entry);\n\t\tif (typeof file.mode !== \"number\" || typeof file.size !== \"number\")\n\t\t\tthrow new VerifiedRunError(\"git_worker_protocol\");\n\t\treturn {\n\t\t\tpath: text(file.path, /^.{1,4096}$/u),\n\t\t\tmode: file.mode,\n\t\t\tsize: file.size,\n\t\t\tdigest: text(file.digest, DIGEST),\n\t\t};\n\t});\n\tconst contents = new Map<string, Buffer>();\n\tfor (const entry of raw.contents) {\n\t\tconst blob = object(entry);\n\t\tconst digest = text(blob.digest, DIGEST);\n\t\tif (typeof blob.bytes !== \"string\" || contents.has(digest)) throw new VerifiedRunError(\"git_worker_protocol\");\n\t\tcontents.set(digest, Buffer.from(blob.bytes, \"base64\"));\n\t}\n\tconst candidate: CandidateManifest = { version: 1, directories, files };\n\tpreflightGitCandidate(candidate, contents);\n\tconst candidateDigest = text(raw.candidateDigest, DIGEST);\n\tif (digestObject(candidate) !== candidateDigest) throw new VerifiedRunError(\"integrity\");\n\tconst parentOid = text(raw.parentOid, OID);\n\tconst zeroOid = text(raw.zeroOid, /^(?:0{40}|0{64})$/);\n\tif (parentOid.length !== zeroOid.length) throw new VerifiedRunError(\"git_worker_protocol\");\n\treturn {\n\t\ttimeoutMs: raw.timeoutMs,\n\t\tdeadlineNs: text(raw.deadlineNs, /^\\d{1,24}$/),\n\t\tinput: {\n\t\t\tmanifest: candidate,\n\t\t\tcontents,\n\t\t\tcandidateDigest,\n\t\t\tparentOid,\n\t\t\tzeroOid,\n\t\t\trunId: text(raw.runId, /^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/),\n\t\t\treceiptDigest: text(raw.receiptDigest, DIGEST),\n\t\t},\n\t};\n}\n\nexport function readGitStartGate(path: string): GitWorkerNotice & { readonly authorizationDeadline: number } {\n\tconst raw = object(readJson(path, 4096));\n\tif (\n\t\traw.kind !== \"prepared\" ||\n\t\ttypeof raw.authorizationDeadline !== \"number\" ||\n\t\t!Number.isSafeInteger(raw.authorizationDeadline) ||\n\t\tDate.now() >= raw.authorizationDeadline\n\t)\n\t\tthrow new VerifiedRunError(\"authority\");\n\treturn {\n\t\tkind: \"prepared\",\n\t\tcandidateOid: text(raw.candidateOid, OID),\n\t\tauthorizationDeadline: raw.authorizationDeadline,\n\t};\n}\n\nexport function readGitNotice(path: string): GitWorkerNotice {\n\tconst raw = object(readJson(path, 4096));\n\tif (raw.kind !== \"prepared\" && raw.kind !== \"committed\" && raw.kind !== \"ref-rejected\")\n\t\tthrow new VerifiedRunError(\"git_worker_protocol\");\n\treturn { kind: raw.kind, candidateOid: text(raw.candidateOid, OID) };\n}\n"]}