@paperclipai/server 2026.824.0 → 2026.825.0-beta.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 (519) hide show
  1. package/dist/adapters/builtin-adapter-types.d.ts.map +1 -1
  2. package/dist/adapters/builtin-adapter-types.js +1 -0
  3. package/dist/adapters/builtin-adapter-types.js.map +1 -1
  4. package/dist/adapters/plugin-loader.d.ts +1 -0
  5. package/dist/adapters/plugin-loader.d.ts.map +1 -1
  6. package/dist/adapters/plugin-loader.js +12 -1
  7. package/dist/adapters/plugin-loader.js.map +1 -1
  8. package/dist/adapters/plugin-loader.test.d.ts +2 -0
  9. package/dist/adapters/plugin-loader.test.d.ts.map +1 -0
  10. package/dist/adapters/plugin-loader.test.js +37 -0
  11. package/dist/adapters/plugin-loader.test.js.map +1 -0
  12. package/dist/adapters/registry.d.ts.map +1 -1
  13. package/dist/adapters/registry.js +68 -5
  14. package/dist/adapters/registry.js.map +1 -1
  15. package/dist/adapters/registry.test.d.ts +2 -0
  16. package/dist/adapters/registry.test.d.ts.map +1 -0
  17. package/dist/adapters/registry.test.js +35 -0
  18. package/dist/adapters/registry.test.js.map +1 -0
  19. package/dist/app.d.ts.map +1 -1
  20. package/dist/app.js +5 -7
  21. package/dist/app.js.map +1 -1
  22. package/dist/auth/better-auth.d.ts +10 -0
  23. package/dist/auth/better-auth.d.ts.map +1 -1
  24. package/dist/auth/better-auth.js +47 -0
  25. package/dist/auth/better-auth.js.map +1 -1
  26. package/dist/auth/workspace-login-handoff-exchange.d.ts +75 -0
  27. package/dist/auth/workspace-login-handoff-exchange.d.ts.map +1 -0
  28. package/dist/auth/workspace-login-handoff-exchange.js +73 -0
  29. package/dist/auth/workspace-login-handoff-exchange.js.map +1 -0
  30. package/dist/auth/workspace-login-handoff-plugin.d.ts +40 -0
  31. package/dist/auth/workspace-login-handoff-plugin.d.ts.map +1 -0
  32. package/dist/auth/workspace-login-handoff-plugin.js +140 -0
  33. package/dist/auth/workspace-login-handoff-plugin.js.map +1 -0
  34. package/dist/auth/workspace-login-handoff.d.ts +189 -0
  35. package/dist/auth/workspace-login-handoff.d.ts.map +1 -0
  36. package/dist/auth/workspace-login-handoff.js +319 -0
  37. package/dist/auth/workspace-login-handoff.js.map +1 -0
  38. package/dist/build-info.json +3 -0
  39. package/dist/config.d.ts +1 -0
  40. package/dist/config.d.ts.map +1 -1
  41. package/dist/config.js +14 -0
  42. package/dist/config.js.map +1 -1
  43. package/dist/dev-runner-worktree.d.ts.map +1 -1
  44. package/dist/dev-runner-worktree.js +5 -0
  45. package/dist/dev-runner-worktree.js.map +1 -1
  46. package/dist/duplex-aggregate-ceiling-env.d.ts +21 -0
  47. package/dist/duplex-aggregate-ceiling-env.d.ts.map +1 -0
  48. package/dist/duplex-aggregate-ceiling-env.js +23 -0
  49. package/dist/duplex-aggregate-ceiling-env.js.map +1 -0
  50. package/dist/embedded-postgres-supervisor.d.ts +27 -0
  51. package/dist/embedded-postgres-supervisor.d.ts.map +1 -0
  52. package/dist/embedded-postgres-supervisor.js +72 -0
  53. package/dist/embedded-postgres-supervisor.js.map +1 -0
  54. package/dist/errors.d.ts +2 -0
  55. package/dist/errors.d.ts.map +1 -1
  56. package/dist/errors.js +6 -0
  57. package/dist/errors.js.map +1 -1
  58. package/dist/index.d.ts.map +1 -1
  59. package/dist/index.js +115 -7
  60. package/dist/index.js.map +1 -1
  61. package/dist/instrumentation.d.ts +33 -0
  62. package/dist/instrumentation.d.ts.map +1 -1
  63. package/dist/instrumentation.js +68 -1
  64. package/dist/instrumentation.js.map +1 -1
  65. package/dist/middleware/auth.d.ts.map +1 -1
  66. package/dist/middleware/auth.js +35 -10
  67. package/dist/middleware/auth.js.map +1 -1
  68. package/dist/middleware/error-handler.d.ts.map +1 -1
  69. package/dist/middleware/error-handler.js +8 -1
  70. package/dist/middleware/error-handler.js.map +1 -1
  71. package/dist/middleware/logger.d.ts.map +1 -1
  72. package/dist/middleware/logger.js +5 -2
  73. package/dist/middleware/logger.js.map +1 -1
  74. package/dist/middleware/redact-sensitive.d.ts.map +1 -1
  75. package/dist/middleware/redact-sensitive.js +4 -0
  76. package/dist/middleware/redact-sensitive.js.map +1 -1
  77. package/dist/middleware/validate.d.ts +3 -1
  78. package/dist/middleware/validate.d.ts.map +1 -1
  79. package/dist/middleware/validate.js +37 -0
  80. package/dist/middleware/validate.js.map +1 -1
  81. package/dist/routes/access.d.ts.map +1 -1
  82. package/dist/routes/access.js +20 -0
  83. package/dist/routes/access.js.map +1 -1
  84. package/dist/routes/activity.js +4 -4
  85. package/dist/routes/activity.js.map +1 -1
  86. package/dist/routes/adapter-login-route-spine.d.ts +81 -0
  87. package/dist/routes/adapter-login-route-spine.d.ts.map +1 -0
  88. package/dist/routes/adapter-login-route-spine.js +40 -0
  89. package/dist/routes/adapter-login-route-spine.js.map +1 -0
  90. package/dist/routes/adapters.d.ts +33 -0
  91. package/dist/routes/adapters.d.ts.map +1 -1
  92. package/dist/routes/adapters.js +35 -1
  93. package/dist/routes/adapters.js.map +1 -1
  94. package/dist/routes/adapters.test.d.ts +2 -0
  95. package/dist/routes/adapters.test.d.ts.map +1 -0
  96. package/dist/routes/adapters.test.js +58 -0
  97. package/dist/routes/adapters.test.js.map +1 -0
  98. package/dist/routes/agents.d.ts.map +1 -1
  99. package/dist/routes/agents.js +281 -91
  100. package/dist/routes/agents.js.map +1 -1
  101. package/dist/routes/cases.d.ts +11 -22
  102. package/dist/routes/cases.d.ts.map +1 -1
  103. package/dist/routes/cases.js +13 -13
  104. package/dist/routes/companies.js +3 -3
  105. package/dist/routes/decision-training.js +6 -6
  106. package/dist/routes/decisions.js +4 -4
  107. package/dist/routes/decisions.js.map +1 -1
  108. package/dist/routes/environments.d.ts.map +1 -1
  109. package/dist/routes/environments.js +79 -6
  110. package/dist/routes/environments.js.map +1 -1
  111. package/dist/routes/execution-workspaces.d.ts.map +1 -1
  112. package/dist/routes/execution-workspaces.js +384 -16
  113. package/dist/routes/execution-workspaces.js.map +1 -1
  114. package/dist/routes/file-resources.js +2 -2
  115. package/dist/routes/health.d.ts.map +1 -1
  116. package/dist/routes/health.js +58 -4
  117. package/dist/routes/health.js.map +1 -1
  118. package/dist/routes/instance-settings.d.ts.map +1 -1
  119. package/dist/routes/instance-settings.js +40 -0
  120. package/dist/routes/instance-settings.js.map +1 -1
  121. package/dist/routes/issues.d.ts +10 -0
  122. package/dist/routes/issues.d.ts.map +1 -1
  123. package/dist/routes/issues.js +495 -65
  124. package/dist/routes/issues.js.map +1 -1
  125. package/dist/routes/openapi.d.ts.map +1 -1
  126. package/dist/routes/openapi.js +241 -122
  127. package/dist/routes/openapi.js.map +1 -1
  128. package/dist/routes/pipelines.js +19 -19
  129. package/dist/routes/plugins.d.ts.map +1 -1
  130. package/dist/routes/plugins.js +22 -0
  131. package/dist/routes/plugins.js.map +1 -1
  132. package/dist/routes/projects.d.ts.map +1 -1
  133. package/dist/routes/projects.js +2 -0
  134. package/dist/routes/projects.js.map +1 -1
  135. package/dist/routes/routines.js +2 -2
  136. package/dist/routes/routines.js.map +1 -1
  137. package/dist/routes/secrets.d.ts +1 -1
  138. package/dist/routes/secrets.d.ts.map +1 -1
  139. package/dist/routes/secrets.js +39 -50
  140. package/dist/routes/secrets.js.map +1 -1
  141. package/dist/routes/setup-token-route.test.js +50 -3
  142. package/dist/routes/setup-token-route.test.js.map +1 -1
  143. package/dist/services/adapter-login-lease.d.ts +50 -0
  144. package/dist/services/adapter-login-lease.d.ts.map +1 -0
  145. package/dist/services/adapter-login-lease.js +26 -0
  146. package/dist/services/adapter-login-lease.js.map +1 -0
  147. package/dist/services/adapter-login-lease.test.d.ts +2 -0
  148. package/dist/services/adapter-login-lease.test.d.ts.map +1 -0
  149. package/dist/services/adapter-login-lease.test.js +68 -0
  150. package/dist/services/adapter-login-lease.test.js.map +1 -0
  151. package/dist/services/agent-action-audit.js +1 -1
  152. package/dist/services/agent-secret-bindings.d.ts +15 -0
  153. package/dist/services/agent-secret-bindings.d.ts.map +1 -1
  154. package/dist/services/agent-secret-bindings.js +2 -2
  155. package/dist/services/agent-secret-bindings.js.map +1 -1
  156. package/dist/services/agents.d.ts +13 -13
  157. package/dist/services/agents.d.ts.map +1 -1
  158. package/dist/services/agents.js +46 -5
  159. package/dist/services/agents.js.map +1 -1
  160. package/dist/services/artifact-review-documents.d.ts +34 -0
  161. package/dist/services/artifact-review-documents.d.ts.map +1 -0
  162. package/dist/services/artifact-review-documents.js +196 -0
  163. package/dist/services/artifact-review-documents.js.map +1 -0
  164. package/dist/services/assets.d.ts +1 -1
  165. package/dist/services/codex-device-login-credential-read.d.ts +58 -0
  166. package/dist/services/codex-device-login-credential-read.d.ts.map +1 -0
  167. package/dist/services/codex-device-login-credential-read.js +118 -0
  168. package/dist/services/codex-device-login-credential-read.js.map +1 -0
  169. package/dist/services/codex-device-login-reaper.d.ts.map +1 -1
  170. package/dist/services/codex-device-login-reaper.js +8 -5
  171. package/dist/services/codex-device-login-reaper.js.map +1 -1
  172. package/dist/services/codex-device-login-service.d.ts +127 -36
  173. package/dist/services/codex-device-login-service.d.ts.map +1 -1
  174. package/dist/services/codex-device-login-service.js +204 -84
  175. package/dist/services/codex-device-login-service.js.map +1 -1
  176. package/dist/services/company-portability.d.ts +3 -1
  177. package/dist/services/company-portability.d.ts.map +1 -1
  178. package/dist/services/company-portability.js +76 -20
  179. package/dist/services/company-portability.js.map +1 -1
  180. package/dist/services/company-skill-policy.d.ts +1 -1
  181. package/dist/services/costs.d.ts +1 -1
  182. package/dist/services/decisions.d.ts +6 -6
  183. package/dist/services/duplex-observability-recorder.d.ts +62 -0
  184. package/dist/services/duplex-observability-recorder.d.ts.map +1 -0
  185. package/dist/services/duplex-observability-recorder.js +54 -0
  186. package/dist/services/duplex-observability-recorder.js.map +1 -0
  187. package/dist/services/environment-config.js +5 -5
  188. package/dist/services/environment-config.js.map +1 -1
  189. package/dist/services/environment-custom-image-runtime.d.ts +116 -0
  190. package/dist/services/environment-custom-image-runtime.d.ts.map +1 -1
  191. package/dist/services/environment-custom-image-runtime.js +255 -1
  192. package/dist/services/environment-custom-image-runtime.js.map +1 -1
  193. package/dist/services/environment-custom-images.d.ts +39 -0
  194. package/dist/services/environment-custom-images.d.ts.map +1 -1
  195. package/dist/services/environment-custom-images.js +219 -17
  196. package/dist/services/environment-custom-images.js.map +1 -1
  197. package/dist/services/environment-driver-traits.d.ts +109 -0
  198. package/dist/services/environment-driver-traits.d.ts.map +1 -0
  199. package/dist/services/environment-driver-traits.js +102 -0
  200. package/dist/services/environment-driver-traits.js.map +1 -0
  201. package/dist/services/environment-execution-target.d.ts +4 -0
  202. package/dist/services/environment-execution-target.d.ts.map +1 -1
  203. package/dist/services/environment-execution-target.js +63 -7
  204. package/dist/services/environment-execution-target.js.map +1 -1
  205. package/dist/services/environment-run-orchestrator.d.ts +27 -1
  206. package/dist/services/environment-run-orchestrator.d.ts.map +1 -1
  207. package/dist/services/environment-run-orchestrator.js +24 -4
  208. package/dist/services/environment-run-orchestrator.js.map +1 -1
  209. package/dist/services/environment-runtime.d.ts +118 -20
  210. package/dist/services/environment-runtime.d.ts.map +1 -1
  211. package/dist/services/environment-runtime.js +436 -91
  212. package/dist/services/environment-runtime.js.map +1 -1
  213. package/dist/services/environments.d.ts.map +1 -1
  214. package/dist/services/environments.js +20 -2
  215. package/dist/services/environments.js.map +1 -1
  216. package/dist/services/execution-workspace-branch-ownership.d.ts +4 -0
  217. package/dist/services/execution-workspace-branch-ownership.d.ts.map +1 -0
  218. package/dist/services/execution-workspace-branch-ownership.js +9 -0
  219. package/dist/services/execution-workspace-branch-ownership.js.map +1 -0
  220. package/dist/services/execution-workspace-policy.d.ts.map +1 -1
  221. package/dist/services/execution-workspace-policy.js +3 -0
  222. package/dist/services/execution-workspace-policy.js.map +1 -1
  223. package/dist/services/execution-workspaces.d.ts +2 -0
  224. package/dist/services/execution-workspaces.d.ts.map +1 -1
  225. package/dist/services/execution-workspaces.js +90 -2
  226. package/dist/services/execution-workspaces.js.map +1 -1
  227. package/dist/services/external-objects.d.ts +19 -19
  228. package/dist/services/finance.d.ts +1 -1
  229. package/dist/services/goals.d.ts +2 -2
  230. package/dist/services/heartbeat-policy.d.ts +3 -0
  231. package/dist/services/heartbeat-policy.d.ts.map +1 -0
  232. package/dist/services/heartbeat-policy.js +10 -0
  233. package/dist/services/heartbeat-policy.js.map +1 -0
  234. package/dist/services/heartbeat-run-runtime-status.test.js +1 -1
  235. package/dist/services/heartbeat-run-runtime-status.test.js.map +1 -1
  236. package/dist/services/heartbeat.d.ts +23 -1
  237. package/dist/services/heartbeat.d.ts.map +1 -1
  238. package/dist/services/heartbeat.js +192 -11
  239. package/dist/services/heartbeat.js.map +1 -1
  240. package/dist/services/index.d.ts +1 -0
  241. package/dist/services/index.d.ts.map +1 -1
  242. package/dist/services/index.js +1 -0
  243. package/dist/services/index.js.map +1 -1
  244. package/dist/services/instance-settings.d.ts.map +1 -1
  245. package/dist/services/instance-settings.js +2 -0
  246. package/dist/services/instance-settings.js.map +1 -1
  247. package/dist/services/issue-dependency-wakeups.d.ts +57 -9
  248. package/dist/services/issue-dependency-wakeups.d.ts.map +1 -1
  249. package/dist/services/issue-dependency-wakeups.js +146 -14
  250. package/dist/services/issue-dependency-wakeups.js.map +1 -1
  251. package/dist/services/issue-dependency-wakeups.test.d.ts +2 -0
  252. package/dist/services/issue-dependency-wakeups.test.d.ts.map +1 -0
  253. package/dist/services/issue-dependency-wakeups.test.js +183 -0
  254. package/dist/services/issue-dependency-wakeups.test.js.map +1 -0
  255. package/dist/services/issue-recovery-actions.d.ts +6 -1
  256. package/dist/services/issue-recovery-actions.d.ts.map +1 -1
  257. package/dist/services/issue-recovery-actions.js +123 -44
  258. package/dist/services/issue-recovery-actions.js.map +1 -1
  259. package/dist/services/issue-thread-interactions.d.ts +8 -0
  260. package/dist/services/issue-thread-interactions.d.ts.map +1 -1
  261. package/dist/services/issue-thread-interactions.js +220 -10
  262. package/dist/services/issue-thread-interactions.js.map +1 -1
  263. package/dist/services/issues.d.ts +8 -7
  264. package/dist/services/issues.d.ts.map +1 -1
  265. package/dist/services/issues.js +84 -12
  266. package/dist/services/issues.js.map +1 -1
  267. package/dist/services/local-service-supervisor.d.ts +61 -1
  268. package/dist/services/local-service-supervisor.d.ts.map +1 -1
  269. package/dist/services/local-service-supervisor.js +221 -25
  270. package/dist/services/local-service-supervisor.js.map +1 -1
  271. package/dist/services/login-command.d.ts +46 -0
  272. package/dist/services/login-command.d.ts.map +1 -0
  273. package/dist/services/login-command.js +87 -0
  274. package/dist/services/login-command.js.map +1 -0
  275. package/dist/services/login-command.test.d.ts +2 -0
  276. package/dist/services/login-command.test.d.ts.map +1 -0
  277. package/dist/services/login-command.test.js +71 -0
  278. package/dist/services/login-command.test.js.map +1 -0
  279. package/dist/services/managed-workspace-identity.d.ts +140 -0
  280. package/dist/services/managed-workspace-identity.d.ts.map +1 -0
  281. package/dist/services/managed-workspace-identity.js +277 -0
  282. package/dist/services/managed-workspace-identity.js.map +1 -0
  283. package/dist/services/plugin-environment-driver.d.ts +15 -1
  284. package/dist/services/plugin-environment-driver.d.ts.map +1 -1
  285. package/dist/services/plugin-environment-driver.js +23 -1
  286. package/dist/services/plugin-environment-driver.js.map +1 -1
  287. package/dist/services/plugin-host-services.d.ts +3 -2
  288. package/dist/services/plugin-host-services.d.ts.map +1 -1
  289. package/dist/services/plugin-host-services.js +11 -2
  290. package/dist/services/plugin-host-services.js.map +1 -1
  291. package/dist/services/plugin-loader.d.ts.map +1 -1
  292. package/dist/services/plugin-loader.js +39 -8
  293. package/dist/services/plugin-loader.js.map +1 -1
  294. package/dist/services/plugin-managed-agents.d.ts.map +1 -1
  295. package/dist/services/plugin-managed-agents.js +50 -5
  296. package/dist/services/plugin-managed-agents.js.map +1 -1
  297. package/dist/services/plugin-manifest-validator.d.ts.map +1 -1
  298. package/dist/services/plugin-manifest-validator.js +5 -2
  299. package/dist/services/plugin-manifest-validator.js.map +1 -1
  300. package/dist/services/plugin-registry.d.ts +5 -5
  301. package/dist/services/plugin-worker-manager.d.ts +158 -11
  302. package/dist/services/plugin-worker-manager.d.ts.map +1 -1
  303. package/dist/services/plugin-worker-manager.js +1139 -79
  304. package/dist/services/plugin-worker-manager.js.map +1 -1
  305. package/dist/services/projects.d.ts +1 -1
  306. package/dist/services/recovery/disposition-repair.d.ts +24 -0
  307. package/dist/services/recovery/disposition-repair.d.ts.map +1 -0
  308. package/dist/services/recovery/disposition-repair.js +125 -0
  309. package/dist/services/recovery/disposition-repair.js.map +1 -0
  310. package/dist/services/recovery/service.d.ts +6 -6
  311. package/dist/services/recovery/service.d.ts.map +1 -1
  312. package/dist/services/recovery/service.js +856 -384
  313. package/dist/services/recovery/service.js.map +1 -1
  314. package/dist/services/recovery/stranded-notice.js +4 -4
  315. package/dist/services/recovery/stranded-notice.js.map +1 -1
  316. package/dist/services/recovery/stranded-notice.test.js +1 -1
  317. package/dist/services/recovery/stranded-notice.test.js.map +1 -1
  318. package/dist/services/recovery/successful-run-handoff.d.ts +1 -1
  319. package/dist/services/recovery/successful-run-handoff.d.ts.map +1 -1
  320. package/dist/services/recovery/successful-run-handoff.js +6 -4
  321. package/dist/services/recovery/successful-run-handoff.js.map +1 -1
  322. package/dist/services/recovery/successful-run-handoff.test.js +1 -1
  323. package/dist/services/recovery/successful-run-handoff.test.js.map +1 -1
  324. package/dist/services/recovery-observability.d.ts +1 -1
  325. package/dist/services/recovery-observability.d.ts.map +1 -1
  326. package/dist/services/recovery-observability.js +4 -1
  327. package/dist/services/recovery-observability.js.map +1 -1
  328. package/dist/services/routines.d.ts.map +1 -1
  329. package/dist/services/routines.js +86 -1
  330. package/dist/services/routines.js.map +1 -1
  331. package/dist/services/runtime-exposure/loopback-listener.js +1 -1
  332. package/dist/services/runtime-exposure/loopback-listener.js.map +1 -1
  333. package/dist/services/runtime-exposure/loopback-listener.test.js +1 -1
  334. package/dist/services/runtime-exposure/loopback-listener.test.js.map +1 -1
  335. package/dist/services/scripts/codex-auth-read.cjs +93 -0
  336. package/dist/services/secret-proposal-authorization.d.ts +15 -0
  337. package/dist/services/secret-proposal-authorization.d.ts.map +1 -0
  338. package/dist/services/secret-proposal-authorization.js +29 -0
  339. package/dist/services/secret-proposal-authorization.js.map +1 -0
  340. package/dist/services/secret-proposal-notifications.d.ts +18 -0
  341. package/dist/services/secret-proposal-notifications.d.ts.map +1 -0
  342. package/dist/services/secret-proposal-notifications.js +37 -0
  343. package/dist/services/secret-proposal-notifications.js.map +1 -0
  344. package/dist/services/secret-proposals.d.ts +20 -10
  345. package/dist/services/secret-proposals.d.ts.map +1 -1
  346. package/dist/services/secret-proposals.js +205 -14
  347. package/dist/services/secret-proposals.js.map +1 -1
  348. package/dist/services/secrets.d.ts +3 -3
  349. package/dist/services/settings-visibility.d.ts +17 -0
  350. package/dist/services/settings-visibility.d.ts.map +1 -0
  351. package/dist/services/settings-visibility.js +29 -0
  352. package/dist/services/settings-visibility.js.map +1 -0
  353. package/dist/services/setup-token-reaper.d.ts +36 -0
  354. package/dist/services/setup-token-reaper.d.ts.map +1 -0
  355. package/dist/services/setup-token-reaper.js +38 -0
  356. package/dist/services/setup-token-reaper.js.map +1 -0
  357. package/dist/services/setup-token-reaper.test.d.ts +2 -0
  358. package/dist/services/setup-token-reaper.test.d.ts.map +1 -0
  359. package/dist/services/setup-token-reaper.test.js +123 -0
  360. package/dist/services/setup-token-reaper.test.js.map +1 -0
  361. package/dist/services/setup-token-session.d.ts +57 -45
  362. package/dist/services/setup-token-session.d.ts.map +1 -1
  363. package/dist/services/setup-token-session.js +118 -110
  364. package/dist/services/setup-token-session.js.map +1 -1
  365. package/dist/services/setup-token-session.test.js +88 -47
  366. package/dist/services/setup-token-session.test.js.map +1 -1
  367. package/dist/services/setup-token-transport-binding.d.ts +20 -12
  368. package/dist/services/setup-token-transport-binding.d.ts.map +1 -1
  369. package/dist/services/setup-token-transport-binding.js +59 -32
  370. package/dist/services/setup-token-transport-binding.js.map +1 -1
  371. package/dist/services/setup-token-transport-binding.test.js +50 -17
  372. package/dist/services/setup-token-transport-binding.test.js.map +1 -1
  373. package/dist/services/smoke-lab.d.ts +1 -1
  374. package/dist/services/stalled-review-decisions.d.ts +1 -1
  375. package/dist/services/status-cards.d.ts +168 -168
  376. package/dist/services/tool-access-policy.d.ts +2 -2
  377. package/dist/services/tool-gateway.d.ts +1 -1
  378. package/dist/services/work-products.d.ts +19 -0
  379. package/dist/services/work-products.d.ts.map +1 -1
  380. package/dist/services/work-products.js +50 -3
  381. package/dist/services/work-products.js.map +1 -1
  382. package/dist/services/workspace-git-operation-scheduler.test.js +10 -3
  383. package/dist/services/workspace-git-operation-scheduler.test.js.map +1 -1
  384. package/dist/services/workspace-instance-cleanup.d.ts +9 -0
  385. package/dist/services/workspace-instance-cleanup.d.ts.map +1 -1
  386. package/dist/services/workspace-instance-cleanup.js +29 -3
  387. package/dist/services/workspace-instance-cleanup.js.map +1 -1
  388. package/dist/services/workspace-login-handoff-issuer.d.ts +95 -0
  389. package/dist/services/workspace-login-handoff-issuer.d.ts.map +1 -0
  390. package/dist/services/workspace-login-handoff-issuer.js +147 -0
  391. package/dist/services/workspace-login-handoff-issuer.js.map +1 -0
  392. package/dist/services/workspace-operations.d.ts +4 -1
  393. package/dist/services/workspace-operations.d.ts.map +1 -1
  394. package/dist/services/workspace-operations.js +29 -15
  395. package/dist/services/workspace-operations.js.map +1 -1
  396. package/dist/services/workspace-readiness.d.ts +56 -0
  397. package/dist/services/workspace-readiness.d.ts.map +1 -0
  398. package/dist/services/workspace-readiness.js +250 -0
  399. package/dist/services/workspace-readiness.js.map +1 -0
  400. package/dist/services/workspace-realization.d.ts.map +1 -1
  401. package/dist/services/workspace-realization.js +5 -33
  402. package/dist/services/workspace-realization.js.map +1 -1
  403. package/dist/services/workspace-runtime-exposure.test.js +321 -12
  404. package/dist/services/workspace-runtime-exposure.test.js.map +1 -1
  405. package/dist/services/workspace-runtime-leases.d.ts.map +1 -1
  406. package/dist/services/workspace-runtime-leases.js +1 -1
  407. package/dist/services/workspace-runtime-leases.js.map +1 -1
  408. package/dist/services/workspace-runtime-read-model.d.ts +8 -8
  409. package/dist/services/workspace-runtime-read-model.test.js +20 -0
  410. package/dist/services/workspace-runtime-read-model.test.js.map +1 -1
  411. package/dist/services/workspace-runtime-ready-comment.test.js +1 -0
  412. package/dist/services/workspace-runtime-ready-comment.test.js.map +1 -1
  413. package/dist/services/workspace-runtime.d.ts +77 -4
  414. package/dist/services/workspace-runtime.d.ts.map +1 -1
  415. package/dist/services/workspace-runtime.js +1020 -126
  416. package/dist/services/workspace-runtime.js.map +1 -1
  417. package/dist/worktree-config.d.ts.map +1 -1
  418. package/dist/worktree-config.js +3 -76
  419. package/dist/worktree-config.js.map +1 -1
  420. package/dist/worktree-seed-manifest.d.ts +8 -0
  421. package/dist/worktree-seed-manifest.d.ts.map +1 -0
  422. package/dist/worktree-seed-manifest.js +47 -0
  423. package/dist/worktree-seed-manifest.js.map +1 -0
  424. package/package.json +34 -30
  425. package/skills/paperclip/SKILL.md +2 -0
  426. package/skills/paperclip/references/api-reference.md +44 -2
  427. package/ui-dist/assets/CompanyExport-DnEsO-St.js +4 -0
  428. package/ui-dist/assets/{abnfDiagram-N423BO3Z-BvgoV-u5.js → abnfDiagram-N423BO3Z-2ff8TsQ0.js} +1 -1
  429. package/ui-dist/assets/{arc-BInnUBUU.js → arc-B2AXsH34.js} +1 -1
  430. package/ui-dist/assets/architectureDiagram-T3A2C74G-BDxtKMxk.js +36 -0
  431. package/ui-dist/assets/{blockDiagram-VBNYF7ZC-D9kzAkLN.js → blockDiagram-VBNYF7ZC-BB8T5Mj5.js} +1 -1
  432. package/ui-dist/assets/{c4Diagram-5PPSVZJV-BwzsgV_0.js → c4Diagram-5PPSVZJV-lMo8qk-x.js} +1 -1
  433. package/ui-dist/assets/channel-DCTVZpyq.js +1 -0
  434. package/ui-dist/assets/{chunk-2GRJ4B5K-D2EQ9vrl.js → chunk-2GRJ4B5K-CsS7EB3G.js} +1 -1
  435. package/ui-dist/assets/{chunk-2Q5K7J3B-DOA_8fSd.js → chunk-2Q5K7J3B-DFyQPjoR.js} +1 -1
  436. package/ui-dist/assets/{chunk-5RXB4S5H-CT5ukRiT.js → chunk-5RXB4S5H-No2SHOQR.js} +1 -1
  437. package/ui-dist/assets/{chunk-5VM5RSS4-D2gOlkyB.js → chunk-5VM5RSS4-DdxQO7V9.js} +1 -1
  438. package/ui-dist/assets/{chunk-6Q2QTUOP-DUb6aG8c.js → chunk-6Q2QTUOP-gbHjh-aK.js} +1 -1
  439. package/ui-dist/assets/{chunk-GF5L2VYU-BPabG3Cx.js → chunk-GF5L2VYU-h-BBl6NY.js} +1 -1
  440. package/ui-dist/assets/{chunk-JWPE2WC7-scNfhlZz.js → chunk-JWPE2WC7-Q3pJdTz5.js} +1 -1
  441. package/ui-dist/assets/{chunk-KBJHAD2P-BcRAzRpq.js → chunk-KBJHAD2P-Ba8LGLSx.js} +1 -1
  442. package/ui-dist/assets/{chunk-RYQCIY6F-BiZ0-EGh.js → chunk-RYQCIY6F-9VcvykBo.js} +1 -1
  443. package/ui-dist/assets/{chunk-XXDRQBXY-lJULxFIE.js → chunk-XXDRQBXY-NVbjDH4W.js} +1 -1
  444. package/ui-dist/assets/classDiagram-JCYQIIEL-CzJ88u6h.js +1 -0
  445. package/ui-dist/assets/classDiagram-v2-OCEON4UE-CzJ88u6h.js +1 -0
  446. package/ui-dist/assets/cose-bilkent-JH36ORCC-Cdz4wtUh.js +1 -0
  447. package/ui-dist/assets/{cynefin-VYW2F7L2-B34jJY1x.js → cynefin-VYW2F7L2-MpzJkW5s.js} +1 -1
  448. package/ui-dist/assets/{cynefinDiagram-MW4NZA55-DQ8QK8JK.js → cynefinDiagram-MW4NZA55-_Nx8av7i.js} +1 -1
  449. package/ui-dist/assets/{dagre-VZM6K2ZE-B7lSKgxH.js → dagre-VZM6K2ZE-DcZTQ4Oh.js} +1 -1
  450. package/ui-dist/assets/{diagram-7IWD3JNH-B3hLAFGE.js → diagram-7IWD3JNH-UyLi2mee.js} +1 -1
  451. package/ui-dist/assets/{diagram-B4RE2ZJO-CH9Ro9e0.js → diagram-B4RE2ZJO-B6p0Ivqg.js} +1 -1
  452. package/ui-dist/assets/{diagram-LBJQPF4R-DdPVMii7.js → diagram-LBJQPF4R-C8u6pa97.js} +1 -1
  453. package/ui-dist/assets/{diagram-Q27KOJAE-f5VXswjc.js → diagram-Q27KOJAE-DbwyagW0.js} +1 -1
  454. package/ui-dist/assets/{diagram-UB23O5K3-DGqxixsR.js → diagram-UB23O5K3-Cn5BMEH7.js} +1 -1
  455. package/ui-dist/assets/{ebnfDiagram-BXEA7PRR-C-1klg_w.js → ebnfDiagram-BXEA7PRR-vE0IZma9.js} +1 -1
  456. package/ui-dist/assets/{erDiagram-JOGREHBK-Dt4qK4gv.js → erDiagram-JOGREHBK-3OZVIlVG.js} +1 -1
  457. package/ui-dist/assets/{flowDiagram-UKHOOZJN-9ZlrTuET.js → flowDiagram-UKHOOZJN-C94FiPyr.js} +1 -1
  458. package/ui-dist/assets/ganttDiagram-PKOTCBZU-DMVaPmF-.js +292 -0
  459. package/ui-dist/assets/{gitGraphDiagram-DS77QQ5N-HH2fSgad.js → gitGraphDiagram-DS77QQ5N-yeFtJ689.js} +1 -1
  460. package/ui-dist/assets/{index-Cm6iEYPt.js → index-B4ZF3vY8.js} +288 -224
  461. package/ui-dist/assets/{index-CHXG4GPL.js → index-Bi_vqkcQ.js} +1 -1
  462. package/ui-dist/assets/{index-Bc9g6q63.js → index-BjDGQg9-.js} +1 -1
  463. package/ui-dist/assets/{index-FHzrJ7iQ.js → index-BnpyUMTb.js} +1 -1
  464. package/ui-dist/assets/{index-C1mpWCcn.js → index-BoqQTVMA.js} +1 -1
  465. package/ui-dist/assets/index-Bq-Mr-4x.js +1 -0
  466. package/ui-dist/assets/{index-DceuCrr8.js → index-Brb2U7N4.js} +1 -1
  467. package/ui-dist/assets/{index-DQIrrn2L.js → index-BsBybVwH.js} +1 -1
  468. package/ui-dist/assets/{index-CQhaM6qd.js → index-C2iv4Wgu.js} +1 -1
  469. package/ui-dist/assets/{index-DV2FOgyD.js → index-CKxIu7uO.js} +1 -1
  470. package/ui-dist/assets/{index-DU4U1fuv.js → index-Cb4VGIwp.js} +1 -1
  471. package/ui-dist/assets/{index-B61ORkIb.js → index-ChpszwcO.js} +1 -1
  472. package/ui-dist/assets/{index-DlVBBF8o.js → index-CoQFdT8N.js} +1 -1
  473. package/ui-dist/assets/index-D6P8_f0W.css +1 -0
  474. package/ui-dist/assets/index-DKdmghUG.js +1 -0
  475. package/ui-dist/assets/{index-CVTL3aAL.js → index-DaBci7Bx.js} +1 -1
  476. package/ui-dist/assets/{index-diFs0CNC.js → index-DjYaNiXZ.js} +1 -1
  477. package/ui-dist/assets/{index-Bf7tyGxE.js → index-DxTBJl4h.js} +1 -1
  478. package/ui-dist/assets/{index-DsdVneqe.js → index-Dz3E8nn0.js} +1 -1
  479. package/ui-dist/assets/{index-DvFUXI-Q.js → index-J7dz_hap.js} +1 -1
  480. package/ui-dist/assets/{index-CLu3Tfpv.js → index-JMp2Gpnz.js} +1 -1
  481. package/ui-dist/assets/{index-CcRTJ93J.js → index-Kp6wavQt.js} +1 -1
  482. package/ui-dist/assets/{index-BvFx-4KW.js → index-LBhYZ0L4.js} +1 -1
  483. package/ui-dist/assets/{index-BbAhzCq8.js → index-c3C0P6l8.js} +4 -4
  484. package/ui-dist/assets/{index-BY5ITKmG.js → index-pBEPheTW.js} +1 -1
  485. package/ui-dist/assets/{infoDiagram-6WML65LV-2jai2fw-.js → infoDiagram-6WML65LV-BiL7jKLA.js} +1 -1
  486. package/ui-dist/assets/{ishikawaDiagram-WSZJBQD7-CUmGhmEb.js → ishikawaDiagram-WSZJBQD7-DYcQy41D.js} +1 -1
  487. package/ui-dist/assets/{journeyDiagram-NVQOT4AX-CGQuPDO1.js → journeyDiagram-NVQOT4AX-Bxva6JgA.js} +1 -1
  488. package/ui-dist/assets/{kanban-definition-27J2QSJJ-zgEPcbHl.js → kanban-definition-27J2QSJJ-B2HpN34Q.js} +1 -1
  489. package/ui-dist/assets/{linear-BVf5VtLS.js → linear-Dq8qSESw.js} +1 -1
  490. package/ui-dist/assets/{mermaid.core-D2TFkGfI.js → mermaid.core-Ikay8Cpl.js} +35 -35
  491. package/ui-dist/assets/{mindmap-definition-FAOFIHXS-xoAQ0Lb_.js → mindmap-definition-FAOFIHXS-C-SIdYSY.js} +1 -1
  492. package/ui-dist/assets/{pegDiagram-VL7TDLO6-CBR1PWLr.js → pegDiagram-VL7TDLO6-C7rIJ_13.js} +1 -1
  493. package/ui-dist/assets/{pieDiagram-7S7Q4E2Y-BMPnzK_e.js → pieDiagram-7S7Q4E2Y-3gx0a0ve.js} +1 -1
  494. package/ui-dist/assets/{quadrantDiagram-CIZ2JOQS-CPtVUPkR.js → quadrantDiagram-CIZ2JOQS-BiwM9QGv.js} +1 -1
  495. package/ui-dist/assets/{railroadDiagram-AXF67PYL-DC0lsZV1.js → railroadDiagram-AXF67PYL-rFS8XcFA.js} +1 -1
  496. package/ui-dist/assets/{requirementDiagram-LRYGKXZP-BF6k05SB.js → requirementDiagram-LRYGKXZP-CEAUDUTQ.js} +1 -1
  497. package/ui-dist/assets/{sankeyDiagram-W5VNT64P-CRN0ibiP.js → sankeyDiagram-W5VNT64P-B7anpjlM.js} +1 -1
  498. package/ui-dist/assets/{sequenceDiagram-SI44F4Z6-CQtTiPWm.js → sequenceDiagram-SI44F4Z6-CJEdJvm_.js} +1 -1
  499. package/ui-dist/assets/{sizeCapture-X5ZJPWSS-BdjuGZd1.js → sizeCapture-X5ZJPWSS-CU1Vm6c1.js} +1 -1
  500. package/ui-dist/assets/{stateDiagram-OKZ733FA-B99onxyh.js → stateDiagram-OKZ733FA-wxVV9WIi.js} +1 -1
  501. package/ui-dist/assets/stateDiagram-v2-UEYNNEHI-BIFLqlqR.js +1 -0
  502. package/ui-dist/assets/{swimlanes-SLNWSIFB-BIByPbrL.js → swimlanes-SLNWSIFB-Cd-C1Z_k.js} +2 -2
  503. package/ui-dist/assets/swimlanesDiagram-ULZ7WXOC-CoBROkkd.js +8 -0
  504. package/ui-dist/assets/{timeline-definition-Z64GVDOM-I1NgOcn9.js → timeline-definition-Z64GVDOM-SWngk4aR.js} +1 -1
  505. package/ui-dist/assets/{vennDiagram-T6HMQDX7-D6t2Njcl.js → vennDiagram-T6HMQDX7-DFdPUr36.js} +1 -1
  506. package/ui-dist/assets/{wardleyDiagram-T6FBY63Y-BiYKm9gh.js → wardleyDiagram-T6FBY63Y-C6IlrZ7t.js} +1 -1
  507. package/ui-dist/assets/{xychartDiagram-ELKLHX3M-BhwXKWIa.js → xychartDiagram-ELKLHX3M-BNm6hHGl.js} +1 -1
  508. package/ui-dist/index.html +2 -2
  509. package/ui-dist/assets/architectureDiagram-T3A2C74G-Dg4MziOm.js +0 -36
  510. package/ui-dist/assets/channel-qoSYbCn0.js +0 -1
  511. package/ui-dist/assets/classDiagram-JCYQIIEL-B24u1REs.js +0 -1
  512. package/ui-dist/assets/classDiagram-v2-OCEON4UE-B24u1REs.js +0 -1
  513. package/ui-dist/assets/cose-bilkent-JH36ORCC-Do8pe8JB.js +0 -1
  514. package/ui-dist/assets/ganttDiagram-PKOTCBZU-CE3lyvFq.js +0 -292
  515. package/ui-dist/assets/index-BHiUiToL.css +0 -1
  516. package/ui-dist/assets/index-hkanj4t6.js +0 -1
  517. package/ui-dist/assets/index-yRJnh4vx.js +0 -1
  518. package/ui-dist/assets/stateDiagram-v2-UEYNNEHI-bzFlYBZ1.js +0 -1
  519. package/ui-dist/assets/swimlanesDiagram-ULZ7WXOC-DgdkBnuK.js +0 -8
