@codyswann/lisa 4.54.13 → 4.55.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 (578) hide show
  1. package/all/copy-contents/.gitattributes +8 -0
  2. package/all/copy-overwrite/scripts/check-orphaned-branches.mjs +78 -9
  3. package/all/copy-overwrite/scripts/check-third-party-action-pins.mjs +17 -1
  4. package/all/copy-overwrite/scripts/lib/process-tree-runner.mjs +194 -7
  5. package/all/copy-overwrite/scripts/lisa-enforcement-fallback.sh +31 -0
  6. package/all/copy-overwrite/scripts/lisa-hooks/block-blind-automerge.sh +81 -2
  7. package/all/copy-overwrite/scripts/lisa-hooks/block-direct-issue-create.sh +293 -8
  8. package/all/copy-overwrite/scripts/lisa-hooks/block-instruction-file-edits.sh +21 -0
  9. package/all/copy-overwrite/scripts/lisa-hooks/block-managed-file-edits.sh +78 -15
  10. package/all/copy-overwrite/scripts/lisa-hooks/block-no-verify.sh +21 -0
  11. package/all/copy-overwrite/scripts/lisa-hooks/block-shell-json-parsing.sh +21 -0
  12. package/all/copy-overwrite/scripts/lisa-hooks/guard-dedupe.bash +340 -0
  13. package/all/copy-overwrite/scripts/lisa-hooks/parity-safety-net.sh +29 -1
  14. package/all/copy-overwrite/scripts/lisa-hooks/worktree-binding-guard.mjs +183 -1
  15. package/all/copy-overwrite/scripts/lisa-hooks/worktree-binding-guard.sh +21 -0
  16. package/all/copy-overwrite/scripts/lisa-postinstall.mjs +21 -1
  17. package/all/copy-overwrite/scripts/lisa-run-gates.mjs +100 -5
  18. package/all/copy-overwrite/scripts/lisa-work-item.mjs +1085 -80
  19. package/all/create-only/.github/workflows/continuous-gates.yml +7 -0
  20. package/cdk/create-only/.github/workflows/ci.yml +7 -0
  21. package/cdk/create-only/.github/workflows/deploy.yml +21 -0
  22. package/dist/cli/apply.d.ts.map +1 -1
  23. package/dist/cli/apply.js +9 -1
  24. package/dist/cli/apply.js.map +1 -1
  25. package/dist/cli/doctor-apply-deletions.d.ts +61 -0
  26. package/dist/cli/doctor-apply-deletions.d.ts.map +1 -0
  27. package/dist/cli/doctor-apply-deletions.js +137 -0
  28. package/dist/cli/doctor-apply-deletions.js.map +1 -0
  29. package/dist/cli/doctor-cdk-preset-adoption.d.ts +15 -0
  30. package/dist/cli/doctor-cdk-preset-adoption.d.ts.map +1 -0
  31. package/dist/cli/doctor-cdk-preset-adoption.js +316 -0
  32. package/dist/cli/doctor-cdk-preset-adoption.js.map +1 -0
  33. package/dist/cli/doctor-config-shadowing.d.ts +22 -0
  34. package/dist/cli/doctor-config-shadowing.d.ts.map +1 -0
  35. package/dist/cli/doctor-config-shadowing.js +123 -0
  36. package/dist/cli/doctor-config-shadowing.js.map +1 -0
  37. package/dist/cli/doctor-rails-deploy-intent.d.ts +15 -0
  38. package/dist/cli/doctor-rails-deploy-intent.d.ts.map +1 -0
  39. package/dist/cli/doctor-rails-deploy-intent.js +197 -0
  40. package/dist/cli/doctor-rails-deploy-intent.js.map +1 -0
  41. package/dist/cli/doctor-seeded-artifacts.d.ts +12 -0
  42. package/dist/cli/doctor-seeded-artifacts.d.ts.map +1 -0
  43. package/dist/cli/doctor-seeded-artifacts.js +54 -0
  44. package/dist/cli/doctor-seeded-artifacts.js.map +1 -0
  45. package/dist/cli/doctor-stale-banner-scan.d.ts +44 -0
  46. package/dist/cli/doctor-stale-banner-scan.d.ts.map +1 -0
  47. package/dist/cli/doctor-stale-banner-scan.js +152 -0
  48. package/dist/cli/doctor-stale-banner-scan.js.map +1 -0
  49. package/dist/cli/doctor-stale-managed-banner.d.ts +19 -0
  50. package/dist/cli/doctor-stale-managed-banner.d.ts.map +1 -0
  51. package/dist/cli/doctor-stale-managed-banner.js +198 -0
  52. package/dist/cli/doctor-stale-managed-banner.js.map +1 -0
  53. package/dist/cli/doctor.d.ts.map +1 -1
  54. package/dist/cli/doctor.js +16 -0
  55. package/dist/cli/doctor.js.map +1 -1
  56. package/dist/cli/ui-detected-stacks.d.ts.map +1 -1
  57. package/dist/cli/ui-detected-stacks.js +3 -2
  58. package/dist/cli/ui-detected-stacks.js.map +1 -1
  59. package/dist/cli/update-check.d.ts.map +1 -1
  60. package/dist/cli/update-check.js +14 -0
  61. package/dist/cli/update-check.js.map +1 -1
  62. package/dist/cli/worktree-liveness.d.ts +5 -0
  63. package/dist/cli/worktree-liveness.d.ts.map +1 -1
  64. package/dist/cli/worktree-liveness.js +7 -6
  65. package/dist/cli/worktree-liveness.js.map +1 -1
  66. package/dist/cli/worktree-ownership.d.ts +13 -0
  67. package/dist/cli/worktree-ownership.d.ts.map +1 -1
  68. package/dist/cli/worktree-ownership.js +14 -0
  69. package/dist/cli/worktree-ownership.js.map +1 -1
  70. package/dist/configs/eslint/base.d.ts +34 -0
  71. package/dist/configs/eslint/base.d.ts.map +1 -1
  72. package/dist/configs/eslint/base.js +34 -0
  73. package/dist/configs/eslint/base.js.map +1 -1
  74. package/dist/core/apply-receipt.d.ts +65 -0
  75. package/dist/core/apply-receipt.d.ts.map +1 -1
  76. package/dist/core/apply-receipt.js +62 -2
  77. package/dist/core/apply-receipt.js.map +1 -1
  78. package/dist/core/cdk-preset-adoption.d.ts +136 -0
  79. package/dist/core/cdk-preset-adoption.d.ts.map +1 -0
  80. package/dist/core/cdk-preset-adoption.js +135 -0
  81. package/dist/core/cdk-preset-adoption.js.map +1 -0
  82. package/dist/core/config-shadowing.d.ts +36 -0
  83. package/dist/core/config-shadowing.d.ts.map +1 -1
  84. package/dist/core/config-shadowing.js +38 -0
  85. package/dist/core/config-shadowing.js.map +1 -1
  86. package/dist/core/config.d.ts +11 -0
  87. package/dist/core/config.d.ts.map +1 -1
  88. package/dist/core/config.js.map +1 -1
  89. package/dist/core/learnings-merge-driver.d.ts +10 -0
  90. package/dist/core/learnings-merge-driver.d.ts.map +1 -1
  91. package/dist/core/learnings-merge-driver.js +18 -0
  92. package/dist/core/learnings-merge-driver.js.map +1 -1
  93. package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
  94. package/dist/core/lisa-owned-hash-ledger.js +136 -0
  95. package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
  96. package/dist/core/lisa.d.ts.map +1 -1
  97. package/dist/core/lisa.js +9 -1
  98. package/dist/core/lisa.js.map +1 -1
  99. package/dist/core/nightly-e2e-guard-behavior-certificate.d.ts +5 -5
  100. package/dist/core/nightly-e2e-guard-behavior-certificate.js +7 -7
  101. package/dist/core/nightly-e2e-guard-behavior-certificate.js.map +1 -1
  102. package/dist/core/ownership-header.d.ts +74 -0
  103. package/dist/core/ownership-header.d.ts.map +1 -0
  104. package/dist/core/ownership-header.js +76 -0
  105. package/dist/core/ownership-header.js.map +1 -0
  106. package/dist/core/rails-deploy-production-intent.d.ts +36 -0
  107. package/dist/core/rails-deploy-production-intent.d.ts.map +1 -0
  108. package/dist/core/rails-deploy-production-intent.js +79 -0
  109. package/dist/core/rails-deploy-production-intent.js.map +1 -0
  110. package/dist/core/stale-managed-banner.d.ts +78 -0
  111. package/dist/core/stale-managed-banner.d.ts.map +1 -0
  112. package/dist/core/stale-managed-banner.js +118 -0
  113. package/dist/core/stale-managed-banner.js.map +1 -0
  114. package/dist/core/two-channel-delivery-scan.d.ts +33 -1
  115. package/dist/core/two-channel-delivery-scan.d.ts.map +1 -1
  116. package/dist/core/two-channel-delivery-scan.js +133 -6
  117. package/dist/core/two-channel-delivery-scan.js.map +1 -1
  118. package/dist/core/two-channel-delivery.d.ts +101 -4
  119. package/dist/core/two-channel-delivery.d.ts.map +1 -1
  120. package/dist/core/two-channel-delivery.js +121 -13
  121. package/dist/core/two-channel-delivery.js.map +1 -1
  122. package/dist/core/two-channel-staleness.d.ts +137 -0
  123. package/dist/core/two-channel-staleness.d.ts.map +1 -0
  124. package/dist/core/two-channel-staleness.js +268 -0
  125. package/dist/core/two-channel-staleness.js.map +1 -0
  126. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  127. package/dist/core/upstream-evidence-manifest.js +265 -121
  128. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  129. package/dist/core/workflow-deletion-ownership.d.ts +6 -24
  130. package/dist/core/workflow-deletion-ownership.d.ts.map +1 -1
  131. package/dist/core/workflow-deletion-ownership.js +22 -42
  132. package/dist/core/workflow-deletion-ownership.js.map +1 -1
  133. package/dist/detection/detectors/cdk.d.ts.map +1 -1
  134. package/dist/detection/detectors/cdk.js +2 -1
  135. package/dist/detection/detectors/cdk.js.map +1 -1
  136. package/dist/health/template-inspection.d.ts.map +1 -1
  137. package/dist/health/template-inspection.js +2 -1
  138. package/dist/health/template-inspection.js.map +1 -1
  139. package/dist/migrations/ensure-lisa-postinstall.d.ts +16 -0
  140. package/dist/migrations/ensure-lisa-postinstall.d.ts.map +1 -1
  141. package/dist/migrations/ensure-lisa-postinstall.js +16 -0
  142. package/dist/migrations/ensure-lisa-postinstall.js.map +1 -1
  143. package/dist/migrations/ensure-pinned-reusable-workflow-refs.d.ts +2 -2
  144. package/dist/migrations/ensure-pinned-reusable-workflow-refs.d.ts.map +1 -1
  145. package/dist/migrations/ensure-pinned-reusable-workflow-refs.js +98 -34
  146. package/dist/migrations/ensure-pinned-reusable-workflow-refs.js.map +1 -1
  147. package/dist/migrations/ensure-playwright-dedicated-caller.d.ts.map +1 -1
  148. package/dist/migrations/ensure-playwright-dedicated-caller.js +1 -0
  149. package/dist/migrations/ensure-playwright-dedicated-caller.js.map +1 -1
  150. package/dist/opencode/hooks-installer.d.ts.map +1 -1
  151. package/dist/opencode/hooks-installer.js +1 -0
  152. package/dist/opencode/hooks-installer.js.map +1 -1
  153. package/dist/opencode/plugin-templates/block-managed-file-edits.sh +78 -15
  154. package/dist/opencode/plugin-templates/block-no-verify.sh +21 -0
  155. package/dist/opencode/plugin-templates/guard-dedupe.bash +337 -0
  156. package/dist/opencode/plugin-templates/lisa-block-direct-issue-create.ts +242 -55
  157. package/dist/opencode/plugin-templates/parity-safety-net.sh +29 -1
  158. package/dist/strategies/package-lisa.d.ts.map +1 -1
  159. package/dist/strategies/package-lisa.js +2 -1
  160. package/dist/strategies/package-lisa.js.map +1 -1
  161. package/dist/utils/path-utils.d.ts +29 -0
  162. package/dist/utils/path-utils.d.ts.map +1 -1
  163. package/dist/utils/path-utils.js +41 -0
  164. package/dist/utils/path-utils.js.map +1 -1
  165. package/expo/create-only/.github/workflows/ci.yml +21 -0
  166. package/expo/create-only/.github/workflows/deploy.yml +28 -0
  167. package/expo/create-only/.github/workflows/maestro-e2e.yml +7 -0
  168. package/expo/create-only/.github/workflows/nightly-e2e-bypass-reaper.yml +124 -13
  169. package/expo/create-only/.github/workflows/nightly-e2e-health.yml +7 -0
  170. package/expo/create-only/.github/workflows/nightly-e2e-report.yml +7 -0
  171. package/expo/create-only/.github/workflows/nightly-e2e-tracking.yml +8 -0
  172. package/expo/create-only/.github/workflows/playwright-e2e.yml +7 -0
  173. package/harper-fabric/copy-overwrite/.github/workflows/ci.yml +7 -0
  174. package/harper-fabric/create-only/.github/workflows/deploy.yml +14 -0
  175. package/nestjs/create-only/.github/workflows/ci.yml +14 -0
  176. package/nestjs/create-only/.github/workflows/deploy.yml +28 -0
  177. package/package.json +10 -5
  178. package/phaser/copy-overwrite/.github/workflows/ci.yml +7 -0
  179. package/plugins/lisa/.claude-plugin/plugin.json +28 -1
  180. package/plugins/lisa/.codex-plugin/hooks.json +27 -0
  181. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  182. package/plugins/lisa/.codex-plugin/skills/lisa-drive-pr-to-merge/SKILL.md +130 -19
  183. package/plugins/lisa/.codex-plugin/skills/lisa-github-build-intake/SKILL.md +27 -4
  184. package/plugins/lisa/.codex-plugin/skills/lisa-github-prd-intake/SKILL.md +1 -1
  185. package/plugins/lisa/.codex-plugin/skills/lisa-github-validate-issue/SKILL.md +22 -0
  186. package/plugins/lisa/.codex-plugin/skills/lisa-github-verify/SKILL.md +14 -0
  187. package/plugins/lisa/.codex-plugin/skills/lisa-github-write-issue/SKILL.md +51 -0
  188. package/plugins/lisa/.codex-plugin/skills/lisa-intake/SKILL.md +1 -1
  189. package/plugins/lisa/.codex-plugin/skills/lisa-jira-build-intake/SKILL.md +27 -4
  190. package/plugins/lisa/.codex-plugin/skills/lisa-jira-validate-ticket/SKILL.md +22 -0
  191. package/plugins/lisa/.codex-plugin/skills/lisa-jira-verify/SKILL.md +14 -0
  192. package/plugins/lisa/.codex-plugin/skills/lisa-jira-write-ticket/SKILL.md +51 -0
  193. package/plugins/lisa/.codex-plugin/skills/lisa-linear-access/SKILL.md +55 -2
  194. package/plugins/lisa/.codex-plugin/skills/lisa-linear-build-intake/SKILL.md +27 -4
  195. package/plugins/lisa/.codex-plugin/skills/lisa-linear-prd-intake/SKILL.md +47 -30
  196. package/plugins/lisa/.codex-plugin/skills/lisa-linear-to-tracker/SKILL.md +3 -3
  197. package/plugins/lisa/.codex-plugin/skills/lisa-linear-validate-issue/SKILL.md +22 -0
  198. package/plugins/lisa/.codex-plugin/skills/lisa-linear-verify/SKILL.md +14 -0
  199. package/plugins/lisa/.codex-plugin/skills/lisa-linear-write-issue/SKILL.md +54 -3
  200. package/plugins/lisa/.codex-plugin/skills/lisa-prd-ticket-coverage/SKILL.md +2 -2
  201. package/plugins/lisa/.codex-plugin/skills/lisa-qa-clear/SKILL.md +19 -7
  202. package/plugins/lisa/.codex-plugin/skills/lisa-qa-fail/SKILL.md +28 -3
  203. package/plugins/lisa/.codex-plugin/skills/lisa-qa-queue/SKILL.md +28 -3
  204. package/plugins/lisa/.codex-plugin/skills/lisa-repair-intake/SKILL.md +94 -24
  205. package/plugins/lisa/.codex-plugin/skills/lisa-rework-triage/SKILL.md +32 -2
  206. package/plugins/lisa/.codex-plugin/skills/lisa-setup-linear/SKILL.md +4 -4
  207. package/plugins/lisa/.codex-plugin/skills/lisa-track/SKILL.md +1 -1
  208. package/plugins/lisa/.codex-plugin/skills/lisa-tracker-build-intake/SKILL.md +9 -0
  209. package/plugins/lisa/agents/linear-prd-intake.md +8 -8
  210. package/plugins/lisa/hooks/block-blind-automerge.sh +81 -2
  211. package/plugins/lisa/hooks/block-direct-issue-create.agy.sh +64 -16
  212. package/plugins/lisa/hooks/block-direct-issue-create.sh +293 -8
  213. package/plugins/lisa/hooks/block-instruction-file-edits.sh +21 -0
  214. package/plugins/lisa/hooks/block-managed-file-edits.sh +78 -15
  215. package/plugins/lisa/hooks/block-no-verify.sh +21 -0
  216. package/plugins/lisa/hooks/block-shell-json-parsing.sh +21 -0
  217. package/plugins/lisa/hooks/failure-signature-index.mjs +240 -5
  218. package/plugins/lisa/hooks/guard-dedupe.bash +337 -0
  219. package/plugins/lisa/hooks/inject-rules.sh +13 -5
  220. package/plugins/lisa/hooks/operational-hazards.mjs +736 -0
  221. package/plugins/lisa/hooks/operational-hazards.sh +28 -0
  222. package/plugins/lisa/hooks/parity-safety-net.sh +29 -1
  223. package/plugins/lisa/hooks/threshold-ratchet-compare.mjs +102 -21
  224. package/plugins/lisa/hooks/threshold-ratchet-families.mjs +130 -2
  225. package/plugins/lisa/hooks/threshold-ratchet.mjs +63 -13
  226. package/plugins/lisa/hooks/worktree-binding-guard.mjs +183 -1
  227. package/plugins/lisa/hooks/worktree-binding-guard.sh +21 -0
  228. package/plugins/lisa/rules/eager/00-rule-index.md +1 -0
  229. package/plugins/lisa/rules/eager/operational-hazards.md +50 -0
  230. package/plugins/lisa/rules/eager/tracked-work.md +1 -1
  231. package/plugins/lisa/rules/reference/config-resolution.md +1 -1
  232. package/plugins/lisa/rules/reference/leaf-only-lifecycle.md +1 -1
  233. package/plugins/lisa/rules/reference/operational-hazards.md +115 -0
  234. package/plugins/lisa/rules/reference/work-item-trailer-definition.md +129 -0
  235. package/plugins/lisa/scripts/intake-blocker-reprobe.mjs +407 -26
  236. package/plugins/lisa/scripts/qa-signal-lifecycle.mjs +507 -0
  237. package/plugins/lisa/skills/lisa-drive-pr-to-merge/SKILL.md +130 -19
  238. package/plugins/lisa/skills/lisa-github-build-intake/SKILL.md +27 -4
  239. package/plugins/lisa/skills/lisa-github-prd-intake/SKILL.md +1 -1
  240. package/plugins/lisa/skills/lisa-github-validate-issue/SKILL.md +22 -0
  241. package/plugins/lisa/skills/lisa-github-verify/SKILL.md +14 -0
  242. package/plugins/lisa/skills/lisa-github-write-issue/SKILL.md +51 -0
  243. package/plugins/lisa/skills/lisa-intake/SKILL.md +1 -1
  244. package/plugins/lisa/skills/lisa-jira-build-intake/SKILL.md +27 -4
  245. package/plugins/lisa/skills/lisa-jira-validate-ticket/SKILL.md +22 -0
  246. package/plugins/lisa/skills/lisa-jira-verify/SKILL.md +14 -0
  247. package/plugins/lisa/skills/lisa-jira-write-ticket/SKILL.md +51 -0
  248. package/plugins/lisa/skills/lisa-linear-access/SKILL.md +55 -2
  249. package/plugins/lisa/skills/lisa-linear-build-intake/SKILL.md +27 -4
  250. package/plugins/lisa/skills/lisa-linear-prd-intake/SKILL.md +48 -31
  251. package/plugins/lisa/skills/lisa-linear-to-tracker/SKILL.md +3 -3
  252. package/plugins/lisa/skills/lisa-linear-validate-issue/SKILL.md +22 -0
  253. package/plugins/lisa/skills/lisa-linear-verify/SKILL.md +14 -0
  254. package/plugins/lisa/skills/lisa-linear-write-issue/SKILL.md +54 -3
  255. package/plugins/lisa/skills/lisa-prd-ticket-coverage/SKILL.md +2 -2
  256. package/plugins/lisa/skills/lisa-qa-clear/SKILL.md +19 -7
  257. package/plugins/lisa/skills/lisa-qa-fail/SKILL.md +28 -3
  258. package/plugins/lisa/skills/lisa-qa-queue/SKILL.md +28 -3
  259. package/plugins/lisa/skills/lisa-repair-intake/SKILL.md +94 -24
  260. package/plugins/lisa/skills/lisa-rework-triage/SKILL.md +32 -2
  261. package/plugins/lisa/skills/lisa-setup-linear/SKILL.md +5 -5
  262. package/plugins/lisa/skills/lisa-track/SKILL.md +1 -1
  263. package/plugins/lisa/skills/lisa-tracker-build-intake/SKILL.md +9 -0
  264. package/plugins/lisa-agy/agents/linear-prd-intake.md +8 -8
  265. package/plugins/lisa-agy/hooks/block-blind-automerge.sh +81 -2
  266. package/plugins/lisa-agy/hooks/block-direct-issue-create.agy.sh +64 -16
  267. package/plugins/lisa-agy/hooks/block-direct-issue-create.sh +293 -8
  268. package/plugins/lisa-agy/hooks/block-instruction-file-edits.sh +21 -0
  269. package/plugins/lisa-agy/hooks/block-managed-file-edits.sh +78 -15
  270. package/plugins/lisa-agy/hooks/block-shell-json-parsing.sh +21 -0
  271. package/plugins/lisa-agy/hooks/guard-dedupe.bash +337 -0
  272. package/plugins/lisa-agy/hooks/parity-safety-net.sh +29 -1
  273. package/plugins/lisa-agy/hooks.json +1 -1
  274. package/plugins/lisa-agy/plugin.json +1 -1
  275. package/plugins/lisa-agy/scripts/intake-blocker-reprobe.mjs +407 -26
  276. package/plugins/lisa-agy/scripts/qa-signal-lifecycle.mjs +507 -0
  277. package/plugins/lisa-agy/skills/lisa-drive-pr-to-merge/SKILL.md +130 -19
  278. package/plugins/lisa-agy/skills/lisa-github-build-intake/SKILL.md +27 -4
  279. package/plugins/lisa-agy/skills/lisa-github-prd-intake/SKILL.md +1 -1
  280. package/plugins/lisa-agy/skills/lisa-github-validate-issue/SKILL.md +22 -0
  281. package/plugins/lisa-agy/skills/lisa-github-verify/SKILL.md +14 -0
  282. package/plugins/lisa-agy/skills/lisa-github-write-issue/SKILL.md +51 -0
  283. package/plugins/lisa-agy/skills/lisa-intake/SKILL.md +1 -1
  284. package/plugins/lisa-agy/skills/lisa-jira-build-intake/SKILL.md +27 -4
  285. package/plugins/lisa-agy/skills/lisa-jira-validate-ticket/SKILL.md +22 -0
  286. package/plugins/lisa-agy/skills/lisa-jira-verify/SKILL.md +14 -0
  287. package/plugins/lisa-agy/skills/lisa-jira-write-ticket/SKILL.md +51 -0
  288. package/plugins/lisa-agy/skills/lisa-linear-access/SKILL.md +55 -2
  289. package/plugins/lisa-agy/skills/lisa-linear-build-intake/SKILL.md +27 -4
  290. package/plugins/lisa-agy/skills/lisa-linear-prd-intake/SKILL.md +48 -31
  291. package/plugins/lisa-agy/skills/lisa-linear-to-tracker/SKILL.md +3 -3
  292. package/plugins/lisa-agy/skills/lisa-linear-validate-issue/SKILL.md +22 -0
  293. package/plugins/lisa-agy/skills/lisa-linear-verify/SKILL.md +14 -0
  294. package/plugins/lisa-agy/skills/lisa-linear-write-issue/SKILL.md +54 -3
  295. package/plugins/lisa-agy/skills/lisa-prd-ticket-coverage/SKILL.md +2 -2
  296. package/plugins/lisa-agy/skills/lisa-qa-clear/SKILL.md +19 -7
  297. package/plugins/lisa-agy/skills/lisa-qa-fail/SKILL.md +28 -3
  298. package/plugins/lisa-agy/skills/lisa-qa-queue/SKILL.md +28 -3
  299. package/plugins/lisa-agy/skills/lisa-repair-intake/SKILL.md +94 -24
  300. package/plugins/lisa-agy/skills/lisa-rework-triage/SKILL.md +32 -2
  301. package/plugins/lisa-agy/skills/lisa-setup-linear/SKILL.md +5 -5
  302. package/plugins/lisa-agy/skills/lisa-track/SKILL.md +1 -1
  303. package/plugins/lisa-agy/skills/lisa-tracker-build-intake/SKILL.md +9 -0
  304. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  305. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  306. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  307. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  308. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  309. package/plugins/lisa-copilot/.claude-plugin/plugin.json +19 -1
  310. package/plugins/lisa-copilot/agents/linear-prd-intake.agent.md +8 -8
  311. package/plugins/lisa-copilot/hooks/block-blind-automerge.sh +81 -2
  312. package/plugins/lisa-copilot/hooks/block-direct-issue-create.sh +293 -8
  313. package/plugins/lisa-copilot/hooks/block-instruction-file-edits.sh +21 -0
  314. package/plugins/lisa-copilot/hooks/block-managed-file-edits.sh +78 -15
  315. package/plugins/lisa-copilot/hooks/block-no-verify.sh +21 -0
  316. package/plugins/lisa-copilot/hooks/block-shell-json-parsing.sh +21 -0
  317. package/plugins/lisa-copilot/hooks/failure-signature-index.mjs +240 -5
  318. package/plugins/lisa-copilot/hooks/guard-dedupe.bash +337 -0
  319. package/plugins/lisa-copilot/hooks/inject-rules.sh +13 -5
  320. package/plugins/lisa-copilot/hooks/operational-hazards.mjs +736 -0
  321. package/plugins/lisa-copilot/hooks/operational-hazards.sh +28 -0
  322. package/plugins/lisa-copilot/hooks/parity-safety-net.sh +29 -1
  323. package/plugins/lisa-copilot/hooks/threshold-ratchet-compare.mjs +102 -21
  324. package/plugins/lisa-copilot/hooks/threshold-ratchet-families.mjs +130 -2
  325. package/plugins/lisa-copilot/hooks/threshold-ratchet.mjs +63 -13
  326. package/plugins/lisa-copilot/hooks/worktree-binding-guard.mjs +183 -1
  327. package/plugins/lisa-copilot/hooks/worktree-binding-guard.sh +21 -0
  328. package/plugins/lisa-copilot/rules/eager/00-rule-index.md +1 -0
  329. package/plugins/lisa-copilot/rules/eager/operational-hazards.md +50 -0
  330. package/plugins/lisa-copilot/rules/eager/tracked-work.md +1 -1
  331. package/plugins/lisa-copilot/rules/reference/config-resolution.md +1 -1
  332. package/plugins/lisa-copilot/rules/reference/leaf-only-lifecycle.md +1 -1
  333. package/plugins/lisa-copilot/rules/reference/operational-hazards.md +115 -0
  334. package/plugins/lisa-copilot/rules/reference/work-item-trailer-definition.md +129 -0
  335. package/plugins/lisa-copilot/scripts/intake-blocker-reprobe.mjs +407 -26
  336. package/plugins/lisa-copilot/scripts/qa-signal-lifecycle.mjs +507 -0
  337. package/plugins/lisa-copilot/skills/lisa-drive-pr-to-merge/SKILL.md +130 -19
  338. package/plugins/lisa-copilot/skills/lisa-github-build-intake/SKILL.md +27 -4
  339. package/plugins/lisa-copilot/skills/lisa-github-prd-intake/SKILL.md +1 -1
  340. package/plugins/lisa-copilot/skills/lisa-github-validate-issue/SKILL.md +22 -0
  341. package/plugins/lisa-copilot/skills/lisa-github-verify/SKILL.md +14 -0
  342. package/plugins/lisa-copilot/skills/lisa-github-write-issue/SKILL.md +51 -0
  343. package/plugins/lisa-copilot/skills/lisa-intake/SKILL.md +1 -1
  344. package/plugins/lisa-copilot/skills/lisa-jira-build-intake/SKILL.md +27 -4
  345. package/plugins/lisa-copilot/skills/lisa-jira-validate-ticket/SKILL.md +22 -0
  346. package/plugins/lisa-copilot/skills/lisa-jira-verify/SKILL.md +14 -0
  347. package/plugins/lisa-copilot/skills/lisa-jira-write-ticket/SKILL.md +51 -0
  348. package/plugins/lisa-copilot/skills/lisa-linear-access/SKILL.md +55 -2
  349. package/plugins/lisa-copilot/skills/lisa-linear-build-intake/SKILL.md +27 -4
  350. package/plugins/lisa-copilot/skills/lisa-linear-prd-intake/SKILL.md +48 -31
  351. package/plugins/lisa-copilot/skills/lisa-linear-to-tracker/SKILL.md +3 -3
  352. package/plugins/lisa-copilot/skills/lisa-linear-validate-issue/SKILL.md +22 -0
  353. package/plugins/lisa-copilot/skills/lisa-linear-verify/SKILL.md +14 -0
  354. package/plugins/lisa-copilot/skills/lisa-linear-write-issue/SKILL.md +54 -3
  355. package/plugins/lisa-copilot/skills/lisa-prd-ticket-coverage/SKILL.md +2 -2
  356. package/plugins/lisa-copilot/skills/lisa-qa-clear/SKILL.md +19 -7
  357. package/plugins/lisa-copilot/skills/lisa-qa-fail/SKILL.md +28 -3
  358. package/plugins/lisa-copilot/skills/lisa-qa-queue/SKILL.md +28 -3
  359. package/plugins/lisa-copilot/skills/lisa-repair-intake/SKILL.md +94 -24
  360. package/plugins/lisa-copilot/skills/lisa-rework-triage/SKILL.md +32 -2
  361. package/plugins/lisa-copilot/skills/lisa-setup-linear/SKILL.md +5 -5
  362. package/plugins/lisa-copilot/skills/lisa-track/SKILL.md +1 -1
  363. package/plugins/lisa-copilot/skills/lisa-tracker-build-intake/SKILL.md +9 -0
  364. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  365. package/plugins/lisa-cursor/agents/linear-prd-intake.md +8 -8
  366. package/plugins/lisa-cursor/hooks/block-blind-automerge.sh +81 -2
  367. package/plugins/lisa-cursor/hooks/block-direct-issue-create.sh +293 -8
  368. package/plugins/lisa-cursor/hooks/block-instruction-file-edits.sh +21 -0
  369. package/plugins/lisa-cursor/hooks/block-managed-file-edits.sh +78 -15
  370. package/plugins/lisa-cursor/hooks/block-no-verify.sh +21 -0
  371. package/plugins/lisa-cursor/hooks/block-shell-json-parsing.sh +21 -0
  372. package/plugins/lisa-cursor/hooks/failure-signature-index.mjs +240 -5
  373. package/plugins/lisa-cursor/hooks/guard-dedupe.bash +337 -0
  374. package/plugins/lisa-cursor/hooks/hooks.json +10 -0
  375. package/plugins/lisa-cursor/hooks/operational-hazards.mjs +736 -0
  376. package/plugins/lisa-cursor/hooks/operational-hazards.sh +28 -0
  377. package/plugins/lisa-cursor/hooks/parity-safety-net.sh +29 -1
  378. package/plugins/lisa-cursor/hooks/threshold-ratchet-compare.mjs +102 -21
  379. package/plugins/lisa-cursor/hooks/threshold-ratchet-families.mjs +130 -2
  380. package/plugins/lisa-cursor/hooks/threshold-ratchet.mjs +63 -13
  381. package/plugins/lisa-cursor/hooks/worktree-binding-guard.mjs +183 -1
  382. package/plugins/lisa-cursor/hooks/worktree-binding-guard.sh +21 -0
  383. package/plugins/lisa-cursor/rules/00-rule-index.mdc +1 -0
  384. package/plugins/lisa-cursor/rules/config-resolution-reference.mdc +1 -1
  385. package/plugins/lisa-cursor/rules/leaf-only-lifecycle-reference.mdc +1 -1
  386. package/plugins/lisa-cursor/rules/operational-hazards-reference.mdc +120 -0
  387. package/plugins/lisa-cursor/rules/operational-hazards.mdc +55 -0
  388. package/plugins/lisa-cursor/rules/tracked-work.mdc +1 -1
  389. package/plugins/lisa-cursor/rules/work-item-trailer-definition-reference.mdc +134 -0
  390. package/plugins/lisa-cursor/scripts/intake-blocker-reprobe.mjs +407 -26
  391. package/plugins/lisa-cursor/scripts/qa-signal-lifecycle.mjs +507 -0
  392. package/plugins/lisa-cursor/skills/lisa-drive-pr-to-merge/SKILL.md +130 -19
  393. package/plugins/lisa-cursor/skills/lisa-github-build-intake/SKILL.md +27 -4
  394. package/plugins/lisa-cursor/skills/lisa-github-prd-intake/SKILL.md +1 -1
  395. package/plugins/lisa-cursor/skills/lisa-github-validate-issue/SKILL.md +22 -0
  396. package/plugins/lisa-cursor/skills/lisa-github-verify/SKILL.md +14 -0
  397. package/plugins/lisa-cursor/skills/lisa-github-write-issue/SKILL.md +51 -0
  398. package/plugins/lisa-cursor/skills/lisa-intake/SKILL.md +1 -1
  399. package/plugins/lisa-cursor/skills/lisa-jira-build-intake/SKILL.md +27 -4
  400. package/plugins/lisa-cursor/skills/lisa-jira-validate-ticket/SKILL.md +22 -0
  401. package/plugins/lisa-cursor/skills/lisa-jira-verify/SKILL.md +14 -0
  402. package/plugins/lisa-cursor/skills/lisa-jira-write-ticket/SKILL.md +51 -0
  403. package/plugins/lisa-cursor/skills/lisa-linear-access/SKILL.md +55 -2
  404. package/plugins/lisa-cursor/skills/lisa-linear-build-intake/SKILL.md +27 -4
  405. package/plugins/lisa-cursor/skills/lisa-linear-prd-intake/SKILL.md +48 -31
  406. package/plugins/lisa-cursor/skills/lisa-linear-to-tracker/SKILL.md +3 -3
  407. package/plugins/lisa-cursor/skills/lisa-linear-validate-issue/SKILL.md +22 -0
  408. package/plugins/lisa-cursor/skills/lisa-linear-verify/SKILL.md +14 -0
  409. package/plugins/lisa-cursor/skills/lisa-linear-write-issue/SKILL.md +54 -3
  410. package/plugins/lisa-cursor/skills/lisa-prd-ticket-coverage/SKILL.md +2 -2
  411. package/plugins/lisa-cursor/skills/lisa-qa-clear/SKILL.md +19 -7
  412. package/plugins/lisa-cursor/skills/lisa-qa-fail/SKILL.md +28 -3
  413. package/plugins/lisa-cursor/skills/lisa-qa-queue/SKILL.md +28 -3
  414. package/plugins/lisa-cursor/skills/lisa-repair-intake/SKILL.md +94 -24
  415. package/plugins/lisa-cursor/skills/lisa-rework-triage/SKILL.md +32 -2
  416. package/plugins/lisa-cursor/skills/lisa-setup-linear/SKILL.md +5 -5
  417. package/plugins/lisa-cursor/skills/lisa-track/SKILL.md +1 -1
  418. package/plugins/lisa-cursor/skills/lisa-tracker-build-intake/SKILL.md +9 -0
  419. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  420. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  421. package/plugins/lisa-expo-agy/plugin.json +1 -1
  422. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  423. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  424. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  425. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  426. package/plugins/lisa-harper-fabric/hooks/inject-rules.sh +14 -3
  427. package/plugins/lisa-harper-fabric/rules/eager/harper-fabric.md +31 -0
  428. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  429. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  430. package/plugins/lisa-harper-fabric-copilot/hooks/inject-rules.sh +14 -3
  431. package/plugins/lisa-harper-fabric-copilot/rules/eager/harper-fabric.md +31 -0
  432. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  433. package/plugins/lisa-harper-fabric-cursor/rules/harper-fabric-reference.mdc +57 -0
  434. package/plugins/lisa-harper-fabric-cursor/rules/harper-fabric.mdc +32 -53
  435. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  436. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  437. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  438. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  439. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  440. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  441. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  442. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  443. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  444. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  445. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  446. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  447. package/plugins/lisa-phaser/hooks/inject-rules.sh +14 -3
  448. package/plugins/lisa-phaser/rules/eager/phaser.md +44 -0
  449. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  450. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  451. package/plugins/lisa-phaser-copilot/hooks/inject-rules.sh +14 -3
  452. package/plugins/lisa-phaser-copilot/rules/eager/phaser.md +44 -0
  453. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  454. package/plugins/lisa-phaser-cursor/rules/phaser-reference.mdc +189 -0
  455. package/plugins/lisa-phaser-cursor/rules/phaser.mdc +45 -185
  456. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  457. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  458. package/plugins/lisa-rails/hooks/inject-rules.sh +14 -4
  459. package/plugins/lisa-rails/rules/eager/rails-conventions.md +23 -0
  460. package/plugins/lisa-rails-agy/plugin.json +1 -1
  461. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  462. package/plugins/lisa-rails-copilot/hooks/inject-rules.sh +14 -4
  463. package/plugins/lisa-rails-copilot/rules/eager/rails-conventions.md +23 -0
  464. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  465. package/plugins/lisa-rails-cursor/rules/rails-conventions-reference.mdc +181 -0
  466. package/plugins/lisa-rails-cursor/rules/rails-conventions.mdc +24 -177
  467. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  468. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  469. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  470. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  471. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  472. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  473. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  474. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  475. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  476. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  477. package/plugins/materialized-artifacts.json +1 -0
  478. package/plugins/src/base/.claude-plugin/plugin.json +27 -0
  479. package/plugins/src/base/agents/linear-prd-intake.md +8 -8
  480. package/plugins/src/base/hooks/block-blind-automerge.sh +81 -2
  481. package/plugins/src/base/hooks/block-direct-issue-create.agy.sh +64 -16
  482. package/plugins/src/base/hooks/block-direct-issue-create.sh +293 -8
  483. package/plugins/src/base/hooks/block-instruction-file-edits.sh +21 -0
  484. package/plugins/src/base/hooks/block-managed-file-edits.sh +78 -15
  485. package/plugins/src/base/hooks/block-no-verify.sh +21 -0
  486. package/plugins/src/base/hooks/block-shell-json-parsing.sh +21 -0
  487. package/plugins/src/base/hooks/failure-signature-index.mjs +240 -5
  488. package/plugins/src/base/hooks/guard-dedupe.bash +337 -0
  489. package/plugins/src/base/hooks/inject-rules.sh +13 -5
  490. package/plugins/src/base/hooks/operational-hazards.mjs +736 -0
  491. package/plugins/src/base/hooks/operational-hazards.sh +28 -0
  492. package/plugins/src/base/hooks/parity-safety-net.sh +29 -1
  493. package/plugins/src/base/hooks/threshold-ratchet-compare.mjs +102 -21
  494. package/plugins/src/base/hooks/threshold-ratchet-families.mjs +130 -2
  495. package/plugins/src/base/hooks/threshold-ratchet.mjs +63 -13
  496. package/plugins/src/base/hooks/worktree-binding-guard.mjs +183 -1
  497. package/plugins/src/base/hooks/worktree-binding-guard.sh +21 -0
  498. package/plugins/src/base/rules/eager/00-rule-index.md +1 -0
  499. package/plugins/src/base/rules/eager/operational-hazards.md +50 -0
  500. package/plugins/src/base/rules/eager/tracked-work.md +1 -1
  501. package/plugins/src/base/rules/reference/config-resolution.md +1 -1
  502. package/plugins/src/base/rules/reference/leaf-only-lifecycle.md +1 -1
  503. package/plugins/src/base/rules/reference/operational-hazards.md +115 -0
  504. package/plugins/src/base/rules/reference/work-item-trailer-definition.md +129 -0
  505. package/plugins/src/base/scripts/intake-blocker-reprobe.mjs +407 -26
  506. package/plugins/src/base/scripts/qa-signal-lifecycle.mjs +507 -0
  507. package/plugins/src/base/skills/lisa-drive-pr-to-merge/SKILL.md +130 -19
  508. package/plugins/src/base/skills/lisa-github-build-intake/SKILL.md +27 -4
  509. package/plugins/src/base/skills/lisa-github-prd-intake/SKILL.md +1 -1
  510. package/plugins/src/base/skills/lisa-github-validate-issue/SKILL.md +22 -0
  511. package/plugins/src/base/skills/lisa-github-verify/SKILL.md +14 -0
  512. package/plugins/src/base/skills/lisa-github-write-issue/SKILL.md +51 -0
  513. package/plugins/src/base/skills/lisa-intake/SKILL.md +1 -1
  514. package/plugins/src/base/skills/lisa-jira-build-intake/SKILL.md +27 -4
  515. package/plugins/src/base/skills/lisa-jira-validate-ticket/SKILL.md +22 -0
  516. package/plugins/src/base/skills/lisa-jira-verify/SKILL.md +14 -0
  517. package/plugins/src/base/skills/lisa-jira-write-ticket/SKILL.md +51 -0
  518. package/plugins/src/base/skills/lisa-linear-access/SKILL.md +55 -2
  519. package/plugins/src/base/skills/lisa-linear-build-intake/SKILL.md +27 -4
  520. package/plugins/src/base/skills/lisa-linear-prd-intake/SKILL.md +48 -31
  521. package/plugins/src/base/skills/lisa-linear-to-tracker/SKILL.md +3 -3
  522. package/plugins/src/base/skills/lisa-linear-validate-issue/SKILL.md +22 -0
  523. package/plugins/src/base/skills/lisa-linear-verify/SKILL.md +14 -0
  524. package/plugins/src/base/skills/lisa-linear-write-issue/SKILL.md +54 -3
  525. package/plugins/src/base/skills/lisa-prd-ticket-coverage/SKILL.md +2 -2
  526. package/plugins/src/base/skills/lisa-qa-clear/SKILL.md +19 -7
  527. package/plugins/src/base/skills/lisa-qa-fail/SKILL.md +28 -3
  528. package/plugins/src/base/skills/lisa-qa-queue/SKILL.md +28 -3
  529. package/plugins/src/base/skills/lisa-repair-intake/SKILL.md +94 -24
  530. package/plugins/src/base/skills/lisa-rework-triage/SKILL.md +32 -2
  531. package/plugins/src/base/skills/lisa-setup-linear/SKILL.md +5 -5
  532. package/plugins/src/base/skills/lisa-track/SKILL.md +1 -1
  533. package/plugins/src/base/skills/lisa-tracker-build-intake/SKILL.md +9 -0
  534. package/plugins/src/harper-fabric/hooks/inject-rules.sh +14 -3
  535. package/plugins/src/harper-fabric/rules/eager/harper-fabric.md +31 -0
  536. package/plugins/src/phaser/hooks/inject-rules.sh +14 -3
  537. package/plugins/src/phaser/rules/eager/phaser.md +44 -0
  538. package/plugins/src/rails/hooks/inject-rules.sh +14 -4
  539. package/plugins/src/rails/rules/eager/rails-conventions.md +23 -0
  540. package/rails/copy-overwrite/scripts/check-threshold-ratchet.mjs +63 -13
  541. package/rails/copy-overwrite/scripts/threshold-ratchet-compare.mjs +102 -21
  542. package/rails/copy-overwrite/scripts/threshold-ratchet-families.mjs +130 -2
  543. package/rails/create-only/.github/workflows/ci.yml +8 -0
  544. package/rails/create-only/.github/workflows/deploy.yml +22 -0
  545. package/scripts/build-plugins.sh +2 -1
  546. package/scripts/check-engine-floor.mjs +361 -0
  547. package/scripts/check-guard-parity-notes.mjs +709 -0
  548. package/scripts/check-template-workflow-refs.mjs +9 -0
  549. package/scripts/check-third-party-action-pins.mjs +17 -1
  550. package/scripts/check-workflow-contract-assertions.mjs +480 -0
  551. package/scripts/copy-opencode-plugin-templates.mjs +1 -0
  552. package/scripts/deployed-guard-advice.mjs +636 -0
  553. package/scripts/generate-agy-plugin-artifacts.mjs +35 -10
  554. package/scripts/generate-export-surface.mjs +105 -19
  555. package/scripts/generate-two-channel-couplings.ts +143 -212
  556. package/scripts/lisa-enforcement-fallback.sh +31 -0
  557. package/scripts/measure-scripts-profile-gap.mts +361 -0
  558. package/scripts/mutation-performance-measure.mjs +21 -5
  559. package/scripts/reconcile-release-tags.mjs +65 -84
  560. package/scripts/two-channel-couplings.json +302 -70
  561. package/scripts/workflow-contract-assertion.sh +47 -0
  562. package/typescript/copy-overwrite/.lintstagedrc.json +1 -0
  563. package/typescript/copy-overwrite/eslint.ignore.config.json +1 -0
  564. package/typescript/copy-overwrite/scripts/check-nightly-e2e-health.mjs +527 -53
  565. package/typescript/copy-overwrite/scripts/check-skipped-required-checks.mjs +301 -13
  566. package/typescript/copy-overwrite/scripts/check-threshold-ratchet.mjs +63 -13
  567. package/typescript/copy-overwrite/scripts/threshold-ratchet-compare.mjs +102 -21
  568. package/typescript/copy-overwrite/scripts/threshold-ratchet-families.mjs +130 -2
  569. package/typescript/create-only/.github/workflows/ci.yml +7 -0
  570. /package/plugins/lisa-harper-fabric/rules/{harper-fabric.md → reference/harper-fabric.md} +0 -0
  571. /package/plugins/lisa-harper-fabric-copilot/rules/{harper-fabric.md → reference/harper-fabric.md} +0 -0
  572. /package/plugins/lisa-phaser/rules/{phaser.md → reference/phaser.md} +0 -0
  573. /package/plugins/lisa-phaser-copilot/rules/{phaser.md → reference/phaser.md} +0 -0
  574. /package/plugins/lisa-rails/rules/{rails-conventions.md → reference/rails-conventions.md} +0 -0
  575. /package/plugins/lisa-rails-copilot/rules/{rails-conventions.md → reference/rails-conventions.md} +0 -0
  576. /package/plugins/src/harper-fabric/rules/{harper-fabric.md → reference/harper-fabric.md} +0 -0
  577. /package/plugins/src/phaser/rules/{phaser.md → reference/phaser.md} +0 -0
  578. /package/plugins/src/rails/rules/{rails-conventions.md → reference/rails-conventions.md} +0 -0
