lastlight 0.1.8 → 0.2.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 (478) hide show
  1. package/README.md +265 -118
  2. package/agent-context/rules.md +62 -9
  3. package/agent-context/security.md +69 -0
  4. package/config/default.yaml +89 -0
  5. package/deploy/.env.production.example +20 -2
  6. package/deploy/entrypoint.sh +16 -17
  7. package/deploy/native/README.md +160 -0
  8. package/deploy/native/install.sh +110 -0
  9. package/deploy/native/lastlight.env.example +95 -0
  10. package/deploy/native/lastlight.service +50 -0
  11. package/deploy/sandbox-entrypoint.sh +59 -42
  12. package/dist/admin/auth.d.ts +1 -1
  13. package/dist/admin/auth.js +3 -1
  14. package/dist/admin/auth.js.map +1 -1
  15. package/dist/admin/chat-session-reader.d.ts +11 -14
  16. package/dist/admin/chat-session-reader.js +27 -51
  17. package/dist/admin/chat-session-reader.js.map +1 -1
  18. package/dist/admin/docker.d.ts +37 -0
  19. package/dist/admin/docker.js +86 -1
  20. package/dist/admin/docker.js.map +1 -1
  21. package/dist/admin/index.js +38 -3
  22. package/dist/admin/index.js.map +1 -1
  23. package/dist/admin/log-search.test.d.ts +1 -0
  24. package/dist/admin/log-search.test.js +78 -0
  25. package/dist/admin/log-search.test.js.map +1 -0
  26. package/dist/admin/routes.d.ts +52 -3
  27. package/dist/admin/routes.js +780 -63
  28. package/dist/admin/routes.js.map +1 -1
  29. package/dist/admin/routes.test.js +680 -14
  30. package/dist/admin/routes.test.js.map +1 -1
  31. package/dist/admin/server-logs.test.d.ts +1 -0
  32. package/dist/admin/server-logs.test.js +58 -0
  33. package/dist/admin/server-logs.test.js.map +1 -0
  34. package/dist/admin/sessions.d.ts +26 -39
  35. package/dist/admin/sessions.js +86 -310
  36. package/dist/admin/sessions.js.map +1 -1
  37. package/dist/admin/sessions.test.d.ts +1 -0
  38. package/dist/admin/sessions.test.js +78 -0
  39. package/dist/admin/sessions.test.js.map +1 -0
  40. package/dist/admin/version.d.ts +15 -0
  41. package/dist/admin/version.js +73 -0
  42. package/dist/admin/version.js.map +1 -0
  43. package/dist/admin/version.test.d.ts +1 -0
  44. package/dist/admin/version.test.js +71 -0
  45. package/dist/admin/version.test.js.map +1 -0
  46. package/dist/cli-config.d.ts +55 -0
  47. package/dist/cli-config.js +119 -0
  48. package/dist/cli-config.js.map +1 -0
  49. package/dist/cli-config.test.d.ts +1 -0
  50. package/dist/cli-config.test.js +92 -0
  51. package/dist/cli-config.test.js.map +1 -0
  52. package/dist/cli-format.d.ts +19 -0
  53. package/dist/cli-format.js +107 -0
  54. package/dist/cli-format.js.map +1 -0
  55. package/dist/cli-server.d.ts +73 -0
  56. package/dist/cli-server.js +347 -0
  57. package/dist/cli-server.js.map +1 -0
  58. package/dist/cli-server.test.d.ts +1 -0
  59. package/dist/cli-server.test.js +38 -0
  60. package/dist/cli-server.test.js.map +1 -0
  61. package/dist/cli-timeline.d.ts +35 -0
  62. package/dist/cli-timeline.js +373 -0
  63. package/dist/cli-timeline.js.map +1 -0
  64. package/dist/cli-timeline.test.d.ts +1 -0
  65. package/dist/cli-timeline.test.js +104 -0
  66. package/dist/cli-timeline.test.js.map +1 -0
  67. package/dist/cli.d.ts +0 -19
  68. package/dist/cli.js +910 -194
  69. package/dist/cli.js.map +1 -1
  70. package/dist/config-overlay.test.d.ts +1 -0
  71. package/dist/config-overlay.test.js +112 -0
  72. package/dist/config-overlay.test.js.map +1 -0
  73. package/dist/config-resolve.d.ts +28 -0
  74. package/dist/config-resolve.js +47 -0
  75. package/dist/config-resolve.js.map +1 -0
  76. package/dist/config-resolve.test.d.ts +1 -0
  77. package/dist/config-resolve.test.js +68 -0
  78. package/dist/config-resolve.test.js.map +1 -0
  79. package/dist/config.d.ts +62 -49
  80. package/dist/config.js +452 -76
  81. package/dist/config.js.map +1 -1
  82. package/dist/config.test.js +201 -32
  83. package/dist/config.test.js.map +1 -1
  84. package/dist/connectors/github-webhook.js +83 -5
  85. package/dist/connectors/github-webhook.js.map +1 -1
  86. package/dist/connectors/github-webhook.test.d.ts +1 -0
  87. package/dist/connectors/github-webhook.test.js +156 -0
  88. package/dist/connectors/github-webhook.test.js.map +1 -0
  89. package/dist/connectors/messaging/session-manager.d.ts +18 -0
  90. package/dist/connectors/messaging/session-manager.js +83 -2
  91. package/dist/connectors/messaging/session-manager.js.map +1 -1
  92. package/dist/connectors/messaging/session-manager.test.d.ts +1 -0
  93. package/dist/connectors/messaging/session-manager.test.js +144 -0
  94. package/dist/connectors/messaging/session-manager.test.js.map +1 -0
  95. package/dist/connectors/slack/connector.d.ts +9 -0
  96. package/dist/connectors/slack/connector.js +15 -0
  97. package/dist/connectors/slack/connector.js.map +1 -1
  98. package/dist/connectors/slack/mrkdwn.js +81 -0
  99. package/dist/connectors/slack/mrkdwn.js.map +1 -1
  100. package/dist/connectors/slack/mrkdwn.test.js +49 -0
  101. package/dist/connectors/slack/mrkdwn.test.js.map +1 -1
  102. package/dist/connectors/types.d.ts +1 -1
  103. package/dist/cron/fanout.d.ts +33 -0
  104. package/dist/cron/fanout.js +55 -0
  105. package/dist/cron/fanout.js.map +1 -0
  106. package/dist/cron/fanout.test.d.ts +1 -0
  107. package/dist/cron/fanout.test.js +73 -0
  108. package/dist/cron/fanout.test.js.map +1 -0
  109. package/dist/cron/jobs.d.ts +5 -0
  110. package/dist/cron/jobs.js +10 -3
  111. package/dist/cron/jobs.js.map +1 -1
  112. package/dist/cron/scheduler.d.ts +12 -0
  113. package/dist/cron/scheduler.js +27 -1
  114. package/dist/cron/scheduler.js.map +1 -1
  115. package/dist/engine/agent-executor.d.ts +158 -0
  116. package/dist/engine/agent-executor.js +1140 -0
  117. package/dist/engine/agent-executor.js.map +1 -0
  118. package/dist/engine/agent-executor.test.d.ts +1 -0
  119. package/dist/engine/agent-executor.test.js +395 -0
  120. package/dist/engine/agent-executor.test.js.map +1 -0
  121. package/dist/engine/chat-runner.d.ts +123 -0
  122. package/dist/engine/chat-runner.js +379 -0
  123. package/dist/engine/chat-runner.js.map +1 -0
  124. package/dist/engine/chat-runner.test.d.ts +1 -0
  125. package/dist/engine/chat-runner.test.js +104 -0
  126. package/dist/engine/chat-runner.test.js.map +1 -0
  127. package/dist/engine/chat-skills.d.ts +45 -0
  128. package/dist/engine/chat-skills.js +184 -0
  129. package/dist/engine/chat-skills.js.map +1 -0
  130. package/dist/engine/chat-skills.test.d.ts +1 -0
  131. package/dist/engine/chat-skills.test.js +20 -0
  132. package/dist/engine/chat-skills.test.js.map +1 -0
  133. package/dist/engine/chat.d.ts +20 -23
  134. package/dist/engine/chat.js +251 -155
  135. package/dist/engine/chat.js.map +1 -1
  136. package/dist/engine/chat.test.d.ts +1 -0
  137. package/dist/engine/chat.test.js +42 -0
  138. package/dist/engine/chat.test.js.map +1 -0
  139. package/dist/engine/classifier.d.ts +35 -2
  140. package/dist/engine/classifier.js +170 -31
  141. package/dist/engine/classifier.js.map +1 -1
  142. package/dist/engine/classifier.test.d.ts +1 -0
  143. package/dist/engine/classifier.test.js +115 -0
  144. package/dist/engine/classifier.test.js.map +1 -0
  145. package/dist/engine/dispatcher.d.ts +60 -0
  146. package/dist/engine/dispatcher.js +601 -0
  147. package/dist/engine/dispatcher.js.map +1 -0
  148. package/dist/engine/dispatcher.test.d.ts +1 -0
  149. package/dist/engine/dispatcher.test.js +511 -0
  150. package/dist/engine/dispatcher.test.js.map +1 -0
  151. package/dist/engine/event-shim.d.ts +117 -0
  152. package/dist/engine/event-shim.js +435 -0
  153. package/dist/engine/event-shim.js.map +1 -0
  154. package/dist/engine/event-shim.test.d.ts +1 -0
  155. package/dist/engine/event-shim.test.js +194 -0
  156. package/dist/engine/event-shim.test.js.map +1 -0
  157. package/dist/engine/git-auth.d.ts +13 -17
  158. package/dist/engine/git-auth.js +99 -42
  159. package/dist/engine/git-auth.js.map +1 -1
  160. package/dist/engine/git-auth.test.d.ts +1 -0
  161. package/dist/engine/git-auth.test.js +117 -0
  162. package/dist/engine/git-auth.test.js.map +1 -0
  163. package/dist/engine/github-app-client.d.ts +7 -0
  164. package/dist/engine/github-app-client.js +16 -0
  165. package/dist/engine/github-app-client.js.map +1 -0
  166. package/dist/engine/github-app-client.test.d.ts +1 -0
  167. package/dist/engine/github-app-client.test.js +44 -0
  168. package/dist/engine/github-app-client.test.js.map +1 -0
  169. package/dist/engine/github-tools.d.ts +12 -0
  170. package/dist/engine/github-tools.js +261 -0
  171. package/dist/engine/github-tools.js.map +1 -0
  172. package/dist/engine/github.d.ts +1027 -43
  173. package/dist/engine/github.js +153 -14
  174. package/dist/engine/github.js.map +1 -1
  175. package/dist/engine/llm.d.ts +47 -0
  176. package/dist/engine/llm.js +221 -0
  177. package/dist/engine/llm.js.map +1 -0
  178. package/dist/engine/llm.test.d.ts +1 -0
  179. package/dist/engine/llm.test.js +189 -0
  180. package/dist/engine/llm.test.js.map +1 -0
  181. package/dist/engine/profiles.d.ts +249 -0
  182. package/dist/engine/profiles.js +42 -0
  183. package/dist/engine/profiles.js.map +1 -0
  184. package/dist/engine/router.d.ts +12 -6
  185. package/dist/engine/router.js +339 -81
  186. package/dist/engine/router.js.map +1 -1
  187. package/dist/engine/router.test.js +428 -78
  188. package/dist/engine/router.test.js.map +1 -1
  189. package/dist/engine/screen.d.ts +41 -0
  190. package/dist/engine/screen.js +93 -0
  191. package/dist/engine/screen.js.map +1 -0
  192. package/dist/engine/screen.test.d.ts +1 -0
  193. package/dist/engine/screen.test.js +82 -0
  194. package/dist/engine/screen.test.js.map +1 -0
  195. package/dist/index.js +423 -437
  196. package/dist/index.js.map +1 -1
  197. package/dist/managed-repos.d.ts +7 -9
  198. package/dist/managed-repos.js +12 -15
  199. package/dist/managed-repos.js.map +1 -1
  200. package/dist/managed-repos.test.js +24 -19
  201. package/dist/managed-repos.test.js.map +1 -1
  202. package/dist/notify/index.d.ts +15 -0
  203. package/dist/notify/index.js +6 -0
  204. package/dist/notify/index.js.map +1 -0
  205. package/dist/notify/model.d.ts +57 -0
  206. package/dist/notify/model.js +89 -0
  207. package/dist/notify/model.js.map +1 -0
  208. package/dist/notify/model.test.d.ts +1 -0
  209. package/dist/notify/model.test.js +109 -0
  210. package/dist/notify/model.test.js.map +1 -0
  211. package/dist/notify/notifier.d.ts +17 -0
  212. package/dist/notify/notifier.js +87 -0
  213. package/dist/notify/notifier.js.map +1 -0
  214. package/dist/notify/notifier.test.d.ts +1 -0
  215. package/dist/notify/notifier.test.js +100 -0
  216. package/dist/notify/notifier.test.js.map +1 -0
  217. package/dist/notify/render.d.ts +21 -0
  218. package/dist/notify/render.js +59 -0
  219. package/dist/notify/render.js.map +1 -0
  220. package/dist/notify/render.test.d.ts +1 -0
  221. package/dist/notify/render.test.js +65 -0
  222. package/dist/notify/render.test.js.map +1 -0
  223. package/dist/notify/transports/github.d.ts +26 -0
  224. package/dist/notify/transports/github.js +26 -0
  225. package/dist/notify/transports/github.js.map +1 -0
  226. package/dist/notify/transports/slack.d.ts +26 -0
  227. package/dist/notify/transports/slack.js +28 -0
  228. package/dist/notify/transports/slack.js.map +1 -0
  229. package/dist/notify/transports.test.d.ts +1 -0
  230. package/dist/notify/transports.test.js +71 -0
  231. package/dist/notify/transports.test.js.map +1 -0
  232. package/dist/notify/types.d.ts +95 -0
  233. package/dist/notify/types.js +16 -0
  234. package/dist/notify/types.js.map +1 -0
  235. package/dist/sandbox/docker-compose.test.d.ts +1 -0
  236. package/dist/sandbox/docker-compose.test.js +128 -0
  237. package/dist/sandbox/docker-compose.test.js.map +1 -0
  238. package/dist/sandbox/docker.d.ts +97 -9
  239. package/dist/sandbox/docker.js +192 -41
  240. package/dist/sandbox/docker.js.map +1 -1
  241. package/dist/sandbox/docker.test.d.ts +1 -0
  242. package/dist/sandbox/docker.test.js +137 -0
  243. package/dist/sandbox/docker.test.js.map +1 -0
  244. package/dist/sandbox/egress-allowlist.d.ts +69 -0
  245. package/dist/sandbox/egress-allowlist.js +164 -0
  246. package/dist/sandbox/egress-allowlist.js.map +1 -0
  247. package/dist/sandbox/egress-allowlist.test.d.ts +1 -0
  248. package/dist/sandbox/egress-allowlist.test.js +65 -0
  249. package/dist/sandbox/egress-allowlist.test.js.map +1 -0
  250. package/dist/sandbox/egress-firewall-config.d.ts +127 -0
  251. package/dist/sandbox/egress-firewall-config.js +434 -0
  252. package/dist/sandbox/egress-firewall-config.js.map +1 -0
  253. package/dist/sandbox/egress-firewall-config.test.d.ts +1 -0
  254. package/dist/sandbox/egress-firewall-config.test.js +244 -0
  255. package/dist/sandbox/egress-firewall-config.test.js.map +1 -0
  256. package/dist/sandbox/images.d.ts +23 -0
  257. package/dist/sandbox/images.js +55 -0
  258. package/dist/sandbox/images.js.map +1 -0
  259. package/dist/sandbox/index.d.ts +82 -3
  260. package/dist/sandbox/index.js +223 -93
  261. package/dist/sandbox/index.js.map +1 -1
  262. package/dist/sandbox/index.test.d.ts +1 -0
  263. package/dist/sandbox/index.test.js +157 -0
  264. package/dist/sandbox/index.test.js.map +1 -0
  265. package/dist/session-log.d.ts +63 -0
  266. package/dist/session-log.js +290 -0
  267. package/dist/session-log.js.map +1 -0
  268. package/dist/session-log.test.d.ts +1 -0
  269. package/dist/session-log.test.js +85 -0
  270. package/dist/session-log.test.js.map +1 -0
  271. package/dist/setup.d.ts +31 -12
  272. package/dist/setup.js +516 -174
  273. package/dist/setup.js.map +1 -1
  274. package/dist/setup.test.js +138 -6
  275. package/dist/setup.test.js.map +1 -1
  276. package/dist/state/approval-store.d.ts +86 -0
  277. package/dist/state/approval-store.js +140 -0
  278. package/dist/state/approval-store.js.map +1 -0
  279. package/dist/state/build-assets.d.ts +50 -0
  280. package/dist/state/build-assets.js +154 -0
  281. package/dist/state/build-assets.js.map +1 -0
  282. package/dist/state/build-assets.test.d.ts +1 -0
  283. package/dist/state/build-assets.test.js +106 -0
  284. package/dist/state/build-assets.test.js.map +1 -0
  285. package/dist/state/db.d.ts +65 -333
  286. package/dist/state/db.js +112 -835
  287. package/dist/state/db.js.map +1 -1
  288. package/dist/state/db.test.js +127 -91
  289. package/dist/state/db.test.js.map +1 -1
  290. package/dist/state/execution-store.d.ts +257 -0
  291. package/dist/state/execution-store.js +527 -0
  292. package/dist/state/execution-store.js.map +1 -0
  293. package/dist/state/migrate.d.ts +15 -0
  294. package/dist/state/migrate.js +175 -0
  295. package/dist/state/migrate.js.map +1 -0
  296. package/dist/state/workflow-run-store.d.ts +195 -0
  297. package/dist/state/workflow-run-store.js +363 -0
  298. package/dist/state/workflow-run-store.js.map +1 -0
  299. package/dist/state/workflow-run-store.test.d.ts +1 -0
  300. package/dist/state/workflow-run-store.test.js +264 -0
  301. package/dist/state/workflow-run-store.test.js.map +1 -0
  302. package/dist/telemetry/index.d.ts +38 -0
  303. package/dist/telemetry/index.js +253 -0
  304. package/dist/telemetry/index.js.map +1 -0
  305. package/dist/telemetry/index.test.d.ts +1 -0
  306. package/dist/telemetry/index.test.js +73 -0
  307. package/dist/telemetry/index.test.js.map +1 -0
  308. package/dist/telemetry/pi-events.d.ts +12 -0
  309. package/dist/telemetry/pi-events.js +134 -0
  310. package/dist/telemetry/pi-events.js.map +1 -0
  311. package/dist/telemetry/pi-events.test.d.ts +1 -0
  312. package/dist/telemetry/pi-events.test.js +69 -0
  313. package/dist/telemetry/pi-events.test.js.map +1 -0
  314. package/dist/workflows/dag.d.ts +13 -1
  315. package/dist/workflows/dag.js +7 -3
  316. package/dist/workflows/dag.js.map +1 -1
  317. package/dist/workflows/dag.test.js +22 -0
  318. package/dist/workflows/dag.test.js.map +1 -1
  319. package/dist/workflows/golden-build.test.d.ts +1 -0
  320. package/dist/workflows/golden-build.test.js +45 -0
  321. package/dist/workflows/golden-build.test.js.map +1 -0
  322. package/dist/workflows/loader-overlay.test.d.ts +1 -0
  323. package/dist/workflows/loader-overlay.test.js +101 -0
  324. package/dist/workflows/loader-overlay.test.js.map +1 -0
  325. package/dist/workflows/loader.d.ts +36 -11
  326. package/dist/workflows/loader.js +311 -87
  327. package/dist/workflows/loader.js.map +1 -1
  328. package/dist/workflows/loader.test.js +114 -10
  329. package/dist/workflows/loader.test.js.map +1 -1
  330. package/dist/workflows/loop-eval.js +2 -0
  331. package/dist/workflows/loop-eval.js.map +1 -1
  332. package/dist/workflows/loop-eval.test.js +14 -0
  333. package/dist/workflows/loop-eval.test.js.map +1 -1
  334. package/dist/workflows/phase-executor.d.ts +145 -0
  335. package/dist/workflows/phase-executor.js +691 -0
  336. package/dist/workflows/phase-executor.js.map +1 -0
  337. package/dist/workflows/phase-executor.test.d.ts +1 -0
  338. package/dist/workflows/phase-executor.test.js +434 -0
  339. package/dist/workflows/phase-executor.test.js.map +1 -0
  340. package/dist/workflows/phase-ref.d.ts +44 -0
  341. package/dist/workflows/phase-ref.js +78 -0
  342. package/dist/workflows/phase-ref.js.map +1 -0
  343. package/dist/workflows/phase-ref.test.d.ts +1 -0
  344. package/dist/workflows/phase-ref.test.js +24 -0
  345. package/dist/workflows/phase-ref.test.js.map +1 -0
  346. package/dist/workflows/resume.d.ts +5 -11
  347. package/dist/workflows/resume.js +88 -7
  348. package/dist/workflows/resume.js.map +1 -1
  349. package/dist/workflows/runner.d.ts +34 -27
  350. package/dist/workflows/runner.js +252 -930
  351. package/dist/workflows/runner.js.map +1 -1
  352. package/dist/workflows/runner.test.js +346 -35
  353. package/dist/workflows/runner.test.js.map +1 -1
  354. package/dist/workflows/schema.d.ts +52 -10
  355. package/dist/workflows/schema.js +147 -7
  356. package/dist/workflows/schema.js.map +1 -1
  357. package/dist/workflows/simple.d.ts +67 -3
  358. package/dist/workflows/simple.js +248 -87
  359. package/dist/workflows/simple.js.map +1 -1
  360. package/dist/workflows/simple.test.d.ts +1 -0
  361. package/dist/workflows/simple.test.js +107 -0
  362. package/dist/workflows/simple.test.js.map +1 -0
  363. package/dist/workflows/templates.d.ts +29 -0
  364. package/dist/workflows/templates.js +42 -4
  365. package/dist/workflows/templates.js.map +1 -1
  366. package/dist/workflows/templates.test.js +103 -0
  367. package/dist/workflows/templates.test.js.map +1 -1
  368. package/dist/workflows/triggers.d.ts +21 -0
  369. package/dist/workflows/triggers.js +44 -0
  370. package/dist/workflows/triggers.js.map +1 -0
  371. package/dist/workflows/verdict.d.ts +19 -0
  372. package/dist/workflows/verdict.js +30 -0
  373. package/dist/workflows/verdict.js.map +1 -0
  374. package/dist/workflows/verdict.test.d.ts +1 -0
  375. package/dist/workflows/verdict.test.js +44 -0
  376. package/dist/workflows/verdict.test.js.map +1 -0
  377. package/dist/worktree/manager.d.ts +1 -1
  378. package/dist/worktree/manager.js +14 -14
  379. package/dist/worktree/manager.js.map +1 -1
  380. package/dist/worktree/manager.test.d.ts +1 -0
  381. package/dist/worktree/manager.test.js +87 -0
  382. package/dist/worktree/manager.test.js.map +1 -0
  383. package/docker-compose.yml +206 -5
  384. package/package.json +19 -7
  385. package/sandbox.Dockerfile +97 -18
  386. package/skills/README.md +40 -0
  387. package/skills/browser-qa/SKILL.md +193 -0
  388. package/skills/browser-qa/scripts/agent-browser.mjs +380 -0
  389. package/skills/building/SKILL.md +95 -0
  390. package/skills/chat/SKILL.md +30 -11
  391. package/skills/code-review/SKILL.md +59 -0
  392. package/skills/debug-production/SKILL.md +108 -0
  393. package/skills/demo/SKILL.md +194 -0
  394. package/skills/demo/scripts/compose-demo.sh +205 -0
  395. package/skills/issue-answer/SKILL.md +90 -0
  396. package/skills/issue-comment/SKILL.md +38 -24
  397. package/skills/issue-triage/SKILL.md +103 -37
  398. package/skills/issue-triage/references/AGENT-BRIEF.md +61 -0
  399. package/skills/pr-comment/SKILL.md +64 -0
  400. package/skills/pr-review/SKILL.md +65 -49
  401. package/skills/qa-test/SKILL.md +97 -0
  402. package/skills/repo-health/SKILL.md +48 -45
  403. package/skills/security-feedback/SKILL.md +173 -0
  404. package/skills/security-feedback/references/templates.md +77 -0
  405. package/skills/security-review/SKILL.md +213 -0
  406. package/skills/security-review/references/issue-format.md +302 -0
  407. package/skills/verify/SKILL.md +118 -0
  408. package/workflows/answer.yaml +37 -0
  409. package/workflows/build.yaml +32 -22
  410. package/workflows/cron-security.yaml +6 -0
  411. package/workflows/demo.yaml +55 -0
  412. package/workflows/explore.yaml +9 -0
  413. package/workflows/pr-comment.yaml +16 -0
  414. package/workflows/pr-fix.yaml +3 -0
  415. package/workflows/pr-review.yaml +4 -1
  416. package/workflows/prompts/answer.md +67 -0
  417. package/workflows/prompts/architect.md +24 -7
  418. package/workflows/prompts/demo.md +100 -0
  419. package/workflows/prompts/executor.md +29 -20
  420. package/workflows/prompts/explore-ask.md +51 -22
  421. package/workflows/prompts/explore-publish.md +2 -2
  422. package/workflows/prompts/explore-read.md +24 -10
  423. package/workflows/prompts/explore-synthesize.md +15 -8
  424. package/workflows/prompts/fix.md +9 -10
  425. package/workflows/prompts/guardrails.md +26 -8
  426. package/workflows/prompts/pr-fix.md +6 -7
  427. package/workflows/prompts/pr.md +11 -10
  428. package/workflows/prompts/qa-browser.md +95 -0
  429. package/workflows/prompts/qa-synth.md +44 -0
  430. package/workflows/prompts/qa-test.md +60 -0
  431. package/workflows/prompts/re-reviewer.md +8 -9
  432. package/workflows/prompts/reviewer.md +10 -9
  433. package/workflows/prompts/verify-browser.md +93 -0
  434. package/workflows/prompts/verify-synth.md +44 -0
  435. package/workflows/prompts/verify.md +63 -0
  436. package/workflows/qa-test.yaml +87 -0
  437. package/workflows/security-feedback.yaml +25 -0
  438. package/workflows/security-review.yaml +29 -0
  439. package/workflows/verify.yaml +85 -0
  440. package/deploy/mcp-config.tmpl.json +0 -14
  441. package/dist/cron/rate-limits.d.ts +0 -26
  442. package/dist/cron/rate-limits.js +0 -193
  443. package/dist/cron/rate-limits.js.map +0 -1
  444. package/dist/engine/executor.d.ts +0 -75
  445. package/dist/engine/executor.js +0 -292
  446. package/dist/engine/executor.js.map +0 -1
  447. package/mcp-github-app/package.json +0 -18
  448. package/mcp-github-app/src/auth.js +0 -66
  449. package/mcp-github-app/src/github.js +0 -371
  450. package/mcp-github-app/src/index.js +0 -534
  451. package/skills/devops/webhook-subscriptions/SKILL.md +0 -180
  452. package/skills/github/DESCRIPTION.md +0 -3
  453. package/skills/github/codebase-inspection/SKILL.md +0 -115
  454. package/skills/github/github-auth/SKILL.md +0 -54
  455. package/skills/github/github-auth/scripts/gh-env.sh +0 -66
  456. package/skills/github/github-code-review/SKILL.md +0 -480
  457. package/skills/github/github-code-review/references/review-output-template.md +0 -74
  458. package/skills/github/github-issues/SKILL.md +0 -369
  459. package/skills/github/github-issues/templates/bug-report.md +0 -35
  460. package/skills/github/github-issues/templates/feature-request.md +0 -31
  461. package/skills/github/github-pr-workflow/SKILL.md +0 -395
  462. package/skills/github/github-pr-workflow/references/ci-troubleshooting.md +0 -183
  463. package/skills/github/github-pr-workflow/references/conventional-commits.md +0 -71
  464. package/skills/github/github-pr-workflow/templates/pr-body-bugfix.md +0 -35
  465. package/skills/github/github-pr-workflow/templates/pr-body-feature.md +0 -33
  466. package/skills/github/github-repo-management/SKILL.md +0 -515
  467. package/skills/github/github-repo-management/references/github-api-cheatsheet.md +0 -161
  468. package/skills/github-orchestrator/SKILL.md +0 -103
  469. package/skills/mcp/DESCRIPTION.md +0 -3
  470. package/skills/mcp/mcporter/SKILL.md +0 -122
  471. package/skills/mcp/native-mcp/SKILL.md +0 -356
  472. package/skills/software-development/architect/SKILL.md +0 -154
  473. package/skills/software-development/assure-guardrails/SKILL.md +0 -239
  474. package/skills/software-development/plan/SKILL.md +0 -64
  475. package/skills/software-development/requesting-code-review/SKILL.md +0 -291
  476. package/skills/software-development/subagent-driven-development/SKILL.md +0 -433
  477. package/skills/software-development/systematic-debugging/SKILL.md +0 -366
  478. package/skills/software-development/test-driven-development/SKILL.md +0 -342
