devrites 5.14.4 → 6.0.1

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 (637) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/NOTICE.md +6 -4
  3. package/README.md +77 -16
  4. package/SECURITY.md +25 -11
  5. package/bin/devrites.mjs +49 -15
  6. package/docs/adr/0001-go-engine-as-control-plane.md +6 -3
  7. package/docs/adr/0029-v5-workspace-schema-and-native-migration.md +9 -0
  8. package/docs/adr/README.md +3 -2
  9. package/docs/agents/issue-tracker.md +1 -1
  10. package/docs/architecture.md +6 -3
  11. package/docs/cli.md +32 -9
  12. package/docs/command-map.md +5 -3
  13. package/docs/engine/state-schema.md +1 -1
  14. package/docs/flow.md +1 -1
  15. package/docs/harness-compliance.md +2 -2
  16. package/docs/release.md +15 -11
  17. package/docs/usage.md +1 -1
  18. package/engine/commands.go +1 -1
  19. package/engine/go.mod +1 -1
  20. package/engine/help.go +41 -15
  21. package/engine/help_test.go +134 -0
  22. package/engine/internal/acceptance/acceptance_test.go +298 -7
  23. package/engine/internal/acceptance/approve.go +7 -2
  24. package/engine/internal/acceptance/cli.go +3 -0
  25. package/engine/internal/acceptance/evidence.go +69 -5
  26. package/engine/internal/acceptance/lint.go +1 -1
  27. package/engine/internal/acceptance/run.go +5 -3
  28. package/engine/internal/acceptance/scaffold.go +5 -16
  29. package/engine/internal/devritespaths/paths.go +7 -6
  30. package/engine/internal/devritespaths/paths_test.go +18 -0
  31. package/engine/internal/fsutil/copy.go +83 -49
  32. package/engine/internal/fsutil/copy_test.go +70 -109
  33. package/engine/internal/gate/gate.go +89 -16
  34. package/engine/internal/gate/gate_test.go +101 -0
  35. package/engine/internal/hostpack/hostpack.go +52 -2
  36. package/engine/internal/hostpack/hostpack_test.go +83 -2
  37. package/engine/internal/install/apply.go +59 -16
  38. package/engine/internal/install/binary.go +10 -1
  39. package/engine/internal/install/install_test.go +428 -0
  40. package/engine/internal/install/merge.go +69 -38
  41. package/engine/internal/install/preflight.go +7 -0
  42. package/engine/internal/install/uninstall.go +43 -4
  43. package/engine/internal/lib/claims.go +25 -4
  44. package/engine/internal/lib/claims_test.go +57 -0
  45. package/engine/internal/lib/closeout.go +41 -3
  46. package/engine/internal/lib/closeout_test.go +144 -0
  47. package/engine/internal/lib/context.go +8 -4
  48. package/engine/internal/lib/context_next_test.go +100 -0
  49. package/engine/internal/lib/detect.go +1 -1
  50. package/engine/internal/lib/detect_test.go +13 -0
  51. package/engine/internal/lib/diffscope.go +19 -9
  52. package/engine/internal/lib/dispatch.go +7 -0
  53. package/engine/internal/lib/dup.go +40 -37
  54. package/engine/internal/lib/dup_test.go +178 -0
  55. package/engine/internal/lib/manifest_union.go +4 -1
  56. package/engine/internal/lib/manifest_union_test.go +37 -0
  57. package/engine/internal/lib/metrics.go +4 -0
  58. package/engine/internal/lib/metrics_test.go +28 -0
  59. package/engine/internal/lib/migrate_test.go +59 -0
  60. package/engine/internal/lib/observe_budgets.go +25 -9
  61. package/engine/internal/lib/observe_budgets_test.go +254 -0
  62. package/engine/internal/lib/observe_summary.go +23 -2
  63. package/engine/internal/lib/open_visual.go +4 -2
  64. package/engine/internal/lib/open_visual_test.go +11 -0
  65. package/engine/internal/lib/regression.go +62 -23
  66. package/engine/internal/lib/regression_test.go +103 -0
  67. package/engine/internal/lib/resolve.go +36 -17
  68. package/engine/internal/lib/resolve_remediation_test.go +132 -0
  69. package/engine/internal/lib/skilltrust.go +0 -11
  70. package/engine/internal/lib/slicecheck.go +7 -5
  71. package/engine/internal/lib/slicecheck_test.go +18 -0
  72. package/engine/internal/lib/triggers.go +9 -3
  73. package/engine/internal/lib/triggers_test.go +23 -0
  74. package/engine/internal/lib/util.go +17 -3
  75. package/engine/internal/lib/util_test.go +104 -0
  76. package/engine/internal/lib/visual_outline.go +7 -3
  77. package/engine/internal/lib/visual_outline_test.go +28 -0
  78. package/engine/internal/lib/windows.go +13 -9
  79. package/engine/internal/lib/windows_test.go +98 -0
  80. package/engine/internal/lib/workspace_read.go +2 -11
  81. package/engine/internal/lib/workspace_read_test.go +102 -0
  82. package/engine/internal/markdowntext/markdowntext.go +194 -11
  83. package/engine/internal/markdowntext/testdata/structural.json +250 -0
  84. package/engine/internal/notes/cli.go +30 -12
  85. package/engine/internal/notes/notes.go +242 -39
  86. package/engine/internal/notes/notes_test.go +372 -0
  87. package/engine/internal/overhaul/admit/packet.go +89 -0
  88. package/engine/internal/overhaul/admit/packet_test.go +223 -0
  89. package/engine/internal/overhaul/admit/run.go +4 -0
  90. package/engine/internal/overhaul/bench/run.go +6 -0
  91. package/engine/internal/overhaul/bench/run_test.go +46 -0
  92. package/engine/internal/overhaul/overhaul.go +6 -1
  93. package/engine/internal/overhaul/ovio/ovio.go +10 -3
  94. package/engine/internal/overhaul/ovio/ovio_test.go +75 -0
  95. package/engine/internal/overhaul/packet/packet.go +208 -0
  96. package/engine/internal/overhaul/packet/packet_test.go +263 -0
  97. package/engine/internal/overhaul/records/check.go +6 -0
  98. package/engine/internal/overhaul/records/init.go +16 -5
  99. package/engine/internal/overhaul/records/records_test.go +4 -0
  100. package/engine/internal/overhaul/records/run.go +66 -0
  101. package/engine/internal/overhaul/records/run_test.go +77 -0
  102. package/engine/internal/overhaul/render/run.go +15 -11
  103. package/engine/internal/overhaul/render/run_test.go +463 -1
  104. package/engine/internal/overhaul/render/visual.go +95 -33
  105. package/engine/internal/overhaul/score/run.go +20 -0
  106. package/engine/internal/overhaul/score/run_test.go +156 -1
  107. package/engine/internal/overhaul/snapshot/run.go +78 -21
  108. package/engine/internal/overhaul/snapshot/run_test.go +344 -8
  109. package/engine/internal/parallel/cli.go +33 -20
  110. package/engine/internal/parallel/cli_test.go +59 -0
  111. package/engine/internal/parallel/git.go +39 -1
  112. package/engine/internal/parallel/ops.go +101 -11
  113. package/engine/internal/parallel/ops_test.go +552 -69
  114. package/engine/internal/parallel/parallel_test.go +31 -1
  115. package/engine/internal/parallel/pathdisjoint.go +19 -1
  116. package/engine/internal/parallel/pathdisjoint_test.go +72 -0
  117. package/engine/internal/parallel/select.go +6 -2
  118. package/engine/internal/release/release.go +13 -3
  119. package/engine/internal/release/release_test.go +208 -3
  120. package/engine/internal/rootfacts/facts.go +9 -0
  121. package/engine/internal/rootfacts/facts_test.go +38 -0
  122. package/engine/internal/state/acceptance.go +7 -1
  123. package/engine/internal/state/budgets.go +11 -10
  124. package/engine/internal/state/budgets_test.go +93 -0
  125. package/engine/internal/state/cursor.go +19 -8
  126. package/engine/internal/state/cursor_test.go +120 -0
  127. package/engine/internal/state/lock_unix.go +7 -1
  128. package/engine/internal/state/lock_windows.go +7 -1
  129. package/engine/internal/state/state_test.go +49 -18
  130. package/engine/internal/state/taskgraph.go +18 -4
  131. package/engine/internal/state/taskgraph_test.go +43 -0
  132. package/engine/internal/state/workspaceschema.go +16 -2
  133. package/engine/internal/state/workspaceschema_test.go +34 -0
  134. package/engine/internal/state/write.go +67 -6
  135. package/engine/internal/state/write_test.go +136 -0
  136. package/engine/internal/version/version_test.go +2 -0
  137. package/engine/main.go +8 -1
  138. package/engine/observation_contract_test.go +1 -1
  139. package/engine/root_routing_test.go +23 -1
  140. package/install.sh +132 -12
  141. package/pack/.claude/agents/devrites-spec-reviewer.md +2 -2
  142. package/pack/.claude/skills/devrites-browser-proof/SKILL.md +2 -2
  143. package/pack/.claude/skills/devrites-frontend-craft/reference/design-references.md +18 -18
  144. package/pack/.claude/skills/devrites-frontend-craft/reference/quality-standards.md +6 -4
  145. package/pack/.claude/skills/devrites-interview/SKILL.md +4 -4
  146. package/pack/.claude/skills/devrites-lib/reference/parallel-dispatch.md +1 -1
  147. package/pack/.claude/skills/devrites-lib/reference/standards/afk-hitl.md +9 -1
  148. package/pack/.claude/skills/devrites-lib/reference/standards/agents.md +5 -2
  149. package/pack/.claude/skills/devrites-lib/reference/standards/gates.md +6 -5
  150. package/pack/.claude/skills/devrites-lib/reference/standards/spec-grammar.md +1 -1
  151. package/pack/.claude/skills/devrites-lib/reference/standards/verification-methods.md +3 -3
  152. package/pack/.claude/skills/devrites-lib/reference/standards/windows.md +3 -3
  153. package/pack/.claude/skills/devrites-lib/reference/standards/workflow-artifacts.md +2 -2
  154. package/pack/.claude/skills/devrites-lib/reference/visual-playbooks/outline-template.md +1 -1
  155. package/pack/.claude/skills/devrites-lib/reference/workspace-artifact-schema.md +4 -4
  156. package/pack/.claude/skills/devrites-ux-shape/SKILL.md +11 -12
  157. package/pack/.claude/skills/devrites-ux-shape/reference/visual-direction-probe.md +3 -1
  158. package/pack/.claude/skills/overhaul/SKILL.md +1 -1
  159. package/pack/.claude/skills/overhaul/references/orchestration.md +5 -3
  160. package/pack/.claude/skills/overhaul/references/records.md +39 -0
  161. package/pack/.claude/skills/overhaul/references/scoring.md +14 -4
  162. package/pack/.claude/skills/rite/reference/menu.md +1 -1
  163. package/pack/.claude/skills/rite-adopt/SKILL.md +8 -2
  164. package/pack/.claude/skills/rite-autocomplete/SKILL.md +11 -6
  165. package/pack/.claude/skills/rite-autocomplete/reference/decision-policy.md +3 -2
  166. package/pack/.claude/skills/rite-autocomplete/reference/loop.md +1 -1
  167. package/pack/.claude/skills/rite-autocomplete/reference/stop-conditions.md +6 -3
  168. package/pack/.claude/skills/rite-build/SKILL.md +2 -1
  169. package/pack/.claude/skills/rite-build/reference/afk-discipline.md +1 -1
  170. package/pack/.claude/skills/rite-build/reference/checkpoint-protocol.md +1 -1
  171. package/pack/.claude/skills/rite-build/reference/checkpoint.md +5 -0
  172. package/pack/.claude/skills/rite-build/reference/parallel-batch.md +2 -2
  173. package/pack/.claude/skills/rite-build/reference/wright-dispatch.md +6 -3
  174. package/pack/.claude/skills/rite-clarify/SKILL.md +5 -4
  175. package/pack/.claude/skills/rite-clarify/reference/anti-patterns.md +2 -2
  176. package/pack/.claude/skills/rite-clarify/reference/decision-coverage.md +3 -2
  177. package/pack/.claude/skills/rite-converge/SKILL.md +2 -0
  178. package/pack/.claude/skills/rite-customize/SKILL.md +6 -4
  179. package/pack/.claude/skills/rite-define/SKILL.md +2 -0
  180. package/pack/.claude/skills/rite-define/reference/gates.md +8 -7
  181. package/pack/.claude/skills/rite-explain/SKILL.md +1 -1
  182. package/pack/.claude/skills/rite-explain/reference/intake.md +1 -1
  183. package/pack/.claude/skills/rite-fast/SKILL.md +1 -1
  184. package/pack/.claude/skills/rite-plan/SKILL.md +4 -3
  185. package/pack/.claude/skills/rite-plan/reference/replan-and-repair.md +4 -4
  186. package/pack/.claude/skills/rite-polish/reference/anti-ai-slop.md +1 -1
  187. package/pack/.claude/skills/rite-prove/reference/browser-proof.md +5 -5
  188. package/pack/.claude/skills/rite-resolve/SKILL.md +3 -3
  189. package/pack/.claude/skills/rite-seal/SKILL.md +4 -3
  190. package/pack/.claude/skills/rite-seal/reference/phase-contract.md +3 -2
  191. package/pack/.claude/skills/rite-seal/reference/seal-template.md +2 -0
  192. package/pack/.claude/skills/rite-ship/SKILL.md +4 -2
  193. package/pack/.claude/skills/rite-ship/reference/git-ship.md +8 -2
  194. package/pack/.claude/skills/rite-ship/reference/ship-template.md +2 -1
  195. package/pack/.claude/skills/rite-spec/SKILL.md +2 -2
  196. package/pack/.claude/skills/rite-spec/reference/spec-checklists.md +1 -1
  197. package/pack/.claude/skills/rite-spec/reference/spec-template.md +7 -3
  198. package/pack/.claude/skills/rite-spec/reference/state-workspace.md +2 -0
  199. package/pack/.claude/skills/rite-temper/SKILL.md +12 -9
  200. package/pack/.claude/skills/rite-temper/reference/scope-modes.md +1 -1
  201. package/pack/.claude/skills/rite-temper/reference/significance.md +10 -3
  202. package/pack/.claude/skills/rite-temper/reference/strategy-template.md +13 -2
  203. package/pack/.claude/skills/rite-vet/SKILL.md +4 -3
  204. package/pack/.claude/skills/rite-vet/reference/artifacts.md +1 -1
  205. package/pack/.claude/workflows/devrites-readonly-review.js +5 -4
  206. package/pack/generated/claude/agents/devrites-spec-reviewer.md +2 -2
  207. package/pack/generated/claude/skills/devrites-browser-proof/SKILL.md +2 -2
  208. package/pack/generated/claude/skills/devrites-frontend-craft/reference/design-references.md +18 -18
  209. package/pack/generated/claude/skills/devrites-frontend-craft/reference/quality-standards.md +6 -4
  210. package/pack/generated/claude/skills/devrites-interview/SKILL.md +4 -4
  211. package/pack/generated/claude/skills/devrites-lib/reference/parallel-dispatch.md +1 -1
  212. package/pack/generated/claude/skills/devrites-lib/reference/standards/afk-hitl.md +9 -1
  213. package/pack/generated/claude/skills/devrites-lib/reference/standards/agents.md +5 -2
  214. package/pack/generated/claude/skills/devrites-lib/reference/standards/gates.md +6 -5
  215. package/pack/generated/claude/skills/devrites-lib/reference/standards/spec-grammar.md +1 -1
  216. package/pack/generated/claude/skills/devrites-lib/reference/standards/verification-methods.md +3 -3
  217. package/pack/generated/claude/skills/devrites-lib/reference/standards/windows.md +3 -3
  218. package/pack/generated/claude/skills/devrites-lib/reference/standards/workflow-artifacts.md +2 -2
  219. package/pack/generated/claude/skills/devrites-lib/reference/visual-playbooks/outline-template.md +1 -1
  220. package/pack/generated/claude/skills/devrites-lib/reference/workspace-artifact-schema.md +4 -4
  221. package/pack/generated/claude/skills/devrites-ux-shape/SKILL.md +11 -12
  222. package/pack/generated/claude/skills/devrites-ux-shape/reference/visual-direction-probe.md +3 -1
  223. package/pack/generated/claude/skills/overhaul/SKILL.md +1 -1
  224. package/pack/generated/claude/skills/overhaul/references/orchestration.md +5 -3
  225. package/pack/generated/claude/skills/overhaul/references/records.md +39 -0
  226. package/pack/generated/claude/skills/overhaul/references/scoring.md +14 -4
  227. package/pack/generated/claude/skills/rite/reference/menu.md +1 -1
  228. package/pack/generated/claude/skills/rite-adopt/SKILL.md +8 -2
  229. package/pack/generated/claude/skills/rite-autocomplete/SKILL.md +11 -6
  230. package/pack/generated/claude/skills/rite-autocomplete/reference/decision-policy.md +3 -2
  231. package/pack/generated/claude/skills/rite-autocomplete/reference/loop.md +1 -1
  232. package/pack/generated/claude/skills/rite-autocomplete/reference/stop-conditions.md +6 -3
  233. package/pack/generated/claude/skills/rite-build/SKILL.md +2 -1
  234. package/pack/generated/claude/skills/rite-build/reference/afk-discipline.md +1 -1
  235. package/pack/generated/claude/skills/rite-build/reference/checkpoint-protocol.md +1 -1
  236. package/pack/generated/claude/skills/rite-build/reference/checkpoint.md +5 -0
  237. package/pack/generated/claude/skills/rite-build/reference/parallel-batch.md +2 -2
  238. package/pack/generated/claude/skills/rite-build/reference/wright-dispatch.md +6 -3
  239. package/pack/generated/claude/skills/rite-clarify/SKILL.md +5 -4
  240. package/pack/generated/claude/skills/rite-clarify/reference/anti-patterns.md +2 -2
  241. package/pack/generated/claude/skills/rite-clarify/reference/decision-coverage.md +3 -2
  242. package/pack/generated/claude/skills/rite-converge/SKILL.md +2 -0
  243. package/pack/generated/claude/skills/rite-customize/SKILL.md +6 -4
  244. package/pack/generated/claude/skills/rite-define/SKILL.md +2 -0
  245. package/pack/generated/claude/skills/rite-define/reference/gates.md +8 -7
  246. package/pack/generated/claude/skills/rite-explain/SKILL.md +1 -1
  247. package/pack/generated/claude/skills/rite-explain/reference/intake.md +1 -1
  248. package/pack/generated/claude/skills/rite-fast/SKILL.md +1 -1
  249. package/pack/generated/claude/skills/rite-plan/SKILL.md +4 -3
  250. package/pack/generated/claude/skills/rite-plan/reference/replan-and-repair.md +4 -4
  251. package/pack/generated/claude/skills/rite-polish/reference/anti-ai-slop.md +1 -1
  252. package/pack/generated/claude/skills/rite-prove/reference/browser-proof.md +5 -5
  253. package/pack/generated/claude/skills/rite-resolve/SKILL.md +3 -3
  254. package/pack/generated/claude/skills/rite-seal/SKILL.md +4 -3
  255. package/pack/generated/claude/skills/rite-seal/reference/phase-contract.md +3 -2
  256. package/pack/generated/claude/skills/rite-seal/reference/seal-template.md +2 -0
  257. package/pack/generated/claude/skills/rite-ship/SKILL.md +4 -2
  258. package/pack/generated/claude/skills/rite-ship/reference/git-ship.md +8 -2
  259. package/pack/generated/claude/skills/rite-ship/reference/ship-template.md +2 -1
  260. package/pack/generated/claude/skills/rite-spec/SKILL.md +2 -2
  261. package/pack/generated/claude/skills/rite-spec/reference/spec-checklists.md +1 -1
  262. package/pack/generated/claude/skills/rite-spec/reference/spec-template.md +7 -3
  263. package/pack/generated/claude/skills/rite-spec/reference/state-workspace.md +2 -0
  264. package/pack/generated/claude/skills/rite-temper/SKILL.md +12 -9
  265. package/pack/generated/claude/skills/rite-temper/reference/scope-modes.md +1 -1
  266. package/pack/generated/claude/skills/rite-temper/reference/significance.md +10 -3
  267. package/pack/generated/claude/skills/rite-temper/reference/strategy-template.md +13 -2
  268. package/pack/generated/claude/skills/rite-vet/SKILL.md +4 -3
  269. package/pack/generated/claude/skills/rite-vet/reference/artifacts.md +1 -1
  270. package/pack/generated/claude/workflows/devrites-readonly-review.js +5 -4
  271. package/pack/generated/codex/AGENTS.md +1 -1
  272. package/pack/generated/codex/agents/devrites-spec-reviewer.toml +2 -2
  273. package/pack/generated/codex/skills/devrites-browser-proof/SKILL.md +2 -2
  274. package/pack/generated/codex/skills/devrites-frontend-craft/reference/design-references.md +18 -18
  275. package/pack/generated/codex/skills/devrites-frontend-craft/reference/quality-standards.md +6 -4
  276. package/pack/generated/codex/skills/devrites-interview/SKILL.md +4 -4
  277. package/pack/generated/codex/skills/devrites-lib/reference/parallel-dispatch.md +1 -1
  278. package/pack/generated/codex/skills/devrites-lib/reference/standards/afk-hitl.md +9 -1
  279. package/pack/generated/codex/skills/devrites-lib/reference/standards/agents.md +5 -2
  280. package/pack/generated/codex/skills/devrites-lib/reference/standards/gates.md +6 -5
  281. package/pack/generated/codex/skills/devrites-lib/reference/standards/spec-grammar.md +1 -1
  282. package/pack/generated/codex/skills/devrites-lib/reference/standards/verification-methods.md +3 -3
  283. package/pack/generated/codex/skills/devrites-lib/reference/standards/windows.md +3 -3
  284. package/pack/generated/codex/skills/devrites-lib/reference/standards/workflow-artifacts.md +2 -2
  285. package/pack/generated/codex/skills/devrites-lib/reference/visual-playbooks/outline-template.md +1 -1
  286. package/pack/generated/codex/skills/devrites-lib/reference/workspace-artifact-schema.md +4 -4
  287. package/pack/generated/codex/skills/devrites-ux-shape/SKILL.md +11 -12
  288. package/pack/generated/codex/skills/devrites-ux-shape/reference/visual-direction-probe.md +3 -1
  289. package/pack/generated/codex/skills/overhaul/SKILL.md +1 -1
  290. package/pack/generated/codex/skills/overhaul/references/orchestration.md +5 -3
  291. package/pack/generated/codex/skills/overhaul/references/records.md +39 -0
  292. package/pack/generated/codex/skills/overhaul/references/scoring.md +14 -4
  293. package/pack/generated/codex/skills/rite/reference/menu.md +1 -1
  294. package/pack/generated/codex/skills/rite-adopt/SKILL.md +8 -2
  295. package/pack/generated/codex/skills/rite-autocomplete/SKILL.md +11 -6
  296. package/pack/generated/codex/skills/rite-autocomplete/reference/decision-policy.md +3 -2
  297. package/pack/generated/codex/skills/rite-autocomplete/reference/loop.md +1 -1
  298. package/pack/generated/codex/skills/rite-autocomplete/reference/stop-conditions.md +6 -3
  299. package/pack/generated/codex/skills/rite-build/SKILL.md +2 -1
  300. package/pack/generated/codex/skills/rite-build/reference/afk-discipline.md +1 -1
  301. package/pack/generated/codex/skills/rite-build/reference/checkpoint-protocol.md +1 -1
  302. package/pack/generated/codex/skills/rite-build/reference/checkpoint.md +5 -0
  303. package/pack/generated/codex/skills/rite-build/reference/parallel-batch.md +2 -2
  304. package/pack/generated/codex/skills/rite-build/reference/wright-dispatch.md +6 -3
  305. package/pack/generated/codex/skills/rite-clarify/SKILL.md +5 -4
  306. package/pack/generated/codex/skills/rite-clarify/reference/anti-patterns.md +2 -2
  307. package/pack/generated/codex/skills/rite-clarify/reference/decision-coverage.md +3 -2
  308. package/pack/generated/codex/skills/rite-converge/SKILL.md +2 -0
  309. package/pack/generated/codex/skills/rite-customize/SKILL.md +6 -4
  310. package/pack/generated/codex/skills/rite-define/SKILL.md +2 -0
  311. package/pack/generated/codex/skills/rite-define/reference/gates.md +8 -7
  312. package/pack/generated/codex/skills/rite-explain/SKILL.md +1 -1
  313. package/pack/generated/codex/skills/rite-explain/reference/intake.md +1 -1
  314. package/pack/generated/codex/skills/rite-fast/SKILL.md +1 -1
  315. package/pack/generated/codex/skills/rite-plan/SKILL.md +4 -3
  316. package/pack/generated/codex/skills/rite-plan/reference/replan-and-repair.md +4 -4
  317. package/pack/generated/codex/skills/rite-polish/reference/anti-ai-slop.md +1 -1
  318. package/pack/generated/codex/skills/rite-prove/reference/browser-proof.md +5 -5
  319. package/pack/generated/codex/skills/rite-resolve/SKILL.md +3 -3
  320. package/pack/generated/codex/skills/rite-seal/SKILL.md +4 -3
  321. package/pack/generated/codex/skills/rite-seal/reference/phase-contract.md +3 -2
  322. package/pack/generated/codex/skills/rite-seal/reference/seal-template.md +2 -0
  323. package/pack/generated/codex/skills/rite-ship/SKILL.md +4 -2
  324. package/pack/generated/codex/skills/rite-ship/reference/git-ship.md +8 -2
  325. package/pack/generated/codex/skills/rite-ship/reference/ship-template.md +2 -1
  326. package/pack/generated/codex/skills/rite-spec/SKILL.md +2 -2
  327. package/pack/generated/codex/skills/rite-spec/reference/spec-checklists.md +1 -1
  328. package/pack/generated/codex/skills/rite-spec/reference/spec-template.md +7 -3
  329. package/pack/generated/codex/skills/rite-spec/reference/state-workspace.md +2 -0
  330. package/pack/generated/codex/skills/rite-temper/SKILL.md +12 -9
  331. package/pack/generated/codex/skills/rite-temper/reference/scope-modes.md +1 -1
  332. package/pack/generated/codex/skills/rite-temper/reference/significance.md +10 -3
  333. package/pack/generated/codex/skills/rite-temper/reference/strategy-template.md +13 -2
  334. package/pack/generated/codex/skills/rite-vet/SKILL.md +4 -3
  335. package/pack/generated/codex/skills/rite-vet/reference/artifacts.md +1 -1
  336. package/pack/generated/devin/AGENTS.md +1 -1
  337. package/pack/generated/devin/agents/devrites-spec-reviewer.md +2 -2
  338. package/pack/generated/devin/skills/devrites-browser-proof/SKILL.md +2 -2
  339. package/pack/generated/devin/skills/devrites-frontend-craft/reference/design-references.md +18 -18
  340. package/pack/generated/devin/skills/devrites-frontend-craft/reference/quality-standards.md +6 -4
  341. package/pack/generated/devin/skills/devrites-interview/SKILL.md +4 -4
  342. package/pack/generated/devin/skills/devrites-lib/reference/parallel-dispatch.md +1 -1
  343. package/pack/generated/devin/skills/devrites-lib/reference/standards/afk-hitl.md +9 -1
  344. package/pack/generated/devin/skills/devrites-lib/reference/standards/agents.md +5 -2
  345. package/pack/generated/devin/skills/devrites-lib/reference/standards/gates.md +6 -5
  346. package/pack/generated/devin/skills/devrites-lib/reference/standards/spec-grammar.md +1 -1
  347. package/pack/generated/devin/skills/devrites-lib/reference/standards/verification-methods.md +3 -3
  348. package/pack/generated/devin/skills/devrites-lib/reference/standards/windows.md +3 -3
  349. package/pack/generated/devin/skills/devrites-lib/reference/standards/workflow-artifacts.md +2 -2
  350. package/pack/generated/devin/skills/devrites-lib/reference/visual-playbooks/outline-template.md +1 -1
  351. package/pack/generated/devin/skills/devrites-lib/reference/workspace-artifact-schema.md +4 -4
  352. package/pack/generated/devin/skills/devrites-ux-shape/SKILL.md +11 -12
  353. package/pack/generated/devin/skills/devrites-ux-shape/reference/visual-direction-probe.md +3 -1
  354. package/pack/generated/devin/skills/overhaul/SKILL.md +1 -1
  355. package/pack/generated/devin/skills/overhaul/references/orchestration.md +5 -3
  356. package/pack/generated/devin/skills/overhaul/references/records.md +39 -0
  357. package/pack/generated/devin/skills/overhaul/references/scoring.md +14 -4
  358. package/pack/generated/devin/skills/rite/reference/menu.md +1 -1
  359. package/pack/generated/devin/skills/rite-adopt/SKILL.md +8 -2
  360. package/pack/generated/devin/skills/rite-autocomplete/SKILL.md +11 -6
  361. package/pack/generated/devin/skills/rite-autocomplete/reference/decision-policy.md +3 -2
  362. package/pack/generated/devin/skills/rite-autocomplete/reference/loop.md +1 -1
  363. package/pack/generated/devin/skills/rite-autocomplete/reference/stop-conditions.md +6 -3
  364. package/pack/generated/devin/skills/rite-build/SKILL.md +2 -1
  365. package/pack/generated/devin/skills/rite-build/reference/afk-discipline.md +1 -1
  366. package/pack/generated/devin/skills/rite-build/reference/checkpoint-protocol.md +1 -1
  367. package/pack/generated/devin/skills/rite-build/reference/checkpoint.md +5 -0
  368. package/pack/generated/devin/skills/rite-build/reference/parallel-batch.md +2 -2
  369. package/pack/generated/devin/skills/rite-build/reference/wright-dispatch.md +6 -3
  370. package/pack/generated/devin/skills/rite-clarify/SKILL.md +5 -4
  371. package/pack/generated/devin/skills/rite-clarify/reference/anti-patterns.md +2 -2
  372. package/pack/generated/devin/skills/rite-clarify/reference/decision-coverage.md +3 -2
  373. package/pack/generated/devin/skills/rite-converge/SKILL.md +2 -0
  374. package/pack/generated/devin/skills/rite-customize/SKILL.md +6 -4
  375. package/pack/generated/devin/skills/rite-define/SKILL.md +2 -0
  376. package/pack/generated/devin/skills/rite-define/reference/gates.md +8 -7
  377. package/pack/generated/devin/skills/rite-explain/SKILL.md +1 -1
  378. package/pack/generated/devin/skills/rite-explain/reference/intake.md +1 -1
  379. package/pack/generated/devin/skills/rite-fast/SKILL.md +1 -1
  380. package/pack/generated/devin/skills/rite-plan/SKILL.md +4 -3
  381. package/pack/generated/devin/skills/rite-plan/reference/replan-and-repair.md +4 -4
  382. package/pack/generated/devin/skills/rite-polish/reference/anti-ai-slop.md +1 -1
  383. package/pack/generated/devin/skills/rite-prove/reference/browser-proof.md +5 -5
  384. package/pack/generated/devin/skills/rite-resolve/SKILL.md +3 -3
  385. package/pack/generated/devin/skills/rite-seal/SKILL.md +4 -3
  386. package/pack/generated/devin/skills/rite-seal/reference/phase-contract.md +3 -2
  387. package/pack/generated/devin/skills/rite-seal/reference/seal-template.md +2 -0
  388. package/pack/generated/devin/skills/rite-ship/SKILL.md +4 -2
  389. package/pack/generated/devin/skills/rite-ship/reference/git-ship.md +8 -2
  390. package/pack/generated/devin/skills/rite-ship/reference/ship-template.md +2 -1
  391. package/pack/generated/devin/skills/rite-spec/SKILL.md +2 -2
  392. package/pack/generated/devin/skills/rite-spec/reference/spec-checklists.md +1 -1
  393. package/pack/generated/devin/skills/rite-spec/reference/spec-template.md +7 -3
  394. package/pack/generated/devin/skills/rite-spec/reference/state-workspace.md +2 -0
  395. package/pack/generated/devin/skills/rite-temper/SKILL.md +12 -9
  396. package/pack/generated/devin/skills/rite-temper/reference/scope-modes.md +1 -1
  397. package/pack/generated/devin/skills/rite-temper/reference/significance.md +10 -3
  398. package/pack/generated/devin/skills/rite-temper/reference/strategy-template.md +13 -2
  399. package/pack/generated/devin/skills/rite-vet/SKILL.md +4 -3
  400. package/pack/generated/devin/skills/rite-vet/reference/artifacts.md +1 -1
  401. package/pack/generated/omp/agents/devrites-spec-reviewer.md +2 -2
  402. package/pack/generated/omp/commands/rite-define.md +1 -1
  403. package/pack/generated/omp/commands/rite-handoff.md +1 -1
  404. package/pack/generated/omp/commands/rite-plan.md +1 -1
  405. package/pack/generated/omp/commands/rite-pressure-test.md +1 -1
  406. package/pack/generated/omp/commands/rite-quick.md +1 -1
  407. package/pack/generated/omp/commands/rite-status.md +1 -1
  408. package/pack/generated/omp/commands/rite-temper.md +1 -1
  409. package/pack/generated/omp/commands/rite-zoom-out.md +1 -1
  410. package/pack/generated/omp/skills/devrites-browser-proof/SKILL.md +2 -2
  411. package/pack/generated/omp/skills/devrites-frontend-craft/reference/design-references.md +18 -18
  412. package/pack/generated/omp/skills/devrites-frontend-craft/reference/quality-standards.md +6 -4
  413. package/pack/generated/omp/skills/devrites-interview/SKILL.md +4 -4
  414. package/pack/generated/omp/skills/devrites-lib/reference/parallel-dispatch.md +1 -1
  415. package/pack/generated/omp/skills/devrites-lib/reference/standards/afk-hitl.md +9 -1
  416. package/pack/generated/omp/skills/devrites-lib/reference/standards/agents.md +5 -2
  417. package/pack/generated/omp/skills/devrites-lib/reference/standards/gates.md +6 -5
  418. package/pack/generated/omp/skills/devrites-lib/reference/standards/spec-grammar.md +1 -1
  419. package/pack/generated/omp/skills/devrites-lib/reference/standards/verification-methods.md +3 -3
  420. package/pack/generated/omp/skills/devrites-lib/reference/standards/windows.md +3 -3
  421. package/pack/generated/omp/skills/devrites-lib/reference/standards/workflow-artifacts.md +2 -2
  422. package/pack/generated/omp/skills/devrites-lib/reference/visual-playbooks/outline-template.md +1 -1
  423. package/pack/generated/omp/skills/devrites-lib/reference/workspace-artifact-schema.md +4 -4
  424. package/pack/generated/omp/skills/devrites-ux-shape/SKILL.md +11 -12
  425. package/pack/generated/omp/skills/devrites-ux-shape/reference/visual-direction-probe.md +3 -1
  426. package/pack/generated/omp/skills/overhaul/SKILL.md +1 -1
  427. package/pack/generated/omp/skills/overhaul/references/orchestration.md +5 -3
  428. package/pack/generated/omp/skills/overhaul/references/records.md +39 -0
  429. package/pack/generated/omp/skills/overhaul/references/scoring.md +14 -4
  430. package/pack/generated/omp/skills/rite/reference/menu.md +1 -1
  431. package/pack/generated/omp/skills/rite-adopt/SKILL.md +8 -2
  432. package/pack/generated/omp/skills/rite-autocomplete/SKILL.md +11 -6
  433. package/pack/generated/omp/skills/rite-autocomplete/reference/decision-policy.md +3 -2
  434. package/pack/generated/omp/skills/rite-autocomplete/reference/loop.md +1 -1
  435. package/pack/generated/omp/skills/rite-autocomplete/reference/stop-conditions.md +6 -3
  436. package/pack/generated/omp/skills/rite-build/SKILL.md +2 -1
  437. package/pack/generated/omp/skills/rite-build/reference/afk-discipline.md +1 -1
  438. package/pack/generated/omp/skills/rite-build/reference/checkpoint-protocol.md +1 -1
  439. package/pack/generated/omp/skills/rite-build/reference/checkpoint.md +5 -0
  440. package/pack/generated/omp/skills/rite-build/reference/parallel-batch.md +2 -2
  441. package/pack/generated/omp/skills/rite-build/reference/wright-dispatch.md +6 -3
  442. package/pack/generated/omp/skills/rite-clarify/SKILL.md +5 -4
  443. package/pack/generated/omp/skills/rite-clarify/reference/anti-patterns.md +2 -2
  444. package/pack/generated/omp/skills/rite-clarify/reference/decision-coverage.md +3 -2
  445. package/pack/generated/omp/skills/rite-converge/SKILL.md +2 -0
  446. package/pack/generated/omp/skills/rite-customize/SKILL.md +6 -4
  447. package/pack/generated/omp/skills/rite-define/SKILL.md +2 -0
  448. package/pack/generated/omp/skills/rite-define/reference/gates.md +8 -7
  449. package/pack/generated/omp/skills/rite-explain/SKILL.md +1 -1
  450. package/pack/generated/omp/skills/rite-explain/reference/intake.md +1 -1
  451. package/pack/generated/omp/skills/rite-fast/SKILL.md +1 -1
  452. package/pack/generated/omp/skills/rite-plan/SKILL.md +4 -3
  453. package/pack/generated/omp/skills/rite-plan/reference/replan-and-repair.md +4 -4
  454. package/pack/generated/omp/skills/rite-polish/reference/anti-ai-slop.md +1 -1
  455. package/pack/generated/omp/skills/rite-prove/reference/browser-proof.md +5 -5
  456. package/pack/generated/omp/skills/rite-resolve/SKILL.md +3 -3
  457. package/pack/generated/omp/skills/rite-seal/SKILL.md +4 -3
  458. package/pack/generated/omp/skills/rite-seal/reference/phase-contract.md +3 -2
  459. package/pack/generated/omp/skills/rite-seal/reference/seal-template.md +2 -0
  460. package/pack/generated/omp/skills/rite-ship/SKILL.md +4 -2
  461. package/pack/generated/omp/skills/rite-ship/reference/git-ship.md +8 -2
  462. package/pack/generated/omp/skills/rite-ship/reference/ship-template.md +2 -1
  463. package/pack/generated/omp/skills/rite-spec/SKILL.md +2 -2
  464. package/pack/generated/omp/skills/rite-spec/reference/spec-checklists.md +1 -1
  465. package/pack/generated/omp/skills/rite-spec/reference/spec-template.md +7 -3
  466. package/pack/generated/omp/skills/rite-spec/reference/state-workspace.md +2 -0
  467. package/pack/generated/omp/skills/rite-temper/SKILL.md +12 -9
  468. package/pack/generated/omp/skills/rite-temper/reference/scope-modes.md +1 -1
  469. package/pack/generated/omp/skills/rite-temper/reference/significance.md +10 -3
  470. package/pack/generated/omp/skills/rite-temper/reference/strategy-template.md +13 -2
  471. package/pack/generated/omp/skills/rite-vet/SKILL.md +4 -3
  472. package/pack/generated/omp/skills/rite-vet/reference/artifacts.md +1 -1
  473. package/pack/generated/pi/AGENTS.md +1 -1
  474. package/pack/generated/pi/agents/devrites-spec-reviewer.md +2 -2
  475. package/pack/generated/pi/prompts/rite-define.md +1 -1
  476. package/pack/generated/pi/prompts/rite-handoff.md +1 -1
  477. package/pack/generated/pi/prompts/rite-plan.md +1 -1
  478. package/pack/generated/pi/prompts/rite-pressure-test.md +1 -1
  479. package/pack/generated/pi/prompts/rite-quick.md +1 -1
  480. package/pack/generated/pi/prompts/rite-status.md +1 -1
  481. package/pack/generated/pi/prompts/rite-temper.md +1 -1
  482. package/pack/generated/pi/prompts/rite-zoom-out.md +1 -1
  483. package/pack/generated/pi/skills/devrites-browser-proof/SKILL.md +2 -2
  484. package/pack/generated/pi/skills/devrites-frontend-craft/reference/design-references.md +18 -18
  485. package/pack/generated/pi/skills/devrites-frontend-craft/reference/quality-standards.md +6 -4
  486. package/pack/generated/pi/skills/devrites-interview/SKILL.md +4 -4
  487. package/pack/generated/pi/skills/devrites-lib/reference/parallel-dispatch.md +1 -1
  488. package/pack/generated/pi/skills/devrites-lib/reference/standards/afk-hitl.md +9 -1
  489. package/pack/generated/pi/skills/devrites-lib/reference/standards/agents.md +5 -2
  490. package/pack/generated/pi/skills/devrites-lib/reference/standards/gates.md +6 -5
  491. package/pack/generated/pi/skills/devrites-lib/reference/standards/spec-grammar.md +1 -1
  492. package/pack/generated/pi/skills/devrites-lib/reference/standards/verification-methods.md +3 -3
  493. package/pack/generated/pi/skills/devrites-lib/reference/standards/windows.md +3 -3
  494. package/pack/generated/pi/skills/devrites-lib/reference/standards/workflow-artifacts.md +2 -2
  495. package/pack/generated/pi/skills/devrites-lib/reference/visual-playbooks/outline-template.md +1 -1
  496. package/pack/generated/pi/skills/devrites-lib/reference/workspace-artifact-schema.md +4 -4
  497. package/pack/generated/pi/skills/devrites-ux-shape/SKILL.md +11 -12
  498. package/pack/generated/pi/skills/devrites-ux-shape/reference/visual-direction-probe.md +3 -1
  499. package/pack/generated/pi/skills/overhaul/SKILL.md +1 -1
  500. package/pack/generated/pi/skills/overhaul/references/orchestration.md +5 -3
  501. package/pack/generated/pi/skills/overhaul/references/records.md +39 -0
  502. package/pack/generated/pi/skills/overhaul/references/scoring.md +14 -4
  503. package/pack/generated/pi/skills/rite/reference/menu.md +1 -1
  504. package/pack/generated/pi/skills/rite-adopt/SKILL.md +8 -2
  505. package/pack/generated/pi/skills/rite-autocomplete/SKILL.md +11 -6
  506. package/pack/generated/pi/skills/rite-autocomplete/reference/decision-policy.md +3 -2
  507. package/pack/generated/pi/skills/rite-autocomplete/reference/loop.md +1 -1
  508. package/pack/generated/pi/skills/rite-autocomplete/reference/stop-conditions.md +6 -3
  509. package/pack/generated/pi/skills/rite-build/SKILL.md +2 -1
  510. package/pack/generated/pi/skills/rite-build/reference/afk-discipline.md +1 -1
  511. package/pack/generated/pi/skills/rite-build/reference/checkpoint-protocol.md +1 -1
  512. package/pack/generated/pi/skills/rite-build/reference/checkpoint.md +5 -0
  513. package/pack/generated/pi/skills/rite-build/reference/parallel-batch.md +2 -2
  514. package/pack/generated/pi/skills/rite-build/reference/wright-dispatch.md +6 -3
  515. package/pack/generated/pi/skills/rite-clarify/SKILL.md +5 -4
  516. package/pack/generated/pi/skills/rite-clarify/reference/anti-patterns.md +2 -2
  517. package/pack/generated/pi/skills/rite-clarify/reference/decision-coverage.md +3 -2
  518. package/pack/generated/pi/skills/rite-converge/SKILL.md +2 -0
  519. package/pack/generated/pi/skills/rite-customize/SKILL.md +6 -4
  520. package/pack/generated/pi/skills/rite-define/SKILL.md +2 -0
  521. package/pack/generated/pi/skills/rite-define/reference/gates.md +8 -7
  522. package/pack/generated/pi/skills/rite-explain/SKILL.md +1 -1
  523. package/pack/generated/pi/skills/rite-explain/reference/intake.md +1 -1
  524. package/pack/generated/pi/skills/rite-fast/SKILL.md +1 -1
  525. package/pack/generated/pi/skills/rite-plan/SKILL.md +4 -3
  526. package/pack/generated/pi/skills/rite-plan/reference/replan-and-repair.md +4 -4
  527. package/pack/generated/pi/skills/rite-polish/reference/anti-ai-slop.md +1 -1
  528. package/pack/generated/pi/skills/rite-prove/reference/browser-proof.md +5 -5
  529. package/pack/generated/pi/skills/rite-resolve/SKILL.md +3 -3
  530. package/pack/generated/pi/skills/rite-seal/SKILL.md +4 -3
  531. package/pack/generated/pi/skills/rite-seal/reference/phase-contract.md +3 -2
  532. package/pack/generated/pi/skills/rite-seal/reference/seal-template.md +2 -0
  533. package/pack/generated/pi/skills/rite-ship/SKILL.md +4 -2
  534. package/pack/generated/pi/skills/rite-ship/reference/git-ship.md +8 -2
  535. package/pack/generated/pi/skills/rite-ship/reference/ship-template.md +2 -1
  536. package/pack/generated/pi/skills/rite-spec/SKILL.md +2 -2
  537. package/pack/generated/pi/skills/rite-spec/reference/spec-checklists.md +1 -1
  538. package/pack/generated/pi/skills/rite-spec/reference/spec-template.md +7 -3
  539. package/pack/generated/pi/skills/rite-spec/reference/state-workspace.md +2 -0
  540. package/pack/generated/pi/skills/rite-temper/SKILL.md +12 -9
  541. package/pack/generated/pi/skills/rite-temper/reference/scope-modes.md +1 -1
  542. package/pack/generated/pi/skills/rite-temper/reference/significance.md +10 -3
  543. package/pack/generated/pi/skills/rite-temper/reference/strategy-template.md +13 -2
  544. package/pack/generated/pi/skills/rite-vet/SKILL.md +4 -3
  545. package/pack/generated/pi/skills/rite-vet/reference/artifacts.md +1 -1
  546. package/package.json +5 -4
  547. package/scripts/build-host-artifacts.sh +15 -0
  548. package/scripts/codex-generate.sh +1 -1
  549. package/scripts/devin-generate.sh +1 -1
  550. package/scripts/expand-includes.py +46 -0
  551. package/scripts/install-lib.sh +42 -7
  552. package/scripts/omp-generate.sh +11 -0
  553. package/scripts/pi-generate.sh +12 -1
  554. package/update.sh +1 -2
  555. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/README.md +0 -7
  556. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/architecture.md +0 -3
  557. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/assumptions.md +0 -3
  558. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/brief.md +0 -3
  559. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/decision-coverage.md +0 -3
  560. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/decisions.md +0 -4
  561. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/eng-review.md +0 -3
  562. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/gates.md +0 -4
  563. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/plan.md +0 -5
  564. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/questions.md +0 -3
  565. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/spec.md +0 -6
  566. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/state.md +0 -8
  567. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/tasks.md +0 -1
  568. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/test-plan.md +0 -3
  569. package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/traceability.md +0 -3
  570. package/engine/testdata/fixtures/basic/devrites-root/work/search-ranking/README.md +0 -7
  571. package/engine/testdata/fixtures/basic/devrites-root/work/search-ranking/assumptions.md +0 -3
  572. package/engine/testdata/fixtures/basic/devrites-root/work/search-ranking/brief.md +0 -3
  573. package/engine/testdata/fixtures/basic/devrites-root/work/search-ranking/decisions.md +0 -3
  574. package/engine/testdata/fixtures/basic/devrites-root/work/search-ranking/questions.md +0 -3
  575. package/engine/testdata/fixtures/basic/devrites-root/work/search-ranking/spec.md +0 -6
  576. package/engine/testdata/fixtures/basic/devrites-root/work/search-ranking/state.md +0 -3
  577. package/engine/testdata/golden/TestParityCloseOut/active_pointed_elsewhere.golden +0 -2
  578. package/engine/testdata/golden/TestParityCloseOut/active_slug_cleared.golden +0 -2
  579. package/engine/testdata/golden/TestParityCloseOut/archive_clobber.golden +0 -1
  580. package/engine/testdata/golden/TestParityCloseOut/missing_slug.golden +0 -1
  581. package/engine/testdata/golden/TestParityCloseOut/missing_workspace.golden +0 -1
  582. package/engine/testdata/golden/TestParityLearnings/add.golden +0 -2
  583. package/engine/testdata/golden/TestParityLearnings/list.golden +0 -5
  584. package/engine/testdata/golden/TestParityLearnings/mine-no-archive.golden +0 -2
  585. package/engine/testdata/golden/TestParityLearnings/mine.golden +0 -5
  586. package/engine/testdata/golden/TestParityLearnings/nudge.golden +0 -2
  587. package/engine/testdata/golden/TestParityLearnings/unknown.golden +0 -1
  588. package/engine/testdata/golden/TestParityPackageExistence/ghost-workspace.golden +0 -1
  589. package/engine/testdata/golden/TestParityPackageExistence/no-manifest.golden +0 -1
  590. package/engine/testdata/golden/TestParityPackageExistence/not-git.golden +0 -1
  591. package/engine/testdata/golden/TestParityPackageExistence/undeclared.golden +0 -1
  592. package/engine/testdata/golden/TestParityPreamble/afk/a.golden +0 -14
  593. package/engine/testdata/golden/TestParityPreamble/hitl/active.golden +0 -18
  594. package/engine/testdata/golden/TestParityPreamble/hitl/bare.golden +0 -10
  595. package/engine/testdata/golden/TestParityPreamble/hitl/full.golden +0 -18
  596. package/engine/testdata/golden/TestParityPreamble/hitl/ghost.golden +0 -2
  597. package/engine/testdata/golden/TestParityPreamble/hitl/nonl.golden +0 -11
  598. package/engine/testdata/golden/TestParityPreamble/hitl/openend.golden +0 -13
  599. package/engine/testdata/golden/TestParityProgress/arg=allbuilt.golden +0 -4
  600. package/engine/testdata/golden/TestParityProgress/arg=done.golden +0 -3
  601. package/engine/testdata/golden/TestParityProgress/arg=ghost.golden +0 -1
  602. package/engine/testdata/golden/TestParityProgress/arg=mid.golden +0 -4
  603. package/engine/testdata/golden/TestParityProgress/arg=nophase.golden +0 -3
  604. package/engine/testdata/golden/TestParityProgress/arg=noslice.golden +0 -3
  605. package/engine/testdata/golden/TestParityProgress/arg=plan.golden +0 -4
  606. package/engine/testdata/golden/TestParityProgress/arg=seal.golden +0 -3
  607. package/engine/testdata/golden/TestParityResolve/answer/questions.md.golden +0 -9
  608. package/engine/testdata/golden/TestParityResolve/answer/state.md.golden +0 -7
  609. package/engine/testdata/golden/TestParityResolve/answer.golden +0 -4
  610. package/engine/testdata/golden/TestParityResolve/batch/questions.md.golden +0 -9
  611. package/engine/testdata/golden/TestParityResolve/batch-unterminated/questions.md.golden +0 -9
  612. package/engine/testdata/golden/TestParityResolve/batch-unterminated.golden +0 -2
  613. package/engine/testdata/golden/TestParityResolve/batch.golden +0 -3
  614. package/engine/testdata/golden/TestParityResolve/drop/questions.md.golden +0 -9
  615. package/engine/testdata/golden/TestParityResolve/drop/state.md.golden +0 -9
  616. package/engine/testdata/golden/TestParityResolve/drop.golden +0 -4
  617. package/engine/testdata/golden/TestParityResolve/missing-answer.golden +0 -1
  618. package/engine/testdata/golden/TestParityResolve/no-workspace.golden +0 -1
  619. package/engine/testdata/golden/TestParityResolve/not-found.golden +0 -1
  620. package/engine/testdata/golden/TestParityResolve/not-open.golden +0 -1
  621. package/engine/testdata/golden/TestStatusLiveWorkspace.golden +0 -10
  622. package/engine/testdata/golden/status/auth-tokens.txt +0 -9
  623. package/engine/testdata/golden/status/search-ranking.txt +0 -9
  624. package/engine/testdata/visual/open-visual-smoke.html +0 -675
  625. package/engine/testdata/visual/open-visual-smoke.outline.md +0 -54
  626. package/engine/tests/adr_0003_gate_exit_code_test.go +0 -32
  627. package/engine/tests/adr_0004_required_by_phase_test.go +0 -54
  628. package/engine/tests/adr_0011_define_plan_test.go +0 -32
  629. package/engine/tests/adr_0027_readiness_binding_test.go +0 -107
  630. package/engine/tests/cli_test.go +0 -126
  631. package/engine/tests/gate_test.go +0 -669
  632. package/engine/tests/meta_test.go +0 -37
  633. package/engine/tests/parity_closeout_test.go +0 -105
  634. package/engine/tests/parity_githelpers_test.go +0 -41
  635. package/engine/tests/parity_resolve_test.go +0 -136
  636. package/engine/tests/parity_test.go +0 -86
  637. package/engine/tests/workspace_observation_migration_test.go +0 -1069
