@intentic/sandbox-contract 1.232.0 → 1.234.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 (538) hide show
  1. package/README.md +11 -5
  2. package/dist/agent-catalog.d.ts +4 -2
  3. package/dist/agent-catalog.d.ts.map +1 -1
  4. package/dist/agent-catalog.js +20 -14
  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/chores.js +36 -1
  9. package/dist/chores/chores.js.map +1 -1
  10. package/dist/chores/probes.d.ts +1 -1
  11. package/dist/chores/probes.d.ts.map +1 -1
  12. package/dist/chores/probes.js +70 -0
  13. package/dist/chores/probes.js.map +1 -1
  14. package/dist/chores/stack.d.ts.map +1 -1
  15. package/dist/chores/stack.js +2 -1
  16. package/dist/chores/stack.js.map +1 -1
  17. package/dist/chores/verdict.d.ts +1 -1
  18. package/dist/chores/verdict.d.ts.map +1 -1
  19. package/dist/command-classes.d.ts +17 -0
  20. package/dist/command-classes.d.ts.map +1 -0
  21. package/dist/command-classes.js +189 -0
  22. package/dist/command-classes.js.map +1 -0
  23. package/dist/contracts/activity.contract.js +1 -1
  24. package/dist/contracts/activity.contract.js.map +1 -1
  25. package/dist/contracts/agent.contract.d.ts +40 -2
  26. package/dist/contracts/agent.contract.d.ts.map +1 -1
  27. package/dist/contracts/agent.contract.js +4 -1
  28. package/dist/contracts/agent.contract.js.map +1 -1
  29. package/dist/contracts/agents.contract.d.ts +24 -0
  30. package/dist/contracts/agents.contract.d.ts.map +1 -1
  31. package/dist/contracts/agents.contract.js +5 -1
  32. package/dist/contracts/agents.contract.js.map +1 -1
  33. package/dist/contracts/automations.contract.d.ts +30 -0
  34. package/dist/contracts/automations.contract.d.ts.map +1 -1
  35. package/dist/contracts/automations.contract.js +2 -1
  36. package/dist/contracts/automations.contract.js.map +1 -1
  37. package/dist/contracts/capabilities.contract.d.ts +63 -0
  38. package/dist/contracts/capabilities.contract.d.ts.map +1 -1
  39. package/dist/contracts/capabilities.contract.js +3 -1
  40. package/dist/contracts/capabilities.contract.js.map +1 -1
  41. package/dist/contracts/chores.contract.d.ts +17 -0
  42. package/dist/contracts/chores.contract.d.ts.map +1 -1
  43. package/dist/contracts/chores.contract.js +2 -1
  44. package/dist/contracts/chores.contract.js.map +1 -1
  45. package/dist/contracts/ci.contract.js +2 -1
  46. package/dist/contracts/ci.contract.js.map +1 -1
  47. package/dist/contracts/claude.contract.js +2 -1
  48. package/dist/contracts/claude.contract.js.map +1 -1
  49. package/dist/contracts/cursor.contract.js +2 -1
  50. package/dist/contracts/cursor.contract.js.map +1 -1
  51. package/dist/contracts/drafts.contract.d.ts.map +1 -1
  52. package/dist/contracts/drafts.contract.js +2 -1
  53. package/dist/contracts/drafts.contract.js.map +1 -1
  54. package/dist/contracts/endpoints.contract.d.ts.map +1 -1
  55. package/dist/contracts/endpoints.contract.js +2 -1
  56. package/dist/contracts/endpoints.contract.js.map +1 -1
  57. package/dist/contracts/exit.contract.d.ts.map +1 -1
  58. package/dist/contracts/exit.contract.js +2 -1
  59. package/dist/contracts/exit.contract.js.map +1 -1
  60. package/dist/contracts/extensions.contract.d.ts +44 -0
  61. package/dist/contracts/extensions.contract.d.ts.map +1 -1
  62. package/dist/contracts/extensions.contract.js +4 -1
  63. package/dist/contracts/extensions.contract.js.map +1 -1
  64. package/dist/contracts/git.contract.d.ts.map +1 -1
  65. package/dist/contracts/git.contract.js +4 -1
  66. package/dist/contracts/git.contract.js.map +1 -1
  67. package/dist/contracts/grok.contract.d.ts.map +1 -1
  68. package/dist/contracts/grok.contract.js +2 -1
  69. package/dist/contracts/grok.contract.js.map +1 -1
  70. package/dist/contracts/history.contract.d.ts.map +1 -1
  71. package/dist/contracts/history.contract.js +2 -1
  72. package/dist/contracts/history.contract.js.map +1 -1
  73. package/dist/contracts/host.contract.d.ts +7 -0
  74. package/dist/contracts/host.contract.d.ts.map +1 -1
  75. package/dist/contracts/host.contract.js +4 -1
  76. package/dist/contracts/host.contract.js.map +1 -1
  77. package/dist/contracts/intentic.contract.d.ts.map +1 -1
  78. package/dist/contracts/intentic.contract.js +2 -1
  79. package/dist/contracts/intentic.contract.js.map +1 -1
  80. package/dist/contracts/inventory.contract.js +1 -1
  81. package/dist/contracts/inventory.contract.js.map +1 -1
  82. package/dist/contracts/issues.contract.d.ts +89 -0
  83. package/dist/contracts/issues.contract.d.ts.map +1 -0
  84. package/dist/contracts/issues.contract.js +50 -0
  85. package/dist/contracts/issues.contract.js.map +1 -0
  86. package/dist/contracts/logs.contract.d.ts.map +1 -1
  87. package/dist/contracts/logs.contract.js +1 -1
  88. package/dist/contracts/logs.contract.js.map +1 -1
  89. package/dist/contracts/loops.contract.js +2 -1
  90. package/dist/contracts/loops.contract.js.map +1 -1
  91. package/dist/contracts/panels.contract.d.ts.map +1 -1
  92. package/dist/contracts/panels.contract.js +2 -1
  93. package/dist/contracts/panels.contract.js.map +1 -1
  94. package/dist/contracts/personas.contract.js +2 -1
  95. package/dist/contracts/personas.contract.js.map +1 -1
  96. package/dist/contracts/ports.contract.d.ts.map +1 -1
  97. package/dist/contracts/ports.contract.js +2 -1
  98. package/dist/contracts/ports.contract.js.map +1 -1
  99. package/dist/contracts/prepush.contract.d.ts.map +1 -1
  100. package/dist/contracts/prepush.contract.js +2 -1
  101. package/dist/contracts/prepush.contract.js.map +1 -1
  102. package/dist/contracts/providers.contract.d.ts.map +1 -1
  103. package/dist/contracts/providers.contract.js +2 -1
  104. package/dist/contracts/providers.contract.js.map +1 -1
  105. package/dist/contracts/public.contract.d.ts.map +1 -1
  106. package/dist/contracts/public.contract.js +2 -1
  107. package/dist/contracts/public.contract.js.map +1 -1
  108. package/dist/contracts/push.contract.d.ts.map +1 -1
  109. package/dist/contracts/push.contract.js +2 -1
  110. package/dist/contracts/push.contract.js.map +1 -1
  111. package/dist/contracts/runner.contract.d.ts +127 -84
  112. package/dist/contracts/runner.contract.d.ts.map +1 -1
  113. package/dist/contracts/runner.contract.js +10 -2
  114. package/dist/contracts/runner.contract.js.map +1 -1
  115. package/dist/contracts/secrets.contract.d.ts.map +1 -1
  116. package/dist/contracts/secrets.contract.js +2 -1
  117. package/dist/contracts/secrets.contract.js.map +1 -1
  118. package/dist/contracts/sessions.contract.js +1 -1
  119. package/dist/contracts/sessions.contract.js.map +1 -1
  120. package/dist/contracts/settings.contract.d.ts +32 -0
  121. package/dist/contracts/settings.contract.d.ts.map +1 -1
  122. package/dist/contracts/settings.contract.js +3 -1
  123. package/dist/contracts/settings.contract.js.map +1 -1
  124. package/dist/contracts/share.contract.d.ts.map +1 -1
  125. package/dist/contracts/share.contract.js +2 -1
  126. package/dist/contracts/share.contract.js.map +1 -1
  127. package/dist/contracts/skills.contract.d.ts.map +1 -1
  128. package/dist/contracts/skills.contract.js +2 -1
  129. package/dist/contracts/skills.contract.js.map +1 -1
  130. package/dist/contracts/system.contract.d.ts +31 -16
  131. package/dist/contracts/system.contract.d.ts.map +1 -1
  132. package/dist/contracts/system.contract.js +6 -1
  133. package/dist/contracts/system.contract.js.map +1 -1
  134. package/dist/contracts/translator.contract.d.ts.map +1 -1
  135. package/dist/contracts/translator.contract.js +4 -1
  136. package/dist/contracts/translator.contract.js.map +1 -1
  137. package/dist/contracts/usage.contract.js +1 -1
  138. package/dist/contracts/usage.contract.js.map +1 -1
  139. package/dist/contracts/vpn.contract.d.ts.map +1 -1
  140. package/dist/contracts/vpn.contract.js +2 -1
  141. package/dist/contracts/vpn.contract.js.map +1 -1
  142. package/dist/contracts/webext.contract.d.ts +45 -0
  143. package/dist/contracts/webext.contract.d.ts.map +1 -0
  144. package/dist/contracts/webext.contract.js +12 -0
  145. package/dist/contracts/webext.contract.js.map +1 -0
  146. package/dist/contracts/workflows.contract.js +2 -1
  147. package/dist/contracts/workflows.contract.js.map +1 -1
  148. package/dist/contracts/workspace.contract.d.ts +2 -2
  149. package/dist/contracts/workspace.contract.d.ts.map +1 -1
  150. package/dist/contracts/workspace.contract.js +7 -1
  151. package/dist/contracts/workspace.contract.js.map +1 -1
  152. package/dist/credential-material.d.ts +2 -0
  153. package/dist/credential-material.d.ts.map +1 -0
  154. package/dist/credential-material.js +36 -0
  155. package/dist/credential-material.js.map +1 -0
  156. package/dist/definition-action.d.ts +7 -0
  157. package/dist/definition-action.d.ts.map +1 -0
  158. package/dist/definition-action.js +3 -0
  159. package/dist/definition-action.js.map +1 -0
  160. package/dist/definition.d.ts +132 -21
  161. package/dist/definition.d.ts.map +1 -1
  162. package/dist/definition.js +29 -7
  163. package/dist/definition.js.map +1 -1
  164. package/dist/events.d.ts +101 -0
  165. package/dist/events.d.ts.map +1 -1
  166. package/dist/events.js +25 -1
  167. package/dist/events.js.map +1 -1
  168. package/dist/fast-tier.d.ts +1 -1
  169. package/dist/fast-tier.d.ts.map +1 -1
  170. package/dist/history-state.d.ts.map +1 -1
  171. package/dist/history-state.js +2 -0
  172. package/dist/history-state.js.map +1 -1
  173. package/dist/hostnames.d.ts +2 -0
  174. package/dist/hostnames.d.ts.map +1 -1
  175. package/dist/hostnames.js +3 -1
  176. package/dist/hostnames.js.map +1 -1
  177. package/dist/index.d.ts +411 -7
  178. package/dist/index.d.ts.map +1 -1
  179. package/dist/index.js +56 -1
  180. package/dist/index.js.map +1 -1
  181. package/dist/listener-protocol.js +1 -1
  182. package/dist/listener-protocol.js.map +1 -1
  183. package/dist/quick-model.d.ts +1 -1
  184. package/dist/quick-model.d.ts.map +1 -1
  185. package/dist/runner-protocol.d.ts +18 -0
  186. package/dist/runner-protocol.d.ts.map +1 -1
  187. package/dist/runner-protocol.js +8 -4
  188. package/dist/runner-protocol.js.map +1 -1
  189. package/dist/runtime-state.d.ts +9 -0
  190. package/dist/runtime-state.d.ts.map +1 -1
  191. package/dist/runtime-state.js +3 -0
  192. package/dist/runtime-state.js.map +1 -1
  193. package/dist/schemas/activity.d.ts +112 -0
  194. package/dist/schemas/activity.d.ts.map +1 -0
  195. package/dist/schemas/activity.js +70 -0
  196. package/dist/schemas/activity.js.map +1 -0
  197. package/dist/schemas/agent.d.ts +195 -0
  198. package/dist/schemas/agent.d.ts.map +1 -0
  199. package/dist/schemas/agent.js +171 -0
  200. package/dist/schemas/agent.js.map +1 -0
  201. package/dist/schemas/agents.d.ts +690 -0
  202. package/dist/schemas/agents.d.ts.map +1 -0
  203. package/dist/schemas/agents.js +314 -0
  204. package/dist/schemas/agents.js.map +1 -0
  205. package/dist/schemas/automations.d.ts +781 -0
  206. package/dist/schemas/automations.d.ts.map +1 -0
  207. package/dist/schemas/automations.js +223 -0
  208. package/dist/schemas/automations.js.map +1 -0
  209. package/dist/schemas/capabilities.d.ts +753 -0
  210. package/dist/schemas/capabilities.d.ts.map +1 -0
  211. package/dist/schemas/capabilities.js +269 -0
  212. package/dist/schemas/capabilities.js.map +1 -0
  213. package/dist/schemas/ci.d.ts +179 -0
  214. package/dist/schemas/ci.d.ts.map +1 -0
  215. package/dist/schemas/ci.js +99 -0
  216. package/dist/schemas/ci.js.map +1 -0
  217. package/dist/schemas/claude-gate.d.ts +13 -0
  218. package/dist/schemas/claude-gate.d.ts.map +1 -0
  219. package/dist/schemas/claude-gate.js +8 -0
  220. package/dist/schemas/claude-gate.js.map +1 -0
  221. package/dist/schemas/codebase-health.d.ts +56 -0
  222. package/dist/schemas/codebase-health.d.ts.map +1 -0
  223. package/dist/schemas/codebase-health.js +43 -0
  224. package/dist/schemas/codebase-health.js.map +1 -0
  225. package/dist/schemas/computers.d.ts +386 -0
  226. package/dist/schemas/computers.d.ts.map +1 -0
  227. package/dist/schemas/computers.js +107 -0
  228. package/dist/schemas/computers.js.map +1 -0
  229. package/dist/schemas/drafts.d.ts +84 -0
  230. package/dist/schemas/drafts.d.ts.map +1 -0
  231. package/dist/schemas/drafts.js +44 -0
  232. package/dist/schemas/drafts.js.map +1 -0
  233. package/dist/schemas/environment.d.ts +349 -0
  234. package/dist/schemas/environment.d.ts.map +1 -0
  235. package/dist/schemas/environment.js +111 -0
  236. package/dist/schemas/environment.js.map +1 -0
  237. package/dist/schemas/exit.d.ts +151 -0
  238. package/dist/schemas/exit.d.ts.map +1 -0
  239. package/dist/schemas/exit.js +115 -0
  240. package/dist/schemas/exit.js.map +1 -0
  241. package/dist/schemas/extension-updates.d.ts +1016 -0
  242. package/dist/schemas/extension-updates.d.ts.map +1 -0
  243. package/dist/schemas/extension-updates.js +199 -0
  244. package/dist/schemas/extension-updates.js.map +1 -0
  245. package/dist/schemas/fast-mode.d.ts +8 -0
  246. package/dist/schemas/fast-mode.d.ts.map +1 -0
  247. package/dist/schemas/fast-mode.js +3 -0
  248. package/dist/schemas/fast-mode.js.map +1 -0
  249. package/dist/schemas/git-history.d.ts +238 -0
  250. package/dist/schemas/git-history.d.ts.map +1 -0
  251. package/dist/schemas/git-history.js +152 -0
  252. package/dist/schemas/git-history.js.map +1 -0
  253. package/dist/schemas/git.d.ts +471 -0
  254. package/dist/schemas/git.d.ts.map +1 -0
  255. package/dist/schemas/git.js +204 -0
  256. package/dist/schemas/git.js.map +1 -0
  257. package/dist/schemas/history.d.ts +100 -0
  258. package/dist/schemas/history.d.ts.map +1 -0
  259. package/dist/schemas/history.js +54 -0
  260. package/dist/schemas/history.js.map +1 -0
  261. package/dist/schemas/hosts.d.ts +41 -0
  262. package/dist/schemas/hosts.d.ts.map +1 -0
  263. package/dist/schemas/hosts.js +18 -0
  264. package/dist/schemas/hosts.js.map +1 -0
  265. package/dist/schemas/intentic.d.ts +5 -0
  266. package/dist/schemas/intentic.d.ts.map +1 -0
  267. package/dist/schemas/intentic.js +3 -0
  268. package/dist/schemas/intentic.js.map +1 -0
  269. package/dist/schemas/internal.d.ts +8 -0
  270. package/dist/schemas/internal.d.ts.map +1 -0
  271. package/dist/schemas/internal.js +12 -0
  272. package/dist/schemas/internal.js.map +1 -0
  273. package/dist/schemas/inventory.d.ts +171 -0
  274. package/dist/schemas/inventory.d.ts.map +1 -0
  275. package/dist/schemas/inventory.js +51 -0
  276. package/dist/schemas/inventory.js.map +1 -0
  277. package/dist/schemas/issues.d.ts +324 -0
  278. package/dist/schemas/issues.d.ts.map +1 -0
  279. package/dist/schemas/issues.js +107 -0
  280. package/dist/schemas/issues.js.map +1 -0
  281. package/dist/schemas/logs.d.ts +67 -0
  282. package/dist/schemas/logs.d.ts.map +1 -0
  283. package/dist/schemas/logs.js +54 -0
  284. package/dist/schemas/logs.js.map +1 -0
  285. package/dist/schemas/loops.d.ts +415 -0
  286. package/dist/schemas/loops.d.ts.map +1 -0
  287. package/dist/schemas/loops.js +188 -0
  288. package/dist/schemas/loops.js.map +1 -0
  289. package/dist/schemas/maintenance.d.ts +618 -0
  290. package/dist/schemas/maintenance.d.ts.map +1 -0
  291. package/dist/schemas/maintenance.js +222 -0
  292. package/dist/schemas/maintenance.js.map +1 -0
  293. package/dist/schemas/marketplace.d.ts +64 -0
  294. package/dist/schemas/marketplace.d.ts.map +1 -0
  295. package/dist/schemas/marketplace.js +17 -0
  296. package/dist/schemas/marketplace.js.map +1 -0
  297. package/dist/schemas/panels.d.ts +61 -0
  298. package/dist/schemas/panels.d.ts.map +1 -0
  299. package/dist/schemas/panels.js +51 -0
  300. package/dist/schemas/panels.js.map +1 -0
  301. package/dist/schemas/personas.d.ts +122 -0
  302. package/dist/schemas/personas.d.ts.map +1 -0
  303. package/dist/schemas/personas.js +102 -0
  304. package/dist/schemas/personas.js.map +1 -0
  305. package/dist/schemas/plan-limits.d.ts +172 -0
  306. package/dist/schemas/plan-limits.d.ts.map +1 -0
  307. package/dist/schemas/plan-limits.js +126 -0
  308. package/dist/schemas/plan-limits.js.map +1 -0
  309. package/dist/schemas/ports.d.ts +71 -0
  310. package/dist/schemas/ports.d.ts.map +1 -0
  311. package/dist/schemas/ports.js +42 -0
  312. package/dist/schemas/ports.js.map +1 -0
  313. package/dist/schemas/provider-oauth.d.ts +128 -0
  314. package/dist/schemas/provider-oauth.d.ts.map +1 -0
  315. package/dist/schemas/provider-oauth.js +91 -0
  316. package/dist/schemas/provider-oauth.js.map +1 -0
  317. package/dist/schemas/provider-subscriptions.d.ts +9 -0
  318. package/dist/schemas/provider-subscriptions.d.ts.map +1 -0
  319. package/dist/schemas/provider-subscriptions.js +3 -0
  320. package/dist/schemas/provider-subscriptions.js.map +1 -0
  321. package/dist/schemas/public.d.ts +32 -0
  322. package/dist/schemas/public.d.ts.map +1 -0
  323. package/dist/schemas/public.js +29 -0
  324. package/dist/schemas/public.js.map +1 -0
  325. package/dist/schemas/push.d.ts +55 -0
  326. package/dist/schemas/push.d.ts.map +1 -0
  327. package/dist/schemas/push.js +60 -0
  328. package/dist/schemas/push.js.map +1 -0
  329. package/dist/schemas/secrets.d.ts +86 -0
  330. package/dist/schemas/secrets.d.ts.map +1 -0
  331. package/dist/schemas/secrets.js +51 -0
  332. package/dist/schemas/secrets.js.map +1 -0
  333. package/dist/schemas/sessions.d.ts +32 -0
  334. package/dist/schemas/sessions.d.ts.map +1 -0
  335. package/dist/schemas/sessions.js +11 -0
  336. package/dist/schemas/sessions.js.map +1 -0
  337. package/dist/schemas/settings.d.ts +554 -0
  338. package/dist/schemas/settings.d.ts.map +1 -0
  339. package/dist/schemas/settings.js +263 -0
  340. package/dist/schemas/settings.js.map +1 -0
  341. package/dist/schemas/share.d.ts +49 -0
  342. package/dist/schemas/share.d.ts.map +1 -0
  343. package/dist/schemas/share.js +26 -0
  344. package/dist/schemas/share.js.map +1 -0
  345. package/dist/schemas/shared.d.ts +22 -0
  346. package/dist/schemas/shared.d.ts.map +1 -0
  347. package/dist/schemas/shared.js +16 -0
  348. package/dist/schemas/shared.js.map +1 -0
  349. package/dist/schemas/system.d.ts +86 -0
  350. package/dist/schemas/system.d.ts.map +1 -0
  351. package/dist/schemas/system.js +64 -0
  352. package/dist/schemas/system.js.map +1 -0
  353. package/dist/schemas/terminal.d.ts +230 -0
  354. package/dist/schemas/terminal.d.ts.map +1 -0
  355. package/dist/schemas/terminal.js +133 -0
  356. package/dist/schemas/terminal.js.map +1 -0
  357. package/dist/schemas/usage.d.ts +113 -0
  358. package/dist/schemas/usage.d.ts.map +1 -0
  359. package/dist/schemas/usage.js +91 -0
  360. package/dist/schemas/usage.js.map +1 -0
  361. package/dist/schemas/vpn.d.ts +229 -0
  362. package/dist/schemas/vpn.d.ts.map +1 -0
  363. package/dist/schemas/vpn.js +115 -0
  364. package/dist/schemas/vpn.js.map +1 -0
  365. package/dist/schemas/webext.d.ts +122 -0
  366. package/dist/schemas/webext.d.ts.map +1 -0
  367. package/dist/schemas/webext.js +45 -0
  368. package/dist/schemas/webext.js.map +1 -0
  369. package/dist/schemas/workflows.d.ts +881 -0
  370. package/dist/schemas/workflows.d.ts.map +1 -0
  371. package/dist/schemas/workflows.js +164 -0
  372. package/dist/schemas/workflows.js.map +1 -0
  373. package/dist/schemas/workspace-repos.d.ts +143 -0
  374. package/dist/schemas/workspace-repos.d.ts.map +1 -0
  375. package/dist/schemas/workspace-repos.js +87 -0
  376. package/dist/schemas/workspace-repos.js.map +1 -0
  377. package/dist/schemas/workspace-search.d.ts +170 -0
  378. package/dist/schemas/workspace-search.d.ts.map +1 -0
  379. package/dist/schemas/workspace-search.js +85 -0
  380. package/dist/schemas/workspace-search.js.map +1 -0
  381. package/dist/schemas/workspace-setup.d.ts +48 -0
  382. package/dist/schemas/workspace-setup.d.ts.map +1 -0
  383. package/dist/schemas/workspace-setup.js +26 -0
  384. package/dist/schemas/workspace-setup.js.map +1 -0
  385. package/dist/schemas/workspace-tree.d.ts +120 -0
  386. package/dist/schemas/workspace-tree.d.ts.map +1 -0
  387. package/dist/schemas/workspace-tree.js +111 -0
  388. package/dist/schemas/workspace-tree.js.map +1 -0
  389. package/dist/webext-links.d.ts +14 -0
  390. package/dist/webext-links.d.ts.map +1 -0
  391. package/dist/webext-links.js +25 -0
  392. package/dist/webext-links.js.map +1 -0
  393. package/dist/webext-protocol.d.ts +8 -0
  394. package/dist/webext-protocol.d.ts.map +1 -0
  395. package/dist/webext-protocol.js +7 -0
  396. package/dist/webext-protocol.js.map +1 -0
  397. package/dist/workflow-faults.d.ts +1 -1
  398. package/dist/workflow-faults.d.ts.map +1 -1
  399. package/dist/workspace-state.d.ts +12 -8
  400. package/dist/workspace-state.d.ts.map +1 -1
  401. package/dist/workspace-state.js +15 -10
  402. package/dist/workspace-state.js.map +1 -1
  403. package/package.json +19 -8
  404. package/src/agent-catalog.test.ts +56 -55
  405. package/src/agent-catalog.ts +33 -33
  406. package/src/capability-ledger.test.ts +11 -2
  407. package/src/chores/chores.test.ts +1 -1
  408. package/src/chores/chores.ts +67 -2
  409. package/src/chores/probes.test.ts +65 -0
  410. package/src/chores/probes.ts +133 -1
  411. package/src/chores/stack.test.ts +19 -0
  412. package/src/chores/stack.ts +19 -3
  413. package/src/chores/verdict.test.ts +40 -20
  414. package/src/chores/verdict.ts +1 -1
  415. package/src/command-classes.test.ts +445 -0
  416. package/src/command-classes.ts +468 -0
  417. package/src/contracts/activity.contract.ts +1 -1
  418. package/src/contracts/agent.contract.ts +4 -13
  419. package/src/contracts/agents.contract.ts +6 -6
  420. package/src/contracts/automations.contract.ts +2 -2
  421. package/src/contracts/capabilities.contract.ts +3 -4
  422. package/src/contracts/chores.contract.ts +2 -1
  423. package/src/contracts/ci.contract.ts +2 -2
  424. package/src/contracts/claude.contract.ts +2 -2
  425. package/src/contracts/cursor.contract.ts +2 -2
  426. package/src/contracts/drafts.contract.ts +2 -1
  427. package/src/contracts/endpoints.contract.ts +2 -1
  428. package/src/contracts/exit.contract.ts +2 -1
  429. package/src/contracts/extensions.contract.ts +8 -7
  430. package/src/contracts/git.contract.ts +19 -18
  431. package/src/contracts/grok.contract.ts +2 -1
  432. package/src/contracts/history.contract.ts +2 -1
  433. package/src/contracts/host.contract.ts +4 -1
  434. package/src/contracts/intentic.contract.ts +2 -1
  435. package/src/contracts/inventory.contract.ts +1 -1
  436. package/src/contracts/issues.contract.ts +60 -0
  437. package/src/contracts/logs.contract.ts +7 -1
  438. package/src/contracts/loops.contract.ts +2 -2
  439. package/src/contracts/panels.contract.ts +2 -1
  440. package/src/contracts/personas.contract.ts +3 -3
  441. package/src/contracts/ports.contract.ts +3 -2
  442. package/src/contracts/prepush.contract.ts +2 -1
  443. package/src/contracts/providers.contract.ts +2 -1
  444. package/src/contracts/public.contract.ts +3 -2
  445. package/src/contracts/push.contract.ts +2 -1
  446. package/src/contracts/runner.contract.ts +18 -2
  447. package/src/contracts/secrets.contract.ts +2 -1
  448. package/src/contracts/sessions.contract.ts +1 -1
  449. package/src/contracts/settings.contract.ts +3 -9
  450. package/src/contracts/share.contract.ts +3 -2
  451. package/src/contracts/skills.contract.ts +2 -1
  452. package/src/contracts/system.contract.ts +6 -9
  453. package/src/contracts/translator.contract.ts +4 -1
  454. package/src/contracts/usage.contract.ts +1 -1
  455. package/src/contracts/vpn.contract.ts +2 -8
  456. package/src/contracts/webext.contract.ts +37 -0
  457. package/src/contracts/workflows.contract.ts +2 -2
  458. package/src/contracts/workspace.contract.ts +10 -12
  459. package/src/conversation-ids.test.ts +1 -1
  460. package/src/credential-material.test.ts +120 -0
  461. package/src/credential-material.ts +100 -0
  462. package/src/definition-action.ts +8 -0
  463. package/src/definition.ts +74 -10
  464. package/src/events.ts +84 -22
  465. package/src/fast-tier.ts +1 -1
  466. package/src/history-state.ts +17 -0
  467. package/src/host-protocol.ts +1 -1
  468. package/src/hostnames.test.ts +2 -2
  469. package/src/hostnames.ts +18 -2
  470. package/src/index.ts +65 -1
  471. package/src/listener-protocol.ts +1 -1
  472. package/src/quick-model.ts +1 -1
  473. package/src/routes.test.ts +4 -2
  474. package/src/runner-protocol.ts +35 -5
  475. package/src/runtime-state.ts +16 -0
  476. package/src/schemas/activity.ts +123 -0
  477. package/src/schemas/agent.ts +422 -0
  478. package/src/schemas/agents.ts +802 -0
  479. package/src/schemas/automations.ts +522 -0
  480. package/src/schemas/capabilities.ts +729 -0
  481. package/src/schemas/ci.ts +235 -0
  482. package/src/schemas/claude-gate.ts +13 -0
  483. package/src/schemas/codebase-health.ts +64 -0
  484. package/src/schemas/computers.ts +287 -0
  485. package/src/schemas/drafts.ts +108 -0
  486. package/src/schemas/environment.ts +276 -0
  487. package/src/schemas/exit.ts +222 -0
  488. package/src/schemas/extension-updates.ts +324 -0
  489. package/src/schemas/fast-mode.ts +8 -0
  490. package/src/schemas/git-history.ts +265 -0
  491. package/src/schemas/git.ts +430 -0
  492. package/src/schemas/history.ts +112 -0
  493. package/src/schemas/hosts.ts +37 -0
  494. package/src/schemas/intentic.ts +2 -0
  495. package/src/schemas/internal.ts +17 -0
  496. package/src/schemas/inventory.ts +68 -0
  497. package/src/schemas/issues.ts +279 -0
  498. package/src/schemas/logs.ts +96 -0
  499. package/src/schemas/loops.ts +401 -0
  500. package/src/schemas/maintenance.ts +471 -0
  501. package/src/schemas/marketplace.ts +23 -0
  502. package/src/schemas/panels.ts +99 -0
  503. package/src/schemas/personas.ts +281 -0
  504. package/src/schemas/plan-limits.ts +255 -0
  505. package/src/schemas/ports.ts +84 -0
  506. package/src/schemas/provider-oauth.ts +191 -0
  507. package/src/schemas/provider-subscriptions.ts +11 -0
  508. package/src/schemas/public.ts +52 -0
  509. package/src/schemas/push.ts +112 -0
  510. package/src/schemas/secrets.ts +68 -0
  511. package/src/schemas/sessions.ts +16 -0
  512. package/src/schemas/settings.ts +964 -0
  513. package/src/schemas/share.ts +71 -0
  514. package/src/schemas/shared.ts +32 -0
  515. package/src/schemas/system.ts +156 -0
  516. package/src/schemas/terminal.ts +288 -0
  517. package/src/schemas/usage.ts +303 -0
  518. package/src/{schemas.test.ts → schemas/version-seam.test.ts} +4 -2
  519. package/src/schemas/vpn.ts +215 -0
  520. package/src/schemas/webext.ts +108 -0
  521. package/src/schemas/workflows.ts +413 -0
  522. package/src/schemas/workspace-repos.ts +123 -0
  523. package/src/schemas/workspace-search.ts +141 -0
  524. package/src/schemas/workspace-setup.ts +43 -0
  525. package/src/schemas/workspace-tree.ts +234 -0
  526. package/src/title.test.ts +1 -1
  527. package/src/tunnel-ids.test.ts +3 -1
  528. package/src/webext-links.ts +90 -0
  529. package/src/webext-protocol.ts +27 -0
  530. package/src/workflow-faults.test.ts +1 -1
  531. package/src/workflow-faults.ts +1 -1
  532. package/src/workspace-state.test.ts +6 -4
  533. package/src/workspace-state.ts +35 -50
  534. package/dist/schemas.d.ts +0 -9909
  535. package/dist/schemas.d.ts.map +0 -1
  536. package/dist/schemas.js +0 -4288
  537. package/dist/schemas.js.map +0 -1
  538. package/src/schemas.ts +0 -10090
