@intentic/sandbox-contract 1.325.0 → 1.327.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 (537) hide show
  1. package/README.md +24 -12
  2. package/dist/chores/chores.d.ts.map +1 -1
  3. package/dist/chores/chores.js +29 -20
  4. package/dist/chores/chores.js.map +1 -1
  5. package/dist/chores/probes.d.ts +1 -0
  6. package/dist/chores/probes.d.ts.map +1 -1
  7. package/dist/chores/probes.js +81 -12
  8. package/dist/chores/probes.js.map +1 -1
  9. package/dist/contracts/agent.contract.d.ts +1467 -6
  10. package/dist/contracts/agent.contract.d.ts.map +1 -1
  11. package/dist/contracts/agent.contract.js +2 -2
  12. package/dist/contracts/agent.contract.js.map +1 -1
  13. package/dist/contracts/agents.contract.d.ts +1391 -0
  14. package/dist/contracts/agents.contract.d.ts.map +1 -1
  15. package/dist/contracts/agents.contract.js +1 -1
  16. package/dist/contracts/automations.contract.d.ts +123 -4
  17. package/dist/contracts/automations.contract.d.ts.map +1 -1
  18. package/dist/contracts/automations.contract.js +13 -2
  19. package/dist/contracts/automations.contract.js.map +1 -1
  20. package/dist/contracts/capabilities.contract.d.ts +79 -8
  21. package/dist/contracts/capabilities.contract.d.ts.map +1 -1
  22. package/dist/contracts/chores.contract.d.ts +2 -0
  23. package/dist/contracts/chores.contract.d.ts.map +1 -1
  24. package/dist/contracts/ci.contract.d.ts +2 -0
  25. package/dist/contracts/ci.contract.d.ts.map +1 -1
  26. package/dist/contracts/device.contract.d.ts +52 -0
  27. package/dist/contracts/device.contract.d.ts.map +1 -1
  28. package/dist/contracts/device.contract.js +2 -0
  29. package/dist/contracts/device.contract.js.map +1 -1
  30. package/dist/contracts/endpoints.contract.d.ts +42 -33
  31. package/dist/contracts/endpoints.contract.d.ts.map +1 -1
  32. package/dist/contracts/endpoints.contract.js +17 -7
  33. package/dist/contracts/endpoints.contract.js.map +1 -1
  34. package/dist/contracts/extensions.contract.d.ts +192 -0
  35. package/dist/contracts/extensions.contract.d.ts.map +1 -1
  36. package/dist/contracts/extensions.contract.js +37 -1
  37. package/dist/contracts/extensions.contract.js.map +1 -1
  38. package/dist/contracts/needs.contract.d.ts +1009 -0
  39. package/dist/contracts/needs.contract.d.ts.map +1 -1
  40. package/dist/contracts/pages.contract.d.ts +34 -0
  41. package/dist/contracts/pages.contract.d.ts.map +1 -0
  42. package/dist/contracts/pages.contract.js +49 -0
  43. package/dist/contracts/pages.contract.js.map +1 -0
  44. package/dist/contracts/phone.contract.d.ts +78 -0
  45. package/dist/contracts/phone.contract.d.ts.map +1 -0
  46. package/dist/contracts/phone.contract.js +11 -0
  47. package/dist/contracts/phone.contract.js.map +1 -0
  48. package/dist/contracts/privacy.contract.d.ts +20 -0
  49. package/dist/contracts/privacy.contract.d.ts.map +1 -1
  50. package/dist/contracts/privacy.contract.js +12 -2
  51. package/dist/contracts/privacy.contract.js.map +1 -1
  52. package/dist/contracts/runner.contract.d.ts +648 -127
  53. package/dist/contracts/runner.contract.d.ts.map +1 -1
  54. package/dist/contracts/runner.contract.js +1 -1
  55. package/dist/contracts/runner.contract.js.map +1 -1
  56. package/dist/contracts/secrets.contract.d.ts +88 -0
  57. package/dist/contracts/secrets.contract.d.ts.map +1 -1
  58. package/dist/contracts/secrets.contract.js +20 -1
  59. package/dist/contracts/secrets.contract.js.map +1 -1
  60. package/dist/contracts/sessions.contract.d.ts +184 -0
  61. package/dist/contracts/sessions.contract.d.ts.map +1 -1
  62. package/dist/contracts/settings.contract.d.ts +16 -58
  63. package/dist/contracts/settings.contract.d.ts.map +1 -1
  64. package/dist/contracts/settings.contract.js +10 -1
  65. package/dist/contracts/settings.contract.js.map +1 -1
  66. package/dist/contracts/system.contract.d.ts +227 -32
  67. package/dist/contracts/system.contract.d.ts.map +1 -1
  68. package/dist/contracts/system.contract.js +18 -1
  69. package/dist/contracts/system.contract.js.map +1 -1
  70. package/dist/documents/conversions.d.ts.map +1 -1
  71. package/dist/documents/conversions.js +2 -1
  72. package/dist/documents/conversions.js.map +1 -1
  73. package/dist/documents/read.d.ts.map +1 -1
  74. package/dist/documents/read.js +4 -4
  75. package/dist/documents/read.js.map +1 -1
  76. package/dist/events/agent-events.d.ts +747 -1
  77. package/dist/events/agent-events.d.ts.map +1 -1
  78. package/dist/events/agent-events.js +14 -1
  79. package/dist/events/agent-events.js.map +1 -1
  80. package/dist/events/requests.d.ts +40 -0
  81. package/dist/events/requests.d.ts.map +1 -1
  82. package/dist/events/requests.js +39 -0
  83. package/dist/events/requests.js.map +1 -1
  84. package/dist/events/system-events.d.ts +120 -0
  85. package/dist/events/system-events.d.ts.map +1 -1
  86. package/dist/events/transcript.d.ts +1131 -1
  87. package/dist/events/transcript.d.ts.map +1 -1
  88. package/dist/events/transcript.js +9 -1
  89. package/dist/events/transcript.js.map +1 -1
  90. package/dist/ids/hostnames.d.ts +2 -0
  91. package/dist/ids/hostnames.d.ts.map +1 -1
  92. package/dist/ids/hostnames.js +18 -15
  93. package/dist/ids/hostnames.js.map +1 -1
  94. package/dist/ids/sandbox-id.d.ts +2 -0
  95. package/dist/ids/sandbox-id.d.ts.map +1 -0
  96. package/dist/ids/sandbox-id.js +2 -0
  97. package/dist/ids/sandbox-id.js.map +1 -0
  98. package/dist/ids/tunnel-ids.d.ts +1 -1
  99. package/dist/ids/tunnel-ids.d.ts.map +1 -1
  100. package/dist/ids/tunnel-ids.js +1 -1
  101. package/dist/ids/tunnel-ids.js.map +1 -1
  102. package/dist/index.d.ts +4902 -177
  103. package/dist/index.d.ts.map +1 -1
  104. package/dist/index.js +25 -9
  105. package/dist/index.js.map +1 -1
  106. package/dist/models/agent-catalog.d.ts +0 -1
  107. package/dist/models/agent-catalog.d.ts.map +1 -1
  108. package/dist/models/agent-catalog.js +0 -1
  109. package/dist/models/agent-catalog.js.map +1 -1
  110. package/dist/models/agent-runtimes.d.ts +1 -1
  111. package/dist/models/agent-runtimes.d.ts.map +1 -1
  112. package/dist/models/agent-runtimes.js +1 -1
  113. package/dist/models/agent-runtimes.js.map +1 -1
  114. package/dist/models/provider-specs.d.ts +1 -0
  115. package/dist/models/provider-specs.d.ts.map +1 -1
  116. package/dist/models/provider-specs.js +11 -0
  117. package/dist/models/provider-specs.js.map +1 -1
  118. package/dist/netd/browser-wire.d.ts.map +1 -0
  119. package/dist/netd/browser-wire.js.map +1 -0
  120. package/dist/{front → netd}/generated/browser-wire.d.ts +8 -0
  121. package/dist/netd/generated/browser-wire.d.ts.map +1 -0
  122. package/dist/netd/generated/browser-wire.js.map +1 -0
  123. package/dist/{front → netd}/generated/wire.d.ts +20 -11
  124. package/dist/netd/generated/wire.d.ts.map +1 -0
  125. package/dist/{front → netd}/generated/wire.js.map +1 -1
  126. package/dist/netd/netd-wire.d.ts +9 -0
  127. package/dist/netd/netd-wire.d.ts.map +1 -0
  128. package/dist/netd/netd-wire.js +8 -0
  129. package/dist/netd/netd-wire.js.map +1 -0
  130. package/dist/policy/credential-material.d.ts +2 -0
  131. package/dist/policy/credential-material.d.ts.map +1 -1
  132. package/dist/policy/credential-material.js +14 -8
  133. package/dist/policy/credential-material.js.map +1 -1
  134. package/dist/policy/message-limits.d.ts +14 -0
  135. package/dist/policy/message-limits.d.ts.map +1 -0
  136. package/dist/policy/message-limits.js +15 -0
  137. package/dist/policy/message-limits.js.map +1 -0
  138. package/dist/policy/request-status.d.ts.map +1 -1
  139. package/dist/policy/request-status.js +9 -1
  140. package/dist/policy/request-status.js.map +1 -1
  141. package/dist/policy/reserved-servers.d.ts.map +1 -1
  142. package/dist/policy/reserved-servers.js +1 -0
  143. package/dist/policy/reserved-servers.js.map +1 -1
  144. package/dist/policy/turned-away.d.ts.map +1 -1
  145. package/dist/policy/turned-away.js +2 -0
  146. package/dist/policy/turned-away.js.map +1 -1
  147. package/dist/protocol/container-requirements.d.ts.map +1 -1
  148. package/dist/protocol/container-requirements.js +3 -4
  149. package/dist/protocol/container-requirements.js.map +1 -1
  150. package/dist/protocol/doors/host-protocol.d.ts.map +1 -0
  151. package/dist/protocol/doors/host-protocol.js.map +1 -0
  152. package/dist/protocol/{listener-protocol.d.ts → doors/listener-protocol.d.ts} +22 -0
  153. package/dist/protocol/doors/listener-protocol.d.ts.map +1 -0
  154. package/dist/protocol/doors/listener-protocol.js +38 -0
  155. package/dist/protocol/doors/listener-protocol.js.map +1 -0
  156. package/dist/protocol/doors/phone-links.d.ts +16 -0
  157. package/dist/protocol/doors/phone-links.d.ts.map +1 -0
  158. package/dist/protocol/doors/phone-links.js +28 -0
  159. package/dist/protocol/doors/phone-links.js.map +1 -0
  160. package/dist/protocol/doors/phone-protocol.d.ts +47 -0
  161. package/dist/protocol/doors/phone-protocol.d.ts.map +1 -0
  162. package/dist/protocol/doors/phone-protocol.js +33 -0
  163. package/dist/protocol/doors/phone-protocol.js.map +1 -0
  164. package/dist/protocol/doors/runner-protocol.d.ts.map +1 -0
  165. package/dist/protocol/{runner-protocol.js → doors/runner-protocol.js} +1 -1
  166. package/dist/protocol/doors/runner-protocol.js.map +1 -0
  167. package/dist/protocol/{webext-links.d.ts → doors/webext-links.d.ts} +1 -0
  168. package/dist/protocol/doors/webext-links.d.ts.map +1 -0
  169. package/dist/protocol/{webext-links.js → doors/webext-links.js} +1 -0
  170. package/dist/protocol/doors/webext-links.js.map +1 -0
  171. package/dist/protocol/doors/webext-protocol.d.ts.map +1 -0
  172. package/dist/protocol/doors/webext-protocol.js.map +1 -0
  173. package/dist/protocol/edge-verdict.d.ts +1 -1
  174. package/dist/protocol/edge-verdict.d.ts.map +1 -1
  175. package/dist/protocol/headers.d.ts +4 -0
  176. package/dist/protocol/headers.d.ts.map +1 -0
  177. package/dist/protocol/headers.js +4 -0
  178. package/dist/protocol/headers.js.map +1 -0
  179. package/dist/protocol/ingress-contract.d.ts +1 -1
  180. package/dist/protocol/ingress-contract.d.ts.map +1 -1
  181. package/dist/protocol/ingress-contract.js +1 -5
  182. package/dist/protocol/ingress-contract.js.map +1 -1
  183. package/dist/protocol/peer-dial.d.ts.map +1 -1
  184. package/dist/protocol/peer-dial.js +18 -36
  185. package/dist/protocol/peer-dial.js.map +1 -1
  186. package/dist/protocol/raw/extension-protocol.d.ts +47 -0
  187. package/dist/protocol/raw/extension-protocol.d.ts.map +1 -0
  188. package/dist/protocol/raw/extension-protocol.js +32 -0
  189. package/dist/protocol/raw/extension-protocol.js.map +1 -0
  190. package/dist/protocol/raw/raw-json-routes.d.ts +855 -0
  191. package/dist/protocol/raw/raw-json-routes.d.ts.map +1 -0
  192. package/dist/protocol/raw/raw-json-routes.js +28 -0
  193. package/dist/protocol/raw/raw-json-routes.js.map +1 -0
  194. package/dist/protocol/{raw-routes.d.ts → raw/raw-routes.d.ts} +50 -3
  195. package/dist/protocol/raw/raw-routes.d.ts.map +1 -0
  196. package/dist/protocol/{raw-routes.js → raw/raw-routes.js} +17 -3
  197. package/dist/protocol/raw/raw-routes.js.map +1 -0
  198. package/dist/protocol/raw/route-path.d.ts +3 -0
  199. package/dist/protocol/raw/route-path.d.ts.map +1 -0
  200. package/dist/protocol/raw/route-path.js +8 -0
  201. package/dist/protocol/raw/route-path.js.map +1 -0
  202. package/dist/protocol/route-meta.d.ts +1 -1
  203. package/dist/protocol/route-meta.d.ts.map +1 -1
  204. package/dist/protocol/routes.d.ts +1 -0
  205. package/dist/protocol/routes.d.ts.map +1 -1
  206. package/dist/protocol/routes.js +8 -0
  207. package/dist/protocol/routes.js.map +1 -1
  208. package/dist/protocol/sse.d.ts +2 -1
  209. package/dist/protocol/sse.d.ts.map +1 -1
  210. package/dist/protocol/sse.js +23 -12
  211. package/dist/protocol/sse.js.map +1 -1
  212. package/dist/protocol/tunnel-bulk.js +1 -1
  213. package/dist/protocol/tunnel-bulk.js.map +1 -1
  214. package/dist/protocol/vitals.d.ts +2 -1
  215. package/dist/protocol/vitals.d.ts.map +1 -1
  216. package/dist/protocol/vitals.js +1 -0
  217. package/dist/protocol/vitals.js.map +1 -1
  218. package/dist/schemas/activity.d.ts +1 -0
  219. package/dist/schemas/activity.d.ts.map +1 -1
  220. package/dist/schemas/activity.js.map +1 -1
  221. package/dist/schemas/agent.d.ts +6 -0
  222. package/dist/schemas/agent.d.ts.map +1 -1
  223. package/dist/schemas/agent.js +9 -4
  224. package/dist/schemas/agent.js.map +1 -1
  225. package/dist/schemas/agents-list.d.ts +404 -0
  226. package/dist/schemas/agents-list.d.ts.map +1 -0
  227. package/dist/schemas/agents-list.js +14 -0
  228. package/dist/schemas/agents-list.js.map +1 -0
  229. package/dist/schemas/agents.d.ts +203 -0
  230. package/dist/schemas/agents.d.ts.map +1 -1
  231. package/dist/schemas/agents.js +44 -0
  232. package/dist/schemas/agents.js.map +1 -1
  233. package/dist/schemas/automations.d.ts +235 -347
  234. package/dist/schemas/automations.d.ts.map +1 -1
  235. package/dist/schemas/automations.js +82 -13
  236. package/dist/schemas/automations.js.map +1 -1
  237. package/dist/schemas/capabilities.d.ts +43 -8
  238. package/dist/schemas/capabilities.d.ts.map +1 -1
  239. package/dist/schemas/capabilities.js +6 -2
  240. package/dist/schemas/capabilities.js.map +1 -1
  241. package/dist/schemas/ci.d.ts +4 -0
  242. package/dist/schemas/ci.d.ts.map +1 -1
  243. package/dist/schemas/ci.js +8 -0
  244. package/dist/schemas/ci.js.map +1 -1
  245. package/dist/schemas/devices.d.ts +67 -0
  246. package/dist/schemas/devices.d.ts.map +1 -1
  247. package/dist/schemas/devices.js +8 -0
  248. package/dist/schemas/devices.js.map +1 -1
  249. package/dist/schemas/engines.d.ts +57 -0
  250. package/dist/schemas/engines.d.ts.map +1 -1
  251. package/dist/schemas/engines.js +4 -0
  252. package/dist/schemas/engines.js.map +1 -1
  253. package/dist/schemas/extension-updates.d.ts +329 -0
  254. package/dist/schemas/extension-updates.d.ts.map +1 -1
  255. package/dist/schemas/extension-updates.js +68 -3
  256. package/dist/schemas/extension-updates.js.map +1 -1
  257. package/dist/schemas/git/git.d.ts +11 -0
  258. package/dist/schemas/git/git.d.ts.map +1 -1
  259. package/dist/schemas/git/git.js +4 -4
  260. package/dist/schemas/git/git.js.map +1 -1
  261. package/dist/schemas/history.d.ts +2 -0
  262. package/dist/schemas/history.d.ts.map +1 -1
  263. package/dist/schemas/history.js.map +1 -1
  264. package/dist/schemas/hosts.d.ts +74 -0
  265. package/dist/schemas/hosts.d.ts.map +1 -1
  266. package/dist/schemas/hosts.js +10 -1
  267. package/dist/schemas/hosts.js.map +1 -1
  268. package/dist/schemas/loopback-catch.d.ts +1 -0
  269. package/dist/schemas/loopback-catch.d.ts.map +1 -1
  270. package/dist/schemas/loopback-catch.js +1 -0
  271. package/dist/schemas/loopback-catch.js.map +1 -1
  272. package/dist/schemas/maintenance.d.ts +8 -0
  273. package/dist/schemas/maintenance.d.ts.map +1 -1
  274. package/dist/schemas/maintenance.js +6 -0
  275. package/dist/schemas/maintenance.js.map +1 -1
  276. package/dist/schemas/members.d.ts +58 -0
  277. package/dist/schemas/members.d.ts.map +1 -0
  278. package/dist/schemas/members.js +16 -0
  279. package/dist/schemas/members.js.map +1 -0
  280. package/dist/schemas/metrics.d.ts +10 -0
  281. package/dist/schemas/metrics.d.ts.map +1 -1
  282. package/dist/schemas/metrics.js +19 -3
  283. package/dist/schemas/metrics.js.map +1 -1
  284. package/dist/schemas/needs.d.ts +1159 -1
  285. package/dist/schemas/needs.d.ts.map +1 -1
  286. package/dist/schemas/needs.js +25 -3
  287. package/dist/schemas/needs.js.map +1 -1
  288. package/dist/schemas/offload.js +1 -1
  289. package/dist/schemas/offload.js.map +1 -1
  290. package/dist/schemas/peer-enrollment.d.ts +7 -0
  291. package/dist/schemas/peer-enrollment.d.ts.map +1 -0
  292. package/dist/schemas/peer-enrollment.js +6 -0
  293. package/dist/schemas/peer-enrollment.js.map +1 -0
  294. package/dist/schemas/phone.d.ts +231 -0
  295. package/dist/schemas/phone.d.ts.map +1 -0
  296. package/dist/schemas/phone.js +57 -0
  297. package/dist/schemas/phone.js.map +1 -0
  298. package/dist/schemas/privacy.d.ts +41 -0
  299. package/dist/schemas/privacy.d.ts.map +1 -1
  300. package/dist/schemas/privacy.js +20 -3
  301. package/dist/schemas/privacy.js.map +1 -1
  302. package/dist/schemas/project-delivery.d.ts +94 -0
  303. package/dist/schemas/project-delivery.d.ts.map +1 -0
  304. package/dist/schemas/project-delivery.js +35 -0
  305. package/dist/schemas/project-delivery.js.map +1 -0
  306. package/dist/schemas/providers/plan-limits.d.ts +7 -0
  307. package/dist/schemas/providers/plan-limits.d.ts.map +1 -1
  308. package/dist/schemas/providers/plan-limits.js +22 -1
  309. package/dist/schemas/providers/plan-limits.js.map +1 -1
  310. package/dist/schemas/providers/usage.d.ts +1 -2
  311. package/dist/schemas/providers/usage.d.ts.map +1 -1
  312. package/dist/schemas/providers/usage.js +1 -2
  313. package/dist/schemas/providers/usage.js.map +1 -1
  314. package/dist/schemas/push.d.ts +1 -0
  315. package/dist/schemas/push.d.ts.map +1 -1
  316. package/dist/schemas/push.js.map +1 -1
  317. package/dist/schemas/secrets.d.ts +99 -0
  318. package/dist/schemas/secrets.d.ts.map +1 -1
  319. package/dist/schemas/secrets.js +34 -3
  320. package/dist/schemas/secrets.js.map +1 -1
  321. package/dist/schemas/settings-history.d.ts +1 -1
  322. package/dist/schemas/settings-history.d.ts.map +1 -1
  323. package/dist/schemas/settings-history.js +1 -0
  324. package/dist/schemas/settings-history.js.map +1 -1
  325. package/dist/schemas/settings.d.ts +13 -58
  326. package/dist/schemas/settings.d.ts.map +1 -1
  327. package/dist/schemas/settings.js +8 -13
  328. package/dist/schemas/settings.js.map +1 -1
  329. package/dist/schemas/terminal.d.ts +32 -0
  330. package/dist/schemas/terminal.d.ts.map +1 -1
  331. package/dist/schemas/terminal.js +37 -0
  332. package/dist/schemas/terminal.js.map +1 -1
  333. package/dist/schemas/updates.d.ts +1 -0
  334. package/dist/schemas/updates.d.ts.map +1 -1
  335. package/dist/schemas/updates.js +4 -0
  336. package/dist/schemas/updates.js.map +1 -1
  337. package/dist/schemas/workspace/workspace-search.d.ts +1 -0
  338. package/dist/schemas/workspace/workspace-search.d.ts.map +1 -1
  339. package/dist/schemas/workspace/workspace-search.js.map +1 -1
  340. package/dist/schemas/workspace/workspace-tree.d.ts +3 -0
  341. package/dist/schemas/workspace/workspace-tree.d.ts.map +1 -1
  342. package/dist/schemas/workspace/workspace-tree.js +22 -5
  343. package/dist/schemas/workspace/workspace-tree.js.map +1 -1
  344. package/dist/state/arrival.d.ts +59 -0
  345. package/dist/state/arrival.d.ts.map +1 -1
  346. package/dist/state/arrival.js +17 -0
  347. package/dist/state/arrival.js.map +1 -1
  348. package/dist/state/contract-lock.js +2 -2
  349. package/dist/state/contract-lock.js.map +1 -1
  350. package/dist/state/definition.d.ts +82 -16
  351. package/dist/state/definition.d.ts.map +1 -1
  352. package/dist/state/history-state.d.ts.map +1 -1
  353. package/dist/state/history-state.js +38 -0
  354. package/dist/state/history-state.js.map +1 -1
  355. package/dist/state/runtime-state.d.ts +6 -0
  356. package/dist/state/runtime-state.d.ts.map +1 -1
  357. package/dist/state/runtime-state.js +2 -0
  358. package/dist/state/runtime-state.js.map +1 -1
  359. package/dist/state/workspace-state.d.ts +24 -6
  360. package/dist/state/workspace-state.d.ts.map +1 -1
  361. package/dist/state/workspace-state.js +29 -7
  362. package/dist/state/workspace-state.js.map +1 -1
  363. package/dist/text/embed.d.ts +10 -0
  364. package/dist/text/embed.d.ts.map +1 -1
  365. package/dist/text/embed.js +25 -0
  366. package/dist/text/embed.js.map +1 -1
  367. package/dist/text/pages.d.ts +53 -0
  368. package/dist/text/pages.d.ts.map +1 -0
  369. package/dist/text/pages.js +230 -0
  370. package/dist/text/pages.js.map +1 -0
  371. package/dist/text/transcript-fold.d.ts +1 -0
  372. package/dist/text/transcript-fold.d.ts.map +1 -1
  373. package/dist/text/transcript-fold.js +30 -2
  374. package/dist/text/transcript-fold.js.map +1 -1
  375. package/dist/webext/index.d.ts +3 -2
  376. package/dist/webext/index.d.ts.map +1 -1
  377. package/dist/webext/index.js +3 -2
  378. package/dist/webext/index.js.map +1 -1
  379. package/package.json +77 -22
  380. package/src/chores/chores.ts +41 -21
  381. package/src/chores/{probes.test.ts → probes.integration.test.ts} +134 -1
  382. package/src/chores/probes.ts +128 -14
  383. package/src/chores/verdict.test.ts +29 -0
  384. package/src/contracts/agent.contract.ts +2 -2
  385. package/src/contracts/agents.contract.ts +1 -1
  386. package/src/contracts/automations.contract.ts +19 -1
  387. package/src/contracts/device.contract.ts +5 -0
  388. package/src/contracts/endpoints.contract.ts +32 -26
  389. package/src/contracts/extensions.contract.ts +49 -0
  390. package/src/contracts/pages.contract.ts +61 -0
  391. package/src/contracts/phone.contract.ts +21 -0
  392. package/src/contracts/privacy.contract.ts +13 -1
  393. package/src/contracts/runner.contract.ts +1 -1
  394. package/src/contracts/secrets.contract.ts +25 -0
  395. package/src/contracts/settings.contract.ts +10 -0
  396. package/src/contracts/system.contract.ts +26 -0
  397. package/src/documents/conversions.ts +3 -1
  398. package/src/documents/read.ts +4 -5
  399. package/src/events/agent-events.ts +27 -3
  400. package/src/events/requests.ts +47 -0
  401. package/src/events/transcript.ts +14 -0
  402. package/src/ids/hostnames.fixture.json +14 -10
  403. package/src/ids/hostnames.test.ts +21 -2
  404. package/src/ids/hostnames.ts +34 -15
  405. package/src/ids/sandbox-id.ts +3 -0
  406. package/src/ids/tunnel-ids.ts +1 -2
  407. package/src/index.ts +29 -12
  408. package/src/models/agent-catalog.ts +1 -2
  409. package/src/models/agent-runtimes.ts +12 -6
  410. package/src/models/provider-specs.test.ts +12 -0
  411. package/src/models/provider-specs.ts +16 -0
  412. package/src/{front → netd}/browser-wire.ts +1 -1
  413. package/src/{front → netd}/generated/browser-wire.json +80 -7
  414. package/src/{front → netd}/generated/browser-wire.ts +34 -7
  415. package/src/{front/generated/front-wire.json → netd/generated/netd-wire.json} +103 -41
  416. package/src/{front → netd}/generated/tunnel.json +15 -1
  417. package/src/{front → netd}/generated/wire.ts +26 -21
  418. package/src/netd/netd-wire.ts +24 -0
  419. package/src/{front → netd}/wire-manifests.test.ts +31 -11
  420. package/src/policy/credential-material.ts +39 -11
  421. package/src/policy/message-limits.ts +25 -0
  422. package/src/policy/request-status.ts +10 -1
  423. package/src/policy/reserved-servers.ts +3 -2
  424. package/src/policy/tests/credential-material.test.ts +49 -1
  425. package/src/policy/tests/message-limits.test.ts +27 -0
  426. package/src/policy/tests/reserved-servers.test.ts +3 -3
  427. package/src/policy/turned-away.ts +5 -1
  428. package/src/protocol/container-requirements.ts +4 -5
  429. package/src/protocol/{listener-protocol.ts → doors/listener-protocol.ts} +37 -15
  430. package/src/protocol/doors/phone-links.ts +50 -0
  431. package/src/protocol/doors/phone-protocol.test.ts +136 -0
  432. package/src/protocol/doors/phone-protocol.ts +71 -0
  433. package/src/protocol/{runner-protocol.ts → doors/runner-protocol.ts} +1 -1
  434. package/src/protocol/{webext-links.ts → doors/webext-links.ts} +4 -0
  435. package/src/protocol/edge-verdict.ts +1 -1
  436. package/src/protocol/headers.ts +14 -0
  437. package/src/protocol/ingress-contract.ts +6 -10
  438. package/src/protocol/peer-dial.test.ts +83 -4
  439. package/src/protocol/peer-dial.ts +33 -40
  440. package/src/protocol/raw/extension-protocol.ts +59 -0
  441. package/src/protocol/raw/raw-json-routes.ts +61 -0
  442. package/src/protocol/{raw-routes.ts → raw/raw-routes.ts} +40 -7
  443. package/src/protocol/raw/route-path.ts +13 -0
  444. package/src/protocol/route-meta.ts +4 -4
  445. package/src/protocol/routes.ts +12 -0
  446. package/src/protocol/sse.test.ts +49 -0
  447. package/src/protocol/sse.ts +29 -14
  448. package/src/protocol/tunnel-bulk.test.ts +1 -1
  449. package/src/protocol/tunnel-bulk.ts +2 -2
  450. package/src/protocol/vitals.test.ts +7 -7
  451. package/src/protocol/vitals.ts +12 -7
  452. package/src/schemas/activity.ts +1 -0
  453. package/src/schemas/agent.ts +11 -4
  454. package/src/schemas/agents-list.ts +24 -0
  455. package/src/schemas/agents.ts +71 -2
  456. package/src/schemas/automations.ts +126 -24
  457. package/src/schemas/capabilities.ts +13 -3
  458. package/src/schemas/ci.ts +10 -0
  459. package/src/schemas/devices.ts +24 -0
  460. package/src/schemas/engines.ts +7 -0
  461. package/src/schemas/extension-updates.ts +93 -3
  462. package/src/schemas/git/git.ts +15 -4
  463. package/src/schemas/history.ts +2 -0
  464. package/src/schemas/hosts.ts +23 -1
  465. package/src/schemas/loopback-catch.ts +6 -1
  466. package/src/schemas/maintenance.ts +9 -0
  467. package/src/schemas/members.ts +33 -0
  468. package/src/schemas/metrics.ts +21 -3
  469. package/src/schemas/needs.ts +36 -3
  470. package/src/schemas/offload.ts +1 -1
  471. package/src/schemas/peer-enrollment.ts +14 -0
  472. package/src/schemas/phone.ts +121 -0
  473. package/src/schemas/privacy.ts +36 -7
  474. package/src/schemas/project-delivery.ts +78 -0
  475. package/src/schemas/providers/plan-limits.ts +27 -3
  476. package/src/schemas/providers/usage.ts +3 -3
  477. package/src/schemas/push.ts +1 -0
  478. package/src/schemas/secrets.ts +54 -3
  479. package/src/schemas/settings-history.ts +2 -0
  480. package/src/schemas/settings.ts +20 -22
  481. package/src/schemas/terminal.ts +50 -0
  482. package/src/schemas/updates.test.ts +47 -0
  483. package/src/schemas/updates.ts +4 -0
  484. package/src/schemas/workspace/workspace-search.ts +2 -0
  485. package/src/schemas/workspace/workspace-tree.ts +40 -12
  486. package/src/state/arrival.ts +40 -0
  487. package/src/state/contract-lock.test.ts +1 -1
  488. package/src/state/contract-lock.ts +5 -5
  489. package/src/state/history-state.ts +72 -1
  490. package/src/state/runtime-state.ts +4 -0
  491. package/src/state/workspace-state.ts +65 -20
  492. package/src/text/embed.test.ts +21 -1
  493. package/src/text/embed.ts +50 -3
  494. package/src/text/pages.test.ts +161 -0
  495. package/src/text/pages.ts +344 -0
  496. package/src/text/transcript-fold.test.ts +22 -0
  497. package/src/text/transcript-fold.ts +41 -2
  498. package/src/webext/index.ts +3 -2
  499. package/dist/front/browser-wire.d.ts.map +0 -1
  500. package/dist/front/browser-wire.js.map +0 -1
  501. package/dist/front/front-wire.d.ts +0 -6
  502. package/dist/front/front-wire.d.ts.map +0 -1
  503. package/dist/front/front-wire.js +0 -5
  504. package/dist/front/front-wire.js.map +0 -1
  505. package/dist/front/generated/browser-wire.d.ts.map +0 -1
  506. package/dist/front/generated/browser-wire.js.map +0 -1
  507. package/dist/front/generated/wire.d.ts.map +0 -1
  508. package/dist/protocol/host-protocol.d.ts.map +0 -1
  509. package/dist/protocol/host-protocol.js.map +0 -1
  510. package/dist/protocol/listener-protocol.d.ts.map +0 -1
  511. package/dist/protocol/listener-protocol.js +0 -33
  512. package/dist/protocol/listener-protocol.js.map +0 -1
  513. package/dist/protocol/raw-routes.d.ts.map +0 -1
  514. package/dist/protocol/raw-routes.js.map +0 -1
  515. package/dist/protocol/request-id.d.ts +0 -2
  516. package/dist/protocol/request-id.d.ts.map +0 -1
  517. package/dist/protocol/request-id.js +0 -2
  518. package/dist/protocol/request-id.js.map +0 -1
  519. package/dist/protocol/runner-protocol.d.ts.map +0 -1
  520. package/dist/protocol/runner-protocol.js.map +0 -1
  521. package/dist/protocol/webext-links.d.ts.map +0 -1
  522. package/dist/protocol/webext-links.js.map +0 -1
  523. package/dist/protocol/webext-protocol.d.ts.map +0 -1
  524. package/dist/protocol/webext-protocol.js.map +0 -1
  525. package/src/front/front-wire.ts +0 -15
  526. package/src/protocol/request-id.ts +0 -2
  527. /package/dist/{front → netd}/browser-wire.d.ts +0 -0
  528. /package/dist/{front → netd}/browser-wire.js +0 -0
  529. /package/dist/{front → netd}/generated/browser-wire.js +0 -0
  530. /package/dist/{front → netd}/generated/wire.js +0 -0
  531. /package/dist/protocol/{host-protocol.d.ts → doors/host-protocol.d.ts} +0 -0
  532. /package/dist/protocol/{host-protocol.js → doors/host-protocol.js} +0 -0
  533. /package/dist/protocol/{runner-protocol.d.ts → doors/runner-protocol.d.ts} +0 -0
  534. /package/dist/protocol/{webext-protocol.d.ts → doors/webext-protocol.d.ts} +0 -0
  535. /package/dist/protocol/{webext-protocol.js → doors/webext-protocol.js} +0 -0
  536. /package/src/protocol/{host-protocol.ts → doors/host-protocol.ts} +0 -0
  537. /package/src/protocol/{webext-protocol.ts → doors/webext-protocol.ts} +0 -0
