@codyswann/lisa 4.74.9 → 4.75.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 (799) hide show
  1. package/.claude-plugin/marketplace.json +60 -0
  2. package/dist/core/lisa-skill-sources.d.ts +3 -3
  3. package/dist/core/lisa-skill-sources.d.ts.map +1 -1
  4. package/dist/core/lisa-skill-sources.js +3 -2
  5. package/dist/core/lisa-skill-sources.js.map +1 -1
  6. package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
  7. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  8. package/dist/core/upstream-evidence-manifest.js +730 -5
  9. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  10. package/package.json +4 -4
  11. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  12. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  13. package/plugins/lisa-agy/plugin.json +1 -1
  14. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  15. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  16. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  17. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  18. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  19. package/plugins/lisa-cdk-devin/.claude-plugin/plugin.json +11 -0
  20. package/plugins/lisa-cdk-devin/.devin-plugin/plugin.json +8 -0
  21. package/plugins/lisa-cdk-devin/skills/setup-aws-accounts/SKILL.md +292 -0
  22. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  23. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  24. package/plugins/lisa-devin/.claude-plugin/plugin.json +8 -0
  25. package/plugins/lisa-devin/.devin-plugin/plugin.json +8 -0
  26. package/plugins/lisa-devin/.mcp.json +8 -0
  27. package/plugins/lisa-devin/agents/architecture-specialist.md +32 -0
  28. package/plugins/lisa-devin/agents/bug-fixer.md +43 -0
  29. package/plugins/lisa-devin/agents/builder.md +44 -0
  30. package/plugins/lisa-devin/agents/confluence-prd-intake.md +65 -0
  31. package/plugins/lisa-devin/agents/debug-specialist.md +34 -0
  32. package/plugins/lisa-devin/agents/eval-specialist.md +33 -0
  33. package/plugins/lisa-devin/agents/git-history-analyzer.md +183 -0
  34. package/plugins/lisa-devin/agents/github-agent.md +155 -0
  35. package/plugins/lisa-devin/agents/github-build-intake.md +64 -0
  36. package/plugins/lisa-devin/agents/github-prd-intake.md +66 -0
  37. package/plugins/lisa-devin/agents/jira-agent.md +135 -0
  38. package/plugins/lisa-devin/agents/jira-build-intake.md +64 -0
  39. package/plugins/lisa-devin/agents/learner.md +85 -0
  40. package/plugins/lisa-devin/agents/learning-judge.md +119 -0
  41. package/plugins/lisa-devin/agents/learnings-synthesizer.md +155 -0
  42. package/plugins/lisa-devin/agents/linear-agent.md +138 -0
  43. package/plugins/lisa-devin/agents/linear-build-intake.md +64 -0
  44. package/plugins/lisa-devin/agents/linear-prd-intake.md +66 -0
  45. package/plugins/lisa-devin/agents/notion-prd-intake.md +63 -0
  46. package/plugins/lisa-devin/agents/performance-specialist.md +26 -0
  47. package/plugins/lisa-devin/agents/pr-mining-specialist.md +85 -0
  48. package/plugins/lisa-devin/agents/product-specialist.md +30 -0
  49. package/plugins/lisa-devin/agents/quality-specialist.md +30 -0
  50. package/plugins/lisa-devin/agents/security-specialist.md +43 -0
  51. package/plugins/lisa-devin/agents/skill-evaluator.md +205 -0
  52. package/plugins/lisa-devin/agents/spec-conformance-specialist.md +56 -0
  53. package/plugins/lisa-devin/agents/test-specialist.md +32 -0
  54. package/plugins/lisa-devin/agents/tracker-mining-specialist.md +85 -0
  55. package/plugins/lisa-devin/agents/verification-specialist.md +145 -0
  56. package/plugins/lisa-devin/hooks/auto-update.mjs +824 -0
  57. package/plugins/lisa-devin/hooks/auto-update.sh +31 -0
  58. package/plugins/lisa-devin/hooks/block-blind-automerge.sh +1242 -0
  59. package/plugins/lisa-devin/hooks/block-direct-issue-create.sh +2603 -0
  60. package/plugins/lisa-devin/hooks/block-host-name-leak.mjs +412 -0
  61. package/plugins/lisa-devin/hooks/block-host-name-leak.sh +61 -0
  62. package/plugins/lisa-devin/hooks/block-instruction-file-edits.sh +207 -0
  63. package/plugins/lisa-devin/hooks/block-managed-file-edits.sh +1175 -0
  64. package/plugins/lisa-devin/hooks/block-no-verify.sh +2288 -0
  65. package/plugins/lisa-devin/hooks/block-shell-json-parsing.sh +263 -0
  66. package/plugins/lisa-devin/hooks/cleanup-stale-worktrees.sh +122 -0
  67. package/plugins/lisa-devin/hooks/devin-tool-name-shim.sh +30 -0
  68. package/plugins/lisa-devin/hooks/discharge-work-item-gates.sh +90 -0
  69. package/plugins/lisa-devin/hooks/enforce-verification-gate.sh +506 -0
  70. package/plugins/lisa-devin/hooks/enforcement-vintage-npm.mjs +320 -0
  71. package/plugins/lisa-devin/hooks/enforcement-vintage.mjs +472 -0
  72. package/plugins/lisa-devin/hooks/enforcement-vintage.sh +48 -0
  73. package/plugins/lisa-devin/hooks/failure-signature-index.mjs +717 -0
  74. package/plugins/lisa-devin/hooks/failure-signature-index.sh +26 -0
  75. package/plugins/lisa-devin/hooks/guard-dedupe.bash +374 -0
  76. package/plugins/lisa-devin/hooks/inject-resolved-config.mjs +903 -0
  77. package/plugins/lisa-devin/hooks/inject-resolved-config.sh +107 -0
  78. package/plugins/lisa-devin/hooks/inject-rules.sh +49 -0
  79. package/plugins/lisa-devin/hooks/install-pkgs.sh +84 -0
  80. package/plugins/lisa-devin/hooks/operational-hazards.mjs +736 -0
  81. package/plugins/lisa-devin/hooks/operational-hazards.sh +28 -0
  82. package/plugins/lisa-devin/hooks/parity-safety-net-heredoc.py +1004 -0
  83. package/plugins/lisa-devin/hooks/parity-safety-net.sh +3275 -0
  84. package/plugins/lisa-devin/hooks/secrets-preflight.sh +72 -0
  85. package/plugins/lisa-devin/hooks/setup-jira-cli.sh +205 -0
  86. package/plugins/lisa-devin/hooks/shell-write-nudge.sh +86 -0
  87. package/plugins/lisa-devin/hooks/sonar-secrets.sh +205 -0
  88. package/plugins/lisa-devin/hooks/threshold-ratchet-compare.mjs +518 -0
  89. package/plugins/lisa-devin/hooks/threshold-ratchet-families.mjs +543 -0
  90. package/plugins/lisa-devin/hooks/threshold-ratchet.mjs +568 -0
  91. package/plugins/lisa-devin/hooks/threshold-ratchet.sh +22 -0
  92. package/plugins/lisa-devin/hooks/withdrawn-rulings.mjs +600 -0
  93. package/plugins/lisa-devin/hooks/withdrawn-rulings.sh +24 -0
  94. package/plugins/lisa-devin/hooks/worktree-binding-guard.mjs +1383 -0
  95. package/plugins/lisa-devin/hooks/worktree-binding-guard.sh +79 -0
  96. package/plugins/lisa-devin/hooks.json +247 -0
  97. package/plugins/lisa-devin/rules/eager/00-rule-index.md +82 -0
  98. package/plugins/lisa-devin/rules/eager/base-rules.md +85 -0
  99. package/plugins/lisa-devin/rules/eager/coding-philosophy.md +27 -0
  100. package/plugins/lisa-devin/rules/eager/config-resolution.md +37 -0
  101. package/plugins/lisa-devin/rules/eager/do-it-now.md +11 -0
  102. package/plugins/lisa-devin/rules/eager/empirical-inquiry.md +24 -0
  103. package/plugins/lisa-devin/rules/eager/falsifiable-checks.md +48 -0
  104. package/plugins/lisa-devin/rules/eager/history-audit.md +27 -0
  105. package/plugins/lisa-devin/rules/eager/integration-access-layer.md +19 -0
  106. package/plugins/lisa-devin/rules/eager/intent-routing.md +18 -0
  107. package/plugins/lisa-devin/rules/eager/learnings-ladder.md +18 -0
  108. package/plugins/lisa-devin/rules/eager/local-ci-first.md +15 -0
  109. package/plugins/lisa-devin/rules/eager/measurement-integrity.md +18 -0
  110. package/plugins/lisa-devin/rules/eager/never-name-a-downstream-project.md +9 -0
  111. package/plugins/lisa-devin/rules/eager/not-blocked-just-waiting.md +13 -0
  112. package/plugins/lisa-devin/rules/eager/operational-hazards.md +50 -0
  113. package/plugins/lisa-devin/rules/eager/report-actionability.md +26 -0
  114. package/plugins/lisa-devin/rules/eager/security-audit-handling.md +40 -0
  115. package/plugins/lisa-devin/rules/eager/session-status-updates.md +20 -0
  116. package/plugins/lisa-devin/rules/eager/settled-decisions.md +75 -0
  117. package/plugins/lisa-devin/rules/eager/stale-state-claims.md +26 -0
  118. package/plugins/lisa-devin/rules/eager/tool-access-gate.md +23 -0
  119. package/plugins/lisa-devin/rules/eager/tracked-work.md +9 -0
  120. package/plugins/lisa-devin/rules/eager/upstream-to-lisa.md +14 -0
  121. package/plugins/lisa-devin/rules/eager/verification.md +33 -0
  122. package/plugins/lisa-devin/rules/eager/wiki-knowledge-source.md +13 -0
  123. package/plugins/lisa-devin/rules/eager/withdrawn-rulings.md +102 -0
  124. package/plugins/lisa-devin/rules/reference/automation-runbook-contract.md +355 -0
  125. package/plugins/lisa-devin/rules/reference/base-rules.md +136 -0
  126. package/plugins/lisa-devin/rules/reference/bdd-e2e-coverage.md +301 -0
  127. package/plugins/lisa-devin/rules/reference/blocker-containment.md +165 -0
  128. package/plugins/lisa-devin/rules/reference/claim-archaeology.md +184 -0
  129. package/plugins/lisa-devin/rules/reference/claim-evidence-mapping.md +362 -0
  130. package/plugins/lisa-devin/rules/reference/claim-time-guards.md +135 -0
  131. package/plugins/lisa-devin/rules/reference/coding-philosophy.md +428 -0
  132. package/plugins/lisa-devin/rules/reference/config-resolution.md +1225 -0
  133. package/plugins/lisa-devin/rules/reference/control-reachability.md +166 -0
  134. package/plugins/lisa-devin/rules/reference/convergent-review.md +145 -0
  135. package/plugins/lisa-devin/rules/reference/credential-substrate-precedence.md +249 -0
  136. package/plugins/lisa-devin/rules/reference/dependency-decision-records.md +177 -0
  137. package/plugins/lisa-devin/rules/reference/dependency-internalization-kit.md +244 -0
  138. package/plugins/lisa-devin/rules/reference/dependency-trust-classes.md +291 -0
  139. package/plugins/lisa-devin/rules/reference/deployed-state-readback.md +142 -0
  140. package/plugins/lisa-devin/rules/reference/derived-branch-plan.md +214 -0
  141. package/plugins/lisa-devin/rules/reference/design-source-of-truth.md +260 -0
  142. package/plugins/lisa-devin/rules/reference/design-value-binding.md +311 -0
  143. package/plugins/lisa-devin/rules/reference/do-it-now.md +19 -0
  144. package/plugins/lisa-devin/rules/reference/documentation-source-paths.md +31 -0
  145. package/plugins/lisa-devin/rules/reference/empirical-inquiry.md +28 -0
  146. package/plugins/lisa-devin/rules/reference/factory-model.md +111 -0
  147. package/plugins/lisa-devin/rules/reference/falsifiable-checks.md +275 -0
  148. package/plugins/lisa-devin/rules/reference/history-audit.md +42 -0
  149. package/plugins/lisa-devin/rules/reference/integration-access-layer.md +89 -0
  150. package/plugins/lisa-devin/rules/reference/intent-routing.md +428 -0
  151. package/plugins/lisa-devin/rules/reference/leaf-only-lifecycle.md +227 -0
  152. package/plugins/lisa-devin/rules/reference/learnings-ladder.md +41 -0
  153. package/plugins/lisa-devin/rules/reference/local-ci-first.md +34 -0
  154. package/plugins/lisa-devin/rules/reference/measurement-integrity.md +119 -0
  155. package/plugins/lisa-devin/rules/reference/never-name-a-downstream-project.md +37 -0
  156. package/plugins/lisa-devin/rules/reference/not-blocked-just-waiting.md +41 -0
  157. package/plugins/lisa-devin/rules/reference/observability-audit.md +146 -0
  158. package/plugins/lisa-devin/rules/reference/operational-hazards.md +115 -0
  159. package/plugins/lisa-devin/rules/reference/prd-definition-of-ready.md +118 -0
  160. package/plugins/lisa-devin/rules/reference/prd-lifecycle-rollup.md +192 -0
  161. package/plugins/lisa-devin/rules/reference/pre-flight-autofill.md +250 -0
  162. package/plugins/lisa-devin/rules/reference/project-learnings.md +159 -0
  163. package/plugins/lisa-devin/rules/reference/promotion-contract.md +148 -0
  164. package/plugins/lisa-devin/rules/reference/readiness-rubric.md +242 -0
  165. package/plugins/lisa-devin/rules/reference/ready-role-filing.md +212 -0
  166. package/plugins/lisa-devin/rules/reference/rejection-detection.md +308 -0
  167. package/plugins/lisa-devin/rules/reference/repo-scope-split.md +119 -0
  168. package/plugins/lisa-devin/rules/reference/report-actionability.md +61 -0
  169. package/plugins/lisa-devin/rules/reference/reset-seed-coverage.md +286 -0
  170. package/plugins/lisa-devin/rules/reference/security-audit-handling.md +55 -0
  171. package/plugins/lisa-devin/rules/reference/session-status-updates.md +111 -0
  172. package/plugins/lisa-devin/rules/reference/settled-decisions.md +39 -0
  173. package/plugins/lisa-devin/rules/reference/stale-state-claims.md +88 -0
  174. package/plugins/lisa-devin/rules/reference/tool-access-gate.md +114 -0
  175. package/plugins/lisa-devin/rules/reference/tracked-work.md +49 -0
  176. package/plugins/lisa-devin/rules/reference/upstream-to-lisa.md +26 -0
  177. package/plugins/lisa-devin/rules/reference/usage-accounting.md +261 -0
  178. package/plugins/lisa-devin/rules/reference/verification.md +278 -0
  179. package/plugins/lisa-devin/rules/reference/wiki-knowledge-source.md +37 -0
  180. package/plugins/lisa-devin/rules/reference/withdrawn-rulings.md +148 -0
  181. package/plugins/lisa-devin/rules/reference/work-item-definition-of-ready.md +177 -0
  182. package/plugins/lisa-devin/rules/reference/work-item-trailer-definition.md +129 -0
  183. package/plugins/lisa-devin/scripts/automation-run-record.mjs +678 -0
  184. package/plugins/lisa-devin/scripts/automation-status-claude-adapter.mjs +804 -0
  185. package/plugins/lisa-devin/scripts/automation-status-codex-adapter.mjs +1081 -0
  186. package/plugins/lisa-devin/scripts/automation-status-contract-drift.mjs +392 -0
  187. package/plugins/lisa-devin/scripts/automation-status-expected-fleet.mjs +508 -0
  188. package/plugins/lisa-devin/scripts/automation-status-report.mjs +200 -0
  189. package/plugins/lisa-devin/scripts/automation-status-run-history.mjs +216 -0
  190. package/plugins/lisa-devin/scripts/automation-status-unrecorded-runs.mjs +127 -0
  191. package/plugins/lisa-devin/scripts/blocker-edge-resolution.mjs +150 -0
  192. package/plugins/lisa-devin/scripts/cross-pollinate.mjs +763 -0
  193. package/plugins/lisa-devin/scripts/design-bindings-probe.mjs +713 -0
  194. package/plugins/lisa-devin/scripts/design-intake-gate.mjs +470 -0
  195. package/plugins/lisa-devin/scripts/design-source-gate.mjs +610 -0
  196. package/plugins/lisa-devin/scripts/design-variable-ids.mjs +567 -0
  197. package/plugins/lisa-devin/scripts/doctor-report.mjs +635 -0
  198. package/plugins/lisa-devin/scripts/install-remote-agent-aws.mjs +443 -0
  199. package/plugins/lisa-devin/scripts/intake-blocker-reprobe.mjs +1065 -0
  200. package/plugins/lisa-devin/scripts/intake-prework-denominator.mjs +249 -0
  201. package/plugins/lisa-devin/scripts/lifecycle-label-trust.mjs +593 -0
  202. package/plugins/lisa-devin/scripts/linear-state-write-target.mjs +362 -0
  203. package/plugins/lisa-devin/scripts/plugin-sync-explain.mjs +654 -0
  204. package/plugins/lisa-devin/scripts/pr-arming-sweep.mjs +561 -0
  205. package/plugins/lisa-devin/scripts/project-ideation-idempotency-harness.mjs +338 -0
  206. package/plugins/lisa-devin/scripts/qa-signal-lifecycle.mjs +523 -0
  207. package/plugins/lisa-devin/scripts/queue-contract-resolution.mjs +583 -0
  208. package/plugins/lisa-devin/scripts/queue-health-classification.mjs +157 -0
  209. package/plugins/lisa-devin/scripts/queue-status-build-readers.mjs +561 -0
  210. package/plugins/lisa-devin/scripts/queue-status-prd-readers.mjs +452 -0
  211. package/plugins/lisa-devin/scripts/remote-agent-aws-setup.sh +677 -0
  212. package/plugins/lisa-devin/scripts/repo-scope-vocabulary-audit.mjs +458 -0
  213. package/plugins/lisa-devin/scripts/resolve-lifecycle-role.mjs +347 -0
  214. package/plugins/lisa-devin/scripts/rollup-blocker-classification.mjs +616 -0
  215. package/plugins/lisa-devin/scripts/scoping-label-audit.mjs +474 -0
  216. package/plugins/lisa-devin/skills/lisa-acceptance-criteria/SKILL.md +73 -0
  217. package/plugins/lisa-devin/skills/lisa-agent-design-best-practices/SKILL.md +242 -0
  218. package/plugins/lisa-devin/skills/lisa-agent-ready/SKILL.md +271 -0
  219. package/plugins/lisa-devin/skills/lisa-analyze-claude-remote/SKILL.md +434 -0
  220. package/plugins/lisa-devin/skills/lisa-atlassian-access/SKILL.md +469 -0
  221. package/plugins/lisa-devin/skills/lisa-atlassian-access/scripts/markdown-to-adf.mjs +236 -0
  222. package/plugins/lisa-devin/skills/lisa-attribute-failure/SKILL.md +142 -0
  223. package/plugins/lisa-devin/skills/lisa-automation-status/SKILL.md +149 -0
  224. package/plugins/lisa-devin/skills/lisa-bug-triage/SKILL.md +23 -0
  225. package/plugins/lisa-devin/skills/lisa-capability-drift/SKILL.md +71 -0
  226. package/plugins/lisa-devin/skills/lisa-codebase-research/SKILL.md +87 -0
  227. package/plugins/lisa-devin/skills/lisa-codify-verification/SKILL.md +213 -0
  228. package/plugins/lisa-devin/skills/lisa-confluence-prd-intake/SKILL.md +417 -0
  229. package/plugins/lisa-devin/skills/lisa-confluence-to-tracker/SKILL.md +469 -0
  230. package/plugins/lisa-devin/skills/lisa-confluence-write-prd/SKILL.md +111 -0
  231. package/plugins/lisa-devin/skills/lisa-cross-pollinate/SKILL.md +175 -0
  232. package/plugins/lisa-devin/skills/lisa-debrief/SKILL.md +96 -0
  233. package/plugins/lisa-devin/skills/lisa-debrief-apply/SKILL.md +106 -0
  234. package/plugins/lisa-devin/skills/lisa-delivery-effectiveness/SKILL.md +62 -0
  235. package/plugins/lisa-devin/skills/lisa-design-intake/SKILL.md +198 -0
  236. package/plugins/lisa-devin/skills/lisa-detect-tooling/SKILL.md +110 -0
  237. package/plugins/lisa-devin/skills/lisa-detect-tooling/scripts/commands.mjs +479 -0
  238. package/plugins/lisa-devin/skills/lisa-detect-tooling/scripts/detect-tooling.mjs +658 -0
  239. package/plugins/lisa-devin/skills/lisa-doctor/SKILL.md +743 -0
  240. package/plugins/lisa-devin/skills/lisa-drive-pr-to-merge/SKILL.md +1587 -0
  241. package/plugins/lisa-devin/skills/lisa-epic-triage/SKILL.md +28 -0
  242. package/plugins/lisa-devin/skills/lisa-evaluation-suite/SKILL.md +63 -0
  243. package/plugins/lisa-devin/skills/lisa-exploratory-qa/SKILL.md +185 -0
  244. package/plugins/lisa-devin/skills/lisa-fix-linter-error/SKILL.md +45 -0
  245. package/plugins/lisa-devin/skills/lisa-generate-claude-remote-build-script/SKILL.md +235 -0
  246. package/plugins/lisa-devin/skills/lisa-git-commit/SKILL.md +53 -0
  247. package/plugins/lisa-devin/skills/lisa-git-prune/SKILL.md +35 -0
  248. package/plugins/lisa-devin/skills/lisa-git-submit-pr/SKILL.md +170 -0
  249. package/plugins/lisa-devin/skills/lisa-github-add-journey/SKILL.md +118 -0
  250. package/plugins/lisa-devin/skills/lisa-github-build-intake/SKILL.md +745 -0
  251. package/plugins/lisa-devin/skills/lisa-github-claim/SKILL.md +27 -0
  252. package/plugins/lisa-devin/skills/lisa-github-create/SKILL.md +105 -0
  253. package/plugins/lisa-devin/skills/lisa-github-evidence/SKILL.md +120 -0
  254. package/plugins/lisa-devin/skills/lisa-github-journey/SKILL.md +134 -0
  255. package/plugins/lisa-devin/skills/lisa-github-prd-intake/SKILL.md +424 -0
  256. package/plugins/lisa-devin/skills/lisa-github-project-v2/SKILL.md +227 -0
  257. package/plugins/lisa-devin/skills/lisa-github-read-issue/SKILL.md +305 -0
  258. package/plugins/lisa-devin/skills/lisa-github-sync/SKILL.md +201 -0
  259. package/plugins/lisa-devin/skills/lisa-github-to-tracker/SKILL.md +456 -0
  260. package/plugins/lisa-devin/skills/lisa-github-validate-issue/SKILL.md +598 -0
  261. package/plugins/lisa-devin/skills/lisa-github-verify/SKILL.md +60 -0
  262. package/plugins/lisa-devin/skills/lisa-github-write-issue/SKILL.md +531 -0
  263. package/plugins/lisa-devin/skills/lisa-github-write-prd/SKILL.md +156 -0
  264. package/plugins/lisa-devin/skills/lisa-health/SKILL.md +142 -0
  265. package/plugins/lisa-devin/skills/lisa-health-drift-cron/SKILL.md +80 -0
  266. package/plugins/lisa-devin/skills/lisa-implement/SKILL.md +372 -0
  267. package/plugins/lisa-devin/skills/lisa-improve-code-complexity/SKILL.md +44 -0
  268. package/plugins/lisa-devin/skills/lisa-improve-harness/SKILL.md +487 -0
  269. package/plugins/lisa-devin/skills/lisa-improve-max-lines/SKILL.md +45 -0
  270. package/plugins/lisa-devin/skills/lisa-improve-max-lines-per-function/SKILL.md +46 -0
  271. package/plugins/lisa-devin/skills/lisa-improve-test-coverage/SKILL.md +47 -0
  272. package/plugins/lisa-devin/skills/lisa-improve-tests/SKILL.md +50 -0
  273. package/plugins/lisa-devin/skills/lisa-intake/SKILL.md +208 -0
  274. package/plugins/lisa-devin/skills/lisa-intake-explain/SKILL.md +279 -0
  275. package/plugins/lisa-devin/skills/lisa-jam-access/SKILL.md +128 -0
  276. package/plugins/lisa-devin/skills/lisa-jira-add-journey/SKILL.md +139 -0
  277. package/plugins/lisa-devin/skills/lisa-jira-build-intake/SKILL.md +556 -0
  278. package/plugins/lisa-devin/skills/lisa-jira-claim/SKILL.md +27 -0
  279. package/plugins/lisa-devin/skills/lisa-jira-create/SKILL.md +157 -0
  280. package/plugins/lisa-devin/skills/lisa-jira-evidence/SKILL.md +106 -0
  281. package/plugins/lisa-devin/skills/lisa-jira-evidence/scripts/post-evidence.sh +262 -0
  282. package/plugins/lisa-devin/skills/lisa-jira-journey/SKILL.md +168 -0
  283. package/plugins/lisa-devin/skills/lisa-jira-journey/scripts/generate-templates.py +239 -0
  284. package/plugins/lisa-devin/skills/lisa-jira-journey/scripts/parse-plan.py +570 -0
  285. package/plugins/lisa-devin/skills/lisa-jira-read-ticket/SKILL.md +199 -0
  286. package/plugins/lisa-devin/skills/lisa-jira-read-ticket/scripts/download-attachment.sh +211 -0
  287. package/plugins/lisa-devin/skills/lisa-jira-sync/SKILL.md +117 -0
  288. package/plugins/lisa-devin/skills/lisa-jira-validate-ticket/SKILL.md +525 -0
  289. package/plugins/lisa-devin/skills/lisa-jira-verify/SKILL.md +61 -0
  290. package/plugins/lisa-devin/skills/lisa-jira-write-ticket/SKILL.md +440 -0
  291. package/plugins/lisa-devin/skills/lisa-jsdoc-best-practices/SKILL.md +491 -0
  292. package/plugins/lisa-devin/skills/lisa-kane-browser/SKILL.md +80 -0
  293. package/plugins/lisa-devin/skills/lisa-learnings-audit/SKILL.md +490 -0
  294. package/plugins/lisa-devin/skills/lisa-linear-access/SKILL.md +483 -0
  295. package/plugins/lisa-devin/skills/lisa-linear-add-journey/SKILL.md +109 -0
  296. package/plugins/lisa-devin/skills/lisa-linear-build-intake/SKILL.md +548 -0
  297. package/plugins/lisa-devin/skills/lisa-linear-claim/SKILL.md +28 -0
  298. package/plugins/lisa-devin/skills/lisa-linear-create/SKILL.md +150 -0
  299. package/plugins/lisa-devin/skills/lisa-linear-evidence/SKILL.md +124 -0
  300. package/plugins/lisa-devin/skills/lisa-linear-journey/SKILL.md +147 -0
  301. package/plugins/lisa-devin/skills/lisa-linear-prd-intake/SKILL.md +411 -0
  302. package/plugins/lisa-devin/skills/lisa-linear-read-issue/SKILL.md +201 -0
  303. package/plugins/lisa-devin/skills/lisa-linear-sync/SKILL.md +164 -0
  304. package/plugins/lisa-devin/skills/lisa-linear-to-tracker/SKILL.md +454 -0
  305. package/plugins/lisa-devin/skills/lisa-linear-validate-issue/SKILL.md +504 -0
  306. package/plugins/lisa-devin/skills/lisa-linear-verify/SKILL.md +65 -0
  307. package/plugins/lisa-devin/skills/lisa-linear-write-issue/SKILL.md +448 -0
  308. package/plugins/lisa-devin/skills/lisa-linear-write-prd/SKILL.md +98 -0
  309. package/plugins/lisa-devin/skills/lisa-monitor/SKILL.md +224 -0
  310. package/plugins/lisa-devin/skills/lisa-nightly-add-test-coverage/SKILL.md +40 -0
  311. package/plugins/lisa-devin/skills/lisa-nightly-improve-tests/SKILL.md +29 -0
  312. package/plugins/lisa-devin/skills/lisa-nightly-lower-code-complexity/SKILL.md +42 -0
  313. package/plugins/lisa-devin/skills/lisa-notion-access/SKILL.md +301 -0
  314. package/plugins/lisa-devin/skills/lisa-notion-prd-intake/SKILL.md +360 -0
  315. package/plugins/lisa-devin/skills/lisa-notion-to-tracker/SKILL.md +467 -0
  316. package/plugins/lisa-devin/skills/lisa-notion-write-prd/SKILL.md +111 -0
  317. package/plugins/lisa-devin/skills/lisa-parity-code-review/SKILL.md +83 -0
  318. package/plugins/lisa-devin/skills/lisa-parity-code-simplifier/SKILL.md +76 -0
  319. package/plugins/lisa-devin/skills/lisa-parity-coderabbit/SKILL.md +87 -0
  320. package/plugins/lisa-devin/skills/lisa-parity-sentry-sdk-setup/SKILL.md +375 -0
  321. package/plugins/lisa-devin/skills/lisa-parity-sentry-seer/SKILL.md +168 -0
  322. package/plugins/lisa-devin/skills/lisa-parity-skill-creator/SKILL.md +155 -0
  323. package/plugins/lisa-devin/skills/lisa-performance-review/SKILL.md +94 -0
  324. package/plugins/lisa-devin/skills/lisa-persist-learning/SKILL.md +247 -0
  325. package/plugins/lisa-devin/skills/lisa-plan/SKILL.md +64 -0
  326. package/plugins/lisa-devin/skills/lisa-plugin-sync-explain/SKILL.md +53 -0
  327. package/plugins/lisa-devin/skills/lisa-posthog-access/SKILL.md +140 -0
  328. package/plugins/lisa-devin/skills/lisa-prd-backlink/SKILL.md +274 -0
  329. package/plugins/lisa-devin/skills/lisa-prd-source-write/SKILL.md +104 -0
  330. package/plugins/lisa-devin/skills/lisa-prd-ticket-coverage/SKILL.md +187 -0
  331. package/plugins/lisa-devin/skills/lisa-product-walkthrough/SKILL.md +106 -0
  332. package/plugins/lisa-devin/skills/lisa-project-ideation/SKILL.md +417 -0
  333. package/plugins/lisa-devin/skills/lisa-project-ideation/examples/evidence-card-format.md +21 -0
  334. package/plugins/lisa-devin/skills/lisa-project-ideation/examples/host-project-only.md +22 -0
  335. package/plugins/lisa-devin/skills/lisa-project-ideation/examples/idempotency-verification-harness.md +57 -0
  336. package/plugins/lisa-devin/skills/lisa-project-ideation/examples/public-external-inspiration.md +22 -0
  337. package/plugins/lisa-devin/skills/lisa-project-ideation/examples/unavailable-data-rejection.md +22 -0
  338. package/plugins/lisa-devin/skills/lisa-pull-request-review/SKILL.md +132 -0
  339. package/plugins/lisa-devin/skills/lisa-quality-review/SKILL.md +63 -0
  340. package/plugins/lisa-devin/skills/lisa-queue-status/SKILL.md +215 -0
  341. package/plugins/lisa-devin/skills/lisa-remote-dispatch/SKILL.md +109 -0
  342. package/plugins/lisa-devin/skills/lisa-remote-dispatch/scripts/dispatch.mjs +535 -0
  343. package/plugins/lisa-devin/skills/lisa-repair-intake/SKILL.md +1621 -0
  344. package/plugins/lisa-devin/skills/lisa-reproduce-bug/SKILL.md +75 -0
  345. package/plugins/lisa-devin/skills/lisa-research/SKILL.md +92 -0
  346. package/plugins/lisa-devin/skills/lisa-review-implementation/SKILL.md +209 -0
  347. package/plugins/lisa-devin/skills/lisa-review-local/SKILL.md +141 -0
  348. package/plugins/lisa-devin/skills/lisa-rework-triage/SKILL.md +206 -0
  349. package/plugins/lisa-devin/skills/lisa-root-cause-analysis/SKILL.md +135 -0
  350. package/plugins/lisa-devin/skills/lisa-secrets-access/SKILL.md +430 -0
  351. package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/aws-bootstrap.mjs +433 -0
  352. package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/bootstrap-store.mjs +288 -0
  353. package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/doctor-secrets.mjs +273 -0
  354. package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/envfile.mjs +80 -0
  355. package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/inspect-vault.mjs +142 -0
  356. package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +1085 -0
  357. package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/note-format.mjs +179 -0
  358. package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/owner.mjs +96 -0
  359. package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/preflight-secrets.mjs +342 -0
  360. package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/prompt-secret.mjs +79 -0
  361. package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/providers.mjs +805 -0
  362. package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/publish-aws-bootstrap.mjs +680 -0
  363. package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/read-secret-note.mjs +105 -0
  364. package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/resolve-expo-token.mjs +90 -0
  365. package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/resolve-secret.mjs +285 -0
  366. package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/rotate-secret.mjs +297 -0
  367. package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/routing-floor.mjs +153 -0
  368. package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/surfaces.mjs +480 -0
  369. package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/sync-secret-to-ci.mjs +510 -0
  370. package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/tools-from-notes.mjs +63 -0
  371. package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/validate-config.mjs +550 -0
  372. package/plugins/lisa-devin/skills/lisa-security-review/SKILL.md +124 -0
  373. package/plugins/lisa-devin/skills/lisa-security-zap-scan/SKILL.md +53 -0
  374. package/plugins/lisa-devin/skills/lisa-sentry-access/SKILL.md +140 -0
  375. package/plugins/lisa-devin/skills/lisa-setup-atlassian/SKILL.md +407 -0
  376. package/plugins/lisa-devin/skills/lisa-setup-automations/SKILL.md +430 -0
  377. package/plugins/lisa-devin/skills/lisa-setup-automations/scripts/generate-workflow.mjs +288 -0
  378. package/plugins/lisa-devin/skills/lisa-setup-confluence/SKILL.md +254 -0
  379. package/plugins/lisa-devin/skills/lisa-setup-github/SKILL.md +319 -0
  380. package/plugins/lisa-devin/skills/lisa-setup-github-repo/SKILL.md +128 -0
  381. package/plugins/lisa-devin/skills/lisa-setup-jira/SKILL.md +198 -0
  382. package/plugins/lisa-devin/skills/lisa-setup-kane/SKILL.md +96 -0
  383. package/plugins/lisa-devin/skills/lisa-setup-linear/SKILL.md +375 -0
  384. package/plugins/lisa-devin/skills/lisa-setup-local-env/SKILL.md +95 -0
  385. package/plugins/lisa-devin/skills/lisa-setup-local-env/scripts/local-env.mjs +196 -0
  386. package/plugins/lisa-devin/skills/lisa-setup-notion/SKILL.md +376 -0
  387. package/plugins/lisa-devin/skills/lisa-setup-remote-aws/SKILL.md +149 -0
  388. package/plugins/lisa-devin/skills/lisa-setup-remote-env/SKILL.md +382 -0
  389. package/plugins/lisa-devin/skills/lisa-setup-remote-env/assets/materialized-env-authority.mjs +262 -0
  390. package/plugins/lisa-devin/skills/lisa-setup-remote-env/assets/session-start.sh +87 -0
  391. package/plugins/lisa-devin/skills/lisa-setup-remote-env/assets/setup.sh +216 -0
  392. package/plugins/lisa-devin/skills/lisa-setup-remote-env/scripts/environment.mjs +227 -0
  393. package/plugins/lisa-devin/skills/lisa-setup-remote-env/scripts/preflight-tools.mjs +378 -0
  394. package/plugins/lisa-devin/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +1632 -0
  395. package/plugins/lisa-devin/skills/lisa-setup-remote-env/scripts/tool-floor.mjs +94 -0
  396. package/plugins/lisa-devin/skills/lisa-setup-remote-env/scripts/toolchain.mjs +448 -0
  397. package/plugins/lisa-devin/skills/lisa-setup-remote-env/scripts/verify-remote-env.mjs +250 -0
  398. package/plugins/lisa-devin/skills/lisa-setup-sonar/SKILL.md +153 -0
  399. package/plugins/lisa-devin/skills/lisa-setup-workstation/SKILL.md +143 -0
  400. package/plugins/lisa-devin/skills/lisa-setup-workstation/scripts/bounded-child.mjs +168 -0
  401. package/plugins/lisa-devin/skills/lisa-setup-workstation/scripts/catalogue.mjs +293 -0
  402. package/plugins/lisa-devin/skills/lisa-setup-workstation/scripts/cli.mjs +333 -0
  403. package/plugins/lisa-devin/skills/lisa-setup-workstation/scripts/workstation.mjs +511 -0
  404. package/plugins/lisa-devin/skills/lisa-sonarcloud-access/SKILL.md +202 -0
  405. package/plugins/lisa-devin/skills/lisa-spec-conformance/SKILL.md +205 -0
  406. package/plugins/lisa-devin/skills/lisa-starter-sync/SKILL.md +35 -0
  407. package/plugins/lisa-devin/skills/lisa-sync-down/SKILL.md +209 -0
  408. package/plugins/lisa-devin/skills/lisa-task-decomposition/SKILL.md +195 -0
  409. package/plugins/lisa-devin/skills/lisa-task-triage/SKILL.md +23 -0
  410. package/plugins/lisa-devin/skills/lisa-tdd-implementation/SKILL.md +91 -0
  411. package/plugins/lisa-devin/skills/lisa-tear-down-automations/SKILL.md +85 -0
  412. package/plugins/lisa-devin/skills/lisa-test-strategy/SKILL.md +66 -0
  413. package/plugins/lisa-devin/skills/lisa-ticket-triage/SKILL.md +214 -0
  414. package/plugins/lisa-devin/skills/lisa-track/SKILL.md +129 -0
  415. package/plugins/lisa-devin/skills/lisa-tracker-add-journey/SKILL.md +28 -0
  416. package/plugins/lisa-devin/skills/lisa-tracker-build-intake/SKILL.md +134 -0
  417. package/plugins/lisa-devin/skills/lisa-tracker-claim/SKILL.md +35 -0
  418. package/plugins/lisa-devin/skills/lisa-tracker-create/SKILL.md +28 -0
  419. package/plugins/lisa-devin/skills/lisa-tracker-evidence/SKILL.md +63 -0
  420. package/plugins/lisa-devin/skills/lisa-tracker-journey/SKILL.md +27 -0
  421. package/plugins/lisa-devin/skills/lisa-tracker-read/SKILL.md +28 -0
  422. package/plugins/lisa-devin/skills/lisa-tracker-source-artifacts/SKILL.md +111 -0
  423. package/plugins/lisa-devin/skills/lisa-tracker-sync/SKILL.md +150 -0
  424. package/plugins/lisa-devin/skills/lisa-tracker-validate/SKILL.md +37 -0
  425. package/plugins/lisa-devin/skills/lisa-tracker-verify/SKILL.md +29 -0
  426. package/plugins/lisa-devin/skills/lisa-tracker-write/SKILL.md +55 -0
  427. package/plugins/lisa-devin/skills/lisa-usage-accounting/SKILL.md +205 -0
  428. package/plugins/lisa-devin/skills/lisa-usage-accounting/references/effectiveness.md +63 -0
  429. package/plugins/lisa-devin/skills/lisa-use-the-product/SKILL.md +86 -0
  430. package/plugins/lisa-devin/skills/lisa-validate-tracker-mapping/SKILL.md +467 -0
  431. package/plugins/lisa-devin/skills/lisa-verification-lifecycle/SKILL.md +384 -0
  432. package/plugins/lisa-devin/skills/lisa-verify/SKILL.md +55 -0
  433. package/plugins/lisa-devin/skills/lisa-verify-prd/SKILL.md +394 -0
  434. package/plugins/lisa-devin/skills/lisa-verify-workflow-change/SKILL.md +154 -0
  435. package/plugins/lisa-devin/skills/lisa-wiki-install/SKILL.md +101 -0
  436. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  437. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  438. package/plugins/lisa-expo-agy/plugin.json +1 -1
  439. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  440. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  441. package/plugins/lisa-expo-devin/.claude-plugin/plugin.json +11 -0
  442. package/plugins/lisa-expo-devin/.devin-plugin/plugin.json +8 -0
  443. package/plugins/lisa-expo-devin/.mcp.json +8 -0
  444. package/plugins/lisa-expo-devin/THIRD-PARTY-NOTICES.md +84 -0
  445. package/plugins/lisa-expo-devin/agents/ops-specialist.md +124 -0
  446. package/plugins/lisa-expo-devin/hooks/devin-tool-name-shim.sh +30 -0
  447. package/plugins/lisa-expo-devin/hooks/register-maestro-mcp.sh +84 -0
  448. package/plugins/lisa-expo-devin/hooks.json +14 -0
  449. package/plugins/lisa-expo-devin/skills/add-app-clip/SKILL.md +280 -0
  450. package/plugins/lisa-expo-devin/skills/add-app-clip/references/native-module.md +96 -0
  451. package/plugins/lisa-expo-devin/skills/apollo-client/SKILL.md +238 -0
  452. package/plugins/lisa-expo-devin/skills/apollo-client/references/mutation-patterns.md +360 -0
  453. package/plugins/lisa-expo-devin/skills/atomic-design-gluestack/SKILL.md +369 -0
  454. package/plugins/lisa-expo-devin/skills/atomic-design-gluestack/references/atomic-levels.md +417 -0
  455. package/plugins/lisa-expo-devin/skills/atomic-design-gluestack/references/folder-structure.md +257 -0
  456. package/plugins/lisa-expo-devin/skills/atomic-design-gluestack/references/gluestack-mapping.md +233 -0
  457. package/plugins/lisa-expo-devin/skills/atomic-design-gluestack/scripts/test_validate_atomic_structure.py +240 -0
  458. package/plugins/lisa-expo-devin/skills/atomic-design-gluestack/scripts/validate_atomic_structure.py +438 -0
  459. package/plugins/lisa-expo-devin/skills/building-native-ui/SKILL.md +321 -0
  460. package/plugins/lisa-expo-devin/skills/building-native-ui/references/animations.md +220 -0
  461. package/plugins/lisa-expo-devin/skills/building-native-ui/references/controls.md +272 -0
  462. package/plugins/lisa-expo-devin/skills/building-native-ui/references/form-sheet.md +253 -0
  463. package/plugins/lisa-expo-devin/skills/building-native-ui/references/gradients.md +106 -0
  464. package/plugins/lisa-expo-devin/skills/building-native-ui/references/icons.md +213 -0
  465. package/plugins/lisa-expo-devin/skills/building-native-ui/references/media.md +198 -0
  466. package/plugins/lisa-expo-devin/skills/building-native-ui/references/route-structure.md +229 -0
  467. package/plugins/lisa-expo-devin/skills/building-native-ui/references/search.md +248 -0
  468. package/plugins/lisa-expo-devin/skills/building-native-ui/references/storage.md +121 -0
  469. package/plugins/lisa-expo-devin/skills/building-native-ui/references/tabs.md +433 -0
  470. package/plugins/lisa-expo-devin/skills/building-native-ui/references/toolbar-and-headers.md +284 -0
  471. package/plugins/lisa-expo-devin/skills/building-native-ui/references/visual-effects.md +197 -0
  472. package/plugins/lisa-expo-devin/skills/building-native-ui/references/webgpu-three.md +605 -0
  473. package/plugins/lisa-expo-devin/skills/building-native-ui/references/zoom-transitions.md +158 -0
  474. package/plugins/lisa-expo-devin/skills/container-view-pattern/SKILL.md +355 -0
  475. package/plugins/lisa-expo-devin/skills/container-view-pattern/references/examples.md +749 -0
  476. package/plugins/lisa-expo-devin/skills/container-view-pattern/references/patterns.md +318 -0
  477. package/plugins/lisa-expo-devin/skills/container-view-pattern/scripts/create_component.py +200 -0
  478. package/plugins/lisa-expo-devin/skills/container-view-pattern/scripts/validate_component.py +332 -0
  479. package/plugins/lisa-expo-devin/skills/cross-platform-compatibility/SKILL.md +268 -0
  480. package/plugins/lisa-expo-devin/skills/cross-platform-compatibility/references/common-issues.md +619 -0
  481. package/plugins/lisa-expo-devin/skills/cross-platform-compatibility/references/file-extensions.md +340 -0
  482. package/plugins/lisa-expo-devin/skills/cross-platform-compatibility/references/platform-api.md +276 -0
  483. package/plugins/lisa-expo-devin/skills/cross-platform-compatibility/scripts/validate_cross_platform.py +416 -0
  484. package/plugins/lisa-expo-devin/skills/directory-structure/SKILL.md +214 -0
  485. package/plugins/lisa-expo-devin/skills/directory-structure/scripts/validate_structure.py +454 -0
  486. package/plugins/lisa-expo-devin/skills/e2e-coverage-gaps/SKILL.md +117 -0
  487. package/plugins/lisa-expo-devin/skills/eas-update-insights/SKILL.md +228 -0
  488. package/plugins/lisa-expo-devin/skills/eas-update-insights/references/channel-insights-schema.md +47 -0
  489. package/plugins/lisa-expo-devin/skills/eas-update-insights/references/update-insights-schema.md +69 -0
  490. package/plugins/lisa-expo-devin/skills/expo-api-routes/SKILL.md +369 -0
  491. package/plugins/lisa-expo-devin/skills/expo-brownfield/SKILL.md +54 -0
  492. package/plugins/lisa-expo-devin/skills/expo-brownfield/references/brownfield-integrated.md +526 -0
  493. package/plugins/lisa-expo-devin/skills/expo-brownfield/references/brownfield-isolated.md +402 -0
  494. package/plugins/lisa-expo-devin/skills/expo-brownfield/references/comparison.md +63 -0
  495. package/plugins/lisa-expo-devin/skills/expo-brownfield/references/troubleshooting.md +88 -0
  496. package/plugins/lisa-expo-devin/skills/expo-cicd-workflows/SKILL.md +92 -0
  497. package/plugins/lisa-expo-devin/skills/expo-cicd-workflows/scripts/fetch.js +113 -0
  498. package/plugins/lisa-expo-devin/skills/expo-cicd-workflows/scripts/package.json +11 -0
  499. package/plugins/lisa-expo-devin/skills/expo-cicd-workflows/scripts/validate.js +85 -0
  500. package/plugins/lisa-expo-devin/skills/expo-deployment/SKILL.md +193 -0
  501. package/plugins/lisa-expo-devin/skills/expo-deployment/references/app-store-metadata.md +479 -0
  502. package/plugins/lisa-expo-devin/skills/expo-deployment/references/ios-app-store.md +355 -0
  503. package/plugins/lisa-expo-devin/skills/expo-deployment/references/play-store.md +264 -0
  504. package/plugins/lisa-expo-devin/skills/expo-deployment/references/testflight.md +58 -0
  505. package/plugins/lisa-expo-devin/skills/expo-deployment/references/workflows.md +200 -0
  506. package/plugins/lisa-expo-devin/skills/expo-dev-client/SKILL.md +164 -0
  507. package/plugins/lisa-expo-devin/skills/expo-env-config/SKILL.md +309 -0
  508. package/plugins/lisa-expo-devin/skills/expo-env-config/references/validation-patterns.md +417 -0
  509. package/plugins/lisa-expo-devin/skills/expo-module/SKILL.md +141 -0
  510. package/plugins/lisa-expo-devin/skills/expo-module/references/config-plugin.md +90 -0
  511. package/plugins/lisa-expo-devin/skills/expo-module/references/create-expo-module.md +206 -0
  512. package/plugins/lisa-expo-devin/skills/expo-module/references/lifecycle.md +127 -0
  513. package/plugins/lisa-expo-devin/skills/expo-module/references/module-config.md +48 -0
  514. package/plugins/lisa-expo-devin/skills/expo-module/references/native-module.md +286 -0
  515. package/plugins/lisa-expo-devin/skills/expo-module/references/native-view.md +171 -0
  516. package/plugins/lisa-expo-devin/skills/expo-router-best-practices/SKILL.md +432 -0
  517. package/plugins/lisa-expo-devin/skills/expo-router-best-practices/references/official-docs.md +290 -0
  518. package/plugins/lisa-expo-devin/skills/expo-router-best-practices/references/static-export-verification.md +54 -0
  519. package/plugins/lisa-expo-devin/skills/expo-router-best-practices/scripts/generate-route.py +171 -0
  520. package/plugins/lisa-expo-devin/skills/expo-tailwind-setup/SKILL.md +487 -0
  521. package/plugins/lisa-expo-devin/skills/expo-ui-jetpack-compose/SKILL.md +40 -0
  522. package/plugins/lisa-expo-devin/skills/expo-ui-swift-ui/SKILL.md +39 -0
  523. package/plugins/lisa-expo-devin/skills/gluestack-nativewind/SKILL.md +419 -0
  524. package/plugins/lisa-expo-devin/skills/gluestack-nativewind/references/color-tokens.md +343 -0
  525. package/plugins/lisa-expo-devin/skills/gluestack-nativewind/references/component-mapping.md +307 -0
  526. package/plugins/lisa-expo-devin/skills/gluestack-nativewind/references/spacing-scale.md +300 -0
  527. package/plugins/lisa-expo-devin/skills/gluestack-nativewind/scripts/test_validate_styling.py +240 -0
  528. package/plugins/lisa-expo-devin/skills/gluestack-nativewind/scripts/validate_styling.py +424 -0
  529. package/plugins/lisa-expo-devin/skills/jira-add-journey/SKILL.md +140 -0
  530. package/plugins/lisa-expo-devin/skills/jira-create/SKILL.md +161 -0
  531. package/plugins/lisa-expo-devin/skills/jira-evidence/SKILL.md +84 -0
  532. package/plugins/lisa-expo-devin/skills/jira-evidence/scripts/post-evidence.sh +262 -0
  533. package/plugins/lisa-expo-devin/skills/jira-journey/SKILL.md +196 -0
  534. package/plugins/lisa-expo-devin/skills/jira-journey/scripts/generate-templates.py +281 -0
  535. package/plugins/lisa-expo-devin/skills/jira-journey/scripts/parse-plan.py +400 -0
  536. package/plugins/lisa-expo-devin/skills/jira-verify/SKILL.md +27 -0
  537. package/plugins/lisa-expo-devin/skills/local-state/SKILL.md +362 -0
  538. package/plugins/lisa-expo-devin/skills/local-state/references/async-storage.md +505 -0
  539. package/plugins/lisa-expo-devin/skills/local-state/references/persistence-patterns.md +711 -0
  540. package/plugins/lisa-expo-devin/skills/local-state/references/reactive-variables.md +446 -0
  541. package/plugins/lisa-expo-devin/skills/maestro-mcp-setup/SKILL.md +144 -0
  542. package/plugins/lisa-expo-devin/skills/native-data-fetching/SKILL.md +507 -0
  543. package/plugins/lisa-expo-devin/skills/native-data-fetching/references/expo-router-loaders.md +344 -0
  544. package/plugins/lisa-expo-devin/skills/ops-browser-uat/SKILL.md +124 -0
  545. package/plugins/lisa-expo-devin/skills/ops-check-logs/SKILL.md +217 -0
  546. package/plugins/lisa-expo-devin/skills/ops-db-ops/SKILL.md +214 -0
  547. package/plugins/lisa-expo-devin/skills/ops-deploy/SKILL.md +123 -0
  548. package/plugins/lisa-expo-devin/skills/ops-monitor-errors/SKILL.md +99 -0
  549. package/plugins/lisa-expo-devin/skills/ops-performance/SKILL.md +165 -0
  550. package/plugins/lisa-expo-devin/skills/ops-run-local/SKILL.md +169 -0
  551. package/plugins/lisa-expo-devin/skills/ops-verify-health/SKILL.md +101 -0
  552. package/plugins/lisa-expo-devin/skills/owasp-zap/SKILL.md +61 -0
  553. package/plugins/lisa-expo-devin/skills/play-store-access/SKILL.md +226 -0
  554. package/plugins/lisa-expo-devin/skills/playwright-ci-debugging/SKILL.md +140 -0
  555. package/plugins/lisa-expo-devin/skills/playwright-selectors/SKILL.md +496 -0
  556. package/plugins/lisa-expo-devin/skills/reduce-complexity/SKILL.md +251 -0
  557. package/plugins/lisa-expo-devin/skills/reduce-complexity/references/extraction-strategies.md +456 -0
  558. package/plugins/lisa-expo-devin/skills/reduce-complexity/references/refactoring-patterns.md +557 -0
  559. package/plugins/lisa-expo-devin/skills/testing-library/SKILL.md +314 -0
  560. package/plugins/lisa-expo-devin/skills/testing-library/references/async-patterns.md +420 -0
  561. package/plugins/lisa-expo-devin/skills/testing-library/references/expo-router-testing.md +556 -0
  562. package/plugins/lisa-expo-devin/skills/testing-library/references/mocking-patterns.md +612 -0
  563. package/plugins/lisa-expo-devin/skills/testing-library/references/query-priority.md +291 -0
  564. package/plugins/lisa-expo-devin/skills/upgrading-expo/SKILL.md +134 -0
  565. package/plugins/lisa-expo-devin/skills/upgrading-expo/references/expo-av-to-audio.md +132 -0
  566. package/plugins/lisa-expo-devin/skills/upgrading-expo/references/expo-av-to-video.md +160 -0
  567. package/plugins/lisa-expo-devin/skills/upgrading-expo/references/native-tabs.md +124 -0
  568. package/plugins/lisa-expo-devin/skills/upgrading-expo/references/new-architecture.md +79 -0
  569. package/plugins/lisa-expo-devin/skills/upgrading-expo/references/react-19.md +79 -0
  570. package/plugins/lisa-expo-devin/skills/upgrading-expo/references/react-compiler.md +59 -0
  571. package/plugins/lisa-expo-devin/skills/upgrading-expo/references/react-navigation-to-expo-router.md +61 -0
  572. package/plugins/lisa-expo-devin/skills/use-dom/SKILL.md +417 -0
  573. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  574. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  575. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  576. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  577. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  578. package/plugins/lisa-harper-fabric-devin/.claude-plugin/plugin.json +11 -0
  579. package/plugins/lisa-harper-fabric-devin/.devin-plugin/plugin.json +8 -0
  580. package/plugins/lisa-harper-fabric-devin/generated-artifact-globs.txt +5 -0
  581. package/plugins/lisa-harper-fabric-devin/hooks/block-generated-artifact-edits.sh +141 -0
  582. package/plugins/lisa-harper-fabric-devin/hooks/devin-tool-name-shim.sh +30 -0
  583. package/plugins/lisa-harper-fabric-devin/hooks/enforce-config-extensions.mjs +196 -0
  584. package/plugins/lisa-harper-fabric-devin/hooks/enforce-config-extensions.sh +46 -0
  585. package/plugins/lisa-harper-fabric-devin/hooks/inject-rules.sh +27 -0
  586. package/plugins/lisa-harper-fabric-devin/hooks.json +36 -0
  587. package/plugins/lisa-harper-fabric-devin/rules/eager/harper-fabric.md +31 -0
  588. package/plugins/lisa-harper-fabric-devin/rules/reference/harper-fabric.md +52 -0
  589. package/plugins/lisa-harper-fabric-devin/skills/e2e-coverage-gaps/SKILL.md +117 -0
  590. package/plugins/lisa-harper-fabric-devin/skills/harper-auth/SKILL.md +368 -0
  591. package/plugins/lisa-harper-fabric-devin/skills/harper-build-and-deploy/SKILL.md +198 -0
  592. package/plugins/lisa-harper-fabric-devin/skills/harper-caching/SKILL.md +265 -0
  593. package/plugins/lisa-harper-fabric-devin/skills/harper-component-model/SKILL.md +87 -0
  594. package/plugins/lisa-harper-fabric-devin/skills/harper-config-yaml/SKILL.md +283 -0
  595. package/plugins/lisa-harper-fabric-devin/skills/harper-operations/SKILL.md +239 -0
  596. package/plugins/lisa-harper-fabric-devin/skills/harper-realtime/SKILL.md +187 -0
  597. package/plugins/lisa-harper-fabric-devin/skills/harper-resources/SKILL.md +142 -0
  598. package/plugins/lisa-harper-fabric-devin/skills/harper-rest-queries/SKILL.md +403 -0
  599. package/plugins/lisa-harper-fabric-devin/skills/harper-schema-graphql/SKILL.md +123 -0
  600. package/plugins/lisa-harper-fabric-devin/skills/harper-testing/SKILL.md +254 -0
  601. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  602. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  603. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  604. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  605. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  606. package/plugins/lisa-nestjs-devin/.claude-plugin/plugin.json +11 -0
  607. package/plugins/lisa-nestjs-devin/.devin-plugin/plugin.json +8 -0
  608. package/plugins/lisa-nestjs-devin/hooks/block-migration-edits.sh +125 -0
  609. package/plugins/lisa-nestjs-devin/hooks/devin-tool-name-shim.sh +30 -0
  610. package/plugins/lisa-nestjs-devin/hooks/lisa-edit-gate.sh +152 -0
  611. package/plugins/lisa-nestjs-devin/hooks.json +15 -0
  612. package/plugins/lisa-nestjs-devin/skills/nestjs-graphql/SKILL.md +176 -0
  613. package/plugins/lisa-nestjs-devin/skills/nestjs-graphql/references/advanced-features.md +527 -0
  614. package/plugins/lisa-nestjs-devin/skills/nestjs-graphql/references/project-patterns.md +531 -0
  615. package/plugins/lisa-nestjs-devin/skills/nestjs-graphql/references/quick-start.md +257 -0
  616. package/plugins/lisa-nestjs-devin/skills/nestjs-graphql/references/resolvers-mutations.md +413 -0
  617. package/plugins/lisa-nestjs-devin/skills/nestjs-graphql/references/types-scalars.md +513 -0
  618. package/plugins/lisa-nestjs-devin/skills/nestjs-rules/SKILL.md +560 -0
  619. package/plugins/lisa-nestjs-devin/skills/typeorm-patterns/SKILL.md +275 -0
  620. package/plugins/lisa-nestjs-devin/skills/typeorm-patterns/references/configuration-patterns.md +487 -0
  621. package/plugins/lisa-nestjs-devin/skills/typeorm-patterns/references/entity-patterns.md +450 -0
  622. package/plugins/lisa-nestjs-devin/skills/typeorm-patterns/references/observability-patterns.md +536 -0
  623. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  624. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  625. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  626. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  627. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  628. package/plugins/lisa-openclaw-devin/.claude-plugin/plugin.json +8 -0
  629. package/plugins/lisa-openclaw-devin/.devin-plugin/plugin.json +8 -0
  630. package/plugins/lisa-openclaw-devin/skills/lisa-openclaw-connect-repo-topic/SKILL.md +163 -0
  631. package/plugins/lisa-openclaw-devin/skills/lisa-openclaw-connect-repo-topic/references/repo-topic-config.md +185 -0
  632. package/plugins/lisa-openclaw-devin/skills/lisa-openclaw-connect-staff/SKILL.md +175 -0
  633. package/plugins/lisa-openclaw-devin/skills/lisa-openclaw-connect-staff/references/platform-routing.md +123 -0
  634. package/plugins/lisa-openclaw-devin/skills/lisa-openclaw-connect-staff/references/prompts.md +78 -0
  635. package/plugins/lisa-openclaw-devin/skills/lisa-openclaw-setup/SKILL.md +141 -0
  636. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  637. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  638. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  639. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  640. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  641. package/plugins/lisa-phaser-devin/.claude-plugin/plugin.json +11 -0
  642. package/plugins/lisa-phaser-devin/.devin-plugin/plugin.json +8 -0
  643. package/plugins/lisa-phaser-devin/agents/accessibility-advocate.md +55 -0
  644. package/plugins/lisa-phaser-devin/agents/art-director.md +90 -0
  645. package/plugins/lisa-phaser-devin/agents/audio-director.md +65 -0
  646. package/plugins/lisa-phaser-devin/agents/combat-designer.md +61 -0
  647. package/plugins/lisa-phaser-devin/agents/economy-designer.md +59 -0
  648. package/plugins/lisa-phaser-devin/agents/game-designer.md +62 -0
  649. package/plugins/lisa-phaser-devin/agents/game-feel-specialist.md +56 -0
  650. package/plugins/lisa-phaser-devin/agents/level-designer.md +59 -0
  651. package/plugins/lisa-phaser-devin/agents/localization-manager.md +61 -0
  652. package/plugins/lisa-phaser-devin/agents/marketing-strategist.md +59 -0
  653. package/plugins/lisa-phaser-devin/agents/monetization-designer.md +59 -0
  654. package/plugins/lisa-phaser-devin/agents/narrative-designer.md +56 -0
  655. package/plugins/lisa-phaser-devin/agents/onboarding-advocate.md +59 -0
  656. package/plugins/lisa-phaser-devin/agents/player-advocate.md +57 -0
  657. package/plugins/lisa-phaser-devin/agents/producer.md +61 -0
  658. package/plugins/lisa-phaser-devin/agents/product-analyst.md +62 -0
  659. package/plugins/lisa-phaser-devin/agents/publisher.md +59 -0
  660. package/plugins/lisa-phaser-devin/agents/qa-playtester.md +57 -0
  661. package/plugins/lisa-phaser-devin/agents/target-player.md +52 -0
  662. package/plugins/lisa-phaser-devin/agents/ux-ui-designer.md +60 -0
  663. package/plugins/lisa-phaser-devin/hooks/devin-tool-name-shim.sh +30 -0
  664. package/plugins/lisa-phaser-devin/hooks/inject-rules.sh +27 -0
  665. package/plugins/lisa-phaser-devin/hooks.json +14 -0
  666. package/plugins/lisa-phaser-devin/rules/eager/phaser.md +44 -0
  667. package/plugins/lisa-phaser-devin/rules/reference/phaser.md +184 -0
  668. package/plugins/lisa-phaser-devin/skills/phaser-accessibility/SKILL.md +135 -0
  669. package/plugins/lisa-phaser-devin/skills/phaser-asset-pipeline/SKILL.md +222 -0
  670. package/plugins/lisa-phaser-devin/skills/phaser-asset-sourcing/SKILL.md +151 -0
  671. package/plugins/lisa-phaser-devin/skills/phaser-build-deploy/SKILL.md +153 -0
  672. package/plugins/lisa-phaser-devin/skills/phaser-i18n/SKILL.md +122 -0
  673. package/plugins/lisa-phaser-devin/skills/phaser-project-structure/SKILL.md +89 -0
  674. package/plugins/lisa-phaser-devin/skills/phaser-services/SKILL.md +208 -0
  675. package/plugins/lisa-phaser-devin/skills/phaser-testing/SKILL.md +192 -0
  676. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  677. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  678. package/plugins/lisa-rails-agy/plugin.json +1 -1
  679. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  680. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  681. package/plugins/lisa-rails-devin/.claude-plugin/plugin.json +11 -0
  682. package/plugins/lisa-rails-devin/.devin-plugin/plugin.json +8 -0
  683. package/plugins/lisa-rails-devin/agents/ops-specialist.md +226 -0
  684. package/plugins/lisa-rails-devin/hooks/devin-tool-name-shim.sh +30 -0
  685. package/plugins/lisa-rails-devin/hooks/inject-rules.sh +40 -0
  686. package/plugins/lisa-rails-devin/hooks/lisa-edit-gate.sh +152 -0
  687. package/plugins/lisa-rails-devin/hooks/rubocop-on-edit.sh +101 -0
  688. package/plugins/lisa-rails-devin/hooks/sg-scan-on-edit.sh +97 -0
  689. package/plugins/lisa-rails-devin/hooks.json +29 -0
  690. package/plugins/lisa-rails-devin/rules/eager/rails-conventions.md +23 -0
  691. package/plugins/lisa-rails-devin/rules/reference/rails-conventions.md +176 -0
  692. package/plugins/lisa-rails-devin/skills/action-controller-best-practices/SKILL.md +374 -0
  693. package/plugins/lisa-rails-devin/skills/action-view-best-practices/SKILL.md +335 -0
  694. package/plugins/lisa-rails-devin/skills/active-record-model-best-practices/SKILL.md +166 -0
  695. package/plugins/lisa-rails-devin/skills/e2e-coverage-gaps/SKILL.md +117 -0
  696. package/plugins/lisa-rails-devin/skills/fix-linter-error/SKILL.md +45 -0
  697. package/plugins/lisa-rails-devin/skills/improve-code-complexity/SKILL.md +51 -0
  698. package/plugins/lisa-rails-devin/skills/improve-max-lines/SKILL.md +46 -0
  699. package/plugins/lisa-rails-devin/skills/improve-max-lines-per-function/SKILL.md +46 -0
  700. package/plugins/lisa-rails-devin/skills/improve-test-coverage/SKILL.md +48 -0
  701. package/plugins/lisa-rails-devin/skills/jira-add-journey/SKILL.md +79 -0
  702. package/plugins/lisa-rails-devin/skills/jira-create/SKILL.md +100 -0
  703. package/plugins/lisa-rails-devin/skills/jira-evidence/SKILL.md +76 -0
  704. package/plugins/lisa-rails-devin/skills/jira-evidence/scripts/post-evidence.sh +262 -0
  705. package/plugins/lisa-rails-devin/skills/jira-journey/SKILL.md +65 -0
  706. package/plugins/lisa-rails-devin/skills/jira-verify/SKILL.md +26 -0
  707. package/plugins/lisa-rails-devin/skills/ops-check-logs/SKILL.md +191 -0
  708. package/plugins/lisa-rails-devin/skills/ops-deploy/SKILL.md +153 -0
  709. package/plugins/lisa-rails-devin/skills/ops-run-local/SKILL.md +169 -0
  710. package/plugins/lisa-rails-devin/skills/ops-verify-jobs/SKILL.md +157 -0
  711. package/plugins/lisa-rails-devin/skills/ops-verify-telemetry/SKILL.md +226 -0
  712. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  713. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  714. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  715. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  716. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  717. package/plugins/lisa-typescript-devin/.claude-plugin/plugin.json +11 -0
  718. package/plugins/lisa-typescript-devin/.devin-plugin/plugin.json +8 -0
  719. package/plugins/lisa-typescript-devin/hooks/block-suppress-directives.sh +141 -0
  720. package/plugins/lisa-typescript-devin/hooks/devin-tool-name-shim.sh +30 -0
  721. package/plugins/lisa-typescript-devin/hooks/format-on-edit.sh +102 -0
  722. package/plugins/lisa-typescript-devin/hooks/lint-on-edit.sh +117 -0
  723. package/plugins/lisa-typescript-devin/hooks/lisa-edit-gate.sh +152 -0
  724. package/plugins/lisa-typescript-devin/hooks/sg-scan-on-edit.sh +94 -0
  725. package/plugins/lisa-typescript-devin/hooks.json +34 -0
  726. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  727. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  728. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  729. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  730. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  731. package/plugins/lisa-wiki-devin/.claude-plugin/plugin.json +8 -0
  732. package/plugins/lisa-wiki-devin/.devin-plugin/plugin.json +8 -0
  733. package/plugins/lisa-wiki-devin/ci/lisa-wiki-validate.yml +33 -0
  734. package/plugins/lisa-wiki-devin/schema/lisa-wiki-config.schema.json +162 -0
  735. package/plugins/lisa-wiki-devin/schema/wiki-structure.schema.json +51 -0
  736. package/plugins/lisa-wiki-devin/scripts/_wiki-lib.mjs +204 -0
  737. package/plugins/lisa-wiki-devin/scripts/diff-guard.mjs +117 -0
  738. package/plugins/lisa-wiki-devin/scripts/ensure-gitignore.mjs +131 -0
  739. package/plugins/lisa-wiki-devin/scripts/ensure-wiki.mjs +268 -0
  740. package/plugins/lisa-wiki-devin/scripts/ingest-git.mjs +198 -0
  741. package/plugins/lisa-wiki-devin/scripts/ingest-memory.mjs +135 -0
  742. package/plugins/lisa-wiki-devin/scripts/ingest-roles.mjs +95 -0
  743. package/plugins/lisa-wiki-devin/scripts/ingest_slack_channel.py +361 -0
  744. package/plugins/lisa-wiki-devin/scripts/lib/bounded-child.mjs +159 -0
  745. package/plugins/lisa-wiki-devin/scripts/lint-wiki.mjs +513 -0
  746. package/plugins/lisa-wiki-devin/scripts/mcp-doctor.mjs +72 -0
  747. package/plugins/lisa-wiki-devin/scripts/render-contract.mjs +107 -0
  748. package/plugins/lisa-wiki-devin/scripts/rewrite-refs.mjs +144 -0
  749. package/plugins/lisa-wiki-devin/scripts/slack_oauth_user.py +179 -0
  750. package/plugins/lisa-wiki-devin/scripts/validate-config.mjs +321 -0
  751. package/plugins/lisa-wiki-devin/scripts/verify-migration.mjs +203 -0
  752. package/plugins/lisa-wiki-devin/scripts/verify-wiki-safety.mjs +126 -0
  753. package/plugins/lisa-wiki-devin/scripts/wiki-safety.mjs +378 -0
  754. package/plugins/lisa-wiki-devin/scripts/wiki-status.mjs +345 -0
  755. package/plugins/lisa-wiki-devin/skills/lisa-wiki-add-ingest/SKILL.md +34 -0
  756. package/plugins/lisa-wiki-devin/skills/lisa-wiki-add-role/SKILL.md +35 -0
  757. package/plugins/lisa-wiki-devin/skills/lisa-wiki-connector-confluence/SKILL.md +25 -0
  758. package/plugins/lisa-wiki-devin/skills/lisa-wiki-connector-docs/SKILL.md +30 -0
  759. package/plugins/lisa-wiki-devin/skills/lisa-wiki-connector-git/SKILL.md +25 -0
  760. package/plugins/lisa-wiki-devin/skills/lisa-wiki-connector-jira/SKILL.md +28 -0
  761. package/plugins/lisa-wiki-devin/skills/lisa-wiki-connector-memory/SKILL.md +28 -0
  762. package/plugins/lisa-wiki-devin/skills/lisa-wiki-connector-notion/SKILL.md +25 -0
  763. package/plugins/lisa-wiki-devin/skills/lisa-wiki-connector-roles/SKILL.md +22 -0
  764. package/plugins/lisa-wiki-devin/skills/lisa-wiki-connector-slack/SKILL.md +30 -0
  765. package/plugins/lisa-wiki-devin/skills/lisa-wiki-connector-web/SKILL.md +23 -0
  766. package/plugins/lisa-wiki-devin/skills/lisa-wiki-doctor/SKILL.md +47 -0
  767. package/plugins/lisa-wiki-devin/skills/lisa-wiki-ingest/SKILL.md +106 -0
  768. package/plugins/lisa-wiki-devin/skills/lisa-wiki-lint/SKILL.md +32 -0
  769. package/plugins/lisa-wiki-devin/skills/lisa-wiki-migrate/SKILL.md +43 -0
  770. package/plugins/lisa-wiki-devin/skills/lisa-wiki-onboard-me/SKILL.md +33 -0
  771. package/plugins/lisa-wiki-devin/skills/lisa-wiki-query/SKILL.md +40 -0
  772. package/plugins/lisa-wiki-devin/skills/lisa-wiki-setup/SKILL.md +75 -0
  773. package/plugins/lisa-wiki-devin/skills/lisa-wiki-setup-automations/SKILL.md +83 -0
  774. package/plugins/lisa-wiki-devin/skills/lisa-wiki-status/SKILL.md +47 -0
  775. package/plugins/lisa-wiki-devin/skills/lisa-wiki-tear-down-automations/SKILL.md +34 -0
  776. package/plugins/lisa-wiki-devin/skills/lisa-wiki-usage/SKILL.md +50 -0
  777. package/plugins/lisa-wiki-devin/templates/agents/role-agent.claude.md +16 -0
  778. package/plugins/lisa-wiki-devin/templates/agents/role-agent.codex.toml +15 -0
  779. package/plugins/lisa-wiki-devin/templates/index.md +17 -0
  780. package/plugins/lisa-wiki-devin/templates/llm-wiki-contract.md +72 -0
  781. package/plugins/lisa-wiki-devin/templates/log.md +8 -0
  782. package/plugins/lisa-wiki-devin/templates/page-types/architecture.md +18 -0
  783. package/plugins/lisa-wiki-devin/templates/page-types/concept.md +18 -0
  784. package/plugins/lisa-wiki-devin/templates/page-types/decision.md +18 -0
  785. package/plugins/lisa-wiki-devin/templates/page-types/entity.md +19 -0
  786. package/plugins/lisa-wiki-devin/templates/page-types/open-question.md +18 -0
  787. package/plugins/lisa-wiki-devin/templates/page-types/playbook.md +18 -0
  788. package/plugins/lisa-wiki-devin/templates/page-types/project.md +19 -0
  789. package/plugins/lisa-wiki-devin/templates/page-types/requirement.md +19 -0
  790. package/plugins/lisa-wiki-devin/templates/page-types/staff.md +26 -0
  791. package/plugins/lisa-wiki-devin/templates/start-here.md +24 -0
  792. package/plugins/lisa-wiki-devin/templates/state-readme.md +20 -0
  793. package/plugins/lisa-wiki-devin/templates/wrapper-gitignore.txt +19 -0
  794. package/scripts/build-plugins.sh +2 -2
  795. package/scripts/deployed-guard-advice.mjs +1 -0
  796. package/scripts/generate-devin-plugin-artifacts.mjs +263 -0
  797. package/scripts/lib/hook-registration-audit.mjs +3 -1
  798. package/scripts/lib/per-agent-hook-filter.mjs +174 -5
  799. package/scripts/lib/plugin-rule-citations.mjs +2 -2
