@codyswann/lisa 4.22.8 → 4.22.10

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 (278) hide show
  1. package/all/copy-overwrite/scripts/lib/process-tree-runner.mjs +127 -0
  2. package/all/copy-overwrite/scripts/lisa-floor-collisions.mjs +63 -8
  3. package/all/copy-overwrite/scripts/lisa-hooks/parity-safety-net.sh +36 -6
  4. package/all/copy-overwrite/scripts/lisa-postinstall.mjs +35 -13
  5. package/all/copy-overwrite/scripts/lisa-reconcile-policy.mjs +11 -3
  6. package/all/copy-overwrite/scripts/lisa-run-gates.mjs +41 -8
  7. package/all/copy-overwrite/scripts/lisa-schema-validate.mjs +2 -2
  8. package/all/copy-overwrite/scripts/lisa-work-item.mjs +2 -1
  9. package/cdk/package-lisa/package.lisa.json +1 -1
  10. package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
  11. package/dist/core/lisa-owned-hash-ledger.js +24 -0
  12. package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
  13. package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
  14. package/dist/core/nightly-e2e-guard-behavior-certificate.js.map +1 -1
  15. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  16. package/dist/core/upstream-evidence-manifest.js +61 -51
  17. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  18. package/dist/opencode/plugin-templates/parity-safety-net.sh +36 -6
  19. package/nestjs/package-lisa/package.lisa.json +1 -1
  20. package/package.json +3 -3
  21. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  22. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  23. package/plugins/lisa/.codex-plugin/skills/lisa-atlassian-access/SKILL.md +10 -13
  24. package/plugins/lisa/.codex-plugin/skills/lisa-doctor/SKILL.md +4 -2
  25. package/plugins/lisa/.codex-plugin/skills/lisa-drive-pr-to-merge/SKILL.md +29 -4
  26. package/plugins/lisa/.codex-plugin/skills/lisa-github-sync/SKILL.md +8 -3
  27. package/plugins/lisa/.codex-plugin/skills/lisa-jam-access/SKILL.md +7 -10
  28. package/plugins/lisa/.codex-plugin/skills/lisa-jira-journey/SKILL.md +5 -0
  29. package/plugins/lisa/.codex-plugin/skills/lisa-jira-journey/scripts/parse-plan.py +36 -2
  30. package/plugins/lisa/.codex-plugin/skills/lisa-jira-sync/SKILL.md +1 -1
  31. package/plugins/lisa/.codex-plugin/skills/lisa-linear-access/SKILL.md +8 -12
  32. package/plugins/lisa/.codex-plugin/skills/lisa-linear-sync/SKILL.md +1 -1
  33. package/plugins/lisa/.codex-plugin/skills/lisa-nightly-lower-code-complexity/SKILL.md +7 -1
  34. package/plugins/lisa/.codex-plugin/skills/lisa-notion-access/SKILL.md +7 -10
  35. package/plugins/lisa/.codex-plugin/skills/lisa-posthog-access/SKILL.md +7 -10
  36. package/plugins/lisa/.codex-plugin/skills/lisa-repair-intake/SKILL.md +19 -3
  37. package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +10 -6
  38. package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/scripts/publish-aws-bootstrap.mjs +95 -44
  39. package/plugins/lisa/.codex-plugin/skills/lisa-sentry-access/SKILL.md +7 -10
  40. package/plugins/lisa/.codex-plugin/skills/lisa-setup-atlassian/SKILL.md +7 -10
  41. package/plugins/lisa/.codex-plugin/skills/lisa-setup-linear/SKILL.md +9 -12
  42. package/plugins/lisa/.codex-plugin/skills/lisa-setup-notion/SKILL.md +7 -10
  43. package/plugins/lisa/.codex-plugin/skills/lisa-setup-remote-aws/SKILL.md +7 -2
  44. package/plugins/lisa/.codex-plugin/skills/lisa-setup-remote-env/SKILL.md +6 -1
  45. package/plugins/lisa/.codex-plugin/skills/lisa-setup-remote-env/assets/session-start.sh +19 -0
  46. package/plugins/lisa/.codex-plugin/skills/lisa-setup-remote-env/assets/setup.sh +1 -0
  47. package/plugins/lisa/.codex-plugin/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +25 -4
  48. package/plugins/lisa/.codex-plugin/skills/lisa-setup-workstation/scripts/bounded-child.mjs +9 -0
  49. package/plugins/lisa/.codex-plugin/skills/lisa-setup-workstation/scripts/workstation.mjs +29 -21
  50. package/plugins/lisa/.codex-plugin/skills/lisa-sonarcloud-access/SKILL.md +7 -10
  51. package/plugins/lisa/.codex-plugin/skills/lisa-tracker-sync/SKILL.md +1 -1
  52. package/plugins/lisa/hooks/parity-safety-net.sh +36 -6
  53. package/plugins/lisa/hooks/threshold-ratchet-families.mjs +31 -7
  54. package/plugins/lisa/rules/reference/base-rules.md +1 -1
  55. package/plugins/lisa/rules/reference/config-resolution.md +5 -14
  56. package/plugins/lisa/scripts/install-remote-agent-aws.mjs +5 -1
  57. package/plugins/lisa/scripts/rollup-blocker-classification.mjs +18 -3
  58. package/plugins/lisa/skills/lisa-atlassian-access/SKILL.md +10 -13
  59. package/plugins/lisa/skills/lisa-doctor/SKILL.md +4 -2
  60. package/plugins/lisa/skills/lisa-drive-pr-to-merge/SKILL.md +29 -4
  61. package/plugins/lisa/skills/lisa-github-sync/SKILL.md +8 -3
  62. package/plugins/lisa/skills/lisa-jam-access/SKILL.md +7 -10
  63. package/plugins/lisa/skills/lisa-jira-journey/SKILL.md +5 -0
  64. package/plugins/lisa/skills/lisa-jira-journey/scripts/parse-plan.py +36 -2
  65. package/plugins/lisa/skills/lisa-jira-sync/SKILL.md +1 -1
  66. package/plugins/lisa/skills/lisa-linear-access/SKILL.md +8 -12
  67. package/plugins/lisa/skills/lisa-linear-sync/SKILL.md +1 -1
  68. package/plugins/lisa/skills/lisa-nightly-lower-code-complexity/SKILL.md +7 -1
  69. package/plugins/lisa/skills/lisa-notion-access/SKILL.md +7 -10
  70. package/plugins/lisa/skills/lisa-posthog-access/SKILL.md +7 -10
  71. package/plugins/lisa/skills/lisa-repair-intake/SKILL.md +19 -3
  72. package/plugins/lisa/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +10 -6
  73. package/plugins/lisa/skills/lisa-secrets-access/scripts/publish-aws-bootstrap.mjs +95 -44
  74. package/plugins/lisa/skills/lisa-sentry-access/SKILL.md +7 -10
  75. package/plugins/lisa/skills/lisa-setup-atlassian/SKILL.md +7 -10
  76. package/plugins/lisa/skills/lisa-setup-linear/SKILL.md +9 -12
  77. package/plugins/lisa/skills/lisa-setup-notion/SKILL.md +7 -10
  78. package/plugins/lisa/skills/lisa-setup-remote-aws/SKILL.md +7 -2
  79. package/plugins/lisa/skills/lisa-setup-remote-env/SKILL.md +6 -1
  80. package/plugins/lisa/skills/lisa-setup-remote-env/assets/session-start.sh +19 -0
  81. package/plugins/lisa/skills/lisa-setup-remote-env/assets/setup.sh +1 -0
  82. package/plugins/lisa/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +25 -4
  83. package/plugins/lisa/skills/lisa-setup-workstation/scripts/bounded-child.mjs +9 -0
  84. package/plugins/lisa/skills/lisa-setup-workstation/scripts/workstation.mjs +29 -21
  85. package/plugins/lisa/skills/lisa-sonarcloud-access/SKILL.md +7 -10
  86. package/plugins/lisa/skills/lisa-tracker-sync/SKILL.md +1 -1
  87. package/plugins/lisa-agy/hooks/parity-safety-net.sh +36 -6
  88. package/plugins/lisa-agy/plugin.json +1 -1
  89. package/plugins/lisa-agy/scripts/install-remote-agent-aws.mjs +5 -1
  90. package/plugins/lisa-agy/scripts/rollup-blocker-classification.mjs +18 -3
  91. package/plugins/lisa-agy/skills/lisa-atlassian-access/SKILL.md +10 -13
  92. package/plugins/lisa-agy/skills/lisa-doctor/SKILL.md +4 -2
  93. package/plugins/lisa-agy/skills/lisa-drive-pr-to-merge/SKILL.md +29 -4
  94. package/plugins/lisa-agy/skills/lisa-github-sync/SKILL.md +8 -3
  95. package/plugins/lisa-agy/skills/lisa-jam-access/SKILL.md +7 -10
  96. package/plugins/lisa-agy/skills/lisa-jira-journey/SKILL.md +5 -0
  97. package/plugins/lisa-agy/skills/lisa-jira-journey/scripts/parse-plan.py +36 -2
  98. package/plugins/lisa-agy/skills/lisa-jira-sync/SKILL.md +1 -1
  99. package/plugins/lisa-agy/skills/lisa-linear-access/SKILL.md +8 -12
  100. package/plugins/lisa-agy/skills/lisa-linear-sync/SKILL.md +1 -1
  101. package/plugins/lisa-agy/skills/lisa-nightly-lower-code-complexity/SKILL.md +7 -1
  102. package/plugins/lisa-agy/skills/lisa-notion-access/SKILL.md +7 -10
  103. package/plugins/lisa-agy/skills/lisa-posthog-access/SKILL.md +7 -10
  104. package/plugins/lisa-agy/skills/lisa-repair-intake/SKILL.md +19 -3
  105. package/plugins/lisa-agy/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +10 -6
  106. package/plugins/lisa-agy/skills/lisa-secrets-access/scripts/publish-aws-bootstrap.mjs +95 -44
  107. package/plugins/lisa-agy/skills/lisa-sentry-access/SKILL.md +7 -10
  108. package/plugins/lisa-agy/skills/lisa-setup-atlassian/SKILL.md +7 -10
  109. package/plugins/lisa-agy/skills/lisa-setup-linear/SKILL.md +9 -12
  110. package/plugins/lisa-agy/skills/lisa-setup-notion/SKILL.md +7 -10
  111. package/plugins/lisa-agy/skills/lisa-setup-remote-aws/SKILL.md +7 -2
  112. package/plugins/lisa-agy/skills/lisa-setup-remote-env/SKILL.md +6 -1
  113. package/plugins/lisa-agy/skills/lisa-setup-remote-env/assets/session-start.sh +19 -0
  114. package/plugins/lisa-agy/skills/lisa-setup-remote-env/assets/setup.sh +1 -0
  115. package/plugins/lisa-agy/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +25 -4
  116. package/plugins/lisa-agy/skills/lisa-setup-workstation/scripts/bounded-child.mjs +9 -0
  117. package/plugins/lisa-agy/skills/lisa-setup-workstation/scripts/workstation.mjs +29 -21
  118. package/plugins/lisa-agy/skills/lisa-sonarcloud-access/SKILL.md +7 -10
  119. package/plugins/lisa-agy/skills/lisa-tracker-sync/SKILL.md +1 -1
  120. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  121. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  122. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  123. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  124. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  125. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  126. package/plugins/lisa-copilot/hooks/parity-safety-net.sh +36 -6
  127. package/plugins/lisa-copilot/hooks/threshold-ratchet-families.mjs +31 -7
  128. package/plugins/lisa-copilot/rules/reference/base-rules.md +1 -1
  129. package/plugins/lisa-copilot/rules/reference/config-resolution.md +5 -14
  130. package/plugins/lisa-copilot/scripts/install-remote-agent-aws.mjs +5 -1
  131. package/plugins/lisa-copilot/scripts/rollup-blocker-classification.mjs +18 -3
  132. package/plugins/lisa-copilot/skills/lisa-atlassian-access/SKILL.md +10 -13
  133. package/plugins/lisa-copilot/skills/lisa-doctor/SKILL.md +4 -2
  134. package/plugins/lisa-copilot/skills/lisa-drive-pr-to-merge/SKILL.md +29 -4
  135. package/plugins/lisa-copilot/skills/lisa-github-sync/SKILL.md +8 -3
  136. package/plugins/lisa-copilot/skills/lisa-jam-access/SKILL.md +7 -10
  137. package/plugins/lisa-copilot/skills/lisa-jira-journey/SKILL.md +5 -0
  138. package/plugins/lisa-copilot/skills/lisa-jira-journey/scripts/parse-plan.py +36 -2
  139. package/plugins/lisa-copilot/skills/lisa-jira-sync/SKILL.md +1 -1
  140. package/plugins/lisa-copilot/skills/lisa-linear-access/SKILL.md +8 -12
  141. package/plugins/lisa-copilot/skills/lisa-linear-sync/SKILL.md +1 -1
  142. package/plugins/lisa-copilot/skills/lisa-nightly-lower-code-complexity/SKILL.md +7 -1
  143. package/plugins/lisa-copilot/skills/lisa-notion-access/SKILL.md +7 -10
  144. package/plugins/lisa-copilot/skills/lisa-posthog-access/SKILL.md +7 -10
  145. package/plugins/lisa-copilot/skills/lisa-repair-intake/SKILL.md +19 -3
  146. package/plugins/lisa-copilot/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +10 -6
  147. package/plugins/lisa-copilot/skills/lisa-secrets-access/scripts/publish-aws-bootstrap.mjs +95 -44
  148. package/plugins/lisa-copilot/skills/lisa-sentry-access/SKILL.md +7 -10
  149. package/plugins/lisa-copilot/skills/lisa-setup-atlassian/SKILL.md +7 -10
  150. package/plugins/lisa-copilot/skills/lisa-setup-linear/SKILL.md +9 -12
  151. package/plugins/lisa-copilot/skills/lisa-setup-notion/SKILL.md +7 -10
  152. package/plugins/lisa-copilot/skills/lisa-setup-remote-aws/SKILL.md +7 -2
  153. package/plugins/lisa-copilot/skills/lisa-setup-remote-env/SKILL.md +6 -1
  154. package/plugins/lisa-copilot/skills/lisa-setup-remote-env/assets/session-start.sh +19 -0
  155. package/plugins/lisa-copilot/skills/lisa-setup-remote-env/assets/setup.sh +1 -0
  156. package/plugins/lisa-copilot/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +25 -4
  157. package/plugins/lisa-copilot/skills/lisa-setup-workstation/scripts/bounded-child.mjs +9 -0
  158. package/plugins/lisa-copilot/skills/lisa-setup-workstation/scripts/workstation.mjs +29 -21
  159. package/plugins/lisa-copilot/skills/lisa-sonarcloud-access/SKILL.md +7 -10
  160. package/plugins/lisa-copilot/skills/lisa-tracker-sync/SKILL.md +1 -1
  161. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  162. package/plugins/lisa-cursor/hooks/parity-safety-net.sh +36 -6
  163. package/plugins/lisa-cursor/hooks/threshold-ratchet-families.mjs +31 -7
  164. package/plugins/lisa-cursor/rules/base-rules-reference.mdc +1 -1
  165. package/plugins/lisa-cursor/rules/config-resolution-reference.mdc +5 -14
  166. package/plugins/lisa-cursor/scripts/install-remote-agent-aws.mjs +5 -1
  167. package/plugins/lisa-cursor/scripts/rollup-blocker-classification.mjs +18 -3
  168. package/plugins/lisa-cursor/skills/lisa-atlassian-access/SKILL.md +10 -13
  169. package/plugins/lisa-cursor/skills/lisa-doctor/SKILL.md +4 -2
  170. package/plugins/lisa-cursor/skills/lisa-drive-pr-to-merge/SKILL.md +29 -4
  171. package/plugins/lisa-cursor/skills/lisa-github-sync/SKILL.md +8 -3
  172. package/plugins/lisa-cursor/skills/lisa-jam-access/SKILL.md +7 -10
  173. package/plugins/lisa-cursor/skills/lisa-jira-journey/SKILL.md +5 -0
  174. package/plugins/lisa-cursor/skills/lisa-jira-journey/scripts/parse-plan.py +36 -2
  175. package/plugins/lisa-cursor/skills/lisa-jira-sync/SKILL.md +1 -1
  176. package/plugins/lisa-cursor/skills/lisa-linear-access/SKILL.md +8 -12
  177. package/plugins/lisa-cursor/skills/lisa-linear-sync/SKILL.md +1 -1
  178. package/plugins/lisa-cursor/skills/lisa-nightly-lower-code-complexity/SKILL.md +7 -1
  179. package/plugins/lisa-cursor/skills/lisa-notion-access/SKILL.md +7 -10
  180. package/plugins/lisa-cursor/skills/lisa-posthog-access/SKILL.md +7 -10
  181. package/plugins/lisa-cursor/skills/lisa-repair-intake/SKILL.md +19 -3
  182. package/plugins/lisa-cursor/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +10 -6
  183. package/plugins/lisa-cursor/skills/lisa-secrets-access/scripts/publish-aws-bootstrap.mjs +95 -44
  184. package/plugins/lisa-cursor/skills/lisa-sentry-access/SKILL.md +7 -10
  185. package/plugins/lisa-cursor/skills/lisa-setup-atlassian/SKILL.md +7 -10
  186. package/plugins/lisa-cursor/skills/lisa-setup-linear/SKILL.md +9 -12
  187. package/plugins/lisa-cursor/skills/lisa-setup-notion/SKILL.md +7 -10
  188. package/plugins/lisa-cursor/skills/lisa-setup-remote-aws/SKILL.md +7 -2
  189. package/plugins/lisa-cursor/skills/lisa-setup-remote-env/SKILL.md +6 -1
  190. package/plugins/lisa-cursor/skills/lisa-setup-remote-env/assets/session-start.sh +19 -0
  191. package/plugins/lisa-cursor/skills/lisa-setup-remote-env/assets/setup.sh +1 -0
  192. package/plugins/lisa-cursor/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +25 -4
  193. package/plugins/lisa-cursor/skills/lisa-setup-workstation/scripts/bounded-child.mjs +9 -0
  194. package/plugins/lisa-cursor/skills/lisa-setup-workstation/scripts/workstation.mjs +29 -21
  195. package/plugins/lisa-cursor/skills/lisa-sonarcloud-access/SKILL.md +7 -10
  196. package/plugins/lisa-cursor/skills/lisa-tracker-sync/SKILL.md +1 -1
  197. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  198. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  199. package/plugins/lisa-expo-agy/plugin.json +1 -1
  200. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  201. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  202. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  203. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  204. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  205. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  206. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  207. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  208. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  209. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  210. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  211. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  212. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  213. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  214. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  215. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  216. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  217. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  218. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  219. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  220. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  221. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  222. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  223. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  224. package/plugins/lisa-rails-agy/plugin.json +1 -1
  225. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  226. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  227. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  228. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  229. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  230. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  231. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  232. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  233. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  234. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  235. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  236. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  237. package/plugins/src/base/hooks/parity-safety-net.sh +36 -6
  238. package/plugins/src/base/hooks/threshold-ratchet-families.mjs +31 -7
  239. package/plugins/src/base/rules/reference/base-rules.md +1 -1
  240. package/plugins/src/base/rules/reference/config-resolution.md +5 -14
  241. package/plugins/src/base/scripts/install-remote-agent-aws.mjs +5 -1
  242. package/plugins/src/base/scripts/rollup-blocker-classification.mjs +18 -3
  243. package/plugins/src/base/skills/lisa-atlassian-access/SKILL.md +10 -13
  244. package/plugins/src/base/skills/lisa-doctor/SKILL.md +4 -2
  245. package/plugins/src/base/skills/lisa-drive-pr-to-merge/SKILL.md +29 -4
  246. package/plugins/src/base/skills/lisa-github-sync/SKILL.md +8 -3
  247. package/plugins/src/base/skills/lisa-jam-access/SKILL.md +7 -10
  248. package/plugins/src/base/skills/lisa-jira-journey/SKILL.md +5 -0
  249. package/plugins/src/base/skills/lisa-jira-journey/scripts/parse-plan.py +36 -2
  250. package/plugins/src/base/skills/lisa-jira-sync/SKILL.md +1 -1
  251. package/plugins/src/base/skills/lisa-linear-access/SKILL.md +8 -12
  252. package/plugins/src/base/skills/lisa-linear-sync/SKILL.md +1 -1
  253. package/plugins/src/base/skills/lisa-nightly-lower-code-complexity/SKILL.md +7 -1
  254. package/plugins/src/base/skills/lisa-notion-access/SKILL.md +7 -10
  255. package/plugins/src/base/skills/lisa-posthog-access/SKILL.md +7 -10
  256. package/plugins/src/base/skills/lisa-repair-intake/SKILL.md +19 -3
  257. package/plugins/src/base/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +10 -6
  258. package/plugins/src/base/skills/lisa-secrets-access/scripts/publish-aws-bootstrap.mjs +95 -44
  259. package/plugins/src/base/skills/lisa-sentry-access/SKILL.md +7 -10
  260. package/plugins/src/base/skills/lisa-setup-atlassian/SKILL.md +7 -10
  261. package/plugins/src/base/skills/lisa-setup-linear/SKILL.md +9 -12
  262. package/plugins/src/base/skills/lisa-setup-notion/SKILL.md +7 -10
  263. package/plugins/src/base/skills/lisa-setup-remote-aws/SKILL.md +7 -2
  264. package/plugins/src/base/skills/lisa-setup-remote-env/SKILL.md +6 -1
  265. package/plugins/src/base/skills/lisa-setup-remote-env/assets/session-start.sh +19 -0
  266. package/plugins/src/base/skills/lisa-setup-remote-env/assets/setup.sh +1 -0
  267. package/plugins/src/base/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs +25 -4
  268. package/plugins/src/base/skills/lisa-setup-workstation/scripts/bounded-child.mjs +9 -0
  269. package/plugins/src/base/skills/lisa-setup-workstation/scripts/workstation.mjs +29 -21
  270. package/plugins/src/base/skills/lisa-sonarcloud-access/SKILL.md +7 -10
  271. package/plugins/src/base/skills/lisa-tracker-sync/SKILL.md +1 -1
  272. package/rails/copy-overwrite/scripts/threshold-ratchet-families.mjs +31 -7
  273. package/scripts/lisa-remote-env/session-start.sh +19 -0
  274. package/scripts/lisa-remote-env/setup.sh +1 -0
  275. package/scripts/two-channel-couplings.json +1 -1
  276. package/typescript/copy-contents/.husky/pre-push +1 -1
  277. package/typescript/copy-overwrite/scripts/threshold-ratchet-families.mjs +31 -7
  278. package/typescript/package-lisa/package.lisa.json +1 -1
