@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
@@ -10,8 +10,8 @@ import { contributedServerMintingKinds } from "@intentic/extension-manifest";
10
10
  export type ServerProvenance = "control" | "outside";
11
11
 
12
12
  // Every server agent/run/agent.ts and agent/run/harness/harness-servers.ts mount themselves, plus the browser router's two
13
- // names (web, browser), which every turn mounts on its lease at the daemon's MCP door (browser-tools.ts) and which the
14
- // text scan reads from their constants. A server added anywhere else without a row here fails the conformance test in the sandbox guard package.
13
+ // names (web, browser) and the virtual desktop's (desktop), which a turn mounts on its lease at the daemon's MCP door
14
+ // (browser-tools.ts, desktop/desktop-tools.ts) and which the text scan reads from their constants. A server added anywhere else without a row here fails the conformance test in the sandbox guard package.
15
15
  export const DAEMON_MCP_SERVERS: Readonly<Record<string, ServerProvenance>> = {
16
16
  ui: "control", // agent.ts: AskUserQuestion
17
17
  accounts: "control", // agent.ts: the account roster and the credential typists
@@ -25,6 +25,7 @@ export const DAEMON_MCP_SERVERS: Readonly<Record<string, ServerProvenance>> = {
25
25
  diagnostics: "outside", // harness: two tools relay a provider's own sentence verbatim
26
26
  web: "outside", // the turn's mounts: the anonymous browser router; the page is the internet
27
27
  browser: "outside", // the turn's mounts: the signed-in browser router; the page is the internet
28
+ desktop: "outside", // the turn's mounts: the sandbox's own virtual desktop; whatever its windows show is outside content
28
29
  };
29
30
 
30
31
  // Every daemon-mounted server name, the set a capability id may not collide with.
@@ -1,4 +1,4 @@
1
- import { holdsCredentialMaterial, maskCredentialMaterial } from "../credential-material.js";
1
+ import { holdsCredentialMaterial, holdsCredentialToken, maskCredentialMaterial } from "../credential-material.js";
2
2
 
3
3
  // The two directions aren't symmetric: a miss just raises an extra card, a wrong clear un-gates a real credential read.
4
4
  // The "no" cases have to be exactly right; every "yes" case is a real file's real shape.
@@ -159,3 +159,51 @@ describe("masking what a credential file holds", () => {
159
159
  }
160
160
  });
161
161
  });