@@ -3,7 +3,7 @@ import { generateKeyPairSync, randomUUID } from "node:crypto";
3
3
  import path from "node:path";
4
4
  import { agents as agentsTable, companies, heartbeatRuns, issues as issuesTable, projects as projectsTable } from "@paperclipai/db";
5
5
  import { and, desc, eq, inArray, not, sql } from "drizzle-orm";
6
- import { agentSkillSyncSchema, agentMineInboxQuerySchema, ADAPTER_AGNOSTIC_KEYS, AGENT_DEFAULT_MAX_CONCURRENT_RUNS, createAgentKeySchema, createAgentHireSchema, createAgentSchema, deriveAgentUrlKey, isUuidLike, normalizeIssueIdentifier, resetAgentSessionSchema, testAdapterEnvironmentSchema, upsertAgentInstructionsFileSchema, updateAgentInstructionsBundleSchema, updateAgentPermissionsSchema, updateAgentInstructionsPathSchema, wakeAgentSchema, updateAgentSchema, supportedEnvironmentDriversForAdapter, LOW_TRUST_REVIEW_PRESET, startClaudeSetupTokenSessionRequestSchema, submitBrowserCodeRequestSchema, } from "@paperclipai/shared";
6
+ import { agentSkillSyncSchema, agentMineInboxQuerySchema, ADAPTER_AGNOSTIC_KEYS, AGENT_DEFAULT_MAX_CONCURRENT_RUNS, createAgentKeySchema, createAgentHireSchema, createAgentSchema, deriveAgentUrlKey, isUuidLike, normalizeIssueIdentifier, resetAgentSessionSchema, testAdapterEnvironmentSchema, upsertAgentInstructionsFileSchema, updateAgentInstructionsBundleSchema, updateAgentPermissionsSchema, updateAgentInstructionsPathSchema, wakeAgentSchema, updateAgentSchema, supportedEnvironmentDriversForAdapter, LOW_TRUST_REVIEW_PRESET, startAdapterAuthSessionRequestSchema, startClaudeSetupTokenSessionRequestSchema, submitBrowserCodeRequestSchema, } from "@paperclipai/shared";
7
7
  import { isForbiddenConfigEnvKey, parseObject, resolvePaperclipInstanceRootForAdapter, readPaperclipSkillSyncPreference, writePaperclipSkillSyncPreference, } from "@paperclipai/adapter-utils/server-utils";