@@ -56,6 +56,11 @@ const ROLE_ARN =
56
56
  /^arn:(?:aws|aws-us-gov|aws-cn):iam::\d{12}:role\/[\w+=,.@/-]+$/;
57
57
  const PUBLICATION_COORDINATION_SCOPE = "AWS_BOOTSTRAP_";
58
58
  const PUBLICATION_LOCK_TTL_MS = 30 * 60 * 1000;
59
+ // Every provider and AWS child has its own 30-second deadline. Stop starting
60
+ // target mutations five minutes before another publisher may reap this lock,
61
+ // leaving ample room for the in-flight child to finish. This is a monotonic
62
+ // duration budget, not a wall clock used to order or expire provider records.
63
+ const PUBLICATION_CRITICAL_SECTION_BUDGET_MS = 25 * 60 * 1000;
59
64
 
60
65
  /**
61
66
  * Validate and normalize one complete bundle without changing its serialized
@@ -257,6 +262,22 @@ function writeProviderValue(cfg, id, value, write) {
257
262
  }
258
263
  }
259
264
 
265
+ function publicationBudgetGuard(startedAt, monotonicNow) {
266
+ return () => {
267
+ const elapsed = monotonicNow() - startedAt;
268
+ if (!Number.isFinite(elapsed) || elapsed < 0) {
269
+ throw new Error(
270
+ "publication lock monotonic timer became invalid; refusing further provider mutation"
271
+ );
272
+ }
273
+ if (elapsed >= PUBLICATION_CRITICAL_SECTION_BUDGET_MS) {
274
+ throw new Error(
275
+ "publication lock execution budget exceeded; refusing further provider mutation"
276
+ );
277
+ }
278
+ };
279
+ }
280
+
260
281
  /**
261
282
  * Enter the provider election for one AWS bootstrap record.
262
283
  *
@@ -427,23 +448,29 @@ export function releasePublicationLock(cfg, lock, operations = {}) {
427
448
  * snapshot can never overwrite a publication that finished while this process
428
449
  * was entering the election.
429
450
  */
