@descryy/mcp 0.11.3 → 0.11.5
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/package.json +20 -20
- package/dist/action-handshake.d.ts +0 -38
- package/dist/action-handshake.d.ts.map +0 -1
- package/dist/action-handshake.js +0 -127
- package/dist/action-handshake.js.map +0 -1
- package/dist/bin/descry-mcp.d.ts +0 -7
- package/dist/bin/descry-mcp.d.ts.map +0 -1
- package/dist/bin/descry-mcp.js +0 -72
- package/dist/bin/descry-mcp.js.map +0 -1
- package/dist/browser/auth.d.ts +0 -84
- package/dist/browser/auth.d.ts.map +0 -1
- package/dist/browser/auth.js +0 -233
- package/dist/browser/auth.js.map +0 -1
- package/dist/browser/capability-probe.d.ts +0 -109
- package/dist/browser/capability-probe.d.ts.map +0 -1
- package/dist/browser/capability-probe.js +0 -201
- package/dist/browser/capability-probe.js.map +0 -1
- package/dist/browser/driver.d.ts +0 -570
- package/dist/browser/driver.d.ts.map +0 -1
- package/dist/browser/driver.js +0 -116
- package/dist/browser/driver.js.map +0 -1
- package/dist/browser/evidence.d.ts +0 -28
- package/dist/browser/evidence.d.ts.map +0 -1
- package/dist/browser/evidence.js +0 -82
- package/dist/browser/evidence.js.map +0 -1
- package/dist/browser/fake-driver.d.ts +0 -116
- package/dist/browser/fake-driver.d.ts.map +0 -1
- package/dist/browser/fake-driver.js +0 -416
- package/dist/browser/fake-driver.js.map +0 -1
- package/dist/browser/fault-attribution.d.ts +0 -178
- package/dist/browser/fault-attribution.d.ts.map +0 -1
- package/dist/browser/fault-attribution.js +0 -266
- package/dist/browser/fault-attribution.js.map +0 -1
- package/dist/browser/graph-write.d.ts +0 -45
- package/dist/browser/graph-write.d.ts.map +0 -1
- package/dist/browser/graph-write.js +0 -103
- package/dist/browser/graph-write.js.map +0 -1
- package/dist/browser/identity-graph-write.d.ts +0 -55
- package/dist/browser/identity-graph-write.d.ts.map +0 -1
- package/dist/browser/identity-graph-write.js +0 -45
- package/dist/browser/identity-graph-write.js.map +0 -1
- package/dist/browser/page-probe.d.ts +0 -81
- package/dist/browser/page-probe.d.ts.map +0 -1
- package/dist/browser/page-probe.js +0 -202
- package/dist/browser/page-probe.js.map +0 -1
- package/dist/browser/playwright-driver.d.ts +0 -114
- package/dist/browser/playwright-driver.d.ts.map +0 -1
- package/dist/browser/playwright-driver.js +0 -1479
- package/dist/browser/playwright-driver.js.map +0 -1
- package/dist/browser/provider.d.ts +0 -26
- package/dist/browser/provider.d.ts.map +0 -1
- package/dist/browser/provider.js +0 -14
- package/dist/browser/provider.js.map +0 -1
- package/dist/browser/reach-recording-session.d.ts +0 -44
- package/dist/browser/reach-recording-session.d.ts.map +0 -1
- package/dist/browser/reach-recording-session.js +0 -143
- package/dist/browser/reach-recording-session.js.map +0 -1
- package/dist/browser/reachability.d.ts +0 -168
- package/dist/browser/reachability.d.ts.map +0 -1
- package/dist/browser/reachability.js +0 -294
- package/dist/browser/reachability.js.map +0 -1
- package/dist/browser/registry.d.ts +0 -126
- package/dist/browser/registry.d.ts.map +0 -1
- package/dist/browser/registry.js +0 -177
- package/dist/browser/registry.js.map +0 -1
- package/dist/browser/scenario-provenance.d.ts +0 -23
- package/dist/browser/scenario-provenance.d.ts.map +0 -1
- package/dist/browser/scenario-provenance.js +0 -73
- package/dist/browser/scenario-provenance.js.map +0 -1
- package/dist/browser/scenario-resolve.d.ts +0 -28
- package/dist/browser/scenario-resolve.d.ts.map +0 -1
- package/dist/browser/scenario-resolve.js +0 -96
- package/dist/browser/scenario-resolve.js.map +0 -1
- package/dist/browser/scenario-runner.d.ts +0 -72
- package/dist/browser/scenario-runner.d.ts.map +0 -1
- package/dist/browser/scenario-runner.js +0 -353
- package/dist/browser/scenario-runner.js.map +0 -1
- package/dist/browser/stack-parser.d.ts +0 -19
- package/dist/browser/stack-parser.d.ts.map +0 -1
- package/dist/browser/stack-parser.js +0 -85
- package/dist/browser/stack-parser.js.map +0 -1
- package/dist/browser/tool-support.d.ts +0 -71
- package/dist/browser/tool-support.d.ts.map +0 -1
- package/dist/browser/tool-support.js +0 -216
- package/dist/browser/tool-support.js.map +0 -1
- package/dist/browser/url-scheme.d.ts +0 -14
- package/dist/browser/url-scheme.d.ts.map +0 -1
- package/dist/browser/url-scheme.js +0 -38
- package/dist/browser/url-scheme.js.map +0 -1
- package/dist/browser/wait-target.d.ts +0 -37
- package/dist/browser/wait-target.d.ts.map +0 -1
- package/dist/browser/wait-target.js +0 -54
- package/dist/browser/wait-target.js.map +0 -1
- package/dist/cancellation.d.ts +0 -20
- package/dist/cancellation.d.ts.map +0 -1
- package/dist/cancellation.js +0 -41
- package/dist/cancellation.js.map +0 -1
- package/dist/capped.d.ts +0 -17
- package/dist/capped.d.ts.map +0 -1
- package/dist/capped.js +0 -15
- package/dist/capped.js.map +0 -1
- package/dist/credential-store.d.ts +0 -22
- package/dist/credential-store.d.ts.map +0 -1
- package/dist/credential-store.js +0 -33
- package/dist/credential-store.js.map +0 -1
- package/dist/disclosure-ledger.d.ts +0 -14
- package/dist/disclosure-ledger.d.ts.map +0 -1
- package/dist/disclosure-ledger.js +0 -18
- package/dist/disclosure-ledger.js.map +0 -1
- package/dist/evidence/observed-route-evidence.d.ts +0 -25
- package/dist/evidence/observed-route-evidence.d.ts.map +0 -1
- package/dist/evidence/observed-route-evidence.js +0 -76
- package/dist/evidence/observed-route-evidence.js.map +0 -1
- package/dist/heap.d.ts +0 -61
- package/dist/heap.d.ts.map +0 -1
- package/dist/heap.js +0 -82
- package/dist/heap.js.map +0 -1
- package/dist/heartbeat.d.ts +0 -46
- package/dist/heartbeat.d.ts.map +0 -1
- package/dist/heartbeat.js +0 -66
- package/dist/heartbeat.js.map +0 -1
- package/dist/index.d.ts +0 -32
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -19
- package/dist/index.js.map +0 -1
- package/dist/module-trust.d.ts +0 -37
- package/dist/module-trust.d.ts.map +0 -1
- package/dist/module-trust.js +0 -77
- package/dist/module-trust.js.map +0 -1
- package/dist/path-confinement.d.ts +0 -31
- package/dist/path-confinement.d.ts.map +0 -1
- package/dist/path-confinement.js +0 -44
- package/dist/path-confinement.js.map +0 -1
- package/dist/planner/predict-then-propose.d.ts +0 -134
- package/dist/planner/predict-then-propose.d.ts.map +0 -1
- package/dist/planner/predict-then-propose.js +0 -138
- package/dist/planner/predict-then-propose.js.map +0 -1
- package/dist/planner/propose-journey.d.ts +0 -75
- package/dist/planner/propose-journey.d.ts.map +0 -1
- package/dist/planner/propose-journey.js +0 -96
- package/dist/planner/propose-journey.js.map +0 -1
- package/dist/protocol.d.ts +0 -57
- package/dist/protocol.d.ts.map +0 -1
- package/dist/protocol.js +0 -90
- package/dist/protocol.js.map +0 -1
- package/dist/registry.d.ts +0 -103
- package/dist/registry.d.ts.map +0 -1
- package/dist/registry.js +0 -319
- package/dist/registry.js.map +0 -1
- package/dist/render.d.ts +0 -580
- package/dist/render.d.ts.map +0 -1
- package/dist/render.js +0 -867
- package/dist/render.js.map +0 -1
- package/dist/runtime-registry.d.ts +0 -22
- package/dist/runtime-registry.d.ts.map +0 -1
- package/dist/runtime-registry.js +0 -142
- package/dist/runtime-registry.js.map +0 -1
- package/dist/sandbox-defaults.d.ts +0 -41
- package/dist/sandbox-defaults.d.ts.map +0 -1
- package/dist/sandbox-defaults.js +0 -14
- package/dist/sandbox-defaults.js.map +0 -1
- package/dist/scenarios/browser-run-plan-projection.d.ts +0 -161
- package/dist/scenarios/browser-run-plan-projection.d.ts.map +0 -1
- package/dist/scenarios/browser-run-plan-projection.js +0 -264
- package/dist/scenarios/browser-run-plan-projection.js.map +0 -1
- package/dist/scenarios/credential-ref.d.ts +0 -102
- package/dist/scenarios/credential-ref.d.ts.map +0 -1
- package/dist/scenarios/credential-ref.js +0 -148
- package/dist/scenarios/credential-ref.js.map +0 -1
- package/dist/scenarios/index.d.ts +0 -7
- package/dist/scenarios/index.d.ts.map +0 -1
- package/dist/scenarios/index.js +0 -7
- package/dist/scenarios/index.js.map +0 -1
- package/dist/scenarios/parse.d.ts +0 -18
- package/dist/scenarios/parse.d.ts.map +0 -1
- package/dist/scenarios/parse.js +0 -212
- package/dist/scenarios/parse.js.map +0 -1
- package/dist/scenarios/scenario.d.ts +0 -93
- package/dist/scenarios/scenario.d.ts.map +0 -1
- package/dist/scenarios/scenario.js +0 -27
- package/dist/scenarios/scenario.js.map +0 -1
- package/dist/scenarios/secret-ref.d.ts +0 -86
- package/dist/scenarios/secret-ref.d.ts.map +0 -1
- package/dist/scenarios/secret-ref.js +0 -125
- package/dist/scenarios/secret-ref.js.map +0 -1
- package/dist/scenarios/storage.d.ts +0 -21
- package/dist/scenarios/storage.d.ts.map +0 -1
- package/dist/scenarios/storage.js +0 -103
- package/dist/scenarios/storage.js.map +0 -1
- package/dist/server.d.ts +0 -61
- package/dist/server.d.ts.map +0 -1
- package/dist/server.js +0 -541
- package/dist/server.js.map +0 -1
- package/dist/session.d.ts +0 -243
- package/dist/session.d.ts.map +0 -1
- package/dist/session.js +0 -602
- package/dist/session.js.map +0 -1
- package/dist/tools/alias-kit.d.ts +0 -29
- package/dist/tools/alias-kit.d.ts.map +0 -1
- package/dist/tools/alias-kit.js +0 -21
- package/dist/tools/alias-kit.js.map +0 -1
- package/dist/tools/aliases.d.ts +0 -42
- package/dist/tools/aliases.d.ts.map +0 -1
- package/dist/tools/aliases.js +0 -52
- package/dist/tools/aliases.js.map +0 -1
- package/dist/tools/analyze-workspace.d.ts +0 -52
- package/dist/tools/analyze-workspace.d.ts.map +0 -1
- package/dist/tools/analyze-workspace.js +0 -207
- package/dist/tools/analyze-workspace.js.map +0 -1
- package/dist/tools/analyze.d.ts +0 -163
- package/dist/tools/analyze.d.ts.map +0 -1
- package/dist/tools/analyze.js +0 -724
- package/dist/tools/analyze.js.map +0 -1
- package/dist/tools/browser-click.d.ts +0 -18
- package/dist/tools/browser-click.d.ts.map +0 -1
- package/dist/tools/browser-click.js +0 -110
- package/dist/tools/browser-click.js.map +0 -1
- package/dist/tools/browser-close-session.d.ts +0 -39
- package/dist/tools/browser-close-session.d.ts.map +0 -1
- package/dist/tools/browser-close-session.js +0 -120
- package/dist/tools/browser-close-session.js.map +0 -1
- package/dist/tools/browser-fill.d.ts +0 -18
- package/dist/tools/browser-fill.d.ts.map +0 -1
- package/dist/tools/browser-fill.js +0 -117
- package/dist/tools/browser-fill.js.map +0 -1
- package/dist/tools/browser-navigate.d.ts +0 -15
- package/dist/tools/browser-navigate.d.ts.map +0 -1
- package/dist/tools/browser-navigate.js +0 -104
- package/dist/tools/browser-navigate.js.map +0 -1
- package/dist/tools/browser-read.d.ts +0 -33
- package/dist/tools/browser-read.d.ts.map +0 -1
- package/dist/tools/browser-read.js +0 -113
- package/dist/tools/browser-read.js.map +0 -1
- package/dist/tools/browser-run-scenario.d.ts +0 -28
- package/dist/tools/browser-run-scenario.d.ts.map +0 -1
- package/dist/tools/browser-run-scenario.js +0 -206
- package/dist/tools/browser-run-scenario.js.map +0 -1
- package/dist/tools/browser-save-scenario.d.ts +0 -19
- package/dist/tools/browser-save-scenario.d.ts.map +0 -1
- package/dist/tools/browser-save-scenario.js +0 -447
- package/dist/tools/browser-save-scenario.js.map +0 -1
- package/dist/tools/browser-select.d.ts +0 -20
- package/dist/tools/browser-select.d.ts.map +0 -1
- package/dist/tools/browser-select.js +0 -120
- package/dist/tools/browser-select.js.map +0 -1
- package/dist/tools/browser-snapshot.d.ts +0 -46
- package/dist/tools/browser-snapshot.d.ts.map +0 -1
- package/dist/tools/browser-snapshot.js +0 -127
- package/dist/tools/browser-snapshot.js.map +0 -1
- package/dist/tools/browser-start-session.d.ts +0 -24
- package/dist/tools/browser-start-session.d.ts.map +0 -1
- package/dist/tools/browser-start-session.js +0 -622
- package/dist/tools/browser-start-session.js.map +0 -1
- package/dist/tools/browser-submit.d.ts +0 -18
- package/dist/tools/browser-submit.d.ts.map +0 -1
- package/dist/tools/browser-submit.js +0 -106
- package/dist/tools/browser-submit.js.map +0 -1
- package/dist/tools/browser-type.d.ts +0 -18
- package/dist/tools/browser-type.d.ts.map +0 -1
- package/dist/tools/browser-type.js +0 -115
- package/dist/tools/browser-type.js.map +0 -1
- package/dist/tools/browser-wait-for.d.ts +0 -45
- package/dist/tools/browser-wait-for.d.ts.map +0 -1
- package/dist/tools/browser-wait-for.js +0 -150
- package/dist/tools/browser-wait-for.js.map +0 -1
- package/dist/tools/browser.d.ts +0 -69
- package/dist/tools/browser.d.ts.map +0 -1
- package/dist/tools/browser.js +0 -386
- package/dist/tools/browser.js.map +0 -1
- package/dist/tools/chain.d.ts +0 -41
- package/dist/tools/chain.d.ts.map +0 -1
- package/dist/tools/chain.js +0 -105
- package/dist/tools/chain.js.map +0 -1
- package/dist/tools/change-scope.d.ts +0 -25
- package/dist/tools/change-scope.d.ts.map +0 -1
- package/dist/tools/change-scope.js +0 -110
- package/dist/tools/change-scope.js.map +0 -1
- package/dist/tools/code-context.d.ts +0 -83
- package/dist/tools/code-context.d.ts.map +0 -1
- package/dist/tools/code-context.js +0 -416
- package/dist/tools/code-context.js.map +0 -1
- package/dist/tools/contracts.d.ts +0 -74
- package/dist/tools/contracts.d.ts.map +0 -1
- package/dist/tools/contracts.js +0 -196
- package/dist/tools/contracts.js.map +0 -1
- package/dist/tools/cross-pr.d.ts +0 -178
- package/dist/tools/cross-pr.d.ts.map +0 -1
- package/dist/tools/cross-pr.js +0 -321
- package/dist/tools/cross-pr.js.map +0 -1
- package/dist/tools/disclosure.d.ts +0 -75
- package/dist/tools/disclosure.d.ts.map +0 -1
- package/dist/tools/disclosure.js +0 -288
- package/dist/tools/disclosure.js.map +0 -1
- package/dist/tools/draw-conclusion.d.ts +0 -55
- package/dist/tools/draw-conclusion.d.ts.map +0 -1
- package/dist/tools/draw-conclusion.js +0 -259
- package/dist/tools/draw-conclusion.js.map +0 -1
- package/dist/tools/git-context.d.ts +0 -39
- package/dist/tools/git-context.d.ts.map +0 -1
- package/dist/tools/git-context.js +0 -364
- package/dist/tools/git-context.js.map +0 -1
- package/dist/tools/git-diff.d.ts +0 -45
- package/dist/tools/git-diff.d.ts.map +0 -1
- package/dist/tools/git-diff.js +0 -338
- package/dist/tools/git-diff.js.map +0 -1
- package/dist/tools/git-history.d.ts +0 -16
- package/dist/tools/git-history.d.ts.map +0 -1
- package/dist/tools/git-history.js +0 -86
- package/dist/tools/git-history.js.map +0 -1
- package/dist/tools/history.d.ts +0 -34
- package/dist/tools/history.d.ts.map +0 -1
- package/dist/tools/history.js +0 -121
- package/dist/tools/history.js.map +0 -1
- package/dist/tools/impact.d.ts +0 -46
- package/dist/tools/impact.d.ts.map +0 -1
- package/dist/tools/impact.js +0 -225
- package/dist/tools/impact.js.map +0 -1
- package/dist/tools/index.d.ts +0 -59
- package/dist/tools/index.d.ts.map +0 -1
- package/dist/tools/index.js +0 -70
- package/dist/tools/index.js.map +0 -1
- package/dist/tools/kit.d.ts +0 -165
- package/dist/tools/kit.d.ts.map +0 -1
- package/dist/tools/kit.js +0 -153
- package/dist/tools/kit.js.map +0 -1
- package/dist/tools/link-workspace.d.ts +0 -24
- package/dist/tools/link-workspace.d.ts.map +0 -1
- package/dist/tools/link-workspace.js +0 -131
- package/dist/tools/link-workspace.js.map +0 -1
- package/dist/tools/lookup.d.ts +0 -19
- package/dist/tools/lookup.d.ts.map +0 -1
- package/dist/tools/lookup.js +0 -63
- package/dist/tools/lookup.js.map +0 -1
- package/dist/tools/mark-incident.d.ts +0 -28
- package/dist/tools/mark-incident.d.ts.map +0 -1
- package/dist/tools/mark-incident.js +0 -188
- package/dist/tools/mark-incident.js.map +0 -1
- package/dist/tools/merged-browser.d.ts +0 -11
- package/dist/tools/merged-browser.d.ts.map +0 -1
- package/dist/tools/merged-browser.js +0 -20
- package/dist/tools/merged-browser.js.map +0 -1
- package/dist/tools/merged-context.d.ts +0 -11
- package/dist/tools/merged-context.d.ts.map +0 -1
- package/dist/tools/merged-context.js +0 -21
- package/dist/tools/merged-context.js.map +0 -1
- package/dist/tools/merged-observe.d.ts +0 -13
- package/dist/tools/merged-observe.d.ts.map +0 -1
- package/dist/tools/merged-observe.js +0 -21
- package/dist/tools/merged-observe.js.map +0 -1
- package/dist/tools/merged-workspace.d.ts +0 -14
- package/dist/tools/merged-workspace.d.ts.map +0 -1
- package/dist/tools/merged-workspace.js +0 -21
- package/dist/tools/merged-workspace.js.map +0 -1
- package/dist/tools/observe-runtime.d.ts +0 -250
- package/dist/tools/observe-runtime.d.ts.map +0 -1
- package/dist/tools/observe-runtime.js +0 -1753
- package/dist/tools/observe-runtime.js.map +0 -1
- package/dist/tools/observe-tests.d.ts +0 -57
- package/dist/tools/observe-tests.d.ts.map +0 -1
- package/dist/tools/observe-tests.js +0 -368
- package/dist/tools/observe-tests.js.map +0 -1
- package/dist/tools/observe.d.ts +0 -28
- package/dist/tools/observe.d.ts.map +0 -1
- package/dist/tools/observe.js +0 -330
- package/dist/tools/observe.js.map +0 -1
- package/dist/tools/pr-analysis.d.ts +0 -189
- package/dist/tools/pr-analysis.d.ts.map +0 -1
- package/dist/tools/pr-analysis.js +0 -299
- package/dist/tools/pr-analysis.js.map +0 -1
- package/dist/tools/pre-push.d.ts +0 -168
- package/dist/tools/pre-push.d.ts.map +0 -1
- package/dist/tools/pre-push.js +0 -416
- package/dist/tools/pre-push.js.map +0 -1
- package/dist/tools/predict-reach.d.ts +0 -57
- package/dist/tools/predict-reach.d.ts.map +0 -1
- package/dist/tools/predict-reach.js +0 -159
- package/dist/tools/predict-reach.js.map +0 -1
- package/dist/tools/propagation.d.ts +0 -37
- package/dist/tools/propagation.d.ts.map +0 -1
- package/dist/tools/propagation.js +0 -162
- package/dist/tools/propagation.js.map +0 -1
- package/dist/tools/propose-journey.d.ts +0 -16
- package/dist/tools/propose-journey.d.ts.map +0 -1
- package/dist/tools/propose-journey.js +0 -121
- package/dist/tools/propose-journey.js.map +0 -1
- package/dist/tools/prove-reach.d.ts +0 -74
- package/dist/tools/prove-reach.d.ts.map +0 -1
- package/dist/tools/prove-reach.js +0 -286
- package/dist/tools/prove-reach.js.map +0 -1
- package/dist/tools/questions.d.ts +0 -30
- package/dist/tools/questions.d.ts.map +0 -1
- package/dist/tools/questions.js +0 -232
- package/dist/tools/questions.js.map +0 -1
- package/dist/tools/refusal-fetch.d.ts +0 -35
- package/dist/tools/refusal-fetch.d.ts.map +0 -1
- package/dist/tools/refusal-fetch.js +0 -103
- package/dist/tools/refusal-fetch.js.map +0 -1
- package/dist/tools/runtime-incident.d.ts +0 -33
- package/dist/tools/runtime-incident.d.ts.map +0 -1
- package/dist/tools/runtime-incident.js +0 -67
- package/dist/tools/runtime-incident.js.map +0 -1
- package/dist/tools/runtime-journey-drive.d.ts +0 -102
- package/dist/tools/runtime-journey-drive.d.ts.map +0 -1
- package/dist/tools/runtime-journey-drive.js +0 -247
- package/dist/tools/runtime-journey-drive.js.map +0 -1
- package/dist/tools/scope.d.ts +0 -45
- package/dist/tools/scope.d.ts.map +0 -1
- package/dist/tools/scope.js +0 -186
- package/dist/tools/scope.js.map +0 -1
- package/dist/tools/similar-incidents.d.ts +0 -43
- package/dist/tools/similar-incidents.d.ts.map +0 -1
- package/dist/tools/similar-incidents.js +0 -179
- package/dist/tools/similar-incidents.js.map +0 -1
- package/dist/tools/validate.d.ts +0 -133
- package/dist/tools/validate.d.ts.map +0 -1
- package/dist/tools/validate.js +0 -442
- package/dist/tools/validate.js.map +0 -1
- package/dist/tools/verb.d.ts +0 -46
- package/dist/tools/verb.d.ts.map +0 -1
- package/dist/tools/verb.js +0 -78
- package/dist/tools/verb.js.map +0 -1
- package/dist/tools/verification-status.d.ts +0 -38
- package/dist/tools/verification-status.d.ts.map +0 -1
- package/dist/tools/verification-status.js +0 -203
- package/dist/tools/verification-status.js.map +0 -1
- package/dist/tools/verify-claim.d.ts +0 -29
- package/dist/tools/verify-claim.d.ts.map +0 -1
- package/dist/tools/verify-claim.js +0 -220
- package/dist/tools/verify-claim.js.map +0 -1
- package/dist/tools/workspace.d.ts +0 -28
- package/dist/tools/workspace.d.ts.map +0 -1
- package/dist/tools/workspace.js +0 -101
- package/dist/tools/workspace.js.map +0 -1
- package/dist/transport.d.ts +0 -32
- package/dist/transport.d.ts.map +0 -1
- package/dist/transport.js +0 -85
- package/dist/transport.js.map +0 -1
- package/dist/workspace-index.d.ts +0 -164
- package/dist/workspace-index.d.ts.map +0 -1
- package/dist/workspace-index.js +0 -381
- package/dist/workspace-index.js.map +0 -1
|
@@ -1,622 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `browser_start_session` — opens a real browser (DEC-380: consent lives here only,
|
|
3
|
-
* bound to the target URL's origin — `browser_navigate` refuses to leave it). Class
|
|
4
|
-
* `action`: the only browser tool that mints a token; the verbs it consents for
|
|
5
|
-
* redeem nothing, since the session is already confirmed. */
|
|
6
|
-
import { CANCELLED_STATE, cancellationHeadline, cancellationNotes } from "../cancellation.js";
|
|
7
|
-
import { browserAnswer, emptyEvidence, observeAndCorrelate, reachNotes } from "../browser/tool-support.js";
|
|
8
|
-
import { NO_GRAPH_WRITE } from "../browser/graph-write.js";
|
|
9
|
-
import { isAbsolute, join } from "node:path";
|
|
10
|
-
import { loadStackParser, StackParserLoadError } from "../browser/stack-parser.js";
|
|
11
|
-
import { headerSecrets, loadStorageStateFile, parseStorageStateJson, resolveSavePath, storageStateSecrets } from "../browser/auth.js";
|
|
12
|
-
import { checkUrlScheme } from "../browser/url-scheme.js";
|
|
13
|
-
import { optionalBoolean, optionalEnum, optionalString, requiredString, ToolInputError } from "./kit.js";
|
|
14
|
-
const SCHEMA = {
|
|
15
|
-
type: "object",
|
|
16
|
-
properties: {
|
|
17
|
-
targetUrl: {
|
|
18
|
-
type: "string",
|
|
19
|
-
description: "REQUIRED. The URL to open, including scheme and port — \"http://localhost:3000/invoices\". " +
|
|
20
|
-
"This is also what consent is granted for: the browser may be driven anywhere on this URL's " +
|
|
21
|
-
"origin for the life of the session, and navigating off it refuses rather than asking again.",
|
|
22
|
-
},
|
|
23
|
-
headless: {
|
|
24
|
-
type: "boolean",
|
|
25
|
-
description: "Run without a visible window. Defaults to true; pass false to watch it happen.",
|
|
26
|
-
},
|
|
27
|
-
stackParser: {
|
|
28
|
-
type: "object",
|
|
29
|
-
description: "The module that can parse this application's stack traces, named the way observe_runtime names a " +
|
|
30
|
-
"runtime adapter. Without one, requests are still observed and the endpoints they reached are still " +
|
|
31
|
-
"named, but NO frontend→backend caller edge is written — a parsed call site is what the confirmation " +
|
|
32
|
-
"needs, and there is no way to guess one. The reply says so rather than reporting a run that found " +
|
|
33
|
-
"nothing.\n\n" +
|
|
34
|
-
'WORKED EXAMPLE: the module to name is "@descryy/runtime-adapter-<language>" — one such package ' +
|
|
35
|
-
"exists per frontend language (never guess a name; a wrong one refuses rather than silently doing " +
|
|
36
|
-
'nothing), each exporting a single "create<Name>StackTraceParser" factory, so most calls need only ' +
|
|
37
|
-
'{ "module": "@descryy/runtime-adapter-<language>" } with no "export". Pick the package matching the ' +
|
|
38
|
-
"language the *frontend* is written in, not the backend. The intuitively-named " +
|
|
39
|
-
"@descryy/runtime-browser is never the right answer here — despite the name, it exports no " +
|
|
40
|
-
'stack-trace parser at all. A package exporting more than one factory (one per web framework it ' +
|
|
41
|
-
'covers) requires "export" to say which.',
|
|
42
|
-
properties: {
|
|
43
|
-
module: { type: "string", description: "Module specifier to import, e.g. a runtime adapter package for the language your frontend is written in." },
|
|
44
|
-
export: { type: "string", description: "Named export to call. Defaults to the module's single create*StackTraceParser factory; two matches is an error rather than a guess." },
|
|
45
|
-
},
|
|
46
|
-
required: ["module"],
|
|
47
|
-
additionalProperties: false,
|
|
48
|
-
},
|
|
49
|
-
documentRoot: {
|
|
50
|
-
type: "string",
|
|
51
|
-
description: "The directory on disk that the target URL's origin serves files from, if it is not the repository " +
|
|
52
|
-
"root. Absolute, or relative to the repository. THIS IS THE ONE THAT SILENTLY BREAKS THE ARROW: a " +
|
|
53
|
-
"server that serves scripts out of \"public/\" makes public/ the document root while the repo root is " +
|
|
54
|
-
"one level above it, and getting it wrong resolves a script URL to a path that does not exist, which " +
|
|
55
|
-
"degrades the call-site stack to nothing and produces a run that looks clean and confirmed no edges. " +
|
|
56
|
-
"Defaults to the repository root.",
|
|
57
|
-
},
|
|
58
|
-
environment: {
|
|
59
|
-
type: "object",
|
|
60
|
-
description: "The environment profile this session runs against, if you have one. Its safetyLevel governs " +
|
|
61
|
-
"whether the session may change the application: \"readOnly\" refuses browser_click, browser_type " +
|
|
62
|
-
"and browser_fill while still permitting browser_navigate and browser_snapshot. Declared once here " +
|
|
63
|
-
"rather than per call, and it is the same profile observe_runtime takes — a browser run and a " +
|
|
64
|
-
"runtime run must not hold two different opinions about the same environment (DEC-270). Omit it and " +
|
|
65
|
-
"the session's own consent is the only authorization, which still means this call had to be confirmed.",
|
|
66
|
-
properties: {
|
|
67
|
-
name: { type: "string", description: "The profile's name, free-form. Named back to you in any refusal it causes." },
|
|
68
|
-
safetyLevel: {
|
|
69
|
-
type: "string",
|
|
70
|
-
enum: ["readOnly", "write", "destructiveWithApproval"],
|
|
71
|
-
description: "\"readOnly\" refuses every action that could change the application, whatever the profile is " +
|
|
72
|
-
"called — a profile named \"local\" with safetyLevel \"readOnly\" is read-only too.",
|
|
73
|
-
},
|
|
74
|
-
},
|
|
75
|
-
required: ["name", "safetyLevel"],
|
|
76
|
-
additionalProperties: true,
|
|
77
|
-
},
|
|
78
|
-
storageState: {
|
|
79
|
-
type: "object",
|
|
80
|
-
description: "11.4-b: an already-authenticated session to seed before the first navigation. Without this, " +
|
|
81
|
-
"browser_click/type/fill can drive a login form within the consented origin, but cannot reach a " +
|
|
82
|
-
"screen that requires an existing session, and every fresh session re-authenticates from scratch. " +
|
|
83
|
-
"Both fields are scoped to targetUrl's own origin by construction — there is no way to name a " +
|
|
84
|
-
"second origin here, so this cannot widen the session's consent.",
|
|
85
|
-
properties: {
|
|
86
|
-
cookies: {
|
|
87
|
-
type: "array",
|
|
88
|
-
description: "Cookies to set before navigating, scoped to targetUrl's own origin.",
|
|
89
|
-
items: {
|
|
90
|
-
type: "object",
|
|
91
|
-
properties: {
|
|
92
|
-
name: { type: "string" },
|
|
93
|
-
value: { type: "string" },
|
|
94
|
-
path: { type: "string", description: "Defaults to \"/\"." },
|
|
95
|
-
httpOnly: { type: "boolean" },
|
|
96
|
-
secure: { type: "boolean" },
|
|
97
|
-
sameSite: { type: "string", enum: ["Strict", "Lax", "None"] },
|
|
98
|
-
},
|
|
99
|
-
required: ["name", "value"],
|
|
100
|
-
additionalProperties: false,
|
|
101
|
-
},
|
|
102
|
-
},
|
|
103
|
-
localStorage: {
|
|
104
|
-
type: "object",
|
|
105
|
-
description: "localStorage entries to set for targetUrl's own origin before navigating, as string values.",
|
|
106
|
-
additionalProperties: { type: "string" },
|
|
107
|
-
},
|
|
108
|
-
},
|
|
109
|
-
additionalProperties: false,
|
|
110
|
-
},
|
|
111
|
-
storageStatePath: {
|
|
112
|
-
type: "string",
|
|
113
|
-
description: "A FILE holding a saved browser storage state, instead of naming cookies inline. Absolute, or " +
|
|
114
|
-
"relative to the repository root. This is the practical way to reach a logged-in screen: start one " +
|
|
115
|
-
"session with headless false and saveStorageStateTo, log in by hand, close it — every later session " +
|
|
116
|
-
"seeds from that file and nobody logs in again. Anything in the file outside this session's " +
|
|
117
|
-
"consented origin is REFUSED by name, not quietly dropped.",
|
|
118
|
-
},
|
|
119
|
-
storageStateCredential: {
|
|
120
|
-
type: "string",
|
|
121
|
-
description: "The NAME of a credential holding a saved browser storage state (the same JSON shape " +
|
|
122
|
-
"storageStatePath reads: a \"cookies\" array and an \"origins\" array), instead of a file on disk. " +
|
|
123
|
-
"Reused a logged-in session without a login-form step or a live file. Set with `descry credential " +
|
|
124
|
-
"set <name>`, reading the JSON from stdin. Refuses by name when no credential store is configured on " +
|
|
125
|
-
"this server, when nothing is stored under the name, or when the value isn't a storage state this " +
|
|
126
|
-
"session's origin can use — never quietly falls back to an unauthenticated session. Anything in it " +
|
|
127
|
-
"outside this session's consented origin is REFUSED by name, not quietly dropped, exactly as " +
|
|
128
|
-
"storageStatePath's own file check does.",
|
|
129
|
-
},
|
|
130
|
-
extraHttpHeaders: {
|
|
131
|
-
type: "object",
|
|
132
|
-
description: "Headers added to every request this session makes TO THE CONSENTED ORIGIN — typically " +
|
|
133
|
-
"{\"Authorization\": \"Bearer ...\"} for an application whose credential is a token rather than a " +
|
|
134
|
-
"cookie. Deliberately NOT sent to any other host: headers set on a whole browser travel with every " +
|
|
135
|
-
"request it makes, which on an ordinary page means handing your token to every third-party script, " +
|
|
136
|
-
"font and analytics endpoint the page loads.",
|
|
137
|
-
additionalProperties: { type: "string" },
|
|
138
|
-
},
|
|
139
|
-
saveStorageStateTo: {
|
|
140
|
-
type: "string",
|
|
141
|
-
description: "Write this session's cookies and stored data to this file when the session closes, so a login done " +
|
|
142
|
-
"once here can seed later sessions with storageStatePath. Must be an ABSOLUTE PATH OUTSIDE THE " +
|
|
143
|
-
"REPOSITORY — the file is a live credential, and one written into a working tree is one `git add .` " +
|
|
144
|
-
"from being committed.",
|
|
145
|
-
},
|
|
146
|
-
confirmToken: {
|
|
147
|
-
type: "string",
|
|
148
|
-
description: "The token returned by a previous call. Starting a browser session takes two calls: the first " +
|
|
149
|
-
"returns a token and launches nothing, the second redeems it — with the arguments frozen when the " +
|
|
150
|
-
"token was minted, never whatever the second call supplies, so changing targetUrl, stackParser or " +
|
|
151
|
-
"any other field on the confirming call is discarded rather than applied, and the reply discloses " +
|
|
152
|
-
"that it was; call again without confirmToken for a fresh " +
|
|
153
|
-
"token if something needs to change. A token is single-use, expires, and is only valid for this " +
|
|
154
|
-
"tool. Consent is granted once here — the click, type and fill tools need no token of their own.",
|
|
155
|
-
},
|
|
156
|
-
},
|
|
157
|
-
required: ["targetUrl"],
|
|
158
|
-
additionalProperties: false,
|
|
159
|
-
};
|
|
160
|
-
const SAFETY_LEVELS = ["readOnly", "write", "destructiveWithApproval"];
|
|
161
|
-
/** Reads the profile, doesn't re-derive it — only the 2 fields this surface consults.
|
|
162
|
-
* `additionalProperties: true` lets a caller pass the same object it gives
|
|
163
|
-
* `observe_runtime` without trimming a second copy. */
|
|
164
|
-
function readProfile(args) {
|
|
165
|
-
const raw = args["environment"];
|
|
166
|
-
if (raw === undefined || raw === null)
|
|
167
|
-
return null;
|
|
168
|
-
if (typeof raw !== "object" || Array.isArray(raw))
|
|
169
|
-
throw new ToolInputError('"environment" must be an object');
|
|
170
|
-
const fields = raw;
|
|
171
|
-
const name = requiredString(fields, "name");
|
|
172
|
-
const safetyLevel = optionalEnum(fields, "safetyLevel", SAFETY_LEVELS);
|
|
173
|
-
if (safetyLevel === undefined) {
|
|
174
|
-
throw new ToolInputError('"environment.safetyLevel" is required when an environment is given — a profile with no declared ' +
|
|
175
|
-
"safety level would be read as permitting everything, which is the one reading it must never get by default");
|
|
176
|
-
}
|
|
177
|
-
return { name, safetyLevel };
|
|
178
|
-
}
|
|
179
|
-
const COOKIE_SAME_SITE = ["Strict", "Lax", "None"];
|
|
180
|
-
/**
|
|
181
|
-
* 11.4-b: an already-authenticated session to seed before the first navigation.
|
|
182
|
-
* No "domain" field is read from a cookie — not merely ignored, refused — so a
|
|
183
|
-
* caller cannot silently widen a session's consent to a second origin the way
|
|
184
|
-
* accepting and dropping one would risk if a future reader trusted the field
|
|
185
|
-
* existed. The driver scopes every seeded cookie to `targetUrl`'s own origin.
|
|
186
|
-
*/
|
|
187
|
-
function readStorageState(args) {
|
|
188
|
-
const raw = args["storageState"];
|
|
189
|
-
if (raw === undefined || raw === null)
|
|
190
|
-
return null;
|
|
191
|
-
if (typeof raw !== "object" || Array.isArray(raw))
|
|
192
|
-
throw new ToolInputError('"storageState" must be an object');
|
|
193
|
-
const fields = raw;
|
|
194
|
-
const rawCookies = fields["cookies"];
|
|
195
|
-
let cookies;
|
|
196
|
-
if (rawCookies !== undefined) {
|
|
197
|
-
if (!Array.isArray(rawCookies))
|
|
198
|
-
throw new ToolInputError('"storageState.cookies" must be an array');
|
|
199
|
-
cookies = rawCookies.map((entry, index) => {
|
|
200
|
-
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
|
|
201
|
-
throw new ToolInputError(`"storageState.cookies[${index}]" must be an object`);
|
|
202
|
-
}
|
|
203
|
-
const cookie = entry;
|
|
204
|
-
if ("domain" in cookie) {
|
|
205
|
-
throw new ToolInputError(`"storageState.cookies[${index}].domain" is not accepted — a seeded cookie is always scoped to ` +
|
|
206
|
-
"targetUrl's own origin, never a domain the caller names, so a session's consent cannot be " +
|
|
207
|
-
"silently widened to a second origin.");
|
|
208
|
-
}
|
|
209
|
-
const name = requiredString(cookie, "name");
|
|
210
|
-
const value = requiredString(cookie, "value");
|
|
211
|
-
const path = optionalString(cookie, "path");
|
|
212
|
-
const httpOnly = optionalBoolean(cookie, "httpOnly");
|
|
213
|
-
const secure = optionalBoolean(cookie, "secure");
|
|
214
|
-
const sameSite = optionalEnum(cookie, "sameSite", COOKIE_SAME_SITE);
|
|
215
|
-
return {
|
|
216
|
-
name,
|
|
217
|
-
value,
|
|
218
|
-
...(path === undefined ? {} : { path }),
|
|
219
|
-
...(httpOnly === undefined ? {} : { httpOnly }),
|
|
220
|
-
...(secure === undefined ? {} : { secure }),
|
|
221
|
-
...(sameSite === undefined ? {} : { sameSite }),
|
|
222
|
-
};
|
|
223
|
-
});
|
|
224
|
-
}
|
|
225
|
-
const rawLocalStorage = fields["localStorage"];
|
|
226
|
-
let localStorage;
|
|
227
|
-
if (rawLocalStorage !== undefined) {
|
|
228
|
-
if (typeof rawLocalStorage !== "object" || rawLocalStorage === null || Array.isArray(rawLocalStorage)) {
|
|
229
|
-
throw new ToolInputError('"storageState.localStorage" must be an object of string values');
|
|
230
|
-
}
|
|
231
|
-
for (const [key, value] of Object.entries(rawLocalStorage)) {
|
|
232
|
-
if (typeof value !== "string")
|
|
233
|
-
throw new ToolInputError(`"storageState.localStorage.${key}" must be a string`);
|
|
234
|
-
}
|
|
235
|
-
localStorage = rawLocalStorage;
|
|
236
|
-
}
|
|
237
|
-
if (cookies === undefined && localStorage === undefined)
|
|
238
|
-
return null;
|
|
239
|
-
return { ...(cookies === undefined ? {} : { cookies }), ...(localStorage === undefined ? {} : { localStorage }) };
|
|
240
|
-
}
|
|
241
|
-
/**
|
|
242
|
-
* Resolves `storageStateCredential` against `Session.credentialStore` — the smaller of the two
|
|
243
|
-
* reuse mechanisms RG-1(4)'s "signin" lane chose to build (the other, wiring
|
|
244
|
-
* `BrowserPageSession.injectStorageState` into scenario replay, would need a new step kind in
|
|
245
|
-
* the scenario schema and its own projection/replay path; this reuses the storage-state
|
|
246
|
-
* machinery `loadStorageStateFile` already established for the file case).
|
|
247
|
-
*
|
|
248
|
-
* Same refusal discipline as a missing/malformed file: named, before anything launches, never a
|
|
249
|
-
* silent fall-through to an unauthenticated session.
|
|
250
|
-
*/
|
|
251
|
-
async function readStorageStateCredential(name, origin, ctx) {
|
|
252
|
-
if (ctx.session.credentialStore === undefined) {
|
|
253
|
-
throw new ToolInputError(`"storageStateCredential" named "${name}", but no credential store is configured on this server. Set one ` +
|
|
254
|
-
'up and store the value with `descry credential set ${name}` (piped through stdin, never typed as an ' +
|
|
255
|
-
"argument), reading the JSON that a session started with saveStorageStateTo already wrote.");
|
|
256
|
-
}
|
|
257
|
-
const value = await ctx.session.credentialStore.retrieve(name);
|
|
258
|
-
if (value === null) {
|
|
259
|
-
throw new ToolInputError(`"storageStateCredential" named "${name}", and nothing is stored under that name. Store a saved storage ` +
|
|
260
|
-
`state there first: start a session with headless false and saveStorageStateTo, log in by hand, close ` +
|
|
261
|
-
`it, then \`descry credential set ${name}\` < that file.`);
|
|
262
|
-
}
|
|
263
|
-
if (value === "") {
|
|
264
|
-
throw new ToolInputError(`the credential "${name}" is stored and empty. An empty storage state is refused rather than used — it ` +
|
|
265
|
-
"would seed a session with nothing, which reads as an ordinary logged-out run rather than the " +
|
|
266
|
-
"misconfiguration it actually is.");
|
|
267
|
-
}
|
|
268
|
-
return parseStorageStateJson(value, `credential "${name}"`, { consentedOrigin: origin, repoPath: ctx.session.repoPath });
|
|
269
|
-
}
|
|
270
|
-
/**
|
|
271
|
-
* Extra headers, or null. Values are checked but never echoed.
|
|
272
|
-
*/
|
|
273
|
-
function readExtraHttpHeaders(args) {
|
|
274
|
-
const raw = args["extraHttpHeaders"];
|
|
275
|
-
if (raw === undefined || raw === null)
|
|
276
|
-
return null;
|
|
277
|
-
if (typeof raw !== "object" || Array.isArray(raw))
|
|
278
|
-
throw new ToolInputError('"extraHttpHeaders" must be an object');
|
|
279
|
-
const headers = {};
|
|
280
|
-
for (const [name, value] of Object.entries(raw)) {
|
|
281
|
-
if (typeof value !== "string")
|
|
282
|
-
throw new ToolInputError(`"extraHttpHeaders.${name}" must be a string`);
|
|
283
|
-
headers[name] = value;
|
|
284
|
-
}
|
|
285
|
-
if (Object.keys(headers).length === 0)
|
|
286
|
-
throw new ToolInputError('"extraHttpHeaders" was given with no headers in it');
|
|
287
|
-
return headers;
|
|
288
|
-
}
|
|
289
|
-
function readStackParserSpec(args) {
|
|
290
|
-
const raw = args["stackParser"];
|
|
291
|
-
if (raw === undefined || raw === null)
|
|
292
|
-
return null;
|
|
293
|
-
if (typeof raw !== "object" || Array.isArray(raw))
|
|
294
|
-
throw new ToolInputError('"stackParser" must be an object');
|
|
295
|
-
const fields = raw;
|
|
296
|
-
const module = requiredString(fields, "module");
|
|
297
|
-
const named = optionalString(fields, "export");
|
|
298
|
-
return named === undefined ? { module } : { module, export: named };
|
|
299
|
-
}
|
|
300
|
-
function parseTarget(args) {
|
|
301
|
-
const raw = requiredString(args, "targetUrl");
|
|
302
|
-
let url;
|
|
303
|
-
try {
|
|
304
|
-
url = new URL(raw);
|
|
305
|
-
}
|
|
306
|
-
catch {
|
|
307
|
-
throw new ToolInputError(`"targetUrl" must be an absolute URL including scheme — got "${raw}". A bare host or path cannot be ` +
|
|
308
|
-
"opened, and cannot be turned into the origin this session's consent is bound to.");
|
|
309
|
-
}
|
|
310
|
-
// file:/data: (untrusted schemes) resolve to origin "null", collapsing
|
|
311
|
-
// tool-support.ts's same-origin containment — see url-scheme.ts.
|
|
312
|
-
const scheme = checkUrlScheme(url);
|
|
313
|
-
if (!scheme.allowed)
|
|
314
|
-
throw new ToolInputError(scheme.reason);
|
|
315
|
-
return url;
|
|
316
|
-
}
|
|
317
|
-
function cancelledBeforeLaunch(ctx, target, safetyLevel) {
|
|
318
|
-
return browserAnswer({
|
|
319
|
-
ctx,
|
|
320
|
-
state: CANCELLED_STATE,
|
|
321
|
-
headline: cancellationHeadline("no browser session is open"),
|
|
322
|
-
notes: cancellationNotes("No browser was left running.", "If a browser had already opened when the cancellation arrived, it has been closed and whatever it " +
|
|
323
|
-
"had observed was flushed with it."),
|
|
324
|
-
data: {
|
|
325
|
-
sessionId: "",
|
|
326
|
-
url: target.href,
|
|
327
|
-
title: "",
|
|
328
|
-
consentedOrigin: target.origin,
|
|
329
|
-
safetyLevel,
|
|
330
|
-
totalElements: 0,
|
|
331
|
-
evidence: emptyEvidence(),
|
|
332
|
-
graph: NO_GRAPH_WRITE,
|
|
333
|
-
},
|
|
334
|
-
});
|
|
335
|
-
}
|
|
336
|
-
async function run(args, ctx) {
|
|
337
|
-
const target = parseTarget(args);
|
|
338
|
-
const headless = optionalBoolean(args, "headless") ?? true;
|
|
339
|
-
const profile = readProfile(args);
|
|
340
|
-
const inlineState = readStorageState(args);
|
|
341
|
-
const statePath = optionalString(args, "storageStatePath");
|
|
342
|
-
const stateCredential = optionalString(args, "storageStateCredential");
|
|
343
|
-
const stateSourcesGiven = [inlineState !== null, statePath !== undefined, stateCredential !== undefined].filter(Boolean).length;
|
|
344
|
-
if (stateSourcesGiven > 1) {
|
|
345
|
-
throw new ToolInputError('"storageState", "storageStatePath" and "storageStateCredential" — more than one was given. There is no ' +
|
|
346
|
-
"precedence rule between them on purpose — picking one silently is how a session ends up seeded from a " +
|
|
347
|
-
"source the caller believed they had overridden. Give exactly one.");
|
|
348
|
-
}
|
|
349
|
-
// Read before anything launches, for the same reason the stack parser below
|
|
350
|
-
// is: an unreadable file, an unresolvable credential, or a cookie for
|
|
351
|
-
// another host is a refusal the caller can fix, and discovering it after a
|
|
352
|
-
// browser is open would mean a session that silently drove the logged-out
|
|
353
|
-
// surface instead.
|
|
354
|
-
const storageState = statePath !== undefined
|
|
355
|
-
? loadStorageStateFile(statePath, { consentedOrigin: target.origin, repoPath: ctx.session.repoPath })
|
|
356
|
-
: stateCredential !== undefined
|
|
357
|
-
? await readStorageStateCredential(stateCredential, target.origin, ctx)
|
|
358
|
-
: inlineState;
|
|
359
|
-
const extraHttpHeaders = readExtraHttpHeaders(args);
|
|
360
|
-
const rawSavePath = optionalString(args, "saveStorageStateTo");
|
|
361
|
-
const saveStorageStateTo = rawSavePath === undefined ? undefined : resolveSavePath(rawSavePath, ctx.session.repoPath);
|
|
362
|
-
// Registered before the launch, not after: if the launch throws, these are
|
|
363
|
-
// still the values anything this server writes must refuse to carry.
|
|
364
|
-
ctx.session.noteBrowserSecrets([...storageStateSecrets(storageState), ...headerSecrets(extraHttpHeaders)]);
|
|
365
|
-
const parserSpec = readStackParserSpec(args);
|
|
366
|
-
const documentRoot = optionalString(args, "documentRoot");
|
|
367
|
-
const backend = ctx.session.browserBackend();
|
|
368
|
-
// Before anything launches — a browser opened for a caller who's already gone is
|
|
369
|
-
// one nothing will ever close (its session id never reaches a suppressed reply);
|
|
370
|
-
// only the 5-minute idle reaper would eventually catch it.
|
|
371
|
-
if (ctx.signal.aborted)
|
|
372
|
-
return cancelledBeforeLaunch(ctx, target, null);
|
|
373
|
-
if (!backend.available) {
|
|
374
|
-
return browserAnswer({
|
|
375
|
-
ctx,
|
|
376
|
-
state: "refused",
|
|
377
|
-
headline: "This build cannot open a browser.",
|
|
378
|
-
notes: [backend.reason, `Remedy: ${backend.remedy}`],
|
|
379
|
-
data: { sessionId: "", url: target.href, title: "", consentedOrigin: target.origin, safetyLevel: null, totalElements: 0, evidence: emptyEvidence(), graph: NO_GRAPH_WRITE },
|
|
380
|
-
});
|
|
381
|
-
}
|
|
382
|
-
// Parser loaded before anything launches — a bad parser is a fixable refusal here;
|
|
383
|
-
// discovering it after a browser is open means tearing it down or running a
|
|
384
|
-
// session that silently can't write the edge it opened for.
|
|
385
|
-
let parser;
|
|
386
|
-
try {
|
|
387
|
-
parser = parserSpec === null ? undefined : await loadStackParser(parserSpec);
|
|
388
|
-
}
|
|
389
|
-
catch (error) {
|
|
390
|
-
if (!(error instanceof StackParserLoadError))
|
|
391
|
-
throw error;
|
|
392
|
-
return browserAnswer({
|
|
393
|
-
ctx,
|
|
394
|
-
state: "refused",
|
|
395
|
-
headline: `Could not load the stack-trace parser "${error.specifier}".`,
|
|
396
|
-
notes: [error.message],
|
|
397
|
-
data: { sessionId: "", url: target.href, title: "", consentedOrigin: target.origin, safetyLevel: null, totalElements: 0, evidence: emptyEvidence(), graph: NO_GRAPH_WRITE },
|
|
398
|
-
});
|
|
399
|
-
}
|
|
400
|
-
// Closed here rather than left to a caller: the origin driven must map to
|
|
401
|
-
// the directory actually serving its scripts — `documentRoot` overrides the repo
|
|
402
|
-
// root for the `public/` case the schema describes.
|
|
403
|
-
const servedFrom = documentRoot === undefined
|
|
404
|
-
? ctx.session.repoPath
|
|
405
|
-
: isAbsolute(documentRoot)
|
|
406
|
-
? documentRoot
|
|
407
|
-
: join(ctx.session.repoPath, documentRoot);
|
|
408
|
-
const resolveSourceRoot = (origin) => origin === target.origin
|
|
409
|
-
? { found: true, root: { serviceName: ctx.session.config.repo, declaredCwd: servedFrom } }
|
|
410
|
-
: { found: false, refusal: "noProcessOnPort", message: `${origin} is not the origin this session was opened against` };
|
|
411
|
-
ctx.progress(`Opening a browser at ${target.href}`);
|
|
412
|
-
const driver = await backend.createDriver({
|
|
413
|
-
...(parser === undefined ? {} : { stackParser: parser }),
|
|
414
|
-
resolveSourceRoot,
|
|
415
|
-
service: ctx.session.config.repo,
|
|
416
|
-
});
|
|
417
|
-
const opened = await ctx.session.browserSessions().open(driver, {
|
|
418
|
-
targetUrl: target.href,
|
|
419
|
-
headless,
|
|
420
|
-
profile,
|
|
421
|
-
...(storageState === null ? {} : { storageState }),
|
|
422
|
-
...(extraHttpHeaders === null ? {} : { extraHttpHeaders }),
|
|
423
|
-
...(saveStorageStateTo === undefined ? {} : { saveStorageStateTo }),
|
|
424
|
-
});
|
|
425
|
-
if (!opened.opened) {
|
|
426
|
-
const notes = opened.kind === "atCapacity"
|
|
427
|
-
? [opened.reason]
|
|
428
|
-
: // Remedy travels verbatim — "could not launch" and stopping there is a
|
|
429
|
-
// refusal the developer has to go research themselves.
|
|
430
|
-
[opened.message, `Remedy: ${opened.remedy}`, `Expected the browser at ${opened.expectedExecutablePath}.`];
|
|
431
|
-
return browserAnswer({
|
|
432
|
-
ctx,
|
|
433
|
-
state: "refused",
|
|
434
|
-
headline: opened.kind === "atCapacity" ? "Too many browser sessions are already open." : "No browser is installed.",
|
|
435
|
-
notes,
|
|
436
|
-
data: { sessionId: "", url: target.href, title: "", consentedOrigin: target.origin, safetyLevel: profile?.safetyLevel ?? null, totalElements: 0, evidence: emptyEvidence(), graph: NO_GRAPH_WRITE },
|
|
437
|
-
});
|
|
438
|
-
}
|
|
439
|
-
// The race actually lost in practice: caller cancelled while Chromium was
|
|
440
|
-
// starting, so the launch succeeded for nobody. Closes the session just opened
|
|
441
|
-
// — the one resource this call started, the only one it may tear down.
|
|
442
|
-
if (ctx.signal.aborted) {
|
|
443
|
-
await ctx.session.browserSessions().close(opened.entry.sessionId);
|
|
444
|
-
return cancelledBeforeLaunch(ctx, target, profile?.safetyLevel ?? null);
|
|
445
|
-
}
|
|
446
|
-
const { entry } = opened;
|
|
447
|
-
const snapshot = await entry.page.snapshot();
|
|
448
|
-
const observed = await observeAndCorrelate(ctx, entry);
|
|
449
|
-
const evidence = observed.evidence;
|
|
450
|
-
return browserAnswer({
|
|
451
|
-
ctx,
|
|
452
|
-
headline: `Browser session ${entry.sessionId} open at ${snapshot.url} (${snapshot.totalElements} elements).`,
|
|
453
|
-
notes: [
|
|
454
|
-
...reachNotes(snapshot),
|
|
455
|
-
`Consent covers ${entry.consentedOrigin} for the life of this session — click, type and fill need no ` +
|
|
456
|
-
"further confirmation, and navigating to another origin will refuse. The session is torn down after " +
|
|
457
|
-
"five idle minutes, when the client disconnects, or when browser_close_session is called.",
|
|
458
|
-
// Names what was seeded, never the values themselves — a cookie or localStorage
|
|
459
|
-
// value is a credential, and this disclosure exists so a caller can tell an
|
|
460
|
-
// authenticated run from an anonymous one without this reply repeating it back.
|
|
461
|
-
...(storageState === null
|
|
462
|
-
? []
|
|
463
|
-
: [
|
|
464
|
-
`Storage state was seeded before the first navigation: ${storageState.cookies?.length ?? 0} ` +
|
|
465
|
-
`cookie(s), ${Object.keys(storageState.localStorage ?? {}).length} localStorage key(s) — both ` +
|
|
466
|
-
`scoped to ${entry.consentedOrigin}. No value is printed here or kept in this session's ` +
|
|
467
|
-
"recorded arguments.",
|
|
468
|
-
]),
|
|
469
|
-
...(extraHttpHeaders === null
|
|
470
|
-
? []
|
|
471
|
-
: [
|
|
472
|
-
`Extra request header(s) ${Object.keys(extraHttpHeaders).join(", ")} will be sent on ` +
|
|
473
|
-
`${entry.consentedOrigin} and on no other host — a credential set on the whole browser would ` +
|
|
474
|
-
"travel to every third-party script the page loads. Values are not printed.",
|
|
475
|
-
]),
|
|
476
|
-
...(saveStorageStateTo === undefined
|
|
477
|
-
? []
|
|
478
|
-
: [
|
|
479
|
-
`This session's cookies and stored data will be written to ${saveStorageStateTo} when it closes, ` +
|
|
480
|
-
"so a login performed here can seed later sessions with storageStatePath. That file is a live " +
|
|
481
|
-
"credential; it is outside the repository for that reason.",
|
|
482
|
-
]),
|
|
483
|
-
// Rule 7: an unauthenticated run is a real, disclosed limit on what was
|
|
484
|
-
// tested, not a neutral default to leave a caller to infer from silence.
|
|
485
|
-
...(storageState === null && extraHttpHeaders === null
|
|
486
|
-
? [
|
|
487
|
-
"No authentication material was given, so this session sees what a logged-out visitor sees. " +
|
|
488
|
-
"Anything behind a login was not reached and is not reported on — pass storageStatePath, " +
|
|
489
|
-
"storageState or extraHttpHeaders to reach it.",
|
|
490
|
-
]
|
|
491
|
-
: []),
|
|
492
|
-
...(parserSpec === null
|
|
493
|
-
? [
|
|
494
|
-
"No stackParser was named, so requests will be observed and the endpoints they reach will be " +
|
|
495
|
-
"named, but no frontend→backend caller edge can be written from this session. That is a gap " +
|
|
496
|
-
"in what this run can confirm, not a finding about your application.",
|
|
497
|
-
]
|
|
498
|
-
: []),
|
|
499
|
-
...(entry.profile === null
|
|
500
|
-
? []
|
|
501
|
-
: [
|
|
502
|
-
`Running under environment profile "${entry.profile.name}" (safetyLevel ` +
|
|
503
|
-
`"${entry.profile.safetyLevel}").` +
|
|
504
|
-
(entry.profile.safetyLevel === "readOnly"
|
|
505
|
-
? " Clicking, typing and filling will be refused; navigate and snapshot remain available."
|
|
506
|
-
: ""),
|
|
507
|
-
]),
|
|
508
|
-
...observed.notes,
|
|
509
|
-
],
|
|
510
|
-
data: {
|
|
511
|
-
sessionId: entry.sessionId,
|
|
512
|
-
url: snapshot.url,
|
|
513
|
-
title: snapshot.title,
|
|
514
|
-
consentedOrigin: entry.consentedOrigin,
|
|
515
|
-
safetyLevel: entry.profile?.safetyLevel ?? null,
|
|
516
|
-
totalElements: snapshot.totalElements,
|
|
517
|
-
evidence,
|
|
518
|
-
graph: observed.graph,
|
|
519
|
-
},
|
|
520
|
-
});
|
|
521
|
-
}
|
|
522
|
-
export const browserStartSessionTool = {
|
|
523
|
-
name: "browser_start_session",
|
|
524
|
-
title: "Open a browser session",
|
|
525
|
-
description: "Open a real browser at a URL in your running application and return a session id the other browser " +
|
|
526
|
-
"tools take. This is where consent is granted: confirming it allows Descry to drive a browser anywhere " +
|
|
527
|
-
"on that URL's origin until the session ends, so the click, type and fill tools do not ask again. " +
|
|
528
|
-
"Reports what the page produced — console errors, failed requests — raw and untriaged; deciding which " +
|
|
529
|
-
"of them matter is yours.",
|
|
530
|
-
class: "action",
|
|
531
|
-
tier: "evidence",
|
|
532
|
-
version: "1.0.0",
|
|
533
|
-
inputSchema: SCHEMA,
|
|
534
|
-
run,
|
|
535
|
-
describeAction(args) {
|
|
536
|
-
const target = parseTarget(args);
|
|
537
|
-
// Same parse the run path uses to enforce the gate (`mutationRefusal` in
|
|
538
|
-
// `tool-support.ts`) — read here, not re-derived, so what's confirmed matches
|
|
539
|
-
// what's enforced.
|
|
540
|
-
const profile = readProfile(args);
|
|
541
|
-
if (profile?.safetyLevel === "readOnly") {
|
|
542
|
-
return (`Descry may navigate, snapshot and wait anywhere on ${target.origin}. Clicking, typing, filling, ` +
|
|
543
|
-
`choosing an option and submitting a form will be refused. It may not leave that origin.`);
|
|
544
|
-
}
|
|
545
|
-
const grant = `Launch a browser and open ${target.href}. For as long as the session lives, Descry may navigate, ` +
|
|
546
|
-
`click, type, fill, choose an option and submit a form anywhere on ${target.origin} without asking ` +
|
|
547
|
-
"again — including actions that change data in that application. It may not leave that origin.";
|
|
548
|
-
// UAT phase 5 §7/B9: absent an explicit safety level, the enforcement really
|
|
549
|
-
// is unrestricted (`mutationRefusal`: no profile ⇒ no refusal) — but the
|
|
550
|
-
// prompt must say that is *because no profile was supplied*, not state
|
|
551
|
-
// unrestricted authority as though it had been deliberately chosen. A
|
|
552
|
-
// consent prompt that reads the same whether a level was set or omitted
|
|
553
|
-
// hides the one piece of information that would tell a caller to go set one.
|
|
554
|
-
// B1: credentials change what is being approved, so they change this
|
|
555
|
-
// text. The unseeded sentence already warns that data may change; a
|
|
556
|
-
// seeded session changes *whose* data — every action runs as the account
|
|
557
|
-
// whose session was handed over. A prompt that read identically either
|
|
558
|
-
// way would be asking for consent to something it had not mentioned.
|
|
559
|
-
const seeded = args["storageState"] !== undefined ||
|
|
560
|
-
args["storageStatePath"] !== undefined ||
|
|
561
|
-
args["storageStateCredential"] !== undefined ||
|
|
562
|
-
args["extraHttpHeaders"] !== undefined;
|
|
563
|
-
const asUser = seeded
|
|
564
|
-
? " The session will be started ALREADY LOGGED IN, from the authentication material in this call: " +
|
|
565
|
-
"everything it does will be done as that user, with whatever that account is permitted to do, on " +
|
|
566
|
-
"screens a logged-out visitor could not reach. The credential itself is not shown here and will " +
|
|
567
|
-
"not appear in any reply."
|
|
568
|
-
: "";
|
|
569
|
-
return profile === null
|
|
570
|
-
? `No environment profile was supplied, so nothing here restricts what Descry may do. ${grant}${asUser}`
|
|
571
|
-
: `Environment profile "${profile.name}" declares safetyLevel "${profile.safetyLevel}". ${grant}${asUser}`;
|
|
572
|
-
},
|
|
573
|
-
/**
|
|
574
|
-
* What may be remembered about this call — B1's secrets rule, at the one
|
|
575
|
-
* place a credential enters this server.
|
|
576
|
-
*
|
|
577
|
-
* `server.ts` records every completed call's arguments on the `Session` so
|
|
578
|
-
* `verify_claim` can check a citation against them. This is the only tool
|
|
579
|
-
* whose arguments can be a credential, so it is the only one that
|
|
580
|
-
* implements this.
|
|
581
|
-
*
|
|
582
|
-
* Structural rather than a known-value substitution, deliberately: this
|
|
583
|
-
* runs on the arguments **as the caller sent them**, including for a call
|
|
584
|
-
* refused before any state was built, so there is no validated seed to take
|
|
585
|
-
* a value list from. Names are kept — a reader of a recorded call must
|
|
586
|
-
* still be able to see that a session was seeded and with what kind of
|
|
587
|
-
* material.
|
|
588
|
-
*/
|
|
589
|
-
redactArgs(args) {
|
|
590
|
-
const out = { ...args };
|
|
591
|
-
let touched = false;
|
|
592
|
-
if (out["storageState"] !== undefined && out["storageState"] !== null) {
|
|
593
|
-
out["storageState"] = redactStorageStateArgument(out["storageState"]);
|
|
594
|
-
touched = true;
|
|
595
|
-
}
|
|
596
|
-
if (typeof out["extraHttpHeaders"] === "object" && out["extraHttpHeaders"] !== null) {
|
|
597
|
-
out["extraHttpHeaders"] = Object.fromEntries(Object.keys(out["extraHttpHeaders"]).map((name) => [name, REDACTED]));
|
|
598
|
-
touched = true;
|
|
599
|
-
}
|
|
600
|
-
// A path is not a credential, and it is the one thing a reader needs in
|
|
601
|
-
// order to reproduce a run or clean up after it. Left intact.
|
|
602
|
-
return touched ? out : args;
|
|
603
|
-
},
|
|
604
|
-
};
|
|
605
|
-
const REDACTED = "[REDACTED]";
|
|
606
|
-
function redactStorageStateArgument(raw) {
|
|
607
|
-
if (typeof raw !== "object" || raw === null)
|
|
608
|
-
return REDACTED;
|
|
609
|
-
const fields = raw;
|
|
610
|
-
const cookies = Array.isArray(fields["cookies"])
|
|
611
|
-
? fields["cookies"].map((cookie) => typeof cookie === "object" && cookie !== null ? { ...cookie, value: REDACTED } : REDACTED)
|
|
612
|
-
: fields["cookies"];
|
|
613
|
-
const stored = typeof fields["localStorage"] === "object" && fields["localStorage"] !== null
|
|
614
|
-
? Object.fromEntries(Object.keys(fields["localStorage"]).map((key) => [key, REDACTED]))
|
|
615
|
-
: fields["localStorage"];
|
|
616
|
-
return {
|
|
617
|
-
...fields,
|
|
618
|
-
...(cookies === undefined ? {} : { cookies }),
|
|
619
|
-
...(stored === undefined ? {} : { localStorage: stored }),
|
|
620
|
-
};
|
|
621
|
-
}
|
|
622
|
-
//# sourceMappingURL=browser-start-session.js.map
|