lastlight 0.16.0 → 0.16.2

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 (385) hide show
  1. package/README.md +71 -692
  2. package/dist/cli-config.js.map +1 -0
  3. package/dist/cli-format.js.map +1 -0
  4. package/dist/{cli/cli-server.d.ts → cli-server.d.ts} +39 -1
  5. package/dist/{cli/cli-server.js → cli-server.js} +105 -5
  6. package/dist/cli-server.js.map +1 -0
  7. package/dist/cli-timeline.js.map +1 -0
  8. package/dist/{cli/cli.js → cli.js} +9 -7
  9. package/dist/cli.js.map +1 -0
  10. package/dist/{cli/fork-cli.d.ts → fork-cli.d.ts} +3 -3
  11. package/dist/{cli/fork-cli.js → fork-cli.js} +28 -27
  12. package/dist/fork-cli.js.map +1 -0
  13. package/dist/{cli/oauth-cli.js → oauth-cli.js} +1 -1
  14. package/dist/oauth-cli.js.map +1 -0
  15. package/dist/{cli/setup.js → setup.js} +10 -4
  16. package/dist/setup.js.map +1 -0
  17. package/dist/{cli/skills-install.d.ts → skills-install.d.ts} +6 -0
  18. package/dist/{cli/skills-install.js → skills-install.js} +6 -2
  19. package/dist/skills-install.js.map +1 -0
  20. package/package.json +20 -65
  21. package/plugins/lastlight/.claude-plugin/plugin.json +1 -1
  22. package/agent-context/rules.md +0 -80
  23. package/agent-context/security.md +0 -69
  24. package/agent-context/soul.md +0 -21
  25. package/config/default.yaml +0 -119
  26. package/deploy/.env.production.example +0 -100
  27. package/deploy/entrypoint.sh +0 -82
  28. package/deploy/native/README.md +0 -160
  29. package/deploy/native/install.sh +0 -110
  30. package/deploy/native/lastlight.env.example +0 -95
  31. package/deploy/native/lastlight.service +0 -50
  32. package/deploy/sandbox-entrypoint.sh +0 -93
  33. package/dist/admin/auth.d.ts +0 -51
  34. package/dist/admin/auth.js +0 -121
  35. package/dist/admin/auth.js.map +0 -1
  36. package/dist/admin/chat-session-reader.d.ts +0 -39
  37. package/dist/admin/chat-session-reader.js +0 -84
  38. package/dist/admin/chat-session-reader.js.map +0 -1
  39. package/dist/admin/docker.d.ts +0 -61
  40. package/dist/admin/docker.js +0 -187
  41. package/dist/admin/docker.js.map +0 -1
  42. package/dist/admin/index.d.ts +0 -9
  43. package/dist/admin/index.js +0 -59
  44. package/dist/admin/index.js.map +0 -1
  45. package/dist/admin/routes.d.ts +0 -81
  46. package/dist/admin/routes.js +0 -1381
  47. package/dist/admin/routes.js.map +0 -1
  48. package/dist/admin/sessions.d.ts +0 -89
  49. package/dist/admin/sessions.js +0 -204
  50. package/dist/admin/sessions.js.map +0 -1
  51. package/dist/admin/tail.d.ts +0 -12
  52. package/dist/admin/tail.js +0 -145
  53. package/dist/admin/tail.js.map +0 -1
  54. package/dist/admin/version.d.ts +0 -22
  55. package/dist/admin/version.js +0 -92
  56. package/dist/admin/version.js.map +0 -1
  57. package/dist/cli/cli-config.js.map +0 -1
  58. package/dist/cli/cli-format.js.map +0 -1
  59. package/dist/cli/cli-server.js.map +0 -1
  60. package/dist/cli/cli-timeline.js.map +0 -1
  61. package/dist/cli/cli.js.map +0 -1
  62. package/dist/cli/fork-cli.js.map +0 -1
  63. package/dist/cli/oauth-cli.js.map +0 -1
  64. package/dist/cli/setup.js.map +0 -1
  65. package/dist/cli/skills-install.js.map +0 -1
  66. package/dist/config/config-resolve.d.ts +0 -28
  67. package/dist/config/config-resolve.js +0 -47
  68. package/dist/config/config-resolve.js.map +0 -1
  69. package/dist/config/config.d.ts +0 -157
  70. package/dist/config/config.js +0 -581
  71. package/dist/config/config.js.map +0 -1
  72. package/dist/config/core-pin.d.ts +0 -16
  73. package/dist/config/core-pin.js +0 -85
  74. package/dist/config/core-pin.js.map +0 -1
  75. package/dist/config/overlay-assets.d.ts +0 -20
  76. package/dist/config/overlay-assets.js +0 -114
  77. package/dist/config/overlay-assets.js.map +0 -1
  78. package/dist/config/overlay-bootstrap.d.ts +0 -44
  79. package/dist/config/overlay-bootstrap.js +0 -304
  80. package/dist/config/overlay-bootstrap.js.map +0 -1
  81. package/dist/connectors/github-webhook.d.ts +0 -45
  82. package/dist/connectors/github-webhook.js +0 -321
  83. package/dist/connectors/github-webhook.js.map +0 -1
  84. package/dist/connectors/index.d.ts +0 -18
  85. package/dist/connectors/index.js +0 -41
  86. package/dist/connectors/index.js.map +0 -1
  87. package/dist/connectors/messaging/base.d.ts +0 -42
  88. package/dist/connectors/messaging/base.js +0 -139
  89. package/dist/connectors/messaging/base.js.map +0 -1
  90. package/dist/connectors/messaging/delivery.d.ts +0 -14
  91. package/dist/connectors/messaging/delivery.js +0 -38
  92. package/dist/connectors/messaging/delivery.js.map +0 -1
  93. package/dist/connectors/messaging/index.d.ts +0 -4
  94. package/dist/connectors/messaging/index.js +0 -4
  95. package/dist/connectors/messaging/index.js.map +0 -1
  96. package/dist/connectors/messaging/session-manager.d.ts +0 -53
  97. package/dist/connectors/messaging/session-manager.js +0 -255
  98. package/dist/connectors/messaging/session-manager.js.map +0 -1
  99. package/dist/connectors/messaging/types.d.ts +0 -58
  100. package/dist/connectors/messaging/types.js +0 -7
  101. package/dist/connectors/messaging/types.js.map +0 -1
  102. package/dist/connectors/slack/connector.d.ts +0 -142
  103. package/dist/connectors/slack/connector.js +0 -494
  104. package/dist/connectors/slack/connector.js.map +0 -1
  105. package/dist/connectors/slack/index.d.ts +0 -2
  106. package/dist/connectors/slack/index.js +0 -3
  107. package/dist/connectors/slack/index.js.map +0 -1
  108. package/dist/connectors/slack/mrkdwn.d.ts +0 -19
  109. package/dist/connectors/slack/mrkdwn.js +0 -240
  110. package/dist/connectors/slack/mrkdwn.js.map +0 -1
  111. package/dist/connectors/types.d.ts +0 -61
  112. package/dist/connectors/types.js +0 -2
  113. package/dist/connectors/types.js.map +0 -1
  114. package/dist/cron/fanout.d.ts +0 -33
  115. package/dist/cron/fanout.js +0 -55
  116. package/dist/cron/fanout.js.map +0 -1
  117. package/dist/cron/jobs.d.ts +0 -18
  118. package/dist/cron/jobs.js +0 -37
  119. package/dist/cron/jobs.js.map +0 -1
  120. package/dist/cron/scheduler.d.ts +0 -45
  121. package/dist/cron/scheduler.js +0 -105
  122. package/dist/cron/scheduler.js.map +0 -1
  123. package/dist/engine/agent-executor.d.ts +0 -34
  124. package/dist/engine/agent-executor.js +0 -246
  125. package/dist/engine/agent-executor.js.map +0 -1
  126. package/dist/engine/chat/chat-runner.d.ts +0 -132
  127. package/dist/engine/chat/chat-runner.js +0 -424
  128. package/dist/engine/chat/chat-runner.js.map +0 -1
  129. package/dist/engine/chat/chat-skills.d.ts +0 -45
  130. package/dist/engine/chat/chat-skills.js +0 -184
  131. package/dist/engine/chat/chat-skills.js.map +0 -1
  132. package/dist/engine/chat/chat.d.ts +0 -54
  133. package/dist/engine/chat/chat.js +0 -316
  134. package/dist/engine/chat/chat.js.map +0 -1
  135. package/dist/engine/chat/message-batcher.d.ts +0 -32
  136. package/dist/engine/chat/message-batcher.js +0 -109
  137. package/dist/engine/chat/message-batcher.js.map +0 -1
  138. package/dist/engine/dispatcher.d.ts +0 -73
  139. package/dist/engine/dispatcher.js +0 -663
  140. package/dist/engine/dispatcher.js.map +0 -1
  141. package/dist/engine/event-shim.d.ts +0 -117
  142. package/dist/engine/event-shim.js +0 -435
  143. package/dist/engine/event-shim.js.map +0 -1
  144. package/dist/engine/executors/orchestrator.d.ts +0 -81
  145. package/dist/engine/executors/orchestrator.js +0 -365
  146. package/dist/engine/executors/orchestrator.js.map +0 -1
  147. package/dist/engine/executors/shared.d.ts +0 -189
  148. package/dist/engine/executors/shared.js +0 -616
  149. package/dist/engine/executors/shared.js.map +0 -1
  150. package/dist/engine/github/git-auth.d.ts +0 -62
  151. package/dist/engine/github/git-auth.js +0 -161
  152. package/dist/engine/github/git-auth.js.map +0 -1
  153. package/dist/engine/github/github-app-client.d.ts +0 -23
  154. package/dist/engine/github/github-app-client.js +0 -33
  155. package/dist/engine/github/github-app-client.js.map +0 -1
  156. package/dist/engine/github/github-tools.d.ts +0 -18
  157. package/dist/engine/github/github-tools.js +0 -263
  158. package/dist/engine/github/github-tools.js.map +0 -1
  159. package/dist/engine/github/github.d.ts +0 -1193
  160. package/dist/engine/github/github.js +0 -357
  161. package/dist/engine/github/github.js.map +0 -1
  162. package/dist/engine/github/profiles.d.ts +0 -279
  163. package/dist/engine/github/profiles.js +0 -42
  164. package/dist/engine/github/profiles.js.map +0 -1
  165. package/dist/engine/github/review-poster.d.ts +0 -98
  166. package/dist/engine/github/review-poster.js +0 -177
  167. package/dist/engine/github/review-poster.js.map +0 -1
  168. package/dist/engine/llm.d.ts +0 -79
  169. package/dist/engine/llm.js +0 -269
  170. package/dist/engine/llm.js.map +0 -1
  171. package/dist/engine/oauth.d.ts +0 -43
  172. package/dist/engine/oauth.js +0 -103
  173. package/dist/engine/oauth.js.map +0 -1
  174. package/dist/engine/router.d.ts +0 -29
  175. package/dist/engine/router.js +0 -680
  176. package/dist/engine/router.js.map +0 -1
  177. package/dist/engine/screen/classifier.d.ts +0 -93
  178. package/dist/engine/screen/classifier.js +0 -215
  179. package/dist/engine/screen/classifier.js.map +0 -1
  180. package/dist/engine/screen/screen.d.ts +0 -41
  181. package/dist/engine/screen/screen.js +0 -93
  182. package/dist/engine/screen/screen.js.map +0 -1
  183. package/dist/evals-api.d.ts +0 -24
  184. package/dist/evals-api.js +0 -22
  185. package/dist/evals-api.js.map +0 -1
  186. package/dist/index.d.ts +0 -1
  187. package/dist/index.js +0 -940
  188. package/dist/index.js.map +0 -1
  189. package/dist/managed-repos.d.ts +0 -30
  190. package/dist/managed-repos.js +0 -72
  191. package/dist/managed-repos.js.map +0 -1
  192. package/dist/notify/blocks.d.ts +0 -23
  193. package/dist/notify/blocks.js +0 -118
  194. package/dist/notify/blocks.js.map +0 -1
  195. package/dist/notify/index.d.ts +0 -17
  196. package/dist/notify/index.js +0 -7
  197. package/dist/notify/index.js.map +0 -1
  198. package/dist/notify/model.d.ts +0 -57
  199. package/dist/notify/model.js +0 -89
  200. package/dist/notify/model.js.map +0 -1
  201. package/dist/notify/notifier.d.ts +0 -18
  202. package/dist/notify/notifier.js +0 -100
  203. package/dist/notify/notifier.js.map +0 -1
  204. package/dist/notify/render.d.ts +0 -21
  205. package/dist/notify/render.js +0 -59
  206. package/dist/notify/render.js.map +0 -1
  207. package/dist/notify/transports/github.d.ts +0 -26
  208. package/dist/notify/transports/github.js +0 -27
  209. package/dist/notify/transports/github.js.map +0 -1
  210. package/dist/notify/transports/slack.d.ts +0 -27
  211. package/dist/notify/transports/slack.js +0 -37
  212. package/dist/notify/transports/slack.js.map +0 -1
  213. package/dist/notify/types.d.ts +0 -119
  214. package/dist/notify/types.js +0 -16
  215. package/dist/notify/types.js.map +0 -1
  216. package/dist/providers.d.ts +0 -125
  217. package/dist/providers.js +0 -279
  218. package/dist/providers.js.map +0 -1
  219. package/dist/sandbox/docker.d.ts +0 -180
  220. package/dist/sandbox/docker.js +0 -517
  221. package/dist/sandbox/docker.js.map +0 -1
  222. package/dist/sandbox/egress-allowlist.d.ts +0 -74
  223. package/dist/sandbox/egress-allowlist.js +0 -164
  224. package/dist/sandbox/egress-allowlist.js.map +0 -1
  225. package/dist/sandbox/egress-firewall-config.d.ts +0 -127
  226. package/dist/sandbox/egress-firewall-config.js +0 -434
  227. package/dist/sandbox/egress-firewall-config.js.map +0 -1
  228. package/dist/sandbox/images.d.ts +0 -23
  229. package/dist/sandbox/images.js +0 -55
  230. package/dist/sandbox/images.js.map +0 -1
  231. package/dist/sandbox/index.d.ts +0 -112
  232. package/dist/sandbox/index.js +0 -332
  233. package/dist/sandbox/index.js.map +0 -1
  234. package/dist/sandbox/sandbox.d.ts +0 -214
  235. package/dist/sandbox/sandbox.js +0 -453
  236. package/dist/sandbox/sandbox.js.map +0 -1
  237. package/dist/sandbox/smol.d.ts +0 -162
  238. package/dist/sandbox/smol.js +0 -485
  239. package/dist/sandbox/smol.js.map +0 -1
  240. package/dist/session-log.d.ts +0 -63
  241. package/dist/session-log.js +0 -290
  242. package/dist/session-log.js.map +0 -1
  243. package/dist/state/approval-store.d.ts +0 -88
  244. package/dist/state/approval-store.js +0 -149
  245. package/dist/state/approval-store.js.map +0 -1
  246. package/dist/state/build-assets.d.ts +0 -50
  247. package/dist/state/build-assets.js +0 -154
  248. package/dist/state/build-assets.js.map +0 -1
  249. package/dist/state/db.d.ts +0 -81
  250. package/dist/state/db.js +0 -155
  251. package/dist/state/db.js.map +0 -1
  252. package/dist/state/execution-store.d.ts +0 -257
  253. package/dist/state/execution-store.js +0 -527
  254. package/dist/state/execution-store.js.map +0 -1
  255. package/dist/state/migrate.d.ts +0 -15
  256. package/dist/state/migrate.js +0 -175
  257. package/dist/state/migrate.js.map +0 -1
  258. package/dist/state/workflow-run-store.d.ts +0 -216
  259. package/dist/state/workflow-run-store.js +0 -403
  260. package/dist/state/workflow-run-store.js.map +0 -1
  261. package/dist/telemetry/index.d.ts +0 -38
  262. package/dist/telemetry/index.js +0 -253
  263. package/dist/telemetry/index.js.map +0 -1
  264. package/dist/telemetry/pi-events.d.ts +0 -12
  265. package/dist/telemetry/pi-events.js +0 -134
  266. package/dist/telemetry/pi-events.js.map +0 -1
  267. package/dist/workflows/dag.d.ts +0 -37
  268. package/dist/workflows/dag.js +0 -118
  269. package/dist/workflows/dag.js.map +0 -1
  270. package/dist/workflows/loader.d.ts +0 -53
  271. package/dist/workflows/loader.js +0 -421
  272. package/dist/workflows/loader.js.map +0 -1
  273. package/dist/workflows/loop-eval.d.ts +0 -28
  274. package/dist/workflows/loop-eval.js +0 -74
  275. package/dist/workflows/loop-eval.js.map +0 -1
  276. package/dist/workflows/phase-executor.d.ts +0 -222
  277. package/dist/workflows/phase-executor.js +0 -1153
  278. package/dist/workflows/phase-executor.js.map +0 -1
  279. package/dist/workflows/phase-ref.d.ts +0 -50
  280. package/dist/workflows/phase-ref.js +0 -91
  281. package/dist/workflows/phase-ref.js.map +0 -1
  282. package/dist/workflows/resume.d.ts +0 -58
  283. package/dist/workflows/resume.js +0 -313
  284. package/dist/workflows/resume.js.map +0 -1
  285. package/dist/workflows/runner.d.ts +0 -63
  286. package/dist/workflows/runner.js +0 -381
  287. package/dist/workflows/runner.js.map +0 -1
  288. package/dist/workflows/schema.d.ts +0 -344
  289. package/dist/workflows/schema.js +0 -460
  290. package/dist/workflows/schema.js.map +0 -1
  291. package/dist/workflows/simple.d.ts +0 -90
  292. package/dist/workflows/simple.js +0 -393
  293. package/dist/workflows/simple.js.map +0 -1
  294. package/dist/workflows/target-policy.d.ts +0 -74
  295. package/dist/workflows/target-policy.js +0 -80
  296. package/dist/workflows/target-policy.js.map +0 -1
  297. package/dist/workflows/templates.d.ts +0 -88
  298. package/dist/workflows/templates.js +0 -127
  299. package/dist/workflows/templates.js.map +0 -1
  300. package/dist/workflows/triggers.d.ts +0 -21
  301. package/dist/workflows/triggers.js +0 -45
  302. package/dist/workflows/triggers.js.map +0 -1
  303. package/dist/workflows/verdict.d.ts +0 -19
  304. package/dist/workflows/verdict.js +0 -30
  305. package/dist/workflows/verdict.js.map +0 -1
  306. package/dist/worktree/manager.d.ts +0 -43
  307. package/dist/worktree/manager.js +0 -127
  308. package/dist/worktree/manager.js.map +0 -1
  309. package/docker-compose.yml +0 -274
  310. package/sandbox.Dockerfile +0 -68
  311. package/skills/README.md +0 -42
  312. package/skills/browser-qa/SKILL.md +0 -208
  313. package/skills/browser-qa/scripts/agent-browser.mjs +0 -531
  314. package/skills/building/SKILL.md +0 -95
  315. package/skills/chat/SKILL.md +0 -36
  316. package/skills/code-review/SKILL.md +0 -82
  317. package/skills/debug-production/SKILL.md +0 -108
  318. package/skills/demo/SKILL.md +0 -228
  319. package/skills/demo/scripts/compose-demo.sh +0 -243
  320. package/skills/issue-answer/SKILL.md +0 -91
  321. package/skills/issue-comment/SKILL.md +0 -49
  322. package/skills/issue-triage/SKILL.md +0 -149
  323. package/skills/issue-triage/references/AGENT-BRIEF.md +0 -65
  324. package/skills/pr-comment/SKILL.md +0 -64
  325. package/skills/pr-review/SKILL.md +0 -148
  326. package/skills/pr-review/references/findings-schema.md +0 -89
  327. package/skills/qa-test/SKILL.md +0 -97
  328. package/skills/repo-health/SKILL.md +0 -67
  329. package/skills/security-feedback/SKILL.md +0 -173
  330. package/skills/security-feedback/references/templates.md +0 -77
  331. package/skills/security-review/SKILL.md +0 -215
  332. package/skills/security-review/references/issue-format.md +0 -302
  333. package/skills/verify/SKILL.md +0 -118
  334. package/workflows/answer.yaml +0 -44
  335. package/workflows/build.yaml +0 -129
  336. package/workflows/cron-health.yaml +0 -6
  337. package/workflows/cron-review.yaml +0 -8
  338. package/workflows/cron-security.yaml +0 -6
  339. package/workflows/cron-triage.yaml +0 -8
  340. package/workflows/demo.yaml +0 -62
  341. package/workflows/examples/bash-smoke.yaml +0 -41
  342. package/workflows/examples/parallel-review.yaml +0 -36
  343. package/workflows/examples/tdd-loop.yaml +0 -17
  344. package/workflows/explore.yaml +0 -80
  345. package/workflows/issue-comment.yaml +0 -15
  346. package/workflows/issue-triage.yaml +0 -22
  347. package/workflows/pr-comment.yaml +0 -16
  348. package/workflows/pr-fix.yaml +0 -17
  349. package/workflows/pr-review.yaml +0 -50
  350. package/workflows/prompts/answer.md +0 -68
  351. package/workflows/prompts/architect.md +0 -44
  352. package/workflows/prompts/classifier.md +0 -60
  353. package/workflows/prompts/classify-adds-info.md +0 -17
  354. package/workflows/prompts/demo.md +0 -125
  355. package/workflows/prompts/executor.md +0 -42
  356. package/workflows/prompts/explore-ask.md +0 -99
  357. package/workflows/prompts/explore-publish.md +0 -31
  358. package/workflows/prompts/explore-read.md +0 -120
  359. package/workflows/prompts/explore-synthesize.md +0 -88
  360. package/workflows/prompts/fix.md +0 -18
  361. package/workflows/prompts/guardrails.md +0 -96
  362. package/workflows/prompts/pr-fix.md +0 -26
  363. package/workflows/prompts/pr.md +0 -39
  364. package/workflows/prompts/qa-browser.md +0 -95
  365. package/workflows/prompts/qa-synth.md +0 -44
  366. package/workflows/prompts/qa-test.md +0 -60
  367. package/workflows/prompts/re-reviewer.md +0 -33
  368. package/workflows/prompts/reviewer.md +0 -60
  369. package/workflows/prompts/verify-browser.md +0 -93
  370. package/workflows/prompts/verify-synth.md +0 -44
  371. package/workflows/prompts/verify.md +0 -63
  372. package/workflows/qa-test.yaml +0 -94
  373. package/workflows/repo-health.yaml +0 -15
  374. package/workflows/security-feedback.yaml +0 -25
  375. package/workflows/security-review.yaml +0 -37
  376. package/workflows/verify.yaml +0 -93
  377. /package/dist/{cli/cli-config.d.ts → cli-config.d.ts} +0 -0
  378. /package/dist/{cli/cli-config.js → cli-config.js} +0 -0
  379. /package/dist/{cli/cli-format.d.ts → cli-format.d.ts} +0 -0
  380. /package/dist/{cli/cli-format.js → cli-format.js} +0 -0
  381. /package/dist/{cli/cli-timeline.d.ts → cli-timeline.d.ts} +0 -0
  382. /package/dist/{cli/cli-timeline.js → cli-timeline.js} +0 -0
  383. /package/dist/{cli/cli.d.ts → cli.d.ts} +0 -0
  384. /package/dist/{cli/oauth-cli.d.ts → oauth-cli.d.ts} +0 -0
  385. /package/dist/{cli/setup.d.ts → setup.d.ts} +0 -0