@@ -178,8 +178,8 @@ test("a far end that never answers is reported a few times, then retried quietly
178
178
  expect.stringContaining("14 failed attempts"),
179
179
  ]);
180
180
  // The retries themselves are untouched while the outage is young: one dial per ladder delay, twenty of them.
181
- // The twentieth failure is what arms the long rest, so the dial after it is LONG_OUTAGE_MS away rather than
182
- // one more rung — quiet in the log and quiet on the wire, which are separate rules meeting here.
181
+ // The twentieth failure is what arms the long rest, so the dial after it is LONG_OUTAGE_MS past its rung rather
182
+ // than one more rung — quiet in the log and quiet on the wire, which are separate rules meeting here.
183
183
  expect(sockets).toHaveLength(20);
184
184
  await advanceTimersByTimeAsync(LONG_OUTAGE_MS);
185
185
  await waitFor(() => expect(sockets).toHaveLength(21));
@@ -286,8 +286,11 @@ test("a link nobody has answered in a long time rests between tries, and is neve
286
286
  await advanceTimersByTimeAsync(RUNG_MS);
287
287
  expect(sockets).toHaveLength(LONG_OUTAGE_ATTEMPTS);
288
288
 
289
- // And it does come round: slowed, never abandoned.
290
- await advanceTimersByTimeAsync(LONG_OUTAGE_MS - RUNG_MS);
289
+ // And it does come round, the rest on top of the ladder's own (jittered) draw so links that went quiet together
290
+ // do not come back together: slowed, never abandoned.
291
+ await advanceTimersByTimeAsync(LONG_OUTAGE_MS - 1);
292
+ expect(sockets).toHaveLength(LONG_OUTAGE_ATTEMPTS);
293
+ await advanceTimersByTimeAsync(1);
291
294
  await waitFor(() => expect(sockets).toHaveLength(LONG_OUTAGE_ATTEMPTS + 1));
292
295
 
293
296
  // And one answer puts it straight back on the fast ladder — the outage is over, the penalty goes with it.
@@ -357,6 +360,82 @@ test("a stop during resolution opens nothing, and a socket a slow resolver still
357
360
  await waitFor(() => expect(late[0]?.closed).toEqual({ code: 1000, reason: "stopping" }));
358
361
  });
