@intentic/sandbox-contract 1.231.0 → 1.233.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (500) hide show
  1. package/README.md +13 -2
  2. package/dist/agent-catalog.d.ts +2 -1
  3. package/dist/agent-catalog.d.ts.map +1 -1
  4. package/dist/agent-catalog.js +1 -1
  5. package/dist/agent-catalog.js.map +1 -1
  6. package/dist/chores/chores.d.ts +1 -1
  7. package/dist/chores/chores.d.ts.map +1 -1
  8. package/dist/chores/probes.d.ts +1 -1
  9. package/dist/chores/probes.d.ts.map +1 -1
  10. package/dist/chores/stack.d.ts.map +1 -1
  11. package/dist/chores/stack.js +2 -1
  12. package/dist/chores/stack.js.map +1 -1
  13. package/dist/chores/verdict.d.ts +1 -1
  14. package/dist/chores/verdict.d.ts.map +1 -1
  15. package/dist/command-classes.d.ts +14 -0
  16. package/dist/command-classes.d.ts.map +1 -0
  17. package/dist/command-classes.js +168 -0
  18. package/dist/command-classes.js.map +1 -0
  19. package/dist/contracts/activity.contract.js +1 -1
  20. package/dist/contracts/activity.contract.js.map +1 -1
  21. package/dist/contracts/agent.contract.d.ts +51 -2
  22. package/dist/contracts/agent.contract.d.ts.map +1 -1
  23. package/dist/contracts/agent.contract.js +13 -1
  24. package/dist/contracts/agent.contract.js.map +1 -1
  25. package/dist/contracts/agents.contract.d.ts +24 -0
  26. package/dist/contracts/agents.contract.d.ts.map +1 -1
  27. package/dist/contracts/agents.contract.js +5 -1
  28. package/dist/contracts/agents.contract.js.map +1 -1
  29. package/dist/contracts/automations.contract.js +2 -1
  30. package/dist/contracts/automations.contract.js.map +1 -1
  31. package/dist/contracts/capabilities.contract.d.ts +63 -0
  32. package/dist/contracts/capabilities.contract.d.ts.map +1 -1
  33. package/dist/contracts/capabilities.contract.js +3 -1
  34. package/dist/contracts/capabilities.contract.js.map +1 -1
  35. package/dist/contracts/chores.contract.d.ts.map +1 -1
  36. package/dist/contracts/chores.contract.js +2 -1
  37. package/dist/contracts/chores.contract.js.map +1 -1
  38. package/dist/contracts/ci.contract.js +2 -1
  39. package/dist/contracts/ci.contract.js.map +1 -1
  40. package/dist/contracts/claude.contract.js +2 -1
  41. package/dist/contracts/claude.contract.js.map +1 -1
  42. package/dist/contracts/cursor.contract.js +2 -1
  43. package/dist/contracts/cursor.contract.js.map +1 -1
  44. package/dist/contracts/drafts.contract.d.ts.map +1 -1
  45. package/dist/contracts/drafts.contract.js +2 -1
  46. package/dist/contracts/drafts.contract.js.map +1 -1
  47. package/dist/contracts/endpoints.contract.d.ts.map +1 -1
  48. package/dist/contracts/endpoints.contract.js +2 -1
  49. package/dist/contracts/endpoints.contract.js.map +1 -1
  50. package/dist/contracts/exit.contract.d.ts.map +1 -1
  51. package/dist/contracts/exit.contract.js +2 -1
  52. package/dist/contracts/exit.contract.js.map +1 -1
  53. package/dist/contracts/extensions.contract.d.ts +42 -0
  54. package/dist/contracts/extensions.contract.d.ts.map +1 -1
  55. package/dist/contracts/extensions.contract.js +4 -1
  56. package/dist/contracts/extensions.contract.js.map +1 -1
  57. package/dist/contracts/git.contract.d.ts.map +1 -1
  58. package/dist/contracts/git.contract.js +4 -1
  59. package/dist/contracts/git.contract.js.map +1 -1
  60. package/dist/contracts/grok.contract.d.ts.map +1 -1
  61. package/dist/contracts/grok.contract.js +2 -1
  62. package/dist/contracts/grok.contract.js.map +1 -1
  63. package/dist/contracts/history.contract.d.ts.map +1 -1
  64. package/dist/contracts/history.contract.js +2 -1
  65. package/dist/contracts/history.contract.js.map +1 -1
  66. package/dist/contracts/host.contract.d.ts +11 -0
  67. package/dist/contracts/host.contract.d.ts.map +1 -1
  68. package/dist/contracts/host.contract.js +4 -1
  69. package/dist/contracts/host.contract.js.map +1 -1
  70. package/dist/contracts/intentic.contract.d.ts.map +1 -1
  71. package/dist/contracts/intentic.contract.js +2 -1
  72. package/dist/contracts/intentic.contract.js.map +1 -1
  73. package/dist/contracts/inventory.contract.js +1 -1
  74. package/dist/contracts/inventory.contract.js.map +1 -1
  75. package/dist/contracts/logs.contract.d.ts.map +1 -1
  76. package/dist/contracts/logs.contract.js +1 -1
  77. package/dist/contracts/logs.contract.js.map +1 -1
  78. package/dist/contracts/loops.contract.js +2 -1
  79. package/dist/contracts/loops.contract.js.map +1 -1
  80. package/dist/contracts/panels.contract.d.ts.map +1 -1
  81. package/dist/contracts/panels.contract.js +2 -1
  82. package/dist/contracts/panels.contract.js.map +1 -1
  83. package/dist/contracts/personas.contract.js +2 -1
  84. package/dist/contracts/personas.contract.js.map +1 -1
  85. package/dist/contracts/ports.contract.d.ts.map +1 -1
  86. package/dist/contracts/ports.contract.js +2 -1
  87. package/dist/contracts/ports.contract.js.map +1 -1
  88. package/dist/contracts/prepush.contract.d.ts.map +1 -1
  89. package/dist/contracts/prepush.contract.js +2 -1
  90. package/dist/contracts/prepush.contract.js.map +1 -1
  91. package/dist/contracts/providers.contract.d.ts.map +1 -1
  92. package/dist/contracts/providers.contract.js +2 -1
  93. package/dist/contracts/providers.contract.js.map +1 -1
  94. package/dist/contracts/public.contract.d.ts.map +1 -1
  95. package/dist/contracts/public.contract.js +2 -1
  96. package/dist/contracts/public.contract.js.map +1 -1
  97. package/dist/contracts/push.contract.d.ts.map +1 -1
  98. package/dist/contracts/push.contract.js +2 -1
  99. package/dist/contracts/push.contract.js.map +1 -1
  100. package/dist/contracts/runner.contract.d.ts +151 -43
  101. package/dist/contracts/runner.contract.d.ts.map +1 -1
  102. package/dist/contracts/runner.contract.js +14 -1
  103. package/dist/contracts/runner.contract.js.map +1 -1
  104. package/dist/contracts/secrets.contract.d.ts.map +1 -1
  105. package/dist/contracts/secrets.contract.js +2 -1
  106. package/dist/contracts/secrets.contract.js.map +1 -1
  107. package/dist/contracts/sessions.contract.js +1 -1
  108. package/dist/contracts/sessions.contract.js.map +1 -1
  109. package/dist/contracts/settings.contract.d.ts +20 -0
  110. package/dist/contracts/settings.contract.d.ts.map +1 -1
  111. package/dist/contracts/settings.contract.js +3 -1
  112. package/dist/contracts/settings.contract.js.map +1 -1
  113. package/dist/contracts/share.contract.d.ts.map +1 -1
  114. package/dist/contracts/share.contract.js +2 -1
  115. package/dist/contracts/share.contract.js.map +1 -1
  116. package/dist/contracts/skills.contract.d.ts.map +1 -1
  117. package/dist/contracts/skills.contract.js +2 -1
  118. package/dist/contracts/skills.contract.js.map +1 -1
  119. package/dist/contracts/system.contract.d.ts +35 -16
  120. package/dist/contracts/system.contract.d.ts.map +1 -1
  121. package/dist/contracts/system.contract.js +6 -1
  122. package/dist/contracts/system.contract.js.map +1 -1
  123. package/dist/contracts/translator.contract.d.ts.map +1 -1
  124. package/dist/contracts/translator.contract.js +4 -1
  125. package/dist/contracts/translator.contract.js.map +1 -1
  126. package/dist/contracts/usage.contract.js +1 -1
  127. package/dist/contracts/usage.contract.js.map +1 -1
  128. package/dist/contracts/vpn.contract.d.ts.map +1 -1
  129. package/dist/contracts/vpn.contract.js +2 -1
  130. package/dist/contracts/vpn.contract.js.map +1 -1
  131. package/dist/contracts/webext.contract.d.ts +45 -0
  132. package/dist/contracts/webext.contract.d.ts.map +1 -0
  133. package/dist/contracts/webext.contract.js +12 -0
  134. package/dist/contracts/webext.contract.js.map +1 -0
  135. package/dist/contracts/workflows.contract.js +2 -1
  136. package/dist/contracts/workflows.contract.js.map +1 -1
  137. package/dist/contracts/workspace.contract.d.ts +2 -2
  138. package/dist/contracts/workspace.contract.d.ts.map +1 -1
  139. package/dist/contracts/workspace.contract.js +7 -1
  140. package/dist/contracts/workspace.contract.js.map +1 -1
  141. package/dist/definition-action.d.ts +7 -0
  142. package/dist/definition-action.d.ts.map +1 -0
  143. package/dist/definition-action.js +3 -0
  144. package/dist/definition-action.js.map +1 -0
  145. package/dist/definition.d.ts +1064 -0
  146. package/dist/definition.d.ts.map +1 -0
  147. package/dist/definition.js +93 -0
  148. package/dist/definition.js.map +1 -0
  149. package/dist/events.d.ts +109 -0
  150. package/dist/events.d.ts.map +1 -1
  151. package/dist/events.js +30 -1
  152. package/dist/events.js.map +1 -1
  153. package/dist/fast-tier.d.ts +1 -1
  154. package/dist/fast-tier.d.ts.map +1 -1
  155. package/dist/history-state.d.ts.map +1 -1
  156. package/dist/history-state.js +1 -0
  157. package/dist/history-state.js.map +1 -1
  158. package/dist/index.d.ts +371 -103
  159. package/dist/index.d.ts.map +1 -1
  160. package/dist/index.js +52 -1
  161. package/dist/index.js.map +1 -1
  162. package/dist/listener-protocol.js +1 -1
  163. package/dist/listener-protocol.js.map +1 -1
  164. package/dist/quick-model.d.ts +1 -1
  165. package/dist/quick-model.d.ts.map +1 -1
  166. package/dist/runner-protocol.d.ts +18 -0
  167. package/dist/runner-protocol.d.ts.map +1 -1
  168. package/dist/runner-protocol.js +8 -4
  169. package/dist/runner-protocol.js.map +1 -1
  170. package/dist/schemas/activity.d.ts +112 -0
  171. package/dist/schemas/activity.d.ts.map +1 -0
  172. package/dist/schemas/activity.js +70 -0
  173. package/dist/schemas/activity.js.map +1 -0
  174. package/dist/schemas/agent.d.ts +189 -0
  175. package/dist/schemas/agent.d.ts.map +1 -0
  176. package/dist/schemas/agent.js +170 -0
  177. package/dist/schemas/agent.js.map +1 -0
  178. package/dist/schemas/agents.d.ts +690 -0
  179. package/dist/schemas/agents.d.ts.map +1 -0
  180. package/dist/schemas/agents.js +314 -0
  181. package/dist/schemas/agents.js.map +1 -0
  182. package/dist/schemas/automations.d.ts +736 -0
  183. package/dist/schemas/automations.d.ts.map +1 -0
  184. package/dist/schemas/automations.js +218 -0
  185. package/dist/schemas/automations.js.map +1 -0
  186. package/dist/schemas/capabilities.d.ts +753 -0
  187. package/dist/schemas/capabilities.d.ts.map +1 -0
  188. package/dist/schemas/capabilities.js +269 -0
  189. package/dist/schemas/capabilities.js.map +1 -0
  190. package/dist/schemas/ci.d.ts +179 -0
  191. package/dist/schemas/ci.d.ts.map +1 -0
  192. package/dist/schemas/ci.js +99 -0
  193. package/dist/schemas/ci.js.map +1 -0
  194. package/dist/schemas/claude-gate.d.ts +13 -0
  195. package/dist/schemas/claude-gate.d.ts.map +1 -0
  196. package/dist/schemas/claude-gate.js +8 -0
  197. package/dist/schemas/claude-gate.js.map +1 -0
  198. package/dist/schemas/codebase-health.d.ts +56 -0
  199. package/dist/schemas/codebase-health.d.ts.map +1 -0
  200. package/dist/schemas/codebase-health.js +43 -0
  201. package/dist/schemas/codebase-health.js.map +1 -0
  202. package/dist/schemas/computers.d.ts +386 -0
  203. package/dist/schemas/computers.d.ts.map +1 -0
  204. package/dist/schemas/computers.js +107 -0
  205. package/dist/schemas/computers.js.map +1 -0
  206. package/dist/schemas/drafts.d.ts +84 -0
  207. package/dist/schemas/drafts.d.ts.map +1 -0
  208. package/dist/schemas/drafts.js +44 -0
  209. package/dist/schemas/drafts.js.map +1 -0
  210. package/dist/schemas/environment.d.ts +349 -0
  211. package/dist/schemas/environment.d.ts.map +1 -0
  212. package/dist/schemas/environment.js +111 -0
  213. package/dist/schemas/environment.js.map +1 -0
  214. package/dist/schemas/exit.d.ts +151 -0
  215. package/dist/schemas/exit.d.ts.map +1 -0
  216. package/dist/schemas/exit.js +115 -0
  217. package/dist/schemas/exit.js.map +1 -0
  218. package/dist/schemas/extension-updates.d.ts +1014 -0
  219. package/dist/schemas/extension-updates.d.ts.map +1 -0
  220. package/dist/schemas/extension-updates.js +197 -0
  221. package/dist/schemas/extension-updates.js.map +1 -0
  222. package/dist/schemas/fast-mode.d.ts +8 -0
  223. package/dist/schemas/fast-mode.d.ts.map +1 -0
  224. package/dist/schemas/fast-mode.js +3 -0
  225. package/dist/schemas/fast-mode.js.map +1 -0
  226. package/dist/schemas/git-history.d.ts +238 -0
  227. package/dist/schemas/git-history.d.ts.map +1 -0
  228. package/dist/schemas/git-history.js +152 -0
  229. package/dist/schemas/git-history.js.map +1 -0
  230. package/dist/schemas/git.d.ts +471 -0
  231. package/dist/schemas/git.d.ts.map +1 -0
  232. package/dist/schemas/git.js +204 -0
  233. package/dist/schemas/git.js.map +1 -0
  234. package/dist/schemas/history.d.ts +100 -0
  235. package/dist/schemas/history.d.ts.map +1 -0
  236. package/dist/schemas/history.js +54 -0
  237. package/dist/schemas/history.js.map +1 -0
  238. package/dist/schemas/hosts.d.ts +41 -0
  239. package/dist/schemas/hosts.d.ts.map +1 -0
  240. package/dist/schemas/hosts.js +18 -0
  241. package/dist/schemas/hosts.js.map +1 -0
  242. package/dist/schemas/intentic.d.ts +5 -0
  243. package/dist/schemas/intentic.d.ts.map +1 -0
  244. package/dist/schemas/intentic.js +3 -0
  245. package/dist/schemas/intentic.js.map +1 -0
  246. package/dist/schemas/internal.d.ts +8 -0
  247. package/dist/schemas/internal.d.ts.map +1 -0
  248. package/dist/schemas/internal.js +12 -0
  249. package/dist/schemas/internal.js.map +1 -0
  250. package/dist/schemas/inventory.d.ts +171 -0
  251. package/dist/schemas/inventory.d.ts.map +1 -0
  252. package/dist/schemas/inventory.js +51 -0
  253. package/dist/schemas/inventory.js.map +1 -0
  254. package/dist/schemas/logs.d.ts +67 -0
  255. package/dist/schemas/logs.d.ts.map +1 -0
  256. package/dist/schemas/logs.js +54 -0
  257. package/dist/schemas/logs.js.map +1 -0
  258. package/dist/schemas/loops.d.ts +415 -0
  259. package/dist/schemas/loops.d.ts.map +1 -0
  260. package/dist/schemas/loops.js +188 -0
  261. package/dist/schemas/loops.js.map +1 -0
  262. package/dist/schemas/maintenance.d.ts +557 -0
  263. package/dist/schemas/maintenance.d.ts.map +1 -0
  264. package/dist/schemas/maintenance.js +201 -0
  265. package/dist/schemas/maintenance.js.map +1 -0
  266. package/dist/schemas/marketplace.d.ts +64 -0
  267. package/dist/schemas/marketplace.d.ts.map +1 -0
  268. package/dist/schemas/marketplace.js +17 -0
  269. package/dist/schemas/marketplace.js.map +1 -0
  270. package/dist/schemas/panels.d.ts +61 -0
  271. package/dist/schemas/panels.d.ts.map +1 -0
  272. package/dist/schemas/panels.js +51 -0
  273. package/dist/schemas/panels.js.map +1 -0
  274. package/dist/schemas/personas.d.ts +122 -0
  275. package/dist/schemas/personas.d.ts.map +1 -0
  276. package/dist/schemas/personas.js +102 -0
  277. package/dist/schemas/personas.js.map +1 -0
  278. package/dist/schemas/plan-limits.d.ts +172 -0
  279. package/dist/schemas/plan-limits.d.ts.map +1 -0
  280. package/dist/schemas/plan-limits.js +126 -0
  281. package/dist/schemas/plan-limits.js.map +1 -0
  282. package/dist/schemas/ports.d.ts +71 -0
  283. package/dist/schemas/ports.d.ts.map +1 -0
  284. package/dist/schemas/ports.js +42 -0
  285. package/dist/schemas/ports.js.map +1 -0
  286. package/dist/schemas/provider-oauth.d.ts +128 -0
  287. package/dist/schemas/provider-oauth.d.ts.map +1 -0
  288. package/dist/schemas/provider-oauth.js +91 -0
  289. package/dist/schemas/provider-oauth.js.map +1 -0
  290. package/dist/schemas/provider-subscriptions.d.ts +9 -0
  291. package/dist/schemas/provider-subscriptions.d.ts.map +1 -0
  292. package/dist/schemas/provider-subscriptions.js +3 -0
  293. package/dist/schemas/provider-subscriptions.js.map +1 -0
  294. package/dist/schemas/public.d.ts +32 -0
  295. package/dist/schemas/public.d.ts.map +1 -0
  296. package/dist/schemas/public.js +29 -0
  297. package/dist/schemas/public.js.map +1 -0
  298. package/dist/schemas/push.d.ts +55 -0
  299. package/dist/schemas/push.d.ts.map +1 -0
  300. package/dist/schemas/push.js +60 -0
  301. package/dist/schemas/push.js.map +1 -0
  302. package/dist/schemas/secrets.d.ts +86 -0
  303. package/dist/schemas/secrets.d.ts.map +1 -0
  304. package/dist/schemas/secrets.js +51 -0
  305. package/dist/schemas/secrets.js.map +1 -0
  306. package/dist/schemas/sessions.d.ts +32 -0
  307. package/dist/schemas/sessions.d.ts.map +1 -0
  308. package/dist/schemas/sessions.js +11 -0
  309. package/dist/schemas/sessions.js.map +1 -0
  310. package/dist/schemas/settings.d.ts +548 -0
  311. package/dist/schemas/settings.d.ts.map +1 -0
  312. package/dist/schemas/settings.js +259 -0
  313. package/dist/schemas/settings.js.map +1 -0
  314. package/dist/schemas/share.d.ts +49 -0
  315. package/dist/schemas/share.d.ts.map +1 -0
  316. package/dist/schemas/share.js +26 -0
  317. package/dist/schemas/share.js.map +1 -0
  318. package/dist/schemas/shared.d.ts +22 -0
  319. package/dist/schemas/shared.d.ts.map +1 -0
  320. package/dist/schemas/shared.js +16 -0
  321. package/dist/schemas/shared.js.map +1 -0
  322. package/dist/schemas/system.d.ts +86 -0
  323. package/dist/schemas/system.d.ts.map +1 -0
  324. package/dist/schemas/system.js +64 -0
  325. package/dist/schemas/system.js.map +1 -0
  326. package/dist/schemas/terminal.d.ts +230 -0
  327. package/dist/schemas/terminal.d.ts.map +1 -0
  328. package/dist/schemas/terminal.js +133 -0
  329. package/dist/schemas/terminal.js.map +1 -0
  330. package/dist/schemas/usage.d.ts +113 -0
  331. package/dist/schemas/usage.d.ts.map +1 -0
  332. package/dist/schemas/usage.js +91 -0
  333. package/dist/schemas/usage.js.map +1 -0
  334. package/dist/schemas/vpn.d.ts +229 -0
  335. package/dist/schemas/vpn.d.ts.map +1 -0
  336. package/dist/schemas/vpn.js +115 -0
  337. package/dist/schemas/vpn.js.map +1 -0
  338. package/dist/schemas/webext.d.ts +98 -0
  339. package/dist/schemas/webext.d.ts.map +1 -0
  340. package/dist/schemas/webext.js +36 -0
  341. package/dist/schemas/webext.js.map +1 -0
  342. package/dist/schemas/workflows.d.ts +881 -0
  343. package/dist/schemas/workflows.d.ts.map +1 -0
  344. package/dist/schemas/workflows.js +164 -0
  345. package/dist/schemas/workflows.js.map +1 -0
  346. package/dist/schemas/workspace-repos.d.ts +143 -0
  347. package/dist/schemas/workspace-repos.d.ts.map +1 -0
  348. package/dist/schemas/workspace-repos.js +87 -0
  349. package/dist/schemas/workspace-repos.js.map +1 -0
  350. package/dist/schemas/workspace-search.d.ts +170 -0
  351. package/dist/schemas/workspace-search.d.ts.map +1 -0
  352. package/dist/schemas/workspace-search.js +85 -0
  353. package/dist/schemas/workspace-search.js.map +1 -0
  354. package/dist/schemas/workspace-setup.d.ts +48 -0
  355. package/dist/schemas/workspace-setup.d.ts.map +1 -0
  356. package/dist/schemas/workspace-setup.js +26 -0
  357. package/dist/schemas/workspace-setup.js.map +1 -0
  358. package/dist/schemas/workspace-tree.d.ts +120 -0
  359. package/dist/schemas/workspace-tree.d.ts.map +1 -0
  360. package/dist/schemas/workspace-tree.js +111 -0
  361. package/dist/schemas/workspace-tree.js.map +1 -0
  362. package/dist/webext-links.d.ts +13 -0
  363. package/dist/webext-links.d.ts.map +1 -0
  364. package/dist/webext-links.js +24 -0
  365. package/dist/webext-links.js.map +1 -0
  366. package/dist/webext-protocol.d.ts +8 -0
  367. package/dist/webext-protocol.d.ts.map +1 -0
  368. package/dist/webext-protocol.js +7 -0
  369. package/dist/webext-protocol.js.map +1 -0
  370. package/dist/workflow-faults.d.ts +1 -1
  371. package/dist/workflow-faults.d.ts.map +1 -1
  372. package/dist/workspace-state.d.ts +11 -2
  373. package/dist/workspace-state.d.ts.map +1 -1
  374. package/dist/workspace-state.js +4 -2
  375. package/dist/workspace-state.js.map +1 -1
  376. package/package.json +17 -6
  377. package/src/agent-catalog.test.ts +1 -1
  378. package/src/agent-catalog.ts +4 -11
  379. package/src/chores/chores.ts +1 -1
  380. package/src/chores/probes.ts +1 -1
  381. package/src/chores/stack.test.ts +19 -0
  382. package/src/chores/stack.ts +19 -3
  383. package/src/chores/verdict.test.ts +11 -1
  384. package/src/chores/verdict.ts +1 -1
  385. package/src/command-classes.test.ts +378 -0
  386. package/src/command-classes.ts +378 -0
  387. package/src/contracts/activity.contract.ts +1 -1
  388. package/src/contracts/agent.contract.ts +22 -12
  389. package/src/contracts/agents.contract.ts +6 -6
  390. package/src/contracts/automations.contract.ts +2 -2
  391. package/src/contracts/capabilities.contract.ts +3 -4
  392. package/src/contracts/chores.contract.ts +2 -1
  393. package/src/contracts/ci.contract.ts +2 -2
  394. package/src/contracts/claude.contract.ts +2 -2
  395. package/src/contracts/cursor.contract.ts +2 -2
  396. package/src/contracts/drafts.contract.ts +2 -1
  397. package/src/contracts/endpoints.contract.ts +2 -1
  398. package/src/contracts/exit.contract.ts +2 -1
  399. package/src/contracts/extensions.contract.ts +5 -5
  400. package/src/contracts/git.contract.ts +19 -18
  401. package/src/contracts/grok.contract.ts +2 -1
  402. package/src/contracts/history.contract.ts +2 -1
  403. package/src/contracts/host.contract.ts +4 -1
  404. package/src/contracts/intentic.contract.ts +2 -1
  405. package/src/contracts/inventory.contract.ts +1 -1
  406. package/src/contracts/logs.contract.ts +7 -1
  407. package/src/contracts/loops.contract.ts +2 -2
  408. package/src/contracts/panels.contract.ts +2 -1
  409. package/src/contracts/personas.contract.ts +3 -3
  410. package/src/contracts/ports.contract.ts +3 -2
  411. package/src/contracts/prepush.contract.ts +2 -1
  412. package/src/contracts/providers.contract.ts +2 -1
  413. package/src/contracts/public.contract.ts +3 -2
  414. package/src/contracts/push.contract.ts +2 -1
  415. package/src/contracts/runner.contract.ts +33 -1
  416. package/src/contracts/secrets.contract.ts +2 -1
  417. package/src/contracts/sessions.contract.ts +1 -1
  418. package/src/contracts/settings.contract.ts +3 -9
  419. package/src/contracts/share.contract.ts +3 -2
  420. package/src/contracts/skills.contract.ts +2 -1
  421. package/src/contracts/system.contract.ts +6 -9
  422. package/src/contracts/translator.contract.ts +4 -1
  423. package/src/contracts/usage.contract.ts +1 -1
  424. package/src/contracts/vpn.contract.ts +2 -8
  425. package/src/contracts/webext.contract.ts +37 -0
  426. package/src/contracts/workflows.contract.ts +2 -2
  427. package/src/contracts/workspace.contract.ts +10 -12
  428. package/src/conversation-ids.test.ts +1 -1
  429. package/src/definition-action.ts +8 -0
  430. package/src/definition.ts +235 -0
  431. package/src/events.ts +128 -22
  432. package/src/fast-tier.ts +1 -1
  433. package/src/history-state.ts +5 -0
  434. package/src/host-protocol.ts +1 -1
  435. package/src/hostnames.test.ts +2 -2
  436. package/src/index.ts +61 -1
  437. package/src/listener-protocol.ts +1 -1
  438. package/src/quick-model.ts +1 -1
  439. package/src/runner-protocol.ts +35 -5
  440. package/src/schemas/activity.ts +123 -0
  441. package/src/schemas/agent.ts +409 -0
  442. package/src/schemas/agents.ts +802 -0
  443. package/src/schemas/automations.ts +510 -0
  444. package/src/schemas/capabilities.ts +729 -0
  445. package/src/schemas/ci.ts +235 -0
  446. package/src/schemas/claude-gate.ts +13 -0
  447. package/src/schemas/codebase-health.ts +64 -0
  448. package/src/schemas/computers.ts +287 -0
  449. package/src/schemas/drafts.ts +108 -0
  450. package/src/schemas/environment.ts +276 -0
  451. package/src/schemas/exit.ts +222 -0
  452. package/src/schemas/extension-updates.ts +322 -0
  453. package/src/schemas/fast-mode.ts +8 -0
  454. package/src/schemas/git-history.ts +265 -0
  455. package/src/schemas/git.ts +430 -0
  456. package/src/schemas/history.ts +112 -0
  457. package/src/schemas/hosts.ts +37 -0
  458. package/src/schemas/intentic.ts +2 -0
  459. package/src/schemas/internal.ts +17 -0
  460. package/src/schemas/inventory.ts +68 -0
  461. package/src/schemas/logs.ts +96 -0
  462. package/src/schemas/loops.ts +401 -0
  463. package/src/schemas/maintenance.ts +421 -0
  464. package/src/schemas/marketplace.ts +23 -0
  465. package/src/schemas/panels.ts +99 -0
  466. package/src/schemas/personas.ts +281 -0
  467. package/src/schemas/plan-limits.ts +255 -0
  468. package/src/schemas/ports.ts +84 -0
  469. package/src/schemas/provider-oauth.ts +191 -0
  470. package/src/schemas/provider-subscriptions.ts +11 -0
  471. package/src/schemas/public.ts +52 -0
  472. package/src/schemas/push.ts +112 -0
  473. package/src/schemas/secrets.ts +68 -0
  474. package/src/schemas/sessions.ts +16 -0
  475. package/src/schemas/settings.ts +932 -0
  476. package/src/schemas/share.ts +71 -0
  477. package/src/schemas/shared.ts +32 -0
  478. package/src/schemas/system.ts +156 -0
  479. package/src/schemas/terminal.ts +286 -0
  480. package/src/schemas/usage.ts +303 -0
  481. package/src/{schemas.test.ts → schemas/version-seam.test.ts} +4 -2
  482. package/src/schemas/vpn.ts +215 -0
  483. package/src/schemas/webext.ts +79 -0
  484. package/src/schemas/workflows.ts +413 -0
  485. package/src/schemas/workspace-repos.ts +123 -0
  486. package/src/schemas/workspace-search.ts +141 -0
  487. package/src/schemas/workspace-setup.ts +43 -0
  488. package/src/schemas/workspace-tree.ts +234 -0
  489. package/src/title.test.ts +1 -1
  490. package/src/webext-links.ts +80 -0
  491. package/src/webext-protocol.ts +27 -0
  492. package/src/workflow-faults.test.ts +1 -1
  493. package/src/workflow-faults.ts +1 -1
  494. package/src/workspace-state.test.ts +7 -3
  495. package/src/workspace-state.ts +27 -13
  496. package/dist/schemas.d.ts +0 -9800
  497. package/dist/schemas.d.ts.map +0 -1
  498. package/dist/schemas.js +0 -4252
  499. package/dist/schemas.js.map +0 -1
  500. package/src/schemas.ts +0 -9999