@@ -0,0 +1,93 @@
1
+ You are running the **browser-QA pass** of a verify run — driving the claim's
2
+ behaviour in a **real headless browser** and capturing **screenshot evidence**.
3
+ A text-evidence verify already ran and posted its verdict; your job is to add
4
+ visual proof (or to settle a claim that can only be shown in a rendered UI).
5
+ Read the `browser-qa` skill for the driver contract and the `verify` skill for
6
+ the investigator rules, then follow them. The `building` skill installs and runs
7
+ the repo.
8
+
9
+ **Stay in the browser.** Do **not** read, quote, or analyse the repo's source
10
+ code — the text pass already covered the code. Your evidence is strictly what
11
+ the browser shows: the driver's extracted text, assertion results, console
12
+ errors, and the screenshots. No `index.html`/CSS walkthroughs, no "from the
13
+ checked-in code" observations.
14
+
15
+ ## The claim to test
16
+
17
+ {{#if commentBody}}
18
+ **Claim / request:**
19
+ {{commentBody}}
20
+ {{/if}}
21
+ {{#if issueTitle}}**Issue/PR title:** {{issueTitle}}{{/if}}
22
+ {{#if issueBody}}
23
+ **Issue/PR body:**
24
+ {{issueBody}}
25
+ {{/if}}
26
+
27
+ Target repo: **{{owner}}/{{repo}}**
28
+ {{#if issueNumber}}Target issue/PR: **#{{issueNumber}}**{{/if}}
29
+
30
+ If the claim is purely about non-UI behaviour (a CLI, an API response, a pure
31
+ function) the text pass already covered it — keep this pass short: note that the
32
+ claim isn't UI-shaped and that no browser evidence was needed. Spend the effort
33
+ where a rendered UI is the only place the claim shows.
34
+
35
+ ## First: confirm the browser is available
36
+
37
+ Run the driver's probe before anything else:
38
+
39
+ ```
40
+ node <browser-qa skill dir>/scripts/agent-browser.mjs doctor
41
+ ```
42
+
43
+ (The `browser-qa` skill is staged into this phase's skill bundle — find its
44
+ absolute path from the available-skills catalogue.) If `doctor` exits non-zero,
45
+ the browser toolchain isn't present: say so plainly and stop — do not fake
46
+ screenshots. This phase only runs on the docker QA image, so `doctor` should
47
+ pass.
48
+
49
+ ## Workspace + run the app
50
+
51
+ You are already inside the **{{repo}}** repo at branch {{branch}} — the harness
52
+ pre-cloned it and your cwd is the repo root (no `cd`). For a PR claim, check out
53
+ the PR head. Follow the `building` skill to install and start the app's
54
+ dev-server in the background; wait until it's listening on `localhost`.
55
+
56
+ ## Drive the UI and capture evidence
57
+
58
+ Author a `flow.json` (shape documented in the `browser-qa` skill), then run
59
+ `agent-browser.mjs run flow.json --base-url http://localhost:<port>
60
+ --out-dir {{issueDir}}`. Save every screenshot under **`{{issueDir}}/`** — the
61
+ harness harvests that directory. Parse the JSON report (extracted text,
62
+ assertion results, console errors) — that, not the images, is what you reason
63
+ over. For a before/after regression claim, capture both states.
64
+
65
+ ## How your report is delivered — read carefully
66
+
67
+ Your **final message is the report**, and the harness posts it for you{{#if issueNumber}} as
68
+ a comment on **#{{issueNumber}}**{{/if}}{{#if !issueNumber}} back into the thread this request came from{{/if}}.
69
+ Title it clearly as the **browser-QA evidence** so it reads as a supplement to
70
+ the text verdict, not a competing one. Use the `verify` report shape
71
+ (Environment / Evidence / **Conclusion: CONFIRMED | REFUTED | INCONCLUSIVE**).
72
+
73
+ **Keep it tight** — a one-line environment summary, the evidence (screenshots +
74
+ the key assertion/text/console results), and a one-sentence conclusion. No
75
+ per-step narration, no code analysis, no long Coverage prose; a short
76
+ "what was / wasn't exercised" is enough.
77
+
78
+ **Embed each screenshot inline** so it renders in the comment.
79
+ {{#if artifactBaseUrl}}Every PNG you saved to `<name>.png` is served publicly at
80
+ `{{artifactBaseUrl}}/<name>.png`. Write a **raw Markdown image** for each one
81
+ under Evidence — `!` then `[caption]` then the URL in parentheses — on its own
82
+ line. Do **NOT** wrap it in backticks or a code fence; inside a code span it
83
+ shows as literal text instead of rendering. For example, a screenshot saved as
84
+ `home.png` becomes a line reading: an exclamation mark, `[Home]`, then
85
+ `({{artifactBaseUrl}}/home.png)` with no spaces and no backticks.{{/if}}{{#if !artifactBaseUrl}}No
86
+ public URL is configured, so reference each screenshot by filename (e.g.
87
+ `after-login.png`) and note it's in the run's Artifacts view.{{/if}}
88
+
89
+ **Do NOT post it yourself** with `github_add_issue_comment` — that would
90
+ double-post. Never fabricate a screenshot or a pass; a clearly-evidenced
91
+ **REFUTED** is a real finding. If screenshots couldn't be persisted (no
92
+ server-mode build assets), still report what the DOM/text evidence showed and
93
+ say the images weren't retained.
@@ -0,0 +1,44 @@
1
+ You are writing the **single final verdict** for a verify run. Two passes have
2
+ already run: a text-evidence verification and (sometimes) a browser-QA pass.
3
+ Your job is to **synthesize them into one concise comment** — the reader sees
4
+ only your output, not the individual passes.
5
+
6
+ This is a **pure writing task**. Do **not** run commands, install anything, read
7
+ repo files, or start a server — everything you need is below. Do **not** post a
8
+ comment yourself (`github_add_issue_comment`); your final message *is* the
9
+ comment, delivered by the harness.
10
+
11
+ ## The claim
12
+
13
+ {{#if commentBody}}{{commentBody}}{{/if}}{{#if issueTitle}} (issue/PR: {{issueTitle}}){{/if}}
14
+
15
+ ## Text-verification report
16
+
17
+ {{verifyResult}}
18
+
19
+ {{#if verifyBrowserResult}}
20
+ ## Browser-QA report (real headless browser + screenshots)
21
+
22
+ {{verifyBrowserResult}}
23
+ {{/if}}
24
+
25
+ ## Write the verdict
26
+
27
+ Produce a tight Markdown comment:
28
+
29
+ - **Lead with the conclusion** on its own line: **CONFIRMED**, **REFUTED**, or
30
+ **INCONCLUSIVE**. If the two passes disagree, reconcile them and say why the
31
+ combined evidence lands where it does (browser evidence is decisive for
32
+ rendered-UI behaviour; text evidence for everything else).
33
+ - One short paragraph of the **key evidence** that settles it — the decisive
34
+ commands/output and assertion results, not a replay of both reports.
35
+ {{#if verifyBrowserResult}}- **Embed the browser screenshots inline** exactly as they appear in the
36
+ browser-QA report above (the `![caption](https://…/<name>.png)` image
37
+ Markdown) so they render in this comment. Keep them; don't turn them into
38
+ plain links or drop them.{{/if}}
39
+ - A one-line **coverage** note: what was exercised, and anything notable that
40
+ wasn't.
41
+
42
+ Keep it short and decisive — no per-step narration, no restating both reports in
43
+ full. If a pass reported a failure or a REFUTED, surface it plainly; don't bury
44
+ it under the other pass.
@@ -0,0 +1,63 @@
1
+ You are **verifying a claim** — testing whether a stated behaviour is actually
2
+ true and reporting the evidence. Read the `verify` skill for the full procedure
3
+ and investigator rules, then follow it. It uses the `building` skill for
4
+ installing and running the repo. This prompt gives you the claim and how your
5
+ report is delivered.
6
+
7
+ ## The claim to test
8
+
9
+ {{#if commentBody}}
10
+ **Claim / request:**
11
+ {{commentBody}}
12
+ {{/if}}
13
+ {{#if issueTitle}}**Issue/PR title:** {{issueTitle}}{{/if}}
14
+ {{#if issueBody}}
15
+ **Issue/PR body:**
16
+ {{issueBody}}
17
+ {{/if}}
18
+
19
+ Target repo: **{{owner}}/{{repo}}**
20
+ {{#if issueNumber}}Target issue/PR: **#{{issueNumber}}**{{/if}}
21
+
22
+ If no explicit claim is given and this is a PR, read the PR description + diff
23
+ and pick the single most important, most testable claim it makes — and say which
24
+ claim you chose.
25
+
26
+ ## Workspace
27
+
28
+ You are already inside the **{{repo}}** repo at branch {{branch}} — the harness
29
+ pre-cloned it and your cwd is the repo root. Git is configured; no clone, no
30
+ `cd`. For a PR claim, check out the PR head (see the `pr-review`/`building`
31
+ workspace notes); for a before/after claim, `git fetch` the base ref too.
32
+
33
+ ## First — is this even a text-checkable claim?
34
+
35
+ You have **bash, file read, and the github tools** — no browser, no
36
+ screenshots, no video. Before doing any setup, judge whether the claim is
37
+ **purely about a rendered UI** (visual layout, mobile rendering, a click/render
38
+ flow that only shows in a browser). If it is, **do not install/build/guess** —
39
+ a dedicated browser-QA pass runs after you and owns it. Say in one line that the
40
+ claim is UI-shaped and defer it to the browser pass, conclude **INCONCLUSIVE
41
+ (UI-only — deferred to browser QA)**, and stop. Spend your effort only on claims
42
+ bash can actually settle.
43
+
44
+ ## Evidence — what you can and can't capture
45
+
46
+ For a text-checkable claim, prove it with test output, command stdout/stderr,
47
+ exit codes, `curl` against a dev-server you start, and log/file excerpts.
48
+
49
+ ## How your report is delivered — read carefully
50
+
51
+ Your **final message is the report**, and the harness posts it for you:
52
+ {{#if issueNumber}}
53
+ - as a comment on **#{{issueNumber}}**.
54
+ {{/if}}
55
+ {{#if !issueNumber}}
56
+ - back into the thread this request came from.
57
+ {{/if}}
58
+
59
+ Make your final message the complete report in the shape the `verify` skill
60
+ defines (Environment / Evidence / **Conclusion: CONFIRMED | REFUTED |
61
+ INCONCLUSIVE**). **Do NOT post it yourself** with `github_add_issue_comment` —
62
+ that would double-post. The only acceptable result that contradicts the claim is
63
+ a clearly-evidenced **REFUTED**; surface it, don't bury it.
@@ -0,0 +1,87 @@
1
+ kind: qa-test
2
+ name: qa-test
3
+ description: |
4
+ Run an automated QA flow against a repo's CLI or locally-served app and report
5
+ step-level pass/fail with evidence. It installs and runs the code in the
6
+ sandbox, exercises a flow (CLI invocations or curl against a dev-server),
7
+ optionally drives the UI in a real browser, then posts a single per-step QA
8
+ report. Does not modify code.
9
+
10
+ Delivery is a single in-place status comment (`status_checklist`): the run
11
+ shows its phases ticking off, then a final `synthesize` phase folds the text
12
+ report and (when it ran) the browser evidence into ONE combined report,
13
+ delivered as the comment's footer via `final_message`. No comment-per-phase.
14
+ Posted on the originating issue/PR for GitHub runs, or into the Slack thread
15
+ for Slack runs. The agents therefore do NOT post anything themselves.
16
+
17
+ When the host runs the docker backend with the browser-QA image built, the
18
+ gated `qa_browser` phase drives a real headless Chromium against the
19
+ locally-served app and captures step-level screenshot evidence; everywhere
20
+ else it is silently skipped (graceful degradation) and the text report stands
21
+ alone. The synthesis runs either way.
22
+
23
+ Triggered by:
24
+ - a `@last-light qa-test <target> [-- steps]` comment on an issue/PR
25
+ - manual CLI: tsx src/cli.ts qa-test owner/repo#N -- "<steps>"
26
+
27
+ status_checklist: true
28
+ final_message: "{{synthesisResult}}"
29
+
30
+ phases:
31
+ - name: phase_0
32
+ label: Context
33
+ type: context
34
+ depends_on: []
35
+
36
+ - name: qa_test
37
+ label: QA Test
38
+ depends_on: [phase_0]
39
+ prompt: prompts/qa-test.md
40
+ # qa-test: the flow procedure + report shape (primary).
41
+ # building: install + run the repo to exercise the flow.
42
+ skills: [qa-test, building]
43
+ model: "{{models.qa-test}}"
44
+ variant: "{{variants.qa-test}}"
45
+ output_var: qaResult
46
+ messages:
47
+ on_start: "Running the QA flow — installing, running, and exercising each step..."
48
+ on_success: "Text QA flow complete."
49
+ on_failure: "I couldn't complete the QA run — see the logs for details."
50
+
51
+ # Browser-QA pass (Tier B). Gated to the docker backend AND the enriched
52
+ # `lastlight-sandbox-qa:latest` image (Playwright + Chromium). On gondolin, or
53
+ # a docker host without that image, the scheduler silently skips this phase.
54
+ # It is terminal (nothing depends on it) — `synthesize` depends only on
55
+ # `qa_test`, so it still runs (after this phase, by declaration order) and
56
+ # folds in `qaBrowserResult` only when this phase actually produced it.
57
+ - name: qa_browser
58
+ label: QA Test (browser)
59
+ depends_on: [qa_test]
60
+ prompt: prompts/qa-browser.md
61
+ skills: [qa-test, building, browser-qa]
62
+ model: "{{models.qa-test}}"
63
+ variant: "{{variants.qa-test}}"
64
+ requires_sandbox: docker
65
+ sandbox_image: qa
66
+ output_var: qaBrowserResult
67
+ messages:
68
+ on_start: "Browser QA available — driving the UI and capturing screenshots..."
69
+ on_success: "Browser QA complete — screenshots captured."
70
+ on_skipped_done: "Browser QA unavailable on this host — text report stands."
71
+
72
+ # Synthesis. Depends only on `qa_test` (always runs after the gated browser
73
+ # phase by declaration order, and never skips when that phase is gated out).
74
+ # Reads the prior reports from phaseOutputs and writes ONE combined report;
75
+ # its output (`synthesisResult`) becomes the comment footer via the
76
+ # workflow-level `final_message`. Pure composition — no skills, no repo work.
77
+ - name: synthesize
78
+ label: Summary
79
+ depends_on: [qa_test]
80
+ prompt: prompts/qa-synth.md
81
+ model: "{{models.qa-test}}"
82
+ variant: "{{variants.qa-test}}"
83
+ output_var: synthesisResult
84
+ messages:
85
+ on_start: "Synthesizing the final report..."
86
+ on_success: "Report posted below."
87
+ on_failure: "I couldn't synthesize the final report — see the logs."
@@ -0,0 +1,25 @@
1
+ kind: health
2
+ name: security-feedback
3
+ description: |
4
+ Process maintainer feedback on a security-labelled issue (usually a
5
+ per-run scan summary). Classifies the comment and acts:
6
+
7
+ - create-issues — break selected findings out into individual issues
8
+ that can later be fed to the `build` skill (the primary flow)
9
+ - accept-risk / false-positive — update SECURITY.md via PR to
10
+ suppress the finding in future scans
11
+ - reopen — ask the maintainer to re-run `@last-light security-review`
12
+ - discuss / ignore — reply conversationally or do nothing
13
+
14
+ The scan-summary issue grammar is defined in
15
+ `skills/security-review/SKILL.md § Issue format`; this skill's parser
16
+ mirrors it (version-checked on entry).
17
+
18
+ Triggered by:
19
+ - @last-light mention on issues labelled "security"
20
+
21
+ phases:
22
+ - name: feedback
23
+ label: Security feedback
24
+ skill: security-feedback
25
+ model: "{{models.security}}"
@@ -0,0 +1,29 @@
1
+ kind: health
2
+ name: security-review
3
+ description: |
4
+ Scan the target repository for security issues using open-source tools
5
+ (npm audit, semgrep, gitleaks) plus AI code review. Files ONE summary
6
+ issue per run (Renovate-style) containing a GitHub task list of every
7
+ finding grouped by Critical / High / Medium / Low. Honours SECURITY.md
8
+ for known false positives and accepted risks.
9
+
10
+ Maintainers break findings out into individual issues by commenting on
11
+ the summary issue (see the `security-feedback` skill — which handles
12
+ `@last-light create issues for the criticals`, per-item accept-risk /
13
+ false-positive commands, and conversational follow-ups).
14
+
15
+ Each invocation scans exactly ONE repo. The weekly cron fans out into
16
+ one independent run per managed repo.
17
+
18
+ Triggered by:
19
+ - weekly cron (Monday 10:00, fans out over every managed repo)
20
+ - manual CLI: tsx src/cli.ts security owner/repo
21
+ - @last-light security-review in a GitHub comment
22
+ - Slack: "security review cliftonc/repo"
23
+
24
+ phases:
25
+ - name: scan
26
+ label: Security scan
27
+ skill: security-review
28
+ model: "{{models.security}}"
29
+ variant: "{{variants.security}}"
@@ -0,0 +1,85 @@
1
+ kind: verify
2
+ name: verify
3
+ description: |
4
+ Verify a behaviour claim against a repo or PR and report whether the evidence
5
+ confirms or refutes it. It installs and runs the code in the sandbox, captures
6
+ bash/text evidence, optionally drives the UI in a real browser, then posts a
7
+ single CONFIRMED / REFUTED / INCONCLUSIVE verdict. Does not modify code.
8
+
9
+ Delivery is a single in-place status comment (`status_checklist`): the run
10
+ shows its phases ticking off, then a final `synthesize` phase folds the text
11
+ verdict and (when it ran) the browser evidence into ONE combined verdict,
12
+ delivered as the comment's footer via `final_message`. No comment-per-phase.
13
+ Posted on the originating issue/PR for GitHub runs, or into the Slack thread
14
+ for Slack runs. The agents therefore do NOT post anything themselves.
15
+
16
+ When the host runs the docker backend with the browser-QA image built, the
17
+ gated `verify_browser` phase drives the UI in a real headless Chromium and
18
+ captures screenshot evidence; everywhere else it is silently skipped (graceful
19
+ degradation) and the text verdict stands alone. The synthesis runs either way.
20
+
21
+ Triggered by:
22
+ - a `@last-light verify <claim>` comment on an issue/PR
23
+ - manual CLI: tsx src/cli.ts verify owner/repo#N -- "<claim>"
24
+
25
+ status_checklist: true
26
+ final_message: "{{synthesisResult}}"
27
+
28
+ phases:
29
+ - name: phase_0
30
+ label: Context
31
+ type: context
32
+ depends_on: []
33
+
34
+ - name: verify
35
+ label: Verify
36
+ depends_on: [phase_0]
37
+ prompt: prompts/verify.md
38
+ # verify: the investigator procedure + report shape (primary).
39
+ # building: install + run the repo to capture evidence.
40
+ skills: [verify, building]
41
+ model: "{{models.verify}}"
42
+ variant: "{{variants.verify}}"
43
+ output_var: verifyResult
44
+ messages:
45
+ on_start: "Verifying the claim — installing, running, and capturing evidence..."
46
+ on_success: "Text verification complete."
47
+ on_failure: "I couldn't complete the verification — see the logs for details."
48
+
49
+ # Browser-QA pass (Tier B). Gated to the docker backend AND the enriched
50
+ # `lastlight-sandbox-qa:latest` image (Playwright + Chromium). On gondolin, or
51
+ # a docker host without that image, the scheduler silently skips this phase.
52
+ # It is terminal (nothing depends on it) — `synthesize` depends only on
53
+ # `verify`, so it still runs (after this phase, by declaration order) and
54
+ # folds in `verifyBrowserResult` only when this phase actually produced it.
55
+ - name: verify_browser
56
+ label: Verify (browser)
57
+ depends_on: [verify]
58
+ prompt: prompts/verify-browser.md
59
+ skills: [verify, building, browser-qa]
60
+ model: "{{models.verify}}"
61
+ variant: "{{variants.verify}}"
62
+ requires_sandbox: docker
63
+ sandbox_image: qa
64
+ output_var: verifyBrowserResult
65
+ messages:
66
+ on_start: "Browser QA available — driving the UI and capturing screenshots..."
67
+ on_success: "Browser QA complete — screenshots captured."
68
+ on_skipped_done: "Browser QA unavailable on this host — text verdict stands."
69
+
70
+ # Synthesis. Depends only on `verify` (always runs after the gated browser
71
+ # phase by declaration order, and never skips when that phase is gated out).
72
+ # Reads the prior reports from phaseOutputs and writes ONE concise combined
73
+ # verdict; its output (`synthesisResult`) becomes the comment footer via the
74
+ # workflow-level `final_message`. Pure composition — no skills, no repo work.
75
+ - name: synthesize
76
+ label: Summary
77
+ depends_on: [verify]
78
+ prompt: prompts/verify-synth.md
79
+ model: "{{models.verify}}"
80
+ variant: "{{variants.verify}}"
81
+ output_var: synthesisResult
82
+ messages:
83
+ on_start: "Synthesizing the final verdict..."
84
+ on_success: "Verdict posted below."
85
+ on_failure: "I couldn't synthesize the final verdict — see the logs."
@@ -1,14 +0,0 @@
1
- {
2
- "mcpServers": {
3
- "github": {
4
- "command": "node",
5
- "args": ["/app/mcp-github-app/src/index.js"],
6
- "env": {
7
- "GITHUB_APP_ID": "${GITHUB_APP_ID}",
8
- "GITHUB_APP_PRIVATE_KEY_PATH": "${GITHUB_APP_PRIVATE_KEY_PATH}",
9
- "GITHUB_APP_INSTALLATION_ID": "${GITHUB_APP_INSTALLATION_ID}",
10
- "GITHUB_TOKEN": "${GITHUB_TOKEN}"
11
- }
12
- }
13
- }
14
- }
@@ -1,26 +0,0 @@
1
- import type { StateDb } from "../state/db.js";
2
- /** Component name used for the host claude CLI auth state in system_status. */
3
- export declare const HOST_CLAUDE_AUTH_COMPONENT = "host-claude-auth";
4
- /**
5
- * Optional notifier — called once when the auth state transitions to degraded.
6
- * Pass a SlackConnector's `sendToDeliveryChannel` (or any other channel).
7
- */
8
- export type AdminNotifier = (text: string) => Promise<void>;
9
- /**
10
- * Check Claude usage limits by making a minimal Agent SDK call
11
- * and parsing the stream-json output for rate_limit_event and usage data.
12
- *
13
- * Works with Claude subscriptions (no API key needed).
14
- *
15
- * Behavior:
16
- * - If the host claude CLI returns "Not logged in" / authentication_failed,
17
- * marks `system_status.host-claude-auth` as `degraded`, notifies the admin
18
- * on the first transition, and halts subsequent runs until cleared.
19
- * - The capacity check creates a JSONL session file as a side effect — we
20
- * delete it after parsing so it doesn't pollute the dashboard Sessions list.
21
- */
22
- export interface CheckApiUsageOptions {
23
- /** Bypass the auth-degraded early return — used by manual rechecks. */
24
- force?: boolean;
25
- }
26
- export declare function checkApiUsage(db: StateDb, notifyAdmin?: AdminNotifier, opts?: CheckApiUsageOptions): Promise<void>;
@@ -1,193 +0,0 @@
1
- /** Component name used for the host claude CLI auth state in system_status. */
2
- export const HOST_CLAUDE_AUTH_COMPONENT = "host-claude-auth";
3
- export async function checkApiUsage(db, notifyAdmin, opts = {}) {
4
- // Halt early if we're already in a degraded state — operator must clear it
5
- // (e.g. after `claude /login` + recheck) before this cron resumes.
6
- // The recheck endpoint passes force:true to bypass this.
7
- const existing = db.getSystemStatus(HOST_CLAUDE_AUTH_COMPONENT);
8
- if (!opts.force && existing?.state === "degraded") {
9
- console.log(`[usage] Skipping capacity check — host claude auth is degraded since ${existing.since}. Run claude /login on the host and trigger a recheck to resume.`);
10
- return;
11
- }
12
- const now = new Date().toISOString();
13
- let capacityCheckSessionId = "";
14
- let authFailed = false;
15
- let authFailureReason = "";
16
- // ── Capacity & rate limit check via claude CLI ──
17
- try {
18
- const { execFile } = await import("child_process");
19
- const { promisify } = await import("util");
20
- const exec = promisify(execFile);
21
- let stdout = "";
22
- try {
23
- // NOTE: do NOT pass --bare here. --bare disables OAuth credential
24
- // reading and requires ANTHROPIC_API_KEY, which we don't have on this
25
- // host (we authenticate via `claude /login` to a Claude subscription).
26
- const result = await exec("claude", [
27
- "--print", "reply with just: ok",
28
- "--output-format", "stream-json",
29
- "--verbose",
30
- "--max-turns", "1",
31
- "--model", process.env.CLAUDE_MODEL || "claude-sonnet-4-6",
32
- ], {
33
- timeout: 30_000,
34
- env: { ...process.env, HOME: process.env.HOME || "/home/lastlight" },
35
- });
36
- stdout = result.stdout;
37
- }
38
- catch (execErr) {
39
- // Non-zero exit (e.g. auth_failed) — claude still emits stream-json on stdout
40
- stdout = execErr.stdout?.toString() || "";
41
- if (!stdout) {
42
- // No output at all — propagate the underlying failure
43
- throw execErr;
44
- }
45
- }
46
- // Parse each JSON line from the stream output
47
- for (const line of stdout.split("\n")) {
48
- if (!line.startsWith("{"))
49
- continue;
50
- try {
51
- const msg = JSON.parse(line);
52
- // Capture session id so we can delete the JSONL file afterwards
53
- if (msg.type === "system" && msg.subtype === "init" && msg.session_id) {
54
- capacityCheckSessionId = msg.session_id;
55
- }
56
- // Detect "Not logged in" — claude emits a synthetic assistant message
57
- // with error: "authentication_failed" when the host CLI has no creds.
58
- if (msg.type === "assistant" && msg.error === "authentication_failed") {
59
- authFailed = true;
60
- const text = msg.message?.content?.[0]?.text || "Not logged in";
61
- authFailureReason = text;
62
- }
63
- // Rate limit info from subscription
64
- if (msg.type === "rate_limit_event" && msg.rate_limit_info) {
65
- const info = msg.rate_limit_info;
66
- db.updateRateLimit("subscription:status", info.status === "allowed" ? 1 : 0, now);
67
- db.updateRateLimit("subscription:type", 0, info.rateLimitType || "unknown");
68
- if (info.resetsAt) {
69
- db.updateRateLimit("subscription:resets_at", info.resetsAt, new Date(info.resetsAt * 1000).toISOString());
70
- }
71
- if (info.overageStatus) {
72
- db.updateRateLimit("subscription:overage_status", info.overageStatus === "allowed" ? 1 : 0, now);
73
- }
74
- if (info.overageResetsAt) {
75
- db.updateRateLimit("subscription:overage_resets_at", info.overageResetsAt, new Date(info.overageResetsAt * 1000).toISOString());
76
- }
77
- db.updateRateLimit("subscription:using_overage", info.isUsingOverage ? 1 : 0, now);
78
- console.log(`[usage] Subscription: ${info.status}, type=${info.rateLimitType}, overage=${info.isUsingOverage ? "yes" : "no"} (${info.overageStatus})`);
79
- }
80
- // Result with cost and usage breakdown
81
- if (msg.type === "result") {
82
- if (msg.total_cost_usd !== undefined) {
83
- // Store as cents to keep as integer
84
- db.updateRateLimit("usage:last_check_cost_cents", Math.round(msg.total_cost_usd * 100), now);
85
- }
86
- if (msg.usage) {
87
- db.updateRateLimit("usage:last_check_input_tokens", msg.usage.input_tokens || 0, now);
88
- db.updateRateLimit("usage:last_check_output_tokens", msg.usage.output_tokens || 0, now);
89
- }
90
- }
91
- }
92
- catch { /* skip unparseable lines */ }
93
- }
94
- }
95
- catch (err) {
96
- // The capacity check is best-effort — log and continue. Cleanup + status
97
- // handling below should still run regardless of the failure mode.
98
- db.updateRateLimit("subscription:status", 0, now);
99
- console.warn(`[usage] Capacity check failed: ${err.message}`);
100
- }
101
- // If the call surfaced an auth failure, mark the component degraded and
102
- // notify the admin once on transition. Subsequent runs early-return above.
103
- if (authFailed) {
104
- const transitioned = db.setSystemStatus(HOST_CLAUDE_AUTH_COMPONENT, "degraded", authFailureReason || "Host claude CLI is not logged in");
105
- if (transitioned) {
106
- console.error(`[usage] Host claude auth is now DEGRADED: ${authFailureReason}`);
107
- if (notifyAdmin) {
108
- const msg = `:rotating_light: *Last Light: host claude CLI auth degraded*\n` +
109
- `Reason: ${authFailureReason}\n` +
110
- `Action: run \`docker exec -it --user lastlight lastlight-agent-1 claude /login\` and then trigger a recheck.\n` +
111
- `The capacity-check cron is now halted to prevent log spam.`;
112
- try {
113
- await notifyAdmin(msg);
114
- }
115
- catch (notifyErr) {
116
- console.error(`[usage] Failed to notify admin: ${notifyErr.message}`);
117
- }
118
- }
119
- }
120
- }
121
- else {
122
- // Successful run — clear any prior degraded state
123
- const existing = db.getSystemStatus(HOST_CLAUDE_AUTH_COMPONENT);
124
- if (existing && existing.state !== "ok") {
125
- db.setSystemStatus(HOST_CLAUDE_AUTH_COMPONENT, "ok");
126
- console.log(`[usage] Host claude auth recovered — state cleared`);
127
- if (notifyAdmin) {
128
- try {
129
- await notifyAdmin(`:white_check_mark: Last Light: host claude CLI auth recovered. Capacity-check cron resuming normal operation.`);
130
- }
131
- catch { /* non-fatal */ }
132
- }
133
- }
134
- else if (!existing) {
135
- // First-ever successful run — initialize the state
136
- db.setSystemStatus(HOST_CLAUDE_AUTH_COMPONENT, "ok");
137
- }
138
- }
139
- // Run JSONL cleanup regardless of outcome (try/finally semantics).
140
- {
141
- // Delete the session JSONL file the capacity check created so it doesn't
142
- // pollute the dashboard Sessions list. Best-effort — ignore failures.
143
- if (capacityCheckSessionId) {
144
- try {
145
- const { unlink } = await import("fs/promises");
146
- const { join } = await import("path");
147
- const home = process.env.HOME || "/home/lastlight";
148
- // claude encodes the project's cwd as the directory name, replacing
149
- // path separators with dashes. e.g. /app -> -app
150
- const projectDir = process.cwd().replace(/\//g, "-");
151
- const sessionFile = join(home, ".claude", "projects", projectDir, `${capacityCheckSessionId}.jsonl`);
152
- await unlink(sessionFile);
153
- }
154
- catch {
155
- /* file may not exist or claude may not have written it — ignore */
156
- }
157
- }
158
- }
159
- // ── Usage stats from our own execution records ──
160
- try {
161
- const stats = computeUsageStats(db);
162
- db.updateRateLimit("usage:executions_1h", stats.lastHour, now);
163
- db.updateRateLimit("usage:executions_24h", stats.last24h, now);
164
- db.updateRateLimit("usage:turns_1h", stats.turnsLastHour, now);
165
- db.updateRateLimit("usage:turns_24h", stats.turnsLast24h, now);
166
- console.log(`[usage] Last 1h: ${stats.lastHour} executions, ${stats.turnsLastHour} turns | ` +
167
- `24h: ${stats.last24h} executions, ${stats.turnsLast24h} turns`);
168
- }
169
- catch (err) {
170
- console.error(`[usage] Stats computation failed: ${err.message}`);
171
- }
172
- }
173
- function computeUsageStats(db) {
174
- const now = Date.now();
175
- const oneHourAgo = new Date(now - 60 * 60 * 1000).toISOString();
176
- const oneDayAgo = new Date(now - 24 * 60 * 60 * 1000).toISOString();
177
- const raw = db.database;
178
- const h1 = raw.prepare(`
179
- SELECT COUNT(*) as count, COALESCE(SUM(turns), 0) as turns
180
- FROM executions WHERE started_at >= ?
181
- `).get(oneHourAgo);
182
- const h24 = raw.prepare(`
183
- SELECT COUNT(*) as count, COALESCE(SUM(turns), 0) as turns
184
- FROM executions WHERE started_at >= ?
185
- `).get(oneDayAgo);
186
- return {
187
- lastHour: h1.count,
188
- turnsLastHour: h1.turns,
189
- last24h: h24.count,
190
- turnsLast24h: h24.turns,
191
- };
192
- }
193
- //# sourceMappingURL=rate-limits.js.map