@codyswann/lisa 4.84.11 → 4.86.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (322) hide show
  1. package/dist/cli/doctor-session-manager-pending.d.ts +17 -0
  2. package/dist/cli/doctor-session-manager-pending.d.ts.map +1 -0
  3. package/dist/cli/doctor-session-manager-pending.js +130 -0
  4. package/dist/cli/doctor-session-manager-pending.js.map +1 -0
  5. package/dist/cli/doctor-session-manager-token.d.ts +69 -0
  6. package/dist/cli/doctor-session-manager-token.d.ts.map +1 -0
  7. package/dist/cli/doctor-session-manager-token.js +264 -0
  8. package/dist/cli/doctor-session-manager-token.js.map +1 -0
  9. package/dist/cli/doctor-session-manager.d.ts +3 -1
  10. package/dist/cli/doctor-session-manager.d.ts.map +1 -1
  11. package/dist/cli/doctor-session-manager.js +168 -146
  12. package/dist/cli/doctor-session-manager.js.map +1 -1
  13. package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
  14. package/dist/core/lisa-owned-hash-ledger.js +34 -0
  15. package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
  16. package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
  17. package/dist/core/nightly-e2e-guard-behavior-certificate.js.map +1 -1
  18. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  19. package/dist/core/upstream-evidence-manifest.js +172 -23
  20. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  21. package/package.json +4 -4
  22. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  23. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  24. package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/SKILL.md +5 -3
  25. package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/scripts/providers.mjs +121 -3
  26. package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/scripts/validate-config.mjs +47 -26
  27. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/SKILL.md +197 -54
  28. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/references/runbook-template.md +23 -10
  29. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/cli-cycle.mjs +21 -3
  30. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/cli-human.mjs +199 -0
  31. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/cli-manager-token.mjs +99 -0
  32. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/cli-manager.mjs +52 -52
  33. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/cli-queue.mjs +51 -139
  34. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/cli-runtime.mjs +5 -3
  35. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/cli-setup.mjs +94 -14
  36. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/cli-status.mjs +73 -0
  37. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/cli-usage.mjs +105 -15
  38. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/config.mjs +39 -11
  39. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/human-answer.mjs +162 -0
  40. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/human-needed.mjs +198 -0
  41. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/json-input.mjs +34 -0
  42. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/launch-shell.mjs +115 -0
  43. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/launch.mjs +69 -60
  44. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/ledger-questions.mjs +252 -0
  45. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/ledger.mjs +22 -56
  46. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/queue-github.mjs +117 -0
  47. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/session-manager.mjs +17 -5
  48. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/token-migrate.mjs +180 -0
  49. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/token-provider.mjs +150 -0
  50. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/token-read.mjs +166 -0
  51. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/token-store.mjs +248 -0
  52. package/plugins/lisa/.codex-plugin/skills/lisa-session-manager/scripts/token.mjs +39 -120
  53. package/plugins/lisa/.codex-plugin/skills/lisa-setup-session-manager/SKILL.md +82 -19
  54. package/plugins/lisa/commands/session-manager.md +1 -1
  55. package/plugins/lisa/commands/setup/session-manager.md +1 -1
  56. package/plugins/lisa/rules/reference/config-resolution.md +39 -7
  57. package/plugins/lisa/skills/lisa-secrets-access/SKILL.md +5 -3
  58. package/plugins/lisa/skills/lisa-secrets-access/scripts/providers.mjs +121 -3
  59. package/plugins/lisa/skills/lisa-secrets-access/scripts/validate-config.mjs +47 -26
  60. package/plugins/lisa/skills/lisa-session-manager/SKILL.md +197 -54
  61. package/plugins/lisa/skills/lisa-session-manager/references/runbook-template.md +23 -10
  62. package/plugins/lisa/skills/lisa-session-manager/scripts/cli-cycle.mjs +21 -3
  63. package/plugins/lisa/skills/lisa-session-manager/scripts/cli-human.mjs +199 -0
  64. package/plugins/lisa/skills/lisa-session-manager/scripts/cli-manager-token.mjs +99 -0
  65. package/plugins/lisa/skills/lisa-session-manager/scripts/cli-manager.mjs +52 -52
  66. package/plugins/lisa/skills/lisa-session-manager/scripts/cli-queue.mjs +51 -139
  67. package/plugins/lisa/skills/lisa-session-manager/scripts/cli-runtime.mjs +5 -3
  68. package/plugins/lisa/skills/lisa-session-manager/scripts/cli-setup.mjs +94 -14
  69. package/plugins/lisa/skills/lisa-session-manager/scripts/cli-status.mjs +73 -0
  70. package/plugins/lisa/skills/lisa-session-manager/scripts/cli-usage.mjs +105 -15
  71. package/plugins/lisa/skills/lisa-session-manager/scripts/config.mjs +39 -11
  72. package/plugins/lisa/skills/lisa-session-manager/scripts/human-answer.mjs +162 -0
  73. package/plugins/lisa/skills/lisa-session-manager/scripts/human-needed.mjs +198 -0
  74. package/plugins/lisa/skills/lisa-session-manager/scripts/json-input.mjs +34 -0
  75. package/plugins/lisa/skills/lisa-session-manager/scripts/launch-shell.mjs +115 -0
  76. package/plugins/lisa/skills/lisa-session-manager/scripts/launch.mjs +69 -60
  77. package/plugins/lisa/skills/lisa-session-manager/scripts/ledger-questions.mjs +252 -0
  78. package/plugins/lisa/skills/lisa-session-manager/scripts/ledger.mjs +22 -56
  79. package/plugins/lisa/skills/lisa-session-manager/scripts/queue-github.mjs +117 -0
  80. package/plugins/lisa/skills/lisa-session-manager/scripts/session-manager.mjs +17 -5
  81. package/plugins/lisa/skills/lisa-session-manager/scripts/token-migrate.mjs +180 -0
  82. package/plugins/lisa/skills/lisa-session-manager/scripts/token-provider.mjs +150 -0
  83. package/plugins/lisa/skills/lisa-session-manager/scripts/token-read.mjs +166 -0
  84. package/plugins/lisa/skills/lisa-session-manager/scripts/token-store.mjs +248 -0
  85. package/plugins/lisa/skills/lisa-session-manager/scripts/token.mjs +39 -120
  86. package/plugins/lisa/skills/lisa-setup-session-manager/SKILL.md +82 -19
  87. package/plugins/lisa-agy/commands/lisa/session-manager.md +1 -1
  88. package/plugins/lisa-agy/commands/lisa/setup/session-manager.md +1 -1
  89. package/plugins/lisa-agy/plugin.json +1 -1
  90. package/plugins/lisa-agy/skills/lisa-secrets-access/SKILL.md +5 -3
  91. package/plugins/lisa-agy/skills/lisa-secrets-access/scripts/providers.mjs +121 -3
  92. package/plugins/lisa-agy/skills/lisa-secrets-access/scripts/validate-config.mjs +47 -26
  93. package/plugins/lisa-agy/skills/lisa-session-manager/SKILL.md +197 -54
  94. package/plugins/lisa-agy/skills/lisa-session-manager/references/runbook-template.md +23 -10
  95. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/cli-cycle.mjs +21 -3
  96. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/cli-human.mjs +199 -0
  97. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/cli-manager-token.mjs +99 -0
  98. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/cli-manager.mjs +52 -52
  99. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/cli-queue.mjs +51 -139
  100. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/cli-runtime.mjs +5 -3
  101. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/cli-setup.mjs +94 -14
  102. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/cli-status.mjs +73 -0
  103. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/cli-usage.mjs +105 -15
  104. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/config.mjs +39 -11
  105. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/human-answer.mjs +162 -0
  106. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/human-needed.mjs +198 -0
  107. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/json-input.mjs +34 -0
  108. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/launch-shell.mjs +115 -0
  109. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/launch.mjs +69 -60
  110. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/ledger-questions.mjs +252 -0
  111. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/ledger.mjs +22 -56
  112. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/queue-github.mjs +117 -0
  113. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/session-manager.mjs +17 -5
  114. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/token-migrate.mjs +180 -0
  115. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/token-provider.mjs +150 -0
  116. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/token-read.mjs +166 -0
  117. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/token-store.mjs +248 -0
  118. package/plugins/lisa-agy/skills/lisa-session-manager/scripts/token.mjs +39 -120
  119. package/plugins/lisa-agy/skills/lisa-setup-session-manager/SKILL.md +82 -19
  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-cdk-devin/.claude-plugin/plugin.json +1 -1
  126. package/plugins/lisa-cdk-devin/.devin-plugin/plugin.json +1 -1
  127. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  128. package/plugins/lisa-copilot/commands/lisa/session-manager.md +1 -1
  129. package/plugins/lisa-copilot/commands/lisa/setup/session-manager.md +1 -1
  130. package/plugins/lisa-copilot/rules/reference/config-resolution.md +39 -7
  131. package/plugins/lisa-copilot/skills/lisa-secrets-access/SKILL.md +5 -3
  132. package/plugins/lisa-copilot/skills/lisa-secrets-access/scripts/providers.mjs +121 -3
  133. package/plugins/lisa-copilot/skills/lisa-secrets-access/scripts/validate-config.mjs +47 -26
  134. package/plugins/lisa-copilot/skills/lisa-session-manager/SKILL.md +197 -54
  135. package/plugins/lisa-copilot/skills/lisa-session-manager/references/runbook-template.md +23 -10
  136. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/cli-cycle.mjs +21 -3
  137. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/cli-human.mjs +199 -0
  138. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/cli-manager-token.mjs +99 -0
  139. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/cli-manager.mjs +52 -52
  140. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/cli-queue.mjs +51 -139
  141. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/cli-runtime.mjs +5 -3
  142. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/cli-setup.mjs +94 -14
  143. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/cli-status.mjs +73 -0
  144. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/cli-usage.mjs +105 -15
  145. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/config.mjs +39 -11
  146. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/human-answer.mjs +162 -0
  147. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/human-needed.mjs +198 -0
  148. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/json-input.mjs +34 -0
  149. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/launch-shell.mjs +115 -0
  150. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/launch.mjs +69 -60
  151. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/ledger-questions.mjs +252 -0
  152. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/ledger.mjs +22 -56
  153. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/queue-github.mjs +117 -0
  154. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/session-manager.mjs +17 -5
  155. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/token-migrate.mjs +180 -0
  156. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/token-provider.mjs +150 -0
  157. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/token-read.mjs +166 -0
  158. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/token-store.mjs +248 -0
  159. package/plugins/lisa-copilot/skills/lisa-session-manager/scripts/token.mjs +39 -120
  160. package/plugins/lisa-copilot/skills/lisa-setup-session-manager/SKILL.md +82 -19
  161. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  162. package/plugins/lisa-cursor/commands/lisa/session-manager.md +1 -1
  163. package/plugins/lisa-cursor/commands/lisa/setup/session-manager.md +1 -1
  164. package/plugins/lisa-cursor/rules/config-resolution-reference.mdc +39 -7
  165. package/plugins/lisa-cursor/skills/lisa-secrets-access/SKILL.md +5 -3
  166. package/plugins/lisa-cursor/skills/lisa-secrets-access/scripts/providers.mjs +121 -3
  167. package/plugins/lisa-cursor/skills/lisa-secrets-access/scripts/validate-config.mjs +47 -26
  168. package/plugins/lisa-cursor/skills/lisa-session-manager/SKILL.md +197 -54
  169. package/plugins/lisa-cursor/skills/lisa-session-manager/references/runbook-template.md +23 -10
  170. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/cli-cycle.mjs +21 -3
  171. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/cli-human.mjs +199 -0
  172. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/cli-manager-token.mjs +99 -0
  173. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/cli-manager.mjs +52 -52
  174. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/cli-queue.mjs +51 -139
  175. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/cli-runtime.mjs +5 -3
  176. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/cli-setup.mjs +94 -14
  177. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/cli-status.mjs +73 -0
  178. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/cli-usage.mjs +105 -15
  179. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/config.mjs +39 -11
  180. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/human-answer.mjs +162 -0
  181. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/human-needed.mjs +198 -0
  182. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/json-input.mjs +34 -0
  183. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/launch-shell.mjs +115 -0
  184. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/launch.mjs +69 -60
  185. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/ledger-questions.mjs +252 -0
  186. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/ledger.mjs +22 -56
  187. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/queue-github.mjs +117 -0
  188. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/session-manager.mjs +17 -5
  189. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/token-migrate.mjs +180 -0
  190. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/token-provider.mjs +150 -0
  191. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/token-read.mjs +166 -0
  192. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/token-store.mjs +248 -0
  193. package/plugins/lisa-cursor/skills/lisa-session-manager/scripts/token.mjs +39 -120
  194. package/plugins/lisa-cursor/skills/lisa-setup-session-manager/SKILL.md +82 -19
  195. package/plugins/lisa-devin/.claude-plugin/plugin.json +1 -1
  196. package/plugins/lisa-devin/.devin-plugin/plugin.json +1 -1
  197. package/plugins/lisa-devin/rules/reference/config-resolution.md +39 -7
  198. package/plugins/lisa-devin/skills/lisa-secrets-access/SKILL.md +5 -3
  199. package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/providers.mjs +121 -3
  200. package/plugins/lisa-devin/skills/lisa-secrets-access/scripts/validate-config.mjs +47 -26
  201. package/plugins/lisa-devin/skills/lisa-session-manager/SKILL.md +197 -54
  202. package/plugins/lisa-devin/skills/lisa-session-manager/references/runbook-template.md +23 -10
  203. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/cli-cycle.mjs +21 -3
  204. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/cli-human.mjs +199 -0
  205. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/cli-manager-token.mjs +99 -0
  206. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/cli-manager.mjs +52 -52
  207. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/cli-queue.mjs +51 -139
  208. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/cli-runtime.mjs +5 -3
  209. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/cli-setup.mjs +94 -14
  210. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/cli-status.mjs +73 -0
  211. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/cli-usage.mjs +105 -15
  212. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/config.mjs +39 -11
  213. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/human-answer.mjs +162 -0
  214. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/human-needed.mjs +198 -0
  215. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/json-input.mjs +34 -0
  216. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/launch-shell.mjs +115 -0
  217. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/launch.mjs +69 -60
  218. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/ledger-questions.mjs +252 -0
  219. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/ledger.mjs +22 -56
  220. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/queue-github.mjs +117 -0
  221. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/session-manager.mjs +17 -5
  222. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/token-migrate.mjs +180 -0
  223. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/token-provider.mjs +150 -0
  224. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/token-read.mjs +166 -0
  225. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/token-store.mjs +248 -0
  226. package/plugins/lisa-devin/skills/lisa-session-manager/scripts/token.mjs +39 -120
  227. package/plugins/lisa-devin/skills/lisa-setup-session-manager/SKILL.md +82 -19
  228. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  229. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  230. package/plugins/lisa-expo-agy/plugin.json +1 -1
  231. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  232. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  233. package/plugins/lisa-expo-devin/.claude-plugin/plugin.json +1 -1
  234. package/plugins/lisa-expo-devin/.devin-plugin/plugin.json +1 -1
  235. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  236. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  237. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  238. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  239. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  240. package/plugins/lisa-harper-fabric-devin/.claude-plugin/plugin.json +1 -1
  241. package/plugins/lisa-harper-fabric-devin/.devin-plugin/plugin.json +1 -1
  242. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  243. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  244. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  245. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  246. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  247. package/plugins/lisa-nestjs-devin/.claude-plugin/plugin.json +1 -1
  248. package/plugins/lisa-nestjs-devin/.devin-plugin/plugin.json +1 -1
  249. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  250. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  251. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  252. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  253. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  254. package/plugins/lisa-openclaw-devin/.claude-plugin/plugin.json +1 -1
  255. package/plugins/lisa-openclaw-devin/.devin-plugin/plugin.json +1 -1
  256. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  257. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  258. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  259. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  260. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  261. package/plugins/lisa-phaser-devin/.claude-plugin/plugin.json +1 -1
  262. package/plugins/lisa-phaser-devin/.devin-plugin/plugin.json +1 -1
  263. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  264. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  265. package/plugins/lisa-rails-agy/plugin.json +1 -1
  266. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  267. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  268. package/plugins/lisa-rails-devin/.claude-plugin/plugin.json +1 -1
  269. package/plugins/lisa-rails-devin/.devin-plugin/plugin.json +1 -1
  270. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  271. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  272. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  273. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  274. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  275. package/plugins/lisa-typescript-devin/.claude-plugin/plugin.json +1 -1
  276. package/plugins/lisa-typescript-devin/.devin-plugin/plugin.json +1 -1
  277. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  278. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  279. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  280. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  281. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  282. package/plugins/lisa-wiki-devin/.claude-plugin/plugin.json +1 -1
  283. package/plugins/lisa-wiki-devin/.devin-plugin/plugin.json +1 -1
  284. package/plugins/src/base/commands/session-manager.md +1 -1
  285. package/plugins/src/base/commands/setup/session-manager.md +1 -1
  286. package/plugins/src/base/rules/reference/config-resolution.md +39 -7
  287. package/plugins/src/base/skills/lisa-secrets-access/SKILL.md +5 -3
  288. package/plugins/src/base/skills/lisa-secrets-access/scripts/providers.mjs +121 -3
  289. package/plugins/src/base/skills/lisa-secrets-access/scripts/validate-config.mjs +47 -26
  290. package/plugins/src/base/skills/lisa-session-manager/SKILL.md +197 -54
  291. package/plugins/src/base/skills/lisa-session-manager/references/runbook-template.md +23 -10
  292. package/plugins/src/base/skills/lisa-session-manager/scripts/cli-cycle.mjs +21 -3
  293. package/plugins/src/base/skills/lisa-session-manager/scripts/cli-human.mjs +199 -0
  294. package/plugins/src/base/skills/lisa-session-manager/scripts/cli-manager-token.mjs +99 -0
  295. package/plugins/src/base/skills/lisa-session-manager/scripts/cli-manager.mjs +52 -52
  296. package/plugins/src/base/skills/lisa-session-manager/scripts/cli-queue.mjs +51 -139
  297. package/plugins/src/base/skills/lisa-session-manager/scripts/cli-runtime.mjs +5 -3
  298. package/plugins/src/base/skills/lisa-session-manager/scripts/cli-setup.mjs +94 -14
  299. package/plugins/src/base/skills/lisa-session-manager/scripts/cli-status.mjs +73 -0
  300. package/plugins/src/base/skills/lisa-session-manager/scripts/cli-usage.mjs +105 -15
  301. package/plugins/src/base/skills/lisa-session-manager/scripts/config.mjs +39 -11
  302. package/plugins/src/base/skills/lisa-session-manager/scripts/human-answer.mjs +162 -0
  303. package/plugins/src/base/skills/lisa-session-manager/scripts/human-needed.mjs +198 -0
  304. package/plugins/src/base/skills/lisa-session-manager/scripts/json-input.mjs +34 -0
  305. package/plugins/src/base/skills/lisa-session-manager/scripts/launch-shell.mjs +115 -0
  306. package/plugins/src/base/skills/lisa-session-manager/scripts/launch.mjs +69 -60
  307. package/plugins/src/base/skills/lisa-session-manager/scripts/ledger-questions.mjs +252 -0
  308. package/plugins/src/base/skills/lisa-session-manager/scripts/ledger.mjs +22 -56
  309. package/plugins/src/base/skills/lisa-session-manager/scripts/queue-github.mjs +117 -0
  310. package/plugins/src/base/skills/lisa-session-manager/scripts/session-manager.mjs +17 -5
  311. package/plugins/src/base/skills/lisa-session-manager/scripts/token-migrate.mjs +180 -0
  312. package/plugins/src/base/skills/lisa-session-manager/scripts/token-provider.mjs +150 -0
  313. package/plugins/src/base/skills/lisa-session-manager/scripts/token-read.mjs +166 -0
  314. package/plugins/src/base/skills/lisa-session-manager/scripts/token-store.mjs +248 -0
  315. package/plugins/src/base/skills/lisa-session-manager/scripts/token.mjs +39 -120
  316. package/plugins/src/base/skills/lisa-setup-session-manager/SKILL.md +82 -19
  317. package/rails/copy-overwrite/scripts/lisa-rspec-shards.mjs +747 -0
  318. package/rails/copy-overwrite/scripts/lisa_rspec_shard_recorder.rb +143 -0
  319. package/rails/copy-overwrite/scripts/lisa_simplecov_collate.rb +51 -0
  320. package/rails/create-only/.github/workflows/ci.yml +4 -0
  321. package/scripts/two-channel-couplings.json +89 -7
  322. package/typescript/copy-overwrite/.prettierignore +1 -0