162
+
163
+ // A masked key keeps the lines that say what it was, and those lines alone must not read as a key: the public outbox
164
+ // sniffs a share page this masker produced, and refusing it would leave the share unserved.
165
+ describe("a private key once masked", () => {
166
+ const keys = [
167
+ "-----BEGIN OPENSSH PRIVATE KEY-----\nb3BlbnNzaC1rZXktdjEAAAAA\n-----END OPENSSH PRIVATE KEY-----\n",
168
+ "-----BEGIN RSA PRIVATE KEY-----\nMIIEow",
169
+ '{"private_key":"-----BEGIN PRIVATE KEY-----\\nMIIEvQIBADANBg\\n-----END PRIVATE KEY-----\\n"}',
170
+ "-----BEGIN PGP PRIVATE KEY BLOCK-----\nVersion: GnuPG v2\n\nlQOYBF0x8bEBCAC5\n=Xy1Z\n-----END PGP PRIVATE KEY BLOCK-----",
171
+ "PuTTY-User-Key-File-3: ssh-ed25519\nEncryption: none\nPrivate-Lines: 1\nAAAAIGr3dHg0\nPrivate-MAC: ab12ab12\n",
172
+ ];
173
+
174
+ test.each(keys)("no longer holds one: %s", (key) => {
175
+ expect(holdsCredentialMaterial(key)).toBe(true);
176
+ expect(holdsCredentialMaterial(maskCredentialMaterial(key))).toBe(false);
177
+ });
178
+
179
+ test("a key cut short is masked through its last body line", () => {
180
+ expect(maskCredentialMaterial("-----BEGIN RSA PRIVATE KEY-----\nMIIEow\nAKCAQEA\nnext line of prose")).toBe(
181
+ "-----BEGIN RSA PRIVATE KEY-----\n***\nnext line of prose",
182
+ );
183
+ expect(maskCredentialMaterial('{"key":"-----BEGIN RSA PRIVATE KEY-----\\nMIIEow\\nAKCAQEA"}')).toBe(
184
+ '{"key":"-----BEGIN RSA PRIVATE KEY-----\n***"}',
185
+ );
186
+ });
187
+
188
+ test("a putty key keeps only its first line's label", () => {
189
+ expect(maskCredentialMaterial(keys[4] ?? "")).toBe("PuTTY-User-Key-File-3: ***\n");
190
+ });
191
+
192
+ test.each(keys)("masking twice changes nothing: %s", (key) => {
193
+ const once = maskCredentialMaterial(key);
194
+ expect(maskCredentialMaterial(once)).toBe(once);
195
+ });
196
+ });
197
+
198
+ // The self-identifying half the outbox sniffs published files with: a key=value guess is the gate's, not the outbox's.
199
+ describe("a credential token in text that is not a credential file", () => {
200
+ test("is a shape that names itself", () => {
201
+ expect(holdsCredentialToken(`npm_${"a1B2".repeat(9)}`)).toBe(true);
202
+ expect(holdsCredentialToken("-----BEGIN PRIVATE KEY-----\nMIIEvQ")).toBe(true);
203
+ });
204
+
205
+ test("is never a credential-named key beside a value", () => {
206
+ expect(holdsCredentialToken("const config={apiKey:process.env.API_KEY,password:hunter22x}")).toBe(false);
207
+ expect(holdsCredentialMaterial("const config={apiKey:process.env.API_KEY,password:hunter22x}")).toBe(true);
208
+ });
209
+ });
@@ -0,0 +1,27 @@
1
+ import { awaitsOwner } from "../../schemas/automations.js";
2
+ import { extensionGatewayUrlFile } from "../../state/workspace-state.js";
3
+ import { MESSAGE_LIMITS, messageLimitOf } from "../message-limits.js";
4
+
5
+ test("a platform's limit is found whatever case the post spelled it in", () => {
6
+ expect(messageLimitOf("Discord")).toBe(2_000);
7
+ expect(messageLimitOf("TELEGRAM")).toBe(4_096);
8
+ expect(messageLimitOf("whatsapp")).toBe(MESSAGE_LIMITS.whatsapp);
9
+ expect(MESSAGE_LIMITS.whatsapp).toBe(65_536);
10
+ });
11
+
12
+ test("an unknown platform has no limit, and neither does a name only an object prototype answers to", () => {
13
+ expect(messageLimitOf("myspace")).toBeUndefined();
14
+ // A plain record lookup answered these with Object.prototype's own members, a function where a number belongs.
15
+ expect(messageLimitOf("constructor")).toBeUndefined();
16
+ expect(messageLimitOf("toString")).toBeUndefined();
17
+ });
18
+
19
+ test("only a held wake with no countdown waits on the owner", () => {
20
+ expect(awaitsOwner({})).toBe(true);
21
+ expect(awaitsOwner({ autoRunAt: 1_700_000_000_000 })).toBe(false);
22
+ });
23
+
24
+ test("a gateway's control address lives beside the extensions' own directories, under its provider", () => {
25
+ expect(extensionGatewayUrlFile("whatsapp")).toBe(".intentic/local/runtime/gateways/whatsapp.url");
26
+ expect(extensionGatewayUrlFile("../x")).toBe(".intentic/local/runtime/gateways/.._x.url");
27
+ });
@@ -24,10 +24,10 @@ describe("reserved MCP server names", () => {
24
24
  });
25
25
 
