@rig-c/create 0.0.0-stage → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (555) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +163 -2
  3. package/docs/CHECKS.md +1665 -0
  4. package/docs/COLLECTIONS.md +337 -0
  5. package/docs/CRAFT.md +277 -0
  6. package/docs/INTERVIEW.md +886 -0
  7. package/docs/LESSONS.md +172 -0
  8. package/docs/PROJECT.md +2657 -0
  9. package/docs/SOURCE.md +225 -0
  10. package/package.json +44 -4
  11. package/src/agent-bounce.ts +27 -0
  12. package/src/agent-guide.ts +237 -0
  13. package/src/amend.ts +193 -0
  14. package/src/applied-review.ts +104 -0
  15. package/src/ask-coverage.ts +69 -0
  16. package/src/assemble-answers.ts +53 -0
  17. package/src/cg-gates.ts +211 -0
  18. package/src/check-reads.ts +106 -0
  19. package/src/check.ts +1059 -0
  20. package/src/checkpoint-evidence-writer.ts +125 -0
  21. package/src/checkpoint-evidence.ts +152 -0
  22. package/src/choice-writers.ts +271 -0
  23. package/src/choices.ts +378 -0
  24. package/src/cli.ts +371 -0
  25. package/src/collection-answer.ts +136 -0
  26. package/src/collection-binding-reader.ts +496 -0
  27. package/src/collection-binding.ts +478 -0
  28. package/src/collection.ts +348 -0
  29. package/src/config-inputs.ts +155 -0
  30. package/src/config-lost.ts +135 -0
  31. package/src/correction-writers.ts +207 -0
  32. package/src/corrections.ts +685 -0
  33. package/src/diff-classes.ts +219 -0
  34. package/src/diff-map.ts +248 -0
  35. package/src/direction-citation.ts +13 -0
  36. package/src/direction-writers.ts +119 -0
  37. package/src/direction.ts +266 -0
  38. package/src/drafts.ts +363 -0
  39. package/src/feedback.ts +744 -0
  40. package/src/figure-mask.ts +143 -0
  41. package/src/fix-ledger.ts +355 -0
  42. package/src/init.ts +265 -0
  43. package/src/inputs.ts +160 -0
  44. package/src/intake.ts +158 -0
  45. package/src/interview.ts +53 -0
  46. package/src/invariants.ts +132 -0
  47. package/src/job-acts.ts +80 -0
  48. package/src/job-advance.ts +65 -0
  49. package/src/job-close.ts +226 -0
  50. package/src/job-host.ts +529 -0
  51. package/src/job-outbox.ts +383 -0
  52. package/src/job-publication.ts +701 -0
  53. package/src/job-runtime.ts +99 -0
  54. package/src/job-writer.ts +123 -0
  55. package/src/meshes-bust.ts +63 -0
  56. package/src/next.ts +1506 -0
  57. package/src/overrides.ts +42 -0
  58. package/src/package-upgrades.ts +32 -0
  59. package/src/packages-upgrade-check.ts +6 -0
  60. package/src/packages-upgrade.ts +168 -0
  61. package/src/parts-act.ts +96 -0
  62. package/src/parts-check.ts +242 -0
  63. package/src/parts-review.ts +196 -0
  64. package/src/parts-sections.ts +98 -0
  65. package/src/parts-verdict-record.ts +265 -0
  66. package/src/parts-verdict.ts +33 -0
  67. package/src/pause.ts +118 -0
  68. package/src/pins-check.ts +619 -0
  69. package/src/pins.ts +17 -0
  70. package/src/plan-bar-amendments.ts +54 -0
  71. package/src/plan-history.ts +147 -0
  72. package/src/plan-writers.ts +202 -0
  73. package/src/plate-receipt.ts +110 -0
  74. package/src/pre-interview.ts +302 -0
  75. package/src/prepared-inputs.ts +113 -0
  76. package/src/progress-writers.ts +181 -0
  77. package/src/provenance.ts +301 -0
  78. package/src/record-direction-target.ts +26 -0
  79. package/src/record-input.ts +18 -0
  80. package/src/refusal-baseline.ts +55 -0
  81. package/src/refusal.ts +30 -0
  82. package/src/reopen-lapses.ts +80 -0
  83. package/src/reopen.ts +144 -0
  84. package/src/republish.ts +93 -0
  85. package/src/restart.ts +141 -0
  86. package/src/review-act-runtime.ts +16 -0
  87. package/src/review-act.ts +592 -0
  88. package/src/review-package.ts +524 -0
  89. package/src/review-read.ts +238 -0
  90. package/src/review.ts +432 -0
  91. package/src/rig-version-date.ts +22 -0
  92. package/src/rig-version.ts +1047 -0
  93. package/src/run-record.ts +232 -0
  94. package/src/scene-authority.ts +410 -0
  95. package/src/scene-writers.ts +144 -0
  96. package/src/scene.ts +284 -0
  97. package/src/setup-painting.ts +46 -0
  98. package/src/signable.ts +65 -0
  99. package/src/signoff-answers.ts +76 -0
  100. package/src/signoff-checkpoint-act.ts +95 -0
  101. package/src/signoff-target.ts +127 -0
  102. package/src/signoff.ts +331 -0
  103. package/src/split-captions.ts +154 -0
  104. package/src/stage-progress.ts +379 -0
  105. package/src/stages.ts +148 -0
  106. package/src/step-hash.ts +19 -0
  107. package/src/structure-snapshot.ts +109 -0
  108. package/src/structure.ts +166 -0
  109. package/src/templates.ts +16 -0
  110. package/src/waypoints.ts +163 -0
  111. package/templates/agent-guide.md +108 -0
  112. package/templates/collection-agent-guide.md +72 -0
  113. package/templates/collection.json +252 -0
  114. package/templates/example-chain/AGENTS.md +134 -0
  115. package/templates/example-chain/CLAUDE.md +3 -0
  116. package/templates/example-chain/README.md +13 -0
  117. package/templates/example-chain/chain.json +2869 -0
  118. package/templates/example-chain/checkpoints/0a-interview-options/AGENTS.md +134 -0
  119. package/templates/example-chain/checkpoints/0a-interview-options/CLAUDE.md +3 -0
  120. package/templates/example-chain/checkpoints/0a-interview-options/evidence/.gitkeep +0 -0
  121. package/templates/example-chain/checkpoints/0a-interview-options/evidence/approval.txt +1 -0
  122. package/templates/example-chain/checkpoints/0a-interview-options/evidence/interview/rig_type.json +59 -0
  123. package/templates/example-chain/checkpoints/0a-interview-options/evidence/split-config.json +1 -0
  124. package/templates/example-chain/checkpoints/0a-interview-options/inputs/painting.png +0 -0
  125. package/templates/example-chain/checkpoints/0a-interview-options/inputs/references/.gitkeep +0 -0
  126. package/templates/example-chain/checkpoints/0a-interview-options/package.json +9 -0
  127. package/templates/example-chain/checkpoints/0a-interview-options/project.json +295 -0
  128. package/templates/example-chain/checkpoints/0a-interview-options.json +127 -0
  129. package/templates/example-chain/checkpoints/0b-plan-pending/AGENTS.md +134 -0
  130. package/templates/example-chain/checkpoints/0b-plan-pending/CLAUDE.md +3 -0
  131. package/templates/example-chain/checkpoints/0b-plan-pending/evidence/.gitkeep +0 -0
  132. package/templates/example-chain/checkpoints/0b-plan-pending/evidence/approval.txt +1 -0
  133. package/templates/example-chain/checkpoints/0b-plan-pending/evidence/interview/assemble.json +309 -0
  134. package/templates/example-chain/checkpoints/0b-plan-pending/evidence/interview/reference.json +59 -0
  135. package/templates/example-chain/checkpoints/0b-plan-pending/evidence/interview/rig_type.json +59 -0
  136. package/templates/example-chain/checkpoints/0b-plan-pending/evidence/interview/seethrough.json +186 -0
  137. package/templates/example-chain/checkpoints/0b-plan-pending/evidence/split-config.json +1 -0
  138. package/templates/example-chain/checkpoints/0b-plan-pending/inputs/painting.png +0 -0
  139. package/templates/example-chain/checkpoints/0b-plan-pending/inputs/references/.gitkeep +0 -0
  140. package/templates/example-chain/checkpoints/0b-plan-pending/package.json +9 -0
  141. package/templates/example-chain/checkpoints/0b-plan-pending/project.json +685 -0
  142. package/templates/example-chain/checkpoints/0b-plan-pending.json +81 -0
  143. package/templates/example-chain/checkpoints/1-parts-verdict/AGENTS.md +134 -0
  144. package/templates/example-chain/checkpoints/1-parts-verdict/CLAUDE.md +3 -0
  145. package/templates/example-chain/checkpoints/1-parts-verdict/evidence/.gitkeep +0 -0
  146. package/templates/example-chain/checkpoints/1-parts-verdict/evidence/approval.txt +1 -0
  147. package/templates/example-chain/checkpoints/1-parts-verdict/evidence/interview/assemble.json +309 -0
  148. package/templates/example-chain/checkpoints/1-parts-verdict/evidence/interview/reference.json +59 -0
  149. package/templates/example-chain/checkpoints/1-parts-verdict/evidence/interview/rig_type.json +59 -0
  150. package/templates/example-chain/checkpoints/1-parts-verdict/evidence/interview/seethrough.json +186 -0
  151. package/templates/example-chain/checkpoints/1-parts-verdict/evidence/parts-check.json +127 -0
  152. package/templates/example-chain/checkpoints/1-parts-verdict/evidence/split-config.json +1 -0
  153. package/templates/example-chain/checkpoints/1-parts-verdict/inputs/painting.png +0 -0
  154. package/templates/example-chain/checkpoints/1-parts-verdict/inputs/references/.gitkeep +0 -0
  155. package/templates/example-chain/checkpoints/1-parts-verdict/package.json +9 -0
  156. package/templates/example-chain/checkpoints/1-parts-verdict/project.json +955 -0
  157. package/templates/example-chain/checkpoints/1-parts-verdict.json +204 -0
  158. package/templates/example-chain/checkpoints/2-rigging-answers/AGENTS.md +134 -0
  159. package/templates/example-chain/checkpoints/2-rigging-answers/CLAUDE.md +3 -0
  160. package/templates/example-chain/checkpoints/2-rigging-answers/evidence/.gitkeep +0 -0
  161. package/templates/example-chain/checkpoints/2-rigging-answers/evidence/approval.txt +1 -0
  162. package/templates/example-chain/checkpoints/2-rigging-answers/evidence/diff-components.json +34 -0
  163. package/templates/example-chain/checkpoints/2-rigging-answers/evidence/interview/assemble.json +309 -0
  164. package/templates/example-chain/checkpoints/2-rigging-answers/evidence/interview/bones.json +190 -0
  165. package/templates/example-chain/checkpoints/2-rigging-answers/evidence/interview/reference.json +59 -0
  166. package/templates/example-chain/checkpoints/2-rigging-answers/evidence/interview/rig_type.json +59 -0
  167. package/templates/example-chain/checkpoints/2-rigging-answers/evidence/interview/seethrough.json +186 -0
  168. package/templates/example-chain/checkpoints/2-rigging-answers/evidence/parts-check.json +127 -0
  169. package/templates/example-chain/checkpoints/2-rigging-answers/evidence/parts-review.json +88 -0
  170. package/templates/example-chain/checkpoints/2-rigging-answers/evidence/review-reads/a12dea02d32508acc99386f894af76a14f1c85f45f804db2aa6b4dea5297973f.json +59 -0
  171. package/templates/example-chain/checkpoints/2-rigging-answers/evidence/split-config.json +1 -0
  172. package/templates/example-chain/checkpoints/2-rigging-answers/evidence/structure.json +30 -0
  173. package/templates/example-chain/checkpoints/2-rigging-answers/inputs/painting.png +0 -0
  174. package/templates/example-chain/checkpoints/2-rigging-answers/inputs/references/.gitkeep +0 -0
  175. package/templates/example-chain/checkpoints/2-rigging-answers/package.json +9 -0
  176. package/templates/example-chain/checkpoints/2-rigging-answers/project.json +1198 -0
  177. package/templates/example-chain/checkpoints/2-rigging-answers.json +254 -0
  178. package/templates/example-chain/checkpoints/3-rig-review/AGENTS.md +134 -0
  179. package/templates/example-chain/checkpoints/3-rig-review/CLAUDE.md +3 -0
  180. package/templates/example-chain/checkpoints/3-rig-review/evidence/.gitkeep +0 -0
  181. package/templates/example-chain/checkpoints/3-rig-review/evidence/approval.txt +1 -0
  182. package/templates/example-chain/checkpoints/3-rig-review/evidence/diff-components.json +34 -0
  183. package/templates/example-chain/checkpoints/3-rig-review/evidence/interview/assemble.json +309 -0
  184. package/templates/example-chain/checkpoints/3-rig-review/evidence/interview/bones.json +190 -0
  185. package/templates/example-chain/checkpoints/3-rig-review/evidence/interview/constraints.json +272 -0
  186. package/templates/example-chain/checkpoints/3-rig-review/evidence/interview/meshes.json +190 -0
  187. package/templates/example-chain/checkpoints/3-rig-review/evidence/interview/motion.json +272 -0
  188. package/templates/example-chain/checkpoints/3-rig-review/evidence/interview/reference.json +59 -0
  189. package/templates/example-chain/checkpoints/3-rig-review/evidence/interview/rig_type.json +59 -0
  190. package/templates/example-chain/checkpoints/3-rig-review/evidence/interview/seethrough.json +186 -0
  191. package/templates/example-chain/checkpoints/3-rig-review/evidence/parts-check.json +127 -0
  192. package/templates/example-chain/checkpoints/3-rig-review/evidence/parts-review.json +88 -0
  193. package/templates/example-chain/checkpoints/3-rig-review/evidence/review-reads/a12dea02d32508acc99386f894af76a14f1c85f45f804db2aa6b4dea5297973f.json +59 -0
  194. package/templates/example-chain/checkpoints/3-rig-review/evidence/setup.png +0 -0
  195. package/templates/example-chain/checkpoints/3-rig-review/evidence/split-config.json +1 -0
  196. package/templates/example-chain/checkpoints/3-rig-review/evidence/structure.json +30 -0
  197. package/templates/example-chain/checkpoints/3-rig-review/evidence/v1/config.json +88 -0
  198. package/templates/example-chain/checkpoints/3-rig-review/evidence/v1/interview-requirements.json +8 -0
  199. package/templates/example-chain/checkpoints/3-rig-review/inputs/painting.png +0 -0
  200. package/templates/example-chain/checkpoints/3-rig-review/inputs/references/.gitkeep +0 -0
  201. package/templates/example-chain/checkpoints/3-rig-review/package.json +9 -0
  202. package/templates/example-chain/checkpoints/3-rig-review/project.json +1909 -0
  203. package/templates/example-chain/checkpoints/3-rig-review.json +424 -0
  204. package/templates/example-chain/checkpoints/4-direction-post/AGENTS.md +134 -0
  205. package/templates/example-chain/checkpoints/4-direction-post/CLAUDE.md +3 -0
  206. package/templates/example-chain/checkpoints/4-direction-post/evidence/.gitkeep +0 -0
  207. package/templates/example-chain/checkpoints/4-direction-post/evidence/approval.txt +1 -0
  208. package/templates/example-chain/checkpoints/4-direction-post/evidence/diff-components.json +34 -0
  209. package/templates/example-chain/checkpoints/4-direction-post/evidence/interview/assemble.json +309 -0
  210. package/templates/example-chain/checkpoints/4-direction-post/evidence/interview/bones.json +190 -0
  211. package/templates/example-chain/checkpoints/4-direction-post/evidence/interview/camera_depth.json +102 -0
  212. package/templates/example-chain/checkpoints/4-direction-post/evidence/interview/constraints.json +272 -0
  213. package/templates/example-chain/checkpoints/4-direction-post/evidence/interview/meshes.json +190 -0
  214. package/templates/example-chain/checkpoints/4-direction-post/evidence/interview/motion.json +272 -0
  215. package/templates/example-chain/checkpoints/4-direction-post/evidence/interview/post_composition.json +122 -0
  216. package/templates/example-chain/checkpoints/4-direction-post/evidence/interview/post_timing.json +102 -0
  217. package/templates/example-chain/checkpoints/4-direction-post/evidence/interview/reference.json +59 -0
  218. package/templates/example-chain/checkpoints/4-direction-post/evidence/interview/rig_type.json +59 -0
  219. package/templates/example-chain/checkpoints/4-direction-post/evidence/interview/seethrough.json +186 -0
  220. package/templates/example-chain/checkpoints/4-direction-post/evidence/parts-check.json +127 -0
  221. package/templates/example-chain/checkpoints/4-direction-post/evidence/parts-review.json +88 -0
  222. package/templates/example-chain/checkpoints/4-direction-post/evidence/review-reads/a12dea02d32508acc99386f894af76a14f1c85f45f804db2aa6b4dea5297973f.json +59 -0
  223. package/templates/example-chain/checkpoints/4-direction-post/evidence/setup.png +0 -0
  224. package/templates/example-chain/checkpoints/4-direction-post/evidence/split-config.json +1 -0
  225. package/templates/example-chain/checkpoints/4-direction-post/evidence/structure.json +30 -0
  226. package/templates/example-chain/checkpoints/4-direction-post/evidence/v1/config.json +88 -0
  227. package/templates/example-chain/checkpoints/4-direction-post/evidence/v1/interview-requirements.json +8 -0
  228. package/templates/example-chain/checkpoints/4-direction-post/inputs/painting.png +0 -0
  229. package/templates/example-chain/checkpoints/4-direction-post/inputs/references/.gitkeep +0 -0
  230. package/templates/example-chain/checkpoints/4-direction-post/package.json +9 -0
  231. package/templates/example-chain/checkpoints/4-direction-post/project.json +2302 -0
  232. package/templates/example-chain/checkpoints/4-direction-post.json +456 -0
  233. package/templates/example-chain/evidence/.gitkeep +0 -0
  234. package/templates/example-chain/evidence/approval.txt +1 -0
  235. package/templates/example-chain/evidence/captions.json +101 -0
  236. package/templates/example-chain/evidence/diff-components.json +34 -0
  237. package/templates/example-chain/evidence/direction/v2.json +74 -0
  238. package/templates/example-chain/evidence/direction-input.json +74 -0
  239. package/templates/example-chain/evidence/interview/assemble.json +309 -0
  240. package/templates/example-chain/evidence/interview/bones.json +190 -0
  241. package/templates/example-chain/evidence/interview/camera_depth.json +102 -0
  242. package/templates/example-chain/evidence/interview/constraints.json +272 -0
  243. package/templates/example-chain/evidence/interview/meshes.json +190 -0
  244. package/templates/example-chain/evidence/interview/motion.json +272 -0
  245. package/templates/example-chain/evidence/interview/post_composition.json +122 -0
  246. package/templates/example-chain/evidence/interview/post_timing.json +102 -0
  247. package/templates/example-chain/evidence/interview/reference.json +59 -0
  248. package/templates/example-chain/evidence/interview/rig_type.json +59 -0
  249. package/templates/example-chain/evidence/interview/seethrough.json +186 -0
  250. package/templates/example-chain/evidence/parts-check.json +127 -0
  251. package/templates/example-chain/evidence/parts-review.json +88 -0
  252. package/templates/example-chain/evidence/review-reads/a12dea02d32508acc99386f894af76a14f1c85f45f804db2aa6b4dea5297973f.json +59 -0
  253. package/templates/example-chain/evidence/scene/s1.json +65 -0
  254. package/templates/example-chain/evidence/scene-citations.json +9 -0
  255. package/templates/example-chain/evidence/setup.png +0 -0
  256. package/templates/example-chain/evidence/split-config.json +1 -0
  257. package/templates/example-chain/evidence/structure.json +30 -0
  258. package/templates/example-chain/evidence/v1/config.json +88 -0
  259. package/templates/example-chain/evidence/v1/interview-requirements.json +8 -0
  260. package/templates/example-chain/inputs/background.png +0 -0
  261. package/templates/example-chain/inputs/painting.png +0 -0
  262. package/templates/example-chain/inputs/references/.gitkeep +0 -0
  263. package/templates/example-chain/package.json +9 -0
  264. package/templates/example-chain/project.json +2593 -0
  265. package/templates/example-diff/diff-components.json +71 -0
  266. package/templates/example-diff/recomposite_rig.png +0 -0
  267. package/templates/example-direction/approval.txt +1 -0
  268. package/templates/example-direction/derived/review/v1/out/check/build/rectangle.png +0 -0
  269. package/templates/example-direction/derived/review/v1/out/check/build/run.json +40 -0
  270. package/templates/example-direction/derived/review/v1/out/check/build/skeleton.atlas +8 -0
  271. package/templates/example-direction/derived/review/v1/out/check/build/skeleton.json +73 -0
  272. package/templates/example-direction/derived/review/v1/out/check/build/skeleton.model.json +195 -0
  273. package/templates/example-direction/evidence/direction/v2.json +69 -0
  274. package/templates/example-direction/evidence/direction/v3.json +59 -0
  275. package/templates/example-direction/evidence/images/rectangle.png +0 -0
  276. package/templates/example-direction/evidence/input.json +69 -0
  277. package/templates/example-direction/evidence/motion.json +33 -0
  278. package/templates/example-direction/evidence/patch.json +23 -0
  279. package/templates/example-direction/evidence/rig-config.json +55 -0
  280. package/templates/example-direction/evidence/still.png +0 -0
  281. package/templates/example-direction/project.json +372 -0
  282. package/templates/example-direction/reasoning.txt +1 -0
  283. package/templates/example-direction/words.txt +1 -0
  284. package/templates/example-draft/README.md +28 -0
  285. package/templates/example-draft/config.json +71 -0
  286. package/templates/example-draft/derived/drafts/lantern/config.json +71 -0
  287. package/templates/example-draft/derived/drafts/lantern/input/painting_in_rig.png +0 -0
  288. package/templates/example-draft/derived/drafts/lantern/input/parts/background.png +0 -0
  289. package/templates/example-draft/derived/drafts/lantern/input/parts/eye_l.png +0 -0
  290. package/templates/example-draft/derived/drafts/lantern/input/parts/eye_r.png +0 -0
  291. package/templates/example-draft/derived/drafts/lantern/input/parts/face.png +0 -0
  292. package/templates/example-draft/derived/drafts/lantern/input/parts/lantern.png +0 -0
  293. package/templates/example-draft/derived/drafts/lantern/input/parts/torso.png +0 -0
  294. package/templates/example-draft/derived/drafts/lantern/input/parts.json +188 -0
  295. package/templates/example-draft/derived/drafts/lantern/input/recomposite_rig.png +0 -0
  296. package/templates/example-draft/derived/drafts/lantern/interview-requirements.json +8 -0
  297. package/templates/example-draft/derived/drafts/lantern/out/check/build/run.json +40 -0
  298. package/templates/example-draft/derived/drafts/lantern/out/check/build/skeleton.atlas +28 -0
  299. package/templates/example-draft/derived/drafts/lantern/out/check/build/skeleton.json +193 -0
  300. package/templates/example-draft/derived/drafts/lantern/out/check/build/skeleton.model.json +483 -0
  301. package/templates/example-draft/derived/drafts/lantern/out/check/build/skeleton.png +0 -0
  302. package/templates/example-draft/derived/drafts/lantern/out/images/background.png +0 -0
  303. package/templates/example-draft/derived/drafts/lantern/out/images/eye_l.png +0 -0
  304. package/templates/example-draft/derived/drafts/lantern/out/images/eye_r.png +0 -0
  305. package/templates/example-draft/derived/drafts/lantern/out/images/face.png +0 -0
  306. package/templates/example-draft/derived/drafts/lantern/out/images/lantern.png +0 -0
  307. package/templates/example-draft/derived/drafts/lantern/out/images/torso.png +0 -0
  308. package/templates/example-draft/derived/drafts/lantern/out/mesh_report.json +1 -0
  309. package/templates/example-draft/derived/drafts/lantern/out/motion.json +137 -0
  310. package/templates/example-draft/derived/drafts/lantern/out/rig.json +102 -0
  311. package/templates/example-draft/derived/drafts/lantern/out/run.json +52 -0
  312. package/templates/example-draft/derived/parts/rig/painting_in_rig.png +0 -0
  313. package/templates/example-draft/derived/parts/rig/parts/background.png +0 -0
  314. package/templates/example-draft/derived/parts/rig/parts/eye_l.png +0 -0
  315. package/templates/example-draft/derived/parts/rig/parts/eye_r.png +0 -0
  316. package/templates/example-draft/derived/parts/rig/parts/face.png +0 -0
  317. package/templates/example-draft/derived/parts/rig/parts/lantern.png +0 -0
  318. package/templates/example-draft/derived/parts/rig/parts/torso.png +0 -0
  319. package/templates/example-draft/derived/parts/rig/parts.json +188 -0
  320. package/templates/example-draft/derived/parts/rig/recomposite_rig.png +0 -0
  321. package/templates/example-draft/derived/review/v1/config.json +71 -0
  322. package/templates/example-draft/derived/review/v1/interview-requirements.json +8 -0
  323. package/templates/example-draft/derived/review/v1/out/check/build/run.json +40 -0
  324. package/templates/example-draft/derived/review/v1/out/check/build/skeleton.atlas +28 -0
  325. package/templates/example-draft/derived/review/v1/out/check/build/skeleton.json +193 -0
  326. package/templates/example-draft/derived/review/v1/out/check/build/skeleton.model.json +483 -0
  327. package/templates/example-draft/derived/review/v1/out/check/build/skeleton.png +0 -0
  328. package/templates/example-draft/derived/review/v1/out/parts/background.png +0 -0
  329. package/templates/example-draft/derived/review/v1/out/parts/eye_l.png +0 -0
  330. package/templates/example-draft/derived/review/v1/out/parts/eye_r.png +0 -0
  331. package/templates/example-draft/derived/review/v1/out/parts/face.png +0 -0
  332. package/templates/example-draft/derived/review/v1/out/parts/lantern.png +0 -0
  333. package/templates/example-draft/derived/review/v1/out/parts/torso.png +0 -0
  334. package/templates/example-draft/derived/review/v1/out/parts.json +188 -0
  335. package/templates/example-draft/derived/review/v1/out/rig/images/background.png +0 -0
  336. package/templates/example-draft/derived/review/v1/out/rig/images/eye_l.png +0 -0
  337. package/templates/example-draft/derived/review/v1/out/rig/images/eye_r.png +0 -0
  338. package/templates/example-draft/derived/review/v1/out/rig/images/face.png +0 -0
  339. package/templates/example-draft/derived/review/v1/out/rig/images/lantern.png +0 -0
  340. package/templates/example-draft/derived/review/v1/out/rig/images/torso.png +0 -0
  341. package/templates/example-draft/derived/review/v1/out/rig/mesh_report.json +1 -0
  342. package/templates/example-draft/derived/review/v1/out/rig/motion.json +137 -0
  343. package/templates/example-draft/derived/review/v1/out/rig/rig.json +102 -0
  344. package/templates/example-draft/derived/review/v1/out/rig/run.json +52 -0
  345. package/templates/example-draft/derived/review/v2/config.json +71 -0
  346. package/templates/example-draft/derived/review/v2/interview-requirements.json +8 -0
  347. package/templates/example-draft/derived/review/v2/out/check/build/run.json +40 -0
  348. package/templates/example-draft/derived/review/v2/out/check/build/skeleton.atlas +28 -0
  349. package/templates/example-draft/derived/review/v2/out/check/build/skeleton.json +193 -0
  350. package/templates/example-draft/derived/review/v2/out/check/build/skeleton.model.json +483 -0
  351. package/templates/example-draft/derived/review/v2/out/check/build/skeleton.png +0 -0
  352. package/templates/example-draft/derived/review/v2/out/parts/background.png +0 -0
  353. package/templates/example-draft/derived/review/v2/out/parts/eye_l.png +0 -0
  354. package/templates/example-draft/derived/review/v2/out/parts/eye_r.png +0 -0
  355. package/templates/example-draft/derived/review/v2/out/parts/face.png +0 -0
  356. package/templates/example-draft/derived/review/v2/out/parts/lantern.png +0 -0
  357. package/templates/example-draft/derived/review/v2/out/parts/torso.png +0 -0
  358. package/templates/example-draft/derived/review/v2/out/parts.json +188 -0
  359. package/templates/example-draft/derived/review/v2/out/rig/images/background.png +0 -0
  360. package/templates/example-draft/derived/review/v2/out/rig/images/eye_l.png +0 -0
  361. package/templates/example-draft/derived/review/v2/out/rig/images/eye_r.png +0 -0
  362. package/templates/example-draft/derived/review/v2/out/rig/images/face.png +0 -0
  363. package/templates/example-draft/derived/review/v2/out/rig/images/lantern.png +0 -0
  364. package/templates/example-draft/derived/review/v2/out/rig/images/torso.png +0 -0
  365. package/templates/example-draft/derived/review/v2/out/rig/mesh_report.json +1 -0
  366. package/templates/example-draft/derived/review/v2/out/rig/motion.json +137 -0
  367. package/templates/example-draft/derived/review/v2/out/rig/rig.json +102 -0
  368. package/templates/example-draft/derived/review/v2/out/rig/run.json +52 -0
  369. package/templates/example-draft/evidence/diff-components.json +71 -0
  370. package/templates/example-draft/evidence/direction/v4.json +64 -0
  371. package/templates/example-draft/evidence/direction-input-v4.json +64 -0
  372. package/templates/example-draft/evidence/fix-ledger/lantern.json +17 -0
  373. package/templates/example-draft/evidence/parts-check.json +127 -0
  374. package/templates/example-draft/evidence/parts-review.json +88 -0
  375. package/templates/example-draft/evidence/review-reads/4ed0507381809746443021554e012032be5b5f8417da0f2e525e9b6df16e9f05.json +59 -0
  376. package/templates/example-draft/evidence/scene/s1.json +65 -0
  377. package/templates/example-draft/evidence/scene-background.png +0 -0
  378. package/templates/example-draft/evidence/scene-citations.json +9 -0
  379. package/templates/example-draft/evidence/structure-decisions.json +9 -0
  380. package/templates/example-draft/evidence/v1/interview-config.json +71 -0
  381. package/templates/example-draft/evidence/v1/interview-requirements.json +8 -0
  382. package/templates/example-draft/evidence/v1/review-config.json +71 -0
  383. package/templates/example-draft/evidence/v2/interview-config.json +71 -0
  384. package/templates/example-draft/evidence/v2/interview-requirements.json +8 -0
  385. package/templates/example-draft/evidence/v2/review-config.json +71 -0
  386. package/templates/example-draft/input/painting_in_rig.png +0 -0
  387. package/templates/example-draft/input/parts/background.png +0 -0
  388. package/templates/example-draft/input/parts/eye_l.png +0 -0
  389. package/templates/example-draft/input/parts/eye_r.png +0 -0
  390. package/templates/example-draft/input/parts/face.png +0 -0
  391. package/templates/example-draft/input/parts/lantern.png +0 -0
  392. package/templates/example-draft/input/parts/torso.png +0 -0
  393. package/templates/example-draft/input/parts.json +188 -0
  394. package/templates/example-draft/input/recomposite_rig.png +0 -0
  395. package/templates/example-draft/inputs/painting.png +0 -0
  396. package/templates/example-draft/interview-requirements.json +8 -0
  397. package/templates/example-draft/out/check/build/run.json +40 -0
  398. package/templates/example-draft/out/check/build/skeleton.atlas +28 -0
  399. package/templates/example-draft/out/check/build/skeleton.json +193 -0
  400. package/templates/example-draft/out/check/build/skeleton.model.json +483 -0
  401. package/templates/example-draft/out/check/build/skeleton.png +0 -0
  402. package/templates/example-draft/out/images/background.png +0 -0
  403. package/templates/example-draft/out/images/eye_l.png +0 -0
  404. package/templates/example-draft/out/images/eye_r.png +0 -0
  405. package/templates/example-draft/out/images/face.png +0 -0
  406. package/templates/example-draft/out/images/lantern.png +0 -0
  407. package/templates/example-draft/out/images/torso.png +0 -0
  408. package/templates/example-draft/out/mesh_report.json +1 -0
  409. package/templates/example-draft/out/motion.json +137 -0
  410. package/templates/example-draft/out/rig.json +102 -0
  411. package/templates/example-draft/out/run.json +52 -0
  412. package/templates/example-draft/outputs/v1/out/check/build/run.json +40 -0
  413. package/templates/example-draft/outputs/v1/out/check/build/skeleton.atlas +28 -0
  414. package/templates/example-draft/outputs/v1/out/check/build/skeleton.json +193 -0
  415. package/templates/example-draft/outputs/v1/out/check/build/skeleton.model.json +483 -0
  416. package/templates/example-draft/outputs/v1/out/check/build/skeleton.png +0 -0
  417. package/templates/example-draft/outputs/v1/out/painting_in_rig.png +0 -0
  418. package/templates/example-draft/outputs/v1/out/parts/background.png +0 -0
  419. package/templates/example-draft/outputs/v1/out/parts/eye_l.png +0 -0
  420. package/templates/example-draft/outputs/v1/out/parts/eye_r.png +0 -0
  421. package/templates/example-draft/outputs/v1/out/parts/face.png +0 -0
  422. package/templates/example-draft/outputs/v1/out/parts/lantern.png +0 -0
  423. package/templates/example-draft/outputs/v1/out/parts/torso.png +0 -0
  424. package/templates/example-draft/outputs/v1/out/parts.json +188 -0
  425. package/templates/example-draft/outputs/v1/out/rig/images/background.png +0 -0
  426. package/templates/example-draft/outputs/v1/out/rig/images/eye_l.png +0 -0
  427. package/templates/example-draft/outputs/v1/out/rig/images/eye_r.png +0 -0
  428. package/templates/example-draft/outputs/v1/out/rig/images/face.png +0 -0
  429. package/templates/example-draft/outputs/v1/out/rig/images/lantern.png +0 -0
  430. package/templates/example-draft/outputs/v1/out/rig/images/torso.png +0 -0
  431. package/templates/example-draft/outputs/v1/out/rig/mesh_report.json +1 -0
  432. package/templates/example-draft/outputs/v1/out/rig/motion.json +137 -0
  433. package/templates/example-draft/outputs/v1/out/rig/rig.json +102 -0
  434. package/templates/example-draft/outputs/v1/out/rig/run.json +52 -0
  435. package/templates/example-draft/outputs/v2/out/check/build/run.json +40 -0
  436. package/templates/example-draft/outputs/v2/out/check/build/skeleton.atlas +28 -0
  437. package/templates/example-draft/outputs/v2/out/check/build/skeleton.json +193 -0
  438. package/templates/example-draft/outputs/v2/out/check/build/skeleton.model.json +483 -0
  439. package/templates/example-draft/outputs/v2/out/check/build/skeleton.png +0 -0
  440. package/templates/example-draft/outputs/v2/out/painting_in_rig.png +0 -0
  441. package/templates/example-draft/outputs/v2/out/parts/background.png +0 -0
  442. package/templates/example-draft/outputs/v2/out/parts/eye_l.png +0 -0
  443. package/templates/example-draft/outputs/v2/out/parts/eye_r.png +0 -0
  444. package/templates/example-draft/outputs/v2/out/parts/face.png +0 -0
  445. package/templates/example-draft/outputs/v2/out/parts/lantern.png +0 -0
  446. package/templates/example-draft/outputs/v2/out/parts/torso.png +0 -0
  447. package/templates/example-draft/outputs/v2/out/parts.json +188 -0
  448. package/templates/example-draft/outputs/v2/out/rig/images/background.png +0 -0
  449. package/templates/example-draft/outputs/v2/out/rig/images/eye_l.png +0 -0
  450. package/templates/example-draft/outputs/v2/out/rig/images/eye_r.png +0 -0
  451. package/templates/example-draft/outputs/v2/out/rig/images/face.png +0 -0
  452. package/templates/example-draft/outputs/v2/out/rig/images/lantern.png +0 -0
  453. package/templates/example-draft/outputs/v2/out/rig/images/torso.png +0 -0
  454. package/templates/example-draft/outputs/v2/out/rig/mesh_report.json +1 -0
  455. package/templates/example-draft/outputs/v2/out/rig/motion.json +137 -0
  456. package/templates/example-draft/outputs/v2/out/rig/rig.json +102 -0
  457. package/templates/example-draft/outputs/v2/out/rig/run.json +52 -0
  458. package/templates/example-interview-choice.json +1068 -0
  459. package/templates/example-interview-options/constraint.json +376 -0
  460. package/templates/example-interview-options/example-assemble.json +376 -0
  461. package/templates/example-interview-options/example-bones.json +190 -0
  462. package/templates/example-interview-options/example-camera-depth.json +99 -0
  463. package/templates/example-interview-options/example-constraints.json +272 -0
  464. package/templates/example-interview-options/example-meshes.json +190 -0
  465. package/templates/example-interview-options/example-motion.json +272 -0
  466. package/templates/example-interview-options/example-picks.json +15 -0
  467. package/templates/example-interview-options/example-post-composition.json +110 -0
  468. package/templates/example-interview-options/example-post-timing.json +105 -0
  469. package/templates/example-interview-options/example-reference.json +63 -0
  470. package/templates/example-interview-options/example-rig-type.json +63 -0
  471. package/templates/example-interview-options/example-seethrough.json +190 -0
  472. package/templates/example-interview-options/fullscreen.json +63 -0
  473. package/templates/example-interview-options/other-explicit.json +63 -0
  474. package/templates/example-interview-options/other-pending.json +63 -0
  475. package/templates/example-interview-options/other-picks.json +16 -0
  476. package/templates/example-interview.md +213 -0
  477. package/templates/example-invariants/invariants.json +1339 -0
  478. package/templates/example-prepared/prepared.svg +1 -0
  479. package/templates/example-prepared/source.svg +1 -0
  480. package/templates/example-project.json +4259 -0
  481. package/templates/example-remesh/AGENTS.md +134 -0
  482. package/templates/example-remesh/CLAUDE.md +3 -0
  483. package/templates/example-remesh/evidence/.gitkeep +0 -0
  484. package/templates/example-remesh/evidence/approval.txt +1 -0
  485. package/templates/example-remesh/evidence/captions.json +101 -0
  486. package/templates/example-remesh/evidence/diff-components.json +34 -0
  487. package/templates/example-remesh/evidence/direction/v4.json +74 -0
  488. package/templates/example-remesh/evidence/direction/v5.json +74 -0
  489. package/templates/example-remesh/evidence/direction-input-v4.json +74 -0
  490. package/templates/example-remesh/evidence/direction-input-v5.json +74 -0
  491. package/templates/example-remesh/evidence/interview/assemble.json +309 -0
  492. package/templates/example-remesh/evidence/interview/bones.json +190 -0
  493. package/templates/example-remesh/evidence/interview/camera_depth.json +103 -0
  494. package/templates/example-remesh/evidence/interview/constraints.json +272 -0
  495. package/templates/example-remesh/evidence/interview/meshes.json +190 -0
  496. package/templates/example-remesh/evidence/interview/motion.json +272 -0
  497. package/templates/example-remesh/evidence/interview/post_composition.json +123 -0
  498. package/templates/example-remesh/evidence/interview/post_timing.json +103 -0
  499. package/templates/example-remesh/evidence/interview/reference.json +59 -0
  500. package/templates/example-remesh/evidence/interview/rig_type.json +59 -0
  501. package/templates/example-remesh/evidence/interview/seethrough.json +186 -0
  502. package/templates/example-remesh/evidence/parts-check.json +127 -0
  503. package/templates/example-remesh/evidence/parts-review.json +88 -0
  504. package/templates/example-remesh/evidence/reopen.txt +1 -0
  505. package/templates/example-remesh/evidence/review-reads/6a17db694db96f1b6049a61a017e0c8e66757b982b8851e0187e561cfcf9af68.json +59 -0
  506. package/templates/example-remesh/evidence/scene/s1.json +69 -0
  507. package/templates/example-remesh/evidence/scene-citations.json +9 -0
  508. package/templates/example-remesh/evidence/setup.png +0 -0
  509. package/templates/example-remesh/evidence/split-config.json +1 -0
  510. package/templates/example-remesh/evidence/structure.json +30 -0
  511. package/templates/example-remesh/evidence/v1/registration/at-source.json +44 -0
  512. package/templates/example-remesh/evidence/v1/registration/citations.json +68 -0
  513. package/templates/example-remesh/evidence/v1/registration/compile-report.json +368 -0
  514. package/templates/example-remesh/evidence/v1/registration/config-source.json +88 -0
  515. package/templates/example-remesh/evidence/v1/registration/config.json +88 -0
  516. package/templates/example-remesh/evidence/v1/registration/interview-requirements.json +8 -0
  517. package/templates/example-remesh/evidence/v1/registration/package-lock.json +11 -0
  518. package/templates/example-remesh/evidence/v1/registration/path-adapter.json +1 -0
  519. package/templates/example-remesh/evidence/v1/registration/rigc-run-1.json +44 -0
  520. package/templates/example-remesh/evidence/v2/registration/at-source.json +44 -0
  521. package/templates/example-remesh/evidence/v2/registration/citations.json +68 -0
  522. package/templates/example-remesh/evidence/v2/registration/compile-report.json +368 -0
  523. package/templates/example-remesh/evidence/v2/registration/config-source.json +88 -0
  524. package/templates/example-remesh/evidence/v2/registration/config.json +88 -0
  525. package/templates/example-remesh/evidence/v2/registration/interview-requirements.json +8 -0
  526. package/templates/example-remesh/evidence/v2/registration/package-lock.json +11 -0
  527. package/templates/example-remesh/evidence/v2/registration/path-adapter.json +1 -0
  528. package/templates/example-remesh/evidence/v2/registration/rigc-run-1.json +44 -0
  529. package/templates/example-remesh/evidence/v3/registration/at-source.json +44 -0
  530. package/templates/example-remesh/evidence/v3/registration/citations.json +68 -0
  531. package/templates/example-remesh/evidence/v3/registration/compile-report.json +368 -0
  532. package/templates/example-remesh/evidence/v3/registration/config-source.json +88 -0
  533. package/templates/example-remesh/evidence/v3/registration/config.json +88 -0
  534. package/templates/example-remesh/evidence/v3/registration/interview-requirements.json +8 -0
  535. package/templates/example-remesh/evidence/v3/registration/package-lock.json +11 -0
  536. package/templates/example-remesh/evidence/v3/registration/path-adapter.json +1 -0
  537. package/templates/example-remesh/evidence/v3/registration/rigc-run-1.json +44 -0
  538. package/templates/example-remesh/inputs/background.png +0 -0
  539. package/templates/example-remesh/inputs/painting.png +0 -0
  540. package/templates/example-remesh/inputs/references/.gitkeep +0 -0
  541. package/templates/example-remesh/package.json +9 -0
  542. package/templates/example-remesh/project.json +3916 -0
  543. package/templates/example-reopened/project.json +4568 -0
  544. package/templates/example-review/config.json +1 -0
  545. package/templates/example-review/out/check/build/skeleton.model.json +1 -0
  546. package/templates/example-review/out/parts/piece.svg +1 -0
  547. package/templates/example-review/out/parts.json +1 -0
  548. package/templates/example-review/out/rig/mesh_report.json +1 -0
  549. package/templates/example-review/out/rig/motion.json +1 -0
  550. package/templates/example-review/out/rig/rig.json +1 -0
  551. package/templates/example-split/captions.json +357 -0
  552. package/templates/example-split/config.json +215 -0
  553. package/templates/legacy-example-project.json +1071 -0
  554. package/templates/project.json +199 -0
  555. package/templates/shared/conventions.json +23 -0