@@ -1,6 +1,8 @@
1
1
  /**
2
2
  * Starting and stopping the session manager, and the Telegram bot token it
3
- * needs.
3
+ * needs when Telegram is its notification channel. Telegram is optional
4
+ * (#4555): with `notify.provider` `"none"` the manager launches with no
5
+ * channel, no state dir and no plugin, and none of the isolation below applies.
4
6
  *
5
7
  * The official Telegram plugin keeps its token, pairing list, inbox and
6
8
  * `bot.pid` in one state dir (`TELEGRAM_STATE_DIR`, else
@@ -11,16 +13,20 @@
11
13
  * env, and the shared default dir is refused outright;
12
14
  * - the plugin is enabled only through the manager's own `--settings`, never
13
15
  * at user scope, so worker sessions never start a poller;
14
- * - the token lives in `<stateDir>/.env` (dir 0700, file 0600), is read from
15
- * the operator's terminal with echo off, and never appears in argv, a
16
- * return value, an error message or a log line.
16
+ * - the token lives in the project's secrets provider when one is configured
17
+ * (token-store.mjs, #4555), reaching the manager's tmux session through
18
+ * `source-file -` on stdin ({@link buildSourcedLaunch}); with no provider it
19
+ * lives in `<stateDir>/.env` (dir 0700, file 0600). Either way it is read
20
+ * from the operator's terminal with echo off (or the clipboard), and never
21
+ * appears in argv, a return value, an error message or a log line.
17
22
  *
18
23
  * The tmux argv is returned as an array and handed straight to `spawnSync`.
19
24
  * With more than one command argument tmux runs the command directly rather
20
25
  * than through `sh -c`, so the settings JSON and the loop prompt are never
21
26
  * re-parsed by a shell.
22
27
  *
23
- * The state dir lives in state-dir.mjs and the token in token.mjs; both are
28
+ * The state dir lives in state-dir.mjs, the token in token.mjs, and the
29
+ * foreground and stdin renderings of the launch in launch-shell.mjs; all are
24
30
  * re-exported here so callers keep one import.
25
31
  *
26
32
  * Everything here is pure or takes injected seams. This module never reads
@@ -33,6 +39,11 @@ import path from "node:path";
33
39
  import { parseLoopInterval } from "./config.mjs";
34
40
  import { LaunchError } from "./state-dir.mjs";
35
41
 
42
+ export {
43
+ buildForegroundCommand,
44
+ buildSourcedLaunch,
45
+ tmuxQuote,
46
+ } from "./launch-shell.mjs";
36
47
  export {
37
48
  LaunchError,
38
49
  realpathExisting,
@@ -42,6 +53,8 @@ export {
42
53
  assertTokenPresent,
43
54
  buildStoreTokenCommand,
44
55
  loadPromptSecret,
56
+ readTokenFromClipboard,
57
+ readTokenFromPrompt,
45
58
  storeToken,
46
59
  storeTokenFromClipboard,
47
60
  validateBotToken,
@@ -54,26 +67,28 @@ export const TELEGRAM_PLUGIN_ID = "telegram@claude-plugins-official";
54
67
  /** Same slug rule the config validator applies to `sessionManager.name`. */