@@ -0,0 +1,120 @@
1
+ import { describe, expect, test } from "vitest";
2
+ import { holdsCredentialMaterial } from "./credential-material.js";
3
+
4
+ /* The two directions are not symmetric and the tests are written to say so: a MISS here costs one permission
5
+ * card that should not have been raised, and a WRONG CLEAR un-gates a real credential read. So the "no" cases
6
+ * are the ones that have to be exactly right, and every "yes" case is a real file's real shape. */
7
+
8
+ describe("files that hold a credential", () => {
9
+ test("an npmrc with a token", () => {
10
+ expect(holdsCredentialMaterial("//registry.npmjs.org/:_authToken=npm_wCq3nTvR8xLm2ZbKp7HdJyE4sUaF6gN0iQ1t\n")).toBe(true);
11
+ });
12
+
13
+ test("an aws credentials ini", () => {
14
+ expect(
15
+ holdsCredentialMaterial("[default]\naws_access_key_id = AKIAIOSFODNN7EXAMPLE\naws_secret_access_key = wJalrXUtnFEMI/K7MDENG\n"),
16
+ ).toBe(true);
17
+ });
18
+
19
+ test("a private key file, whatever generated it", () => {
20
+ for (const text of [
21
+ "-----BEGIN OPENSSH PRIVATE KEY-----\nb3BlbnNzaC1rZXktdjEAAAAA\n-----END OPENSSH PRIVATE KEY-----\n",
22
+ "-----BEGIN RSA PRIVATE KEY-----\nMIIEow\n",
23
+ "-----BEGIN PRIVATE KEY-----\nMIIEvQ\n",
24
+ "PuTTY-User-Key-File-3: ssh-ed25519\nEncryption: none\n",
25
+ ]) {
26
+ expect(holdsCredentialMaterial(text), text.slice(0, 30)).toBe(true);
27
+ }
28
+ });
29
+
30
+ // `.git-credentials` is nothing but these lines, and a dotenv hides the same secret inside a connection
31
+ // string, where no key names it.
32
+ test("a password carried in a URL", () => {
33
+ expect(holdsCredentialMaterial("https://radarsu:ghp_S8kQ2mVx@github.com\n")).toBe(true);
34
+ expect(holdsCredentialMaterial("DATABASE_URL=postgres://app:Rk29fPqz@db.internal:5432/app\n")).toBe(true);
35
+ });
36
+
37
+ test("a dotenv with one real value among the ordinary ones", () => {
38
+ expect(holdsCredentialMaterial("PORT=3000\nNODE_ENV=production\nSTRIPE_SECRET=sk_live_51H8xQzRvKpLmNbTy\n")).toBe(true);
39
+ });
40
+
41
+ test("a json credentials file", () => {
42
+ expect(holdsCredentialMaterial('{"accessToken":"ya29.a0AfB_bJq2Lm","expiresAt":1767000000}')).toBe(true);
43
+ });
44
+
45
+ // The issuers whose tokens announce themselves, found without any key naming them.
46
+ test("a token that carries its own prefix", () => {
47
+ for (const text of [
48
+ "ghp_16C7e42F292c6912E7710c838347Ae178B4a",
49
+ "xoxb-2410-1230-AbCdEfGhIjKlMnOpQrSt",
50
+ "AKIAIOSFODNN7EXAMPLE",
51
+ "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U",
52
+ ]) {
53
+ expect(holdsCredentialMaterial(text), text.slice(0, 20)).toBe(true);
54
+ }
55
+ });
56
+ });
57
+
58
+ describe("files that do not", () => {
59
+ /* THE FILE THAT STARTED THIS. An npmrc is the most-named credential path in this workspace's own commands
60
+ * and most of them are three lines of registry config. */
61
+ test("an npmrc with only registry config", () => {
62
+ expect(holdsCredentialMaterial("registry=https://registry.npmjs.org/\nengine-strict=true\nstore-dir=/root/.pnpm-store\n")).toBe(
63
+ false,
64
+ );
65
+ });
66
+
67
+ test("a dotenv of ports and flags", () => {
68
+ expect(holdsCredentialMaterial("PORT=3000\nNODE_ENV=development\nVITE_API_URL=http://localhost:8080\nLOG_LEVEL=debug\n")).toBe(false);
69
+ });
70
+
71
+ /* THE TEMPLATE THAT IS STILL A TEMPLATE. A key named `TOKEN` proves nothing on its own — half the dotenvs
72
+ * in a monorepo are this file, waiting for someone to fill them in. */
73
+ test("a dotenv whose credential keys are still placeholders", () => {
74
+ expect(
75
+ holdsCredentialMaterial(
76
+ [
77
+ "GITHUB_TOKEN=",
78
+ "NPM_TOKEN=${NPM_TOKEN}",
79
+ "API_KEY=<your-api-key>",
80
+ 'CLIENT_SECRET=""',
81
+ "DB_PASSWORD=changeme",
82
+ "SLACK_TOKEN=xxxxxxxx",
83
+ "STRIPE_SECRET={{secret:STRIPE}}",
84
+ "AUTH_TOKEN=your-token-here",
85
+ "SESSION_SECRET=REDACTED",
86
+ ].join("\n"),
87
+ ),
88
+ ).toBe(false);
89
+ });
90
+
91
+ // The public half of a keypair, and the host list beside it: named in the same directory, credential
92
+ // material in neither.
93
+ test("the public files an ssh directory is full of", () => {
94
+ expect(holdsCredentialMaterial("ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH1x radarsu@omen\n")).toBe(false);
95
+ expect(holdsCredentialMaterial("github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzr\n")).toBe(false);
96
+ expect(holdsCredentialMaterial("Host github.com\n User git\n IdentityFile ~/.ssh/id_ed25519\n")).toBe(false);
97
+ });
98
+
99
+ test("a key whose name only looks like one", () => {
100
+ expect(holdsCredentialMaterial("TOKEN_EXPIRY=3600\nREFRESH_TOKEN_URL=https://auth.example.com/refresh\nMAX_TOKENS=8192\n")).toBe(
101
+ false,
102
+ );
103
+ });
104
+
105
+ // A dev default is a real password in the strictest reading and nothing this class exists to stop; the
106
+ // length floor is what draws that line.
107
+ test("a dev-compose default is not what the card is for", () => {
108
+ expect(holdsCredentialMaterial("POSTGRES_PASSWORD=dev\nREDIS_PASSWORD=x\n")).toBe(false);
109
+ });
110
+
111
+ test("an empty file", () => {
112
+ expect(holdsCredentialMaterial("")).toBe(false);
113
+ expect(holdsCredentialMaterial("\n\n# nothing here\n")).toBe(false);
114
+ });
115
+
116
+ // A URL with a port is not a URL with a password: `user:pass@` needs both halves and the `@`.
117
+ test("an ordinary url is not userinfo", () => {
118
+ expect(holdsCredentialMaterial("API=http://localhost:8080/v1\nSENTRY_DSN=https://abc123@o1.ingest.sentry.io/1\n")).toBe(false);
119
+ });
120
+ });
@@ -0,0 +1,100 @@
1
+ /* WHETHER A FILE ACTUALLY HOLDS A CREDENTIAL, the fact that `secrets.access` only guesses at from a path.
2
+ *
3
+ * The classifier next door (command-classes.ts) reads shell text, so the strongest thing it can honestly say
4
+ * about `sed … ~/.npmrc` is "this names a file that USUALLY holds a token". Usually is not always, and the gap
5
+ * is where the class earns its reputation: most `~/.npmrc` files are three lines of registry config, most
6
+ * `.env` files in a monorepo are ports and feature flags, `~/.ssh/known_hosts` is a list of public keys, and a
7
+ * file that does not exist reads nothing at all. A card raised over one of those is not a near miss, it is
8
+ * noise, and noise is what teaches an owner to answer the card without reading it, which is precisely how a
9
+ * real credential read gets waved through six weeks later.
10
+ *
11
+ * So the class is split in two. The path table says WHICH FILES ARE WORTH LOOKING AT; this says WHAT A
12
+ * CREDENTIAL LOOKS LIKE once one has been opened. It lives here, beside that table, because the two halves are
13
+ * one definition of the class and an enforcement point that has a filesystem should not have to invent the
14
+ * second half for itself (guard/credential-files.ts is the sandbox's fs half; a caller with no filesystem, the
15
+ * browser or the machine agent, simply never asks and the path stands on its name alone).
16
+ *
17
+ * PURE, over the file's own text: no fs, no path logic, nothing to configure. That keeps this package free of
18
+ * a runtime the editor bundle cannot have, and keeps the rule testable as a table of strings.
19
+ *
20
+ * IT ANSWERS THE EASY DIRECTION WELL AND THE HARD ONE CONSERVATIVELY. Everything below is written to say YES
21
+ * on anything credential-shaped, because a yes costs one card and a no costs the whole rule: the only use of
22
+ * this answer is to REMOVE a class the path table already added, so a false yes leaves behavior exactly as it
23
+ * was and a false no silently un-gates a real read.
24
+ */
25
+
26
+ /* A KEY THAT NAMES A CREDENTIAL, AND ITS VALUE. Matched as a suffix of whatever the key is spelled as, because
27
+ * these files say the same thing a dozen ways and only the last word carries the meaning: `NPM_TOKEN`,
28
+ * `//registry.npmjs.org/:_authToken`, `"accessToken"`, `aws_secret_access_key`, `password =`.
29
+ *
30
+ * The three value arms are the three ways a value is quoted across the formats this ever sees: JSON's double
31
+ * quotes, a shell-ish dotenv's single quotes, and an ini file's bare rest-of-line.
32
+ *
33
+ * THE SEPARATOR MAY NOT CROSS A LINE, which is the difference between reading a file and reading a soup: with
34
+ * `\s*` around it, an empty `GITHUB_TOKEN=` borrows the NEXT line as its value, and a dotenv of nine blank
35
+ * placeholders reads as eight credentials. Every format here puts a value on its key's own line. */
36
+ const CREDENTIAL_ASSIGNMENT =
37
+ /(?:auth[_-]?token|access[_-]?token|refresh[_-]?token|api[_-]?key|access[_-]?key|secret[_-]?key|client[_-]?secret|private[_-]?key|passwo?rd|passphrase|credentials?|secret|token|bearer)["']?[ \t]*[:=][ \t]*(?:"([^"\n]*)"|'([^'\n]*)'|([^\s"',;}\n]*))/gi;
38
+
39
+ /* A VALUE THAT IS NOT A CREDENTIAL EVEN THOUGH ITS KEY SAYS IT IS: the empty one, the one still holding the
40
+ * template's own words, and the one deferring to an environment variable or a secret reference. Every dotenv
41
+ * that ships in a repo is made of these, and firing on `GITHUB_TOKEN=${GITHUB_TOKEN}` would put a card in front
42
+ * of reading a file whose entire content is the absence of a secret. */
43
+ const PLACEHOLDER =
44
+ /^(?:\$\{?[\w:.-]+\}?|\{\{[^}]*\}\}|<[^>]*>|%\w+%|x{3,}|\*{3,}|\.{3,}|…|(?:your|my|our|the)[-_\s].*|change[-_]?me|replace[-_]?(?:me|this|with)|todo|tbd|fixme|none|null|nil|undefined|true|false|example|placeholder|redacted|dummy|sample|test|fake|secret|password|token|value|here)$/i;
45
+
46
+ /* Shorter than any credential a service actually issues. It clears the dev-compose defaults an agent reads all
47
+ * day (`POSTGRES_PASSWORD=dev`, `password=x`), which are not what a card asking about credential material is
48
+ * for, and it is well under the shortest real token below (a 36-character npm one). */
49
+ const MIN_VALUE = 6;
50
+
51
+ /* A CREDENTIAL RECOGNISABLE WITHOUT ITS KEY: the issuers whose tokens carry their own prefix, the PEM and PuTTY
52
+ * headers that ARE the private key file, and a URL that carries a password in its userinfo (which is the whole
53
+ * content of `.git-credentials`, and the shape a `DATABASE_URL` hides one in).
54
+ *
55
+ * These are checked first and independently of any key, because half of these files have no `key = value` in
56
+ * them at all. */
57
+ const TOKEN_SHAPES = [
58
+ /-----BEGIN (?:[A-Z0-9]+ )*PRIVATE KEY-----/,
59
+ /PuTTY-User-Key-File-\d/,
60
+ // scheme://user:password@host — the password is the point; a Sentry DSN (`https://key@host`) has no colon
61
+ // before the `@` and is deliberately not this.
62
+ /\b[a-z][a-z0-9+.-]*:\/\/[^\s/:@]+:[^\s/@]{3,}@/i,
63
+ /\bnpm_[A-Za-z0-9]{30,}/,
64
+ /\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{30,}/,
65
+ /\bgithub_pat_[A-Za-z0-9_]{50,}/,
66
+ /\bglpat-[A-Za-z0-9_-]{16,}/,
67
+ /\bxox[baprs]-[A-Za-z0-9-]{10,}/,
68
+ /\bsk-[A-Za-z0-9_-]{20,}/,
69
+ /\b(?:sk|rk)_live_[A-Za-z0-9]{16,}/,
70
+ /\bAKIA[0-9A-Z]{16}\b/,
71
+ /\bASIA[0-9A-Z]{16}\b/,
72
+ /\bAIza[0-9A-Za-z_-]{35}\b/,
73
+ /\bhf_[A-Za-z0-9]{30,}/,
74
+ /\bdop_v1_[a-f0-9]{60,}/,
75
+ // A JWT: three base64url segments, the first two of which decode from `{"` and so always begin `ey`.
76
+ /\bey[A-Za-z0-9_-]{10,}\.ey[A-Za-z0-9_-]{10,}\./,
77
+ ];
78
+
79
+ /* A VALUE DEFERRED TO SOMEWHERE ELSE, removed before anything is read, because it is not one value but two
80
+ * things to get wrong. `STRIPE_SECRET={{secret:STRIPE}}` holds no credential — that is the platform's own
81
+ * convention for a file that must not hold one — and yet it reads as a credential twice over: the outer
82
+ * assignment has a substantial-looking value, and the reference's own `secret:STRIPE` is a second `key: value`
83
+ * inside it. Cutting them out first is simpler and steadier than teaching the value patterns to survive them. */
84
+ const DEFERRED_VALUE = /\{\{[^}\n]*\}\}|\$\{[^}\n]*\}/g;
85
+
86
+ // Does this file's text hold something worth a card? Handed the WHOLE file by its caller, which is why the
87
+ // caller (not this) is the one that decides how much of a large file is worth reading.
88
+ export const holdsCredentialMaterial = (file: string): boolean => {
89
+ const text = file.replace(DEFERRED_VALUE, "");
90
+ if (TOKEN_SHAPES.some((pattern) => pattern.test(text))) {
91
+ return true;
92
+ }
93
+ for (const match of text.matchAll(CREDENTIAL_ASSIGNMENT)) {
94
+ const value = (match[1] ?? match[2] ?? match[3] ?? "").trim();
95
+ if (value.length >= MIN_VALUE && !PLACEHOLDER.test(value)) {
96
+ return true;
97
+ }
98
+ }
99
+ return false;
100
+ };
@@ -0,0 +1,8 @@
1
+ import { z } from "zod";
2
+
3
+ /* One "do this by hand" line, the definition surface's honesty unit (definition.ts is the home story; this
4
+ * lives in its own leaf module because runner-protocol.ts also speaks it, and THAT file is imported by
5
+ * schemas/agent.ts, which definition.ts imports — the schema living in definition.ts made a cycle that left
6
+ * schemas half-initialized under module-eval). A subject the UI bolds, a detail written as an instruction. */
7
+ export const DefinitionActionSchema = z.object({ subject: z.string(), detail: z.string() });
8
+ export type DefinitionAction = z.infer<typeof DefinitionActionSchema>;
package/src/definition.ts CHANGED
@@ -1,9 +1,11 @@
1
1
  import { z } from "zod";
