@wenathlan/devthink 2.0.15 → 2.0.19

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 (444) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/{dist/bridge.d.ts → bridge.d.ts} +1 -1
  3. package/bridge.d.ts.map +1 -0
  4. package/bridge.js +1877 -0
  5. package/bun.d.ts.map +1 -0
  6. package/bun.js +52329 -0
  7. package/caps/background.json +712 -0
  8. package/caps/cli.json +360 -0
  9. package/caps/library.json +3611 -0
  10. package/caps/mcp.json +126 -0
  11. package/caps/pagebridge.json +377 -0
  12. package/caps/popup.json +51 -0
  13. package/caps/sidepanel.json +522 -0
  14. package/checksums.txt +142 -0
  15. package/cli.d.ts.map +1 -0
  16. package/{dist/cli.js → cli.js} +2 -2
  17. package/companion.d.ts.map +1 -0
  18. package/companion.js +389 -0
  19. package/crossbrowser.d.ts.map +1 -0
  20. package/crossbrowser.js +1191 -0
  21. package/dashdone.d.ts.map +1 -0
  22. package/dashdone.js +368 -0
  23. package/deno.d.ts.map +1 -0
  24. package/deno.js +52325 -0
  25. package/devthink.umd.js +52346 -0
  26. package/fixtures/bun.ts +7 -0
  27. package/fixtures/cjs.js +6 -0
  28. package/fixtures/deno.ts +6 -0
  29. package/fixtures/example-org-pagestate.json +22 -0
  30. package/fixtures/importers/automa-workflow.json +18 -0
  31. package/fixtures/importers/selenium-side.json +20 -0
  32. package/fixtures/importers/tabular-plan.csv +7 -0
  33. package/fixtures/importers/uivision-macro.json +10 -0
  34. package/fixtures/importers/v1-plan.json +13 -0
  35. package/fixtures/mcp-client.mjs +14 -0
  36. package/fixtures/pages/checkout.html +192 -0
  37. package/fixtures/pages/dashboard.html +110 -0
  38. package/fixtures/pages/feed.html +113 -0
  39. package/fixtures/pages/product-grid.html +150 -0
  40. package/fixtures/plans/form-inventory-plan.json +11 -0
  41. package/fixtures/plans/release-notes-plan.json +11 -0
  42. package/fixtures/recipes/agentscompete.json +11 -0
  43. package/fixtures/recipes/agentsforms.json +11 -0
  44. package/fixtures/recipes/agentsmonitor.json +11 -0
  45. package/fixtures/recipes/agentsreview.json +29 -0
  46. package/fixtures/recipes/agentswarm.json +11 -0
  47. package/fixtures/recipes/fillcalendar.json +12 -0
  48. package/fixtures/recipes/fillcheckout.json +13 -0
  49. package/fixtures/recipes/filldependentdropdowns.json +12 -0
  50. package/fixtures/recipes/fillfromcsv.json +13 -0
  51. package/fixtures/recipes/fillloginform.json +12 -0
  52. package/fixtures/recipes/fillmultistepwizard.json +13 -0
  53. package/fixtures/recipes/fillregistration.json +12 -0
  54. package/fixtures/recipes/fillsearchfilters.json +12 -0
  55. package/fixtures/recipes/filltypeahead.json +11 -0
  56. package/fixtures/recipes/monitoralerts.json +12 -0
  57. package/fixtures/recipes/monitoravailability.json +11 -0
  58. package/fixtures/recipes/monitornetworkquiet.json +12 -0
  59. package/fixtures/recipes/monitorpagechanges.json +11 -0
  60. package/fixtures/recipes/monitorpricechange.json +11 -0
  61. package/fixtures/recipes/monitorschedule.json +12 -0
  62. package/fixtures/recipes/scrapedynamicprices.json +13 -0
  63. package/fixtures/recipes/scrapeimagegallery.json +12 -0
  64. package/fixtures/recipes/scrapeinfinitefeed.json +13 -0
  65. package/fixtures/recipes/scrapenestedlists.json +12 -0
  66. package/fixtures/recipes/scrapeproductgrid.json +12 -0
  67. package/fixtures/recipes/scrapereviews.json +12 -0
  68. package/fixtures/recipes/scrapesearchresults.json +12 -0
  69. package/fixtures/recipes/scrapetablepagination.json +12 -0
  70. package/fixtures/recipes/testaccessibility.json +34 -0
  71. package/fixtures/recipes/testconsoleerrors.json +12 -0
  72. package/fixtures/recipes/testdeeplinks.json +12 -0
  73. package/fixtures/recipes/testformvalidation.json +13 -0
  74. package/fixtures/recipes/testlayoutshift.json +12 -0
  75. package/fixtures/recipes/testlinkcheck.json +12 -0
  76. package/fixtures/recipes/testloadtiming.json +12 -0
  77. package/fixtures/recipes/testvisualdiff.json +12 -0
  78. package/fixtures/workflows/changelog-digest-workflow.json +13 -0
  79. package/fixtures/workflows/form-survey-workflow.json +13 -0
  80. package/gallery.json +706 -0
  81. package/hardening.d.ts.map +1 -0
  82. package/hardening.js +188 -0
  83. package/headless.d.ts.map +1 -0
  84. package/headless.js +11522 -0
  85. package/http.d.ts.map +1 -0
  86. package/http.js +2165 -0
  87. package/index.cjs +54682 -0
  88. package/index.d.ts.map +1 -0
  89. package/index.js +52310 -0
  90. package/index.neutral.js +46343 -0
  91. package/{web/manifest.json → manifest.json} +1 -1
  92. package/mcp.d.ts.map +1 -0
  93. package/mcp.js +20515 -0
  94. package/memory.d.ts.map +1 -0
  95. package/{memory.ts → memory.js} +2310 -3834
  96. package/nativehost.template.json +10 -0
  97. package/node.cjs +54686 -0
  98. package/node.d.ts.map +1 -0
  99. package/pack.d.ts.map +1 -0
  100. package/pack.js +805 -0
  101. package/package.json +83 -176
  102. package/policy.d.ts.map +1 -0
  103. package/{policy.ts → policy.js} +4679 -5073
  104. package/progress.d.ts.map +1 -0
  105. package/progress.js +645 -0
  106. package/protocol.d.ts.map +1 -0
  107. package/protocol.js +8334 -0
  108. package/schemas/audit.schema.json +226 -0
  109. package/schemas/capability.schema.json +113 -0
  110. package/schemas/envelope.schema.json +162 -0
  111. package/schemas/memory.schema.json +51 -0
  112. package/schemas/observation.schema.json +113 -0
  113. package/schemas/plan.schema.json +208 -0
  114. package/schemas/progress.schema.json +126 -0
  115. package/schemas/proposal.schema.json +68 -0
  116. package/schemas/session.schema.json +82 -0
  117. package/schemas/tool.schema.json +94 -0
  118. package/server.d.ts.map +1 -0
  119. package/server.js +28877 -0
  120. package/umd-example.html +18 -0
  121. package/umd.d.ts.map +1 -0
  122. package/accounts.ts +0 -2087
  123. package/agent.ts +0 -2331
  124. package/antigravity.ts +0 -2139
  125. package/apifreeze.ts +0 -4146
  126. package/auth.ts +0 -642
  127. package/background.ts +0 -16837
  128. package/bridge.ts +0 -2080
  129. package/build.ts +0 -54
  130. package/bun.ts +0 -26
  131. package/capture.ts +0 -1614
  132. package/checksecrets.ts +0 -72
  133. package/cjs.ts +0 -9
  134. package/cli.ts +0 -3500
  135. package/commands.ts +0 -1101
  136. package/companion.ts +0 -450
  137. package/compatibility.ts +0 -37
  138. package/config.ts +0 -3137
  139. package/constants.ts +0 -943
  140. package/core.ts +0 -1473
  141. package/crossbrowser.ts +0 -1359
  142. package/dashdone.ts +0 -605
  143. package/data.ts +0 -943
  144. package/database.ts +0 -133
  145. package/debug.ts +0 -850
  146. package/deno.ts +0 -27
  147. package/devthink.ts +0 -707
  148. package/dist/accounts.d.ts +0 -409
  149. package/dist/agent.d.ts +0 -837
  150. package/dist/antigravity.d.ts +0 -380
  151. package/dist/apifreeze.d.ts +0 -113
  152. package/dist/auth.d.ts +0 -224
  153. package/dist/capture.d.ts +0 -595
  154. package/dist/cjs.d.ts +0 -6
  155. package/dist/commands.d.ts +0 -310
  156. package/dist/compatibility.d.ts +0 -17
  157. package/dist/config.d.ts +0 -1853
  158. package/dist/constants.d.ts +0 -637
  159. package/dist/core.d.ts +0 -361
  160. package/dist/data.d.ts +0 -330
  161. package/dist/database.d.ts +0 -24
  162. package/dist/debug.d.ts +0 -270
  163. package/dist/engine.d.ts +0 -74
  164. package/dist/environments.d.ts +0 -244
  165. package/dist/evidence.d.ts +0 -277
  166. package/dist/export.d.ts +0 -311
  167. package/dist/fingerprint.d.ts +0 -594
  168. package/dist/flow.d.ts +0 -300
  169. package/dist/gates.d.ts +0 -103
  170. package/dist/identity.d.ts +0 -51
  171. package/dist/ids.d.ts +0 -7
  172. package/dist/llm.d.ts +0 -652
  173. package/dist/models.d.ts +0 -1807
  174. package/dist/net.d.ts +0 -325
  175. package/dist/neutral.d.ts +0 -41
  176. package/dist/oauth.d.ts +0 -703
  177. package/dist/page.d.ts +0 -1166
  178. package/dist/perf.d.ts +0 -481
  179. package/dist/plan.d.ts +0 -134
  180. package/dist/project.d.ts +0 -395
  181. package/dist/providers.d.ts +0 -37
  182. package/dist/quota.d.ts +0 -453
  183. package/dist/recovery.d.ts +0 -621
  184. package/dist/request.d.ts +0 -1492
  185. package/dist/run.d.ts +0 -779
  186. package/dist/runtime.d.ts +0 -212
  187. package/dist/search.d.ts +0 -375
  188. package/dist/security.d.ts +0 -534
  189. package/dist/serve.d.ts +0 -136
  190. package/dist/session.d.ts +0 -296
  191. package/dist/storage.d.ts +0 -53
  192. package/dist/streaming.d.ts +0 -1119
  193. package/dist/swarm.d.ts +0 -328
  194. package/dist/tools.d.ts +0 -170
  195. package/dist/types.d.ts +0 -8357
  196. package/dist/utils.d.ts +0 -82
  197. package/dist/version.d.ts +0 -7
  198. package/dist/versionregistry.d.ts +0 -406
  199. package/dist/views.d.ts +0 -579
  200. package/dist/workbenchsession.d.ts +0 -69
  201. package/dist/workflow.d.ts +0 -649
  202. package/docs/readme.md +0 -92
  203. package/docs/schemas/antigravity.json +0 -192
  204. package/engine.ts +0 -1524
  205. package/environments.ts +0 -1005
  206. package/evidence.ts +0 -643
  207. package/export.ts +0 -889
  208. package/fingerprint.ts +0 -1458
  209. package/flow.ts +0 -1190
  210. package/gates.ts +0 -307
  211. package/gateway.ts +0 -34
  212. package/hardening.ts +0 -191
  213. package/headless.ts +0 -369
  214. package/http.ts +0 -2110
  215. package/identity.ts +0 -246
  216. package/ids.ts +0 -26
  217. package/index.ts +0 -369
  218. package/llm.ts +0 -2682
  219. package/mcp.ts +0 -1835
  220. package/models.ts +0 -3805
  221. package/modes.ts +0 -43
  222. package/net.ts +0 -1214
  223. package/neutral.ts +0 -362
  224. package/node.ts +0 -26
  225. package/oauth.ts +0 -2216
  226. package/offscreen.ts +0 -170
  227. package/pack.ts +0 -956
  228. package/page.ts +0 -7824
  229. package/pagebridge.ts +0 -1116
  230. package/perf.ts +0 -957
  231. package/plan.ts +0 -672
  232. package/plugin.ts +0 -76
  233. package/prisma.config.ts +0 -27
  234. package/progress.ts +0 -1308
  235. package/project.ts +0 -1291
  236. package/protocol.ts +0 -4187
  237. package/providers.ts +0 -246
  238. package/quota.ts +0 -1887
  239. package/recovery.ts +0 -2433
  240. package/request.ts +0 -4482
  241. package/run.ts +0 -2135
  242. package/runtime.ts +0 -526
  243. package/search.ts +0 -1760
  244. package/security.ts +0 -1673
  245. package/serve.ts +0 -419
  246. package/server.ts +0 -5538
  247. package/session.ts +0 -1162
  248. package/storage.ts +0 -182
  249. package/streaming.ts +0 -4101
  250. package/swarm.ts +0 -884
  251. package/sync.ts +0 -56
  252. package/tests/agentcert.test.ts +0 -128
  253. package/tests/agentfleet.test.ts +0 -214
  254. package/tests/agentreview.test.ts +0 -241
  255. package/tests/agentstream.test.ts +0 -335
  256. package/tests/agentwork.test.ts +0 -356
  257. package/tests/apifreeze.test.ts +0 -290
  258. package/tests/apimap.test.ts +0 -112
  259. package/tests/approvalgate.test.ts +0 -175
  260. package/tests/artifactmanifest.test.ts +0 -204
  261. package/tests/attentionfeed.test.ts +0 -163
  262. package/tests/backgroundruns.test.ts +0 -100
  263. package/tests/batchscheduling.test.ts +0 -131
  264. package/tests/blackboard.test.ts +0 -238
  265. package/tests/bridge.test.ts +0 -1088
  266. package/tests/browsercoverage.test.ts +0 -134
  267. package/tests/browserpolyfills.test.ts +0 -124
  268. package/tests/build.mjs +0 -1260
  269. package/tests/clientauth.test.ts +0 -223
  270. package/tests/clitools.test.ts +0 -578
  271. package/tests/confirmgates.test.ts +0 -190
  272. package/tests/containerpack.test.ts +0 -143
  273. package/tests/controlflow.test.ts +0 -2120
  274. package/tests/coordination.test.ts +0 -345
  275. package/tests/copyscreen.test.ts +0 -139
  276. package/tests/core.test.ts +0 -417
  277. package/tests/costcert.test.ts +0 -95
  278. package/tests/crossbrowser.test.ts +0 -115
  279. package/tests/cspaudit.test.ts +0 -79
  280. package/tests/dashdone.test.ts +0 -615
  281. package/tests/datagrid.test.ts +0 -137
  282. package/tests/doccheck.test.ts +0 -107
  283. package/tests/dombatch.test.ts +0 -109
  284. package/tests/emulation.test.ts +0 -282
  285. package/tests/environments.test.ts +0 -259
  286. package/tests/evidenceviews.test.ts +0 -88
  287. package/tests/exporttools.test.ts +0 -185
  288. package/tests/firefoxprep.test.ts +0 -134
  289. package/tests/flowlibrary.test.ts +0 -242
  290. package/tests/flowrun.test.ts +0 -303
  291. package/tests/forensics.test.ts +0 -439
  292. package/tests/gateway.test.ts +0 -939
  293. package/tests/headlesslib.test.ts +0 -171
  294. package/tests/httpstream.test.ts +0 -277
  295. package/tests/immutablelog.test.ts +0 -157
  296. package/tests/inboundguard.test.ts +0 -177
  297. package/tests/lazyload.test.ts +0 -72
  298. package/tests/librarymodes.test.ts +0 -623
  299. package/tests/llm.test.ts +0 -696
  300. package/tests/manifest.test.ts +0 -226
  301. package/tests/maskinputs.test.ts +0 -150
  302. package/tests/matrixverify.test.ts +0 -111
  303. package/tests/mavenpack.test.ts +0 -75
  304. package/tests/mcpserver.test.ts +0 -704
  305. package/tests/memory.test.ts +0 -4155
  306. package/tests/memorycare.test.ts +0 -230
  307. package/tests/migrateplan.test.ts +0 -349
  308. package/tests/minimization.test.ts +0 -414
  309. package/tests/modelroute.test.ts +0 -112
  310. package/tests/multiagent.test.ts +0 -440
  311. package/tests/nativebridge.test.ts +0 -807
  312. package/tests/navigation.test.ts +0 -284
  313. package/tests/nugetpack.test.ts +0 -83
  314. package/tests/orchestration.test.ts +0 -449
  315. package/tests/originpolicy.test.ts +0 -405
  316. package/tests/outputcompare.test.ts +0 -97
  317. package/tests/package.test.ts +0 -91
  318. package/tests/pagebridge.test.ts +0 -5909
  319. package/tests/pentest.test.ts +0 -75
  320. package/tests/perfrecords.test.ts +0 -257
  321. package/tests/permdiff.test.ts +0 -85
  322. package/tests/phishguard.test.ts +0 -128
  323. package/tests/pickerviews.test.ts +0 -155
  324. package/tests/pipelines.test.ts +0 -381
  325. package/tests/planlint.test.ts +0 -240
  326. package/tests/planreview.test.ts +0 -383
  327. package/tests/platformtargets.test.ts +0 -56
  328. package/tests/policy.test.ts +0 -8284
  329. package/tests/portability.test.ts +0 -96
  330. package/tests/progress.test.ts +0 -1036
  331. package/tests/promptlibrary.test.ts +0 -116
  332. package/tests/protocol.test.ts +0 -4793
  333. package/tests/publishingpipeline.test.ts +0 -314
  334. package/tests/quickactions.test.ts +0 -164
  335. package/tests/readiness.test.ts +0 -78
  336. package/tests/recipes.test.ts +0 -163
  337. package/tests/redactshots.test.ts +0 -216
  338. package/tests/registernvidiakeys.ts +0 -51
  339. package/tests/relayserve.test.ts +0 -304
  340. package/tests/releasenotes.test.ts +0 -276
  341. package/tests/resilience.test.ts +0 -467
  342. package/tests/resourceaware.test.ts +0 -187
  343. package/tests/runbudget.test.ts +0 -125
  344. package/tests/runhistory.test.ts +0 -299
  345. package/tests/runreplay.test.ts +0 -113
  346. package/tests/runresume.test.ts +0 -184
  347. package/tests/runstate.test.ts +0 -288
  348. package/tests/runtimeadapters.test.ts +0 -251
  349. package/tests/safariskeleton.test.ts +0 -115
  350. package/tests/sandboxframe.test.ts +0 -196
  351. package/tests/sbom.test.ts +0 -105
  352. package/tests/secretvault.test.ts +0 -188
  353. package/tests/selcache.test.ts +0 -111
  354. package/tests/sessioninterface.test.ts +0 -791
  355. package/tests/sessions.test.ts +0 -591
  356. package/tests/siteprefs.test.ts +0 -228
  357. package/tests/snapshotdelta.test.ts +0 -165
  358. package/tests/statusviews.test.ts +0 -237
  359. package/tests/stepmeter.test.ts +0 -200
  360. package/tests/streamparse.test.ts +0 -163
  361. package/tests/stylepruning.test.ts +0 -90
  362. package/tests/surfaces.test.ts +0 -282
  363. package/tests/sweep.test.ts +0 -78
  364. package/tests/syncbridge.test.ts +0 -164
  365. package/tests/taskqueue.test.ts +0 -206
  366. package/tests/toolcalls.test.ts +0 -336
  367. package/tests/toolcatalog.test.ts +0 -201
  368. package/tests/torture-agent.test.ts +0 -706
  369. package/tests/torture-auth.test.ts +0 -461
  370. package/tests/torture-commands.test.ts +0 -895
  371. package/tests/torture-data.test.ts +0 -923
  372. package/tests/torture-environments.test.ts +0 -285
  373. package/tests/torture-export.test.ts +0 -263
  374. package/tests/torture-http.test.ts +0 -1379
  375. package/tests/torture-llm.test.ts +0 -808
  376. package/tests/torture-memory.test.ts +0 -1084
  377. package/tests/torture-plan.test.ts +0 -829
  378. package/tests/torture-run.test.ts +0 -626
  379. package/tests/torture-session.test.ts +0 -928
  380. package/tests/torture-swarm.test.ts +0 -1245
  381. package/tests/torture-tools.test.ts +0 -964
  382. package/tests/torture-workflow.test.ts +0 -2354
  383. package/tests/tourviews.test.ts +0 -52
  384. package/tests/transparency.test.ts +0 -147
  385. package/tests/trigger.test.ts +0 -941
  386. package/tests/v1sunset.test.ts +0 -428
  387. package/tests/virtlist.test.ts +0 -94
  388. package/tests/vision.test.ts +0 -540
  389. package/tests/vsixpack.test.ts +0 -145
  390. package/tests/webapi.test.ts +0 -523
  391. package/tests/workflow.test.ts +0 -1785
  392. package/tests/workfloweditor.test.ts +0 -759
  393. package/tests/xpipack.test.ts +0 -128
  394. package/tools.ts +0 -734
  395. package/types.ts +0 -9908
  396. package/umd.ts +0 -9
  397. package/utils.ts +0 -249
  398. package/version.ts +0 -8
  399. package/versionregistry.ts +0 -1310
  400. package/views.ts +0 -2153
  401. package/vitest.config.ts +0 -12
  402. package/web/App.tsx +0 -78
  403. package/web/README.md +0 -47
  404. package/web/capacitor.config.ts +0 -46
  405. package/web/const.ts +0 -19
  406. package/web/control.shell.tsx +0 -66
  407. package/web/dashboardpage.ts +0 -554
  408. package/web/db.ts +0 -493
  409. package/web/design.html +0 -541
  410. package/web/gatewayview/Gateway.tsx +0 -345
  411. package/web/gatewayview/config.ts +0 -1042
  412. package/web/gatewayview/definition.ts +0 -174
  413. package/web/icons.ts +0 -15
  414. package/web/optionspage.ts +0 -691
  415. package/web/popup.ts +0 -1651
  416. package/web/schema.prisma +0 -176
  417. package/web/sidepanel.ts +0 -7941
  418. package/web/sitemanifest.json +0 -13
  419. package/web/terminal-ui.tsx +0 -622
  420. package/web/transparencypage.ts +0 -541
  421. package/web/vite.config.ts +0 -39
  422. package/web/workspace.ts +0 -23
  423. package/workbenchmemory.ts +0 -104
  424. package/workbenchsession.ts +0 -304
  425. package/workflow.ts +0 -4495
  426. /package/{dist/bun.d.ts → bun.d.ts} +0 -0
  427. /package/{dist/cli.d.ts → cli.d.ts} +0 -0
  428. /package/{dist/companion.d.ts → companion.d.ts} +0 -0
  429. /package/{dist/crossbrowser.d.ts → crossbrowser.d.ts} +0 -0
  430. /package/{dist/dashdone.d.ts → dashdone.d.ts} +0 -0
  431. /package/{dist/deno.d.ts → deno.d.ts} +0 -0
  432. /package/{dist/hardening.d.ts → hardening.d.ts} +0 -0
  433. /package/{dist/headless.d.ts → headless.d.ts} +0 -0
  434. /package/{dist/http.d.ts → http.d.ts} +0 -0
  435. /package/{dist/index.d.ts → index.d.ts} +0 -0
  436. /package/{dist/mcp.d.ts → mcp.d.ts} +0 -0
  437. /package/{dist/memory.d.ts → memory.d.ts} +0 -0
  438. /package/{dist/node.d.ts → node.d.ts} +0 -0
  439. /package/{dist/pack.d.ts → pack.d.ts} +0 -0
  440. /package/{dist/policy.d.ts → policy.d.ts} +0 -0
  441. /package/{dist/progress.d.ts → progress.d.ts} +0 -0
  442. /package/{dist/protocol.d.ts → protocol.d.ts} +0 -0
  443. /package/{dist/server.d.ts → server.d.ts} +0 -0
  444. /package/{dist/umd.d.ts → umd.d.ts} +0 -0