359
362
 
363
+ // The redial used to be a bare timer: a link stopped while it waited on the ladder still dialled when the wait ran
364
+ // out (a real socket, closed again only once the resolver had answered), read "connecting" while it did, and held
365
+ // the process open for as long as the rung, fifteen minutes and more in a long outage.
366
+ test("a stop during the wait on the ladder ends the wait: nothing is dialled and nothing is left armed", async () => {
367
+ jest.useFakeTimers();
368
+ try {
369
+ const { link, sockets } = dialling(60_000);
370
+ await waitFor(() => expect(sockets).toHaveLength(1));
371
+ sockets[0]?.opens();
372
+ sockets[0]?.drops(1006);
373
+ expect(link.state()).toBe("connecting");
374
+
375
+ link.stop();
376
+ await link.done;
377
+ expect(link.state()).toBe("closed");
378
+ expect(jest.getTimerCount()).toBe(0);
379
+ await advanceTimersByTimeAsync(120_000);
380
+ expect(sockets).toHaveLength(1);
381
+ expect(link.state()).toBe("closed");
382
+ } finally {
383
+ jest.useRealTimers();
384
+ }
385
+ });
386
+
387
+ // A socket abandoned for its silence can still deliver a frame it had buffered; that is no reason to arm a watchdog
388
+ // for it again, which used to fire later only to find the socket already given up.
389
+ test("a frame from a socket already abandoned arms nothing", async () => {
390
+ jest.useFakeTimers();
391
+ try {
392
+ const { link, sockets } = dialling(60_000);
393
+ await waitFor(() => expect(sockets).toHaveLength(1));
394
+ sockets[0]?.opens();
395
+ await advanceTimersByTimeAsync(SILENCE_MS);
396
+ expect(sockets[0]?.closed).toEqual({ code: 1000, reason: "no heartbeat" });
397
+ // The ladder's wait is the one timer now.
398
+ expect(jest.getTimerCount()).toBe(1);
399
+ sockets[0]?.says();
400
+ expect(jest.getTimerCount()).toBe(1);
401
+ link.stop();
402
+ await link.done;
403
+ } finally {
404
+ jest.useRealTimers();
405
+ }
406
+ });
407
+
408
+ // A hello that has to be fetched (the webext reads its token from storage) can resolve after the link is gone.
409
+ test("a hello that resolves after a stop sends nothing and announces no connection", async () => {
410
+ let hand: ((hello: Record<string, unknown>) => void) | undefined;
411
+ const sockets: FakeSocket[] = [];
412
+ const said: string[] = [];
413
+ const link = dialPeer<FakeSocket>({
414
+ open: async () => {
415
+ const socket = new FakeSocket();
416
+ sockets.push(socket);
417
+ return { socket, said: "connected" };
418
+ },
419
+ hello: () =>
420
+ new Promise((resolve) => {
421
+ hand = resolve;
422
+ }),
423
+ attach: () => undefined,
424
+ backoff: ladder(),
425
+ silenceMs: SILENCE_MS,
426
+ log: (message) => void said.push(message),
427
+ revoked: () => undefined,
428
+ });
429
+ await waitFor(() => expect(sockets).toHaveLength(1));
430
+ sockets[0]?.opens();
431
+ link.stop();
432
+ await link.done;
433
+ hand?.({ type: "hello" });
434
+ await new Promise<void>((resolve) => setTimeout(resolve, 0));
435
+ expect(sockets[0]?.sent).toEqual([]);
436
+ expect(said).toEqual([]);
437
+ });
438
+
360
439
  test("a pairing that is gone by the next attempt ends the loop rather than dialling nowhere", async () => {
361
440
  let pairings = 1;
362
441
  const sockets: FakeSocket[] = [];
@@ -1,3 +1,5 @@
1
+ import { anySignal, sleep, whenAborted } from "@intentic/base/async";
2
+
1
3
  // The one outbound socket a peer (machine agent, webext, runner) holds to its sandbox: hello carries the enrollment
2
4
  // token in the frame, then the link is pure oRPC. Reconnects on backoff after any drop except a revoked enrollment
3
5
  // (code 1008), which never retries.
@@ -85,17 +87,13 @@ export interface PeerLink {
85
87
  }
86
88
 
87
89
  export const dialPeer = <S extends SocketLike>(spec: PeerDialSpec<S>): PeerLink => {
90
+ // The loop's whole life: every way it ends (a stop, a revocation, a pairing gone) aborts this, and everything the
91
+ // loop arms hangs off it, so nothing it left behind can dial, wait or fire once it is over. A stopped link that
92
+ // kept a timer armed is a process the runtime keeps alive for a socket nobody holds any more.
88
93
  const stopping = new AbortController();
94
+ const done = new Promise<void>((resolve) => void whenAborted(stopping.signal, () => resolve()));
89
95
  let socket: S | undefined;
90
- let waiting = false;
91
96
  let openedAt: number | undefined;
92
- // The live attempt's watchdog, reachable from `stop`: a stopped link that left a timer armed is a process
93
- // the runtime keeps alive for a socket nobody holds any more.
94
- let disarmWatchdog: () => void = () => undefined;
95
- let resolveDone: () => void = () => undefined;
96
- const done = new Promise<void>((resolve) => {
97
- resolveDone = resolve;
98
- });
99
97
  // Consecutive attempts that have failed since this link was last open, and when the loop last complained out
100
98
  // loud: between them they are the whole of the quiet rule above.
101
99
  let failures = 0;
@@ -124,9 +122,7 @@ export const dialPeer = <S extends SocketLike>(spec: PeerDialSpec<S>): PeerLink
124
122
  };
125
123
 
126
124
  const open = async (): Promise<void> => {
127
- waiting = true;
128
125
  const attempt = await spec.open(stopping.signal);
129
- waiting = false;
130
126
  // Aborted while resolving: nothing to open, `done` settled; a socket handed over late is closed, not dialled.
131
127
  if (stopping.signal.aborted) {
132
128
  attempt?.socket.close(1000, "stopping");
@@ -134,48 +130,44 @@ export const dialPeer = <S extends SocketLike>(spec: PeerDialSpec<S>): PeerLink
134
130
  }
135
131
  if (attempt === undefined) {
136
132
  stopping.abort();
137
- resolveDone();
138
133
  return;
139
134
  }
140
135
  const ws = attempt.socket;
141
136
  socket = ws;
142
137
 
138
+ // This socket's own life, ended by its drop or by the loop's. Its watchdog is cleared with it, so no way out of
139
+ // an attempt leaves a timer armed, and whatever the socket still emits afterwards speaks for nothing.
140
+ const dropped = new AbortController();
141
+ const live = anySignal(dropped.signal, stopping.signal);
143
142
  let watchdog: ReturnType<typeof setTimeout> | undefined;
144
- const disarm = (): void => {
145
- if (watchdog !== undefined) {
146
- clearTimeout(watchdog);
147
- watchdog = undefined;
148
- }
149
- };
150
- disarmWatchdog = disarm;
143
+ whenAborted(live, () => clearTimeout(watchdog));
151
144
 
152
- /* An attempt drop is recorded when either endpoint notices the closed far end. */
153
- let dropped = false;
145
+ /* An attempt drop is recorded when either endpoint notices the closed far end; the first to notice ends it. */
154
146
  const drop = (said: string): void => {
155
- if (dropped) {
156
- return;
147
+ if (live.aborted) {
148
+ return; // noticed already, or the link was stopped and owes the ladder nothing
157
149
  }
158
- dropped = true;
159
- disarm();
150
+ dropped.abort();
160
151
  if (socket === ws) {
161
152
  socket = undefined;
162
153
  }
163
- if (stopping.signal.aborted) {
164
- resolveDone();
165
- return;
166
- }
167
154
  const rung = spec.backoff.next(openedAt === undefined ? 0 : Date.now() - openedAt);
168
155
  openedAt = undefined;
169
156
  failures += 1;
170
157
  failingSince ??= Date.now();
171
- const delay = failures >= LONG_OUTAGE_ATTEMPTS ? Math.max(rung, LONG_OUTAGE_MS) : rung;
158
+ // The rest is added to the ladder's draw rather than replacing it: a flat fifteen minutes would bring back in
159
+ // lockstep every link that entered the long outage together.
160
+ const delay = failures >= LONG_OUTAGE_ATTEMPTS ? LONG_OUTAGE_MS + rung : rung;
172
161
  complain(said, delay);
173
- waiting = true;
174
- setTimeout(() => void open(), delay);
162
+ // The wait hangs off the stop: a link stopped during it is done at once and never dials again.
163
+ void sleep(delay, { signal: stopping.signal }).then(() => (stopping.signal.aborted ? undefined : open()));
175
164
  };
176
165
 
177
166
  const arm = (): void => {
178
- disarm();
167
+ clearTimeout(watchdog);
168
+ if (live.aborted) {
169
+ return; // a frame from a socket already abandoned proves nothing about the link
170
+ }
179
171
  watchdog = setTimeout(() => {
180
172
  /* ABANDONED, not closed politely. A close frame sent to an end that is gone waits on a reply. */
181
173
  ws.close(1000, "no heartbeat");
@@ -189,7 +181,7 @@ export const dialPeer = <S extends SocketLike>(spec: PeerDialSpec<S>): PeerLink
189
181
  ws.addEventListener("message", arm);
190
182
 
191
183
  ws.addEventListener("open", () => {
192
- if (dropped) {
184
+ if (live.aborted) {
193
185
  return; // abandoned mid-connect: this socket is already closed and its replacement is on the ladder
194
186
  }
195
187
  openedAt = Date.now();
@@ -201,6 +193,10 @@ export const dialPeer = <S extends SocketLike>(spec: PeerDialSpec<S>): PeerLink
201
193
  arm();
202
194
  spec.attach(ws);
203
195
  const send = (hello: Record<string, unknown>): void => {
196
+ // A hello that resolves after its socket dropped, or the link stopped, has no connection to announce.
197
+ if (live.aborted) {
198
+ return;
199
+ }
204
200
  ws.send(JSON.stringify(hello));
205
201
  if (attempt.said !== undefined) {
206
202
  spec.log(attempt.said);
@@ -218,13 +214,10 @@ export const dialPeer = <S extends SocketLike>(spec: PeerDialSpec<S>): PeerLink
218
214
  ws.addEventListener("close", (event) => {
219
215
  /* A revocation is answered here rather than through `drop`: it is the one close that ends the loop. */
220
216
  if (event.code === PEER_UNAUTHORIZED) {
221
- dropped = true;
222
- disarm();
223
217
  if (socket === ws) {
224
218
  socket = undefined;
225
219
  }
226
220
  stopping.abort();
227
- resolveDone();
228
221
  spec.revoked();
229
222
  return;
230
223
  }
@@ -247,15 +240,15 @@ export const dialPeer = <S extends SocketLike>(spec: PeerDialSpec<S>): PeerLink
247
240
  done,
248
241
  stop: (reason = "stopping") => {
249
242
  stopping.abort();
250
- waiting = false;
251
- disarmWatchdog();
252
243
  // Forgotten before the close frame arrives, so `state` reads closed the moment the peer asked.
253
244
  const held = socket;
254
245
  socket = undefined;
255
246
  held?.close(1000, reason);
256
- resolveDone();
257
247
  },
258
- state: () => (socket?.readyState === OPEN ? "open" : socket !== undefined || waiting ? "connecting" : "closed"),
248
+ // Short of an open socket, a loop still running is "connecting" (a dial resolving, a handshake, a wait on the
249
+ // ladder) and a finished one is closed: read off the loop itself, not a flag kept beside it that a redial
250
+ // firing after the stop could set back.
251
+ state: () => (socket?.readyState === OPEN ? "open" : stopping.signal.aborted ? "closed" : "connecting"),
259
252
  outage: () => (failingSince === undefined ? undefined : { failures, since: failingSince }),
260
253
  };
261
254
  };
@@ -0,0 +1,59 @@
1
+ import { z } from "zod";
2
+ import { rawRouteUrl } from "./raw-routes.js";
3
+
4
+ // The wire between the daemon and an extension's own code, its backend in the shared host and its declared processes
5
+ // alike: the two routes every extension token reaches about itself (EXTENSION_OWN_ROUTES in extension-manifest), and
6
+ // the environment a process is started with. `@intentic/extension-api/runtime` reads both, so the daemon and the SDK
7
+ // compile against one declaration. A subpath of its own, since a gateway process loads no more of the contract than it
8
+ // needs (the root builds every schema there is).
9
+
10
+ // GET /extension/settings: the calling extension's own settings, secret values included, keyed by the declaration.
11
+ export const ExtensionOwnSettingsSchema = z.object({
12
+ settings: z.record(z.string(), z.union([z.string(), z.number(), z.boolean()])),
13
+ });
14
+ export type ExtensionOwnSettings = z.infer<typeof ExtensionOwnSettingsSchema>;
15
+
16
+ // GET /extension/events: one ndjson frame per line, for as long as the caller holds the stream. A heartbeat every
17
+ // EXTENSION_EVENTS_HEARTBEAT_MS says the daemon is still there; the rest name what moved. `settings` carries only the
18
+ // calling extension's own keys whose value changed.
19
+ export const ExtensionEventSchema = z.discriminatedUnion("kind", [
20
+ z.object({ kind: z.literal("heartbeat") }),
21
+ z.object({ kind: z.literal("files"), paths: z.array(z.string()) }),
22
+ z.object({ kind: z.literal("refs"), repos: z.array(z.string()) }),
23
+ z.object({ kind: z.literal("repos"), repos: z.array(z.string()) }),
24
+ z.object({ kind: z.literal("settings"), keys: z.array(z.string()) }),
25
+ ]);
26
+ export type ExtensionEvent = z.infer<typeof ExtensionEventSchema>;
27
+
28
+ export const EXTENSION_EVENTS_HEARTBEAT_MS = 15_000;
29
+
30
+ // The kinds a listener subscribes to, every frame but the heartbeat.
31
+ export const EXTENSION_EVENT_KINDS = ["files", "refs", "repos", "settings"] as const;
32
+ export type ExtensionEventKind = (typeof EXTENSION_EVENT_KINDS)[number];
33
+
34
+ // A backend's own account of itself (`ServerActivation.health` in @intentic/extension-api), as the host reads it from
35
+ // the extension's code and passes it on: a closed set of states and an optional sentence.
36
+ export const ExtensionHealthSchema = z.object({
37
+ state: z.enum(["ok", "starting", "degraded", "failed"]),
38
+ detail: z.string().optional(),
39
+ });
40
+
41
+ export const extensionSettingsUrl = (): string => rawRouteUrl("GET /extension/settings");
42
+ export const extensionEventsUrl = (): string => rawRouteUrl("GET /extension/events");
43
+
44
+ // What the daemon starts an extension's process with, and what `connectExtensionProcess` reads. The token is the same
45
+ // minted per-extension token its backend carries; the directories are the ones the backend api names.
46
+ export const EXTENSION_PROCESS_ENV = {
47
+ daemon: "INTENTIC_DAEMON",
48
+ token: "INTENTIC_EXTENSION_TOKEN",
49
+ id: "INTENTIC_EXTENSION_ID",
50
+ workspace: "INTENTIC_WORKSPACE",
51
+ dir: "INTENTIC_EXTENSION_DIR",
52
+ state: "INTENTIC_EXTENSION_STATE",
53
+ cache: "INTENTIC_EXTENSION_CACHE",
54
+ // The manifest's `permissions.daemon` as a JSON array, so a typed call outside it is refused before it is sent.
55
+ permissions: "INTENTIC_EXTENSION_PERMISSIONS",
56
+ } as const;
57
+
58
+ // What the permissions variable holds.
59
+ export const ExtensionPermissionsSchema = z.array(z.string());
@@ -0,0 +1,61 @@
1
+ import type { z } from "zod";
2
+ import { EngineChannelInputSchema, EngineRevertInputSchema, EnginesViewSchema, EngineUpdateInputSchema, EngineWriteResultSchema } from "../../schemas/engines.js";
3
+ import {
4
+ EnvironmentApproveSchema,
5
+ EnvironmentContentsSchema,
6
+ EnvironmentRebuildWhenIdleSchema,
7
+ EnvironmentRemoveSchema,
8
+ EnvironmentRuntimeDecisionSchema,
9
+ EnvironmentSchema,
10
+ } from "../../schemas/environment.js";
11
+ import { MemberEmailSchema, MemberGrantSchema, MembersListSchema, MembersRosterSchema } from "../../schemas/members.js";
12
+ import { OkSchema } from "../../schemas/shared.js";
13
+ import { DefinitionDiffSchema, DefinitionExportSchema, WorkspacePublishResultSchema, WorkspacePublishSchema, WorkspaceRemoteSchema } from "../../state/definition.js";
14
+ import type { RawRouteKey } from "./raw-routes.js";
15
+
16
+ // What a raw route that answers plain JSON takes and answers, under its RAW_ROUTES key. `input` is the JSON body a write
17
+ // sends; `text` marks one whose body is a document rather than JSON (a sandbox.toml to diff). A caller reaches these by
18
+ // key through a typed helper that parses the answer with `output`, so a hand-written route is as typed as a procedure.
19
+ // A refusal is the daemon's `{ "error": … }` with a 4xx status on every one of them, outside these schemas.
20
+ export interface RawJsonRoute {
21
+ readonly input?: z.ZodType;
22
+ readonly text?: true;
23
+ readonly output: z.ZodType;
24
+ }
25
+
26
+ export const RAW_JSON_ROUTES = {
27
+ // The roster is ownership's; every write answers the roster after it.
28
+ "GET /members": { output: MembersRosterSchema },
29
+ "POST /members": { input: MemberGrantSchema, output: MembersListSchema },
30
+ "DELETE /members": { input: MemberEmailSchema, output: MembersListSchema },
31
+ "DELETE /members/self": { output: OkSchema },
32
+ // Every environment write answers the environment after it. `/environment/contents` takes `?refresh` to probe again.
33
+ "GET /environment": { output: EnvironmentSchema },
34
+ "GET /environment/contents": { output: EnvironmentContentsSchema },
35
+ "POST /environment/approve": { input: EnvironmentApproveSchema, output: EnvironmentSchema },
36
+ "POST /environment/reject": { output: EnvironmentSchema },
37
+ "POST /environment/runtime-install": { input: EnvironmentRuntimeDecisionSchema, output: EnvironmentSchema },
38
+ "POST /environment/remove": { input: EnvironmentRemoveSchema, output: EnvironmentSchema },
39
+ "POST /environment/rebuild-when-idle": { input: EnvironmentRebuildWhenIdleSchema, output: EnvironmentSchema },
40
+ "DELETE /environment/rebuild-when-idle": { output: EnvironmentSchema },
41
+ "GET /engines": { output: EnginesViewSchema },
42
+ "POST /engines/channel": { input: EngineChannelInputSchema, output: EngineWriteResultSchema },
43
+ "POST /engines/update": { input: EngineUpdateInputSchema, output: EngineWriteResultSchema },
44
+ "POST /engines/revert": { input: EngineRevertInputSchema, output: EngineWriteResultSchema },
45
+ "GET /definition": { output: DefinitionExportSchema },
46
+ "POST /definition/diff": { text: true, output: DefinitionDiffSchema },
47
+ "GET /definition/workspace": { output: WorkspaceRemoteSchema },
48
+ "POST /definition/workspace/publish": { input: WorkspacePublishSchema, output: WorkspacePublishResultSchema },
49
+ } as const satisfies Partial<Record<RawRouteKey, RawJsonRoute>>;
50
+
51
+ export type RawJsonRouteKey = keyof typeof RAW_JSON_ROUTES;
52
+
53
+ // What a JSON raw route answers, parsed.
54
+ export type RawJsonOutput<Key extends RawJsonRouteKey> = z.output<(typeof RAW_JSON_ROUTES)[Key]["output"]>;
55
+
56
+ // What a JSON raw route's body is: its input's shape, a string for a document body, undefined for one that takes none.
57
+ export type RawJsonInput<Key extends RawJsonRouteKey> = (typeof RAW_JSON_ROUTES)[Key] extends { readonly input: infer Input extends z.ZodType }
58
+ ? z.input<Input>
59
+ : (typeof RAW_JSON_ROUTES)[Key] extends { readonly text: true }
60
+ ? string
61
+ : undefined;
@@ -1,10 +1,12 @@
1
- import type { RouteMeta } from "./route-meta.js";
2
- import type { ContractRoute } from "./routes.js";
3
- import { runnerTranslatorPath } from "./runner-protocol.js";
1
+ import type { RouteMeta } from "../route-meta.js";
2
+ import { fillRoutePath, type RoutePathParams } from "./route-path.js";
3
+ import type { ContractRoute } from "../routes.js";
4
+ import { runnerTranslatorPath } from "../doors/runner-protocol.js";
4
5
 
5
6
  // Every route the daemon serves outside oRPC (streamed bytes, WebSocket upgrades, doors checking their own credential),
6
7
  // keyed `METHOD /path` in the order the daemon registers them: among overlapping ones the first registered answers.
7
8
  // `{param}` is one path segment, a trailing `/*` any further ones, `ALL` every method; the daemon serves no other.
9
+ // A route that answers plain JSON has its input and answer schemas in raw-json-routes.ts, under the same key.
8
10
  export const RAW_ROUTES = {
9
11
  // The "is a daemon there" probe every flow uses; it names the sandbox and says whether it is still converging.
10
12
  "GET /health": { auth: "door", beforeBoot: true },
@@ -29,15 +31,18 @@ export const RAW_ROUTES = {
29
31
  "POST /workspace/upload-archive": { lane: "bulk" },
30
32
  // Minting is cheap: each WebSocket upgrade floors its own redemption.
31
33
  "POST /system/ws-ticket": { beforeBoot: true, floor: "collaborator", control: "never" },
32
- // A WebSocket upgrade carries no Authorization header; the terminal and both browser wires check a query ticket.
33
- "GET /system/terminal": { auth: "door", beforeBoot: true, control: "never", front: true },
34
- // The front's proof of life (vitals.ts): no credential and nothing of the workspace, readable by any origin, answered
34
+ // A WebSocket upgrade carries no Authorization header; the terminal, both browser wires and the desktop's check a
35
+ // query ticket.
36
+ "GET /system/terminal": { auth: "door", beforeBoot: true, control: "never", netd: true },
37
+ // netd's proof of life (vitals.ts): no credential and nothing of the workspace, readable by any origin, answered
35
38
  // whatever state the daemon is in.
36
- "GET /system/vitals": { auth: "door", beforeBoot: true, front: true },
39
+ "GET /system/vitals": { auth: "door", beforeBoot: true, netd: true },
37
40
  // Desktop sync's byte pipe, guarded again by sshd's own key check against the same enrollment.
38
41
  "GET /system/sync/ssh": { sync: "pipe", control: "never", lane: "bulk" },
39
42
  "GET /system/browser-profile": { auth: "door", beforeBoot: true, control: "never" },
40
43
  "GET /system/browser-view": { auth: "door", beforeBoot: true, control: "never" },
44
+ // The sandbox's own desktop, watched and driven by the owner (desktop/desktop-view.ts); the same query ticket.
45
+ "GET /system/desktop-view": { auth: "door", beforeBoot: true, control: "never" },
41
46
  // Deploy-target enrollment, gated by the connect token.
42
47
  "POST /enroll": { auth: "door", control: "never" },
43
48
  // An event automation's webhook, gated by the automation's own token.
@@ -90,6 +95,9 @@ export const RAW_ROUTES = {
90
95
  "GET /arrivals/hosts": {},
91
96
  "POST /arrivals/scan": {},
92
97
  "POST /arrivals/apply": {},
98
+ // Model API keys on the owner's devices, and turning the picked ones into model endpoints.
99
+ "GET /arrivals/keys": {},
100
+ "POST /arrivals/keys/apply": {},
93
101
  "DELETE /arrivals": {},
94
102
  "GET /extensions/{id}/bundle": { lane: "bulk" },
95
103
  // An extension backend's own namespace, proxied verbatim.
@@ -122,6 +130,11 @@ export const RAW_ROUTES = {
122
130
  "POST /listeners/{provider}/dispatch": { panel: false, control: "never" },
123
131
  "POST /listeners/{provider}/failure": { panel: false, control: "never" },
124
132
  "POST /listeners/{provider}/status": { panel: false, control: "never" },
133
+ // What an extension's own code asks about itself (extension-protocol.ts): its settings with their secrets, and its
134
+ // event stream. Every extension token reaches both undeclared, and each answers only about the extension asking, so
135
+ // no other credential reaches them; the handler resolves the caller from its token again.
136
+ "GET /extension/settings": { floor: "maintainer", panel: false, control: "never" },
137
+ "GET /extension/events": { floor: "maintainer", panel: false, control: "never", stream: true },
125
138
  // The CI webhook receiver, gated by the per-sandbox webhook secret.
126
139
  "POST /ci/webhook/{host}": { auth: "door" },
127
140
  // Below maintainer a pairing is capped to port-mirror, so a collaborator may mint a preview tunnel.
@@ -138,6 +151,13 @@ export const RAW_ROUTES = {
138
151
  "GET /system/webext": { control: "never" },
139
152
  "DELETE /system/webext/{id}": { control: "never" },
140
153
  "GET /system/webext/connect": { auth: "door", beforeBoot: true, control: "never" },
154
+ "POST /system/phones/pair": { control: "never" },
155
+ "POST /system/phones/enroll": { auth: "door", control: "never" },
156
+ "GET /system/phones": { control: "never" },
157
+ "DELETE /system/phones/{id}": { control: "never" },
158
+ "GET /system/phones/connect": { auth: "door", beforeBoot: true, control: "never" },
159
+ // The editor hands over the push-relay channel it registered for a phone, so the sandbox can wake it.
160
+ "POST /system/phones/{id}/wake": { control: "never" },
141
161
  "POST /system/runners/pair": { control: "never" },
142
162
  "POST /system/runners/enroll": { auth: "door", control: "never" },
143
163
  "GET /system/runners": { control: "never" },
@@ -162,6 +182,9 @@ export const RAW_ROUTES = {
162
182
  // (privacy/gateway/session-token.ts), which names the provider and the only upstream it may forward to. Held open
163
183
  // while a model streams its answer.
164
184
  "ALL /privacy/gateway/{session}/*": { auth: "door", control: "never", stream: true },
185
+ // Its sibling for MCP: a hooked runtime's (Cursor's) calls to its turn's MCP servers, on a session signed the same
186
+ // way, naming the provider and the one server it may forward to. Held open while a server streams its answer.
187
+ "ALL /privacy/mcp/{session}": { auth: "door", control: "never", stream: true },
165
188
  "POST /system/control/tokens": { control: "never" },
166
189
  "GET /system/control/tokens": { control: "never" },
167
190
  "DELETE /system/control/tokens/{id}": { control: "never" },
@@ -196,6 +219,16 @@ export type RawRouteKey = keyof typeof RAW_ROUTES;
196
219
  // A raw route's path, for a caller that builds a URL to it rather than registering it.
197
220
  export const rawRoutePath = (key: RawRouteKey): string => key.slice(key.indexOf(" ") + 1);
198
221
 
222
+ // The `{param}` values a raw route's path needs, by name; an empty record for a route with none.
223
+ export type RawRouteParams<Key extends RawRouteKey> = Readonly<Record<RoutePathParams<Key>, string>>;
224
+
225
+ // The path to call a raw route at: its template with every `{param}` filled and encoded as one segment. The one place a
226
+ // caller outside the daemon spells a raw route, so a path that moves in the table moves for every caller.
227
+ export const rawRouteUrl = <Key extends RawRouteKey>(
228
+ key: Key,
229
+ ...[params]: [RoutePathParams<Key>] extends [never] ? [] : [params: RawRouteParams<Key>]
230
+ ): string => fillRoutePath(rawRoutePath(key), params);
231
+
199
232
  // The table as routes of their own, each named by its key, in registration order.
200
233
  export const RAW_ROUTE_LIST: readonly (ContractRoute & { readonly name: RawRouteKey })[] = (Object.keys(RAW_ROUTES) as RawRouteKey[]).map((name) => ({
201
234
  name,
@@ -0,0 +1,13 @@
1
+ // A route template's `{param}` names, read off the template itself so a caller cannot leave one out.
2
+ export type RoutePathParams<Path extends string> = Path extends `${string}{${infer Name}}${infer Rest}` ? Name | RoutePathParams<Rest> : never;
3
+
4
+ // A route template with each `{param}` filled by its value, encoded as exactly one path segment. A value missing for a
5
+ // name the template carries throws: the path it would build names some other route.
6
+ export const fillRoutePath = (template: string, params: Readonly<Record<string, string>> = {}): string =>
7
+ template.replace(/\{([^}]+)\}/gu, (_, name: string) => {
8
+ const value = params[name];
9
+ if (value === undefined) {
10
+ throw new Error(`${template} needs a value for {${name}}`);
11
+ }
12
+ return encodeURIComponent(value);
13
+ });
@@ -33,11 +33,11 @@ export interface RouteMeta {
33
33
  // Withheld from the panel token, which reaches every other route: it puts a stored credential in motion.
34
34
  readonly panel?: false;
35
35
  readonly control?: ControlReach;
36
- // A transfer: announced to the edge through the front (tunnel-bulk.ts), which sends it down the tunnel's bulk socket,
36
+ // A transfer: announced to the edge through netd (tunnel-bulk.ts), which sends it down the tunnel's bulk socket,
37
37
  // off the connection every keystroke and call waits on.
38
38
  readonly lane?: "bulk";
39
- // Served by intentic-front itself (_sandbox/front, term/): the daemon only answers the front's question about it.
40
- readonly front?: true;
39
+ // Served by intentic-netd itself (_sandbox/netd, term/): the daemon only answers netd's question about it.
40
+ readonly netd?: true;
41
41
  }
42
42
 
43
43
  // The floor a route gets when it declares none: a read (GET, HEAD) floors at viewer, anything else (`ALL` included) at
@@ -45,7 +45,7 @@ export interface RouteMeta {
45
45
  export const defaultFloor = (method: string): MemberRole => (method === "GET" || method === "HEAD" ? "viewer" : "maintainer");
46
46
 
47
47
  // The fields that say how a request travels, not who may send it; every other RouteMeta field decides reach.
48
- type TransportField = "lane" | "front";
48
+ type TransportField = "lane" | "netd";
49
49
 
50
50
  // Every field that decides who reaches a route, with its default resolved, so an absent field and a declared one read
51
51
  // alike and loosening either is a changed value: what contract.lock.json records per route (`access:METHOD /path`),
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import type { RouteMeta } from "./route-meta.js";
3
+ import { fillRoutePath } from "./raw/route-path.js";
3
4
  import { FRAME, streamOf } from "./stream-of.js";
4
5
 
5
6
  // Named route surface of the daemon's contract (`<group>.<route>`), derived automatically so nothing here is
@@ -38,6 +39,17 @@ export interface ContractRoute {
38
39
  readonly meta: RouteMeta;
39
40
  }
40
41
 
42
+ // The path to call one contract procedure at, its `{param}`s filled and encoded, for a caller that speaks to the daemon
43
+ // without oRPC's client (a stream it reads itself, a published tool keeping its install small): the path comes from
44
+ // the contract, never spelled a second time.
45
+ export const procedurePath = (procedure: unknown, params?: Readonly<Record<string, string>>): string => {
46
+ const route = procedureRoute(procedure);
47
+ if (route === undefined) {
48
+ throw new Error("not a contract procedure with a route");
49
+ }
50
+ return fillRoutePath(route.path, params);
51
+ };
52
+
41
53
  // Walks a contract object (group → procedure) into a flat route list, sorted by name for a stable diff.
42
54
  export const contractRoutes = (contract: Record<string, unknown>): ContractRoute[] => {
43
55
  const routes: ContractRoute[] = [];
@@ -0,0 +1,49 @@
1
+ import { sseData, sseFrames } from "./sse.js";
2
+
3
+ const encoder = new TextEncoder();
4
+
5
+ // A body that hands over `chunks` in order, then either closes or stays open saying nothing, as a daemon behind a
6
+ // wedged tunnel does. `cancelled` records whether the reader let go of it.
7
+ const body = (chunks: readonly string[], close: boolean): { stream: ReadableStream<Uint8Array>; cancelled: () => boolean } => {
8
+ let cancelled = false;
9
+ let index = 0;
10
+ const stream = new ReadableStream<Uint8Array>({
11
+ pull(controller) {
12
+ const chunk = chunks[index++];
13
+ if (chunk !== undefined) {
14
+ controller.enqueue(encoder.encode(chunk));
15
+ } else if (close) {
16
+ controller.close();
17
+ }
18
+ },
19
+ cancel() {
20
+ cancelled = true;
21
+ },
22
+ });
23
+ return { stream, cancelled: () => cancelled };
24
+ };
25
+
26
+ const collect = async (frames: AsyncGenerator<string>): Promise<string[]> => {
27
+ const seen: string[] = [];
28
+ for await (const frame of frames) {
29
+ seen.push(frame);
30
+ }
31
+ return seen;
32
+ };
33
+
34
+ it("reassembles frames split across chunks and ends when the stream closes", async () => {
35
+ const { stream } = body([`data: {"a":1}\n`, `\ndata: {"b"`, `:2}\n\n`], true);
36
+ expect(await collect(sseFrames(stream))).toEqual([`data: {"a":1}`, `data: {"b":2}`]);
37
+ });
38
+
39
+ it("ends a stream that goes silent past the idle window, and lets go of it", async () => {
40
+ const { stream, cancelled } = body([`data: {"a":1}\n\n`], false);
41
+ expect(await collect(sseFrames(stream, 20))).toEqual([`data: {"a":1}`]);
42
+ expect(cancelled()).toBe(true);
43
+ });
44
+
45
+ it("reads a frame's data line as JSON, and nothing from a frame without one or with a malformed payload", () => {
46
+ expect(sseData(`event: turn\ndata: {"kind":"end"}`)).toEqual({ kind: `end` });
47
+ expect(sseData(`: keep-alive`)).toBeUndefined();
48
+ expect(sseData(`data: {not json`)).toBeUndefined();
49
+ });