@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/sync.ts
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { getIdentity } from "./identity.js";
|
|
2
|
-
import { listSessions, loadWorkspace, type Session, type Workspace } from "./workbenchsession.js";
|
|
3
|
-
import { isSecureRemoteEndpoint } from "./compatibility.js";
|
|
4
|
-
import type { DevThinkConfig, DevThinkPaths } from "./config.ts";
|
|
5
|
-
|
|
6
|
-
export type SyncSnapshot = {
|
|
7
|
-
version: 1;
|
|
8
|
-
userId: string;
|
|
9
|
-
deviceId: string;
|
|
10
|
-
exportedAt: string;
|
|
11
|
-
workspaces: Workspace[];
|
|
12
|
-
sessions: Session[];
|
|
13
|
-
};
|
|
14
|
-
export type RemoteSyncStatus = { enabled: boolean; endpoint?: string; ready: boolean; reason?: string };
|
|
15
|
-
|
|
16
|
-
export function exportLocalSnapshot(paths: DevThinkPaths): SyncSnapshot {
|
|
17
|
-
const identity = getIdentity(paths);
|
|
18
|
-
const sessions = listSessions(paths);
|
|
19
|
-
const workspaces = [...new Set(sessions.map((session) => session.workspaceId))].flatMap((workspaceId) => {
|
|
20
|
-
const workspace = loadWorkspace(paths, workspaceId);
|
|
21
|
-
return workspace ? [workspace] : [];
|
|
22
|
-
});
|
|
23
|
-
return {
|
|
24
|
-
version: 1,
|
|
25
|
-
userId: identity.userId,
|
|
26
|
-
deviceId: identity.deviceId,
|
|
27
|
-
exportedAt: new Date().toISOString(),
|
|
28
|
-
workspaces,
|
|
29
|
-
sessions,
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export function remoteSyncStatus(config: DevThinkConfig): RemoteSyncStatus {
|
|
34
|
-
const remote = config.web?.remoteSync;
|
|
35
|
-
if (!remote?.enabled)
|
|
36
|
-
return {
|
|
37
|
-
enabled: false,
|
|
38
|
-
ready: false,
|
|
39
|
-
reason: "Remote synchronization is disabled; local pairing remains available.",
|
|
40
|
-
};
|
|
41
|
-
if (!remote.endpoint)
|
|
42
|
-
return {
|
|
43
|
-
enabled: true,
|
|
44
|
-
ready: false,
|
|
45
|
-
reason: "Set web.remoteSync.endpoint to a user-operated HTTPS API that implements the DevThink sync contract.",
|
|
46
|
-
};
|
|
47
|
-
if (!isSecureRemoteEndpoint(remote.endpoint)) {
|
|
48
|
-
return {
|
|
49
|
-
enabled: true,
|
|
50
|
-
endpoint: remote.endpoint,
|
|
51
|
-
ready: false,
|
|
52
|
-
reason: "Remote synchronization endpoint is not a valid HTTPS URL.",
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
return { enabled: true, endpoint: new URL(remote.endpoint).toString(), ready: true };
|
|
56
|
-
}
|
package/tests/agentcert.test.ts
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { execFile } from "node:child_process";
|
|
3
|
-
import { existsSync } from "node:fs";
|
|
4
|
-
import { readFile } from "node:fs/promises";
|
|
5
|
-
import { promisify } from "node:util";
|
|
6
|
-
|
|
7
|
-
const execute = promisify(execFile);
|
|
8
|
-
|
|
9
|
-
/* ── The 1.1.96 multi agent coordination certification coverage. ── */
|
|
10
|
-
|
|
11
|
-
describe("the agentcert coordination artifact", () => {
|
|
12
|
-
it("declares every automated entry of the release candidate coordination checklist with its family and module", async () => {
|
|
13
|
-
const source = await readFile("tests/agentcert.mjs", "utf8");
|
|
14
|
-
const declarations = [
|
|
15
|
-
...source.matchAll(/await entry\(\{ id: (\d+), title: "([^"]+)", family: "([^"]+)", module: "([^"]+)" \}/g),
|
|
16
|
-
].map((match) => ({ id: Number(match[1]), title: match[2], family: match[3], module: match[4] }));
|
|
17
|
-
expect(declarations).toHaveLength(30);
|
|
18
|
-
expect(declarations.map((entry) => entry.id)).toEqual(Array.from({ length: 30 }, (_, index) => index + 1));
|
|
19
|
-
const families = new Set(declarations.map((entry) => entry.family));
|
|
20
|
-
for (const family of [
|
|
21
|
-
"topology",
|
|
22
|
-
"roles",
|
|
23
|
-
"review",
|
|
24
|
-
"verification",
|
|
25
|
-
"messaging",
|
|
26
|
-
"queue",
|
|
27
|
-
"work stealing",
|
|
28
|
-
"blackboard",
|
|
29
|
-
"tab handoff",
|
|
30
|
-
"locking",
|
|
31
|
-
"conflicts",
|
|
32
|
-
"merging",
|
|
33
|
-
"consensus",
|
|
34
|
-
"emergency stops",
|
|
35
|
-
"lifecycle",
|
|
36
|
-
"sub agents",
|
|
37
|
-
"escalation",
|
|
38
|
-
"review flow",
|
|
39
|
-
"audit replay",
|
|
40
|
-
"comparison",
|
|
41
|
-
"lanes",
|
|
42
|
-
"arbitration",
|
|
43
|
-
"scaling",
|
|
44
|
-
"budgets",
|
|
45
|
-
"scopes",
|
|
46
|
-
"reporting",
|
|
47
|
-
"timeline",
|
|
48
|
-
"lessons",
|
|
49
|
-
"pool coverage",
|
|
50
|
-
])
|
|
51
|
-
expect(families.has(family)).toBe(true);
|
|
52
|
-
for (const entry of declarations) expect((entry.title ?? "").length).toBeGreaterThan(10);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it("covers every coordination scenario entry with a passing outcome once the gate has run", async () => {
|
|
56
|
-
const artifactpath = "tests/artifacts/agentcert.json";
|
|
57
|
-
const built = existsSync("dist/extension/manifest.json");
|
|
58
|
-
const packagejson = JSON.parse(await readFile("package.json", "utf8")) as { version: string };
|
|
59
|
-
/* a built tree runs the gate itself when no fresh artifact of this release exists, so every lane that builds before the suite — the bun lane, the deno lane, a local two-pass validate — verifies the coordination artifact without depending on the gate having run before the tests */
|
|
60
|
-
if (built && !existsSync(artifactpath)) await execute("node", ["tests/agentcert.mjs"]);
|
|
61
|
-
if (built && existsSync(artifactpath)) {
|
|
62
|
-
const stored = JSON.parse(await readFile(artifactpath, "utf8")) as { release: string };
|
|
63
|
-
if (stored.release !== packagejson.version) await execute("node", ["tests/agentcert.mjs"]);
|
|
64
|
-
}
|
|
65
|
-
const stored = existsSync(artifactpath);
|
|
66
|
-
if (built) expect(stored).toBe(true);
|
|
67
|
-
if (!stored) return;
|
|
68
|
-
const report = JSON.parse(await readFile(artifactpath, "utf8")) as {
|
|
69
|
-
release: string;
|
|
70
|
-
clockmode: string;
|
|
71
|
-
faketabkinds: string[];
|
|
72
|
-
entries: Array<{ id: number; title: string; outcome: string; detail: string }>;
|
|
73
|
-
summary: {
|
|
74
|
-
total: number;
|
|
75
|
-
passed: number;
|
|
76
|
-
failed: number;
|
|
77
|
-
poolitems: { from: number; to: number; covered: number };
|
|
78
|
-
};
|
|
79
|
-
};
|
|
80
|
-
expect(report.release).toBe(packagejson.version);
|
|
81
|
-
expect(report.summary.total).toBe(30);
|
|
82
|
-
expect(report.summary.failed).toBe(0);
|
|
83
|
-
expect(report.summary.passed).toBe(30);
|
|
84
|
-
expect(report.entries.map((entry) => entry.id)).toEqual(Array.from({ length: 30 }, (_, index) => index + 1));
|
|
85
|
-
for (const entry of report.entries) {
|
|
86
|
-
expect(entry.outcome).toBe("pass");
|
|
87
|
-
expect(entry.detail.length).toBeGreaterThan(10);
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it("records the deterministic run mode, the fake tab kinds of every browser and the pool coverage of 469 through 502", async () => {
|
|
92
|
-
const artifactpath = "tests/artifacts/agentcert.json";
|
|
93
|
-
if (!existsSync(artifactpath)) return;
|
|
94
|
-
const report = JSON.parse(await readFile(artifactpath, "utf8")) as {
|
|
95
|
-
clockmode: string;
|
|
96
|
-
faketabkinds: string[];
|
|
97
|
-
summary: { poolitems: { from: number; to: number; covered: number } };
|
|
98
|
-
};
|
|
99
|
-
/* the fake clock mode keeps every coordination scenario deterministic, the fake tab provider covers every browser kind and the pool mapping covers every multi agent coordination item of the feature pool */
|
|
100
|
-
expect(report.clockmode).toBe("fake");
|
|
101
|
-
expect(report.faketabkinds).toEqual(["chromium", "firefox", "safari"]);
|
|
102
|
-
expect(report.summary.poolitems).toEqual({ from: 469, to: 502, covered: 34 });
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
it("exercises the real compiled modules the checklist names and stays deterministic", async () => {
|
|
106
|
-
const source = await readFile("tests/agentcert.mjs", "utf8");
|
|
107
|
-
expect(source).toContain('import("../dist/index.js")');
|
|
108
|
-
expect(source).toContain('import("../dist/policy.js")');
|
|
109
|
-
expect(source).toContain('import("../dist/dashdone.js")');
|
|
110
|
-
/* every fixture time flows from the fixed epoch of the fake clock that stays the default mode — the real clock exists only behind the explicit opt in switch the operator drives — and the artifact carries no timestamps so reruns stay byte identical */
|
|
111
|
-
expect(source).toContain("fakeclock");
|
|
112
|
-
expect(source).toContain("1_800_000_000_000");
|
|
113
|
-
expect(source).toContain('clockmode = process.argv.includes("--clock")');
|
|
114
|
-
const artifactpath = "tests/artifacts/agentcert.json";
|
|
115
|
-
if (existsSync(artifactpath)) expect(await readFile(artifactpath, "utf8")).not.toContain('"at"');
|
|
116
|
-
expect(source).toContain("process.exitCode = 1");
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
it("exports the leader worker topology scenario the chromium smoke executes end to end", async () => {
|
|
120
|
-
const source = await readFile("tests/agentcert.mjs", "utf8");
|
|
121
|
-
expect(source).toContain("export async function runleaderworkertopologyscenario");
|
|
122
|
-
expect(source).toContain("faketabprovider.tabof");
|
|
123
|
-
/* the scenario registers five fake agents across the fake tabs of every browser kind, so the smoke covers one coordination scenario against the shipped bundles */
|
|
124
|
-
expect(source).toContain('tabof("chromium"');
|
|
125
|
-
expect(source).toContain('tabof("firefox"');
|
|
126
|
-
expect(source).toContain('tabof("safari"');
|
|
127
|
-
});
|
|
128
|
-
});
|
package/tests/agentfleet.test.ts
DELETED
|
@@ -1,214 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import {
|
|
3
|
-
agentbudgetof,
|
|
4
|
-
agentname,
|
|
5
|
-
agentscopeof,
|
|
6
|
-
budgetremaining,
|
|
7
|
-
engagekillswitch,
|
|
8
|
-
fleetoverview,
|
|
9
|
-
pauseagent,
|
|
10
|
-
readonlyscope,
|
|
11
|
-
spendbudget,
|
|
12
|
-
unpauseagent,
|
|
13
|
-
} from "../agent.js";
|
|
14
|
-
import {
|
|
15
|
-
agentnamevalid,
|
|
16
|
-
agentscopegate,
|
|
17
|
-
budgetgate,
|
|
18
|
-
killswitchgate,
|
|
19
|
-
pauseagentgate,
|
|
20
|
-
voteweightvalid,
|
|
21
|
-
} from "../policy.js";
|
|
22
|
-
import type { agentrecord, runrecord, taskqueue } from "../types.js";
|
|
23
|
-
import { emptyqueue } from "../swarm.js";
|
|
24
|
-
|
|
25
|
-
const now = 1_800_000_000_000;
|
|
26
|
-
|
|
27
|
-
/** Builds one fleet record fixture with every value user chosen. */
|
|
28
|
-
function record(over: Partial<agentrecord> = {}): agentrecord {
|
|
29
|
-
return {
|
|
30
|
-
id: "a1",
|
|
31
|
-
name: "scout",
|
|
32
|
-
role: "worker",
|
|
33
|
-
origin: "https://example.com",
|
|
34
|
-
state: "active",
|
|
35
|
-
registeredat: now,
|
|
36
|
-
lastseenat: now,
|
|
37
|
-
...over,
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/** Builds one run record fixture of the fleet attribution. */
|
|
42
|
-
function run(over: Partial<runrecord> = {}): runrecord {
|
|
43
|
-
return {
|
|
44
|
-
runid: "run1",
|
|
45
|
-
planid: "plan1",
|
|
46
|
-
sessionid: "session1",
|
|
47
|
-
state: "running",
|
|
48
|
-
createdat: now,
|
|
49
|
-
updatedat: now,
|
|
50
|
-
agentid: "a1",
|
|
51
|
-
...over,
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
describe("agentfleet naming and scope narrowing", () => {
|
|
56
|
-
it("assigns unique lowercase names and refuses duplicates, reserved words and out of rule names", () => {
|
|
57
|
-
const first = agentname({ records: [], id: "a1", proposed: " Scout ", origin: "https://example.com", now });
|
|
58
|
-
expect(first.name).toBe("scout");
|
|
59
|
-
expect(first.state).toBe("active");
|
|
60
|
-
expect(agentnamevalid({ name: "Scout", records: [first] }).allowed).toBe(false);
|
|
61
|
-
expect(() =>
|
|
62
|
-
agentname({ records: [first], id: "a2", proposed: "scout", origin: "https://example.com", now }),
|
|
63
|
-
).toThrow(/already registered/i);
|
|
64
|
-
expect(() =>
|
|
65
|
-
agentname({ records: [first], id: "a2", proposed: "user", origin: "https://example.com", now }),
|
|
66
|
-
).toThrow(/reserved/i);
|
|
67
|
-
expect(() =>
|
|
68
|
-
agentname({ records: [first], id: "a2", proposed: "Scout Two", origin: "https://example.com", now }),
|
|
69
|
-
).toThrow(/lowercase identifier/i);
|
|
70
|
-
const second = agentname({
|
|
71
|
-
records: [first],
|
|
72
|
-
id: "a2",
|
|
73
|
-
proposed: "verifier",
|
|
74
|
-
role: "verifier",
|
|
75
|
-
origin: "https://example.com",
|
|
76
|
-
now,
|
|
77
|
-
});
|
|
78
|
-
expect(second.name).toBe("verifier");
|
|
79
|
-
expect(second.role).toBe("verifier");
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
it("intersects the requested scope with the session grants and narrows the action kinds", () => {
|
|
83
|
-
const grants = ["https://example.com", "https://other.example"];
|
|
84
|
-
const scope = agentscopeof({
|
|
85
|
-
agentid: "a1",
|
|
86
|
-
requested: {
|
|
87
|
-
origins: ["https://example.com", "https://denied.example"],
|
|
88
|
-
actionkinds: ["observe", "readtext", "click"],
|
|
89
|
-
},
|
|
90
|
-
grants,
|
|
91
|
-
allowedkinds: ["observe", "readtext", "navigate", "click"],
|
|
92
|
-
});
|
|
93
|
-
expect(scope.origins).toEqual(["https://example.com"]);
|
|
94
|
-
expect(scope.actionkinds).toEqual(["observe", "readtext", "click"]);
|
|
95
|
-
expect(() =>
|
|
96
|
-
agentscopeof({
|
|
97
|
-
agentid: "a1",
|
|
98
|
-
requested: { origins: ["https://denied.example"] },
|
|
99
|
-
grants,
|
|
100
|
-
allowedkinds: ["observe"],
|
|
101
|
-
}),
|
|
102
|
-
).toThrow(/outside the session grants/i);
|
|
103
|
-
expect(() =>
|
|
104
|
-
agentscopeof({ agentid: "a1", requested: { actionkinds: ["typetime"] }, grants, allowedkinds: ["observe"] }),
|
|
105
|
-
).toThrow(/outside the allowed catalog/i);
|
|
106
|
-
const observer = readonlyscope({ agentid: "a2", readkinds: ["observe", "readtext"] });
|
|
107
|
-
expect(observer.readonly).toBe(true);
|
|
108
|
-
expect(observer.toolnamespaces).toEqual(["memory", "system"]);
|
|
109
|
-
expect(agentscopegate({ scope: observer, kind: "click", risk: "sensitive" }).allowed).toBe(false);
|
|
110
|
-
expect(agentscopegate({ scope: observer, kind: "observe", risk: "read" }).allowed).toBe(true);
|
|
111
|
-
expect(agentscopegate({ scope, kind: "observe", origin: "https://example.com", risk: "read" }).allowed).toBe(true);
|
|
112
|
-
expect(agentscopegate({ scope, kind: "click", origin: "https://denied.example", risk: "sensitive" }).allowed).toBe(
|
|
113
|
-
false,
|
|
114
|
-
);
|
|
115
|
-
});
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
describe("agentfleet budget grant, spend refusal and reporting", () => {
|
|
119
|
-
it("grants a budget from user configuration, spends one unit per step and refuses past the ceiling", () => {
|
|
120
|
-
const grant = agentbudgetof({ agentid: "a1", maxsteps: 2, maxtokens: 100, maxdurationms: 5_000, now });
|
|
121
|
-
expect(grant.state.spentsteps).toBe(0);
|
|
122
|
-
expect(grant.budget.maxsteps).toBe(2);
|
|
123
|
-
const onestep = spendbudget({ state: grant.state, steps: 1, tokens: 40, durationms: 1_000, now });
|
|
124
|
-
expect(onestep.spentsteps).toBe(1);
|
|
125
|
-
const twosteps = spendbudget({ state: onestep, steps: 1, tokens: 40, durationms: 1_000, now });
|
|
126
|
-
expect(twosteps.spentsteps).toBe(2);
|
|
127
|
-
expect(() => spendbudget({ state: twosteps, steps: 1, now })).toThrow(/budgeted steps/i);
|
|
128
|
-
expect(() => spendbudget({ state: twosteps, steps: 0, tokens: 40, now })).toThrow(/budgeted tokens/i);
|
|
129
|
-
expect(() => spendbudget({ state: twosteps, steps: 0, tokens: 0, durationms: 5_000, now })).toThrow(
|
|
130
|
-
/budgeted milliseconds/i,
|
|
131
|
-
);
|
|
132
|
-
const gate = budgetgate({ state: twosteps, steps: 1 });
|
|
133
|
-
expect(gate.allowed).toBe(false);
|
|
134
|
-
expect(gate.reason).toMatch(/user configured steps/i);
|
|
135
|
-
const unbounded = agentbudgetof({ agentid: "a2", now });
|
|
136
|
-
expect(budgetgate({ state: unbounded.state, steps: 1_000 }).allowed).toBe(true);
|
|
137
|
-
const remaining = budgetremaining(twosteps);
|
|
138
|
-
expect(remaining.steps).toBe(0);
|
|
139
|
-
expect(remaining.reason).toMatch(/0 of 2 steps left/i);
|
|
140
|
-
expect(() => agentbudgetof({ agentid: "a1", maxsteps: -3, now })).toThrow(/positive number/i);
|
|
141
|
-
});
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
describe("agentfleet pause isolation and killswitch completeness", () => {
|
|
145
|
-
it("pauses one agent without stopping its peers and leaves their run records untouched", () => {
|
|
146
|
-
const fleet = [record(), record({ id: "a2", name: "mapper" })];
|
|
147
|
-
const gate = pauseagentgate({ records: fleet, agentid: "a1" });
|
|
148
|
-
expect(gate.allowed).toBe(true);
|
|
149
|
-
expect(gate.reason).toMatch(/1 peer/i);
|
|
150
|
-
const paused = pauseagent({ records: fleet, agentid: "a1", now });
|
|
151
|
-
expect(paused.find((entry) => entry.id === "a1")?.state).toBe("paused");
|
|
152
|
-
expect(paused.find((entry) => entry.id === "a2")?.state).toBe("active");
|
|
153
|
-
expect(() => pauseagent({ records: paused, agentid: "missing", now })).toThrow(/not registered/i);
|
|
154
|
-
const resumed = unpauseagent({ records: paused, agentid: "a1", now });
|
|
155
|
-
expect(resumed.find((entry) => entry.id === "a1")?.state).toBe("active");
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
it("engages the killswitch in one call: every record stops, every agent run cancels, every queue clears and each stopped agent counts", () => {
|
|
159
|
-
const fleet = [
|
|
160
|
-
record(),
|
|
161
|
-
record({ id: "a2", name: "mapper" }),
|
|
162
|
-
record({ id: "a3", name: "watcher", state: "paused" }),
|
|
163
|
-
];
|
|
164
|
-
const userrun: runrecord = {
|
|
165
|
-
runid: "run3",
|
|
166
|
-
planid: "plan3",
|
|
167
|
-
sessionid: "session1",
|
|
168
|
-
state: "running",
|
|
169
|
-
createdat: now,
|
|
170
|
-
updatedat: now,
|
|
171
|
-
};
|
|
172
|
-
const runs = [
|
|
173
|
-
run(),
|
|
174
|
-
run({ runid: "run2", agentid: "a2", state: "queued" }),
|
|
175
|
-
userrun,
|
|
176
|
-
run({ runid: "run4", agentid: "a2", state: "completed" }),
|
|
177
|
-
];
|
|
178
|
-
const queue: taskqueue = {
|
|
179
|
-
...emptyqueue({ lanes: ["main"] }),
|
|
180
|
-
items: [{ id: "t1", lane: "main", priority: 1, payload: "task", state: "queued", enqueuedat: now }],
|
|
181
|
-
claims: [],
|
|
182
|
-
};
|
|
183
|
-
const usergate = killswitchgate({ triggeredby: "user", pausedagents: 1 });
|
|
184
|
-
expect(usergate.allowed).toBe(true);
|
|
185
|
-
expect(usergate.reason).toMatch(/stays effective over the 1 paused agent/i);
|
|
186
|
-
expect(killswitchgate({ triggeredby: "agent" }).allowed).toBe(false);
|
|
187
|
-
const stop = engagekillswitch({ records: fleet, runs, queues: [queue], reason: "The user halted the fleet.", now });
|
|
188
|
-
expect(stop.records.every((entry) => entry.state === "stopped")).toBe(true);
|
|
189
|
-
expect(stop.runs.find((entry) => entry.runid === "run1")?.state).toBe("cancelled");
|
|
190
|
-
expect(stop.runs.find((entry) => entry.runid === "run2")?.state).toBe("cancelled");
|
|
191
|
-
expect(stop.runs.find((entry) => entry.runid === "run3")?.state).toBe("running");
|
|
192
|
-
expect(stop.runs.find((entry) => entry.runid === "run4")?.state).toBe("completed");
|
|
193
|
-
expect(stop.queues[0]?.items).toHaveLength(0);
|
|
194
|
-
expect(stop.stopped).toHaveLength(3);
|
|
195
|
-
expect(stop.stopped.map((entry) => entry.name)).toEqual(["scout", "mapper", "watcher"]);
|
|
196
|
-
expect(stop.stopped.find((entry) => entry.agentid === "a1")?.runs).toEqual(["run1"]);
|
|
197
|
-
const overview = fleetoverview({
|
|
198
|
-
records: stop.records,
|
|
199
|
-
budgets: [],
|
|
200
|
-
openescalations: 1,
|
|
201
|
-
openreviews: 2,
|
|
202
|
-
killswitchat: now,
|
|
203
|
-
});
|
|
204
|
-
expect(overview.stopped).toBe(3);
|
|
205
|
-
expect(overview.openescalations).toBe(1);
|
|
206
|
-
expect(overview.lastkillswitchat).toBe(now);
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
it("keeps the vote weight at one per agentrecord", () => {
|
|
210
|
-
expect(voteweightvalid({ votes: [{ agentid: "a1" }, { agentid: "a2" }] }).allowed).toBe(true);
|
|
211
|
-
expect(voteweightvalid({ votes: [{ agentid: "a1" }, { agentid: "a1" }] }).reason).toMatch(/voted twice/i);
|
|
212
|
-
expect(voteweightvalid({ votes: [{ agentid: " " }] }).allowed).toBe(false);
|
|
213
|
-
});
|
|
214
|
-
});
|
|
@@ -1,241 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import {
|
|
3
|
-
consensusrecordof,
|
|
4
|
-
escalationblock,
|
|
5
|
-
outputcompare,
|
|
6
|
-
recordverdict,
|
|
7
|
-
reconstructreplay,
|
|
8
|
-
reviewrecordof,
|
|
9
|
-
runreplay,
|
|
10
|
-
} from "../agent.js";
|
|
11
|
-
import { escalate, resolveescalation } from "../swarm.js";
|
|
12
|
-
import { escalateholdgate, fleetoperationgrade, replayexportgate, reviewrequestgate } from "../policy.js";
|
|
13
|
-
import type { agentrecord, escalationrecord } from "../types.js";
|
|
14
|
-
|
|
15
|
-
const now = 1_800_000_000_000;
|
|
16
|
-
|
|
17
|
-
/** Builds one fleet record fixture with every value user chosen. */
|
|
18
|
-
function record(over: Partial<agentrecord> = {}): agentrecord {
|
|
19
|
-
return {
|
|
20
|
-
id: "a1",
|
|
21
|
-
name: "scout",
|
|
22
|
-
role: "worker",
|
|
23
|
-
origin: "https://example.com",
|
|
24
|
-
state: "active",
|
|
25
|
-
registeredat: now,
|
|
26
|
-
lastseenat: now,
|
|
27
|
-
...over,
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
describe("agentreview escalation blocking and review request routing", () => {
|
|
32
|
-
it("blocks the raising agent until the human answers and lifts the hold with the decision", () => {
|
|
33
|
-
const raised = escalate({
|
|
34
|
-
id: "e1",
|
|
35
|
-
agentid: "a1",
|
|
36
|
-
subject: "Which pricing table should the extraction target?",
|
|
37
|
-
context: "The page carries two tables and the plan covers one.",
|
|
38
|
-
now,
|
|
39
|
-
});
|
|
40
|
-
expect(raised.state).toBe("open");
|
|
41
|
-
const held = escalationblock({ escalations: [raised], agentid: "a1" });
|
|
42
|
-
expect(held.blocked).toBe(true);
|
|
43
|
-
expect(held.reason).toMatch(/only the human answer lifts the hold/i);
|
|
44
|
-
expect(escalateholdgate({ escalations: [raised], agentid: "a1" }).allowed).toBe(false);
|
|
45
|
-
expect(escalateholdgate({ escalations: [raised], agentid: "a2" }).allowed).toBe(true);
|
|
46
|
-
expect(escalationblock({ escalations: [raised], agentid: "a2" }).blocked).toBe(false);
|
|
47
|
-
const decided = resolveescalation({
|
|
48
|
-
escalation: raised,
|
|
49
|
-
decision: "Extract the second table; the first one repeats the header row.",
|
|
50
|
-
now: now + 1_000,
|
|
51
|
-
});
|
|
52
|
-
expect(decided.state).toBe("decided");
|
|
53
|
-
expect(escalateholdgate({ escalations: [decided], agentid: "a1" }).allowed).toBe(true);
|
|
54
|
-
expect(escalationblock({ escalations: [decided], agentid: "a1" }).blocked).toBe(false);
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it("routes one review request between two agents of the shared origin and records the verdict beside the original output", () => {
|
|
58
|
-
const from = record();
|
|
59
|
-
const to = record({ id: "a2", name: "mapper", role: "critic" });
|
|
60
|
-
expect(reviewrequestgate({ from, to }).allowed).toBe(true);
|
|
61
|
-
expect(
|
|
62
|
-
reviewrequestgate({ from, to: record({ id: "a3", name: "outsider", origin: "https://other.example" }) }).allowed,
|
|
63
|
-
).toBe(false);
|
|
64
|
-
const request = reviewrecordof({
|
|
65
|
-
id: "r1",
|
|
66
|
-
fromagentid: "a1",
|
|
67
|
-
toagentid: "a2",
|
|
68
|
-
subject: "the extracted pricing rows",
|
|
69
|
-
output: "rows: 12, columns: 4, currency: brl",
|
|
70
|
-
now,
|
|
71
|
-
});
|
|
72
|
-
expect(request.state).toBe("open");
|
|
73
|
-
expect(() =>
|
|
74
|
-
reviewrecordof({ id: "r2", fromagentid: "a1", toagentid: "a1", subject: "self", output: "own", now }),
|
|
75
|
-
).toThrow(/never reviews its own/i);
|
|
76
|
-
expect(() => recordverdict({ records: [request], id: "r1", reviewerid: "a3", verdict: "approve", now })).toThrow(
|
|
77
|
-
/waits for the agent a2/i,
|
|
78
|
-
);
|
|
79
|
-
expect(() => recordverdict({ records: [request], id: "r1", reviewerid: "a2", verdict: "reject", now })).toThrow(
|
|
80
|
-
/names its issues/i,
|
|
81
|
-
);
|
|
82
|
-
const answered = recordverdict({
|
|
83
|
-
records: [request],
|
|
84
|
-
id: "r1",
|
|
85
|
-
reviewerid: "a2",
|
|
86
|
-
verdict: "changes",
|
|
87
|
-
issues: ["the currency column missed the second page"],
|
|
88
|
-
now: now + 1_000,
|
|
89
|
-
});
|
|
90
|
-
expect(answered.state).toBe("answered");
|
|
91
|
-
expect(answered.verdict).toBe("changes");
|
|
92
|
-
expect(answered.output).toBe("rows: 12, columns: 4, currency: brl");
|
|
93
|
-
expect(answered.issues).toEqual(["the currency column missed the second page"]);
|
|
94
|
-
expect(() => recordverdict({ records: [answered], id: "r1", reviewerid: "a2", verdict: "approve", now })).toThrow(
|
|
95
|
-
/never rewrites/i,
|
|
96
|
-
);
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
describe("agentreview runreplay capture and audit reconstruction", () => {
|
|
101
|
-
it("captures the ordered steps and results of an agent run", () => {
|
|
102
|
-
const capture = runreplay({
|
|
103
|
-
id: "p1",
|
|
104
|
-
agentid: "a1",
|
|
105
|
-
runid: "run1",
|
|
106
|
-
steps: [
|
|
107
|
-
{ stepid: "s2", kind: "extract", summary: "read the pricing table", state: "done", at: now + 200 },
|
|
108
|
-
{ stepid: "s1", kind: "observe", summary: "snapshot the page", state: "done", at: now + 100 },
|
|
109
|
-
],
|
|
110
|
-
now: now + 300,
|
|
111
|
-
});
|
|
112
|
-
expect(capture.steps.map((step) => step.stepid)).toEqual(["s1", "s2"]);
|
|
113
|
-
expect(capture.reconstructed).toBeUndefined();
|
|
114
|
-
expect(() => runreplay({ id: "p2", agentid: "a1", runid: "run1", steps: [], now })).toThrow(
|
|
115
|
-
/at least one recorded step/i,
|
|
116
|
-
);
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
it("reconstructs a run from the audit trail when the run memory is gone and marks the reconstruction", () => {
|
|
120
|
-
const events = [
|
|
121
|
-
{
|
|
122
|
-
id: "ev1",
|
|
123
|
-
kind: "action",
|
|
124
|
-
summary: "The observe step s1 completed.",
|
|
125
|
-
at: now + 100,
|
|
126
|
-
agentid: "a1",
|
|
127
|
-
stepid: "s1",
|
|
128
|
-
planid: "run1",
|
|
129
|
-
},
|
|
130
|
-
{
|
|
131
|
-
id: "ev2",
|
|
132
|
-
kind: "error",
|
|
133
|
-
summary: "The extract step s2 failed.",
|
|
134
|
-
at: now + 200,
|
|
135
|
-
agentid: "a1",
|
|
136
|
-
stepid: "s2",
|
|
137
|
-
planid: "run1",
|
|
138
|
-
},
|
|
139
|
-
{
|
|
140
|
-
id: "ev3",
|
|
141
|
-
kind: "action",
|
|
142
|
-
summary: "The navigate step s3 of another agent completed.",
|
|
143
|
-
at: now + 300,
|
|
144
|
-
agentid: "a2",
|
|
145
|
-
stepid: "s3",
|
|
146
|
-
planid: "run2",
|
|
147
|
-
},
|
|
148
|
-
];
|
|
149
|
-
const rebuilt = reconstructreplay({ id: "p3", agentid: "a1", runid: "run1", events, now: now + 400 });
|
|
150
|
-
expect(rebuilt.reconstructed).toBe(true);
|
|
151
|
-
expect(rebuilt.steps.map((step) => step.stepid)).toEqual(["s1", "s2"]);
|
|
152
|
-
expect(rebuilt.steps.find((step) => step.stepid === "s2")?.state).toBe("failed");
|
|
153
|
-
expect(() => reconstructreplay({ id: "p4", agentid: "a9", runid: "run9", events, now })).toThrow(
|
|
154
|
-
/carries no event/i,
|
|
155
|
-
);
|
|
156
|
-
expect(replayexportgate({ consent: false, agentid: "a1" }).allowed).toBe(false);
|
|
157
|
-
expect(replayexportgate({ consent: true, agentid: "a1" }).allowed).toBe(true);
|
|
158
|
-
});
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
describe("agentreview outputcompare alignment and consensusvote tallies", () => {
|
|
162
|
-
it("aligns two agent outputs field by field with matching, conflicting and missing fields", () => {
|
|
163
|
-
const comparison = outputcompare({
|
|
164
|
-
id: "c1",
|
|
165
|
-
subject: "the extracted totals",
|
|
166
|
-
left: { agentid: "a1", fields: { rows: "12", currency: "brl", totals: "4" } },
|
|
167
|
-
right: { agentid: "a2", fields: { rows: "12", currency: "usd" } },
|
|
168
|
-
now,
|
|
169
|
-
});
|
|
170
|
-
expect(comparison.matching).toEqual(["rows"]);
|
|
171
|
-
expect(comparison.conflicting).toEqual(["currency"]);
|
|
172
|
-
expect(comparison.missing).toEqual(["totals"]);
|
|
173
|
-
expect(() =>
|
|
174
|
-
outputcompare({
|
|
175
|
-
id: "c2",
|
|
176
|
-
subject: "self",
|
|
177
|
-
left: { agentid: "a1", fields: {} },
|
|
178
|
-
right: { agentid: "a1", fields: {} },
|
|
179
|
-
now,
|
|
180
|
-
}),
|
|
181
|
-
).toThrow(/never competes with itself/i);
|
|
182
|
-
expect(fleetoperationgrade("outputcompare").allowed).toBe(true);
|
|
183
|
-
expect(fleetoperationgrade("consensusvote").allowed).toBe(true);
|
|
184
|
-
expect(fleetoperationgrade("navigate").allowed).toBe(false);
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
it("collects one vote per agent, computes the outcome by the quorum rule and keeps the dissent", () => {
|
|
188
|
-
const carried = consensusrecordof({
|
|
189
|
-
id: "v1",
|
|
190
|
-
proposal: "the fleet extracts the second pricing table",
|
|
191
|
-
votes: [
|
|
192
|
-
{ agentid: "a1", vote: "yes", castat: now },
|
|
193
|
-
{ agentid: "a2", vote: "yes", castat: now + 100 },
|
|
194
|
-
{ agentid: "a3", vote: "no", reason: "the first table carries the live prices", castat: now + 200 },
|
|
195
|
-
],
|
|
196
|
-
quorum: 2,
|
|
197
|
-
voters: 3,
|
|
198
|
-
now: now + 300,
|
|
199
|
-
});
|
|
200
|
-
expect(carried.tally).toEqual({ yes: 2, no: 1, abstain: 0 });
|
|
201
|
-
expect(carried.outcome).toBe("carried");
|
|
202
|
-
expect(carried.votes.find((vote) => vote.agentid === "a3")?.reason).toBe("the first table carries the live prices");
|
|
203
|
-
expect(() =>
|
|
204
|
-
consensusrecordof({
|
|
205
|
-
id: "v2",
|
|
206
|
-
proposal: "duplicate vote",
|
|
207
|
-
votes: [
|
|
208
|
-
{ agentid: "a1", vote: "yes", castat: now },
|
|
209
|
-
{ agentid: "a1", vote: "no", castat: now + 100 },
|
|
210
|
-
],
|
|
211
|
-
quorum: 1,
|
|
212
|
-
now,
|
|
213
|
-
}),
|
|
214
|
-
).toThrow(/already voted/i);
|
|
215
|
-
const failed = consensusrecordof({
|
|
216
|
-
id: "v3",
|
|
217
|
-
proposal: "the fleet opens a second tab",
|
|
218
|
-
votes: [
|
|
219
|
-
{ agentid: "a1", vote: "no", castat: now },
|
|
220
|
-
{ agentid: "a2", vote: "abstain", castat: now + 100 },
|
|
221
|
-
],
|
|
222
|
-
quorum: 2,
|
|
223
|
-
voters: 2,
|
|
224
|
-
now: now + 200,
|
|
225
|
-
});
|
|
226
|
-
expect(failed.outcome).toBe("failed");
|
|
227
|
-
const open = consensusrecordof({
|
|
228
|
-
id: "v4",
|
|
229
|
-
proposal: "the fleet opens a second tab",
|
|
230
|
-
votes: [{ agentid: "a1", vote: "yes", castat: now }],
|
|
231
|
-
quorum: 2,
|
|
232
|
-
voters: 3,
|
|
233
|
-
now: now + 100,
|
|
234
|
-
});
|
|
235
|
-
expect(open.outcome).toBe("open");
|
|
236
|
-
expect(open.closedat).toBeUndefined();
|
|
237
|
-
expect(() => consensusrecordof({ id: "v5", proposal: "no quorum", votes: [], quorum: 0, now })).toThrow(
|
|
238
|
-
/positive whole number/i,
|
|
239
|
-
);
|
|
240
|
-
});
|
|
241
|
-
});
|