package/protocol.ts DELETED
@@ -1,4187 +0,0 @@
1
- import { defaultmaskshapes } from "./security.js";
2
- import {
3
- actionrisk,
4
- environmentrequirements,
5
- iscdpkind,
6
- isemulationkind,
7
- isprofilekind,
8
- issessionkind,
9
- istriggeraction,
10
- isworkflowkind,
11
- outboundtarget,
12
- parseoptions,
13
- resolvedrisk,
14
- sockettarget,
15
- submitreviewgranted,
16
- triggerorigins,
17
- validatestep,
18
- } from "./policy.js";
19
- import { blockinvocationof, composeworkflow, validateworkflow, workflowblockof, workflowstepof } from "./workflow.js";
20
- import { controlsummary } from "./workflow.js";
21
- import { importsessionfile } from "./session.js";
22
- import type {
23
- classconsent,
24
- consentwindow,
25
- controlflowdecision,
26
- editormodel,
27
- environmentkind,
28
- environmentrequirement,
29
- manualrun,
30
- maskrule,
31
- offscreenregistryentry,
32
- originprofile,
33
- revokerunevent,
34
- runlogentry,
35
- runhistoryentry,
36
- siteoverride,
37
- steptemplate,
38
- timeoutabort,
39
- triggerfire,
40
- triggerule,
41
- variablescope,
42
- watchdogconfig,
43
- watchdogrecord,
44
- workflowprovenance,
45
- workflowrecord,
46
- workflowrun,
47
- workflowversion,
48
- versiondiff,
49
- } from "./types.js";
50
- import { blockruleof, patternorigin, proxyrouteof } from "./net.js";
51
- import { allowlistcovers, cdpallowlistof, cdpdomains, methoddomain, teardownplanof } from "./debug.js";
52
- import { annotationof, attachtargetof, tracecategories } from "./debug.js";
53
- import { loglevels } from "./run.js";
54
- import { locationpresetof, permissiongrantof, revertplanof } from "./environments.js";
55
- import {
56
- protocolversion,
57
- servercontractversion,
58
- type agentplan,
59
- type agentrecord,
60
- type agentrole,
61
- type aggregaterecord,
62
- type apimapentry,
63
- type attachtarget,
64
- type auditexportrecord,
65
- type bannerreport,
66
- type budgetstate,
67
- type consensusrecord,
68
- type costentry,
69
- type depthlimit,
70
- type lessonrecord,
71
- type loadreport,
72
- type prefetchplan,
73
- type spawnrecord,
74
- type subagentspec,
75
- type tasklane,
76
- type allowlistentry,
77
- type approvalrequest,
78
- type authchallenge,
79
- type blockrule,
80
- type breakpointspec,
81
- type callrecord,
82
- type cdpallowlist,
83
- type cdpcommand,
84
- type cdpeventrule,
85
- type cdpsession,
86
- type channelrecord,
87
- type clientidentity,
88
- type clickablemap,
89
- type consolediff,
90
- type cookieoperation,
91
- type cpuprofile,
92
- type dataset,
93
- type debuggergrant,
94
- type downloadrecord,
95
- type errorrecord,
96
- type errorreport,
97
- type eventsubscription,
98
- type exchangerecord,
99
- type extractsession,
100
- type flowmetric,
101
- type focusevent,
102
- type formreport,
103
- type growsample,
104
- type headerule,
105
- type heaprecord,
106
- type httpstreamconfig,
107
- type imagebatch,
108
- type jsonrpcframe,
109
- type keyholdstate,
110
- type longtaskentry,
111
- type mediarecord,
112
- type memoryitem,
113
- type memoryprovenance,
114
- type memorytrend,
115
- type mockspec,
116
- type mutationevent,
117
- type navstate,
118
- type netlogrecord,
119
- type observation,
120
- type pagesignals,
121
- type pausestate,
122
- type planproposal,
123
- type proposalrequest,
124
- type provenancerecord,
125
- type proxyroute,
126
- type quarantineentry,
127
- type ratelimitread,
128
- type rejectionrecord,
129
- type resolvedtarget,
130
- type rpcerror,
131
- type rpcerrorcode,
132
- type safetyverdict,
133
- type scriptoverride,
134
- type selectorcandidate,
135
- type sessiontoken,
136
- type shiftentry,
137
- type shotpair,
138
- type shotrecord,
139
- type snapshotdiff,
140
- type sourcemapconsent,
141
- type sourcemapref,
142
- type stepoutcome,
143
- type streamchannel,
144
- type tablayout,
145
- type tabreport,
146
- type timelineentry,
147
- type tlsconfig,
148
- type tokenrecord,
149
- type toolresult,
150
- type toolstep,
151
- type tracerecord,
152
- type trailentry,
153
- type transformrule,
154
- type typeaheadpick,
155
- type watchexpression,
156
- type wizardstate,
157
- type blackboxrule,
158
- type devicepreset,
159
- type networkpreset,
160
- type locationconsent,
161
- type locationpreset,
162
- type agentpreset,
163
- type presetlibrary,
164
- type emulationlayer,
165
- type emulationstate,
166
- type permissionoverriderecord,
167
- type sessionrecord,
168
- type sessionevent,
169
- type sessionfolder,
170
- type sessiondiff,
171
- type autointerval,
172
- type runtimelineevent,
173
- type urlvisit,
174
- type servereventtype,
175
- } from "./types.js";
176
- import { authrefusedmessage } from "./auth.js";
177
- import { bridgepayload } from "./bridge.js";
178
- import { defaultheartbeatms, defaultidlewindowms } from "./http.js";
179
- import { redactparams } from "./gates.js";
180
- import { rpcerrorof } from "./mcp.js";
181
- import type {
182
- agentevent,
183
- batchcall,
184
- batchoutcome,
185
- callcontext,
186
- callratelimit,
187
- cancelframe,
188
- criticreview,
189
- eventkind,
190
- handoffrecord,
191
- idempotencykey,
192
- idempotencyrecord,
193
- modeloutput,
194
- plandraft,
195
- progressnotice,
196
- promptdef,
197
- protocoleventsubscription,
198
- progressboard,
199
- resourcewatch,
200
- reviewrequest,
201
- samplingrequest,
202
- streamchunk,
203
- structurederror,
204
- swarmstate,
205
- toolcallrecord,
206
- toolmock,
207
- tooldryrun,
208
- } from "./types.js";
209
-
210
- function record(value: unknown): Record<string, unknown> {
211
- if (!value || typeof value !== "object" || Array.isArray(value))
212
- throw new Error("Protocol message must be an object.");
213
- return value as Record<string, unknown>;
214
- }
215
-
216
- function text(value: unknown, field: string): string {
217
- if (typeof value !== "string" || !value.trim()) throw new Error(`${field} must be a non-empty string.`);
218
- return value.trim();
219
- }
220
-
221
- /**
222
- * Reviewed options grammar shared by every step kind.
223
- *
224
- * A step may carry a JSON `options` object with the following reviewed fields:
225
- * - `targetref`: element addressing without a css selector, with `mode` one of `selector`, `text`, `aria`, `name`, `xpath`, `index` or `point`; the text mode carries `text`, the aria mode carries `role` plus `name`, the name mode carries `name`, the xpath mode carries `xpath`, the index mode carries a one based clickable map `index`, and the point mode carries viewport `x` and `y` coordinates.
226
- * - `pointpath`: pointer travel between two points, with `start` and `end` points, optional `waypoints` and a `duration` in milliseconds.
227
- * - `speedprofile`: pointer speed shape with `easing` (`linear` or `easeinout`), a `peak` velocity in pixels per second and a `jitter` window in milliseconds.
228
- * - `framepath`: ordered frame indexes routing a step inside same origin iframes.
229
- * - `shadow`: ordered host selectors addressing a target across open shadow roots.
230
- * - `retryrule`: retry bounds with `attempts`, a `settle` window in milliseconds and a movement `tolerance` in pixels; attempts carry no code ceiling.
231
- * - `dialogpolicy`: dialog answers with an `accept` flag and a reviewed prompt `answer` string.
232
- * - wrapper steps (`retryaction`, `enterframe`) reference an inner step by `stepid` or inline with `kind`, `target`, `value` and an `options` object.
233
- * - control kinds add reviewed `delay`, `values`, `results`, `timeout`, `holdid` and `modifiers` fields.
234
- * - watch kinds (`watchmutate`, `watchbanner`, `watchfocus`) carry a reviewed `lifetime` window in milliseconds, optional selector `scopes`, optional event kind filters `events` and an optional `poll` interval; the lifetime window carries no code ceiling.
235
- * - `waitquiet` carries a reviewed `quietrule` with a positive `idle` threshold in milliseconds, an optional `poll` interval and an optional `timeout`; every value carries no code ceiling.
236
- * - `diffsnapshots` carries exactly two reviewed observation `versions` to compare.
237
- * - navigation kinds carry the navigation parameter grammar: `navtarget` with a `url`, a `container` (`current`, `tab`, `window` or `private`), a `position` (`adjacent` or `end`) and a `private` flag; `waitprofile` with non-empty load `signals`, optional `idle` and `timeout` thresholds and per origin `overrides`; and `urlpattern` with a `mode` (`exact`, `prefix`, `host` or `pattern`), a `url`, optional `query` parameter expectations and an optional `fragment`.
238
- * - `waiturl` and `spawait` carry a reviewed `urlpattern`, `timeout` and `poll`; `spanav` carries an optional `routepattern`, `followlink` an optional `fragment` flag, `rewritequery` reviewed `set` and `remove` query edits, `navlist`/`prefetch`/`batchopen` reviewed `urls` lists, `preconnect` reviewed `origins`, `navrate` a reviewed `ratelimit` with `domain`, `window` and `ceiling` (never capped in code), and `deeplink` a reviewed `app` pattern with `params`.
239
- * - observation kinds attach structured evidence to step details: a11y trees, reader articles, list patterns, table shapes, pagination estimates, watch event records, quiet probe samples, snapshot diffs and derived selector candidates with stability scores.
240
- * - navigation steps attach structured evidence to step details: load phases and ready states, final urls after redirects, redirect chains with statuses and timing, http error, offline and certificate interstitial states, safety verdicts and navlist entry completions.
241
- * - the tabs and windows command family adds its parameter grammar: `tabquery` with url, title, id and pattern matchers (at least one matcher required, patterns use `*` and `**` wildcards); `group` with a `name`, a Chromium tab group `color`, member `tabids` and a `collapsed` flag; `layout` names for `savelayout` and `restorelayout`; reviewed `pinned`, `muted`, `index`, `windowid`, `direction`, `step`, `bounds`, `label`, `labels`, `taskrefs`, `provenance` and `run` fields; `tabcreate` gains reviewed `background` and `window` options and `windowcreate` gains reviewed `left`, `top`, `width`, `height` and `state` options; `closepattern` requires the explicit `reviewed` flag before any tab closes.
242
- * - tab command steps attach structured evidence to step details: tab reports with matched tabs carrying audio state and metadata, group registries, badge states, layout snapshots, clone warnings, discard candidates and watchtab event records.
243
- * - the forms and data family adds its parameter grammar: `formrecord` with an optional `form` selector and non-empty `entries` of `{ match, kind, value }` where `match` is a `fieldmatch` with `mode` one of `label`, `placeholder`, `arialabel` or `name`; `valuegen` with a field `kind`, an optional `locale` and an optional numeric `seed`; `fields` lists of label or placeholder value pairs for filllabel and fillplaceholder; a reviewed `name` plus `formrecord` for saveprofiles; a reviewed `consentref` for submitform and consentpassword; a reviewed `backoff` rule with `wait` and `factor` plus an optional `attempts` for retryform with no code ceiling; a reviewed `child` selector, `pick` entry, `pause` and `timeout` for chains, typeaheads and card typing; reviewed card `segments`; and a reviewed `source` for fillcode; password entries inside form records are refused because passwords need the explicit consentpassword consent.
244
- * - form steps attach structured evidence to step details: form reports with detected fields, kinds and matched controls, error reports with field refs and messages, wizard states with step history, typeahead picks, honeypot flags, login detections with session link markers and signup or checkout template detections.
245
- * - the forms and data part two family adds its parameter grammar: `scrapetable` and `paginateextract` carry an optional dataset `name`, an optional positive integer `rowlimit` (never capped in code), a reviewed `next` control selector, an optional positive integer `pages` count (never capped in code) and an optional `wait` row freshness window; the export kinds (`exportcsv`, `exportjson`, `exportexcel`, `copytable`, `streamdisk`, `pushsheets`) carry a reviewed `dataset` id, an optional artifact `name`, an optional single character csv `delimiter`, a reviewed positive integer streaming `chunk` size (never capped in code) and, for sheet pushes, a reviewed HTTPS `sheet` endpoint plus the explicit `reviewed` flag; `importcsv` carries reviewed `csv` text with an optional `name` and a `mapping` object of csv headers to target keys; `looprows` carries a reviewed `dataset` id, an optional row `variable` name and a wrapped inner step by `stepid` or inline; `transformvalues` carries reviewed `rules` of `{ expression, sources, target }` where the expression is `trim`, `upper`, `lower`, `number`, `prefix:x`, `suffix:x` or `replace:from=>to`; `deduperows` carries reviewed dedupe `keys`; `mergepages` carries a reviewed `datasets` id list; `stamplerows` carries a reviewed `dataset` id with an optional `url`; `previewgrid` carries a reviewed `dataset` id with an optional `sample` row count (never capped in code); `resumeextract` carries a reviewed `session` id; and `logprovenance` carries a reviewed `artifact` id or name.
246
- * - the data pipelines family of the 1.1.75 release adds its parameter grammar: every extract step (`scrapetable`, `paginateextract`, `resumeextract`, `transformvalues`, `deduperows`, `stamplerows`, `previewgrid`, `streamdisk` and `logprovenance`) may carry a reviewed `pipeline` reference naming the extractpipeline its rows flow through, the transform rules of the pipeline grammar pair their `field` with a reviewed `operation` of `trim`, `case`, `number` or `date` (an unknown operation refuses), the dedupe key carries its `columns` with their `normalization` of none, whitespace, case or whitespace and case, and the sample policy carries its `rows` count with its `strategy` of first, random or stratified — every count stays a user choice with no code ceiling.
247
- * - data steps attach structured evidence to step details: scraped grids with normalized column specs, span filled rows and nested child datasets, pagination page counts with remaining next controls, dataset previews with sampled rows, dedupe removed counts, transform error lists, stream chunk states and provenance records with checksums and row ranges.
248
- * - the files, clipboard and downloads family adds its parameter grammar: `batchdownload` carries a reviewed `downloadspec` with a non-empty `urls` list, an optional `filename` rule and an optional `complete` criterion (`size` or `checksum`) plus an optional positive integer `concurrent` window (never capped in code); `pausedownload`, `resumedownload`, `verifydownload`, `quarantinedownload` and `scanvirus` carry a reviewed download or quarantine reference with optional `checksum`, `bytes`, `scanner` and `reason` fields; `interceptmime` carries a reviewed `mimefilter` with non-empty `include` patterns, optional `exclude` patterns and the `deny` or `allow` default for unlisted mime types; `readclipboard` carries a reviewed `consentref` plus an optional `prompt`; `exportnetlog` carries an optional `stepid` filter; `namecaptures` carries a reviewed `task` with optional `steps` and `extension`; and `cleanupartifacts` carries reviewed `rules` of `{ age, kind, keep }` where the age window carries no code ceiling and the keep policy is `none`, `latest` or `all`.
249
- * - files steps attach structured evidence to step details: batch download reports with per file states, resolved paths and checksums, verification match results, netlog records correlated with steps through request ids, clipboard entries with payload hashes and origin provenance (the payload text never appears), quarantine entries with scan verdicts and release refs, capture names stamped from task, step and sequence parts, and cleanup run outcomes with removed and kept counts.
250
- * - the media capture family adds its parameter grammar: every capture kind (`shotview`, `shotfullpage`, `shotelement`, `shotregion`, `contactsheet`) carries a reviewed `capture` options object with `format` (`png`, `jpeg` or `webp`), `quality` between zero and one hundred, `pixelratio` from one up with no code ceiling, an `annotate` flag and an `exporttarget` of `memory`, `download` or `clipboard`; `shotfullpage` adds reviewed `settle`, `overlap` and `wait` windows that keep the stitching scroll budget inside the reviewed wait window; `shotelement` addresses its element through the step target; `shotregion` requires a reviewed `regionrect` of `x`, `y`, `width` and `height` in css pixels plus the explicit `reviewed` flag, with an optional scrollable `container` selector and `steps` count; `contactsheet` carries reviewed `elements` selectors with an optional `sheet` layout of `cellsize`, `columns` and `label` (`none`, `index`, `selector` or `both`); and a reviewed `naming` rule of `run`, `step`, `sequence` and `kind` segment flags extends the 1.1.39 capture naming rule with the capture kind segment.
251
- * - capture steps attach structured evidence to step details: shotrecords with record id, run, step, kind, format, geometry and byte size, the stitch tile count of full page captures, shotpair ids of before and after state captures with their action kind, target selector and dom snapshot id, and contact sheet cells with selector labels; the response envelope gains a capture block with the record id, format and byte size, and the capture report carries every stored record and pair.
252
- * - the media capture part two family adds its parameter grammar: `capturepdf` carries reviewed `pdf` options of `paperwidth` and `paperheight` inches (positive, never capped in code), `margins` of `top`, `right`, `bottom` and `left` inches (negative margins are refused), a positive `scale`, `landscape` and `paginate` flags, optional reviewed break point `selectors` and an `exporttarget` of memory or download; `recordscreen` and `captureaudio` carry reviewed `recording` options of `scope` (`tab` or `run`), positive `fps` and `bitrate` values with no code ceilings, an `audio` flag, a positive `duration` window and a reviewed `consentref` of an approved recording consent prompt; `captureframe` addresses a video element through the step target with an optional `timestamp` in seconds and a `poster` flag; `downloadimages` carries a reviewed `imagefilter` of `selector` scope, `minwidth` and `minheight` thresholds and a `formats` list plus an optional `naming` rule; `shotcanvas` addresses a canvas element through the step target with reviewed capture options; `probestream` carries an optional scope `selector`; `readmedia` and `readassets` carry no parameters; `timelapse` carries a reviewed `lapse` plan of positive `interval` and `duration` windows with a `format` and the lapse duration kept inside the reviewed `wait` budget; `convertimage` carries reviewed `capture` or `captures` ids plus a `convert` directive of `source`, `target` (png, jpeg or webp) and `quality`; and `makethumbs` carries the same capture ids plus a `thumb` directive of positive `size`, `fit` (cover or contain) and `suffix`.
253
- * - media steps attach structured evidence to step details: pdf records with page count, paper size, margins and byte size, recording records with ids, durations, frame counts and file refs, image batches with filter match counts and deduplicated url lists, frame records with source, timestamp and poster flag, canvas records with context kind, stream probe results with track details, asset lists and ordered lapse frame ids; the response envelope gains a media block with the record id, kind and byte size, and the media report carries every stored media record and image batch.
254
- * - the network observation family adds its parameter grammar: `fetchurl` carries a reviewed `fetch` request of `url`, `method` (a known HTTP verb), a custom header `allowlist` object whose names must be non-empty (empty header names are refused), an optional string `body` and a `mode` of `cors`, `no-cors` or `same-origin`, plus a reviewed `fetchoptions` object of `timeout`, `retries`, `backoff` and the redirect `follow` limit (every bound a user choice with no code ceiling) whose worst case must fit the reviewed `wait` budget, an optional `stream` window with its byte `budget` ceiling and a reviewed `consentref` required before any custom header leaves the extension; `parsejson` carries a reviewed stored `call` id and `fields` json path rules of `{ name, path, kind, default }` with dotted paths of non-empty segments; `parsehtml` carries the same `call` id and `queries` of `{ selector, attribute, multi }`; `callrest` carries a reviewed typed `endpoint` name, an optional `payload` object, an optional method `override` and a reviewed `success` status list; `callgraphql` carries the same `endpoint` name and a reviewed `graphql` request of `query` text, `operationkind` (`query` or `mutation`, unknown kinds are refused), optional `variables` and `operationname`; both typed calls accept reviewed `apikeys` references to stored key records.
255
- * - the network observation part two family adds its parameter grammar: `opensocket` carries a reviewed `socket` of `url` (wss for websockets, https for streams), optional `protocols`, an integer `reconnect` budget, a `backoff` base, a `backoffceiling` where exponential growth stops and an optional `lifetime` window (every bound a user choice with no code ceiling); `sendmessage` carries a reviewed `message` of the open `channel` id, an optional named `stream` and the reviewed `payload` string; `waitmessage` carries a reviewed `filter` of `stream`, a dotted json `path` and the `limit` match count plus the `wait` budget it stops on; `subscribesse` carries a reviewed `subscription` of the event stream `url`, an optional resume `lasteventid`, an optional `lifetime` and the required `cancel` cancellation path; `longpoll` carries a reviewed `poll` cursor of `url`, `cursorfield`, positive `interval`, the required `stop` condition of `{ field, equals }`, an optional `maxpolls` ceiling and the cursor `param` name, with the interval kept inside the reviewed `wait` budget; `watchrequests` carries an optional `watch` window and a user configured match `limit`; `readheaders` carries a reviewed `headers` filter whose `allow` allowlist and `redact` redaction list are both required non-empty before any header value is stored; `capturebodies` carries a reviewed `body` filter of `urlpattern`, `mimes` and the byte `ceiling`; `mapapi` carries an optional match `limit`; and `extractapi` carries a reviewed `replay` spec of the captured `endpoint`, the replay `verb`, parameter `overrides` and dotted extraction `paths`.
256
- * - network observation part two steps attach structured evidence to step details: the network block with the exchange count and channel state, matched message envelopes with their channel scoped sequence numbers and event counts of stream subscriptions, poll loop iterations with cursor values and stop reasons, observed exchanges with correlation ids, request lifecycle timings and error classes, redacted header views, captured body records with mime types and byte sizes inside the reviewed ceiling, ranked api map entries with frequency, json share and payload stability, and replayed endpoint fields mapped onto extraction paths; the response envelope gains a network block, and the exchanges report carries every exchange, channel, subscription and api map entry of the run.
257
- * - http steps attach structured evidence to step details: the transport block with status, response header names, byte size and duration, retry counts and stream byte counts, parsedfield values extracted by dotted paths with miss flags, html query results with attribute values, text and element counts, the endpoint name of rest and graphql results, structured json error bodies and every graphql error mapped beside the step that produced it; the response envelope gains a transport block, and the calls report carries every stored call record with the bodies held back.
258
- * - the network control family adds its parameter grammar: `blockrequest` carries a reviewed `block` rule of an https origin `urlpattern` (patterns without a named origin are refused), an optional `resourcetypes` list and the explicit `reviewed` flag behind the blockgate; `mockresponse` carries a reviewed `mock` fixture of the same origin `urlpattern`, an integer `status`, optional `headers` and either the full `body` reviewed through the explicit `reviewed` flag or a `bodyref` of a captured body of the 1.1.43 body store the fixture replays; `rewriteheaders` carries reviewed `rules` of `{ urlpattern, name, operation, value }` where every pattern names its origin explicitly and the operation is `set`, `append` or `remove`; `setcookies` carries reviewed `cookies` records of `{ name, domain, path, value, expiresat }` scoped to granted domains by the cookiegate; `readcookies` carries an optional `domain`; `clearcookies` carries a reviewed `domain` with an optional `names` list; `authflow` carries a reviewed `oauth` flow of `provider`, https `authorizeurl` and `tokenurl`, `scopes` and the granted `redirectorigin` plus the reviewed provider `consentref`; `saveapikey` carries a reviewed `key` entry of `name`, https origin `origins` scopes, the attaching `header` and the secret `value` behind the explicit `consentref`; `routeproxy` carries a reviewed `proxy` route of `scheme` (http, https, socks4 or socks5), `host`, `port` and the required non-empty `bypass` origin list behind the reviewed `consentref` of the proxygate; `postform` carries a reviewed `form` payload of the https `url` and its `fields`; and `postfiles` carries a reviewed `upload` payload of the https `url`, `fields` and `files` where every file carries the explicit `reviewed` flag before any multipart upload includes it.
259
- * - network control steps attach structured evidence to step details: the control block with the applied, blocked and mocked rule counts of the run, blocked counts per rule, applied header rewrite rules with their provenance, redacted cookie views without values, oauth flow state with provider and scopes while token values never appear, api key entries with last use timestamps and no key material, proxy route state with apply and revert times, rate limit waits with reset times, urlencoded form encodings and streamed multipart upload progress; the response envelope gains a control block, and the auth report carries token metadata per provider with scopes and expiry windows but no token values.
260
- * - the debugging family adds its parameter grammar: `watchconsole`, `watcherrors` and `watchtasks` carry a reviewed `watch` window object with a `window` in milliseconds kept inside the reviewed `wait` budget (both user choices with no code ceiling), a `level` floor from the reviewed level set (`error`, `warn`, `info`, `log`, `debug`, `trace`) and optional `sources` filters from the reviewed timeline source grammar (`console`, `error`, `rejection`, `resource`, `longtask`, `network`); `watchconsole` adds the required non-empty `redact` pattern list applied before any console text leaves the page bridge, a `depth` serialization bound, a `spam` rule of `pattern`, `windowsize` and `collapse` threshold and a `rotation` rule of `maxentries` with an `overflowtarget` store; `watchtasks` adds an optional `threshold` in milliseconds; the kinds stay read only behind the timelinegate that scopes capture to the run tab.
261
- * - debugging steps attach structured evidence to step details: the timeline block with the entry counts per level and the spam collapse count, console entries with their level, redacted text and argument kinds, error and rejection ids with stack frames, source urls and lines, resource failures with element context, long task entries with attribution names and the blocking duration per step window; the response envelope gains a timeline block, and the timeline report carries every entry, error record, rejection record and long task entry of the run while the console diff report carries the added, removed and repeated line classes of two compared runs.
262
- * - the debugging part two family adds its parameter grammar: `attachcdp` carries a reviewed non-empty `domains` list of the reviewed domain grammar (`Runtime`, `Log`, `Debugger`, `DOM`, `Network`, `Page`), the required `teardown` plan of `revertsteps` with the `resumepolicy` of resume, pause or ask (attaches without one are refused at validation and in the proposal parser) and an optional method `allowlist` of `Domain.method` gates inside the enabled domains; `detachcdp` carries no parameters and reverts every breakpoint and override before detaching; `cdpcmd` carries a reviewed `command` of the `Domain.method` form with optional `params` and a dotted `resultpath`, and its method domain must stay inside the enabled domain allowlist of the plan attach; `watchcdp` carries reviewed `events` rules of `domain`, `event` and optional payload `match` plus the required `watch` lifetime window kept inside the reviewed `wait` budget; `setbreakpoint` carries a reviewed `breakpoint` of https `url`, zero based `line`, optional `column` and a `condition` of the reviewed expression grammar (member chains, literals, comparison and logic operators, negation and parentheses only); `stepcode` carries the reviewed `mode` of stepover, stepinto, stepout or resume; `watchexpr` carries the reviewed `expression` text with its pause `scope` and the explicit `reviewed` flag before any evaluation; and `overridescript` carries a reviewed `override` of an https origin `urlpattern` with the full fixture `source` behind the explicit `reviewed` flag.
263
- * - debugging part two steps attach structured evidence to step details: the cdp block with the session state and command ids, pausestate summaries with their call frames and dom snapshot ids, event counts per domain of watchcdp results, breakpoint registrations with hit counts, watch expression values per pause and override applications with revert controls; the response envelope gains a cdp block, and the cdp report carries every session, command outcome, event rule, breakpoint, pause state, watch expression and override of the run with the override sources held back.
264
- * - the debugging part three family adds its parameter grammar: `measureflow` carries a reviewed `flow` spec of the `prefix` mark prefix, the `steps` step window and the `metrics` list of the reviewed metric set (`navigation`, `paint`, `lcp`, `fid`, `interaction`, `blocking`) plus the required `watch` window inside the reviewed `wait` budget; `heapshot` carries an optional reviewed `heap` object with the user chosen snapshot `interval` only; `trackmemory` carries a reviewed `growth` object with the reviewed `slope` in bytes per millisecond and the optional user chosen sampling `interval`; `profilecpu` carries a reviewed `profile` object with the profiled `duration` kept inside the reviewed `wait` budget; `watchshifts` carries the reviewed `watch` window of the user chosen observation length with an optional score `threshold`; `traceload` carries a reviewed `trace` object with a non-empty `categories` list of the reviewed category grammar (`navigation`, `scripting`, `rendering`, `painting`, `loading`, `network`), the reviewed trace `window` it stops at and the optional `exporttarget` of memory or download, and the user configured trace byte ceiling applies at export; `annotatetrace` carries the stored `trace` id with its `traceid` plus the required non-empty `annotations` list of `stepid`, `label` and optional `offset` so exported traces never lose their step ids; `replaytrace` carries the stored trace id of a recorded trace and renders the file offline; `capturesourcemaps` carries an optional `scripts` list of reviewed HTTPS urls and needs the per origin source map consent first; profiling kinds also accept `target` and `attachtargets` parameters of the reviewed attach target grammar with the `kind` of page, iframe, worker or serviceworker and the https `url`, and every non page target stays inside the granted origins.
265
- * - the emulation family adds its parameter grammar: `emulatedevice` carries a reviewed `device` preset of `name`, positive integer `width` and `height`, positive `pixelratio` and the `mobile` flag, an optional boolean `reload` flag so the page reloads only when the reviewed plan asks, the explicit `reviewed` flag behind the emulation gate and the required `revertplan` list beside every layer (steps without one are refused at validation and in the proposal parser); `emulatenetwork` carries a reviewed `network` preset of `name`, zero or positive `latency`, `download` and `upload` bounds and the `offline` flag with an optional offline `window` in milliseconds; `emulatelocate` carries a reviewed `location` preset of `name`, a `latitude` inside -90 and 90, a `longitude` inside -180 and 180 and a zero or positive `accuracy` radius behind the per origin location consent with the coordinates shown in the prompt (values out of range are refused in the proposal parser); `setuseragent` carries a reviewed `agent` preset of the `useragent` string of the reviewed grammar, the `platform` and the non-empty `brands` list applied together and scoped to the run tab only; `overridepermission` carries a reviewed `permission` grant of the reviewed browser permission set `name`, the `state` of granted, denied or prompt and the `runscope` flag while the prior state restores at run end (unknown permission names are refused in the proposal parser); `blackboxscripts` carries a reviewed non-empty `rules` list of `urlpatterns` where every pattern names its https origin explicitly with single star segments and double star subtrees plus the `tracescope` of profiles, traces or both, and blackboxing stays read only trace shaping.
266
- * - the session memory family adds its parameter grammar: `persiststate` writes the task state checkpoint of the run with an optional boolean `resume` flag; `capturesession` carries a reviewed `snapshot` plan of the `scope` of tab, run or all, the non-empty `sections` list of the reviewed toggle grammar (`tabs`, `scroll`, `forms`, `storage`, `cookies`), the `captures` link flag and the optional `auto` interval of a positive `period`, a positive `maxsnapshots` count and a zero or positive `expiry` window where every value stays a user choice with no code ceiling; `restoresession` carries the reviewed `sessionid` of the saved record, a reviewed `restore` plan of the `tabpolicy` of reopen or skip, the `formpolicy` of restore or skip and the `capturepolicy` of link or skip, the explicit `reviewed` flag of the restore review and the `origins` list of every origin the record reopens (a restore that reopens an origin outside the grants is refused in the proposal parser, and a restore without the reviewed flag or plan is refused at validation); `namedsessions` carries the reviewed `sessionid`, a unique non-empty `name`, an optional `folder` and an optional `tags` list; `diffsessions` carries the reviewed `left` and `right` ids of two saved sessions; `searchsessions` carries a reviewed `query` of the non-empty `terms` list, the `fields` subset of urls, titles, names and text and the optional `from` and `to` time window; `exportsessions` carries the explicit `reviewed` flag of the export review and an optional non-empty `ids` list of the saved records it packs; `importsessions` carries the explicit `reviewed` flag of the full record review and the reviewed `file` of the known format version with an intact checksum (import files of unknown format versions are refused in the proposal parser).
267
- * - session memory steps attach structured evidence to step details: the session block with the record id and the section counts of a capture, the restored and skipped tab counts of a restore, the match count of a search, the cursor of a persist checkpoint and the byte size of an export; snapshot and restore ids travel in the step result details, and the session report carries every saved record, session event, folder, stored diff and the auto snapshot interval of the run.
268
- * - debugging part three steps attach structured evidence to step details: the profile block with the flow metric count and the memory sample count, the flow durations per step, the heap and cpu profile record ids with their byte, node and sample counts, the layout shift entries with scores and impacted selectors, the trace record with its category list, event count and step annotations, and the source map references with their parsed state; the response envelope gains a profile block, and the profile report carries every flow metric, heap record, growth sample, growth trend, cpu profile, shift entry, trace record and source map reference of the run while the source map consent prompts stay held back.
269
- *
270
- * Workflow kinds add the reviewed grammar of the 1.1.50 family: `composeworkflow` carries the `workflow` payload with its `name`, positive integer `version`, granted HTTPS `origins`, the `steps` list of workflow steps (each with `id`, `kind`, `label` and optional `target`, `value`, `options`, output `bindings`, an inline `expression` and an inline `extract` regex rule) and the reusable `blocks` list (each with a unique lowercase `name`, `label` and child steps or further `{ block, label }` invocations); blocks expand before review so no step stays hidden and the derived `risk` grade marks workflows that write, submit or navigate as sensitive.
271
- * - `savetemplate` carries the `template` payload (a reviewed `name` plus a valid workflow step) shared across workflows.
272
- * - `runworkflow` carries the `workflowid` of a composed workflow, the explicit `reviewed: true` run review flag and the optional `variables` object of string, number or boolean seed values.
273
- * - `dryrun` carries the `workflowid` of a composed workflow and marks the whole run free of side effects.
274
- * - Control flow kinds of the 1.1.51 family carry their reviewed payloads in options: `condition` carries the boolean `expression` tested over the extracted values; `branch` carries the named `paths` with boolean `when` expressions over page state (the snapshot accessor exposes `pageurl`, `pagetitle` and `pageready` variables) and the mandatory `else` path so every branch terminates; `loop` carries the `list` variable with the `item` and `index` variables rebound per iteration, the optional positive `bound` (an absent bound keeps the documented default of one thousand iterations) and the body `steps`; `repeatuntil` carries the convergence `until` expression with its optional `bound` and body; `whileloop` carries the `while` condition, the mandatory positive `bound` and the body — a while loop without a safety bound is refused; `foreach` carries the non-empty `selector`, the `item` and `index` variables and the body; `parallel` carries the uniquely identified `branches` and the `join` policy whose `strategy` is first, last or fail and whose `onfail` is cancel or continue — the join merges conflicting variable writes with the last branch winning under the last strategy, the first branch winning under first and any conflict refusing under fail, cancelled siblings never contribute; `trycatch` carries the fragile body `steps`, the `catch` handler with its optional `rerun`, the optional `retry` policy of user configured `attempts` with no code ceiling, `backoff` of fixed or exponential shape with base and seeded jitter and the `retryable` error classes, and the optional `timeout` policy of positive `stepms` and `runms` budgets whose aborts carry the cancelled error class. Every child step of a control payload must itself be a reviewed action kind and composition grades the whole record by its worst child, so no control construct hides a step or bypasses review; the outcome envelope reports branch outcomes with their reason, loop counters, retry attempts with backoff durations, timeout aborts with the exceeded budget, join records with conflicts and parallel branch outcomes, and the response envelope reports timeout aborts and retry exhaustion distinctly.
275
- * - `delay` carries the `delay` payload with a zero or positive `base` in milliseconds and a zero or positive `jitter` window; no code ceiling applies.
276
- * - `waitelement` carries the `wait` payload with a non-empty `selector`, a zero or positive `timeout` and a zero or positive `poll` interval; no code ceiling applies.
277
- * - `compute` carries the `expression` payload with `left` and optional `right` operands (each a `{ ref }` variable reference or a literal), the `operator` of the reviewed set, the `result` variable name and the `resultkind`.
278
- * - `extractvars` carries the `rule` payload with its `pattern`, `flags` and named capture `groups` beside the reviewed `text`; regex patterns that nest unbounded quantifiers inside quantified groups are refused.
279
- * - Workflow step options may reference scope variables with `${name}` placeholders; the engine refuses references no scope defines.
280
- * - Trigger kinds add the reviewed trigger rule grammar of the 1.1.52 family: every trigger kind (`visitrule`, `urlrule`, `menurule`, `keyrule`, `buttonrule`, `cronrule`, `intervalrule`, `urllistrule`, `webhookrule`, `eventrule`) carries the `workflowid` of the composed workflow it launches, the explicit `reviewed: true` arm review flag, an optional non-empty `label`, an optional positive `cooldown` window in milliseconds with the documented default of the webhook and event families winning when none is configured, and the family `rule` payload: visit rules carry non-empty HTTPS `origins`, url rules carry an HTTPS glob `pattern` where `*` spans one path segment and `**` spans across segments, menu rules carry the context menu entry `title`, key rules carry the lowercase `command` name and optional suggested `key`, button rules carry no match fields, cron rules carry the five field `cron` expression with named weekdays and months and an optional resolvable `timezone`, interval rules carry the positive `period` in milliseconds and optional zero or positive `jitter`, url list rules carry the non-empty HTTPS `urls` list, webhook rules carry the `secret` of at least twenty four characters mixing letters and digits and the `schema` list of `{ name, kind, required }` payload fields, and event rules carry the `events` list of the observed event catalog (mutate, focus, banner, console, error, navigate); the proposal parser refuses rules without the arm review and rules whose match origins stay outside the grants.
281
- * - The agent protocol of the 1.1.54 family documents the mcp tool list and schema grammar: the catalog serves the `browser`, `workflow`, `memory` and `system` namespaces, every tool name carries its namespace prefix so colliding base names stay unambiguous, every tooldef appends its `version` for compatibility checks, every input schema maps the tool inputs to typed json schema properties with required markers and default values, read only tools take their reviewed `target`, `value` and `options` inputs while every tool with side effects takes only the `stepid` of the approved plan step whose reviewed payload it executes, tool descriptions state the consent class and side effects in plain language, and tools with side effects declare their `consentmeta` review requirement; the memory namespace serves its run accessor through the read kind `listruns` with the optional reviewed `state` filter of the listing grammar.
282
- * - The agent protocol frames messages in json rpc: a `jsonrpcframe` carries the `jsonrpc` tag with an `id`, `method` and `params` on requests and the same `id` with either a `result` or an `error` on responses; the wire supports newline delimited blocks and http post envelopes, the error codes are `parse`, `method`, `params`, `internal` and `consentrefused` with `consentrefused` reserved for consent gate refusals, the routing table maps `initialize`, `ping`, `tools/list`, `negotiate` and `tools/call` to their handlers, and capability negotiation exchanges the `protocolversion`, the `toolversion` compatibility floor, the tool count, the namespaces and the allowed `transports` of stdio and http.
283
- * - The fleet identity contract of the 1.1.72 family travels with every envelope: the proposal request carries the `agent` block of the requesting agent's `agentid`, `name` and `role` beside its `budget` state so the reviewer reads who asks and what it already spent, `parseproposal` attributes every step of the plan to its requesting agent and refuses proposals from agents missing from the fleet registry, the escalation message grammar carries `{ agentid, subject, context, stepid }` lifting one stalled agent decision to the user with the hold blocking the raising agent until the human answers, the reviewrequest message grammar carries `{ fromagentid, toagentid, subject, output }` moving one agent output to a peer of the shared origin for review with the `{ verdict, issues }` answer recorded beside the original output, and the consensus response carries the vote records of every agent with the tally, the quorum rule and the outcome while the dissenting reasons stay in the record.
284
- * - The scaled coordination contract of the 1.1.73 family documents the spawn and lane grammar: the `spawnsubagent` request carries `{ parentid, objective, role, narrowscope, depth }` where the parent must sit registered in the fleet, the `depth` must sit exactly one level under the parent lineage depth and never past the user configured depth limit — the boundary refuses the exceeding spawn before any registry write — and the spawn response carries the registered `agentid`, its `name`, its `role`, its `parentid` and its `depth`; the proposal requestbody now includes the active `lanes` of the user configured priority order and the latest `load` reports per origin beside the matching `lessons` of the lessonshare so the endpoint plans inside the lane order, feels the origin loads and reads what the fleet learned; the aggregation response carries the per agent `sections` with their run provenance, the `conflicts` with their resolvers and the open state; the lessonshare payload schema carries each lesson with its `agentid`, its `finding`, its `origin` and its `reusecount`; and the cost ledger report attributes every cost entry to the requesting `agentid` with its `units`, its `runid` and its plain language `description` while the split names each agent's own share beside the peers it shared its costs with.
285
- * - The navigation intelligence contract of the 1.1.74 family documents the navintent prediction schema, the deeplinkpattern grammar and the navigation safety blocks: the navintent prediction schema carries each predicted url with its `confidence` between zero and one ranked by step order and urlhistory frequency, the prediction report envelopes the ranked `predictedurls` under the version so the endpoint reads exactly which pages the approved plan is about to need while navintent and prefetchpage stay read only observations that issue no request of their own; the proposal requestbody now includes the `predictedurls` of the latest navintent pass so the endpoint plans against the predicted pages; `parseproposal` accepts an `intenthint` plain language label on every navigate step so the steps name the predicted navigation they belong to, and it rejects a `batchopen` proposal whose reviewed `urls` list carries an origin outside the grants because a batch never widens the grants; the deeplinkpattern grammar carries `{ app, origin, route, params }` where the `route` template substitutes its named `{name}` parameters from the reviewed step params and the pattern builds only into its granted `origin`; the step results carry the `safety` block with the url, the safe flag and the `reasons` of the checksafeurl verdict so the ui shows why a url opened or refused; and the response envelope carries the `ratelimitwait` block with the domain and the milliseconds a delayed navigation waited inside the sliding window so a rate limited step never drops silently.
286
- * - The data pipelines contract of the 1.1.75 family documents the extractpipeline schema, the transformrule grammar and the pipeline result blocks: the extractpipeline schema carries `{ id, runid, name, source, steps, transforms, sink, dedupe, sample, state, origin }` where the `source` stays the reviewed target the pipeline extracts from, the `steps` list the step ids that drive the extraction, the `transforms` hold the reviewed transform rules applied between extraction and export, the `sink` stays one of csv, json or excel and always flows through the reviewed export machinery, the optional `dedupe` key names its columns with their normalization, the optional `sample` policy names its row count with its strategy and the `origin` binds the pipeline to the site it extracts from; the transformrule grammar pairs a `field` with a reviewed `operation` of `trim`, `case`, `number` or `date` — trim folds the whitespace, case folds the letters, number strips the non numeric shapes and date normalizes to ISO 8601 — while an unknown operation refuses at the protocol boundary before any value reshapes; `parseproposal` accepts a `pipeline` reference in the options of the extract steps (scrapetable, paginateextract, resumeextract, transformvalues, deduperows, stamplerows, previewgrid, streamdisk and logprovenance) so a reviewed step names the extractpipeline its rows flow through, and it rejects a transform of an unknown operation because the pipeline never applies an unreviewed rule; the step results carry the `streamcursor` block with the pipeline id, the row offset and the chunk index of the last written position so an interrupted stream resumes exactly where it stopped; the response envelope carries the `dedupe` report block with the removed and kept counts and the key columns of a dedupe pass, and the `sampledpreview` block records the preview payload as read only — the row count with its strategy and its read only mark — so a sampled preview never grades as a write; the protocol version bumps to carry the pipeline contract.
287
- * - The web api transport contract of the 1.1.76 family documents the widened transport surface: the eventsubscription schema carries `{ id, runid, stepid, url, origin, state, lasteventid, events, names, cancel, lifetime }` where the `cancel` path stays required (`stop` with its value or `lifetime` with its window) so a subscription without a cancellation path refuses at the boundary before any channel opens, and the `lasteventid` persists so a reconnect resumes exactly where the stream stopped; the graphqlsubscription schema carries `{ query, variables, channel }` where the `query` stays the reviewed subscription operation, the `variables` ride the operation and the `channel` names the websocket channel the subscription rides; the longpollrequest grammar carries `{ url, timeout, cursor }` where the `timeout` bounds one request under the user configured backoff and the `cursor` resumes the loop from the stored value, with every bound a user choice with no code default; the multipartfield grammar carries `{ name, filename, contenttype }` building the part headers of one reviewed file of a multipart body while the payload's own `boundary` streams the parts without buffering the whole upload; the proposal requestbody now includes the `correlations` block of the run — the per run request map with its request ids, correlation ids and pair states — so the endpoint sees exactly which outbound requests the run already made; `parseproposal` accepts the transport options on the steps (the `pollrequest` of a longpoll step and the `graphql` subscription of a channel step) and still rejects a subscription without its cancellation path; the step results carry the `cachehit` block with the cache key, the hit count and the served status so a served read names the entry it came from, and the response envelope carries the `correlation` block with the request id, the correlation id and the paired response so every api result answers its request; the protocol version bumps to carry the transport contract.
288
- * - The vision and ocr contract of the 1.1.77 family documents the seeing surface: the ocrresult schema carries `{ id, runid, stepid, imageid, text, words, lines, paragraphs, at }` where every word of `words` carries its `text`, its `box` of the ocrregion grammar `{ x, y, width, height }` in css pixels and its `confidence` between zero and one, the `lines` hold the merged word boxes with the joined text, the covering box and the lowest word confidence, and the `paragraphs` hold the merged line texts — so a recognition answers word by word instead of one opaque blob; the visiondescription schema carries `{ id, runid, stepid, imageid, prompt, text, regions, at }` where the `prompt` stays the reviewed non-empty question the model answers and every region of `regions` carries its plain language `label` with its `box` on the image, so every visual claim traces back to pixels; `parseproposal` accepts the vision options on the extract and capture steps (the `vision` prompt block of a step that sends the capture to the configured vision model and the `ocrregion` of a regionocr reading) and rejects a vision prompt that is not a non-empty string because the model answers exactly what the review asked; the proposal requestbody now includes the `vision` capability report of the run — the available vision kinds with the configured model — so the endpoint sees what the run can see; the step results carry the `grounding` block with the description id and its ranked selectors with their scores so a grounded claim names the element it answered, the `ocr` block with the image id, the word, line and character counts, and the `vision` block with the image id, the description id and the labeled region count; the audit payload carries the redaction masks through the `redactionreport` envelope with the capture id, the masked region count and the plain language reason, so a masked share records exactly what it covered; the protocol version bumps to carry the vision contract.
289
- * - The capture forensics contract of the 1.1.78 family documents the evidence surface: the beforeafterpair schema carries `{ id, runid, stepid, precaptureid, postcaptureid, stepkind, beat, at }` where the `precaptureid` stays absent for a read only step because a page a read never changed needs no before state while both captures link to the `stepid` they wrap; the console trace entry schema carries `{ id, runid, stepid, level, text, source, sequence, reload, beat, at }` where the `sequence` climbs run wide so a page reload never resets the ordering, the `level` classifies errors, warnings and logs by the loglevel grammar and the `source` names the timelinesource the entry came from; the nettraceentry schema carries `{ id, runid, stepid, url, method, status, correlationid, paired, beat, at }` where the `correlationid` joins the request and its response through the correlateids map of the run and a request without its pair stays unjoined so the gap names itself; `parseproposal` accepts the capture options on the capture steps (the `naming` lowercase pattern of the capture filenames, the `pair` mode of `beforeafter`, `post` or `none` around the step, and the `diff` flag that runs the diffshot comparison after a sensitive step) and rejects a naming pattern that is not a non-empty lowercase string because a filename the review never saw names nothing honestly; the proposal requestbody now includes the `diffscore` of the last step so the endpoint plans against the latest visual regression signal; the step results carry the `beforeafter` block with the pre and post capture ids of the step and the `diff` block with the baseline id, the capture id, the similarity score, the changed region count and the regression flag; the audit payload carries the capture names through the capture bundle report, and an export payload without provlog provenance entries for every capture refuses at this boundary because a bundle that cannot answer where its captures came from never leaves the device; the protocol version bumps to carry the forensics contract.
290
- * - The data minimization contract of the 1.1.79 family documents the smallest footprint: the sync payload schema carries `{ version, classes, cipher, formattag, payloadhash, syncedat }` where the `classes` list exactly the data classes the user opted in per class, the `cipher` stays the encrypted envelope the encryptsync pass built from the user passphrase — a payload whose `encrypted` reads false or whose `formattag` sits empty refuses at this boundary because plaintext never transports — and the `payloadhash` names the cipher so the receiving side verifies what left the device; the exportall bundle schema carries `{ id, runs, memory, captures, settings, provenance, records, bytes, at }` where the `runs`, `memory`, `captures` and `provenance` lists name every stored record id the portable file carries, `settings` marks whether the user settings rode along, and the bundle streams through the download flow without a size cap because a bundle the user asked for streams whole; the quarantine verdict schema carries `{ id, path, reason, scan, status, release, at, updatedat }` where the `scan` rides the scanverdict grammar of the security family, the `status` reads held while the verdict waits, released once the verdict reads clean and deleted once it reads flagged, and only a clean verdict ever releases a file; the session records now carry the `jarid` of the cookie jar the run owns so every protocol frame names the jar its cookie state stays scoped to; the requestbody omits every telemetry field by construction — the envelope builds from the reviewed objective, session, observation and capability blocks only, and no telemetry key exists on the wire format at all — so the notelemetry posture holds at the schema level, not by omission at runtime; the audit payload carries the sync consent through the syncconsentreport envelope with the data class and its consent stamp, so every synced class answers when the user opted it in; and the protocol version bumps to carry the minimization contract.
291
- * - The servercontract of the 1.1.82 site integration family documents the site bridge wire: the serverenvelope schema carries `{ version, op, opid, sessionid, token, at, body }` where the `version` is the negotiated servercontract version of the handshake, the `op` is one of the four wire operations `sessioncreate`, `sessionjoin`, `eventpost` and `eventstream`, the `opid` is the stable operation id every reply quotes for correlation, the `sessionid` and `token` carry the frame authentication (the session token rides frames only and never appears in urls or logs) and the `body` carries the operation payload — an envelope that fails this schema rejects at the boundary with the field that named it; the event payloads carry the four event types `chat`, `planproposal`, `planreview` and `progress` where the chat payload carries the human typed task text, the plan proposal payload carries the plan title and the step digest with kinds, origins and sensitive flags, the plan review payload carries the returned decision of approved, changes or refused and the progress payload carries the step id and its status word; the heartbeat rides a progress event on the heartbeat stream so the four operations stay complete with no extra kind; the data minimization holds at the schema level through the bridgepayloadreport — a payload key of page content shape never crosses the bridge without the explicit page consent flag, so plan text and statuses stay the default wire payload; and the relay url stays entirely outside the wire format because the url is the user's setting, never a protocol constant.
292
- * - The stdio bridge relays frames between a local client process and the server through the native messaging host manifest: the bridge launches under the host name of the installed manifest, stamps the process id, relays inbound frames from the client wire and outbound frames back to it, and restarts a dead client process on demand while the http listener binds localhost by default with the bind address, port, transports, frame size and queue depth all user configured with no code ceiling.
293
- * - The provider gateway contract of the 1.1.83 family documents the model provider wire: the gatewaycallreport envelope carries `{ version, requestid, providerid, kind, model, tokens, cost, at }` where the `requestid` correlates every provider call with its audit entry and its usage record across the run, the `kind` names the adapter wire shape (the openai compatible chat completions shape, the anthropic messages shape, the gemini generate content shape or the local ollama runtime), the `tokens` block carries the prompt, completion and total counts and the `cost` answers the user configured price per million tokens; the gateway models never execute tools — a model answer only proposes plan steps the same human review approves before anything runs, the capabilityad advertisement declares the consent requirement of every tool and the plan review gate as a required capability, every key resolves through the vault seam at the last possible moment and never rides a payload, a log or an export, and no provider endpoint is contacted unless the user configured one — the base url of every remote provider stays a user value with no default while the ollamalocal adapter alone defaults to the localhost machine and never to a cloud url; the protocol version bumps to carry the gateway contract.
294
- * - The response envelope carries tool errors with the json rpc error codes: the `tool` block reports the calling client, the namespaced tool name, the origin, the outcome flag and the `code` of the refusal while tool payloads never ride the envelope.
295
- * Ambiguous text, aria or name resolutions are refused at execution time with the candidate list so the user can choose.
296
- */
297
-
298
- /** Validates agent output before it becomes a locally reviewable plan. Plans may carry any number of steps. Fetch requests must target granted origins, channel urls must target granted origins with cancellation paths and bounded lifetimes, and header allowlists must carry non-empty names. */
299
- export function parseproposal(value: unknown, origin: string, grants?: string[], agents?: agentrecord[]): planproposal {
300
- const root = record(value);
301
- if (root.version !== protocolversion) throw new Error("Unsupported protocol version.");
302
- const covered = grants !== undefined && grants.length > 0 ? grants : [origin];
303
- const agentid = typeof root.agentid === "string" && root.agentid.trim() !== "" ? root.agentid.trim() : undefined;
304
- if (agentid !== undefined && agents !== undefined && !agents.some((record) => record.id === agentid))
305
- throw new Error(
306
- `The proposal names the agent ${agentid} which the fleet registry does not carry; every proposal attributes to a registered agent.`,
307
- );
308
- const planinput = record(root.plan);
309
- const stepsinput = planinput.steps;
310
- if (!Array.isArray(stepsinput) || stepsinput.length === 0) throw new Error("A plan needs at least one step.");
311
- const createdat = Date.now();
312
- const expiresat = typeof planinput.expiresat === "number" ? planinput.expiresat : createdat + 10 * 60 * 1000;
313
- if (expiresat <= createdat) throw new Error("Plan expiry must be in the future.");
314
- const planwindow = expiresat - createdat;
315
- const attachinput = stepsinput.map((input) => record(input)).find((candidate) => candidate.kind === "attachcdp");
316
- let planallowlist: cdpallowlist | undefined;
317
- if (attachinput !== undefined) {
318
- const attachoptions = (() => {
319
- try {
320
- return parseoptions({
321
- id: "attach",
322
- kind: "attachcdp",
323
- summary: "attach",
324
- risk: "sensitive",
325
- ...(typeof attachinput.options === "string" ? { options: attachinput.options } : {}),
326
- });
327
- } catch {
328
- return {};
329
- }
330
- })();
331
- const domains = Array.isArray(attachoptions.domains)
332
- ? attachoptions.domains.filter(
333
- (domain): domain is string => typeof domain === "string" && cdpdomains.includes(domain),
334
- )
335
- : [];
336
- const gated = cdpallowlistof(attachoptions.allowlist);
337
- planallowlist =
338
- domains.length > 0 ? { domains, ...(gated?.methods !== undefined ? { methods: gated.methods } : {}) } : undefined;
339
- }
340
- const steps: toolstep[] = stepsinput.map((input, index) => {
341
- const candidate = record(input);
342
- const kind = text(candidate.kind, `step ${index + 1} kind`) as toolstep["kind"];
343
- const step: toolstep = {
344
- id: typeof candidate.id === "string" ? candidate.id : crypto.randomUUID(),
345
- kind,
346
- summary: text(candidate.summary, `step ${index + 1} summary`),
347
- risk: resolvedrisk(stepof(kind, candidate, index)),
348
- ...(typeof candidate.idempotencykey === "string" ? { idempotencykey: candidate.idempotencykey } : {}),
349
- ...(typeof candidate.target === "string" ? { target: candidate.target } : {}),
350
- ...(typeof candidate.value === "string" ? { value: candidate.value } : {}),
351
- ...(typeof candidate.options === "string" ? { options: candidate.options } : {}),
352
- ...(typeof candidate.intenthint === "string" && candidate.intenthint.trim() !== ""
353
- ? { intenthint: candidate.intenthint.trim() }
354
- : {}),
355
- };
356
- if (
357
- step.kind === "scrapetable" ||
358
- step.kind === "paginateextract" ||
359
- step.kind === "resumeextract" ||
360
- step.kind === "transformvalues" ||
361
- step.kind === "deduperows" ||
362
- step.kind === "stamplerows" ||
363
- step.kind === "previewgrid" ||
364
- step.kind === "streamdisk" ||
365
- step.kind === "logprovenance"
366
- ) {
367
- let pipelineoptions: Record<string, unknown> = {};
368
- try {
369
- pipelineoptions = parseoptions(step);
370
- } catch {
371
- pipelineoptions = {};
372
- }
373
- const pipelineref = pipelineoptions.pipeline;
374
- if (pipelineref !== undefined && (typeof pipelineref !== "string" || pipelineref.trim() === ""))
375
- throw new Error(
376
- `The ${step.kind} step names its pipeline reference as the non-empty id of the extractpipeline its rows flow through.`,
377
- );
378
- const pipelinerules = Array.isArray(pipelineoptions.rules) ? pipelineoptions.rules : [];
379
- for (const rule of pipelinerules) {
380
- if (!rule || typeof rule !== "object" || Array.isArray(rule)) continue;
381
- const operation = (rule as Record<string, unknown>).operation;
382
- if (operation === undefined) continue;
383
- if (typeof operation !== "string" || !["trim", "case", "number", "date"].includes(operation))
384
- throw new Error(
385
- `The ${step.kind} proposal carries the transform operation ${String(operation)} which the reviewed transform grammar does not carry; the pipeline refuses an unknown operation before any value reshapes.`,
386
- );
387
- }
388
- const visionoption = pipelineoptions.vision;
389
- if (visionoption !== undefined) {
390
- if (!visionoption || typeof visionoption !== "object" || Array.isArray(visionoption))
391
- throw new Error(
392
- `The ${step.kind} proposal carries its vision block as an object with the reviewed prompt; an opaque vision option refuses at the boundary.`,
393
- );
394
- const visionprompt = (visionoption as Record<string, unknown>).prompt;
395
- if (typeof visionprompt !== "string" || visionprompt.trim() === "")
396
- throw new Error(
397
- `The ${step.kind} proposal carries a vision prompt that is not a non-empty string; the vision model answers exactly what the review asked.`,
398
- );
399
- const visionregion = (visionoption as Record<string, unknown>).ocrregion;
400
- if (
401
- visionregion !== undefined &&
402
- (!visionregion || typeof visionregion !== "object" || Array.isArray(visionregion))
403
- )
404
- throw new Error(
405
- `The ${step.kind} proposal carries its ocrregion as the { x, y, width, height } rectangle of the reviewed grammar; an opaque region refuses at the boundary.`,
406
- );
407
- }
408
- }
409
- if (step.kind === "batchopen") {
410
- let batchoptions: Record<string, unknown> = {};
411
- try {
412
- batchoptions = parseoptions(step);
413
- } catch {
414
- batchoptions = {};
415
- }
416
- const batchurls = Array.isArray(batchoptions.urls)
417
- ? batchoptions.urls.filter((item): item is string => typeof item === "string" && item.trim().length > 0)
418
- : [];
419
- const outsidegrant = batchurls.filter((url) => {
420
- try {
421
- return !covered.some((pattern) => new URL(url).origin === new URL(pattern).origin);
422
- } catch {
423
- return true;
424
- }
425
- });
426
- if (outsidegrant.length > 0)
427
- throw new Error(
428
- `The batchopen proposal carries ${outsidegrant.length} url${outsidegrant.length === 1 ? "" : "s"} outside the grants (${outsidegrant.slice(0, 3).join(", ")}); a batch never widens the origin grants.`,
429
- );
430
- }
431
- if (
432
- step.kind === "shotview" ||
433
- step.kind === "shotfullpage" ||
434
- step.kind === "shotelement" ||
435
- step.kind === "shotregion" ||
436
- step.kind === "contactsheet" ||
437
- step.kind === "captureframe" ||
438
- step.kind === "shotcanvas"
439
- ) {
440
- let captureoptions: Record<string, unknown> = {};
441
- try {
442
- captureoptions = parseoptions(step);
443
- } catch {
444
- captureoptions = {};
445
- }
446
- const captureblock = captureoptions.capture;
447
- if (captureblock !== undefined) {
448
- if (!captureblock || typeof captureblock !== "object" || Array.isArray(captureblock))
449
- throw new Error(
450
- `The ${step.kind} proposal carries its capture block as an object with the reviewed naming pattern, pair mode and diff flag; an opaque capture option refuses at the boundary.`,
451
- );
452
- const capturefields = captureblock as Record<string, unknown>;
453
- const naming = capturefields.naming;
454
- if (naming !== undefined && (typeof naming !== "string" || naming.trim() === ""))
455
- throw new Error(
456
- `The ${step.kind} proposal carries its capture naming pattern as a non-empty lowercase string with the {plan}, {step}, {timestamp} and {sequence} parts; a filename the review never saw names nothing honestly.`,
457
- );
458
- const pairmode = capturefields.pair;
459
- if (pairmode !== undefined && pairmode !== "beforeafter" && pairmode !== "post" && pairmode !== "none")
460
- throw new Error(
461
- `The ${step.kind} proposal carries its capture pair mode as one of beforeafter, post or none; an unknown pair mode never wraps a step.`,
462
- );
463
- const diff = capturefields.diff;
464
- if (diff !== undefined && typeof diff !== "boolean")
465
- throw new Error(
466
- `The ${step.kind} proposal carries its capture diff flag as a boolean; the diffshot comparison runs only when the review asked for it.`,
467
- );
468
- }
469
- }
470
- if (step.kind === "blockrequest") {
471
- let blockoptions: Record<string, unknown> = {};
472
- try {
473
- blockoptions = parseoptions(step);
474
- } catch {
475
- blockoptions = {};
476
- }
477
- const rule = blockruleof(blockoptions.block);
478
- if (rule && patternorigin(rule.urlpattern) === undefined)
479
- throw new Error("Block rules without a named origin pattern are refused.");
480
- }
481
- if (step.kind === "routeproxy") {
482
- let proxyoptions: Record<string, unknown> = {};
483
- try {
484
- proxyoptions = parseoptions(step);
485
- } catch {
486
- proxyoptions = {};
487
- }
488
- const proxy = proxyoptions.proxy;
489
- const bypass =
490
- proxy && typeof proxy === "object" && !Array.isArray(proxy)
491
- ? (proxy as Record<string, unknown>).bypass
492
- : undefined;
493
- if (!Array.isArray(bypass) || bypass.length === 0)
494
- throw new Error("Proxy routes without a bypass list are refused.");
495
- }
496
- if (step.kind === "watchconsole" || step.kind === "watcherrors" || step.kind === "watchtasks") {
497
- let debugoptions: Record<string, unknown> = {};
498
- try {
499
- debugoptions = parseoptions(step);
500
- } catch {
501
- debugoptions = {};
502
- }
503
- const granted = covered.some((pattern) => {
504
- try {
505
- return new URL(origin).origin === new URL(pattern).origin;
506
- } catch {
507
- return false;
508
- }
509
- });
510
- if (!granted) throw new Error(`The ${step.kind} capture of ${origin} targets an origin outside the grants.`);
511
- if (debugoptions.level !== undefined && !loglevels.includes(debugoptions.level as never))
512
- throw new Error(`The reviewed level floor must be one of ${loglevels.join(", ")}.`);
513
- }
514
- if (iscdpkind(step.kind)) {
515
- const granted = covered.some((pattern) => {
516
- try {
517
- return new URL(origin).origin === new URL(pattern).origin;
518
- } catch {
519
- return false;
520
- }
521
- });
522
- if (!granted) throw new Error(`The ${step.kind} step of ${origin} targets an origin outside the grants.`);
523
- let cdpoptions: Record<string, unknown> = {};
524
- try {
525
- cdpoptions = parseoptions(step);
526
- } catch {
527
- cdpoptions = {};
528
- }
529
- if (step.kind === "attachcdp") {
530
- if (teardownplanof(cdpoptions.teardown) === undefined)
531
- throw new Error("Attach steps without a reviewed teardown plan are refused.");
532
- const domains = Array.isArray(cdpoptions.domains)
533
- ? cdpoptions.domains.filter(
534
- (domain): domain is string => typeof domain === "string" && cdpdomains.includes(domain),
535
- )
536
- : [];
537
- if (domains.length === 0)
538
- throw new Error("Attach steps need a non-empty enabled domain list of the reviewed domain grammar.");
539
- const gated = cdpallowlistof(cdpoptions.allowlist);
540
- if (
541
- cdpoptions.allowlist !== undefined &&
542
- (!gated || !gated.domains.every((domain) => domains.includes(domain)))
543
- )
544
- throw new Error("The reviewed method allowlist must stay inside the enabled domains of the attach.");
545
- }
546
- if (step.kind === "cdpcmd") {
547
- const command =
548
- cdpoptions.command && typeof cdpoptions.command === "object" && !Array.isArray(cdpoptions.command)
549
- ? (cdpoptions.command as Record<string, unknown>)
550
- : undefined;
551
- const method = typeof command?.method === "string" ? command.method : "";
552
- if (methoddomain(method) === undefined)
553
- throw new Error("Raw commands need a reviewed method of the Domain.method form.");
554
- if (planallowlist === undefined)
555
- throw new Error("Raw command steps need the attachcdp step of the same plan with its enabled domains first.");
556
- if (!allowlistcovers(planallowlist, method))
557
- throw new Error(`The raw command ${method} stays outside the enabled domain allowlist of the plan attach.`);
558
- }
559
- }
560
- if (isprofilekind(step.kind)) {
561
- const granted = covered.some((pattern) => {
562
- try {
563
- return new URL(origin).origin === new URL(pattern).origin;
564
- } catch {
565
- return false;
566
- }
567
- });
568
- if (!granted) throw new Error(`The ${step.kind} step of ${origin} targets an origin outside the grants.`);
569
- let profileoptions: Record<string, unknown> = {};
570
- try {
571
- profileoptions = parseoptions(step);
572
- } catch {
573
- profileoptions = {};
574
- }
575
- const targets: attachtarget[] = [
576
- ...(attachtargetof(profileoptions.target) !== undefined
577
- ? [attachtargetof(profileoptions.target) as attachtarget]
578
- : []),
579
- ...(Array.isArray(profileoptions.attachtargets)
580
- ? profileoptions.attachtargets.flatMap((target) => {
581
- const parsed = attachtargetof(target);
582
- return parsed !== undefined ? [parsed] : [];
583
- })
584
- : []),
585
- ];
586
- for (const target of targets) {
587
- if (target.kind === "page") continue;
588
- const targetgranted = covered.some((pattern) => {
589
- try {
590
- return new URL(target.url).origin === new URL(pattern).origin;
591
- } catch {
592
- return false;
593
- }
594
- });
595
- if (!targetgranted)
596
- throw new Error(
597
- `The ${target.kind} target ${target.url} of the ${step.kind} step stays outside the granted origins.`,
598
- );
599
- }
600
- if (step.kind === "traceload") {
601
- const trace =
602
- profileoptions.trace && typeof profileoptions.trace === "object" && !Array.isArray(profileoptions.trace)
603
- ? (profileoptions.trace as Record<string, unknown>)
604
- : undefined;
605
- const categories = trace !== undefined && Array.isArray(trace.categories) ? trace.categories : [];
606
- if (categories.some((category): boolean => typeof category !== "string" || !tracecategories.includes(category)))
607
- throw new Error(`Trace categories outside the reviewed list are refused: ${tracecategories.join(", ")}.`);
608
- }
609
- if (step.kind === "capturesourcemaps") {
610
- for (const url of Array.isArray(profileoptions.scripts) ? profileoptions.scripts : []) {
611
- if (typeof url !== "string") continue;
612
- const scriptgranted = covered.some((pattern) => {
613
- try {
614
- return new URL(url).origin === new URL(pattern).origin;
615
- } catch {
616
- return false;
617
- }
618
- });
619
- if (!scriptgranted) throw new Error(`The source map capture of ${url} targets an origin outside the grants.`);
620
- }
621
- }
622
- if (
623
- step.kind === "annotatetrace" &&
624
- (!Array.isArray(profileoptions.annotations) ||
625
- profileoptions.annotations.length === 0 ||
626
- !profileoptions.annotations.every((annotation) => annotationof(annotation) !== undefined))
627
- )
628
- throw new Error("Trace annotation steps without reviewed step annotations are refused.");
629
- }
630
- if (isemulationkind(step.kind)) {
631
- const granted = covered.some((pattern) => {
632
- try {
633
- return new URL(origin).origin === new URL(pattern).origin;
634
- } catch {
635
- return false;
636
- }
637
- });
638
- if (!granted) throw new Error(`The ${step.kind} step of ${origin} targets an origin outside the grants.`);
639
- let emulationoptions: Record<string, unknown> = {};
640
- try {
641
- emulationoptions = parseoptions(step);
642
- } catch {
643
- emulationoptions = {};
644
- }
645
- if (revertplanof(emulationoptions.revertplan) === undefined)
646
- throw new Error("Emulation steps without a reviewed revert plan are refused.");
647
- if (step.kind === "emulatelocate") {
648
- const preset = locationpresetof(emulationoptions.location);
649
- if (preset === undefined)
650
- throw new Error(
651
- "Location emulation needs a reviewed preset with coordinates inside the latitude and longitude ranges.",
652
- );
653
- }
654
- if (step.kind === "overridepermission" && permissiongrantof(emulationoptions.permission) === undefined)
655
- throw new Error("Permission overrides of unknown permission names are refused.");
656
- }
657
- if (issessionkind(step.kind)) {
658
- let sessionoptions: Record<string, unknown> = {};
659
- try {
660
- sessionoptions = parseoptions(step);
661
- } catch {
662
- sessionoptions = {};
663
- }
664
- if (step.kind === "restoresession") {
665
- for (const url of Array.isArray(sessionoptions.origins) ? sessionoptions.origins : []) {
666
- if (typeof url !== "string" || !url) continue;
667
- const granted = covered.some((pattern) => {
668
- try {
669
- return new URL(url).origin === new URL(pattern).origin;
670
- } catch {
671
- return false;
672
- }
673
- });
674
- if (!granted) throw new Error(`The session restore reopens ${url} outside the grants.`);
675
- }
676
- }
677
- if (step.kind === "importsessions" && importsessionfile(sessionoptions.file) === undefined)
678
- throw new Error("Session import files of unknown format versions are refused.");
679
- }
680
- if (isworkflowkind(step.kind)) {
681
- let workflowoptions: Record<string, unknown> = {};
682
- try {
683
- workflowoptions = parseoptions(step);
684
- } catch {
685
- workflowoptions = {};
686
- }
687
- if (step.kind === "composeworkflow") {
688
- const payload =
689
- workflowoptions.workflow &&
690
- typeof workflowoptions.workflow === "object" &&
691
- !Array.isArray(workflowoptions.workflow)
692
- ? (workflowoptions.workflow as Record<string, unknown>)
693
- : undefined;
694
- const origins =
695
- payload && Array.isArray(payload.origins)
696
- ? payload.origins.filter((originvalue): originvalue is string => typeof originvalue === "string")
697
- : [];
698
- for (const workfloworigin of origins) {
699
- const granted = covered.some((pattern) => {
700
- try {
701
- return new URL(workfloworigin).origin === new URL(pattern).origin;
702
- } catch {
703
- return false;
704
- }
705
- });
706
- if (!granted) throw new Error(`The workflow origin ${workfloworigin} stays outside the grants.`);
707
- }
708
- }
709
- if (step.kind === "runworkflow" && workflowoptions.reviewed !== true)
710
- throw new Error("Workflow runs without the explicit run review of the expanded step list are refused.");
711
- }
712
- if (istriggeraction(step.kind)) {
713
- let triggeroptions: Record<string, unknown> = {};
714
- try {
715
- triggeroptions = parseoptions(step);
716
- } catch {
717
- triggeroptions = {};
718
- }
719
- if (triggeroptions.reviewed !== true)
720
- throw new Error(
721
- "Trigger rules without the explicit arm review of their match fields and bound workflow are refused.",
722
- );
723
- for (const ruleorigin of triggerorigins(step)) {
724
- const granted = covered.some((pattern) => {
725
- try {
726
- return new URL(ruleorigin).origin === new URL(pattern).origin;
727
- } catch {
728
- return false;
729
- }
730
- });
731
- if (!granted) throw new Error(`The trigger on ${ruleorigin} stays outside the grants.`);
732
- }
733
- }
734
- const evaluation = validatestep(step, origin);
735
- if (!evaluation.allowed) throw new Error(evaluation.reason);
736
- const target = outboundtarget(step);
737
- if (target !== undefined) {
738
- const granted = covered.some((pattern) => {
739
- try {
740
- return new URL(target).origin === new URL(pattern).origin;
741
- } catch {
742
- return false;
743
- }
744
- });
745
- if (!granted) throw new Error(`The fetch request to ${target} targets an origin outside the grants.`);
746
- }
747
- const channelurl = sockettarget(step);
748
- if (channelurl !== undefined) {
749
- const channeloriginvalue = channeloriginof(channelurl);
750
- const granted = covered.some((pattern) => {
751
- try {
752
- return (
753
- new URL(channelurl).origin === new URL(pattern).origin || channeloriginvalue === new URL(pattern).origin
754
- );
755
- } catch {
756
- return false;
757
- }
758
- });
759
- if (!granted) throw new Error(`The channel to ${channelurl} targets an origin outside the grants.`);
760
- }
761
- let lifetime: number | undefined;
762
- try {
763
- const options = parseoptions(step);
764
- for (const key of ["socket", "subscription"] as const) {
765
- const value = options[key];
766
- if (
767
- value &&
768
- typeof value === "object" &&
769
- !Array.isArray(value) &&
770
- typeof (value as Record<string, unknown>).lifetime === "number"
771
- )
772
- lifetime = (value as Record<string, number>).lifetime;
773
- }
774
- } catch {
775
- lifetime = undefined;
776
- }
777
- if (lifetime !== undefined && lifetime > planwindow)
778
- throw new Error(
779
- `The channel lifetime of ${lifetime} milliseconds exceeds the reviewed plan window of ${planwindow} milliseconds.`,
780
- );
781
- return step;
782
- });
783
- for (const step of steps) {
784
- if (step.kind !== "retryaction" && step.kind !== "enterframe" && step.kind !== "looprows") continue;
785
- const options = parseoptions(step);
786
- if (typeof options.stepid === "string" && !steps.some((candidate) => candidate.id === options.stepid))
787
- throw new Error("A retry, frame or loop wrapper references an unknown step id.");
788
- }
789
- for (const step of steps) {
790
- if (step.kind !== "submitform" && step.kind !== "retryform") continue;
791
- const review = submitreviewgranted(steps, step.id);
792
- if (!review.allowed) throw new Error(review.reason);
793
- }
794
- const plan: agentplan = {
795
- id: typeof planinput.id === "string" ? planinput.id : crypto.randomUUID(),
796
- objective: text(planinput.objective, "objective"),
797
- origin,
798
- steps: agentid !== undefined ? steps.map((step) => ({ ...step, agentid })) : steps,
799
- createdat,
800
- expiresat,
801
- state: "pending",
802
- };
803
- const idempotencykeys = steps.map((step) => step.idempotencykey).filter((key): key is string => key !== undefined);
804
- if (new Set(idempotencykeys).size !== idempotencykeys.length)
805
- throw new Error(
806
- "Two steps of one plan collide on the same idempotencykey; the protocol refuses a plan whose replays could deduplicate the wrong step.",
807
- );
808
- const resumedfrom = Array.isArray(root.resumedfrom)
809
- ? root.resumedfrom.filter((stepid): stepid is string => typeof stepid === "string" && stepid.trim() !== "")
810
- : undefined;
811
- if (resumedfrom !== undefined && resumedfrom.length > 0) {
812
- const known = new Set(steps.map((step) => step.id));
813
- const unknown = resumedfrom.filter((stepid) => !known.has(stepid));
814
- if (unknown.length > 0)
815
- throw new Error(`The resumedfrom marker names step ids the plan does not carry: ${unknown.join(", ")}.`);
816
- return { version: protocolversion, plan, resumedfrom, ...(agentid !== undefined ? { agentid } : {}) };
817
- }
818
- const lockid = typeof root.lockid === "string" && root.lockid.trim() !== "" ? root.lockid : undefined;
819
- if (lockid !== undefined)
820
- return { version: protocolversion, plan, lockid, ...(agentid !== undefined ? { agentid } : {}) };
821
- return { version: protocolversion, plan, ...(agentid !== undefined ? { agentid } : {}) };
822
- }
823
-
824
- /** One workflow proposal envelope: the versioned workflow record with the expanded step list so review sees every step, and the control flow summaries of the control steps so review renders their paths, bounds, branches, join policies and retry and timeout policies. */
825
- export interface workflowproposal {
826
- version: typeof protocolversion;
827
- workflow: workflowrecord;
828
- /** True when the caller proposes a dry run of the workflow free of side effects. */
829
- dryrun?: boolean;
830
- /** Control flow summaries of the control steps of the record so review renders the whole control grammar. */
831
- control?: Array<{ stepid: string; summary: ReturnType<typeof controlsummary> }>;
832
- }
833
-
834
- /** One step outcome entry of a workflow outcome envelope: the step identity, its run state, duration, summary, block context, the bindings produced and consumed and the control flow decision of a control step. */
835
- export interface workflowstepoutcome {
836
- stepid: string;
837
- label: string;
838
- state: runlogentry["state"];
839
- duration: number;
840
- summary: string;
841
- block?: string;
842
- produced?: string[];
843
- consumed?: string[];
844
- checkpoint?: boolean;
845
- /** Control flow decision of a control step: the branch outcome with its reason, the loop counters, the retry attempts, the timeout aborts, the join record and the parallel branch outcomes. */
846
- control?: controlflowdecision;
847
- }
848
-
849
- /** Parses one workflow proposal before it becomes a reviewable workflow record: the version must match, the payload must compose with the expanded block list so no step stays hidden, every step kind must be a reviewed action kind, every workflow origin must stay inside the grants and the review risk grade lands on the record. */
850
- export function parseworkflowproposal(
851
- value: unknown,
852
- origin: string,
853
- grants?: string[],
854
- dryrun?: boolean,
855
- ): workflowproposal {
856
- const root = record(value);
857
- if (root.version !== protocolversion) throw new Error("Unsupported protocol version.");
858
- const covered = grants !== undefined && grants.length > 0 ? grants : [origin];
859
- const candidate = record(root.workflow);
860
- const name = text(candidate.name, "workflow name");
861
- const version =
862
- typeof candidate.version === "number" && Number.isInteger(candidate.version) && candidate.version >= 1
863
- ? candidate.version
864
- : undefined;
865
- if (version === undefined) throw new Error("The workflow version must be a positive integer.");
866
- const origins = Array.isArray(candidate.origins) ? candidate.origins : [];
867
- if (
868
- origins.length === 0 ||
869
- !origins.every(
870
- (workfloworigin): workfloworigin is string =>
871
- typeof workfloworigin === "string" && workfloworigin.startsWith("https://"),
872
- )
873
- )
874
- throw new Error("The workflow needs at least one granted HTTPS origin.");
875
- for (const workfloworigin of origins) {
876
- const granted = covered.some((pattern) => {
877
- try {
878
- return new URL(workfloworigin).origin === new URL(pattern).origin;
879
- } catch {
880
- return false;
881
- }
882
- });
883
- if (!granted) throw new Error(`The workflow origin ${workfloworigin} stays outside the grants.`);
884
- }
885
- const steps = Array.isArray(candidate.steps) ? candidate.steps : [];
886
- if (steps.length === 0) throw new Error("A workflow proposal needs at least one step or block invocation.");
887
- const blocks = Array.isArray(candidate.blocks)
888
- ? candidate.blocks.flatMap((block) =>
889
- workflowblockof(block) !== undefined ? [workflowblockof(block) as import("./types.js").workflowblock] : [],
890
- )
891
- : [];
892
- if (Array.isArray(candidate.blocks) && blocks.length !== (candidate.blocks as unknown[]).length)
893
- throw new Error("The reviewed block list must carry unique lowercase names, labels and valid child steps.");
894
- const composed = composeworkflow({
895
- name,
896
- version,
897
- origins,
898
- steps: steps.map((entry) => {
899
- const step = workflowstepof(entry);
900
- if (step) return step;
901
- const invocation = blockinvocationof(entry);
902
- if (invocation) return invocation;
903
- throw new Error("Every workflow entry must be a reviewed step or a block invocation.");
904
- }),
905
- blocks,
906
- now: Date.now(),
907
- kindallowed: (kind) => {
908
- try {
909
- actionrisk(kind as import("./types.js").actionkind);
910
- return true;
911
- } catch {
912
- return false;
913
- }
914
- },
915
- riskof: (kind) => actionrisk(kind as import("./types.js").actionkind),
916
- });
917
- const inputs = Array.isArray(candidate.inputs)
918
- ? candidate.inputs.flatMap((inputname) => (typeof inputname === "string" ? [inputname] : []))
919
- : undefined;
920
- const checked = validateworkflow(composed, {
921
- kindallowed: (kind) => {
922
- try {
923
- actionrisk(kind as import("./types.js").actionkind);
924
- return true;
925
- } catch {
926
- return false;
927
- }
928
- },
929
- ...(inputs !== undefined ? { inputs } : {}),
930
- });
931
- if (!checked.allowed) throw new Error(checked.reason ?? "The workflow proposal failed its validation.");
932
- const control = composed.steps.flatMap((step) => {
933
- const summary = controlsummary(step);
934
- return summary !== undefined ? [{ stepid: step.id, summary }] : [];
935
- });
936
- return {
937
- version: protocolversion,
938
- workflow: composed,
939
- ...(dryrun === true ? { dryrun: true } : {}),
940
- ...(control.length > 0 ? { control } : {}),
941
- };
942
- }
943
-
944
- /** Builds the workflow outcome envelope of one run: the run id, workflow id, state and dry run flag beside the step outcome list with the control flow decisions of the control steps; a single step outcome travels through the same envelope for debugging callers. */
945
- export function workflowoutcome(input: { run: workflowrun; entries: runlogentry[]; stepid?: string }): {
946
- version: typeof protocolversion;
947
- runid: string;
948
- workflowid: string;
949
- state: string;
950
- dryrun?: boolean;
951
- steps: workflowstepoutcome[];
952
- } {
953
- const selected =
954
- input.stepid !== undefined ? input.entries.filter((entry) => entry.stepid === input.stepid) : input.entries;
955
- const steps: workflowstepoutcome[] = selected.map((entry) => ({
956
- stepid: entry.stepid,
957
- label: entry.label,
958
- state: entry.state,
959
- duration: entry.duration,
960
- summary: entry.summary,
961
- ...(entry.block !== undefined ? { block: entry.block } : {}),
962
- ...(entry.produced !== undefined ? { produced: entry.produced } : {}),
963
- ...(entry.consumed !== undefined ? { consumed: entry.consumed } : {}),
964
- ...(entry.checkpoint === true ? { checkpoint: true } : {}),
965
- ...(entry.details !== undefined && entry.details.control !== undefined
966
- ? { control: entry.details.control as controlflowdecision }
967
- : {}),
968
- }));
969
- return {
970
- version: protocolversion,
971
- runid: input.run.id,
972
- workflowid: input.run.workflowid,
973
- state: input.run.state,
974
- ...(input.run.dryrun === true ? { dryrun: true } : {}),
975
- steps,
976
- };
977
- }
978
-
979
- /** Builds one tool step from a raw candidate without its risk grade so resolvedrisk can read the reviewed options of conditional kinds. */
980
- function stepof(kind: toolstep["kind"], candidate: Record<string, unknown>, index: number): toolstep {
981
- return {
982
- id: typeof candidate.id === "string" ? candidate.id : `candidate${index + 1}`,
983
- kind,
984
- summary: typeof candidate.summary === "string" ? candidate.summary : "",
985
- risk: "read",
986
- ...(typeof candidate.options === "string" ? { options: candidate.options } : {}),
987
- };
988
- }
989
-
990
- /** Resolves the https origin behind a channel url so grants cover wss websocket channels and https event streams alike. */
991
- function channeloriginof(url: string): string {
992
- try {
993
- const parsed = new URL(url);
994
- return `${parsed.protocol === "wss:" ? "https:" : parsed.protocol}//${parsed.host}`;
995
- } catch {
996
- return "";
997
- }
998
- }
999
-
1000
- /** Shapes the only data that may be sent to a user-configured agent endpoint; the 1.1.70 family adds the live runstate and the offline queue depth so the agent context sees the run machine it replays into, the 1.1.71 family adds the isolated tab namespace id and the provenance of the observations so the endpoint sees the tab the run owns and where every observation came from, the 1.1.73 family adds the active priority lanes, the latest load reports per origin and the matching lessonshare records so the endpoint plans inside the lane order the user configured, feels the load of every origin and reads the lessons the fleet already learned, the 1.1.74 family adds the predicted next urls of the latest navintent pass so the endpoint plans against the pages the approved plan is about to need, the 1.1.76 family adds the correlations block of the run — the per run request map with its request ids, correlation ids and pair states — so the endpoint sees exactly which outbound requests the run already made, the 1.1.77 family adds the vision capability report of the run — the available vision kinds with the configured vision model — so the endpoint sees what the run can see, the 1.1.78 family adds the diff score of the last step so the endpoint plans against the latest visual regression signal the forensics measured, and the 1.1.79 family keeps the envelope telemetry free by construction — no telemetry key exists on this wire format at all, the session block rides with its jarid so the endpoint sees the cookie jar the run scopes to, and a payload that carries a localrule field refuses before the transport because a field marked local never leaves the device. */
1001
- export function requestbody(
1002
- input: proposalrequest & {
1003
- runstate?: string;
1004
- queuedepth?: number;
1005
- tabnamespace?: string;
1006
- provenance?: memoryprovenance[];
1007
- agent?: { agentid: string; name: string; role: string };
1008
- budget?: budgetstate;
1009
- lanes?: tasklane[];
1010
- load?: loadreport[];
1011
- lessons?: lessonrecord[];
1012
- predictedurls?: string[];
1013
- correlations?: Array<{
1014
- requestid: string;
1015
- correlationid: string;
1016
- method: string;
1017
- url: string;
1018
- paired: boolean;
1019
- status?: number;
1020
- }>;
1021
- vision?: { kinds: string[]; model?: string };
1022
- diffscore?: number;
1023
- },
1024
- ): string {
1025
- const body: Record<string, unknown> = {
1026
- version: protocolversion,
1027
- objective: input.objective,
1028
- session: input.session,
1029
- observation: input.observation,
1030
- capabilities: input.capabilities,
1031
- ...(input.runstate !== undefined ? { runstate: input.runstate } : {}),
1032
- ...(input.queuedepth !== undefined ? { queuedepth: input.queuedepth } : {}),
1033
- ...(input.tabnamespace !== undefined ? { tabnamespace: input.tabnamespace } : {}),
1034
- ...(input.provenance !== undefined ? { provenance: input.provenance } : {}),
1035
- ...(input.agent !== undefined ? { agent: input.agent } : {}),
1036
- ...(input.budget !== undefined ? { budget: input.budget } : {}),
1037
- ...(input.lanes !== undefined ? { lanes: input.lanes } : {}),
1038
- ...(input.load !== undefined ? { load: input.load } : {}),
1039
- ...(input.lessons !== undefined ? { lessons: input.lessons } : {}),
1040
- ...(input.predictedurls !== undefined ? { predictedurls: input.predictedurls } : {}),
1041
- ...(input.correlations !== undefined ? { correlations: input.correlations } : {}),
1042
- ...(input.vision !== undefined ? { vision: input.vision } : {}),
1043
- ...(input.diffscore !== undefined ? { diffscore: input.diffscore } : {}),
1044
- };
1045
- return JSON.stringify(body);
1046
- }
1047
-
1048
- /** Wraps one fleet consensus record with its votes, tally and outcome in the versioned response envelope: every vote record travels with its dissenting reason so the reviewer reads who voted what. */
1049
- export function consensusreport(input: { record: consensusrecord }): {
1050
- version: typeof protocolversion;
1051
- proposal: string;
1052
- votes: consensusrecord["votes"];
1053
- tally: consensusrecord["tally"];
1054
- quorum: number;
1055
- outcome: string;
1056
- } {
1057
- return {
1058
- version: protocolversion,
1059
- proposal: input.record.proposal,
1060
- votes: input.record.votes,
1061
- tally: input.record.tally,
1062
- quorum: input.record.quorum,
1063
- outcome: input.record.outcome,
1064
- };
1065
- }
1066
-
1067
- /** Parses one spawnsubagent request of the 1.1.73 family grammar `{ parentid, objective, role, narrowscope, depth }` against the fleet registry and the user configured depth limit: the parent must sit registered in the fleet, the objective stays the plain language task the parent hands over, an optional `narrowscope` of `origins` and `actionkinds` keeps only the parent grants it names, and the `depth` must sit at exactly the parent lineage depth plus one and never past the configured limit — a spawn whose depth exceeds the limit refuses at the protocol boundary before any registry write. */
1068
- export function parsespawnrequest(
1069
- input: unknown,
1070
- limit: depthlimit,
1071
- agents: agentrecord[],
1072
- spawns: spawnrecord[],
1073
- ): { spec: subagentspec; parent: agentrecord } {
1074
- const root = input as {
1075
- parentid?: string;
1076
- objective?: string;
1077
- role?: string;
1078
- narrowscope?: { origins?: string[]; actionkinds?: string[] };
1079
- depth?: number;
1080
- };
1081
- const parentid = root.parentid?.trim() ?? "";
1082
- if (parentid === "")
1083
- throw new Error("The spawn request names its parent agentid; every spawned child carries its lineage.");
1084
- const parent = agents.find((record) => record.id === parentid);
1085
- if (!parent)
1086
- throw new Error(
1087
- `The spawn request names the parent ${parentid} which the fleet registry does not carry; the protocol boundary refuses unknown agents.`,
1088
- );
1089
- const objective = root.objective?.trim() ?? "";
1090
- if (objective === "")
1091
- throw new Error(
1092
- "The spawn request needs its parent objective in plain language; the child works on what its parent handed over.",
1093
- );
1094
- const depth = root.depth;
1095
- if (depth === undefined || !Number.isInteger(depth) || depth <= 0)
1096
- throw new Error("The spawn request carries its depth as a positive whole number of the lineage.");
1097
- if (limit.maxdepth !== undefined && depth > limit.maxdepth)
1098
- throw new Error(
1099
- `The spawn request depth ${depth} exceeds the user configured depth limit ${limit.maxdepth}; the protocol boundary refuses the spawn before any registry write.`,
1100
- );
1101
- const seen = new Set<string>([parentid]);
1102
- let lineage = parentid;
1103
- let parentdepth = 0;
1104
- for (;;) {
1105
- const spawn = spawns.find((entry) => entry.childid === lineage);
1106
- if (spawn === undefined) break;
1107
- if (seen.has(spawn.parentid))
1108
- throw new Error(
1109
- `The spawn lineage of the parent ${parentid} carries a cycle at ${spawn.parentid}; the protocol boundary refuses a looping lineage.`,
1110
- );
1111
- seen.add(spawn.parentid);
1112
- lineage = spawn.parentid;
1113
- parentdepth += 1;
1114
- }
1115
- if (depth !== parentdepth + 1)
1116
- throw new Error(
1117
- `The spawn request depth ${depth} must sit exactly one level under the parent lineage depth ${parentdepth}.`,
1118
- );
1119
- const spec: subagentspec = { parentid, objective, depth };
1120
- if (root.role !== undefined && root.role.trim() !== "") spec.role = root.role.trim() as agentrole;
1121
- if (root.narrowscope !== undefined) spec.narrowscope = root.narrowscope;
1122
- return { spec, parent };
1123
- }
1124
-
1125
- /** Wraps one spawnsubagent result in the versioned response envelope: the response carries the registered child beside its `parentid` and its `depth` so the caller reads exactly where the child sits in the lineage. */
1126
- export function spawnreply(input: { child: agentrecord; parentid: string; depth: number }): {
1127
- version: typeof protocolversion;
1128
- agentid: string;
1129
- name: string;
1130
- role: string;
1131
- parentid: string;
1132
- depth: number;
1133
- } {
1134
- return {
1135
- version: protocolversion,
1136
- agentid: input.child.id,
1137
- name: input.child.name,
1138
- role: input.child.role,
1139
- parentid: input.parentid,
1140
- depth: input.depth,
1141
- };
1142
- }
1143
-
1144
- /** Wraps one merged aggregaterecord in the versioned response envelope: the report carries the per agent sections with their run provenance, the conflicts with their resolvers and the open state so the reviewer reads exactly which parallel outputs merged and which conflicts wait for the escalation. */
1145
- export function aggregationreport(input: { record: aggregaterecord }): {
1146
- version: typeof protocolversion;
1147
- subject: string;
1148
- sections: aggregaterecord["cells"];
1149
- conflicts: aggregaterecord["conflicts"];
1150
- state: string;
1151
- } {
1152
- return {
1153
- version: protocolversion,
1154
- subject: input.record.subject,
1155
- sections: input.record.cells,
1156
- conflicts: input.record.conflicts,
1157
- state: input.record.state,
1158
- };
1159
- }
1160
-
1161
- /** Wraps the served lessonshare matches in the versioned response envelope: the lessonshare payload schema carries each `lessonrecord` with its `agentid`, its `finding`, its `origin` and its `reusecount` so the receiving agent reads what the fleet learned, where it learned it and how often the lesson served. */
1162
- export function lessonreport(input: { lessons: lessonrecord[] }): {
1163
- version: typeof protocolversion;
1164
- lessons: Array<{
1165
- id: string;
1166
- agentid: string;
1167
- finding: string;
1168
- origin: string;
1169
- reusecount: number;
1170
- lastusedat?: number;
1171
- }>;
1172
- } {
1173
- return {
1174
- version: protocolversion,
1175
- lessons: input.lessons.map((lesson) => ({
1176
- id: lesson.id,
1177
- agentid: lesson.agentid,
1178
- finding: lesson.finding,
1179
- origin: lesson.origin,
1180
- reusecount: lesson.reusecount,
1181
- ...(lesson.lastusedat !== undefined ? { lastusedat: lesson.lastusedat } : {}),
1182
- })),
1183
- };
1184
- }
1185
-
1186
- /** Wraps the shared cost ledger in the versioned response envelope: every cost entry travels attributed to the `agentid` that requested it with its `units`, its `runid` and its plain language `description`, and the split report names each agent's own share beside the peers it shared its costs with. */
1187
- /** Wraps one redactionmask of the 1.1.77 family in the versioned audit payload: the capture it covered, the region count it masked and its plain language reason travel together so the audit trail records exactly what a shared capture hid while the image bytes and the region payloads never ride the envelope. */
1188
- export function redactionreport(input: {
1189
- mask: {
1190
- captureid: string;
1191
- regions: Array<{ x: number; y: number; width: number; height: number }>;
1192
- reason: string;
1193
- source: string;
1194
- at: number;
1195
- };
1196
- }): {
1197
- version: typeof protocolversion;
1198
- captureid: string;
1199
- regions: number;
1200
- reason: string;
1201
- source: string;
1202
- at: number;
1203
- } {
1204
- return {
1205
- version: protocolversion,
1206
- captureid: input.mask.captureid,
1207
- regions: input.mask.regions.length,
1208
- reason: input.mask.reason,
1209
- source: input.mask.source,
1210
- at: input.mask.at,
1211
- };
1212
- }
1213
-
1214
- /** Wraps one capturebundle of the 1.1.78 family in the versioned audit payload: the capture names, the timeline counts, the diff and thumbnail references and the provenance entry count travel together while the capture bytes never ride the envelope, and an export payload whose captures carry no provlog provenance entries refuses at this boundary because a bundle that cannot answer where its captures came from never leaves the device. */
1215
- export function capturebundlereport(input: {
1216
- bundle: {
1217
- runid: string;
1218
- captures: string[];
1219
- names: Array<{ captureid: string; name: string }>;
1220
- consoleentries: number;
1221
- netentries: number;
1222
- diffs: string[];
1223
- thumbnails: string[];
1224
- lapses: string[];
1225
- provenance: string[];
1226
- masked: boolean;
1227
- at: number;
1228
- };
1229
- }): {
1230
- version: typeof protocolversion;
1231
- runid: string;
1232
- captures: number;
1233
- names: Array<{ captureid: string; name: string }>;
1234
- consoleentries: number;
1235
- netentries: number;
1236
- diffs: number;
1237
- thumbnails: number;
1238
- lapses: number;
1239
- provenance: number;
1240
- masked: boolean;
1241
- at: number;
1242
- } {
1243
- const covered = new Set(input.bundle.provenance);
1244
- if (input.bundle.captures.length > 0 && (input.bundle.provenance.length === 0 || covered.size === 0))
1245
- throw new Error(
1246
- `The capture bundle of the run ${input.bundle.runid} carries ${input.bundle.captures.length} capture${input.bundle.captures.length === 1 ? "" : "s"} with no provlog provenance entries; an export payload without provenance never leaves the device.`,
1247
- );
1248
- if (!input.bundle.masked)
1249
- throw new Error(
1250
- `The capture bundle of the run ${input.bundle.runid} assembles only after the redactshot masks ran over its captures; an unmasked capture never exports.`,
1251
- );
1252
- return {
1253
- version: protocolversion,
1254
- runid: input.bundle.runid,
1255
- captures: input.bundle.captures.length,
1256
- names: input.bundle.names,
1257
- consoleentries: input.bundle.consoleentries,
1258
- netentries: input.bundle.netentries,
1259
- diffs: input.bundle.diffs.length,
1260
- thumbnails: input.bundle.thumbnails.length,
1261
- lapses: input.bundle.lapses.length,
1262
- provenance: input.bundle.provenance.length,
1263
- masked: input.bundle.masked,
1264
- at: input.bundle.at,
1265
- };
1266
- }
1267
-
1268
- /** Wraps one sync payload of the 1.1.79 family in the versioned envelope: the classes the user opted in, the format tag, the payload hash and the sync time travel together while the cipher text stays opaque and the passphrase never rides the envelope — a payload that reads plaintext or carries no format tag refuses at this boundary because plaintext never transports. */
1269
- export function syncpayloadreport(input: {
1270
- classes: string[];
1271
- payloadhash: string;
1272
- formattag: string;
1273
- encrypted: boolean;
1274
- syncedat: number;
1275
- }): {
1276
- version: typeof protocolversion;
1277
- classes: string[];
1278
- payloadhash: string;
1279
- formattag: string;
1280
- encrypted: true;
1281
- syncedat: number;
1282
- } {
1283
- if (!input.encrypted)
1284
- throw new Error(
1285
- "The sync payload ships plaintext; every payload encrypts with the user passphrase before the transport.",
1286
- );
1287
- if (input.formattag.trim() === "")
1288
- throw new Error(
1289
- "The sync payload carries no format version tag; an envelope that cannot name its format answers no decoder.",
1290
- );
1291
- if (input.classes.length === 0)
1292
- throw new Error(
1293
- "The sync payload names the data classes it carries; a payload without classes answers no consent.",
1294
- );
1295
- return {
1296
- version: protocolversion,
1297
- classes: input.classes,
1298
- payloadhash: input.payloadhash,
1299
- formattag: input.formattag,
1300
- encrypted: true,
1301
- syncedat: input.syncedat,
1302
- };
1303
- }
1304
-
1305
- /** Wraps one exportall bundle of the 1.1.79 family in the versioned envelope: the record ids of every stored family — runs, memory, captures and provenance — ride with the settings marker, the record count and the byte size, and the bundle streams through the download flow without a size cap because a bundle the user asked for streams whole. */
1306
- export function exportallreport(input: {
1307
- bundle: {
1308
- runs: string[];
1309
- memory: string[];
1310
- captures: string[];
1311
- settings: boolean;
1312
- provenance: string[];
1313
- records: number;
1314
- bytes: number;
1315
- at: number;
1316
- };
1317
- }): {
1318
- version: typeof protocolversion;
1319
- runs: number;
1320
- memory: number;
1321
- captures: number;
1322
- settings: boolean;
1323
- provenance: number;
1324
- records: number;
1325
- bytes: number;
1326
- at: number;
1327
- } {
1328
- return {
1329
- version: protocolversion,
1330
- runs: input.bundle.runs.length,
1331
- memory: input.bundle.memory.length,
1332
- captures: input.bundle.captures.length,
1333
- settings: input.bundle.settings,
1334
- provenance: input.bundle.provenance.length,
1335
- records: input.bundle.records,
1336
- bytes: input.bundle.bytes,
1337
- at: input.bundle.at,
1338
- };
1339
- }
1340
-
1341
- /** Wraps one quarantine verdict of the 1.1.79 family in the versioned envelope: the path, the scan verdict, the lifecycle status and the release ref travel together while only a clean verdict ever releases — a held or flagged file never opens, and the entry carries its verdict for the audit trail. */
1342
- export function quarantineverdictreport(input: {
1343
- entry: {
1344
- id: string;
1345
- path: string;
1346
- reason: string;
1347
- scan: string;
1348
- status: string;
1349
- release?: string;
1350
- at: number;
1351
- updatedat: number;
1352
- };
1353
- }): {
1354
- version: typeof protocolversion;
1355
- id: string;
1356
- path: string;
1357
- reason: string;
1358
- scan: string;
1359
- status: string;
1360
- released: boolean;
1361
- at: number;
1362
- updatedat: number;
1363
- } {
1364
- if (input.entry.status === "released" && input.entry.scan !== "clean")
1365
- throw new Error("Only a clean scanner verdict releases a quarantined file; a held or flagged file never opens.");
1366
- return {
1367
- version: protocolversion,
1368
- id: input.entry.id,
1369
- path: input.entry.path,
1370
- reason: input.entry.reason,
1371
- scan: input.entry.scan,
1372
- status: input.entry.status,
1373
- released: input.entry.status === "released",
1374
- at: input.entry.at,
1375
- updatedat: input.entry.updatedat,
1376
- };
1377
- }
1378
-
1379
- /** Wraps one sync consent of the 1.1.79 family in the versioned audit payload: the data class and the consent stamp of every opted in class travel together so the audit trail answers exactly when the user enabled each class, because a synced class without its consent stamp answers no review. */
1380
- export function syncconsentreport(input: { consent: Array<{ dataclass: string; at: number }> }): {
1381
- version: typeof protocolversion;
1382
- consent: Array<{ dataclass: string; at: number }>;
1383
- count: number;
1384
- } {
1385
- const seen = new Set<string>();
1386
- for (const entry of input.consent) {
1387
- const key = entry.dataclass.toLowerCase();
1388
- if (key.trim() === "")
1389
- throw new Error("The sync consent names its data class; an unnamed class answers no consent.");
1390
- if (seen.has(key))
1391
- throw new Error(
1392
- `The sync consent carries the data class ${entry.dataclass} twice; one class answers one consent stamp.`,
1393
- );
1394
- seen.add(key);
1395
- }
1396
- return { version: protocolversion, consent: input.consent, count: input.consent.length };
1397
- }
1398
-
1399
- /** Checks one outbound payload of the 1.1.79 family against the local rule fields: a payload that carries a field the user marked local refuses at this protocol boundary before any transport — the request body, the sync payload or the export — because a field marked local never leaves the device. */
1400
- export function outboundpayloadcheck(input: { payload: Record<string, unknown>; localfields: string[] }): {
1401
- ok: true;
1402
- reason: string;
1403
- } {
1404
- const keys = Object.keys(input.payload).map((key) => key.trim().toLowerCase());
1405
- const carried = input.localfields
1406
- .map((field) => field.trim().toLowerCase())
1407
- .filter((field) => field !== "" && keys.includes(field));
1408
- if (carried.length > 0)
1409
- throw new Error(
1410
- `The outbound payload carries the local rule field${carried.length === 1 ? "" : "s"} ${carried.join(", ")}; a field marked local never leaves the device.`,
1411
- );
1412
- return {
1413
- ok: true,
1414
- reason: "The outbound payload carries no local rule field; every field marked local stayed on the device.",
1415
- };
1416
- }
1417
-
1418
- export function costledgerreport(input: {
1419
- entries: costentry[];
1420
- split: Array<{ agentid: string; units: number; share: number; sharedwith?: string[] }>;
1421
- }): {
1422
- version: typeof protocolversion;
1423
- entries: costentry[];
1424
- split: Array<{ agentid: string; units: number; share: number; sharedwith?: string[] }>;
1425
- } {
1426
- return {
1427
- version: protocolversion,
1428
- entries: input.entries.map((entry) => ({
1429
- agentid: entry.agentid,
1430
- ...(entry.runid !== undefined ? { runid: entry.runid } : {}),
1431
- units: entry.units,
1432
- description: entry.description,
1433
- at: entry.at,
1434
- })),
1435
- split: input.split,
1436
- };
1437
- }
1438
-
1439
- /** Wraps one navintent prediction pass in the versioned response envelope: the report carries the ranked predicted urls with their confidence between zero and one so the endpoint and the sidepanel read exactly which pages the approved plan is about to need; the predictions grade read only and issue no request of their own. */
1440
- export function predictionreport(input: { plan: prefetchplan }): {
1441
- version: typeof protocolversion;
1442
- predictedurls: prefetchplan["predictedurls"];
1443
- createdat: number;
1444
- } {
1445
- return { version: protocolversion, predictedurls: input.plan.predictedurls, createdat: input.plan.createdat };
1446
- }
1447
-
1448
- /** Wraps one executed step outcome in the versioned response envelope for callers, returning the execution environment beside the outcome, attaching the matched element summary, the capture block of capture steps, the media block of media steps, the transport block of outbound calls, the network block of observed exchanges and channels, the control block of applied traffic rules, the timeline block of debugging steps, the cdp block of devtools protocol steps, the profile block of profiling steps, the emulation block with the applied and reverted layer names and the session block with the record id and section counts of session memory steps; the 1.1.70 family carries the runid and the live runstate so a replay maps to its run and every caller sees the machine state, the 1.1.74 family carries the safety block with the checksafeurl verdict reasons and the ratelimitwait block with the domain and the milliseconds a delayed navigation waited so a rate limited step never drops silently, the 1.1.75 family carries the streamcursor block with the pipeline id, the row offset and the chunk index of the last written position, the dedupe report block with the removed and kept counts and the key columns, and the sampledpreview block that records the preview payload as read only, and the 1.1.76 family carries the correlation block with the request id, the correlation id and the paired response so every api result answers its request, the cachehit block with the cache key, the hit count and the served status so a served read names the entry it came from, and the 1.1.77 family carries the ocr block with the image id, the word, line and character counts of a recognition, the vision block with the image id, the description id, the labeled region count and the model that answered, and the grounding block with the description id and its ranked selectors with their scores so every grounded visual claim names the page element it answered, and the 1.1.78 family carries the beforeafter block with the pre and post capture ids of the step so every executed step names the states it wrapped, and the diff block with the baseline id, the capture id, the similarity score, the changed region count and the regression flag so a compared step names exactly what changed. */
1449
- export function outcomeresponse(input: {
1450
- outcome: stepoutcome;
1451
- plan: agentplan;
1452
- resolvedtarget?: resolvedtarget;
1453
- runid?: string;
1454
- runstate?: string;
1455
- capture?: { id: string; format: string; bytes: number };
1456
- media?: { id: string; kind: string; bytes: number };
1457
- transport?: { status: number; headers: string[]; bytes: number; duration: number };
1458
- network?: { exchanges: number; channelstate: string; messages: number };
1459
- control?: { applied: number; blocked: number; mocked: number };
1460
- timeline?: { entries: number; levels: Record<string, number>; collapsed: number };
1461
- cdp?: { sessionid: string; state: string; commandids: string[] };
1462
- profile?: { metrics: number; samples: number };
1463
- emulation?: { applied: string[]; reverted: string[] };
1464
- session?: {
1465
- recordid: string;
1466
- sections: number;
1467
- matches?: number;
1468
- restored?: number;
1469
- skipped?: number;
1470
- cursor?: number;
1471
- bytes?: number;
1472
- };
1473
- workflow?: {
1474
- runid: string;
1475
- state: string;
1476
- dryrun?: boolean;
1477
- produced: string[];
1478
- consumed: string[];
1479
- timeout?: timeoutabort;
1480
- retry?: { stepid: string; attempts: number; exhausted: boolean };
1481
- };
1482
- trigger?: { ruleid: string; kind: string; enabled: boolean; nextfireat?: number };
1483
- tool?: { clientid: string; tool: string; origin: string; ok: boolean; code?: rpcerrorcode };
1484
- safety?: { url: string; safe: boolean; reasons: string[] };
1485
- ratelimitwait?: { domain: string; waitedms: number };
1486
- streamcursor?: { pipelineid: string; offset: number; chunk: number; updatedat: number };
1487
- dedupe?: { removed: number; kept: number; keys: string[] };
1488
- sampledpreview?: { rows: number; strategy: string; readonly: true };
1489
- correlation?: {
1490
- requestid: string;
1491
- correlationid: string;
1492
- responseid?: string;
1493
- status?: number;
1494
- method: string;
1495
- url: string;
1496
- };
1497
- cachehit?: { key: string; hits: number; status: number; url: string };
1498
- ocr?: { imageid: string; words: number; lines: number; characters: number };
1499
- vision?: { imageid: string; descriptionid: string; regions: number; model: string };
1500
- grounding?: { descriptionid: string; selectors: Array<{ selector: string; score: number }> };
1501
- beforeafter?: { stepid: string; preid?: string; postid?: string; stepkind: string };
1502
- diff?: { baselineid: string; captureid: string; score: number; regions: number; regression: boolean };
1503
- }): string {
1504
- return JSON.stringify({
1505
- version: protocolversion,
1506
- planid: input.plan.id,
1507
- planstate: input.plan.state,
1508
- outcome: input.outcome,
1509
- ...(input.runid !== undefined ? { runid: input.runid } : {}),
1510
- ...(input.runstate !== undefined ? { runstate: input.runstate } : {}),
1511
- ...(input.resolvedtarget ? { resolvedtarget: input.resolvedtarget } : {}),
1512
- ...(input.capture ? { capture: input.capture } : {}),
1513
- ...(input.media ? { media: input.media } : {}),
1514
- ...(input.transport ? { transport: input.transport } : {}),
1515
- ...(input.network ? { network: input.network } : {}),
1516
- ...(input.control ? { control: input.control } : {}),
1517
- ...(input.timeline ? { timeline: input.timeline } : {}),
1518
- ...(input.cdp ? { cdp: input.cdp } : {}),
1519
- ...(input.profile ? { profile: input.profile } : {}),
1520
- ...(input.emulation ? { emulation: input.emulation } : {}),
1521
- ...(input.session ? { session: input.session } : {}),
1522
- ...(input.workflow
1523
- ? {
1524
- workflow: {
1525
- runid: input.workflow.runid,
1526
- state: input.workflow.state,
1527
- ...(input.workflow.dryrun === true ? { dryrun: true } : {}),
1528
- produced: input.workflow.produced,
1529
- consumed: input.workflow.consumed,
1530
- ...(input.workflow.timeout !== undefined ? { timeout: input.workflow.timeout } : {}),
1531
- ...(input.workflow.retry !== undefined ? { retry: input.workflow.retry } : {}),
1532
- },
1533
- }
1534
- : {}),
1535
- ...(input.trigger
1536
- ? {
1537
- trigger: {
1538
- ruleid: input.trigger.ruleid,
1539
- kind: input.trigger.kind,
1540
- enabled: input.trigger.enabled,
1541
- ...(input.trigger.nextfireat !== undefined ? { nextfireat: input.trigger.nextfireat } : {}),
1542
- },
1543
- }
1544
- : {}),
1545
- ...(input.tool
1546
- ? {
1547
- tool: {
1548
- clientid: input.tool.clientid,
1549
- tool: input.tool.tool,
1550
- origin: input.tool.origin,
1551
- ok: input.tool.ok,
1552
- ...(input.tool.code !== undefined ? { code: input.tool.code } : {}),
1553
- },
1554
- }
1555
- : {}),
1556
- ...(input.safety ? { safety: input.safety } : {}),
1557
- ...(input.ratelimitwait ? { ratelimitwait: input.ratelimitwait } : {}),
1558
- ...(input.streamcursor ? { streamcursor: input.streamcursor } : {}),
1559
- ...(input.dedupe ? { dedupe: input.dedupe } : {}),
1560
- ...(input.sampledpreview ? { sampledpreview: input.sampledpreview } : {}),
1561
- ...(input.correlation ? { correlation: input.correlation } : {}),
1562
- ...(input.cachehit ? { cachehit: input.cachehit } : {}),
1563
- ...(input.ocr ? { ocr: input.ocr } : {}),
1564
- ...(input.vision ? { vision: input.vision } : {}),
1565
- ...(input.grounding ? { grounding: input.grounding } : {}),
1566
- ...(input.beforeafter ? { beforeafter: input.beforeafter } : {}),
1567
- ...(input.diff ? { diff: input.diff } : {}),
1568
- });
1569
- }
1570
-
1571
- /** Wraps a clickable map payload with numbered entries in the versioned response envelope. */
1572
- export function mapresponse(input: { map: clickablemap; plan: agentplan }): string {
1573
- return JSON.stringify({
1574
- version: protocolversion,
1575
- planid: input.plan.id,
1576
- planstate: input.plan.state,
1577
- map: input.map,
1578
- });
1579
- }
1580
-
1581
- /** Reports the keys currently held on one tab for the live context envelope, refreshed per step. */
1582
- export function heldkeysreport(input: { tabid: number; holds: keyholdstate[] }): {
1583
- version: typeof protocolversion;
1584
- tabid: number;
1585
- heldkeys: keyholdstate[];
1586
- } {
1587
- return { version: protocolversion, tabid: input.tabid, heldkeys: input.holds };
1588
- }
1589
-
1590
- /** Wraps one observation capture with its a11y, reader, listpattern, tableshape and diff sections in the versioned response envelope. */
1591
- export function observationresponse(input: { observation: observation; plan: agentplan }): string {
1592
- return JSON.stringify({
1593
- version: protocolversion,
1594
- planid: input.plan.id,
1595
- planstate: input.plan.state,
1596
- observation: input.observation,
1597
- });
1598
- }
1599
-
1600
- /** Wraps mutation, focus and banner event records with their timestamps and target paths in the versioned response envelope. */
1601
- export function eventresponse(input: {
1602
- events: Array<mutationevent | focusevent | bannerreport>;
1603
- plan: agentplan;
1604
- }): string {
1605
- return JSON.stringify({
1606
- version: protocolversion,
1607
- planid: input.plan.id,
1608
- planstate: input.plan.state,
1609
- events: input.events,
1610
- });
1611
- }
1612
-
1613
- /** Wraps one snapshot diff with its added, removed and changed nodes and its two observation versions in the versioned response envelope. */
1614
- export function diffresponse(input: { diff: snapshotdiff; plan: agentplan }): string {
1615
- return JSON.stringify({
1616
- version: protocolversion,
1617
- planid: input.plan.id,
1618
- planstate: input.plan.state,
1619
- diff: input.diff,
1620
- });
1621
- }
1622
-
1623
- /** Reports the detected page language, template class, scroll lock and banner state in the live context envelope. */
1624
- export function signalsreport(input: { signals?: pagesignals }): {
1625
- version: typeof protocolversion;
1626
- language?: string;
1627
- template?: string;
1628
- scrolllocked?: boolean;
1629
- banner?: string;
1630
- } {
1631
- const signals = input.signals;
1632
- return {
1633
- version: protocolversion,
1634
- ...(signals && signals.language !== undefined ? { language: signals.language } : {}),
1635
- ...(signals && signals.template !== undefined ? { template: signals.template } : {}),
1636
- ...(signals && signals.scrolllocked !== undefined ? { scrolllocked: signals.scrolllocked } : {}),
1637
- ...(signals && signals.banner !== undefined ? { banner: signals.banner } : {}),
1638
- };
1639
- }
1640
-
1641
- /** Wraps derived selector candidates with their stability scores in the versioned response envelope. */
1642
- export function selectorresponse(input: { candidates: selectorcandidate[]; plan: agentplan }): string {
1643
- return JSON.stringify({
1644
- version: protocolversion,
1645
- planid: input.plan.id,
1646
- planstate: input.plan.state,
1647
- candidates: input.candidates,
1648
- });
1649
- }
1650
-
1651
- /** Wraps the live navigation state with its load phase, final url and redirect chain in the versioned response envelope. */
1652
- export function navstateresponse(input: { navstate: navstate; plan: agentplan }): string {
1653
- return JSON.stringify({
1654
- version: protocolversion,
1655
- planid: input.plan.id,
1656
- planstate: input.plan.state,
1657
- navstate: input.navstate,
1658
- });
1659
- }
1660
-
1661
- /** Carries the navigation trail of a session with its visited urls, titles and step refs in the session context envelope. */
1662
- export function trailreport(input: { sessionid?: string; trail: trailentry[] }): {
1663
- version: typeof protocolversion;
1664
- sessionid?: string;
1665
- trail: trailentry[];
1666
- } {
1667
- return { version: protocolversion, ...(input.sessionid ? { sessionid: input.sessionid } : {}), trail: input.trail };
1668
- }
1669
-
1670
- /** Wraps url safety verdicts with their reasons in the versioned response envelope for external link review. */
1671
- export function safetyresponse(input: { verdicts: safetyverdict[]; plan: agentplan }): string {
1672
- return JSON.stringify({
1673
- version: protocolversion,
1674
- planid: input.plan.id,
1675
- planstate: input.plan.state,
1676
- verdicts: input.verdicts,
1677
- });
1678
- }
1679
-
1680
- /** Wraps one tab report with its matched tabs, groups and badges in the versioned response envelope. */
1681
- export function tabreportresponse(input: { report: tabreport; plan: agentplan }): string {
1682
- return JSON.stringify({
1683
- version: protocolversion,
1684
- planid: input.plan.id,
1685
- planstate: input.plan.state,
1686
- report: input.report,
1687
- });
1688
- }
1689
-
1690
- /** Carries the saved tab layouts with their window bounds and group states in the session context envelope. */
1691
- export function layoutreport(input: { layouts: tablayout[] }): {
1692
- version: typeof protocolversion;
1693
- layouts: tablayout[];
1694
- } {
1695
- return { version: protocolversion, layouts: input.layouts };
1696
- }
1697
-
1698
- /** Wraps one form report with the detected fields, their kinds and the matched controls in the versioned response envelope. */
1699
- export function formreportresponse(input: { report: formreport; plan: agentplan }): string {
1700
- return JSON.stringify({
1701
- version: protocolversion,
1702
- planid: input.plan.id,
1703
- planstate: input.plan.state,
1704
- report: input.report,
1705
- });
1706
- }
1707
-
1708
- /** Wraps one collected error report with its field refs and messages in the versioned response envelope for correction loops. */
1709
- export function errorreportresponse(input: { report: errorreport; plan: agentplan }): string {
1710
- return JSON.stringify({
1711
- version: protocolversion,
1712
- planid: input.plan.id,
1713
- planstate: input.plan.state,
1714
- report: input.report,
1715
- });
1716
- }
1717
-
1718
- /** Carries the wizard states with their step history and the recorded typeahead picks in the session context envelope. */
1719
- export function wizardreport(input: { sessionid?: string; wizards: wizardstate[]; picks: typeaheadpick[] }): {
1720
- version: typeof protocolversion;
1721
- sessionid?: string;
1722
- wizards: wizardstate[];
1723
- picks: typeaheadpick[];
1724
- } {
1725
- return {
1726
- version: protocolversion,
1727
- ...(input.sessionid ? { sessionid: input.sessionid } : {}),
1728
- wizards: input.wizards,
1729
- picks: input.picks,
1730
- };
1731
- }
1732
-
1733
- /** Wraps one dataset payload with its column specs and a sampled row list in the versioned response envelope. */
1734
- export function datasetresponse(input: { dataset: dataset; plan: agentplan; sample?: number }): string {
1735
- const sample = Math.max(0, Math.floor(input.sample ?? 10));
1736
- const payload = { ...input.dataset, rows: input.dataset.rows.slice(0, sample), totalrows: input.dataset.rows.length };
1737
- return JSON.stringify({
1738
- version: protocolversion,
1739
- planid: input.plan.id,
1740
- planstate: input.plan.state,
1741
- dataset: payload,
1742
- });
1743
- }
1744
-
1745
- /** Carries the extraction progress with visited page counts, collected row counts and resume cursors in the session context envelope. */
1746
- export function extractionreport(input: { sessions: extractsession[] }): {
1747
- version: typeof protocolversion;
1748
- sessions: extractsession[];
1749
- } {
1750
- return { version: protocolversion, sessions: input.sessions };
1751
- }
1752
-
1753
- /** Reports the provenance records of every exported artifact with its source url, step ref, row range and checksum in the session context envelope. */
1754
- export function provenancereport(input: { records: provenancerecord[] }): {
1755
- version: typeof protocolversion;
1756
- records: provenancerecord[];
1757
- } {
1758
- return { version: protocolversion, records: input.records };
1759
- }
1760
-
1761
- /** Documents the reviewed transform rule grammar shared by transformvalues steps and the task rules store. */
1762
- export function transformgrammar(rules: transformrule[]): string {
1763
- return JSON.stringify({
1764
- rules: rules.map((rule) => ({ expression: rule.expression, sources: rule.sources, target: rule.target })),
1765
- });
1766
- }
1767
-
1768
- /** Wraps the batch download queue with per file states, resolved paths and checksums in the versioned response envelope. */
1769
- export function downloadreport(input: { downloads: downloadrecord[]; plan: agentplan }): string {
1770
- return JSON.stringify({
1771
- version: protocolversion,
1772
- planid: input.plan.id,
1773
- planstate: input.plan.state,
1774
- downloads: input.downloads,
1775
- });
1776
- }
1777
-
1778
- /** Carries the captured network log records with their step correlation through request ids in the session context envelope. */
1779
- export function netlogreport(input: { records: netlogrecord[] }): {
1780
- version: typeof protocolversion;
1781
- records: netlogrecord[];
1782
- } {
1783
- return { version: protocolversion, records: input.records };
1784
- }
1785
-
1786
- /** Carries the quarantine entries with their scan verdicts and release refs in the session context envelope. */
1787
- export function quarantinereport(input: { entries: quarantineentry[] }): {
1788
- version: typeof protocolversion;
1789
- entries: quarantineentry[];
1790
- } {
1791
- return { version: protocolversion, entries: input.entries };
1792
- }
1793
-
1794
- /** Carries every stored capture record with its metadata and the before and after shotpairs of the run in the session context envelope. */
1795
- export function capturereport(input: { records: shotrecord[]; pairs: shotpair[] }): {
1796
- version: typeof protocolversion;
1797
- records: shotrecord[];
1798
- pairs: shotpair[];
1799
- } {
1800
- return { version: protocolversion, records: input.records, pairs: input.pairs };
1801
- }
1802
-
1803
- /** Carries every stored media record of pdf documents, recordings, frames, canvases, stream probes and assets beside the observed image batches in the session context envelope. */
1804
- export function mediareport(input: { records: mediarecord[]; images: imagebatch[] }): {
1805
- version: typeof protocolversion;
1806
- records: mediarecord[];
1807
- images: imagebatch[];
1808
- } {
1809
- return { version: protocolversion, records: input.records, images: input.images };
1810
- }
1811
-
1812
- /** Carries every outbound call record of the run in the session context envelope with the response bodies held back; the metadata keeps method, origin, status class, retries and byte counts. */
1813
- export function callsreport(input: { calls: callrecord[] }): {
1814
- version: typeof protocolversion;
1815
- calls: Array<Omit<callrecord, "body"> & { body?: undefined }>;
1816
- } {
1817
- const calls = input.calls.map((call) => {
1818
- const { body, ...metadata } = call;
1819
- void body;
1820
- return metadata;
1821
- });
1822
- return { version: protocolversion, calls };
1823
- }
1824
-
1825
- /** Carries every observed exchange, channel, stream subscription and api map entry of the run in the session context envelope with correlation ids kept and captured body bytes held back. */
1826
- export function exchangesreport(input: {
1827
- exchanges: exchangerecord[];
1828
- channels: channelrecord[];
1829
- subscriptions: eventsubscription[];
1830
- apimap: apimapentry[];
1831
- }): {
1832
- version: typeof protocolversion;
1833
- exchanges: exchangerecord[];
1834
- channels: channelrecord[];
1835
- subscriptions: eventsubscription[];
1836
- apimap: apimapentry[];
1837
- } {
1838
- return {
1839
- version: protocolversion,
1840
- exchanges: input.exchanges,
1841
- channels: input.channels,
1842
- subscriptions: input.subscriptions,
1843
- apimap: input.apimap,
1844
- };
1845
- }
1846
-
1847
- /** Carries every stored token record per provider in the session context envelope with scopes, origin scope and expiry windows; token values and their storage ids never appear because the material stays behind the storage seam. */
1848
- export function authreport(input: { tokens: tokenrecord[] }): {
1849
- version: typeof protocolversion;
1850
- tokens: Array<
1851
- Omit<tokenrecord, "accessstorageid" | "refreshstorageid"> & {
1852
- accessstorageid?: undefined;
1853
- refreshstorageid?: undefined;
1854
- }
1855
- >;
1856
- } {
1857
- const tokens = input.tokens.map((token) => {
1858
- const { accessstorageid, refreshstorageid, ...metadata } = token;
1859
- void accessstorageid;
1860
- void refreshstorageid;
1861
- return metadata;
1862
- });
1863
- return { version: protocolversion, tokens };
1864
- }
1865
-
1866
- /** Carries the traffic control state of the run in the session context envelope: the active block, mock and rewrite rule sets with hit counts, the cookie operations with values redacted, the proxy route history with apply and revert times and the rate limit states with reset windows. */
1867
- export function controlreport(input: {
1868
- blocks: blockrule[];
1869
- mocks: mockspec[];
1870
- rewrites: headerule[];
1871
- cookies: cookieoperation[];
1872
- proxies: proxyroute[];
1873
- ratelimits: ratelimitread[];
1874
- }): {
1875
- version: typeof protocolversion;
1876
- blocks: blockrule[];
1877
- mocks: Array<Omit<mockspec, "body"> & { body?: undefined }>;
1878
- rewrites: headerule[];
1879
- cookies: cookieoperation[];
1880
- proxies: proxyroute[];
1881
- ratelimits: ratelimitread[];
1882
- } {
1883
- const mocks = input.mocks.map((spec) => {
1884
- const { body, ...metadata } = spec;
1885
- void body;
1886
- return metadata;
1887
- });
1888
- return {
1889
- version: protocolversion,
1890
- blocks: input.blocks,
1891
- mocks,
1892
- rewrites: input.rewrites,
1893
- cookies: input.cookies,
1894
- proxies: input.proxies,
1895
- ratelimits: input.ratelimits,
1896
- };
1897
- }
1898
-
1899
- /** Carries the run timeline in the session context envelope: every entry with its level, source, step id and message, the error and rejection records with their stack frames, the long task entries with attribution names and the entry counts per level. */
1900
- export function timelinereport(input: {
1901
- entries: timelineentry[];
1902
- errors: errorrecord[];
1903
- rejections: rejectionrecord[];
1904
- longtasks: longtaskentry[];
1905
- levelcounts: Record<string, number>;
1906
- }): {
1907
- version: typeof protocolversion;
1908
- entries: timelineentry[];
1909
- errors: errorrecord[];
1910
- rejections: rejectionrecord[];
1911
- longtasks: longtaskentry[];
1912
- levelcounts: Record<string, number>;
1913
- } {
1914
- return {
1915
- version: protocolversion,
1916
- entries: input.entries,
1917
- errors: input.errors,
1918
- rejections: input.rejections,
1919
- longtasks: input.longtasks,
1920
- levelcounts: input.levelcounts,
1921
- };
1922
- }
1923
-
1924
- /** Carries one console diff result in the session context envelope with every line classified as added, removed or repeated and the counts of each class. */
1925
- export function consolediffreport(input: { diff: consolediff }): {
1926
- version: typeof protocolversion;
1927
- diff: consolediff;
1928
- } {
1929
- return { version: protocolversion, diff: input.diff };
1930
- }
1931
-
1932
- /** Carries the devtools protocol state of the run in the session context envelope: every session with its domains and durations, the command outcomes with durations and error classes, the event rules with match counts, the breakpoints with hit counts and conditions, the pause states with their call frames and dom snapshot ids, the watch expressions with their per pause values and the script overrides with review provenance while the fixture sources stay held back. */
1933
- export function cdpreport(input: {
1934
- sessions: cdpsession[];
1935
- commands: cdpcommand[];
1936
- events: cdpeventrule[];
1937
- breakpoints: breakpointspec[];
1938
- pauses: pausestate[];
1939
- watches: watchexpression[];
1940
- overrides: scriptoverride[];
1941
- grants: debuggergrant[];
1942
- }): {
1943
- version: typeof protocolversion;
1944
- sessions: cdpsession[];
1945
- commands: cdpcommand[];
1946
- events: cdpeventrule[];
1947
- breakpoints: breakpointspec[];
1948
- pauses: pausestate[];
1949
- watches: watchexpression[];
1950
- overrides: Array<Omit<scriptoverride, "source"> & { source?: undefined }>;
1951
- grants: Array<Omit<debuggergrant, "prompt"> & { prompt?: undefined }>;
1952
- } {
1953
- const overrides = input.overrides.map((spec) => {
1954
- const { source, ...metadata } = spec;
1955
- void source;
1956
- return metadata;
1957
- });
1958
- const grants = input.grants.map((grant) => {
1959
- const { prompt, ...metadata } = grant;
1960
- void prompt;
1961
- return metadata;
1962
- });
1963
- return {
1964
- version: protocolversion,
1965
- sessions: input.sessions,
1966
- commands: input.commands,
1967
- events: input.events,
1968
- breakpoints: input.breakpoints,
1969
- pauses: input.pauses,
1970
- watches: input.watches,
1971
- overrides,
1972
- grants,
1973
- };
1974
- }
1975
-
1976
- /** Carries the profiling state of the run in the session context envelope: every flow metric with its step span and duration, the heap records with byte and node counts, the growth samples with the computed trend of flagged steps, the cpu profiles with hot function lists, the layout shift entries with scores and impacted selectors, the trace records with their category lists, event counts and step annotations, and the source map references with their parsed state while the source map consent prompts stay held back. */
1977
- export function profilereport(input: {
1978
- flows: flowmetric[];
1979
- heaps: heaprecord[];
1980
- samples: growsample[];
1981
- trends: memorytrend[];
1982
- profiles: cpuprofile[];
1983
- shifts: shiftentry[];
1984
- traces: tracerecord[];
1985
- sourcemaps: sourcemapref[];
1986
- consents: sourcemapconsent[];
1987
- }): {
1988
- version: typeof protocolversion;
1989
- flows: flowmetric[];
1990
- heaps: heaprecord[];
1991
- samples: growsample[];
1992
- trends: memorytrend[];
1993
- profiles: cpuprofile[];
1994
- shifts: shiftentry[];
1995
- traces: tracerecord[];
1996
- sourcemaps: sourcemapref[];
1997
- consents: Array<Omit<sourcemapconsent, "prompt"> & { prompt?: undefined }>;
1998
- } {
1999
- const consents = input.consents.map((consent) => {
2000
- const { prompt, ...metadata } = consent;
2001
- void prompt;
2002
- return metadata;
2003
- });
2004
- return {
2005
- version: protocolversion,
2006
- flows: input.flows,
2007
- heaps: input.heaps,
2008
- samples: input.samples,
2009
- trends: input.trends,
2010
- profiles: input.profiles,
2011
- shifts: input.shifts,
2012
- traces: input.traces,
2013
- sourcemaps: input.sourcemaps,
2014
- consents,
2015
- };
2016
- }
2017
-
2018
- /** Builds the emulation report envelope of the run: the layer history with revert plans beside every layer, the user curated device, network, location and agent preset libraries, the blackbox rule sets per origin, the permission override history with restore states and the location consents with their coordinates shown while the prompt text stays out of the envelope. */
2019
- export function emulationreport(input: {
2020
- state?: emulationstate;
2021
- devices: devicepreset[];
2022
- networks: networkpreset[];
2023
- locations: locationpreset[];
2024
- agents: agentpreset[];
2025
- blackbox: Array<{ origin: string; rules: blackboxrule[] }>;
2026
- permissions: permissionoverriderecord[];
2027
- consents: locationconsent[];
2028
- }): {
2029
- version: typeof protocolversion;
2030
- state?: emulationstate;
2031
- layers: emulationlayer[];
2032
- devices: devicepreset[];
2033
- networks: networkpreset[];
2034
- locations: locationpreset[];
2035
- agents: agentpreset[];
2036
- blackbox: Array<{ origin: string; rules: blackboxrule[] }>;
2037
- permissions: permissionoverriderecord[];
2038
- consents: Array<Omit<locationconsent, "prompt"> & { prompt?: undefined }>;
2039
- } {
2040
- const consents = input.consents.map((consent) => {
2041
- const { prompt, ...metadata } = consent;
2042
- void prompt;
2043
- return metadata;
2044
- });
2045
- return {
2046
- version: protocolversion,
2047
- ...(input.state !== undefined ? { state: input.state } : {}),
2048
- layers: input.state?.layers ?? [],
2049
- devices: input.devices,
2050
- networks: input.networks,
2051
- locations: input.locations,
2052
- agents: input.agents,
2053
- blackbox: input.blackbox,
2054
- permissions: input.permissions,
2055
- consents,
2056
- };
2057
- }
2058
-
2059
- /** Builds the session memory report envelope of the run: every saved session record with its tabs, sections, folder and tags, the session event history with timestamps, the folder tree, the stored diff results and the reviewed auto snapshot interval; the crash marker of an interrupted run travels beside the records so the sessions view can offer the crash restore. */
2060
- export function sessionreport(input: {
2061
- records: sessionrecord[];
2062
- events: sessionevent[];
2063
- folders: sessionfolder[];
2064
- diffs: sessiondiff[];
2065
- auto?: autointerval;
2066
- crashed?: boolean;
2067
- }): {
2068
- version: typeof protocolversion;
2069
- records: sessionrecord[];
2070
- events: sessionevent[];
2071
- folders: sessionfolder[];
2072
- diffs: sessiondiff[];
2073
- auto?: autointerval;
2074
- crashed?: boolean;
2075
- } {
2076
- return {
2077
- version: protocolversion,
2078
- records: input.records,
2079
- events: input.events,
2080
- folders: input.folders,
2081
- diffs: input.diffs,
2082
- ...(input.auto !== undefined ? { auto: input.auto } : {}),
2083
- ...(input.crashed === true ? { crashed: true } : {}),
2084
- };
2085
- }
2086
-
2087
- /** Builds the workflow report envelope of the run: the saved workflow records with their expanded step lists, the run states, the shareable step templates, the live runlog of the newest run, the variable values per scope, the provenance of expression results and regex captures and the control flow decisions of the newest run. */
2088
- export function workflowreport(input: {
2089
- workflows: workflowrecord[];
2090
- runs: workflowrun[];
2091
- templates: steptemplate[];
2092
- log?: runlogentry[];
2093
- scopes?: variablescope[];
2094
- provenance?: workflowprovenance[];
2095
- control?: controlflowdecision[];
2096
- }): {
2097
- version: typeof protocolversion;
2098
- workflows: workflowrecord[];
2099
- runs: workflowrun[];
2100
- templates: steptemplate[];
2101
- log: runlogentry[];
2102
- scopes: variablescope[];
2103
- provenance: workflowprovenance[];
2104
- control: controlflowdecision[];
2105
- } {
2106
- return {
2107
- version: protocolversion,
2108
- workflows: input.workflows,
2109
- runs: input.runs,
2110
- templates: input.templates,
2111
- log: input.log ?? [],
2112
- scopes: input.scopes ?? [],
2113
- provenance: input.provenance ?? [],
2114
- control: input.control ?? [],
2115
- };
2116
- }
2117
-
2118
- /** One trigger list entry of the trigger report envelope: the rule identity, its family, the workflow name beside the id, the runtime state with the effective cooldown, the per rule counters, the next scheduled fire time and the review summary of the match fields. */
2119
- export interface triggerentry {
2120
- id: string;
2121
- kind: string;
2122
- workflowid: string;
2123
- workflowname?: string;
2124
- label: string;
2125
- enabled: boolean;
2126
- paused?: boolean;
2127
- cooldown: number;
2128
- lastfireat?: number;
2129
- nextfireat?: number;
2130
- fires: number;
2131
- launches: number;
2132
- suppressions: number;
2133
- summary: Record<string, unknown>;
2134
- }
2135
-
2136
- /** Builds the trigger list envelope of the run: every armed rule with its workflow name, runtime state, counters and next scheduled fire time beside the queued fires waiting for a busy run or a paused session. */
2137
- export function triggerlist(input: { rules: triggerule[]; workflows: workflowrecord[]; queue?: triggerfire[] }): {
2138
- version: typeof protocolversion;
2139
- rules: triggerentry[];
2140
- queued: number;
2141
- } {
2142
- const names = new Map(input.workflows.map((record) => [record.id, record.name]));
2143
- const rules = input.rules.map((rule) => {
2144
- const workflowname = names.get(rule.workflowid);
2145
- return {
2146
- id: rule.id,
2147
- kind: rule.kind,
2148
- workflowid: rule.workflowid,
2149
- ...(workflowname !== undefined ? { workflowname } : {}),
2150
- label: rule.label,
2151
- enabled: rule.state.enabled,
2152
- ...(rule.state.pausedat !== undefined ? { paused: true } : {}),
2153
- cooldown: rule.state.cooldown,
2154
- ...(rule.state.lastfireat !== undefined ? { lastfireat: rule.state.lastfireat } : {}),
2155
- ...(rule.state.nextfireat !== undefined ? { nextfireat: rule.state.nextfireat } : {}),
2156
- fires: rule.stats.fires,
2157
- launches: rule.stats.launches,
2158
- suppressions: rule.stats.suppressions,
2159
- summary: triggersummaryof(rule),
2160
- };
2161
- });
2162
- return { version: protocolversion, rules, queued: (input.queue ?? []).length };
2163
- }
2164
-
2165
- /** Renders the review summary of one armed rule for the trigger list without importing the engine module so the envelope stays a pure projection. */
2166
- function triggersummaryof(rule: triggerule): Record<string, unknown> {
2167
- const summary: Record<string, unknown> = { kind: rule.kind, workflowid: rule.workflowid };
2168
- if (rule.origins !== undefined) summary.origins = rule.origins;
2169
- if (rule.pattern !== undefined) summary.pattern = rule.pattern;
2170
- if (rule.title !== undefined) summary.title = rule.title;
2171
- if (rule.command !== undefined) summary.command = rule.command;
2172
- if (rule.key !== undefined) summary.key = rule.key;
2173
- if (rule.cron !== undefined) summary.cron = rule.cron;
2174
- if (rule.timezone !== undefined) summary.timezone = rule.timezone;
2175
- if (rule.period !== undefined) summary.period = rule.period;
2176
- if (rule.jitter !== undefined) summary.jitter = rule.jitter;
2177
- if (rule.urls !== undefined) summary.urls = rule.urls;
2178
- if (rule.events !== undefined) summary.events = rule.events;
2179
- if (rule.schema !== undefined) summary.fields = rule.schema.length;
2180
- return summary;
2181
- }
2182
-
2183
- /** Builds the trigger fired notification envelope for listeners: the fire identity, the rule and workflow it launched, the cause, the triggering url and title and the payload carried into the run context; cooldown and dedupe suppressions never notify, they only count. */
2184
- export function triggerfired(input: { fire: triggerfire; workflowid: string; runid?: string }): {
2185
- version: typeof protocolversion;
2186
- triggerfired: {
2187
- fireid: string;
2188
- ruleid: string;
2189
- workflowid: string;
2190
- at: number;
2191
- cause: string;
2192
- url?: string;
2193
- title?: string;
2194
- runid?: string;
2195
- };
2196
- } {
2197
- return {
2198
- version: protocolversion,
2199
- triggerfired: {
2200
- fireid: input.fire.id,
2201
- ruleid: input.fire.ruleid,
2202
- workflowid: input.workflowid,
2203
- at: input.fire.at,
2204
- cause: input.fire.cause,
2205
- ...(input.fire.url !== undefined ? { url: input.fire.url } : {}),
2206
- ...(input.fire.title !== undefined ? { title: input.fire.title } : {}),
2207
- ...(input.runid !== undefined ? { runid: input.runid } : {}),
2208
- },
2209
- };
2210
- }
2211
-
2212
- /** Builds the manual run preview envelope: the manual run request with its step preview so a human always sees what a run will do before confirming it. */
2213
- export function manualrunpreview(input: { preview: manualrun; workflowname?: string }): {
2214
- version: typeof protocolversion;
2215
- manualrun: manualrun;
2216
- workflowname?: string;
2217
- } {
2218
- return {
2219
- version: protocolversion,
2220
- manualrun: input.preview,
2221
- ...(input.workflowname !== undefined ? { workflowname: input.workflowname } : {}),
2222
- };
2223
- }
2224
-
2225
- /** Builds one agent protocol toolcall frame: the json rpc request a paired client sends to invoke one namespaced tool behind the consent gates. */
2226
- export function toolcallframe(input: {
2227
- id: number | string;
2228
- name: string;
2229
- params?: Record<string, unknown>;
2230
- }): jsonrpcframe {
2231
- return { jsonrpc: "2.0", id: input.id, method: "tools/call", params: { ...(input.params ?? {}), name: input.name } };
2232
- }
2233
-
2234
- /** Builds one agent protocol toolresult frame: the json rpc response that answers a tool call with the tool result or the rpc error, carrying the consent refusals with the consentrefused code. */
2235
- export function toolresultframe(input: {
2236
- id: number | string | null;
2237
- result?: toolresult;
2238
- error?: rpcerror;
2239
- }): jsonrpcframe {
2240
- return {
2241
- jsonrpc: "2.0",
2242
- id: input.id,
2243
- ...(input.error !== undefined ? { error: input.error } : { result: input.result }),
2244
- };
2245
- }
2246
-
2247
- /** The file format version of an exported workflow file: a json or yaml document carrying the format marker, the export time, the composed workflow record with its version metadata, an optional change note and the packed step templates of a share bundle. Secrets never travel: the export content review refuses any step options or template payloads that name a secret, token, api key or password field before the file is written. */
2248
- export const workflowfileversion = 1 as const;
2249
-
2250
- /** Builds the editor state envelope for panel synchronization: the canvas model of the open workflow beside its version timeline, the stored diff results, the run history with the filter answers, the breakpoints, the per site overrides, the pending imports held for review and the watchdog status with its recent events. */
2251
- export function editorstate(input: {
2252
- model?: editormodel;
2253
- versions: workflowversion[];
2254
- diffs?: versiondiff[];
2255
- history: runhistoryentry[];
2256
- breakpoints?: string[];
2257
- overrides: siteoverride[];
2258
- imports: Array<{
2259
- id: string;
2260
- workflowid: string;
2261
- name: string;
2262
- version: number;
2263
- steps: number;
2264
- risk: string;
2265
- importedat: number;
2266
- filename?: string;
2267
- }>;
2268
- backgroundruns?: Record<string, boolean>;
2269
- watchdog: { config?: watchdogconfig; events: watchdogrecord[] };
2270
- }): {
2271
- version: typeof protocolversion;
2272
- editor: {
2273
- versions: workflowversion[];
2274
- diffs: versiondiff[];
2275
- history: runhistoryentry[];
2276
- breakpoints: string[];
2277
- overrides: siteoverride[];
2278
- imports: Array<{
2279
- id: string;
2280
- workflowid: string;
2281
- name: string;
2282
- version: number;
2283
- steps: number;
2284
- risk: string;
2285
- importedat: number;
2286
- filename?: string;
2287
- }>;
2288
- backgroundruns: Record<string, boolean>;
2289
- watchdog: { config?: watchdogconfig; events: watchdogrecord[] };
2290
- };
2291
- model?: editormodel;
2292
- } {
2293
- const editor = {
2294
- versions: input.versions,
2295
- diffs: input.diffs ?? [],
2296
- history: input.history,
2297
- breakpoints: input.breakpoints ?? [],
2298
- overrides: input.overrides,
2299
- imports: input.imports,
2300
- backgroundruns: input.backgroundruns ?? {},
2301
- watchdog: {
2302
- ...(input.watchdog.config !== undefined ? { config: input.watchdog.config } : {}),
2303
- events: input.watchdog.events,
2304
- },
2305
- };
2306
- return { version: protocolversion, editor, ...(input.model !== undefined ? { model: input.model } : {}) };
2307
- }
2308
-
2309
- /** Parses one run history query envelope with its filters: the workflow id, the outcome, the time floor and the entry count the caller asks for, each optional and each a user choice with no code ceiling. */
2310
- export function runhistoryquery(value: unknown): {
2311
- workflowid?: string;
2312
- outcome?: string;
2313
- since?: number;
2314
- limit?: number;
2315
- } {
2316
- if (value === undefined || value === null) return {};
2317
- const candidate = record(value);
2318
- const query: { workflowid?: string; outcome?: string; since?: number; limit?: number } = {};
2319
- if (candidate.workflowid !== undefined) {
2320
- if (typeof candidate.workflowid !== "string" || !candidate.workflowid.trim())
2321
- throw new Error("The run history workflow filter must be a non-empty string.");
2322
- query.workflowid = candidate.workflowid;
2323
- }
2324
- if (candidate.outcome !== undefined) {
2325
- if (typeof candidate.outcome !== "string" || !candidate.outcome.trim())
2326
- throw new Error("The run history outcome filter must be a non-empty string.");
2327
- query.outcome = candidate.outcome;
2328
- }
2329
- if (candidate.since !== undefined) {
2330
- if (typeof candidate.since !== "number" || !Number.isFinite(candidate.since))
2331
- throw new Error("The run history time floor must be a finite timestamp.");
2332
- query.since = candidate.since;
2333
- }
2334
- if (candidate.limit !== undefined) {
2335
- if (typeof candidate.limit !== "number" || !Number.isInteger(candidate.limit) || candidate.limit < 1)
2336
- throw new Error("The run history entry count must be a positive integer with no code ceiling.");
2337
- query.limit = candidate.limit;
2338
- }
2339
- return query;
2340
- }
2341
-
2342
- /** Builds the run history report envelope: the filtered entries newest first with the applied filter echoed so the panel renders what it asked for. */
2343
- export function runhistoryreport(input: {
2344
- entries: runhistoryentry[];
2345
- query?: { workflowid?: string; outcome?: string; since?: number; limit?: number };
2346
- }): {
2347
- version: typeof protocolversion;
2348
- entries: runhistoryentry[];
2349
- query: { workflowid?: string; outcome?: string; since?: number; limit?: number };
2350
- } {
2351
- return { version: protocolversion, entries: input.entries, query: input.query ?? {} };
2352
- }
2353
-
2354
- /** Builds the http stream transport report: the posted json rpc endpoint, the server sent event channel path, the heartbeat rhythm and the open and dead channel counts of the remote surface. */
2355
- export function httpstreamreport(input: { stream: httpstreamconfig; channels: streamchannel[]; now: number }): {
2356
- version: typeof protocolversion;
2357
- endpoint: string;
2358
- streampath: string;
2359
- heartbeatms: number;
2360
- idlewindowms: number;
2361
- channelsopen: number;
2362
- channelsdead: number;
2363
- } {
2364
- const open = input.channels.filter(
2365
- (channel) =>
2366
- channel.closedat === undefined &&
2367
- input.now - channel.lastbeatat < (input.stream.idlewindowms ?? defaultidlewindowms),
2368
- );
2369
- return {
2370
- version: protocolversion,
2371
- endpoint: input.stream.endpoint,
2372
- streampath: input.stream.streampath,
2373
- heartbeatms: input.stream.heartbeatms ?? defaultheartbeatms,
2374
- idlewindowms: input.stream.idlewindowms ?? defaultidlewindowms,
2375
- channelsopen: open.length,
2376
- channelsdead: input.channels.length - open.length,
2377
- };
2378
- }
2379
-
2380
- /** Builds the pairing and auth handshake frames: the request frame carries the pairing code or the token answer while the response frame answers the verified exchange or the fixed refusal that leaks no pairing state. */
2381
- export function pairingframes(input: {
2382
- id: number | string;
2383
- challenge: authchallenge;
2384
- answer?: string;
2385
- outcome: "issued" | "verified" | "refused";
2386
- }): { request: jsonrpcframe; response: jsonrpcframe } {
2387
- const request = {
2388
- jsonrpc: "2.0" as const,
2389
- id: input.id,
2390
- method: "pairing",
2391
- params: {
2392
- nonce: input.challenge.nonce,
2393
- method: input.challenge.method,
2394
- ...(input.answer !== undefined ? { answer: input.answer } : {}),
2395
- },
2396
- };
2397
- const response =
2398
- input.outcome === "verified"
2399
- ? { jsonrpc: "2.0" as const, id: input.id, result: { paired: true, method: input.challenge.method } }
2400
- : input.outcome === "issued"
2401
- ? {
2402
- jsonrpc: "2.0" as const,
2403
- id: input.id,
2404
- result: {
2405
- challenge: input.challenge.nonce,
2406
- method: input.challenge.method,
2407
- expiresat: input.challenge.expiresat,
2408
- },
2409
- }
2410
- : { jsonrpc: "2.0" as const, id: input.id, error: rpcerrorof("consentrefused", authrefusedmessage) };
2411
- return { request, response };
2412
- }
2413
-
2414
- /** Builds the session token report: every stored token with its client, scopes, issue and expiry times and the remaining lifetime — never the raw token or its digest. */
2415
- export function tokenreport(
2416
- tokens: sessiontoken[],
2417
- now: number,
2418
- ): {
2419
- version: typeof protocolversion;
2420
- tokens: Array<{
2421
- id: string;
2422
- clientid: string;
2423
- scopes: string[];
2424
- issuedat: number;
2425
- expiresat: number;
2426
- revokedat?: number;
2427
- msremaining?: number;
2428
- }>;
2429
- } {
2430
- return {
2431
- version: protocolversion,
2432
- tokens: tokens.map((token) => ({
2433
- id: token.id,
2434
- clientid: token.clientid,
2435
- scopes: token.scopes,
2436
- issuedat: token.issuedat,
2437
- expiresat: token.expiresat,
2438
- ...(token.revokedat !== undefined
2439
- ? { revokedat: token.revokedat }
2440
- : { msremaining: Math.max(0, token.expiresat - now) }),
2441
- })),
2442
- };
2443
- }
2444
-
2445
- /** Builds the approval gate request and response frames: the request frame raises the gate with the redacted arguments while the response frame answers the decision or the expiry refusal. */
2446
- export function approvalframes(input: { id: number | string; request: approvalrequest; identity?: clientidentity }): {
2447
- raise: jsonrpcframe;
2448
- decision: jsonrpcframe;
2449
- } {
2450
- const raise = {
2451
- jsonrpc: "2.0" as const,
2452
- id: input.id,
2453
- method: "approval",
2454
- params: {
2455
- approvalid: input.request.id,
2456
- clientid: input.request.clientid,
2457
- tool: input.request.tool,
2458
- reason: input.request.reason,
2459
- arguments: JSON.stringify(redactparams(input.request.params, input.request.secretfields ?? [])),
2460
- ...(input.request.timeoutat !== undefined ? { timeoutat: input.request.timeoutat } : {}),
2461
- },
2462
- };
2463
- const decision =
2464
- input.request.state === "pending"
2465
- ? { jsonrpc: "2.0" as const, id: input.id, result: { approvalid: input.request.id, state: "pending" as const } }
2466
- : input.request.state === "approved"
2467
- ? {
2468
- jsonrpc: "2.0" as const,
2469
- id: input.id,
2470
- result: {
2471
- approvalid: input.request.id,
2472
- state: "approved" as const,
2473
- ...(input.identity !== undefined ? { client: input.identity.displayname } : {}),
2474
- },
2475
- }
2476
- : {
2477
- jsonrpc: "2.0" as const,
2478
- id: input.id,
2479
- error: rpcerrorof(
2480
- "consentrefused",
2481
- input.request.state === "refused"
2482
- ? `The approval gate for ${input.request.tool} was refused and the call never executes.`
2483
- : `The approval gate for ${input.request.tool} expired and the call refuses by default.`,
2484
- ),
2485
- };
2486
- return { raise, decision };
2487
- }
2488
-
2489
- /** Builds the tls report of the remote transport: the user configured mode, the certificate requirement and whether the peer was verified. */
2490
- export function tlsreport(tls: tlsconfig): {
2491
- version: typeof protocolversion;
2492
- mode: string;
2493
- certificaterequired: boolean;
2494
- verified: boolean;
2495
- } {
2496
- return {
2497
- version: protocolversion,
2498
- mode: tls.mode,
2499
- certificaterequired: tls.mode === "required" || tls.certificatefingerprint !== undefined,
2500
- verified: tls.verifiedat !== undefined,
2501
- };
2502
- }
2503
-
2504
- /** Builds the allowlist report with the namespace scoping: every entry with its display name, granted namespaces, grant time and grant history count. */
2505
- export function allowlistreport(entries: allowlistentry[]): {
2506
- version: typeof protocolversion;
2507
- entries: Array<{ fingerprint: string; displayname: string; namespaces: string[]; grantedat: number; grants: number }>;
2508
- } {
2509
- return {
2510
- version: protocolversion,
2511
- entries: entries.map((entry) => ({
2512
- fingerprint: entry.fingerprint,
2513
- displayname: entry.displayname,
2514
- namespaces: entry.namespaces,
2515
- grantedat: entry.grantedat,
2516
- grants: entry.history.length,
2517
- })),
2518
- };
2519
- }
2520
-
2521
- /** Builds the heartbeat report of the stream channels: the last beat times, the open and dead counts and whether the client heartbeats stayed inside the idle window. */
2522
- export function heartbeatreport(input: { channels: streamchannel[]; now: number; idlewindow?: number }): {
2523
- version: typeof protocolversion;
2524
- beats: number;
2525
- open: number;
2526
- dead: number;
2527
- } {
2528
- const open = input.channels.filter(
2529
- (channel) =>
2530
- channel.closedat === undefined && input.now - channel.lastbeatat < (input.idlewindow ?? defaultidlewindowms),
2531
- );
2532
- return {
2533
- version: protocolversion,
2534
- beats: input.channels.filter((channel) => channel.lastbeatat > channel.openedat).length,
2535
- open: open.length,
2536
- dead: input.channels.length - open.length,
2537
- };
2538
- }
2539
-
2540
- /**
2541
- * Agent protocol part three envelopes of the 1.1.56 family: the event subscription frames with their kinds and filters, the event notification frames, the page state delta reports of the resource watchers, the sampling callback frames with the exact prompt payload, the prompt tool report and its call frame, the stream chunk and progress notice frames, the cancellation frames with their partial results, the structured error report with its retry hints, the idempotent replay frame, the batch report with its per item outcomes, the rate limit usage report, the call log report, the in flight call report, the dry run report and the mock report.
2542
- */
2543
-
2544
- /** Builds the event subscription frames: the subscribe frame carries the event kinds with the origin and tool filters while the unsubscribe frame cancels the subscription by its id. */
2545
- export function subscriptionframes(input: { id: number | string; subscription: protocoleventsubscription }): {
2546
- subscribe: jsonrpcframe;
2547
- unsubscribe: jsonrpcframe;
2548
- } {
2549
- const subscribe = {
2550
- jsonrpc: "2.0" as const,
2551
- id: input.id,
2552
- method: "events/subscribe",
2553
- params: {
2554
- subscriptionid: input.subscription.id,
2555
- kinds: input.subscription.kinds,
2556
- ...(input.subscription.origin !== undefined ? { origin: input.subscription.origin } : {}),
2557
- ...(input.subscription.tool !== undefined ? { tool: input.subscription.tool } : {}),
2558
- },
2559
- };
2560
- const unsubscribe = {
2561
- jsonrpc: "2.0" as const,
2562
- id: input.id,
2563
- method: "events/unsubscribe",
2564
- params: { subscriptionid: input.subscription.id },
2565
- };
2566
- return { subscribe, unsubscribe };
2567
- }
2568
-
2569
- /** Builds one event notification frame that pushes one protocol event to a subscriber: the subscription id, the event kind and the payload of the event. */
2570
- export function eventnotification(input: {
2571
- subscriptionid: string;
2572
- kind: eventkind;
2573
- origin?: string;
2574
- tool?: string;
2575
- payload?: Record<string, unknown>;
2576
- now: number;
2577
- }): jsonrpcframe {
2578
- return {
2579
- jsonrpc: "2.0",
2580
- method: "events/notify",
2581
- params: {
2582
- subscriptionid: input.subscriptionid,
2583
- kind: input.kind,
2584
- ...(input.origin !== undefined ? { origin: input.origin } : {}),
2585
- ...(input.tool !== undefined ? { tool: input.tool } : {}),
2586
- ...(input.payload !== undefined ? { payload: input.payload } : {}),
2587
- at: input.now,
2588
- },
2589
- };
2590
- }
2591
-
2592
- /** Builds the page state delta report of one resource watcher: the watch id, the client, the watched resource, the changed keys against the baseline and the delivery time. */
2593
- export function resourcedeltareport(input: {
2594
- watchid: string;
2595
- clientid: string;
2596
- resource: string;
2597
- delta: Record<string, unknown>;
2598
- now: number;
2599
- }): {
2600
- version: typeof protocolversion;
2601
- watchid: string;
2602
- clientid: string;
2603
- resource: string;
2604
- delta: Record<string, unknown>;
2605
- at: number;
2606
- } {
2607
- return {
2608
- version: protocolversion,
2609
- watchid: input.watchid,
2610
- clientid: input.clientid,
2611
- resource: input.resource,
2612
- delta: input.delta,
2613
- at: input.now,
2614
- };
2615
- }
2616
-
2617
- /** Builds the sampling callback frames: the request frame carries the exact prompt payload with the granted page content and the system text while the answer frame carries the client completion or the refusal. */
2618
- export function samplingframes(input: { id: number | string; request: samplingrequest }): {
2619
- request: jsonrpcframe;
2620
- answer: jsonrpcframe;
2621
- } {
2622
- const request = {
2623
- jsonrpc: "2.0" as const,
2624
- id: input.id,
2625
- method: "sampling/request",
2626
- params: {
2627
- samplingid: input.request.id,
2628
- prompt: input.request.prompt,
2629
- ...(input.request.system !== undefined ? { system: input.request.system } : {}),
2630
- ...(input.request.pagecontent !== undefined ? { pagecontent: input.request.pagecontent } : {}),
2631
- ...(input.request.maxtokens !== undefined ? { maxtokens: input.request.maxtokens } : {}),
2632
- },
2633
- };
2634
- const answer =
2635
- input.request.state === "answered"
2636
- ? {
2637
- jsonrpc: "2.0" as const,
2638
- id: input.id,
2639
- method: "sampling/answer",
2640
- params: { samplingid: input.request.id, answer: input.request.answer ?? "" },
2641
- }
2642
- : input.request.state === "refused"
2643
- ? {
2644
- jsonrpc: "2.0" as const,
2645
- id: input.id,
2646
- method: "sampling/answer",
2647
- params: { samplingid: input.request.id, refused: true },
2648
- }
2649
- : {
2650
- jsonrpc: "2.0" as const,
2651
- id: input.id,
2652
- method: "sampling/answer",
2653
- params: { samplingid: input.request.id, state: "pending" as const },
2654
- };
2655
- return { request, answer };
2656
- }
2657
-
2658
- /** Builds the prompt tool report: every prompt def with its name, description, declared arguments and template so a client discovers the prompts as callable tools. */
2659
- export function promptreport(input: { prompts: promptdef[] }): {
2660
- version: typeof protocolversion;
2661
- prompts: Array<{ name: string; description: string; arguments: promptdef["arguments"]; template: string }>;
2662
- } {
2663
- return {
2664
- version: protocolversion,
2665
- prompts: input.prompts.map((prompt) => ({
2666
- name: prompt.name,
2667
- description: prompt.description,
2668
- arguments: prompt.arguments,
2669
- template: prompt.template,
2670
- })),
2671
- };
2672
- }
2673
-
2674
- /** Builds the prompt call frame: the prompt name with its arguments that renders the template and returns the arguments as one tool call. */
2675
- export function promptcallframe(input: {
2676
- id: number | string;
2677
- name: string;
2678
- args: Record<string, unknown>;
2679
- }): jsonrpcframe {
2680
- return { jsonrpc: "2.0", id: input.id, method: "prompts/call", params: { name: input.name, arguments: input.args } };
2681
- }
2682
-
2683
- /** Builds one stream chunk notification frame: the call id, the sequence number, the content slice and the done marker of the progressive result. */
2684
- export function streamchunkframe(chunk: streamchunk): jsonrpcframe {
2685
- return {
2686
- jsonrpc: "2.0",
2687
- method: "calls/stream",
2688
- params: { callid: chunk.callid, seq: chunk.seq, content: chunk.content, done: chunk.done, at: chunk.at },
2689
- };
2690
- }
2691
-
2692
- /** Builds one progress notice notification frame: the call id, the percent, the message and the cancel hint of a long tool call. */
2693
- export function progressnoticeframe(notice: progressnotice): jsonrpcframe {
2694
- return {
2695
- jsonrpc: "2.0",
2696
- method: "calls/progress",
2697
- params: {
2698
- callid: notice.callid,
2699
- ...(notice.percent !== undefined ? { percent: notice.percent } : {}),
2700
- message: notice.message,
2701
- cancellable: notice.cancellable,
2702
- at: notice.at,
2703
- },
2704
- };
2705
- }
2706
-
2707
- /** Builds the cancellation frames: the cancel request frame aborts the in flight call by its id while the cancelled response frame carries the preserved partial result. */
2708
- export function cancelframes(input: { id: number | string; frame: cancelframe; partial?: toolresult }): {
2709
- cancel: jsonrpcframe;
2710
- cancelled: jsonrpcframe;
2711
- } {
2712
- const cancel = {
2713
- jsonrpc: "2.0" as const,
2714
- id: input.id,
2715
- method: "calls/cancel",
2716
- params: { callid: input.frame.callid, ...(input.frame.reason !== undefined ? { reason: input.frame.reason } : {}) },
2717
- };
2718
- const cancelled = {
2719
- jsonrpc: "2.0" as const,
2720
- id: input.id,
2721
- result: {
2722
- cancelled: true as const,
2723
- callid: input.frame.callid,
2724
- ...(input.frame.reason !== undefined ? { reason: input.frame.reason } : {}),
2725
- ...(input.partial !== undefined ? { partial: input.partial } : {}),
2726
- },
2727
- };
2728
- return { cancel, cancelled };
2729
- }
2730
-
2731
- /** Builds the structured error report of a refused or failed tool call: the code, the message, the retry hint and the retry after window beside the per client rate limit usage that produced it. */
2732
- export function structurederrorreport(input: {
2733
- error: structurederror;
2734
- usage?: { clientid: string; used: number; budget?: number };
2735
- }): {
2736
- version: typeof protocolversion;
2737
- code: string;
2738
- message: string;
2739
- retryhint: string;
2740
- retryafter?: number;
2741
- usage?: { clientid: string; used: number; budget?: number };
2742
- } {
2743
- return {
2744
- version: protocolversion,
2745
- code: input.error.code,
2746
- message: input.error.message,
2747
- retryhint: input.error.retryhint,
2748
- ...(input.error.retryafter !== undefined ? { retryafter: input.error.retryafter } : {}),
2749
- ...(input.usage !== undefined ? { usage: input.usage } : {}),
2750
- };
2751
- }
2752
-
2753
- /** Builds the idempotent replay frame: the response frame answers a repeated idempotency key with the stored result and the marker that names the original call time. */
2754
- export function idempotencyreplayframe(input: {
2755
- id: number | string;
2756
- key: idempotencykey;
2757
- result: toolresult;
2758
- originalat: number;
2759
- }): jsonrpcframe {
2760
- return {
2761
- jsonrpc: "2.0",
2762
- id: input.id,
2763
- result: { replayed: true, idempotencykey: input.key, originalat: input.originalat, result: input.result },
2764
- };
2765
- }
2766
-
2767
- /** Builds the batch call report: the ordered per item outcomes, the stop on error flag, the state and the member the batch stopped at. */
2768
- export function batchreport(input: { batch: batchcall }): {
2769
- version: typeof protocolversion;
2770
- batchid: string;
2771
- clientid: string;
2772
- state: string;
2773
- stoponerror: boolean;
2774
- done: number;
2775
- total: number;
2776
- outcomes: batchoutcome[];
2777
- } {
2778
- return {
2779
- version: protocolversion,
2780
- batchid: input.batch.id,
2781
- clientid: input.batch.clientid,
2782
- state: input.batch.state,
2783
- stoponerror: input.batch.stoponerror,
2784
- done: input.batch.outcomes.length,
2785
- total: input.batch.calls.length,
2786
- outcomes: input.batch.outcomes,
2787
- };
2788
- }
2789
-
2790
- /** Builds the rate limit usage report: every per client limit with its window, budget, used count and the reset time of the window. */
2791
- export function ratelimitreport(input: { limits: callratelimit[]; now: number }): {
2792
- version: typeof protocolversion;
2793
- limits: Array<{
2794
- clientid: string;
2795
- windowms: number;
2796
- budget?: number;
2797
- used: number;
2798
- unbounded: boolean;
2799
- resetat: number;
2800
- }>;
2801
- } {
2802
- return {
2803
- version: protocolversion,
2804
- limits: input.limits.map((limit) => ({
2805
- clientid: limit.clientid,
2806
- windowms: limit.windowms,
2807
- ...(limit.budget !== undefined ? { budget: limit.budget } : {}),
2808
- used: limit.used,
2809
- unbounded: limit.budget === undefined,
2810
- resetat: limit.windowstartedat + limit.windowms,
2811
- })),
2812
- };
2813
- }
2814
-
2815
- /** Builds the audited tool call log report: every call record with its caller, tool, outcome, idempotency key and markers under the requested filters. */
2816
- export function calllogreport(input: {
2817
- calls: toolcallrecord[];
2818
- filters?: { clientid?: string; tool?: string; ok?: boolean; since?: number; limit?: number };
2819
- }): {
2820
- version: typeof protocolversion;
2821
- calls: toolcallrecord[];
2822
- filters: { clientid?: string; tool?: string; ok?: boolean; since?: number; limit?: number };
2823
- } {
2824
- return { version: protocolversion, calls: input.calls, filters: input.filters ?? {} };
2825
- }
2826
-
2827
- /** Builds the in flight call report: every open call context with its client, tool, start time, chunk count and the markers of the 1.1.56 family. */
2828
- export function inflightreport(input: { contexts: callcontext[]; now: number }): {
2829
- version: typeof protocolversion;
2830
- inflight: Array<{
2831
- callid: string;
2832
- clientid: string;
2833
- tool: string;
2834
- startedat: number;
2835
- msopen: number;
2836
- chunks: number;
2837
- dryrun?: boolean;
2838
- batchid?: string;
2839
- idempotencykey?: idempotencykey;
2840
- }>;
2841
- } {
2842
- return {
2843
- version: protocolversion,
2844
- inflight: input.contexts
2845
- .filter((context) => context.state === "inflight")
2846
- .map((context) => ({
2847
- callid: context.callid,
2848
- clientid: context.clientid,
2849
- tool: context.tool,
2850
- startedat: context.startedat,
2851
- msopen: input.now - context.startedat,
2852
- chunks: context.chunks,
2853
- ...(context.dryrun === true ? { dryrun: true } : {}),
2854
- ...(context.batchid !== undefined ? { batchid: context.batchid } : {}),
2855
- ...(context.idempotencykey !== undefined ? { idempotencykey: context.idempotencykey } : {}),
2856
- })),
2857
- };
2858
- }
2859
-
2860
- /** Builds the dry run report: the findings, the argument validity, the consent evaluation and the executed and mutation markers that stay false and empty. */
2861
- export function dryrunreport(dryrun: tooldryrun): {
2862
- version: typeof protocolversion;
2863
- callid: string;
2864
- tool: string;
2865
- argsvalid: boolean;
2866
- consentok: boolean;
2867
- findings: string[];
2868
- executed: boolean;
2869
- mutations: string[];
2870
- } {
2871
- return {
2872
- version: protocolversion,
2873
- callid: dryrun.callid,
2874
- tool: dryrun.tool,
2875
- argsvalid: dryrun.argsvalid,
2876
- consentok: dryrun.consentok,
2877
- findings: dryrun.findings,
2878
- executed: dryrun.executed,
2879
- mutations: dryrun.mutations,
2880
- };
2881
- }
2882
-
2883
- /** Builds the tool mock report for client testing: every mock with its tool, canned result content, test context marker and creation time. */
2884
- export function mockreport(mocks: toolmock[]): {
2885
- version: typeof protocolversion;
2886
- mocks: Array<{ tool: string; content: string; testcontext: boolean; createdat: number }>;
2887
- } {
2888
- return {
2889
- version: protocolversion,
2890
- mocks: mocks.map((mock) => ({
2891
- tool: mock.tool,
2892
- content: mock.result.content,
2893
- testcontext: mock.testcontext,
2894
- createdat: mock.createdat,
2895
- })),
2896
- };
2897
- }
2898
-
2899
- /** Builds the idempotency record report with the replay semantics: every live record with its key, client, tool and expiry — never the stored result payload. */
2900
- export function idempotencyreport(
2901
- records: idempotencyrecord[],
2902
- now: number,
2903
- ): {
2904
- version: typeof protocolversion;
2905
- records: Array<{
2906
- key: idempotencykey;
2907
- clientid: string;
2908
- tool: string;
2909
- createdat: number;
2910
- expiresat: number;
2911
- live: boolean;
2912
- }>;
2913
- } {
2914
- return {
2915
- version: protocolversion,
2916
- records: records.map((record) => ({
2917
- key: record.key,
2918
- clientid: record.clientid,
2919
- tool: record.tool,
2920
- createdat: record.createdat,
2921
- expiresat: record.expiresat,
2922
- live: now < record.expiresat,
2923
- })),
2924
- };
2925
- }
2926
-
2927
- /**
2928
- * Llm integration envelopes of the 1.1.57 family: the model proposal that carries a model drafted plan to the human review and the model outcome that reports the usage totals and the guard verdicts of the model calls a run made.
2929
- * Both envelopes ride the protocol version like every other report so external reviewers read one grammar.
2930
- */
2931
-
2932
- /** Builds the model proposal envelope that carries one model drafted plan to the human review: the goal, the drafted steps with their fresh review markers, the open questions, the lint findings of the grammar check, the model provenance and the review state; nothing executes until the review approves. */
2933
- export function modelproposal(input: { draft: plandraft }): {
2934
- version: typeof protocolversion;
2935
- modelproposal: {
2936
- draftid: string;
2937
- goal: string;
2938
- steps: Array<{ id: string; kind: string; target?: string; value?: string; summary: string; freshreview?: boolean }>;
2939
- openquestions: string[];
2940
- lintfindings: string[];
2941
- providerid: string;
2942
- model: string;
2943
- state: string;
2944
- createdat: number;
2945
- };
2946
- } {
2947
- return {
2948
- version: protocolversion,
2949
- modelproposal: {
2950
- draftid: input.draft.id,
2951
- goal: input.draft.goal,
2952
- steps: input.draft.steps.map((step) => ({
2953
- id: step.id,
2954
- kind: step.kind,
2955
- ...(step.target !== undefined ? { target: step.target } : {}),
2956
- ...(step.value !== undefined ? { value: step.value } : {}),
2957
- summary: step.summary,
2958
- ...(step.freshreview === true ? { freshreview: true } : {}),
2959
- })),
2960
- openquestions: input.draft.openquestions,
2961
- lintfindings: input.draft.lintfindings,
2962
- providerid: input.draft.providerid,
2963
- model: input.draft.model,
2964
- state: input.draft.state,
2965
- createdat: input.draft.createdat,
2966
- },
2967
- };
2968
- }
2969
-
2970
- /** Builds the model outcome envelope that reports one run of model calls: the usage totals with the token counts, the cost and the call count plus every guard verdict with its reason, so the reviewer reads what the models produced and what the guardrails refused. */
2971
- export function modeloutcome(input: {
2972
- runid?: string;
2973
- outputs: modeloutput[];
2974
- totals: { prompttokens: number; completiontokens: number; totaltokens: number; cost: number; calls: number };
2975
- }): {
2976
- version: typeof protocolversion;
2977
- modeloutcome: {
2978
- runid?: string;
2979
- usage: { prompttokens: number; completiontokens: number; totaltokens: number; cost: number; calls: number };
2980
- guards: Array<{ verdict: string; reason?: string; attempts: number }>;
2981
- };
2982
- } {
2983
- return {
2984
- version: protocolversion,
2985
- modeloutcome: {
2986
- ...(input.runid !== undefined && input.runid.trim() !== "" ? { runid: input.runid } : {}),
2987
- usage: input.totals,
2988
- guards: input.outputs.map((output) => ({
2989
- verdict: output.verdict,
2990
- ...(output.reason !== undefined ? { reason: output.reason } : {}),
2991
- attempts: output.attempts,
2992
- })),
2993
- },
2994
- };
2995
- }
2996
-
2997
- /**
2998
- * Multi agent part one envelopes of the 1.1.58 family: the swarm state report that carries every agent, the shared task queue and every mailbox beside the killswitch state, and the agent event notification frames that push the lifecycle changes.
2999
- *
3000
- * The task queue grammar a client reads: one `taskqueue` object carries the user configured `lanes` (lane names), the `priorities` (the user configured priority scale), the `completionpolicy` (`all` or `any`), the `items` and the live `claims`; one task item carries its `id`, its `lane`, its `priority`, its `payload` in plain language, its `state` (`queued`, `claimed`, `done` or `cancelled`) and its `enqueuedat`; one claim carries the `agentid`, the `taskid`, the `claimedat` and the `heartbeatat` that keeps it alive — a claim whose heartbeat stays silent past the user configured window releases and its task requeues.
3001
- *
3002
- * The mailbox grammar a client reads: one `agentmessage` carries its `id`, the `senderid`, the `recipient` (an agent id for a direct message, a role name for a role addressed message or `*` for the broadcast), the `routing` (`direct`, `broadcast` or `role`), the `payload`, the `sentat` and the optional `readat` of the receive ack; one `agentmailbox` carries its `agentid`, the `inbox`, the `outbox` and the `unread` count.
3003
- *
3004
- * The blackboard grammar a client reads: one `blackboard` carries the `sections` in use (`goals`, `facts`, `findings`, `scratch`), every `entry` and the optional user configured `retirementwindow`; one entry carries its `id`, its `key`, its `valuekind` (`text` or `json`), its `value`, its `author` (an agent id or `user`), its `section`, the `consentclass` inherited from the source extraction (`read`, `interaction` or `sensitive`), the `postedat` and the optional `retiredat` — every agent of the swarm reads the same board and a retired entry stays stored for the audit trail while the live reads stop showing it.
3005
- */
3006
-
3007
- /** Builds the swarm state report: every agent with its id, name, role, tab, state, depth and heartbeat, the shared task queue with its lanes, priorities, policy, items and claims, every mailbox with its unread count and the killswitch state. */
3008
- export function swarmstatereport(state: swarmstate): {
3009
- version: typeof protocolversion;
3010
- swarm: {
3011
- agents: Array<{
3012
- id: string;
3013
- name: string;
3014
- role: string;
3015
- state: string;
3016
- depth: number;
3017
- tabid?: number;
3018
- parentid?: string;
3019
- heartbeatat?: number;
3020
- }>;
3021
- queue: {
3022
- lanes: string[];
3023
- priorities: number[];
3024
- completionpolicy: string;
3025
- items: Array<{ id: string; lane: string; priority: number; payload: string; state: string; enqueuedat: number }>;
3026
- claims: Array<{ agentid: string; taskid: string; claimedat: number; heartbeatat: number }>;
3027
- };
3028
- mailboxes: Array<{ agentid: string; unread: number; inbox: number; outbox: number }>;
3029
- killswitch: { engaged: boolean; engagedat?: number; reason?: string };
3030
- };
3031
- } {
3032
- return {
3033
- version: protocolversion,
3034
- swarm: {
3035
- agents: state.agents.map((agent) => ({
3036
- id: agent.id,
3037
- name: agent.name,
3038
- role: agent.role,
3039
- state: agent.state,
3040
- depth: agent.depth,
3041
- ...(agent.tabid !== undefined ? { tabid: agent.tabid } : {}),
3042
- ...(agent.parentid !== undefined ? { parentid: agent.parentid } : {}),
3043
- ...(agent.heartbeatat !== undefined ? { heartbeatat: agent.heartbeatat } : {}),
3044
- })),
3045
- queue: {
3046
- lanes: state.queue.lanes,
3047
- priorities: state.queue.priorities,
3048
- completionpolicy: state.queue.completionpolicy,
3049
- items: state.queue.items.map((item) => ({
3050
- id: item.id,
3051
- lane: item.lane,
3052
- priority: item.priority,
3053
- payload: item.payload,
3054
- state: item.state,
3055
- enqueuedat: item.enqueuedat,
3056
- })),
3057
- claims: state.queue.claims,
3058
- },
3059
- mailboxes: state.mailboxes.map((mailbox) => ({
3060
- agentid: mailbox.agentid,
3061
- unread: mailbox.unread,
3062
- inbox: mailbox.inbox.length,
3063
- outbox: mailbox.outbox.length,
3064
- })),
3065
- killswitch: {
3066
- engaged: state.killswitch.engaged,
3067
- ...(state.killswitch.engagedat !== undefined ? { engagedat: state.killswitch.engagedat } : {}),
3068
- ...(state.killswitch.reason !== undefined ? { reason: state.killswitch.reason } : {}),
3069
- },
3070
- },
3071
- };
3072
- }
3073
-
3074
- /** Builds one agent event notification frame that pushes a lifecycle change: the event kind, the agent and task it names and the summary in plain language; the frame rides the agents/notify method of the swarm grammar. */
3075
- export function agenteventframe(event: agentevent): jsonrpcframe {
3076
- return {
3077
- jsonrpc: "2.0",
3078
- method: "agents/notify",
3079
- params: {
3080
- eventid: event.id,
3081
- kind: event.kind,
3082
- ...(event.agentid !== undefined ? { agentid: event.agentid } : {}),
3083
- ...(event.taskid !== undefined ? { taskid: event.taskid } : {}),
3084
- summary: event.summary,
3085
- at: event.at,
3086
- },
3087
- };
3088
- }
3089
-
3090
- /**
3091
- * Multi agent part two envelopes of the 1.1.59 family: the boardstate snapshot that carries the progressboard lanes and milestones for dashboards, the handoff frame that pushes a tab handoff state and the review frame that pushes one review request with its optional critic verdict.
3092
- *
3093
- * The leader worker and handoff grammar a client reads: one `leaderworker` topology carries its `id`, the `leaderid`, the `workerids`, `criticids` and `verifierids` lanes, every `assignment` (a `workerid`, a `taskid`, a plain language `slice` and the `assignedat`) and the user configured `rule` (`first` takes the first registration, `named` takes the agent the user named); one `handoffrecord` carries its `id`, the `fromagentid`, the `toagentid`, the `tabid`, the packaged `taskstate` in plain language, the `state` (`prepared`, `transferred` or `resumed`) and the `transferredat` and `resumedat` times — the transfer moves the tab binding under the one agent per tab rule and the resume continues exactly from the packaged task state while the original session grants stay preserved.
3094
- *
3095
- * The locks, conflicts and merge grammar a client reads: one `resourcelock` carries its `key` (the one origin and the one selector joined by `|`, so a lock never spans unrelated origins), its `holder`, the `kind` (`exclusive` or `shared`), the `origin`, the `selector`, the `acquiredat` and the optional `expiresat` a sweep honours; one `conflictscan` carries the `writers` examined, the `overlaps` (every origin and selector with its writers), the deterministic `suggestedorder` and the `clean` marker; one `mergeentry` carries the `agentid`, the `taskid`, the `key`, the `value` and the optional `conflict` resolution note, and the `mergerule` stays `first`, `last`, `preferagent` or `fail` — the overwriting rules grade sensitive, every merged value keeps its provenance and an exported report that includes page content grades as a data egress event.
3096
- */
3097
-
3098
- /** Builds the boardstate snapshot envelope for dashboards: every progressboard lane with its agent, name, role, state, lane of work, current task and milestones, so one report reads every agent at once. */
3099
- export function boardstatesnapshot(board: progressboard): {
3100
- version: typeof protocolversion;
3101
- board: {
3102
- id: string;
3103
- builtat: number;
3104
- lanes: Array<{
3105
- agentid: string;
3106
- name: string;
3107
- role: string;
3108
- state: string;
3109
- lane: string;
3110
- currenttask?: string;
3111
- milestones: Array<{ label: string; done: boolean; at?: number }>;
3112
- }>;
3113
- };
3114
- } {
3115
- return {
3116
- version: protocolversion,
3117
- board: {
3118
- id: board.id,
3119
- builtat: board.builtat,
3120
- lanes: board.lanes.map((lane) => ({
3121
- agentid: lane.agentid,
3122
- name: lane.name,
3123
- role: lane.role,
3124
- state: lane.state,
3125
- lane: lane.lane,
3126
- ...(lane.currenttask !== undefined ? { currenttask: lane.currenttask } : {}),
3127
- milestones: lane.milestones.map((milestone) => ({
3128
- label: milestone.label,
3129
- done: milestone.done,
3130
- ...(milestone.at !== undefined ? { at: milestone.at } : {}),
3131
- })),
3132
- })),
3133
- },
3134
- };
3135
- }
3136
-
3137
- /** Builds one handoff frame that pushes a tab handoff state: the agents, the tab, the packaged task state, the handoff state and the transfer and resume times; the frame rides the agents/handoff method of the swarm grammar. */
3138
- export function handoffframe(record: handoffrecord): jsonrpcframe {
3139
- return {
3140
- jsonrpc: "2.0",
3141
- method: "agents/handoff",
3142
- params: {
3143
- id: record.id,
3144
- from: record.fromagentid,
3145
- to: record.toagentid,
3146
- ...(record.tabid !== undefined ? { tabid: record.tabid } : {}),
3147
- taskstate: record.taskstate,
3148
- state: record.state,
3149
- ...(record.transferredat !== undefined ? { transferredat: record.transferredat } : {}),
3150
- ...(record.resumedat !== undefined ? { resumedat: record.resumedat } : {}),
3151
- },
3152
- };
3153
- }
3154
-
3155
- /** Builds one review frame that pushes a routed review request with its optional critic verdict: the requester, the reviewer, the subject, the request state and the verdict with its issues and required changes when the critic answered; the frame rides the agents/review method of the swarm grammar. */
3156
- export function reviewframe(input: { request: reviewrequest; review?: criticreview }): jsonrpcframe {
3157
- return {
3158
- jsonrpc: "2.0",
3159
- method: "agents/review",
3160
- params: {
3161
- id: input.request.id,
3162
- from: input.request.fromagentid,
3163
- to: input.request.toagentid,
3164
- subject: input.request.subject,
3165
- state: input.request.state,
3166
- ...(input.request.ackedat !== undefined ? { ackedat: input.request.ackedat } : {}),
3167
- ...(input.request.answeredat !== undefined ? { answeredat: input.request.answeredat } : {}),
3168
- ...(input.review !== undefined
3169
- ? { verdict: input.review.verdict, issues: input.review.issues, requiredchanges: input.review.requiredchanges }
3170
- : {}),
3171
- },
3172
- };
3173
- }
3174
-
3175
- /**
3176
- * Execution environment envelopes of the 1.1.60 family.
3177
- * The environment grammar per kind: the evaluate kind runs inside the isolated world only, a step whose reviewed options carry untrusted markup renders inside the sandboxframe only, the parse heavy read kinds (html snapshots, network json payloads, table row reductions, accessibility tree shaping, complex selector evaluation and screenshot stitching) choose between the pagecontext and the offscreen worker pool, and every other kind keeps the pagecontext of the page bridge because page events only fire there.
3178
- * Every environment executes only reviewed steps against granted origins: the session environment grant list narrows the steps of one session, the optional offscreen capability keeps the worker pool behind the user grant with an inline fallback, and the sandbox frame strips scripts and handlers before any render.
3179
- */
3180
-
3181
- /** Documents the environment grammar of every reviewed action kind as one versioned envelope: one profile per kind with its allowed environments and its default beside the consent notes every environment carries. */
3182
- export function environmentgrammar(): {
3183
- version: typeof protocolversion;
3184
- kinds: environmentrequirement[];
3185
- notes: string[];
3186
- } {
3187
- return {
3188
- version: protocolversion,
3189
- kinds: environmentrequirements(),
3190
- notes: [
3191
- "The evaluate kind runs inside the isolated world only where page globals stay unreachable from step code.",
3192
- "A step whose reviewed options carry untrusted markup renders inside the sandboxframe only, with scripts and event handlers stripped before the render.",
3193
- "The parse heavy read kinds offload into the offscreen worker pool only under the user granted offscreen capability and the parse offload toggle, with an inline fallback inside the page.",
3194
- "Every environment executes only reviewed steps against granted origins; the session environment grant list narrows the steps of one session and no environment ever bypasses the human review.",
3195
- ],
3196
- };
3197
- }
3198
-
3199
- /** Wraps the execution environment view in the versioned response envelope: the environment of every executed step, the worker turnaround of every offloaded step, the offscreen document registry, the worker pool count and the keepalive heartbeat trail. */
3200
- export function environmentreport(input: {
3201
- environments: Record<string, environmentkind>;
3202
- turnarounds?: Record<string, number>;
3203
- offscreen?: offscreenregistryentry[];
3204
- workers?: number;
3205
- keepalive?: { runid: string; state: string; beats: number; lastbeatat: number; portopen: boolean };
3206
- }): {
3207
- version: typeof protocolversion;
3208
- environments: Array<{ stepid: string; environment: environmentkind }>;
3209
- turnarounds: Array<{ stepid: string; milliseconds: number }>;
3210
- offscreen: offscreenregistryentry[];
3211
- workers: number;
3212
- keepalive?: { runid: string; state: string; beats: number; lastbeatat: number; portopen: boolean };
3213
- } {
3214
- return {
3215
- version: protocolversion,
3216
- environments: Object.entries(input.environments).map(([stepid, environment]) => ({ stepid, environment })),
3217
- turnarounds: Object.entries(input.turnarounds ?? {}).map(([stepid, milliseconds]) => ({ stepid, milliseconds })),
3218
- offscreen: input.offscreen ?? [],
3219
- workers: input.workers ?? 0,
3220
- ...(input.keepalive !== undefined ? { keepalive: input.keepalive } : {}),
3221
- };
3222
- }
3223
-
3224
- /**
3225
- * Security part one envelopes of the 1.1.61 family.
3226
- * The consent model grammar per origin: the denydefault posture refuses every ungranted origin, the per origin automation allowlist binds each grant to one exact origin with no wildcard expansion while the active tab grant counts as exactly one explicit single origin grant, the per site originprofiles grant and deny single action kinds, the consentwindows bind every grant in time with a named boundary that never defaults to unlimited, the sensitive classes route payment, credential, delete and publish steps through one fresh consent prompt per class per origin, the revokerun halts the pending step and every queued step as a terminal session event, and the immutable run log chains every entry through its loghash while the completion seal closes the chain.
3227
- */
3228
-
3229
- /** Documents the consent model grammar as one versioned envelope: the posture, the sensitive classes, the mask shape families and the consent notes every security surface carries. */
3230
- export function consentmodel(): {
3231
- version: typeof protocolversion;
3232
- posture: "denydefault";
3233
- sensitiveclasses: string[];
3234
- maskshapes: string[];
3235
- notes: string[];
3236
- } {
3237
- return {
3238
- version: protocolversion,
3239
- posture: "denydefault",
3240
- sensitiveclasses: ["payment", "credential", "delete", "publish"],
3241
- maskshapes: [...defaultmaskshapes],
3242
- notes: [
3243
- "The denydefault posture refuses every origin the user never granted; the per origin automation allowlist holds one exact origin per entry with no wildcard expansion and the active tab grant counts as exactly one explicit single origin grant.",
3244
- "The per site originprofiles grant and deny single action kinds; a denied kind never runs on that origin and a granted kind still routes its sensitive classes through the fresh consent prompts.",
3245
- "Every consent window scopes to one session and one origin, binds the duration the user chose and names its boundary; no grant ever defaults to unlimited, and a window past its boundary suspends the run mid step until a new explicit prompt renews it.",
3246
- "The revokerun is a terminal session event: the pending step and every queued step halt without executing and the immutable log records the user action.",
3247
- "The immutable run log appends only: every entry chains through its loghash to the hash of its predecessor, the completion seal writes the final hash, and the read path verifies the whole chain before serving a single entry.",
3248
- "maskinputs keeps typed values, form values and stored values out of every record behind the documented password, token, card and secret shapes the user extends; the observation schema keeps its field shapes while the values carry the redaction marker.",
3249
- ],
3250
- };
3251
- }
3252
-
3253
- /** Wraps the security view in the versioned response envelope: the automation allowlist, the per origin profiles, the active consent windows with their remaining time, the fresh class consents, the revocation history, the mask rules and the per run chain verification with the seal hash. */
3254
- export function securityreport(input: {
3255
- allowlist: Array<{ origin: string; profileid: string; grantedat: number }>;
3256
- profiles: originprofile[];
3257
- windows: consentwindow[];
3258
- consents: classconsent[];
3259
- revocations: revokerunevent[];
3260
- maskrules: maskrule[];
3261
- chain: Array<{
3262
- runid: string;
3263
- valid: boolean;
3264
- entries: number;
3265
- brokenat?: number;
3266
- reason: string;
3267
- sealhash?: string;
3268
- sealedat?: number;
3269
- }>;
3270
- }): {
3271
- version: typeof protocolversion;
3272
- posture: "denydefault";
3273
- allowlist: Array<{ origin: string; profileid: string; grantedat: number }>;
3274
- profiles: originprofile[];
3275
- windows: consentwindow[];
3276
- consents: classconsent[];
3277
- revocations: revokerunevent[];
3278
- maskrules: maskrule[];
3279
- chain: Array<{
3280
- runid: string;
3281
- valid: boolean;
3282
- entries: number;
3283
- brokenat?: number;
3284
- reason: string;
3285
- sealhash?: string;
3286
- sealedat?: number;
3287
- }>;
3288
- } {
3289
- return {
3290
- version: protocolversion,
3291
- posture: "denydefault",
3292
- allowlist: input.allowlist,
3293
- profiles: input.profiles,
3294
- windows: input.windows,
3295
- consents: input.consents,
3296
- revocations: input.revocations,
3297
- maskrules: input.maskrules,
3298
- chain: input.chain,
3299
- };
3300
- }
3301
-
3302
- /** Wraps one run log chain verification in the versioned response envelope: the chain validity, the entry count, the broken link when one exists, the seal hash at completion and the reason in plain language. */
3303
- export function logchainreport(input: {
3304
- runid: string;
3305
- valid: boolean;
3306
- entries: number;
3307
- brokenat?: number;
3308
- reason: string;
3309
- sealhash?: string;
3310
- sealedat?: number;
3311
- }): {
3312
- version: typeof protocolversion;
3313
- runid: string;
3314
- valid: boolean;
3315
- entries: number;
3316
- brokenat?: number;
3317
- reason: string;
3318
- sealhash?: string;
3319
- sealedat?: number;
3320
- } {
3321
- return {
3322
- version: protocolversion,
3323
- runid: input.runid,
3324
- valid: input.valid,
3325
- entries: input.entries,
3326
- ...(input.brokenat !== undefined ? { brokenat: input.brokenat } : {}),
3327
- reason: input.reason,
3328
- ...(input.sealhash !== undefined ? { sealhash: input.sealhash } : {}),
3329
- ...(input.sealedat !== undefined ? { sealedat: input.sealedat } : {}),
3330
- };
3331
- }
3332
-
3333
- /**
3334
- * Security part two envelopes of the 1.1.62 family.
3335
- * The transparency grammar: the transparencypage reads every active grant with its origin, scope and boundary, every consent window ever granted with its expiry, the connectallow entries with their senders, the permdiff of each installed update and the revoke action every listed grant offers, in one versioned envelope served by a single memory read.
3336
- */
3337
-
3338
- /** Wraps the transparency view of the transparencypage in the versioned response envelope: the grant rows with their revoke actions, the whole consent window history, the connectallow senders, the permdiff records of each installed update, the safedefaults applications and the posture notice. */
3339
- export function transparencyreport(input: {
3340
- grants: Array<{ origin: string; scope: string; boundary: string; grantedat: number }>;
3341
- windows: Array<{ id: string; origin: string; state: string; boundary: string; startedat: number; expiresat: number }>;
3342
- connectallow: Array<{ senderid: string; displayname: string; origin?: string; addedat: number }>;
3343
- permdiffs: Array<{ fromversion: string; toversion: string; added: string[]; removed: string[]; computedat: number }>;
3344
- safedefaults: Array<{ origin: string; firstseenat: number }>;
3345
- vault: Array<{
3346
- vaultid: string;
3347
- label: string;
3348
- scope: string;
3349
- provenance: string;
3350
- createdat: number;
3351
- lastusedat?: number;
3352
- }>;
3353
- }): {
3354
- version: typeof protocolversion;
3355
- posture: "denydefault";
3356
- grants: Array<{ origin: string; scope: string; boundary: string; grantedat: number }>;
3357
- windows: Array<{ id: string; origin: string; state: string; boundary: string; startedat: number; expiresat: number }>;
3358
- connectallow: Array<{ senderid: string; displayname: string; origin?: string; addedat: number }>;
3359
- permdiffs: Array<{ fromversion: string; toversion: string; added: string[]; removed: string[]; computedat: number }>;
3360
- safedefaults: Array<{ origin: string; firstseenat: number }>;
3361
- vault: Array<{
3362
- vaultid: string;
3363
- label: string;
3364
- scope: string;
3365
- provenance: string;
3366
- createdat: number;
3367
- lastusedat?: number;
3368
- }>;
3369
- } {
3370
- return {
3371
- version: protocolversion,
3372
- posture: "denydefault",
3373
- grants: input.grants,
3374
- windows: input.windows,
3375
- connectallow: input.connectallow,
3376
- permdiffs: input.permdiffs,
3377
- safedefaults: input.safedefaults,
3378
- vault: input.vault,
3379
- };
3380
- }
3381
-
3382
- /**
3383
- * Interface surface envelope of the 1.1.64 family.
3384
- * The surface grammar: one versioned envelope carries the snapshot a surface renders — its ranked commandpalette matches, its stepstimeline nodes derived from progress with no new state, its live logstream events with their mask verdicts, its plancard groups with the sensitive classes expanded by default and its onboarding state — so every surface reads the same shaped answer from the single command bus.
3385
- */
3386
-
3387
- /** Wraps one interface surface snapshot in the versioned response envelope: the ranked palette matches, the stepstimeline nodes, the bounded live logstream window with its chain verdict, the plancard groups and the onboarding state. */
3388
- export function surfacesnapshot(input: {
3389
- surface: "popup" | "sidepanel" | "dashboardpage" | "optionspage" | "onboarding" | "omnibox" | "page";
3390
- palette: Array<{
3391
- entry: {
3392
- id: string;
3393
- label: string;
3394
- keywords: string[];
3395
- action: { command: string; surface: string; permission?: string; session?: boolean };
3396
- };
3397
- score: number;
3398
- reason: string;
3399
- }>;
3400
- timeline: Array<{
3401
- stepid: string;
3402
- kind: string;
3403
- status: string;
3404
- durationms?: number;
3405
- environment?: string;
3406
- active: boolean;
3407
- anchor: string;
3408
- resultsummary?: string;
3409
- }>;
3410
- logstream: {
3411
- events: Array<{
3412
- id: string;
3413
- level: string;
3414
- source: string;
3415
- origin: string;
3416
- summary: string;
3417
- stepid?: string;
3418
- masked: boolean;
3419
- maskverdict: string;
3420
- at: number;
3421
- }>;
3422
- chainvalid: boolean;
3423
- reason: string;
3424
- };
3425
- plancards: Array<{
3426
- risk: string;
3427
- cards: Array<{
3428
- stepid: string;
3429
- kind: string;
3430
- risk: string;
3431
- environment: string;
3432
- options: string;
3433
- summary: string;
3434
- corrections: Array<{ id: string; source: string; reason: string }>;
3435
- editable: boolean;
3436
- }>;
3437
- expanded: boolean;
3438
- }>;
3439
- onboarding?: { stepscompleted: string[]; done: boolean };
3440
- }): {
3441
- version: typeof protocolversion;
3442
- surface: string;
3443
- palette: Array<{
3444
- entry: {
3445
- id: string;
3446
- label: string;
3447
- keywords: string[];
3448
- action: { command: string; surface: string; permission?: string; session?: boolean };
3449
- };
3450
- score: number;
3451
- reason: string;
3452
- }>;
3453
- timeline: Array<{
3454
- stepid: string;
3455
- kind: string;
3456
- status: string;
3457
- durationms?: number;
3458
- environment?: string;
3459
- active: boolean;
3460
- anchor: string;
3461
- resultsummary?: string;
3462
- }>;
3463
- logstream: {
3464
- events: Array<{
3465
- id: string;
3466
- level: string;
3467
- source: string;
3468
- origin: string;
3469
- summary: string;
3470
- stepid?: string;
3471
- masked: boolean;
3472
- maskverdict: string;
3473
- at: number;
3474
- }>;
3475
- chainvalid: boolean;
3476
- reason: string;
3477
- };
3478
- plancards: Array<{
3479
- risk: string;
3480
- cards: Array<{
3481
- stepid: string;
3482
- kind: string;
3483
- risk: string;
3484
- environment: string;
3485
- options: string;
3486
- summary: string;
3487
- corrections: Array<{ id: string; source: string; reason: string }>;
3488
- editable: boolean;
3489
- }>;
3490
- expanded: boolean;
3491
- }>;
3492
- onboarding?: { stepscompleted: string[]; done: boolean };
3493
- } {
3494
- return {
3495
- version: protocolversion,
3496
- surface: input.surface,
3497
- palette: input.palette,
3498
- timeline: input.timeline,
3499
- logstream: input.logstream,
3500
- plancards: input.plancards,
3501
- ...(input.onboarding !== undefined ? { onboarding: input.onboarding } : {}),
3502
- };
3503
- }
3504
-
3505
- /**
3506
- * Interface surface envelope of the 1.1.65 family, part two.
3507
- * The finishing surface grammar: one versioned envelope carries the second interface snapshot a surface renders — its datagrid view with the inferred columns, its exportmenu descriptors, its statusbadge state with the waiting gate count, its recenttray entries with the resume and reopen offers, its steteoast live stack with the full history count and its appearance resolution naming whether the os preference, the user override or the siteprofile decided — so every surface reads the same shaped answer from the single command bus.
3508
- */
3509
-
3510
- /** Wraps one finishing interface snapshot in the versioned response envelope: the datagrid view, the exportmenu descriptors, the statusbadge state, the recenttray entries, the steteoast stack and the resolved appearance tokens. */
3511
- export function interfaceviews(input: {
3512
- datagrid?: {
3513
- id: string;
3514
- title: string;
3515
- origin: string;
3516
- runid: string;
3517
- columns: Array<{ field: string; label: string; type: string; inferred: boolean }>;
3518
- rows: Array<{ index: number; values: Record<string, string>; selected?: boolean }>;
3519
- at: number;
3520
- };
3521
- exportmenu: Array<{ format: string; scope: string; destination: string }>;
3522
- badge: { state: string; waitingcount: number; runid?: string };
3523
- recenttray: Array<{
3524
- runid: string;
3525
- origin: string;
3526
- outcome: string;
3527
- title: string;
3528
- at: number;
3529
- resumable: boolean;
3530
- reopenable: boolean;
3531
- }>;
3532
- toasts: { live: Array<{ id: string; stepid: string; kind: string; durationms: number; at: number }>; total: number };
3533
- appearance: { mode: string; tokens: Record<string, string>; source: string };
3534
- }): {
3535
- version: typeof protocolversion;
3536
- datagrid?: {
3537
- id: string;
3538
- title: string;
3539
- origin: string;
3540
- runid: string;
3541
- columns: Array<{ field: string; label: string; type: string; inferred: boolean }>;
3542
- rows: Array<{ index: number; values: Record<string, string>; selected?: boolean }>;
3543
- at: number;
3544
- };
3545
- exportmenu: Array<{ format: string; scope: string; destination: string }>;
3546
- badge: { state: string; waitingcount: number; runid?: string };
3547
- recenttray: Array<{
3548
- runid: string;
3549
- origin: string;
3550
- outcome: string;
3551
- title: string;
3552
- at: number;
3553
- resumable: boolean;
3554
- reopenable: boolean;
3555
- }>;
3556
- toasts: { live: Array<{ id: string; stepid: string; kind: string; durationms: number; at: number }>; total: number };
3557
- appearance: { mode: string; tokens: Record<string, string>; source: string };
3558
- } {
3559
- return {
3560
- version: protocolversion,
3561
- ...(input.datagrid !== undefined ? { datagrid: input.datagrid } : {}),
3562
- exportmenu: input.exportmenu,
3563
- badge: input.badge,
3564
- recenttray: input.recenttray,
3565
- toasts: input.toasts,
3566
- appearance: input.appearance,
3567
- };
3568
- }
3569
-
3570
- /**
3571
- * Ecosystem envelope of the 1.1.66 family.
3572
- * The ecosystem grammar: one versioned envelope carries the ecosystem snapshot a surface renders — the flowlibrary browser rows with their publishers, versions and required grants, the installed library entries beside the native workflows, the syncbridge hooks with their opt in states and conflict records, the ranked attentionfeed entries with their deep links, the background run queue with its progress, the runreplay view with its cursor and the outputcompare view with its divergence highlights — so every surface reads the same shaped answer from the single command bus.
3573
- */
3574
-
3575
- /** Wraps one ecosystem snapshot in the versioned response envelope: the library browser rows, the installed entries, the syncbridge hooks and conflicts, the ranked attention entries, the background runs, the replay view and the comparison view. */
3576
- export function ecosystemviews(input: {
3577
- library: Array<{
3578
- id: string;
3579
- title: string;
3580
- publisher: string;
3581
- version: string;
3582
- grants: string[];
3583
- sensitive: boolean;
3584
- state: string;
3585
- registry?: string;
3586
- }>;
3587
- installed: Array<{ id: string; title: string; version: string; forkable: boolean }>;
3588
- syncbridge: {
3589
- hooks: Array<{ id: string; provider: string; direction: string; optin: boolean; endpoint: string; state: string }>;
3590
- conflicts: Array<{
3591
- id: string;
3592
- manifestid: string;
3593
- localversion: string;
3594
- remoteversion: string;
3595
- resolution?: string;
3596
- }>;
3597
- };
3598
- attention: Array<{
3599
- id: string;
3600
- cause: string;
3601
- severity: string;
3602
- runid: string;
3603
- summary: string;
3604
- deeplink: string;
3605
- at: number;
3606
- }>;
3607
- backgroundruns: Array<{ id: string; workflowid: string; state: string; keepaliveheld: boolean; progress: string }>;
3608
- replay?: {
3609
- runid: string;
3610
- cursor: number;
3611
- playing: boolean;
3612
- steps: Array<{ stepid: string; index: number; summary: string; agreement?: string }>;
3613
- restored: { stepid: string; summary: string; observationversion?: number; captureid?: string };
3614
- };
3615
- compare?: {
3616
- runids: [string, string];
3617
- metrics: string[];
3618
- firstdivergence?: number;
3619
- steps: Array<{
3620
- stepid: string;
3621
- agreement: string;
3622
- summarya: string;
3623
- summaryb: string;
3624
- durationdelta: number;
3625
- highlighted: boolean;
3626
- }>;
3627
- };
3628
- }): {
3629
- version: typeof protocolversion;
3630
- library: Array<{
3631
- id: string;
3632
- title: string;
3633
- publisher: string;
3634
- version: string;
3635
- grants: string[];
3636
- sensitive: boolean;
3637
- state: string;
3638
- registry?: string;
3639
- }>;
3640
- installed: Array<{ id: string; title: string; version: string; forkable: boolean }>;
3641
- syncbridge: {
3642
- hooks: Array<{ id: string; provider: string; direction: string; optin: boolean; endpoint: string; state: string }>;
3643
- conflicts: Array<{
3644
- id: string;
3645
- manifestid: string;
3646
- localversion: string;
3647
- remoteversion: string;
3648
- resolution?: string;
3649
- }>;
3650
- };
3651
- attention: Array<{
3652
- id: string;
3653
- cause: string;
3654
- severity: string;
3655
- runid: string;
3656
- summary: string;
3657
- deeplink: string;
3658
- at: number;
3659
- }>;
3660
- backgroundruns: Array<{ id: string; workflowid: string; state: string; keepaliveheld: boolean; progress: string }>;
3661
- replay?: {
3662
- runid: string;
3663
- cursor: number;
3664
- playing: boolean;
3665
- steps: Array<{ stepid: string; index: number; summary: string; agreement?: string }>;
3666
- restored: { stepid: string; summary: string; observationversion?: number; captureid?: string };
3667
- };
3668
- compare?: {
3669
- runids: [string, string];
3670
- metrics: string[];
3671
- firstdivergence?: number;
3672
- steps: Array<{
3673
- stepid: string;
3674
- agreement: string;
3675
- summarya: string;
3676
- summaryb: string;
3677
- durationdelta: number;
3678
- highlighted: boolean;
3679
- }>;
3680
- };
3681
- } {
3682
- return {
3683
- version: protocolversion,
3684
- library: input.library,
3685
- installed: input.installed,
3686
- syncbridge: input.syncbridge,
3687
- attention: input.attention,
3688
- backgroundruns: input.backgroundruns,
3689
- ...(input.replay !== undefined ? { replay: input.replay } : {}),
3690
- ...(input.compare !== undefined ? { compare: input.compare } : {}),
3691
- };
3692
- }
3693
-
3694
- /** Builds the perf report envelope of the 1.1.68 performance family: the perf summary of one recent run beside its step duration chart, the selcache generation, the worker queue depth and the chunk cursor progress, all in one envelope the dashboardpage and the sidepanel read. */
3695
- export function perfreport(input: {
3696
- runid: string;
3697
- summary: {
3698
- steps: number;
3699
- duration: number;
3700
- average: number;
3701
- queries: number;
3702
- cachehits: number;
3703
- hitratio: number;
3704
- deltashare: number;
3705
- };
3706
- chart: Array<{ stepid: string; duration: number; delta: boolean }>;
3707
- selcache: { generation: number; entries: number };
3708
- queue: { depth: number; deferred: number; peak: number };
3709
- chunk?: { tableid: string; extracted: number; total: number; complete: boolean };
3710
- }): {
3711
- version: typeof protocolversion;
3712
- runid: string;
3713
- summary: {
3714
- steps: number;
3715
- duration: number;
3716
- average: number;
3717
- queries: number;
3718
- cachehits: number;
3719
- hitratio: number;
3720
- deltashare: number;
3721
- };
3722
- chart: Array<{ stepid: string; duration: number; delta: boolean }>;
3723
- selcache: { generation: number; entries: number };
3724
- queue: { depth: number; deferred: number; peak: number };
3725
- chunk?: { tableid: string; extracted: number; total: number; complete: boolean };
3726
- } {
3727
- if (input.runid.trim() === "") throw new Error("The perf report needs its run id.");
3728
- return {
3729
- version: protocolversion,
3730
- runid: input.runid,
3731
- summary: input.summary,
3732
- chart: [...input.chart],
3733
- selcache: input.selcache,
3734
- queue: input.queue,
3735
- ...(input.chunk !== undefined ? { chunk: input.chunk } : {}),
3736
- };
3737
- }
3738
-
3739
- /** Builds the schedule report envelope of the 1.1.69 performance part two family: the batch backpressure signal, the domain lanes with their concurrency slots, the budgetalerts with their thresholds, the timeoutcancel events with their retry hints, the cold start sample and the selectorprofile latencies, all in one envelope the sidepanel, the dashboardpage and the popup read. */
3740
- export function schedulereport(input: {
3741
- backpressure: {
3742
- runid: string;
3743
- enqueued: number;
3744
- completed: number;
3745
- behind: number;
3746
- paused: boolean;
3747
- window?: number;
3748
- };
3749
- lanes: Array<{ domain: string; slots: number; running: number; queued: number }>;
3750
- alerts: Array<{ runid: string; level: string; kind: string; ratio: number; paused: boolean }>;
3751
- timeouts: Array<{ stepid: string; bound: number; elapsed: number; logged: boolean }>;
3752
- startup?: { duration: number; spent: number; target?: number };
3753
- selectors?: Array<{ selector: string; average: number; count: number; failures: number; flagged: boolean }>;
3754
- }): {
3755
- version: typeof protocolversion;
3756
- backpressure: {
3757
- runid: string;
3758
- enqueued: number;
3759
- completed: number;
3760
- behind: number;
3761
- paused: boolean;
3762
- window?: number;
3763
- };
3764
- lanes: Array<{ domain: string; slots: number; running: number; queued: number }>;
3765
- alerts: Array<{ runid: string; level: string; kind: string; ratio: number; paused: boolean }>;
3766
- timeouts: Array<{ stepid: string; bound: number; elapsed: number; logged: boolean }>;
3767
- startup?: { duration: number; spent: number; target?: number };
3768
- selectors?: Array<{ selector: string; average: number; count: number; failures: number; flagged: boolean }>;
3769
- } {
3770
- if (input.backpressure.runid.trim() === "") throw new Error("The schedule report needs its run id.");
3771
- return {
3772
- version: protocolversion,
3773
- backpressure: input.backpressure,
3774
- lanes: input.lanes.map((lane) => ({ ...lane })),
3775
- alerts: input.alerts.map((alert) => ({ ...alert })),
3776
- timeouts: input.timeouts.map((timeout) => ({ ...timeout })),
3777
- ...(input.startup !== undefined ? { startup: input.startup } : {}),
3778
- ...(input.selectors !== undefined ? { selectors: input.selectors.map((stats) => ({ ...stats })) } : {}),
3779
- };
3780
- }
3781
-
3782
- /**
3783
- * The queue and replay message grammar of the 1.1.70 resilience family: a plan proposal may carry the `resumedfrom` marker naming the checkpointed step ids of the run it resumes, every step may carry its `idempotencykey` derived from the plan and step identity, two steps of one plan never collide on the same key, the request body carries the live `runstate` and the `queuedepth` of the offlinequeue beside the observation so the agent context sees the run machine it replays into, and every response envelope carries the `runid` and the `runstate` so a replay maps to its run.
3784
- * The offlinequeue itself lives behind the memory adapter: an approved plan enqueues with a monotonic sequence, the replay drains the tasks in sequence order once connectivity returns, and a task whose plan window passed offline expires and fails instead of replaying.
3785
- */
3786
-
3787
- /** Validates that one rollback step summary stays human readable: a compensation the user cannot read never runs, whatever its machine payload says. */
3788
- export function rollbacksummarycheck(summary: string): { ok: boolean; reason: string } {
3789
- if (summary.trim() === "")
3790
- return { ok: false, reason: "The rollback step summary is empty; a compensation the user cannot read never runs." };
3791
- if (summary !== summary.trim())
3792
- return {
3793
- ok: false,
3794
- reason: "The rollback step summary carries untrimmed padding; a compensation the user cannot read never runs.",
3795
- };
3796
- if (/[\u0000-\u001f\u007f]/.test(summary))
3797
- return {
3798
- ok: false,
3799
- reason: "The rollback step summary carries control characters; a compensation the user cannot read never runs.",
3800
- };
3801
- return { ok: true, reason: "The rollback step summary stays plain human readable language." };
3802
- }
3803
-
3804
- /**
3805
- * The state depth message grammar of the 1.1.71 family: a plan proposal may carry its `lockid` so a replay preserves the sessionlock of the run it belongs to, the request body carries the isolated `tabnamespace` id and the `provenance` of the observations so the endpoint sees the tab the run owns and where every observation came from, a memory payload must carry its full provenance fields (origin, runid, stepid, capturedat) before the protocol accepts it, and every urlvisit validates against the session origin before it enters the urlhistory.
3806
- * The audit export grammar: one auditexportrecord bundles `runs` with their urlhistory, `memory` items with their provenance, `expiryrules`, the `timeline` stream and the `locks`; the auditexportreport envelope wraps the record with the protocol version and streams without a size cap while the export itself waits behind the explicit user action.
3807
- */
3808
-
3809
- /** Builds one runtimeline report envelope for external consumers: the versioned event stream of one run with its phase buckets so a consumer renders the same timeline the sidepanel renders; the timeline event schema carries `at`, `runid`, `source` of step, audit or visit, `summary`, the optional `stepid` and the optional audit `kind`. */
3810
- export function runtimelinereport(input: {
3811
- runid: string;
3812
- events: runtimelineevent[];
3813
- buckets: Array<{ phase: string; events: runtimelineevent[] }>;
3814
- }): {
3815
- version: typeof protocolversion;
3816
- runid: string;
3817
- events: runtimelineevent[];
3818
- buckets: Array<{ phase: string; count: number }>;
3819
- } {
3820
- return {
3821
- version: protocolversion,
3822
- runid: input.runid,
3823
- events: input.events,
3824
- buckets: input.buckets.map((bucket) => ({ phase: bucket.phase, count: bucket.events.length })),
3825
- };
3826
- }
3827
-
3828
- /** Parses one memory item payload before it stores: the key, the value, the provenance fields of origin, runid, stepid and capturedat are all required because the protocol rejects memory payloads that lack provenance fields, and the memoryclass, expiresat and encrypted flag stay optional. The 1.1.91 api freeze adds the versioned envelope check: a payload that carries the version field must carry the frozen protocol version — an absent version stays the version one tolerance of the deprecation window. */
3829
- export function memoryitemframe(value: unknown): memoryitem {
3830
- const root = record(value);
3831
- if (root.version !== undefined && root.version !== protocolversion) throw new Error("Unsupported protocol version.");
3832
- const key = text(root.key, "memory item key");
3833
- const provenance = record(root.provenance);
3834
- const origin = text(provenance.origin, "memory item provenance origin");
3835
- const runid = text(provenance.runid, "memory item provenance runid");
3836
- const stepid = text(provenance.stepid, "memory item provenance stepid");
3837
- if (typeof provenance.capturedat !== "number" || !Number.isFinite(provenance.capturedat))
3838
- throw new Error(
3839
- "The memory item provenance needs its capturedat timestamp; a payload without provenance never stores.",
3840
- );
3841
- return {
3842
- key,
3843
- value: root.value,
3844
- provenance: { origin, runid, stepid, capturedat: provenance.capturedat },
3845
- ...(typeof root.memoryclass === "string" && root.memoryclass.trim() !== ""
3846
- ? { memoryclass: root.memoryclass }
3847
- : {}),
3848
- ...(typeof root.expiresat === "number" && Number.isFinite(root.expiresat) ? { expiresat: root.expiresat } : {}),
3849
- ...(root.encrypted === true ? { encrypted: true } : {}),
3850
- };
3851
- }
3852
-
3853
- /** Wraps one auditexportrecord in the versioned response envelope for the audit export flow; the record grammar carries the runs, the memory items, the expiry rules, the timeline stream and the locks of the workspace. */
3854
- export function auditexportreport(input: { record: auditexportrecord }): {
3855
- version: typeof protocolversion;
3856
- record: auditexportrecord;
3857
- } {
3858
- return { version: protocolversion, record: input.record };
3859
- }
3860
-
3861
- /** Validates one urlvisit record against the session origin and its grants: a visit outside the covered origins never enters the urlhistory because the urlhistory confines every visit to the approved origin of its run. */
3862
- export function urlvisitscheck(input: { visits: urlvisit[]; origin: string; grants?: string[] }): {
3863
- ok: boolean;
3864
- refused: string[];
3865
- } {
3866
- const covered = new Set([input.origin, ...(input.grants ?? [])]);
3867
- const refused = input.visits
3868
- .filter((visit) => {
3869
- try {
3870
- return !covered.has(new URL(visit.url).origin);
3871
- } catch {
3872
- return true;
3873
- }
3874
- })
3875
- .map((visit) => visit.url);
3876
- return { ok: refused.length === 0, refused };
3877
- }
3878
-
3879
- /** Validates one bridge payload at the wire boundary of the 1.1.82 site integration family: the payload minimizes through the servercontract data minimization — plan text and statuses cross while a page content key never crosses without the explicit page consent flag — and a payload that fails the minimization refuses at this boundary with every held key named, so the wire never carries page content by default. */
3880
- export function bridgepayloadreport(input: {
3881
- kind: servereventtype;
3882
- payload: Record<string, unknown>;
3883
- pageconsent?: boolean;
3884
- }): { version: number; kind: servereventtype; payload: Record<string, unknown>; held: string[] } {
3885
- const minimized = bridgepayload(input.kind, input.payload, input.pageconsent);
3886
- if (minimized.held.length > 0)
3887
- throw new Error(
3888
- `The bridge payload holds the page content key${minimized.held.length === 1 ? "" : "s"} ${minimized.held.join(", ")}; page content never crosses the bridge without the explicit consent flag.`,
3889
- );
3890
- return { version: servercontractversion, kind: input.kind, payload: minimized.payload, held: [] };
3891
- }
3892
-
3893
- /** Builds the gateway call report envelope of the 1.1.83 family: the request id that correlates the provider call with its audit entry and its usage record across the run, the provider and adapter kind that answered, the model, the token counts, the recorded cost and the time — the envelope carries provenance only, never key material, because the audit trail of a provider call records what left the machine and what it cost, not the credential that opened the door. */
3894
- export function gatewaycallreport(input: {
3895
- requestid: string;
3896
- providerid: string;
3897
- kind: string;
3898
- model: string;
3899
- tokens: { prompttokens: number; completiontokens: number; totaltokens: number };
3900
- cost: number;
3901
- at: number;
3902
- }): {
3903
- version: typeof protocolversion;
3904
- requestid: string;
3905
- providerid: string;
3906
- kind: string;
3907
- model: string;
3908
- tokens: { prompttokens: number; completiontokens: number; totaltokens: number };
3909
- cost: number;
3910
- at: number;
3911
- } {
3912
- if (input.requestid.trim() === "")
3913
- throw new Error("The gateway call report needs its request id; every provider call correlates through it.");
3914
- if (input.providerid.trim() === "") throw new Error("The gateway call report needs its provider id.");
3915
- if (input.model.trim() === "") throw new Error("The gateway call report needs its model name.");
3916
- return {
3917
- version: protocolversion,
3918
- requestid: input.requestid,
3919
- providerid: input.providerid,
3920
- kind: input.kind,
3921
- model: input.model,
3922
- tokens: input.tokens,
3923
- cost: input.cost,
3924
- at: input.at,
3925
- };
3926
- }
3927
-
3928
- /* ── The protocolv2 frozen contract of the 1.1.91 api freeze. ── */
3929
-
3930
- /**
3931
- * The frozen message catalog, the error code table, the framing rules and the stability rules of the 1.1.91 api freeze.
3932
- * The freeze pins the external contracts before the release candidates: every message type the protocol declares travels in one enumerable catalog entry with its schema file, its message family, its envelope class and its carrier — the builder or validator that stamps or checks the versioned envelope — while the response envelope carries the stable error code table with the retry semantics of every code, the stdio and http framing rules join the written contract, and the stability rules promise additive changes only inside protocolv2 with breaking changes demanding a new major by written rule.
3933
- * The deprecation policy of the window lives in the apifreeze family: version one messages stay accepted with one warning per session until 2.0.0, and the sunset list renders in docs/deprecation.md.
3934
- */
3935
-
3936
- /** One frozen message type of the protocolv2 contract: the type name, its message family, the schema file that freezes its shape, the envelope class it travels in and the carrier function that builds or validates it. */
3937
- export interface frozenmessage {
3938
- type: string;
3939
- family: string;
3940
- schema: string;
3941
- envelope: "protocolversion" | "jsonrpcframe" | "serverenvelope" | "runtime";
3942
- carrier: string;
3943
- }
3944
-
3945
- /** The frozen message catalog of the api freeze: every message type the protocol declares with its schema link and its envelope carrier, so the freeze gate enumerates the contract, verifies every carrier stamps or checks the versioned envelope and hashes every schema the catalog names — an entry joins or leaves the catalog only through a release bump. */
3946
- export const frozenmessagecatalog: ReadonlyArray<frozenmessage> = [
3947
- {
3948
- type: "proposalrequest",
3949
- family: "proposal",
3950
- schema: "schemas/proposal.schema.json",
3951
- envelope: "protocolversion",
3952
- carrier: "requestbody",
3953
- },
3954
- {
3955
- type: "proposalresponse",
3956
- family: "proposal",
3957
- schema: "schemas/proposal.schema.json",
3958
- envelope: "protocolversion",
3959
- carrier: "parseproposal",
3960
- },
3961
- {
3962
- type: "plan",
3963
- family: "plan",
3964
- schema: "schemas/plan.schema.json",
3965
- envelope: "protocolversion",
3966
- carrier: "parseproposal",
3967
- },
3968
- {
3969
- type: "planstep",
3970
- family: "plan",
3971
- schema: "schemas/plan.schema.json",
3972
- envelope: "protocolversion",
3973
- carrier: "parseproposal",
3974
- },
3975
- {
3976
- type: "workflowproposal",
3977
- family: "plan",
3978
- schema: "schemas/plan.schema.json",
3979
- envelope: "protocolversion",
3980
- carrier: "parseworkflowproposal",
3981
- },
3982
- {
3983
- type: "workflowoutcome",
3984
- family: "plan",
3985
- schema: "schemas/plan.schema.json",
3986
- envelope: "protocolversion",
3987
- carrier: "workflowoutcome",
3988
- },
3989
- {
3990
- type: "sessionstart",
3991
- family: "session",
3992
- schema: "schemas/session.schema.json",
3993
- envelope: "runtime",
3994
- carrier: "handlerequest",
3995
- },
3996
- {
3997
- type: "sessionpause",
3998
- family: "session",
3999
- schema: "schemas/session.schema.json",
4000
- envelope: "runtime",
4001
- carrier: "handlerequest",
4002
- },
4003
- {
4004
- type: "sessionresume",
4005
- family: "session",
4006
- schema: "schemas/session.schema.json",
4007
- envelope: "runtime",
4008
- carrier: "handlerequest",
4009
- },
4010
- {
4011
- type: "sessionrecord",
4012
- family: "session",
4013
- schema: "schemas/session.schema.json",
4014
- envelope: "protocolversion",
4015
- carrier: "requestbody",
4016
- },
4017
- {
4018
- type: "observation",
4019
- family: "observation",
4020
- schema: "schemas/observation.schema.json",
4021
- envelope: "protocolversion",
4022
- carrier: "requestbody",
4023
- },
4024
- {
4025
- type: "observationresponse",
4026
- family: "observation",
4027
- schema: "schemas/observation.schema.json",
4028
- envelope: "protocolversion",
4029
- carrier: "observationresponse",
4030
- },
4031
- {
4032
- type: "responseenvelope",
4033
- family: "envelope",
4034
- schema: "schemas/envelope.schema.json",
4035
- envelope: "protocolversion",
4036
- carrier: "outcomeresponse",
4037
- },
4038
- {
4039
- type: "jsonrpcresponse",
4040
- family: "envelope",
4041
- schema: "schemas/envelope.schema.json",
4042
- envelope: "jsonrpcframe",
4043
- carrier: "handleframe",
4044
- },
4045
- {
4046
- type: "serverenvelope",
4047
- family: "envelope",
4048
- schema: "schemas/envelope.schema.json",
4049
- envelope: "serverenvelope",
4050
- carrier: "composeenvelope",
4051
- },
4052
- {
4053
- type: "capabilityreport",
4054
- family: "capability",
4055
- schema: "schemas/capability.schema.json",
4056
- envelope: "protocolversion",
4057
- carrier: "requestbody",
4058
- },
4059
- {
4060
- type: "auditevent",
4061
- family: "audit",
4062
- schema: "schemas/audit.schema.json",
4063
- envelope: "protocolversion",
4064
- carrier: "auditexportreport",
4065
- },
4066
- {
4067
- type: "auditexport",
4068
- family: "audit",
4069
- schema: "schemas/audit.schema.json",
4070
- envelope: "protocolversion",
4071
- carrier: "auditexportreport",
4072
- },
4073
- {
4074
- type: "memoryitem",
4075
- family: "memory",
4076
- schema: "schemas/memory.schema.json",
4077
- envelope: "protocolversion",
4078
- carrier: "memoryitemframe",
4079
- },
4080
- {
4081
- type: "planprogress",
4082
- family: "progress",
4083
- schema: "schemas/progress.schema.json",
4084
- envelope: "runtime",
4085
- carrier: "recordstep",
4086
- },
4087
- {
4088
- type: "stepoutcome",
4089
- family: "progress",
4090
- schema: "schemas/progress.schema.json",
4091
- envelope: "protocolversion",
4092
- carrier: "outcomeresponse",
4093
- },
4094
- {
4095
- type: "tooldef",
4096
- family: "tool",
4097
- schema: "schemas/tool.schema.json",
4098
- envelope: "jsonrpcframe",
4099
- carrier: "listtools",
4100
- },
4101
- {
4102
- type: "toolcall",
4103
- family: "tool",
4104
- schema: "schemas/tool.schema.json",
4105
- envelope: "jsonrpcframe",
4106
- carrier: "dispatchtool",
4107
- },
4108
- ];
4109
-
4110
- /** The frozen response envelope outcomes: success, error and cancel — every reply the protocol writes answers in exactly one of the three outcome classes, so the envelope check covers the full reply grammar. */
4111
- export const responseenvelopeoutcomes: readonly string[] = Object.freeze(["success", "error", "cancel"]);
4112
-
4113
- /** The stable error code table of the response envelope: every json rpc error code of the frozen wire with its retry semantics in plain language, so a client reads from the table alone whether a failure answers a permanent refusal, an immediate retry after fixing the request or a retry behind the reviewed backoff — the codes stay the frozen five with consentrefused reserved for the consent gate refusals. */
4114
- export const errorcodetable: ReadonlyArray<{
4115
- code: rpcerrorcode;
4116
- retry: "never" | "immediate" | "afterbackoff";
4117
- semantics: string;
4118
- }> = [
4119
- {
4120
- code: "parse",
4121
- retry: "never",
4122
- semantics:
4123
- "The wire frame does not parse as json; the same bytes never parse on a retry, so the client fixes its framing before the next frame.",
4124
- },
4125
- {
4126
- code: "method",
4127
- retry: "never",
4128
- semantics:
4129
- "The server routes no method of the name the frame carries; the method table is frozen, so an unknown method stays unknown until a release bump adds it.",
4130
- },
4131
- {
4132
- code: "params",
4133
- retry: "immediate",
4134
- semantics:
4135
- "The frame parses but its params fail the frozen schema or the negotiation range; the client may retry immediately once its params carry the reviewed fields.",
4136
- },
4137
- {
4138
- code: "internal",
4139
- retry: "afterbackoff",
4140
- semantics:
4141
- "The handler failed inside the server; the client retries behind the reviewed backoff of its own configuration because the failure names no request defect.",
4142
- },
4143
- {
4144
- code: "consentrefused",
4145
- retry: "never",
4146
- semantics:
4147
- "The consent gates refused the call; no retry passes without a new human decision, because the refusal records exactly the gate that held it.",
4148
- },
4149
- ];
4150
-
4151
- /** The stdio and http framing rules of the frozen contract: the stdio transport carries one newline delimited json frame per block with the frame size bound the user configures, and the http transport carries one json frame per post body on the localhost listener under the same bound — the framing rules join the written contract so a client implements the wire from the document alone. */
4152
- export const framingrules: Readonly<{ stdio: string; http: string }> = Object.freeze({
4153
- stdio:
4154
- "One newline delimited json frame per block on stdin with one reply frame per line on stdout; the frame size bound stays the user configured limit with no code default.",
4155
- http: "One json frame per http post body on the localhost listener with the reply in the response body under the same user configured frame size bound; no other verb carries frames.",
4156
- });
4157
-
4158
- /** The stability rules of protocolv2: inside the frozen major every change stays additive — new optional fields, new message types, new tools and new permissions — while a breaking change demands a new major protocol version by written rule, and the deprecation window that spans the release candidates until 2.0.0 carries every removal notice. */
4159
- export const stabilityrules: Readonly<{ additive: string; breaking: string; window: string }> = Object.freeze({
4160
- additive:
4161
- "Inside protocolv2 every change stays additive: new optional fields, new message types, new tools and new permissions join the contract without touching a frozen entry, because the freeze artifact hashes every schema and refuses a changed hash on the same release version.",
4162
- breaking:
4163
- "A breaking change — removing a field, narrowing a type, refusing a message the contract accepted or renaming a frozen entry — requires a new major protocol version with its own release note, because the written rule is the only path the freeze gate accepts.",
4164
- window:
4165
- "The deprecation window spans the release candidates until 2.0.0: version one messages stay accepted with one warning per session and every deprecated field carries its sunset release in docs/deprecation.md.",
4166
- });
4167
-
4168
- /** Maps one frozen message catalog entry to the root modules that carry its envelope: the carrier function must exist as an exported function of one of the named modules, so the freeze gate and the protocol tests verify every catalog entry lands on a real carrier — an entry whose carrier maps to no module refuses the check. */
4169
- export function frozenmessagecarriers(entry: frozenmessage): readonly string[] {
4170
- const carriermodules: Readonly<Record<string, readonly string[]>> = Object.freeze({
4171
- requestbody: ["protocol.ts"],
4172
- parseproposal: ["protocol.ts"],
4173
- parseworkflowproposal: ["protocol.ts"],
4174
- workflowoutcome: ["protocol.ts"],
4175
- observationresponse: ["protocol.ts"],
4176
- outcomeresponse: ["protocol.ts"],
4177
- auditexportreport: ["protocol.ts"],
4178
- memoryitemframe: ["protocol.ts"],
4179
- handlerequest: ["background.ts"],
4180
- recordstep: ["progress.ts"],
4181
- handleframe: ["mcp.ts"],
4182
- listtools: ["mcp.ts"],
4183
- dispatchtool: ["mcp.ts"],
4184
- composeenvelope: ["bridge.ts"],
4185
- });
4186
- return carriermodules[entry.carrier] ?? [];
4187
- }