26
26
  describe("collidesWithReservedServer", () => {
27
- // Derived from the manifest schema's meanings: a cli card mints a server when it serves tools, a device and a
28
- // connected browser always do, and `mcp` is the core kind that is its own endpoint.
27
+ // Derived from the manifest schema's meanings: a cli card mints a server when it serves tools, a device, a
28
+ // connected browser and a connected phone always do, and `mcp` is the core kind that is its own endpoint.
29
29
  test("the minting kinds are exactly the ones whose id becomes a server name", () => {
30
- expect([...MCP_SERVER_MINTING_KINDS].toSorted()).toEqual(["cli", "device", "mcp", "webext"]);
30
+ expect([...MCP_SERVER_MINTING_KINDS].toSorted()).toEqual(["cli", "device", "mcp", "phone", "webext"]);
31
31
  });
32
32
 
33
33
  test("a kind whose id becomes a server name may not reuse a reserved one", () => {
@@ -11,8 +11,12 @@ const TURNED_AWAY: ReadonlySet<string> = new Set([
11
11
  "unknown-command",
12
12
  "context-window-too-small",
13
13
  "model-helper-only",
14
- // The privacy shield refused an untrusted provider on a runtime it cannot stand in front of.
14
+ // The privacy shield refused an untrusted provider on a runtime it cannot read by content at all.
15
15
  "privacy-unshielded",
16
+ // The protected execution boundary refused admission, not an executed provider/runtime failure.
17
+ "agent-domain-refused",
18
+ // The privacy shield found personal data in instructions a runtime loads itself, where it could not mask them.
19
+ "privacy-instructions",
16
20
  "sandbox-memory-low",
17
21
  "trial-unavailable",
18
22
  "trial-model-unavailable",
@@ -23,11 +23,10 @@ export const CONTAINER_REQUIREMENTS: readonly ContainerRequirement[] = [
23
23
  key: "reachability",
24
24
  requires: ["SANDBOX_GRANT", "INGRESS_URL"],
25
25
  given: ["SANDBOX_PUBLIC_URL"],
26
- enables: "reaching this sandbox at its public address, from anywhere",
27
- lost:
28
- "Its public address answers 502 to everyone, including this browser when it is not on the same machine as the sandbox. " +
29
- "On that machine the workspace still works, over a direct connection that never leaves it — which is why this can go unnoticed for a long time.",
30
- repair: "Re-run this sandbox's setup command. It carries a freshly signed grant, and it keeps the workspace, its history and its Docker engine.",
26
+ // Kept to a sentence each: a client may show them as sent (the editor words this key itself, translated).
27
+ enables: "reaching it at its public address",
28
+ lost: "Its public address answers 502 everywhere except on the computer it runs on.",
29
+ repair: "Re-run its setup command. Files, history and Docker are kept.",
31
30
  },
32
31
  ];
33
32
 
@@ -1,9 +1,35 @@
1
1
  import { z } from "zod";
2
- import { ActivityStatusSchema } from "../schemas/activity.js";
2
+ import { ActivityStatusSchema } from "../../schemas/activity.js";
3
+ import { rawRouteUrl } from "../raw/raw-routes.js";
3
4
 
4
5
  // Wire between the daemon and an extension's realtime-listener gateway (ext-discord, ext-slack, ext-telegram,
5
- // ext-whatsapp, ext-imap): the four /listeners/:provider routes (state, dispatch, failure, status). Shared here so both
6
- // ends compile against one declaration.
6
+ // ext-whatsapp, ext-imap, ext-google-workspace): the four /listeners/:provider routes (state, dispatch, failure,
7
+ // status). Shared here so both ends compile against one declaration.
8
+
9
+ // The path of one of the four listener routes for a provider, built from RAW_ROUTES so the gateway and the daemon
10
+ // cannot spell it two ways.
11
+ export const listenerRouteUrl = (route: "state" | "dispatch" | "failure" | "status", provider: string): string =>
12
+ route === "state" ? rawRouteUrl("GET /listeners/{provider}/state", { provider }) : rawRouteUrl(`POST /listeners/{provider}/${route}`, { provider });
13
+
14
+ // The reconcile feed GET /listeners/<provider>/state answers: the enabled automations listening to this provider and
15
+ // the connectors the asking extension contributes, each with its whole config, secrets included, since the gateway
16
+ // connects with them. The gateway reads only an automation's id and whether it is on; a connector's config is the
17
+ // connector's own shape, which the connector reads itself.
18
+ export const ListenerStateSchema = z.object({
19
+ automations: z.array(z.object({ id: z.string(), enabled: z.boolean() })),
20
+ connectors: z.array(z.object({ id: z.string(), config: z.record(z.string(), z.unknown()) })),
21
+ });
22
+ export type ListenerState = z.infer<typeof ListenerStateSchema>;
23
+
24
+ // One prior message a gateway hands over with a mention, oldest first; `self` marks one of our own bots' posts, so the
25
+ // model recognizes its earlier replies.
26
+ export const ListenerHistoryEntrySchema = z.object({
27
+ author: z.object({ id: z.string(), name: z.string() }),
28
+ content: z.string(),
29
+ timestamp: z.string(),
30
+ self: z.boolean().optional(),
31
+ });
32
+ export type ListenerHistoryEntry = z.infer<typeof ListenerHistoryEntrySchema>;
7
33
 
8
34
  // One normalized inbound event: the JSON body a realtime source POSTs to /listeners/<provider>/dispatch. A zod schema
9
35
  // since it's parsed from untrusted gateway input; `provider` and `type` are open strings, not a core enum.
@@ -16,24 +42,20 @@ export const ListenerMessageSchema = z.object({
16
42
  // service's own group ids on this sender (Discord role ids), absent on a source without them.
17
43
  author: z.object({ id: z.string(), name: z.string(), groups: z.array(z.string()).optional() }),
18
44
  content: z.string(),
19
- // Discord only: the message @mentions or replies to one of our bots; voice events never set it.
45
+ // The message is addressed to us, by each provider's own rule: an @mention of or reply to one of our bots, a direct
46
+ // message, a Slack thread we already answered in, or mail whose To line holds the connected address. Voice events
47
+ // never set it.
20
48
  mentioned: z.boolean().optional(),
21
49
  // CI pipeline event: the ref it ran on. Top-level, not in `extra`, since the dispatcher matches triggers on it.
22
50
  branch: z.string().optional(),
23
51
  // Prior channel messages fetched when tagged; top-level so it reaches the model but skips the activity feed.
24
- history: z
25
- .array(
26
- z.object({
27
- author: z.object({ id: z.string(), name: z.string() }),
28
- content: z.string(),
29
- timestamp: z.string(),
30
- self: z.boolean().optional(),
31
- }),
32
- )
33
- .optional(),
52
+ history: z.array(ListenerHistoryEntrySchema).optional(),
34
53
  timestamp: z.string(),
35
- // Provider-specific fields:
54
+ // Provider-specific fields, for example:
36
55
  // - discord message: guildId, attachments
56
+ // - slack message: threadTs, teamId, attachments
57
+ // - telegram message: chatType, messageId, chatTitle, messageThreadId, attachments
58
+ // - whatsapp message: chatType, chatName, replyTo, attachments
37
59
  // - voice_utterance: path
38
60
  // - voice_transcript: path, participants, durationSeconds
39
61
  extra: z.record(z.string(), z.unknown()).optional(),
@@ -0,0 +1,50 @@
1
+ // Zod-free half of the phone door's wire: URL builders and the pairing code. Split from phone-protocol.ts so the
2
+ // editor's pairing dialog does not pull zod in for two string functions. No imports allowed here, ever.
3
+
4
+ const base = (sandboxUrl: string): string => sandboxUrl.replace(/\/$/, "");
5
+
6
+ // URL the phone dials, from the sandbox's public URL; carries no credential, the token rides the hello frame.
7
+ export const phoneConnectUrl = (sandboxUrl: string): string => `${base(sandboxUrl).replace(/^http/, "ws")}/system/phones/connect`;
8
+
9
+ // Where the phone redeems its one-time pairing for its durable token (header `x-intentic-pair`).
10
+ export const phoneEnrollUrl = (sandboxUrl: string): string => `${base(sandboxUrl)}/system/phones/enroll`;
11
+
12
+ // One code rather than two fields, like the browser extension's: base64url of {url, token}, the prefix versioning the
13
+ // format. `token` is single-use and expires in ten minutes.
14
+ const PAIRING_PREFIX = "ixp1_";
15
+
16
+ // Where a pairing opens: an App Link the app claims (intentic.dev serves its assetlinks.json), so scanning the code
17
+ // with the phone's camera opens the app straight on the pairing screen, and a phone without the app lands on the page
18
+ // that offers it. The code rides the fragment, which no server ever receives, so no access log holds a live pairing.
19
+ export const PHONE_PAIR_LINK = "https://intentic.dev/phone/pair";
20
+
21
+ const base64url = (value: string): string => btoa(value).replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "");
22
+
23
+ export const phonePairingCode = (pairing: { readonly url: string; readonly token: string }): string =>
24
+ `${PAIRING_PREFIX}${base64url(JSON.stringify({ url: pairing.url, token: pairing.token }))}`;
25
+
26
+ export const phonePairingLink = (pairing: { readonly url: string; readonly token: string }): string =>
27
+ `${PHONE_PAIR_LINK}#${phonePairingCode(pairing)}`;
28
+
29
+ // The phone's side, and the editor's for a pasted code; undefined for anything not one of ours. Accepts the bare code
30
+ // or the whole link, since a person may paste either.
31
+ export const parsePhonePairingCode = (input: string): { readonly url: string; readonly token: string } | undefined => {
32
+ const trimmed = input.trim();
33
+ // The site serves the page with a trailing slash, so a link copied out of the browser may carry one.
34
+ const linked = [`${PHONE_PAIR_LINK}#`, `${PHONE_PAIR_LINK}/#`].find((prefix) => trimmed.startsWith(prefix));
35
+ const code = linked === undefined ? trimmed : trimmed.slice(linked.length);
36
+ if (!code.startsWith(PAIRING_PREFIX)) {
37
+ return undefined;
38
+ }
39
+ try {
40
+ const padded = code.slice(PAIRING_PREFIX.length).replaceAll("-", "+").replaceAll("_", "/");
41
+ const decoded = JSON.parse(atob(padded)) as { url?: unknown; token?: unknown };
42
+ if (typeof decoded.url !== "string" || typeof decoded.token !== "string" || decoded.token === "" || !/^https?:\/\//.test(decoded.url)) {
43
+ return undefined;
44
+ }
45
+ return { url: decoded.url, token: decoded.token };
46
+ } catch {
47
+ // allow(silent-catch): atob and JSON.parse only throw on a code that is not base64 or not JSON, which is no pairing code, the same as the checks above.
48
+ return undefined;
49
+ }
50
+ };
@@ -0,0 +1,136 @@
1
+ import { readFileSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { packageRoot } from "@intentic/constants/node";
4
+ import { OkSchema } from "../../schemas/shared.js";
5
+ import { PhoneFactsSchema, PhoneScopesSchema } from "../../schemas/phone.js";
6
+ import { PHONE_ERROR, PhoneHelloSchema, PhoneRequestSchema, PhoneResponseSchema } from "./phone-protocol.js";
7
+ import { parsePhonePairingCode, phoneConnectUrl, phoneEnrollUrl, phonePairingCode, phonePairingLink } from "./phone-links.js";
8
+
9
+ // The phone door's wire as examples, spelled once here: golden/phone-wire.json is this file's `wire` as JSON, and both
10
+ // far ends test against it — the daemon's JSON-RPC link (_sandbox/sandbox/src/phones/json-rpc-link.test.ts) sends
11
+ // exactly each `request` for its `call` and resolves each `response` to `resolves`, and the Android app's tests
12
+ // (_devices/android) parse every request and answer in the same shapes. A change here the committed file does not carry
13
+ // fails, naming the file; `INTENTIC_WRITE_GOLDEN=1` rewrites it.
14
+
15
+ const GOLDEN = join(packageRoot(import.meta.url), "golden", "phone-wire.json");
16
+
17
+ const facts = PhoneFactsSchema.parse({
18
+ device: "Google Pixel 8",
19
+ android: "16",
20
+ sdk: 36,
21
+ build: "direct",
22
+ paused: false,
23
+ access: { accessibility: true, notifications: false, screenCapture: "accessibility" },
24
+ folders: [{ name: "Download", writable: true }],
25
+ apps: [{ package: "com.android.chrome", label: "Chrome", mode: "act" }],
26
+ battery: { level: 81, charging: false },
27
+ wake: { fcm: "fcm-token-example" },
28
+ features: ["touch", "notifications"],
29
+ });
30
+
31
+ const scopes = { ...PhoneScopesSchema.parse({}), platform: "android" };
32
+
33
+ const toolsList = {
34
+ tools: [
35
+ {
36
+ name: "screenshot",
37
+ description: "What the phone's screen shows now, as an image with a frame id.",
38
+ inputSchema: { type: "object", properties: {}, additionalProperties: false },
39
+ annotations: { readOnlyHint: true },
40
+ },
41
+ ],
42
+ };
43
+
44
+ const callResult = { content: [{ type: "text", text: 'Tapped [e4] "Send".' }] };
45
+
46
+ const wire = {
47
+ hello: PhoneHelloSchema.parse({ type: "hello", token: "iph_example-enrollment-token", version: "1.0.0" }),
48
+ exchanges: [
49
+ {
50
+ name: "describe",
51
+ call: { path: ["describe"] },
52
+ request: { jsonrpc: "2.0", id: 0, method: "describe" },
53
+ response: { jsonrpc: "2.0", id: 0, result: facts },
54
+ resolves: facts,
55
+ },
56
+ {
57
+ name: "setScopes",
58
+ call: { path: ["setScopes"], input: scopes },
59
+ request: { jsonrpc: "2.0", id: 1, method: "setScopes", params: scopes },
60
+ response: { jsonrpc: "2.0", id: 1, result: OkSchema.parse({ ok: true }) },
61
+ resolves: { ok: true },
62
+ },
63
+ {
64
+ name: "ping",
65
+ call: { path: ["ping"] },
66
+ request: { jsonrpc: "2.0", id: 2, method: "ping" },
67
+ response: { jsonrpc: "2.0", id: 2, result: { ok: true } },
68
+ resolves: { ok: true },
69
+ },
70
+ {
71
+ name: "mcp tools/list",
72
+ call: { path: ["mcp"], input: { jsonrpc: "2.0", id: "phones-tools", method: "tools/list", params: {} } },
73
+ request: { jsonrpc: "2.0", id: 3, method: "mcp", params: { jsonrpc: "2.0", id: "phones-tools", method: "tools/list", params: {} } },
74
+ response: { jsonrpc: "2.0", id: 3, result: { jsonrpc: "2.0", id: "phones-tools", result: toolsList } },
75
+ resolves: { jsonrpc: "2.0", id: "phones-tools", result: toolsList },
76
+ },
77
+ {
78
+ name: "mcp tools/call",
79
+ call: {
80
+ path: ["mcp"],
81
+ input: { jsonrpc: "2.0", id: 9, method: "tools/call", params: { name: "ui_act", arguments: { ref: "e4", action: "tap" } } },
82
+ },
83
+ request: {
84
+ jsonrpc: "2.0",
85
+ id: 4,
86
+ method: "mcp",
87
+ params: { jsonrpc: "2.0", id: 9, method: "tools/call", params: { name: "ui_act", arguments: { ref: "e4", action: "tap" } } },
88
+ },
89
+ response: { jsonrpc: "2.0", id: 4, result: { jsonrpc: "2.0", id: 9, result: callResult } },
90
+ resolves: { jsonrpc: "2.0", id: 9, result: callResult },
91
+ },
92
+ {
93
+ name: "refused",
94
+ call: { path: ["describe"] },
95
+ request: { jsonrpc: "2.0", id: 5, method: "describe" },
96
+ response: { jsonrpc: "2.0", id: 5, error: { code: PHONE_ERROR.refused, message: "The person paused the agent on this phone." } },
97
+ rejects: "The person paused the agent on this phone.",
98
+ },
99
+ ],
100
+ };
101
+
102
+ test("every example frame is one the protocol's schemas accept", () => {
103
+ for (const exchange of wire.exchanges) {
104
+ expect(PhoneRequestSchema.safeParse(exchange.request).success).toBe(true);
105
+ expect(PhoneResponseSchema.safeParse(exchange.response).success).toBe(true);
106
+ expect(exchange.request.id).toBe(exchange.response.id);
107
+ }
108
+ });
109
+
110
+ test("golden/phone-wire.json is the protocol's example, as the app reads it", () => {
111
+ const expected = `${JSON.stringify(wire, undefined, 2)}\n`;
112
+ if (process.env["INTENTIC_WRITE_GOLDEN"] === "1") {
113
+ writeFileSync(GOLDEN, expected);
114
+ }
115
+ expect(readFileSync(GOLDEN, "utf8")).toBe(expected);
116
+ });
117
+
118
+ test("a pairing round-trips as a code and as the link the QR carries", () => {
119
+ const pairing = { url: "https://sandbox-abc.sbx.intentic.dev", token: "one-time" };
120
+ expect(parsePhonePairingCode(phonePairingCode(pairing))).toEqual(pairing);
121
+ expect(parsePhonePairingCode(phonePairingLink(pairing))).toEqual(pairing);
122
+ expect(phonePairingLink(pairing).startsWith("https://intentic.dev/phone/pair#ixp1_")).toBe(true);
123
+ expect(parsePhonePairingCode(phonePairingLink(pairing).replace("/pair#", "/pair/#"))).toEqual(pairing);
124
+ });
125
+
126
+ test("a code that is not ours, or carries no usable url or token, is refused rather than attempted", () => {
127
+ expect(parsePhonePairingCode("ixb1_abc")).toBeUndefined();
128
+ expect(parsePhonePairingCode("ixp1_not-base64!")).toBeUndefined();
129
+ expect(parsePhonePairingCode(phonePairingCode({ url: "ftp://x", token: "t" }))).toBeUndefined();
130
+ expect(parsePhonePairingCode(phonePairingCode({ url: "https://x", token: "" }))).toBeUndefined();
131
+ });
132
+
133
+ test("the phone dials and enrolls at the sandbox's own address", () => {
134
+ expect(phoneConnectUrl("https://sandbox-abc.sbx.intentic.dev/")).toBe("wss://sandbox-abc.sbx.intentic.dev/system/phones/connect");
135
+ expect(phoneEnrollUrl("https://sandbox-abc.sbx.intentic.dev")).toBe("https://sandbox-abc.sbx.intentic.dev/system/phones/enroll");
136
+ });
@@ -0,0 +1,71 @@
1
+ import { z } from "zod";
2
+
3
+ // The phone door's wire, /system/phones/connect. The first frame is the same hello every peer sends. After it, unlike
4
+ // the machine and browser doors, the socket carries plain JSON-RPC 2.0 rather than oRPC's own framing: the far end is
5
+ // a Kotlin app, and JSON-RPC is a format it can implement from its one-page spec, where oRPC's is an internal of a
6
+ // TypeScript library. The daemon still drives it through the same typed client every door has (phones/json-rpc-link.ts
7
+ // on the daemon side), so only the bytes differ. fixtures/phone-wire.json holds example exchanges both sides test
8
+ // against.
9
+ //
10
+ // The daemon sends requests, the phone only answers:
11
+ // → {"jsonrpc":"2.0","id":7,"method":"describe"}
12
+ // ← {"jsonrpc":"2.0","id":7,"result":{...PhoneFacts}}
13
+ // `method` is a procedure of phoneContract; `params` is its input, absent when it takes none. A failure is an `error`
14
+ // with a code and a message the agent may read.
15
+
16
+ /* HOW OFTEN THIS DOOR PINGS A CONNECTED PHONE, read by both sides of the socket. Longer than a computer's: every ping
17
+ wakes the phone's radio, and the phone holds the socket only while it is working or set to stay connected. Carrier NATs
18
+ drop an idle connection after a few minutes, so the ping still has to come well inside that. The app declares the link
19
+ dead after three missed pings, as every peer does. */
20
+ export const PHONE_HEARTBEAT_MS = 60_000;
21
+
22
+ /* How long a call to a sleeping phone waits for it to wake and dial in, after the sandbox pushed it awake. Long enough
23
+ for a push to arrive and a phone on mobile data to connect, short enough that a phone that will not come answers the
24
+ agent with "asleep" while the turn can still do something else. */
25
+ export const PHONE_WAKE_WAIT_MS = 20_000;
26
+
27
+ /* How long an awake phone keeps its socket after its last call, unless the person set it to stay connected. Read by
28
+ the app; the sandbox only learns of it as a socket that closed normally. */
29
+ export const PHONE_LINGER_MS = 5 * 60_000;
30
+
31
+ export const PhoneHelloSchema = z.object({
32
+ type: z.literal("hello"),
33
+ // Enrollment token, in the first frame and never the URL.
34
+ token: z.string(),
35
+ // The app's build, so an outdated one is visible rather than mysteriously missing a tool.
36
+ version: z.string(),
37
+ });
38
+ export type PhoneHello = z.infer<typeof PhoneHelloSchema>;
39
+
40
+ // The procedures the daemon calls; each is a key of phoneContract.
41
+ export const PHONE_METHODS = ["describe", "setScopes", "ping", "mcp"] as const;
42
+ export type PhoneMethod = (typeof PHONE_METHODS)[number];
43
+
44
+ export const PhoneRequestSchema = z.object({
45
+ jsonrpc: z.literal("2.0"),
46
+ id: z.number().int().nonnegative(),
47
+ method: z.enum(PHONE_METHODS),
48
+ params: z.unknown().optional(),
49
+ });
50
+ export type PhoneRequest = z.infer<typeof PhoneRequestSchema>;
51
+
52
+ // JSON-RPC's own codes, plus the two the phone answers with for a refusal the agent should read as a refusal.
53
+ export const PHONE_ERROR = {
54
+ parse: -32700,
55
+ invalidRequest: -32600,
56
+ methodNotFound: -32601,
57
+ invalidParams: -32602,
58
+ internal: -32603,
59
+ // The person paused the app, or a switch is off.
60
+ refused: -32001,
61
+ } as const;
62
+
63
+ export const PhoneResponseSchema = z.union([
64
+ z.object({ jsonrpc: z.literal("2.0"), id: z.number().int().nonnegative(), result: z.unknown() }),
65
+ z.object({
66
+ jsonrpc: z.literal("2.0"),
67
+ id: z.number().int().nonnegative().nullable(),
68
+ error: z.object({ code: z.number().int(), message: z.string(), data: z.unknown().optional() }),
69
+ }),
70
+ ]);
71
+ export type PhoneResponse = z.infer<typeof PhoneResponseSchema>;
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { NeedsActionSchema } from "../policy/needs-action.js";
2
+ import { NeedsActionSchema } from "../../policy/needs-action.js";
3
3
 
4
4
  // The runner link's edges: the /system/runners/connect handshake, boot env, and turn placement (procedures live in
5
5
  // contracts/runner.contract.ts). A runner is a sandbox image in runner mode, no browser owner or tunnel, that dials its
@@ -5,6 +5,10 @@
5
5
  // URL the extension dials, from the sandbox's public URL; carries no credential, the token rides the hello frame.
6
6
  export const webextConnectUrl = (sandboxUrl: string): string => `${sandboxUrl.replace(/^http/, "ws").replace(/\/$/, "")}/system/webext/connect`;
7
7
 
8
+ // Where the extension redeems a pairing code's one-time token (sent as `x-intentic-pair`) for its durable token; the
9
+ // answer is a PeerEnrollmentAnswer.
10
+ export const webextEnrollUrl = (sandboxUrl: string): string => `${sandboxUrl.replace(/\/$/, "")}/system/webext/enroll`;
11
+
8
12
  // Where the extension POSTs a site's session when the owner connects it, bearer-authenticated. A separate door from the
9
13
  // socket, since the socket's answers land in the agent's context and cookies must never reach a model.
10
14
  export const webextSessionUrl = (sandboxUrl: string): string => `${sandboxUrl.replace(/\/$/, "")}/system/webext/session`;
@@ -3,7 +3,7 @@
3
3
  // JavaScript unless the responder allows it — so the verdict rides an exposed header and the edge CORS-allows its own
4
4
  // errors. Ingress writes it, the editor's connection machine reads it; both sides import this file so they cannot drift.
5
5
 
6
- import type { EdgeVerdict } from "../front/generated/browser-wire.js";
6
+ import type { EdgeVerdict } from "../netd/generated/browser-wire.js";
7
7
 
8
8
  export const EDGE_VERDICT_HEADER = "x-intentic-edge";
9
9
 
@@ -0,0 +1,14 @@
1
+ // The header names the daemon, the platform, `ic` and extensions agree on, each spelled once.
2
+
3
+ // Correlates a browser call to the daemon request that served it; a token only, never a security boundary.
4
+ export const REQUEST_ID_HEADER = "x-intentic-request-id";
5
+
6
+ // The header a sandbox's connect token travels in: the platform's routes a sandbox calls as itself
7
+ // (api-contract's PLATFORM_INGRESS), the daemon's own gate, which takes the token from `ic` and the owner's browser,
8
+ // and its `/enroll`. `ic` spells it in Rust; api-contract's ingress test holds that spelling to this value.
9
+ export const CONNECT_TOKEN_HEADER = "x-intentic-connect";
10
+
11
+ // The header an extension's backend and its processes present their per-extension token in, checked against the
12
+ // manifest's `permissions.daemon` (the daemon's auth/grants.ts). Declared here so the daemon's grant, the backend host
13
+ // that proxies to it and the connector runtime's daemon client spell it once.
14
+ export const EXTENSION_TOKEN_HEADER = "x-intentic-extension";
@@ -53,18 +53,14 @@ export const verifyReachabilityGrant = (publicKeyPem: string, token: string): Re
53
53
 
54
54
  // Host to owner routing
55
55
 
56
- // Resolves which sandbox owns a Host: the leftmost DNS label is `sandbox-<id>` or ends in `-<id>` (12-hex); anything
57
- // else, including the loopback `<id>.local.<zone>` label, returns undefined.
58
- export const hostOwnerId = (host: string): string | undefined => {
59
- const label = host.split(":")[0]?.split(".")[0] ?? "";
60
- const match = /-([0-9a-f]{12})$/.exec(label);
61
- return match === null ? undefined : match[1];
62
- };
56
+ // Which sandbox owns a Host, declared with the names it parses (ids/hostnames.ts) and re-exported for this subpath's
57
+ // callers: the leftmost DNS label is `sandbox-<id>` or ends in `-<id>` (12-hex).
58
+ export { hostOwnerId } from "../ids/hostnames.js";
63
59
 
64
60
  // Wire constants
65
61
 
66
62
  // Tunnel door on the ingress (the tunnel crate's TUNNEL_PATH); versioned, so a new session shape adds a path. `/tunnel/v1`
67
- // is the edge's alone to answer now, for fronts that predate this one.
63
+ // is the edge's alone to answer now, for netd versions that predate this one.
68
64
  export const INGRESS_TUNNEL_PATH = "/tunnel/v2";
69
65
 
70
66
  // Grant travels as a header on the tunnel upgrade; this connection is never a browser's.
@@ -79,9 +75,9 @@ export const ENV_SANDBOX_GRANT = "SANDBOX_GRANT";
79
75
  // and cache the answer, failing open if the platform doesn't respond. A 404 refuses the tunnel.
80
76
  // - Displacement: a new tunnel for an id closes the old session (code 4001) and takes the registration.
81
77
  // - Streams: every exchange is a stream of its own carrying HTTP/1.1 (yamux over a WebSocket, or QUIC). Over TCP a
82
- // transfer rides the bulk socket: a preview's request, or a route the front announced (tunnel-bulk.ts); over QUIC a
78
+ // transfer rides the bulk socket: a preview's request, or a route netd announced (tunnel-bulk.ts); over QUIC a
83
79
  // stream that sends a megabyte without pausing yields to the others.
84
- // - Liveness: the front pings every 15s; a peer silent for 45s is unregistered.
80
+ // - Liveness: netd pings every 15s; a peer silent for 45s is unregistered.
85
81
  // - Routing: host maps via hostOwnerId to a registered tunnel; no tunnel answers 502 naming the sandbox label, with
86
82
  // the verdict header and CORS of edge-verdict.ts, and admits the preflight of the request it is about to refuse.
87
83
  // - The tunnel door and any host without a sandbox id are served directly by the ingress, never routed.