@@ -1,424 +0,0 @@
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/github-tools.js";
17
- import { OAUTH_ONLY_PROVIDERS, getOAuthProvider, oauthProviderIdForModel, resolveOAuthApiKey, } from "../oauth.js";
18
- const MAX_TOOL_ROUNDS = 8;
19
- /**
20
- * Exponential backoff schedule (ms) for transient chat-model failures —
21
- * rate limits (429) and provider hiccups (5xx / overloaded / transient
22
- * network). pi-ai disables the provider SDK's own retries (`maxRetries: 0`),
23
- * so without this a single 429 from the model would kill the whole turn.
24
- * The sandbox path already retries via pi-coding-agent's auto-retry; the
25
- * chat path drives pi-ai directly, so it needs its own.
26
- */
27
- const CHAT_RETRY_BACKOFF_MS = [10_000, 30_000, 60_000];
28
- /**
29
- * Match transient, retryable model errors. Deliberately conservative: auth /
30
- * validation / context-overflow / other 4xx (anything but 429) are NOT
31
- * retried — only rate limits, server errors, and transient network faults.
32
- */
33
- export function isRetryableModelError(message) {
34
- const m = message.toLowerCase();
35
- return (/\b429\b/.test(m) ||
36
- m.includes("rate limit") ||
37
- m.includes("rate_limit") ||
38
- m.includes("too many requests") ||
39
- m.includes("overloaded") ||
40
- /\b50[0234]\b/.test(m) || // 500 / 502 / 503 / 504
41
- m.includes("service unavailable") ||
42
- m.includes("timeout") ||
43
- m.includes("etimedout") ||
44
- m.includes("econnreset") ||
45
- m.includes("fetch failed"));
46
- }
47
- const sleepMs = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
48
- /**
49
- * Call `complete`, retrying transient failures with exponential backoff.
50
- * Handles both shapes pi-ai surfaces a failure as: a thrown error, and a
51
- * returned AssistantMessage with `stopReason === "error"`. Non-retryable
52
- * outcomes (and the final attempt) are returned/thrown unchanged so the
53
- * caller's existing error handling still applies. Dependency-injected for
54
- * testing (`delaysMs` / `sleepFn` / `onRetry`).
55
- */
56
- export async function completeWithRetry(complete, model, context, opts, deps = {}) {
57
- const delays = deps.delaysMs ?? CHAT_RETRY_BACKOFF_MS;
58
- const doSleep = deps.sleepFn ?? sleepMs;
59
- let attempt = 0;
60
- for (;;) {
61
- let assistant;
62
- let errMsg;
63
- let thrown;
64
- try {
65
- assistant = await complete(model, context, opts);
66
- if (assistant.stopReason !== "error")
67
- return assistant;
68
- errMsg = assistant.errorMessage ?? "error";
69
- }
70
- catch (err) {
71
- thrown = err;
72
- errMsg = err instanceof Error ? err.message : String(err);
73
- }
74
- if (attempt >= delays.length || !isRetryableModelError(errMsg)) {
75
- if (thrown !== undefined)
76
- throw thrown; // preserve the original error
77
- return assistant; // non-retryable / exhausted errored assistant
78
- }
79
- const delayMs = delays[attempt];
80
- deps.onRetry?.({ attempt: attempt + 1, delayMs, reason: errMsg });
81
- await doSleep(delayMs);
82
- attempt++;
83
- }
84
- }
85
- export class ChatRunner {
86
- cfg;
87
- sessionManager;
88
- tools;
89
- extraTools;
90
- /** Concatenated tool list passed to pi-ai (github + extra). */
91
- mergedTools;
92
- /**
93
- * Resolved lazily on the first chat turn. A bad chat model spec
94
- * (unknown id) MUST NOT crash the whole harness — webhooks, crons and
95
- * workflows don't depend on it.
96
- */
97
- model;
98
- modelError;
99
- chains = new Map();
100
- /**
101
- * OAuth provider id backing the chat model (e.g. `openai-codex` for a
102
- * `openai-codex/gpt-5.4` spec), or undefined for API-key providers. When
103
- * set, each turn resolves a fresh subscription token instead of relying on
104
- * a provider env var. Derived once from `cfg.model`.
105
- */
106
- oauthProviderId;
107
- constructor(cfg, sessionManager) {
108
- this.cfg = cfg;
109
- this.sessionManager = sessionManager;
110
- this.oauthProviderId = oauthProviderIdForModel(cfg.model);
111
- if (cfg.github) {
112
- this.tools = buildChatGitHubTools(cfg.github);
113
- }
114
- this.extraTools = cfg.extraTools;
115
- const merged = [
116
- ...(this.tools?.tools ?? []),
117
- ...(this.extraTools?.tools ?? []),
118
- ];
119
- this.mergedTools = merged.length > 0 ? merged : undefined;
120
- }
121
- /**
122
- * Dispatch a tool call to whichever toolset registered it. Github
123
- * tools take precedence (they're registered first); fall back to the
124
- * extra toolset for anything not in the github name set.
125
- */
126
- async dispatchTool(call) {
127
- if (this.tools?.tools.some((t) => t.name === call.name)) {
128
- return this.tools.execute(call);
129
- }
130
- if (this.extraTools?.tools.some((t) => t.name === call.name)) {
131
- return this.extraTools.execute(call);
132
- }
133
- return {
134
- content: JSON.stringify({ error: `unknown tool: ${call.name}` }),
135
- isError: true,
136
- };
137
- }
138
- /** Build a failed-turn result carrying a single actionable error message. */
139
- errorTurn(agentSessionId, message) {
140
- return {
141
- text: "",
142
- agentSessionId,
143
- tokens: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
144
- costUsd: 0,
145
- modelTurns: 0,
146
- finish: "error",
147
- errors: [message],
148
- assistantMessages: [],
149
- toolResults: [],
150
- modelId: this.cfg.model,
151
- };
152
- }
153
- resolveModelLazy() {
154
- if (this.model)
155
- return this.model;
156
- if (this.modelError)
157
- return undefined;
158
- try {
159
- this.model = resolveModel(this.cfg.model);
160
- return this.model;
161
- }
162
- catch (err) {
163
- this.modelError = err instanceof Error ? err.message : String(err);
164
- console.error(`[chat] ${this.modelError}`);
165
- return undefined;
166
- }
167
- }
168
- /**
169
- * Run one chat turn. Each messagingSessionId maps to a stable pi-ai
170
- * `agentSessionId` (a UUID we mint on first turn) which the dashboard
171
- * uses to look up the JSONL on disk.
172
- */
173
- async turn(messagingSessionId, prompt) {
174
- const prev = this.chains.get(messagingSessionId) ?? Promise.resolve();
175
- const next = prev
176
- .catch(() => undefined)
177
- .then(() => this.doTurn(messagingSessionId, prompt));
178
- this.chains.set(messagingSessionId, next);
179
- const cleanup = () => {
180
- if (this.chains.get(messagingSessionId) === next) {
181
- this.chains.delete(messagingSessionId);
182
- }
183
- };
184
- next.then(cleanup, cleanup);
185
- return next;
186
- }
187
- async doTurn(messagingSessionId, prompt) {
188
- // Resolve (or mint) the stable agentSessionId pinned to this thread.
189
- const session = this.sessionManager.getSession(messagingSessionId);
190
- let agentSessionId = session?.agentSessionId || null;
191
- if (!agentSessionId) {
192
- agentSessionId = randomUUID();
193
- this.sessionManager.setAgentSessionId(messagingSessionId, agentSessionId);
194
- }
195
- // Bail with a clear error if the chat model spec is unknown to pi-ai.
196
- // Done here rather than in the constructor so a misconfigured chat
197
- // model only fails chat turns, not the whole server.
198
- const model = this.resolveModelLazy();
199
- if (!model) {
200
- return this.errorTurn(agentSessionId, this.modelError ?? "chat model not configured");
201
- }
202
- // Resolve the effective model + credentials. For OAuth-backed chat models
203
- // (Codex / Claude Pro / Copilot) we mint a fresh subscription token per
204
- // turn (pi-ai refreshes it if expired) and pass it as the per-call apiKey
205
- // — the in-process chat path can carry an explicit key, unlike the sandbox.
206
- let effectiveModel = model;
207
- let apiKey;
208
- if (this.oauthProviderId) {
209
- try {
210
- const res = await resolveOAuthApiKey(this.oauthProviderId);
211
- if (res) {
212
- apiKey = res.apiKey;
213
- // Some providers rewrite the model (e.g. base URL) from credentials.
214
- const prov = getOAuthProvider(this.oauthProviderId);
215
- if (prov?.modifyModels) {
216
- effectiveModel = prov.modifyModels([model], res.credentials)[0] ?? model;
217
- }
218
- }
219
- else if (OAUTH_ONLY_PROVIDERS.has(this.oauthProviderId)) {
220
- // OAuth-only provider with no stored credentials — cannot fall back
221
- // to an API key, so fail this turn with an actionable message.
222
- return this.errorTurn(agentSessionId, `Chat model '${this.cfg.model}' requires an OAuth login. Run: ` +
223
- `lastlight oauth login ${this.oauthProviderId}`);
224
- }
225
- // Non-OAuth-only (anthropic) with no creds: fall through to env-key auth.
226
- }
227
- catch (err) {
228
- const msg = err instanceof Error ? err.message : String(err);
229
- return this.errorTurn(agentSessionId, `OAuth token refresh failed for '${this.oauthProviderId}': ${msg}. ` +
230
- `Re-run: lastlight oauth login ${this.oauthProviderId}`);
231
- }
232
- }
233
- // Rehydrate conversation context from the DB. Messages were stored
234
- // text-only on prior turns; we replay them as alternating user /
235
- // assistant text messages. Tool calls/results inside a single turn
236
- // never persist (they only live for that turn's loop) — that's a
237
- // deliberate simplification: the agent gets a clean conversation
238
- // history and can re-tool if asked again.
239
- const history = this.sessionManager.getHistory(messagingSessionId, 50);
240
- const messages = history.map((h) => textMessage(h.role, h.content, h.timestamp));
241
- messages.push(textMessage("user", prompt, new Date().toISOString()));
242
- const context = {
243
- systemPrompt: this.cfg.systemPrompt,
244
- messages,
245
- tools: this.mergedTools,
246
- };
247
- const errors = [];
248
- const assistantMessages = [];
249
- const toolResults = [];
250
- const opts = {
251
- reasoning: pickReasoning(this.cfg.thinking),
252
- timeoutMs: this.cfg.timeoutMs ?? 120_000,
253
- ...(apiKey ? { apiKey } : {}),
254
- };
255
- let finish = "stop";
256
- let tokensIn = 0;
257
- let tokensOut = 0;
258
- let cacheRead = 0;
259
- let cacheWrite = 0;
260
- let costUsd = 0;
261
- let modelTurns = 0;
262
- let finalText = "";
263
- for (let round = 0; round < MAX_TOOL_ROUNDS + 1; round++) {
264
- modelTurns++;
265
- let assistant;
266
- try {
267
- assistant = await completeWithRetry(completeSimple, effectiveModel, context, opts, {
268
- onRetry: ({ attempt, delayMs, reason }) => console.warn(`[chat] transient model error (retry ${attempt}/${CHAT_RETRY_BACKOFF_MS.length} ` +
269
- `in ${delayMs / 1000}s): ${reason}`),
270
- });
271
- }
272
- catch (err) {
273
- const msg = err instanceof Error ? err.message : String(err);
274
- errors.push(msg);
275
- finish = "error";
276
- break;
277
- }
278
- assistantMessages.push(assistant);
279
- context.messages.push(assistant);
280
- tokensIn += assistant.usage.input;
281
- tokensOut += assistant.usage.output;
282
- cacheRead += assistant.usage.cacheRead;
283
- cacheWrite += assistant.usage.cacheWrite;
284
- costUsd += assistant.usage.cost.total;
285
- if (assistant.stopReason === "error" || assistant.stopReason === "aborted") {
286
- errors.push(assistant.errorMessage ?? assistant.stopReason);
287
- finish = "error";
288
- break;
289
- }
290
- // Pull text out (last text block wins — same convention as pi-ai's run() helper).
291
- const text = assistant.content
292
- .filter((c) => c.type === "text" && typeof c.text === "string")
293
- .map((c) => c.text)
294
- .join("");
295
- if (text)
296
- finalText = text;
297
- // Tool calls? Execute and loop.
298
- const toolCalls = assistant.content.filter((c) => c.type === "toolCall");
299
- if (toolCalls.length === 0) {
300
- finish = "stop";
301
- break;
302
- }
303
- if (!this.mergedTools) {
304
- // Model emitted a tool call without any tools registered — shouldn't
305
- // happen, but bail out rather than loop forever.
306
- errors.push("Model called a tool, but no tools are registered for chat.");
307
- finish = "error";
308
- break;
309
- }
310
- for (const call of toolCalls) {
311
- const { content, isError } = await this.dispatchTool(call);
312
- const tr = {
313
- role: "toolResult",
314
- toolCallId: call.id,
315
- toolName: call.name,
316
- content: [{ type: "text", text: content }],
317
- isError,
318
- timestamp: Date.now(),
319
- };
320
- toolResults.push(tr);
321
- context.messages.push(tr);
322
- if (isError)
323
- errors.push(`${call.name}: ${content}`);
324
- }
325
- if (round === MAX_TOOL_ROUNDS) {
326
- finish = "max-rounds";
327
- errors.push(`Hit MAX_TOOL_ROUNDS (${MAX_TOOL_ROUNDS}); giving up on this turn.`);
328
- break;
329
- }
330
- }
331
- // Persist this turn's user + final assistant text. We do NOT persist
332
- // tool calls or intermediate model responses — only the human-visible
333
- // turn boundaries — to keep the rehydrated context compact.
334
- this.sessionManager.addMessage(messagingSessionId, "user", prompt);
335
- if (finalText) {
336
- this.sessionManager.addMessage(messagingSessionId, "assistant", finalText);
337
- }
338
- this.sessionManager.touchSession(messagingSessionId);
339
- return {
340
- text: finalText,
341
- agentSessionId,
342
- tokens: {
343
- input: tokensIn,
344
- output: tokensOut,
345
- cacheRead,
346
- cacheWrite,
347
- },
348
- costUsd,
349
- modelTurns,
350
- finish,
351
- errors,
352
- assistantMessages,
353
- toolResults,
354
- modelId: this.cfg.model,
355
- };
356
- }
357
- }
358
- // ── Helpers ─────────────────────────────────────────────────────────
359
- function resolveModel(spec) {
360
- const idx = spec.indexOf("/");
361
- if (idx < 0)
362
- throw new Error(`model spec must be 'provider/id', got '${spec}'`);
363
- const provider = spec.slice(0, idx);
364
- const modelId = spec.slice(idx + 1);
365
- // pi-ai's getModel is typed against its static registry; at runtime it
366
- // accepts arbitrary strings AND returns undefined for unknown ids rather
367
- // than throwing. Without this guard the first chat turn crashes deep in
368
- // the provider stack with "Cannot read properties of undefined (reading
369
- // 'api')" — surface a clear, actionable error instead.
370
- const model = getModel(provider, modelId);
371
- if (!model) {
372
- throw new Error(`Unknown chat model '${spec}'. pi-ai's registry has no '${modelId}' for provider '${provider}'. ` +
373
- `Set LASTLIGHT_MODELS (or LASTLIGHT_MODEL) to a registered model id.`);
374
- }
375
- return model;
376
- }
377
- function textMessage(role, content, timestamp) {
378
- const ts = parseTimestamp(timestamp);
379
- if (role === "user") {
380
- const m = { role: "user", content, timestamp: ts };
381
- return m;
382
- }
383
- // Treat any non-user historical role as assistant text.
384
- const m = {
385
- role: "assistant",
386
- content: [{ type: "text", text: content }],
387
- api: "openai-completions",
388
- provider: "history",
389
- model: "history",
390
- usage: zeroUsage(),
391
- stopReason: "stop",
392
- timestamp: ts,
393
- };
394
- return m;
395
- }
396
- function parseTimestamp(raw) {
397
- const ms = Date.parse(raw);
398
- return Number.isFinite(ms) ? ms : Date.now();
399
- }
400
- function zeroUsage() {
401
- return {
402
- input: 0,
403
- output: 0,
404
- cacheRead: 0,
405
- cacheWrite: 0,
406
- totalTokens: 0,
407
- cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
408
- };
409
- }
410
- function pickReasoning(level) {
411
- // pi-ai's SimpleStreamOptions.reasoning excludes "off" — pi-ai default
412
- // is no reasoning, so we pass undefined for "off".
413
- if (!level || level === "off")
414
- return undefined;
415
- return level;
416
- }
417
- /**
418
- * Octokit is bundled here only because github-tools.ts imports it at module
419
- * load. Re-export so callers can probe whether the integration is wired
420
- * without round-tripping through that file. Typed as `unknown` to avoid
421
- * dragging the Octokit type chain into the published .d.ts.
422
- */
423
- export const __octokitForTest = Octokit;
424
- //# sourceMappingURL=chat-runner.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"chat-runner.js","sourceRoot":"","sources":["../../../src/engine/chat/chat-runner.ts"],"names":[],"mappings":"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"}
@@ -1,45 +0,0 @@
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;
@@ -1,184 +0,0 @@
1
- /**
2
- * Skill catalogue + read tool for the in-process chat path.
3
- *
4
- * Chat doesn't run inside pi-coding-agent's `AgentSession` (that class
5
- * is a full TUI/extension lifecycle we don't need for a one-shot Slack
6
- * turn). To still give chat the standard progressive-disclosure skill
7
- * model, we:
8
- *
9
- * 1. Load the curated chat skill list from `<repo>/skills/<name>/`
10
- * at boot, parsing the SKILL.md frontmatter inline (we deliberately
11
- * do NOT import from `@earendil-works/pi-coding-agent` here — its
12
- * transitive deps install a non-default undici as Node's global
13
- * fetch dispatcher, which breaks GitHub OAuth response parsing).
14
- * 2. Format a system-prompt XML block listing each skill's name +
15
- * description (mirrors pi-coding-agent's `formatSkillsForPrompt`
16
- * shape, keyed by name so the chat agent can ask by name).
17
- * 3. Expose a `read_skill` tool that resolves a name to that skill's
18
- * SKILL.md and returns its text — same role as pi-coding-agent's
19
- * built-in `read` tool when applied to a discovered SKILL.md.
20
- *
21
- * The curated list is intentionally hard-coded for v1. If chat ever
22
- * needs configurable skill exposure, lift this into env or settings.
23
- */
24
- import { existsSync, readFileSync } from "node:fs";
25
- import { join, resolve } from "node:path";
26
- import { Type } from "@sinclair/typebox";
27
- import { resolveSkillPaths } from "../../workflows/loader.js";
28
- /**
29
- * Skills exposed to chat threads. `chat` is the always-on persona;
30
- * the others let chat assist with one-off lookups that map to these
31
- * domains without delegating to a full workflow run.
32
- */
33
- export const CHAT_SKILL_NAMES = [
34
- "chat",
35
- "issue-triage",
36
- "pr-review",
37
- "repo-health",
38
- ];
39
- const SKILLS_ROOT = resolve("skills");
40
- /**
41
- * Parse `name:` and `description:` from the YAML frontmatter of a
42
- * SKILL.md. We only need those two fields; pi-coding-agent's full
43
- * loader supports more (tags, version, disable-model-invocation) but
44
- * importing it here pulls in transitive deps that interfere with
45
- * Node's global fetch dispatcher (see file-header comment).
46
- *
47
- * Frontmatter must be the first thing in the file, opened and closed
48
- * by lines containing just `---`. Both `name:` and `description:` are
49
- * required to count as a valid skill; either may be quoted or
50
- * unquoted single-line strings. Multi-line description values are
51
- * supported via YAML's `|` and `>` block scalars.
52
- */
53
- function parseSkillFrontmatter(md) {
54
- const lines = md.split(/\r?\n/);
55
- if (lines[0]?.trim() !== "---")
56
- return {};
57
- const end = lines.findIndex((l, i) => i > 0 && l.trim() === "---");
58
- if (end < 0)
59
- return {};
60
- const body = lines.slice(1, end);
61
- const out = {};
62
- for (let i = 0; i < body.length; i++) {
63
- const m = body[i].match(/^([A-Za-z0-9_-]+)\s*:\s*(.*)$/);
64
- if (!m)
65
- continue;
66
- const key = m[1];
67
- const raw = m[2];
68
- if (key !== "name" && key !== "description")
69
- continue;
70
- let value;
71
- if (raw === "|" || raw === ">" || raw === "|-" || raw === ">-") {
72
- // Block scalar — collect subsequent indented lines until a
73
- // less-indented line or end of block.
74
- const collected = [];
75
- let j = i + 1;
76
- while (j < body.length && /^\s+/.test(body[j])) {
77
- collected.push(body[j].replace(/^\s+/, ""));
78
- j++;
79
- }
80
- value = raw.startsWith(">") ? collected.join(" ") : collected.join("\n");
81
- i = j - 1;
82
- }
83
- else {
84
- value = raw.replace(/^['"]|['"]$/g, "").trim();
85
- }
86
- if (value)
87
- out[key] = value;
88
- }
89
- return out;
90
- }
91
- /**
92
- * Load the curated chat skill catalogue from `<repo>/skills/`.
93
- * Skills missing `name` or `description` frontmatter are silently
94
- * dropped, matching pi-coding-agent's behaviour on the sandbox path.
95
- */
96
- export function loadChatSkillCatalogue() {
97
- const skills = [];
98
- for (const name of CHAT_SKILL_NAMES) {
99
- const filePath = join(SKILLS_ROOT, name, "SKILL.md");
100
- if (!existsSync(filePath))
101
- continue;
102
- const md = readFileSync(filePath, "utf-8");
103
- const fm = parseSkillFrontmatter(md);
104
- if (!fm.name || !fm.description)
105
- continue;
106
- skills.push({ name: fm.name, description: fm.description, filePath });
107
- }
108
- if (skills.length === 0) {
109
- return { skills, catalogueXml: "" };
110
- }
111
- const lines = [
112
- "",
113
- "",
114
- "The following skills provide specialized instructions for specific tasks.",
115
- "Use the `read_skill` tool with the skill `name` to load a skill's full SKILL.md when the user's task matches its description.",
116
- "",
117
- "<available_skills>",
118
- ];
119
- for (const skill of skills) {
120
- lines.push(" <skill>");
121
- lines.push(` <name>${escapeXml(skill.name)}</name>`);
122
- lines.push(` <description>${escapeXml(skill.description)}</description>`);
123
- lines.push(" </skill>");
124
- }
125
- lines.push("</available_skills>");
126
- return { skills, catalogueXml: lines.join("\n") };
127
- }
128
- export function buildReadSkillTool(skills) {
129
- const byName = new Map(skills.map((s) => [s.name, s]));
130
- const enumNames = skills.map((s) => s.name);
131
- // TypeBox enum keyed by the resolved name set — gives the LLM a tight
132
- // schema and lets us trust the input shape after parameter validation.
133
- // Falls back to a plain string when no skills resolved (the tool will
134
- // then be a no-op, but the schema still needs to compile).
135
- const parameters = Type.Object({
136
- name: enumNames.length > 0
137
- ? Type.Union(enumNames.map((n) => Type.Literal(n)), { description: "The skill name from <available_skills>." })
138
- : Type.String({ description: "The skill name from <available_skills>." }),
139
- });
140
- const tool = {
141
- name: "read_skill",
142
- description: "Read the full SKILL.md text for a skill listed in <available_skills>. " +
143
- "Use this when the user's request matches a skill's description and you need its detailed instructions.",
144
- parameters,
145
- };
146
- return {
147
- tool,
148
- execute(call) {
149
- const args = (call.arguments ?? {});
150
- const name = typeof args.name === "string" ? args.name : "";
151
- const skill = byName.get(name);
152
- if (!skill) {
153
- return {
154
- content: JSON.stringify({
155
- error: `unknown skill "${name}". Available: ${enumNames.join(", ") || "(none)"}.`,
156
- }),
157
- isError: true,
158
- };
159
- }
160
- try {
161
- // Re-resolve through the loader's allowlist + safety check rather
162
- // than trusting `skill.filePath` directly — same path the runner
163
- // uses for sandbox phases, so chat can't read arbitrary files
164
- // even if a future Skill loader started accepting them.
165
- const [dir] = resolveSkillPaths([skill.name]);
166
- const md = readFileSync(`${dir}/SKILL.md`, "utf-8");
167
- return { content: md, isError: false };
168
- }
169
- catch (err) {
170
- const msg = err instanceof Error ? err.message : String(err);
171
- return { content: JSON.stringify({ error: msg }), isError: true };
172
- }
173
- },
174
- };
175
- }
176
- function escapeXml(s) {
177
- return s
178
- .replace(/&/g, "&amp;")
179
- .replace(/</g, "&lt;")
180
- .replace(/>/g, "&gt;")
181
- .replace(/"/g, "&quot;")
182
- .replace(/'/g, "&apos;");
183
- }
184
- //# sourceMappingURL=chat-skills.js.map