@cursor/july 0.1.1 → 0.1.3

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 (298) hide show
  1. package/AGENTS.md +40 -7
  2. package/README.md +33 -24
  3. package/dist/bin/agent-serve.d.ts +3 -1
  4. package/dist/bin/agent-serve.d.ts.map +1 -1
  5. package/dist/bin/agent-serve.js +466 -140
  6. package/dist/channels/github/api.d.ts.map +1 -1
  7. package/dist/channels/github/api.js +31 -14
  8. package/dist/channels/github/cursor-account.d.ts +43 -0
  9. package/dist/channels/github/cursor-account.d.ts.map +1 -0
  10. package/dist/channels/github/cursor-account.js +95 -0
  11. package/dist/channels/github/github-channel.d.ts.map +1 -1
  12. package/dist/channels/github/github-channel.js +46 -9
  13. package/dist/channels/github/index.d.ts +2 -2
  14. package/dist/channels/github/index.js +2 -2
  15. package/dist/channels/github/types.d.ts +17 -0
  16. package/dist/channels/github/types.d.ts.map +1 -1
  17. package/dist/channels/slack/slack-channel.d.ts +8 -2
  18. package/dist/channels/slack/slack-channel.d.ts.map +1 -1
  19. package/dist/channels/slack/slack-channel.js +8 -0
  20. package/dist/channels/slack/types.d.ts +24 -3
  21. package/dist/channels/slack/types.d.ts.map +1 -1
  22. package/dist/channels/slack/types.js +15 -1
  23. package/dist/docs/404.html +2 -2
  24. package/dist/docs/ab.html +8 -8
  25. package/dist/docs/assets/{ab.md.COdXkces.js → ab.md.BMCZ6Hd7.js} +3 -3
  26. package/dist/docs/assets/{ab.md.COdXkces.lean.js → ab.md.BMCZ6Hd7.lean.js} +1 -1
  27. package/dist/docs/assets/{app.DqfFEmJd.js → app.BR0RbIdx.js} +1 -1
  28. package/dist/docs/assets/chunks/@localSearchIndexroot.DtIOQzGj.js +1 -0
  29. package/dist/docs/assets/chunks/{VPLocalSearchBox.BaLEdS15.js → VPLocalSearchBox.qjsVTneI.js} +1 -1
  30. package/dist/docs/assets/chunks/{theme.CZRvu_0q.js → theme.2Kg8jIp_.js} +2 -2
  31. package/dist/docs/assets/{deployment.md.Dx1TYNk5.js → deployment.md.DTKwE15Z.js} +3 -3
  32. package/dist/docs/assets/{deployment.md.Dx1TYNk5.lean.js → deployment.md.DTKwE15Z.lean.js} +1 -1
  33. package/dist/docs/assets/{evals.md.DPZ_MAnI.js → evals.md.DAgEc_hL.js} +3 -3
  34. package/dist/docs/assets/{guides_agent-to-agent.md.CrtrsySy.js → guides_agent-to-agent.md.Bpzgq2Pq.js} +1 -1
  35. package/dist/docs/assets/{guides_cloud-runtime.md.CYlNMTNp.js → guides_cloud-runtime.md.gVzabdQL.js} +1 -1
  36. package/dist/docs/assets/{guides_github.md.DwbKhCeS.js → guides_github.md.DOOCpqsW.js} +11 -4
  37. package/dist/docs/assets/{guides_github.md.DwbKhCeS.lean.js → guides_github.md.DOOCpqsW.lean.js} +1 -1
  38. package/dist/docs/assets/{guides_human-in-the-loop.md.Dvuctx7s.js → guides_human-in-the-loop.md.DlUqsp1S.js} +2 -2
  39. package/dist/docs/assets/{guides_slack.md.bv41fHfW.js → guides_slack.md.CCwqHvSV.js} +4 -4
  40. package/dist/docs/assets/{guides_slack.md.bv41fHfW.lean.js → guides_slack.md.CCwqHvSV.lean.js} +1 -1
  41. package/dist/docs/assets/{guides_webhooks.md.hFTik3lf.js → guides_webhooks.md.B1EswtUu.js} +2 -2
  42. package/dist/docs/assets/index.md.m81y7TY7.js +20 -0
  43. package/dist/docs/assets/{index.md.BPKcj5AI.lean.js → index.md.m81y7TY7.lean.js} +1 -1
  44. package/dist/docs/assets/quickstart.md.BU6Iwi_9.js +204 -0
  45. package/dist/docs/assets/quickstart.md.BU6Iwi_9.lean.js +1 -0
  46. package/dist/docs/assets/{reference_agent-config.md.Bpd7HQwf.js → reference_agent-config.md.DrW2JUM8.js} +4 -4
  47. package/dist/docs/assets/{reference_agent-config.md.Bpd7HQwf.lean.js → reference_agent-config.md.DrW2JUM8.lean.js} +1 -1
  48. package/dist/docs/assets/{reference_channels.md.D7JTR03W.js → reference_channels.md.DdmiKgqf.js} +4 -4
  49. package/dist/docs/assets/{reference_channels.md.D7JTR03W.lean.js → reference_channels.md.DdmiKgqf.lean.js} +1 -1
  50. package/dist/docs/assets/{reference_cli.md.DA730zCu.js → reference_cli.md.Bv6pOxcF.js} +11 -6
  51. package/dist/docs/assets/{reference_cli.md.DA730zCu.lean.js → reference_cli.md.Bv6pOxcF.lean.js} +1 -1
  52. package/dist/docs/assets/{reference_connections.md.C3vNH_DE.js → reference_connections.md.zaEYCLHT.js} +1 -1
  53. package/dist/docs/assets/{reference_hooks.md.BCEc3MyM.js → reference_hooks.md.DyLVfE1O.js} +1 -1
  54. package/dist/docs/assets/{reference_hooks.md.BCEc3MyM.lean.js → reference_hooks.md.DyLVfE1O.lean.js} +1 -1
  55. package/dist/docs/assets/{reference_http-api.md.DBAahtdz.js → reference_http-api.md.Dx_nmDG6.js} +1 -1
  56. package/dist/docs/assets/{reference_instructions.md.BC05LEQ8.js → reference_instructions.md.CgoV-YEb.js} +9 -7
  57. package/dist/docs/assets/{reference_instructions.md.BC05LEQ8.lean.js → reference_instructions.md.CgoV-YEb.lean.js} +1 -1
  58. package/dist/docs/assets/{reference_schedules.md.D7qijxLk.js → reference_schedules.md.w_F2mXB6.js} +2 -2
  59. package/dist/docs/assets/{reference_skills.md.VQnlBT3Q.js → reference_skills.md.B_jHN7JL.js} +3 -3
  60. package/dist/docs/assets/{reference_skills.md.VQnlBT3Q.lean.js → reference_skills.md.B_jHN7JL.lean.js} +1 -1
  61. package/dist/docs/assets/{reference_subagents.md.CIRAVcPK.js → reference_subagents.md.zWAMNfi1.js} +1 -1
  62. package/dist/docs/assets/{reference_tools.md.DF5kwlt0.js → reference_tools.md.CqgJroI0.js} +2 -2
  63. package/dist/docs/assets/scaffolding-agents.md.C3pTrmoE.js +1 -0
  64. package/dist/docs/assets/scaffolding-agents.md.C3pTrmoE.lean.js +1 -0
  65. package/dist/docs/assets/storage.md.CVnInNiN.js +17 -0
  66. package/dist/docs/assets/storage.md.CVnInNiN.lean.js +1 -0
  67. package/dist/docs/building-with-agents.html +4 -4
  68. package/dist/docs/concepts.html +4 -4
  69. package/dist/docs/deployment.html +7 -7
  70. package/dist/docs/evals.html +7 -7
  71. package/dist/docs/guides/agent-to-agent.html +6 -6
  72. package/dist/docs/guides/cloud-runtime.html +5 -5
  73. package/dist/docs/guides/github.html +14 -7
  74. package/dist/docs/guides/human-in-the-loop.html +6 -6
  75. package/dist/docs/guides/slack.html +8 -8
  76. package/dist/docs/guides/webhooks.html +6 -6
  77. package/dist/docs/hashmap.json +1 -1
  78. package/dist/docs/hillclimbing.html +5 -5
  79. package/dist/docs/index.html +7 -7
  80. package/dist/docs/quickstart.html +195 -26
  81. package/dist/docs/reference/agent-config.html +7 -7
  82. package/dist/docs/reference/channels.html +8 -8
  83. package/dist/docs/reference/cli.html +14 -9
  84. package/dist/docs/reference/connections.html +5 -5
  85. package/dist/docs/reference/hooks.html +5 -5
  86. package/dist/docs/reference/http-api.html +6 -6
  87. package/dist/docs/reference/instructions.html +13 -11
  88. package/dist/docs/reference/playground.html +4 -4
  89. package/dist/docs/reference/project-layout.html +4 -4
  90. package/dist/docs/reference/schedules.html +7 -7
  91. package/dist/docs/reference/sessions.html +4 -4
  92. package/dist/docs/reference/skills.html +6 -6
  93. package/dist/docs/reference/subagents.html +6 -6
  94. package/dist/docs/reference/tools.html +7 -7
  95. package/dist/docs/scaffolding-agents.html +5 -5
  96. package/dist/docs/storage.html +41 -0
  97. package/dist/docs/troubleshooting.html +4 -4
  98. package/dist/index.d.ts +2 -0
  99. package/dist/index.d.ts.map +1 -1
  100. package/dist/index.js +1 -0
  101. package/dist/internal/chat-client.d.ts +29 -3
  102. package/dist/internal/chat-client.d.ts.map +1 -1
  103. package/dist/internal/chat-client.js +180 -27
  104. package/dist/internal/cli-ax.d.ts +75 -2
  105. package/dist/internal/cli-ax.d.ts.map +1 -1
  106. package/dist/internal/cli-ax.js +600 -52
  107. package/dist/internal/cli-cursor.d.ts.map +1 -1
  108. package/dist/internal/cli-cursor.js +8 -36
  109. package/dist/internal/cli-deploy.d.ts +108 -0
  110. package/dist/internal/cli-deploy.d.ts.map +1 -0
  111. package/dist/internal/cli-deploy.js +1009 -0
  112. package/dist/internal/cursor/backend-client.d.ts +10 -1
  113. package/dist/internal/cursor/backend-client.d.ts.map +1 -1
  114. package/dist/internal/cursor/backend-client.js +79 -1
  115. package/dist/internal/cursor/credentials.d.ts +9 -0
  116. package/dist/internal/cursor/credentials.d.ts.map +1 -1
  117. package/dist/internal/cursor/credentials.js +12 -0
  118. package/dist/internal/cursor/github-credentials.d.ts +44 -0
  119. package/dist/internal/cursor/github-credentials.d.ts.map +1 -0
  120. package/dist/internal/cursor/github-credentials.js +195 -0
  121. package/dist/internal/deploy-client.d.ts +184 -0
  122. package/dist/internal/deploy-client.d.ts.map +1 -0
  123. package/dist/internal/deploy-client.js +395 -0
  124. package/dist/internal/deploy-source.d.ts +35 -0
  125. package/dist/internal/deploy-source.d.ts.map +1 -0
  126. package/dist/internal/deploy-source.js +118 -0
  127. package/dist/internal/discovery.d.ts +11 -0
  128. package/dist/internal/discovery.d.ts.map +1 -1
  129. package/dist/internal/discovery.js +116 -19
  130. package/dist/internal/distribution.d.ts.map +1 -1
  131. package/dist/internal/distribution.js +1 -0
  132. package/dist/internal/eval-run-store.d.ts +22 -3
  133. package/dist/internal/eval-run-store.d.ts.map +1 -1
  134. package/dist/internal/eval-run-store.js +39 -20
  135. package/dist/internal/eval-runner.d.ts +2 -0
  136. package/dist/internal/eval-runner.d.ts.map +1 -1
  137. package/dist/internal/eval-runner.js +2 -0
  138. package/dist/internal/event-mapper.d.ts +54 -1
  139. package/dist/internal/event-mapper.d.ts.map +1 -1
  140. package/dist/internal/event-mapper.js +151 -41
  141. package/dist/internal/handleAgentServeTrigger.d.ts.map +1 -1
  142. package/dist/internal/handleAgentServeTrigger.js +10 -12
  143. package/dist/internal/host-platforms.d.ts +7 -2
  144. package/dist/internal/host-platforms.d.ts.map +1 -1
  145. package/dist/internal/host-platforms.js +15 -10
  146. package/dist/internal/hosting.d.ts +37 -0
  147. package/dist/internal/hosting.d.ts.map +1 -0
  148. package/dist/internal/hosting.js +67 -0
  149. package/dist/internal/init-project.d.ts +88 -1
  150. package/dist/internal/init-project.d.ts.map +1 -1
  151. package/dist/internal/init-project.js +221 -31
  152. package/dist/internal/install-cursor-skills.d.ts +64 -0
  153. package/dist/internal/install-cursor-skills.d.ts.map +1 -0
  154. package/dist/internal/install-cursor-skills.js +274 -0
  155. package/dist/internal/logs-client.d.ts +60 -0
  156. package/dist/internal/logs-client.d.ts.map +1 -0
  157. package/dist/internal/logs-client.js +311 -0
  158. package/dist/internal/open-browser.d.ts +5 -0
  159. package/dist/internal/open-browser.d.ts.map +1 -0
  160. package/dist/internal/open-browser.js +34 -0
  161. package/dist/internal/playground/toolchain.d.ts.map +1 -1
  162. package/dist/internal/playground/toolchain.js +16 -11
  163. package/dist/internal/playground-proxy.d.ts +69 -0
  164. package/dist/internal/playground-proxy.d.ts.map +1 -0
  165. package/dist/internal/playground-proxy.js +468 -0
  166. package/dist/internal/prompt-context.d.ts +35 -0
  167. package/dist/internal/prompt-context.d.ts.map +1 -0
  168. package/dist/internal/prompt-context.js +71 -0
  169. package/dist/internal/reminder-runner.d.ts +7 -0
  170. package/dist/internal/reminder-runner.d.ts.map +1 -1
  171. package/dist/internal/reminder-runner.js +50 -6
  172. package/dist/internal/reminder-store.d.ts +2 -0
  173. package/dist/internal/reminder-store.d.ts.map +1 -1
  174. package/dist/internal/reminder-store.js +18 -0
  175. package/dist/internal/request-headers.d.ts +11 -0
  176. package/dist/internal/request-headers.d.ts.map +1 -0
  177. package/dist/internal/request-headers.js +14 -0
  178. package/dist/internal/resolve-prod-target.d.ts +42 -0
  179. package/dist/internal/resolve-prod-target.d.ts.map +1 -0
  180. package/dist/internal/resolve-prod-target.js +111 -0
  181. package/dist/internal/run-client.d.ts +2 -2
  182. package/dist/internal/run-client.d.ts.map +1 -1
  183. package/dist/internal/run-client.js +38 -23
  184. package/dist/internal/server.d.ts.map +1 -1
  185. package/dist/internal/server.js +182 -45
  186. package/dist/internal/session-engine.d.ts +50 -1
  187. package/dist/internal/session-engine.d.ts.map +1 -1
  188. package/dist/internal/session-engine.js +267 -23
  189. package/dist/internal/sessions-client.d.ts +21 -0
  190. package/dist/internal/sessions-client.d.ts.map +1 -0
  191. package/dist/internal/sessions-client.js +168 -0
  192. package/dist/internal/storage-coordinator.d.ts +139 -0
  193. package/dist/internal/storage-coordinator.d.ts.map +1 -0
  194. package/dist/internal/storage-coordinator.js +499 -0
  195. package/dist/internal/stream-progress.d.ts.map +1 -1
  196. package/dist/internal/stream-progress.js +31 -3
  197. package/dist/internal/terminal-style.d.ts +22 -0
  198. package/dist/internal/terminal-style.d.ts.map +1 -0
  199. package/dist/internal/terminal-style.js +49 -0
  200. package/dist/internal/trajectory.d.ts +10 -5
  201. package/dist/internal/trajectory.d.ts.map +1 -1
  202. package/dist/internal/trajectory.js +82 -10
  203. package/dist/internal/workspace.d.ts +11 -0
  204. package/dist/internal/workspace.d.ts.map +1 -1
  205. package/dist/internal/workspace.js +38 -4
  206. package/dist/playground/assets/cursor-icons-outline-BxTT_FVJ.woff2 +0 -0
  207. package/dist/playground/assets/index-D-vo2lV_.css +1 -0
  208. package/dist/playground/assets/index-x60b9q2j.js +312 -0
  209. package/dist/playground/index.html +2 -2
  210. package/dist/storage.d.ts +204 -0
  211. package/dist/storage.d.ts.map +1 -0
  212. package/dist/storage.js +153 -0
  213. package/dist/types.d.ts +70 -4
  214. package/dist/types.d.ts.map +1 -1
  215. package/docs/README.md +3 -2
  216. package/docs/guides/github.md +43 -8
  217. package/docs/guides/slack.md +1 -1
  218. package/docs/quickstart.md +350 -57
  219. package/docs/reference/cli.md +51 -3
  220. package/docs/reference/instructions.md +8 -6
  221. package/docs/scaffolding-agents.md +1 -1
  222. package/docs/storage.md +98 -0
  223. package/package.json +10 -1
  224. package/skills/ab/SKILL.md +8 -8
  225. package/skills/create-agent/SKILL.md +28 -22
  226. package/skills/debug/SKILL.md +11 -11
  227. package/skills/evals/SKILL.md +16 -16
  228. package/skills/framework-map/SKILL.md +6 -6
  229. package/skills/github/SKILL.md +22 -14
  230. package/skills/hillclimb/SKILL.md +10 -10
  231. package/skills/setup-slack/SKILL.md +13 -13
  232. package/src/bin/agent-serve.ts +552 -179
  233. package/src/channels/github/api.ts +42 -23
  234. package/src/channels/github/cursor-account.ts +165 -0
  235. package/src/channels/github/github-channel.ts +66 -6
  236. package/src/channels/github/index.ts +2 -2
  237. package/src/channels/github/types.ts +19 -0
  238. package/src/channels/slack/slack-channel.ts +17 -3
  239. package/src/channels/slack/types.ts +44 -3
  240. package/src/index.ts +13 -0
  241. package/src/internal/chat-client.ts +252 -37
  242. package/src/internal/cli-ax.ts +722 -72
  243. package/src/internal/cli-cursor.ts +14 -42
  244. package/src/internal/cli-deploy.ts +1319 -0
  245. package/src/internal/cursor/backend-client.ts +103 -1
  246. package/src/internal/cursor/credentials.ts +14 -0
  247. package/src/internal/cursor/github-credentials.ts +248 -0
  248. package/src/internal/deploy-client.ts +632 -0
  249. package/src/internal/deploy-source.ts +133 -0
  250. package/src/internal/discovery.ts +141 -17
  251. package/src/internal/distribution.ts +1 -0
  252. package/src/internal/eval-run-store.ts +50 -20
  253. package/src/internal/eval-runner.ts +5 -0
  254. package/src/internal/event-mapper.ts +222 -42
  255. package/src/internal/handleAgentServeTrigger.ts +10 -12
  256. package/src/internal/host-platforms.ts +28 -11
  257. package/src/internal/hosting.ts +77 -0
  258. package/src/internal/init-project.ts +333 -51
  259. package/src/internal/install-cursor-skills.ts +327 -0
  260. package/src/internal/logs-client.ts +442 -0
  261. package/src/internal/open-browser.ts +41 -0
  262. package/src/internal/playground/toolchain.ts +15 -13
  263. package/src/internal/playground-proxy.ts +576 -0
  264. package/src/internal/prompt-context.ts +95 -0
  265. package/src/internal/reminder-runner.ts +50 -6
  266. package/src/internal/reminder-store.ts +21 -0
  267. package/src/internal/request-headers.ts +23 -0
  268. package/src/internal/resolve-prod-target.ts +150 -0
  269. package/src/internal/run-client.ts +39 -36
  270. package/src/internal/server.ts +223 -28
  271. package/src/internal/session-engine.ts +307 -10
  272. package/src/internal/sessions-client.ts +182 -0
  273. package/src/internal/storage-coordinator.ts +615 -0
  274. package/src/internal/stream-progress.ts +36 -2
  275. package/src/internal/terminal-style.ts +74 -0
  276. package/src/internal/trajectory.ts +91 -13
  277. package/src/internal/workspace.ts +42 -4
  278. package/src/storage.ts +325 -0
  279. package/src/types.ts +82 -8
  280. package/dist/docs/assets/chunks/@localSearchIndexroot.CcVk1uKq.js +0 -1
  281. package/dist/docs/assets/index.md.BPKcj5AI.js +0 -20
  282. package/dist/docs/assets/quickstart.md.tVPiGK_L.js +0 -35
  283. package/dist/docs/assets/quickstart.md.tVPiGK_L.lean.js +0 -1
  284. package/dist/docs/assets/scaffolding-agents.md.CyYfWGdc.js +0 -1
  285. package/dist/docs/assets/scaffolding-agents.md.CyYfWGdc.lean.js +0 -1
  286. package/dist/playground/assets/cursor-icons-outline-oY2V_mvK.woff2 +0 -0
  287. package/dist/playground/assets/index-1K-hG-7p.css +0 -1
  288. package/dist/playground/assets/index-FlWjhg3x.js +0 -79
  289. /package/dist/docs/assets/{evals.md.DPZ_MAnI.lean.js → evals.md.DAgEc_hL.lean.js} +0 -0
  290. /package/dist/docs/assets/{guides_agent-to-agent.md.CrtrsySy.lean.js → guides_agent-to-agent.md.Bpzgq2Pq.lean.js} +0 -0
  291. /package/dist/docs/assets/{guides_cloud-runtime.md.CYlNMTNp.lean.js → guides_cloud-runtime.md.gVzabdQL.lean.js} +0 -0
  292. /package/dist/docs/assets/{guides_human-in-the-loop.md.Dvuctx7s.lean.js → guides_human-in-the-loop.md.DlUqsp1S.lean.js} +0 -0
  293. /package/dist/docs/assets/{guides_webhooks.md.hFTik3lf.lean.js → guides_webhooks.md.B1EswtUu.lean.js} +0 -0
  294. /package/dist/docs/assets/{reference_connections.md.C3vNH_DE.lean.js → reference_connections.md.zaEYCLHT.lean.js} +0 -0
  295. /package/dist/docs/assets/{reference_http-api.md.DBAahtdz.lean.js → reference_http-api.md.Dx_nmDG6.lean.js} +0 -0
  296. /package/dist/docs/assets/{reference_schedules.md.D7qijxLk.lean.js → reference_schedules.md.w_F2mXB6.lean.js} +0 -0
  297. /package/dist/docs/assets/{reference_subagents.md.CIRAVcPK.lean.js → reference_subagents.md.zWAMNfi1.lean.js} +0 -0
  298. /package/dist/docs/assets/{reference_tools.md.DF5kwlt0.lean.js → reference_tools.md.CqgJroI0.lean.js} +0 -0
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Infer `agentkit deploy` git source fields from a local checkout.
3
+ *
4
+ * From an agent directory inside a git repo with an `origin` remote, the
5
+ * CLI can fill `--repo` / `--ref` / `--path` so `agentkit deploy` (no
6
+ * flags) is enough. Explicit flags always win.
7
+ */
8
+
9
+ import { execFile } from "node:child_process";
10
+ import { relative, resolve, sep } from "node:path";
11
+ import { promisify } from "node:util";
12
+
13
+ const execFileAsync = promisify(execFile);
14
+
15
+ /** Injectable git runner (cwd + args → stdout, or undefined on failure). */
16
+ export type GitRunner = (
17
+ args: readonly string[],
18
+ cwd: string
19
+ ) => Promise<string | undefined>;
20
+
21
+ export interface InferredDeploySource {
22
+ gitRepoUrl?: string;
23
+ gitRef?: string;
24
+ /** Agent directory relative to the repo root (posix). Omitted at root. */
25
+ agentPath?: string;
26
+ }
27
+
28
+ const defaultGitRunner: GitRunner = async (args, cwd) => {
29
+ try {
30
+ const { stdout } = await execFileAsync("git", [...args], { cwd });
31
+ const trimmed = stdout.trim();
32
+ return trimmed === "" ? undefined : trimmed;
33
+ } catch {
34
+ return undefined;
35
+ }
36
+ };
37
+
38
+ /**
39
+ * Normalize a git remote URL to the https form the control plane accepts
40
+ * (`https://host/owner/repo`, no `.git` suffix). Returns undefined for
41
+ * unrecognized shapes.
42
+ */
43
+ export function httpsGitRepoUrlFromRemote(remote: string): string | undefined {
44
+ let url = remote.trim();
45
+ if (url === "") {
46
+ return undefined;
47
+ }
48
+ if (url.startsWith("git@")) {
49
+ // git@host:owner/repo.git → https://host/owner/repo.git
50
+ url = `https://${url.slice("git@".length).replace(":", "/")}`;
51
+ } else if (url.startsWith("ssh://git@")) {
52
+ url = `https://${url.slice("ssh://git@".length)}`;
53
+ } else if (!/^https?:\/\//i.test(url)) {
54
+ return undefined;
55
+ }
56
+
57
+ let parsed: URL;
58
+ try {
59
+ parsed = new URL(url);
60
+ } catch {
61
+ return undefined;
62
+ }
63
+ const path = parsed.pathname
64
+ .replace(/\.git$/i, "")
65
+ .replace(/\/+$/, "")
66
+ .replace(/^\/+/, "");
67
+ if (path === "" || !path.includes("/")) {
68
+ return undefined;
69
+ }
70
+ // Use hostname (not host) so ssh://git@github.com:22/… does not keep :22.
71
+ return `https://${parsed.hostname}/${path}`;
72
+ }
73
+
74
+ /**
75
+ * Path of `dir` relative to `gitRoot`, using `/` separators. Undefined when
76
+ * `dir` is outside the root; omitted (undefined) when `dir` *is* the root
77
+ * so the control plane treats the agent as living at the repo root.
78
+ */
79
+ export function agentPathRelativeToGitRoot(
80
+ dir: string,
81
+ gitRoot: string
82
+ ): string | undefined {
83
+ const absDir = resolve(dir);
84
+ const absRoot = resolve(gitRoot);
85
+ const rel = relative(absRoot, absDir);
86
+ if (rel === "") {
87
+ return undefined;
88
+ }
89
+ // Outside the repo (or a Windows drive mismatch) → cannot infer.
90
+ if (rel.startsWith("..") || rel.split(sep).includes("..")) {
91
+ return undefined;
92
+ }
93
+ return rel.split(sep).join("/");
94
+ }
95
+
96
+ /**
97
+ * Probe the git checkout containing `dir` for deploy source fields.
98
+ * Missing pieces stay undefined (static deploy / server defaults).
99
+ */
100
+ export async function inferDeployGitSource(
101
+ dir: string,
102
+ options?: { git?: GitRunner }
103
+ ): Promise<InferredDeploySource> {
104
+ const git = options?.git ?? defaultGitRunner;
105
+ const absDir = resolve(dir);
106
+
107
+ const gitRoot = await git(["rev-parse", "--show-toplevel"], absDir);
108
+ if (gitRoot === undefined) {
109
+ return {};
110
+ }
111
+
112
+ const remote = await git(["remote", "get-url", "origin"], gitRoot);
113
+ const gitRepoUrl =
114
+ remote === undefined ? undefined : httpsGitRepoUrlFromRemote(remote);
115
+
116
+ const branch = await git(["rev-parse", "--abbrev-ref", "HEAD"], gitRoot);
117
+ let gitRef: string | undefined;
118
+ if (branch !== undefined && branch !== "HEAD") {
119
+ gitRef = branch;
120
+ } else {
121
+ // Detached HEAD — pin the exact commit so the control plane still
122
+ // has something concrete to build.
123
+ gitRef = await git(["rev-parse", "HEAD"], gitRoot);
124
+ }
125
+
126
+ const agentPath = agentPathRelativeToGitRoot(absDir, gitRoot);
127
+
128
+ return {
129
+ gitRepoUrl,
130
+ gitRef,
131
+ agentPath,
132
+ };
133
+ }
@@ -19,8 +19,10 @@ import {
19
19
  import { pathToFileURL } from "node:url";
20
20
  import { type ABConfigFile, resolveABMaxPlaygroundSessions } from "../ab.js";
21
21
  import { httpChannel } from "../channels.js";
22
+ import type { StorageDefinition } from "../storage.js";
22
23
  import {
23
24
  type AgentConfigDefinition,
25
+ type AgentHostingOptions,
24
26
  type AgentProject,
25
27
  type AgentProjectInfo,
26
28
  type ChannelDefinition,
@@ -51,8 +53,15 @@ import { registerAuthoredModuleLoaders } from "./authored-loaders.js";
51
53
  import { getDefinitionKind } from "./brand.js";
52
54
  import { isValidCron } from "./cron.js";
53
55
  import { parseFrontmatter } from "./frontmatter.js";
56
+ import {
57
+ isReservedSecretName,
58
+ MAX_EGRESS_DOMAINS,
59
+ validateEgressDomain,
60
+ validateSecretName,
61
+ } from "./hosting.js";
54
62
  import { toolInputJsonSchema } from "./json-schema.js";
55
63
  import { MCP_ENDPOINT_PATH, mcpEndpointToolNames } from "./mcp-endpoint.js";
64
+ import { withIdentityPreamble } from "./workspace.js";
56
65
 
57
66
  const MODULE_EXTENSIONS = new Set([".ts", ".mts", ".js", ".mjs"]);
58
67
  const NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;
@@ -97,23 +106,26 @@ export async function isAgentProjectDir(dir: string): Promise<boolean> {
97
106
  return hasFlatLayoutMarkers(resolved);
98
107
  }
99
108
 
109
+ /** One immediate child agent directory under a multi-agent parent. */
110
+ export interface ChildAgentDir {
111
+ slug: string;
112
+ dir: string;
113
+ }
114
+
100
115
  /**
101
- * Discover the agent projects directly under `rootDir` (one level deep):
102
- * each immediate child directory that is itself an agent project becomes a
103
- * mounted agent, keyed by a slug derived from its directory name. Used for
104
- * multi-agent serving, where one server hosts many agents under
105
- * `/<slug>/...`. Throws when no child projects are found.
116
+ * List agent projects directly under `rootDir` (one level deep) without
117
+ * loading them. Empty when the path is missing or has no child agents.
118
+ * Slug rules match {@link loadAgentProjects} / multi-agent serve.
106
119
  */
107
- export async function loadAgentProjects(
108
- rootDir: string,
109
- options: LoadAgentProjectOptions = {}
110
- ): Promise<Array<{ slug: string; project: AgentProject }>> {
120
+ export async function listChildAgentDirs(
121
+ rootDir: string
122
+ ): Promise<ChildAgentDir[]> {
111
123
  const resolved = resolve(rootDir);
112
124
  if (!(await isDirectory(resolved))) {
113
- throw new Error(`Agent projects directory does not exist: ${resolved}`);
125
+ return [];
114
126
  }
115
127
 
116
- const results: Array<{ slug: string; project: AgentProject }> = [];
128
+ const results: ChildAgentDir[] = [];
117
129
  const seenSlugs = new Set<string>();
118
130
  for (const entry of await sortedEntries(resolved)) {
119
131
  if (!entry.isDirectory() || entry.name.startsWith(".")) {
@@ -131,14 +143,40 @@ export async function loadAgentProjects(
131
143
  throw new Error(`Duplicate agent slug "${slug}" under ${resolved}.`);
132
144
  }
133
145
  seenSlugs.add(slug);
134
- results.push({ slug, project: await loadAgentProject(childDir, options) });
146
+ results.push({ slug, dir: childDir });
135
147
  }
148
+ return results;
149
+ }
136
150
 
137
- if (results.length === 0) {
151
+ /**
152
+ * Discover the agent projects directly under `rootDir` (one level deep):
153
+ * each immediate child directory that is itself an agent project becomes a
154
+ * mounted agent, keyed by a slug derived from its directory name. Used for
155
+ * multi-agent serving, where one server hosts many agents under
156
+ * `/<slug>/...`. Throws when no child projects are found.
157
+ */
158
+ export async function loadAgentProjects(
159
+ rootDir: string,
160
+ options: LoadAgentProjectOptions = {}
161
+ ): Promise<Array<{ slug: string; project: AgentProject }>> {
162
+ const resolved = resolve(rootDir);
163
+ if (!(await isDirectory(resolved))) {
164
+ throw new Error(`Agent projects directory does not exist: ${resolved}`);
165
+ }
166
+
167
+ const children = await listChildAgentDirs(resolved);
168
+ if (children.length === 0) {
138
169
  throw new Error(
139
170
  `No agent projects found directly under ${resolved}. Each agent should be a subdirectory with its own agent/ directory (or flat-layout markers).`
140
171
  );
141
172
  }
173
+ const results: Array<{ slug: string; project: AgentProject }> = [];
174
+ for (const child of children) {
175
+ results.push({
176
+ slug: child.slug,
177
+ project: await loadAgentProject(child.dir, options),
178
+ });
179
+ }
142
180
  return results;
143
181
  }
144
182
 
@@ -233,6 +271,7 @@ export async function loadAgentProject(
233
271
  const hooks = await loadHooks(ctx, join(agentDir, "hooks"));
234
272
  const abs = await loadABs(ctx, agentDir);
235
273
  const abConfig = await loadABConfig(ctx, agentDir);
274
+ const storage = await loadStorage(ctx, agentDir);
236
275
 
237
276
  if (agentDir !== rootDir) {
238
277
  await warnUnknownSlots(ctx, agentDir);
@@ -248,7 +287,8 @@ export async function loadAgentProject(
248
287
  schedules,
249
288
  hooks,
250
289
  abs,
251
- ...(abConfig === undefined ? {} : { abConfig }),
290
+ abConfig,
291
+ storage,
252
292
  diagnostics,
253
293
  };
254
294
  }
@@ -277,12 +317,19 @@ async function loadAgent(
277
317
  options: { name: string; isRoot: boolean }
278
318
  ): Promise<ResolvedAgent> {
279
319
  const config = await loadAgentConfig(ctx, agentDir, options.isRoot);
280
- const instructions = await loadInstructions(
320
+ const name = config?.name ?? options.name;
321
+ const authoredInstructions = await loadInstructions(
281
322
  ctx,
282
323
  agentDir,
283
324
  config,
284
325
  options.isRoot
285
326
  );
327
+ // Root agents without authored instructions stay undefined (diagnostic
328
+ // already recorded). Subagents still get the identity line alone.
329
+ const instructions =
330
+ authoredInstructions === undefined && options.isRoot
331
+ ? undefined
332
+ : withIdentityPreamble(name, authoredInstructions);
286
333
 
287
334
  // Subagents run as Cursor SDK custom subagents (prompt + description +
288
335
  // model); their other slots are inert today, so don't load them — just
@@ -290,7 +337,7 @@ async function loadAgent(
290
337
  if (!options.isRoot) {
291
338
  await warnUnsupportedSubagentSlots(ctx, agentDir);
292
339
  return {
293
- name: config?.name ?? options.name,
340
+ name,
294
341
  ...(config?.description === undefined
295
342
  ? {}
296
343
  : { description: config.description }),
@@ -324,6 +371,7 @@ async function loadAgent(
324
371
  : {
325
372
  cwd: localCwd,
326
373
  };
374
+ const hosting = resolveHosting(ctx, agentDir, config?.hosting);
327
375
 
328
376
  if (runtime === "cloud") {
329
377
  warnCloudRuntimeLimitations(ctx, agentDir, {
@@ -336,7 +384,7 @@ async function loadAgent(
336
384
  }
337
385
 
338
386
  return {
339
- name: config?.name ?? options.name,
387
+ name,
340
388
  description: config?.description,
341
389
  // Root agents always get a concrete model: authored value or DEFAULT_MODEL.
342
390
  model: isValidModelSetting(config?.model) ? config.model : DEFAULT_MODEL,
@@ -344,6 +392,7 @@ async function loadAgent(
344
392
  runtime,
345
393
  cloud,
346
394
  local,
395
+ hosting,
347
396
  tools,
348
397
  skills,
349
398
  connections,
@@ -367,6 +416,59 @@ function resolveAgentCwd(
367
416
  return isAbsolute(trimmed) ? trimmed : resolve(ctx.rootDir, trimmed);
368
417
  }
369
418
 
419
+ /**
420
+ * Validate the authored `hosting` block against the same grammar the
421
+ * backend enforces on deploy. Violations are warning diagnostics (reported
422
+ * by `agentkit validate`), not hard failures: the backend stays
423
+ * authoritative and `agentkit deploy` re-checks before any network call.
424
+ */
425
+ function resolveHosting(
426
+ ctx: DiscoveryContext,
427
+ agentDir: string,
428
+ hosting: AgentHostingOptions | undefined
429
+ ): AgentHostingOptions | undefined {
430
+ if (hosting === undefined) {
431
+ return undefined;
432
+ }
433
+ const agentPath = displayPath(ctx, join(agentDir, "agent.ts"));
434
+ const warn = (message: string): void => {
435
+ ctx.diagnostics.push({ severity: "warning", path: agentPath, message });
436
+ };
437
+
438
+ const egressDomains = hosting.egressDomains ?? [];
439
+ for (const domain of egressDomains) {
440
+ const domainError = validateEgressDomain(domain);
441
+ if (domainError !== undefined) {
442
+ warn(`hosting.egressDomains: ${domainError}`);
443
+ }
444
+ }
445
+ if (egressDomains.length > MAX_EGRESS_DOMAINS) {
446
+ warn(
447
+ `hosting.egressDomains lists ${egressDomains.length} domains; deploys are capped at ${MAX_EGRESS_DOMAINS}.`
448
+ );
449
+ }
450
+
451
+ for (const name of hosting.secretNames ?? []) {
452
+ const nameError = validateSecretName(name);
453
+ if (nameError !== undefined) {
454
+ warn(`hosting.secretNames: ${nameError}`);
455
+ } else if (isReservedSecretName(name)) {
456
+ warn(
457
+ `hosting.secretNames: ${JSON.stringify(name)} is platform-reserved (CURSOR_*) and injected automatically; it cannot be set with \`secrets set\`.`
458
+ );
459
+ }
460
+ }
461
+
462
+ return {
463
+ ...(hosting.egressDomains === undefined
464
+ ? {}
465
+ : { egressDomains: [...hosting.egressDomains] }),
466
+ ...(hosting.secretNames === undefined
467
+ ? {}
468
+ : { secretNames: [...hosting.secretNames] }),
469
+ };
470
+ }
471
+
370
472
  async function loadAgentConfig(
371
473
  ctx: DiscoveryContext,
372
474
  agentDir: string,
@@ -1323,6 +1425,22 @@ async function loadABConfig(
1323
1425
  }
1324
1426
  }
1325
1427
 
1428
+ // ============================================================================
1429
+ // Storage (agent/storage.ts)
1430
+ // ============================================================================
1431
+
1432
+ async function loadStorage(
1433
+ ctx: DiscoveryContext,
1434
+ agentDir: string
1435
+ ): Promise<StorageDefinition | undefined> {
1436
+ const path = await findModuleFile(agentDir, "storage");
1437
+ if (path === undefined) {
1438
+ return undefined;
1439
+ }
1440
+ const definition = await importDefault(ctx, path, "storage");
1441
+ return definition as StorageDefinition | undefined;
1442
+ }
1443
+
1326
1444
  function resolveABName(definition: unknown, fallback: string): string {
1327
1445
  if (
1328
1446
  typeof definition === "object" &&
@@ -1410,6 +1528,7 @@ export function projectInfo(project: AgentProject): AgentProjectInfo {
1410
1528
  cloud:
1411
1529
  agent.cloud === undefined ? undefined : toPublicCloudInfo(agent.cloud),
1412
1530
  local: agent.local,
1531
+ hosting: agent.hosting,
1413
1532
  mcp: { path: MCP_ENDPOINT_PATH, tools: mcpEndpointToolNames(project) },
1414
1533
  instructions:
1415
1534
  agent.instructions === undefined
@@ -1496,6 +1615,10 @@ export function projectInfo(project: AgentProject): AgentProjectInfo {
1496
1615
  durableSnapshots: project.abConfig?.persistSnapshots !== undefined,
1497
1616
  },
1498
1617
  }),
1618
+ storage:
1619
+ project.storage === undefined
1620
+ ? undefined
1621
+ : { name: project.storage.name },
1499
1622
  diagnostics: project.diagnostics,
1500
1623
  };
1501
1624
  }
@@ -1515,6 +1638,7 @@ async function importDefault(
1515
1638
  | "schedule"
1516
1639
  | "hook"
1517
1640
  | "ab"
1641
+ | "storage"
1518
1642
  ): Promise<unknown> {
1519
1643
  let mod: Record<string, unknown>;
1520
1644
  try {
@@ -94,4 +94,5 @@ export const AUTHORING_ENTRY_FILES: ReadonlyArray<
94
94
  ["hooks", "hooks.js"],
95
95
  ["evals", "evals.js"],
96
96
  ["ab", "ab.js"],
97
+ ["storage", "storage.js"],
97
98
  ];
@@ -62,9 +62,21 @@ export class EvalRunStore {
62
62
 
63
63
  constructor(
64
64
  private readonly projectRoot: string,
65
- private readonly logger: (line: string) => void
65
+ private readonly logger: (line: string) => void,
66
+ /**
67
+ * Project-wide sink from `agent/storage.ts` (`defineStorage`),
68
+ * used when `evals.config.ts` sets no `persistRuns` of its own.
69
+ */
70
+ private readonly fallbackPersistence?: EvalRunPersistence
66
71
  ) {}
67
72
 
73
+ /** `evals.config.ts` `persistRuns` wins; `defineStorage` is fallback. */
74
+ private resolvePersist(
75
+ config: Partial<EvalConfigFile>
76
+ ): EvalRunPersistence | undefined {
77
+ return config.persistRuns ?? this.fallbackPersistence;
78
+ }
79
+
68
80
  async list(): Promise<{
69
81
  evals: Array<{
70
82
  id: string;
@@ -74,7 +86,7 @@ export class EvalRunStore {
74
86
  }>;
75
87
  config: EvalListConfig;
76
88
  }> {
77
- await this.ensureHydrated();
89
+ await this.hydrate();
78
90
  const { evals, config } = await discoverEvals(this.projectRoot);
79
91
  return {
80
92
  evals: evals.map((e) => ({
@@ -85,18 +97,21 @@ export class EvalRunStore {
85
97
  : { description: e.definition.description }),
86
98
  ...(e.definition.tags === undefined ? {} : { tags: e.definition.tags }),
87
99
  })),
88
- config: snapshotListConfig(config),
100
+ config: snapshotListConfig(
101
+ config,
102
+ this.resolvePersist(config) !== undefined
103
+ ),
89
104
  };
90
105
  }
91
106
 
92
107
  async get(runId: string): Promise<EvalRunSnapshot | undefined> {
93
- await this.ensureHydrated();
108
+ await this.hydrate();
94
109
  return this.runs.get(runId);
95
110
  }
96
111
 
97
112
  /** Newest-first snapshots for playground rehydrate after navigation/reload. */
98
113
  async listRuns(): Promise<EvalRunSnapshot[]> {
99
- await this.ensureHydrated();
114
+ await this.hydrate();
100
115
  return this.sortedRuns();
101
116
  }
102
117
 
@@ -109,7 +124,7 @@ export class EvalRunStore {
109
124
  runs: EvalRunSnapshot[];
110
125
  activeRunId?: string;
111
126
  }> {
112
- await this.ensureHydrated();
127
+ await this.hydrate();
113
128
  const activeRunId = this.activeRunId;
114
129
  return {
115
130
  runs: this.sortedRuns(),
@@ -122,7 +137,7 @@ export class EvalRunStore {
122
137
  }
123
138
 
124
139
  async start(input: StartEvalRunInput = {}): Promise<EvalRunSnapshot> {
125
- await this.ensureHydrated();
140
+ await this.hydrate();
126
141
  if (this.activeRunId !== undefined) {
127
142
  const active = this.runs.get(this.activeRunId);
128
143
  if (active !== undefined && active.status === "running") {
@@ -160,12 +175,15 @@ export class EvalRunStore {
160
175
  done: 0,
161
176
  },
162
177
  cases,
163
- config: snapshotRunConfig(config),
178
+ config: snapshotRunConfig(
179
+ config,
180
+ this.resolvePersist(config) !== undefined
181
+ ),
164
182
  };
165
183
  this.runs.set(runId, snapshot);
166
184
  this.activeRunId = runId;
167
185
  await this.pruneOldRuns(config);
168
- await this.enqueuePersist(snapshot, config.persistRuns);
186
+ await this.enqueuePersist(snapshot, this.resolvePersist(config));
169
187
  this.logger(
170
188
  `[agent-serve] eval run ${runId}: starting ${cases.length} case(s)`
171
189
  );
@@ -189,7 +207,14 @@ export class EvalRunStore {
189
207
  );
190
208
  }
191
209
 
192
- private async ensureHydrated(): Promise<void> {
210
+ /**
211
+ * Hydrate playground eval history from durable persistence
212
+ * (`evals.config.ts` `persistRuns`, else the `defineStorage`
213
+ * fallback). Called eagerly from the serve startup restore step —
214
+ * alongside session restore — and lazily as a safety net by every read.
215
+ * Idempotent; concurrent callers share one pass.
216
+ */
217
+ async hydrate(): Promise<void> {
193
218
  if (this.hydrated) {
194
219
  return;
195
220
  }
@@ -202,7 +227,7 @@ export class EvalRunStore {
202
227
  private async hydrateFromPersistence(): Promise<void> {
203
228
  try {
204
229
  const { config } = await discoverEvals(this.projectRoot);
205
- const persist = config.persistRuns;
230
+ const persist = this.resolvePersist(config);
206
231
  if (persist === undefined) {
207
232
  this.hydrated = true;
208
233
  return;
@@ -260,7 +285,7 @@ export class EvalRunStore {
260
285
  continue;
261
286
  }
262
287
  this.runs.delete(stale.runId);
263
- await this.persistDelete(stale.runId, config.persistRuns);
288
+ await this.persistDelete(stale.runId, this.resolvePersist(config));
264
289
  }
265
290
  }
266
291
 
@@ -375,7 +400,8 @@ export class EvalRunStore {
375
400
  }
376
401
  if (
377
402
  event.type === "message.completed" &&
378
- typeof event.data?.text === "string"
403
+ typeof event.data?.text === "string" &&
404
+ event.data.parentCallId === undefined
379
405
  ) {
380
406
  c.finalText = event.data.text;
381
407
  }
@@ -384,7 +410,7 @@ export class EvalRunStore {
384
410
  this.applyCaseResult(runId, result);
385
411
  const run = this.runs.get(runId);
386
412
  if (run !== undefined) {
387
- void this.enqueuePersist(run, opts.config.persistRuns);
413
+ void this.enqueuePersist(run, this.resolvePersist(opts.config));
388
414
  }
389
415
  },
390
416
  });
@@ -394,7 +420,7 @@ export class EvalRunStore {
394
420
  }
395
421
  run.status = "completed";
396
422
  run.finishedAt = new Date().toISOString();
397
- await this.enqueuePersist(run, opts.config.persistRuns);
423
+ await this.enqueuePersist(run, this.resolvePersist(opts.config));
398
424
  this.logger(
399
425
  `[agent-serve] eval run ${runId}: done — ${run.summary.passed} passed, ${run.summary.failed} failed`
400
426
  );
@@ -406,7 +432,7 @@ export class EvalRunStore {
406
432
  run.status = "failed";
407
433
  run.finishedAt = new Date().toISOString();
408
434
  run.error = error instanceof Error ? error.message : String(error);
409
- await this.enqueuePersist(run, opts.config.persistRuns);
435
+ await this.enqueuePersist(run, this.resolvePersist(opts.config));
410
436
  this.logger(`[agent-serve] eval run ${runId}: failed — ${run.error}`);
411
437
  } finally {
412
438
  if (this.activeRunId === runId) {
@@ -467,21 +493,25 @@ function markInterruptedRun(run: EvalRunSnapshot): void {
467
493
  }
468
494
  }
469
495
 
470
- function snapshotListConfig(config: Partial<EvalConfigFile>): EvalListConfig {
496
+ function snapshotListConfig(
497
+ config: Partial<EvalConfigFile>,
498
+ durableRuns: boolean
499
+ ): EvalListConfig {
471
500
  return {
472
501
  ...(config.maxConcurrency === undefined
473
502
  ? {}
474
503
  : { maxConcurrency: config.maxConcurrency }),
475
504
  ...(config.timeoutMs === undefined ? {} : { timeoutMs: config.timeoutMs }),
476
505
  maxPlaygroundRuns: resolveEvalMaxPlaygroundRuns(config.maxPlaygroundRuns),
477
- durableRuns: config.persistRuns !== undefined,
506
+ durableRuns,
478
507
  };
479
508
  }
480
509
 
481
510
  function snapshotRunConfig(
482
- config: Partial<EvalConfigFile>
511
+ config: Partial<EvalConfigFile>,
512
+ durableRuns: boolean
483
513
  ): EvalRunSnapshot["config"] {
484
- const list = snapshotListConfig(config);
514
+ const list = snapshotListConfig(config, durableRuns);
485
515
  return {
486
516
  ...(list.maxConcurrency === undefined
487
517
  ? {}
@@ -76,6 +76,8 @@ export interface RunEvalsOptions extends EvalSelectionOptions {
76
76
  baseUrl: string;
77
77
  timeoutMs?: number;
78
78
  bearerToken?: string;
79
+ /** Extra request headers (e.g. hosted engineAccess). */
80
+ headers?: Record<string, string>;
79
81
  verbose?: boolean;
80
82
  onEvent?: (event: SessionEvent) => void;
81
83
  /** Fired when a case begins executing (after concurrency slot acquired). */
@@ -240,6 +242,7 @@ export async function runDiscoveredEvals(
240
242
  baseUrl: options.baseUrl,
241
243
  defaultTimeoutMs,
242
244
  bearerToken: options.bearerToken,
245
+ headers: options.headers,
243
246
  verbose: Boolean(options.verbose),
244
247
  onEvent: (event) => {
245
248
  options.onCaseEvent?.(discovered.id, event);
@@ -268,6 +271,7 @@ async function runOneEval(
268
271
  baseUrl: string;
269
272
  defaultTimeoutMs: number;
270
273
  bearerToken?: string;
274
+ headers?: Record<string, string>;
271
275
  verbose: boolean;
272
276
  onEvent?: (event: SessionEvent) => void;
273
277
  }
@@ -330,6 +334,7 @@ async function runOneEval(
330
334
  // Keep defineEval traffic out of live defineAB enrollment/metrics.
331
335
  purpose: "eval",
332
336
  bearerToken: opts.bearerToken,
337
+ headers: opts.headers,
333
338
  workspaceDir: options.workspaceDir,
334
339
  workspaceFiles: options.workspaceFiles,
335
340
  timeoutMs,