@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
@@ -1,554 +0,0 @@
1
- export {};
2
-
3
- /**
4
- * Dashboardpage runtime of the 1.1.64 family.
5
- * The dashboardpage opens in a new tab from the popup and the sidepanel and aggregates the sessions, the runs, the notes and the transparency views of the profile workspace; it renders the sessiongrid and the historysearch of the 1.1.63 session interface beside the transparency report of the 1.1.62 family and the onboarding state, and it subscribes to session and run updates through the single broadcast channel so the view stays live without a reload. The 1.1.96 dashdone completion adds the multi agent panels: the overview with the topology status, the per agent status cards with their live progress, the shared queue view with its lane filter, the message flow between the agents, the conflict and arbitration log, the cost per agent panel, the escalation inbox with its answer controls, the kill switch and the per agent pause controls, the timeline scrubber over the interleaved events, the aggregate report download, the read only rendering for observers without the run role and the empty states that guide the first multi agent run.
6
- */
7
-
8
- import type { multiagentview } from "../dashdone.js";
9
- import { applycontrasttheme, contrasttokensof, panelwidthslayout, panelwidthsof, resizepanel } from "../views.js";
10
-
11
- type sessionview = {
12
- grid: Array<{ sessionid: string; runid: string; origins: string[]; state: string; outcome: string; steps: number; completed: number; lock: string; tabid?: number; sealhash?: string; updatedat: number; actions: string[] }>;
13
- notes: Array<{ id: string; origin: string; title: string; body: string; author: string; sensitive: boolean; updatedat: number }>;
14
- summaries: Array<{ runid: string; origins: string[]; kinds: string[]; steps: number; provenance: string; distilledat: number }>;
15
- };
16
- type transparencyview = {
17
- grants: Array<{ origin: string; scope: string; boundary: string; grantedat: number }>;
18
- windows: Array<{ id: string; origin: string; state: string; boundary: string; startedat: number; expiresat: number }>;
19
- permdiffs: Array<{ fromversion: string; toversion: string; added: string[]; removed: string[]; computedat: number }>;
20
- safedefaults: Array<{ origin: string; firstseenat: number }>;
21
- };
22
- type dashboardview = { sessionview: sessionview; transparency: transparencyview; onboarding: { stepscompleted: string[]; done: boolean }; environments?: { offscreengranted: boolean; parseoffload: boolean; workers?: number }; security?: { posture?: string }; multiagent?: multiagentview };
23
- type libraryrow = { id: string; title: string; publisher: string; version: string; grants: string[]; sensitive: boolean; state: string; registry?: string };
24
- type backgroundrow = { id: string; workflowid: string; state: string; keepaliveheld: boolean; progress: string };
25
-
26
- const statusnode = document.querySelector<HTMLElement>("#status");
27
- const sessiongridroot = document.querySelector<HTMLElement>("#sessiongrid");
28
- const historyhitsroot = document.querySelector<HTMLElement>("#historyhits");
29
- const sitenotesroot = document.querySelector<HTMLElement>("#sitenotes");
30
- const transparencyroot = document.querySelector<HTMLElement>("#transparency");
31
- const onboardingroot = document.querySelector<HTMLElement>("#onboarding");
32
- const historyinput = document.querySelector<HTMLInputElement>("#historyquery");
33
- const libraryroot = document.querySelector<HTMLElement>("#flowlibrary");
34
- const librarystatusnode = document.querySelector<HTMLElement>("#librarystatus");
35
- const libraryinput = document.querySelector<HTMLInputElement>("#libraryquery");
36
- const backgroundrunsroot = document.querySelector<HTMLElement>("#backgroundruns");
37
- /* the multi agent panel roots of the 1.1.96 dashdone completion */
38
- const multiagentoverviewroot = document.querySelector<HTMLElement>("#multiagentoverview");
39
- const multiagentviewernode = document.querySelector<HTMLElement>("#multiagentviewer");
40
- const agentstatuscardsroot = document.querySelector<HTMLElement>("#agentstatuscards");
41
- const sharedqueueviewroot = document.querySelector<HTMLElement>("#sharedqueueview");
42
- const queuelanefilternode = document.querySelector<HTMLSelectElement>("#queuelanefilter");
43
- const multiagentstatusnode = document.querySelector<HTMLElement>("#multiagentstatus");
44
- const messageflowroot = document.querySelector<HTMLElement>("#messageflow");
45
- const conflictlogroot = document.querySelector<HTMLElement>("#conflictlog");
46
- const agentcostpanelroot = document.querySelector<HTMLElement>("#agentcostpanel");
47
- const escalationinboxroot = document.querySelector<HTMLElement>("#escalationinbox");
48
- const timelinescrubbernode = document.querySelector<HTMLInputElement>("#timelinescrubber");
49
- const timelinescrubreadoutnode = document.querySelector<HTMLElement>("#timelinescrubreadout");
50
- const aggregatetimelineroot = document.querySelector<HTMLElement>("#aggregatetimeline");
51
- const killswitchbuttonnode = document.querySelector<HTMLButtonElement>("#killswitch");
52
- const reportdownloadbuttonnode = document.querySelector<HTMLButtonElement>("#reportdownload");
53
-
54
- function status(message: string, error = false): void { if (statusnode) { statusnode.textContent = message; statusnode.dataset.state = error ? "error" : "ready"; } }
55
- async function request(message: unknown): Promise<unknown> { const response = await chrome.runtime.sendMessage(message) as { ok: boolean; value?: unknown; error?: string }; if (!response.ok) throw new Error(response.error); return response.value; }
56
- function button(label: string, action: () => Promise<void>): HTMLButtonElement { const element = document.createElement("button"); element.type = "button"; element.className = "secondary"; element.textContent = label; element.addEventListener("click", () => action().catch(error => status(error instanceof Error ? error.message : String(error), true))); return element; }
57
-
58
- /** Renders the sessiongrid rows of the 1.1.63 session interface with their resume, cancelrun and reopen actions as deep links. */
59
- function rendersessiongrid(view: sessionview): void {
60
- if (!sessiongridroot) return;
61
- sessiongridroot.replaceChildren();
62
- if (view.grid.length === 0) { sessiongridroot.textContent = "No session exists yet; start the first run from the popup taskinput."; return; }
63
- const list = document.createElement("ol");
64
- list.className = "audit";
65
- for (const row of view.grid) {
66
- const item = document.createElement("li");
67
- item.textContent = `${row.state} ${row.runid} — ${row.origins.join(", ")} — ${row.completed}/${row.steps} steps — ${row.outcome} — ${row.lock}${row.sealhash !== undefined ? ` — sealed ${row.sealhash.slice(0, 12)}` : ""}`;
68
- for (const action of row.actions) item.append(" ", button(action === "cancelrun" ? "Cancel run" : action === "resume" ? "Resume" : "Reopen", async () => {
69
- await request({ kind: "sessions", grid: action === "cancelrun" ? { open: { runid: row.runid } } : action === "resume" ? { resume: { runid: row.runid } } : { reopen: { runid: row.runid } } });
70
- if (action === "cancelrun") await request({ kind: "surface", bus: { action: { surface: "dashboardpage", command: "cancelrun" } } });
71
- status(`The ${action} action of the run ${row.runid} routed through the command bus.`);
72
- await render();
73
- }));
74
- list.append(item);
75
- }
76
- sessiongridroot.append(list);
77
- }
78
-
79
- /** Renders the historysearch corpus of the 1.1.63 session interface with the matched terms highlighted. */
80
- async function renderhistorysearch(text: string): Promise<void> {
81
- if (!historyhitsroot) return;
82
- try {
83
- const result = await request({ kind: "sessions", search: { query: { text } } }) as { hits: Array<{ source: string; title: string; excerpt: string; highlights: string[]; origin?: string; at: number }> };
84
- historyhitsroot.replaceChildren();
85
- if (result.hits.length === 0) { historyhitsroot.append(Object.assign(document.createElement("li"), { textContent: "No history matches yet." })); return; }
86
- for (const hit of result.hits) {
87
- const item = document.createElement("li");
88
- item.textContent = `${hit.source} — ${hit.title}${hit.origin !== undefined ? ` (${hit.origin})` : ""}: ${hit.excerpt}${hit.highlights.length > 0 ? ` [${hit.highlights.join(", ")}]` : ""}`;
89
- historyhitsroot.append(item);
90
- }
91
- } catch (error) { historyhitsroot.textContent = error instanceof Error ? error.message : String(error); }
92
- }
93
-
94
- /** Renders the site notes of the session interface with their author provenance. */
95
- function rendersitenotes(view: sessionview): void {
96
- if (!sitenotesroot) return;
97
- if (view.notes.length === 0) { sitenotesroot.textContent = "No site note exists yet; write the first note from the sidepanel."; return; }
98
- sitenotesroot.replaceChildren();
99
- const list = document.createElement("ul");
100
- list.className = "audit";
101
- for (const note of view.notes) list.append(Object.assign(document.createElement("li"), { textContent: `${note.title} (${note.origin}, by ${note.author}${note.sensitive ? ", sealed at rest" : ""}): ${note.body}` }));
102
- sitenotesroot.append(list);
103
- }
104
-
105
- /** Renders the transparency views of the 1.1.62 family: the grants with their boundaries, the window history, the permdiffs and the safedefaults applications. */
106
- function rendertransparency(view: transparencyview): void {
107
- if (!transparencyroot) return;
108
- transparencyroot.replaceChildren();
109
- const grants = document.createElement("p");
110
- grants.textContent = `Grants: ${view.grants.length} grant row${view.grants.length === 1 ? "" : "s"}${view.grants.length > 0 ? ` (${view.grants.slice(0, 5).map(grant => `${grant.origin} — ${grant.scope} — ${grant.boundary}`).join(" · ")})` : ""}.`;
111
- const windows = document.createElement("p");
112
- windows.textContent = `Consent windows: ${view.windows.length} recorded window${view.windows.length === 1 ? "" : "s"}.`;
113
- const permdiffs = document.createElement("p");
114
- permdiffs.textContent = `Permdiffs: ${view.permdiffs.length} record${view.permdiffs.length === 1 ? "" : "s"}${view.permdiffs.length > 0 ? ` (latest ${view.permdiffs[0]?.fromversion} → ${view.permdiffs[0]?.toversion})` : ""}.`;
115
- const safedefaults = document.createElement("p");
116
- safedefaults.textContent = `Safedefaults applications: ${view.safedefaults.length} origin${view.safedefaults.length === 1 ? "" : "s"} under the reads only posture.`;
117
- transparencyroot.append(grants, windows, permdiffs, safedefaults);
118
- }
119
-
120
- /** Renders the 1.1.68 perf summary of the most recent run beside its step duration chart: the step count, the total and average duration, the query count, the cache hit ratio and the delta share of the run. */
121
- async function renderperfsummary(): Promise<void> {
122
- const summarynode = document.querySelector<HTMLElement>("#perfsummary");
123
- const chartnode = document.querySelector<HTMLElement>("#perfchart");
124
- if (!summarynode || !chartnode) return;
125
- try {
126
- const report = await request({ kind: "perf", summary: {} }) as { runid: string; summary: { steps: number; duration: number; average: number; queries: number; cachehits: number; hitratio: number; deltashare: number }; chart: Array<{ stepid: string; duration: number; delta: boolean }>; selcache: { generation: number; entries: number }; queue: { depth: number; deferred: number; peak: number } };
127
- summarynode.replaceChildren();
128
- if (report.summary.steps === 0) { summarynode.textContent = "No run measured yet; the perf summary builds from the recorded perf records of the recent runs."; chartnode.textContent = "The step duration chart renders one point per measured step."; return; }
129
- const line = document.createElement("p");
130
- line.textContent = `Run ${report.runid}: ${report.summary.steps} measured step${report.summary.steps === 1 ? "" : "s"} · ${report.summary.duration}ms total · ${report.summary.average}ms average · ${report.summary.queries} querie${report.summary.queries === 1 ? "" : "s"} · ${report.summary.cachehits} cache hit${report.summary.cachehits === 1 ? "" : "s"} (ratio ${Math.round(report.summary.hitratio * 100)}%) · ${Math.round(report.summary.deltashare * 100)}% served from deltas · selcache generation ${report.selcache.generation} · worker queue peak ${report.queue.peak}.`;
131
- summarynode.append(line);
132
- chartnode.replaceChildren();
133
- const chart = document.createElement("ol");
134
- chart.className = "audit";
135
- const peak = Math.max(...report.chart.map(point => point.duration), 1);
136
- for (const point of report.chart) {
137
- const bars = Math.max(Math.round((point.duration / peak) * 10), 1);
138
- chart.append(Object.assign(document.createElement("li"), { textContent: `${point.stepid} — ${point.duration}ms${point.delta ? " (delta)" : ""} ${"▮".repeat(bars)}` }));
139
- }
140
- chartnode.append(chart);
141
- } catch (error) { summarynode.textContent = error instanceof Error ? error.message : String(error); chartnode.textContent = ""; }
142
- }
143
-
144
- /** Renders the 1.1.69 budgetalerts with their thresholds beside the selectorprofile latencies of the profile workspace: every alert names its severity level and its ratio, and every selector bars its average resolution time with its failure rate and its latency flag. */
145
- async function renderbudgetalerts(): Promise<void> {
146
- const alertnode = document.querySelector<HTMLElement>("#budgetalerts");
147
- const selectornode = document.querySelector<HTMLElement>("#selectorprofile");
148
- if (!alertnode || !selectornode) return;
149
- try {
150
- const view = await request({ kind: "schedule", view: true }) as { backpressure: { runid: string; behind: number; paused: boolean; window?: number }; alerts: Array<{ runid: string; level: string; kind: string; ratio: number; paused: boolean }>; selectors?: Array<{ selector: string; average: number; count: number; failures: number; flagged: boolean }>; startup?: { duration: number; spent: number; target?: number } };
151
- alertnode.replaceChildren();
152
- const line = document.createElement("p");
153
- line.textContent = `Run budget of ${view.backpressure.runid}: ${view.backpressure.behind} step${view.backpressure.behind === 1 ? "" : "s"} ahead of its outcomes${view.backpressure.window !== undefined ? ` against the user backpressure window of ${view.backpressure.window}` : " with no user window"}${view.startup !== undefined ? ` · cold start ${view.startup.duration}ms with ${view.startup.spent} lazymod${view.startup.spent === 1 ? "" : "s"} at ready${view.startup.target !== undefined ? ` (user target ${view.startup.target}ms)` : ""}` : ""}.`;
154
- alertnode.append(line);
155
- if (view.alerts.length === 0) { const empty = document.createElement("p"); empty.textContent = "No budgetalert fired yet; the alerts report the user thresholds and only the critical threshold pauses a run pending a user choice."; alertnode.append(empty); }
156
- else {
157
- const alerts = document.createElement("ol");
158
- alerts.className = "audit";
159
- for (const alert of view.alerts) alerts.append(Object.assign(document.createElement("li"), { textContent: `${alert.level} ${alert.kind} alert of ${alert.runid} at ${Math.round(alert.ratio * 100)} percent${alert.paused ? " — run paused pending a user choice" : " — reported, the run keeps running"}` }));
160
- alertnode.append(alerts);
161
- }
162
- selectornode.replaceChildren();
163
- const selectors = view.selectors ?? [];
164
- if (selectors.length === 0) { selectornode.textContent = "No selectorprofile recorded yet; the chart bars the average resolution latency of every selector the runs resolved."; return; }
165
- const chart = document.createElement("ol");
166
- chart.className = "audit";
167
- const peak = Math.max(...selectors.map(stats => stats.average), 1);
168
- for (const stats of selectors) {
169
- const bars = Math.max(Math.round((stats.average / peak) * 10), 1);
170
- chart.append(Object.assign(document.createElement("li"), { textContent: `${stats.selector} — ${stats.average}ms over ${stats.count} resolution${stats.count === 1 ? "" : "s"} · ${Math.round(stats.failures / stats.count * 100)}% failed${stats.flagged ? " · flagged above the user latency threshold" : ""} ${"▮".repeat(bars)}` }));
171
- }
172
- selectornode.append(chart);
173
- } catch (error) { alertnode.textContent = error instanceof Error ? error.message : String(error); selectornode.textContent = ""; }
174
- }
175
-
176
- /** Renders the onboarding state with its replay offer on demand. */
177
- function renderonboarding(onboarding: { stepscompleted: string[]; done: boolean }): void {
178
- if (!onboardingroot) return;
179
- onboardingroot.replaceChildren();
180
- const state = document.createElement("p");
181
- state.textContent = onboarding.done ? "The onboarding walkthrough is done; replay it on demand from the optionspage." : `The onboarding walkthrough stands at ${onboarding.stepscompleted.length} completed step${onboarding.stepscompleted.length === 1 ? "" : "s"}.`;
182
- onboardingroot.append(state);
183
- }
184
-
185
- /** Renders the flowlibrary browser of the 1.1.66 ecosystem family: every row names its publisher, version and required grants, the entry view shows the full step list before install, the grant diff opens the diff dialog and the install lands as a pending import behind the same review. */
186
- async function renderlibrary(query: string): Promise<void> {
187
- if (!libraryroot) return;
188
- try {
189
- const view = await request({ kind: "ecosystem", library: { browse: { ...(query.trim() !== "" ? { query } : {}) } } }) as { library: libraryrow[] };
190
- libraryroot.replaceChildren();
191
- if (view.library.length === 0) { libraryroot.textContent = "No flowlibrary entry matches yet; import a manifest from a file or pull one through a syncbridge hook."; return; }
192
- const list = document.createElement("ol");
193
- list.className = "audit";
194
- for (const row of view.library) {
195
- const item = document.createElement("li");
196
- item.textContent = `${row.title} ${row.version} — ${row.publisher}${row.registry !== undefined ? ` — ${row.registry}` : ""} — ${row.state}${row.sensitive ? " — sensitive" : ""} — grants: ${row.grants.join(", ") || "none"}`;
197
- item.append(" ", button("Steps", async () => {
198
- const detail = await request({ kind: "ecosystem", library: { entry: { entryid: row.id } } }) as { steps: Array<{ id: string; kind: string; label: string; target?: string; families: string[]; fields: string[] }> };
199
- if (librarystatusnode) librarystatusnode.textContent = detail.steps.map(step => `${step.id}: ${step.kind} — ${step.label}${step.target !== undefined ? ` (${step.target})` : ""}${step.fields.length > 0 ? ` [${step.families.join(", ")}: ${step.fields.join(", ")}]` : ""}`).join(" · ");
200
- }));
201
- item.append(" ", button("Grant diff", async () => {
202
- const diff = await request({ kind: "ecosystem", library: { grants: { entryid: row.id } } }) as { diff: { added: string[]; kept: string[] } };
203
- if (librarystatusnode) librarystatusnode.textContent = `Grant diff: added ${diff.diff.added.join(", ") || "none"}, held ${diff.diff.kept.join(", ") || "none"}; the added grants map onto originprofiles before the import completes.`;
204
- }));
205
- item.append(" ", button("Install", async () => {
206
- const result = await request({ kind: "ecosystem", library: { install: { entryid: row.id, ...(row.sensitive ? { consent: true } : {}) } } }) as { record: { id: string; steps: number } };
207
- if (librarystatusnode) librarystatusnode.textContent = `The install landed as the pending workflow ${result.record.id} with ${result.record.steps} steps; the import review approves its step list before anything runs.`;
208
- await renderlibrary(query);
209
- }));
210
- item.append(" ", button("Fork", async () => {
211
- const result = await request({ kind: "ecosystem", library: { fork: { entryid: row.id } } }) as { fork: { id: string } };
212
- if (librarystatusnode) librarystatusnode.textContent = `The fork created the independent local workflow ${result.fork.id}; the fork owns its name from its creation on.`;
213
- }));
214
- item.append(" ", button("Remove", async () => {
215
- await request({ kind: "ecosystem", library: { remove: { entryid: row.id } } });
216
- if (librarystatusnode) librarystatusnode.textContent = `The entry ${row.id} left the flowlibrary while its local forks stayed untouched.`;
217
- await renderlibrary(query);
218
- }));
219
- list.append(item);
220
- }
221
- libraryroot.append(list);
222
- } catch (error) { libraryroot.textContent = error instanceof Error ? error.message : String(error); }
223
- }
224
-
225
- /** Renders the background run queue of the 1.1.66 ecosystem family with its progress and its keepalive hold. */
226
- async function renderbackgroundruns(): Promise<void> {
227
- if (!backgroundrunsroot) return;
228
- try {
229
- const view = await request({ kind: "ecosystem", background: { list: true } }) as { queue: backgroundrow[] };
230
- backgroundrunsroot.replaceChildren();
231
- if (view.queue.length === 0) { backgroundrunsroot.textContent = "No background run stands in the queue; queue a reviewed workflow and it keeps executing with the panel closed."; return; }
232
- const list = document.createElement("ol");
233
- list.className = "audit";
234
- for (const row of view.queue) {
235
- const item = document.createElement("li");
236
- item.textContent = `${row.state} — ${row.workflowid} — ${row.progress}${row.keepaliveheld ? " — keepalive held" : ""}`;
237
- if (row.state === "queued") item.append(" ", button("Cancel", async () => { await request({ kind: "ecosystem", background: { cancel: { id: row.id } } }); await renderbackgroundruns(); }));
238
- list.append(item);
239
- }
240
- backgroundrunsroot.append(list);
241
- } catch (error) { backgroundrunsroot.textContent = error instanceof Error ? error.message : String(error); }
242
- }
243
-
244
- /** Renders the multi agent panels of the 1.1.96 dashdone completion from the shaped view the background serves: the overview with the topology status, the per agent status cards with their live progress and controls, the shared queue with its lane filter, the message flow, the conflict and arbitration log, the cost per agent panel, the escalation inbox, the timeline scrubber, the aggregate report download, the viewer mode and the empty states that guide the first multi agent run. */
245
- let currentmultiagent: multiagentview | undefined;
246
- let selectedlane = "";
247
- function rendermultiagent(view: multiagentview | undefined): void {
248
- currentmultiagent = view;
249
- if (view === undefined) {
250
- if (multiagentoverviewroot) multiagentoverviewroot.textContent = "The multi agent view is unavailable; the swarm state read failed.";
251
- return;
252
- }
253
- if (multiagentoverviewroot) {
254
- multiagentoverviewroot.replaceChildren();
255
- if (view.empty.empty) {
256
- const empty = document.createElement("p");
257
- empty.textContent = "No agent is registered yet; the panels below stay empty until the first multi agent run registers its fleet.";
258
- multiagentoverviewroot.append(empty);
259
- const guidance = document.createElement("ol");
260
- guidance.className = "audit";
261
- for (const step of view.empty.guidance) guidance.append(Object.assign(document.createElement("li"), { textContent: step }));
262
- multiagentoverviewroot.append(guidance);
263
- } else {
264
- const line = document.createElement("p");
265
- line.textContent = `Topology: ${view.overview.topology}; ${view.overview.killswitch}. Agents: ${view.overview.agents} (${view.overview.active} active, ${view.overview.paused} paused, ${view.overview.stopped} stopped). Queue: ${view.overview.tasks} task${view.overview.tasks === 1 ? "" : "s"} — ${view.overview.queued} queued, ${view.overview.claimed} claimed, ${view.overview.done} done. Unread messages: ${view.overview.unread}.`;
266
- multiagentoverviewroot.append(line);
267
- }
268
- }
269
- if (multiagentviewernode) multiagentviewernode.textContent = view.viewer.reason;
270
- renderagentcards(view);
271
- rendersharedqueue(view);
272
- rendermessageflow(view);
273
- renderconflictlog(view);
274
- rendercostpanel(view);
275
- renderescalationinbox(view);
276
- rendertimeline(view);
277
- }
278
-
279
- /** Renders the per agent status cards with their live progress, their usage against the budget and the pause, resume and stop controls the viewer role gates. */
280
- function renderagentcards(view: multiagentview): void {
281
- if (!agentstatuscardsroot) return;
282
- agentstatuscardsroot.replaceChildren();
283
- if (view.cards.length === 0) { agentstatuscardsroot.textContent = "No agent status card exists yet; register the first agents of the fleet from the sidepanel fleet control."; return; }
284
- const list = document.createElement("ol");
285
- list.className = "audit";
286
- for (const card of view.cards) {
287
- const item = document.createElement("li");
288
- item.textContent = `${card.state} ${card.name} (${card.agentid}) — ${card.role}, depth ${card.depth}${card.tabid !== undefined ? `, tab ${card.tabid}` : ""}${card.parentid !== undefined ? `, sub agent of ${card.parentid}` : ""}${card.sessionid !== undefined ? `, session ${card.sessionid}` : ""} — ${card.done} done, ${card.claimed} claimed${card.currenttask !== undefined ? `, working on ${card.currenttask}` : ""} — ${card.tokens} token${card.tokens === 1 ? "" : "s"}, ${card.cost} cost, ${card.steps} step${card.steps === 1 ? "" : "s"} — ${card.unread} unread${card.reviewstatus !== undefined ? `, ${card.reviewstatus}` : ""}.`;
289
- if (view.viewer.controls) {
290
- if (card.state === "active") item.append(" ", button("Pause", async () => { await request({ kind: "swarmagent", action: "pause", agentid: card.agentid }); status(`The pause of the agent ${card.name} routed through the swarm command; the peers keep running.`); await render(); }));
291
- if (card.state === "paused") item.append(" ", button("Resume", async () => { await request({ kind: "swarmagent", action: "resume", agentid: card.agentid }); status(`The agent ${card.name} resumed; its peers never changed.`); await render(); }));
292
- if (card.state !== "stopped") item.append(" ", button("Stop", async () => { await request({ kind: "swarmagent", action: "stop", agentid: card.agentid }); status(`The agent ${card.name} stopped; its claims release through the requeue pass.`); await render(); }));
293
- }
294
- list.append(item);
295
- }
296
- agentstatuscardsroot.append(list);
297
- }
298
-
299
- /** Renders the shared queue view with its lane filter: one row per task with its lane, priority, state and the claim that holds it. */
300
- function rendersharedqueue(view: multiagentview): void {
301
- if (queuelanefilternode) {
302
- const lanes = view.queueview.lanes;
303
- const current = queuelanefilternode.value;
304
- queuelanefilternode.replaceChildren(Object.assign(document.createElement("option"), { value: "", textContent: "Every lane" }));
305
- for (const lane of lanes) queuelanefilternode.append(Object.assign(document.createElement("option"), { value: lane, textContent: lane }));
306
- queuelanefilternode.value = lanes.includes(current) ? current : "";
307
- }
308
- if (!sharedqueueviewroot) return;
309
- sharedqueueviewroot.replaceChildren();
310
- const rows = view.queueview.rows.filter(row => selectedlane === "" || row.lane === selectedlane);
311
- if (rows.length === 0) { sharedqueueviewroot.textContent = view.queueview.lanes.length === 0 ? "No lane is configured yet; the shared queue fills when the first multi agent run enqueues its tasks." : `No task sits in the ${selectedlane === "" ? "queue" : `lane ${selectedlane}`} yet; enqueue the shared work from the sidepanel fleet control.`; return; }
312
- const list = document.createElement("ol");
313
- list.className = "audit";
314
- for (const row of rows) list.append(Object.assign(document.createElement("li"), { textContent: `${row.state} ${row.taskid} — lane ${row.lane}, priority ${row.priority} — ${row.payload}${row.holder !== undefined ? ` — claimed by ${row.holder}${row.heartbeatat !== undefined ? ` (heartbeat ${row.heartbeatat})` : ""}` : " — unclaimed"}` }));
315
- sharedqueueviewroot.append(list);
316
- }
317
-
318
- /** Renders the message flow view between agents: every delivered message with its sender, its recipient and its routing kind. */
319
- function rendermessageflow(view: multiagentview): void {
320
- if (!messageflowroot) return;
321
- messageflowroot.replaceChildren();
322
- if (view.messageflow.rows.length === 0) { messageflowroot.textContent = "No message passed between the agents yet; the flow view lists every delivery with its sender, its recipient and its routing kind."; return; }
323
- const list = document.createElement("ol");
324
- list.className = "audit";
325
- for (const row of view.messageflow.rows) list.append(Object.assign(document.createElement("li"), { textContent: `${row.senderid} → ${row.recipient} (${row.routing}) at ${row.sentat}${row.read ? " — read" : " — unread"}: ${row.payload}` }));
326
- messageflowroot.append(list);
327
- }
328
-
329
- /** Renders the conflict and arbitration log panel: the conflict scans with their overlapping writers beside the live resource locks. */
330
- function renderconflictlog(view: multiagentview): void {
331
- if (!conflictlogroot) return;
332
- conflictlogroot.replaceChildren();
333
- if (view.conflictlog.rows.length === 0) { conflictlogroot.textContent = "No conflict and no arbitration case exists yet; the log lists every overlapping write beside the resource locks the swarm holds."; return; }
334
- const head = document.createElement("p");
335
- head.textContent = `Open conflicts: ${view.conflictlog.open}.`;
336
- conflictlogroot.append(head);
337
- const list = document.createElement("ol");
338
- list.className = "audit";
339
- for (const row of view.conflictlog.rows) list.append(Object.assign(document.createElement("li"), { textContent: `${row.source} ${row.key} at ${row.at}: ${row.detail}` }));
340
- conflictlogroot.append(list);
341
- }
342
-
343
- /** Renders the cost per agent panel the costcert totals feed: one row per agent with its tokens, cost and steps beside its share of the swarm total. */
344
- function rendercostpanel(view: multiagentview): void {
345
- if (!agentcostpanelroot) return;
346
- agentcostpanelroot.replaceChildren();
347
- if (view.costview.rows.length === 0) { agentcostpanelroot.textContent = "No cost is recorded per agent yet; the panel sums the same accounting the costcert gate reconciles once the agents spend tokens."; return; }
348
- const total = document.createElement("p");
349
- total.textContent = `Swarm totals: ${view.costview.total.tokens} token${view.costview.total.tokens === 1 ? "" : "s"}, ${view.costview.total.cost} cost${view.costview.total.currency !== undefined ? ` ${view.costview.total.currency}` : ""}, ${view.costview.total.steps} step${view.costview.total.steps === 1 ? "" : "s"} — ${view.costview.source}.`;
350
- agentcostpanelroot.append(total);
351
- const list = document.createElement("ol");
352
- list.className = "audit";
353
- for (const row of view.costview.rows) list.append(Object.assign(document.createElement("li"), { textContent: `${row.agentid}: ${row.tokens} token${row.tokens === 1 ? "" : "s"}, ${row.cost} cost, ${row.steps} step${row.steps === 1 ? "" : "s"} — ${Math.round(row.share * 100)} percent of the token total.` }));
354
- agentcostpanelroot.append(list);
355
- }
356
-
357
- /** Renders the escalation inbox for human review: every escalation with its answer control when the viewer holds the run role. */
358
- function renderescalationinbox(view: multiagentview): void {
359
- if (!escalationinboxroot) return;
360
- escalationinboxroot.replaceChildren();
361
- if (view.escalationinbox.rows.length === 0) { escalationinboxroot.textContent = "No escalation waits for the human; the inbox lists every stalled agent decision that only the user decides."; return; }
362
- const head = document.createElement("p");
363
- head.textContent = `Open escalations: ${view.escalationinbox.open}.`;
364
- escalationinboxroot.append(head);
365
- const list = document.createElement("ol");
366
- list.className = "audit";
367
- for (const row of view.escalationinbox.rows) {
368
- const item = document.createElement("li");
369
- item.textContent = `${row.state} ${row.escalationid} — the agent ${row.agentid} asks: ${row.subject} (raised at ${row.raisedat})${row.decision !== undefined ? ` — decided: ${row.decision}` : ""}.`;
370
- if (view.viewer.controls && row.state === "open") {
371
- const answer = document.createElement("input");
372
- answer.placeholder = "The decision the user writes";
373
- answer.setAttribute("aria-label", `The escalation answer of ${row.escalationid}`);
374
- item.append(" ", answer, " ", button("Answer", async () => {
375
- const decision = answer.value.trim();
376
- if (decision === "") throw new Error("The escalation decision needs the words the user wrote; escalations stay human decided.");
377
- await request({ kind: "fleet", answer: { id: row.escalationid, decision } });
378
- status(`The escalation ${row.escalationid} was answered; the hold on the agent ${row.agentid} lifts.`);
379
- await render();
380
- }));
381
- }
382
- list.append(item);
383
- }
384
- escalationinboxroot.append(list);
385
- }
386
-
387
- /** Renders the timeline scrubber over the interleaved events: the range input walks the merged fleet timeline and the readout names the mark it rests on. */
388
- function rendertimeline(view: multiagentview): void {
389
- if (aggregatetimelineroot) {
390
- aggregatetimelineroot.replaceChildren();
391
- if (view.timeline.marks.length === 0) { aggregatetimelineroot.textContent = "No interleaved event exists yet; the timeline merges the actions of every agent into one ordered stream once the swarm runs."; }
392
- else {
393
- const list = document.createElement("ol");
394
- list.className = "audit";
395
- for (const mark of view.timeline.marks) list.append(Object.assign(document.createElement("li"), { textContent: `${mark.agentid ?? "swarm"} ${mark.kind} at ${mark.at} (position ${mark.position}): ${mark.summary}` }));
396
- aggregatetimelineroot.append(list);
397
- }
398
- }
399
- if (timelinescrubbernode) {
400
- timelinescrubbernode.max = String(Math.max(view.timeline.marks.length - 1, 0));
401
- if (timelinescrubbernode.value === "" || Number(timelinescrubbernode.value) > view.timeline.marks.length - 1) timelinescrubbernode.value = String(Math.max(view.timeline.marks.length - 1, 0));
402
- }
403
- updatetimelinescrubreadout();
404
- }
405
-
406
- /** Updates the timeline scrubber readout with the mark the scrubber rests on. */
407
- function updatetimelinescrubreadout(): void {
408
- const view = currentmultiagent;
409
- if (!timelinescrubreadoutnode || view === undefined) return;
410
- const index = Math.min(Math.max(Number(timelinescrubbernode?.value ?? 0) || 0, 0), Math.max(view.timeline.marks.length - 1, 0));
411
- const mark = view.timeline.marks[index];
412
- timelinescrubreadoutnode.textContent = mark === undefined ? "No interleaved event yet." : `${mark.agentid ?? "swarm"} ${mark.kind} at ${mark.at}: ${mark.summary}`;
413
- }
414
-
415
- /** Loads the aggregated dashboard view: the sessionview of 1.1.63, the transparency report of 1.1.62, the onboarding state and the multi agent view of the 1.1.96 dashdone completion. */
416
- async function render(): Promise<void> {
417
- const view = await request({ kind: "surface", dashboard: { view: true } }) as dashboardview;
418
- rendersessiongrid(view.sessionview);
419
- rendersitenotes(view.sessionview);
420
- rendertransparency(view.transparency);
421
- renderonboarding(view.onboarding);
422
- rendermultiagent(view.multiagent);
423
- await renderperfsummary();
424
- await renderbudgetalerts();
425
- status(`Dashboard view live: ${view.sessionview.grid.length} run${view.sessionview.grid.length === 1 ? "" : "s"}, ${view.sessionview.notes.length} note${view.sessionview.notes.length === 1 ? "" : "s"}, ${view.transparency.grants.length} grant row${view.transparency.grants.length === 1 ? "" : "s"} and ${view.multiagent?.overview.agents ?? 0} agent${(view.multiagent?.overview.agents ?? 0) === 1 ? "" : "s"}${view.multiagent?.viewer.readonly === true ? " (read only)" : ""}.`);
426
- }
427
-
428
- document.querySelector<HTMLButtonElement>("#openpanel")?.addEventListener("click", () => { void chrome.sidePanel.open({ windowId: chrome.windows.WINDOW_ID_CURRENT }).catch(() => { /* the panel opens beside the dashboard tab */ }); });
429
- document.querySelector<HTMLButtonElement>("#openoptions")?.addEventListener("click", () => { void chrome.tabs.create({ url: chrome.runtime.getURL("optionspage.html") }); });
430
- document.querySelector<HTMLButtonElement>("#historyrun")?.addEventListener("click", () => { void renderhistorysearch(historyinput?.value ?? "").catch(error => status(error instanceof Error ? error.message : String(error), true)); });
431
- historyinput?.addEventListener("keydown", event => { if (event.key === "Enter") document.querySelector<HTMLButtonElement>("#historyrun")?.click(); });
432
- document.querySelector<HTMLButtonElement>("#libraryrun")?.addEventListener("click", () => { void renderlibrary(libraryinput?.value ?? "").catch(error => status(error instanceof Error ? error.message : String(error), true)); });
433
- libraryinput?.addEventListener("keydown", event => { if (event.key === "Enter") document.querySelector<HTMLButtonElement>("#libraryrun")?.click(); });
434
- document.querySelector<HTMLButtonElement>("#libraryexport")?.addEventListener("click", () => { void request({ kind: "ecosystem", library: { export: true } }).then(result => { const manifests = (result as { manifests: Array<{ title: string; publisher: string; version: string; digest: string; state: string }> }).manifests; if (librarystatusnode) librarystatusnode.textContent = `The manifest list exported ${manifests.length} entr${manifests.length === 1 ? "y" : "ies"} for audit with digest, publisher, version, state and provenance and no step payload.`; }).catch(error => { if (librarystatusnode) librarystatusnode.textContent = error instanceof Error ? error.message : String(error); }); });
435
- /* the multi agent controls of the 1.1.96 dashdone completion: the lane filter, the kill switch, the aggregate report download and the timeline scrubber */
436
- queuelanefilternode?.addEventListener("change", () => { selectedlane = queuelanefilternode.value; if (currentmultiagent !== undefined) rendersharedqueue(currentmultiagent); if (multiagentstatusnode) multiagentstatusnode.textContent = selectedlane === "" ? "The shared queue view lists every task with its lane, priority, state and the agent that claimed it." : `The lane filter shows only the lane ${selectedlane}; every other lane stays one selection away.`; });
437
- killswitchbuttonnode?.addEventListener("click", () => {
438
- if (currentmultiagent?.viewer.controls !== true) { status(currentmultiagent?.viewer.reason ?? "The viewer carries no run role; the kill switch control stays unavailable.", true); return; }
439
- void request({ kind: "swarmagent", killall: true, reason: "The dashboardpage engaged the kill switch." }).then(() => { status("The kill switch engaged: every agent stopped at once, every attributed run cancelled and the queue cleared."); return render(); }).catch(error => status(error instanceof Error ? error.message : String(error), true));
440
- });
441
- reportdownloadbuttonnode?.addEventListener("click", () => {
442
- const download = currentmultiagent?.reportdownload;
443
- if (download === undefined || download.payload === "") { status("No aggregate report exists yet; the swarm builds one when the parallel results merge after the review.", true); return; }
444
- const anchor = document.createElement("a");
445
- anchor.href = URL.createObjectURL(new Blob([download.payload], { type: "application/json" }));
446
- anchor.download = download.filename;
447
- anchor.click();
448
- URL.revokeObjectURL(anchor.href);
449
- status(download.reason);
450
- });
451
- timelinescrubbernode?.addEventListener("input", updatetimelinescrubreadout);
452
-
453
- /**
454
- * Dashboard panel resize of the 2.0.2 final polish (roadmap rc.2 item 37): the dashboardcolumns split carries the separator handle between the two panel columns; the pointer drag moves the left column width through the resizepanel clamp (the readable minimum, the shared maximum and a viewport that keeps the sibling column its own minimum), the arrow keys walk the split for the keyboard, the aria value tracks the live width, and every settled split persists as the panelwidths preference through the same surface layout seam the per surface preferences ride.
455
- */
456
- const dashboardleftnode = document.querySelector<HTMLElement>("#dashboardleft");
457
- const panelresizernode = document.querySelector<HTMLElement>("#panelresizer");
458
- const viewportwidth = (): number | undefined => (typeof window === "undefined" ? undefined : window.innerWidth);
459
- let panelwidths = panelwidthsof(undefined, viewportwidth());
460
-
461
- /** Applies the current panelwidths state to the left column and the separator's live aria value. */
462
- function applypanelwidths(): void {
463
- if (dashboardleftnode) dashboardleftnode.style.width = `${panelwidths.left}px`;
464
- panelresizernode?.setAttribute("aria-valuenow", String(panelwidths.left));
465
- }
466
-
467
- /** Loads the persisted panelwidths preference through the surface layout seam; an absent preference keeps the shipped split. */
468
- async function loadpanelwidths(): Promise<void> {
469
- try {
470
- const layout = await request({ kind: "surface", layout: { get: { surface: "dashboardpage" } } }) as { layout?: { preferences?: { panelwidths?: string } } };
471
- panelwidths = panelwidthsof(layout.layout?.preferences?.panelwidths, typeof window === "undefined" ? undefined : window.innerWidth);
472
- applypanelwidths();
473
- } catch { /* an unreadable preference keeps the shipped split */ }
474
- }
475
-
476
- /** Persists the current panelwidths state through the surface layout seam, merging into the preferences the surface already stores. */
477
- async function savepanelwidths(): Promise<void> {
478
- try {
479
- const layout = await request({ kind: "surface", layout: { get: { surface: "dashboardpage" } } }) as { layout?: { preferences?: Record<string, string> } };
480
- const preferences = { ...(layout.layout?.preferences ?? {}), panelwidths: panelwidthslayout(panelwidths) };
481
- await request({ kind: "surface", layout: { set: { surface: "dashboardpage", preferences } } });
482
- status(`The dashboard panel split of ${panelwidths.left} pixels saved; the columns keep their widths across reloads.`);
483
- } catch (error) { status(error instanceof Error ? error.message : String(error), true); }
484
- }
485
-
486
- if (panelresizernode) {
487
- let dragstartx = 0;
488
- let dragstartwidths = panelwidths;
489
- panelresizernode.addEventListener("pointerdown", event => {
490
- dragstartx = event.clientX;
491
- dragstartwidths = panelwidths;
492
- panelresizernode?.setPointerCapture(event.pointerId);
493
- });
494
- panelresizernode.addEventListener("pointermove", event => {
495
- if (panelresizernode?.hasPointerCapture(event.pointerId) !== true) return;
496
- const viewport = typeof window === "undefined" ? undefined : window.innerWidth;
497
- const move = resizepanel({ widths: dragstartwidths, delta: event.clientX - dragstartx, ...(viewport !== undefined ? { viewport } : {}) });
498
- panelwidths = move.widths;
499
- applypanelwidths();
500
- });
501
- panelresizernode.addEventListener("pointerup", event => {
502
- if (panelresizernode?.hasPointerCapture(event.pointerId) !== true) return;
503
- panelresizernode?.releasePointerCapture(event.pointerId);
504
- void savepanelwidths().catch(() => { /* an unsaved split keeps working until the next write */ });
505
- });
506
- panelresizernode.addEventListener("keydown", event => {
507
- if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") return;
508
- event.preventDefault();
509
- const viewport = typeof window === "undefined" ? undefined : window.innerWidth;
510
- const move = resizepanel({ widths: panelwidths, delta: event.key === "ArrowLeft" ? -16 : 16, ...(viewport !== undefined ? { viewport } : {}) });
511
- panelwidths = move.widths;
512
- applypanelwidths();
513
- void savepanelwidths().catch(() => { /* an unsaved step keeps working until the next write */ });
514
- });
515
- }
516
- void loadpanelwidths().catch(() => { /* an unreadable preference keeps the shipped split */ });
517
-
518
- /** Applies the resolved contrast variant of the 2.0.2 final polish (roadmap rc.2 item 35): the layout preferences seam carries the contrastpreference the optionspage toggle persisted for this surface, and a high preference writes the high contrast token set over the --theme-* custom properties the darklight family resolves — the mode still comes from the theme seam while the default preference keeps the shipped tokens untouched. */
519
- void (async () => {
520
- try {
521
- const layout = await request({ kind: "surface", layout: { get: { surface: "dashboardpage" } } }) as { layout?: { preferences?: { contrastpreference?: string } } };
522
- if (layout.layout?.preferences?.contrastpreference !== "high") return;
523
- const theme = await request({ kind: "views", theme: { resolve: true } }) as { appearance: { mode: "dark" | "light" } };
524
- applycontrasttheme(document.documentElement, document.body, contrasttokensof({ mode: theme.appearance.mode, contrast: "high" }), "high");
525
- status("The high contrast theme is active; the reading tokens answer WCAG AA against the surface.");
526
- } catch { /* a failing preference read keeps the shipped default tokens */ }
527
- })();
528
-
529
- /** The dashboardpage subscribes to session and run updates through the single broadcast channel. */
530
- const surfacechannel: BroadcastChannel | undefined = typeof BroadcastChannel === "function" ? new BroadcastChannel("devthinksurfaces") : undefined;
531
- surfacechannel?.addEventListener("message", () => { void render().catch(() => { /* a failing refresh keeps the last rendered dashboard */ }); });
532
-
533
- void render().catch(error => status(error instanceof Error ? error.message : String(error), true));
534
- void renderhistorysearch("").catch(() => { /* an empty first search shows the empty state */ });
535
- void renderlibrary("").catch(() => { /* an empty first browse shows the empty state */ });
536
- void renderbackgroundruns().catch(() => { /* a failing background runs read keeps the last rendered queue */ });
537
-
538
- /**
539
- * Dropimport zone of the 1.1.65 family: the dashboardpage accepts the csv, json and workflow files the user drops with the same file kind detection and the same import path as the optionspage.
540
- */
541
- const dropzonenode = document.querySelector<HTMLElement>("#dropzone");
542
- const dropstatusnode = document.querySelector<HTMLElement>("#dropstatus");
543
- if (dropzonenode) {
544
- dropzonenode.addEventListener("dragover", event => { event.preventDefault(); });
545
- dropzonenode.addEventListener("drop", event => {
546
- event.preventDefault();
547
- const file = event.dataTransfer?.files[0];
548
- if (file === undefined) return;
549
- void file.text().then(head => request({ kind: "views", dropimport: { file: { filename: file.name, bytes: file.size, head: head.slice(0, 2000) } } })).then(result => {
550
- const session = (result as { session: { filename: string; kind: string; bytes: number } }).session;
551
- if (dropstatusnode) dropstatusnode.textContent = `The dropimport detected the ${session.kind} kind of ${session.filename} (${session.bytes} byte${session.bytes === 1 ? "" : "s"}); the import path takes the file from here.`;
552
- }).catch(error => { if (dropstatusnode) dropstatusnode.textContent = error instanceof Error ? error.message : String(error); });
553
- });
554
- }