@wenathlan/devthink 2.0.14 → 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.
- package/CHANGELOG.md +60 -0
- package/{dist/bridge.d.ts → bridge.d.ts} +1 -1
- package/bridge.d.ts.map +1 -0
- package/bridge.js +1877 -0
- package/bun.d.ts.map +1 -0
- package/bun.js +52329 -0
- package/caps/background.json +712 -0
- package/caps/cli.json +360 -0
- package/caps/library.json +3611 -0
- package/caps/mcp.json +126 -0
- package/caps/pagebridge.json +377 -0
- package/caps/popup.json +51 -0
- package/caps/sidepanel.json +522 -0
- package/checksums.txt +142 -0
- package/cli.d.ts.map +1 -0
- package/{dist/cli.js → cli.js} +2 -2
- package/companion.d.ts.map +1 -0
- package/companion.js +389 -0
- package/crossbrowser.d.ts.map +1 -0
- package/crossbrowser.js +1191 -0
- package/dashdone.d.ts.map +1 -0
- package/dashdone.js +368 -0
- package/deno.d.ts.map +1 -0
- package/deno.js +52325 -0
- package/devthink.umd.js +52346 -0
- package/fixtures/bun.ts +7 -0
- package/fixtures/cjs.js +6 -0
- package/fixtures/deno.ts +6 -0
- package/fixtures/example-org-pagestate.json +22 -0
- package/fixtures/importers/automa-workflow.json +18 -0
- package/fixtures/importers/selenium-side.json +20 -0
- package/fixtures/importers/tabular-plan.csv +7 -0
- package/fixtures/importers/uivision-macro.json +10 -0
- package/fixtures/importers/v1-plan.json +13 -0
- package/fixtures/mcp-client.mjs +14 -0
- package/fixtures/pages/checkout.html +192 -0
- package/fixtures/pages/dashboard.html +110 -0
- package/fixtures/pages/feed.html +113 -0
- package/fixtures/pages/product-grid.html +150 -0
- package/fixtures/plans/form-inventory-plan.json +11 -0
- package/fixtures/plans/release-notes-plan.json +11 -0
- package/fixtures/recipes/agentscompete.json +11 -0
- package/fixtures/recipes/agentsforms.json +11 -0
- package/fixtures/recipes/agentsmonitor.json +11 -0
- package/fixtures/recipes/agentsreview.json +29 -0
- package/fixtures/recipes/agentswarm.json +11 -0
- package/fixtures/recipes/fillcalendar.json +12 -0
- package/fixtures/recipes/fillcheckout.json +13 -0
- package/fixtures/recipes/filldependentdropdowns.json +12 -0
- package/fixtures/recipes/fillfromcsv.json +13 -0
- package/fixtures/recipes/fillloginform.json +12 -0
- package/fixtures/recipes/fillmultistepwizard.json +13 -0
- package/fixtures/recipes/fillregistration.json +12 -0
- package/fixtures/recipes/fillsearchfilters.json +12 -0
- package/fixtures/recipes/filltypeahead.json +11 -0
- package/fixtures/recipes/monitoralerts.json +12 -0
- package/fixtures/recipes/monitoravailability.json +11 -0
- package/fixtures/recipes/monitornetworkquiet.json +12 -0
- package/fixtures/recipes/monitorpagechanges.json +11 -0
- package/fixtures/recipes/monitorpricechange.json +11 -0
- package/fixtures/recipes/monitorschedule.json +12 -0
- package/fixtures/recipes/scrapedynamicprices.json +13 -0
- package/fixtures/recipes/scrapeimagegallery.json +12 -0
- package/fixtures/recipes/scrapeinfinitefeed.json +13 -0
- package/fixtures/recipes/scrapenestedlists.json +12 -0
- package/fixtures/recipes/scrapeproductgrid.json +12 -0
- package/fixtures/recipes/scrapereviews.json +12 -0
- package/fixtures/recipes/scrapesearchresults.json +12 -0
- package/fixtures/recipes/scrapetablepagination.json +12 -0
- package/fixtures/recipes/testaccessibility.json +34 -0
- package/fixtures/recipes/testconsoleerrors.json +12 -0
- package/fixtures/recipes/testdeeplinks.json +12 -0
- package/fixtures/recipes/testformvalidation.json +13 -0
- package/fixtures/recipes/testlayoutshift.json +12 -0
- package/fixtures/recipes/testlinkcheck.json +12 -0
- package/fixtures/recipes/testloadtiming.json +12 -0
- package/fixtures/recipes/testvisualdiff.json +12 -0
- package/fixtures/workflows/changelog-digest-workflow.json +13 -0
- package/fixtures/workflows/form-survey-workflow.json +13 -0
- package/gallery.json +706 -0
- package/hardening.d.ts.map +1 -0
- package/hardening.js +188 -0
- package/headless.d.ts.map +1 -0
- package/headless.js +11522 -0
- package/http.d.ts.map +1 -0
- package/http.js +2165 -0
- package/index.cjs +54682 -0
- package/index.d.ts.map +1 -0
- package/index.js +52310 -0
- package/index.neutral.js +46343 -0
- package/{web/manifest.json → manifest.json} +1 -1
- package/mcp.d.ts.map +1 -0
- package/mcp.js +20515 -0
- package/memory.d.ts.map +1 -0
- package/{memory.ts → memory.js} +2310 -3834
- package/nativehost.template.json +10 -0
- package/node.cjs +54686 -0
- package/node.d.ts.map +1 -0
- package/pack.d.ts.map +1 -0
- package/pack.js +805 -0
- package/package.json +83 -176
- package/policy.d.ts.map +1 -0
- package/{policy.ts → policy.js} +4679 -5073
- package/progress.d.ts.map +1 -0
- package/progress.js +645 -0
- package/protocol.d.ts.map +1 -0
- package/protocol.js +8334 -0
- package/schemas/audit.schema.json +226 -0
- package/schemas/capability.schema.json +113 -0
- package/schemas/envelope.schema.json +162 -0
- package/schemas/memory.schema.json +51 -0
- package/schemas/observation.schema.json +113 -0
- package/schemas/plan.schema.json +208 -0
- package/schemas/progress.schema.json +126 -0
- package/schemas/proposal.schema.json +68 -0
- package/schemas/session.schema.json +82 -0
- package/schemas/tool.schema.json +94 -0
- package/server.d.ts.map +1 -0
- package/server.js +28877 -0
- package/umd-example.html +18 -0
- package/umd.d.ts.map +1 -0
- package/accounts.ts +0 -2087
- package/agent.ts +0 -2331
- package/antigravity.ts +0 -2139
- package/apifreeze.ts +0 -4146
- package/auth.ts +0 -642
- package/background.ts +0 -16837
- package/bridge.ts +0 -2080
- package/build.ts +0 -54
- package/bun.ts +0 -26
- package/capture.ts +0 -1614
- package/checksecrets.ts +0 -72
- package/cjs.ts +0 -9
- package/cli.ts +0 -3500
- package/commands.ts +0 -1101
- package/companion.ts +0 -450
- package/compatibility.ts +0 -37
- package/config.ts +0 -3137
- package/constants.ts +0 -943
- package/core.ts +0 -1473
- package/crossbrowser.ts +0 -1359
- package/dashdone.ts +0 -605
- package/data.ts +0 -943
- package/database.ts +0 -133
- package/debug.ts +0 -850
- package/deno.ts +0 -27
- package/devthink.ts +0 -707
- package/dist/accounts.d.ts +0 -409
- package/dist/agent.d.ts +0 -837
- package/dist/antigravity.d.ts +0 -380
- package/dist/apifreeze.d.ts +0 -113
- package/dist/auth.d.ts +0 -224
- package/dist/capture.d.ts +0 -595
- package/dist/cjs.d.ts +0 -6
- package/dist/commands.d.ts +0 -310
- package/dist/compatibility.d.ts +0 -17
- package/dist/config.d.ts +0 -1853
- package/dist/constants.d.ts +0 -637
- package/dist/core.d.ts +0 -361
- package/dist/data.d.ts +0 -330
- package/dist/database.d.ts +0 -24
- package/dist/debug.d.ts +0 -270
- package/dist/engine.d.ts +0 -74
- package/dist/environments.d.ts +0 -244
- package/dist/evidence.d.ts +0 -277
- package/dist/export.d.ts +0 -311
- package/dist/fingerprint.d.ts +0 -594
- package/dist/flow.d.ts +0 -300
- package/dist/gates.d.ts +0 -103
- package/dist/identity.d.ts +0 -51
- package/dist/ids.d.ts +0 -7
- package/dist/llm.d.ts +0 -652
- package/dist/models.d.ts +0 -1807
- package/dist/net.d.ts +0 -325
- package/dist/neutral.d.ts +0 -41
- package/dist/oauth.d.ts +0 -703
- package/dist/page.d.ts +0 -1166
- package/dist/perf.d.ts +0 -481
- package/dist/plan.d.ts +0 -134
- package/dist/project.d.ts +0 -395
- package/dist/providers.d.ts +0 -37
- package/dist/quota.d.ts +0 -453
- package/dist/recovery.d.ts +0 -621
- package/dist/request.d.ts +0 -1492
- package/dist/run.d.ts +0 -779
- package/dist/runtime.d.ts +0 -212
- package/dist/search.d.ts +0 -375
- package/dist/security.d.ts +0 -534
- package/dist/serve.d.ts +0 -136
- package/dist/session.d.ts +0 -296
- package/dist/storage.d.ts +0 -53
- package/dist/streaming.d.ts +0 -1119
- package/dist/swarm.d.ts +0 -328
- package/dist/tools.d.ts +0 -170
- package/dist/types.d.ts +0 -8357
- package/dist/utils.d.ts +0 -82
- package/dist/version.d.ts +0 -7
- package/dist/versionregistry.d.ts +0 -406
- package/dist/views.d.ts +0 -579
- package/dist/workbenchsession.d.ts +0 -69
- package/dist/workflow.d.ts +0 -649
- package/docs/readme.md +0 -92
- package/docs/schemas/antigravity.json +0 -192
- package/engine.ts +0 -1524
- package/environments.ts +0 -1005
- package/evidence.ts +0 -643
- package/export.ts +0 -889
- package/fingerprint.ts +0 -1458
- package/flow.ts +0 -1190
- package/gates.ts +0 -307
- package/gateway.ts +0 -34
- package/hardening.ts +0 -191
- package/headless.ts +0 -369
- package/http.ts +0 -2110
- package/identity.ts +0 -246
- package/ids.ts +0 -26
- package/index.ts +0 -369
- package/llm.ts +0 -2682
- package/mcp.ts +0 -1835
- package/models.ts +0 -3805
- package/modes.ts +0 -43
- package/net.ts +0 -1214
- package/neutral.ts +0 -362
- package/node.ts +0 -26
- package/oauth.ts +0 -2216
- package/offscreen.ts +0 -170
- package/pack.ts +0 -956
- package/page.ts +0 -7824
- package/pagebridge.ts +0 -1116
- package/perf.ts +0 -957
- package/plan.ts +0 -672
- package/plugin.ts +0 -76
- package/prisma.config.ts +0 -27
- package/progress.ts +0 -1308
- package/project.ts +0 -1291
- package/protocol.ts +0 -4187
- package/providers.ts +0 -246
- package/quota.ts +0 -1887
- package/recovery.ts +0 -2433
- package/request.ts +0 -4482
- package/run.ts +0 -2135
- package/runtime.ts +0 -526
- package/search.ts +0 -1760
- package/security.ts +0 -1673
- package/serve.ts +0 -419
- package/server.ts +0 -5538
- package/session.ts +0 -1162
- package/storage.ts +0 -182
- package/streaming.ts +0 -4101
- package/swarm.ts +0 -884
- package/sync.ts +0 -56
- package/tests/agentcert.test.ts +0 -128
- package/tests/agentfleet.test.ts +0 -214
- package/tests/agentreview.test.ts +0 -241
- package/tests/agentstream.test.ts +0 -335
- package/tests/agentwork.test.ts +0 -356
- package/tests/apifreeze.test.ts +0 -290
- package/tests/apimap.test.ts +0 -112
- package/tests/approvalgate.test.ts +0 -175
- package/tests/artifactmanifest.test.ts +0 -204
- package/tests/attentionfeed.test.ts +0 -163
- package/tests/backgroundruns.test.ts +0 -100
- package/tests/batchscheduling.test.ts +0 -131
- package/tests/blackboard.test.ts +0 -238
- package/tests/bridge.test.ts +0 -1088
- package/tests/browsercoverage.test.ts +0 -134
- package/tests/browserpolyfills.test.ts +0 -124
- package/tests/build.mjs +0 -1260
- package/tests/clientauth.test.ts +0 -223
- package/tests/clitools.test.ts +0 -578
- package/tests/confirmgates.test.ts +0 -190
- package/tests/containerpack.test.ts +0 -143
- package/tests/controlflow.test.ts +0 -2120
- package/tests/coordination.test.ts +0 -345
- package/tests/copyscreen.test.ts +0 -139
- package/tests/core.test.ts +0 -417
- package/tests/costcert.test.ts +0 -95
- package/tests/crossbrowser.test.ts +0 -115
- package/tests/cspaudit.test.ts +0 -79
- package/tests/dashdone.test.ts +0 -615
- package/tests/datagrid.test.ts +0 -137
- package/tests/doccheck.test.ts +0 -107
- package/tests/dombatch.test.ts +0 -109
- package/tests/emulation.test.ts +0 -282
- package/tests/environments.test.ts +0 -259
- package/tests/evidenceviews.test.ts +0 -88
- package/tests/exporttools.test.ts +0 -185
- package/tests/firefoxprep.test.ts +0 -134
- package/tests/flowlibrary.test.ts +0 -242
- package/tests/flowrun.test.ts +0 -303
- package/tests/forensics.test.ts +0 -439
- package/tests/gateway.test.ts +0 -939
- package/tests/headlesslib.test.ts +0 -171
- package/tests/httpstream.test.ts +0 -277
- package/tests/immutablelog.test.ts +0 -157
- package/tests/inboundguard.test.ts +0 -177
- package/tests/lazyload.test.ts +0 -72
- package/tests/librarymodes.test.ts +0 -623
- package/tests/llm.test.ts +0 -696
- package/tests/manifest.test.ts +0 -226
- package/tests/maskinputs.test.ts +0 -150
- package/tests/matrixverify.test.ts +0 -111
- package/tests/mavenpack.test.ts +0 -75
- package/tests/mcpserver.test.ts +0 -704
- package/tests/memory.test.ts +0 -4155
- package/tests/memorycare.test.ts +0 -230
- package/tests/migrateplan.test.ts +0 -349
- package/tests/minimization.test.ts +0 -414
- package/tests/modelroute.test.ts +0 -112
- package/tests/multiagent.test.ts +0 -440
- package/tests/nativebridge.test.ts +0 -807
- package/tests/navigation.test.ts +0 -284
- package/tests/nugetpack.test.ts +0 -83
- package/tests/orchestration.test.ts +0 -449
- package/tests/originpolicy.test.ts +0 -405
- package/tests/outputcompare.test.ts +0 -97
- package/tests/package.test.ts +0 -91
- package/tests/pagebridge.test.ts +0 -5909
- package/tests/pentest.test.ts +0 -75
- package/tests/perfrecords.test.ts +0 -257
- package/tests/permdiff.test.ts +0 -85
- package/tests/phishguard.test.ts +0 -128
- package/tests/pickerviews.test.ts +0 -155
- package/tests/pipelines.test.ts +0 -381
- package/tests/planlint.test.ts +0 -240
- package/tests/planreview.test.ts +0 -383
- package/tests/platformtargets.test.ts +0 -56
- package/tests/policy.test.ts +0 -8284
- package/tests/portability.test.ts +0 -96
- package/tests/progress.test.ts +0 -1036
- package/tests/promptlibrary.test.ts +0 -116
- package/tests/protocol.test.ts +0 -4793
- package/tests/publishingpipeline.test.ts +0 -314
- package/tests/quickactions.test.ts +0 -164
- package/tests/readiness.test.ts +0 -78
- package/tests/recipes.test.ts +0 -163
- package/tests/redactshots.test.ts +0 -216
- package/tests/registernvidiakeys.ts +0 -51
- package/tests/relayserve.test.ts +0 -304
- package/tests/releasenotes.test.ts +0 -276
- package/tests/resilience.test.ts +0 -467
- package/tests/resourceaware.test.ts +0 -187
- package/tests/runbudget.test.ts +0 -125
- package/tests/runhistory.test.ts +0 -299
- package/tests/runreplay.test.ts +0 -113
- package/tests/runresume.test.ts +0 -184
- package/tests/runstate.test.ts +0 -288
- package/tests/runtimeadapters.test.ts +0 -251
- package/tests/safariskeleton.test.ts +0 -115
- package/tests/sandboxframe.test.ts +0 -196
- package/tests/sbom.test.ts +0 -105
- package/tests/secretvault.test.ts +0 -188
- package/tests/selcache.test.ts +0 -111
- package/tests/sessioninterface.test.ts +0 -791
- package/tests/sessions.test.ts +0 -591
- package/tests/siteprefs.test.ts +0 -228
- package/tests/snapshotdelta.test.ts +0 -165
- package/tests/statusviews.test.ts +0 -237
- package/tests/stepmeter.test.ts +0 -200
- package/tests/streamparse.test.ts +0 -163
- package/tests/stylepruning.test.ts +0 -90
- package/tests/surfaces.test.ts +0 -282
- package/tests/sweep.test.ts +0 -78
- package/tests/syncbridge.test.ts +0 -164
- package/tests/taskqueue.test.ts +0 -206
- package/tests/toolcalls.test.ts +0 -336
- package/tests/toolcatalog.test.ts +0 -201
- package/tests/torture-agent.test.ts +0 -706
- package/tests/torture-auth.test.ts +0 -461
- package/tests/torture-commands.test.ts +0 -895
- package/tests/torture-data.test.ts +0 -923
- package/tests/torture-environments.test.ts +0 -285
- package/tests/torture-export.test.ts +0 -263
- package/tests/torture-http.test.ts +0 -1379
- package/tests/torture-llm.test.ts +0 -808
- package/tests/torture-memory.test.ts +0 -1084
- package/tests/torture-plan.test.ts +0 -829
- package/tests/torture-run.test.ts +0 -626
- package/tests/torture-session.test.ts +0 -928
- package/tests/torture-swarm.test.ts +0 -1245
- package/tests/torture-tools.test.ts +0 -964
- package/tests/torture-workflow.test.ts +0 -2354
- package/tests/tourviews.test.ts +0 -52
- package/tests/transparency.test.ts +0 -147
- package/tests/trigger.test.ts +0 -941
- package/tests/v1sunset.test.ts +0 -428
- package/tests/virtlist.test.ts +0 -94
- package/tests/vision.test.ts +0 -540
- package/tests/vsixpack.test.ts +0 -145
- package/tests/webapi.test.ts +0 -523
- package/tests/workflow.test.ts +0 -1785
- package/tests/workfloweditor.test.ts +0 -759
- package/tests/xpipack.test.ts +0 -128
- package/tools.ts +0 -734
- package/types.ts +0 -9908
- package/umd.ts +0 -9
- package/utils.ts +0 -249
- package/version.ts +0 -8
- package/versionregistry.ts +0 -1310
- package/views.ts +0 -2153
- package/vitest.config.ts +0 -12
- package/web/App.tsx +0 -78
- package/web/README.md +0 -47
- package/web/capacitor.config.ts +0 -46
- package/web/const.ts +0 -19
- package/web/control.shell.tsx +0 -66
- package/web/dashboardpage.ts +0 -554
- package/web/db.ts +0 -493
- package/web/design.html +0 -541
- package/web/gatewayview/Gateway.tsx +0 -345
- package/web/gatewayview/config.ts +0 -1042
- package/web/gatewayview/definition.ts +0 -174
- package/web/icons.ts +0 -15
- package/web/optionspage.ts +0 -691
- package/web/popup.ts +0 -1651
- package/web/schema.prisma +0 -176
- package/web/sidepanel.ts +0 -7941
- package/web/sitemanifest.json +0 -13
- package/web/terminal-ui.tsx +0 -622
- package/web/transparencypage.ts +0 -541
- package/web/vite.config.ts +0 -39
- package/web/workspace.ts +0 -23
- package/workbenchmemory.ts +0 -104
- package/workbenchsession.ts +0 -304
- package/workflow.ts +0 -4495
- /package/{dist/bun.d.ts → bun.d.ts} +0 -0
- /package/{dist/cli.d.ts → cli.d.ts} +0 -0
- /package/{dist/companion.d.ts → companion.d.ts} +0 -0
- /package/{dist/crossbrowser.d.ts → crossbrowser.d.ts} +0 -0
- /package/{dist/dashdone.d.ts → dashdone.d.ts} +0 -0
- /package/{dist/deno.d.ts → deno.d.ts} +0 -0
- /package/{dist/hardening.d.ts → hardening.d.ts} +0 -0
- /package/{dist/headless.d.ts → headless.d.ts} +0 -0
- /package/{dist/http.d.ts → http.d.ts} +0 -0
- /package/{dist/index.d.ts → index.d.ts} +0 -0
- /package/{dist/mcp.d.ts → mcp.d.ts} +0 -0
- /package/{dist/memory.d.ts → memory.d.ts} +0 -0
- /package/{dist/node.d.ts → node.d.ts} +0 -0
- /package/{dist/pack.d.ts → pack.d.ts} +0 -0
- /package/{dist/policy.d.ts → policy.d.ts} +0 -0
- /package/{dist/progress.d.ts → progress.d.ts} +0 -0
- /package/{dist/protocol.d.ts → protocol.d.ts} +0 -0
- /package/{dist/server.d.ts → server.d.ts} +0 -0
- /package/{dist/umd.d.ts → umd.d.ts} +0 -0
package/web/dashboardpage.ts
DELETED
|
@@ -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
|
-
}
|