2
- import { CapabilitySchema, SandboxSettingsSchema } from "./schemas.js";
2
+ import { DefinitionActionSchema } from "./definition-action.js";
3
+ import { CapabilitySchema } from "./schemas/capabilities.js";
4
+ import { SandboxSettingsSchema } from "./schemas/settings.js";
3
5
 
4
6
  /* THE SANDBOX DEFINITION: the declarable SHAPE of a sandbox, split off from its state.
5
7
  *
6
- * A bundle (portability section of schemas.ts) moves everything a sandbox holds; this is the half of it that
8
+ * A bundle (BundleSchema, schemas/maintenance.ts) moves everything a sandbox holds; this is the half of it that
7
9
  * is a REFERENCE to a source of truth rather than bytes only this sandbox has: which repos (as remotes a
8
10
  * target can clone), which connections (as shapes a target re-authenticates), which overlay steps (as source
9
11
  * a target's owner approves), which secrets (as NAMES a target asks for), which agent settings. Everything
@@ -19,7 +21,7 @@ import { CapabilitySchema, SandboxSettingsSchema } from "./schemas.js";
19
21
  // One repository, by reference: the id it lands under in the workspace, where a target clones it from, and
20
22
  // (optionally) the branch to check out. A repo with NO remote cannot appear here, the exporter reports it as
21
23
  // omitted instead of inventing a source for bytes only the source sandbox holds.
22
- export const DefinitionRepositorySchema = z.object({
24
+ export const DefinitionRepositorySchema = z.strictObject({
23
25
  // Workspace-relative repo id ("intentic", "clients/foo"), the same id the wire {repo} routes use.
24
26
  id: z.string().min(1),
25
27
  // The clone URL, verbatim from the source repo's own remote.
@@ -29,7 +31,26 @@ export const DefinitionRepositorySchema = z.object({
29
31
  });
30
32
  export type DefinitionRepository = z.infer<typeof DefinitionRepositorySchema>;
31
33
 
32
- export const DefinitionEnvironmentSchema = z.object({
34
+ /* THE WORKSPACE ITSELF, by reference. `/work` is a git repo of its own (the daemon's `root` scope, git dir on
35
+ * /history), tracking every workspace file that is not a nested repo, the reference shelf, or daemon-internal
36
+ * state — which by the versioned-state allowlist means the owner's AUTHORED content: notes, skills, personas,
37
+ * automations, workflow and loop designs, drafts, workspace extensions. None of that has a source anywhere else,
38
+ * so before this section a definition could only shrug at it and a bundle was the sole way to move it.
39
+ *
40
+ * With a remote it becomes referenceable like any other repo, which is the whole point: `[workspace]` plus
41
+ * `[[repositories]]` is a sandbox's code AND its way of working, and what remains bundle-only is exactly what
42
+ * cannot be pushed anywhere — secrets, identity, /history, the built image.
43
+ *
44
+ * A workspace with no remote cannot appear here; the exporter says so in `omitted` rather than inventing one. */
45
+ export const DefinitionWorkspaceSchema = z.strictObject({
46
+ // The clone URL, verbatim from the workspace repo's own remote.
47
+ remote: z.string().min(1),
48
+ // The branch to check out; absent means the remote's default.
49
+ ref: z.string().optional(),
50
+ });
51
+ export type DefinitionWorkspace = z.infer<typeof DefinitionWorkspaceSchema>;
52
+
53
+ export const DefinitionEnvironmentSchema = z.strictObject({
33
54
  // The image the overlay extends, informational: the target composes against ITS OWN base (see
34
55
  // composeEnvironment's baseImageOf), this records what the source was on.
35
56
  baseImage: z.string().optional(),
@@ -57,16 +78,19 @@ const bareField = (field: z.ZodType): z.ZodType => {
57
78
 
58
79
  const definitionSettings = (): z.ZodType<Partial<z.infer<typeof SandboxSettingsSchema>>> => {
59
80
  const shape = Object.fromEntries(Object.entries(SandboxSettingsSchema.shape).map(([key, field]) => [key, bareField(field).optional()]));
60
- return z.object(shape).prefault({}) as unknown as z.ZodType<Partial<z.infer<typeof SandboxSettingsSchema>>>;
81
+ return z.strictObject(shape).prefault({}) as unknown as z.ZodType<Partial<z.infer<typeof SandboxSettingsSchema>>>;
61
82
  };
62
83
 
63
- export const SandboxDefinitionSchema = z.object({
84
+ export const SandboxDefinitionSchema = z.strictObject({
64
85
  // Bumped when the layout changes in a way an older daemon would misread. Refused rather than guessed at,
65
86
  // the bundle manifest's own rule.
66
87
  schemaVersion: z.literal(1),
67
88
  // What the source sandbox was called, for the reader; never used to authorize anything.
68
89
  name: z.string().optional(),
69
90
  environment: DefinitionEnvironmentSchema.prefault({}),
91
+ // The workspace repo itself, when it has a remote to be named by. Absent is the ordinary state of a
92
+ // workspace nobody has published, not an error.
93
+ workspace: DefinitionWorkspaceSchema.optional(),
70
94
  repositories: z.array(DefinitionRepositorySchema).prefault([]),
71
95
  /* Each connection IN FULL (id, kind, config), not merely named: the manifest they come from carries the
72
96
  * SHAPE of a connection and never its credential (workspace-state.ts argues the split on the
@@ -82,9 +106,9 @@ export const SandboxDefinitionSchema = z.object({
82
106
  export type SandboxDefinition = z.infer<typeof SandboxDefinitionSchema>;
83
107
 
84
108
  // One "do this by hand" line, the same honesty unit ImportReportSchema carries: a subject the UI bolds and a
85
- // detail written as an instruction to the owner.
86
- export const DefinitionActionSchema = z.object({ subject: z.string(), detail: z.string() });
87
- export type DefinitionAction = z.infer<typeof DefinitionActionSchema>;
109
+ // detail written as an instruction to the owner. Defined in its own leaf module (definition-action.ts says
110
+ // why) and re-exported here, where every consumer of the definition surface finds it.
111
+ export { DefinitionActionSchema, type DefinitionAction } from "./definition-action.js";
88
112
 
89
113
  // What GET /definition answers: the emitted TOML, plus what the derivation could not express (a repo with no
90
114
  // remote), listed rather than silent, the export's own `excluded` discipline.
@@ -99,7 +123,7 @@ export type DefinitionExport = z.infer<typeof DefinitionExportSchema>;
99
123
  // same items the owner reviewed.
100
124
  export const DefinitionItemSchema = z.object({
101
125
  id: z.string(),
102
- kind: z.enum(["repo", "capability", "environment", "settings"]),
126
+ kind: z.enum(["workspace", "repo", "capability", "environment", "settings"]),
103
127
  label: z.string(),
104
128
  detail: z.string().optional(),
105
129
  /* False when the target already holds this piece (the repo's directory exists, a capability with that id
@@ -144,6 +168,46 @@ export const DefinitionDiffSchema = z.object({
144
168
  });
145
169
  export type DefinitionDiff = z.infer<typeof DefinitionDiffSchema>;
146
170
 
171
+ /* ---- publishing the workspace repo, the one step a definition cannot take for itself ----
172
+ *
173
+ * `[workspace]` names a remote; nothing can name one that does not exist. So the owner-facing half of the
174
+ * feature is this: create a PRIVATE repo on a connected git host and push /work to it, or adopt a URL the
175
+ * owner made themselves. Deliberately its own route rather than a side effect of the export, publishing a
176
+ * workspace is an outward act with its own confirmation, and deriving a document must stay read-only.
177
+ */
178
+ export const WorkspacePublishSchema = z.object({
179
+ /* An existing repo's clone URL. Given, nothing is created: the remote is wired up and pushed to, which is
180
+ * the path for an owner who made the repo themselves or is moving hosts. */
181
+ remote: z.string().min(1).optional(),
182
+ // The repo to create when `remote` is absent. Owner-side default is the sandbox's own name.
183
+ name: z.string().min(1).optional(),
184
+ /* The account or organization to create it under; absent means the authenticated user. Ignored when
185
+ * `remote` is given. */
186
+ owner: z.string().min(1).optional(),
187
+ });
188
+ export type WorkspacePublish = z.infer<typeof WorkspacePublishSchema>;
189
+
190
+ // Where the workspace now lives, and what a definition will name. `created` distinguishes "made you a repo"
191
+ // from "wired up the one you gave me", which is the difference the card reports back.
192
+ export const WorkspacePublishResultSchema = z.object({
193
+ remote: z.string(),
194
+ branch: z.string(),
195
+ created: z.boolean(),
196
+ });
197
+ export type WorkspacePublishResult = z.infer<typeof WorkspacePublishResultSchema>;
198
+
199
+ // What the card renders before anything is published: whether /work has a remote, and which connected git
200
+ // hosts could make one. Read-only, so the button can say "Publish to github.com" rather than opening a form
201
+ // into a void.
202
+ export const WorkspaceRemoteSchema = z.object({
203
+ remote: z.string().optional(),
204
+ branch: z.string().optional(),
205
+ // Hostnames of connected github/gitlab accounts, in the order they would be tried. Empty means the owner
206
+ // must connect one (or paste a URL).
207
+ hosts: z.array(z.string()),
208
+ });
209
+ export type WorkspaceRemote = z.infer<typeof WorkspaceRemoteSchema>;
210
+
147
211
  /* ---- the bundle manifest, restated on the definition ----
148
212
  *
149
213
  * A bundle is DEFINITION + STATE: its manifest embeds the same definition `GET /definition` emits, and the
package/src/events.ts CHANGED
@@ -1,18 +1,12 @@
1
1
  import { z } from "zod";
2
- import {
3
- AgentProviderSchema,
4
- AgentReplySchema,
5
- AgentSummarySchema,
6
- FastModeStateSchema,
7
- LandConflictSchema,
8
- MemberRoleSchema,
9
- PermissionModeSchema,
10
- RateLimitInfoSchema,
11
- ShareDetailSchema,
12
- SubagentKindSchema,
13
- SubagentStatusSchema,
14
- UsageWindowSchema,
15
- } from "./schemas.js";
2
+ import { AgentProviderSchema, PermissionModeSchema } from "./schemas/agent.js";
3
+ import { AgentSummarySchema, LandConflictSchema } from "./schemas/agents.js";
4
+ import { RateLimitInfoSchema } from "./schemas/claude-gate.js";
5
+ import { FastModeStateSchema } from "./schemas/fast-mode.js";
6
+ import { AgentReplySchema, UsageWindowSchema } from "./schemas/plan-limits.js";
7
+ import { ShareDetailSchema } from "./schemas/share.js";
8
+ import { MemberRoleSchema } from "./schemas/shared.js";
9
+ import { SubagentKindSchema, SubagentStatusSchema, SubagentVerificationSchema } from "./schemas/terminal.js";
16
10
 
17
11
  // The wire shapes streamed from the daemon's event-iterator procedures. This is their canonical home: the
18
12
  // daemon yields them and the browser client consumes them from the same schema, so the two can't drift (they
@@ -35,6 +29,29 @@ export const AskQuestionSchema = z.object({
35
29
  });
36
30
  export type AskQuestion = z.infer<typeof AskQuestionSchema>;
37
31
 
32
+ /* THE PROGRAM A COMMAND CARD IS HOLDING, as the thing it is rather than as prose about it.
33
+ *
34
+ * It used to ride in `description`, the field every other permission ask fills with a sentence, which left the
35
+ * card with no way to know it was holding four hundred characters of shell: it rendered them as a paragraph,
36
+ * wrapped mid-flag, and the fragment that caused the hold was somewhere in the middle of it.
37
+ *
38
+ * `spans` is the gate's own evidence, computed by the classifier at the moment the rule fired (contract's
39
+ * command-classes.ts, matchCommand) and carried rather than re-derived: a browser that re-ran the patterns
40
+ * would be a second classifier, and the day the two disagreed the card would be marking a fragment that is not
41
+ * the one anybody was held for. Offsets are into `text` AFTER truncation, so they are always paintable.
42
+ *
43
+ * `language` is a Shiki grammar id, and the two are the two execution backends the gate reads (command-gate's
44
+ * EXECUTION_SOURCES): a shell line and a script. */
45
+ export const ProgramAskSchema = z.object({
46
+ text: z.string().describe("What would run."),
47
+ language: z.enum(["bash", "javascript"]).describe("Which of the two backends it is written for, named as the grammar that colours it."),
48
+ truncated: z.boolean().describe("Whether this is the head of a longer program, so the card can say so instead of ending mid-word."),
49
+ spans: z
50
+ .array(z.object({ start: z.number().int().nonnegative(), end: z.number().int().nonnegative() }))
51
+ .describe("Which fragments of the text put it in the class that held it. Offsets into text, in order, never overlapping."),
52
+ });
53
+ export type ProgramAsk = z.infer<typeof ProgramAskSchema>;
54
+
38
55
  // One per-tool permission prompt (the SDK's canUseTool callback, surfaced as a card). The daemon passes the
39
56
  // bridge's own rendered strings through rather than re-deriving them, so the prompt reads exactly as Claude
40
57
  // Code words it. `alwaysLabel` is present only when the SDK offered rules to persist, without it the card
@@ -56,6 +73,15 @@ export const PermissionAskSchema = z.object({
56
73
  .describe(
57
74
  "The wording for an always-allow answer. Present only when there is something an always could actually remember; without it the only answers are once and no.",
58
75
  ),
76
+ program: ProgramAskSchema.optional().describe(
77
+ "The program this card is holding, when the card is about one. Present on a command gate's card and absent on every other permission ask.",
78
+ ),
79
+ explain: z
80
+ .string()
81
+ .optional()
82
+ .describe(
83
+ "One plain sentence saying what the program does and why the agent wants it. Written by the quick model, never by the agent being gated, and only when the owner switched the setting on.",
84
+ ),
59
85
  });
60
86
  export type PermissionAsk = z.infer<typeof PermissionAskSchema>;
61
87
 
@@ -360,8 +386,9 @@ export const RestoredMessageSchema = z.object({
360
386
  thinking: z.string().optional().describe("What the agent was reasoning about."),
361
387
  tools: z.array(RestoredToolCallSchema).optional().describe("The tool calls this part of the turn made."),
362
388
  /* What the daemon added to this turn's message (user rows only), the same notes the live `preamble` frame
363
- * carries, recovered from the stored prompt when the transcript is read back. The reader that strips them out
364
- * of the user's words is the one that hands them over here instead of dropping them on the floor.
389
+ * carries. A daemon-recorded turn takes them straight off that frame in its own log, typed end to end
390
+ * (sessions/turn-transcript.ts); only a conversation adopted from a provider's session store recovers them
391
+ * by parsing the composed prompt kept there, the one store the daemon never wrote typed.
365
392
  *
366
393
  * On the message rather than as a row of its own, and that matters twice: they ARE part of what was
367
394
  * sent, and a record row per turn preamble would break the one-row-per-bubble correspondence a branch counts
@@ -489,8 +516,9 @@ export type ParkedCard = z.infer<typeof ParkedCardSchema>;
489
516
  // ~40 SDKMessage types down to this union: high-value block types get a dedicated frame
490
517
  // (delta/thinking/tool_call/tool_call_update/todos/usage/rate_limit_info/account_usage/context_usage/init/compact); any SDK message
491
518
  // without a UI mapping is dropped. `plan`/`question`/`permission` pause the turn until the user answers on the
492
- // `POST /agent/reply` side channel, and `resolved` releases the one it names; `mode` reports the live
493
- // permission posture as the agent changes it.
519
+ // `POST /agent/reply` side channel, and `resolved` releases the one it names; `permission_note` adds a sentence
520
+ // to a permission card already on screen without settling it; `mode` reports the live permission posture as the
521
+ // agent changes it.
494
522
  // `parentToolUseId` tags frames produced inside a subagent (Task tool); `subagent`/`subagent_update` report the
495
523
  // subagent itself, keyed by the same tool_use id those tagged frames carry.
496
524
  export const AgentEventSchema = z.discriminatedUnion("kind", [
@@ -554,12 +582,14 @@ export const AgentEventSchema = z.discriminatedUnion("kind", [
554
582
  * way to find out what those instructions said. This frame is the fix: the note text verbatim, one entry per
555
583
  * note, rendered collapsed so it costs a click rather than a scroll.
556
584
  *
557
- * `title` is the note's own opening header, which is what the stripper already anchors on, so the two
558
- * cannot drift, and a note nobody thought to title cannot reach the wire unlabelled.
585
+ * Emitted from the TYPED notes the wire prompt is serialized from at the same point (turn-preamble.ts,
586
+ * composeWirePrompt), so the disclosure and what the model receives cannot drift: a note is in both or in
587
+ * neither, and a note nobody thought to title cannot reach the wire unlabelled.
559
588
  *
560
589
  * ONE MOMENT, always: the notes went in front of the user's own message before the turn started, so they hang
561
- * off that message and are stored on it, which is how a reopened tab still has them. Nothing is injected into
562
- * a RUNNING turn, the rebase taken while a card sat waiting was the only thing that ever was, and it no
590
+ * off that message and are stored on it, the transcript fold reads this very frame out of the turn's own
591
+ * frame log (sessions/turn-transcript.ts), which is how a reopened tab still has them. Nothing is injected
592
+ * into a RUNNING turn, the rebase taken while a card sat waiting was the only thing that ever was, and it no
563
593
  * longer says anything to the model at all (agent/turn-preamble.ts). */
564
594
  z.object({ kind: z.literal("preamble"), notes: z.array(TurnNoteSchema) }),
565
595
  // The SDK's init handshake; carries the model it actually resolved for the turn.
@@ -666,6 +696,9 @@ export const AgentEventSchema = z.discriminatedUnion("kind", [
666
696
  lastTool: z.string().optional(),
667
697
  summary: z.string().optional(),
668
698
  error: z.string().optional(),
699
+ // Whether anything checked the work the report describes (SubagentVerificationSchema). Rides the frame
700
+ // that ENDS the child, beside the report itself, so the card carries both at once.
701
+ verification: SubagentVerificationSchema.optional(),
669
702
  }),
670
703
  z.object({ kind: z.literal("todos"), items: z.array(TodoItemSchema) }),
671
704
  // The provider's own slash commands (ACP available_commands_update), replaced whole each time, the
@@ -875,6 +908,19 @@ export const AgentEventSchema = z.discriminatedUnion("kind", [
875
908
  // already moved on. It rides verbatim, exactly as the client POSTed it; absent, nobody answered (the turn
876
909
  // was stopped, or died under the card), which is not a decision and must not replay as one.
877
910
  z.object({ kind: z.literal("resolved"), requestId: z.string(), reply: AgentReplySchema.optional() }),
911
+ /* A LATE SENTENCE FOR A CARD ALREADY ON SCREEN: the quick model's plain-language reading of a held command,
912
+ * landing on the permission card named by `requestId` (see PermissionAsk.explain).
913
+ *
914
+ * A frame of its own rather than a field on the card, because the card MUST NOT WAIT FOR IT. This is a
915
+ * safety prompt and the turn is parked on it; a quick-model rung can take tens of seconds before the chain
916
+ * steps down (agent/quick-model.ts measured one at 58), and holding the card back for that reads exactly
917
+ * like the agent freezing, which is the failure the explanation was meant to prevent rather than cause. So
918
+ * the card goes out complete and unexplained, and this arrives if and when it does. Same shape and the same
919
+ * reason as `service_event`, which streams a running service's status onto an offer already rendered.
920
+ *
921
+ * Never arrives at all when the setting is off, when nothing is connected to answer, or when the user
922
+ * settles the card first, and none of those change what the card says. */
923
+ z.object({ kind: z.literal("permission_note"), requestId: z.string(), explain: z.string() }),
878
924
  // The turn's permission mode, whenever it changes, the user's pick at turn start, then every move the
879
925
  // AGENT makes on its own (EnterPlanMode on a request that needs thinking through, ExitPlanMode once the
880
926
  // user approves). The composer's mode selector follows this, so the UI never lies about the live posture.
@@ -955,6 +1001,22 @@ export const AgentEventSchema = z.discriminatedUnion("kind", [
955
1001
  * context-window-too-small does: they never reached a provider, and losing them to a
956
1002
  * capacity fact the user did not cause would be ours to answer for. */
957
1003
  "sandbox-memory-low",
1004
+ /* THE LOOP RAN OUT OF ITERATIONS, not out of work: the runtime hit its own turn ceiling and
1005
+ * stopped. Nothing failed, nothing is disconnected and nothing is spent, which is exactly why
1006
+ * it needs a code of its own rather than a sentence: it is the one ending that LOOKS like a
1007
+ * finished turn from the outside, and a ledger that filed it as an ordinary error told a
1008
+ * reader nothing they could act on.
1009
+ *
1010
+ * The recovery is the user's, not the daemon's: whatever the turn was doing is half done, and
1011
+ * re-running it blind would either redo the finished half or resume work nobody looked at. */
1012
+ "turn-cap",
1013
+ /* THE HARNESS ENDED THE TURN WITHOUT SUCCEEDING and did not say why in terms anything here
1014
+ * models: an internal execution error, or a result subtype a later vendor build invented. The
1015
+ * sentence carries the subtype verbatim, because that word is the only thing separating two of
1016
+ * these, and a code that meant "one of several unrelated things" would be worse than none. It
1017
+ * is a real classification all the same: it says the failure came from the LOOP rather than
1018
+ * from the provider, the credential or the request, which rules out every recovery next door. */
1019
+ "harness-incomplete",
958
1020
  ])
959
1021
  .optional(),
960
1022
  // rate_limit only: when the exhausted window reopens (epoch seconds, from the stream's own
package/src/fast-tier.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { compareCheapestFirst, isCheaperRung } from "./model-order.js";
2
2
  import { parsePinned } from "./quick-model.js";
3
- import type { AgentProvider } from "./schemas.js";
3
+ import type { AgentProvider } from "./schemas/agent.js";
4
4
 
5
5
  /* WHICH MODEL A DOWNGRADED TURN ACTUALLY RUNS ON, the second half of automatic tier selection.
6
6
  * prompt-complexity.ts decides a turn COULD be cheaper; this decides whether there is anything cheaper to put
@@ -37,6 +37,18 @@ export const HISTORY_STATE_FILES: readonly StateFile[] = [
37
37
  // The fleet: every conversation card, its branch, its session ids, its standing.
38
38
  { path: "agents.json", portability: "carry" },
39
39
  { path: "turns/", portability: "carry" },
40
+ /* THE ARMED CONDITION WATCHES, one file per watch, put back at boot (agent/watchers.ts `restoreWatchers`).
41
+ *
42
+ * Carried for the reason loops.json is: an arrangement the agent entered into on the user's behalf and
43
+ * that is still outstanding travels with the conversation that is waiting on it, or a restored sandbox
44
+ * shows a card parked on a condition nothing will ever check. It can be carried safely because the journal
45
+ * holds no credential, only the NAMES of the environment its check ran with (agent/watch-journal.ts); the
46
+ * values are re-derived on the target from whatever capabilities it actually has, so a watch landing
47
+ * somewhere without them fails its check honestly and ends in a wake that says so, rather than arriving
48
+ * with a working copy of a token the bundle was never supposed to carry. A watch whose isolated checkout
49
+ * did not travel (those are `derived`) is dropped by the restore rather than re-armed against a tree that
50
+ * is not there. */
51
+ { path: "watches/", portability: "carry" },
40
52
  { path: "transcripts/", portability: "carry" },
41
53
  // What each message can be put back to, a workspace checkpoint, or an isolated conversation's own commits.
42
54
  // Carried WITH the transcripts and the scopes above, because it is the join between them: without it a
@@ -128,6 +140,11 @@ export const HISTORY_STATE_FILES: readonly StateFile[] = [
128
140
  { path: "sync-enrollments.json", portability: "identity", note: "Re-pair desktop sync from the Sync tab." },
129
141
  { path: "sync-pair-consumed.json", portability: "identity" },
130
142
  { path: "host-enrollments.json", portability: "identity" },
143
+ /* A connected BROWSER's enrollment (webext/webext-store.ts). Identity for the hosts file's reason and one
144
+ * more of its own: the token admits a socket into somebody's signed-in browser, and that browser was paired
145
+ * with THIS sandbox — carried into another one it would either be dead weight or, worse, a second sandbox
146
+ * holding a live key to a browser its owner never connected it to. Re-pairing is a code and one click. */
147
+ { path: "webext-enrollments.json", portability: "identity", note: "Pair your browser again from its card: the extension is still installed." },
131
148
  // The burn list for setup-time computer pairings. Identity, like sync's beside it, and for a sharper reason:
132
149
  // carrying it into another sandbox would mark that sandbox's own fresh pairing as already spent.
133
150
  { path: "host-pair-consumed.json", portability: "identity" },
@@ -24,7 +24,7 @@ export const HostHelloSchema = z.object({
24
24
  * onto one-shot tickets, auth/ws-tickets.ts). A frame is body, not URL, so it is logged nowhere. Until this
25
25
  * arrives the socket is anonymous and short-lived: the daemon closes it in seconds if it never does. */
26
26
  token: z.string(),
27
- // The @intentic/host build the machine is running, surfaced per machine so an old binary is visible rather
27
+ // The @intentic/machine build the machine is running, surfaced per machine so an old binary is visible rather
28
28
  // than mysteriously missing a tool. What the machine IS (`describe`) is not here: it is pulled over the
29
29
  // typed link a moment later, so there is one definition of those facts rather than two.
30
30
  version: z.string(),
@@ -25,8 +25,8 @@ test("preview and port hostnames round-trip through their Host-header parsers",
25
25
  });
26
26
 
27
27
  test("the two schemes never bleed into each other, and stray/wrong-id hosts parse to nothing", () => {
28
- expect(portSlotFromHost("preview-app-" + ID + ".example.com", ID)).toBeUndefined();
29
- expect(panelFromHost("port-a-" + ID + ".example.com", ID)).toBeUndefined();
28
+ expect(portSlotFromHost(`preview-app-${ID}.example.com`, ID)).toBeUndefined();
29
+ expect(panelFromHost(`port-a-${ID}.example.com`, ID)).toBeUndefined();
30
30
  expect(panelFromHost("app.example.com", ID)).toBeUndefined();
31
31
  expect(panelFromHost(`preview-app-000000000000.example.com`, ID)).toBeUndefined();
32
32
  expect(portSlotFromHost(`port-a-000000000000.example.com`, ID)).toBeUndefined();