@descryy/mcp 0.1.2 → 0.3.0
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/dist/bin/descry-mcp.js +30 -2
- package/dist/bin/descry-mcp.js.map +1 -1
- package/dist/browser/driver.d.ts +236 -0
- package/dist/browser/driver.d.ts.map +1 -0
- package/dist/browser/driver.js +70 -0
- package/dist/browser/driver.js.map +1 -0
- package/dist/browser/evidence.d.ts +47 -0
- package/dist/browser/evidence.d.ts.map +1 -0
- package/dist/browser/evidence.js +55 -0
- package/dist/browser/evidence.js.map +1 -0
- package/dist/browser/fake-driver.d.ts +58 -0
- package/dist/browser/fake-driver.d.ts.map +1 -0
- package/dist/browser/fake-driver.js +161 -0
- package/dist/browser/fake-driver.js.map +1 -0
- package/dist/browser/graph-write.d.ts +86 -0
- package/dist/browser/graph-write.d.ts.map +1 -0
- package/dist/browser/graph-write.js +135 -0
- package/dist/browser/graph-write.js.map +1 -0
- package/dist/browser/playwright-driver.d.ts +65 -0
- package/dist/browser/playwright-driver.d.ts.map +1 -0
- package/dist/browser/playwright-driver.js +359 -0
- package/dist/browser/playwright-driver.js.map +1 -0
- package/dist/browser/provider.d.ts +49 -0
- package/dist/browser/provider.d.ts.map +1 -0
- package/dist/browser/provider.js +28 -0
- package/dist/browser/provider.js.map +1 -0
- package/dist/browser/registry.d.ts +182 -0
- package/dist/browser/registry.d.ts.map +1 -0
- package/dist/browser/registry.js +215 -0
- package/dist/browser/registry.js.map +1 -0
- package/dist/browser/scenario-resolve.d.ts +62 -0
- package/dist/browser/scenario-resolve.d.ts.map +1 -0
- package/dist/browser/scenario-resolve.js +127 -0
- package/dist/browser/scenario-resolve.js.map +1 -0
- package/dist/browser/scenario-runner.d.ts +113 -0
- package/dist/browser/scenario-runner.d.ts.map +1 -0
- package/dist/browser/scenario-runner.js +315 -0
- package/dist/browser/scenario-runner.js.map +1 -0
- package/dist/browser/stack-parser.d.ts +43 -0
- package/dist/browser/stack-parser.d.ts.map +1 -0
- package/dist/browser/stack-parser.js +112 -0
- package/dist/browser/stack-parser.js.map +1 -0
- package/dist/browser/tool-support.d.ts +113 -0
- package/dist/browser/tool-support.d.ts.map +1 -0
- package/dist/browser/tool-support.js +181 -0
- package/dist/browser/tool-support.js.map +1 -0
- package/dist/disclosure-ledger.d.ts +38 -0
- package/dist/disclosure-ledger.d.ts.map +1 -0
- package/dist/disclosure-ledger.js +40 -0
- package/dist/disclosure-ledger.js.map +1 -0
- package/dist/index.d.ts +12 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -1
- package/dist/protocol.d.ts +12 -3
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +12 -3
- package/dist/protocol.js.map +1 -1
- package/dist/render.d.ts +121 -10
- package/dist/render.d.ts.map +1 -1
- package/dist/render.js +96 -15
- package/dist/render.js.map +1 -1
- package/dist/runtime-registry.d.ts +63 -0
- package/dist/runtime-registry.d.ts.map +1 -0
- package/dist/runtime-registry.js +131 -0
- package/dist/runtime-registry.js.map +1 -0
- package/dist/scenarios/index.d.ts +4 -0
- package/dist/scenarios/index.d.ts.map +1 -0
- package/dist/scenarios/index.js +4 -0
- package/dist/scenarios/index.js.map +1 -0
- package/dist/scenarios/parse.d.ts +32 -0
- package/dist/scenarios/parse.d.ts.map +1 -0
- package/dist/scenarios/parse.js +199 -0
- package/dist/scenarios/parse.js.map +1 -0
- package/dist/scenarios/scenario.d.ts +115 -0
- package/dist/scenarios/scenario.d.ts.map +1 -0
- package/dist/scenarios/scenario.js +41 -0
- package/dist/scenarios/scenario.js.map +1 -0
- package/dist/scenarios/storage.d.ts +51 -0
- package/dist/scenarios/storage.d.ts.map +1 -0
- package/dist/scenarios/storage.js +93 -0
- package/dist/scenarios/storage.js.map +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +11 -3
- package/dist/server.js.map +1 -1
- package/dist/session.d.ts +142 -2
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +266 -4
- package/dist/session.js.map +1 -1
- package/dist/tools/analyze.d.ts +41 -1
- package/dist/tools/analyze.d.ts.map +1 -1
- package/dist/tools/analyze.js +111 -9
- package/dist/tools/analyze.js.map +1 -1
- package/dist/tools/browser-click.d.ts +36 -0
- package/dist/tools/browser-click.d.ts.map +1 -0
- package/dist/tools/browser-click.js +117 -0
- package/dist/tools/browser-click.js.map +1 -0
- package/dist/tools/browser-close-session.d.ts +24 -0
- package/dist/tools/browser-close-session.d.ts.map +1 -0
- package/dist/tools/browser-close-session.js +63 -0
- package/dist/tools/browser-close-session.js.map +1 -0
- package/dist/tools/browser-fill.d.ts +49 -0
- package/dist/tools/browser-fill.d.ts.map +1 -0
- package/dist/tools/browser-fill.js +138 -0
- package/dist/tools/browser-fill.js.map +1 -0
- package/dist/tools/browser-navigate.d.ts +32 -0
- package/dist/tools/browser-navigate.d.ts.map +1 -0
- package/dist/tools/browser-navigate.js +103 -0
- package/dist/tools/browser-navigate.js.map +1 -0
- package/dist/tools/browser-run-scenario.d.ts +54 -0
- package/dist/tools/browser-run-scenario.d.ts.map +1 -0
- package/dist/tools/browser-run-scenario.js +228 -0
- package/dist/tools/browser-run-scenario.js.map +1 -0
- package/dist/tools/browser-save-scenario.d.ts +44 -0
- package/dist/tools/browser-save-scenario.d.ts.map +1 -0
- package/dist/tools/browser-save-scenario.js +298 -0
- package/dist/tools/browser-save-scenario.js.map +1 -0
- package/dist/tools/browser-snapshot.d.ts +60 -0
- package/dist/tools/browser-snapshot.d.ts.map +1 -0
- package/dist/tools/browser-snapshot.js +139 -0
- package/dist/tools/browser-snapshot.js.map +1 -0
- package/dist/tools/browser-start-session.d.ts +43 -0
- package/dist/tools/browser-start-session.d.ts.map +1 -0
- package/dist/tools/browser-start-session.js +272 -0
- package/dist/tools/browser-start-session.js.map +1 -0
- package/dist/tools/browser-type.d.ts +48 -0
- package/dist/tools/browser-type.d.ts.map +1 -0
- package/dist/tools/browser-type.js +136 -0
- package/dist/tools/browser-type.js.map +1 -0
- package/dist/tools/contracts.d.ts +15 -0
- package/dist/tools/contracts.d.ts.map +1 -1
- package/dist/tools/contracts.js +14 -3
- package/dist/tools/contracts.js.map +1 -1
- package/dist/tools/cross-pr.d.ts.map +1 -1
- package/dist/tools/cross-pr.js +1 -0
- package/dist/tools/cross-pr.js.map +1 -1
- package/dist/tools/git-diff.d.ts.map +1 -1
- package/dist/tools/git-diff.js +104 -4
- package/dist/tools/git-diff.js.map +1 -1
- package/dist/tools/git-history.d.ts.map +1 -1
- package/dist/tools/git-history.js +1 -0
- package/dist/tools/git-history.js.map +1 -1
- package/dist/tools/history.js +1 -1
- package/dist/tools/history.js.map +1 -1
- package/dist/tools/impact.d.ts +9 -0
- package/dist/tools/impact.d.ts.map +1 -1
- package/dist/tools/impact.js +4 -4
- package/dist/tools/impact.js.map +1 -1
- package/dist/tools/index.d.ts +12 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +31 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/kit.d.ts +11 -1
- package/dist/tools/kit.d.ts.map +1 -1
- package/dist/tools/kit.js +3 -0
- package/dist/tools/kit.js.map +1 -1
- package/dist/tools/link-workspace.d.ts.map +1 -1
- package/dist/tools/link-workspace.js +13 -1
- package/dist/tools/link-workspace.js.map +1 -1
- package/dist/tools/mark-incident.d.ts +69 -0
- package/dist/tools/mark-incident.d.ts.map +1 -0
- package/dist/tools/mark-incident.js +212 -0
- package/dist/tools/mark-incident.js.map +1 -0
- package/dist/tools/observe-runtime.d.ts +292 -0
- package/dist/tools/observe-runtime.d.ts.map +1 -0
- package/dist/tools/observe-runtime.js +1192 -0
- package/dist/tools/observe-runtime.js.map +1 -0
- package/dist/tools/observe-tests.d.ts +125 -0
- package/dist/tools/observe-tests.d.ts.map +1 -0
- package/dist/tools/observe-tests.js +313 -0
- package/dist/tools/observe-tests.js.map +1 -0
- package/dist/tools/pr-analysis.d.ts +71 -13
- package/dist/tools/pr-analysis.d.ts.map +1 -1
- package/dist/tools/pr-analysis.js +55 -12
- package/dist/tools/pr-analysis.js.map +1 -1
- package/dist/tools/pre-push.d.ts +77 -0
- package/dist/tools/pre-push.d.ts.map +1 -0
- package/dist/tools/pre-push.js +250 -0
- package/dist/tools/pre-push.js.map +1 -0
- package/dist/tools/propagation.d.ts.map +1 -1
- package/dist/tools/propagation.js +1 -0
- package/dist/tools/propagation.js.map +1 -1
- package/dist/tools/questions.d.ts.map +1 -1
- package/dist/tools/questions.js +101 -14
- package/dist/tools/questions.js.map +1 -1
- package/dist/tools/refusal-fetch.d.ts.map +1 -1
- package/dist/tools/refusal-fetch.js +1 -0
- package/dist/tools/refusal-fetch.js.map +1 -1
- package/dist/tools/runtime-incident.d.ts +92 -0
- package/dist/tools/runtime-incident.d.ts.map +1 -0
- package/dist/tools/runtime-incident.js +144 -0
- package/dist/tools/runtime-incident.js.map +1 -0
- package/dist/tools/scope.d.ts.map +1 -1
- package/dist/tools/scope.js +1 -0
- package/dist/tools/scope.js.map +1 -1
- package/dist/tools/similar-incidents.d.ts +13 -0
- package/dist/tools/similar-incidents.d.ts.map +1 -1
- package/dist/tools/similar-incidents.js +22 -8
- package/dist/tools/similar-incidents.js.map +1 -1
- package/dist/tools/verification-status.d.ts +22 -0
- package/dist/tools/verification-status.d.ts.map +1 -1
- package/dist/tools/verification-status.js +52 -5
- package/dist/tools/verification-status.js.map +1 -1
- package/dist/tools/verify-claim.d.ts.map +1 -1
- package/dist/tools/verify-claim.js +5 -0
- package/dist/tools/verify-claim.js.map +1 -1
- package/package.json +16 -4
package/dist/bin/descry-mcp.js
CHANGED
|
@@ -15,10 +15,33 @@
|
|
|
15
15
|
* writes nothing itself and does its argument handling before opening anything.
|
|
16
16
|
*/
|
|
17
17
|
import process from "node:process";
|
|
18
|
+
import { createRequire } from "node:module";
|
|
18
19
|
import { resolve } from "node:path";
|
|
19
20
|
import { createMcpServer } from "../server.js";
|
|
20
21
|
import { Session } from "../session.js";
|
|
21
22
|
import { serveStdio } from "../transport.js";
|
|
23
|
+
/**
|
|
24
|
+
* The version this build actually is, read from the installed package rather
|
|
25
|
+
* than written here.
|
|
26
|
+
*
|
|
27
|
+
* It was the literal `"0.0.0"` for every release, so every host reported the
|
|
28
|
+
* same version no matter which package it was running — and that is not a
|
|
29
|
+
* cosmetic gap. `@descryy/mcp` 0.1.2 went to npm from a branch that never
|
|
30
|
+
* reached `main`, carrying a tool `main` did not have, and nothing any host
|
|
31
|
+
* could see said so: `tools/list` showed seventeen tools and `serverInfo` said
|
|
32
|
+
* 0.0.0. A server that cannot say what it is cannot be caught drifting.
|
|
33
|
+
*/
|
|
34
|
+
const VERSION = (() => {
|
|
35
|
+
try {
|
|
36
|
+
const pkg = createRequire(import.meta.url)("../../package.json");
|
|
37
|
+
return typeof pkg.version === "string" ? pkg.version : "0.0.0";
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// Never fatal. A host that cannot read a version still gets a server, and
|
|
41
|
+
// failing the handshake over a label would be the worse trade.
|
|
42
|
+
return "0.0.0";
|
|
43
|
+
}
|
|
44
|
+
})();
|
|
22
45
|
const USAGE = `descry-mcp — Descry's MCP server (stdio)
|
|
23
46
|
|
|
24
47
|
descry-mcp [repository-path]
|
|
@@ -34,7 +57,7 @@ async function main() {
|
|
|
34
57
|
}
|
|
35
58
|
const repoPath = resolve(args[0] ?? process.cwd());
|
|
36
59
|
const session = await Session.open({ repoPath });
|
|
37
|
-
const server = createMcpServer({ session, name: "descry", version:
|
|
60
|
+
const server = createMcpServer({ session, name: "descry", version: VERSION });
|
|
38
61
|
try {
|
|
39
62
|
await serveStdio({ stdin: process.stdin, stdout: process.stdout, stderr: process.stderr }, (line, transport) => server.dispatch(line, transport));
|
|
40
63
|
return 0;
|
|
@@ -42,7 +65,12 @@ async function main() {
|
|
|
42
65
|
finally {
|
|
43
66
|
// The SQLite handle and anything else with a lifetime. Held open past the
|
|
44
67
|
// end of stdin, a WAL journal outlives the process that owned it.
|
|
45
|
-
|
|
68
|
+
//
|
|
69
|
+
// `dispose`, not `close`, because end-of-stdin is how an MCP host says
|
|
70
|
+
// "disconnect" — and §4 requires that signal to reap every browser this
|
|
71
|
+
// connection owns. A leaked SQLite handle costs a file descriptor; a
|
|
72
|
+
// leaked Chromium keeps running on the developer's machine.
|
|
73
|
+
await session.dispose();
|
|
46
74
|
}
|
|
47
75
|
}
|
|
48
76
|
main().then((code) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"descry-mcp.js","sourceRoot":"","sources":["../../src/bin/descry-mcp.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,OAAO,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,MAAM,KAAK,GAAG;;;;;;CAMb,CAAC;AAEF,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC5B,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACnD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,eAAe,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;IAE9E,IAAI,CAAC;QACH,MAAM,UAAU,CACd,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,EACxE,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,CACtD,CAAC;QACF,OAAO,CAAC,CAAC;IACX,CAAC;YAAS,CAAC;QACT,0EAA0E;QAC1E,kEAAkE;QAClE,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"descry-mcp.js","sourceRoot":"","sources":["../../src/bin/descry-mcp.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,OAAO,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C;;;;;;;;;;GAUG;AACH,MAAM,OAAO,GAAW,CAAC,GAAW,EAAE;IACpC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,oBAAoB,CAA0B,CAAC;QAC1F,OAAO,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;IACjE,CAAC;IAAC,MAAM,CAAC;QACP,0EAA0E;QAC1E,+DAA+D;QAC/D,OAAO,OAAO,CAAC;IACjB,CAAC;AACH,CAAC,CAAC,EAAE,CAAC;AAEL,MAAM,KAAK,GAAG;;;;;;CAMb,CAAC;AAEF,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC5B,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACnD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,eAAe,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;IAE9E,IAAI,CAAC;QACH,MAAM,UAAU,CACd,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,EACxE,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,CACtD,CAAC;QACF,OAAO,CAAC,CAAC;IACX,CAAC;YAAS,CAAC;QACT,0EAA0E;QAC1E,kEAAkE;QAClE,EAAE;QACF,uEAAuE;QACvE,wEAAwE;QACxE,qEAAqE;QACrE,4DAA4D;QAC5D,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;IAC1B,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,IAAI,CACT,CAAC,IAAI,EAAE,EAAE;IACP,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;AAC1B,CAAC,EACD,CAAC,KAAc,EAAE,EAAE;IACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,eAAe,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CACzF,CAAC;IACF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CACF,CAAC"}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The browser port — what `@descryy/mcp` needs from a browser, stated as an
|
|
3
|
+
* interface this package owns.
|
|
4
|
+
*
|
|
5
|
+
* ## Why a port at all
|
|
6
|
+
*
|
|
7
|
+
* `@descryy/runtime-browser` is not on the registry yet
|
|
8
|
+
* (`mcp-browser-tools.md` §3.1), so a lane that imported it directly could
|
|
9
|
+
* not run today. That is the immediate reason and it is the weakest one.
|
|
10
|
+
* The lasting reason is that everything above this line — seven tools, the
|
|
11
|
+
* session registry, the scenario runner — otherwise becomes untestable
|
|
12
|
+
* without launching a real Chromium per assertion, and a suite that needs a
|
|
13
|
+
* browser to test its session bookkeeping is a suite people stop running.
|
|
14
|
+
*
|
|
15
|
+
* ## Derived, not invented
|
|
16
|
+
*
|
|
17
|
+
* Every member below exists because a real export in
|
|
18
|
+
* `descry-runtime/packages/browser/src/index.ts` provides it. The refusal
|
|
19
|
+
* shape is `launchBrowserSessionOrRefuse`'s verbatim; `isUsable()` is
|
|
20
|
+
* `BrowserSession`'s, including its reason for existing (a crashed page
|
|
21
|
+
* still reports `isClosed() === false`, so crash tracking cannot be derived
|
|
22
|
+
* from closure); the action verbs are `BrowserActionCollector`'s; the
|
|
23
|
+
* console and network observations are what the two collectors emit. The
|
|
24
|
+
* port narrows that surface — it does not add to it. Nothing here can be
|
|
25
|
+
* satisfied by the real package only by writing new runtime code, with one
|
|
26
|
+
* disclosed exception, `type()` below.
|
|
27
|
+
*
|
|
28
|
+
* ## What the port deliberately does not carry
|
|
29
|
+
*
|
|
30
|
+
* A verdict. There is no `severity`, no `isBug`, no `category` on any
|
|
31
|
+
* observation, because `DEC-381` rules that
|
|
32
|
+
* classification stays in the desktop pipeline. That is enforced structurally
|
|
33
|
+
* rather than by convention: a tool cannot report a triaged finding through
|
|
34
|
+
* a port that has nowhere to put one.
|
|
35
|
+
*
|
|
36
|
+
* Rule 1 holds here as everywhere — nothing in this file names a language, a
|
|
37
|
+
* framework, or a file extension.
|
|
38
|
+
*/
|
|
39
|
+
import type { StackTrace } from "@descryy/runtime-contracts";
|
|
40
|
+
/** A page element as a snapshot presented it. `ref` is the handle an action takes. */
|
|
41
|
+
export interface SnapshotElement {
|
|
42
|
+
readonly ref: string;
|
|
43
|
+
readonly role: string;
|
|
44
|
+
readonly name: string;
|
|
45
|
+
/**
|
|
46
|
+
* How the driver will find this element again. Present so a reply can be
|
|
47
|
+
* read by a human, **not** so a caller can act on it: every verb takes a
|
|
48
|
+
* `ref`, never a selector, because a ref ties the action to a snapshot the
|
|
49
|
+
* agent actually saw and a selector does not.
|
|
50
|
+
*/
|
|
51
|
+
readonly selector: string;
|
|
52
|
+
}
|
|
53
|
+
export interface PageSnapshot {
|
|
54
|
+
readonly url: string;
|
|
55
|
+
readonly title: string;
|
|
56
|
+
readonly elements: readonly SnapshotElement[];
|
|
57
|
+
/**
|
|
58
|
+
* How many elements the page had, before any budget applied.
|
|
59
|
+
*
|
|
60
|
+
* Always present, and always the uncapped figure. §5.2's requirement in one
|
|
61
|
+
* field: without it a caller cannot tell "there are no more elements" from
|
|
62
|
+
* "the rest did not fit", and those are different facts about their page.
|
|
63
|
+
* The driver never truncates — it returns what it saw and this equals
|
|
64
|
+
* `elements.length` here — but the field is on the port rather than
|
|
65
|
+
* invented by the tool, so the tool cannot lose track of the real count
|
|
66
|
+
* while paging.
|
|
67
|
+
*/
|
|
68
|
+
readonly totalElements: number;
|
|
69
|
+
}
|
|
70
|
+
export type BrowserActionKind = "navigate" | "click" | "type" | "fill";
|
|
71
|
+
export interface ObservedAction {
|
|
72
|
+
readonly action: BrowserActionKind;
|
|
73
|
+
/** Null for `navigate`, which acts on the page rather than on an element. */
|
|
74
|
+
readonly ref: string | null;
|
|
75
|
+
/**
|
|
76
|
+
* How text reached the field — `"append"` for `type`, `"replace"` for
|
|
77
|
+
* `fill`, null for actions that enter no text.
|
|
78
|
+
*
|
|
79
|
+
* Carried because without it the two text verbs' evidence reads
|
|
80
|
+
* identically, and "the field now contains X" and "X was added to whatever
|
|
81
|
+
* the field already contained" are different facts about a run. The runtime
|
|
82
|
+
* collector's own `INPUT` payload carries the same field for the same
|
|
83
|
+
* reason.
|
|
84
|
+
*/
|
|
85
|
+
readonly mode: "replace" | "append" | null;
|
|
86
|
+
readonly url: string;
|
|
87
|
+
readonly at: string;
|
|
88
|
+
}
|
|
89
|
+
export interface ObservedConsoleError {
|
|
90
|
+
readonly text: string;
|
|
91
|
+
/**
|
|
92
|
+
* Raw stack text as the page produced it, or null. **Not yet rewritten to
|
|
93
|
+
* real files and lines** — that is `rewriteScriptUrls`' job and it needs a
|
|
94
|
+
* source-root resolver the driver does not have. The port carries the raw
|
|
95
|
+
* text so the mapping happens once, above, where the repo root is known.
|
|
96
|
+
*/
|
|
97
|
+
readonly stackText: string | null;
|
|
98
|
+
readonly at: string;
|
|
99
|
+
}
|
|
100
|
+
export interface ObservedRequest {
|
|
101
|
+
readonly method: string;
|
|
102
|
+
readonly url: string;
|
|
103
|
+
/** Null when the request produced no response at all, which is a different fact from a 500. */
|
|
104
|
+
readonly status: number | null;
|
|
105
|
+
/** The `fetch()` call site as raw text, when the initiator capture claimed one. Null is honest absence. */
|
|
106
|
+
readonly stackText: string | null;
|
|
107
|
+
/**
|
|
108
|
+
* The same call site, parsed into frames with real file paths.
|
|
109
|
+
*
|
|
110
|
+
* Null unless the caller named a stack-trace parser for the application
|
|
111
|
+
* being driven — this package cannot parse a stack itself without naming a
|
|
112
|
+
* language, which rule 1 forbids above the IR. **This is the field the R4
|
|
113
|
+
* edge write needs**: `confirmObservedFrontendCaller` takes a `StackTrace`,
|
|
114
|
+
* not text, and a run with no parser produces no arrow and says so.
|
|
115
|
+
*/
|
|
116
|
+
readonly stackTrace: StackTrace | null;
|
|
117
|
+
readonly at: string;
|
|
118
|
+
}
|
|
119
|
+
/** A request that did not succeed. Mechanical, not a judgement: no response, or a 4xx/5xx status. */
|
|
120
|
+
export declare function isFailedRequest(request: ObservedRequest): boolean;
|
|
121
|
+
/** Everything witnessed since the last drain. Raw — see this file's header. */
|
|
122
|
+
export interface BrowserObservation {
|
|
123
|
+
readonly actions: readonly ObservedAction[];
|
|
124
|
+
readonly consoleErrors: readonly ObservedConsoleError[];
|
|
125
|
+
/**
|
|
126
|
+
* Every request the page issued, not only the ones that failed.
|
|
127
|
+
*
|
|
128
|
+
* A successful call is what proves *this frontend action reached this
|
|
129
|
+
* backend route* — the arrow the whole plan exists for — so filtering to
|
|
130
|
+
* failures here would throw away the evidence the R4 edge write runs on.
|
|
131
|
+
* The reply narrows to failures for readability; the correlation does not.
|
|
132
|
+
*/
|
|
133
|
+
readonly requests: readonly ObservedRequest[];
|
|
134
|
+
}
|
|
135
|
+
export declare const EMPTY_OBSERVATION: BrowserObservation;
|
|
136
|
+
export interface BrowserLaunchOptions {
|
|
137
|
+
readonly targetUrl: string;
|
|
138
|
+
readonly headless?: boolean;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* `launchBrowserSessionOrRefuse`'s refusal, unchanged.
|
|
142
|
+
*
|
|
143
|
+
* `remedy` is the exact command that fixes it, **supplied by the driver and
|
|
144
|
+
* never held as a constant in this package**. The real driver passes
|
|
145
|
+
* `CHROMIUM_INSTALL_REMEDY` through; a copy here would be a second source of
|
|
146
|
+
* truth for one string, and the copy is the one that goes stale.
|
|
147
|
+
*/
|
|
148
|
+
export interface ChromiumRefusal {
|
|
149
|
+
readonly refusal: "chromiumNotInstalled";
|
|
150
|
+
readonly message: string;
|
|
151
|
+
readonly remedy: string;
|
|
152
|
+
readonly expectedExecutablePath: string;
|
|
153
|
+
}
|
|
154
|
+
export type BrowserLaunchResult = {
|
|
155
|
+
readonly launched: true;
|
|
156
|
+
readonly session: BrowserPageSession;
|
|
157
|
+
} | ({
|
|
158
|
+
readonly launched: false;
|
|
159
|
+
} & ChromiumRefusal);
|
|
160
|
+
/** The browser died. Distinct from a closed session: a crash invalidates the id rather than ending it cleanly. */
|
|
161
|
+
export declare class BrowserSessionCrashedError extends Error {
|
|
162
|
+
readonly sessionId: string;
|
|
163
|
+
constructor(sessionId: string);
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* The ref named no element in the current snapshot.
|
|
167
|
+
*
|
|
168
|
+
* Thrown for an invented ref **and** for a ref from a superseded snapshot,
|
|
169
|
+
* because those are the same mistake: acting on an element the agent has not
|
|
170
|
+
* seen. Falling back to the stale selector would let a click land on whatever
|
|
171
|
+
* now matches it on a page the caller has never inspected.
|
|
172
|
+
*/
|
|
173
|
+
export declare class UnknownElementRefError extends Error {
|
|
174
|
+
constructor(ref: string);
|
|
175
|
+
}
|
|
176
|
+
export interface BrowserPageSession {
|
|
177
|
+
readonly sessionId: string;
|
|
178
|
+
/** When the page was actually created, ISO-8601. What evidence is ordered by. */
|
|
179
|
+
readonly startedAt: string;
|
|
180
|
+
/**
|
|
181
|
+
* False once the page has crashed or closed. Not derivable from closure —
|
|
182
|
+
* `runtime-browser` verified directly that a real crash still reports
|
|
183
|
+
* `isClosed() === false`, which is why this is a member rather than
|
|
184
|
+
* something a caller computes.
|
|
185
|
+
*/
|
|
186
|
+
isUsable(): boolean;
|
|
187
|
+
currentUrl(): string;
|
|
188
|
+
navigate(url: string): Promise<void>;
|
|
189
|
+
snapshot(): Promise<PageSnapshot>;
|
|
190
|
+
click(ref: string): Promise<void>;
|
|
191
|
+
/**
|
|
192
|
+
* Type `text` as real keystrokes, appending to whatever the field holds.
|
|
193
|
+
*
|
|
194
|
+
* The append/replace difference against `fill` is the visible half. The
|
|
195
|
+
* half that decides which verb is correct for a page is that **this one
|
|
196
|
+
* fires key events and `fill` fires none**: a field that opens an
|
|
197
|
+
* autocomplete on keydown, validates per character, or debounces a search
|
|
198
|
+
* sees nothing at all from a `fill`. A caller reaching for `fill` on a
|
|
199
|
+
* search box gets a page that was never typed into — a wrong answer
|
|
200
|
+
* produced by entirely correct code — so both members exist and the tool
|
|
201
|
+
* prose has to state the real distinction, not the tidy one.
|
|
202
|
+
*/
|
|
203
|
+
type(ref: string, text: string): Promise<void>;
|
|
204
|
+
/** Replace the element's value with `text`, setting it directly. Fires no key events. */
|
|
205
|
+
fill(ref: string, text: string): Promise<void>;
|
|
206
|
+
/**
|
|
207
|
+
* Everything witnessed since the last drain, removed from the session as it
|
|
208
|
+
* is returned.
|
|
209
|
+
*
|
|
210
|
+
* Drained rather than peeked, and that is a contract, not an implementation
|
|
211
|
+
* detail: §4 requires evidence to be flushed on four separate teardown
|
|
212
|
+
* paths, and a peeking read would make the flush re-report every
|
|
213
|
+
* observation already attached to an earlier reply.
|
|
214
|
+
*/
|
|
215
|
+
drainEvidence(): Promise<BrowserObservation>;
|
|
216
|
+
/**
|
|
217
|
+
* Tear down and return whatever was still held.
|
|
218
|
+
*
|
|
219
|
+
* Idempotent, and returns the final flush rather than `void`. Evidence
|
|
220
|
+
* captured and then dropped is worse than evidence never captured, because
|
|
221
|
+
* nothing discloses it — so the last thing a session does is hand back what
|
|
222
|
+
* it was holding, on every path including a crash.
|
|
223
|
+
*/
|
|
224
|
+
close(): Promise<BrowserObservation>;
|
|
225
|
+
}
|
|
226
|
+
export interface BrowserDriver {
|
|
227
|
+
/**
|
|
228
|
+
* Open a session at `targetUrl`, or refuse.
|
|
229
|
+
*
|
|
230
|
+
* A missing browser is a **returned value**, never a thrown error, so a
|
|
231
|
+
* tool mapping it onto the `refused` state cannot forget to catch it —
|
|
232
|
+
* `refused` is a fact about Descry, never about the user's code.
|
|
233
|
+
*/
|
|
234
|
+
launch(options: BrowserLaunchOptions): Promise<BrowserLaunchResult>;
|
|
235
|
+
}
|
|
236
|
+
//# sourceMappingURL=driver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"driver.d.ts","sourceRoot":"","sources":["../../src/browser/driver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The browser port — what `@descryy/mcp` needs from a browser, stated as an
|
|
3
|
+
* interface this package owns.
|
|
4
|
+
*
|
|
5
|
+
* ## Why a port at all
|
|
6
|
+
*
|
|
7
|
+
* `@descryy/runtime-browser` is not on the registry yet
|
|
8
|
+
* (`mcp-browser-tools.md` §3.1), so a lane that imported it directly could
|
|
9
|
+
* not run today. That is the immediate reason and it is the weakest one.
|
|
10
|
+
* The lasting reason is that everything above this line — seven tools, the
|
|
11
|
+
* session registry, the scenario runner — otherwise becomes untestable
|
|
12
|
+
* without launching a real Chromium per assertion, and a suite that needs a
|
|
13
|
+
* browser to test its session bookkeeping is a suite people stop running.
|
|
14
|
+
*
|
|
15
|
+
* ## Derived, not invented
|
|
16
|
+
*
|
|
17
|
+
* Every member below exists because a real export in
|
|
18
|
+
* `descry-runtime/packages/browser/src/index.ts` provides it. The refusal
|
|
19
|
+
* shape is `launchBrowserSessionOrRefuse`'s verbatim; `isUsable()` is
|
|
20
|
+
* `BrowserSession`'s, including its reason for existing (a crashed page
|
|
21
|
+
* still reports `isClosed() === false`, so crash tracking cannot be derived
|
|
22
|
+
* from closure); the action verbs are `BrowserActionCollector`'s; the
|
|
23
|
+
* console and network observations are what the two collectors emit. The
|
|
24
|
+
* port narrows that surface — it does not add to it. Nothing here can be
|
|
25
|
+
* satisfied by the real package only by writing new runtime code, with one
|
|
26
|
+
* disclosed exception, `type()` below.
|
|
27
|
+
*
|
|
28
|
+
* ## What the port deliberately does not carry
|
|
29
|
+
*
|
|
30
|
+
* A verdict. There is no `severity`, no `isBug`, no `category` on any
|
|
31
|
+
* observation, because `DEC-381` rules that
|
|
32
|
+
* classification stays in the desktop pipeline. That is enforced structurally
|
|
33
|
+
* rather than by convention: a tool cannot report a triaged finding through
|
|
34
|
+
* a port that has nowhere to put one.
|
|
35
|
+
*
|
|
36
|
+
* Rule 1 holds here as everywhere — nothing in this file names a language, a
|
|
37
|
+
* framework, or a file extension.
|
|
38
|
+
*/
|
|
39
|
+
/** A request that did not succeed. Mechanical, not a judgement: no response, or a 4xx/5xx status. */
|
|
40
|
+
export function isFailedRequest(request) {
|
|
41
|
+
return request.status === null || request.status >= 400;
|
|
42
|
+
}
|
|
43
|
+
export const EMPTY_OBSERVATION = { actions: [], consoleErrors: [], requests: [] };
|
|
44
|
+
/** The browser died. Distinct from a closed session: a crash invalidates the id rather than ending it cleanly. */
|
|
45
|
+
export class BrowserSessionCrashedError extends Error {
|
|
46
|
+
sessionId;
|
|
47
|
+
constructor(sessionId) {
|
|
48
|
+
super(`Browser session ${sessionId} is no longer usable — the browser process crashed or the page closed. ` +
|
|
49
|
+
"The session id is invalidated; start a new session. It is deliberately not reopened against a " +
|
|
50
|
+
"different browser, which would silently change what later evidence refers to.");
|
|
51
|
+
this.name = "BrowserSessionCrashedError";
|
|
52
|
+
this.sessionId = sessionId;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The ref named no element in the current snapshot.
|
|
57
|
+
*
|
|
58
|
+
* Thrown for an invented ref **and** for a ref from a superseded snapshot,
|
|
59
|
+
* because those are the same mistake: acting on an element the agent has not
|
|
60
|
+
* seen. Falling back to the stale selector would let a click land on whatever
|
|
61
|
+
* now matches it on a page the caller has never inspected.
|
|
62
|
+
*/
|
|
63
|
+
export class UnknownElementRefError extends Error {
|
|
64
|
+
constructor(ref) {
|
|
65
|
+
super(`"${ref}" is not an element in this session's current snapshot. Refs are issued per snapshot and are ` +
|
|
66
|
+
"invalidated by navigation — call browser_snapshot and use a ref from the result.");
|
|
67
|
+
this.name = "UnknownElementRefError";
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=driver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"driver.js","sourceRoot":"","sources":["../../src/browser/driver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAyFH,qGAAqG;AACrG,MAAM,UAAU,eAAe,CAAC,OAAwB;IACtD,OAAO,OAAO,CAAC,MAAM,KAAK,IAAI,IAAI,OAAO,CAAC,MAAM,IAAI,GAAG,CAAC;AAC1D,CAAC;AAiBD,MAAM,CAAC,MAAM,iBAAiB,GAAuB,EAAE,OAAO,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;AA0BtG,kHAAkH;AAClH,MAAM,OAAO,0BAA2B,SAAQ,KAAK;IAC1C,SAAS,CAAS;IAE3B,YAAY,SAAiB;QAC3B,KAAK,CACH,mBAAmB,SAAS,yEAAyE;YACnG,gGAAgG;YAChG,+EAA+E,CAClF,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,4BAA4B,CAAC;QACzC,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;CACF;AAED;;;;;;;GAOG;AACH,MAAM,OAAO,sBAAuB,SAAQ,KAAK;IAC/C,YAAY,GAAW;QACrB,KAAK,CACH,IAAI,GAAG,+FAA+F;YACpG,kFAAkF,CACrF,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC;IACvC,CAAC;CACF"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How a browser observation becomes part of a tool reply — §5.3.
|
|
3
|
+
*
|
|
4
|
+
* Two rules live here rather than in each of the seven tools, because seven
|
|
5
|
+
* copies of a disclosure is seven chances for one of them to be missing.
|
|
6
|
+
*
|
|
7
|
+
* **Attached, not fetched.** Evidence rides on the reply for the action that
|
|
8
|
+
* produced it. A separate `browser_get_evidence` would make the caller
|
|
9
|
+
* correlate two replies to learn that its own click caused the error, and
|
|
10
|
+
* would let it skip the second call entirely.
|
|
11
|
+
*
|
|
12
|
+
* **Raw, and disclosed as raw.** Per
|
|
13
|
+
* `DEC-381`, nothing here classifies. The
|
|
14
|
+
* note below is not decoration: a calling agent that receives a console error
|
|
15
|
+
* has to know Descry is not claiming it is a bug, or it will report Descry as
|
|
16
|
+
* having said so.
|
|
17
|
+
*/
|
|
18
|
+
import { type BrowserObservation, type ObservedRequest } from "./driver.ts";
|
|
19
|
+
export interface BrowserEvidenceReport {
|
|
20
|
+
readonly consoleErrors: BrowserObservation["consoleErrors"];
|
|
21
|
+
/**
|
|
22
|
+
* The requests that did not succeed, listed.
|
|
23
|
+
*
|
|
24
|
+
* Narrowed from everything the page issued, because a page load can issue
|
|
25
|
+
* fifty requests and a reply that lists every stylesheet is a reply nobody
|
|
26
|
+
* reads. The narrowing is mechanical — no response, or a 4xx/5xx — and it
|
|
27
|
+
* is **only a narrowing of the reply**: the correlation that mints R4 edges
|
|
28
|
+
* runs over every request, since a successful call is exactly what proves a
|
|
29
|
+
* frontend action reached a backend route.
|
|
30
|
+
*/
|
|
31
|
+
readonly failedRequests: readonly ObservedRequest[];
|
|
32
|
+
/** How many requests the page issued in total, so the list above is read as a subset and not as all of it. */
|
|
33
|
+
readonly totalRequests: number;
|
|
34
|
+
readonly actions: BrowserObservation["actions"];
|
|
35
|
+
}
|
|
36
|
+
export declare function evidenceReport(observation: BrowserObservation): BrowserEvidenceReport;
|
|
37
|
+
export declare function isEmpty(report: BrowserEvidenceReport): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* The notes any reply carrying evidence must include.
|
|
40
|
+
*
|
|
41
|
+
* The triage disclaimer is emitted **only when there is something to
|
|
42
|
+
* disclaim**. A reply with no errors that solemnly explained it had not
|
|
43
|
+
* triaged them would be noise on the overwhelmingly common path, and noise is
|
|
44
|
+
* how a real disclosure stops being read.
|
|
45
|
+
*/
|
|
46
|
+
export declare function evidenceNotes(report: BrowserEvidenceReport): string[];
|
|
47
|
+
//# sourceMappingURL=evidence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evidence.d.ts","sourceRoot":"","sources":["../../src/browser/evidence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAmB,KAAK,kBAAkB,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAE7F,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,aAAa,EAAE,kBAAkB,CAAC,eAAe,CAAC,CAAC;IAC5D;;;;;;;;;OASG;IACH,QAAQ,CAAC,cAAc,EAAE,SAAS,eAAe,EAAE,CAAC;IACpD,8GAA8G;IAC9G,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC,SAAS,CAAC,CAAC;CACjD;AAED,wBAAgB,cAAc,CAAC,WAAW,EAAE,kBAAkB,GAAG,qBAAqB,CAOrF;AAED,wBAAgB,OAAO,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAE9D;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,qBAAqB,GAAG,MAAM,EAAE,CAsBrE"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How a browser observation becomes part of a tool reply — §5.3.
|
|
3
|
+
*
|
|
4
|
+
* Two rules live here rather than in each of the seven tools, because seven
|
|
5
|
+
* copies of a disclosure is seven chances for one of them to be missing.
|
|
6
|
+
*
|
|
7
|
+
* **Attached, not fetched.** Evidence rides on the reply for the action that
|
|
8
|
+
* produced it. A separate `browser_get_evidence` would make the caller
|
|
9
|
+
* correlate two replies to learn that its own click caused the error, and
|
|
10
|
+
* would let it skip the second call entirely.
|
|
11
|
+
*
|
|
12
|
+
* **Raw, and disclosed as raw.** Per
|
|
13
|
+
* `DEC-381`, nothing here classifies. The
|
|
14
|
+
* note below is not decoration: a calling agent that receives a console error
|
|
15
|
+
* has to know Descry is not claiming it is a bug, or it will report Descry as
|
|
16
|
+
* having said so.
|
|
17
|
+
*/
|
|
18
|
+
import { isFailedRequest } from "./driver.js";
|
|
19
|
+
export function evidenceReport(observation) {
|
|
20
|
+
return {
|
|
21
|
+
consoleErrors: observation.consoleErrors,
|
|
22
|
+
failedRequests: observation.requests.filter(isFailedRequest),
|
|
23
|
+
totalRequests: observation.requests.length,
|
|
24
|
+
actions: observation.actions,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export function isEmpty(report) {
|
|
28
|
+
return report.consoleErrors.length === 0 && report.failedRequests.length === 0;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The notes any reply carrying evidence must include.
|
|
32
|
+
*
|
|
33
|
+
* The triage disclaimer is emitted **only when there is something to
|
|
34
|
+
* disclaim**. A reply with no errors that solemnly explained it had not
|
|
35
|
+
* triaged them would be noise on the overwhelmingly common path, and noise is
|
|
36
|
+
* how a real disclosure stops being read.
|
|
37
|
+
*/
|
|
38
|
+
export function evidenceNotes(report) {
|
|
39
|
+
if (isEmpty(report))
|
|
40
|
+
return [];
|
|
41
|
+
const notes = [
|
|
42
|
+
`${report.consoleErrors.length} console error(s) and ${report.failedRequests.length} failed request(s) ` +
|
|
43
|
+
"were observed in the browser during this call. They are reported raw and have not been triaged — " +
|
|
44
|
+
"Descry is not claiming any of them is a bug, only that the page produced them. Deciding which " +
|
|
45
|
+
"matter is the calling agent's job.",
|
|
46
|
+
];
|
|
47
|
+
const unmapped = [...report.consoleErrors, ...report.failedRequests].filter((item) => item.stackText !== null && !item.stackText.startsWith("/") && item.stackText.includes("http")).length;
|
|
48
|
+
if (unmapped > 0) {
|
|
49
|
+
notes.push(`${unmapped} stack trace(s) still name script URLs rather than repository files. Mapping them back ` +
|
|
50
|
+
"to real files and lines needs the browser backend's source-root resolver, which this build does " +
|
|
51
|
+
"not have wired yet, so the raw text is passed through rather than a guess being printed.");
|
|
52
|
+
}
|
|
53
|
+
return notes;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=evidence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evidence.js","sourceRoot":"","sources":["../../src/browser/evidence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,eAAe,EAAiD,MAAM,aAAa,CAAC;AAoB7F,MAAM,UAAU,cAAc,CAAC,WAA+B;IAC5D,OAAO;QACL,aAAa,EAAE,WAAW,CAAC,aAAa;QACxC,cAAc,EAAE,WAAW,CAAC,QAAQ,CAAC,MAAM,CAAC,eAAe,CAAC;QAC5D,aAAa,EAAE,WAAW,CAAC,QAAQ,CAAC,MAAM;QAC1C,OAAO,EAAE,WAAW,CAAC,OAAO;KAC7B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,MAA6B;IACnD,OAAO,MAAM,CAAC,aAAa,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,cAAc,CAAC,MAAM,KAAK,CAAC,CAAC;AACjF,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAAC,MAA6B;IACzD,IAAI,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,CAAC;IAE/B,MAAM,KAAK,GAAG;QACZ,GAAG,MAAM,CAAC,aAAa,CAAC,MAAM,yBAAyB,MAAM,CAAC,cAAc,CAAC,MAAM,qBAAqB;YACtG,mGAAmG;YACnG,gGAAgG;YAChG,oCAAoC;KACvC,CAAC;IAEF,MAAM,QAAQ,GAAG,CAAC,GAAG,MAAM,CAAC,aAAa,EAAE,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC,MAAM,CACzE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,CACxG,CAAC,MAAM,CAAC;IACT,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;QACjB,KAAK,CAAC,IAAI,CACR,GAAG,QAAQ,yFAAyF;YAClG,kGAAkG;YAClG,0FAA0F,CAC7F,CAAC;IACJ,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A `BrowserDriver` with no browser behind it.
|
|
3
|
+
*
|
|
4
|
+
* Not a stub. It implements every rule the port states — ref issuance and
|
|
5
|
+
* invalidation, drain-not-peek, crash invalidation, idempotent close that
|
|
6
|
+
* still flushes — and `browser-driver-contract.test.ts` runs the same
|
|
7
|
+
* assertions against it that the real driver will have to pass. Its purpose
|
|
8
|
+
* is to make those rules *checkable in milliseconds*, so the session
|
|
9
|
+
* lifecycle in §4 is tested against timeouts, disconnects and crashes that
|
|
10
|
+
* would otherwise each need a real Chromium.
|
|
11
|
+
*
|
|
12
|
+
* Two deliberate non-goals. It does not simulate a page — pages are declared
|
|
13
|
+
* with `setPage`, because a fake DOM would be a second, wrong browser. And it
|
|
14
|
+
* does not classify anything, for the same structural reason the port does
|
|
15
|
+
* not: there is nowhere to put a verdict.
|
|
16
|
+
*/
|
|
17
|
+
import { type BrowserDriver, type ObservedRequest } from "./driver.ts";
|
|
18
|
+
/** A page as a test declares it. `ref` is issued by the fake, not written here. */
|
|
19
|
+
export interface FakePage {
|
|
20
|
+
readonly url: string;
|
|
21
|
+
readonly title: string;
|
|
22
|
+
readonly elements: readonly {
|
|
23
|
+
readonly role: string;
|
|
24
|
+
readonly name: string;
|
|
25
|
+
readonly selector: string;
|
|
26
|
+
}[];
|
|
27
|
+
}
|
|
28
|
+
export interface FakeBrowserDriver extends BrowserDriver {
|
|
29
|
+
/** Declare what is served at `url`. Navigating anywhere undeclared yields an empty page, not an error — an empty page is a real thing a URL can serve. */
|
|
30
|
+
setPage(url: string, page: FakePage): void;
|
|
31
|
+
/** Every subsequent launch refuses, in `launchBrowserSessionOrRefuse`'s shape. */
|
|
32
|
+
setChromiumMissing(remedy?: string): void;
|
|
33
|
+
emitConsoleError(sessionId: string, error: {
|
|
34
|
+
readonly text: string;
|
|
35
|
+
readonly stackText: string | null;
|
|
36
|
+
}): void;
|
|
37
|
+
/** Record a request the page issued. Status and stack are whatever the test needs them to be. */
|
|
38
|
+
emitRequest(sessionId: string, request: {
|
|
39
|
+
readonly method: string;
|
|
40
|
+
readonly url: string;
|
|
41
|
+
readonly status: number | null;
|
|
42
|
+
readonly stackText: string | null;
|
|
43
|
+
readonly stackTrace?: ObservedRequest["stackTrace"];
|
|
44
|
+
}): void;
|
|
45
|
+
/** Sugar for `emitRequest` with a failing status. */
|
|
46
|
+
emitFailedRequest(sessionId: string, request: {
|
|
47
|
+
readonly method: string;
|
|
48
|
+
readonly url: string;
|
|
49
|
+
readonly status: number | null;
|
|
50
|
+
readonly stackText: string | null;
|
|
51
|
+
}): void;
|
|
52
|
+
/** Kill the browser behind a session, the way a real crash does — usable goes false, the id stays invalid. */
|
|
53
|
+
crash(sessionId: string): void;
|
|
54
|
+
/** Every session this driver has opened and not closed. What the registry's orphan-cleanup tests assert against. */
|
|
55
|
+
openSessionIds(): readonly string[];
|
|
56
|
+
}
|
|
57
|
+
export declare function createFakeBrowserDriver(): FakeBrowserDriver;
|
|
58
|
+
//# sourceMappingURL=fake-driver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fake-driver.d.ts","sourceRoot":"","sources":["../../src/browser/fake-driver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,OAAO,EAGL,KAAK,aAAa,EAOlB,KAAK,eAAe,EAGrB,MAAM,aAAa,CAAC;AAErB,mFAAmF;AACnF,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,SAAS;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC3G;AAED,MAAM,WAAW,iBAAkB,SAAQ,aAAa;IACtD,0JAA0J;IAC1J,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC3C,kFAAkF;IAClF,kBAAkB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;IAC/G,iGAAiG;IACjG,WAAW,CACT,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE;QACP,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QAClC,QAAQ,CAAC,UAAU,CAAC,EAAE,eAAe,CAAC,YAAY,CAAC,CAAC;KACrD,GACA,IAAI,CAAC;IACR,qDAAqD;IACrD,iBAAiB,CACf,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE;QAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAC5H,IAAI,CAAC;IACR,8GAA8G;IAC9G,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,oHAAoH;IACpH,cAAc,IAAI,SAAS,MAAM,EAAE,CAAC;CACrC;AAeD,wBAAgB,uBAAuB,IAAI,iBAAiB,CAsJ3D"}
|