@codyswann/lisa 4.80.2 → 4.81.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (334) hide show
  1. package/all/copy-contents/gitignore +5 -0
  2. package/dist/cli/doctor-session-manager-trust.d.ts +62 -0
  3. package/dist/cli/doctor-session-manager-trust.d.ts.map +1 -0
  4. package/dist/cli/doctor-session-manager-trust.js +174 -0
  5. package/dist/cli/doctor-session-manager-trust.js.map +1 -0
  6. package/dist/cli/doctor-session-manager.d.ts +35 -0
  7. package/dist/cli/doctor-session-manager.d.ts.map +1 -0
  8. package/dist/cli/doctor-session-manager.js +209 -0
  9. package/dist/cli/doctor-session-manager.js.map +1 -0
  10. package/dist/cli/doctor.d.ts.map +1 -1
  11. package/dist/cli/doctor.js +3 -0
  12. package/dist/cli/doctor.js.map +1 -1
  13. package/dist/cli/lisa-test-run-bootstrap.js +28 -0
  14. package/dist/cli/lisa-test-run-bootstrap.js.map +1 -1
  15. package/dist/cli/session-manager-config-merge.d.ts +25 -0
  16. package/dist/cli/session-manager-config-merge.d.ts.map +1 -0
  17. package/dist/cli/session-manager-config-merge.js +54 -0
  18. package/dist/cli/session-manager-config-merge.js.map +1 -0
  19. package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
  20. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  21. package/dist/core/upstream-evidence-manifest.js +258 -12
  22. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  23. package/dist/migrations/deploy-outcome-guard-edit.d.ts.map +1 -1
  24. package/dist/migrations/deploy-outcome-guard-edit.js +35 -14
  25. package/dist/migrations/deploy-outcome-guard-edit.js.map +1 -1
  26. package/dist/migrations/deploy-outcome-guard-yaml.d.ts +30 -1
  27. package/dist/migrations/deploy-outcome-guard-yaml.d.ts.map +1 -1
  28. package/dist/migrations/deploy-outcome-guard-yaml.js +88 -7
  29. package/dist/migrations/deploy-outcome-guard-yaml.js.map +1 -1
  30. package/package.json +4 -4
  31. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  32. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  33. package/plugins/lisa/.codex-plugin/skills/lisa-automation-status/SKILL.md +10 -0
  34. package/plugins/lisa/.codex-plugin/skills/lisa-implement/SKILL.md +17 -2
  35. package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/scripts/validate-config.mjs +377 -5
  36. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/SKILL.md +287 -0
  37. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/agents/openai.yaml +4 -0
  38. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/references/runbook-template.md +66 -0
  39. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/capacity.mjs +186 -0
  40. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/cli-cycle.mjs +262 -0
  41. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/cli-manager.mjs +308 -0
  42. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/cli-queue.mjs +148 -0
  43. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/cli-runtime.mjs +326 -0
  44. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/cli-usage.mjs +114 -0
  45. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/cli-workers.mjs +295 -0
  46. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/config.mjs +265 -0
  47. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/isolation.mjs +130 -0
  48. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/launch.mjs +234 -0
  49. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/ledger.mjs +445 -0
  50. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/reconcile.mjs +134 -0
  51. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/session-manager.mjs +274 -0
  52. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/state-dir.mjs +112 -0
  53. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/telegram-route.mjs +210 -0
  54. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/token.mjs +191 -0
  55. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/worker-launch.mjs +92 -0
  56. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/workers.mjs +406 -0
  57. package/plugins/lisa/.codex-plugin/skills/lisa-setup-session-manager/SKILL.md +158 -0
  58. package/plugins/lisa/.codex-plugin/skills/lisa-setup-session-manager/agents/openai.yaml +4 -0
  59. package/plugins/lisa/.codex-plugin/skills/lisa-tear-down-automations/SKILL.md +10 -0
  60. package/plugins/lisa/commands/implement.md +2 -2
  61. package/plugins/lisa/commands/session-manager.md +7 -0
  62. package/plugins/lisa/commands/setup/session-manager.md +6 -0
  63. package/plugins/lisa/rules/reference/automation-runbook-contract.md +14 -0
  64. package/plugins/lisa/rules/reference/config-resolution.md +58 -0
  65. package/plugins/lisa/scripts/automation-status-claude-adapter.mjs +4 -1
  66. package/plugins/lisa/scripts/automation-status-codex-adapter.mjs +4 -1
  67. package/plugins/lisa/scripts/automation-status-expected-fleet.mjs +98 -0
  68. package/plugins/lisa/scripts/automation-status-run-history.mjs +29 -7
  69. package/plugins/lisa/scripts/ready-queue-order.mjs +352 -0
  70. package/plugins/lisa/skills/lisa-automation-status/SKILL.md +10 -0
  71. package/plugins/lisa/skills/lisa-implement/SKILL.md +17 -2
  72. package/plugins/lisa/skills/lisa-secrets-access/scripts/validate-config.mjs +377 -5
  73. package/plugins/lisa/skills/lisa-session-manager/SKILL.md +285 -0
  74. package/plugins/lisa/skills/lisa-session-manager/agents/openai.yaml +4 -0
  75. package/plugins/lisa/skills/lisa-session-manager/references/runbook-template.md +66 -0
  76. package/plugins/lisa/skills/lisa-session-manager/scripts/capacity.mjs +186 -0
  77. package/plugins/lisa/skills/lisa-session-manager/scripts/cli-cycle.mjs +262 -0
  78. package/plugins/lisa/skills/lisa-session-manager/scripts/cli-manager.mjs +308 -0
  79. package/plugins/lisa/skills/lisa-session-manager/scripts/cli-queue.mjs +148 -0
  80. package/plugins/lisa/skills/lisa-session-manager/scripts/cli-runtime.mjs +326 -0
  81. package/plugins/lisa/skills/lisa-session-manager/scripts/cli-usage.mjs +114 -0
  82. package/plugins/lisa/skills/lisa-session-manager/scripts/cli-workers.mjs +295 -0
  83. package/plugins/lisa/skills/lisa-session-manager/scripts/config.mjs +265 -0
  84. package/plugins/lisa/skills/lisa-session-manager/scripts/isolation.mjs +130 -0
  85. package/plugins/lisa/skills/lisa-session-manager/scripts/launch.mjs +234 -0
  86. package/plugins/lisa/skills/lisa-session-manager/scripts/ledger.mjs +445 -0
  87. package/plugins/lisa/skills/lisa-session-manager/scripts/reconcile.mjs +134 -0
  88. package/plugins/lisa/skills/lisa-session-manager/scripts/session-manager.mjs +274 -0
  89. package/plugins/lisa/skills/lisa-session-manager/scripts/state-dir.mjs +112 -0
  90. package/plugins/lisa/skills/lisa-session-manager/scripts/telegram-route.mjs +210 -0
  91. package/plugins/lisa/skills/lisa-session-manager/scripts/token.mjs +191 -0
  92. package/plugins/lisa/skills/lisa-session-manager/scripts/worker-launch.mjs +92 -0
  93. package/plugins/lisa/skills/lisa-session-manager/scripts/workers.mjs +406 -0
  94. package/plugins/lisa/skills/lisa-setup-session-manager/SKILL.md +156 -0
  95. package/plugins/lisa/skills/lisa-setup-session-manager/agents/openai.yaml +4 -0
  96. package/plugins/lisa/skills/lisa-tear-down-automations/SKILL.md +10 -0
  97. package/plugins/lisa-agy/commands/lisa/implement.md +2 -2
  98. package/plugins/lisa-agy/commands/lisa/session-manager.md +7 -0
  99. package/plugins/lisa-agy/commands/lisa/setup/session-manager.md +6 -0
  100. package/plugins/lisa-agy/plugin.json +1 -1
  101. package/plugins/lisa-agy/scripts/automation-status-claude-adapter.mjs +4 -1
  102. package/plugins/lisa-agy/scripts/automation-status-codex-adapter.mjs +4 -1
  103. package/plugins/lisa-agy/scripts/automation-status-expected-fleet.mjs +98 -0
  104. package/plugins/lisa-agy/scripts/automation-status-run-history.mjs +29 -7
  105. package/plugins/lisa-agy/scripts/ready-queue-order.mjs +352 -0
  106. package/plugins/lisa-agy/skills/lisa-automation-status/SKILL.md +10 -0
  107. package/plugins/lisa-agy/skills/lisa-implement/SKILL.md +17 -2
  108. package/plugins/lisa-agy/skills/lisa-secrets-access/scripts/validate-config.mjs +377 -5
  109. package/plugins/lisa-agy/skills/lisa-session-manager/SKILL.md +285 -0
  110. package/plugins/lisa-agy/skills/lisa-session-manager/references/runbook-template.md +66 -0
  111. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/capacity.mjs +186 -0
  112. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/cli-cycle.mjs +262 -0
  113. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/cli-manager.mjs +308 -0
  114. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/cli-queue.mjs +148 -0
  115. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/cli-runtime.mjs +326 -0
  116. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/cli-usage.mjs +114 -0
  117. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/cli-workers.mjs +295 -0
  118. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/config.mjs +265 -0
  119. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/isolation.mjs +130 -0
  120. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/launch.mjs +234 -0
  121. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/ledger.mjs +445 -0
  122. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/reconcile.mjs +134 -0
  123. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/session-manager.mjs +274 -0
  124. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/state-dir.mjs +112 -0
  125. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/telegram-route.mjs +210 -0
  126. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/token.mjs +191 -0
  127. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/worker-launch.mjs +92 -0
  128. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/workers.mjs +406 -0
  129. package/plugins/lisa-agy/skills/lisa-setup-session-manager/SKILL.md +156 -0
  130. package/plugins/lisa-agy/skills/lisa-tear-down-automations/SKILL.md +10 -0
  131. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  132. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  133. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  134. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  135. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  136. package/plugins/lisa-cdk-devin/.claude-plugin/plugin.json +1 -1
  137. package/plugins/lisa-cdk-devin/.devin-plugin/plugin.json +1 -1
  138. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  139. package/plugins/lisa-copilot/commands/lisa/implement.md +2 -2
  140. package/plugins/lisa-copilot/commands/lisa/session-manager.md +7 -0
  141. package/plugins/lisa-copilot/commands/lisa/setup/session-manager.md +6 -0
  142. package/plugins/lisa-copilot/rules/reference/automation-runbook-contract.md +14 -0
  143. package/plugins/lisa-copilot/rules/reference/config-resolution.md +58 -0
  144. package/plugins/lisa-copilot/scripts/automation-status-claude-adapter.mjs +4 -1
  145. package/plugins/lisa-copilot/scripts/automation-status-codex-adapter.mjs +4 -1
  146. package/plugins/lisa-copilot/scripts/automation-status-expected-fleet.mjs +98 -0
  147. package/plugins/lisa-copilot/scripts/automation-status-run-history.mjs +29 -7
  148. package/plugins/lisa-copilot/scripts/ready-queue-order.mjs +352 -0
  149. package/plugins/lisa-copilot/skills/lisa-automation-status/SKILL.md +10 -0
  150. package/plugins/lisa-copilot/skills/lisa-implement/SKILL.md +17 -2
  151. package/plugins/lisa-copilot/skills/lisa-secrets-access/scripts/validate-config.mjs +377 -5
  152. package/plugins/lisa-copilot/skills/lisa-session-manager/SKILL.md +285 -0
  153. package/plugins/lisa-copilot/skills/lisa-session-manager/references/runbook-template.md +66 -0
  154. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/capacity.mjs +186 -0
  155. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/cli-cycle.mjs +262 -0
  156. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/cli-manager.mjs +308 -0
  157. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/cli-queue.mjs +148 -0
  158. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/cli-runtime.mjs +326 -0
  159. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/cli-usage.mjs +114 -0
  160. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/cli-workers.mjs +295 -0
  161. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/config.mjs +265 -0
  162. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/isolation.mjs +130 -0
  163. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/launch.mjs +234 -0
  164. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/ledger.mjs +445 -0
  165. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/reconcile.mjs +134 -0
  166. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/session-manager.mjs +274 -0
  167. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/state-dir.mjs +112 -0
  168. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/telegram-route.mjs +210 -0
  169. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/token.mjs +191 -0
  170. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/worker-launch.mjs +92 -0
  171. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/workers.mjs +406 -0
  172. package/plugins/lisa-copilot/skills/lisa-setup-session-manager/SKILL.md +156 -0
  173. package/plugins/lisa-copilot/skills/lisa-tear-down-automations/SKILL.md +10 -0
  174. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  175. package/plugins/lisa-cursor/commands/lisa/implement.md +2 -2
  176. package/plugins/lisa-cursor/commands/lisa/session-manager.md +7 -0
  177. package/plugins/lisa-cursor/commands/lisa/setup/session-manager.md +6 -0
  178. package/plugins/lisa-cursor/rules/automation-runbook-contract-reference.mdc +14 -0
  179. package/plugins/lisa-cursor/rules/config-resolution-reference.mdc +58 -0
  180. package/plugins/lisa-cursor/scripts/automation-status-claude-adapter.mjs +4 -1
  181. package/plugins/lisa-cursor/scripts/automation-status-codex-adapter.mjs +4 -1
  182. package/plugins/lisa-cursor/scripts/automation-status-expected-fleet.mjs +98 -0
  183. package/plugins/lisa-cursor/scripts/automation-status-run-history.mjs +29 -7
  184. package/plugins/lisa-cursor/scripts/ready-queue-order.mjs +352 -0
  185. package/plugins/lisa-cursor/skills/lisa-automation-status/SKILL.md +10 -0
  186. package/plugins/lisa-cursor/skills/lisa-implement/SKILL.md +17 -2
  187. package/plugins/lisa-cursor/skills/lisa-secrets-access/scripts/validate-config.mjs +377 -5
  188. package/plugins/lisa-cursor/skills/lisa-session-manager/SKILL.md +285 -0
  189. package/plugins/lisa-cursor/skills/lisa-session-manager/references/runbook-template.md +66 -0
  190. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/capacity.mjs +186 -0
  191. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/cli-cycle.mjs +262 -0
  192. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/cli-manager.mjs +308 -0
  193. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/cli-queue.mjs +148 -0
  194. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/cli-runtime.mjs +326 -0
  195. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/cli-usage.mjs +114 -0
  196. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/cli-workers.mjs +295 -0
  197. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/config.mjs +265 -0
  198. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/isolation.mjs +130 -0
  199. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/launch.mjs +234 -0
  200. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/ledger.mjs +445 -0
  201. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/reconcile.mjs +134 -0
  202. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/session-manager.mjs +274 -0
  203. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/state-dir.mjs +112 -0
  204. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/telegram-route.mjs +210 -0
  205. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/token.mjs +191 -0
  206. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/worker-launch.mjs +92 -0
  207. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/workers.mjs +406 -0
  208. package/plugins/lisa-cursor/skills/lisa-setup-session-manager/SKILL.md +156 -0
  209. package/plugins/lisa-cursor/skills/lisa-tear-down-automations/SKILL.md +10 -0
  210. package/plugins/lisa-devin/.claude-plugin/plugin.json +1 -1
  211. package/plugins/lisa-devin/.devin-plugin/plugin.json +1 -1
  212. package/plugins/lisa-devin/rules/reference/automation-runbook-contract.md +14 -0
  213. package/plugins/lisa-devin/rules/reference/config-resolution.md +58 -0
  214. package/plugins/lisa-devin/scripts/automation-status-claude-adapter.mjs +4 -1
  215. package/plugins/lisa-devin/scripts/automation-status-codex-adapter.mjs +4 -1
  216. package/plugins/lisa-devin/scripts/automation-status-expected-fleet.mjs +98 -0
  217. package/plugins/lisa-devin/scripts/automation-status-run-history.mjs +29 -7
  218. package/plugins/lisa-devin/scripts/ready-queue-order.mjs +352 -0
  219. package/plugins/lisa-devin/skills/lisa-automation-status/SKILL.md +10 -0
  220. package/plugins/lisa-devin/skills/lisa-implement/SKILL.md +17 -2
  221. package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/validate-config.mjs +377 -5
  222. package/plugins/lisa-devin/skills/lisa-session-manager/SKILL.md +285 -0
  223. package/plugins/lisa-devin/skills/lisa-session-manager/references/runbook-template.md +66 -0
  224. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/capacity.mjs +186 -0
  225. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/cli-cycle.mjs +262 -0
  226. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/cli-manager.mjs +308 -0
  227. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/cli-queue.mjs +148 -0
  228. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/cli-runtime.mjs +326 -0
  229. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/cli-usage.mjs +114 -0
  230. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/cli-workers.mjs +295 -0
  231. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/config.mjs +265 -0
  232. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/isolation.mjs +130 -0
  233. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/launch.mjs +234 -0
  234. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/ledger.mjs +445 -0
  235. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/reconcile.mjs +134 -0
  236. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/session-manager.mjs +274 -0
  237. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/state-dir.mjs +112 -0
  238. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/telegram-route.mjs +210 -0
  239. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/token.mjs +191 -0
  240. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/worker-launch.mjs +92 -0
  241. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/workers.mjs +406 -0
  242. package/plugins/lisa-devin/skills/lisa-setup-session-manager/SKILL.md +156 -0
  243. package/plugins/lisa-devin/skills/lisa-tear-down-automations/SKILL.md +10 -0
  244. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  245. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  246. package/plugins/lisa-expo-agy/plugin.json +1 -1
  247. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  248. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  249. package/plugins/lisa-expo-devin/.claude-plugin/plugin.json +1 -1
  250. package/plugins/lisa-expo-devin/.devin-plugin/plugin.json +1 -1
  251. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  252. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  253. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  254. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  255. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  256. package/plugins/lisa-harper-fabric-devin/.claude-plugin/plugin.json +1 -1
  257. package/plugins/lisa-harper-fabric-devin/.devin-plugin/plugin.json +1 -1
  258. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  259. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  260. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  261. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  262. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  263. package/plugins/lisa-nestjs-devin/.claude-plugin/plugin.json +1 -1
  264. package/plugins/lisa-nestjs-devin/.devin-plugin/plugin.json +1 -1
  265. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  266. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  267. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  268. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  269. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  270. package/plugins/lisa-openclaw-devin/.claude-plugin/plugin.json +1 -1
  271. package/plugins/lisa-openclaw-devin/.devin-plugin/plugin.json +1 -1
  272. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  273. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  274. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  275. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  276. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  277. package/plugins/lisa-phaser-devin/.claude-plugin/plugin.json +1 -1
  278. package/plugins/lisa-phaser-devin/.devin-plugin/plugin.json +1 -1
  279. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  280. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  281. package/plugins/lisa-rails-agy/plugin.json +1 -1
  282. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  283. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  284. package/plugins/lisa-rails-devin/.claude-plugin/plugin.json +1 -1
  285. package/plugins/lisa-rails-devin/.devin-plugin/plugin.json +1 -1
  286. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  287. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  288. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  289. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  290. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  291. package/plugins/lisa-typescript-devin/.claude-plugin/plugin.json +1 -1
  292. package/plugins/lisa-typescript-devin/.devin-plugin/plugin.json +1 -1
  293. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  294. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  295. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  296. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  297. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  298. package/plugins/lisa-wiki-devin/.claude-plugin/plugin.json +1 -1
  299. package/plugins/lisa-wiki-devin/.devin-plugin/plugin.json +1 -1
  300. package/plugins/src/base/commands/implement.md +2 -2
  301. package/plugins/src/base/commands/session-manager.md +7 -0
  302. package/plugins/src/base/commands/setup/session-manager.md +6 -0
  303. package/plugins/src/base/rules/reference/automation-runbook-contract.md +14 -0
  304. package/plugins/src/base/rules/reference/config-resolution.md +58 -0
  305. package/plugins/src/base/scripts/automation-status-claude-adapter.mjs +4 -1
  306. package/plugins/src/base/scripts/automation-status-codex-adapter.mjs +4 -1
  307. package/plugins/src/base/scripts/automation-status-expected-fleet.mjs +98 -0
  308. package/plugins/src/base/scripts/automation-status-run-history.mjs +29 -7
  309. package/plugins/src/base/scripts/ready-queue-order.mjs +352 -0
  310. package/plugins/src/base/skills/lisa-automation-status/SKILL.md +10 -0
  311. package/plugins/src/base/skills/lisa-implement/SKILL.md +17 -2
  312. package/plugins/src/base/skills/lisa-secrets-access/scripts/validate-config.mjs +377 -5
  313. package/plugins/src/base/skills/lisa-session-manager/SKILL.md +285 -0
  314. package/plugins/src/base/skills/lisa-session-manager/references/runbook-template.md +66 -0
  315. package/plugins/src/base/skills/lisa-session-manager/scripts/capacity.mjs +186 -0
  316. package/plugins/src/base/skills/lisa-session-manager/scripts/cli-cycle.mjs +262 -0
  317. package/plugins/src/base/skills/lisa-session-manager/scripts/cli-manager.mjs +308 -0
  318. package/plugins/src/base/skills/lisa-session-manager/scripts/cli-queue.mjs +148 -0
  319. package/plugins/src/base/skills/lisa-session-manager/scripts/cli-runtime.mjs +326 -0
  320. package/plugins/src/base/skills/lisa-session-manager/scripts/cli-usage.mjs +114 -0
  321. package/plugins/src/base/skills/lisa-session-manager/scripts/cli-workers.mjs +295 -0
  322. package/plugins/src/base/skills/lisa-session-manager/scripts/config.mjs +265 -0
  323. package/plugins/src/base/skills/lisa-session-manager/scripts/isolation.mjs +130 -0
  324. package/plugins/src/base/skills/lisa-session-manager/scripts/launch.mjs +234 -0
  325. package/plugins/src/base/skills/lisa-session-manager/scripts/ledger.mjs +445 -0
  326. package/plugins/src/base/skills/lisa-session-manager/scripts/reconcile.mjs +134 -0
  327. package/plugins/src/base/skills/lisa-session-manager/scripts/session-manager.mjs +274 -0
  328. package/plugins/src/base/skills/lisa-session-manager/scripts/state-dir.mjs +112 -0
  329. package/plugins/src/base/skills/lisa-session-manager/scripts/telegram-route.mjs +210 -0
  330. package/plugins/src/base/skills/lisa-session-manager/scripts/token.mjs +191 -0
  331. package/plugins/src/base/skills/lisa-session-manager/scripts/worker-launch.mjs +92 -0
  332. package/plugins/src/base/skills/lisa-session-manager/scripts/workers.mjs +406 -0
  333. package/plugins/src/base/skills/lisa-setup-session-manager/SKILL.md +156 -0
  334. package/plugins/src/base/skills/lisa-tear-down-automations/SKILL.md +10 -0
