@intentic/sandbox-contract 1.326.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
@@ -193,6 +193,22 @@ const STATE_FILES = [
193
193
  why: "Scheduler bookkeeping nothing in the browser renders: what a catch-up fire produces reaches the run ledger, which carries the automations key.",
194
194
  portability: "carry",
195
195
  },
196
+ // What each watch's check saw last (automations/automations-store.ts), so `fireOn: change` can say what moved and
197
+ // the list can show the last value. `carry`: a restored sandbox must not read every release it already saw as new.
198
+ {
199
+ path: ".intentic/records/automation-watch.json",
200
+ invalidates: [],
201
+ why: "Declared by the intentic.automations extension's contributes.files, `automations` is its query key, not core's.",
202
+ portability: "carry",
203
+ },
204
+ // One file per automation that a guard command may keep between runs ($AUTOMATION_STATE); the daemon only makes the
205
+ // directory and deletes an automation's file with it. `carry`: it is the guard's memory of what it already saw.
206
+ {
207
+ path: ".intentic/records/automation-state/",
208
+ invalidates: [],
209
+ why: "A guard's own scratch file; the daemon never reads it and nothing in the browser renders it.",
210
+ portability: "carry",
211
+ },
196
212
  {
197
213
  path: ".intentic/records/approvals/",
198
214
  invalidates: [],
@@ -312,6 +328,16 @@ const STATE_FILES = [
312
328
  // Owner's per-extension update posture (notify/agent/auto, advisory opt-out). `carry`: a decision about the
313
329
  // extension, not the machine.
314
330
  { path: ".intentic/config/extension-update-policy.json", invalidates: ["extensions"], portability: "carry", versioned: true },
331
+ // Which installed extensions run from a source checkout instead of their pinned clone (extensions/extension-dev.ts).
332
+ // Local and never versioned: it can name a conversation's worktree, a path that means nothing in a commit or on
333
+ // another machine. `extensions` because the row says where it runs from, and a rebuild reported here is what offers
334
+ // the reload.
335
+ {
336
+ path: ".intentic/local/extension-dev.json",
337
+ invalidates: ["extensions"],
338
+ portability: "derived",
339
+ note: "Extensions run their pinned versions on the target; point one at its source checkout again there if you were working on it.",
340
+ },
315
341
  // `carry`: evidence is about the extension, not the machine; dropping it would make every permission look unused
316
342
  // rather than simply unmeasured.
317
343
  {
@@ -320,14 +346,13 @@ const STATE_FILES = [
320
346
  why: "Which of the routes each extension DECLARED it has actually called, the evidence behind the permissions list on its row. The one entry here whose empty set is a RATE decision rather than an architectural one: every browser with the app open reports its batch on a timer, so wiring this to the `extensions` query would refetch the whole list every few seconds for a figure nobody is watching change. The tab reads it when it loads, which is when anyone is reading it.",
321
347
  portability: "carry",
322
348
  },
323
- // Holds no credential but stays `identity`, not `carry`: it mirrors the platform's own invite records (the
324
- // enforcer's copy, so a grant it never received is never honoured), and review already happens on the Access tab
325
- // against the authoritative record. An access list that traveled would let a source sandbox hand itself the
326
- // target's ownership.
349
+ // The roster's address before 2026-10-06 (now the history volume's `identity/members.json`). Holds no credential but
350
+ // stays `identity`, not `carry`: an access list that traveled would let a source sandbox hand itself the target's
351
+ // ownership, and a pre-move copy may still sit here.
327
352
  {
328
353
  path: ".intentic/identity/members.json",
329
354
  invalidates: [],
330
- why: "Not this view's source at all: SandboxAccess renders the PLATFORM's invite records (apiClient.invite.list), and this file is the daemon's ENFORCED copy, written first so a grant the enforcer never got is never recorded, then never read back. A change here means the two disagreed, which the write order makes fail-closed rather than stale.",
355
+ why: "Where releases before 2026-10-06 kept the daemon's enforced roster; it now lives on the history volume (`identity/members.json`), off the workspace every turn writes, and nothing reads this copy. Kept declared, locked and never exported, since it may still hold a pre-move roster a rollback reads.",
331
356
  portability: "identity",
332
357
  note: "Re-invite collaborators from the Access tab, a grant is the platform's record, and the target enforces its own copy.",
333
358
  },
@@ -375,14 +400,15 @@ const STATE_FILES = [
375
400
  why: "Rebuildable indexes and caches, the iq index and its vector sidecar, the whisper model, fileq's derived/ markdown shadows of binary files; ignored by the watcher and recreated from carried workspace content.",
376
401
  portability: "derived",
377
402
  },
378
- // Extension runtime scratch, one directory per extension via `extensionRuntimeDir` below (the only way an
379
- // extension may name a home here). Resume watermarks and cached tokens; all of it expires or re-derives.
403
+ // Extension runtime scratch, one directory per extension via `extensionStateDir` below (the only way an extension
404
+ // may name a home here), plus the gateways' published control addresses. Resume watermarks and cached tokens; all
405
+ // of it expires or re-derives.
380
406
  {
381
407
  path: ".intentic/local/runtime/",
382
408
  invalidates: [],
383
409
  why: "Extension runtime scratch (watermarks, cached short-lived tokens); nothing renders it and gateways re-derive it.",
384
410
  portability: "derived",
385
- outsideWriter: "extensions, through extensionRuntimeDir below",
411
+ outsideWriter: "extensions, through extensionStateDir below",
386
412
  },
387
413
  {
388
414
  path: ".intentic/local/tmp/",
@@ -447,7 +473,7 @@ const STATE_FILES = [
447
473
  {
448
474
  path: ".intentic/identity/control-tokens.json",
449
475
  invalidates: [],
450
- why: "Hashed control tokens (the ACP editor bridge, and anything else driving this sandbox from outside), listed on demand by the owner.",
476
+ why: "Where releases before 2026-10-06 kept the hashed control tokens; they now live on the history volume (`identity/control-tokens.json`), and nothing reads this copy.",
451
477
  portability: "identity",
452
478
  backup: false,
453
479
  note: "Mint fresh control tokens, the old ones authenticate against the source sandbox.",
@@ -455,7 +481,7 @@ const STATE_FILES = [
455
481
  {
456
482
  path: ".intentic/identity/owner.json",
457
483
  invalidates: [],
458
- why: "Bound once on first use; a change here means the sandbox was re-owned, which re-authenticates anyway.",
484
+ why: "Where releases before 2026-10-06 kept the bound owner; it now lives on the history volume (`identity/owner.json`), and nothing reads this copy.",
459
485
  portability: "identity",
460
486
  },
461
487
  {
@@ -464,13 +490,13 @@ const STATE_FILES = [
464
490
  why: "The workspace identity, read from the /events hello frame rather than as a file.",
465
491
  portability: "identity",
466
492
  },
467
- // Public keys and the owner's require-a-passkey switch; the one credential-shaped thing in it, the recovery codes,
468
- // is stored hashed. `identity` because a passkey admits its holder to THIS sandbox: a copy that traveled would let
469
- // a source sandbox's passkeys open the target.
493
+ // The passkeys' address before the passkeys-off-workspace step (now the history volume's `identity/passkeys.json`):
494
+ // public keys, the owner's require-a-passkey switch and the hashes of their recovery codes. Stays `identity`, since
495
+ // a pre-move copy may still sit here and a passkey admits its holder to THIS sandbox.
470
496
  {
471
497
  path: ".intentic/identity/passkeys.json",
472
498
  invalidates: [],
473
- why: "The passkeys registered with this sandbox, whether one is required to open it, and the hashes of the owner's recovery codes; the Access tab reads them through /system/passkeys, never off disk.",
499
+ why: "Where earlier releases kept the passkeys registered with this sandbox, whether one is required to open it, and the hashes of the owner's recovery codes; they now live on the history volume (`identity/passkeys.json`), off the workspace every turn writes, and nothing reads this copy.",
474
500
  portability: "identity",
475
501
  note: "Passkeys are bound to the sandbox they were registered with: add them again on the new one from its Access tab.",
476
502
  },
@@ -606,10 +632,28 @@ export const UNBACKED_STATE_PATHS: readonly string[] = WORKSPACE_STATE_FILES.fil
606
632
  (file) => file.path,
607
633
  );
608
634
 
609
- // The only way an extension may name a scratch home, workspace-relative and forward-slash so the browser bundle
610
- // can hold it too. Extension ids are already validated slugs; the character replace is defense in depth.
611
- export const extensionRuntimeDir = (extension: string): string =>
612
- `${STATE_GROUP_DIR.local}/runtime/extensions/${extension.replaceAll(/[^a-zA-Z0-9._-]/g, "_")}`;
635
+ // A name made safe as one path segment. Extension identities are already validated slugs joined by a dot; the replace
636
+ // is defence in depth.
637
+ const segmentOf = (name: string): string => name.replaceAll(/[^a-zA-Z0-9._-]/g, "_");
638
+
639
+ // The only way an extension may name a home for its own state, workspace-relative and forward-slash so the browser
640
+ // bundle can hold it too. Keyed by the extension's identity (`publisher.name`, extensionIdOf), like its settings and its
641
+ // switch, so it survives an update, a re-install and dev mode. The daemon creates it and hands it to the extension's
642
+ // code as `api.stateDir`; an agent-side CLI of the same extension names it by its own identity.
643
+ export const extensionStateDir = (identity: string): string => `${STATE_GROUP_DIR.local}/runtime/extensions/${segmentOf(identity)}`;
644
+
645
+ // Its counterpart for what can be fetched or built again (`api.cacheDir`), under the rebuildable cache the watcher
646
+ // ignores and no backup carries.
647
+ export const extensionCacheDir = (identity: string): string => `${STATE_GROUP_DIR.local}/cache/extensions/${segmentOf(identity)}`;
648
+
649
+ // Where an extension kept its state before the directory was keyed by identity: its bare manifest name. Read only by
650
+ // the daemon, which moves a first-party extension's directory from here to extensionStateDir once.
651
+ export const legacyExtensionStateDir = (name: string): string => `${STATE_GROUP_DIR.local}/runtime/extensions/${segmentOf(name)}`;
652
+
653
+ // Where a gateway publishes its loopback control address for the agent's CLI to read (`publishGatewayUrl`), keyed by
654
+ // the listener provider the gateway serves. Beside the extensions' own directories rather than inside one, since the
655
+ // provider is the rendezvous both sides know, and the CLI never learns which extension owns it.
656
+ export const extensionGatewayUrlFile = (provider: string): string => `${STATE_GROUP_DIR.local}/runtime/gateways/${segmentOf(provider)}.url`;
613
657
 
614
658
  // Manifests the unreadable-manifest notice reports on: exactly the entries that declare `manifests` in
615
659
  // Report broken manifests only when a file change can refresh their notice.
@@ -619,8 +663,9 @@ export const REPORTED_MANIFEST_PATHS: readonly string[] = WORKSPACE_STATE_FILES.
619
663
 
620
664
  // Files on the daemon's own volume whose unreadable records are reported too, named by their absolute path there: the
621
665
  // conversation registry's rows, one of which this build could not read costs that conversation until a build that can
622
- // runs. Reported, never repaired from the card (no route edits them), and refreshed whenever the card is fetched.
623
- export const REPORTED_VOLUME_FILES: readonly string[] = [`${HISTORY_ROOT}/conversations.db`];
666
+ // runs. Reported, never repaired from the card (no route edits them), and refreshed whenever the card is fetched. The
667
+ // boot record (2026-10-05) is reported when a restart storm kept a boot from resuming the turns it cut.
668
+ export const REPORTED_VOLUME_FILES: readonly string[] = [`${HISTORY_ROOT}/conversations.db`, `${HISTORY_ROOT}/boot-history.json`];
624
669
 
625
670
  // Accepts either separator; the daemon holds these as platform paths and normalizing at every call site is what
626
671
  // eventually gets forgotten.
@@ -1,6 +1,6 @@
1
1
  import { webcrypto } from "node:crypto";
2
2
  import { stubGlobal, unstubAllGlobals } from "@intentic/testing/bun";
3
- import { EmbedError, embedFailure, embedUrl, fetchEmbedJson, solveProofOfWork } from "./embed.js";
3
+ import { DEFAULT_ACCENT, EmbedError, embedFailure, embedUrl, escapeHtml, fetchEmbedJson, onAccent, parseHex, solveProofOfWork } from "./embed.js";
4
4
 
5
5
  /* The wire every embed speaks before it speaks its own, against a fake fetch and the real WebCrypto. */
6
6
 
@@ -72,3 +72,23 @@ test("an http:// page is told the truth, in the embed's own words, instead of ha
72
72
  );
73
73
  Object.defineProperty(globalThis, "crypto", { value: webcrypto, configurable: true });
74
74
  });
75
+
76
+ test("an accent is read as three channels from either hex spelling, and anything else is unreadable", () => {
77
+ expect(parseHex(DEFAULT_ACCENT)).toEqual([228, 113, 0]);
78
+ expect(parseHex(" #FA0 ")).toEqual([255, 170, 0]);
79
+ expect(parseHex("rebeccapurple")).toBeUndefined();
80
+ expect(parseHex("#12345")).toBeUndefined();
81
+ });
82
+
83
+ // The default orange is where a brightness threshold gets it wrong: it read as dark and put white on it, at 3.15:1.
84
+ test("the label on an accent is whichever of the dark ink and white contrasts more, so the default orange gets dark text", () => {
85
+ expect(onAccent(DEFAULT_ACCENT, "#111827")).toBe("#111827");
86
+ expect(onAccent(DEFAULT_ACCENT, "#201c19")).toBe("#201c19");
87
+ expect(onAccent("#1a3d8f", "#111827")).toBe("#ffffff");
88
+ expect(onAccent("#fde047", "#111827")).toBe("#111827");
89
+ });
90
+
91
+ test("escaped text stays text both between tags and inside a quoted attribute", () => {
92
+ expect(escapeHtml(`<img src=x onerror="alert('hi')"> & more`)).toBe("&lt;img src=x onerror=&quot;alert(&#39;hi&#39;)&quot;&gt; &amp; more");
93
+ expect(escapeHtml("Report a problem")).toBe("Report a problem");
94
+ });
package/src/text/embed.ts CHANGED
@@ -1,6 +1,6 @@
1
- // The zod-free half of an embed's wire, shared by the two embeds (webchat-widget, issue-sdk) and the daemon's
2
- // public-door.ts. No imports, ever: this bundles into someone else's page, and the contract's barrel would drag in zod
3
- // (measured at 1.1 MB for two strings).
1
+ // The zod-free half of an embed's wire and look, shared by the two embeds (webchat-widget, issue-sdk) and the daemon's
2
+ // doors behind them. No imports, ever: this bundles into someone else's page, and the contract's barrel would drag in
3
+ // zod (measured at 1.1 MB for two strings).
4
4
 
5
5
  // Where an embed talks to: the daemon it came from, and the automation it is the public face of.
6
6
  export interface EmbedEndpoint {
@@ -130,3 +130,50 @@ export const embedEndpointOf = (script: HTMLScriptElement): EmbedEndpoint | unde
130
130
  }
131
131
  return { automationId, base: (script.dataset["base"] ?? new URL(script.src, window.location.href).origin).replace(/\/$/, "") };
132
132
  };
133
+
134
+ // The frames of a Visitor chat reply, streamed as server-sent events on the POST that sent the message: a chunk of the
135
+ // answer, the notice that the owner reviews it first, the one failure sentence a visitor sees, and the end of the turn.
136
+ export const WEBCHAT_EVENT = { delta: "delta", pending: "pending", error: "error", done: "done" } as const;
137
+
138
+ // Intentic's brand orange (`--color-brand-600`): the accent of an embed nobody configured, so it still looks like the
139
+ // product, and what an embed paints when it cannot read the configured one.
140
+ export const DEFAULT_ACCENT = "#e47100";
141
+
142
+ // The red, green and blue of a `#rgb` or `#rrggbb` colour, undefined for anything else. The embeds do their colour maths
143
+ // here rather than in CSS: an unsupported color-mix() is invalid at computed-value time and would paint nothing.
144
+ export const parseHex = (value: string): [number, number, number] | undefined => {
145
+ const digits = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(value.trim())?.[1];
146
+ if (digits === undefined) {
147
+ return undefined;
148
+ }
149
+ const full = digits.length === 3 ? [...digits].map((char) => char + char).join("") : digits;
150
+ const channel = (at: number): number => Number.parseInt(full.slice(at, at + 2), 16);
151
+ return [channel(0), channel(2), channel(4)];
152
+ };
153
+
154
+ // One sRGB channel on WCAG's linear scale.
155
+ const linear = (channel: number): number => {
156
+ const unit = channel / 255;
157
+ return unit <= 0.03928 ? unit / 12.92 : ((unit + 0.055) / 1.055) ** 2.4;
158
+ };
159
+
160
+ // WCAG relative luminance; an unreadable colour scores 0, which only ever picks a label and is never shown.
161
+ const luminance = (color: string): number => {
162
+ const [r, g, b] = parseHex(color) ?? [0, 0, 0];
163
+ return 0.2126 * linear(r) + 0.7152 * linear(g) + 0.0722 * linear(b);
164
+ };
165
+
166
+ const contrast = (a: number, b: number): number => (Math.max(a, b) + 0.05) / (Math.min(a, b) + 0.05);
167
+
168
+ // The label on a solid accent: the embed's own dark ink or white, whichever contrasts more. Measured, not assumed:
169
+ // white on the default orange is 3.15:1, under AA, where either embed's dark ink clears 5:1, and comparing the two works
170
+ // for any accent a customer picks.
171
+ export const onAccent = (accent: string, dark: string): string => {
172
+ const field = luminance(accent);
173
+ return contrast(field, luminance(dark)) >= contrast(field, luminance("#ffffff")) ? dark : "#ffffff";
174
+ };
175
+
176
+ // Text for innerHTML, safe both between tags and inside a quoted attribute: neither an owner's config nor what a
177
+ // visitor typed is trusted with markup.
178
+ export const escapeHtml = (value: string): string =>
179
+ value.replace(/[&<>"']/g, (char) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[char] ?? char);
@@ -0,0 +1,161 @@
1
+ import type { AgentEvent } from "../events/agent-events.js";
2
+ import type { Page } from "../events/requests.js";
3
+ import { settledRequests } from "../policy/request-status.js";
4
+ import {
5
+ intoHead,
6
+ mcpAppDataScript,
7
+ PAGE_FALLBACK_THEMES,
8
+ PAGE_THEME_VARIABLES,
9
+ pageThemeCss,
10
+ publishedPage,
11
+ readMcpAppData,
12
+ sealedPage,
13
+ SEALED_PAGE_POLICY,
14
+ sizedFirst,
15
+ standalonePage,
16
+ } from "./pages.js";
17
+ import { foldTurn, userRow } from "./transcript-fold.js";
18
+
19
+ // path-literals: content, a page's stored path as a transcript row carries it
20
+ const PAGE: Page = { id: "a1b2c3d4e5", title: "Q3 revenue", path: ".intentic/records/artifacts/pages/c1/a1b2c3d4e5.r0.html" };
21
+
22
+ describe("intoHead", () => {
23
+ it("puts markup first inside an existing head", () => {
24
+ expect(intoHead(`<!doctype html><html><head><title>x</title></head><body></body></html>`, `<i>`)).toBe(
25
+ `<!doctype html><html><head><i><title>x</title></head><body></body></html>`,
26
+ );
27
+ });
28
+
29
+ it("makes a head inside the html element when the page wrote none", () => {
30
+ expect(intoHead(`<html lang="en"><body>hi</body></html>`, `<i>`)).toBe(`<html lang="en"><head><i></head><body>hi</body></html>`);
31
+ });
32
+
33
+ it("makes one after a lone doctype, and for a bare fragment", () => {
34
+ expect(intoHead(`<!DOCTYPE html><p>hi</p>`, `<i>`)).toBe(`<!DOCTYPE html><head><i></head><p>hi</p>`);
35
+ expect(intoHead(`<p>hi</p>`, `<i>`)).toBe(`<!doctype html><head><i></head><p>hi</p>`);
36
+ });
37
+
38
+ it("never takes a head written inside a script or comment for the real one", () => {
39
+ const html = `<!-- <head> --><html><head><script>const s = "<head>";</script></head></html>`;
40
+ expect(intoHead(html, `<i>`)).toBe(`<!-- <head> --><html><head><i><script>const s = "<head>";</script></head></html>`);
41
+ });
42
+ });
43
+
44
+ describe("sealedPage", () => {
45
+ it("leads with the policy, then the theme and the bootstrap, before the page's own head", () => {
46
+ const sealed = sealedPage(`<html><head><style>body{color:red}</style></head><body></body></html>`, PAGE_FALLBACK_THEMES.dark);
47
+ const policy = sealed.indexOf(SEALED_PAGE_POLICY);
48
+ const theme = sealed.indexOf(`id="intentic-theme"`);
49
+ const own = sealed.indexOf(`body{color:red}`);
50
+ expect(policy).toBeGreaterThan(-1);
51
+ expect(policy).toBeLessThan(theme);
52
+ expect(theme).toBeLessThan(own);
53
+ expect(sealed).toContain(`window.intentic=`);
54
+ });
55
+
56
+ it("keeps the theme's values from ending the rule they sit in", () => {
57
+ const hostile = { ...PAGE_FALLBACK_THEMES.light, variables: { ...PAGE_FALLBACK_THEMES.light.variables, "--foreground": `red;}</style><script>x()` } };
58
+ expect(pageThemeCss(hostile)).not.toContain(`</style>`);
59
+ expect(pageThemeCss(hostile)).toContain(`--foreground:red/stylescriptx();`);
60
+ });
61
+
62
+ it("names every theme variable", () => {
63
+ const css = pageThemeCss(PAGE_FALLBACK_THEMES.dark);
64
+ for (const name of PAGE_THEME_VARIABLES) {
65
+ expect(css).toContain(`${name}:`);
66
+ }
67
+ });
68
+ });
69
+
70
+ describe("standalonePage", () => {
71
+ it("carries defaults at no specificity, so the chat's theme and the page's own rules win", () => {
72
+ const stored = standalonePage(`<html><head></head><body>x</body></html>`);
73
+ expect(stored).toContain(`:where(:root){`);
74
+ expect(stored).toContain(`@media (prefers-color-scheme: light)`);
75
+ expect(stored).not.toMatch(/(^|[^(]):root\{/);
76
+ expect(stored).toContain(`if(!window.intentic)`);
77
+ });
78
+ });
79
+
80
+ describe("pages in the fold", () => {
81
+ const fold = (events: readonly AgentEvent[]) => foldTurn([userRow("show me", 1, [])], events).slice(1);
82
+
83
+ it("draws a page on the bubble whose call showed it, and starts the next words below", () => {
84
+ const rows = fold([
85
+ { kind: "tool_call", id: "t1", name: "mcp__ui__show_page", category: "other", status: "in_progress" },
86
+ { kind: "page", page: PAGE },
87
+ { kind: "tool_call_update", id: "t1", status: "completed" },
88
+ { kind: "delta", text: "Revenue doubled." },
89
+ ]);
90
+ expect(rows).toHaveLength(2);
91
+ expect(rows[0]?.page).toEqual(PAGE);
92
+ expect(rows[0]?.tools?.[0]?.status).toBe("completed");
93
+ expect(rows[1]).toEqual({ role: "assistant", text: "Revenue doubled." });
94
+ });
95
+
96
+ it("folds an earlier drawing away when the page is redrawn", () => {
97
+ const redrawn: Page = { ...PAGE, path: PAGE.path.replace(".r0.", ".r1."), revision: 1 };
98
+ const rows = fold([
99
+ { kind: "page", page: PAGE },
100
+ { kind: "delta", text: "Here." },
101
+ { kind: "text_end" },
102
+ { kind: "page", page: redrawn },
103
+ ]);
104
+ expect(rows[0]?.page?.superseded).toBe(true);
105
+ expect(rows.at(-1)?.page).toEqual(redrawn);
106
+ });
107
+
108
+ it("parks a page asked on as a card, and settles it with what the page sent", () => {
109
+ const rows = fold([
110
+ { kind: "page_ask", requestId: "r1", page: PAGE },
111
+ { kind: "resolved", requestId: "r1", reply: { kind: "page_ask", requestId: "r1", value: `{"pick":"B"}` } },
112
+ ]);
113
+ expect(rows[0]?.pageAsk).toEqual({ requestId: "r1", page: PAGE, status: "answered", value: `{"pick":"B"}` });
114
+ });
115
+
116
+ it("draws nothing for a draft: it is live state, never transcript", () => {
117
+ expect(fold([{ kind: "page_draft", callId: "t1", at: 0, text: "<p>" }])).toEqual([]);
118
+ });
119
+
120
+ it("reads a dismissal, or a turn that died, as cancelled with no value", () => {
121
+ const card = { pageAsk: { requestId: "r1", page: PAGE, status: "pending" as const } };
122
+ expect(settledRequests(card, { kind: "page_ask", requestId: "r1", cancelled: true }).pageAsk).toEqual({ ...card.pageAsk, status: "cancelled" });
123
+ expect(settledRequests(card, undefined).pageAsk?.status).toBe("cancelled");
124
+ });
125
+ });
126
+
127
+ describe("an MCP app's call, kept inside its page", () => {
128
+ it("reads back exactly what was stored, markup in its values included", () => {
129
+ const data = { server: "maps", tool: "show_map", input: { q: "</script><b>" }, result: { content: [{ type: "text", text: "<i>3</i>" }] } };
130
+ const stored = standalonePage(intoHead(`<html><head></head><body></body></html>`, mcpAppDataScript(data)));
131
+ expect(stored).not.toContain("</script><b>");
132
+ expect(readMcpAppData(stored)).toEqual(data);
133
+ expect(readMcpAppData(`<html></html>`)).toBeUndefined();
134
+ });
135
+ });
136
+
137
+ describe("publishedPage", () => {
138
+ it("seals a stored page off the network and has it say its height to the page around it", () => {
139
+ const published = publishedPage(standalonePage(`<html><head></head><body>x</body></html>`));
140
+ expect(published.indexOf(SEALED_PAGE_POLICY)).toBeLessThan(published.indexOf(`intentic-page-defaults`));
141
+ expect(published).toContain(`ui/notifications/size-changed`);
142
+ });
143
+ });
144
+
145
+ describe("sizedFirst", () => {
146
+ const page = `<!DOCTYPE html><html><head><script>var a = "</script>";</script></head><body>x</body></html>`;
147
+ const shell = sizedFirst(page);
148
+
149
+ it("carries the page whole inside one script the page cannot close", () => {
150
+ expect(shell.startsWith(`<!DOCTYPE html><script>`)).toBe(true);
151
+ expect(shell.endsWith(`</script>`)).toBe(true);
152
+ // The only `</` left is the shell's own closing tag: the page's markup cannot end the script early.
153
+ expect(shell.split(`</`).length).toBe(2);
154
+ });
155
+
156
+ it("writes back exactly the page it was given", () => {
157
+ const literal = /var page=(".*?"),done=/.exec(shell)?.[1];
158
+ expect(literal).toBeDefined();
159
+ expect(JSON.parse(literal!)).toBe(page);
160
+ });
161
+ });