@@ -0,0 +1,281 @@
1
+ // Personas: the named faces a sandbox shows the outside world — which accounts each speaks for, what a
2
+ // session wearing one may do, and where it works.
3
+ import { z } from "zod";
4
+ import { entryId } from "./internal.js";
5
+ import { SkillDraftSchema, SkillNameSchema, SystemPromptModeSchema } from "./settings.js";
6
+ /* A NAMED PERSONA THE SANDBOX SHOWS THE OUTSIDE WORLD, "work-reddit", "the studio account", and the layer
7
+ * that decides which connected accounts a given turn may act through.
8
+ *
9
+ * IT ANSWERS FOUR QUESTIONS AND NO MORE: who it speaks as, what it may do, where it works, and what it is told.
10
+ * Making one is then a name, a few accounts, some switches and, only if you want one, a prompt. That is the
11
+ * whole of what an owner is deciding, and short enough that they finish.
12
+ *
13
+ * NO PUBLISH-OR-DRAFT SWITCH. It read as a lock and was a sentence: it asked the turn to route outward things
14
+ * through the approvals queue and could not stop it posting. The queue is the mechanism, and a control whose
15
+ * label promises more than it delivers is worse than no control, it is the one an owner trusts.
16
+ *
17
+ * THE FOURTH QUESTION IS THE SYSTEM PROMPT, NOT A TONE NOTE, and the difference is why the field that used to
18
+ * sit here was removed and this one is not it. What was removed was a paragraph on how a persona WRITES:
19
+ * optional, answered by almost nobody, and shaping nothing a person could see afterwards. `systemPromptMode`
20
+ * is the same setting the sandbox has, asked per card, it replaces the whole prompt, and with the kit folder
21
+ * beside it (persona-kit.ts) a card can carry its own skills and tools too. That is a persona being a working
22
+ * posture rather than a label, and it shows: a release-notes writer and a code reviewer are two prompts, not
23
+ * two adjectives.
24
+ *
25
+ * THE CARD AND THE KEYS ARE DELIBERATELY SEPARATE. This is the card: a name, the accounts it speaks for, what a
26
+ * session wearing it may do, where it works. It carries NO credential, which is what lets it be the one thing under
27
+ * .intentic that is committed and reviewed like the workspace's instructions are (see personas-store.ts for
28
+ * the exclude carve-out that makes that true). The keys, the logged-in browser profile, its cookies, its
29
+ * passkey, stay where they already are: private to the sandbox, never exported without an explicit opt-in. So a
30
+ * cloned workspace arrives listing its personas, each visibly unconnected, waiting for one sign-in apiece.
31
+ *
32
+ * WHAT IT IS NOT is a security boundary. A chat still reaches every connected account by default (that is the
33
+ * owner's chosen posture, a chat has a human in the room), and an agent with a shell can reach a token whatever
34
+ * this file says. What it prevents is the mistake this codebase already names as the one that cannot be undone:
35
+ * a post from the wrong account. Where nobody is watching, an unattended wake, it is a real fence, because
36
+ * there the resolver's default is NOTHING rather than everything (see turnPersona in personas.ts). */
37
+ /* WHAT A PERSONA MAY DO, the shelves, one switch each, and the half of the card that bounds the turn rather
38
+ * than the account it speaks for.
39
+ *
40
+ * SHELVES, NOT TOOL NAMES. Every field here is a phrase a person decides about ("run commands", "read the
41
+ * web"), never the name of a tool. Tool names drift with every runtime upgrade, one power answers to several of
42
+ * them, and a connector is not a tool at all, it is a shell command plus a credential. Naming the shelf means
43
+ * a tool added next month lands inside an answer the owner already gave, and a card written today still means
44
+ * what it said after the SDK renames something.
45
+ *
46
+ * TWO STRENGTHS, AND THE DIFFERENCE IS VISIBLE FROM HERE. Everything capability-shaped (`connectors`,
47
+ * `computers`, `mcp`, and the accounts in `capabilities`) is enforced by ABSENCE, the credential is never
48
+ * injected, the server never mounted, the browser never launched, which is the same mechanism the account
49
+ * filter already uses and needs no cooperation from the model. The plain switches are enforced by taking the
50
+ * tools out of the turn's context, which holds for every tool the harness owns and cannot reach a program the
51
+ * agent runs for itself.
52
+ *
53
+ * WHICH IS WHY `shell` IS THE ONE THAT DECIDES. A session with a shell can read a credential this card never
54
+ * granted it, so switching it off is what turns the rest of these into a fence; leaving it on leaves them a
55
+ * strong default. The card's own UI says so at the switch, see PersonaForm.vue, because a limit that is
56
+ * weaker than it looks is worse than no limit at all.
57
+ *
58
+ * PERMISSIVE BY DEFAULT, deliberately, and the opposite of the account rule directly below it. An unrepeatable
59
+ * public post is worth defaulting to nothing for; an over-powered turn inside a container the owner can throw
60
+ * away is not, and it is the same reasoning that makes bypassPermissions this sandbox's default posture. So an
61
+ * absent `powers` means today's full toolbox, and a workspace that never opens this notices nothing. */
62
+ export const PersonaPowersSchema = z.object({
63
+ // "read" is look-and-search only; "write" adds creating and changing; "none" takes both away.
64
+ files: z
65
+ .enum(["none", "read", "write"])
66
+ .default("write")
67
+ .describe("What it may do with files: nothing, look and search, or also create and change."),
68
+ // Shell commands, and with them the terminals, the test runs, and every CLI on the image. See the header:
69
+ // this is the switch the others' strength depends on.
70
+ shell: z
71
+ .boolean()
72
+ .default(true)
73
+ .describe(
74
+ "Whether it may run commands, and with them the terminals, the test runs and every tool on the image. The switch the strength of the others depends on.",
75
+ ),
76
+ /* The JS execution backend (AgentCapabilities.execution): the model writes a script instead of a command
77
+ * line, run in a permission-fenced Node subprocess. Its fence is REAL where the shell's is not, reads and
78
+ * writes follow the `files` answer, and it can start no other program unless `shell` is also on, with one
79
+ * stated gap: the fence cannot cut the network, so a script can fetch whatever `web` says. */
80
+ code: z
81
+ .boolean()
82
+ .default(true)
83
+ .describe(
84
+ "Whether it may write and run a script rather than a command line. Its fence is real where the shell's is not: reads and writes follow the files answer, and it can start no other program unless commands are allowed too. The one stated gap is that the fence cannot cut the network.",
85
+ ),
86
+ // Fetch a page, run a search.
87
+ web: z.boolean().default(true).describe("Whether it may fetch a page or run a search."),
88
+ // The credential-free browser. The SIGNED-IN browsers are `capabilities` below, a different question, and
89
+ // the reason this one is safe to leave on: it holds nobody's account.
90
+ browser: z.boolean().default(true),
91
+ // Spawn sub-agents and run workflows.
92
+ delegate: z.boolean().default(true),
93
+ /* Change the sandbox itself: its settings and manifests, and the public outbox that publishes a file to
94
+ * anyone with the link. Enforced as a refusal on the paths that carry those, not as a tool switch, there
95
+ * is no "install a capability" tool to take away, only files that mean it. */
96
+ sandbox: z.boolean().default(true),
97
+ /* The connected accounts and services this persona may reach, BY ID. Absent means every one of them, which
98
+ * is what a card that has never thought about it should get; an empty list means none. That tri-state is the
99
+ * whole reason these are optional rather than defaulted arrays, "all" and "none" are both real answers and
100
+ * an empty default could only spell one of them. */
101
+ connectors: z.array(entryId).max(100).optional(),
102
+ computers: z.array(entryId).max(50).optional(),
103
+ mcp: z.array(entryId).max(50).optional(),
104
+ });
105
+ export type PersonaPowers = z.infer<typeof PersonaPowersSchema>;
106
+ /* WHERE A PERSONA WORKS, the third question after who it is and what it may do.
107
+ *
108
+ * `folders` is the one field here that promises less than it looks like it promises, and the card says so where
109
+ * it is set: it is enforced by refusing file tool calls that point outside, which stops a misread instruction
110
+ * and an honest mistake, and does not stop a shell. The workspace-wide fence is the container. */
111
+ /* WHERE A SESSION WEARING THIS CARD WORKS, the folder it opens in, and the folders its file tools may touch.
112
+ *
113
+ * There is no placement field, and that is a decision rather than an omission. A card used to be able to ask
114
+ * for the SHARED tree instead of its own copy; every surface already defaults to a private worktree
115
+ * (conversation.ts), so the setting existed only to opt out of the isolation that makes parallel work safe,
116
+ * expressed in three words ("whatever started it", "its own copy", "the shared workspace") that a reader had no
117
+ * way to choose between. A persona starts where it is told and works in its own copy. */
118
+ export const PersonaWorkspaceSchema = z.object({
119
+ // The repo (or folder) under the workspace a session starts in. Absent ⇒ the workspace root, as today.
120
+ startIn: z.string().max(200).optional().describe("Which folder a conversation opens in."),
121
+ // Workspace-relative folders the file tools may touch. Absent ⇒ anywhere under the workspace.
122
+ folders: z.array(z.string().min(1)).max(50).optional().describe("Which folders it may touch at all. Absent means the whole workspace."),
123
+ });
124
+ export type PersonaWorkspace = z.infer<typeof PersonaWorkspaceSchema>;
125
+ export const PersonaSchema = z.object({
126
+ id: entryId.describe("The persona's id."),
127
+ // What the owner calls it in the composer chip. Absent ⇒ surfaces read the id, which is already human-chosen.
128
+ label: z.string().max(60).optional().describe("What to call it on screen. Absent falls back to the id, which somebody chose anyway."),
129
+ /* The capability ids this persona acts THROUGH, the logged-in browser accounts (and, later, the credential
130
+ * connectors) that are its hands. Ids rather than platforms, because "two accounts of one site" is the whole
131
+ * problem: `reddit-work` and `reddit-personal` are two capabilities and exactly one of them belongs here.
132
+ *
133
+ * An id naming a capability that isn't connected is not an error, it is a card describing an account this
134
+ * sandbox has yet to sign into, which is precisely what a freshly cloned workspace looks like. */
135
+ capabilities: z
136
+ .array(entryId)
137
+ .max(50)
138
+ .describe(
139
+ "Which connected accounts are its hands. Named individually rather than by site, because two accounts on one site is the whole problem this solves. Naming one that is not connected yet is not an error: it is a card describing an account this sandbox has still to sign into.",
140
+ ),
141
+ /* Which workspace repos prefer this persona, so a chat opened on a project starts with the right chip already
142
+ * selected. A PREFERENCE, not a fence, the owner's chosen chat default is still "every account", and it
143
+ * lives on the card rather than in each project's own config so that one account named by three repos stays
144
+ * one definition instead of three that drift. */
145
+ repos: z
146
+ .array(z.string().min(1))
147
+ .max(50)
148
+ .optional()
149
+ .describe(
150
+ "Which repositories prefer this persona, so a conversation opened on one starts with the right choice already made. A preference rather than a fence.",
151
+ ),
152
+ // What a session wearing this card may do, and where it works. Both absent ⇒ the full toolbox and the whole
153
+ // workspace, so a card written before these existed keeps behaving exactly as it did.
154
+ powers: PersonaPowersSchema.optional().describe(
155
+ "What a conversation wearing it may do. Absent means the full toolbox, so a card written before this existed behaves exactly as it did.",
156
+ ),
157
+ workspace: PersonaWorkspaceSchema.optional().describe("Where it works. Absent means the whole workspace."),
158
+ /* WHICH SYSTEM PROMPT A SESSION WEARING THIS CARD RUNS ON, the same three bases the sandbox chooses
159
+ * between, asked per card. ABSENT is the fourth answer and the default: follow the sandbox, which is what
160
+ * every card meant before this field existed and what almost every card will go on meaning.
161
+ *
162
+ * Absent rather than a fifth enum value spelling the same thing. "inherit" and "not set" would be two
163
+ * spellings of one answer, and the surface that offers four options maps its first to leaving this off.
164
+ *
165
+ * THE TEXT IS NOT HERE. Under "custom" it is `PROMPT.md` in the card's own kit folder
166
+ * (personas/persona-kit.ts), for two reasons that point the same way: a system prompt is prose, and prose
167
+ * belongs in a file where it diffs line by line rather than as one escaped string inside a record nobody
168
+ * writes by hand, and the kit is already where that persona's skills and tools live, so there is one folder
169
+ * to look in rather than a field here and a directory there.
170
+ *
171
+ * "custom" with no PROMPT.md written yet falls back to the sandbox's answer rather than running the turn on
172
+ * an empty prompt: the card is half-made, and a half-made card should behave like the one it was before
173
+ * somebody started editing it. */
174
+ systemPromptMode: SystemPromptModeSchema.optional(),
175
+ });
176
+ export type Persona = z.infer<typeof PersonaSchema>;
177
+ /* THE ONE CARD ID THE PRODUCT NAMES ITSELF, the read-only persona a public web chat answers through.
178
+ *
179
+ * Nothing else is stock: a fresh workspace has no personas at all, and every card on the Personas page is one
180
+ * the owner wrote. This id is the exception because a Front Desk is driven by a stranger with nobody watching, so
181
+ * it is the one wake whose bounds cannot be left to the prompt's wording, the daemon writes the card the moment
182
+ * a Front Desk is saved (personas/front-desk.ts) and the automations form fills a blank Front Desk persona with it.
183
+ *
184
+ * It lives HERE because those two are in different packages and must agree exactly. A literal in each would
185
+ * drift into a Front Desk pinned to a card nobody creates, and turnPersona answers a missing card by denying
186
+ * everything, a public chat that cannot even read, which is safe and useless.
187
+ *
188
+ * It is FRONT DESK and not "visitor": the card is who answers the people who arrive, not the person arriving. */
189
+ export const FRONT_DESK_PERSONA = "front-desk";
190
+ /* HOW BOUNDED A CARD IS, in one phrase, for the row badge on the Personas page and for the sentence under the
191
+ * automations composer's persona picker.
192
+ *
193
+ * It lives in the contract rather than in either surface because those two are in different packages and would
194
+ * otherwise each grow their own vocabulary for the same card: a workspace where the Personas page says
195
+ * "Read-only" and the automation under it says "3 limits" is one where the reader cannot tell whether they are
196
+ * looking at the same thing.
197
+ *
198
+ * TWO NAMED SHAPES AND THEN A COUNT. "Read-only" and "no shell" are the two people actually reach for, so they
199
+ * get words; everything else gets a number, because listing four switched-off shelves in a badge produces a line
200
+ * nobody reads and buries the one fact that matters, that this card is limited at all. */
201
+ export const personaBounds = (persona: Persona): string => {
202
+ const powers = persona.powers;
203
+ if (powers === undefined) {
204
+ return "Full powers";
205
+ }
206
+ const resolved = PersonaPowersSchema.parse(powers);
207
+ if (resolved.files === "read" && !resolved.shell) {
208
+ return "Read-only";
209
+ }
210
+ if (!resolved.shell) {
211
+ return "No shell";
212
+ }
213
+ const limits = [
214
+ resolved.files === "none",
215
+ !resolved.code,
216
+ !resolved.web,
217
+ !resolved.browser,
218
+ !resolved.delegate,
219
+ !resolved.sandbox,
220
+ resolved.connectors !== undefined,
221
+ resolved.computers !== undefined,
222
+ resolved.mcp !== undefined,
223
+ ].filter(Boolean).length;
224
+ return limits === 0 ? "Full powers" : `${limits} limit${limits === 1 ? "" : "s"}`;
225
+ };
226
+ export const PersonaIdParamSchema = z.object({ id: entryId.describe("Which persona.") });
227
+ /* Every persona, plus which of the accounts they name this sandbox is actually signed into. The second half is
228
+ * what makes the list honest on a freshly cloned workspace: every card is present and most of them cannot act
229
+ * yet, and a surface that showed only the cards would present a persona that is one login away from working as
230
+ * though it already did. Ids the manifest has no capability for at all are `connected: false` too, a card may
231
+ * name an account nobody has added here. */
232
+ export const PersonasListSchema = z.object({
233
+ personas: z.array(PersonaSchema).describe("The characters an agent can wear."),
234
+ connected: z
235
+ .array(z.string())
236
+ .describe(
237
+ "Which accounts are actually connected right now, so a persona naming one that has since been disconnected can be shown as broken rather than as working.",
238
+ ),
239
+ });
240
+ /* A PERSONA'S KIT, as one read, the prompt it runs on and the skills it carries.
241
+ *
242
+ * ONE ROUTE FOR BOTH because they are one folder and one screen: the card's editor draws them together, and two
243
+ * requests to render one section is two chances for it to arrive half-drawn. The skills come back as name and
244
+ * description only, for the same reason the sandbox's own skill list does, a body runs to thousands of words
245
+ * and a group of one-line rows should not cost a hundred kilobytes to draw.
246
+ *
247
+ * An empty prompt is a card with no PROMPT.md, which is every card until somebody writes one. It is "" rather
248
+ * than absent because the field behind it is a textarea, and a textarea's empty value is "". */
249
+ export const PersonaKitSchema = z.object({
250
+ prompt: z
251
+ .string()
252
+ .describe("What this persona is told, on top of everything else. Empty means it simply follows the sandbox's own instructions."),
253
+ skills: z
254
+ .array(
255
+ z.object({
256
+ name: z.string().describe("The skill's name."),
257
+ description: z.string().describe("What it is for."),
258
+ }),
259
+ )
260
+ .describe(
261
+ "Skills only this persona's conversations can reach. A different question from what the agent knows generally, with a different answer.",
262
+ ),
263
+ });
264
+ export type PersonaKit = z.infer<typeof PersonaKitSchema>;
265
+ export const PersonaPromptSchema = PersonaIdParamSchema.extend({
266
+ prompt: z
267
+ .string()
268
+ .max(20000)
269
+ .describe(
270
+ "What to tell this persona. Sending an empty one removes it entirely rather than storing a blank, so the persona falls back to the sandbox's own instructions.",
271
+ ),
272
+ });
273
+ export const PersonaSkillSchema = PersonaIdParamSchema.extend(SkillDraftSchema.shape);
274
+ export const PersonaSkillNameSchema = PersonaIdParamSchema.extend({ name: SkillNameSchema.describe("Which skill.") });
275
+ // One kit skill's instructions, for editing it, the same split the sandbox's own skills make between a listing
276
+ // and a body, and for the same reason.
277
+ export const PersonaSkillBodySchema = z.object({
278
+ name: z.string().describe("The skill's name."),
279
+ description: z.string().describe("What it is for."),
280
+ body: z.string().describe("The skill itself, in full."),
281
+ });
@@ -0,0 +1,255 @@
1
+ import { z } from "zod";
2
+ import { EditorContextSchema } from "./agent.js";
3
+ // Declared ABOVE both account shapes because both carry it: headroom is one idea in this product, not a Claude
4
+ // idea that other providers imitate. A native account (OauthAccount) and a routed subscription
5
+ // (TranslatorAccount) differ in who holds the credential and how the reading is taken, never in what a
6
+ // reading IS, so every surface that draws a percentage reads this one type and no other.
7
+
8
+ // One plan-limit pool. `kind` is the provider's own key ('five_hour' | 'seven_day' | 'seven_day_opus' |
9
+ // 'seven_day_sonnet' | 'model:Fable' | …) rather than an enum we'd have to keep in step with the provider: an
10
+ // unrecognised pool is shown under its raw key, which is far better than being silently folded into a
11
+ // neighbour. `label` is the provider's OWN display name where it supplies one (the per-model buckets do), it
12
+ // wins over anything we'd infer, because the model names in a plan's limits are the provider's to rename.
13
+ // `resetsAt` is epoch SECONDS (matching the SDK's frame).
14
+ export const UsageWindowSchema = z.object({
15
+ kind: z.string(),
16
+ label: z.string().optional(),
17
+ utilization: z.number(), // 0-100
18
+ resetsAt: z.number().optional(),
19
+ });
20
+ export type UsageWindow = z.infer<typeof UsageWindowSchema>;
21
+ // An account's headroom: EVERY window the provider reports, read together, plus when the reading was taken.
22
+ // All of them, not the binding one, because "which pool is binding" changes between turns and a reader
23
+ // comparing accounts needs the same pools on every row. How the reading is TAKEN is per provider and stops at
24
+ // the daemon's readers: Claude's rides the turn's own stream, ChatGPT's, Google's and Kimi's are pulled through
25
+ // CLIProxyAPI's credential-scoped management call. All of them are control requests, so none costs tokens.
26
+ //
27
+ // Within one window utilization only climbs, so an un-reset window stays a valid FLOOR however old it is; past
28
+ // its `resetsAt` it describes a pool that no longer exists and the store drops it. `measuredAt` is epoch MS
29
+ // (matching connectedAt), deliberately a different unit from the windows' seconds.
30
+ export const AccountUsageSchema = z.object({
31
+ windows: z.array(UsageWindowSchema),
32
+ measuredAt: z.number(),
33
+ });
34
+ export type AccountUsage = z.infer<typeof AccountUsageSchema>;
35
+ /* THE LAST TIME A PROVIDER ACTUALLY REFUSED A TURN, the other half of "can I run on this", and the half no
36
+ * meter can supply.
37
+ *
38
+ * A snapshot above is POLLED and therefore always a floor: read at turn end (Claude) or on a five-minute sweep
39
+ * (the routed subscriptions), and account-wide, so every other client on the plan spends the same pools without
40
+ * this sandbox hearing about it. A refusal is the opposite kind of fact, observed, exact, and timestamped by
41
+ * the only event that proves the plan said no. Between them they answer a question neither can alone: a green
42
+ * meter beside "refused a turn 4 minutes ago" means the reading is stale, not that the account has room.
43
+ *
44
+ * Keyed by PROVIDER rather than by account, because that is the resolution the daemon honestly has. A native
45
+ * Claude turn knows which account served it and names it; a routed turn does not. CLIProxyAPI picks the auth
46
+ * file itself and only refuses once every credential it holds is cooling down, which makes the refusal a fact
47
+ * about the provider in the first place.
48
+ *
49
+ * `kind` is read off what the provider SAID, not off the frame code the harness filed it under, because those
50
+ * two disagree: Kimi answers a spent plan with `403 You've reached your usage limit for this billing cycle`,
51
+ * which the CLI prints under "Failed to authenticate" and the stream codes as a refused credential. Sending
52
+ * someone to reconnect a perfectly good account is the cost of believing the code over the sentence. */
53
+ export const ProviderRefusalSchema = z.object({
54
+ // Epoch MS, matching AccountUsage.measuredAt, the two are read side by side.
55
+ at: z.number().describe("When it refused, in milliseconds."),
56
+ /* Three ways a plan says no, kept apart because WHAT ANSWERS EACH is different and a screen that conflates
57
+ * them tells the user to do the wrong thing. A spent allowance is answered by a later reading with room in
58
+ * it; a refused credential by the account being read at all through it; and an entitlement refusal, an
59
+ * organization that has turned Claude Code off for this seat, by NOTHING either of those can produce. Its
60
+ * token authenticates and its usage endpoint answers with real pools the whole time it cannot run a turn,
61
+ * so filing it as `auth` let the very next quota sweep dismiss it and leave a full green ring over an
62
+ * account that refused everything asked of it. Only a turn that actually runs settles this one. */
63
+ kind: z
64
+ .enum(["limit", "auth", "entitlement"])
65
+ .describe(
66
+ "Three different noes, kept apart because what fixes each is different. A spent allowance is answered by waiting; a refused credential by signing in again; and an entitlement refusal, where somebody has switched this off for your seat, by neither of those. That last one authenticates fine and reports healthy limits the whole time it refuses everything.",
67
+ ),
68
+ // The provider's own sentence, verbatim. It is the only part that says WHICH pool or WHICH credential.
69
+ message: z.string().describe("The provider's own words, verbatim. The only part that says which limit or which credential."),
70
+ // The account that was serving, when the daemon knows it (native turns only, see above).
71
+ account: z.string().optional().describe("Which account was serving, where that is known."),
72
+ });
73
+ export type ProviderRefusal = z.infer<typeof ProviderRefusalSchema>;
74
+ export const ProviderRefusalsSchema = z.object({
75
+ refusals: z
76
+ .record(z.string(), ProviderRefusalSchema)
77
+ .describe(
78
+ "The most recent refusal per provider. Read alongside an account's usage: that says how full it was when last checked, this says whether it has since started saying no.",
79
+ ),
80
+ });
81
+ export type ProviderRefusals = z.infer<typeof ProviderRefusalsSchema>;
82
+ // One connected subscription in the translator. `name` is CLIProxyAPI's auth-file name, the stable store key a
83
+ // disconnect addresses, and `label` the sign-in identity it reported (the account email, else the file name).
84
+ export const TranslatorAccountSchema = z.object({
85
+ name: z.string(),
86
+ label: z.string(),
87
+ // The same headroom an OauthAccount carries, on the same field, for the same reason: the account rows are
88
+ // one list to the reader. Optional because a provider whose quota this sandbox cannot read (Grok),
89
+ // or one that did not answer, must still render as the connected account it is, with a dot instead of a
90
+ // ring.
91
+ usage: AccountUsageSchema.optional(),
92
+ });
93
+ export type TranslatorAccount = z.infer<typeof TranslatorAccountSchema>;
94
+ // Which routed-provider subscriptions are connected in the translator, per provider, a LIST per provider, not
95
+ // a flag: CLIProxyAPI holds any number of auth files per provider side by side and balances requests across
96
+ // them, so connecting a second ChatGPT or Google account is more headroom, and each is disconnectable on its
97
+ // own. Drives the account rows in Sandbox ▸ Agent.
98
+ export const TranslatorAccountsSchema = z.object({
99
+ codex: z.array(TranslatorAccountSchema),
100
+ grok: z.array(TranslatorAccountSchema),
101
+ kimi: z.array(TranslatorAccountSchema),
102
+ gemini: z.array(TranslatorAccountSchema),
103
+ });
104
+ export type TranslatorAccounts = z.infer<typeof TranslatorAccountsSchema>;
105
+ // The side-channel body that un-parks a turn waiting on the user. Every interactive card, plan approval,
106
+ // clarifying questions, a per-tool permission prompt, parks on the SAME registry keyed by `requestId`, so
107
+ // one route resolves all three; the `kind` says which card answered and carries its payload.
108
+ export const AgentReplySchema = z.discriminatedUnion("kind", [
109
+ // ExitPlanMode approval. Approving carries NO posture: an approved plan executes under bypassPermissions,
110
+ // set on the SDK session by the gate that raised the card. The container is the isolation boundary, so a
111
+ // plan the user has read and approved is exactly the point where per-tool prompts stop earning their
112
+ // interruption, landing anywhere else means approving a plan to run `git log` and then being asked whether
113
+ // `git log` may run. Rejection feedback loops back into the model as the denial reason.
114
+ z.object({
115
+ kind: z.literal("plan").describe("Answering a plan the agent proposed."),
116
+ requestId: z.string().min(1).describe("Which card you are answering, from the frame that raised it."),
117
+ approve: z
118
+ .boolean()
119
+ .describe(
120
+ "Whether to go ahead. Approving means the plan then runs without asking again per tool, because being asked whether a plan you just approved may run its first command is not a question worth having.",
121
+ ),
122
+ feedback: z.string().optional().describe("Why not, which goes back to the model as the reason."),
123
+ }),
124
+ // AskUserQuestion picks: question text → chosen option label(s) (+ any free-text "Other"). `cancelled`
125
+ // is the dismissal, which tells the model to proceed on sensible defaults rather than leaving it parked.
126
+ z.object({
127
+ kind: z.literal("question").describe("Answering a question the agent asked."),
128
+ requestId: z.string().min(1).describe("Which card you are answering."),
129
+ answers: z
130
+ .record(z.string(), z.array(z.string()))
131
+ .optional()
132
+ .describe("What you chose, keyed by the question, with the chosen labels or your own words."),
133
+ cancelled: z
134
+ .boolean()
135
+ .optional()
136
+ .describe("Dismissing it instead, which tells the agent to carry on using sensible defaults rather than leaving it waiting."),
137
+ }),
138
+ // A per-tool permission prompt. 'once' allows this call only; 'always' allows the whole TOOL for the rest
139
+ // of the session (plus the SDK's own narrower suggestions), which is what the card's label promises;
140
+ // 'deny' blocks it and feeds `feedback` back as the reason.
141
+ z.object({
142
+ kind: z.literal("permission").describe("Answering a request to use a tool."),
143
+ requestId: z.string().min(1).describe("Which card you are answering."),
144
+ decision: z
145
+ .enum(["once", "always", "deny"])
146
+ .describe("Once allows this call alone; always allows that whole tool for the rest of the conversation; no blocks it."),
147
+ feedback: z.string().optional().describe("Why not, which goes back to the model as the reason."),
148
+ }),
149
+ // A browser help request (the agent parked mid-sign-in on something only a person can clear, a captcha, a
150
+ // password it does not hold). `helped: true` is "done, hand back": the user took control of the agent's
151
+ // browser, fixed the step, and the turn continues from the page as they left it. `helped: false` is "can't
152
+ // help now", the agent is told so and moves on rather than waiting forever. `note` rides back to the model
153
+ // either way ("typed the password, don't touch the remember-me box").
154
+ z.object({
155
+ kind: z
156
+ .literal("browser_help")
157
+ .describe("Answering a request for help in the agent's browser: a captcha, a password it does not hold, a check on your phone."),
158
+ requestId: z.string().min(1).describe("Which card you are answering."),
159
+ helped: z
160
+ .boolean()
161
+ .describe(
162
+ "Whether you cleared it. Yes means the turn carries on from the page as you left it; no tells the agent so, and it moves on rather than waiting for ever.",
163
+ ),
164
+ note: z.string().optional().describe("Anything the agent should know, which goes back to it either way."),
165
+ }),
166
+ // A terminal help request, the same two answers as the browser's, for a command parked at a prompt only a
167
+ // person can answer. `helped: true` is "typed it, carry on"; false is "can't right now". `note` rides back
168
+ // either way, and on `helped` the daemon adds what the pane SAYS to the tool result: the user answering the
169
+ // prompt is exactly the moment the agent cannot see, and it would otherwise have to ask them how it went.
170
+ z.object({
171
+ kind: z
172
+ .literal("terminal_help")
173
+ .describe("Answering a request for help at a terminal: a code to type, a confirmation only a person can give."),
174
+ requestId: z.string().min(1).describe("Which card you are answering."),
175
+ helped: z
176
+ .boolean()
177
+ .describe(
178
+ "Whether you did it. Yes also hands the agent what the terminal now says, because a person answering a prompt is exactly the moment the agent cannot see.",
179
+ ),
180
+ note: z.string().optional().describe("Anything the agent should know, which goes back to it either way."),
181
+ }),
182
+ // A premium service run's yes or no. The click is the ONLY way the spend can happen, the daemon holds the
183
+ // agent's run request parked until this settles it (platform/service-offer.ts), so `approve` carries no
184
+ // qualifiers: one true releases exactly one run, and anything else charges nothing.
185
+ z.object({
186
+ kind: z.literal("service_offer").describe("Answering a request to spend on a paid service."),
187
+ requestId: z.string().min(1).describe("Which card you are answering."),
188
+ approve: z
189
+ .boolean()
190
+ .describe("Yes releases exactly one run. Anything else charges nothing. This click is the only way the spend can happen."),
191
+ }),
192
+ // A missing-capability ask's yes or no. `connect: true` is "I'll set it up", it opens the card's setup
193
+ // and keeps the agent's request parked while the daemon watches for the connection to come live
194
+ // (capabilities/capability-offer.ts); false tells the agent to continue without it. The click decides
195
+ // only the WATCHING: nothing is connected by the reply itself, the setup is the owner's own flow.
196
+ z.object({
197
+ kind: z.literal("capability_offer").describe("Answering a request to connect something the agent needs."),
198
+ requestId: z.string().min(1).describe("Which card you are answering."),
199
+ connect: z
200
+ .boolean()
201
+ .describe(
202
+ "Yes keeps the agent waiting while you set it up, and it carries on the moment the connection comes alive. No tells it to continue without. The reply itself connects nothing: setting it up is still your own doing.",
203
+ ),
204
+ }),
205
+ // A USDC payment's yes or no. The click is the ONLY way the money can move, the daemon holds the agent's
206
+ // `wallet fetch` parked until this settles it (wallet/payment-offer.ts), so `approve` carries no
207
+ // qualifiers: one true releases exactly one payment, and anything else spends nothing.
208
+ z.object({
209
+ kind: z.literal("payment_offer").describe("Answering a request to pay for something."),
210
+ requestId: z.string().min(1).describe("Which card you are answering."),
211
+ approve: z
212
+ .boolean()
213
+ .describe("Yes releases exactly one payment. Anything else spends nothing. This click is the only way the money can move."),
214
+ }),
215
+ ]);
216
+ export type AgentReply = z.infer<typeof AgentReplySchema>;
217
+ // Steering: a user message delivered INTO the running turn (injected between tool calls, Claude Code style),
218
+ // keyed by the conversation whose turn is in flight. NOT_FOUND when no steerable turn is running, the client
219
+ // then holds the message in its queue and sends it as the next turn instead. Carries everything a turn's own
220
+ // prompt can carry (files, the editor-context chip), because "add more while it works" is worth nothing if it
221
+ // only takes bare text: the daemon folds the same notes into the injected message that a fresh turn gets.
222
+ export const SteerSchema = z
223
+ .object({
224
+ conversationId: z.string().min(1).describe("Which running conversation to interrupt."),
225
+ text: z.string().max(20_000).describe("What to say to it. It arrives mid-turn without stopping the turn."),
226
+ attachments: z
227
+ .array(z.string().min(1))
228
+ .max(20)
229
+ .optional()
230
+ .describe("Files to send with it, as workspace paths. A screenshot dropped in mid-turn with no words is a legitimate thing to send."),
231
+ editorContext: EditorContextSchema.optional().describe("What you have open, folded in so that pointing words resolve."),
232
+ })
233
+ // An attachment-only steer (a screenshot dropped in mid-turn) is legal; an entirely empty one is not.
234
+ .refine((steer) => steer.text.trim().length > 0 || (steer.attachments?.length ?? 0) > 0, {
235
+ message: "text or attachments required",
236
+ });
237
+ // True cancel for the conversation's in-flight turn, aborts the agent daemon-side, unlike closing the
238
+ // /agent fetch (which sends no cancel frame).
239
+ export const StopTurnSchema = z.object({ conversationId: z.string().min(1).describe("Which conversation's running turn to cancel.") });
240
+ /* RUN THE HELD TURN AGAIN, and it carries a conversation id and NOTHING else, which is the entire point of it
241
+ * existing as its own route rather than as a flag on a turn.
242
+ *
243
+ * A spent allowance leaves a turn stranded that the daemon still holds in full: the prompt, the attachments, the
244
+ * model, the effort, the mode, the worktree, the session that holds whatever it managed to do. Every one of
245
+ * those is on the turn the daemon already has, and a client that re-derived them from its own transcript would
246
+ * be re-deriving them from the STRIPPED copy it renders (no preamble notes, no attachment note, no model), which
247
+ * is how a re-send comes to run a different turn from the one it claims to repeat.
248
+ *
249
+ * So the caller says only WHICH conversation, and the daemon re-runs the turn it kept. What comes back is an
250
+ * ordinary StartedTurn, and the caller then attaches to it exactly as it would to a turn somebody else started
251
+ * (the resume note on the prompt is what tells an attaching window to reuse the bubble that is already there
252
+ * instead of drawing the same message twice). */
253
+ export const ResumeTurnSchema = z.object({
254
+ conversationId: z.string().min(1).describe("Which conversation's held turn to run again."),
255
+ });
@@ -0,0 +1,84 @@
1
+ // ports: every listening TCP socket in the sandbox + explicit port forwarding
2
+ import { z } from "zod";
3
+ // Anything run in a terminal (a turbo TUI fanning out dev servers, `python -m http.server`, an agent's ad-hoc
4
+ // process) binds ports the daemon never assigned, the panel machinery can't see them. The /ports routes are
5
+ // the generic complement: `list` reports the live listeners (procfs scan, on demand), `forward` makes one
6
+ // reachable at port-<slot>-<sandboxId>.<zone> through the preview proxy. Forwarding is an explicit gesture,
7
+ // previews are public, so nothing is exposed until the owner (or an agent acting for them) asks.
8
+
9
+ export const PortSummarySchema = z.object({
10
+ port: z.number().describe("The port number."),
11
+ // The loopback address the listener actually answers at inside the sandbox, a `localhost` bind can land
12
+ // on ::1 only (Vite). The preview proxy and the desktop mirror (Mutagen forward) both dial this.
13
+ host: z
14
+ .enum(["127.0.0.1", "::1"])
15
+ .describe("Which loopback address it actually answers on. Some tools bind only one of the two, and anything dialling it has to know which."),
16
+ // Whether the proxy can actually reach the listener at `host`. False for a bind to a loopback alias like
17
+ // Docker's embedded DNS (127.0.0.11), which answers only at its own address, not 127.0.0.1, such rows are
18
+ // listed for transparency but the Ports view hides Preview and forwarding them is refused.
19
+ forwardable: z
20
+ .boolean()
21
+ .describe(
22
+ "Whether it can be exposed at all. Some listeners answer only at their own address and nowhere else; those are listed for honesty and refused for forwarding.",
23
+ ),
24
+ // Which bucket the Ports view files it under: `workspace` = user-run (dev servers in repos, terminal
25
+ // processes, published container ports), the previewable set; `system` = the sandbox's own machinery
26
+ // (agent runtimes, translator, dockerd, sshd), listed for transparency but nobody previews it.
27
+ kind: z
28
+ .enum(["workspace", "system"])
29
+ .describe("Whether somebody's own work put it there, or the sandbox's own machinery did. Only the first kind is worth previewing."),
30
+ /* WHAT IS ON THIS PORT, IN WORDS: resolved by the daemon (ports/port-identity.ts), because the two facts
31
+ * that attribute a listener (the panel key → extension index, the workspace root) exist there and nowhere
32
+ * else. `title` is what a person would call it ("Vite dev server", "Sandbox service", "Container port"),
33
+ * `purpose` is the one sentence a row shows under it, and `origin` says who put it there, which is what
34
+ * the reader is really asking when they ask what a port is: mine, my agent's, or the box's own.
35
+ *
36
+ * All three are required. A listener nothing can explain still gets a name ("Unclaimed port") and a
37
+ * sentence that says so out loud, because the alternative (a raw argv, or nothing) is what made this
38
+ * view unreadable, and the button beside the row publishes the port to the internet. */
39
+ title: z
40
+ .string()
41
+ .describe(
42
+ "What a person would call it. Always present: a listener nothing can explain is still named, because the button beside it publishes the port to the internet.",
43
+ ),
44
+ purpose: z.string().describe("One sentence about what it is for, including when the honest answer is that nothing could work it out."),
45
+ origin: z
46
+ .enum(["terminal", "agent", "panel", "extension", "container", "sandbox", "unknown"])
47
+ .describe("Who put it there, which is the question somebody is really asking: mine, my agent's, or the box's own."),
48
+ // The owning process, resolved from procfs; absent when no /proc/*/fd entry matched the socket's inode.
49
+ pid: z.number().optional().describe("The process holding it. Absent when nothing could be matched to the socket."),
50
+ // How the row is labeled: the process argv joined with spaces ("node /work/app/node_modules/.bin/vite"),
51
+ // falling back to the kernel `comm` name when argv is empty, or a synthesized name for attributable
52
+ // infrastructure the pid walk can't reach ("Docker embedded DNS"). Absent only when wholly unattributable.
53
+ command: z.string().optional().describe("The command behind it, as it was run. Absent only when nothing could be attributed at all."),
54
+ // The process working directory (how the UI attributes a port to a repo).
55
+ cwd: z.string().optional().describe("Where it is running from, which is how a port gets attributed to a repository."),
56
+ // The tmux session the listener descends from, the terminal to watch it in or stop it from. Absent when
57
+ // nothing in its ancestry is a pane (a daemon-managed runtime, a published container's docker-proxy), which
58
+ // is the honest "you cannot reach this from here" rather than a terminal that would open onto nothing.
59
+ session: z
60
+ .string()
61
+ .optional()
62
+ .describe(
63
+ 'The terminal it came from, to watch it in or stop it from. Absent when nothing in its ancestry is one, which is the honest "you cannot reach this from here".',
64
+ ),
65
+ forwarded: z.boolean().describe("Whether it is currently reachable from outside."),
66
+ // https://port-<slot>-<sandboxId>.<zone>; present only while forwarded AND the sandbox has a zone + id.
67
+ previewUrl: z.string().optional().describe("Where to open it. Present only while forwarded, and only on a sandbox that has an outside address."),
68
+ });
69
+ export type PortSummary = z.infer<typeof PortSummarySchema>;
70
+ export const PortsListSchema = z.object({
71
+ ports: z
72
+ .array(PortSummarySchema)
73
+ .describe("Everything listening inside the sandbox right now, read fresh each time rather than from a register the sandbox keeps."),
74
+ });
75
+ export type PortsList = z.infer<typeof PortsListSchema>;
76
+ export const PortParamSchema = z.object({ port: z.number().int().min(1).max(65535).describe("Which port.") });
77
+ // `previewUrl` is absent on a loopback/no-tunnel sandbox, the slot is mapped, but no public hostname exists.
78
+ export const PortForwardResultSchema = z.object({
79
+ previewUrl: z
80
+ .string()
81
+ .optional()
82
+ .describe("Where it can now be reached. Absent on a sandbox with no outside address, where the mapping exists but has no public name."),
83
+ });
84
+ export type PortForwardResult = z.infer<typeof PortForwardResultSchema>;