@@ -0,0 +1,406 @@
1
+ /**
2
+ * Worker bookkeeping for the session manager: names, live detection, spawn
3
+ * argv and stall classification.
4
+ *
5
+ * A worker is a background Claude Code session (`claude --bg`) running
6
+ * `/lisa:implement <REF> managedBy=<manager>` for one work item. The manager
7
+ * never keeps a handle on a worker; it rediscovers every worker each cycle
8
+ * from `claude agents --json` by name. So the name is the join key between the
9
+ * tracker item, the ledger row and the live session, and everything here is
10
+ * about keeping that join exact.
11
+ *
12
+ * Every export is pure. `session-manager.mjs` owns the real `process.env`,
13
+ * `child_process` and clock, and passes them in.
14
+ * @module workers
15
+ */
16
+
17
+ /** Settings blob every worker gets, so the manager's messages reach it. */
18
+ export const WORKER_SETTINGS = JSON.stringify({
19
+ crossSessionInbound: "accept",
20
+ });
21
+
22
+ /**
23
+ * Stall policy used when the caller passes none. Mirrors the
24
+ * `sessionManager.stall` defaults, so a missing config block still classifies.
25
+ */
26
+ export const DEFAULT_STALL = Object.freeze({
27
+ noOutputMinutes: 60,
28
+ requestionHours: 4,
29
+ maxAttempts: 3,
30
+ });
31
+
32
+ /** Every worker session name starts with this. Anything else is not ours. */
33
+ const WORKER_PREFIX = "wk-";
34
+
35
+ /**
36
+ * `wk-<token>-<MMDD>-<HHMM>[-<n>]`, read from the right. The token is greedy,
37
+ * so it is everything before the LAST stamp group: a ref whose number has four
38
+ * or more digits (`PROJ-1234`) or that itself ends in `-dddd-dddd` keeps its
39
+ * whole token. A lazy token read `wk-PROJ-1234-1012-1530` as `PROJ`, and the
40
+ * live-worker guard never fired. The collision suffix is capped at three
41
+ * digits so it can never be mistaken for the `HHMM` half of a stamp. The name
42
+ * is anchored so a token is compared exactly — never by `startsWith`, which
43
+ * would let an `ABC-12` worker answer for `ABC-1`.
44
+ */
45
+ const WORKER_NAME_PATTERN = /^wk-(.+)-(\d{4}-\d{4})(?:-([1-9]\d{0,2}))?$/;
46
+
47
+ /**
48
+ * `claude agents --json --all` states a finished row carries. Never enough on
49
+ * its own: an idle worker whose turn ended is alive but also reads `done`.
50
+ */
51
+ const TERMINAL_AGENT_STATES = new Set(["done", "stopped"]);
52
+
53
+ /** Ledger statuses that mean the worker reported its own outcome. */
54
+ const FINISHED_STATUSES = new Set(["DONE", "FAILED"]);
55
+
56
+ /** The `managedBy=` value contract `lisa-implement` enforces. */
57
+ const MANAGER_NAME_PATTERN = /^[A-Za-z0-9._-]{1,64}$/;
58
+
59
+ /** A full session UUID, which `--resume` accepts directly. */
60
+ const SESSION_UUID_PATTERN =
61
+ /\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/i;
62
+
63
+ /** The short id `claude --bg` prints and `claude agents` lists. */
64
+ const SHORT_ID_PATTERN = /\b[0-9a-f]{8}\b/i;
65
+
66
+ const MINUTE_MS = 60_000;
67
+ const HOUR_MS = 60 * MINUTE_MS;
68
+
69
+ /**
70
+ * Reduce a work-item ref to the `[A-Za-z0-9-]` token used in worker names.
71
+ *
72
+ * A GitHub ref `owner/repo#12` becomes `repo-12`: the owner adds nothing
73
+ * inside one project and `/` and `#` are not safe in a session name. Jira and
74
+ * Linear keys already fit and pass through unchanged.
75
+ * @param {string} ref - Tracker ref as the queue reported it
76
+ * @returns {string} Name-safe token
77
+ */
78
+ export function sanitizeRefToken(ref) {
79
+ if (typeof ref !== "string") {
80
+ throw new TypeError(`ref must be a string, got ${typeof ref}`);
81
+ }
82
+ const github = /^(?:[^/\s]+\/)?([^/#\s]*)#(\d+)$/.exec(ref.trim());
83
+ const raw = github ? [github[1], github[2]].filter(Boolean).join("-") : ref;
84
+ const token = raw
85
+ .replace(/[^A-Za-z0-9-]+/g, "-")
86
+ .replace(/-{2,}/g, "-")
87
+ .replace(/^-|-$/g, "");
88
+ if (token === "") {
89
+ throw new Error(`ref ${JSON.stringify(ref)} yields an empty worker token`);
90
+ }
91
+ return token;
92
+ }
93
+
94
+ /**
95
+ * Format a clock reading as local `MMDD-HHMM`.
96
+ * @param {Date | number} now - Clock reading
97
+ * @returns {string} Stamp
98
+ */
99
+ function formatStamp(now) {
100
+ const date = now instanceof Date ? now : new Date(now);
101
+ const pad = value => String(value).padStart(2, "0");
102
+ return `${pad(date.getMonth() + 1)}${pad(date.getDate())}-${pad(date.getHours())}${pad(date.getMinutes())}`;
103
+ }
104
+
105
+ /**
106
+ * Name a new worker for `ref`, unique against every name already known.
107
+ *
108
+ * A retry in the same minute would otherwise reuse the name of the worker it
109
+ * replaces, and `claude agents` could no longer tell them apart, so a
110
+ * collision gets `-2`, `-3`, ….
111
+ * @param {string} ref - Tracker ref
112
+ * @param {Date | number} now - Clock reading
113
+ * @param {Iterable<string>} [existingNames] - Every session name in use or on record
114
+ * @returns {string} Worker session name
115
+ */
116
+ export function buildWorkerName(ref, now, existingNames = []) {
117
+ const known = new Set(existingNames);
118
+ const base = `${WORKER_PREFIX}${sanitizeRefToken(ref)}-${formatStamp(now)}`;
119
+ if (!known.has(base)) return base;
120
+ const suffix = Array.from(
121
+ { length: known.size + 1 },
122
+ (_, index) => index + 2
123
+ ).find(candidate => !known.has(`${base}-${candidate}`));
124
+ return `${base}-${suffix}`;
125
+ }
126
+
127
+ /**
128
+ * Split a worker session name into its parts.
129
+ * @param {string} name - Session name
130
+ * @returns {{token: string, stamp: string, suffix: number | null} | null} Parts, or null when the name is not a worker's
131
+ */
132
+ export function parseWorkerName(name) {
133
+ const match =
134
+ typeof name === "string" ? WORKER_NAME_PATTERN.exec(name) : null;
135
+ if (!match) return null;
136
+ return {
137
+ token: match[1],
138
+ stamp: match[2],
139
+ suffix: match[3] === undefined ? null : Number(match[3]),
140
+ };
141
+ }
142
+
143
+ /**
144
+ * Read a value only when it is a string.
145
+ * @param {unknown} value - Candidate
146
+ * @returns {string | null} The string, or null
147
+ */
148
+ function stringOrNull(value) {
149
+ return typeof value === "string" ? value : null;
150
+ }
151
+
152
+ /**
153
+ * Normalize `claude agents --json` output (with or without `--all`).
154
+ *
155
+ * The shapes differ: an active row carries `{pid,status}`; a completed row
156
+ * from `--all` carries `{id,state}` with `state` of `done` or `stopped` and no
157
+ * `pid` or `status`. Claude Code 2.1.296 also prints hybrids: an idle worker
158
+ * whose turn ended is `{pid,status:"idle",state:"done"}` while its process is
159
+ * alive, a worker waiting on a question is `state:"blocked"`, and a worker
160
+ * that has just been spawned is `{pid:null,status:null,state:"working"}`. So a
161
+ * row is alive when it has a pid or a status (the active shape) whatever its
162
+ * `state`, or when its state is not terminal; only a row with neither, in a
163
+ * terminal state, has finished. Reading `state` alone undercounted capacity,
164
+ * let `spawn` duplicate a live worker and made `classify` say `dead`.
165
+ * Every row comes back with all fields present (null when absent) and an
166
+ * `active` flag, so callers never branch on shape.
167
+ * @param {unknown} parsed - `JSON.parse` of the command's stdout
168
+ * @returns {Array<{name: string|null, sessionId: string|null, id: string|null, pid: number|null, cwd: string|null, kind: string|null, startedAt: number|null, status: string|null, state: string|null, active: boolean}>} Rows
169
+ */
170
+ export function normalizeAgents(parsed) {
171
+ if (!Array.isArray(parsed)) {
172
+ throw new TypeError("claude agents --json must return an array");
173
+ }
174
+ return parsed
175
+ .filter(row => row !== null && typeof row === "object")
176
+ .map(row => {
177
+ const state = stringOrNull(row.state);
178
+ const pid = typeof row.pid === "number" ? row.pid : null;
179
+ const status = stringOrNull(row.status);
180
+ const activeShape = pid !== null || status !== null;
181
+ return {
182
+ name: stringOrNull(row.name),
183
+ sessionId: stringOrNull(row.sessionId),
184
+ id: stringOrNull(row.id),
185
+ pid,
186
+ cwd: stringOrNull(row.cwd),
187
+ kind: stringOrNull(row.kind),
188
+ startedAt: typeof row.startedAt === "number" ? row.startedAt : null,
189
+ status,
190
+ state,
191
+ active:
192
+ activeShape || state === null || !TERMINAL_AGENT_STATES.has(state),
193
+ };
194
+ });
195
+ }
196
+
197
+ /**
198
+ * Whether a normalized row is a running worker.
199
+ * @param {{active: boolean, name: string|null}} agent - Normalized row
200
+ * @returns {boolean} True for an active `wk-` session
201
+ */
202
+ function isRunningWorker(agent) {
203
+ return agent.active && parseWorkerName(agent.name) !== null;
204
+ }
205
+
206
+ /**
207
+ * Count running workers, the `running` input to capacity.
208
+ * @param {ReturnType<typeof normalizeAgents>} agents - Normalized rows
209
+ * @returns {number} Active `wk-` sessions
210
+ */
211
+ export function countRunningWorkers(agents) {
212
+ return agents.filter(isRunningWorker).length;
213
+ }
214
+
215
+ /**
216
+ * Find the running worker for `ref`, by exact token.
217
+ * @param {ReturnType<typeof normalizeAgents>} agents - Normalized rows
218
+ * @param {string} ref - Tracker ref
219
+ * @returns {ReturnType<typeof normalizeAgents>[number] | null} The row, or null
220
+ */
221
+ export function findLiveWorker(agents, ref) {
222
+ const token = sanitizeRefToken(ref);
223
+ return (
224
+ agents.find(
225
+ agent =>
226
+ isRunningWorker(agent) && parseWorkerName(agent.name)?.token === token
227
+ ) ?? null
228
+ );
229
+ }
230
+
231
+ /**
232
+ * Copy an environment without any `TELEGRAM_*` key.
233
+ *
234
+ * The manager runs with `TELEGRAM_STATE_DIR` (and possibly
235
+ * `TELEGRAM_BOT_TOKEN`) set. A worker that inherited either could start a
236
+ * second poller on the same bot and take the manager's messages, so every
237
+ * `TELEGRAM_*` key goes — a superset of the two that matter today.
238
+ * @param {Record<string, string | undefined>} env - Source environment
239
+ * @returns {Record<string, string | undefined>} New environment
240
+ */
241
+ export function scrubWorkerEnv(env) {
242
+ return Object.fromEntries(
243
+ Object.entries(env).filter(([key]) => !key.startsWith("TELEGRAM_"))
244
+ );
245
+ }
246
+
247
+ /**
248
+ * Throw unless `value` is a non-empty string.
249
+ * @param {string} label - Field name for the message
250
+ * @param {unknown} value - Candidate
251
+ */
252
+ function requireText(label, value) {
253
+ if (typeof value !== "string" || value.trim() === "") {
254
+ throw new Error(`${label} must be a non-empty string`);
255
+ }
256
+ }
257
+
258
+ /**
259
+ * Build the spawn for a new worker. Passed as argv to `spawnSync`, never a
260
+ * shell string, so no ref or name is ever interpreted by a shell.
261
+ *
262
+ * The prompt is exactly `/lisa:implement <REF> managedBy=<manager>`: any
263
+ * trailing prose would make `lisa-track` classify the arguments as free text.
264
+ * @param {{ref: string, name: string, manager: string, repoDir: string, env: Record<string, string | undefined>}} input - Spawn inputs
265
+ * @returns {{command: string, args: string[], cwd: string, env: Record<string, string | undefined>}} Spawn spec
266
+ */
267
+ export function buildWorkerSpawn({ ref, name, manager, repoDir, env }) {
268
+ requireText("ref", ref);
269
+ if (/\s/.test(ref)) {
270
+ throw new Error(`ref ${JSON.stringify(ref)} must not contain whitespace`);
271
+ }
272
+ if (typeof manager !== "string" || !MANAGER_NAME_PATTERN.test(manager)) {
273
+ throw new Error(
274
+ `manager ${JSON.stringify(manager)} must match ${MANAGER_NAME_PATTERN}`
275
+ );
276
+ }
277
+ if (parseWorkerName(name) === null) {
278
+ throw new Error(`name ${JSON.stringify(name)} is not a worker name`);
279
+ }
280
+ requireText("repoDir", repoDir);
281
+ return {
282
+ command: "claude",
283
+ args: [
284
+ "--bg",
285
+ "-n",
286
+ name,
287
+ "--dangerously-skip-permissions",
288
+ "--settings",
289
+ WORKER_SETTINGS,
290
+ `/lisa:implement ${ref} managedBy=${manager}`,
291
+ ],
292
+ cwd: repoDir,
293
+ env: scrubWorkerEnv(env),
294
+ };
295
+ }
296
+
297
+ /**
298
+ * Build the spawn that resumes a worker with one message (an answer, or a
299
+ * nudge after a stall), with the same cwd and environment scrub as a spawn.
300
+ * @param {{sessionId: string, text: string, repoDir: string, env: Record<string, string | undefined>}} input - Resume inputs
301
+ * @returns {{command: string, args: string[], cwd: string, env: Record<string, string | undefined>}} Spawn spec
302
+ */
303
+ export function buildWorkerResume({ sessionId, text, repoDir, env }) {
304
+ requireText("sessionId", sessionId);
305
+ if (sessionId.startsWith("-")) {
306
+ throw new Error(
307
+ `sessionId ${JSON.stringify(sessionId)} must not look like a flag`
308
+ );
309
+ }
310
+ requireText("text", text);
311
+ requireText("repoDir", repoDir);
312
+ return {
313
+ command: "claude",
314
+ // `--` ends option parsing: an answer that starts with `--` (claude
315
+ // 2.1.296 reads `--x` there as an unknown option) stays message text.
316
+ args: ["--bg", "--resume", sessionId, "--", text],
317
+ cwd: repoDir,
318
+ env: scrubWorkerEnv(env),
319
+ };
320
+ }
321
+
322
+ /**
323
+ * Pull the session id out of `claude --bg` stdout. A full UUID wins; else the
324
+ * short id `claude --bg` prints. The manager can always map either back to
325
+ * the full `sessionId` through `claude agents --json` by worker name.
326
+ * @param {string} stdout - Command output
327
+ * @returns {string | null} Session id, or null
328
+ */
329
+ export function parseSessionId(stdout) {
330
+ const text = typeof stdout === "string" ? stdout : "";
331
+ return (
332
+ SESSION_UUID_PATTERN.exec(text)?.[0] ??
333
+ SHORT_ID_PATTERN.exec(text)?.[0] ??
334
+ null
335
+ );
336
+ }
337
+
338
+ /**
339
+ * Read a timestamp that may be an ISO string, epoch milliseconds or a Date.
340
+ * @param {unknown} value - Candidate
341
+ * @returns {number | null} Epoch milliseconds, or null
342
+ */
343
+ function toMillis(value) {
344
+ if (value instanceof Date) return value.getTime();
345
+ if (typeof value === "number") return value;
346
+ if (typeof value === "string") {
347
+ const parsed = Date.parse(value);
348
+ return Number.isNaN(parsed) ? null : parsed;
349
+ }
350
+ return null;
351
+ }
352
+
353
+ /**
354
+ * Classify one dispatched item for this cycle.
355
+ *
356
+ * Order matters: a recorded DONE/FAILED wins; a pending question means the
357
+ * worker ended its turn on purpose, so it is `waiting` even when its row
358
+ * reads `done`; only then is liveness judged. `stalled` and `dead` become
359
+ * `exhausted` at `maxAttempts`, which is the manager's cue to move the item to
360
+ * Blocked instead of retrying it again.
361
+ * @param {{agent: ReturnType<typeof normalizeAgents>[number] | null, entry: {status?: string, startedAt?: string|number, lastProgressAt?: string|number|null, logsHash?: string|null, pendingQuestion?: {askedAt?: string|number, lastPingAt?: string|number|null} | null, attempts?: number}, logsHash?: string | null | undefined, now: Date | number, stall?: {noOutputMinutes: number, requestionHours: number, maxAttempts: number}}} input - Classification inputs
362
+ * @returns {"finished"|"waiting"|"requestion"|"working"|"stalled"|"dead"|"exhausted"} Classification
363
+ */
364
+ export function classifyWorker({
365
+ agent,
366
+ entry,
367
+ logsHash,
368
+ now,
369
+ stall = DEFAULT_STALL,
370
+ }) {
371
+ if (FINISHED_STATUSES.has(entry.status ?? "")) return "finished";
372
+ const nowMs = toMillis(now) ?? 0;
373
+ const question = entry.pendingQuestion;
374
+ if (question) {
375
+ const lastPing =
376
+ toMillis(question.lastPingAt) ?? toMillis(question.askedAt) ?? nowMs;
377
+ return nowMs - lastPing > stall.requestionHours * HOUR_MS
378
+ ? "requestion"
379
+ : "waiting";
380
+ }
381
+ const outcome = agent?.active
382
+ ? judgeActive(entry, logsHash, nowMs, stall)
383
+ : "dead";
384
+ if (outcome !== "working" && (entry.attempts ?? 0) >= stall.maxAttempts) {
385
+ return "exhausted";
386
+ }
387
+ return outcome;
388
+ }
389
+
390
+ /**
391
+ * Decide whether an active worker is making progress.
392
+ * @param {{logsHash?: string|null, lastProgressAt?: string|number|null, startedAt?: string|number}} entry - Ledger row
393
+ * @param {string | null | undefined} logsHash - This cycle's hash of `claude logs <name>`
394
+ * @param {number} nowMs - Clock reading
395
+ * @param {{noOutputMinutes: number}} stall - Stall policy
396
+ * @returns {"working"|"stalled"} Classification
397
+ */
398
+ function judgeActive(entry, logsHash, nowMs, stall) {
399
+ if (typeof logsHash === "string" && logsHash !== entry.logsHash)
400
+ return "working";
401
+ const lastProgress =
402
+ toMillis(entry.lastProgressAt) ?? toMillis(entry.startedAt) ?? nowMs;
403
+ return nowMs - lastProgress <= stall.noOutputMinutes * MINUTE_MS
404
+ ? "working"
405
+ : "stalled";
406
+ }
@@ -0,0 +1,156 @@
1
+ ---
2
+ name: lisa-setup-session-manager
3
+ description: "Set up the local session manager for this project: writes the non-secret `sessionManager` block to `.lisa.config.json` (detecting a multi-repo `projects/*` layout), stores the project's own Telegram bot token outside the repo, checks the Telegram plugin is installed but not enabled at user scope, keeps the manager's state out of git, seeds the checked-in runbook, starts the manager in tmux, walks the operator through pairing, and finishes with doctor's session-manager check. Idempotent."
4
+ allowed-tools: ["Bash", "Read", "Write", "Skill", "AskUserQuestion"]
5
+ ---
6
+
7
+ # Setup session manager
8
+
9
+ After this skill the project has a `sessionManager` block, a bot token in its own state directory, a
10
+ runbook at `.lisa/automations/session-manager.runbook.md`, and a running manager paired with the
11
+ operator's Telegram chat. Re-running is safe: every step keeps what is already there.
12
+
13
+ The manager itself always runs on Claude Code (see `lisa-session-manager` "Runtime parity"). Setup
14
+ can run from any agent that can reach the scripts; `start` launches the Claude Code manager.
15
+
16
+ ## Step 0: Preconditions
17
+
18
+ Stop with the named gap if any of these fail:
19
+
20
+ - **Tracker configured.** `.tracker` in `.lisa.config.json` is `github`, `jira` or `linear`.
21
+ Otherwise stop: "No tracker configured. Run the matching /lisa:setup:<tracker> first."
22
+ - **Tools.** `claude --version` is at least 2.1.224; `tmux -V` and `bun --version` succeed. Name the
23
+ missing or outdated tool and stop.
24
+
25
+ ## Step 1: Locate the scripts
26
+
27
+ Resolve the scripts directory with the same ladder as `lisa-session-manager`:
28
+
29
+ ```bash
30
+ SM="${SM_SCRIPTS_DIR:-}"
31
+ [ -z "$SM" ] && [ -n "${CLAUDE_PLUGIN_ROOT:-}" ] && SM="$CLAUDE_PLUGIN_ROOT/skills/lisa-session-manager/scripts"
32
+ [ -n "$SM" ] && [ -f "$SM/session-manager.mjs" ] || SM="$(claude plugin list --json 2>/dev/null | node -e 'let s="";process.stdin.on("data",d=>{s+=d}).on("end",()=>{let l=[];try{l=JSON.parse(s)}catch{}const c=l.filter(p=>String(p.id).startsWith("lisa@"));const p=c.find(p=>p.projectPath===process.cwd())||c.find(p=>p.scope==="user");process.stdout.write(p?p.installPath:"")})')/skills/lisa-session-manager/scripts"
33
+ [ -f "$SM/session-manager.mjs" ] || SM="$PWD/node_modules/@codyswann/lisa/plugins/lisa/skills/lisa-session-manager/scripts"
34
+ [ -f "$SM/session-manager.mjs" ] || { echo "lisa-session-manager scripts not found" >&2; exit 1; }
35
+ echo "$SM"
36
+ ```
37
+
38
+ Shell variables do not survive between Bash calls: use the printed absolute path wherever this skill
39
+ writes `$SM`, and pass `--project-root "$ROOT"` (the absolute project root) on every call.
40
+
41
+ ## Step 2: Write the config block
42
+
43
+ 1. Preview: `node "$SM/session-manager.mjs" init-config --project-root "$ROOT"`. It detects
44
+ `projects/*/.lisa.config.json` and proposes `name`, `interval`, `repos`, `capacity`, `stall` and a
45
+ per-project `notify.stateDir`. Show the block to the operator.
46
+ 2. Write it: the same command with `--write`. It adds only non-secret fields and never overwrites an
47
+ existing block (`reason: "exists"` means keep it).
48
+ 3. Ask the operator to replace each repo's starter `hints` with the technologies and areas that
49
+ identify it (e.g. `api`: `["NestJS","migrations"]`, `web`: `["Expo","screens"]`), and whether to
50
+ set `sessionManager.trustedAuthorIds`. Without it, any author's Ready item reaches a
51
+ bypass-permissions worker; say so plainly. The list holds stable tracker user ids as strings,
52
+ never logins: the GitHub numeric user id (`gh api users/<login> --jq .id`), the Jira
53
+ `accountId`, or the Linear user id. A login matches no one and silently excludes every item.
54
+ 4. `node "$SM/session-manager.mjs" validate --project-root "$ROOT"` must print `valid: true`.
55
+
56
+ ## Step 3: Store the bot token
57
+
58
+ The operator creates a bot with @BotFather, one per project. Then run
59
+ `node "$SM/session-manager.mjs" store-token --project-root "$ROOT"`.
60
+
61
+ - `stored: true`: done.
62
+ - Exit 2 because a token already exists: keep it (re-running setup is safe). Only when the operator
63
+ says the stored token is wrong or belongs to another project, re-run with `store-token --replace`.
64
+ - `reason: "no-tty"` (an agent's Bash has no terminal): print `command` from the output and ask the
65
+ operator to run it in their own terminal, where it prompts with echo off. Wait for them to confirm.
66
+ - `empty` / `invalid`: say what was wrong and ask again.
67
+
68
+ Never ask for the token in chat, never echo, log or commit it, and never put it in
69
+ `.lisa.config.json`. It lives only in `<notify.stateDir>/.env`.
70
+
71
+ ## Step 4: Telegram plugin scope
72
+
73
+ Read `claude plugin list --json` and look at the `telegram@claude-plugins-official` entries.
74
+
75
+ - **Not installed:** ask the operator to install it with
76
+ `claude plugin install telegram@claude-plugins-official -s user`, then re-check.
77
+ - **Enabled at user scope** (`scope: "user"` and `enabled: true`): every session on this machine
78
+ would start its own poller and take the bot away from the manager. Print the remedy and stop until
79
+ it is fixed:
80
+
81
+ ```bash
82
+ claude plugin disable telegram@claude-plugins-official -s user
83
+ ```
84
+
85
+ - **Installed and not enabled at user scope:** correct. The manager enables it for itself only.
86
+
87
+ ## Step 5: Keep manager state out of git
88
+
89
+ At the project root, when it is a git repo:
90
+ `git check-ignore -q .lisa/session-manager/ledger.json || printf '%s\n' '.lisa/session-manager/' >> "$(git rev-parse --git-common-dir)/info/exclude"`,
91
+ then re-run `git check-ignore -q .lisa/session-manager/ledger.json`. If it is still not ignored, stop
92
+ and report. A root that is not a git repo needs nothing.
93
+
94
+ ## Step 6: Seed the runbook
95
+
96
+ If `.lisa/automations/session-manager.runbook.md` does not exist, copy
97
+ `$SM/../references/runbook-template.md` there. Never overwrite an existing runbook: it is the
98
+ project's. It is checked in, like every automation runbook (`automation-runbook-contract`).
99
+
100
+ ## Step 7: Coexistence warning
101
+
102
+ Tell the operator, before starting: if this project also runs the scheduled `intake-repair` loop, it
103
+ can re-dispatch an item a local worker is still building (it treats a claimed item with no tracker
104
+ activity for `intake.repair.staleAfterHours` as stalled). `intake-tickets` competes for the same
105
+ Ready items. Recommend tearing down `intake-tickets` (`/lisa:tear-down-automations intake-tickets`)
106
+ and either raising `intake.repair.staleAfterHours` above `stall.noOutputMinutes × stall.maxAttempts`
107
+ or tearing down `intake-repair`.
108
+
109
+ ## Step 8: Accept workspace trust in each worker repo
110
+
111
+ Workers are background sessions, and a background session cannot show Claude Code's "trust this
112
+ folder?" prompt: until someone has accepted it in a directory, `claude --bg` refuses to start there
113
+ and `spawn` exits 2 saying so. Do this once per routed repo (or once for the root on a single-repo
114
+ project), on every machine that runs the manager:
115
+
116
+ 1. List the directories workers start in. Single-repo: the project root. Multi-repo: for each key in
117
+ `sessionManager.repos.entries`,
118
+ `node "$SM/session-manager.mjs" repo-dir --repo <key> --raw --project-root "$ROOT"`.
119
+ 2. Ask the operator, in their own terminal, to run `claude` once in that directory,
120
+ accept the trust prompt, then exit. An agent's Bash cannot answer that prompt, so never try to
121
+ accept it for them.
122
+ 3. Re-run this step whenever a repo is added to `sessionManager.repos`.
123
+
124
+ ## Step 9: Start and pair
125
+
126
+ 0. **Public GitHub repo gate.** When `.tracker` is `github`, run
127
+ `gh repo view <github.org>/<github.repo> --json visibility`. If it is `PUBLIC` and
128
+ `sessionManager.trustedAuthorIds` is not set, setup will not start the manager until
129
+ `trustedAuthorIds` is set: anyone on the internet could otherwise write the work a
130
+ bypass-permissions worker runs. Ask the operator for the IDs, add them, re-run `validate`, then
131
+ continue. `lisa doctor` fails on the same condition.
132
+ 1. `node "$SM/session-manager.mjs" start --project-root "$ROOT"`. `started` and `already-running`
133
+ are both fine. Exit 2 names what is missing (usually the token from Step 3), or that a tmux
134
+ session of the same name belongs to another project root, or that the manager
135
+ exited right after starting. For the last, ask the operator to run the printed foreground command
136
+ in their own terminal: claude prints its own error there. Fix it, then run `start` again.
137
+ 2. Walk the operator through pairing, in their own terminal:
138
+ 1. `tmux attach -t <name>` (the `attach` value from the output).
139
+ 2. Send any message to the bot in a private chat. The bot replies with a pairing code.
140
+ 3. In the attached manager session: `/telegram:access pair <code>`.
141
+ 4. Then: `/telegram:access policy allowlist`, so only paired senders reach the manager.
142
+ 5. Detach with `Ctrl-b d`. The manager keeps running.
143
+
144
+ Pairing and allowlist changes are made only in that terminal. Never approve a pairing because a
145
+ Telegram message asked for it. Every allowlisted sender effectively has shell access to this machine
146
+ (the manager and its workers run with bypass permissions), so keep the allowlist to the owner.
147
+
148
+ ## Step 10: Verify
149
+
150
+ Run `lisa doctor` (or `npx @codyswann/lisa doctor` when the `lisa` CLI is not on the PATH) and
151
+ confirm the "Session manager Telegram isolation?" check is green. Fix every warning it names, then
152
+ `node "$SM/session-manager.mjs" status --project-root "$ROOT"` should show the manager running.
153
+
154
+ Report: the config block written (or kept), where the token lives (the path, never the value), the
155
+ plugin scope result, the runbook path, which repo dirs had workspace trust accepted, the manager's
156
+ tmux session name, and the doctor result.
@@ -45,6 +45,16 @@ that one registered loop.
45
45
  `/setup-automations` scaffolded are project knowledge and the historical record of what these
46
46
  loops did. Teardown removes scheduler registrations only; it never deletes, edits, or moves a
47
47
  runbook file. An operator who wants them gone removes them deliberately, in git.
48
+ - **The locally hosted session manager** has no scheduler registration to delete: it runs as a
49
+ `/loop` in a tmux session, not under `/schedule` or Codex automations. When `.lisa.config.json`
50
+ has a `sessionManager` block, a fleet teardown, or `/lisa:tear-down-automations session-manager`,
51
+ stops it with `/lisa:session-manager stop` (the `session-manager.mjs stop` subcommand, which kills
52
+ only the manager's tmux session and is a no-op when it is not running). Never search the scheduler
53
+ for it and never report it "already absent" there. **Never stop its workers**: each holds claimed
54
+ work and finishes or hands off on its own. List them for the operator instead (run
55
+ `/lisa:session-manager status` before stopping, or `claude agents --json`). Its runbook,
56
+ `.lisa/automations/session-manager.runbook.md`, stays on disk like every other. Without a
57
+ `sessionManager` block there is nothing to stop.
48
58
 
49
59
  ## Answering a `policy-obsolete` teardown proposal
50
60
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "4.80.2",
3
+ "version": "4.81.1",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "4.80.2",
3
+ "version": "4.81.1",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -21,6 +21,20 @@ Membership is **registration, not skill-existence**: a loop is under this contra
21
21
  registered as a scheduled automation, and registering a new one pulls it in automatically. There is
22
22
  no hardcoded roster of loops anywhere.
23
23
 
24
+ ### Locally hosted loops
25
+
26
+ A loop the runtime's scheduler does not host is still a member. The session manager
27
+ (`lisa-session-manager`) is the case: its registration is the tmux session
28
+ `/lisa:setup:session-manager` starts, running a `/loop`, not a `/schedule` routine or a Codex
29
+ automation. It is a member exactly when `.lisa.config.json` has a `sessionManager` block. It keeps
30
+ the same obligations as a scheduled loop: a checked-in runbook at
31
+ `.lisa/automations/session-manager.runbook.md`, one of the six outcomes per cycle, and a run record
32
+ written through `automation-run-record.mjs` under loop id `session-manager`. Only the scheduler-facing
33
+ surfaces differ. `lisa-automation-status` lists it `UNSUPPORTED`, with a reason naming the tmux
34
+ session, because no scheduler can see it, and still shows its runbook and recorded cycles.
35
+ `lisa-tear-down-automations` stops the tmux session instead of deleting a scheduler entry, never
36
+ stops its workers, and leaves the runbook.
37
+
24
38
  ### Interactive flows are members too
25
39
 
26
40
  The outcome vocabulary is **not cron-specific** — it answers "did this need me?", which an operator