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,379 @@
1
+ /**
2
+ * In-process chat agent for Slack/Discord threads. Replaces the
3
+ * `opencode serve` HTTP supervisor with a direct pi-ai conversation:
4
+ *
5
+ * - One pi-ai conversation per messaging thread.
6
+ * - Conversation state lives in our existing `messaging_messages` DB
7
+ * table — rehydrated on every turn so harness restarts are transparent.
8
+ * - Tools are limited to read-only GitHub (see github-tools.ts). No bash,
9
+ * no edit, no file system, no MCP.
10
+ * - Per-thread in-flight chain so two messages in the same thread
11
+ * serialize cleanly while different threads stay parallel.
12
+ */
13
+ import { randomUUID } from "node:crypto";
14
+ import { Octokit } from "octokit";
15
+ import { completeSimple, getModel, } from "@earendil-works/pi-ai";
16
+ import { buildChatGitHubTools } from "./github-tools.js";
17
+ const MAX_TOOL_ROUNDS = 8;
18
+ /**
19
+ * Exponential backoff schedule (ms) for transient chat-model failures —
20
+ * rate limits (429) and provider hiccups (5xx / overloaded / transient
21
+ * network). pi-ai disables the provider SDK's own retries (`maxRetries: 0`),
22
+ * so without this a single 429 from the model would kill the whole turn.
23
+ * The sandbox path already retries via pi-coding-agent's auto-retry; the
24
+ * chat path drives pi-ai directly, so it needs its own.
25
+ */
26
+ const CHAT_RETRY_BACKOFF_MS = [10_000, 30_000, 60_000];
27
+ /**
28
+ * Match transient, retryable model errors. Deliberately conservative: auth /
29
+ * validation / context-overflow / other 4xx (anything but 429) are NOT
30
+ * retried — only rate limits, server errors, and transient network faults.
31
+ */
32
+ export function isRetryableModelError(message) {
33
+ const m = message.toLowerCase();
34
+ return (/\b429\b/.test(m) ||
35
+ m.includes("rate limit") ||
36
+ m.includes("rate_limit") ||
37
+ m.includes("too many requests") ||
38
+ m.includes("overloaded") ||
39
+ /\b50[0234]\b/.test(m) || // 500 / 502 / 503 / 504
40
+ m.includes("service unavailable") ||
41
+ m.includes("timeout") ||
42
+ m.includes("etimedout") ||
43
+ m.includes("econnreset") ||
44
+ m.includes("fetch failed"));
45
+ }
46
+ const sleepMs = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
47
+ /**
48
+ * Call `complete`, retrying transient failures with exponential backoff.
49
+ * Handles both shapes pi-ai surfaces a failure as: a thrown error, and a
50
+ * returned AssistantMessage with `stopReason === "error"`. Non-retryable
51
+ * outcomes (and the final attempt) are returned/thrown unchanged so the
52
+ * caller's existing error handling still applies. Dependency-injected for
53
+ * testing (`delaysMs` / `sleepFn` / `onRetry`).
54
+ */
55
+ export async function completeWithRetry(complete, model, context, opts, deps = {}) {
56
+ const delays = deps.delaysMs ?? CHAT_RETRY_BACKOFF_MS;
57
+ const doSleep = deps.sleepFn ?? sleepMs;
58
+ let attempt = 0;
59
+ for (;;) {
60
+ let assistant;
61
+ let errMsg;
62
+ let thrown;
63
+ try {
64
+ assistant = await complete(model, context, opts);
65
+ if (assistant.stopReason !== "error")
66
+ return assistant;
67
+ errMsg = assistant.errorMessage ?? "error";
68
+ }
69
+ catch (err) {
70
+ thrown = err;
71
+ errMsg = err instanceof Error ? err.message : String(err);
72
+ }
73
+ if (attempt >= delays.length || !isRetryableModelError(errMsg)) {
74
+ if (thrown !== undefined)
75
+ throw thrown; // preserve the original error
76
+ return assistant; // non-retryable / exhausted errored assistant
77
+ }
78
+ const delayMs = delays[attempt];
79
+ deps.onRetry?.({ attempt: attempt + 1, delayMs, reason: errMsg });
80
+ await doSleep(delayMs);
81
+ attempt++;
82
+ }
83
+ }
84
+ export class ChatRunner {
85
+ cfg;
86
+ sessionManager;
87
+ tools;
88
+ extraTools;
89
+ /** Concatenated tool list passed to pi-ai (github + extra). */
90
+ mergedTools;
91
+ /**
92
+ * Resolved lazily on the first chat turn. A bad chat model spec
93
+ * (unknown id) MUST NOT crash the whole harness — webhooks, crons and
94
+ * workflows don't depend on it.
95
+ */
96
+ model;
97
+ modelError;
98
+ chains = new Map();
99
+ constructor(cfg, sessionManager) {
100
+ this.cfg = cfg;
101
+ this.sessionManager = sessionManager;
102
+ if (cfg.github) {
103
+ this.tools = buildChatGitHubTools(cfg.github);
104
+ }
105
+ this.extraTools = cfg.extraTools;
106
+ const merged = [
107
+ ...(this.tools?.tools ?? []),
108
+ ...(this.extraTools?.tools ?? []),
109
+ ];
110
+ this.mergedTools = merged.length > 0 ? merged : undefined;
111
+ }
112
+ /**
113
+ * Dispatch a tool call to whichever toolset registered it. Github
114
+ * tools take precedence (they're registered first); fall back to the
115
+ * extra toolset for anything not in the github name set.
116
+ */
117
+ async dispatchTool(call) {
118
+ if (this.tools?.tools.some((t) => t.name === call.name)) {
119
+ return this.tools.execute(call);
120
+ }
121
+ if (this.extraTools?.tools.some((t) => t.name === call.name)) {
122
+ return this.extraTools.execute(call);
123
+ }
124
+ return {
125
+ content: JSON.stringify({ error: `unknown tool: ${call.name}` }),
126
+ isError: true,
127
+ };
128
+ }
129
+ resolveModelLazy() {
130
+ if (this.model)
131
+ return this.model;
132
+ if (this.modelError)
133
+ return undefined;
134
+ try {
135
+ this.model = resolveModel(this.cfg.model);
136
+ return this.model;
137
+ }
138
+ catch (err) {
139
+ this.modelError = err instanceof Error ? err.message : String(err);
140
+ console.error(`[chat] ${this.modelError}`);
141
+ return undefined;
142
+ }
143
+ }
144
+ /**
145
+ * Run one chat turn. Each messagingSessionId maps to a stable pi-ai
146
+ * `agentSessionId` (a UUID we mint on first turn) which the dashboard
147
+ * uses to look up the JSONL on disk.
148
+ */
149
+ async turn(messagingSessionId, prompt) {
150
+ const prev = this.chains.get(messagingSessionId) ?? Promise.resolve();
151
+ const next = prev
152
+ .catch(() => undefined)
153
+ .then(() => this.doTurn(messagingSessionId, prompt));
154
+ this.chains.set(messagingSessionId, next);
155
+ const cleanup = () => {
156
+ if (this.chains.get(messagingSessionId) === next) {
157
+ this.chains.delete(messagingSessionId);
158
+ }
159
+ };
160
+ next.then(cleanup, cleanup);
161
+ return next;
162
+ }
163
+ async doTurn(messagingSessionId, prompt) {
164
+ // Resolve (or mint) the stable agentSessionId pinned to this thread.
165
+ const session = this.sessionManager.getSession(messagingSessionId);
166
+ let agentSessionId = session?.agentSessionId || null;
167
+ if (!agentSessionId) {
168
+ agentSessionId = randomUUID();
169
+ this.sessionManager.setAgentSessionId(messagingSessionId, agentSessionId);
170
+ }
171
+ // Bail with a clear error if the chat model spec is unknown to pi-ai.
172
+ // Done here rather than in the constructor so a misconfigured chat
173
+ // model only fails chat turns, not the whole server.
174
+ const model = this.resolveModelLazy();
175
+ if (!model) {
176
+ return {
177
+ text: "",
178
+ agentSessionId,
179
+ tokens: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
180
+ costUsd: 0,
181
+ modelTurns: 0,
182
+ finish: "error",
183
+ errors: [this.modelError ?? "chat model not configured"],
184
+ assistantMessages: [],
185
+ toolResults: [],
186
+ modelId: this.cfg.model,
187
+ };
188
+ }
189
+ // Rehydrate conversation context from the DB. Messages were stored
190
+ // text-only on prior turns; we replay them as alternating user /
191
+ // assistant text messages. Tool calls/results inside a single turn
192
+ // never persist (they only live for that turn's loop) — that's a
193
+ // deliberate simplification: the agent gets a clean conversation
194
+ // history and can re-tool if asked again.
195
+ const history = this.sessionManager.getHistory(messagingSessionId, 50);
196
+ const messages = history.map((h) => textMessage(h.role, h.content, h.timestamp));
197
+ messages.push(textMessage("user", prompt, new Date().toISOString()));
198
+ const context = {
199
+ systemPrompt: this.cfg.systemPrompt,
200
+ messages,
201
+ tools: this.mergedTools,
202
+ };
203
+ const errors = [];
204
+ const assistantMessages = [];
205
+ const toolResults = [];
206
+ const opts = {
207
+ reasoning: pickReasoning(this.cfg.thinking),
208
+ timeoutMs: this.cfg.timeoutMs ?? 120_000,
209
+ };
210
+ let finish = "stop";
211
+ let tokensIn = 0;
212
+ let tokensOut = 0;
213
+ let cacheRead = 0;
214
+ let cacheWrite = 0;
215
+ let costUsd = 0;
216
+ let modelTurns = 0;
217
+ let finalText = "";
218
+ for (let round = 0; round < MAX_TOOL_ROUNDS + 1; round++) {
219
+ modelTurns++;
220
+ let assistant;
221
+ try {
222
+ assistant = await completeWithRetry(completeSimple, model, context, opts, {
223
+ onRetry: ({ attempt, delayMs, reason }) => console.warn(`[chat] transient model error (retry ${attempt}/${CHAT_RETRY_BACKOFF_MS.length} ` +
224
+ `in ${delayMs / 1000}s): ${reason}`),
225
+ });
226
+ }
227
+ catch (err) {
228
+ const msg = err instanceof Error ? err.message : String(err);
229
+ errors.push(msg);
230
+ finish = "error";
231
+ break;
232
+ }
233
+ assistantMessages.push(assistant);
234
+ context.messages.push(assistant);
235
+ tokensIn += assistant.usage.input;
236
+ tokensOut += assistant.usage.output;
237
+ cacheRead += assistant.usage.cacheRead;
238
+ cacheWrite += assistant.usage.cacheWrite;
239
+ costUsd += assistant.usage.cost.total;
240
+ if (assistant.stopReason === "error" || assistant.stopReason === "aborted") {
241
+ errors.push(assistant.errorMessage ?? assistant.stopReason);
242
+ finish = "error";
243
+ break;
244
+ }
245
+ // Pull text out (last text block wins — same convention as pi-ai's run() helper).
246
+ const text = assistant.content
247
+ .filter((c) => c.type === "text" && typeof c.text === "string")
248
+ .map((c) => c.text)
249
+ .join("");
250
+ if (text)
251
+ finalText = text;
252
+ // Tool calls? Execute and loop.
253
+ const toolCalls = assistant.content.filter((c) => c.type === "toolCall");
254
+ if (toolCalls.length === 0) {
255
+ finish = "stop";
256
+ break;
257
+ }
258
+ if (!this.mergedTools) {
259
+ // Model emitted a tool call without any tools registered — shouldn't
260
+ // happen, but bail out rather than loop forever.
261
+ errors.push("Model called a tool, but no tools are registered for chat.");
262
+ finish = "error";
263
+ break;
264
+ }
265
+ for (const call of toolCalls) {
266
+ const { content, isError } = await this.dispatchTool(call);
267
+ const tr = {
268
+ role: "toolResult",
269
+ toolCallId: call.id,
270
+ toolName: call.name,
271
+ content: [{ type: "text", text: content }],
272
+ isError,
273
+ timestamp: Date.now(),
274
+ };
275
+ toolResults.push(tr);
276
+ context.messages.push(tr);
277
+ if (isError)
278
+ errors.push(`${call.name}: ${content}`);
279
+ }
280
+ if (round === MAX_TOOL_ROUNDS) {
281
+ finish = "max-rounds";
282
+ errors.push(`Hit MAX_TOOL_ROUNDS (${MAX_TOOL_ROUNDS}); giving up on this turn.`);
283
+ break;
284
+ }
285
+ }
286
+ // Persist this turn's user + final assistant text. We do NOT persist
287
+ // tool calls or intermediate model responses — only the human-visible
288
+ // turn boundaries — to keep the rehydrated context compact.
289
+ this.sessionManager.addMessage(messagingSessionId, "user", prompt);
290
+ if (finalText) {
291
+ this.sessionManager.addMessage(messagingSessionId, "assistant", finalText);
292
+ }
293
+ this.sessionManager.touchSession(messagingSessionId);
294
+ return {
295
+ text: finalText,
296
+ agentSessionId,
297
+ tokens: {
298
+ input: tokensIn,
299
+ output: tokensOut,
300
+ cacheRead,
301
+ cacheWrite,
302
+ },
303
+ costUsd,
304
+ modelTurns,
305
+ finish,
306
+ errors,
307
+ assistantMessages,
308
+ toolResults,
309
+ modelId: this.cfg.model,
310
+ };
311
+ }
312
+ }
313
+ // ── Helpers ─────────────────────────────────────────────────────────
314
+ function resolveModel(spec) {
315
+ const idx = spec.indexOf("/");
316
+ if (idx < 0)
317
+ throw new Error(`model spec must be 'provider/id', got '${spec}'`);
318
+ const provider = spec.slice(0, idx);
319
+ const modelId = spec.slice(idx + 1);
320
+ // pi-ai's getModel is typed against its static registry; at runtime it
321
+ // accepts arbitrary strings AND returns undefined for unknown ids rather
322
+ // than throwing. Without this guard the first chat turn crashes deep in
323
+ // the provider stack with "Cannot read properties of undefined (reading
324
+ // 'api')" — surface a clear, actionable error instead.
325
+ const model = getModel(provider, modelId);
326
+ if (!model) {
327
+ throw new Error(`Unknown chat model '${spec}'. pi-ai's registry has no '${modelId}' for provider '${provider}'. ` +
328
+ `Set LASTLIGHT_MODELS (or LASTLIGHT_MODEL) to a registered model id.`);
329
+ }
330
+ return model;
331
+ }
332
+ function textMessage(role, content, timestamp) {
333
+ const ts = parseTimestamp(timestamp);
334
+ if (role === "user") {
335
+ const m = { role: "user", content, timestamp: ts };
336
+ return m;
337
+ }
338
+ // Treat any non-user historical role as assistant text.
339
+ const m = {
340
+ role: "assistant",
341
+ content: [{ type: "text", text: content }],
342
+ api: "openai-completions",
343
+ provider: "history",
344
+ model: "history",
345
+ usage: zeroUsage(),
346
+ stopReason: "stop",
347
+ timestamp: ts,
348
+ };
349
+ return m;
350
+ }
351
+ function parseTimestamp(raw) {
352
+ const ms = Date.parse(raw);
353
+ return Number.isFinite(ms) ? ms : Date.now();
354
+ }
355
+ function zeroUsage() {
356
+ return {
357
+ input: 0,
358
+ output: 0,
359
+ cacheRead: 0,
360
+ cacheWrite: 0,
361
+ totalTokens: 0,
362
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
363
+ };
364
+ }
365
+ function pickReasoning(level) {
366
+ // pi-ai's SimpleStreamOptions.reasoning excludes "off" — pi-ai default
367
+ // is no reasoning, so we pass undefined for "off".
368
+ if (!level || level === "off")
369
+ return undefined;
370
+ return level;
371
+ }
372
+ /**
373
+ * Octokit is bundled here only because github-tools.ts imports it at module
374
+ * load. Re-export so callers can probe whether the integration is wired
375
+ * without round-tripping through that file. Typed as `unknown` to avoid
376
+ * dragging the Octokit type chain into the published .d.ts.
377
+ */
378
+ export const __octokitForTest = Octokit;
379
+ //# sourceMappingURL=chat-runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-runner.js","sourceRoot":"","sources":["../../src/engine/chat-runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,104 @@
1
+ import { describe, it, expect, vi } from "vitest";
2
+ import { completeWithRetry, isRetryableModelError } from "./chat-runner.js";
3
+ // Minimal stand-ins — the helper only ever forwards these to `complete`.
4
+ const model = {};
5
+ const context = { messages: [] };
6
+ const opts = {};
7
+ function ok(text = "hi") {
8
+ return {
9
+ role: "assistant",
10
+ content: [{ type: "text", text }],
11
+ stopReason: "stop",
12
+ usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: { total: 0 } },
13
+ };
14
+ }
15
+ function erroredAssistant(message) {
16
+ return {
17
+ role: "assistant",
18
+ content: [],
19
+ stopReason: "error",
20
+ errorMessage: message,
21
+ usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: { total: 0 } },
22
+ };
23
+ }
24
+ const noSleep = () => Promise.resolve();
25
+ const delays = [10, 20, 30];
26
+ describe("isRetryableModelError", () => {
27
+ it("matches rate limits and transient server/network errors", () => {
28
+ for (const m of [
29
+ '429 {"error":{"code":"RATE_LIMIT_EXCEEDED"}}',
30
+ "You have exceeded your rate limit for this API",
31
+ "Error: overloaded_error",
32
+ "503 Service Unavailable",
33
+ "502 Bad Gateway",
34
+ "fetch failed",
35
+ "ETIMEDOUT",
36
+ ]) {
37
+ expect(isRetryableModelError(m)).toBe(true);
38
+ }
39
+ });
40
+ it("does NOT match auth / validation / overflow (non-transient)", () => {
41
+ for (const m of [
42
+ "401 Unauthorized",
43
+ "403 Resource not accessible by integration",
44
+ "400 invalid_request_error",
45
+ "context length exceeded",
46
+ "Unknown chat model",
47
+ ]) {
48
+ expect(isRetryableModelError(m)).toBe(false);
49
+ }
50
+ });
51
+ });
52
+ describe("completeWithRetry", () => {
53
+ it("returns immediately on success (no retries)", async () => {
54
+ const complete = vi.fn().mockResolvedValue(ok());
55
+ const onRetry = vi.fn();
56
+ const res = await completeWithRetry(complete, model, context, opts, { delaysMs: delays, sleepFn: noSleep, onRetry });
57
+ expect(res.stopReason).toBe("stop");
58
+ expect(complete).toHaveBeenCalledTimes(1);
59
+ expect(onRetry).not.toHaveBeenCalled();
60
+ });
61
+ it("retries a thrown 429 then succeeds, backing off per the schedule", async () => {
62
+ const complete = vi
63
+ .fn()
64
+ .mockRejectedValueOnce(new Error('429 {"code":"RATE_LIMIT_EXCEEDED"}'))
65
+ .mockResolvedValueOnce(ok("recovered"));
66
+ const slept = [];
67
+ const sleepFn = (ms) => { slept.push(ms); return Promise.resolve(); };
68
+ const res = await completeWithRetry(complete, model, context, opts, { delaysMs: delays, sleepFn });
69
+ expect(res.stopReason).toBe("stop");
70
+ expect(complete).toHaveBeenCalledTimes(2);
71
+ expect(slept).toEqual([10]); // first backoff only
72
+ });
73
+ it("retries an errored-assistant 429 (non-throw shape)", async () => {
74
+ const complete = vi
75
+ .fn()
76
+ .mockResolvedValueOnce(erroredAssistant("rate limit exceeded"))
77
+ .mockResolvedValueOnce(ok());
78
+ const res = await completeWithRetry(complete, model, context, opts, { delaysMs: delays, sleepFn: noSleep });
79
+ expect(res.stopReason).toBe("stop");
80
+ expect(complete).toHaveBeenCalledTimes(2);
81
+ });
82
+ it("does NOT retry a non-retryable thrown error", async () => {
83
+ const complete = vi.fn().mockRejectedValue(new Error("401 Unauthorized"));
84
+ await expect(completeWithRetry(complete, model, context, opts, { delaysMs: delays, sleepFn: noSleep })).rejects.toThrow("401");
85
+ expect(complete).toHaveBeenCalledTimes(1);
86
+ });
87
+ it("gives up after exhausting the backoff schedule and rethrows the last error", async () => {
88
+ const complete = vi.fn().mockRejectedValue(new Error("429 rate limit"));
89
+ const slept = [];
90
+ await expect(completeWithRetry(complete, model, context, opts, {
91
+ delaysMs: delays,
92
+ sleepFn: (ms) => { slept.push(ms); return Promise.resolve(); },
93
+ })).rejects.toThrow("429");
94
+ expect(complete).toHaveBeenCalledTimes(delays.length + 1); // initial + 3 retries
95
+ expect(slept).toEqual(delays);
96
+ });
97
+ it("returns the errored assistant unchanged when retries are exhausted (non-throw shape)", async () => {
98
+ const complete = vi.fn().mockResolvedValue(erroredAssistant("429 rate limit"));
99
+ const res = await completeWithRetry(complete, model, context, opts, { delaysMs: [5], sleepFn: noSleep });
100
+ expect(res.stopReason).toBe("error");
101
+ expect(complete).toHaveBeenCalledTimes(2); // initial + 1 retry, then surfaces the errored assistant
102
+ });
103
+ });
104
+ //# sourceMappingURL=chat-runner.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-runner.test.js","sourceRoot":"","sources":["../../src/engine/chat-runner.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ import type { Tool, ToolCall } from "@earendil-works/pi-ai";
2
+ /**
3
+ * Minimal subset of pi-coding-agent's `Skill` shape — only the fields
4
+ * the chat catalogue + read tool actually use.
5
+ */
6
+ export interface ChatSkill {
7
+ name: string;
8
+ description: string;
9
+ filePath: string;
10
+ }
11
+ /**
12
+ * Skills exposed to chat threads. `chat` is the always-on persona;
13
+ * the others let chat assist with one-off lookups that map to these
14
+ * domains without delegating to a full workflow run.
15
+ */
16
+ export declare const CHAT_SKILL_NAMES: readonly ["chat", "issue-triage", "pr-review", "repo-health"];
17
+ export interface ChatSkillCatalogue {
18
+ /** Skills the chat agent can read on demand, keyed by name. */
19
+ skills: ChatSkill[];
20
+ /**
21
+ * XML block describing each skill (name + description) suitable for
22
+ * prepending to the chat system prompt. Empty string if no skills
23
+ * resolved cleanly.
24
+ */
25
+ catalogueXml: string;
26
+ }
27
+ /**
28
+ * Load the curated chat skill catalogue from `<repo>/skills/`.
29
+ * Skills missing `name` or `description` frontmatter are silently
30
+ * dropped, matching pi-coding-agent's behaviour on the sandbox path.
31
+ */
32
+ export declare function loadChatSkillCatalogue(): ChatSkillCatalogue;
33
+ /**
34
+ * Build the `read_skill` tool that chat uses to pull a SKILL.md on
35
+ * demand. Returns the pi-ai `Tool` definition plus a name-keyed
36
+ * dispatcher the chat-runner's toolset can merge into its `execute`.
37
+ */
38
+ export interface ReadSkillToolset {
39
+ tool: Tool;
40
+ execute(call: ToolCall): {
41
+ content: string;
42
+ isError: boolean;
43
+ };
44
+ }
45
+ export declare function buildReadSkillTool(skills: ChatSkill[]): ReadSkillToolset;