8
8
  import { trackAgentCreated } from "@paperclipai/shared/telemetry";
9
9
  import { validate } from "../middleware/validate.js";
@@ -11,6 +11,8 @@ import { agentService, agentInstructionsService, accessService, approvalService,
11
11
  import { badRequest, conflict, forbidden, HttpError, notFound, unprocessable } from "../errors.js";
12
12
  import { createRunSecretRedactionRegistry } from "../services/run-secret-redaction.js";
13
13
  import { assertAuthenticated, assertBoard, assertCompanyAccess, assertInstanceAdmin, buildActorSecretContext, getAccessibleResource, getActorInfo, hasCompanyAccess } from "./authz.js";
14
+ import { runAdapterLoginStartSpine } from "./adapter-login-route-spine.js";
15
+ import { isLoginCommandSupportedAdapterType } from "../services/login-command.js";
14
16
  import { assertNoAgentHostWorkspaceCommandMutation, collectAgentAdapterWorkspaceCommandPaths, } from "./workspace-command-authz.js";
15
17
  import { environmentService } from "../services/environments.js";
16
18
  import { resolveEnvironmentExecutionTarget } from "../services/environment-execution-target.js";
@@ -31,9 +33,10 @@ import { SetupTokenSessionService, SetupTokenSessionError, assessConfidentialSta
31
33
  import { SETUP_TOKEN_TRANSPORT_ADVISORY_CODE } from "@paperclipai/shared";
32
34
  import { DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX } from "@paperclipai/adapter-codex-local";
33
35
  import { checkStagedCredentialReadiness, promoteDeviceLoginCredential, } from "@paperclipai/adapter-codex-local/server";
34
- import { AdapterAuthSessionConflictError, CODEX_DEVICE_LOGIN_ADAPTER_TYPE, createCodexDeviceLoginService, createDbAdapterAuthSessionStore, createProductionLoginSessionRuntime, } from "../services/codex-device-login-service.js";
36
+ import { AdapterAuthSessionConflictError, createCodexDeviceLoginService, createCodexWorkerBoundLoginPtyOpener, createDbAdapterAuthSessionStore, createProductionLoginSessionRuntime, CODEX_DEVICE_LOGIN_PROVIDER_UNSUPPORTED, CODEX_DEVICE_LOGIN_PROVIDER_UNSUPPORTED_CODE, } from "../services/codex-device-login-service.js";
35
37
  import { DEFAULT_CURSOR_LOCAL_MODEL } from "@paperclipai/adapter-cursor-local";
36
38
  import { DEFAULT_GEMINI_LOCAL_MODEL } from "@paperclipai/adapter-gemini-local";
39
+ import { DEFAULT_KIMI_LOCAL_MODEL } from "@paperclipai/adapter-kimi-local";
37
40
  import { DEFAULT_OPENCODE_LOCAL_MODEL } from "@paperclipai/adapter-opencode-local";
38
41
  import { requireOpenCodeModelId } from "@paperclipai/adapter-opencode-local/server";
39
42
  import { loadDefaultAgentInstructionsBundle, resolveDefaultAgentInstructionsBundleRole, } from "../services/default-agent-instructions.js";
@@ -97,6 +100,7 @@ export function agentRoutes(db, options = {}) {
97
100
  codex_local: "instructionsFilePath",
98
101
  droid_local: "instructionsFilePath",
99
102
  gemini_local: "instructionsFilePath",
103
+ kimi_local: "instructionsFilePath",
100
104
  opencode_local: "instructionsFilePath",
101
105
  cursor: "instructionsFilePath",
102
106
  pi_local: "instructionsFilePath",
@@ -178,8 +182,7 @@ export function agentRoutes(db, options = {}) {
178
182
  const setupTokenCleanupRows = new Map();
179
183
  const scopeMatchesRow = (row, identity) => row.companyId === identity.companyId &&
180
184
  row.ownerUserId === identity.ownerUserId &&
181
- row.adapterType === identity.adapterType &&
182
- row.environmentId === identity.environmentId;
185
+ row.adapterType === identity.adapterType;
183
186
  const inMemorySetupTokenCleanupStore = {
184
187
  async record(record) {
185
188
  setupTokenCleanupRows.set(record.sessionId, { ...record });
@@ -285,7 +288,27 @@ export function agentRoutes(db, options = {}) {
285
288
  const adapterLoginStore = createDbAdapterAuthSessionStore(db);
286
289
  const adapterLoginService = createCodexDeviceLoginService({
287
290
  store: adapterLoginStore,
288
- runtime: createProductionLoginSessionRuntime({ db, environmentRuntime }),
291
+ runtime: createProductionLoginSessionRuntime({
292
+ db,
293
+ environmentRuntime,
294
+ // Re-check the provider login pseudo-terminal capability from current
295
+ // runtime state immediately before the provider lease. The route gate ran
296
+ // earlier, so a managed reconciliation can rebind the environment to an
297
+ // unsupported provider between the gate and the acquire; this fails closed
298
+ // before the lease and the pseudo-terminal.
299
+ assertProviderSupportsLoginPty: (environmentId) => assertCodexLoginProviderCapability(environmentId),
300
+ // Wire the live Codex pseudo-terminal opener through the plugin worker
301
+ // manager route. The opener sets the sandbox `CODEX_HOME` to the same
302
+ // server-controlled session home the descriptor-bound credential read
303
+ // opens. When no worker manager is bound, the runtime keeps its fail-closed
304
+ // opener and the login fails closed.
305
+ openLivePtySession: options.pluginWorkerManager
306
+ ? createCodexWorkerBoundLoginPtyOpener({
307
+ workerManager: options.pluginWorkerManager,
308
+ log: (line) => logger.info(line),
309
+ })
310
+ : undefined,
311
+ }),
289
312
  // The mandatory credential promotion. A successful login authenticates only
290
313
  // after this promotion validates the exact staged credential, runs an
291
314
  // independent readiness check, confirms the session still holds the sole
@@ -301,7 +324,7 @@ export function agentRoutes(db, options = {}) {
301
324
  // first under the lock and the reaper reclaims only after it completes. A
302
325
  // read-only fence is not enough, because the filesystem write can start
303
326
  // after the fence; the lock spans the whole section.
304
- const outcome = await adapterLoginStore.withCompanyAdapterPromotionLock(context.companyId, context.adapterType, () => promoteDeviceLoginCredential({
327
+ const outcome = await adapterLoginStore.withCompanyAdapterPromotionLock(context.companyId, context.startedByUserId, context.adapterType, () => promoteDeviceLoginCredential({
305
328
  authBytes,
306
329
  companyId: context.companyId,
307
330
  userInitiated: true,
@@ -404,8 +427,8 @@ export function agentRoutes(db, options = {}) {
404
427
  release: noopRelease,
405
428
  };
406
429
  }
407
- const environment = await environmentsSvc.getById(input.environmentId);
408
- if (!environment) {
430
+ const requestedEnvironment = await environmentsSvc.getById(input.environmentId);
431
+ if (!requestedEnvironment) {
409
432
  return {
410
433
  executionTarget: null,
411
434
  environmentName: null,
@@ -419,6 +442,35 @@ export function agentRoutes(db, options = {}) {
419
442
  release: noopRelease,
420
443
  };
421
444
  }
445
+ // Managed-sandbox-only policy: redirect a Test that would run on the local
446
+ // host onto the platform-managed sandbox, the same as a real run does
447
+ // (resolveExecutionWorkspaceEnvironmentId in heartbeat). Without this
448
+ // redirect the Test probes the local host while the run executes in the
449
+ // managed sandbox, so a passing Test validates the wrong execution target.
450
+ // With no active managed sandbox the Test fails closed — never local.
451
+ let environment = requestedEnvironment;
452
+ if (requestedEnvironment.driver === "local") {
453
+ const managedSandboxOnly = (await instanceSettings.getExperimental()).enableManagedSandboxOnly === true;
454
+ if (managedSandboxOnly) {
455
+ const managedSandboxEnvironment = await environmentsSvc.findManagedSandboxEnvironment(input.companyId);
456
+ if (!managedSandboxEnvironment) {
457
+ return {
458
+ executionTarget: null,
459
+ environmentName: requestedEnvironment.name,
460
+ fallbackChecks: [
461
+ {
462
+ code: "managed_sandbox_unavailable",
463
+ level: "error",
464
+ message: "This instance runs agents only in its platform-managed sandbox, but no active managed sandbox environment exists. The test did not run.",
465
+ hint: "Restore the managed sandbox environment, then test again.",
466
+ },
467
+ ],
468
+ release: noopRelease,
469
+ };
470
+ }
471
+ environment = managedSandboxEnvironment;
472
+ }
473
+ }
422
474
  if (environment.driver === "local") {
423
475
  return {
424
476
  executionTarget: null,
@@ -509,6 +561,11 @@ export function agentRoutes(db, options = {}) {
509
561
  issueId: null,
510
562
  heartbeatRunId: null,
511
563
  persistedExecutionWorkspace: null,
564
+ // Re-check the company binding atomically at lease time. The route
565
+ // guard already rejected a foreign environment, but the binding could
566
+ // change between the guard check and the lease acquire. This closes
567
+ // that check-to-lease race so a foreign sandbox never gets a lease.
568
+ assertCompanyBinding: true,
512
569
  // Apply the active custom-image template so the Test boots with the
513
570
  // operator's captured sandbox customizations and prepared image state,
514
571
  // matching what real agent runs use. Without this the test would
@@ -613,7 +670,7 @@ export function agentRoutes(db, options = {}) {
613
670
  {
614
671
  code: "environment_target_failed",
615
672
  level: "error",
616
- message: `Could not resolve a sandbox execution target for "${environment.name}".`,
673
+ message: `Could not resolve an execution target for "${environment.name}".`,
617
674
  detail: err instanceof Error ? err.message : String(err),
618
675
  },
619
676
  ],
@@ -692,9 +749,9 @@ export function agentRoutes(db, options = {}) {
692
749
  return {
693
750
  code: "sandbox_test_identity",
694
751
  level: "info",
695
- message: `Sandbox test identity for "${input.environmentName}".`,
752
+ message: `Environment test identity for "${input.environmentName}".`,
696
753
  detail: detailParts.join("; "),
697
- hint: "Use these provider-neutral IDs when comparing model-test output with provider logs or refreshed sandbox snapshots.",
754
+ hint: "Use these provider-neutral IDs when comparing model-test output with provider logs or refreshed environment snapshots.",
698
755
  };
699
756
  }
700
757
  async function getCurrentUserRedactionOptions() {
@@ -881,9 +938,31 @@ export function agentRoutes(db, options = {}) {
881
938
  }
882
939
  return userId;
883
940
  }
884
- // The device-login flow supports only the Codex adapter. Reject any other type.
885
- function assertCodexLoginAdapter(type) {
886
- if (type !== CODEX_DEVICE_LOGIN_ADAPTER_TYPE) {
941
+ // Read the interactive login capability the registry declares for an adapter
942
+ // type. Return null when the adapter declares no capability, so a guard fails
943
+ // closed on the absent case.
944
+ function getRegistryLoginCapability(type) {
945
+ return findActiveServerAdapter(type)?.loginCapability ?? null;
946
+ }
947
+ // The device-login route drives a login that shows a one-time code on a real
948
+ // pseudo-terminal. It serves an adapter whose registry login capability
949
+ // declares the displayed-code panel mode and whose trusted adapter type maps
950
+ // to a login command key. The guard reads the panel mode and the command map,
951
+ // not the adapter name, so a new adapter that satisfies both passes with no
952
+ // guard code change. It rejects an adapter with no matching capability, and an
953
+ // adapter with no mapped command key, with the same fixed 400.
954
+ //
955
+ // The command-map check keeps admission consistent with the closed command
956
+ // map. The login opener resolves the command key from the same map. An adapter
957
+ // that declares the displayed-code capability but has no mapped key would pass
958
+ // the panel-mode check, then fail at command resolution after the route
959
+ // creates session state. The guard rejects it before any session or lease side
960
+ // effect.
961
+ function assertDeviceLoginAdapter(type) {
962
+ if (getRegistryLoginCapability(type)?.panelMode !== "displayed_code") {
963
+ throw badRequest(`Adapter "${type}" does not support a device login.`);
964
+ }
965
+ if (!isLoginCommandSupportedAdapterType(type)) {
887
966
  throw badRequest(`Adapter "${type}" does not support a device login.`);
888
967
  }
889
968
  }
@@ -927,14 +1006,15 @@ export function agentRoutes(db, options = {}) {
927
1006
  }
928
1007
  }
929
1008
  /**
930
- * Fails closed when the environment provider does not advertise the Claude
931
- * setup-token login capability. It resolves the effective provider from the
932
- * environment config, then reads the static capability from the provider
933
- * plugin manifest. It never checks the provider by name. A missing plugin, a
934
- * non-plugin provider, and a provider without the flag all fail closed with
935
- * the fixed, typed error, so no session row, lease, or pseudo-terminal starts.
1009
+ * Reports whether the environment provider advertises the login pseudo-terminal
1010
+ * capability. It resolves the effective provider from the current environment
1011
+ * config, then reads the static capability from the provider plugin manifest. It
1012
+ * never checks the provider by name. A missing provider, a missing plugin, a
1013
+ * non-plugin provider, and a provider without the flag all return false. Both
1014
+ * login flows share this resolver, so both gates read the same current
1015
+ * capability.
936
1016
  */
937
- async function assertSetupTokenLoginProviderCapability(environmentId) {
1017
+ async function resolveProviderSupportsLoginPty(environmentId) {
938
1018
  const environment = await environmentsSvc.getById(environmentId);
939
1019
  const config = environment?.config && typeof environment.config === "object"
940
1020
  ? environment.config
@@ -943,26 +1023,50 @@ export function agentRoutes(db, options = {}) {
943
1023
  const resolved = provider
944
1024
  ? await resolvePluginSandboxProviderDriverByKey({ db, driverKey: provider })
945
1025
  : null;
946
- if (!resolved?.driver.supportsSetupTokenLogin) {
1026
+ return resolved?.driver.supportsLoginPty === true;
1027
+ }
1028
+ /**
1029
+ * Fails closed when the environment provider does not advertise the login
1030
+ * pseudo-terminal capability that the Claude setup-token login needs. It reads
1031
+ * the current provider capability. It fails closed with the fixed, typed error,
1032
+ * so no session row, lease, or pseudo-terminal starts.
1033
+ */
1034
+ async function assertSetupTokenLoginProviderCapability(environmentId) {
1035
+ if (!(await resolveProviderSupportsLoginPty(environmentId))) {
947
1036
  throw unprocessable(SETUP_TOKEN_PROVIDER_UNSUPPORTED, {
948
1037
  code: SETUP_TOKEN_PROVIDER_UNSUPPORTED_CODE,
949
1038
  });
950
1039
  }
951
1040
  }
1041
+ /**
1042
+ * Fails closed when the environment provider does not advertise the login
1043
+ * pseudo-terminal capability that the Codex device login needs. It reads the
1044
+ * current provider capability. The Codex route runs it before any session or
1045
+ * lease state, and the lease-acquisition path runs it again from current runtime
1046
+ * state before the provider lease. It fails closed with the fixed, typed error,
1047
+ * so no session row, lease, or pseudo-terminal starts.
1048
+ */
1049
+ async function assertCodexLoginProviderCapability(environmentId) {
1050
+ if (!(await resolveProviderSupportsLoginPty(environmentId))) {
1051
+ throw unprocessable(CODEX_DEVICE_LOGIN_PROVIDER_UNSUPPORTED, {
1052
+ code: CODEX_DEVICE_LOGIN_PROVIDER_UNSUPPORTED_CODE,
1053
+ });
1054
+ }
1055
+ }
952
1056
  // Read a login session for its owner. The durable row is the authority for the
953
1057
  // company and the owner. This returns null when the row is absent, when it
954
1058
  // belongs to another company or adapter, or when the requesting user is not the
955
1059
  // owner. So a non-owner and a cross-company caller both receive a 404 and cannot
956
1060
  // enumerate a session. Only the owner path reads the one-time prompt.
957
- async function readOwnerLoginSession(companyId, adapterType, sessionId, requestingUserId) {
958
- const row = await adapterLoginStore.get(sessionId);
959
- if (!row ||
960
- row.companyId !== companyId ||
961
- row.adapterType !== adapterType ||
962
- row.startedByUserId !== requestingUserId) {
1061
+ async function readOwnerLoginSession(companyId, adapterType, publicSessionId, requestingUserId) {
1062
+ // Read by the public session id, scoped to the company. The store predicate
1063
+ // already carries the company id, so a foreign-company caller reads nothing
1064
+ // and the internal row id never matches. Keep the adapter and owner checks.
1065
+ const row = await adapterLoginStore.getByPublicId(publicSessionId, companyId);
1066
+ if (!row || row.adapterType !== adapterType || row.startedByUserId !== requestingUserId) {
963
1067
  return null;
964
1068
  }
965
- return adapterLoginService.readOwnerSession(sessionId, requestingUserId);
1069
+ return adapterLoginService.readOwnerSession(publicSessionId, companyId, requestingUserId);
966
1070
  }
967
1071
  async function assertCanReadConfigurations(req, companyId) {
968
1072
  // Reading agent configurations, skills, and config revisions is a
@@ -1453,6 +1557,10 @@ export function agentRoutes(db, options = {}) {
1453
1557
  next.model = DEFAULT_GEMINI_LOCAL_MODEL;
1454
1558
  return ensureGatewayDeviceKey(adapterType, next);
1455
1559
  }
1560
+ if (adapterType === "kimi_local" && !asNonEmptyString(next.model)) {
1561
+ next.model = DEFAULT_KIMI_LOCAL_MODEL;
1562
+ return ensureGatewayDeviceKey(adapterType, next);
1563
+ }
1456
1564
  if (adapterType === "opencode_local" && !asNonEmptyString(next.model)) {
1457
1565
  next.model = DEFAULT_OPENCODE_LOCAL_MODEL;
1458
1566
  return ensureGatewayDeviceKey(adapterType, next);
@@ -1577,6 +1685,19 @@ export function agentRoutes(db, options = {}) {
1577
1685
  async function assertCanApplyAgentProfileChange(req, targetAgent) {
1578
1686
  await assertCanApplyProtectedAgentChange(req, targetAgent, [agentProfileChangeTargetKey(targetAgent.id)]);
1579
1687
  }
1688
+ async function assertCanResumeAgent(req, targetAgent) {
1689
+ if (req.actor.type !== "agent")
1690
+ return;
1691
+ const decision = await access.decide({
1692
+ actor: req.actor,
1693
+ action: "agent_config:update",
1694
+ resource: { type: "agent", companyId: targetAgent.companyId, agentId: targetAgent.id },
1695
+ scope: { requiresChangeGrant: true },
1696
+ });
1697
+ if (decision.allowed)
1698
+ return;
1699
+ throw forbidden(decision.explanation, authorizationDeniedDetails(decision));
1700
+ }
1580
1701
  function assertNoAgentInstructionsConfigMutation(req, adapterConfig, path = "adapterConfig") {
1581
1702
  if (req.actor.type !== "agent" || !adapterConfig)
1582
1703
  return;
@@ -1822,6 +1943,34 @@ export function agentRoutes(db, options = {}) {
1822
1943
  const detected = await detectAdapterModel(type);
1823
1944
  res.json(detected);
1824
1945
  });
1946
+ // The environment drivers the adapter Test route accepts. A local, SSH, or
1947
+ // sandbox environment can host a probe; a plugin environment cannot.
1948
+ const ADAPTER_TEST_ALLOWED_ENVIRONMENT_DRIVERS = ["local", "ssh", "sandbox"];
1949
+ // The fail-closed tenant-binding guard for the adapter Test route. A caller
1950
+ // may name any instance environment by id, so the route must reject an
1951
+ // environment that binds to another company before it resolves secrets,
1952
+ // merges env, resolves the target, leases a sandbox, or runs the adapter
1953
+ // test. The guard checks the company binding BEFORE it validates the status
1954
+ // or the driver, so it never reveals the status or the driver of a foreign
1955
+ // environment. A same-company or an instance-global environment then gets the
1956
+ // shared driver and status validation.
1957
+ async function assertAdapterTestEnvironmentForCompany(companyId, environmentId) {
1958
+ const environment = await environmentsSvc.getById(environmentId);
1959
+ if (!environment) {
1960
+ // A missing environment leaks no tenant state. The execution-context
1961
+ // resolver surfaces the existing environment_not_found check.
1962
+ return;
1963
+ }
1964
+ const boundCompanyIds = await environmentsSvc.listBoundCompanyIds(environmentId);
1965
+ if (boundCompanyIds.length > 0 && !boundCompanyIds.includes(companyId)) {
1966
+ throw forbidden("The selected environment belongs to another company.", {
1967
+ code: "environment_company_mismatch",
1968
+ });
1969
+ }
1970
+ await assertEnvironmentSelectionForCompany(environmentsSvc, companyId, environmentId, {
1971
+ allowedDrivers: ADAPTER_TEST_ALLOWED_ENVIRONMENT_DRIVERS,
1972
+ });
1973
+ }
1825
1974
  router.post("/companies/:companyId/adapters/:type/test-environment", validate(testAdapterEnvironmentSchema), async (req, res) => {
1826
1975
  const companyId = req.params.companyId;
1827
1976
  const type = assertKnownAdapterType(req.params.type);
@@ -1831,6 +1980,11 @@ export function agentRoutes(db, options = {}) {
1831
1980
  const requestedEnvironmentId = typeof req.body?.environmentId === "string" && req.body.environmentId.trim().length > 0
1832
1981
  ? req.body.environmentId
1833
1982
  : null;
1983
+ // Fail closed on a foreign environment before any secret resolution, env
1984
+ // merge, target resolution, sandbox lease, or adapter test runs.
1985
+ if (requestedEnvironmentId) {
1986
+ await assertAdapterTestEnvironmentForCompany(companyId, requestedEnvironmentId);
1987
+ }
1834
1988
  const normalizedAdapterConfig = await secretsSvc.normalizeAdapterConfigForPersistence(companyId, inputAdapterConfig, { strictMode: strictSecretsMode, adapterType: type });
1835
1989
  // Prospective, non-persisted config: resolve the acting user's own user
1836
1990
  // secrets in owner_scoped mode (no declaration rows exist for this config).
@@ -1945,28 +2099,42 @@ export function agentRoutes(db, options = {}) {
1945
2099
  router.post("/companies/:companyId/adapters/:type/login-sessions", async (req, res) => {
1946
2100
  const companyId = req.params.companyId;
1947
2101
  const type = req.params.type;
1948
- const startedByUserId = await assertCanManageAdapterLogin(req, companyId);
1949
- assertCodexLoginAdapter(type);
1950
- const environmentId = typeof req.body?.environmentId === "string" && req.body.environmentId.trim().length > 0
1951
- ? req.body.environmentId
1952
- : null;
1953
- if (!environmentId) {
1954
- throw badRequest("A sandbox environment is required to start a device login.");
1955
- }
1956
- const ttlSeconds = typeof req.body?.ttlSeconds === "number" && Number.isFinite(req.body.ttlSeconds)
1957
- ? req.body.ttlSeconds
1958
- : undefined;
1959
- // Reject a non-sandbox or inactive environment before the service starts.
1960
- await assertSandboxLoginEnvironment(companyId, environmentId);
2102
+ // The shared start-route spine derives the owner, checks the path adapter
2103
+ // type, validates the strict request schema, and checks the sandbox
2104
+ // environment before any session or lease side effect. The client body
2105
+ // carries no adapter type, so the spine injects the path type into the
2106
+ // parse. The strict schema rejects an unknown field, a non-uuid
2107
+ // environment id, and an out-of-range time-to-live with a fixed 400.
2108
+ const resolved = await runAdapterLoginStartSpine({
2109
+ req,
2110
+ res,
2111
+ deriveOwner: () => assertCanManageAdapterLogin(req, companyId),
2112
+ guardBeforeValidate: () => assertDeviceLoginAdapter(type),
2113
+ requestSchema: startAdapterAuthSessionRequestSchema,
2114
+ invalidRequestError: "The device login start request is invalid.",
2115
+ requestOverrides: { adapterType: type },
2116
+ assertSandbox: async (data) => {
2117
+ // The device login runs on a real pseudo-terminal, so it needs a
2118
+ // provider that advertises the login pseudo-terminal capability. Gate
2119
+ // the route on the current provider capability before any session or
2120
+ // lease state. The lease-acquisition path re-checks it from current
2121
+ // runtime state before the provider lease.
2122
+ await assertSandboxLoginEnvironment(companyId, data.environmentId);
2123
+ await assertCodexLoginProviderCapability(data.environmentId);
2124
+ },
2125
+ });
2126
+ if (!resolved)
2127
+ return;
2128
+ const { ownerUserId: startedByUserId, data } = resolved;
1961
2129
  const controller = new AbortController();
1962
2130
  let result;
1963
2131
  try {
1964
2132
  result = await adapterLoginService.start({
1965
2133
  companyId,
1966
- environmentId,
2134
+ environmentId: data.environmentId,
1967
2135
  adapterType: type,
1968
2136
  startedByUserId,
1969
- ttlSeconds,
2137
+ ttlSeconds: data.ttlSeconds,
1970
2138
  signal: controller.signal,
1971
2139
  });
1972
2140
  }
@@ -1997,7 +2165,7 @@ export function agentRoutes(db, options = {}) {
1997
2165
  const type = req.params.type;
1998
2166
  const sessionId = req.params.sessionId;
1999
2167
  const ownerUserId = await assertCanManageAdapterLogin(req, companyId);
2000
- assertCodexLoginAdapter(type);
2168
+ assertDeviceLoginAdapter(type);
2001
2169
  const owner = await readOwnerLoginSession(companyId, type, sessionId, ownerUserId);
2002
2170
  if (!owner) {
2003
2171
  res.status(404).json({ error: "Adapter login session not found" });
@@ -2012,7 +2180,7 @@ export function agentRoutes(db, options = {}) {
2012
2180
  const type = req.params.type;
2013
2181
  const sessionId = req.params.sessionId;
2014
2182
  const ownerUserId = await assertCanManageAdapterLogin(req, companyId);
2015
- assertCodexLoginAdapter(type);
2183
+ assertDeviceLoginAdapter(type);
2016
2184
  // Scope the cancel to this company, adapter, and owner. A non-owner and a
2017
2185
  // cross-company caller both receive a 404 and cannot cancel a session.
2018
2186
  const owner = await readOwnerLoginSession(companyId, type, sessionId, ownerUserId);
@@ -2024,7 +2192,7 @@ export function agentRoutes(db, options = {}) {
2024
2192
  // even when this process does not own the in-flight run, so a cross-process
2025
2193
  // cancel or a cancel after a restart does not leave the slot held until the
2026
2194
  // expiry. The reaper deletes the sandbox and finalizes the terminal.
2027
- const cancelled = await adapterLoginService.cancelOwnerSession(sessionId, ownerUserId);
2195
+ const cancelled = await adapterLoginService.cancelOwnerSession(sessionId, companyId, ownerUserId);
2028
2196
  // Abort the in-flight run this process owns, so the local login stops at
2029
2197
  // once instead of waiting for the reaper. A run in another process, or an
2030
2198
  // already-terminal run, has no controller here.
@@ -3105,12 +3273,12 @@ export function agentRoutes(db, options = {}) {
3105
3273
  res.json(agent);
3106
3274
  });
3107
3275
  router.post("/agents/:id/resume", async (req, res) => {
3108
- assertBoard(req);
3109
3276
  const id = req.params.id;
3110
3277
  const existing = await getAccessibleAgent(req, res, id);
3111
3278
  if (!existing) {
3112
3279
  return;
3113
3280
  }
3281
+ await assertCanResumeAgent(req, existing);
3114
3282
  if (existing.orgChainHealth?.status === "invalid_org_chain") {
3115
3283
  res.status(409).json({
3116
3284
  error: existing.orgChainHealth?.repairGuidance ?? "Repair this agent's reporting chain before resuming it",
@@ -3122,10 +3290,14 @@ export function agentRoutes(db, options = {}) {
3122
3290
  res.status(404).json({ error: "Agent not found" });
3123
3291
  return;
3124
3292
  }
3293
+ const actor = getActorInfo(req);
3125
3294
  await logActivity(db, {
3126
3295
  companyId: agent.companyId,
3127
- actorType: "user",
3128
- actorId: req.actor.userId ?? "board",
3296
+ actorType: actor.actorType,
3297
+ actorId: actor.actorId,
3298
+ agentId: actor.agentId,
3299
+ runId: actor.runId,
3300
+ agentApiKeyId: actor.agentApiKeyId,
3129
3301
  action: "agent.resumed",
3130
3302
  entityType: "agent",
3131
3303
  entityId: agent.id,
@@ -3702,61 +3874,79 @@ export function agentRoutes(db, options = {}) {
3702
3874
  });
3703
3875
  router.post("/companies/:companyId/setup-token-login-sessions", async (req, res) => {
3704
3876
  const companyId = req.params.companyId;
3705
- assertCompanyAccess(req, companyId);
3706
- const ownerUserId = deriveSetupTokenOwnerUserId(req);
3707
- res.setHeader("Cache-Control", "no-store");
3708
- // Parse the request with the shared strict validator before any session,
3709
- // lease, or pseudo-terminal side effect. `.strict()` rejects an unknown field,
3710
- // including a legacy `ttlSeconds`, with a fixed 400. The route echoes no input.
3711
- const parsed = startClaudeSetupTokenSessionRequestSchema.safeParse(req.body);
3712
- if (!parsed.success) {
3713
- res.status(400).json({ error: "The Claude login start request is invalid." });
3714
- return;
3715
- }
3716
- const { environmentId, adapterType } = parsed.data;
3717
- const confirmedOverwrite = parsed.data.overwrite ?? null;
3718
- // The company-and-environment login serves only the Claude adapter. A
3719
- // different adapter type gets a fixed 400.
3720
- if (adapterType !== CLAUDE_SETUP_TOKEN_ADAPTER_TYPE) {
3721
- res.status(400).json({ error: "Only the claude_local adapter supports a setup-token login." });
3722
- return;
3723
- }
3724
- if (!SETUP_TOKEN_LOGIN_TRANSPORT_READY) {
3725
- // The live login transport binds at a later call site. Fail closed with the
3726
- // fixed no-secret error until then.
3727
- res.status(503).json({ error: SETUP_TOKEN_START_FAILED });
3728
- return;
3729
- }
3730
- // Resolve the environment server-side to a live instance sandbox. It fails
3731
- // closed on a missing, archived, non-sandbox, or fake-provider environment, so
3732
- // the route never persists an empty or invalid environment scope. It runs
3733
- // before the session starts, so no store holds a rejected environment. It
3734
- // also rejects an environment that another company owns (see
3735
- // `assertSandboxLoginEnvironment`), so a login never runs in a foreign
3736
- // company sandbox. It also fails closed when the provider does not advertise
3737
- // the setup-token login capability, so an unsupported provider never reaches
3738
- // a session row, a lease, or a pseudo-terminal.
3739
- await assertSandboxLoginEnvironment(companyId, environmentId, {
3740
- requireSetupTokenLoginProvider: true,
3877
+ // The shared start-route spine derives the owner, validates the strict
3878
+ // request schema, runs the Claude-only guards, and checks the sandbox
3879
+ // environment before any session, lease, or pseudo-terminal side effect.
3880
+ //
3881
+ // The owner step runs the company access check, derives the owner, and then
3882
+ // sets `Cache-Control: no-store`, so a rejected member sees no cache header
3883
+ // and every other response carries it. The strict schema rejects an unknown
3884
+ // field, including a legacy `ttlSeconds`, with a fixed 400. The post-validate
3885
+ // guard rejects a non-Claude adapter with a fixed 400 and fails closed with
3886
+ // the fixed no-secret 503 until the live login transport binds. The sandbox
3887
+ // check fails closed on a missing, archived, non-sandbox, fake-provider, or
3888
+ // foreign environment, and on a provider without the setup-token login
3889
+ // capability, so no rejected environment reaches a session row, a lease, or a
3890
+ // pseudo-terminal.
3891
+ const resolved = await runAdapterLoginStartSpine({
3892
+ req,
3893
+ res,
3894
+ deriveOwner: () => {
3895
+ assertCompanyAccess(req, companyId);
3896
+ const ownerUserId = deriveSetupTokenOwnerUserId(req);
3897
+ res.setHeader("Cache-Control", "no-store");
3898
+ return ownerUserId;
3899
+ },
3900
+ requestSchema: startClaudeSetupTokenSessionRequestSchema,
3901
+ invalidRequestError: "The Claude login start request is invalid.",
3902
+ guardAfterValidate: (data) => {
3903
+ // The setup-token route drives a login on a pseudo-terminal and records a
3904
+ // stored session identifier on success. It serves any adapter whose
3905
+ // registry login capability records that completion claim. The guard reads
3906
+ // the capability, not the adapter name, so a new adapter with the same
3907
+ // claim passes with no code change. It rejects an adapter with no matching
3908
+ // capability with a fixed 400.
3909
+ const capability = getRegistryLoginCapability(data.adapterType);
3910
+ if (capability?.completionClaim !== "storedSessionId") {
3911
+ res.status(400).json({ error: "This adapter does not support a setup-token login." });
3912
+ return true;
3913
+ }
3914
+ if (!SETUP_TOKEN_LOGIN_TRANSPORT_READY) {
3915
+ res.status(503).json({ error: SETUP_TOKEN_START_FAILED });
3916
+ return true;
3917
+ }
3918
+ return false;
3919
+ },
3920
+ assertSandbox: (data) => assertSandboxLoginEnvironment(companyId, data.environmentId, {
3921
+ requireSetupTokenLoginProvider: true,
3922
+ }),
3741
3923
  });
3924
+ if (!resolved)
3925
+ return;
3926
+ const { ownerUserId, data } = resolved;
3927
+ const { environmentId, adapterType } = data;
3928
+ const confirmedOverwrite = data.overwrite ?? null;
3742
3929
  const scope = {
3743
3930
  companyId,
3744
3931
  ownerUserId,
3745
- targetAgentId: null,
3746
3932
  adapterType,
3747
3933
  environmentId,
3748
3934
  confirmedOverwrite,
3749
3935
  };
3936
+ // Read the panel mode from the adapter capability. The guard already checked
3937
+ // the capability, so it is present here. The client renders the panel from
3938
+ // this value instead of a hard-coded mode.
3939
+ const panelMode = getRegistryLoginCapability(adapterType)?.panelMode ?? "submitted_browser_code";
3750
3940
  try {
3751
3941
  const started = await setupTokenLoginService.start(scope);
3752
3942
  const descriptor = setupTokenLoginService.describeOwned(started.sessionId, scope);
3753
3943
  // The start response carries the panel mode, so the client renders the
3754
- // browser-code panel. The full login URL rides only through the
3755
- // guarded prompt read, not the start response, so the prompt is null here.
3756
- // The client reads the prompt route for the login URL.
3944
+ // correct panel. The full login URL rides only through the guarded prompt
3945
+ // read, not the start response, so the prompt is null here. The client
3946
+ // reads the prompt route for the login URL.
3757
3947
  const body = {
3758
3948
  ...toClaudePublicResponse(descriptor),
3759
- panelMode: "submitted_browser_code",
3949
+ panelMode,
3760
3950
  prompt: null,
3761
3951
  };
3762
3952
  res.status(201).json(body);