55
68
  const SESSION_NAME_PATTERN = /^[a-z0-9][a-z0-9_-]{0,63}$/;
56
69
 
57
- /** A `'` inside a single-quoted shell word: close, escaped quote, reopen. */
58
- const ESCAPED_QUOTE = "'\\''";
59
-
60
- /** An argument a POSIX shell reads back unchanged without quotes. */
61
- const SHELL_SAFE = /^[A-Za-z0-9_@%+=:,./-]+$/;
62
-
63
70
  /** The skill command each manager loop iteration runs. */
64
71
  const CYCLE_COMMAND = "/lisa:session-manager cycle";
65
72
 
73
+ /** The notification providers a launch can be built for. */
74
+ const LAUNCH_NOTIFY = new Set(["none", "telegram"]);
75
+
66
76
  /**
67
- * Settings blob for the manager session only: the Telegram plugin on, and
68
- * workers' messages accepted.
77
+ * Settings blob for the manager session only: workers' messages accepted,
78
+ * and the Telegram plugin on when Telegram is the notification channel. With
79
+ * no channel (`"none"`) the plugin is left out entirely, so the manager never
80
+ * starts a poller (#4555).
81
+ * @param {string} [notify] - Notification provider: "telegram" (default) or "none"
69
82
  * @returns {{ crossSessionInbound: "accept",
70
- * enabledPlugins: Record<string, boolean> }} Fresh settings object
83
+ * enabledPlugins?: Record<string, boolean> }} Fresh settings object
71
84
  */