@@ -0,0 +1,383 @@
1
+ import { createHash, randomUUID } from 'node:crypto';
2
+ import { closeSync, constants, fsyncSync, mkdirSync, openSync, renameSync, rmdirSync, rmSync, writeFileSync } from 'node:fs';
3
+ import { existsSync, JOB_PRIVATE_DIRECTORY, lstatSync, readFileSync, readdirSync, realpathSync } from './check-reads.ts';
4
+ import { basename, dirname, join, resolve } from 'node:path';
5
+ import { tmpdir } from 'node:os';
6
+ import { isDeepStrictEqual } from 'node:util';
7
+ import type { JobPublishRequest, JobReviewerBinding, JobSubject, RecordResult } from '@rig-c/review/job-host';
8
+ import { refuse } from './refusal.ts';
9
+
10
+ export const JOB_BINDING_FILE = '.rig-create-review-binding.json';
11
+ export const JOB_OUTBOX_DIRECTORY = JOB_PRIVATE_DIRECTORY;
12
+ const PRIVATE_TEMP_ROOT = realpathSync(tmpdir());
13
+ export const jobHash = (bytes: string | Uint8Array): string => createHash('sha256').update(bytes).digest('hex');
14
+
15
+ export interface JobIdentity {
16
+ publicationMode?: 'record-and-package';
17
+ root: string;
18
+ stateDir: string;
19
+ fingerprint: string;
20
+ reviewer: JobReviewerBinding;
21
+ readerId: string;
22
+ bindingId: string;
23
+ partsEnumeratorId: string;
24
+ apiSchema: string;
25
+ actSchema: string;
26
+ enumeratorVersion: string;
27
+ }
28
+
29
+ export interface WriterBinding {
30
+ schema: 'rig-create/job-binding@1';
31
+ identity: JobIdentity;
32
+ jobId: string;
33
+ origin: string;
34
+ fetchCapability: string;
35
+ listenerIncarnation: string;
36
+ }
37
+
38
+ export type PublicationResult = JobPublishRequest['result'] | (RecordResult & { readonly selector?: never; readonly path?: never });
39
+ export const isRecordResult = (result: PublicationResult): result is RecordResult & { readonly selector?: never; readonly path?: never } => 'kind' in result && (result.kind === 'option-set' || result.kind === 'plan');
40
+
41
+ export interface PendingPublication {
42
+ schema: 'rig-create/job-pending@1';
43
+ root: string;
44
+ id: string;
45
+ jobId: string;
46
+ origin: string;
47
+ identity: JobIdentity;
48
+ recordHash: string;
49
+ versionHash?: string;
50
+ previousVersionHash?: string;
51
+ result: PublicationResult;
52
+ failure: { code: string; message: string } | null;
53
+ generation?: number;
54
+ phase?: 'intent' | 'pending';
55
+ }
56
+
57
+ /** Directory installation is atomic. Stale cleanup removes only the dead
58
+ * owner's unique token and cannot remove a replacement owner's nonempty lock.
59
+ */
60
+ export function acquireJobLock(root: string, required = true): (() => void) | null {
61
+ const lock = join(root, '.rig-create-job-write.lock');
62
+ const token = `${process.pid}-${randomUUID()}`;
63
+ const candidate = `${lock}.${token}`;
64
+ mkdirSync(candidate, { mode: 0o700 });
65
+ writeFileSync(join(candidate, token), '', { flag: 'wx', mode: 0o600 });
66
+ const install = (): boolean => {
67
+ try { renameSync(candidate, lock); return true; }
68
+ catch (error) {
69
+ if (!['EEXIST', 'ENOTEMPTY'].includes((error as NodeJS.ErrnoException).code ?? '')) throw error;
70
+ return false;
71
+ }
72
+ };
73
+ try {
74
+ if (!install()) {
75
+ const owners = lstatSync(lock).isDirectory() ? readdirSync(lock) : [];
76
+ const owner = owners.length === 1 && /^\d+-[a-f0-9-]{36}$/.test(owners[0]) ? owners[0] : null;
77
+ let dead = false;
78
+ if (owner) {
79
+ try { process.kill(Number(owner.split('-')[0]), 0); }
80
+ catch (error) { dead = (error as NodeJS.ErrnoException).code === 'ESRCH'; }
81
+ }
82
+ if (owner && dead) {
83
+ rmSync(join(lock, owner), { force: true });
84
+ try { rmdirSync(lock); } catch (error) {
85
+ if (!['ENOENT', 'ENOTEMPTY'].includes((error as NodeJS.ErrnoException).code ?? '')) throw error;
86
+ }
87
+ }
88
+ if (!install()) {
89
+ if (required) refuse('JOB_WRITE_BUSY', 'project.json: a bound writer holds its publication freeze; wait before retrying');
90
+ return null;
91
+ }
92
+ }
93
+ return () => { rmSync(join(lock, token)); rmdirSync(lock); };
94
+ } finally { rmSync(candidate, { recursive: true, force: true }); }
95
+ }
96
+
97
+ /** Fixed independently of the binding, so close cannot hide an outstanding HOLE. */
98
+ export function jobPrivateRoot(root: string): string {
99
+ return join(realpathSync(root), JOB_OUTBOX_DIRECTORY);
100
+ }
101
+
102
+ /** Review's managed host must remain outside the producer root. */
103
+ export function jobHostStateRoot(root: string): string {
104
+ return join(PRIVATE_TEMP_ROOT, `rig-create-review-${process.getuid?.() ?? 'user'}`, jobHash(realpathSync(root)));
105
+ }
106
+
107
+ /** Existing repositories use their local exclude so opening a job does not
108
+ * dirty a tracked ignore file. New projects already carry these root patterns.
109
+ */
110
+ export function ensureJobPrivateIgnores(root: string): void {
111
+ const names = [JOB_BINDING_FILE, JOB_OUTBOX_DIRECTORY];
112
+ for (const name of names) {
113
+ const tracked = Bun.spawnSync(['git', 'ls-files', '--error-unmatch', '--', name], { cwd: root, stdout: 'ignore', stderr: 'ignore' });
114
+ if (tracked.exitCode === 0) refuse('JOB_BINDING_INVALID', `project.json: private ${name} is tracked; remove it from version control before opening the job`);
115
+ }
116
+ const missing = names.filter(name => Bun.spawnSync(['git', 'check-ignore', '--quiet', '--no-index', '--', name === JOB_OUTBOX_DIRECTORY ? `${name}/receipt.json` : name],
117
+ { cwd: root, stdout: 'ignore', stderr: 'ignore' }).exitCode !== 0);
118
+ if (!missing.length) return;
119
+ const gitPath = Bun.spawnSync(['git', 'rev-parse', '--git-path', 'info/exclude'], { cwd: root, stdout: 'pipe', stderr: 'ignore' });
120
+ const path = gitPath.exitCode === 0 ? resolve(root, gitPath.stdout.toString().trim()) : join(root, '.gitignore');
121
+ try {
122
+ const info = lstatSync(path);
123
+ if (!info.isFile() || info.isSymbolicLink()) refuse('JOB_BINDING_INVALID', 'project.json: private ignore destination must be a regular file; restore it before opening the job');
124
+ } catch (error) { if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error; }
125
+ const before = existsSync(path) ? readFileSync(path, 'utf8') : '';
126
+ const prefix = gitPath.exitCode === 0 ? Bun.spawnSync(['git', 'rev-parse', '--show-prefix'],
127
+ { cwd: root, stdout: 'pipe', stderr: 'ignore' }).stdout.toString().trimEnd() : '';
128
+ const patterns = missing.map(name => `/${prefix}${name}${name === JOB_OUTBOX_DIRECTORY ? '/' : ''}`);
129
+ writeFileSync(path, `${before}${before && !before.endsWith('\n') ? '\n' : ''}${patterns.join('\n')}\n`);
130
+ if (gitPath.exitCode === 0 && names.some(name => Bun.spawnSync(['git', 'check-ignore', '--quiet', '--no-index', '--', name === JOB_OUTBOX_DIRECTORY ? `${name}/receipt.json` : name],
131
+ { cwd: root, stdout: 'ignore', stderr: 'ignore' }).exitCode !== 0)) {
132
+ refuse('JOB_BINDING_INVALID', 'project.json: private binding/outbox are not effectively ignored; remove conflicting unignore rules before opening the job');
133
+ }
134
+ }
135
+
136
+ export function privateDirectory(path: string): void {
137
+ if (existsSync(path)) {
138
+ const info = lstatSync(path);
139
+ if (!info.isDirectory() || info.isSymbolicLink() || realpathSync(path) !== path || (info.mode & 0o077)
140
+ || process.getuid && info.uid !== process.getuid()) {
141
+ refuse('JOB_PRIVATE_STORAGE_INVALID', 'project.json: private publication storage is unsafe; restore its owner-only real directory');
142
+ }
143
+ return;
144
+ }
145
+ const parent = dirname(path);
146
+ if (parent !== PRIVATE_TEMP_ROOT && basename(path) !== JOB_OUTBOX_DIRECTORY) privateDirectory(parent);
147
+ mkdirSync(path, { mode: 0o700 });
148
+ syncDirectory(parent);
149
+ }
150
+
151
+ function assertPrivateFile(path: string): void {
152
+ const info = lstatSync(path);
153
+ if (!info.isFile() || info.isSymbolicLink() || (info.mode & 0o077) || realpathSync(path) !== path
154
+ || process.getuid && info.uid !== process.getuid()) {
155
+ refuse('JOB_PRIVATE_STORAGE_INVALID', 'project.json: private publication file is unsafe; restore its owner-only regular file');
156
+ }
157
+ }
158
+
159
+ export function privateJson(path: string): unknown {
160
+ assertPrivateFile(path);
161
+ return JSON.parse(readFileSync(path, 'utf8'));
162
+ }
163
+
164
+ function syncDirectory(path: string): void {
165
+ const fd = openSync(path, 'r');
166
+ try { fsyncSync(fd); } finally { closeSync(fd); }
167
+ }
168
+
169
+ export function writePrivateJson(path: string, value: unknown, projectSibling = false): void {
170
+ if (!projectSibling) privateDirectory(dirname(path));
171
+ try { privateJson(path); }
172
+ catch (error) { if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error; }
173
+ const temporary = `${path}.${randomUUID()}.tmp`;
174
+ const fd = openSync(temporary, 'wx', 0o600);
175
+ try {
176
+ writeFileSync(fd, `${JSON.stringify(value)}\n`);
177
+ fsyncSync(fd);
178
+ renameSync(temporary, path);
179
+ syncDirectory(dirname(path));
180
+ } finally {
181
+ closeSync(fd);
182
+ rmSync(temporary, { force: true });
183
+ }
184
+ }
185
+
186
+ export function readWriterBinding(root: string): WriterBinding | null {
187
+ const path = join(realpathSync(root), JOB_BINDING_FILE);
188
+ let value: WriterBinding;
189
+ try { value = privateJson(path) as WriterBinding; }
190
+ catch (error) { if ((error as NodeJS.ErrnoException).code === 'ENOENT') return null; throw error; }
191
+ if (value?.schema !== 'rig-create/job-binding@1' || !value.identity || typeof value.jobId !== 'string'
192
+ || typeof value.origin !== 'string' || typeof value.fetchCapability !== 'string'
193
+ || value.listenerIncarnation !== undefined && typeof value.listenerIncarnation !== 'string') {
194
+ refuse('JOB_BINDING_INVALID', 'project.json: malformed private live-job binding; reopen the job through rig-create job open');
195
+ }
196
+ return value;
197
+ }
198
+
199
+ export function assertJobIdentity(expected: JobIdentity, found: JobIdentity): void {
200
+ for (const field of Object.keys(expected) as (keyof JobIdentity)[]) {
201
+ if (!isDeepStrictEqual(expected[field], found[field])) {
202
+ refuse('JOB_HOST_REUSE_MISMATCH', `project.json: ${field} expected=${JSON.stringify(expected[field])} found=${JSON.stringify(found[field])}; restore the bound host configuration, then run rig-create job reconcile`);
203
+ }
204
+ }
205
+ }
206
+
207
+ export function enqueuePublication<R extends PublicationResult>(root: string, binding: WriterBinding, result: R, intentBytes?: Buffer): PendingPublication & { result: R } {
208
+ const bytes = intentBytes ?? readFileSync(join(root, 'project.json'));
209
+ const recordHash = jobHash(bytes);
210
+ const versionHash = publicationVersionHash(bytes, result);
211
+ if (versionHash === null) refuse('JOB_PUBLICATION_INVALID', 'project.json: publication version is absent; restore the recorded rig/post before publishing');
212
+ const id = jobHash(JSON.stringify([binding.jobId, versionHash, result]));
213
+ const pending: PendingPublication & { result: R } = {
214
+ schema: 'rig-create/job-pending@1', root: realpathSync(root), id, jobId: binding.jobId, origin: binding.origin,
215
+ identity: binding.identity, recordHash, versionHash,
216
+ ...(intentBytes && publicationVersionHash(readFileSync(join(root, 'project.json')), result) !== versionHash
217
+ ? { previousVersionHash: publicationVersionHash(readFileSync(join(root, 'project.json')), result) ?? undefined } : {}),
218
+ result, failure: null, phase: intentBytes ? 'intent' : 'pending',
219
+ };
220
+ ensureJobPrivateIgnores(root);
221
+ const path = pendingPath(root, id);
222
+ if (existsSync(path)) return privateJson(path) as PendingPublication & { result: R };
223
+ writePrivateJson(path, pending);
224
+ return pending;
225
+ }
226
+
227
+ /** The writers use the same two-space JSON serialization for version entries.
228
+ * Whole-record bytes are retained only for Review's current freeze/attempt.
229
+ */
230
+ export function publicationVersionHash(bytes: Buffer, result: PublicationResult): string | null {
231
+ if (isRecordResult(result)) return jobHash(bytes);
232
+ const selector = result.selector;
233
+ if (!selector) refuse('JOB_PUBLICATION_INVALID', 'project.json: publication requires a result selector; restore the writer result');
234
+ if (selector.kind === 'draft') {
235
+ const project = JSON.parse(bytes.toString('utf8')) as { drafts?: { id: string }[] };
236
+ const found = project.drafts?.filter(draft => draft.id === selector.id) ?? [];
237
+ if (!found.length) return null;
238
+ if (found.length !== 1) refuse('JOB_PUBLICATION_INVALID', 'project.json: draft identity is ambiguous; restore its unique entry');
239
+ return jobHash(`${JSON.stringify(found[0], null, 2)}\n`);
240
+ }
241
+ const project = JSON.parse(bytes.toString('utf8')) as { versions?: { n: number; kind: string }[] };
242
+ if (!Array.isArray(project.versions)) refuse('JOB_PUBLICATION_INVALID', 'project.json: versions must be an array; restore the recorded rig/post');
243
+ const found = project.versions.filter(version => version.n === selector.version);
244
+ if (!found.length) return null;
245
+ if (found.length !== 1) refuse('JOB_PUBLICATION_INVALID', 'project.json: publication version is ambiguous; restore its unique rig/post entry');
246
+ return jobHash(`${JSON.stringify(found[0], null, 2)}\n`);
247
+ }
248
+
249
+ function currentVersionHash(root: string, entry: PendingPublication): string | null {
250
+ return publicationVersionHash(readFileSync(join(root, 'project.json')), entry.result);
251
+ }
252
+
253
+ function pendingPath(root: string, id: string): string {
254
+ if (!/^[a-f0-9]{64}$/.test(id)) refuse('JOB_OUTBOX_INVALID', 'project.json: invalid pending identity; restore the writer-owned outbox');
255
+ return join(jobPrivateRoot(root), 'outbox', `${id}.json`);
256
+ }
257
+
258
+ export function pendingPublications(root: string, recoverIntents = false): PendingPublication[] {
259
+ const directory = join(jobPrivateRoot(root), 'outbox');
260
+ if (!existsSync(directory)) return [];
261
+ privateDirectory(directory);
262
+ return readdirSync(directory).filter(name => name.endsWith('.json')).sort().flatMap(name => {
263
+ const entry = privateJson(join(directory, name)) as PendingPublication;
264
+ if (entry?.schema !== 'rig-create/job-pending@1' || `${entry.id}.json` !== name
265
+ || entry.root !== realpathSync(root) || !/^[a-f0-9]{64}$/.test(entry.recordHash)
266
+ || entry.versionHash !== undefined && !/^[a-f0-9]{64}$/.test(entry.versionHash)
267
+ || entry.previousVersionHash !== undefined && !/^[a-f0-9]{64}$/.test(entry.previousVersionHash) || !entry.result || !entry.identity) {
268
+ refuse('JOB_OUTBOX_INVALID', 'project.json: malformed pending publication; restore the writer-owned outbox before reconciling');
269
+ }
270
+ if (!entry.versionHash) {
271
+ if (jobHash(readFileSync(join(root, 'project.json'))) !== entry.recordHash) refuse('JOB_OUTBOX_INVALID', 'project.json: legacy receipt cannot identify its version after later edits; restore its original receipt/source before reconciling');
272
+ entry.versionHash = currentVersionHash(root, entry) ?? undefined;
273
+ }
274
+ if (entry.phase === 'intent' && (currentVersionHash(root, entry) === null || entry.previousVersionHash !== undefined && currentVersionHash(root, entry) === entry.previousVersionHash)) {
275
+ if (recoverIntents) discardIntent(root, entry);
276
+ return [];
277
+ }
278
+ return [entry];
279
+ });
280
+ }
281
+
282
+ function discardIntent(root: string, entry: PendingPublication): void {
283
+ const log = join(jobPrivateRoot(root), 'discarded-intents.jsonl');
284
+ if (existsSync(log)) assertPrivateFile(log);
285
+ const fd = openSync(log, constants.O_WRONLY | constants.O_CREAT | constants.O_APPEND | constants.O_NOFOLLOW, 0o600);
286
+ try {
287
+ writeFileSync(fd, `${JSON.stringify({ id: entry.id, versionHash: entry.versionHash, event: 'intent-not-committed' })}\n`);
288
+ fsyncSync(fd);
289
+ } finally { closeSync(fd); }
290
+ rmSync(pendingPath(root, entry.id), { force: true });
291
+ syncDirectory(join(jobPrivateRoot(root), 'outbox'));
292
+ }
293
+
294
+ export function cancelUncommittedIntent(root: string, entry: PendingPublication | null): void {
295
+ if (entry && existsSync(pendingPath(root, entry.id)) && (currentVersionHash(root, entry) === null || entry.previousVersionHash !== undefined && currentVersionHash(root, entry) === entry.previousVersionHash)) discardIntent(root, entry);
296
+ }
297
+
298
+ /** Receipt updates and reconciliation never rewrite the published project. */
299
+ export function failPublication(root: string, entry: PendingPublication, failure: PendingPublication['failure']): void {
300
+ writePrivateJson(pendingPath(root, entry.id), { ...entry, failure });
301
+ }
302
+
303
+ export async function reconcilePublication(root: string, entry: PendingPublication,
304
+ publish: (entry: PendingPublication) => Promise<unknown>): Promise<void> {
305
+ if (currentVersionHash(root, entry) !== entry.versionHash) {
306
+ refuse('JOB_PUBLICATION_STALE', 'project.json: the pending version entry is absent or changed; restore that retained version and its files before rig-create job reconcile');
307
+ }
308
+ const recordHash = jobHash(readFileSync(join(root, 'project.json')));
309
+ if (recordHash !== entry.recordHash) { entry.recordHash = recordHash; delete entry.generation; }
310
+ entry.phase = 'pending';
311
+ failPublication(root, entry, entry.failure);
312
+ await publish(entry);
313
+ rmSync(pendingPath(root, entry.id));
314
+ syncDirectory(join(jobPrivateRoot(root), 'outbox'));
315
+ }
316
+
317
+ export function pendingPublicationHoles(root: string, readOnly = false): { code: string; path: string; message: string }[] {
318
+ try {
319
+ if (!existsSync(root) || !existsSync(join(jobPrivateRoot(root), 'outbox'))) return [];
320
+ const release = readOnly ? null : acquireJobLock(root, false);
321
+ let entries: PendingPublication[];
322
+ try { entries = pendingPublications(root, release !== null); }
323
+ finally { release?.(); }
324
+ return entries.map(entry => {
325
+ const changed = currentVersionHash(root, entry) !== entry.versionHash;
326
+ return {
327
+ code: changed ? 'JOB_PUBLICATION_STALE' : 'JOB_PUBLISH_PENDING', path: 'project.json',
328
+ message: `project.json: HOLE publication ${entry.id} for version hash ${entry.versionHash} ${changed ? 'has a changed or missing version' : 'is pending'}${entry.failure ? ` (${entry.failure.code}: ${entry.failure.message})` : ''}; restore the retained version/files and run rig-create job reconcile`,
329
+ };
330
+ });
331
+ } catch {
332
+ return [{ code: 'JOB_OUTBOX_INVALID', path: 'project.json', message: 'project.json: HOLE private publication outbox is unreadable; restore its owner-only bytes before rig-create job reconcile' }];
333
+ }
334
+ }
335
+
336
+ export interface AcknowledgedPublication {
337
+ schema: 'rig-create/job-acknowledged@1';
338
+ jobId: string;
339
+ publicationId: string;
340
+ generation: number;
341
+ requestId: string;
342
+ result: PendingPublication['result'];
343
+ versionHash: string;
344
+ /** The subjects the published context declared. Receipts written before they were retained omit it. */
345
+ subjects?: readonly JobSubject[];
346
+ }
347
+
348
+ function acknowledgedPath(root: string, jobId: string, publicationId: string): string {
349
+ return join(jobPrivateRoot(root), 'acknowledged-publications', `${jobHash(JSON.stringify([jobId, publicationId]))}.json`);
350
+ }
351
+
352
+ /** Persist the version identity before the pending publication is removed. */
353
+ export function acknowledgePublication(entry: PendingPublication, publicationId: string, generation: number, requestId: string, subjects?: readonly JobSubject[]): void {
354
+ if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(publicationId) || !Number.isSafeInteger(generation) || generation < 0 || !entry.versionHash) {
355
+ refuse('JOB_OUTBOX_INVALID', 'project.json: publication acknowledgment lacks its identity; reconcile the original pending publication');
356
+ }
357
+ const receipt: AcknowledgedPublication = { schema: 'rig-create/job-acknowledged@1', jobId: entry.jobId,
358
+ publicationId, generation, requestId, result: entry.result, versionHash: entry.versionHash, ...(subjects === undefined ? {} : { subjects }) };
359
+ const path = acknowledgedPath(entry.root, entry.jobId, publicationId);
360
+ let existing: unknown;
361
+ try { existing = privateJson(path); }
362
+ catch (error) { if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error; }
363
+ if (existing !== undefined && !isDeepStrictEqual(existing, receipt)) {
364
+ refuse('JOB_OUTBOX_INVALID', 'project.json: acknowledgment identity conflicts with retained receipt; restore the original publication receipt');
365
+ }
366
+ if (existing === undefined) writePrivateJson(path, receipt);
367
+ }
368
+
369
+ export function readAcknowledgedPublication(root: string, jobId: string, publicationId: string): AcknowledgedPublication | null {
370
+ const directory = join(jobPrivateRoot(root), 'acknowledged-publications');
371
+ if (!existsSync(directory)) return null;
372
+ privateDirectory(directory);
373
+ let value: AcknowledgedPublication;
374
+ try { value = privateJson(acknowledgedPath(root, jobId, publicationId)) as AcknowledgedPublication; }
375
+ catch (error) { if ((error as NodeJS.ErrnoException).code === 'ENOENT') return null; throw error; }
376
+ if (value?.schema !== 'rig-create/job-acknowledged@1' || value.jobId !== jobId || value.publicationId !== publicationId
377
+ || !/^[a-f0-9]{64}$/.test(value.versionHash) || !Number.isSafeInteger(value.generation) || value.generation < 0
378
+ || typeof value.requestId !== 'string' || !value.result || (!isRecordResult(value.result) && !value.result.selector)
379
+ || value.subjects !== undefined && (!Array.isArray(value.subjects) || value.subjects.some(subject => subject === null || typeof subject !== 'object' || typeof subject.kind !== 'string'))) {
380
+ refuse('JOB_OUTBOX_INVALID', 'project.json: acknowledged publication receipt is malformed; restore its owner-only original');
381
+ }
382
+ return value;
383
+ }