lastlight 0.6.2 → 0.7.1

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 (343) hide show
  1. package/dist/admin/routes.d.ts +1 -1
  2. package/dist/admin/routes.js +1 -1
  3. package/dist/admin/routes.js.map +1 -1
  4. package/dist/cli/cli-config.js.map +1 -0
  5. package/dist/cli/cli-format.js.map +1 -0
  6. package/dist/{cli-server.d.ts → cli/cli-server.d.ts} +1 -1
  7. package/dist/{cli-server.js → cli/cli-server.js} +2 -2
  8. package/dist/cli/cli-server.js.map +1 -0
  9. package/dist/cli/cli-timeline.js.map +1 -0
  10. package/dist/{cli.js → cli/cli.js} +2 -0
  11. package/dist/cli/cli.js.map +1 -0
  12. package/dist/{fork-cli.d.ts → cli/fork-cli.d.ts} +14 -5
  13. package/dist/{fork-cli.js → cli/fork-cli.js} +86 -16
  14. package/dist/cli/fork-cli.js.map +1 -0
  15. package/dist/{setup.js → cli/setup.js} +1 -1
  16. package/dist/cli/setup.js.map +1 -0
  17. package/dist/{skills-install.js → cli/skills-install.js} +1 -1
  18. package/dist/cli/skills-install.js.map +1 -0
  19. package/dist/config/config-resolve.js.map +1 -0
  20. package/dist/{config.js → config/config.js} +2 -2
  21. package/dist/config/config.js.map +1 -0
  22. package/dist/config/overlay-assets.js.map +1 -0
  23. package/dist/config/overlay-bootstrap.js.map +1 -0
  24. package/dist/connectors/github-webhook.js +5 -0
  25. package/dist/connectors/github-webhook.js.map +1 -1
  26. package/dist/connectors/types.d.ts +2 -0
  27. package/dist/engine/agent-executor.d.ts +8 -17
  28. package/dist/engine/agent-executor.js +35 -306
  29. package/dist/engine/agent-executor.js.map +1 -1
  30. package/dist/engine/{chat-runner.d.ts → chat/chat-runner.d.ts} +2 -2
  31. package/dist/engine/{chat-runner.js → chat/chat-runner.js} +1 -1
  32. package/dist/engine/chat/chat-runner.js.map +1 -0
  33. package/dist/engine/{chat-skills.js → chat/chat-skills.js} +1 -1
  34. package/dist/engine/chat/chat-skills.js.map +1 -0
  35. package/dist/engine/{chat.d.ts → chat/chat.d.ts} +2 -2
  36. package/dist/engine/{chat.js → chat/chat.js} +7 -7
  37. package/dist/engine/chat/chat.js.map +1 -0
  38. package/dist/engine/{message-batcher.d.ts → chat/message-batcher.d.ts} +1 -1
  39. package/dist/engine/chat/message-batcher.js.map +1 -0
  40. package/dist/engine/dispatcher.d.ts +2 -2
  41. package/dist/engine/dispatcher.js +24 -0
  42. package/dist/engine/dispatcher.js.map +1 -1
  43. package/dist/engine/executors/orchestrator.d.ts +81 -0
  44. package/dist/engine/executors/orchestrator.js +340 -0
  45. package/dist/engine/executors/orchestrator.js.map +1 -0
  46. package/dist/engine/executors/shared.d.ts +1 -1
  47. package/dist/engine/github/git-auth.js.map +1 -0
  48. package/dist/engine/github/github-app-client.js.map +1 -0
  49. package/dist/engine/github/github-tools.js.map +1 -0
  50. package/dist/engine/github/github.js.map +1 -0
  51. package/dist/engine/{profiles.d.ts → github/profiles.d.ts} +1 -1
  52. package/dist/engine/{profiles.js → github/profiles.js} +1 -1
  53. package/dist/engine/github/profiles.js.map +1 -0
  54. package/dist/engine/router.js +49 -3
  55. package/dist/engine/router.js.map +1 -1
  56. package/dist/engine/{classifier.d.ts → screen/classifier.d.ts} +11 -1
  57. package/dist/engine/{classifier.js → screen/classifier.js} +45 -1
  58. package/dist/engine/screen/classifier.js.map +1 -0
  59. package/dist/engine/{screen.d.ts → screen/screen.d.ts} +1 -1
  60. package/dist/engine/{screen.js → screen/screen.js} +1 -1
  61. package/dist/engine/screen/screen.js.map +1 -0
  62. package/dist/evals-api.d.ts +3 -3
  63. package/dist/evals-api.js +1 -1
  64. package/dist/evals-api.js.map +1 -1
  65. package/dist/index.js +17 -17
  66. package/dist/index.js.map +1 -1
  67. package/dist/managed-repos.js +1 -1
  68. package/dist/managed-repos.js.map +1 -1
  69. package/dist/notify/transports/github.d.ts +1 -1
  70. package/dist/sandbox/sandbox.d.ts +189 -0
  71. package/dist/sandbox/sandbox.js +429 -0
  72. package/dist/sandbox/sandbox.js.map +1 -0
  73. package/dist/state/workflow-run-store.d.ts +7 -0
  74. package/dist/state/workflow-run-store.js +14 -0
  75. package/dist/state/workflow-run-store.js.map +1 -1
  76. package/dist/telemetry/index.d.ts +1 -1
  77. package/dist/workflows/loader.d.ts +1 -1
  78. package/dist/workflows/phase-executor.d.ts +1 -1
  79. package/dist/workflows/resume.d.ts +3 -3
  80. package/dist/workflows/runner.d.ts +2 -2
  81. package/dist/workflows/runner.js +1 -1
  82. package/dist/workflows/runner.js.map +1 -1
  83. package/dist/workflows/schema.d.ts +2 -2
  84. package/dist/workflows/simple.d.ts +26 -5
  85. package/dist/workflows/simple.js +30 -4
  86. package/dist/workflows/simple.js.map +1 -1
  87. package/dist/workflows/triggers.js +1 -1
  88. package/dist/workflows/triggers.js.map +1 -1
  89. package/docker-compose.yml +1 -1
  90. package/package.json +4 -3
  91. package/plugins/lastlight/.claude-plugin/plugin.json +1 -1
  92. package/plugins/lastlight/skills/lastlight-overlay/SKILL.md +7 -1
  93. package/plugins/lastlight/skills/lastlight-overlay/references/forking.md +23 -4
  94. package/skills/README.md +1 -1
  95. package/skills/issue-triage/SKILL.md +34 -7
  96. package/skills/issue-triage/references/AGENT-BRIEF.md +28 -24
  97. package/dist/admin/auth.test.d.ts +0 -1
  98. package/dist/admin/auth.test.js +0 -60
  99. package/dist/admin/auth.test.js.map +0 -1
  100. package/dist/admin/log-search.test.d.ts +0 -1
  101. package/dist/admin/log-search.test.js +0 -78
  102. package/dist/admin/log-search.test.js.map +0 -1
  103. package/dist/admin/routes.test.d.ts +0 -1
  104. package/dist/admin/routes.test.js +0 -877
  105. package/dist/admin/routes.test.js.map +0 -1
  106. package/dist/admin/server-logs.test.d.ts +0 -1
  107. package/dist/admin/server-logs.test.js +0 -58
  108. package/dist/admin/server-logs.test.js.map +0 -1
  109. package/dist/admin/sessions.test.d.ts +0 -1
  110. package/dist/admin/sessions.test.js +0 -78
  111. package/dist/admin/sessions.test.js.map +0 -1
  112. package/dist/admin/version.test.d.ts +0 -1
  113. package/dist/admin/version.test.js +0 -71
  114. package/dist/admin/version.test.js.map +0 -1
  115. package/dist/cli-config.js.map +0 -1
  116. package/dist/cli-config.test.d.ts +0 -1
  117. package/dist/cli-config.test.js +0 -92
  118. package/dist/cli-config.test.js.map +0 -1
  119. package/dist/cli-format.js.map +0 -1
  120. package/dist/cli-server.js.map +0 -1
  121. package/dist/cli-server.test.d.ts +0 -1
  122. package/dist/cli-server.test.js +0 -41
  123. package/dist/cli-server.test.js.map +0 -1
  124. package/dist/cli-timeline.js.map +0 -1
  125. package/dist/cli-timeline.test.d.ts +0 -1
  126. package/dist/cli-timeline.test.js +0 -104
  127. package/dist/cli-timeline.test.js.map +0 -1
  128. package/dist/cli.js.map +0 -1
  129. package/dist/config-overlay.test.d.ts +0 -1
  130. package/dist/config-overlay.test.js +0 -112
  131. package/dist/config-overlay.test.js.map +0 -1
  132. package/dist/config-resolve.js.map +0 -1
  133. package/dist/config-resolve.test.d.ts +0 -1
  134. package/dist/config-resolve.test.js +0 -68
  135. package/dist/config-resolve.test.js.map +0 -1
  136. package/dist/config.js.map +0 -1
  137. package/dist/config.test.d.ts +0 -1
  138. package/dist/config.test.js +0 -288
  139. package/dist/config.test.js.map +0 -1
  140. package/dist/connectors/github-webhook.test.d.ts +0 -1
  141. package/dist/connectors/github-webhook.test.js +0 -156
  142. package/dist/connectors/github-webhook.test.js.map +0 -1
  143. package/dist/connectors/messaging/session-manager.test.d.ts +0 -1
  144. package/dist/connectors/messaging/session-manager.test.js +0 -144
  145. package/dist/connectors/messaging/session-manager.test.js.map +0 -1
  146. package/dist/connectors/slack/connector.test.d.ts +0 -1
  147. package/dist/connectors/slack/connector.test.js +0 -135
  148. package/dist/connectors/slack/connector.test.js.map +0 -1
  149. package/dist/connectors/slack/mrkdwn.test.d.ts +0 -1
  150. package/dist/connectors/slack/mrkdwn.test.js +0 -114
  151. package/dist/connectors/slack/mrkdwn.test.js.map +0 -1
  152. package/dist/cron/fanout.test.d.ts +0 -1
  153. package/dist/cron/fanout.test.js +0 -73
  154. package/dist/cron/fanout.test.js.map +0 -1
  155. package/dist/engine/agent-executor.seam.test.d.ts +0 -1
  156. package/dist/engine/agent-executor.seam.test.js +0 -57
  157. package/dist/engine/agent-executor.seam.test.js.map +0 -1
  158. package/dist/engine/agent-executor.test.d.ts +0 -1
  159. package/dist/engine/agent-executor.test.js +0 -395
  160. package/dist/engine/agent-executor.test.js.map +0 -1
  161. package/dist/engine/chat-runner.js.map +0 -1
  162. package/dist/engine/chat-runner.test.d.ts +0 -1
  163. package/dist/engine/chat-runner.test.js +0 -104
  164. package/dist/engine/chat-runner.test.js.map +0 -1
  165. package/dist/engine/chat-skills.js.map +0 -1
  166. package/dist/engine/chat-skills.test.d.ts +0 -1
  167. package/dist/engine/chat-skills.test.js +0 -20
  168. package/dist/engine/chat-skills.test.js.map +0 -1
  169. package/dist/engine/chat.js.map +0 -1
  170. package/dist/engine/chat.test.d.ts +0 -1
  171. package/dist/engine/chat.test.js +0 -42
  172. package/dist/engine/chat.test.js.map +0 -1
  173. package/dist/engine/classifier.js.map +0 -1
  174. package/dist/engine/classifier.test.d.ts +0 -1
  175. package/dist/engine/classifier.test.js +0 -115
  176. package/dist/engine/classifier.test.js.map +0 -1
  177. package/dist/engine/dispatcher.test.d.ts +0 -1
  178. package/dist/engine/dispatcher.test.js +0 -511
  179. package/dist/engine/dispatcher.test.js.map +0 -1
  180. package/dist/engine/event-shim.test.d.ts +0 -1
  181. package/dist/engine/event-shim.test.js +0 -194
  182. package/dist/engine/event-shim.test.js.map +0 -1
  183. package/dist/engine/executors/backends.d.ts +0 -41
  184. package/dist/engine/executors/backends.js +0 -541
  185. package/dist/engine/executors/backends.js.map +0 -1
  186. package/dist/engine/git-auth.js.map +0 -1
  187. package/dist/engine/git-auth.test.d.ts +0 -1
  188. package/dist/engine/git-auth.test.js +0 -117
  189. package/dist/engine/git-auth.test.js.map +0 -1
  190. package/dist/engine/github-app-client.js.map +0 -1
  191. package/dist/engine/github-app-client.test.d.ts +0 -1
  192. package/dist/engine/github-app-client.test.js +0 -44
  193. package/dist/engine/github-app-client.test.js.map +0 -1
  194. package/dist/engine/github-tools.js.map +0 -1
  195. package/dist/engine/github.js.map +0 -1
  196. package/dist/engine/llm.test.d.ts +0 -1
  197. package/dist/engine/llm.test.js +0 -189
  198. package/dist/engine/llm.test.js.map +0 -1
  199. package/dist/engine/message-batcher.js.map +0 -1
  200. package/dist/engine/message-batcher.test.d.ts +0 -1
  201. package/dist/engine/message-batcher.test.js +0 -109
  202. package/dist/engine/message-batcher.test.js.map +0 -1
  203. package/dist/engine/profiles.js.map +0 -1
  204. package/dist/engine/router.test.d.ts +0 -1
  205. package/dist/engine/router.test.js +0 -695
  206. package/dist/engine/router.test.js.map +0 -1
  207. package/dist/engine/screen.js.map +0 -1
  208. package/dist/engine/screen.test.d.ts +0 -1
  209. package/dist/engine/screen.test.js +0 -82
  210. package/dist/engine/screen.test.js.map +0 -1
  211. package/dist/fork-cli.js.map +0 -1
  212. package/dist/fork-cli.test.d.ts +0 -1
  213. package/dist/fork-cli.test.js +0 -109
  214. package/dist/fork-cli.test.js.map +0 -1
  215. package/dist/managed-repos.test.d.ts +0 -1
  216. package/dist/managed-repos.test.js +0 -39
  217. package/dist/managed-repos.test.js.map +0 -1
  218. package/dist/notify/model.test.d.ts +0 -1
  219. package/dist/notify/model.test.js +0 -109
  220. package/dist/notify/model.test.js.map +0 -1
  221. package/dist/notify/notifier.test.d.ts +0 -1
  222. package/dist/notify/notifier.test.js +0 -100
  223. package/dist/notify/notifier.test.js.map +0 -1
  224. package/dist/notify/render.test.d.ts +0 -1
  225. package/dist/notify/render.test.js +0 -65
  226. package/dist/notify/render.test.js.map +0 -1
  227. package/dist/notify/transports.test.d.ts +0 -1
  228. package/dist/notify/transports.test.js +0 -71
  229. package/dist/notify/transports.test.js.map +0 -1
  230. package/dist/overlay-assets.js.map +0 -1
  231. package/dist/overlay-assets.test.d.ts +0 -1
  232. package/dist/overlay-assets.test.js +0 -75
  233. package/dist/overlay-assets.test.js.map +0 -1
  234. package/dist/overlay-bootstrap.js.map +0 -1
  235. package/dist/overlay-bootstrap.test.d.ts +0 -1
  236. package/dist/overlay-bootstrap.test.js +0 -61
  237. package/dist/overlay-bootstrap.test.js.map +0 -1
  238. package/dist/sandbox/command-exec.integration.test.d.ts +0 -1
  239. package/dist/sandbox/command-exec.integration.test.js +0 -183
  240. package/dist/sandbox/command-exec.integration.test.js.map +0 -1
  241. package/dist/sandbox/docker-compose.test.d.ts +0 -1
  242. package/dist/sandbox/docker-compose.test.js +0 -128
  243. package/dist/sandbox/docker-compose.test.js.map +0 -1
  244. package/dist/sandbox/docker.test.d.ts +0 -1
  245. package/dist/sandbox/docker.test.js +0 -137
  246. package/dist/sandbox/docker.test.js.map +0 -1
  247. package/dist/sandbox/egress-allowlist.test.d.ts +0 -1
  248. package/dist/sandbox/egress-allowlist.test.js +0 -65
  249. package/dist/sandbox/egress-allowlist.test.js.map +0 -1
  250. package/dist/sandbox/egress-firewall-config.test.d.ts +0 -1
  251. package/dist/sandbox/egress-firewall-config.test.js +0 -244
  252. package/dist/sandbox/egress-firewall-config.test.js.map +0 -1
  253. package/dist/sandbox/index.test.d.ts +0 -1
  254. package/dist/sandbox/index.test.js +0 -157
  255. package/dist/sandbox/index.test.js.map +0 -1
  256. package/dist/sandbox/smol.integration.test.d.ts +0 -1
  257. package/dist/sandbox/smol.integration.test.js +0 -130
  258. package/dist/sandbox/smol.integration.test.js.map +0 -1
  259. package/dist/session-log.test.d.ts +0 -1
  260. package/dist/session-log.test.js +0 -85
  261. package/dist/session-log.test.js.map +0 -1
  262. package/dist/setup.js.map +0 -1
  263. package/dist/setup.test.d.ts +0 -1
  264. package/dist/setup.test.js +0 -281
  265. package/dist/setup.test.js.map +0 -1
  266. package/dist/skills-install.js.map +0 -1
  267. package/dist/state/build-assets.test.d.ts +0 -1
  268. package/dist/state/build-assets.test.js +0 -106
  269. package/dist/state/build-assets.test.js.map +0 -1
  270. package/dist/state/db.test.d.ts +0 -1
  271. package/dist/state/db.test.js +0 -484
  272. package/dist/state/db.test.js.map +0 -1
  273. package/dist/state/workflow-run-store.test.d.ts +0 -1
  274. package/dist/state/workflow-run-store.test.js +0 -264
  275. package/dist/state/workflow-run-store.test.js.map +0 -1
  276. package/dist/telemetry/index.test.d.ts +0 -1
  277. package/dist/telemetry/index.test.js +0 -73
  278. package/dist/telemetry/index.test.js.map +0 -1
  279. package/dist/telemetry/pi-events.test.d.ts +0 -1
  280. package/dist/telemetry/pi-events.test.js +0 -69
  281. package/dist/telemetry/pi-events.test.js.map +0 -1
  282. package/dist/workflows/dag.test.d.ts +0 -1
  283. package/dist/workflows/dag.test.js +0 -197
  284. package/dist/workflows/dag.test.js.map +0 -1
  285. package/dist/workflows/golden-build.test.d.ts +0 -1
  286. package/dist/workflows/golden-build.test.js +0 -45
  287. package/dist/workflows/golden-build.test.js.map +0 -1
  288. package/dist/workflows/loader-overlay.test.d.ts +0 -1
  289. package/dist/workflows/loader-overlay.test.js +0 -101
  290. package/dist/workflows/loader-overlay.test.js.map +0 -1
  291. package/dist/workflows/loader.test.d.ts +0 -1
  292. package/dist/workflows/loader.test.js +0 -375
  293. package/dist/workflows/loader.test.js.map +0 -1
  294. package/dist/workflows/loop-eval.test.d.ts +0 -1
  295. package/dist/workflows/loop-eval.test.js +0 -89
  296. package/dist/workflows/loop-eval.test.js.map +0 -1
  297. package/dist/workflows/phase-executor.test.d.ts +0 -1
  298. package/dist/workflows/phase-executor.test.js +0 -497
  299. package/dist/workflows/phase-executor.test.js.map +0 -1
  300. package/dist/workflows/phase-ref.test.d.ts +0 -1
  301. package/dist/workflows/phase-ref.test.js +0 -24
  302. package/dist/workflows/phase-ref.test.js.map +0 -1
  303. package/dist/workflows/runner.test.d.ts +0 -1
  304. package/dist/workflows/runner.test.js +0 -1174
  305. package/dist/workflows/runner.test.js.map +0 -1
  306. package/dist/workflows/simple.test.d.ts +0 -1
  307. package/dist/workflows/simple.test.js +0 -107
  308. package/dist/workflows/simple.test.js.map +0 -1
  309. package/dist/workflows/templates.test.d.ts +0 -1
  310. package/dist/workflows/templates.test.js +0 -258
  311. package/dist/workflows/templates.test.js.map +0 -1
  312. package/dist/workflows/verdict.test.d.ts +0 -1
  313. package/dist/workflows/verdict.test.js +0 -44
  314. package/dist/workflows/verdict.test.js.map +0 -1
  315. package/dist/worktree/manager.test.d.ts +0 -1
  316. package/dist/worktree/manager.test.js +0 -87
  317. package/dist/worktree/manager.test.js.map +0 -1
  318. /package/dist/{cli-config.d.ts → cli/cli-config.d.ts} +0 -0
  319. /package/dist/{cli-config.js → cli/cli-config.js} +0 -0
  320. /package/dist/{cli-format.d.ts → cli/cli-format.d.ts} +0 -0
  321. /package/dist/{cli-format.js → cli/cli-format.js} +0 -0
  322. /package/dist/{cli-timeline.d.ts → cli/cli-timeline.d.ts} +0 -0
  323. /package/dist/{cli-timeline.js → cli/cli-timeline.js} +0 -0
  324. /package/dist/{cli.d.ts → cli/cli.d.ts} +0 -0
  325. /package/dist/{setup.d.ts → cli/setup.d.ts} +0 -0
  326. /package/dist/{skills-install.d.ts → cli/skills-install.d.ts} +0 -0
  327. /package/dist/{config-resolve.d.ts → config/config-resolve.d.ts} +0 -0
  328. /package/dist/{config-resolve.js → config/config-resolve.js} +0 -0
  329. /package/dist/{config.d.ts → config/config.d.ts} +0 -0
  330. /package/dist/{overlay-assets.d.ts → config/overlay-assets.d.ts} +0 -0
  331. /package/dist/{overlay-assets.js → config/overlay-assets.js} +0 -0
  332. /package/dist/{overlay-bootstrap.d.ts → config/overlay-bootstrap.d.ts} +0 -0
  333. /package/dist/{overlay-bootstrap.js → config/overlay-bootstrap.js} +0 -0
  334. /package/dist/engine/{chat-skills.d.ts → chat/chat-skills.d.ts} +0 -0
  335. /package/dist/engine/{message-batcher.js → chat/message-batcher.js} +0 -0
  336. /package/dist/engine/{git-auth.d.ts → github/git-auth.d.ts} +0 -0
  337. /package/dist/engine/{git-auth.js → github/git-auth.js} +0 -0
  338. /package/dist/engine/{github-app-client.d.ts → github/github-app-client.d.ts} +0 -0
  339. /package/dist/engine/{github-app-client.js → github/github-app-client.js} +0 -0
  340. /package/dist/engine/{github-tools.d.ts → github/github-tools.d.ts} +0 -0
  341. /package/dist/engine/{github-tools.js → github/github-tools.js} +0 -0
  342. /package/dist/engine/{github.d.ts → github/github.d.ts} +0 -0
  343. /package/dist/engine/{github.js → github/github.js} +0 -0