430
- function withPublicationLock(cfg, operations, task) {
451
+ function withPublicationLock(cfg, operations, task, completedMessage) {
431
452
  const fetch = operations.fetch ?? fetchAll;
432
453
  const acquire = operations.acquireLock ?? acquirePublicationLock;
433
454
  const release = operations.releaseLock ?? releasePublicationLock;
455
+ const monotonicNow = operations.monotonicNow ?? (() => performance.now());
456
+ const startedAt = monotonicNow();
457
+ const assertWithinBudget = publicationBudgetGuard(startedAt, monotonicNow);
434
458
  const target = currentEntry(cfg, fetch);
435
459
  const lock = acquire(cfg, target, operations);
436
460
  let result;
437
461
  let taskError;
438
462
 
439
463
  try {
464
+ assertWithinBudget();
440
465
  const current = currentEntry(cfg, fetch);
441
466
  if (current.id !== target.id || current.projectId !== target.projectId) {
442
467
  throw new Error(
443
468
  `${BOOTSTRAP_KEY} moved after publication lock acquisition; retry from the new provider record`
444
469
  );
445
470
  }
446
- result = task(current);
471
+ assertWithinBudget();
472
+ result = task(current, assertWithinBudget);
473
+ assertWithinBudget();
447
474
  } catch (error) {
448
475
  taskError = error;
449
476
  }
@@ -455,15 +482,18 @@ function withPublicationLock(cfg, operations, task) {
455
482
  if (taskError) {
456
483
  throw new Error(`${firstLine(taskError)}; ${releaseReason}`);
457
484
  }
458
- throw new Error(releaseReason);
485
+ throw new Error(
486
+ `${completedMessage}; ${releaseReason}; remove the coordination record before the next publication`
487
+ );
459
488
  }
460
489
 
461
490
  if (taskError) throw taskError;
462
491
  return result;
463
492
  }
464
493
 
465
- function preflightUnderLock(cfg, entry, write) {
494
+ function preflightUnderLock(cfg, entry, write, assertWithinBudget) {
466
495
  try {
496
+ assertWithinBudget();
467
497
  writeProviderValue(cfg, entry.id, entry.value, write);
468
498
  } catch (error) {
469
499
  throw new Error(
@@ -482,8 +512,12 @@ function preflightUnderLock(cfg, entry, write) {
482
512
  */
483
513
  export function preflightAwsBootstrap(cfg, operations = {}) {
484
514
  const write = operations.write ?? writeSecret;
485
- return withPublicationLock(cfg, operations, entry =>
486
- preflightUnderLock(cfg, entry, write)
515
+ return withPublicationLock(
516
+ cfg,
517
+ operations,
518
+ (entry, assertWithinBudget) =>
519
+ preflightUnderLock(cfg, entry, write, assertWithinBudget),
520
+ "preflight completed"
487
521
  );
488
522
  }
489
523
 
@@ -496,12 +530,20 @@ export function preflightAwsBootstrap(cfg, operations = {}) {
496
530
  * @param {Function} write Provider writer.
497
531
  * @returns {string} Human-readable rollback outcome with no secret material.
498
532
  */
499
- function rollback(cfg, previous, candidateRaw, fetch, write) {
533
+ function rollback(
534
+ cfg,
535
+ previous,
536
+ candidateRaw,
537
+ fetch,
538
+ write,
539
+ assertWithinBudget
540
+ ) {
500
541
  try {
501
542
  const current = currentEntry(cfg, fetch);
502
543
  if (current.value !== candidateRaw) {
503
544
  return "rollback skipped because the provider changed after this publication";
504
545
  }
546
+ assertWithinBudget();
505
547
  writeProviderValue(cfg, previous.id, previous.value, write);
506
548
  const restored = currentEntry(cfg, fetch);
507
549
  if (restored.value !== previous.value) {
@@ -528,47 +570,56 @@ export function publishAwsBootstrap(raw, cfg, operations = {}) {
528
570
  const write = operations.write ?? writeSecret;
529
571
  const verify = operations.verify ?? verifyAwsBootstrap;
530
572
  const candidate = validateAwsBootstrap(raw);
531
- return withPublicationLock(cfg, operations, previous => {
532
- preflightUnderLock(cfg, previous, write);
533
-
534
- // Verify before the write. A candidate that cannot assume one of its roles
535
- // never becomes the value every new remote session receives.
536
- verify(candidate);
537
-
538
- if (candidate.raw === previous.value) {
539
- return {
540
- changed: false,
541
- profiles: candidate.profiles.map(profile => profile.name),
542
- };
543
- }
573
+ return withPublicationLock(
574
+ cfg,
575
+ operations,
576
+ (previous, assertWithinBudget) => {
577
+ preflightUnderLock(cfg, previous, write, assertWithinBudget);
578
+
579
+ // Verify before the write. A candidate that cannot assume one of its roles
580
+ // never becomes the value every new remote session receives.
581
+ verify(candidate);
582
+ assertWithinBudget();
583
+
584
+ if (candidate.raw === previous.value) {
585
+ return {
586
+ changed: false,
587
+ profiles: candidate.profiles.map(profile => profile.name),
588
+ };
589
+ }
544
590
 
545
- try {
546
- writeProviderValue(cfg, previous.id, candidate.raw, write);
547
- const stored = currentEntry(cfg, fetch);
548
- if (stored.value !== candidate.raw) {
591
+ try {
592
+ assertWithinBudget();
593
+ writeProviderValue(cfg, previous.id, candidate.raw, write);
594
+ const stored = currentEntry(cfg, fetch);
595
+ if (stored.value !== candidate.raw) {
596
+ throw new Error(
597
+ "provider read-back did not match the candidate exactly"
598
+ );
599
+ }
600
+ const storedCandidate = validateAwsBootstrap(stored.value);
601
+ verify(storedCandidate);
602
+ assertWithinBudget();
603
+ return {
604
+ changed: true,
605
+ profiles: storedCandidate.profiles.map(profile => profile.name),
606
+ };
607
+ } catch (error) {
608
+ const rollbackOutcome = rollback(
609
+ cfg,
610
+ previous,
611
+ candidate.raw,
612
+ fetch,
613
+ write,
614
+ assertWithinBudget
615
+ );
549
616
  throw new Error(
550
- "provider read-back did not match the candidate exactly"
617
+ `${BOOTSTRAP_KEY} publication failed: ${firstLine(error)}; ${rollbackOutcome}`
551
618
  );
552
619
  }
553
- const storedCandidate = validateAwsBootstrap(stored.value);
554
- verify(storedCandidate);
555
- return {
556
- changed: true,
557
- profiles: storedCandidate.profiles.map(profile => profile.name),
558
- };
559
- } catch (error) {
560
- const rollbackOutcome = rollback(
561
- cfg,
562
- previous,
563
- candidate.raw,
564
- fetch,
565
- write
566
- );
567
- throw new Error(
568
- `${BOOTSTRAP_KEY} publication failed: ${firstLine(error)}; ${rollbackOutcome}`
569
- );
570
- }
571
- });
620
+ },
621
+ "publication completed"
622
+ );
572
623
  }
573
624
 
574
625
  /** Read a candidate from stdin without ever placing it in argv. */
@@ -48,9 +48,9 @@ interactively and headlessly — which is why it leads. The REST tier uses:
48
48
  read_sentry_token() {
49
49
  [ -n "${SENTRY_AUTH_TOKEN:-}" ] && { echo "$SENTRY_AUTH_TOKEN"; return; }
50
50
  #
51
- # Ordered repo-first, ending at the plugin's own copy. Repo-relative rungs
52
- # lead because a project that vendors the resolver has declared which copy it
53
- # wants used, and that decision must survive this change untouched. The plugin
51
+ # Ordered across trusted machine-managed substrates, ending at the installed
52
+ # package. Checkout-local paths are deliberately absent: a familiar generated
53
+ # destination is still repository-controlled executable code. The plugin
54
54
  # rungs are the floor: `resolve-secret.mjs` ships beside this skill, so a rung
55
55
  # pointing at it is reachable from anywhere the plugin itself is installed.
56
56
  # Without one, a consumer repository that vendors none of the leading paths
@@ -59,12 +59,9 @@ read_sentry_token() {
59
59
  # lookups. This LADDER is identical in every skill that resolves a credential
60
60
  # and `credential-resolver-ladder` fails if any copy diverges. Only what
61
61
  # happens AFTER the ladder may differ between them.
62
- local candidates=(
63
- .claude/skills/lisa-secrets-access/scripts/resolve-secret.mjs
64
- .agents/skills/lisa-secrets-access/scripts/resolve-secret.mjs
65
- .opencode/skills/lisa/lisa-secrets-access/scripts/resolve-secret.mjs
66
- .codex/skills/lisa/lisa-secrets-access/scripts/resolve-secret.mjs
67
- )
62
+ # Execute only machine-managed plugin/package resolvers. Checkout-local
63
+ # candidates are repository-controlled code, not trusted merely by path.
64
+ local candidates=()
68
65
  if [ -n "${CLAUDE_PLUGIN_ROOT:-}" ]; then
69
66
  candidates+=("$CLAUDE_PLUGIN_ROOT/skills/lisa-secrets-access/scripts/resolve-secret.mjs")
70
67
  fi
@@ -83,7 +80,7 @@ read_sentry_token() {
83
80
  local via_lisa
84
81
  via_lisa=$(node "$resolver" get SENTRY_AUTH_TOKEN 2>/dev/null) \
85
82
  && [ -n "$via_lisa" ] && { echo "$via_lisa"; return; }
86
- break
83
+ # Empty/error means this substrate had no answer; try the next trusted one.
87
84
  fi
88
85
  done
89
86
  # Name every path. A bare `return 1` sends the next reader hunting for a
@@ -86,9 +86,9 @@ read_token() {
86
86
  # than "this function" is deliberate — the old wording asked for something
87
87
  # unachievable, and an unachievable rule is one that gets quietly dropped.
88
88
  #
89
- # Ordered repo-first, ending at the plugin's own copy. Repo-relative rungs
90
- # lead because a project that vendors the resolver has declared which copy it
91
- # wants used, and that decision must survive this change untouched. The plugin
89
+ # Ordered across trusted machine-managed substrates, ending at the installed
90
+ # package. Checkout-local paths are deliberately absent: a familiar generated
91
+ # destination is still repository-controlled executable code. The plugin
92
92
  # rungs are the floor: `resolve-secret.mjs` ships beside this skill, so a rung
93
93
  # pointing at it is reachable from anywhere the plugin itself is installed.
94
94
  # Without one, a consumer repository that vendors none of the leading paths
@@ -97,12 +97,9 @@ read_token() {
97
97
  # lookups. This LADDER is identical in every skill that resolves a credential
98
98
  # and `credential-resolver-ladder` fails if any copy diverges. Only what
99
99
  # happens AFTER the ladder may differ between them.
100
- local candidates=(
101
- .claude/skills/lisa-secrets-access/scripts/resolve-secret.mjs
102
- .agents/skills/lisa-secrets-access/scripts/resolve-secret.mjs
103
- .opencode/skills/lisa/lisa-secrets-access/scripts/resolve-secret.mjs
104
- .codex/skills/lisa/lisa-secrets-access/scripts/resolve-secret.mjs
105
- )
100
+ # Execute only machine-managed plugin/package resolvers. Checkout-local
101
+ # candidates are repository-controlled code, not trusted merely by path.
102
+ local candidates=()
106
103
  if [ -n "${CLAUDE_PLUGIN_ROOT:-}" ]; then
107
104
  candidates+=("$CLAUDE_PLUGIN_ROOT/skills/lisa-secrets-access/scripts/resolve-secret.mjs")
108
105
  fi
@@ -121,7 +118,7 @@ read_token() {
121
118
  local via_lisa
122
119
  via_lisa=$(node "$resolver" get ATLASSIAN_API_TOKEN 2>/dev/null) \
123
120
  && [ -n "$via_lisa" ] && { echo "$via_lisa"; return; }
124
- break
121
+ # Empty/error means this substrate had no answer; try the next trusted one.
125
122
  fi
126
123
  done
127
124
  # Legacy fallback: the OS keychain written by the guided flow below, for
@@ -104,17 +104,14 @@ read_linear_key() { # $1=workspace slug
104
104
  # `linear-access` grew to seven, leaving `/lisa:setup:linear` unable to reach
105
105
  # a key that `lisa-linear-access` could read from the same repository.
106
106
  #
107
- # Ordered repo-first, ending at the plugin's own copy. Repo-relative rungs
108
- # lead because a project that vendors the resolver has declared which copy it
109
- # wants used. The plugin rungs are the floor: `resolve-secret.mjs` ships
110
- # beside this skill, so a rung pointing at it is reachable from anywhere the
111
- # plugin itself is installed.
112
- local candidates=(
113
- .claude/skills/lisa-secrets-access/scripts/resolve-secret.mjs
114
- .agents/skills/lisa-secrets-access/scripts/resolve-secret.mjs
115
- .opencode/skills/lisa/lisa-secrets-access/scripts/resolve-secret.mjs
116
- .codex/skills/lisa/lisa-secrets-access/scripts/resolve-secret.mjs
117
- )
107
+ # Ordered across trusted machine-managed substrates, ending at the installed
108
+ # package. Checkout-local paths are deliberately absent: a familiar generated
109
+ # destination is still repository-controlled executable code. The plugin
110
+ # rungs are the floor: `resolve-secret.mjs` ships beside this skill, so a rung
111
+ # pointing at it is reachable from anywhere the plugin itself is installed.
112
+ # Execute only machine-managed plugin/package resolvers. Checkout-local
113
+ # candidates are repository-controlled code, not trusted merely by path.
114
+ local candidates=()
118
115
  if [ -n "${CLAUDE_PLUGIN_ROOT:-}" ]; then
119
116
  candidates+=("$CLAUDE_PLUGIN_ROOT/skills/lisa-secrets-access/scripts/resolve-secret.mjs")
120
117
  fi
@@ -133,7 +130,7 @@ read_linear_key() { # $1=workspace slug
133
130
  local via_lisa
134
131
  via_lisa=$(node "$resolver" get LINEAR_API_KEY 2>/dev/null) \
135
132
  && [ -n "$via_lisa" ] && { echo "$via_lisa"; return; }
136
- break
133
+ # Empty/error means this substrate had no answer; try the next trusted one.
137
134
  fi
138
135
  done
139
136
  # Legacy fallback: the OS keychain written by the guided flow below, for
@@ -173,9 +173,9 @@ read_notion_token() {
173
173
  # than "this function" is deliberate — the old wording asked for something
174
174
  # unachievable, and an unachievable rule is one that gets quietly dropped.
175
175
  #
176
- # Ordered repo-first, ending at the plugin's own copy. Repo-relative rungs
177
- # lead because a project that vendors the resolver has declared which copy it
178
- # wants used, and that decision must survive this change untouched. The plugin
176
+ # Ordered across trusted machine-managed substrates, ending at the installed
177
+ # package. Checkout-local paths are deliberately absent: a familiar generated
178
+ # destination is still repository-controlled executable code. The plugin
179
179
  # rungs are the floor: `resolve-secret.mjs` ships beside this skill, so a rung
180
180
  # pointing at it is reachable from anywhere the plugin itself is installed.
181
181
  # Without one, a consumer repository that vendors none of the leading paths
@@ -184,12 +184,9 @@ read_notion_token() {
184
184
  # lookups. This LADDER is identical in every skill that resolves a credential
185
185
  # and `credential-resolver-ladder` fails if any copy diverges. Only what
186
186
  # happens AFTER the ladder may differ between them.
187
- local candidates=(
188
- .claude/skills/lisa-secrets-access/scripts/resolve-secret.mjs
189
- .agents/skills/lisa-secrets-access/scripts/resolve-secret.mjs
190
- .opencode/skills/lisa/lisa-secrets-access/scripts/resolve-secret.mjs
191
- .codex/skills/lisa/lisa-secrets-access/scripts/resolve-secret.mjs
192
- )
187
+ # Execute only machine-managed plugin/package resolvers. Checkout-local
188
+ # candidates are repository-controlled code, not trusted merely by path.
189
+ local candidates=()
193
190
  if [ -n "${CLAUDE_PLUGIN_ROOT:-}" ]; then
194
191
  candidates+=("$CLAUDE_PLUGIN_ROOT/skills/lisa-secrets-access/scripts/resolve-secret.mjs")
195
192
  fi
@@ -208,7 +205,7 @@ read_notion_token() {
208
205
  local via_lisa
209
206
  via_lisa=$(node "$resolver" get NOTION_API_TOKEN 2>/dev/null) \
210
207
  && [ -n "$via_lisa" ] && { echo "$via_lisa"; return; }
211
- break
208
+ # Empty/error means this substrate had no answer; try the next trusted one.
212
209
  fi
213
210
  done
214
211
  # Legacy fallback: the OS keychain written by the guided flow below, for
@@ -64,13 +64,18 @@ The lock remains held through rollback and its deletion is verified before the
64
64
  command reports success:
65
65
 
66
66
  ```bash
67
- aws --profile shared secretsmanager get-secret-value \
68
- --secret-id remote-agent-credentials \
67
+ aws secretsmanager get-secret-value \
68
+ --secret-id <selected-secret-name> \
69
69
  --query SecretString \
70
70
  --output text \
71
71
  | node .claude/skills/lisa-secrets-access/scripts/publish-aws-bootstrap.mjs publish
72
72
  ```
73
73
 
74
+ Use the same secret name passed to `--secret-name`; the default is
75
+ `remote-agent-credentials`. Add `--profile <source-profile>` only when the
76
+ operator's ambient AWS identity cannot read the emission and the project names
77
+ a source profile. A named `shared` profile is not otherwise required.
78
+
74
79
  Resolve the script from the installed runtime or `node_modules` when the
75
80
  `.claude/skills` copy is not present. Never print or place the candidate in an
76
81
  argument or temporary file. A CDK deployment followed later by a human copy is
@@ -97,9 +97,14 @@ A surface that **re-runs this script when a container resumes** — Codex Cloud
97
97
  A surface that **skips this script whenever a filesystem cache exists** — Claude Code web — must not. Materializing here would write the values once and then never refresh them, so a credential rotated on Tuesday would still be serving Monday's value until the cache expired days later. Those surfaces materialize from a session-start hook instead, which runs every session including a resumed one:
98
98
 
99
99
  ```sh
100
- bash scripts/lisa-remote-env/session-start.sh # guard; reruns toolchain, secrets, then hook
100
+ bash "$CLAUDE_PROJECT_DIR/scripts/lisa-remote-env/session-start.sh" # project-scoped absolute hook
101
101
  ```
102
102
 
103
+ The installer also registers a user-scoped hook using the checkout's resolved
104
+ absolute path. If invoking this asset by hand, either use that absolute path or
105
+ change to the repository root first; a bare checkout-relative command is not a
106
+ portable session-start configuration.
107
+
103
108
  The selection comes from the surface's `materializeAt` capability in `lisa-secrets-access`, not from its name, so adding a surface does not mean editing a branch. The hook is committed to the repository, so it also fires on a developer's machine — it exits `0` immediately there rather than failing, because a correct local session must not look broken.
104
109
 
105
110
  ## Detect before you provision
@@ -46,8 +46,27 @@ here="$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)"
46
46
  # SessionStart hosts are fail-open, so they surface that result and still allow
47
47
  # the agent session to continue.
48
48
  bash "${here}/setup.sh" --phase=toolchain "$@"
49
+
50
+ # The toolchain child cannot export into this parent shell. Its durable output
51
+ # is linked into ~/.local/bin, so make that directory visible before the next
52
+ # child tries to execute the provider CLI it just installed.
53
+ case ":$PATH:" in
54
+ *":$HOME/.local/bin:"*) ;;
55
+ *) PATH="$HOME/.local/bin:$PATH"; export PATH ;;
56
+ esac
57
+
49
58
  bash "${here}/setup.sh" --phase=secrets "$@"
50
59
 
60
+ # Materialization writes a Lisa-owned block into .profile that sources the
61
+ # generated environment and removes ambient AWS credential poison. The project
62
+ # hook is another non-login child, so load that block here and let the child
63
+ # inherit the exact environment materialization just produced.
64
+ if [ -r "$HOME/.profile" ]; then
65
+ # The materializer owns this runtime path.
66
+ # shellcheck disable=SC1090
67
+ . "$HOME/.profile"
68
+ fi
69
+
51
70
  # A project hook is part of the remote toolchain contract too. It covers tools
52
71
  # that cannot be expressed by the pinned manifest, so skipping it on a cached
53
72
  # session can leave fresh credentials with no client capable of using them.
@@ -132,6 +132,7 @@ for candidate in \
132
132
  ".claude/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs" \
133
133
  ".agents/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs" \
134
134
  ".codex/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs" \
135
+ ".opencode/skills/lisa/lisa-setup-remote-env/scripts/setup-remote-env.mjs" \
135
136
  "plugins/lisa/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs" \
136
137
  "node_modules/@codyswann/lisa/plugins/lisa/skills/lisa-setup-remote-env/scripts/setup-remote-env.mjs"; do
137
138
  if [ -f "$candidate" ]; then
@@ -51,7 +51,10 @@ import { pathDirs } from "../../lisa-setup-workstation/scripts/catalogue.mjs";
51
51
 
52
52
  import { assertPinned, extractVersion, planToolchain } from "./toolchain.mjs";
53
53
 
54
- import { boundedChildOutput } from "../../lisa-setup-workstation/scripts/bounded-child.mjs";
54
+ import {
55
+ boundedChildOutput,
56
+ SETUP_OPERATION_BUDGET_MS,
57
+ } from "../../lisa-setup-workstation/scripts/bounded-child.mjs";
55
58
 
56
59
  const HERE = dirname(fileURLToPath(import.meta.url));
57
60
 
@@ -173,12 +176,14 @@ function installReleaseZip(tool, binDir) {
173
176
  const archive = join(temporary, "download.zip");
174
177
  boundedChildOutput("curl", ["-fsSL", tool.url, "-o", archive], {
175
178
  stdio: "inherit",
179
+ timeout: SETUP_OPERATION_BUDGET_MS,
176
180
  });
177
181
  // Verify before unpacking, not after. An unexpected archive must fail
178
182
  // before any of its contents reach a directory that is on PATH.
179
183
  verifyChecksum(archive, tool.sha256, tool.name);
180
184
  boundedChildOutput("unzip", ["-q", "-o", archive, "-d", temporary], {
181
185
  stdio: "inherit",
186
+ timeout: SETUP_OPERATION_BUDGET_MS,
182
187
  });
183
188
  const binary = join(temporary, tool.binary ?? tool.name);
184
189
  boundedChildOutput(
@@ -186,6 +191,7 @@ function installReleaseZip(tool, binDir) {
186
191
  ["-m", "0755", binary, join(binDir, tool.name)],
187
192
  {
188
193
  stdio: "inherit",
194
+ timeout: SETUP_OPERATION_BUDGET_MS,
189
195
  }
190
196
  );
191
197
  } finally {
@@ -210,10 +216,12 @@ function installReleaseTar(tool, binDir) {
210
216
  const archive = join(temporary, "download.tar.gz");
211
217
  boundedChildOutput("curl", ["-fsSL", tool.url, "-o", archive], {
212
218
  stdio: "inherit",
219
+ timeout: SETUP_OPERATION_BUDGET_MS,
213
220
  });
214
221
  verifyChecksum(archive, tool.sha256, tool.name);
215
222
  boundedChildOutput("tar", ["-xzf", archive, "-C", temporary], {
216
223
  stdio: "inherit",
224
+ timeout: SETUP_OPERATION_BUDGET_MS,
217
225
  });
218
226
  // Release tarballs usually nest under a versioned directory, so `binary` is
219
227
  // a path within the archive rather than a bare name.
@@ -223,6 +231,7 @@ function installReleaseTar(tool, binDir) {
223
231
  ["-m", "0755", binary, join(binDir, tool.name)],
224
232
  {
225
233
  stdio: "inherit",
234
+ timeout: SETUP_OPERATION_BUDGET_MS,
226
235
  }
227
236
  );
228
237
  } finally {
@@ -272,6 +281,7 @@ function installReleaseTree(tool, binDir) {
272
281
  const archive = join(temporary, "download.archive");
273
282
  boundedChildOutput("curl", ["-fsSL", tool.url, "-o", archive], {
274
283
  stdio: "inherit",
284
+ timeout: SETUP_OPERATION_BUDGET_MS,
275
285
  });
276
286
  // Verify before unpacking, as everywhere else here: an unexpected archive
277
287
  // must fail before any of its contents reach the filesystem.
@@ -285,10 +295,12 @@ function installReleaseTree(tool, binDir) {
285
295
  if (tool.url.endsWith(".zip")) {
286
296
  boundedChildOutput("unzip", ["-q", "-o", archive, "-d", prefix], {
287
297
  stdio: "inherit",
298
+ timeout: SETUP_OPERATION_BUDGET_MS,
288
299
  });
289
300
  } else {
290
301
  boundedChildOutput("tar", ["-xzf", archive, "-C", prefix], {
291
302
  stdio: "inherit",
303
+ timeout: SETUP_OPERATION_BUDGET_MS,
292
304
  });
293
305
  }
294
306
 
@@ -342,6 +354,7 @@ function installReleaseBinary(tool, binDir) {
342
354
  const artifact = join(temporary, tool.name);
343
355
  boundedChildOutput("curl", ["-fsSL", tool.url, "-o", artifact], {
344
356
  stdio: "inherit",
357
+ timeout: SETUP_OPERATION_BUDGET_MS,
345
358
  });
346
359
  // Verify before it reaches a directory on PATH. For this kind that ordering
347
360
  // matters more than for the archives: the downloaded file is directly
@@ -353,6 +366,7 @@ function installReleaseBinary(tool, binDir) {
353
366
  ["-m", "0755", artifact, join(binDir, tool.name)],
354
367
  {
355
368
  stdio: "inherit",
369
+ timeout: SETUP_OPERATION_BUDGET_MS,
356
370
  }
357
371
  );
358
372
  } finally {
@@ -370,6 +384,7 @@ function installNpmGlobal(tool) {
370
384
  ["install", "--global", `${tool.package}@${tool.version}`],
371
385
  {
372
386
  stdio: "inherit",
387
+ timeout: SETUP_OPERATION_BUDGET_MS,
373
388
  }
374
389
  );
375
390
  }
@@ -509,7 +524,10 @@ function runHook(hook, dryRun) {
509
524
  console.log(`\nProject hook: ${hook}`);
510
525
  if (dryRun) return;
511
526
  chmodSync(path, 0o755);
512
- boundedChildOutput("bash", [path], { stdio: "inherit" });
527
+ boundedChildOutput("bash", [path], {
528
+ stdio: "inherit",
529
+ timeout: SETUP_OPERATION_BUDGET_MS,
530
+ });
513
531
  }
514
532
 
515
533
  /** Phases this runner can execute, in the order they must happen. */
@@ -789,7 +807,10 @@ export function installUserSessionHook(repoRoot, options = {}) {
789
807
 
790
808
  const dir = join(home, ".claude");
791
809
  const settingsPath = join(dir, "settings.json");
792
- const command = `bash ${script}`;
810
+ // Settings stores shell source, so the absolute path still needs quoting.
811
+ // JSON string syntax is accepted by the shell for ordinary path text and
812
+ // safely escapes spaces, quotes, dollars and backticks.
813
+ const command = `bash ${JSON.stringify(script)}`;
793
814
 
794
815
  let settings = {};
795
816
  if (exists(settingsPath)) {
@@ -1506,7 +1527,7 @@ async function main() {
1506
1527
  boundedChildOutput(
1507
1528
  "node",
1508
1529
  dryRun ? [materialize, "--dry-run"] : [materialize],
1509
- { stdio: "inherit" }
1530
+ { stdio: "inherit", timeout: SETUP_OPERATION_BUDGET_MS }
1510
1531
  );
1511
1532
  } catch (err) {
1512
1533
  if (!retried) throw err;
@@ -83,6 +83,15 @@ import { execFileSync, spawnSync } from "node:child_process";
83
83
  */
84
84
  export const CHILD_BUDGET_MS = 30_000;
85
85
 
86
+ /**
87
+ * Deadline for setup operations that legitimately include downloads, package
88
+ * installation, secret-provider calls, or a project-declared hook.
89
+ *
90
+ * Kept separate from {@link CHILD_BUDGET_MS}: probes should still fail quickly,
91
+ * while a cold network install must not be killed by the probe budget.
92
+ */
93
+ export const SETUP_OPERATION_BUDGET_MS = 10 * 60_000;
94
+
86
95
  /**
87
96
  * Whether this value is a child that was killed at its deadline.
88
97
  *