@@ -28,6 +28,15 @@
28
28
  * This script reads what the templates actually reference and confirms the
29
29
  * target exists. Only that.
30
30
  *
31
+ * Its sibling, `check-workflow-contract-assertions.mjs`, answers the question
32
+ * this one cannot: a reference that resolves today still says nothing about
33
+ * whether what it resolves TO has changed under the consumer. Under the `@main`
34
+ * ruling one push here alters what gates and what ships in every downstream
35
+ * repository at once, and an unchanged workflow and a rewritten one produce
36
+ * identical silence (CodySwannGT/lisa#3698). That gate requires each reusable to
37
+ * declare a contract major and each caller template to be seeded with it, and
38
+ * the two run in the same CI step so neither can be adopted without the other.
39
+ *
31
40
  * Determinism guarantees (so the unit test is reproducible and CI is stable):
32
41
  * - zero third-party dependencies (Node built-ins only),
33
42
  * - no network access,
@@ -158,8 +158,24 @@ const NO_VERSION = "missing-version-comment";
158
158
  * `uses: <owner>/<repo>[/<subpath>]@<ref>` with anything after it captured, so
159
159
  * a trailing `# v1.2.3` can be read. Local (`./path`) and container
160
160
  * (`docker://`) references have no owner and never match.
161
+ *
162
+ * The value may be QUOTED, and that is not a stylistic detail here. YAML
163
+ * accepts `uses: "owner/repo@ref"` and `uses: 'owner/repo@ref'` as the same
164
+ * scalar GitHub Actions resolves identically, but a value class that excluded
165
+ * quotes could not begin matching at one — so a quoted reference did not fail
166
+ * the scan, it left it entirely, and the gate reported clean over an entry it
167
+ * had never inspected. A pin checker that silently skips a spelling is a
168
+ * vacuous pass on every reference written that way, which is the failure this
169
+ * gate exists to close rather than to reproduce.
170
+ *
171
+ * The closing quote is matched by back-reference so `"a'` cannot read as a
172
+ * quoted value, and it is consumed by the match so the trailing `# v1.2.3` is
173
+ * still found by the slice in `findActionRefs`. An unquoted value binds the
174
+ * group to the empty string, where the back-reference matches empty and the
175
+ * pattern behaves exactly as it did before.
161
176
  */
162
- const USES_RE = /^[ \t]*(?:-[ \t]*)?uses:[ \t]*(?<value>[^\s"'#]+)/;
177
+ const USES_RE =
178
+ /^[ \t]*(?:-[ \t]*)?uses:[ \t]*(?<quote>["']?)(?<value>[^\s"'#]+)\k<quote>/;
163
179
 
164
180
  /** A well-formed action owner. Anchored, so matching is linear. */
165
181
  const OWNER_RE = /^[A-Za-z0-9][A-Za-z0-9-]*$/;
@@ -0,0 +1,480 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Deterministic gate that every Lisa reusable workflow carries a staleness
4
+ * assertion, and that every shipped caller template is seeded with it
5
+ * (CodySwannGT/lisa#3698).
6
+ *
7
+ * ## The defect
8
+ *
9
+ * Every consumer reference to a Lisa reusable workflow tracks `@main` by owner
10
+ * ruling. One push here changes what gates — and what ships — in every
11
+ * downstream repository simultaneously, with no pull request, no review and no
12
+ * record in those repositories. That is intended, and it removed pinning as a
13
+ * mitigation without putting anything in its place:
14
+ *
15
+ * **a consumer silently receives a behaviour change, or silently receives
16
+ * nothing, and has no signal either way.**
17
+ *
18
+ * An unchanged workflow and a rewritten one produce identical silence. It is
19
+ * also why an audit cannot reproduce itself: an investigation that fetches
20
+ * `@main` afterwards is reading a different artifact than the run it is
21
+ * investigating, and cannot tell.
22
+ *
23
+ * ## What is asserted, and what deliberately is not
24
+ *
25
+ * Not the ref. A staleness check that pins a tag, a SHA or a tree hash goes red
26
+ * on every legitimate upstream change, and a check that is red for good reasons
27
+ * is disabled within a week — the staleness check becomes the staleness
28
+ * problem. What a caller depends on is the CONTRACT: the inputs it passes and
29
+ * the behaviour it relies on. So each reusable declares a contract MAJOR, each
30
+ * caller is seeded with the major it was written against, and the workflow
31
+ * compares the two at run time. A compatible change stays green, because
32
+ * receiving compatible changes is the whole point of tracking `@main`; only a
33
+ * declared break speaks up, naming both numbers.
34
+ *
35
+ * ## Why this gate exists on top of the run-time assertion
36
+ *
37
+ * The assertion and the `uses:` line are one unit. A template that takes the
38
+ * reference and drops the assertion is back to silent staleness and looks
39
+ * perfectly healthy doing it, so the two must not be separable by copy-paste.
40
+ * This gate is the thing that refuses that separation, and it is the reason the
41
+ * run-time half can afford to be non-fatal when a caller declares nothing.
42
+ *
43
+ * Local `./.github/workflows/...` callers inside this repository are
44
+ * deliberately exempt: a local reference resolves at the same commit as its
45
+ * caller and so cannot be stale. Requiring the assertion there would be a check
46
+ * that could not fail.
47
+ *
48
+ * Determinism: no network, no clock, no randomness. The template list comes
49
+ * from `git ls-files`, so the gate sees exactly what a release would carry.
50
+ *
51
+ * CLI:
52
+ * node scripts/check-workflow-contract-assertions.mjs [--root <dir>] [--json]
53
+ *
54
+ * Exit codes:
55
+ * 0 — every reusable is registered and asserts, every caller template is
56
+ * seeded with the current major.
57
+ * 1 — ≥1 finding.
58
+ * 2 — NOT DETERMINED: the registry or the canonical assertion body could not
59
+ * be read, or the scan discovered zero reusable workflows or zero caller
60
+ * templates. A gate that could not look must not report that it looked.
61
+ *
62
+ * @module scripts/check-workflow-contract-assertions
63
+ */
64
+ import yaml from "js-yaml";
65
+ import fs from "node:fs";
66
+ import path from "node:path";
67
+ import process from "node:process";
68
+ import { fileURLToPath } from "node:url";
69
+
70
+ import { boundedExecFileSync } from "./lib/bounded-spawn.mjs";
71
+ import { invokedAsScript } from "./lib/invoked-as-script.mjs";
72
+
73
+ const REPO_ROOT = path.resolve(
74
+ path.dirname(fileURLToPath(import.meta.url)),
75
+ ".."
76
+ );
77
+
78
+ /** Where the declared majors live. */
79
+ export const REGISTRY_REL = ".github/reusable-workflow-contracts.json";
80
+
81
+ /** The single source of truth for the inlined assertion body. */
82
+ export const CANONICAL_REL = "scripts/workflow-contract-assertion.sh";
83
+
84
+ /** The input a caller passes and the workflow compares. */
85
+ export const INPUT_NAME = "expected_workflow_contract_major";
86
+
87
+ /** The job every covered reusable carries. */
88
+ export const JOB_ID = "workflow_contract";
89
+
90
+ /** `<lane>/<mode>/.github/workflows/<name>.yml` — a SHIPPED caller template. */
91
+ const TEMPLATE_RE = /^[^/]+\/[^/]+\/\.github\/workflows\/[^/]+\.ya?ml$/;
92
+
93
+ /** `CodySwannGT/lisa/.github/workflows/<file>@<ref>`. */
94
+ const REMOTE_USES_RE =
95
+ /^CodySwannGT\/lisa\/\.github\/workflows\/([\w.-]+\.ya?ml)@\S+$/;
96
+
97
+ /** Max bytes of `git ls-files` output. */
98
+ const MAX_GIT_OUTPUT_BYTES = 64 * 1024 * 1024;
99
+
100
+ /** Raised for an invalid invocation or a state the gate cannot judge. */
101
+ export class UsageError extends Error {}
102
+
103
+ /**
104
+ * Parse a workflow file, returning `null` when it is not a mapping.
105
+ *
106
+ * @param {string} file - absolute path.
107
+ * @returns {Record<string, unknown> | null} the parsed document.
108
+ */
109
+ function loadWorkflow(file) {
110
+ const document = yaml.load(fs.readFileSync(file, "utf8"));
111
+ return document !== null && typeof document === "object" ? document : null;
112
+ }
113
+
114
+ /**
115
+ * The `workflow_call` block of a parsed workflow, or `null` when the workflow
116
+ * is not reusable.
117
+ *
118
+ * @param {Record<string, unknown> | null} document - a parsed workflow.
119
+ * @returns {Record<string, unknown> | null} the `workflow_call` mapping.
120
+ */
121
+ export function workflowCallOf(document) {
122
+ const triggers = document?.on;
123
+ if (triggers === null || typeof triggers !== "object") return null;
124
+ const call = triggers.workflow_call;
125
+ if (call === undefined) return null;
126
+ return call !== null && typeof call === "object" ? call : {};
127
+ }
128
+
129
+ /**
130
+ * Validate one registry entry's shape.
131
+ *
132
+ * @param {unknown} entry - the value stored for a workflow.
133
+ * @returns {string | null} a complaint, or `null` when the entry is well formed.
134
+ */
135
+ export function describeEntryProblem(entry) {
136
+ if (entry === null || typeof entry !== "object") {
137
+ return "entry is not an object";
138
+ }
139
+ const hasMajor = Object.hasOwn(entry, "major");
140
+ const hasUncovered = Object.hasOwn(entry, "uncovered");
141
+ if (hasMajor === hasUncovered) {
142
+ return "entry must carry exactly one of `major` or `uncovered`";
143
+ }
144
+ if (hasUncovered) {
145
+ return typeof entry.uncovered === "string" && entry.uncovered.trim() !== ""
146
+ ? null
147
+ : "`uncovered` must be a non-empty reason, so a gap is recorded rather than inherited";
148
+ }
149
+ return Number.isInteger(entry.major) && entry.major >= 1
150
+ ? null
151
+ : "`major` must be an integer >= 1";
152
+ }
153
+
154
+ /**
155
+ * Findings about ONE covered reusable workflow: does it declare the input, and
156
+ * does it carry the assertion job with the canonical body?
157
+ *
158
+ * @param {{ file: string, major: number, document: Record<string, unknown>, canonical: string }} subject
159
+ * the workflow under inspection.
160
+ * @returns {string[]} complaints, empty when the workflow is conformant.
161
+ */
162
+ export function auditReusable(subject) {
163
+ const { canonical, document, file, major } = subject;
164
+ const problems = [];
165
+ const declared = workflowCallOf(document)?.inputs?.[INPUT_NAME];
166
+ if (declared === undefined) {
167
+ problems.push(`does not declare the \`${INPUT_NAME}\` input`);
168
+ } else if (declared.type !== "string" || declared.default !== "") {
169
+ problems.push(
170
+ `\`${INPUT_NAME}\` must be \`type: string\` with \`default: ''\` so an absent value is distinguishable from a declared one`
171
+ );
172
+ }
173
+ const job = document?.jobs?.[JOB_ID];
174
+ if (job === undefined) {
175
+ problems.push(
176
+ `has no \`${JOB_ID}\` job, so a caller is never told anything`
177
+ );
178
+ return problems;
179
+ }
180
+ const step = (job.steps ?? []).find(
181
+ candidate => candidate?.env?.DECLARED_MAJOR !== undefined
182
+ );
183
+ if (step === undefined) {
184
+ problems.push(`\`${JOB_ID}\` has no step declaring \`DECLARED_MAJOR\``);
185
+ return problems;
186
+ }
187
+ if (String(step.env.DECLARED_MAJOR) !== String(major)) {
188
+ problems.push(
189
+ `declares major ${step.env.DECLARED_MAJOR} but ${REGISTRY_REL} records ${major} — bump both in one commit`
190
+ );
191
+ }
192
+ if (step.env.WORKFLOW_FILE !== file) {
193
+ problems.push(
194
+ `names \`${step.env.WORKFLOW_FILE}\` in WORKFLOW_FILE; a mismatch sends a reader to the wrong file`
195
+ );
196
+ }
197
+ if (step.env.EXPECTED_MAJOR !== `\${{ inputs.${INPUT_NAME} }}`) {
198
+ problems.push(
199
+ `EXPECTED_MAJOR must read \`\${{ inputs.${INPUT_NAME} }}\`, otherwise the comparison is against something the caller never passed`
200
+ );
201
+ }
202
+ if (String(step.run ?? "").trimEnd() !== canonical.trimEnd()) {
203
+ problems.push(
204
+ `the inlined assertion has drifted from ${CANONICAL_REL}; copy it back verbatim`
205
+ );
206
+ }
207
+ return problems;
208
+ }
209
+
210
+ /**
211
+ * Every remote Lisa reference in one caller template, with the value seeded
212
+ * beside it.
213
+ *
214
+ * @param {Record<string, unknown> | null} document - a parsed caller template.
215
+ * @returns {{ job: string, target: string, seeded: unknown }[]} one per reference.
216
+ */
217
+ export function callerReferences(document) {
218
+ const jobs = document?.jobs;
219
+ if (jobs === null || typeof jobs !== "object") return [];
220
+ const references = [];
221
+ for (const [job, definition] of Object.entries(jobs)) {
222
+ const uses = definition?.uses;
223
+ if (typeof uses !== "string") continue;
224
+ const match = REMOTE_USES_RE.exec(uses.trim());
225
+ if (match === null) continue;
226
+ references.push({
227
+ job,
228
+ seeded: definition?.with?.[INPUT_NAME],
229
+ target: match[1],
230
+ });
231
+ }
232
+ return references;
233
+ }
234
+
235
+ /**
236
+ * List every tracked file in `root`, relative to it.
237
+ *
238
+ * @param {string} root - the repository root.
239
+ * @returns {string[]} tracked paths.
240
+ */
241
+ function listTrackedFiles(root) {
242
+ let stdout;
243
+ try {
244
+ stdout = boundedExecFileSync("git", ["-C", root, "ls-files", "-z"], {
245
+ encoding: "utf8",
246
+ maxBuffer: MAX_GIT_OUTPUT_BYTES,
247
+ stdio: ["ignore", "pipe", "ignore"],
248
+ });
249
+ } catch (error) {
250
+ throw new UsageError(
251
+ `could not list tracked files in ${root}: ${error.message}`
252
+ );
253
+ }
254
+ return stdout.split("\0").filter(entry => entry !== "");
255
+ }
256
+
257
+ /**
258
+ * Parse argv into resolved options.
259
+ *
260
+ * @param {readonly string[]} argv - arguments (without node/script prefix).
261
+ * @returns {{ root: string, json: boolean }} options.
262
+ */
263
+ export function parseArgs(argv) {
264
+ let root = null;
265
+ let json = false;
266
+ for (let index = 0; index < argv.length; index++) {
267
+ const arg = argv[index];
268
+ if (arg === "--json") {
269
+ json = true;
270
+ } else if (arg === "--root") {
271
+ const next = argv[index + 1];
272
+ if (next === undefined || next.startsWith("--")) {
273
+ throw new UsageError("--root requires a value");
274
+ }
275
+ root = next;
276
+ index += 1;
277
+ } else {
278
+ throw new UsageError(`unknown argument: ${arg}`);
279
+ }
280
+ }
281
+ return { json, root: path.resolve(root ?? REPO_ROOT) };
282
+ }
283
+
284
+ /**
285
+ * Read the registry and the canonical assertion body, or refuse.
286
+ *
287
+ * @param {string} root - the repository root.
288
+ * @returns {{ registry: Record<string, unknown>, canonical: string }} the inputs.
289
+ */
290
+ function readContract(root) {
291
+ let registry;
292
+ try {
293
+ registry = JSON.parse(
294
+ fs.readFileSync(path.join(root, REGISTRY_REL), "utf8")
295
+ );
296
+ } catch (error) {
297
+ throw new UsageError(`could not read ${REGISTRY_REL}: ${error.message}`);
298
+ }
299
+ if (registry?.workflows === null || typeof registry?.workflows !== "object") {
300
+ throw new UsageError(`${REGISTRY_REL} has no \`workflows\` mapping`);
301
+ }
302
+ let canonical;
303
+ try {
304
+ canonical = fs.readFileSync(path.join(root, CANONICAL_REL), "utf8");
305
+ } catch (error) {
306
+ throw new UsageError(`could not read ${CANONICAL_REL}: ${error.message}`);
307
+ }
308
+ return { canonical, registry };
309
+ }
310
+
311
+ /**
312
+ * Compare the registry against the reusable workflows on disk.
313
+ *
314
+ * @param {{ root: string, registry: Record<string, unknown>, canonical: string }} context
315
+ * the resolved inputs.
316
+ * @returns {{ findings: { where: string, problem: string }[], reusables: string[] }}
317
+ * findings plus the discovered reusable filenames.
318
+ */
319
+ function auditReusables(context) {
320
+ const { canonical, registry, root } = context;
321
+ const directory = path.join(root, ".github", "workflows");
322
+ const findings = [];
323
+ const reusables = [];
324
+ const entries = fs.existsSync(directory) ? fs.readdirSync(directory) : [];
325
+ for (const name of entries.filter(file => /\.ya?ml$/.test(file)).sort()) {
326
+ const document = loadWorkflow(path.join(directory, name));
327
+ if (workflowCallOf(document) === null) continue;
328
+ reusables.push(name);
329
+ const entry = registry.workflows[name];
330
+ if (entry === undefined) {
331
+ findings.push({
332
+ problem: `reusable workflow is absent from ${REGISTRY_REL}; record a \`major\` for it, or an \`uncovered\` reason it cannot carry one`,
333
+ where: name,
334
+ });
335
+ continue;
336
+ }
337
+ const problem = describeEntryProblem(entry);
338
+ if (problem !== null) {
339
+ findings.push({ problem: `${REGISTRY_REL}: ${problem}`, where: name });
340
+ continue;
341
+ }
342
+ if (entry.uncovered !== undefined) continue;
343
+ for (const complaint of auditReusable({
344
+ canonical,
345
+ document,
346
+ file: name,
347
+ major: entry.major,
348
+ })) {
349
+ findings.push({ problem: complaint, where: name });
350
+ }
351
+ }
352
+ for (const name of Object.keys(registry.workflows)) {
353
+ if (!reusables.includes(name)) {
354
+ findings.push({
355
+ problem: `${REGISTRY_REL} records this workflow, but no reusable workflow of that name exists — a registry entry for nothing hides the absence of a real one`,
356
+ where: name,
357
+ });
358
+ }
359
+ }
360
+ return { findings, reusables };
361
+ }
362
+
363
+ /**
364
+ * Check every shipped caller template is seeded beside its `uses:` line.
365
+ *
366
+ * @param {{ root: string, registry: Record<string, unknown>, templates: readonly string[] }} context
367
+ * the resolved inputs.
368
+ * @returns {{ findings: { where: string, problem: string }[], checked: number }}
369
+ * findings plus the number of references examined.
370
+ */
371
+ function auditTemplates(context) {
372
+ const { registry, root, templates } = context;
373
+ const findings = [];
374
+ let checked = 0;
375
+ for (const file of templates) {
376
+ const document = loadWorkflow(path.join(root, file));
377
+ for (const reference of callerReferences(document)) {
378
+ const entry = registry.workflows[reference.target];
379
+ if (entry === undefined || entry.major === undefined) continue;
380
+ checked += 1;
381
+ const expected = String(entry.major);
382
+ if (reference.seeded === undefined) {
383
+ findings.push({
384
+ problem: `job \`${reference.job}\` calls ${reference.target} but seeds no \`${INPUT_NAME}\`. The reference and the assertion are one unit: without it the run cannot tell a behaviour change from silence. Add \`${INPUT_NAME}: '${expected}'\` to its \`with:\` block`,
385
+ where: file,
386
+ });
387
+ } else if (String(reference.seeded) !== expected) {
388
+ findings.push({
389
+ problem: `job \`${reference.job}\` seeds ${reference.target} with major ${reference.seeded}, but the workflow now declares ${expected}. A shipped template must hand a NEW consumer the current major`,
390
+ where: file,
391
+ });
392
+ }
393
+ }
394
+ }
395
+ return { checked, findings };
396
+ }
397
+
398
+ /**
399
+ * Render the human-readable report.
400
+ *
401
+ * @param {{ findings: readonly { where: string, problem: string }[], summary: Record<string, number> }} report
402
+ * the report object.
403
+ * @returns {string} the rendered report.
404
+ */
405
+ function humanReport(report) {
406
+ const { summary } = report;
407
+ if (report.findings.length === 0) {
408
+ return `✓ ${summary.reusables} reusable workflow(s) declare a contract major; ${summary.checked} caller reference(s) across ${summary.templates} template(s) are seeded with it`;
409
+ }
410
+ return [
411
+ ...report.findings.map(
412
+ finding => `✗ ${finding.where}\n ${finding.problem}`
413
+ ),
414
+ "",
415
+ "A reusable workflow tracked at @main changes under every consumer with no",
416
+ "pull request in their repository. The contract major is the only thing",
417
+ "telling them a compatible change from a breaking one — and a caller that",
418
+ "carries the reference without the assertion is back to silence while",
419
+ "looking perfectly healthy.",
420
+ ].join("\n");
421
+ }
422
+
423
+ /**
424
+ * Run the gate. Returns the process exit code (does not call `exit`).
425
+ *
426
+ * @param {readonly string[]} argv - arguments (without node/script prefix).
427
+ * @param {{ stdout?: { write(s: string): void }, stderr?: { write(s: string): void } }} [io]
428
+ * injectable streams.
429
+ * @returns {number} exit code (0 clean, 1 finding, 2 not determined).
430
+ */
431
+ export function main(argv, io = {}) {
432
+ const out = io.stdout ?? process.stdout;
433
+ const err = io.stderr ?? process.stderr;
434
+ let report;
435
+ let json = false;
436
+ try {
437
+ const opts = parseArgs(argv);
438
+ json = opts.json;
439
+ if (!fs.existsSync(opts.root) || !fs.statSync(opts.root).isDirectory()) {
440
+ throw new UsageError(`--root is not a directory: ${opts.root}`);
441
+ }
442
+ const { canonical, registry } = readContract(opts.root);
443
+ const reusable = auditReusables({ canonical, registry, root: opts.root });
444
+ if (reusable.reusables.length === 0) {
445
+ throw new UsageError(
446
+ `no reusable workflows found under ${opts.root}/.github/workflows — refusing to report a clean run for a scan that examined nothing`
447
+ );
448
+ }
449
+ const templates = listTrackedFiles(opts.root).filter(file =>
450
+ TEMPLATE_RE.test(file)
451
+ );
452
+ if (templates.length === 0) {
453
+ throw new UsageError(
454
+ `no caller templates found under ${opts.root} — expected paths like expo/create-only/.github/workflows/*.yml. Refusing to report a clean run for a scan that examined nothing`
455
+ );
456
+ }
457
+ const caller = auditTemplates({ registry, root: opts.root, templates });
458
+ report = {
459
+ findings: [...reusable.findings, ...caller.findings],
460
+ schemaVersion: 1,
461
+ summary: {
462
+ checked: caller.checked,
463
+ findings: reusable.findings.length + caller.findings.length,
464
+ reusables: reusable.reusables.length,
465
+ templates: templates.length,
466
+ },
467
+ };
468
+ } catch (error) {
469
+ err.write(`NOT DETERMINED: ${error.message}\n`);
470
+ return 2;
471
+ }
472
+ out.write(
473
+ `${json ? JSON.stringify(report, null, 2) : humanReport(report)}\n`
474
+ );
475
+ return report.findings.length === 0 ? 0 : 1;
476
+ }
477
+
478
+ if (invokedAsScript(import.meta.url)) {
479
+ process.exitCode = main(process.argv.slice(2));
480
+ }
@@ -24,6 +24,7 @@ const canonicalSupportFiles = [
24
24
  "block-no-verify.sh",
25
25
  "parity-safety-net.sh",
26
26
  "parity-safety-net-heredoc.py",
27
+ "guard-dedupe.bash",
27
28
  ];
28
29
 
29
30
  fs.rmSync(destDir, { recursive: true, force: true });