@@ -0,0 +1,189 @@
1
+ import type { RunResult, ThinkingLevel } from "agentic-pi";
2
+ import type { OtelConfig, SandboxBackend } from "../config/config.js";
3
+ /**
4
+ * The **Sandbox port** — the single named interface every isolation backend
5
+ * (`docker`, `smol`, `gondolin`, `none`) implements. Before this seam existed,
6
+ * the orchestration around the four backends was copy-pasted twin-for-twin
7
+ * (`executeDocker` / `executeSmol` / `executeInProcess`). Now the orchestrator
8
+ * (`src/engine/executors/orchestrator.ts`) is written once and drives any
9
+ * adapter through these methods.
10
+ *
11
+ * See `CONTEXT.md` → "Sandbox execution" for the pinned vocabulary; in short:
12
+ * - **Sandbox** (this interface) is the *port*.
13
+ * - **adapters** are the concrete backends below (`DockerSandbox`,
14
+ * `SmolSandbox`, `InProcessSandbox`, `FakeSandbox`). Each owns its
15
+ * isolation mechanism + egress enforcement; none of that surfaces here.
16
+ * - the **orchestrator** is the deep module that brackets a run.
17
+ *
18
+ * A Sandbox instance is created per task (the factory carries `taskId`), so the
19
+ * `taskId` argument on `runAgent` / `runCommand` is threaded purely for the
20
+ * underlying driver APIs.
21
+ */
22
+ export interface Sandbox {
23
+ /** Which backend this adapter is — used only for telemetry tagging. */
24
+ readonly backend: SandboxBackend;
25
+ /**
26
+ * Provision the workspace and any isolation primitive (container / VM /
27
+ * worktree). **Owns provisioning** — each adapter orders its own
28
+ * clone-vs-boot internally (docker pre-clones then mounts; smol boots then
29
+ * probes the share then clones; in-process just sets up the worktree) and
30
+ * returns the two paths the orchestrator needs.
31
+ */
32
+ provision(prePopulate?: PrePopulateSpec): Promise<ProvisionResult>;
33
+ /**
34
+ * Stage this phase's skill bundle into the workspace and return the skill
35
+ * dirs to hand the agent (already mapped to sandbox-visible paths). The
36
+ * mode (symlink vs copy), root (workspace vs cwd), and any post-stage git
37
+ * exclusion are adapter-local. Returns undefined when the phase has none.
38
+ */
39
+ stageSkills(phaseKey: string, skillPaths: string[] | undefined): string[] | undefined;
40
+ /**
41
+ * Map a workspace-relative path (written to `hostWorkspaceDir`) to the
42
+ * absolute path the sandboxed process sees. Used for staged `type: script`
43
+ * source files. docker/smol prefix the in-sandbox workspace root; in-process
44
+ * returns the host path verbatim.
45
+ */
46
+ sandboxPathFor(relPath: string): string;
47
+ /**
48
+ * Run one agent turn. Emits **parsed** event records to `onEvent` — the
49
+ * `startsWith("{")` guard + `JSON.parse` of the subprocess line stream live
50
+ * inside the docker/smol adapters; the in-process adapter forwards
51
+ * agentic-pi's already-parsed events straight through. Returns the run's
52
+ * authoritative `RunResult` when the adapter has one (in-process), else
53
+ * `undefined` (docker/smol) — the orchestrator reconstructs it from the
54
+ * accumulated events in that case.
55
+ */
56
+ runAgent(taskId: string, prompt: string, opts: RunAgentOpts, onEvent: (record: SandboxEvent) => void): Promise<RunResult | undefined>;
57
+ /** Run a deterministic shell command (no LLM). Resolves with its raw result. */
58
+ runCommand(taskId: string, command: string, opts: RunCommandOpts): Promise<RawCommandResult>;
59
+ /** Tear down the isolation primitive (container/VM destroy; no-op in-process). */
60
+ dispose(): Promise<void> | void;
61
+ }
62
+ /**
63
+ * The **intent-only** egress value object. The orchestrator decides *what is
64
+ * allowed* once (hosts already merged with any OTEL collector hosts); each
65
+ * adapter translates it to its *mechanism* — docker `--dns` strict/open, smol
66
+ * `--allow-host`, in-process `allowedHttpHosts` / `["*"]`. The `172.30.0.x`
67
+ * constants and the `"*"` sentinel live inside the adapters, never here.
68
+ */
69
+ export interface EgressPolicy {
70
+ /** True iff a phase opted out of the allowlist (`unrestricted_egress`). */
71
+ unrestricted: boolean;
72
+ /** Allowed apex hostnames when not unrestricted (incl. collector hosts). */
73
+ hosts: string[];
74
+ }
75
+ /** The repo pre-clone descriptor handed to {@link Sandbox.provision}. */
76
+ export interface PrePopulateSpec {
77
+ owner: string;
78
+ repo: string;
79
+ branch: string;
80
+ token: string;
81
+ runId?: string;
82
+ shallow?: boolean;
83
+ }
84
+ /** What {@link Sandbox.provision} hands back to the orchestrator. */
85
+ export interface ProvisionResult {
86
+ /** Host dir backing the workspace (where the orchestrator stages files). */
87
+ hostWorkspaceDir: string;
88
+ /** Working directory the agent/command process runs in (sandbox-visible). */
89
+ agentCwd: string;
90
+ }
91
+ export type SandboxEvent = Record<string, unknown>;
92
+ export interface RunAgentOpts {
93
+ model: string;
94
+ thinking?: ThinkingLevel;
95
+ /** agentic-pi github profile (`read` | `issues-write` | … ). */
96
+ profile?: string;
97
+ /** Base inner-run env (git identity); adapters merge their own OTEL/HOME. */
98
+ sandboxEnv: Record<string, string>;
99
+ agentCwd: string;
100
+ skillDirs?: string[];
101
+ webSearch?: boolean;
102
+ webSearchProvider?: "tavily" | "brave" | "exa";
103
+ /** Test/eval escape hatch — only honoured by the in-process adapter. */
104
+ githubApiBaseUrl?: string;
105
+ }
106
+ export interface RunCommandOpts {
107
+ cwd: string;
108
+ /** Extra env forwarded into the command (upstream phase outputs, etc.). */
109
+ sandboxEnv?: Record<string, string>;
110
+ timeoutSeconds: number;
111
+ }
112
+ export interface RawCommandResult {
113
+ exitCode: number;
114
+ stdout: string;
115
+ stderr: string;
116
+ timedOut: boolean;
117
+ }
118
+ /** Construction-time opts for {@link sandboxFor} / each adapter. */
119
+ export interface SandboxFactoryOpts {
120
+ taskId: string;
121
+ egress: EgressPolicy;
122
+ /** Env forwarded into the sandbox (provider keys, minted GITHUB_TOKEN, …). */
123
+ env: Record<string, string>;
124
+ stateDir: string;
125
+ sandboxDir?: string;
126
+ /** Docker image override (the browser-QA image for `sandbox_image: qa`). */
127
+ imageName?: string;
128
+ otel?: OtelConfig;
129
+ timeoutSeconds?: number;
130
+ }
131
+ export type SandboxFactory = (backend: SandboxBackend, opts: SandboxFactoryOpts) => Sandbox;
132
+ /** The base (git-identity) sandbox env the orchestrator passes to `runAgent`. */
133
+ export declare const AGENT_GIT_IDENTITY_ENV: Record<string, string>;
134
+ /**
135
+ * The single factory replacing the `if (backend === …)` ladder. Given a
136
+ * backend and construction opts, returns the matching adapter. Docker's
137
+ * old null-fallback is now a thrown error from `provision` (the orchestrator's
138
+ * bracket surfaces it), so this never returns null.
139
+ */
140
+ export declare function sandboxFor(backend: SandboxBackend, opts: SandboxFactoryOpts): Sandbox;
141
+ export interface FakeBehavior {
142
+ /** Canned parsed pi-event records replayed through `onEvent`. */
143
+ events?: SandboxEvent[];
144
+ /** Throw from `runAgent` to exercise the fallback path. */
145
+ throwOnRunAgent?: Error | string;
146
+ /** Authoritative RunResult `runAgent` returns (else undefined → acc.build). */
147
+ returnRunResult?: RunResult;
148
+ /** Result `runCommand` resolves with (default exit 0, empty output). */
149
+ commandResult?: RawCommandResult;
150
+ /** Throw from `runCommand`. */
151
+ throwOnRunCommand?: Error | string;
152
+ }
153
+ /**
154
+ * In-memory `Sandbox` adapter for unit-testing the orchestrator without
155
+ * Docker/VMs. `provision()` returns a **real** `mkdtemp` workspace (so skill
156
+ * staging + artifact harvest run for real), `runAgent` replays a canned array
157
+ * of pi event records through `onEvent`, and it **records** the opts it
158
+ * received for assertions. Covers Last Light's orchestration, not agentic-pi's
159
+ * semantics.
160
+ *
161
+ * Inject it via the optional `sandboxFactory` on `executeAgent`/`executeCommand`
162
+ * — see {@link FakeSandbox.asFactory}.
163
+ */
164
+ export declare class FakeSandbox implements Sandbox {
165
+ private readonly behavior;
166
+ backend: SandboxBackend;
167
+ egress?: EgressPolicy;
168
+ env?: Record<string, string>;
169
+ hostWorkspaceDir: string;
170
+ agentCwd: string;
171
+ stagedSkillDirs?: string[];
172
+ receivedAgentOpts?: RunAgentOpts;
173
+ receivedCommandOpts?: RunCommandOpts;
174
+ receivedCommand?: string;
175
+ provisionCalls: number;
176
+ disposed: boolean;
177
+ constructor(behavior?: FakeBehavior);
178
+ /**
179
+ * Build a {@link SandboxFactory} that always returns THIS instance, capturing
180
+ * the construction opts (egress, env, backend) for later inspection.
181
+ */
182
+ asFactory(): SandboxFactory;
183
+ provision(pre?: PrePopulateSpec): Promise<ProvisionResult>;
184
+ stageSkills(phaseKey: string, skillPaths: string[] | undefined): string[] | undefined;
185
+ sandboxPathFor(relPath: string): string;
186
+ runAgent(_taskId: string, _prompt: string, opts: RunAgentOpts, onEvent: (record: SandboxEvent) => void): Promise<RunResult | undefined>;
187
+ runCommand(_taskId: string, command: string, opts: RunCommandOpts): Promise<RawCommandResult>;
188
+ dispose(): void;
189
+ }
@@ -0,0 +1,429 @@
1
+ import { join, relative } from "path";
2
+ import { mkdtempSync, mkdirSync, rmSync } from "fs";
3
+ import { tmpdir } from "os";
4
+ import { spawnSync } from "child_process";
5
+ import { createTaskSandbox, setupTaskWorktree, prePopulateWorkspace } from "./index.js";
6
+ import { SmolSandbox as SmolDriver, smolAvailable, SMOL_WORKSPACE_DIR } from "./smol.js";
7
+ import { ALLOW_ALL_SENTINEL } from "./egress-allowlist.js";
8
+ import { getDockerSandboxOtelEnv, getOtelEnvForSandbox } from "../telemetry/index.js";
9
+ import { DOCKER_WORKSPACE_DIR, SKILL_BUNDLE_ROOT, stageSkillBundle, excludeFromGit, applyEnv, } from "../engine/executors/shared.js";
10
+ /** Inner-run git identity, shared by every adapter's agent path. */
11
+ const GIT_IDENTITY_ENV = {
12
+ GIT_AUTHOR_NAME: "last-light[bot]",
13
+ GIT_AUTHOR_EMAIL: "last-light[bot]@users.noreply.github.com",
14
+ GIT_COMMITTER_NAME: "last-light[bot]",
15
+ GIT_COMMITTER_EMAIL: "last-light[bot]@users.noreply.github.com",
16
+ // /workspace is a host-UID bind mount into a different-UID guest; git refuses
17
+ // to operate without an explicit safe-directory. GIT_CONFIG_* avoids needing
18
+ // a writeable ~/.gitconfig.
19
+ GIT_CONFIG_COUNT: "1",
20
+ GIT_CONFIG_KEY_0: "safe.directory",
21
+ GIT_CONFIG_VALUE_0: "*",
22
+ };
23
+ /** The base (git-identity) sandbox env the orchestrator passes to `runAgent`. */
24
+ export const AGENT_GIT_IDENTITY_ENV = GIT_IDENTITY_ENV;
25
+ /**
26
+ * The single factory replacing the `if (backend === …)` ladder. Given a
27
+ * backend and construction opts, returns the matching adapter. Docker's
28
+ * old null-fallback is now a thrown error from `provision` (the orchestrator's
29
+ * bracket surfaces it), so this never returns null.
30
+ */
31
+ export function sandboxFor(backend, opts) {
32
+ switch (backend) {
33
+ case "docker":
34
+ return new DockerSandbox(opts);
35
+ case "smol":
36
+ return new SmolSandbox(opts);
37
+ case "gondolin":
38
+ return new InProcessSandbox("gondolin", opts);
39
+ case "none":
40
+ return new InProcessSandbox("none", opts);
41
+ }
42
+ }
43
+ // ── Docker adapter ──────────────────────────────────────────────────
44
+ /**
45
+ * Wraps the docker container driver ({@link DockerDriver}) + the
46
+ * `createTaskSandbox` provisioning helper. Egress is the strict/open coredns
47
+ * pair selected by `--dns`; the host constants live here.
48
+ */
49
+ class DockerSandbox {
50
+ opts;
51
+ backend = "docker";
52
+ sbx;
53
+ agentCwd = DOCKER_WORKSPACE_DIR;
54
+ constructor(opts) {
55
+ this.opts = opts;
56
+ }
57
+ async provision(pre) {
58
+ // Strict allowlist by default; an `unrestricted_egress` phase points at the
59
+ // open coredns sidecar instead. IPs match docker-compose.yml's static
60
+ // assignments (see src/sandbox/egress-firewall-config.ts).
61
+ const dnsIp = this.opts.egress.unrestricted
62
+ ? process.env.LASTLIGHT_DNS_OPEN || "172.30.0.11"
63
+ : process.env.LASTLIGHT_DNS_STRICT || "172.30.0.10";
64
+ const sbx = await createTaskSandbox({
65
+ taskId: this.opts.taskId,
66
+ stateDir: this.opts.stateDir,
67
+ sandboxDir: this.opts.sandboxDir,
68
+ env: this.opts.env,
69
+ prePopulate: pre,
70
+ dnsIp,
71
+ imageName: this.opts.imageName,
72
+ });
73
+ if (!sbx) {
74
+ throw new Error("LASTLIGHT_SANDBOX=docker but no docker sandbox was available. " +
75
+ "Install Docker and build the sandbox image, or set LASTLIGHT_SANDBOX=gondolin / none.");
76
+ }
77
+ this.sbx = sbx;
78
+ this.agentCwd = pre ? `${DOCKER_WORKSPACE_DIR}/${pre.repo}` : DOCKER_WORKSPACE_DIR;
79
+ return { hostWorkspaceDir: sbx.workDir, agentCwd: this.agentCwd };
80
+ }
81
+ stageSkills(phaseKey, skillPaths) {
82
+ if (!this.sbx)
83
+ throw new Error("DockerSandbox.stageSkills before provision");
84
+ // Copy (not symlink): the agent's tools run inside the container and host
85
+ // symlink targets wouldn't resolve there. Map host dests → in-container paths.
86
+ const staged = stageSkillBundle(this.sbx.workDir, phaseKey, skillPaths, "copy");
87
+ if (!staged)
88
+ return undefined;
89
+ return staged.map((d) => `${DOCKER_WORKSPACE_DIR}/${relative(this.sbx.workDir, d)}`);
90
+ }
91
+ sandboxPathFor(relPath) {
92
+ return `${DOCKER_WORKSPACE_DIR}/${relPath}`;
93
+ }
94
+ async runAgent(taskId, prompt, opts, onEvent) {
95
+ if (!this.sbx)
96
+ throw new Error("DockerSandbox.runAgent before provision");
97
+ await this.sbx.sandbox.runAgent(taskId, prompt, {
98
+ model: opts.model,
99
+ thinking: opts.thinking,
100
+ profile: opts.profile,
101
+ sandboxEnv: this.innerAgentEnv(opts.sandboxEnv),
102
+ agentCwd: opts.agentCwd,
103
+ skillDirs: opts.skillDirs,
104
+ webSearch: opts.webSearch,
105
+ webSearchProvider: opts.webSearchProvider,
106
+ onLine: parseLine(onEvent),
107
+ });
108
+ return undefined;
109
+ }
110
+ async runCommand(taskId, command, opts) {
111
+ if (!this.sbx)
112
+ throw new Error("DockerSandbox.runCommand before provision");
113
+ return this.sbx.sandbox.runCommand(taskId, command, {
114
+ cwd: opts.cwd,
115
+ sandboxEnv: opts.sandboxEnv,
116
+ timeoutSeconds: opts.timeoutSeconds,
117
+ onLine: () => { },
118
+ });
119
+ }
120
+ async dispose() {
121
+ if (this.sbx)
122
+ await this.sbx.cleanup();
123
+ }
124
+ /** Git identity + (inside-container) OTEL collector env. */
125
+ innerAgentEnv(base) {
126
+ const otel = this.opts.otel?.enabled && this.opts.otel.forwardToSandbox ? getDockerSandboxOtelEnv() : {};
127
+ return { ...otel, ...base };
128
+ }
129
+ }
130
+ // ── smol adapter ────────────────────────────────────────────────────
131
+ /**
132
+ * Wraps the smolvm micro-VM driver ({@link SmolDriver}). Egress is native
133
+ * per-machine `--allow-host`; unrestricted → null (open). Provisioning boots
134
+ * the VM first, then probes the share-backed host dir before cloning into it.
135
+ */
136
+ class SmolSandbox {
137
+ opts;
138
+ backend = "smol";
139
+ driver;
140
+ agentCwd = SMOL_WORKSPACE_DIR;
141
+ hostWorkspaceDir = "";
142
+ constructor(opts) {
143
+ this.opts = opts;
144
+ }
145
+ async provision(pre) {
146
+ if (!smolAvailable()) {
147
+ throw new Error("LASTLIGHT_SANDBOX=smol but the smolvm CLI is not available. " +
148
+ "Install smolvm (https://smolmachines.com) and start `smolvm serve`, " +
149
+ "or set LASTLIGHT_SANDBOX=docker / gondolin / none.");
150
+ }
151
+ // Boot FIRST (workspace dir mounted), then provision the probed share. No
152
+ // pre-clone here — see SmolSandbox.resolveHostWorkspace for why the mount
153
+ // source isn't always the share root.
154
+ const workDir = setupTaskWorktree({
155
+ taskId: this.opts.taskId,
156
+ stateDir: this.opts.stateDir,
157
+ sandboxDir: this.opts.sandboxDir,
158
+ });
159
+ this.driver = new SmolDriver({
160
+ env: this.opts.env,
161
+ allowHosts: this.opts.egress.unrestricted ? null : this.opts.egress.hosts,
162
+ });
163
+ const machine = await this.driver.create({ taskId: this.opts.taskId, worktreePath: workDir });
164
+ const hostWs = machine.hostWorkspace;
165
+ if (pre)
166
+ prePopulateWorkspace(hostWs, pre);
167
+ this.hostWorkspaceDir = hostWs;
168
+ this.agentCwd = pre ? `${SMOL_WORKSPACE_DIR}/${pre.repo}` : SMOL_WORKSPACE_DIR;
169
+ return { hostWorkspaceDir: hostWs, agentCwd: this.agentCwd };
170
+ }
171
+ stageSkills(phaseKey, skillPaths) {
172
+ const staged = stageSkillBundle(this.hostWorkspaceDir, phaseKey, skillPaths, "copy");
173
+ if (!staged)
174
+ return undefined;
175
+ return staged.map((d) => `${SMOL_WORKSPACE_DIR}/${relative(this.hostWorkspaceDir, d)}`);
176
+ }
177
+ sandboxPathFor(relPath) {
178
+ return `${SMOL_WORKSPACE_DIR}/${relPath}`;
179
+ }
180
+ async runAgent(taskId, prompt, opts, onEvent) {
181
+ if (!this.driver)
182
+ throw new Error("SmolSandbox.runAgent before provision");
183
+ await this.driver.runAgent(taskId, prompt, {
184
+ model: opts.model,
185
+ thinking: opts.thinking,
186
+ profile: opts.profile,
187
+ sandboxEnv: opts.sandboxEnv,
188
+ agentCwd: opts.agentCwd,
189
+ skillDirs: opts.skillDirs,
190
+ webSearch: opts.webSearch,
191
+ webSearchProvider: opts.webSearchProvider,
192
+ onLine: parseLine(onEvent),
193
+ });
194
+ return undefined;
195
+ }
196
+ async runCommand(taskId, command, opts) {
197
+ if (!this.driver)
198
+ throw new Error("SmolSandbox.runCommand before provision");
199
+ return this.driver.runCommand(taskId, command, {
200
+ cwd: opts.cwd,
201
+ sandboxEnv: opts.sandboxEnv,
202
+ timeoutSeconds: opts.timeoutSeconds,
203
+ onLine: () => { },
204
+ });
205
+ }
206
+ async dispose() {
207
+ if (this.driver)
208
+ await this.driver.destroy(this.opts.taskId);
209
+ }
210
+ }
211
+ // ── In-process adapter (gondolin / none) ────────────────────────────
212
+ /**
213
+ * **One** adapter for the two in-process backends, parameterized by
214
+ * `mode: 'gondolin' | 'none'`. The two differ only in agentic-pi's `sandbox`
215
+ * arg and a `HOME` override. Owns the `applyEnv`/restore `process.env` splice
216
+ * and the lazy `import("agentic-pi")`.
217
+ *
218
+ * The `mode` flag is a **tombstone** for gondolin's planned removal — when
219
+ * gondolin is retired it collapses to single-mode `none`.
220
+ */
221
+ class InProcessSandbox {
222
+ mode;
223
+ opts;
224
+ backend;
225
+ hostWorkspaceDir = "";
226
+ agentCwd = "";
227
+ constructor(mode, opts) {
228
+ this.mode = mode;
229
+ this.opts = opts;
230
+ this.backend = mode;
231
+ }
232
+ async provision(pre) {
233
+ const workDir = setupTaskWorktree({
234
+ taskId: this.opts.taskId,
235
+ stateDir: this.opts.stateDir,
236
+ sandboxDir: this.opts.sandboxDir,
237
+ prePopulate: pre,
238
+ });
239
+ this.hostWorkspaceDir = workDir;
240
+ // When pre-cloned, cwd is the checkout so the agent runs inside the repo
241
+ // with no `cd` preamble; otherwise the workspace root.
242
+ this.agentCwd = pre ? join(workDir, pre.repo) : workDir;
243
+ return { hostWorkspaceDir: workDir, agentCwd: this.agentCwd };
244
+ }
245
+ stageSkills(phaseKey, skillPaths) {
246
+ // none: stage at the workspace ROOT (host FS fully visible). gondolin
247
+ // mounts only cwd, so its bundle is staged under the repo + added to the
248
+ // checkout's local `.git/info/exclude` so the agent can't commit it.
249
+ const gondolin = this.mode === "gondolin";
250
+ const skillRoot = gondolin ? this.agentCwd : this.hostWorkspaceDir;
251
+ const staged = stageSkillBundle(skillRoot, phaseKey, skillPaths, "symlink");
252
+ if (staged && gondolin)
253
+ excludeFromGit(this.agentCwd, SKILL_BUNDLE_ROOT);
254
+ return staged; // host paths — passed through to agentic-pi's skillPaths
255
+ }
256
+ sandboxPathFor(relPath) {
257
+ return join(this.hostWorkspaceDir, relPath);
258
+ }
259
+ async runAgent(_taskId, prompt, opts, onEvent) {
260
+ // agentic-pi reads its own env (provider keys, App PEM, …) from
261
+ // process.env. Splice in our scoped values for the call, then restore.
262
+ const restore = applyEnv(this.opts.env);
263
+ const allowedHttpHosts = this.opts.egress.unrestricted ? [ALLOW_ALL_SENTINEL] : this.opts.egress.hosts;
264
+ try {
265
+ // Loaded lazily: agentic-pi transitively poisons the global undici
266
+ // dispatcher on import, which would break the harness's own fetch. The
267
+ // dynamic import keeps the harness clean unless an in-process run happens.
268
+ const { run: agenticRun } = await import("agentic-pi");
269
+ return await agenticRun({
270
+ model: opts.model,
271
+ prompt,
272
+ thinking: opts.thinking,
273
+ profile: opts.profile,
274
+ githubApiBaseUrl: opts.githubApiBaseUrl,
275
+ sandbox: this.mode === "gondolin" ? "gondolin" : "none",
276
+ sandboxEnv: this.innerAgentEnv(opts.sandboxEnv),
277
+ cwd: opts.agentCwd,
278
+ noSession: true,
279
+ skillPaths: opts.skillDirs,
280
+ allowedHttpHosts,
281
+ webSearch: opts.webSearch === true,
282
+ webSearchProvider: opts.webSearchProvider,
283
+ onEvent,
284
+ onWarn: (msg) => console.warn(`[agentic] ${msg}`),
285
+ });
286
+ }
287
+ finally {
288
+ restore();
289
+ }
290
+ }
291
+ async runCommand(_taskId, command, opts) {
292
+ // gondolin / none run the command on the host worktree via spawnSync — the
293
+ // same degraded model those backends already used.
294
+ const proc = spawnSync("sh", ["-c", command], {
295
+ cwd: opts.cwd,
296
+ env: { ...process.env, ...this.opts.env, ...(opts.sandboxEnv ?? {}) },
297
+ encoding: "utf-8",
298
+ timeout: opts.timeoutSeconds * 1000,
299
+ maxBuffer: 256 * 1024 * 1024,
300
+ });
301
+ const exitCode = proc.status ?? (proc.signal ? 124 : 1);
302
+ return {
303
+ exitCode,
304
+ stdout: proc.stdout ?? "",
305
+ stderr: proc.stderr ?? "",
306
+ timedOut: proc.signal === "SIGTERM",
307
+ };
308
+ }
309
+ dispose() {
310
+ // No isolation primitive to tear down — the env splice is restored inside
311
+ // runAgent, and the worktree is reaped elsewhere.
312
+ }
313
+ /** Git identity + OTEL env + (gondolin only) a HOME override into the VM. */
314
+ innerAgentEnv(base) {
315
+ const otel = this.opts.otel?.enabled && this.opts.otel.forwardToSandbox ? getOtelEnvForSandbox() : {};
316
+ // gondolin: the VM user inherits HOME from the agentic-pi process (the
317
+ // host's HOME leaks in). Force HOME=/root so `git config --global` /
318
+ // `gh auth status` write to a real path inside the VM. none runs on the
319
+ // host — never override HOME.
320
+ const homeOverride = this.mode === "gondolin" ? { HOME: "/root", USER: "root", LOGNAME: "root" } : {};
321
+ return { ...otel, ...base, ...homeOverride };
322
+ }
323
+ }
324
+ /**
325
+ * In-memory `Sandbox` adapter for unit-testing the orchestrator without
326
+ * Docker/VMs. `provision()` returns a **real** `mkdtemp` workspace (so skill
327
+ * staging + artifact harvest run for real), `runAgent` replays a canned array
328
+ * of pi event records through `onEvent`, and it **records** the opts it
329
+ * received for assertions. Covers Last Light's orchestration, not agentic-pi's
330
+ * semantics.
331
+ *
332
+ * Inject it via the optional `sandboxFactory` on `executeAgent`/`executeCommand`
333
+ * — see {@link FakeSandbox.asFactory}.
334
+ */
335
+ export class FakeSandbox {
336
+ behavior;
337
+ backend = "none";
338
+ // Recorded for assertions.
339
+ egress;
340
+ env;
341
+ hostWorkspaceDir = "";
342
+ agentCwd = "";
343
+ stagedSkillDirs;
344
+ receivedAgentOpts;
345
+ receivedCommandOpts;
346
+ receivedCommand;
347
+ provisionCalls = 0;
348
+ disposed = false;
349
+ constructor(behavior = {}) {
350
+ this.behavior = behavior;
351
+ }
352
+ /**
353
+ * Build a {@link SandboxFactory} that always returns THIS instance, capturing
354
+ * the construction opts (egress, env, backend) for later inspection.
355
+ */
356
+ asFactory() {
357
+ return (backend, opts) => {
358
+ this.backend = backend;
359
+ this.egress = opts.egress;
360
+ this.env = opts.env;
361
+ return this;
362
+ };
363
+ }
364
+ async provision(pre) {
365
+ this.provisionCalls += 1;
366
+ const dir = mkdtempSync(join(tmpdir(), "fake-sbx-"));
367
+ this.hostWorkspaceDir = dir;
368
+ this.agentCwd = pre ? join(dir, pre.repo) : dir;
369
+ if (pre)
370
+ mkdirSync(this.agentCwd, { recursive: true });
371
+ return { hostWorkspaceDir: dir, agentCwd: this.agentCwd };
372
+ }
373
+ stageSkills(phaseKey, skillPaths) {
374
+ this.stagedSkillDirs = stageSkillBundle(this.hostWorkspaceDir, phaseKey, skillPaths, "symlink");
375
+ return this.stagedSkillDirs;
376
+ }
377
+ sandboxPathFor(relPath) {
378
+ return join(this.hostWorkspaceDir, relPath);
379
+ }
380
+ async runAgent(_taskId, _prompt, opts, onEvent) {
381
+ this.receivedAgentOpts = opts;
382
+ if (this.behavior.throwOnRunAgent)
383
+ throw asError(this.behavior.throwOnRunAgent);
384
+ for (const record of this.behavior.events ?? [])
385
+ onEvent(record);
386
+ return this.behavior.returnRunResult;
387
+ }
388
+ async runCommand(_taskId, command, opts) {
389
+ this.receivedCommand = command;
390
+ this.receivedCommandOpts = opts;
391
+ if (this.behavior.throwOnRunCommand)
392
+ throw asError(this.behavior.throwOnRunCommand);
393
+ return this.behavior.commandResult ?? { exitCode: 0, stdout: "", stderr: "", timedOut: false };
394
+ }
395
+ dispose() {
396
+ this.disposed = true;
397
+ try {
398
+ if (this.hostWorkspaceDir)
399
+ rmSync(this.hostWorkspaceDir, { recursive: true, force: true });
400
+ }
401
+ catch {
402
+ /* best effort */
403
+ }
404
+ }
405
+ }
406
+ // ── helpers ─────────────────────────────────────────────────────────
407
+ function asError(e) {
408
+ return e instanceof Error ? e : new Error(e);
409
+ }
410
+ /**
411
+ * Wrap an `onEvent(record)` consumer as an `onLine(line)` handler for the
412
+ * subprocess (docker/smol) drivers: apply the cheap `{`-prefix guard, parse
413
+ * JSON, and forward the parsed record. Non-JSON / malformed lines are dropped.
414
+ */
415
+ function parseLine(onEvent) {
416
+ return (line) => {
417
+ if (!line.startsWith("{"))
418
+ return;
419
+ let record;
420
+ try {
421
+ record = JSON.parse(line);
422
+ }
423
+ catch {
424
+ return;
425
+ }
426
+ onEvent(record);
427
+ };
428
+ }
429
+ //# sourceMappingURL=sandbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../../src/sandbox/sandbox.ts"],"names":[],"mappings":"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"}
@@ -93,6 +93,13 @@ export declare class WorkflowRunStore {
93
93
  getRun(id: string): WorkflowRun | null;
94
94
  /** Find the most recent active (running or paused) workflow run for a trigger */
95
95
  getByTrigger(triggerId: string): WorkflowRun | null;
96
+ /**
97
+ * True if any run of `workflowName` exists for this trigger, in ANY status.
98
+ * Unlike `getByTrigger` (active runs only), this also sees a build that has
99
+ * already succeeded/failed/cancelled — the signal the router uses to gate
100
+ * reporter-driven re-triage to the pre-build window.
101
+ */
102
+ hasRunForTrigger(triggerId: string, workflowName: string): boolean;
96
103
  /** List all active (running or paused) workflow runs */
97
104
  listActive(): WorkflowRun[];
98
105
  /** List recent workflow runs, ordered by start time descending */