@@ -0,0 +1,1175 @@
1
+ #!/usr/bin/env bash
2
+ # This file is managed by Lisa and IS replaced on each `lisa` run.
3
+ # Do not edit directly — durable changes belong upstream in Lisa.
4
+
5
+ # PreToolUse hook: refuse agent writes to files Lisa overwrites on every apply.
6
+ #
7
+ # Lisa ships templates in three modes, and only one of them is unsafe to edit:
8
+ #
9
+ # copy-overwrite — see below; the harm depends on the file.
10
+ # copy-contents — Lisa APPENDS its lines; host content survives.
11
+ # create-only — skipped when the file exists; the host owns it outright.
12
+ #
13
+ # So this guard covers copy-overwrite and nothing else. Blocking the other two
14
+ # would stop agents editing files they are supposed to own, which is worse than
15
+ # the problem being solved.
16
+ #
17
+ # The name `copy-overwrite` is misleading, and two successive versions of this
18
+ # guard got the consequence wrong by trusting it. MEASURED, by mutating four
19
+ # files in a scratch project and running a real `lisa apply` against them:
20
+ #
21
+ # scripts/lisa-gates.mjs (ledger-tracked) → SURVIVED
22
+ # .lintstagedrc.json (untracked, JSON) → SURVIVED
23
+ # .prettierignore (untracked, text) → SURVIVED
24
+ # .yamllint (untracked, text) → SURVIVED
25
+ #
26
+ # Summary line: `Overwritten: 0 files` / `Out of date: 3 files (managed
27
+ # templates changed; NOT updated)`.
28
+ #
29
+ # copy-overwrite overwrites an UNMODIFIED copy — it refreshes. It does not
30
+ # overwrite a host-edited one, in any population tested. So the harm is the same
31
+ # for both, and it is not deletion:
32
+ #
33
+ # THE FILE SILENTLY FORKS. It keeps looking current while every upstream fix
34
+ # stops reaching it. Nothing is lost, which is exactly what makes it invisible.
35
+ #
36
+ # Ledger membership changes the MESSAGE apply prints, not the outcome — tracked
37
+ # files get a provenance verdict naming the fork and offering
38
+ # `lisa-guard-capabilities:`; untracked ones get a bare "Out of date" warning.
39
+ # The refusal branches on that so the reader sees the words apply will use.
40
+ #
41
+ # Measured, not hypothetical. Nothing enforced this, so downstream copies were
42
+ # edited and then silently diverged: `classify-maestro-failures.mjs` reached
43
+ # 36,061 bytes in one fleet repo against 29,586 shipped, and five gate files in
44
+ # another stopped receiving upstream fixes — one over roughly 138 bytes of
45
+ # cosmetic change. The edits were made in good faith; nothing told anyone the
46
+ # file was not theirs.
47
+ #
48
+ # ## Why the path, not a banner comment
49
+ #
50
+ # 103 of Lisa's 145 copy-overwrite files carry a "managed by Lisa" header, and
51
+ # the other 42 CANNOT: 30 are `.json` (no comment syntax), 8 are `.gitkeep` /
52
+ # `.keep` placeholders, and the rest are bare-value files like `.nvmrc`. A guard
53
+ # keyed on the banner would miss every one of them, so this resolves the path
54
+ # against the installed package instead and covers all 145 regardless of format.
55
+ #
56
+ # Blocked signatures:
57
+ # 1. Write / Edit / MultiEdit / NotebookEdit whose target resolves to a
58
+ # copy-overwrite template in the installed Lisa package;
59
+ # 2. Bash output redirection (`>`, `>>`, `>|`), `tee`, or an in-place `sed`
60
+ # aimed at one — `-i`, `-i ''`, `-i.bak`, a cluster such as `-ni`, and the
61
+ # long `--in-place[=SUFFIX]`. Reads never fire;
62
+ # 3. any of those inside a script the command EXECUTES — `bash edit.sh`,
63
+ # `sh`, `source`, `.`, `bash < edit.sh`, and behind wrappers that carry an
64
+ # operand of their own (`nice -n 5`, `timeout 5`, `sudo`).
65
+ #
66
+ # ## What signature 3 deliberately does NOT do
67
+ #
68
+ # A path is followed ONLY when the command EXECUTES it. `grep -n x edit.sh`,
69
+ # `wc -l edit.sh`, `git diff edit.sh` and a test run over it name a file as
70
+ # DATA, and following those is the known-wrong fix this guard family has already
71
+ # made once: it refuses ordinary reads and attributes a file's capability to a
72
+ # command that merely mentions it. Command POSITION decides. Taint does not
73
+ # propagate any further either — a path a followed script merely NAMES is data
74
+ # one file further out, not a third hop.
75
+ #
76
+ # ## Every agent surface reaches this guard, and Codex reaches it twice over
77
+ #
78
+ # There is no parity gap left to record. A note here used to record one, and it
79
+ # was wrong by the time anyone read it — through two wordings. The first named
80
+ # three surfaces; every one of those ports then shipped and the note stayed
81
+ # unedited. The second named Codex alone, and Codex had never been the gap
82
+ # either: the note and the check that read it were both looking in
83
+ # `src/codex/scripts/`, and `src/codex/hooks-installer.ts` says in its own
84
+ # opening remark that the linked-script layout that directory serves is RETIRED
85
+ # (CodySwannGT/lisa#3750).
86
+ #
87
+ # The note is deleted rather than trimmed, because a stale gap note is worse
88
+ # than none: it OVERSTATES the gap, and a reader who trusts it goes looking for
89
+ # three missing ports, finds two present, and cannot tell which third is real
90
+ # without redoing the measurement from scratch. AGENTS.md asks for a gap to be
91
+ # documented instead of silently dropped — that only works while the document
92
+ # is true.
93
+ #
94
+ # The deeper lesson is not "the note was stale". It is that a note asserting
95
+ # ABSENCE and a check deriving presence from ONE path shape agree with each
96
+ # other for free — the check read the same retired directory the note did, so
97
+ # it returned a clean tick on a claim that was false.
98
+ #
99
+ # Where each surface picks it up, so the next reader measures instead of
100
+ # guessing: Claude and Copilot from `.claude-plugin/plugin.json`, Cursor from
101
+ # `hooks/hooks.json`, Antigravity from `hooks.json` via the `.agy.sh` adapter
102
+ # beside this file, OpenCode from
103
+ # `src/opencode/plugin-templates/lisa-block-managed-file-edits.ts`, and Codex
104
+ # from TWO channels rather than one:
105
+ #
106
+ # `plugins/lisa/.codex-plugin/hooks.json` registers this guard directly, on
107
+ # the Codex plugin channel.
108
+ #
109
+ # `scripts/lisa-enforcement-fallback.sh` names this guard in its roster, and
110
+ # `src/codex/enforcement-fallback-installer.ts` registers that dispatcher on
111
+ # `PreToolUse` for `Bash|Edit|Write|apply_patch` — which is how Codex's
112
+ # `apply_patch` writes are reached at all.
113
+ #
114
+ # Both Codex channels are measured rather than inferred — see
115
+ # `tests/unit/codex/block-managed-file-edits-codex.test.ts`, which drives the
116
+ # registered command as a subprocess in a synthetic host project: a Codex
117
+ # `apply_patch` or `Bash` redirect at a copy-overwrite template exits 2; an
118
+ # ordinary edit to a host-owned file exits 0.
119
+ #
120
+ # Two checks hold this paragraph to the tree.
121
+ # `tests/unit/hooks/managed-file-guard-parity-note.test.ts` fails if it goes
122
+ # stale in either direction — a port that ships without the note being
123
+ # narrowed, and a port REMOVED without it being restored.
124
+ # `check:guard-parity-notes` refuses an absence claim written back in, and now
125
+ # resolves Codex from those two registration channels as well as from a path
126
+ # shape, so it can no longer agree with a false note for free.
127
+ #
128
+ # Exemptions (allowed):
129
+ # - `LISA_ALLOW_MANAGED_FILE_WRITE` set — the operator's explicit override,
130
+ # named in the refusal;
131
+ # - paths under `node_modules/` or `dist/` — vendored copies, not the host's;
132
+ # - the Lisa source repository itself, where these files are the originals and
133
+ # editing them is the entire point.
134
+ #
135
+ # The line below lets `lisa apply` tell a downstream copy of this guard that is
136
+ # BEHIND from one that is AHEAD. Byte comparison cannot: both look like "differs
137
+ # from mine", and guessing "behind" is how a fork's stronger guard gets silently
138
+ # replaced by a weaker upstream one. Add a name here in the same commit that
139
+ # closes a vector.
140
+ # lisa-guard-capabilities: managed-path-resolution, lisaignore-precedence, generated-path-rebuild, redirect-target, tee-target, sed-in-place-all-spellings, executed-script-reach, source-builtin-reach, stdin-redirect-reach, wrapper-positional-operand, direct-script-command-reach, analyzer-failure-visible, apply-patch-parse-failure-visible, apply-patch-move-target, shell-command-string-reach
141
+ set -euo pipefail
142
+
143
+ input="$(cat)"
144
+
145
+ # Evaluate once per tool call when this guard is registered on both channels.
146
+ #
147
+ # Lisa reaches an agent through the repository dispatcher AND the plugin
148
+ # manifest, and where both are live the harness runs this guard twice for one
149
+ # tool call. `guard-dedupe.bash` short-circuits the second run ONLY when a
150
+ # byte-identical copy already ALLOWED this exact payload on this exact tool
151
+ # call; a differing vintage, a refusal, and a host with one channel all
152
+ # evaluate exactly as before. Nothing is de-registered by it
153
+ # (CodySwannGT/lisa#3814).
154
+ #
155
+ # Absent library means no dedupe, which is the pre-existing behaviour, so an
156
+ # older channel copy that predates it is unaffected.
157
+ lisa_guard_hook_dir="${BASH_SOURCE[0]%/*}"
158
+ lisa_guard_dedupe_lib="$lisa_guard_hook_dir/guard-dedupe.bash"
159
+ if [ -r "$lisa_guard_dedupe_lib" ]; then
160
+ # shellcheck source=guard-dedupe.bash
161
+ . "$lisa_guard_dedupe_lib"
162
+ trap 'lisa_guard_dedupe_record $?' EXIT
163
+ lisa_guard_dedupe block-managed-file-edits "$input"
164
+ fi
165
+
166
+ command -v jq >/dev/null 2>&1 || exit 0
167
+
168
+ # The operator's override, checked first so it is always the cheapest way out.
169
+ if [ -n "${LISA_ALLOW_MANAGED_FILE_WRITE:-}" ]; then
170
+ exit 0
171
+ fi
172
+
173
+ tool_name="$(printf '%s' "$input" | jq -r '.tool_name // empty')"
174
+ [ -n "$tool_name" ] || exit 0
175
+
176
+ project_root="${CLAUDE_PROJECT_DIR:-$PWD}"
177
+ package_root="$project_root/node_modules/@codyswann/lisa"
178
+
179
+ # No installed Lisa means nothing to classify against. Silent, because a project
180
+ # that has not installed Lisa is not doing anything wrong.
181
+ [ -d "$package_root" ] || exit 0
182
+
183
+ # In Lisa's own repository these files ARE the originals. Blocking here would
184
+ # make the templates uneditable by the only agents that should edit them.
185
+ if [ -f "$project_root/package.json" ] &&
186
+ grep -q '"name": *"@codyswann/lisa"' "$project_root/package.json" 2>/dev/null; then
187
+ exit 0
188
+ fi
189
+
190
+ # Whether the project has claimed a path in `.lisaignore`.
191
+ #
192
+ # THIS IS THE OWNERSHIP QUESTION, and it decides whether blocking is right at
193
+ # all. `lisa apply` skips an ignored path — it logs `Kept (.lisaignore)` and
194
+ # counts it as ignored rather than overwritten — so the file is the project's,
195
+ # its edits survive, and refusing them would be refusing someone access to their
196
+ # own file. `doctor-lisa-owned-artifacts` already consults this list; this guard
197
+ # did not, which would have blocked deliberate forks.
198
+ #
199
+ # The real matcher is minimatch in `src/utils/ignore-patterns.ts` and cannot be
200
+ # reproduced faithfully in shell. This covers the common shapes — exact path,
201
+ # directory prefix, glob, and a bare pattern matching any segment — and where it
202
+ # is unsure it ALLOWS. Wrongly allowing costs an edit that apply may overwrite,
203
+ # which is the behaviour before this guard existed; wrongly blocking locks
204
+ # someone out of a file they own.
205
+ lisaignored() {
206
+ local rel="$1"
207
+ local list="$project_root/.lisaignore"
208
+ [ -f "$list" ] || return 1
209
+ # Gitignore precedence: patterns are read in order and the LAST one to select
210
+ # the path decides, so `!x` re-includes something an earlier line ignored.
211
+ # This mirrors `matchesAnyPattern` in `src/utils/ignore-patterns.ts`; the two
212
+ # must agree, or an agent gets blocked on a file apply considers the
213
+ # project's, or waved through on one it does not.
214
+ #
215
+ # `ignored` carries shell truth: 0 = ignored, 1 = not.
216
+ local ignored=1
217
+ local pattern
218
+ while IFS= read -r pattern || [ -n "$pattern" ]; do
219
+ pattern="${pattern#"${pattern%%[![:space:]]*}"}"
220
+ pattern="${pattern%"${pattern##*[![:space:]]}"}"
221
+ [ -n "$pattern" ] || continue
222
+ case "$pattern" in \#*) continue ;; esac
223
+ local negated=1
224
+ case "$pattern" in
225
+ # A bare `!` selects nothing rather than everything.
226
+ !) continue ;;
227
+ !*)
228
+ negated=0
229
+ pattern="${pattern#!}"
230
+ ;;
231
+ # `\!x` is a literal leading `!`, not a negation.
232
+ \\!*) pattern="${pattern#\\}" ;;
233
+ esac
234
+ local selected=1
235
+ case "$pattern" in
236
+ */)
237
+ case "$rel" in "${pattern%/}"/* | "${pattern%/}") selected=0 ;; esac
238
+ ;;
239
+ esac
240
+ if [ "$selected" -ne 0 ]; then
241
+ # The pattern is a glob on purpose, so it is deliberately unquoted.
242
+ #
243
+ # The reason sits on its own line because a shellcheck directive is
244
+ # `key=value` pairs and NOTHING else. Written as
245
+ # `disable=SC2254 -- <prose>`, the trailing words are read as more
246
+ # directive keys: the directive fails with SC1072/SC1073, shellcheck
247
+ # stops checking the rest of THIS FILE, and SC2254 is left unsuppressed
248
+ # as well. Measured with shellcheck 0.11.0. Do not rejoin these lines.
249
+ # shellcheck disable=SC2254
250
+ case "$rel" in $pattern) selected=0 ;; esac
251
+ fi
252
+ if [ "$selected" -ne 0 ]; then
253
+ case "$pattern" in
254
+ */*) ;;
255
+ *)
256
+ # Ditto, matched against the basename — and ditto about the reason
257
+ # living on its own line rather than after the directive.
258
+ # shellcheck disable=SC2254
259
+ case "${rel##*/}" in $pattern) selected=0 ;; esac
260
+ ;;
261
+ esac
262
+ fi
263
+ [ "$selected" -eq 0 ] || continue
264
+ # A positive match ignores the path; a negated one un-ignores it. Both
265
+ # OVERWRITE any earlier verdict rather than short-circuiting — that is what
266
+ # makes the last matching pattern win.
267
+ if [ "$negated" -eq 0 ]; then
268
+ ignored=1
269
+ else
270
+ ignored=0
271
+ fi
272
+ done <"$list"
273
+ return "$ignored"
274
+ }
275
+
276
+ # A candidate rewritten relative to the project, so an absolute target from a
277
+ # tool payload and a relative one from a shell command classify identically.
278
+ relative_path() {
279
+ local rel="${1#"$project_root"/}"
280
+ printf '%s' "${rel#./}"
281
+ }
282
+
283
+ # Whether a host-relative path is shipped as a copy-overwrite template.
284
+ #
285
+ # A few stat calls rather than an enumeration: the same relative path is probed
286
+ # under each stack's copy-overwrite tree, so cost does not grow with the 145
287
+ # templates.
288
+ managed_source() {
289
+ local candidate="$1"
290
+ case "$candidate" in
291
+ */node_modules/* | node_modules/* | */dist/* | dist/*) return 1 ;;
292
+ esac
293
+ local rel
294
+ rel="$(relative_path "$candidate")"
295
+ [ -n "$rel" ] || return 1
296
+ # Claimed by the project, so not ours to refuse.
297
+ lisaignored "$rel" && return 1
298
+ local stack
299
+ for stack in "$package_root"/*/copy-overwrite; do
300
+ [ -d "$stack" ] || continue
301
+ if [ -e "$stack/$rel" ]; then
302
+ printf '%s' "${stack#"$package_root"/}/$rel"
303
+ return 0
304
+ fi
305
+ done
306
+ # A generated path has no template to point at — apply rebuilds it from the
307
+ # migration rather than copying it — so the source is named for the reader
308
+ # rather than resolved to a file that does not exist.
309
+ if generated_path "$rel"; then
310
+ printf '%s' "generated by lisa apply"
311
+ return 0
312
+ fi
313
+ return 1
314
+ }
315
+
316
+ # Whether a destination is a path `lisa apply` GENERATES rather than copies.
317
+ #
318
+ # Read out of the installed package, never restated here.
319
+ # `dist/migrations/generated-paths.js` is the single source the vendoring
320
+ # migration also imports, so a new generated tree is covered without editing this
321
+ # hook. A hook carrying its own copy of that list would be a second place to
322
+ # update that nobody updates, which then governs silently — the defect this file
323
+ # already documents for copy-overwrite, one step along.
324
+ #
325
+ # The distinction earns its keep because the two populations fail in OPPOSITE
326
+ # ways, and a guard that gives one answer is wrong for half the files it covers:
327
+ # an edited copy-overwrite file is PRESERVED and silently forks, while a
328
+ # generated file is REBUILT and the edit vanishes on the next explicit apply.
329
+ generated_path() {
330
+ local rel="$1"
331
+ local module="$package_root/dist/migrations/generated-paths.js"
332
+ [ -f "$module" ] || return 1
333
+ local prefixes
334
+ prefixes="$(grep -oE '"[^"]+"' "$module" 2>/dev/null | tr -d '"')"
335
+ local prefix
336
+ for prefix in $prefixes; do
337
+ case "$prefix" in
338
+ */*) ;;
339
+ *) continue ;;
340
+ esac
341
+ case "$rel" in
342
+ "$prefix" | "$prefix"/*) return 0 ;;
343
+ esac
344
+ done
345
+ return 1
346
+ }
347
+
348
+ # Whether a destination is a ledger-tracked Lisa-owned guard.
349
+ #
350
+ # Both populations are PRESERVED once edited (measured — see the header). What
351
+ # membership changes is what apply prints and what the escape hatch is: a tracked
352
+ # guard gets a provenance verdict and can declare `lisa-guard-capabilities:`,
353
+ # while an untracked template gets a bare "Out of date" line and `.lisaignore`.
354
+ # The refusal quotes the words the reader will actually see, so it has to know
355
+ # which side it is on.
356
+ ledger_tracked() {
357
+ local rel="$1"
358
+ local ledger="$package_root/dist/core/lisa-owned-hash-ledger.js"
359
+ [ -f "$ledger" ] || return 1
360
+ grep -q "\"$rel\"" "$ledger" 2>/dev/null
361
+ }
362
+
363
+ refuse() {
364
+ local target="$1"
365
+ local source="$2"
366
+ local rel="$3"
367
+ if generated_path "$rel"; then
368
+ cat >&2 <<EOF
369
+ BLOCKED: refusing to write \`$target\`.
370
+
371
+ WHY: this file is generated by \`lisa apply\` (\`$source\`).
372
+ \`lisa apply\` REGENERATES this file. The next explicit \`lisa apply\`
373
+ rebuilds it, so a direct edit will be lost.
374
+
375
+ Change the generation source upstream in Lisa, or the supported project
376
+ configuration that supplies it, then run \`lisa apply\` to regenerate the file.
377
+
378
+ If a human explicitly asked for this edit, they can re-run with
379
+ \`LISA_ALLOW_MANAGED_FILE_WRITE=1\` set, which bypasses this guard.
380
+ EOF
381
+ exit 2
382
+ fi
383
+ local consequence
384
+ if ledger_tracked "$rel"; then
385
+ consequence="\`lisa apply\` will KEEP your edit — this is a Lisa-owned guard,
386
+ and apply says so: \"its contents match no Lisa release, so Lisa cannot tell
387
+ whether it is out of date or deliberately stronger. Kept yours.\"
388
+
389
+ That is the trap. Nothing is deleted; the file silently FORKS. It keeps looking
390
+ current while every upstream fix stops reaching it. One repository in this fleet
391
+ carries 243 lines of divergence nobody knew about, in a guard that had quietly
392
+ stopped receiving fixes."
393
+ else
394
+ consequence="\`lisa apply\` will KEEP your edit and report the file as
395
+ \"Out of date, not updated\" on every run from now on.
396
+
397
+ That is the trap. Nothing is deleted; the file silently FORKS, stops receiving
398
+ upstream changes, and adds a permanent warning line that the next person learns
399
+ to scroll past."
400
+ fi
401
+ cat >&2 <<EOF
402
+ BLOCKED: refusing to write \`$target\`.
403
+
404
+ WHY: this file is Lisa-managed, shipped as a **copy-overwrite** template
405
+ (\`$source\` in the installed package).
406
+
407
+ $consequence
408
+
409
+ WHERE IT GOES INSTEAD — take the first one that fits:
410
+
411
+ 1. The change should apply everywhere. Edit the template upstream in Lisa and
412
+ release it — \`/lisa:cross-pollinate\`, or an issue on CodySwannGT/lisa.
413
+ That is the only edit that survives an install.
414
+
415
+ 2. Only this project needs to differ. Look for the local escape hatch beside the
416
+ file — Lisa ships \`.local\` variants for the configs that support one
417
+ (\`eslint.config.local.ts\`, \`tsconfig.local.json\`, \`audit.ignore.local.json\`,
418
+ and others). Those are yours and are never overwritten.
419
+
420
+ 3. The behaviour is configurable rather than hardcoded. Check \`.lisa.config.json\`
421
+ — the \`gates\` block in particular decides which checks run and what command
422
+ proves each one, so a project can substitute its own task without touching a
423
+ shipped file.
424
+
425
+ 4. This project has deliberately FORKED this file and means to keep its own
426
+ version. Apply already preserves the edit either way, so what is left to
427
+ choose is whether the fork stays VISIBLE. Keeping it visible is the point:
428
+
429
+ - **A Lisa-owned guard (hash-tracked).** Do NOT add it to \`.lisaignore\`.
430
+ Apply preserves your version regardless, so ignoring it buys nothing — and
431
+ it silences the standoff \`lisa doctor\` reports on every run, replacing a
432
+ true warning with the line "Enforcement guards match the installed Lisa
433
+ version", which is then false. A visible, resolvable fork becomes a silent
434
+ permanent one. Instead declare what your version defends with a
435
+ \`lisa-guard-capabilities:\` line; apply then classifies it \`host-ahead\`
436
+ and says so by name, rather than reporting that it cannot tell.
437
+ - **Any other template.** \`.lisaignore\` records the divergence where the
438
+ next person can see it and stops the recurring "Out of date" line. It does
439
+ not preserve the file — apply already does — so use it to DECLARE a fork
440
+ you have decided on, never to quiet one you have not.
441
+
442
+ 5. You believe this file should not be Lisa-managed at all. That is a real
443
+ argument and it belongs upstream, not in a local edit that will be erased.
444
+
445
+ If a human explicitly asked for this edit, they can re-run with
446
+ \`LISA_ALLOW_MANAGED_FILE_WRITE=1\` set, which bypasses this guard.
447
+ EOF
448
+ exit 2
449
+ }
450
+
451
+ case "$tool_name" in
452
+ apply_patch)
453
+ # Codex's primary edit mechanism, and the one this guard was already
454
+ # registered for while being unable to read it.
455
+ #
456
+ # `src/codex/enforcement-fallback-installer.ts` registers the dispatcher
457
+ # on `Bash|Edit|Write|apply_patch`, so this envelope was already being
458
+ # delivered here - and matched no arm below, fell off the end of the
459
+ # `case`, and exited 0. A registered guard that receives the call and
460
+ # allows it is worse than an unregistered one, because the wiring reads
461
+ # as complete: an auditor sees the matcher forwarding `apply_patch` into
462
+ # a guard about managed files and correctly concludes it is covered
463
+ # (CodySwannGT/lisa#3776).
464
+ #
465
+ # The envelope carries no `file_path`. Verified against codex-cli 0.125.0
466
+ # by capturing real hook stdin - see `src/codex/scripts/_extract-edit-paths.sh`,
467
+ # which performs this same header parse for the Codex-side hooks:
468
+ #
469
+ # Edit / Write -> tool_input.file_path (single string)
470
+ # apply_patch -> tool_input.command (a STRING holding the whole
471
+ # patch, NOT an array)
472
+ #
473
+ # and the patch names its targets in header lines, MANY per patch:
474
+ #
475
+ # *** Add File: <path>
476
+ # *** Update File: <path>
477
+ # *** Delete File: <path>
478
+ # *** Move to: <path>
479
+ #
480
+ # So every header is walked and each target classified; one managed
481
+ # target anywhere in a multi-file patch refuses the whole call, because
482
+ # the patch applies atomically and there is no partial acceptance to
483
+ # offer.
484
+ #
485
+ # This restates `_extract-edit-paths.sh`'s header match rather than
486
+ # sourcing it, and that is forced by where the two files ship: this guard
487
+ # installs to a host's `scripts/lisa-hooks/`, that helper to
488
+ # `.codex/hooks/lisa/`, and neither tree can source across to the other.
489
+ # `tests/unit/hooks/block-managed-file-edits-apply-patch.test.ts` pins the
490
+ # two header sets equal so the restatement cannot drift into a gap - the
491
+ # same answer `core/hook-copy-parity` gives for sibling copies that
492
+ # legitimately cannot be one file. What is NOT restated is the
493
+ # classification: `managed_source` and `refuse` are the single copy here,
494
+ # exactly as for every other arm.
495
+ if ! patch_text="$(printf '%s' "$input" | jq -er '
496
+ if ((.tool_input.command? // "") | type) == "string"
497
+ then (.tool_input.command? // "")
498
+ else error("tool_input.command must be a string")
499
+ end')"; then
500
+ printf 'block-managed-file-edits: could not parse the apply_patch command; managed-file protection refused the edit\n' >&2
501
+ exit 2
502
+ fi
503
+ [ -n "$patch_text" ] || exit 0
504
+ while IFS= read -r patch_line; do
505
+ case "$patch_line" in
506
+ "*** Add File: "* | "*** Update File: "* | "*** Delete File: "*)
507
+ candidate="${patch_line#*File: }"
508
+ ;;
509
+ "*** Move to: "*)
510
+ candidate="${patch_line#*** Move to: }"
511
+ ;;
512
+ *) continue ;;
513
+ esac
514
+ [ -n "$candidate" ] || continue
515
+ if source_path="$(managed_source "$candidate")"; then
516
+ refuse "$candidate" "$source_path" "$(relative_path "$candidate")"
517
+ fi
518
+ done <<EOF
519
+ $patch_text
520
+ EOF
521
+ ;;
522
+ Write | Edit | MultiEdit | NotebookEdit | Update)
523
+ paths="$(printf '%s' "$input" | jq -r '
524
+ [ .tool_input.file_path?,
525
+ .tool_input.path?,
526
+ .tool_input.notebook_path?,
527
+ (.tool_input.edits? // [] | .[].file_path?)
528
+ ] | map(select(. != null and . != "")) | .[]' 2>/dev/null || true)"
529
+ while IFS= read -r candidate; do
530
+ [ -n "$candidate" ] || continue
531
+ if source_path="$(managed_source "$candidate")"; then
532
+ refuse "$candidate" "$source_path" "$(relative_path "$candidate")"
533
+ fi
534
+ done <<EOF
535
+ $paths
536
+ EOF
537
+ ;;
538
+ Bash)
539
+ command_str="$(printf '%s' "$input" | jq -r '.tool_input.command // empty')"
540
+ [ -n "$command_str" ] || exit 0
541
+ # A missing interpreter must be announced rather than swallowed. This guard
542
+ # degrades to "allow" — a hook that cannot parse its input cannot tell a
543
+ # write from a read — but a guard that is silently absent reads exactly like
544
+ # a guard that is passing.
545
+ if ! command -v python3 >/dev/null 2>&1; then
546
+ printf 'block-managed-file-edits: python3 not found; Bash write protection is NOT active\n' >&2
547
+ exit 0
548
+ fi
549
+ # Why a tokenizer replaced the two-stage regex.
550
+ #
551
+ # The old extraction was `grep -Eo` for a redirect / tee / in-place sed,
552
+ # followed by a `sed -E` strip of the matched prefix. MEASURED against it:
553
+ # `tee <path>` and `tee -a <path>` extracted correctly, and EVERY `sed -i`
554
+ # spelling extracted NOTHING — `-i`, `-i ''` and `-i.bak` alike. The
555
+ # `grep` matched; the strip pattern `sed[[:space:]]+[^|;&]*-i[^|;&]*` is
556
+ # greedy, so it consumed the path along with the flags and left an empty
557
+ # token. The arm was DEAD, not merely missing macOS's two-token spelling.
558
+ #
559
+ # A regex cannot answer the question this guard actually asks — is this path
560
+ # WRITTEN or merely NAMED — because that depends on token position, which is
561
+ # what a tokenizer is for.
562
+ #
563
+ # The analyzer is read into a variable by `read -d ''` rather than run
564
+ # inside a command substitution wrapping a here-document. Bash finds the
565
+ # closing paren of a command substitution by re-scanning its text, and a
566
+ # here-document body nested there is scanned too: the lone backtick in
567
+ # `re.compile(r"[$`]")` below then reads as an unterminated backtick
568
+ # substitution and the whole script fails to parse. Keeping the
569
+ # here-document out of the substitution is the fix. This is also the shape
570
+ # `block-direct-issue-create.sh` already uses for its own classifier.
571
+ #
572
+ # The delimiter is deliberately not spelled out in this comment: a tool that
573
+ # greps for here-document starts would otherwise match the prose and read
574
+ # the wrong span.
575
+ analyzer=''
576
+ IFS= read -r -d '' analyzer <<'PY' || true
577
+ import os
578
+ import re
579
+ import shlex
580
+ import sys
581
+
582
+ command = os.environ.get("MANAGED_EDIT_COMMAND", "")
583
+ project = os.environ.get("MANAGED_EDIT_PROJECT", "") or os.getcwd()
584
+
585
+ # Following a script costs a read on every intercepted command, so the walk is
586
+ # bounded three ways, and a file past the cap is skipped rather than half-read:
587
+ # a truncated scan reports a confident ALLOW about text it never saw.
588
+ FOLLOW_MAX_BYTES = 262144
589
+ FOLLOW_MAX_FILES = 8
590
+ FOLLOW_MAX_DEPTH = 3
591
+ ENV_SPLIT_UNRESOLVED = 42
592
+
593
+ # Spelled with chr() rather than backslash escapes on purpose. This source is
594
+ # embedded in a shell heredoc and copied verbatim through several generators
595
+ # into every shipped plugin; a backslash literal is the one thing in it most
596
+ # likely to be mangled in transit, and the mangling would be silent.
597
+ BACKSLASH = chr(92)
598
+ NEWLINE = chr(10)
599
+
600
+ # `|&` pipes stdout and stderr into the next command, and the case terminators
601
+ # end a statement as `;` does. Without them `printf x |& tee <managed>` stayed
602
+ # one statement whose command word was `printf`, so the `tee` write target was
603
+ # never examined.
604
+ STATEMENT_SEPARATORS = {
605
+ ";", "|", "||", "&", "&&", "(", ")", "&|", "|&", ";;", ";&", ";;&",
606
+ }
607
+ # Ordinary output, noclobber override, and combined stdout/stderr output.
608
+ # shlex separates fd prefixes (e.g. 10>>) from the operator automatically.
609
+ REDIRECT_OUT = {">", ">>", ">|", "&>", "&>>", ">&"}
610
+ REDIRECT_IN = "<"
611
+ SYNTAX_OPERATORS = STATEMENT_SEPARATORS | REDIRECT_OUT | {REDIRECT_IN}
612
+ # shlex groups adjacent punctuation even across distinct shell operators.
613
+ # Retain other shell operators intact so a here-string is not three `<` reads.
614
+ PUNCTUATION = re.compile(r"^[();<>|&]+$")
615
+ SHELL_OPERATOR = re.compile("|".join(
616
+ re.escape(operator) for operator in sorted(
617
+ SYNTAX_OPERATORS | {"<<<", "<<", "<&", "<>", ";;&", ";;", ";&", "|&"},
618
+ key=lambda operator: (-len(operator), operator),
619
+ )
620
+ ))
621
+
622
+
623
+ class LiteralOperator(str):
624
+ """Quoted or escaped operator text is an argument, never shell syntax."""
625
+
626
+
627
+ SHELL_PROGRAMS = {"bash", "dash", "ksh", "sh", "zsh"}
628
+ SOURCE_BUILTINS = {"source", "."}
629
+
630
+ # Wrappers that run what FOLLOWS them without changing what it is, mapped to
631
+ # (options whose value is a SEPARATE token, positional operands consumed).
632
+ # The positional count is why this is a table rather than a set: `timeout 5
633
+ # bash x` puts an operand between the wrapper and the interpreter, so a walk
634
+ # that steps over `-flags` only stops at `5` and never reaches `bash`.
635
+ FOLLOW_WRAPPERS = {
636
+ "builtin": (frozenset(), 0),
637
+ "command": (frozenset(), 0),
638
+ # `env bash edit.sh` runs `bash edit.sh`. Its absence here was the one
639
+ # wrapper on this list a caller reaches for without thinking about
640
+ # wrappers at all, because `env VAR=value <cmd>` is how a one-off
641
+ # environment override is spelled. Those `VAR=value` operands need no
642
+ # positional count: the walk below re-enters its assignment skip on the
643
+ # next iteration and steps over as many as are present.
644
+ "env": (
645
+ frozenset({"-C", "--chdir", "-P", "-u", "--unset"}),
646
+ 0,
647
+ ),
648
+ "exec": (frozenset({"-a"}), 0),
649
+ "nice": (frozenset({"-n", "--adjustment"}), 0),
650
+ "nohup": (frozenset(), 0),
651
+ "setsid": (frozenset(), 0),
652
+ "stdbuf": (frozenset({"-i", "-o", "-e"}), 0),
653
+ "sudo": (
654
+ frozenset(
655
+ {
656
+ "-C", "--close-from", "-g", "--group", "-h", "--host",
657
+ "-p", "--prompt", "-r", "--role", "-t", "--type",
658
+ "-U", "--other-user", "-u", "--user",
659
+ }
660
+ ),
661
+ 0,
662
+ ),
663
+ "time": (frozenset(), 0),
664
+ "timeout": (frozenset({"-k", "--kill-after", "-s", "--signal"}), 1),
665
+ }
666
+
667
+ # `-i`, `-i.bak`, a cluster such as `-ni`, and the long `--in-place[=SUFFIX]`.
668
+ IN_PLACE = re.compile(r"^(--in-place(=.*)?|-[a-zA-Z]*i.*)$")
669
+ # A value the SHELL computes; this hook runs before expansion and cannot know
670
+ # which file it will name.
671
+ COMPUTED_VALUE = re.compile(r"[$`]")
672
+
673
+
674
+ def normalise_lines(text):
675
+ """Spell line breaks as statement separators.
676
+
677
+ A newline ends a command exactly as `;` does, but shlex treats it as plain
678
+ whitespace — so two consecutive lines of a followed script would read as
679
+ one invocation and only the first program would be classified. A
680
+ backslash-newline is joined first, because there the newline is NOT a
681
+ boundary.
682
+
683
+ Args:
684
+ text: A command line or a script's contents.
685
+
686
+ Returns:
687
+ The same text with line breaks spelled as separators.
688
+ """
689
+ output = []
690
+ quote = ""
691
+ position = 0
692
+ while position < len(text):
693
+ character = text[position]
694
+ if character == BACKSLASH and quote != "'" and position + 1 < len(text):
695
+ following = text[position + 1]
696
+ # The shell deletes continuations; inserting whitespace can split
697
+ # an operator or pathname and hide the actual output target.
698
+ if following != NEWLINE:
699
+ output.extend((character, following))
700
+ position += 2
701
+ continue
702
+ if quote:
703
+ if character == quote:
704
+ quote = ""
705
+ elif character in "'\"":
706
+ quote = character
707
+ if character == NEWLINE and not quote:
708
+ output.append(" ; ")
709
+ else:
710
+ output.append(character)
711
+ position += 1
712
+ return "".join(output)
713
+
714
+
715
+ def tokenize(text):
716
+ """Tokenize with shell operators kept as their own tokens.
717
+
718
+ Args:
719
+ text: A command line or a script's contents.
720
+
721
+ Returns:
722
+ The token list, or None when the text does not lex.
723
+ """
724
+ normalized = normalise_lines(text)
725
+ lexer = shlex.shlex(normalized, posix=True, punctuation_chars=True)
726
+ lexer.whitespace_split = True
727
+ # `#` is not a comment introducer on a typed command line, and letting shlex
728
+ # treat it as one silently truncates the rest of the line.
729
+ lexer.commenters = ""
730
+ try:
731
+ tokens = []
732
+ start = 0
733
+ for token in lexer:
734
+ # shlex strips quotes/escapes and reads one character ahead when
735
+ # emitting punctuation. Exclude its character pushback from the
736
+ # consumed source span so a quoted operator retains its provenance.
737
+ end = lexer.instream.tell() - len(lexer._pushback_chars)
738
+ raw = normalized[start:end].strip()
739
+ start = end
740
+ if PUNCTUATION.fullmatch(token):
741
+ if raw != token:
742
+ tokens.append(LiteralOperator(token))
743
+ else:
744
+ tokens.extend(SHELL_OPERATOR.findall(token))
745
+ else:
746
+ tokens.append(token)
747
+ return tokens
748
+ except ValueError:
749
+ return None
750
+
751
+
752
+ def strip_comments(text):
753
+ """Drop `#` comments from a FOLLOWED SCRIPT, quote-aware.
754
+
755
+ Applied to file contents and never to a typed command. A comment cannot
756
+ execute, and Lisa's own managed templates discuss redirection and `sed -i`
757
+ against managed paths in their headers — classifying a followed file
758
+ without dropping its comments reads documentation as an edit.
759
+
760
+ Args:
761
+ text: A script's contents.
762
+
763
+ Returns:
764
+ The same text with unquoted comments removed.
765
+ """
766
+ output = []
767
+ for line in text.split(NEWLINE):
768
+ quote = ""
769
+ escaped = False
770
+ cut = None
771
+ for position, character in enumerate(line):
772
+ if escaped:
773
+ escaped = False
774
+ continue
775
+ if character == BACKSLASH and quote != "'":
776
+ escaped = True
777
+ continue
778
+ if quote:
779
+ if character == quote:
780
+ quote = ""
781
+ continue
782
+ if character in "'\"":
783
+ quote = character
784
+ continue
785
+ # A `#` opens a comment only at the start of a word, so `x#y` and
786
+ # `${x#y}` keep their hashes.
787
+ if character == "#" and (position == 0 or line[position - 1].isspace()):
788
+ cut = position
789
+ break
790
+ output.append(line if cut is None else line[:cut])
791
+ return NEWLINE.join(output)
792
+
793
+
794
+ def statements(tokens):
795
+ """Split a token list at statement separators, keeping redirects inline.
796
+
797
+ Redirect operators are deliberately NOT separators here: `>` and its target
798
+ have to stay in the same group, because the pair is the write signature.
799
+
800
+ Args:
801
+ tokens: The operator-aware token list.
802
+
803
+ Returns:
804
+ A list of statements.
805
+ """
806
+ grouped = []
807
+ current = []
808
+ for token in tokens:
809
+ if not isinstance(token, LiteralOperator) and token in STATEMENT_SEPARATORS:
810
+ grouped.append(current)
811
+ current = []
812
+ continue
813
+ current.append(token)
814
+ grouped.append(current)
815
+ return grouped
816
+
817
+
818
+ class UnresolvedEnvSplit(ValueError):
819
+ """Split-string syntax whose executed arguments cannot be proven here."""
820
+
821
+
822
+ def parse_env_split(split_string):
823
+ """Parse only the env -S subset shared with ordinary quoted arguments.
824
+
825
+ GNU env has its own escapes, comments and environment interpolation. Do
826
+ not pretend shlex implements those, or invent environment values in a
827
+ pre-execution guard. The operator can spell the resulting command directly.
828
+
829
+ Args:
830
+ split_string: The literal argument supplied to env's split option.
831
+
832
+ Returns:
833
+ Arguments for the supported subset; otherwise raises UnresolvedEnvSplit.
834
+ """
835
+ if any(marker in split_string for marker in (BACKSLASH, "#", "$", chr(96), chr(11), chr(12))):
836
+ raise UnresolvedEnvSplit("escapes, comments, shell substitution, variable expansion or control whitespace")
837
+ try:
838
+ return shlex.split(split_string, comments=False, posix=True)
839
+ except ValueError as error:
840
+ raise UnresolvedEnvSplit("unbalanced quoting") from error
841
+
842
+
843
+ def command_word(statement):
844
+ """The program a statement runs, and the tokens after it.
845
+
846
+ Steps over leading variable assignments and over wrappers that do not
847
+ change what runs. Reading a wrapper as the command is how a payload hides
848
+ from a guard that inspects only a statement's first word.
849
+
850
+ Args:
851
+ statement: One statement's tokens.
852
+
853
+ Returns:
854
+ A triple (token, program, args); (None, None, []) when no program is
855
+ named. The raw token is retained because `./edit.sh` has no interpreter:
856
+ its command word is itself the executed script.
857
+ """
858
+ index = 0
859
+ split_expansions = 0
860
+ while index < len(statement):
861
+ token = statement[index]
862
+ if "=" in token and not token.startswith(("=", "-")):
863
+ index += 1
864
+ continue
865
+ program = token.rsplit("/", 1)[-1]
866
+ if program not in FOLLOW_WRAPPERS:
867
+ return (token, program, statement[index + 1 :])
868
+ separate, positional = FOLLOW_WRAPPERS[program]
869
+ index += 1
870
+ while index < len(statement) and statement[index].startswith("-"):
871
+ option = statement[index]
872
+ if option == "--":
873
+ index += 1
874
+ break
875
+ # env -S inserts the split string back into env's argument list;
876
+ # it is executable input, not an option value to discard. Keep
877
+ # shell -c's quoted operand intact while expanding the env layer.
878
+ # The known no-operand flags can be combined before S (-vS/-ivS).
879
+ # Stop at S: the rest belongs to its argument, not more flags.
880
+ short_split = re.match(r"^-[iv0]*S(.*)$", option)
881
+ if program == "env" and (
882
+ option == "--split-string"
883
+ or option.startswith("--split-string=")
884
+ or short_split is not None
885
+ ):
886
+ consumed = 1
887
+ if option == "--split-string" or (
888
+ short_split is not None and not short_split.group(1)
889
+ ):
890
+ if index + 1 >= len(statement):
891
+ raise UnresolvedEnvSplit("missing split-string operand")
892
+ split_string = statement[index + 1]
893
+ consumed = 2
894
+ elif option.startswith("--split-string="):
895
+ split_string = option.split("=", 1)[1]
896
+ else:
897
+ split_string = short_split.group(1)
898
+ if split_expansions >= 64:
899
+ raise UnresolvedEnvSplit("nested split-string limit")
900
+ expanded = parse_env_split(split_string)
901
+ statement = [token] + expanded + statement[index + consumed :]
902
+ split_expansions += 1
903
+ index = 0
904
+ break
905
+ index += 2 if option in separate else 1
906
+ index += positional
907
+ return (None, None, [])
908
+
909
+
910
+ def shell_script_operand(args):
911
+ """The file a shell invocation runs, or None when it runs no script file.
912
+
913
+ Args:
914
+ args: The tokens following the shell's own name.
915
+
916
+ Returns:
917
+ The operand token, or None for an interactive shell or a `-c` string.
918
+ """
919
+ for token in args:
920
+ if token == "--":
921
+ continue
922
+ if token.startswith(("-", "+")):
923
+ # A single-dash cluster containing `c` carries a command string,
924
+ # not a script file.
925
+ if not token.startswith("--") and "c" in token[1:]:
926
+ return None
927
+ # `-n` is noexec: the shell READS and parses the file, then exits
928
+ # without executing a line of it. `bash -n <file>` is the one shape
929
+ # that puts a path at a command position while provably running
930
+ # nothing — the exact seam between reading and running, and this
931
+ # walk got it wrong (CodySwannGT/lisa#3781). Here that meant a
932
+ # syntax check of any script mentioning a managed path was refused
933
+ # as though it were about to write one.
934
+ #
935
+ # `bash <file>` still executes and is still refused. Noexec is the
936
+ # distinction, not the program.
937
+ if token == "--noexec" or (
938
+ not token.startswith("--") and "n" in token[1:]
939
+ ):
940
+ return None
941
+ continue
942
+ return token
943
+ return None
944
+
945
+
946
+ def shell_command_string(statement):
947
+ """The inline command a shell executes with `-c`, or None.
948
+
949
+ Args:
950
+ statement: One statement's tokens.
951
+
952
+ Returns:
953
+ The command string operand, or None when this is not a shell `-c` call.
954
+ """
955
+ _token, program, args = command_word(statement)
956
+ if program not in SHELL_PROGRAMS:
957
+ return None
958
+ for index, token in enumerate(args):
959
+ if token == "--":
960
+ return None
961
+ if token.startswith("-") and not token.startswith("--") and "c" in token[1:]:
962
+ command_index = index + 1
963
+ if command_index < len(args) and args[command_index] == "--":
964
+ command_index += 1
965
+ return args[command_index] if command_index < len(args) else None
966
+ return None
967
+
968
+
969
+ def write_targets(statement):
970
+ """Paths this statement WRITES.
971
+
972
+ Reads never fire. A path has to be the target of an output redirection, or
973
+ an operand of `tee` or of an in-place `sed`. That is the whole distinction
974
+ this guard turns on: `grep -n x <managed>` names the same path and stays
975
+ allowed, and following a merely-named path is the known-wrong fix that
976
+ refuses ordinary reads elsewhere in this family.
977
+
978
+ Extraction is deliberately GENEROUS for `tee` and `sed`: every non-flag
979
+ operand is offered. It costs nothing, because the caller classifies each
980
+ candidate by resolving it against the installed package, and a `sed` script
981
+ expression such as `s/a/b/` resolves to no template. Being narrow here is
982
+ precisely what left the old `sed -i` arm dead in every spelling.
983
+
984
+ Args:
985
+ statement: One statement's tokens.
986
+
987
+ Returns:
988
+ Candidate paths this statement writes.
989
+ """
990
+ found = []
991
+ _token, program, args = command_word(statement)
992
+ for index, token in enumerate(statement):
993
+ if not isinstance(token, LiteralOperator) and token in REDIRECT_OUT and index + 1 < len(statement):
994
+ target = statement[index + 1]
995
+ # >&digit duplicates an fd, >&digit- moves it, and >&- closes it.
996
+ # Only the nonnumeric >&word form opens a pathname; &>1 still
997
+ # writes a file named 1 and must remain a write candidate.
998
+ if token == ">&" and re.fullmatch(r"(?:[0-9]+-?|-)", target):
999
+ continue
1000
+ found.append(target)
1001
+ if program == "tee":
1002
+ found.extend(token for token in args if not token.startswith("-"))
1003
+ elif program == "sed" and any(IN_PLACE.match(token) for token in args):
1004
+ found.extend(token for token in args if not token.startswith("-"))
1005
+ return found
1006
+
1007
+
1008
+ def executed_script(statement):
1009
+ """The path this statement EXECUTES, or None.
1010
+
1011
+ Only a COMMAND POSITION can execute something. A path anywhere else is an
1012
+ argument, and an argument is data.
1013
+
1014
+ Args:
1015
+ statement: One statement's tokens.
1016
+
1017
+ Returns:
1018
+ The operand token naming a script that will run, or None.
1019
+ """
1020
+ token, program, args = command_word(statement)
1021
+ if program is None:
1022
+ return None
1023
+ if program in SHELL_PROGRAMS:
1024
+ for index, token in enumerate(statement):
1025
+ # `bash < script.sh` runs that file as surely as `bash script.sh`.
1026
+ if not isinstance(token, LiteralOperator) and token == REDIRECT_IN and index + 1 < len(statement):
1027
+ return statement[index + 1]
1028
+ return shell_script_operand(args)
1029
+ if program in SOURCE_BUILTINS:
1030
+ return args[0] if args else None
1031
+ # A script in command position executes through its shebang. This also
1032
+ # covers a direct path after wrappers such as `sudo ./edit.sh`; `command_word`
1033
+ # deliberately keeps the raw token while using its basename for wrapper and
1034
+ # shell classification.
1035
+ if resolve(token) is not None:
1036
+ return token
1037
+ return None
1038
+
1039
+
1040
+ def resolve(token):
1041
+ """An existing readable script a token names, or None.
1042
+
1043
+ A computed target (`bash "$SCRIPT"`) is NOT followed and NOT refused. This
1044
+ guard's harm is a template that silently forks — recoverable, and reported
1045
+ by `lisa doctor` on every run — so failing closed on every `bash "$SCRIPT"`
1046
+ in every host project would cost far more than it buys. Its sibling
1047
+ `block-no-verify` DOES fail closed on the identical shape, because an
1048
+ unverified commit is not recoverable. The divergence is deliberate, and it
1049
+ is recorded here so the next reader does not read it as an oversight.
1050
+
1051
+ Args:
1052
+ token: The operand naming a script.
1053
+
1054
+ Returns:
1055
+ A path, or None.
1056
+ """
1057
+ if COMPUTED_VALUE.search(token):
1058
+ return None
1059
+ text = token.strip().strip("'\"")
1060
+ if not text or text == "-":
1061
+ return None
1062
+ if os.path.isabs(text):
1063
+ candidates = [text]
1064
+ else:
1065
+ candidates = [os.path.join(project, text), os.path.join(os.getcwd(), text)]
1066
+ for candidate in candidates:
1067
+ try:
1068
+ if not os.path.isfile(candidate):
1069
+ continue
1070
+ if os.path.getsize(candidate) > FOLLOW_MAX_BYTES:
1071
+ continue
1072
+ except OSError:
1073
+ continue
1074
+ return candidate
1075
+ return None
1076
+
1077
+
1078
+ def collect(text, depth, seen, out):
1079
+ """Accumulate every write target in this text and in the scripts it runs.
1080
+
1081
+ Args:
1082
+ text: A command line, or a followed script's contents.
1083
+ depth: Number of scripts already followed.
1084
+ seen: Real paths already inspected, so a cycle terminates.
1085
+ out: Accumulator for candidate paths.
1086
+
1087
+ Returns:
1088
+ Nothing; `out` is extended in place.
1089
+ """
1090
+ tokens = tokenize(text)
1091
+ if tokens is None:
1092
+ return
1093
+ for statement in statements(tokens):
1094
+ if not statement:
1095
+ continue
1096
+ out.extend(write_targets(statement))
1097
+ nested = shell_command_string(statement)
1098
+ if nested is not None and depth < FOLLOW_MAX_DEPTH:
1099
+ collect(nested, depth + 1, seen, out)
1100
+ operand = executed_script(statement)
1101
+ if operand is None:
1102
+ continue
1103
+ if depth >= FOLLOW_MAX_DEPTH or len(seen) >= FOLLOW_MAX_FILES:
1104
+ continue
1105
+ path = resolve(operand)
1106
+ if path is None:
1107
+ continue
1108
+ try:
1109
+ key = os.path.realpath(path)
1110
+ except OSError:
1111
+ key = path
1112
+ if key in seen:
1113
+ continue
1114
+ seen.add(key)
1115
+ try:
1116
+ with open(path, encoding="utf-8", errors="replace") as handle:
1117
+ body = handle.read(FOLLOW_MAX_BYTES)
1118
+ except OSError:
1119
+ continue
1120
+ collect(strip_comments(body), depth + 1, seen, out)
1121
+
1122
+
1123
+ targets = []
1124
+ try:
1125
+ collect(command, 0, set(), targets)
1126
+ except UnresolvedEnvSplit as error:
1127
+ sys.stderr.write(str(error) + NEWLINE)
1128
+ sys.exit(ENV_SPLIT_UNRESOLVED)
1129
+ for target in targets:
1130
+ cleaned = target.strip().strip("'\"")
1131
+ if cleaned:
1132
+ print(cleaned)
1133
+ PY
1134
+ analyzer_stderr="$(mktemp "${TMPDIR:-/tmp}/lisa-managed-edit-analyzer.XXXXXX")" || {
1135
+ printf 'block-managed-file-edits: could not allocate analyzer stderr capture; Bash write protection is NOT active\n' >&2
1136
+ exit 0
1137
+ }
1138
+ if write_targets="$(printf '%s' "$analyzer" |
1139
+ MANAGED_EDIT_COMMAND="$command_str" \
1140
+ MANAGED_EDIT_PROJECT="$project_root" \
1141
+ python3 - 2>"$analyzer_stderr")"; then
1142
+ analyzer_status=0
1143
+ else
1144
+ analyzer_status=$?
1145
+ fi
1146
+ if [ "$analyzer_status" -eq 42 ]; then
1147
+ printf 'Blocked: cannot resolve env --split-string for managed-file protection.\n' >&2
1148
+ printf 'Use an explicit command without split-string escapes, comments or variable expansion.\n' >&2
1149
+ while IFS= read -r analyzer_line; do
1150
+ [ -n "$analyzer_line" ] && printf ' %s\n' "$analyzer_line" >&2
1151
+ done <"$analyzer_stderr"
1152
+ rm -f "$analyzer_stderr"
1153
+ exit 2
1154
+ fi
1155
+ if [ "$analyzer_status" -ne 0 ]; then
1156
+ printf 'block-managed-file-edits: Bash analyzer failed (exit %s); Bash write protection is NOT active\n' "$analyzer_status" >&2
1157
+ while IFS= read -r analyzer_line; do
1158
+ [ -n "$analyzer_line" ] && printf ' python3: %s\n' "$analyzer_line" >&2
1159
+ done <"$analyzer_stderr"
1160
+ rm -f "$analyzer_stderr"
1161
+ exit 0
1162
+ fi
1163
+ rm -f "$analyzer_stderr"
1164
+ while IFS= read -r token; do
1165
+ [ -n "$token" ] || continue
1166
+ if source_path="$(managed_source "$token")"; then
1167
+ refuse "$token" "$source_path" "$(relative_path "$token")"
1168
+ fi
1169
+ done <<EOF
1170
+ $write_targets
1171
+ EOF
1172
+ ;;
1173
+ esac
1174
+
1175
+ exit 0