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,434 @@
1
+ import { mkdirSync, writeFileSync } from "fs";
2
+ import { join } from "path";
3
+ import { DEFAULT_ALLOWLIST, mergeAllowlist } from "./egress-allowlist.js";
4
+ /**
5
+ * Egress firewall config generation for the docker sandbox backend.
6
+ *
7
+ * Architecture (replaces the earlier tinyproxy CONNECT-proxy):
8
+ *
9
+ * sandbox-egress (internal: true, subnet 172.30.0.0/24)
10
+ * ├─ sandbox containers (docker run --dns <coredns-ip>)
11
+ * ├─ coredns-strict 172.30.0.10 → returns nginx-strict IP for allowlist hosts, NXDOMAIN otherwise
12
+ * ├─ coredns-open 172.30.0.11 → returns nginx-open IP for ANY hostname (except hard-deny SSRF magnets)
13
+ * ├─ nginx-egress-strict 172.30.0.20 → ssl_preread, SNI must match allowlist; tunnel upstream via proxy-egress
14
+ * └─ nginx-egress-open 172.30.0.21 → tunnel any SNI; client DNS already gated through coredns-open
15
+ *
16
+ * Why this instead of a forward proxy (tinyproxy/smokescreen): clients
17
+ * inside the sandbox (especially the OpenAI/Anthropic SDKs that build
18
+ * their own undici dispatchers) don't honour HTTP_PROXY / HTTPS_PROXY.
19
+ * Forcing them to cooperate is a losing battle. By spoofing DNS and
20
+ * peeking SNI at the network layer, the sandbox sees no proxy at all —
21
+ * it dials `api.openai.com:443` directly. The firewall intercepts the
22
+ * connection by virtue of being the only thing the spoofed DNS pointed
23
+ * at.
24
+ *
25
+ * Inspired by Vercel Sandbox's egress firewall (SNI peeking, no env
26
+ * vars). Their implementation also handles TLS termination for
27
+ * credentials brokering and Postgres STARTTLS — we don't (yet).
28
+ *
29
+ * ## Wildcards
30
+ *
31
+ * Entries in egress-allowlist.ts with a leading dot (`".github.com"`)
32
+ * match the apex plus every subdomain. nginx's `map` directive supports
33
+ * this syntax natively. CoreDNS uses the `template` plugin with an
34
+ * anchored regex to do the same.
35
+ */
36
+ /** Fixed IPs assigned in docker-compose.yml so `--dns` and nginx upstreams can reference them. */
37
+ export const COREDNS_STRICT_IP = "172.30.0.10";
38
+ export const COREDNS_OPEN_IP = "172.30.0.11";
39
+ export const NGINX_STRICT_IP = "172.30.0.20";
40
+ export const NGINX_OPEN_IP = "172.30.0.21";
41
+ /**
42
+ * Static IP of the in-network OTEL collector (docker backend). Sandboxes
43
+ * dial it directly by IP — it lives on `sandbox-egress` alongside the
44
+ * firewalls, so no DNS lookup (and therefore no coredns allowlist entry)
45
+ * is involved. The collector is the ONLY OTLP endpoint a sandbox ever
46
+ * sees: it terminates the sandbox's telemetry and re-exports to the real
47
+ * backend over `proxy-egress` using credentials that stay host-side. This
48
+ * is why the strict SNI firewall no longer needs to know about collector
49
+ * hosts or non-443 ports — that hop happens on the trusted outbound leg,
50
+ * not through `ssl_preread`.
51
+ */
52
+ export const OTEL_COLLECTOR_IP = "172.30.0.30";
53
+ /** OTLP/HTTP + OTLP/gRPC receiver ports the in-network collector listens on. */
54
+ export const OTEL_COLLECTOR_OTLP_HTTP_PORT = 4318;
55
+ export const OTEL_COLLECTOR_OTLP_GRPC_PORT = 4317;
56
+ /** Endpoint a docker sandbox is told to export OTLP to (HTTP/protobuf). */
57
+ export const OTEL_COLLECTOR_SANDBOX_ENDPOINT = `http://${OTEL_COLLECTOR_IP}:${OTEL_COLLECTOR_OTLP_HTTP_PORT}`;
58
+ /**
59
+ * UID the `otel/opentelemetry-collector` image runs as (its Dockerfile
60
+ * `USER`). The collector reads the OTLP config (which can hold backend auth
61
+ * headers) as this non-root user. To let it read a mode-0600 file from the
62
+ * shared volume WITHOUT running as root or making the secret world-readable,
63
+ * the harness's own `lastlight` user is pinned to this same UID (see the
64
+ * Dockerfile `useradd -u`), so the collector reads files it wrote as their
65
+ * owner. The Dockerfile and the collector image tag in docker-compose.yml
66
+ * must move together if a future image bumps the UID — enforced by a test in
67
+ * docker-compose.test.ts.
68
+ */
69
+ export const OTEL_COLLECTOR_UID = 10001;
70
+ /** Subnet for sandbox-egress. Compose declares this CIDR so the IPs above are valid. */
71
+ export const SANDBOX_EGRESS_SUBNET = "172.30.0.0/24";
72
+ /**
73
+ * Hostnames the open coredns explicitly NXDOMAINs even in unrestricted
74
+ * mode — known SSRF magnets. nginx's `ssl_preread` SNI inspection alone
75
+ * can't catch hostnames that resolve to private IPs (the DNS server
76
+ * we control gets the first say), so this is the right layer to enforce
77
+ * "no cloud metadata, no internal services" even with `unrestricted_egress`.
78
+ */
79
+ const OPEN_MODE_HARD_DENY = [
80
+ "metadata.google.internal",
81
+ "169.254.169.254", // GCP / AWS / Azure metadata service IP literal
82
+ ];
83
+ /**
84
+ * Convert one allowlist entry to its nginx `map` line.
85
+ *
86
+ * "openai.com" → '.openai.com $ssl_preread_server_name:443;'
87
+ *
88
+ * Every entry is treated as apex+subdomain (see egress-allowlist.ts).
89
+ * The generated line uses nginx's `.foo.com` leading-dot syntax,
90
+ * which is its built-in "match this domain and all subdomains" form.
91
+ * Upstream is whatever SNI the client sent — we don't know which
92
+ * subdomain they're targeting at config-gen time.
93
+ */
94
+ function nginxMapLine(entry) {
95
+ return ` .${entry} $ssl_preread_server_name:443;`;
96
+ }
97
+ /**
98
+ * Build one CoreDNS `match` regex per allowlist entry. All entries
99
+ * share a SINGLE `template` block (see renderCorefileStrict) because
100
+ * CoreDNS only honours one `template` per zone — multiple blocks
101
+ * silently shadow each other.
102
+ *
103
+ * The `(^|\.)` prefix matches the apex (`openai.com.`) or any subdomain
104
+ * (`api.openai.com.`) — same semantics as nginx's leading-dot form.
105
+ */
106
+ function corednsMatchLineForEntry(entry) {
107
+ const escapedHost = entry.replaceAll(".", "\\.");
108
+ return ` match (^|\\.)${escapedHost}\\.$`;
109
+ }
110
+ /** Build the strict nginx.conf — ssl_preread + map on SNI allowlist. */
111
+ export function renderNginxStrictConf() {
112
+ const mapLines = mergeAllowlist(DEFAULT_ALLOWLIST).map(nginxMapLine).join("\n");
113
+ return `# Generated by lastlight at harness boot. DO NOT EDIT BY HAND —
114
+ # source of truth is src/sandbox/egress-allowlist.ts.
115
+
116
+ error_log /dev/stderr warn;
117
+ pid /tmp/nginx.pid;
118
+
119
+ events { worker_connections 1024; }
120
+
121
+ # Streams (TCP/UDP). \`ssl_preread\` reads the TLS ClientHello without
122
+ # terminating the session, exposing the SNI hostname as
123
+ # \`$ssl_preread_server_name\`. We \`map\` that to an upstream — anything
124
+ # unmatched is sunk to 127.0.0.1:1 (no listener, instant reset).
125
+ stream {
126
+ log_format basic '$remote_addr -> $ssl_preread_server_name -> $upstream_addr status=$status';
127
+ access_log /dev/stdout basic;
128
+
129
+ # Runtime resolver for upstream hostnames (docker's embedded DNS).
130
+ resolver 127.0.0.11 valid=30s ipv6=off;
131
+
132
+ # Allowlist. The \`hostnames\` directive enables nginx's wildcard
133
+ # hostname match: a key like ".github.com" matches "github.com" AND
134
+ # any subdomain. WITHOUT \`hostnames\`, map does exact string match
135
+ # only and ".github.com" never matches anything real (we hit this
136
+ # exact bug in prod — every allowlisted host fell through to the
137
+ # black hole).
138
+ map $ssl_preread_server_name $upstream_target {
139
+ hostnames;
140
+ ${mapLines}
141
+ # Anything else → black hole. The connection resets immediately;
142
+ # no data ever leaves the sandbox-egress network.
143
+ default 127.0.0.1:1;
144
+ }
145
+
146
+ server {
147
+ listen 443;
148
+ ssl_preread on;
149
+ proxy_pass $upstream_target;
150
+ proxy_connect_timeout 5s;
151
+ proxy_timeout 60s;
152
+ }
153
+ }
154
+ `;
155
+ }
156
+ /** Build the open nginx.conf — no SNI allowlist, just tunnel whatever DNS pointed at. */
157
+ export function renderNginxOpenConf() {
158
+ return `# Generated by lastlight at harness boot. DO NOT EDIT BY HAND.
159
+ # This nginx is used only by phases that declared \`unrestricted_egress: true\`.
160
+ # No SNI allowlist — every host is tunnelled. The corresponding coredns-open
161
+ # refuses to resolve the cloud-metadata hostnames so SSRF to them is blocked
162
+ # even in this mode.
163
+
164
+ error_log /dev/stderr warn;
165
+ pid /tmp/nginx.pid;
166
+
167
+ events { worker_connections 1024; }
168
+
169
+ stream {
170
+ log_format basic '$remote_addr -> $ssl_preread_server_name -> $upstream_addr status=$status';
171
+ access_log /dev/stdout basic;
172
+ resolver 127.0.0.11 valid=30s ipv6=off;
173
+
174
+ server {
175
+ listen 443;
176
+ ssl_preread on;
177
+ # $ssl_preread_server_name is whatever SNI the client sent. Tunnel
178
+ # to that hostname on :443. No allowlist check.
179
+ proxy_pass $ssl_preread_server_name:443;
180
+ proxy_connect_timeout 5s;
181
+ proxy_timeout 60s;
182
+ }
183
+ }
184
+ `;
185
+ }
186
+ /** Build the Corefile that returns the strict nginx IP for allowlist hosts. */
187
+ export function renderCorefileStrict() {
188
+ // ALL allowlist entries share a SINGLE template block. CoreDNS only
189
+ // honours one `template` per (class, type, zone), so multiple blocks
190
+ // silently overwrite each other — we learned this in prod when only
191
+ // the first host in the list resolved.
192
+ const matchLines = mergeAllowlist(DEFAULT_ALLOWLIST).map(corednsMatchLineForEntry).join("\n");
193
+ return `# Generated by lastlight from src/sandbox/egress-allowlist.ts.
194
+ # All allowlist hosts live in a single \`template IN A\` block (multiple
195
+ # template blocks per zone are NOT additive — they shadow each other).
196
+ # Queries that don't match any \`match\` regex fall through to the
197
+ # catch-all NXDOMAIN at the end.
198
+ .:53 {
199
+ template IN A {
200
+ ${matchLines}
201
+ answer "{{ .Name }} 60 IN A ${NGINX_STRICT_IP}"
202
+ }
203
+ # Catch-all: NXDOMAIN for everything else (including AAAA queries,
204
+ # since nginx-egress only binds 443 on IPv4).
205
+ template IN ANY {
206
+ rcode NXDOMAIN
207
+ }
208
+ errors
209
+ log
210
+ }
211
+ `;
212
+ }
213
+ /** Build the Corefile that returns the open nginx IP for ANY hostname (except hard-denies). */
214
+ export function renderCorefileOpen() {
215
+ // Hard-deny hosts each get their OWN zone block. CoreDNS routes queries
216
+ // to the longest-suffix-matching zone, so `metadata.google.internal:53`
217
+ // catches both the apex and every subdomain before the catch-all `.`
218
+ // zone ever sees them. We do NOT use a multi-`template` layout inside
219
+ // the catch-all zone because CoreDNS only honours one template per
220
+ // (class, type) and prior templates with non-matching `match` clauses
221
+ // silently drop the query — leaving sandboxes with no DNS answer at
222
+ // all (which is exactly what failed in prod the first time explore
223
+ // ran on the open path).
224
+ const hardDenyZones = OPEN_MODE_HARD_DENY.map((host) => `# Hard-deny zone for ${host} (SSRF floor — NXDOMAIN even in unrestricted mode).
225
+ ${host}:53 {
226
+ template IN ANY {
227
+ rcode NXDOMAIN
228
+ }
229
+ errors
230
+ log
231
+ }
232
+ `).join("\n");
233
+ return `# Generated by lastlight. Used by sandbox phases with unrestricted_egress: true.
234
+ # Returns nginx-egress-open's IP for every hostname EXCEPT the SSRF hard-denies
235
+ # (cloud metadata literals etc).
236
+ .:53 {
237
+ # Everything → nginx-egress-open IP. Hard-deny names are intercepted
238
+ # by the per-host zones declared below (longest-suffix zone match).
239
+ template IN A {
240
+ answer "{{ .Name }} 60 IN A ${NGINX_OPEN_IP}"
241
+ }
242
+ # AAAA returns empty (we route only via IPv4).
243
+ template IN AAAA {
244
+ rcode NOERROR
245
+ }
246
+ errors
247
+ log
248
+ }
249
+
250
+ ${hardDenyZones}`;
251
+ }
252
+ /**
253
+ * Write the four config files under $STATE_DIR/proxy/. Idempotent.
254
+ * Returns the directory path. Compose bind-mounts this dir into the
255
+ * coredns + nginx containers read-only.
256
+ */
257
+ export function writeEgressFirewallConfigs(stateDir) {
258
+ const dir = join(stateDir, "proxy");
259
+ mkdirSync(dir, { recursive: true });
260
+ writeFileSync(join(dir, "nginx-strict.conf"), renderNginxStrictConf());
261
+ writeFileSync(join(dir, "nginx-open.conf"), renderNginxOpenConf());
262
+ writeFileSync(join(dir, "Corefile.strict"), renderCorefileStrict());
263
+ writeFileSync(join(dir, "Corefile.open"), renderCorefileOpen());
264
+ return dir;
265
+ }
266
+ /**
267
+ * Parse an OTLP headers string (`key1=val1,key2=val2`, the OTEL spec format
268
+ * used by `OTEL_EXPORTER_OTLP_HEADERS`) into an ordered list of pairs.
269
+ * Malformed segments (no `=`, empty key) are dropped. Values keep any inner
270
+ * `=` so bearer tokens survive intact.
271
+ */
272
+ function parseOtlpHeaders(raw) {
273
+ if (!raw)
274
+ return [];
275
+ const out = [];
276
+ for (const segment of raw.split(",")) {
277
+ const eq = segment.indexOf("=");
278
+ if (eq <= 0)
279
+ continue;
280
+ const key = segment.slice(0, eq).trim();
281
+ const value = segment.slice(eq + 1).trim();
282
+ // Reject CR/LF in either part: a real newline in an HTTP header value is
283
+ // header injection on the collector→backend leg, and would also break the
284
+ // YAML scalar. A header carrying a newline is corruption/injection, not a
285
+ // valid OTLP config — drop the pair rather than emit something dangerous.
286
+ if (!key || /[\r\n]/.test(key) || /[\r\n]/.test(value))
287
+ continue;
288
+ out.push([key, value]);
289
+ }
290
+ return out;
291
+ }
292
+ /**
293
+ * YAML double-quoted-scalar escape. Backslash and quote are the cases that
294
+ * appear in tokens/URLs; CR/LF/TAB are escaped too as a hard guarantee that
295
+ * we NEVER emit a syntactically invalid collector config regardless of input
296
+ * (header values are already CR/LF-filtered in parseOtlpHeaders, but a stray
297
+ * control char in any other field must not be able to break the file).
298
+ */
299
+ function yamlQuote(s) {
300
+ return `"${s
301
+ .replace(/\\/g, "\\\\")
302
+ .replace(/"/g, '\\"')
303
+ .replace(/\n/g, "\\n")
304
+ .replace(/\r/g, "\\r")
305
+ .replace(/\t/g, "\\t")}"`;
306
+ }
307
+ /** OTLP signals the collector pipelines cover, in stable output order. */
308
+ const OTLP_SIGNALS = ["traces", "metrics", "logs"];
309
+ /**
310
+ * Resolve one signal's backend per the OTEL env precedence: a
311
+ * signal-specific endpoint/headers var wins, otherwise the generic one.
312
+ * Returns null when neither is set — that signal's pipeline then drops to
313
+ * the `debug` exporter instead of being misrouted to another signal's URL.
314
+ */
315
+ function resolveSignalBackend(env, signal) {
316
+ const SIG = signal.toUpperCase();
317
+ const specificEndpoint = (env[`OTEL_EXPORTER_OTLP_${SIG}_ENDPOINT`] || "").trim();
318
+ const genericEndpoint = (env.OTEL_EXPORTER_OTLP_ENDPOINT || "").trim();
319
+ if (!specificEndpoint && !genericEndpoint)
320
+ return null;
321
+ const specificHeaders = (env[`OTEL_EXPORTER_OTLP_${SIG}_HEADERS`] || "").trim();
322
+ const genericHeaders = env.OTEL_EXPORTER_OTLP_HEADERS;
323
+ return specificEndpoint
324
+ ? { endpointField: `${signal}_endpoint`, endpoint: specificEndpoint, headers: parseOtlpHeaders(specificHeaders || genericHeaders) }
325
+ : { endpointField: "endpoint", endpoint: genericEndpoint, headers: parseOtlpHeaders(specificHeaders || genericHeaders) };
326
+ }
327
+ /**
328
+ * Render the in-network OTEL collector config (docker backend).
329
+ *
330
+ * `opts.active` gates whether the collector forwards anywhere. It MUST track
331
+ * the harness's effective `otel.enabled && otel.forwardToSandbox` — when
332
+ * false, every pipeline is wired to a `debug` exporter (drops data) and NO
333
+ * backend endpoint or credential is emitted, even if `OTEL_EXPORTER_OTLP_*`
334
+ * env vars are present. This is the security floor: the collector listens on
335
+ * a static IP that sandboxes can reach, so if forwarding weren't gated, a
336
+ * sandbox could POST directly to it and exfil to the real backend regardless
337
+ * of the documented `LASTLIGHT_OTEL_ENABLED` / `FORWARD_TO_SANDBOX` opt-outs.
338
+ *
339
+ * When active, the collector re-exports to the REAL backend — the standard
340
+ * `OTEL_EXPORTER_OTLP_ENDPOINT` / `OTEL_EXPORTER_OTLP_HEADERS` plus their
341
+ * per-signal `OTEL_EXPORTER_OTLP_<SIGNAL>_ENDPOINT` / `_HEADERS` overrides,
342
+ * resolved with the spec's precedence. Each signal gets its own exporter so
343
+ * a split traces/metrics/logs setup is routed correctly rather than all
344
+ * collapsing onto whichever endpoint won a fallback chain. Those credentials
345
+ * live here, in a file on the host mounted read-only into the collector, and
346
+ * are NEVER forwarded into an untrusted sandbox. The sandbox can only
347
+ * influence span *content* sent to the harness's own fixed backend — it
348
+ * cannot redirect where the collector exports, so this adds no SSRF/exfil
349
+ * surface.
350
+ *
351
+ * A signal with no configured endpoint (neither specific nor generic) is
352
+ * likewise wired to `debug` so the collector still boots cleanly and accepts
353
+ * connections — sandboxes simply never send what isn't routed.
354
+ */
355
+ export function renderOtelCollectorConfig(opts) {
356
+ const env = opts.env ?? process.env;
357
+ const exporterBlocks = [];
358
+ const pipelineBlocks = [];
359
+ let needsDebug = false;
360
+ for (const signal of OTLP_SIGNALS) {
361
+ // When inactive, resolve NO backend — every signal drops to debug and
362
+ // not a single OTEL_* value reaches the generated file.
363
+ const backend = opts.active ? resolveSignalBackend(env, signal) : null;
364
+ let exporterName;
365
+ if (!backend) {
366
+ exporterName = "debug";
367
+ needsDebug = true;
368
+ }
369
+ else {
370
+ exporterName = `otlphttp/${signal}`;
371
+ const headerLines = backend.headers.length
372
+ ? `\n headers:\n${backend.headers.map(([k, v]) => ` ${yamlQuote(k)}: ${yamlQuote(v)}`).join("\n")}`
373
+ : "";
374
+ exporterBlocks.push(` ${exporterName}:\n ${backend.endpointField}: ${yamlQuote(backend.endpoint)}${headerLines}`);
375
+ }
376
+ pipelineBlocks.push(` ${signal}:\n receivers: [otlp]\n processors: [batch]\n exporters: [${exporterName}]`);
377
+ }
378
+ if (needsDebug)
379
+ exporterBlocks.push(` debug:\n verbosity: normal`);
380
+ const statusComment = opts.active
381
+ ? `# Sandboxes export OTLP to this collector (reached by its internal IP on
382
+ # sandbox-egress); the collector re-exports to the configured backend over
383
+ # proxy-egress. Backend credentials below stay host-side — they are never
384
+ # forwarded into a sandbox.`
385
+ : `# Telemetry forwarding is DISABLED (LASTLIGHT_OTEL_ENABLED is off, or
386
+ # LASTLIGHT_OTEL_FORWARD_TO_SANDBOX is false). The collector still listens so
387
+ # sandboxes don't get connection errors, but every signal drops to a local
388
+ # debug exporter — nothing is forwarded to any backend, and no OTEL_* endpoint
389
+ # or credential is emitted here. This is the egress floor for the static
390
+ # collector IP regardless of any OTEL_* env vars present.`;
391
+ return `# Generated by lastlight at harness boot. DO NOT EDIT BY HAND —
392
+ # source of truth is src/sandbox/egress-firewall-config.ts.
393
+ #
394
+ ${statusComment}
395
+ receivers:
396
+ otlp:
397
+ protocols:
398
+ http:
399
+ endpoint: 0.0.0.0:${OTEL_COLLECTOR_OTLP_HTTP_PORT}
400
+ grpc:
401
+ endpoint: 0.0.0.0:${OTEL_COLLECTOR_OTLP_GRPC_PORT}
402
+
403
+ processors:
404
+ batch: {}
405
+
406
+ exporters:
407
+ ${exporterBlocks.join("\n")}
408
+
409
+ service:
410
+ pipelines:
411
+ ${pipelineBlocks.join("\n")}
412
+ `;
413
+ }
414
+ /**
415
+ * Write the in-network collector config to $STATE_DIR/proxy/otel-collector.yaml.
416
+ * Mode 0600 — it can contain backend auth headers. Called at harness boot
417
+ * (and by the compose `egress-init` one-shot) so the file exists before the
418
+ * `otel-collector` service reads it. `opts.active` gates forwarding — see
419
+ * `renderOtelCollectorConfig`. The harness passes its parsed
420
+ * `otel.enabled && otel.forwardToSandbox`; the env-only callers compute it
421
+ * via `otelForwardActiveFromEnv`.
422
+ */
423
+ export function writeOtelCollectorConfig(stateDir, opts) {
424
+ const dir = join(stateDir, "proxy");
425
+ mkdirSync(dir, { recursive: true });
426
+ const path = join(dir, "otel-collector.yaml");
427
+ // Mode 0600 — it can carry backend auth headers. In the docker deployment
428
+ // the writer (harness/egress-init, gosu'd to `lastlight`) and the collector
429
+ // share UID 10001 (see OTEL_COLLECTOR_UID + the Dockerfile pin), so the
430
+ // collector reads this file as its owner without it being world-readable.
431
+ writeFileSync(path, renderOtelCollectorConfig(opts), { mode: 0o600 });
432
+ return path;
433
+ }
434
+ //# sourceMappingURL=egress-firewall-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"egress-firewall-config.js","sourceRoot":"","sources":["../../src/sandbox/egress-firewall-config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};