@@ -11,6 +11,8 @@ import (
11
11
  "runtime"
12
12
  "slices"
13
13
  "strings"
14
+
15
+ "strconv"
14
16
  "testing"
15
17
  "time"
16
18
 
@@ -355,6 +357,7 @@ func TestGeneratedPayloadInstallsVerbatim(t *testing.T) {
355
357
  }
356
358
 
357
359
  func TestInstallBinaryUsesEngineHandoff(t *testing.T) {
360
+ t.Setenv("DEVRITES_NO_BINARY", "")
358
361
  payload := testPayload(t)
359
362
  target := t.TempDir()
360
363
  binDir := t.TempDir()
@@ -398,6 +401,7 @@ func TestAcquireBinaryRequiresCompatibleEngineHandoff(t *testing.T) {
398
401
  }
399
402
 
400
403
  func TestInstallBinaryRejectsIncompatibleEngineHandoff(t *testing.T) {
404
+ t.Setenv("DEVRITES_NO_BINARY", "")
401
405
  engine := buildVersionBinary(t, "1.2.2")
402
406
  t.Setenv("DEVRITES_ENGINE_CLI", engine)
403
407
  t.Setenv("DEVRITES_BIN_DIR", t.TempDir())
@@ -410,6 +414,7 @@ func TestInstallBinaryRejectsIncompatibleEngineHandoff(t *testing.T) {
410
414
  }
411
415
 
412
416
  func TestInstallBinaryRejectsMissingConfiguredEngineHandoff(t *testing.T) {
417
+ t.Setenv("DEVRITES_NO_BINARY", "")
413
418
  handoff := filepath.Join(t.TempDir(), "missing-devrites-engine")
414
419
  t.Setenv("DEVRITES_ENGINE_CLI", handoff)
415
420
  t.Setenv("DEVRITES_BIN_DIR", t.TempDir())
@@ -433,6 +438,7 @@ func TestAcquireBinaryRejectsMissingEngineHandoff(t *testing.T) {
433
438
  }
434
439
 
435
440
  func TestInstallBinaryFailsWhenPreparedUpdateCannotBeWritten(t *testing.T) {
441
+ t.Setenv("DEVRITES_NO_BINARY", "")
436
442
  prepared := filepath.Join(t.TempDir(), "devrites-engine")
437
443
  testutil.WriteExecutable(t, prepared, "#!/bin/sh\nif [ \"$1\" = version ]; then echo 1.2.3; fi\n")
438
444
  blocked := filepath.Join(t.TempDir(), "not-a-directory")
@@ -450,6 +456,7 @@ func TestInstallBinaryFailsWhenPreparedUpdateCannotBeWritten(t *testing.T) {
450
456
  }
451
457
 
452
458
  func TestInstallBinaryWithoutBinaryReportsSkip(t *testing.T) {
459
+ t.Setenv("DEVRITES_NO_BINARY", "")
453
460
  var stdout bytes.Buffer
454
461
  opts := DefaultOptions(ModeInstall)
455
462
  opts.WithBinary = false
@@ -466,6 +473,23 @@ func TestInstallBinaryWithoutBinaryReportsSkip(t *testing.T) {
466
473
  }
467
474
  }
468
475
 
476
+ func TestInstallBinaryEnvSkipNamesEnvVar(t *testing.T) {
477
+ t.Setenv("DEVRITES_NO_BINARY", "1")
478
+ var stdout bytes.Buffer
479
+ opts := DefaultOptions(ModeInstall)
480
+ opts.WithBinary = true
481
+ opts.Stdout = &stdout
482
+
483
+ r := runner{opts: opts}
484
+ if err := r.installBinary(); err != nil {
485
+ t.Fatalf("installBinary() error = %v", err)
486
+ }
487
+
488
+ if got, want := stdout.String(), " engine binary: skipped (DEVRITES_NO_BINARY=1).\n"; got != want {
489
+ t.Fatalf("stdout = %q, want %q", got, want)
490
+ }
491
+ }
492
+
469
493
  func TestInstallBinaryDoesNotRequirePATH(t *testing.T) {
470
494
  payload := testPayload(t)
471
495
  target := t.TempDir()
@@ -1100,6 +1124,7 @@ func TestVerifyEngineBinary(t *testing.T) {
1100
1124
  }
1101
1125
 
1102
1126
  func TestInstallBinaryRollsBackVerificationFailure(t *testing.T) {
1127
+ t.Setenv("DEVRITES_NO_BINARY", "")
1103
1128
  if runtime.GOOS == "windows" {
1104
1129
  t.Skip("shell fixture is Unix-only; backup/restore portability is covered separately")
1105
1130
  }
@@ -1311,3 +1336,406 @@ func testSource(t *testing.T, version string) string {
1311
1336
  testutil.WriteFile(t, filepath.Join(root, "package.json"), `{"version":"`+version+`"}`+"\n")
1312
1337
  return root
1313
1338
  }
1339
+
1340
+ func manifestEntries(t *testing.T, manifest string) []string {
1341
+ t.Helper()
1342
+ var out []string
1343
+ for _, line := range strings.Split(testutil.ReadFile(t, manifest), "\n") {
1344
+ line = strings.TrimSpace(line)
1345
+ if line == "" || strings.HasPrefix(line, "#") {
1346
+ continue
1347
+ }
1348
+ out = append(out, line)
1349
+ }
1350
+ return out
1351
+ }
1352
+
1353
+ func slicesContains(haystack []string, needle string) bool {
1354
+ for _, s := range haystack {
1355
+ if s == needle {
1356
+ return true
1357
+ }
1358
+ }
1359
+ return false
1360
+ }
1361
+
1362
+ func summaryCount(out, key string) (int, error) {
1363
+ for _, line := range strings.Split(out, "\n") {
1364
+ i := strings.Index(line, key)
1365
+ if i < 0 {
1366
+ continue
1367
+ }
1368
+ fields := strings.Fields(line[i+len(key):])
1369
+ if len(fields) == 0 {
1370
+ continue
1371
+ }
1372
+ n, err := strconv.Atoi(fields[0])
1373
+ if err != nil {
1374
+ return 0, fmt.Errorf("parse %s count %q: %w", key, fields[0], err)
1375
+ }
1376
+ return n, nil
1377
+ }
1378
+ return 0, fmt.Errorf("install output has no %s counter:\n%s", key, out)
1379
+ }
1380
+
1381
+ func TestInstallAdoptsResidueAfterLostManifest(t *testing.T) {
1382
+ t.Setenv("DEVRITES_NO_BINARY", "1")
1383
+ payload := testPayload(t)
1384
+ target := t.TempDir()
1385
+ runInstall(t, target, payload, func(*Options) {})
1386
+
1387
+ first := manifestEntries(t, filepath.Join(target, ManifestName))
1388
+ if len(first) == 0 {
1389
+ t.Fatal("first install recorded no managed paths")
1390
+ }
1391
+
1392
+ // Exactly the state a run that dies before writeManifest leaves behind.
1393
+ if err := os.Remove(filepath.Join(target, ManifestName)); err != nil {
1394
+ t.Fatal(err)
1395
+ }
1396
+
1397
+ var out, errOut bytes.Buffer
1398
+ opts := DefaultOptions(ModeInstall)
1399
+ opts.Target = target
1400
+ opts.PayloadDir = payload
1401
+ opts.Stdout = &out
1402
+ opts.Stderr = &errOut
1403
+ if err := Apply(opts); err != nil {
1404
+ t.Fatalf("reinstall after manifest loss returned %v; want the tree adopted, not refused\nstdout:\n%s\nstderr:\n%s", err, out.String(), errOut.String())
1405
+ }
1406
+ if !strings.Contains(out.String(), "DevRites installed") {
1407
+ t.Fatalf("reinstall did not report an install:\n%s", out.String())
1408
+ }
1409
+ if got := strings.Count(errOut.String(), "not DevRites-managed"); got != 0 {
1410
+ t.Fatalf("reinstall rejected %d payload-identical files as foreign:\n%s", got, errOut.String())
1411
+ }
1412
+
1413
+ installed, err := summaryCount(out.String(), "installed:")
1414
+ if err != nil {
1415
+ t.Fatal(err)
1416
+ }
1417
+ skipped, err := summaryCount(out.String(), "skipped(conflict):")
1418
+ if err != nil {
1419
+ t.Fatal(err)
1420
+ }
1421
+ if installed != len(first) || skipped != 0 {
1422
+ t.Fatalf("reinstall installed %d of %d payload files and skipped %d; want the whole tree adopted\n%s", installed, len(first), skipped, out.String())
1423
+ }
1424
+
1425
+ second := manifestEntries(t, filepath.Join(target, ManifestName))
1426
+ if len(second) != len(first) {
1427
+ t.Fatalf("reinstall manifest records %d paths, want the %d the first install owned", len(second), len(first))
1428
+ }
1429
+ for _, rel := range first {
1430
+ if !slicesContains(second, rel) {
1431
+ t.Fatalf("reinstall manifest dropped %s", rel)
1432
+ }
1433
+ }
1434
+
1435
+ // The orphan leg: every file the crashed run left on disk must be removable
1436
+ // again. This asserts against the first manifest on purpose, so a reinstall
1437
+ // that records nothing cannot pass it vacuously.
1438
+ opts = DefaultOptions(ModeUninstall)
1439
+ opts.Target = target
1440
+ opts.KeepBinary = true
1441
+ opts.Stdout = &bytes.Buffer{}
1442
+ opts.Stderr = &bytes.Buffer{}
1443
+ if err := Apply(opts); err != nil {
1444
+ t.Fatalf("uninstall after adopted reinstall returned %v", err)
1445
+ }
1446
+ for _, rel := range first {
1447
+ if exists(filepath.Join(target, filepath.FromSlash(rel))) {
1448
+ t.Fatalf("uninstall orphaned %s", rel)
1449
+ }
1450
+ }
1451
+ }
1452
+
1453
+ func TestReinstallAfterLostManifestSkipsDifferingFile(t *testing.T) {
1454
+ t.Setenv("DEVRITES_NO_BINARY", "1")
1455
+ payload := testPayload(t)
1456
+ target := t.TempDir()
1457
+ runInstall(t, target, payload, func(*Options) {})
1458
+
1459
+ var foreign string
1460
+ for _, rel := range manifestEntries(t, filepath.Join(target, ManifestName)) {
1461
+ if strings.HasSuffix(rel, "agents/devrites-code-reviewer.md") {
1462
+ foreign = rel
1463
+ }
1464
+ }
1465
+ if foreign == "" {
1466
+ t.Fatal("first install did not record the agent file")
1467
+ }
1468
+ path := filepath.Join(target, filepath.FromSlash(foreign))
1469
+ if err := os.Remove(filepath.Join(target, ManifestName)); err != nil {
1470
+ t.Fatal(err)
1471
+ }
1472
+ const mine = "user-authored bytes\n"
1473
+ testutil.WriteFile(t, path, mine)
1474
+
1475
+ var out, errOut bytes.Buffer
1476
+ opts := DefaultOptions(ModeInstall)
1477
+ opts.Target = target
1478
+ opts.PayloadDir = payload
1479
+ opts.Stdout = &out
1480
+ opts.Stderr = &errOut
1481
+ if err := Apply(opts); err != nil {
1482
+ t.Fatalf("reinstall returned %v\n%s", err, errOut.String())
1483
+ }
1484
+
1485
+ if got := testutil.ReadFile(t, path); got != mine {
1486
+ t.Fatalf("reinstall rewrote a file whose bytes differ from the payload: %q", got)
1487
+ }
1488
+ if slicesContains(manifestEntries(t, filepath.Join(target, ManifestName)), foreign) {
1489
+ t.Fatalf("manifest adopted %s although its bytes differ from the payload", foreign)
1490
+ }
1491
+ if !strings.Contains(errOut.String(), "skip "+foreign) {
1492
+ t.Fatalf("reinstall did not warn about skipping %s:\n%s", foreign, errOut.String())
1493
+ }
1494
+
1495
+ opts = DefaultOptions(ModeUninstall)
1496
+ opts.Target = target
1497
+ opts.KeepBinary = true
1498
+ opts.Stdout = &bytes.Buffer{}
1499
+ opts.Stderr = &bytes.Buffer{}
1500
+ if err := Apply(opts); err != nil {
1501
+ t.Fatalf("uninstall returned %v", err)
1502
+ }
1503
+ if got := testutil.ReadFile(t, path); got != mine {
1504
+ t.Fatalf("uninstall removed or changed the unmanaged file: %q", got)
1505
+ }
1506
+ }
1507
+
1508
+ func TestApplyReportsSkippedEngineBinary(t *testing.T) {
1509
+ t.Setenv("DEVRITES_NO_BINARY", "")
1510
+ t.Setenv("DEVRITES_ENGINE_CLI", "")
1511
+ t.Setenv("HOME", t.TempDir())
1512
+ t.Setenv("DEVRITES_BIN_DIR", t.TempDir())
1513
+ var out, errOut bytes.Buffer
1514
+ opts := DefaultOptions(ModeInstall)
1515
+ opts.Target = t.TempDir()
1516
+ opts.PayloadDir = testPayload(t)
1517
+ opts.WithBinary = true
1518
+ opts.Stdout = &out
1519
+ opts.Stderr = &errOut
1520
+ if err := Apply(opts); err != nil {
1521
+ t.Fatalf("Apply() error = %v, want nil", err)
1522
+ }
1523
+ if !strings.Contains(out.String(), "DevRites installed") {
1524
+ t.Fatalf("stdout = %q, want install success", out.String())
1525
+ }
1526
+ if !strings.Contains(out.String(), "engine binary: skipped (no DEVRITES_ENGINE_CLI handoff)") {
1527
+ t.Fatalf("stdout = %q, want the skipped engine binary and its reason in the summary", out.String())
1528
+ }
1529
+ }
1530
+
1531
+ func TestApplySkippedEngineBinaryKeepsExistingBinary(t *testing.T) {
1532
+ t.Setenv("DEVRITES_NO_BINARY", "")
1533
+ t.Setenv("DEVRITES_ENGINE_CLI", "")
1534
+ t.Setenv("HOME", t.TempDir())
1535
+ binDir := t.TempDir()
1536
+ t.Setenv("DEVRITES_BIN_DIR", binDir)
1537
+ old := filepath.Join(binDir, engineBinaryName())
1538
+ if err := os.WriteFile(old, []byte("old engine"), 0o755); err != nil {
1539
+ t.Fatal(err)
1540
+ }
1541
+ var out, errOut bytes.Buffer
1542
+ opts := DefaultOptions(ModeInstall)
1543
+ opts.Target = t.TempDir()
1544
+ opts.PayloadDir = testPayload(t)
1545
+ opts.WithBinary = true
1546
+ opts.Stdout = &out
1547
+ opts.Stderr = &errOut
1548
+ if err := Apply(opts); err != nil {
1549
+ t.Fatalf("Apply() error = %v, want nil", err)
1550
+ }
1551
+ if strings.Contains(out.String(), "will not be on PATH") {
1552
+ t.Fatalf("stdout = %q, must not claim the command is missing while an older binary is kept", out.String())
1553
+ }
1554
+ if !strings.Contains(out.String(), "existing devrites-engine binary was kept") {
1555
+ t.Fatalf("stdout = %q, want the kept existing binary reported", out.String())
1556
+ }
1557
+ if got := testutil.ReadFile(t, old); got != "old engine" {
1558
+ t.Fatalf("existing binary changed: %q", got)
1559
+ }
1560
+ }
1561
+
1562
+ func installForSwap(t *testing.T) (Options, string, string) {
1563
+ t.Helper()
1564
+ t.Setenv("DEVRITES_NO_BINARY", "1")
1565
+ target := filepath.Join(t.TempDir(), "target")
1566
+ if err := os.MkdirAll(target, 0o755); err != nil {
1567
+ t.Fatal(err)
1568
+ }
1569
+ opts := DefaultOptions(ModeInstall)
1570
+ opts.Target = target
1571
+ opts.PayloadDir = testPayload(t)
1572
+ opts.Stdout = &bytes.Buffer{}
1573
+ opts.Stderr = &bytes.Buffer{}
1574
+ if err := Apply(opts); err != nil {
1575
+ t.Fatal(err)
1576
+ }
1577
+ outside := filepath.Join(filepath.Dir(target), "outside")
1578
+ if err := os.MkdirAll(outside, 0o755); err != nil {
1579
+ t.Fatal(err)
1580
+ }
1581
+ return opts, target, outside
1582
+ }
1583
+
1584
+ // swapDirAfterRecheck replaces dir with a symlink to outside once rel has been
1585
+ // rechecked, the way a concurrent process could.
1586
+ func swapDirAfterRecheck(t *testing.T, rel, dir, outside string) *bool {
1587
+ t.Helper()
1588
+ swapped := new(bool)
1589
+ afterRecheckPath = func(r string) {
1590
+ if *swapped || r != rel {
1591
+ return
1592
+ }
1593
+ if err := os.Rename(dir, dir+".real"); err != nil {
1594
+ t.Fatal(err)
1595
+ }
1596
+ if err := os.Symlink(outside, dir); err != nil {
1597
+ t.Fatal(err)
1598
+ }
1599
+ *swapped = true
1600
+ }
1601
+ t.Cleanup(func() { afterRecheckPath = nil })
1602
+ return swapped
1603
+ }
1604
+
1605
+ func TestUninstallStripAfterRecheckStaysInTarget(t *testing.T) {
1606
+ opts, target, outside := installForSwap(t)
1607
+ cfg := filepath.Join(target, ".codex", "config.toml")
1608
+ orig, err := os.ReadFile(cfg)
1609
+ if err != nil {
1610
+ t.Fatal(err)
1611
+ }
1612
+ withUser := append([]byte("model = \"user\"\n"), orig...)
1613
+ if err := os.WriteFile(cfg, withUser, 0o644); err != nil {
1614
+ t.Fatal(err)
1615
+ }
1616
+ outsideCfg := filepath.Join(outside, "config.toml")
1617
+ if err := os.WriteFile(outsideCfg, withUser, 0o600); err != nil {
1618
+ t.Fatal(err)
1619
+ }
1620
+ swapped := swapDirAfterRecheck(t, ".codex/config.toml", filepath.Join(target, ".codex"), outside)
1621
+ opts.Mode = ModeUninstall
1622
+ _ = Apply(opts)
1623
+ if !*swapped {
1624
+ t.Fatal("swap never happened")
1625
+ }
1626
+ after, err := os.ReadFile(outsideCfg)
1627
+ if err != nil || !bytes.Equal(after, withUser) {
1628
+ t.Fatalf("uninstall rewrote a file outside the target: err=%v content=%q", err, after)
1629
+ }
1630
+ }
1631
+
1632
+ func TestUninstallRemoveAfterRecheckStaysInTarget(t *testing.T) {
1633
+ opts, target, outside := installForSwap(t)
1634
+ victim := filepath.Join(outside, "devrites-code-reviewer.toml")
1635
+ if err := os.WriteFile(victim, []byte("precious\n"), 0o644); err != nil {
1636
+ t.Fatal(err)
1637
+ }
1638
+ swapped := swapDirAfterRecheck(t, ".codex/agents/devrites-code-reviewer.toml", filepath.Join(target, ".codex", "agents"), outside)
1639
+ opts.Mode = ModeUninstall
1640
+ _ = Apply(opts)
1641
+ if !*swapped {
1642
+ t.Fatal("swap never happened")
1643
+ }
1644
+ if _, err := os.Stat(victim); err != nil {
1645
+ t.Fatalf("uninstall removed a file outside the target: %v", err)
1646
+ }
1647
+ }
1648
+
1649
+ func TestUninstallDryRunUnbalancedMarker(t *testing.T) {
1650
+ opts, target, _ := installForSwap(t)
1651
+ agents := filepath.Join(target, "AGENTS.md")
1652
+ data, err := os.ReadFile(agents)
1653
+ if err != nil {
1654
+ t.Fatal(err)
1655
+ }
1656
+ broken := strings.Replace(string(data), "<!-- END DEVRITES CODEX -->\n", "", 1)
1657
+ if broken == string(data) {
1658
+ t.Fatalf("no END marker in %q", data)
1659
+ }
1660
+ if err := os.WriteFile(agents, []byte(broken+"user tail\n"), 0o644); err != nil {
1661
+ t.Fatal(err)
1662
+ }
1663
+ opts.Mode = ModeUninstall
1664
+ dry := opts
1665
+ dry.DryRun = true
1666
+ dryErr := Apply(dry)
1667
+ realErr := Apply(opts)
1668
+ if realErr == nil {
1669
+ t.Fatal("real uninstall accepted an unterminated marker block")
1670
+ }
1671
+ if dryErr == nil || dryErr.Error() != realErr.Error() {
1672
+ t.Fatalf("dry-run err=%v, real uninstall err=%v; want the same error", dryErr, realErr)
1673
+ }
1674
+ }
1675
+
1676
+ func hashTree(t *testing.T, root string) string {
1677
+ t.Helper()
1678
+ h := sha256.New()
1679
+ err := filepath.WalkDir(root, func(p string, d os.DirEntry, err error) error {
1680
+ if err != nil {
1681
+ return err
1682
+ }
1683
+ rel, _ := filepath.Rel(root, p)
1684
+ fmt.Fprintf(h, "%s|%v\n", rel, d.Type())
1685
+ if d.Type().IsRegular() {
1686
+ data, err := os.ReadFile(p)
1687
+ if err != nil {
1688
+ return err
1689
+ }
1690
+ h.Write(data)
1691
+ }
1692
+ return nil
1693
+ })
1694
+ if err != nil {
1695
+ t.Fatal(err)
1696
+ }
1697
+ return fmt.Sprintf("%x", h.Sum(nil))
1698
+ }
1699
+
1700
+ func TestUninstallDryRunMatchesRealMarkerErrors(t *testing.T) {
1701
+ const (
1702
+ piBegin = "<!-- BEGIN DEVRITES PI -->\n"
1703
+ piEnd = "<!-- END DEVRITES PI -->\n"
1704
+ codexBegin = "<!-- BEGIN DEVRITES CODEX -->\n"
1705
+ codexEnd = "<!-- END DEVRITES CODEX -->\n"
1706
+ )
1707
+ for _, tc := range []struct {
1708
+ name string
1709
+ agents string
1710
+ wantErr bool
1711
+ }{
1712
+ {name: "balanced", agents: "user\n" + codexBegin + "x\n" + codexEnd + piBegin + "y\n" + piEnd},
1713
+ {name: "only blocks", agents: codexBegin + "x\n" + codexEnd},
1714
+ {name: "unterminated codex", agents: codexBegin + "x\nuser tail\n", wantErr: true},
1715
+ {name: "unterminated pi", agents: piBegin + "x\nuser tail\n", wantErr: true},
1716
+ {name: "crossed", agents: "u\n" + piBegin + "A\n" + codexBegin + "B\n" + piEnd + "C\n" + codexEnd + "v\n", wantErr: true},
1717
+ {name: "crossed other way", agents: codexBegin + "A\n" + piBegin + "B\n" + codexEnd + "C\n" + piEnd},
1718
+ } {
1719
+ t.Run(tc.name, func(t *testing.T) {
1720
+ opts, target, _ := installForSwap(t)
1721
+ if err := os.WriteFile(filepath.Join(target, "AGENTS.md"), []byte(tc.agents), 0o644); err != nil {
1722
+ t.Fatal(err)
1723
+ }
1724
+ opts.Mode = ModeUninstall
1725
+ dry := opts
1726
+ dry.DryRun = true
1727
+ before := hashTree(t, target)
1728
+ dryErr := Apply(dry)
1729
+ if hashTree(t, target) != before {
1730
+ t.Fatal("dry-run changed the target tree")
1731
+ }
1732
+ realErr := Apply(opts)
1733
+ if (realErr != nil) != tc.wantErr {
1734
+ t.Fatalf("real uninstall err=%v, want error=%v", realErr, tc.wantErr)
1735
+ }
1736
+ if fmt.Sprint(dryErr) != fmt.Sprint(realErr) {
1737
+ t.Fatalf("dry-run err=%v, real uninstall err=%v; want the same error", dryErr, realErr)
1738
+ }
1739
+ })
1740
+ }
1741
+ }
@@ -11,7 +11,6 @@ import (
11
11
  "sort"
12
12
  "strings"
13
13
 
14
- "github.com/devrites/devrites/internal/fsutil"
15
14
  "github.com/devrites/devrites/internal/hostpack"
16
15
  )
17
16
 
@@ -85,11 +84,20 @@ func (r *runner) mergeMarkerFile(merge hostpack.MarkerMerge) error {
85
84
  return fmt.Errorf("read payload %s: %w", merge.PayloadRel, err)
86
85
  }
87
86
  dest := filepath.Join(r.target, filepath.FromSlash(merge.TargetRel))
87
+ // #nosec G304 -- dest joins the operator target with a fixed manifest-relative record
88
+ if current, readErr := os.ReadFile(dest); readErr == nil {
89
+ if err := hostpack.ValidateMarkerBlocks(current, r.sharedMarkerMerges(merge)...); err != nil {
90
+ return fmt.Errorf("%w in %s; fix it and rerun", err, merge.TargetRel)
91
+ }
92
+ }
88
93
  if r.opts.DryRun {
89
94
  verb := "create DevRites block"
90
95
  // #nosec G304 -- dest joins the operator target with a fixed manifest-relative record
91
96
  current, readErr := os.ReadFile(dest)
92
97
  if readErr == nil {
98
+ if _, mergeErr := hostpack.MergeMarkerBlock(current, block, merge.Begin, merge.End); mergeErr != nil {
99
+ return fmt.Errorf("%w in %s; fix it and rerun", mergeErr, merge.TargetRel)
100
+ }
93
101
  if bytes.Contains(current, []byte(merge.Begin)) {
94
102
  verb = "refresh DevRites block"
95
103
  } else {
@@ -107,11 +115,15 @@ func (r *runner) mergeMarkerFile(merge hostpack.MarkerMerge) error {
107
115
  // #nosec G304 -- dest joins the operator target with a fixed manifest-relative record
108
116
  current, readErr := os.ReadFile(dest)
109
117
  if readErr == nil {
110
- next = hostpack.MergeMarkerBlock(current, block, merge.Begin, merge.End)
118
+ var mergeErr error
119
+ next, mergeErr = hostpack.MergeMarkerBlock(current, block, merge.Begin, merge.End)
120
+ if mergeErr != nil {
121
+ return fmt.Errorf("%w in %s; fix it and rerun", mergeErr, merge.TargetRel)
122
+ }
111
123
  } else if !errors.Is(readErr, fs.ErrNotExist) {
112
124
  return fmt.Errorf("cannot read %s: %w", merge.TargetRel, readErr)
113
125
  }
114
- if err := fsutil.WriteFileAtomic(dest, next, 0o644); err != nil {
126
+ if err := r.writeConfined(dest, next, 0o644); err != nil {
115
127
  return fmt.Errorf("cannot write %s: %w", merge.TargetRel, err)
116
128
  }
117
129
  // Multiple marker blocks can share one target (AGENTS.md carries both
@@ -123,6 +135,23 @@ func (r *runner) mergeMarkerFile(merge hostpack.MarkerMerge) error {
123
135
  return r.installMarker(merge.MarkerRel, merge.MarkerText)
124
136
  }
125
137
 
138
+ func (r *runner) sharedMarkerMerges(merge hostpack.MarkerMerge) []hostpack.MarkerMerge {
139
+ merges := []hostpack.MarkerMerge{merge}
140
+ for _, other := range []struct {
141
+ enabled bool
142
+ merge hostpack.MarkerMerge
143
+ }{
144
+ {r.opts.WithCodex, hostpack.CodexAgentsMerge},
145
+ {r.opts.WithPi, hostpack.PiAgentsMerge},
146
+ {r.opts.WithDevin, hostpack.DevinAgentsMerge},
147
+ } {
148
+ if other.enabled && other.merge.TargetRel == merge.TargetRel && other.merge.Begin != merge.Begin {
149
+ merges = append(merges, other.merge)
150
+ }
151
+ }
152
+ return merges
153
+ }
154
+
126
155
  func (r *runner) mergeCodexConfig() error {
127
156
  merge := hostpack.CodexConfigMerge
128
157
  block, err := fs.ReadFile(r.payloadFS, merge.PayloadRel)
@@ -131,6 +160,12 @@ func (r *runner) mergeCodexConfig() error {
131
160
  }
132
161
  dest := filepath.Join(r.target, filepath.FromSlash(merge.TargetRel))
133
162
  if r.opts.DryRun {
163
+ // #nosec G304 -- dest joins the operator target with a fixed manifest-relative record
164
+ if data, readErr := os.ReadFile(dest); readErr == nil {
165
+ if _, stripErr := hostpack.StripCodexConfigBlocks(data); stripErr != nil {
166
+ return fmt.Errorf("%w in %s; fix it and rerun", stripErr, merge.TargetRel)
167
+ }
168
+ }
134
169
  fmt.Fprintf(r.opts.Stdout, " [merge] %s (prepend DevRites permission block)\n", merge.TargetRel)
135
170
  return r.installMarker(merge.MarkerRel, merge.MarkerText)
136
171
  }
@@ -140,9 +175,11 @@ func (r *runner) mergeCodexConfig() error {
140
175
  var current []byte
141
176
  // #nosec G304 -- dest joins the operator target with a fixed manifest-relative record
142
177
  if data, readErr := os.ReadFile(dest); readErr == nil {
143
- current = stripMarkerBlock(data, merge.Begin, merge.End)
144
- current = stripMarkerBlock(current, "# BEGIN DEVRITES CODEX MCP", "# END DEVRITES CODEX MCP")
145
- current = stripMarkerBlock(current, "### BEGIN DEVRITES CODEX MCP", "### END DEVRITES CODEX MCP")
178
+ var stripErr error
179
+ if data, stripErr = hostpack.StripCodexConfigBlocks(data); stripErr != nil {
180
+ return fmt.Errorf("%w in %s; fix it and rerun", stripErr, merge.TargetRel)
181
+ }
182
+ current = data
146
183
  if hasTopLevelTOMLKey(current, "default_permissions") {
147
184
  return fmt.Errorf("%s already sets top-level default_permissions; remove that project override before installing the DevRites read-only-root profile", merge.TargetRel)
148
185
  }
@@ -157,7 +194,7 @@ func (r *runner) mergeCodexConfig() error {
157
194
  next = append(next, '\n')
158
195
  next = append(next, current...)
159
196
  }
160
- if err := fsutil.WriteFileAtomic(dest, next, 0o644); err != nil {
197
+ if err := r.writeConfined(dest, next, 0o644); err != nil {
161
198
  return fmt.Errorf("cannot write %s: %w", merge.TargetRel, err)
162
199
  }
163
200
  return r.installMarker(merge.MarkerRel, merge.MarkerText)
@@ -191,7 +228,7 @@ func (r *runner) mergeClaudeSettings(merge hostpack.JSONMerge) error {
191
228
  return fmt.Errorf("encode merged Claude settings: %w", err)
192
229
  }
193
230
  data = append(data, '\n')
194
- if err := fsutil.WriteFileAtomic(dest, data, 0o644); err != nil {
231
+ if err := r.writeConfined(dest, data, 0o644); err != nil {
195
232
  return fmt.Errorf("cannot write %s: %w", merge.TargetRel, err)
196
233
  }
197
234
  return r.installClaudeSettingsMarker(ownsDefaultMode, managedRulesFromPayload(devrites))
@@ -201,7 +238,13 @@ func (r *runner) seedClaudeSettings() error {
201
238
  return r.mergeClaudeSettings(hostpack.ClaudeSettingsMerge)
202
239
  }
203
240
 
204
- func stripHooksPath(path string) error {
241
+ func (r *runner) stripHooksConfined(path string) error {
242
+ return stripHooksWith(path, func(data []byte) error {
243
+ return r.writeConfined(path, data, 0o644)
244
+ }, func() error { return r.removeConfined(path) })
245
+ }
246
+
247
+ func stripHooksWith(path string, write func([]byte) error, remove func() error) error {
205
248
  current, err := readJSON(path)
206
249
  if err != nil {
207
250
  if errors.Is(err, fs.ErrNotExist) {
@@ -211,14 +254,14 @@ func stripHooksPath(path string) error {
211
254
  }
212
255
  next := stripDevritesHooks(current)
213
256
  if len(next) == 0 {
214
- return os.Remove(path)
257
+ return remove()
215
258
  }
216
259
  data, err := json.MarshalIndent(next, "", " ")
217
260
  if err != nil {
218
261
  return fmt.Errorf("encode hooks config: %w", err)
219
262
  }
220
263
  data = append(data, '\n')
221
- return fsutil.WriteFileAtomic(path, data, 0o644)
264
+ return write(data)
222
265
  }
223
266
 
224
267
  func (r *runner) stripClaudeSettings(path string, preserveEmpty bool) error {
@@ -231,17 +274,23 @@ func (r *runner) stripClaudeSettings(path string, preserveEmpty bool) error {
231
274
  }
232
275
  next := stripDevritesSettings(current, r.claudeDefaultModeOwned(), r.managedClaudePermissionRules())
233
276
  if len(next) == 0 && !preserveEmpty {
234
- return os.Remove(path)
277
+ return r.removeConfined(path)
235
278
  }
236
279
  data, err := json.MarshalIndent(next, "", " ")
237
280
  if err != nil {
238
281
  return fmt.Errorf("encode Claude settings: %w", err)
239
282
  }
240
283
  data = append(data, '\n')
241
- return fsutil.WriteFileAtomic(path, data, 0o644)
284
+ return r.writeConfined(path, data, 0o644)
285
+ }
286
+
287
+ func (r *runner) stripMarkerConfined(path, begin, end string) error {
288
+ return stripMarkerWith(path, begin, end, func(data []byte) error {
289
+ return r.writeConfined(path, data, 0o644)
290
+ }, func() error { return r.removeConfined(path) })
242
291
  }
243
292
 
244
- func stripMarkerPath(path, begin, end string) error {
293
+ func stripMarkerWith(path, begin, end string, write func([]byte) error, remove func() error) error {
245
294
  // #nosec G304 -- managed file path from the install manifest
246
295
  data, err := os.ReadFile(path)
247
296
  if err != nil {
@@ -250,32 +299,14 @@ func stripMarkerPath(path, begin, end string) error {
250
299
  }
251
300
  return fmt.Errorf("read %s: %w", path, err)
252
301
  }
253
- next := stripMarkerBlock(data, begin, end)
254
- if strings.TrimSpace(string(next)) == "" {
255
- return os.Remove(path)
302
+ next, err := hostpack.StripMarkerBlock(data, begin, end)
303
+ if err != nil {
304
+ return fmt.Errorf("%w in %s; fix it and rerun", err, path)
256
305
  }
257
- return fsutil.WriteFileAtomic(path, next, 0o644)
258
- }
259
-
260
- func stripMarkerBlock(data []byte, begin, end string) []byte {
261
- var out strings.Builder
262
- inBlock := false
263
- for _, line := range strings.SplitAfter(string(data), "\n") {
264
- trim := strings.TrimSuffix(line, "\n")
265
- trim = strings.TrimSuffix(trim, "\r")
266
- switch trim {
267
- case begin:
268
- inBlock = true
269
- continue
270
- case end:
271
- inBlock = false
272
- continue
273
- }
274
- if !inBlock {
275
- out.WriteString(line)
276
- }
306
+ if strings.TrimSpace(string(next)) == "" {
307
+ return remove()
277
308
  }
278
- return []byte(out.String())
309
+ return write(next)
279
310
  }
280
311
 
281
312
  func hasTopLevelTOMLKey(data []byte, key string) bool {