72
- export function buildManagerSettings() {
73
- return {
74
- crossSessionInbound: "accept",
75
- enabledPlugins: { [TELEGRAM_PLUGIN_ID]: true },
76
- };
85
+ export function buildManagerSettings(notify = "telegram") {
86
+ return notify === "telegram"
87
+ ? {
88
+ crossSessionInbound: "accept",
89
+ enabledPlugins: { [TELEGRAM_PLUGIN_ID]: true },
90
+ }
91
+ : { crossSessionInbound: "accept" };
77
92
  }
78
93
 
79
94
  /**
@@ -111,9 +126,15 @@ function assertAbsolute(label, value) {
111
126
  * `TELEGRAM_STATE_DIR` goes only into this session's env so no other session
112
127
  * ever sees it. `SM_SCRIPTS_DIR` lets every cycle's Bash find these scripts
113
128
  * without re-resolving the plugin root.
114
- * @param {{ name: string, root: string, stateDir: string, scriptsDir: string,
115
- * interval: string }} input - Session name, project root, resolved state
116
- * dir, this scripts dir, and the loop interval (e.g. "5m")
129
+ *
130
+ * With `notify: "none"` there is no channel: no `TELEGRAM_STATE_DIR`, no
131
+ * `--channels` and no plugin in the settings, and a `stateDir` is refused
132
+ * because only the telegram provider uses one (#4555).
133
+ * @param {{ name: string, root: string, stateDir?: string,
134
+ * scriptsDir: string, interval: string,
135
+ * notify?: string }} input - Session name, project root,
136
+ * resolved state dir (telegram only), this scripts dir, the loop interval
137
+ * (e.g. "5m") and the notification provider (default telegram)
117
138
  * @returns {string[]} argv for `spawnSync("tmux", argv)`
118
139
  */
119
140
  export function buildManagerLaunch({
@@ -122,10 +143,11 @@ export function buildManagerLaunch({
122
143
  stateDir,
123
144
  scriptsDir,
124
145
  interval,
146
+ notify = "telegram",
125
147
  }) {
126
148
  assertSessionName(name);
127
149
  assertAbsolute("root", root);
128
- assertAbsolute("stateDir", stateDir);
150
+ const telegram = assertNotify(notify, stateDir) === "telegram";
129
151
  assertAbsolute("scriptsDir", scriptsDir);
130
152
  if (parseLoopInterval(interval) === null) {
131
153
  throw new LaunchError(
@@ -139,8 +161,7 @@ export function buildManagerLaunch({
139
161
  name,
140
162
  "-c",
141
163
  root,
142
- "-e",
143
- `TELEGRAM_STATE_DIR=${stateDir}`,
164
+ ...(telegram ? ["-e", `TELEGRAM_STATE_DIR=${stateDir}`] : []),
144
165
  "-e",
145
166
  `SM_SCRIPTS_DIR=${scriptsDir}`,
146
167
  "claude",
@@ -148,50 +169,38 @@ export function buildManagerLaunch({
148
169
  name,
149
170
  "--dangerously-skip-permissions",
150
171
  "--settings",
151
- JSON.stringify(buildManagerSettings()),
152
- "--channels",
153
- `plugin:${TELEGRAM_PLUGIN_ID}`,
172
+ JSON.stringify(buildManagerSettings(notify)),
173
+ ...(telegram ? ["--channels", `plugin:${TELEGRAM_PLUGIN_ID}`] : []),
154
174
  // `--channels` is variadic (claude 2.1.296): without `--` it takes the
155
175
  // prompt as a second channel entry and claude exits 1 ("--channels
156
- // entries must be tagged") before the session starts.
176
+ // entries must be tagged") before the session starts. Kept with no
177
+ // channel too, so the prompt is never read as an option.
157
178
  "--",
158
179
  `/loop ${interval} ${CYCLE_COMMAND}`,
159
180
  ];
160
181
  }
161
182
 
162
183
  /**
163
- * Quote one argument for a POSIX shell, for display only.
164
- * @param {string} value - Argument
165
- * @returns {string} Single-quoted argument
166
- */
167
- function shellQuote(value) {
168
- return `'${value.replaceAll("'", ESCAPED_QUOTE)}'`;
169
- }
170
-
171
- /**
172
- * The shell line an operator runs to start the manager in the foreground,
173
- * from the tmux argv {@link buildManagerLaunch} returned: same cwd, the same
174
- * two session variables, the same claude argv. `start` prints it when the
175
- * tmux session dies at once, because tmux closes the window and claude's own
176
- * error goes with it. It is display text only and is never executed here.
177
- * The token is not in the argv, so it is not in this line either.
178
- * @param {readonly string[]} argv - Result of {@link buildManagerLaunch}
179
- * @returns {string} One shell line
184
+ * Refuse an unsupported provider, a telegram launch without an absolute state
185
+ * dir, and a state dir on a launch with no channel.
186
+ * @param {unknown} notify - Notification provider
187
+ * @param {unknown} stateDir - Resolved state dir, if any
188
+ * @returns {"telegram" | "none"} The provider
180
189
  */
181
- export function buildForegroundCommand(argv) {
182
- const claudeAt = argv.indexOf("claude");
183
- const head = argv.slice(0, claudeAt);
184
- const cwd = head[head.indexOf("-c") + 1];
185
- const vars = head
186
- .filter((_, index) => head[index - 1] === "-e")
187
- .map(entry => {
188
- const at = entry.indexOf("=");
189
- return `${entry.slice(0, at)}=${shellQuote(entry.slice(at + 1))}`;
190
- });
191
- const command = argv
192
- .slice(claudeAt)
193
- .map(arg => (SHELL_SAFE.test(arg) ? arg : shellQuote(arg)));
194
- return `cd ${shellQuote(cwd)} && ${[...vars, ...command].join(" ")}`;
190
+ function assertNotify(notify, stateDir) {
191
+ if (!LAUNCH_NOTIFY.has(notify)) {
192
+ throw new LaunchError(
193
+ `notify "${String(notify)}" is not supported; use "none" or "telegram".`
194
+ );
195
+ }
196
+ if (notify === "telegram") {
197
+ assertAbsolute("stateDir", stateDir);
198
+ } else if (stateDir !== undefined) {
199
+ throw new LaunchError(
200
+ `stateDir is only used with the telegram provider; notify is "none".`
201
+ );
202
+ }
203
+ return notify;
195
204
  }
196
205
 
197
206
  /**
@@ -0,0 +1,252 @@
1
+ /**
2
+ * The ledger side of "mark and move on" (CodySwannGT/lisa#4555, part 3):
3
+ * recording that an item's human-needed mark was read back on the tracker,
4
+ * queueing a human's answer for the next cycle to deliver, and listing what
5
+ * is waiting on a person.
6
+ *
7
+ * The manager records a question in the ledger BEFORE it writes the tracker
8
+ * marker, then records `marked` once the marker is read back. A crash in
9
+ * between leaves a pending question with `markedAt: null`, which the next
10
+ * cycle (and `lisa doctor`) can see and finish, rather than a marker on the
11
+ * tracker the ledger knows nothing about and so would never remove.
12
+ *
13
+ * Recording and clearing the question itself ({@link setPendingQuestion},
14
+ * {@link clearPendingQuestion}) lives here too; ledger.mjs re-exports both.
15
+ * Writes go through ledger.mjs's atomic read-transform-write.
16
+ * @module session-manager/ledger-questions
17
+ */
18
+ import { HUMAN_NEEDED_KINDS } from "./human-needed.mjs";
19
+ import {
20
+ placeholderItem,
21
+ requireItem,
22
+ updateLedger,
23
+ withItem,
24
+ } from "./ledger.mjs";
25
+
26
+ /** Ways an item can be marked human-needed. */
27
+ const MARKER_TYPES = new Set(["label", "role"]);
28
+
29
+ /** A tracker comment id: GitHub numeric or node id, Jira id, Linear uuid. */
30
+ const COMMENT_ID = /^[A-Za-z0-9_.:-]{1,200}$/;
31
+
32
+ /** Where a queued answer came from. */
33
+ const ANSWER_SOURCES = new Set(["cli", "item", "channel"]);
34
+
35
+ /**
36
+ * The item's pending question, or a refusal naming the ref.
37
+ * @param {import("./ledger.mjs").LedgerItem} entry - Ledger item
38
+ * @param {string} ref - Its ref
39
+ * @returns {NonNullable<import("./ledger.mjs").LedgerItem["pendingQuestion"]>}
40
+ * The pending question
41
+ */
42
+ function requirePending(entry, ref) {
43
+ if (!entry.pendingQuestion) {
44
+ throw new Error(`${ref} has no pending question in the ledger`);
45
+ }
46
+ return entry.pendingQuestion;
47
+ }
48
+
49
+ /**
50
+ * Record that the item's human-needed marker was applied and read back.
51
+ * @param {string} projectRoot - Absolute project root
52
+ * `commentId` is the id of the question comment the manager posted, read
53
+ * back from `lisa-tracker-write`. It is kept in `managerCommentIds` so
54
+ * `item-answer` never takes the manager's own comment as an answer, whoever
55
+ * the tracker says wrote it and whatever it says.
56
+ * @param {{ref: string, markerType: string, marker: string,
57
+ * commentId?: string}} mark - The mark
58
+ * @param {import("./ledger.mjs").LedgerSeams} [seams] - Injected seams
59
+ * @returns {Promise<import("./ledger.mjs").LedgerItem>} The updated item
60
+ */
61
+ export function recordMarked(
62
+ projectRoot,
63
+ { ref, markerType, marker, commentId },
64
+ seams
65
+ ) {
66
+ if (!MARKER_TYPES.has(markerType)) {
67
+ return Promise.reject(new Error("--marker-type must be label or role."));
68
+ }
69
+ if (typeof marker !== "string" || marker.trim() === "") {
70
+ return Promise.reject(new Error("--marker must name the label or role."));
71
+ }
72
+ if (commentId !== undefined && !COMMENT_ID.test(commentId)) {
73
+ return Promise.reject(
74
+ new Error("--comment-id must be the tracker's comment id.")
75
+ );
76
+ }
77
+ return updateLedger(projectRoot, seams, (ledger, at) => {
78
+ const previous = requireItem(ledger, ref);
79
+ const pending = requirePending(previous, ref);
80
+ return withItem(ledger, ref, {
81
+ ...previous,
82
+ pendingQuestion: {
83
+ ...pending,
84
+ markerType,
85
+ marker,
86
+ markedAt: at,
87
+ managerCommentIds: [
88
+ ...new Set([
89
+ ...(pending.managerCommentIds ?? []),
90
+ ...(commentId === undefined ? [] : [commentId]),
91
+ ]),
92
+ ],
93
+ },
94
+ history: [
95
+ ...(previous.history ?? []),
96
+ { event: "marked", at, markerType, marker },
97
+ ],
98
+ });
99
+ });
100
+ }
101
+
102
+ /**
103
+ * Queue a human's answer on a pending question. The manager delivers it on
104
+ * its next cycle (SendMessage, or `resume`), then clears the question.
105
+ * @param {string} projectRoot - Absolute project root
106
+ * @param {{ref: string, source: string, text: string, author?: string|null}}
107
+ * answer - The answer
108
+ * @param {import("./ledger.mjs").LedgerSeams} [seams] - Injected seams
109
+ * @returns {Promise<import("./ledger.mjs").LedgerItem>} The updated item
110
+ */
111
+ export function queueAnswer(
112
+ projectRoot,
113
+ { ref, source, text, author = null },
114
+ seams
115
+ ) {
116
+ if (!ANSWER_SOURCES.has(source)) {
117
+ return Promise.reject(new Error(`unknown answer source ${source}`));
118
+ }
119
+ return updateLedger(projectRoot, seams, (ledger, at) => {
120
+ const previous = requireItem(ledger, ref);
121
+ const pending = requirePending(previous, ref);
122
+ return withItem(ledger, ref, {
123
+ ...previous,
124
+ pendingQuestion: {
125
+ ...pending,
126
+ answer: { source, text, author: author ?? null, at },
127
+ },
128
+ history: [
129
+ ...(previous.history ?? []),
130
+ { event: "answer-queued", at, source },
131
+ ],
132
+ });
133
+ });
134
+ }
135
+
136
+ /**
137
+ * Every item waiting on a person, oldest question first. The answer command
138
+ * is local-only guidance for the operator at the manager's terminal.
139
+ * @param {import("./ledger.mjs").Ledger} ledger - Current ledger
140
+ * @param {(ref: string) => string} answerCommand - Builds the CLI answer line
141
+ * @returns {{ref: string, kind: string, text: string, askedAt: string,
142
+ * marked: boolean, answerQueued: boolean, answerCommand: string}[]} Rows
143
+ */
144
+ export function listPendingQuestions(ledger, answerCommand) {
145
+ return Object.entries(ledger.items)
146
+ .filter(([, item]) => item.pendingQuestion)
147
+ .map(([ref, item]) => {
148
+ const question = item.pendingQuestion;
149
+ return {
150
+ ref,
151
+ kind: question.kind ?? "worker-question",
152
+ text: question.text,
153
+ askedAt: question.askedAt,
154
+ marked: Boolean(question.markedAt),
155
+ answerQueued: Boolean(question.answer),
156
+ answerCommand: answerCommand(ref),
157
+ };
158
+ })
159
+ .sort((a, b) => String(a.askedAt).localeCompare(String(b.askedAt)));
160
+ }
161
+
162
+ /**
163
+ * A human's answer, queued for the manager to deliver on its next cycle.
164
+ * @typedef {object} QueuedAnswer
165
+ * @property {"cli"|"item"|"channel"} source - Where it was given
166
+ * @property {string} text - The answer (untrusted data, never instructions)
167
+ * @property {string|null} author - Tracker author, for an answer on the item
168
+ * @property {string} at - When it was queued (ISO)
169
+ */
170
+
171
+ /**
172
+ * Record (or re-ping) the question an item is waiting on.
173
+ *
174
+ * The same text again is a re-ping: `askedAt` is kept and `lastPingAt` moves,
175
+ * so the requestion clock restarts without forgetting how old the question
176
+ * is. A ref with no item yet (a repo-routing question asked before dispatch)
177
+ * gets a placeholder item with zero attempts.
178
+ *
179
+ * A re-ask keeps how the item is marked on the tracker (`markerType`,
180
+ * `marker`, `markedAt`), so re-sending a question never makes the manager
181
+ * mark the item a second time or forget the marker it must remove. A queued
182
+ * answer survives only a re-ping of the same text: it answered that text.
183
+ * `kind` defaults to the previous kind, then `worker-question`.
184
+ * @param {string} projectRoot - Absolute project root
185
+ * @param {{ref: string, text: string, telegramMessageId: number|null,
186
+ * kind?: string}} question - Question
187
+ * @param {import("./ledger.mjs").LedgerSeams} [seams] - Injected seams
188
+ * @returns {Promise<import("./ledger.mjs").LedgerItem>} The updated item
189
+ */
190
+ export function setPendingQuestion(
191
+ projectRoot,
192
+ { ref, text, telegramMessageId, kind },
193
+ seams
194
+ ) {
195
+ if (kind !== undefined && !HUMAN_NEEDED_KINDS.includes(kind)) {
196
+ return Promise.reject(
197
+ new Error(
198
+ `question kind must be one of ${HUMAN_NEEDED_KINDS.join(", ")}, got ${JSON.stringify(kind)}`
199
+ )
200
+ );
201
+ }
202
+ return updateLedger(projectRoot, seams, (ledger, at) => {
203
+ const previous = ledger.items[ref] ?? placeholderItem();
204
+ const existing = previous.pendingQuestion;
205
+ const sameText = existing?.text === text;
206
+ return withItem(ledger, ref, {
207
+ ...previous,
208
+ pendingQuestion: {
209
+ text,
210
+ kind: kind ?? existing?.kind ?? "worker-question",
211
+ askedAt: sameText ? existing.askedAt : at,
212
+ lastPingAt: at,
213
+ telegramMessageId: telegramMessageId ?? null,
214
+ markerType: existing?.markerType ?? null,
215
+ marker: existing?.marker ?? null,
216
+ markedAt: existing?.markedAt ?? null,
217
+ managerCommentIds: existing?.managerCommentIds ?? [],
218
+ answer: sameText ? (existing.answer ?? null) : null,
219
+ },
220
+ history: [...(previous.history ?? []), { event: "question", at }],
221
+ });
222
+ });
223
+ }
224
+
225
+ /**
226
+ * Clear an item's pending question, once its answer has been delivered and
227
+ * the manager's own marker removed. `resetAttempts` zeroes the attempt count:
228
+ * an `exhausted` item a human has answered starts again from attempt one
229
+ * instead of being exhausted again on its first stall.
230
+ * @param {string} projectRoot - Absolute project root
231
+ * @param {{ref: string, resetAttempts?: boolean}} target - Item
232
+ * @param {import("./ledger.mjs").LedgerSeams} [seams] - Injected seams
233
+ * @returns {Promise<import("./ledger.mjs").LedgerItem>} The updated item
234
+ */
235
+ export function clearPendingQuestion(
236
+ projectRoot,
237
+ { ref, resetAttempts = false },
238
+ seams
239
+ ) {
240
+ return updateLedger(projectRoot, seams, (ledger, at) => {
241
+ const previous = requireItem(ledger, ref);
242
+ return withItem(ledger, ref, {
243
+ ...previous,
244
+ pendingQuestion: null,
245
+ ...(resetAttempts ? { attempts: 0 } : {}),
246
+ history: [
247
+ ...(previous.history ?? []),
248
+ { event: "answered", at, ...(resetAttempts ? { reset: true } : {}) },
249
+ ],
250
+ });
251
+ });
252
+ }
@@ -21,6 +21,14 @@ import { randomUUID } from "node:crypto";
21
21
  import * as nodeFs from "node:fs/promises";
22
22
  import { dirname, join } from "node:path";
23
23
 
24
+ // The question writers live in ledger-questions.mjs (#4555), re-exported so
25
+ // callers keep one import. They are called, never evaluated, at load time, so
26
+ // the import cycle back to this module's primitives is safe.
27
+ export {
28
+ clearPendingQuestion,
29
+ setPendingQuestion,
30
+ } from "./ledger-questions.mjs";
31
+
24
32
  /** Shape version, bumped only on an incompatible change. */
25
33
  const LEDGER_VERSION = 1;
26
34
 
@@ -43,6 +51,16 @@ const FINISH_STATUSES = new Set(["DONE", "FAILED"]);
43
51
  * @property {string} askedAt - When it was first asked (ISO)
44
52
  * @property {string} lastPingAt - When it was last (re-)sent (ISO)
45
53
  * @property {number|null} telegramMessageId - Telegram message carrying it
54
+ * @property {string} [kind] - Why a human is needed: worker-question |
55
+ * repo-route | exhausted | decision (#4555)
56
+ * @property {"label"|"role"|null} [markerType] - How the item is marked
57
+ * human-needed on the tracker, once the manager has read the mark back
58
+ * @property {string|null} [marker] - The label or role value it carries
59
+ * @property {string|null} [markedAt] - When the mark was read back (ISO);
60
+ * null means recorded but not yet marked on the tracker
61
+ * @property {string[]} [managerCommentIds] - Ids of the comments the manager
62
+ * posted on the item (its question comment), never read as an answer
63
+ * @property {import("./ledger-questions.mjs").QueuedAnswer|null} [answer] - An answer waiting to be delivered
46
64
  */
47
65
 
48
66
  /**
@@ -199,7 +217,7 @@ export async function writeLedger(projectRoot, ledger, seams) {
199
217
  * @param {(ledger: Ledger, at: string) => {ledger: Ledger, result: T}} transform - Pure update
200
218
  * @returns {Promise<T>} The transform's result
201
219
  */
202
- async function updateLedger(projectRoot, seams, transform) {
220
+ export async function updateLedger(projectRoot, seams, transform) {
203
221
  const { now } = resolveSeams(seams);
204
222
  const current = await readLedger(projectRoot, seams);
205
223
  const { ledger, result } = transform(current, now().toISOString());
@@ -214,7 +232,7 @@ async function updateLedger(projectRoot, seams, transform) {
214
232
  * @param {LedgerItem} entry - New item
215
233
  * @returns {{ledger: Ledger, result: LedgerItem}} Update
216
234
  */
217
- function withItem(ledger, ref, entry) {
235
+ export function withItem(ledger, ref, entry) {
218
236
  return {
219
237
  ledger: { ...ledger, items: { ...ledger.items, [ref]: entry } },
220
238
  result: entry,
@@ -227,7 +245,7 @@ function withItem(ledger, ref, entry) {
227
245
  * @param {string} ref - Item key
228
246
  * @returns {LedgerItem} The item
229
247
  */
230
- function requireItem(ledger, ref) {
248
+ export function requireItem(ledger, ref) {
231
249
  const entry = ledger.items[ref];
232
250
  if (!entry)
233
251
  throw new Error(
@@ -240,7 +258,7 @@ function requireItem(ledger, ref) {
240
258
  * A ledger item for a ref the manager has asked about but not dispatched.
241
259
  * @returns {LedgerItem} Placeholder item
242
260
  */
243
- function placeholderItem() {
261
+ export function placeholderItem() {
244
262
  return {
245
263
  repo: null,
246
264
  worker: null,
@@ -291,58 +309,6 @@ export function recordSpawn(
291
309
  });
292
310
  }
293
311
 
294
- /**
295
- * Record (or re-ping) the question an item is waiting on.
296
- *
297
- * The same text again is a re-ping: `askedAt` is kept and `lastPingAt` moves,
298
- * so the requestion clock restarts without forgetting how old the question
299
- * is. A ref with no item yet (a repo-routing question asked before dispatch)
300
- * gets a placeholder item with zero attempts.
301
- * @param {string} projectRoot - Absolute project root
302
- * @param {{ref: string, text: string, telegramMessageId: number|null}} question - Question
303
- * @param {LedgerSeams} [seams] - Injected seams
304
- * @returns {Promise<LedgerItem>} The updated item
305
- */
306
- export function setPendingQuestion(
307
- projectRoot,
308
- { ref, text, telegramMessageId },
309
- seams
310
- ) {
311
- return updateLedger(projectRoot, seams, (ledger, at) => {
312
- const previous = ledger.items[ref] ?? placeholderItem();
313
- const existing = previous.pendingQuestion;
314
- const askedAt = existing?.text === text ? existing.askedAt : at;
315
- return withItem(ledger, ref, {
316
- ...previous,
317
- pendingQuestion: {
318
- text,
319
- askedAt,
320
- lastPingAt: at,
321
- telegramMessageId: telegramMessageId ?? null,
322
- },
323
- history: [...(previous.history ?? []), { event: "question", at }],
324
- });
325
- });
326
- }
327
-
328
- /**
329
- * Clear an item's pending question, once its answer has been delivered.
330
- * @param {string} projectRoot - Absolute project root
331
- * @param {{ref: string}} target - Item
332
- * @param {LedgerSeams} [seams] - Injected seams
333
- * @returns {Promise<LedgerItem>} The updated item
334
- */
335
- export function clearPendingQuestion(projectRoot, { ref }, seams) {
336
- return updateLedger(projectRoot, seams, (ledger, at) => {
337
- const previous = requireItem(ledger, ref);
338
- return withItem(ledger, ref, {
339
- ...previous,
340
- pendingQuestion: null,
341
- history: [...(previous.history ?? []), { event: "answered", at }],
342
- });
343
- });
344
- }
345
-
346
312
  /**
347
313
  * Record this cycle's hash of the worker's logs. `lastProgressAt` moves only
348
314
  * when the hash changed, which is what "no output for N minutes" measures.