@descryy/mcp 0.2.0 → 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.
Files changed (160) hide show
  1. package/dist/bin/descry-mcp.js +6 -1
  2. package/dist/bin/descry-mcp.js.map +1 -1
  3. package/dist/browser/driver.d.ts +236 -0
  4. package/dist/browser/driver.d.ts.map +1 -0
  5. package/dist/browser/driver.js +70 -0
  6. package/dist/browser/driver.js.map +1 -0
  7. package/dist/browser/evidence.d.ts +47 -0
  8. package/dist/browser/evidence.d.ts.map +1 -0
  9. package/dist/browser/evidence.js +55 -0
  10. package/dist/browser/evidence.js.map +1 -0
  11. package/dist/browser/fake-driver.d.ts +58 -0
  12. package/dist/browser/fake-driver.d.ts.map +1 -0
  13. package/dist/browser/fake-driver.js +161 -0
  14. package/dist/browser/fake-driver.js.map +1 -0
  15. package/dist/browser/graph-write.d.ts +86 -0
  16. package/dist/browser/graph-write.d.ts.map +1 -0
  17. package/dist/browser/graph-write.js +135 -0
  18. package/dist/browser/graph-write.js.map +1 -0
  19. package/dist/browser/playwright-driver.d.ts +65 -0
  20. package/dist/browser/playwright-driver.d.ts.map +1 -0
  21. package/dist/browser/playwright-driver.js +359 -0
  22. package/dist/browser/playwright-driver.js.map +1 -0
  23. package/dist/browser/provider.d.ts +49 -0
  24. package/dist/browser/provider.d.ts.map +1 -0
  25. package/dist/browser/provider.js +28 -0
  26. package/dist/browser/provider.js.map +1 -0
  27. package/dist/browser/registry.d.ts +182 -0
  28. package/dist/browser/registry.d.ts.map +1 -0
  29. package/dist/browser/registry.js +215 -0
  30. package/dist/browser/registry.js.map +1 -0
  31. package/dist/browser/scenario-resolve.d.ts +62 -0
  32. package/dist/browser/scenario-resolve.d.ts.map +1 -0
  33. package/dist/browser/scenario-resolve.js +127 -0
  34. package/dist/browser/scenario-resolve.js.map +1 -0
  35. package/dist/browser/scenario-runner.d.ts +113 -0
  36. package/dist/browser/scenario-runner.d.ts.map +1 -0
  37. package/dist/browser/scenario-runner.js +315 -0
  38. package/dist/browser/scenario-runner.js.map +1 -0
  39. package/dist/browser/stack-parser.d.ts +43 -0
  40. package/dist/browser/stack-parser.d.ts.map +1 -0
  41. package/dist/browser/stack-parser.js +112 -0
  42. package/dist/browser/stack-parser.js.map +1 -0
  43. package/dist/browser/tool-support.d.ts +113 -0
  44. package/dist/browser/tool-support.d.ts.map +1 -0
  45. package/dist/browser/tool-support.js +181 -0
  46. package/dist/browser/tool-support.js.map +1 -0
  47. package/dist/index.d.ts +11 -0
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +10 -0
  50. package/dist/index.js.map +1 -1
  51. package/dist/render.d.ts +112 -10
  52. package/dist/render.d.ts.map +1 -1
  53. package/dist/render.js +79 -13
  54. package/dist/render.js.map +1 -1
  55. package/dist/scenarios/index.d.ts +4 -0
  56. package/dist/scenarios/index.d.ts.map +1 -0
  57. package/dist/scenarios/index.js +4 -0
  58. package/dist/scenarios/index.js.map +1 -0
  59. package/dist/scenarios/parse.d.ts +32 -0
  60. package/dist/scenarios/parse.d.ts.map +1 -0
  61. package/dist/scenarios/parse.js +199 -0
  62. package/dist/scenarios/parse.js.map +1 -0
  63. package/dist/scenarios/scenario.d.ts +115 -0
  64. package/dist/scenarios/scenario.d.ts.map +1 -0
  65. package/dist/scenarios/scenario.js +41 -0
  66. package/dist/scenarios/scenario.js.map +1 -0
  67. package/dist/scenarios/storage.d.ts +51 -0
  68. package/dist/scenarios/storage.d.ts.map +1 -0
  69. package/dist/scenarios/storage.js +93 -0
  70. package/dist/scenarios/storage.js.map +1 -0
  71. package/dist/server.d.ts.map +1 -1
  72. package/dist/server.js +6 -3
  73. package/dist/server.js.map +1 -1
  74. package/dist/session.d.ts +68 -0
  75. package/dist/session.d.ts.map +1 -1
  76. package/dist/session.js +89 -0
  77. package/dist/session.js.map +1 -1
  78. package/dist/tools/analyze.d.ts +41 -1
  79. package/dist/tools/analyze.d.ts.map +1 -1
  80. package/dist/tools/analyze.js +81 -8
  81. package/dist/tools/analyze.js.map +1 -1
  82. package/dist/tools/browser-click.d.ts +36 -0
  83. package/dist/tools/browser-click.d.ts.map +1 -0
  84. package/dist/tools/browser-click.js +117 -0
  85. package/dist/tools/browser-click.js.map +1 -0
  86. package/dist/tools/browser-close-session.d.ts +24 -0
  87. package/dist/tools/browser-close-session.d.ts.map +1 -0
  88. package/dist/tools/browser-close-session.js +63 -0
  89. package/dist/tools/browser-close-session.js.map +1 -0
  90. package/dist/tools/browser-fill.d.ts +49 -0
  91. package/dist/tools/browser-fill.d.ts.map +1 -0
  92. package/dist/tools/browser-fill.js +138 -0
  93. package/dist/tools/browser-fill.js.map +1 -0
  94. package/dist/tools/browser-navigate.d.ts +32 -0
  95. package/dist/tools/browser-navigate.d.ts.map +1 -0
  96. package/dist/tools/browser-navigate.js +103 -0
  97. package/dist/tools/browser-navigate.js.map +1 -0
  98. package/dist/tools/browser-run-scenario.d.ts +54 -0
  99. package/dist/tools/browser-run-scenario.d.ts.map +1 -0
  100. package/dist/tools/browser-run-scenario.js +228 -0
  101. package/dist/tools/browser-run-scenario.js.map +1 -0
  102. package/dist/tools/browser-save-scenario.d.ts +44 -0
  103. package/dist/tools/browser-save-scenario.d.ts.map +1 -0
  104. package/dist/tools/browser-save-scenario.js +298 -0
  105. package/dist/tools/browser-save-scenario.js.map +1 -0
  106. package/dist/tools/browser-snapshot.d.ts +60 -0
  107. package/dist/tools/browser-snapshot.d.ts.map +1 -0
  108. package/dist/tools/browser-snapshot.js +139 -0
  109. package/dist/tools/browser-snapshot.js.map +1 -0
  110. package/dist/tools/browser-start-session.d.ts +43 -0
  111. package/dist/tools/browser-start-session.d.ts.map +1 -0
  112. package/dist/tools/browser-start-session.js +272 -0
  113. package/dist/tools/browser-start-session.js.map +1 -0
  114. package/dist/tools/browser-type.d.ts +48 -0
  115. package/dist/tools/browser-type.d.ts.map +1 -0
  116. package/dist/tools/browser-type.js +136 -0
  117. package/dist/tools/browser-type.js.map +1 -0
  118. package/dist/tools/contracts.d.ts +15 -0
  119. package/dist/tools/contracts.d.ts.map +1 -1
  120. package/dist/tools/contracts.js +14 -3
  121. package/dist/tools/contracts.js.map +1 -1
  122. package/dist/tools/git-diff.d.ts.map +1 -1
  123. package/dist/tools/git-diff.js +85 -6
  124. package/dist/tools/git-diff.js.map +1 -1
  125. package/dist/tools/impact.d.ts +9 -0
  126. package/dist/tools/impact.d.ts.map +1 -1
  127. package/dist/tools/impact.js +3 -3
  128. package/dist/tools/impact.js.map +1 -1
  129. package/dist/tools/index.d.ts +9 -0
  130. package/dist/tools/index.d.ts.map +1 -1
  131. package/dist/tools/index.js +27 -0
  132. package/dist/tools/index.js.map +1 -1
  133. package/dist/tools/kit.d.ts +10 -1
  134. package/dist/tools/kit.d.ts.map +1 -1
  135. package/dist/tools/kit.js +2 -0
  136. package/dist/tools/kit.js.map +1 -1
  137. package/dist/tools/observe-runtime.d.ts +113 -19
  138. package/dist/tools/observe-runtime.d.ts.map +1 -1
  139. package/dist/tools/observe-runtime.js +293 -52
  140. package/dist/tools/observe-runtime.js.map +1 -1
  141. package/dist/tools/observe-tests.d.ts +125 -0
  142. package/dist/tools/observe-tests.d.ts.map +1 -0
  143. package/dist/tools/observe-tests.js +313 -0
  144. package/dist/tools/observe-tests.js.map +1 -0
  145. package/dist/tools/pr-analysis.d.ts +11 -0
  146. package/dist/tools/pr-analysis.d.ts.map +1 -1
  147. package/dist/tools/pr-analysis.js +3 -3
  148. package/dist/tools/pr-analysis.js.map +1 -1
  149. package/dist/tools/pre-push.d.ts +77 -0
  150. package/dist/tools/pre-push.d.ts.map +1 -0
  151. package/dist/tools/pre-push.js +250 -0
  152. package/dist/tools/pre-push.js.map +1 -0
  153. package/dist/tools/questions.d.ts.map +1 -1
  154. package/dist/tools/questions.js +41 -16
  155. package/dist/tools/questions.js.map +1 -1
  156. package/dist/tools/verification-status.d.ts +22 -0
  157. package/dist/tools/verification-status.d.ts.map +1 -1
  158. package/dist/tools/verification-status.js +51 -5
  159. package/dist/tools/verification-status.js.map +1 -1
  160. package/package.json +14 -13
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-snapshot.d.ts","sourceRoot":"","sources":["../../src/tools/browser-snapshot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAEpE,OAAO,EAAkB,KAAK,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACnF,OAAO,EAAqD,KAAK,cAAc,EAAE,MAAM,UAAU,CAAC;AAClG,OAAO,KAAK,EAAE,QAAQ,EAAc,MAAM,cAAc,CAAC;AACzD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5D,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,SAAS,eAAe,EAAE,CAAC;IAC9C;;;OAGG;IACH,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,qBAAqB,CAAC;IACzC,6IAA6I;IAC7I,QAAQ,CAAC,KAAK,EAAE,iBAAiB,CAAC;CACnC;AAED;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,eAAe,CAAC;AA6ElD;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,GAAG,QAAQ,CAAC,mBAAmB,CAAC,CAwBzG;AAED,eAAO,MAAM,mBAAmB,EAAE,cAajC,CAAC"}
@@ -0,0 +1,139 @@
1
+ /**
2
+ * `browser_snapshot` — what is on the page, as refs an action can take.
3
+ *
4
+ * ## Why this tool implements `fitToBudget` from its first commit
5
+ *
6
+ * A real accessibility tree is tens of thousands of bytes. `get_git_diff`
7
+ * shipped without an aggregate reply ceiling, returned 228,860 characters on
8
+ * an ordinary branch diff, and was rejected by the host before the caller saw
9
+ * any of it; the fix that followed bounded patch text and still failed at
10
+ * 84,516, because a reply is not only patch text. That lesson was paid for
11
+ * twice, and a brand-new tool whose payload grows with the user's application
12
+ * is precisely where it would be paid for a third time.
13
+ *
14
+ * So the budget hook is here from day one, and the test asserts the
15
+ * serialized `CallToolResult` rather than asserting that a cap ran.
16
+ *
17
+ * ## `totalElements` is never the capped number
18
+ *
19
+ * A snapshot that quietly returned the first forty elements would teach a
20
+ * calling agent that the page has forty elements. It would then conclude the
21
+ * button it needs is absent, which is a wrong answer produced by a correct
22
+ * tool. So the uncapped count is always present and always the real one, and
23
+ * a shortened reply says so in a note.
24
+ */
25
+ import { browserAnswer, observeAndCorrelate, useSession } from "../browser/tool-support.js";
26
+ import { NO_GRAPH_WRITE } from "../browser/graph-write.js";
27
+ import { optionalInteger, requiredString } from "./kit.js";
28
+ const SCHEMA = {
29
+ type: "object",
30
+ properties: {
31
+ sessionId: {
32
+ type: "string",
33
+ description: "REQUIRED. The id returned by browser_start_session.",
34
+ },
35
+ startAt: {
36
+ type: "integer",
37
+ minimum: 0,
38
+ description: "Skip this many elements before listing. Use it to page through a large page: compare the number " +
39
+ "of elements you received against totalElements, which is always the real count, and ask again " +
40
+ "with startAt set past what you have seen.",
41
+ },
42
+ limit: {
43
+ type: "integer",
44
+ minimum: 1,
45
+ description: "At most this many elements. A reply too large for the host is shortened further regardless, and says so.",
46
+ },
47
+ },
48
+ required: ["sessionId"],
49
+ additionalProperties: false,
50
+ };
51
+ async function run(args, ctx) {
52
+ const sessionId = requiredString(args, "sessionId");
53
+ const startAt = optionalInteger(args, "startAt", 0) ?? 0;
54
+ const limit = optionalInteger(args, "limit", 1);
55
+ const found = await useSession(ctx.session.browserSessions(), sessionId);
56
+ if (!found.ok) {
57
+ return browserAnswer({
58
+ ctx,
59
+ state: found.dead.state,
60
+ headline: found.dead.headline,
61
+ notes: found.dead.notes,
62
+ data: { sessionId: "", url: "", title: "", elements: [], totalElements: 0, evidence: found.dead.evidence, graph: NO_GRAPH_WRITE },
63
+ });
64
+ }
65
+ const { entry } = found;
66
+ ctx.progress("Reading the page");
67
+ const snapshot = await entry.page.snapshot();
68
+ const observed = await observeAndCorrelate(ctx, entry);
69
+ const evidence = observed.evidence;
70
+ const windowed = snapshot.elements.slice(startAt, limit === undefined ? undefined : startAt + limit);
71
+ const notes = [...observed.notes];
72
+ if (windowed.length < snapshot.totalElements) {
73
+ notes.push(`Showing ${windowed.length} of ${snapshot.totalElements} elements, from index ${startAt}. ` +
74
+ "totalElements is always the real count — ask again with startAt past what you have seen.");
75
+ }
76
+ const data = {
77
+ sessionId: entry.sessionId,
78
+ url: snapshot.url,
79
+ title: snapshot.title,
80
+ elements: windowed,
81
+ totalElements: snapshot.totalElements,
82
+ evidence,
83
+ graph: observed.graph,
84
+ };
85
+ return browserAnswer({
86
+ ctx,
87
+ headline: `${snapshot.url} — ${windowed.length} of ${snapshot.totalElements} elements.`,
88
+ notes,
89
+ data,
90
+ fitToBudget: (budgetBytes) => fitSnapshot(data, budgetBytes),
91
+ });
92
+ }
93
+ /**
94
+ * Shrink by dropping elements from the end of the window, never by dropping
95
+ * the count or the evidence.
96
+ *
97
+ * Evidence stays because it is the part a caller cannot re-request by paging —
98
+ * the observations were drained when this reply was built, and a second
99
+ * snapshot would return a different set. Elements can always be asked for
100
+ * again with `startAt`, so they are what gives way.
101
+ */
102
+ export function fitSnapshot(data, budgetBytes) {
103
+ const fits = (elements) => Buffer.byteLength(JSON.stringify({ ...data, elements }), "utf8") <= budgetBytes;
104
+ if (fits(data.elements))
105
+ return { data, notes: [] };
106
+ let low = 0;
107
+ let high = data.elements.length;
108
+ while (low < high) {
109
+ const mid = Math.ceil((low + high) / 2);
110
+ if (fits(data.elements.slice(0, mid)))
111
+ low = mid;
112
+ else
113
+ high = mid - 1;
114
+ }
115
+ const kept = data.elements.slice(0, low);
116
+ return {
117
+ data: { ...data, elements: kept },
118
+ notes: [
119
+ `The page's elements did not fit in one reply, so ${kept.length} of ${data.totalElements} are included. ` +
120
+ `totalElements is the real count, not the number shown — ask again with startAt set to ${kept.length} ` +
121
+ "for the next batch.",
122
+ ],
123
+ truncatedDetail: { shown: kept.length, total: data.totalElements, more: null },
124
+ };
125
+ }
126
+ export const browserSnapshotTool = {
127
+ name: "browser_snapshot",
128
+ title: "Read the current page",
129
+ description: "Return the elements on the page an open browser session is showing, each with a ref the click, type " +
130
+ "and fill tools take. Also returns anything the page produced since your last call — console errors and " +
131
+ "failed requests, raw and untriaged. totalElements is always the page's real element count, so a short " +
132
+ "list means the rest did not fit rather than that the page is small.",
133
+ class: "stateful-read",
134
+ tier: "evidence",
135
+ version: "1.0.0",
136
+ inputSchema: SCHEMA,
137
+ run,
138
+ };
139
+ //# sourceMappingURL=browser-snapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-snapshot.js","sourceRoot":"","sources":["../../src/tools/browser-snapshot.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * `browser_start_session` — open a real browser against the developer's app.
3
+ *
4
+ * ## Why this one is the gate
5
+ *
6
+ * `DEC-380` puts consent here and nowhere
7
+ * else. This is the call where a target URL is named, so it is the only call
8
+ * where the fact a developer actually approves — *Descry may drive a browser
9
+ * against this application* — can be stated. A per-click confirmation would
10
+ * describe "click ref-14", which is a string the caller supplied one call
11
+ * earlier and can neither evaluate nor be surprised by, and it would train
12
+ * callers to confirm reflexively.
13
+ *
14
+ * The grant is bound to this URL's **origin**. `browser_navigate` refuses to
15
+ * leave it. Without that bound, "drive my local app" would silently become
16
+ * "drive anything".
17
+ *
18
+ * ## Class
19
+ *
20
+ * `action`, unambiguously: this launches a process and points it at a running
21
+ * application. It is the only browser tool that mints a token; the verbs it
22
+ * consents for redeem nothing, because the session they run in has already
23
+ * been confirmed.
24
+ */
25
+ import type { BrowserEvidenceReport } from "../browser/evidence.ts";
26
+ import { type BrowserGraphWrite } from "../browser/graph-write.ts";
27
+ import { type ToolDefinition } from "./kit.ts";
28
+ export interface BrowserStartSessionData {
29
+ /** Hand this to every other browser tool. Valid on this connection only. */
30
+ readonly sessionId: string;
31
+ readonly url: string;
32
+ readonly title: string;
33
+ /** The origin this session's consent covers. Navigation outside it refuses. */
34
+ readonly consentedOrigin: string;
35
+ /** The safety level this session runs under, or null when no profile was given. */
36
+ readonly safetyLevel: "readOnly" | "write" | "destructiveWithApproval" | null;
37
+ /** How many elements the landing page has, before any reply budget applies. */
38
+ readonly totalElements: number;
39
+ readonly evidence: BrowserEvidenceReport;
40
+ readonly graph: BrowserGraphWrite;
41
+ }
42
+ export declare const browserStartSessionTool: ToolDefinition;
43
+ //# sourceMappingURL=browser-start-session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-start-session.d.ts","sourceRoot":"","sources":["../../src/tools/browser-start-session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAEpE,OAAO,EAAkB,KAAK,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAOnF,OAAO,EAAmG,KAAK,cAAc,EAAE,MAAM,UAAU,CAAC;AAGhJ,MAAM,WAAW,uBAAuB;IACtC,4EAA4E;IAC5E,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,+EAA+E;IAC/E,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,mFAAmF;IACnF,QAAQ,CAAC,WAAW,EAAE,UAAU,GAAG,OAAO,GAAG,yBAAyB,GAAG,IAAI,CAAC;IAC9E,+EAA+E;IAC/E,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,qBAAqB,CAAC;IACzC,QAAQ,CAAC,KAAK,EAAE,iBAAiB,CAAC;CACnC;AAoPD,eAAO,MAAM,uBAAuB,EAAE,cAsBrC,CAAC"}
@@ -0,0 +1,272 @@
1
+ /**
2
+ * `browser_start_session` — open a real browser against the developer's app.
3
+ *
4
+ * ## Why this one is the gate
5
+ *
6
+ * `DEC-380` puts consent here and nowhere
7
+ * else. This is the call where a target URL is named, so it is the only call
8
+ * where the fact a developer actually approves — *Descry may drive a browser
9
+ * against this application* — can be stated. A per-click confirmation would
10
+ * describe "click ref-14", which is a string the caller supplied one call
11
+ * earlier and can neither evaluate nor be surprised by, and it would train
12
+ * callers to confirm reflexively.
13
+ *
14
+ * The grant is bound to this URL's **origin**. `browser_navigate` refuses to
15
+ * leave it. Without that bound, "drive my local app" would silently become
16
+ * "drive anything".
17
+ *
18
+ * ## Class
19
+ *
20
+ * `action`, unambiguously: this launches a process and points it at a running
21
+ * application. It is the only browser tool that mints a token; the verbs it
22
+ * consents for redeem nothing, because the session they run in has already
23
+ * been confirmed.
24
+ */
25
+ import { browserAnswer, emptyEvidence, observeAndCorrelate } from "../browser/tool-support.js";
26
+ import { NO_GRAPH_WRITE } from "../browser/graph-write.js";
27
+ import { isAbsolute, join } from "node:path";
28
+ import { loadStackParser, StackParserLoadError } from "../browser/stack-parser.js";
29
+ import { optionalBoolean, optionalEnum, optionalString, requiredString, ToolInputError } from "./kit.js";
30
+ const SCHEMA = {
31
+ type: "object",
32
+ properties: {
33
+ targetUrl: {
34
+ type: "string",
35
+ description: "REQUIRED. The URL to open, including scheme and port — \"http://localhost:3000/invoices\". " +
36
+ "This is also what consent is granted for: the browser may be driven anywhere on this URL's " +
37
+ "origin for the life of the session, and navigating off it refuses rather than asking again.",
38
+ },
39
+ headless: {
40
+ type: "boolean",
41
+ description: "Run without a visible window. Defaults to true; pass false to watch it happen.",
42
+ },
43
+ stackParser: {
44
+ type: "object",
45
+ description: "The module that can parse this application's stack traces, named the way observe_runtime names a " +
46
+ "runtime adapter. Without one, requests are still observed and the endpoints they reached are still " +
47
+ "named, but NO frontend→backend caller edge is written — a parsed call site is what the confirmation " +
48
+ "needs, and there is no way to guess one. The reply says so rather than reporting a run that found " +
49
+ "nothing.",
50
+ properties: {
51
+ module: { type: "string", description: "Module specifier to import, e.g. a runtime adapter package for the language your frontend is written in." },
52
+ 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." },
53
+ },
54
+ required: ["module"],
55
+ additionalProperties: false,
56
+ },
57
+ documentRoot: {
58
+ type: "string",
59
+ description: "The directory on disk that the target URL's origin serves files from, if it is not the repository " +
60
+ "root. Absolute, or relative to the repository. THIS IS THE ONE THAT SILENTLY BREAKS THE ARROW: a " +
61
+ "server that serves scripts out of \"public/\" makes public/ the document root while the repo root is " +
62
+ "one level above it, and getting it wrong resolves a script URL to a path that does not exist, which " +
63
+ "degrades the call-site stack to nothing and produces a run that looks clean and confirmed no edges. " +
64
+ "Defaults to the repository root.",
65
+ },
66
+ environment: {
67
+ type: "object",
68
+ description: "The environment profile this session runs against, if you have one. Its safetyLevel governs " +
69
+ "whether the session may change the application: \"readOnly\" refuses browser_click, browser_type " +
70
+ "and browser_fill while still permitting browser_navigate and browser_snapshot. Declared once here " +
71
+ "rather than per call, and it is the same profile observe_runtime takes — a browser run and a " +
72
+ "runtime run must not hold two different opinions about the same environment (DEC-270). Omit it and " +
73
+ "the session's own consent is the only authorization, which still means this call had to be confirmed.",
74
+ properties: {
75
+ name: { type: "string", description: "The profile's name, free-form. Named back to you in any refusal it causes." },
76
+ safetyLevel: {
77
+ type: "string",
78
+ enum: ["readOnly", "write", "destructiveWithApproval"],
79
+ description: "\"readOnly\" refuses every action that could change the application, whatever the profile is " +
80
+ "called — a profile named \"local\" with safetyLevel \"readOnly\" is read-only too.",
81
+ },
82
+ },
83
+ required: ["name", "safetyLevel"],
84
+ additionalProperties: true,
85
+ },
86
+ confirmToken: {
87
+ type: "string",
88
+ description: "The token returned by a previous call. Starting a browser session takes two calls: the first " +
89
+ "returns a token and launches nothing, the second redeems it. A token is single-use, expires, " +
90
+ "and is only valid for this tool. Consent is granted once here — the click, type and fill tools " +
91
+ "need no token of their own.",
92
+ },
93
+ },
94
+ required: ["targetUrl"],
95
+ additionalProperties: false,
96
+ };
97
+ const SAFETY_LEVELS = ["readOnly", "write", "destructiveWithApproval"];
98
+ /**
99
+ * Read the profile, do not re-derive it.
100
+ *
101
+ * Only the two fields this surface actually consults are read; everything
102
+ * else a caller sends is carried by the profile it came from and is none of
103
+ * this tool's business. `additionalProperties: true` on the schema is what
104
+ * lets a caller pass the same object it passes `observe_runtime` rather than
105
+ * trimming a second copy of it.
106
+ */
107
+ function readProfile(args) {
108
+ const raw = args["environment"];
109
+ if (raw === undefined || raw === null)
110
+ return null;
111
+ if (typeof raw !== "object" || Array.isArray(raw))
112
+ throw new ToolInputError('"environment" must be an object');
113
+ const fields = raw;
114
+ const name = requiredString(fields, "name");
115
+ const safetyLevel = optionalEnum(fields, "safetyLevel", SAFETY_LEVELS);
116
+ if (safetyLevel === undefined) {
117
+ throw new ToolInputError('"environment.safetyLevel" is required when an environment is given — a profile with no declared ' +
118
+ "safety level would be read as permitting everything, which is the one reading it must never get by default");
119
+ }
120
+ return { name, safetyLevel };
121
+ }
122
+ function readStackParserSpec(args) {
123
+ const raw = args["stackParser"];
124
+ if (raw === undefined || raw === null)
125
+ return null;
126
+ if (typeof raw !== "object" || Array.isArray(raw))
127
+ throw new ToolInputError('"stackParser" must be an object');
128
+ const fields = raw;
129
+ const module = requiredString(fields, "module");
130
+ const named = optionalString(fields, "export");
131
+ return named === undefined ? { module } : { module, export: named };
132
+ }
133
+ function parseTarget(args) {
134
+ const raw = requiredString(args, "targetUrl");
135
+ try {
136
+ return new URL(raw);
137
+ }
138
+ catch {
139
+ throw new ToolInputError(`"targetUrl" must be an absolute URL including scheme — got "${raw}". A bare host or path cannot be ` +
140
+ "opened, and cannot be turned into the origin this session's consent is bound to.");
141
+ }
142
+ }
143
+ async function run(args, ctx) {
144
+ const target = parseTarget(args);
145
+ const headless = optionalBoolean(args, "headless") ?? true;
146
+ const profile = readProfile(args);
147
+ const parserSpec = readStackParserSpec(args);
148
+ const documentRoot = optionalString(args, "documentRoot");
149
+ const backend = ctx.session.browserBackend();
150
+ if (!backend.available) {
151
+ return browserAnswer({
152
+ ctx,
153
+ state: "refused",
154
+ headline: "This build cannot open a browser.",
155
+ notes: [backend.reason, `Remedy: ${backend.remedy}`],
156
+ data: { sessionId: "", url: target.href, title: "", consentedOrigin: target.origin, safetyLevel: null, totalElements: 0, evidence: emptyEvidence(), graph: NO_GRAPH_WRITE },
157
+ });
158
+ }
159
+ // The parser is loaded before anything launches. A parser that will not
160
+ // import is a refusal the caller can fix, and finding that out after a
161
+ // browser is open would mean either tearing it down again or running a
162
+ // session that quietly cannot write the edge it was opened for.
163
+ let parser;
164
+ try {
165
+ parser = parserSpec === null ? undefined : await loadStackParser(parserSpec);
166
+ }
167
+ catch (error) {
168
+ if (!(error instanceof StackParserLoadError))
169
+ throw error;
170
+ return browserAnswer({
171
+ ctx,
172
+ state: "refused",
173
+ headline: `Could not load the stack-trace parser "${error.specifier}".`,
174
+ notes: [error.message],
175
+ data: { sessionId: "", url: target.href, title: "", consentedOrigin: target.origin, safetyLevel: null, totalElements: 0, evidence: emptyEvidence(), graph: NO_GRAPH_WRITE },
176
+ });
177
+ }
178
+ // Trap A, closed here rather than left to a caller to get right silently.
179
+ // The origin being driven maps to the directory that actually serves its
180
+ // scripts; `documentRoot` overrides the repository root for exactly the
181
+ // `public/` case the schema describes.
182
+ const servedFrom = documentRoot === undefined
183
+ ? ctx.session.repoPath
184
+ : isAbsolute(documentRoot)
185
+ ? documentRoot
186
+ : join(ctx.session.repoPath, documentRoot);
187
+ const resolveSourceRoot = (origin) => origin === target.origin
188
+ ? { found: true, root: { serviceName: ctx.session.config.repo, declaredCwd: servedFrom } }
189
+ : { found: false, refusal: "noProcessOnPort", message: `${origin} is not the origin this session was opened against` };
190
+ ctx.progress(`Opening a browser at ${target.href}`);
191
+ const driver = await backend.createDriver({
192
+ ...(parser === undefined ? {} : { stackParser: parser }),
193
+ resolveSourceRoot,
194
+ service: ctx.session.config.repo,
195
+ });
196
+ const opened = await ctx.session.browserSessions().open(driver, { targetUrl: target.href, headless, profile });
197
+ if (!opened.opened) {
198
+ const notes = opened.kind === "atCapacity"
199
+ ? [opened.reason]
200
+ : // The remedy travels verbatim. A refusal that says "could not launch"
201
+ // and stops is one the developer has to go and research.
202
+ [opened.message, `Remedy: ${opened.remedy}`, `Expected the browser at ${opened.expectedExecutablePath}.`];
203
+ return browserAnswer({
204
+ ctx,
205
+ state: "refused",
206
+ headline: opened.kind === "atCapacity" ? "Too many browser sessions are already open." : "No browser is installed.",
207
+ notes,
208
+ data: { sessionId: "", url: target.href, title: "", consentedOrigin: target.origin, safetyLevel: profile?.safetyLevel ?? null, totalElements: 0, evidence: emptyEvidence(), graph: NO_GRAPH_WRITE },
209
+ });
210
+ }
211
+ const { entry } = opened;
212
+ const snapshot = await entry.page.snapshot();
213
+ const observed = await observeAndCorrelate(ctx, entry);
214
+ const evidence = observed.evidence;
215
+ return browserAnswer({
216
+ ctx,
217
+ headline: `Browser session ${entry.sessionId} open at ${snapshot.url} (${snapshot.totalElements} elements).`,
218
+ notes: [
219
+ `Consent covers ${entry.consentedOrigin} for the life of this session — click, type and fill need no ` +
220
+ "further confirmation, and navigating to another origin will refuse. The session is torn down after " +
221
+ "five idle minutes, when the client disconnects, or when browser_close_session is called.",
222
+ ...(parserSpec === null
223
+ ? [
224
+ "No stackParser was named, so requests will be observed and the endpoints they reach will be " +
225
+ "named, but no frontend→backend caller edge can be written from this session. That is a gap " +
226
+ "in what this run can confirm, not a finding about your application.",
227
+ ]
228
+ : []),
229
+ ...(entry.profile === null
230
+ ? []
231
+ : [
232
+ `Running under environment profile "${entry.profile.name}" (safetyLevel ` +
233
+ `"${entry.profile.safetyLevel}").` +
234
+ (entry.profile.safetyLevel === "readOnly"
235
+ ? " Clicking, typing and filling will be refused; navigate and snapshot remain available."
236
+ : ""),
237
+ ]),
238
+ ...observed.notes,
239
+ ],
240
+ data: {
241
+ sessionId: entry.sessionId,
242
+ url: snapshot.url,
243
+ title: snapshot.title,
244
+ consentedOrigin: entry.consentedOrigin,
245
+ safetyLevel: entry.profile?.safetyLevel ?? null,
246
+ totalElements: snapshot.totalElements,
247
+ evidence,
248
+ graph: observed.graph,
249
+ },
250
+ });
251
+ }
252
+ export const browserStartSessionTool = {
253
+ name: "browser_start_session",
254
+ title: "Open a browser session",
255
+ description: "Open a real browser at a URL in your running application and return a session id the other browser " +
256
+ "tools take. This is where consent is granted: confirming it allows Descry to drive a browser anywhere " +
257
+ "on that URL's origin until the session ends, so the click, type and fill tools do not ask again. " +
258
+ "Reports what the page produced — console errors, failed requests — raw and untriaged; deciding which " +
259
+ "of them matter is yours.",
260
+ class: "action",
261
+ tier: "evidence",
262
+ version: "1.0.0",
263
+ inputSchema: SCHEMA,
264
+ run,
265
+ describeAction(args) {
266
+ const target = parseTarget(args);
267
+ return (`Launch a browser and open ${target.href}. For as long as the session lives, Descry may navigate, ` +
268
+ `click, type and fill anywhere on ${target.origin} without asking again — including actions that ` +
269
+ "change data in that application. It may not leave that origin.");
270
+ },
271
+ };
272
+ //# sourceMappingURL=browser-start-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-start-session.js","sourceRoot":"","sources":["../../src/tools/browser-start-session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * `browser_type` — type into a field with real keystrokes.
3
+ *
4
+ * ## Consent, and why this tool asks for none
5
+ *
6
+ * `DEC-380` grants consent once, at
7
+ * `browser_start_session`, bound to that call's origin. So this tool declares
8
+ * `class: "action"` — it does change a running application, and pretending
9
+ * otherwise would be the lie — while its `describeAction` returns `undefined`,
10
+ * the existing "this particular call has nothing to confirm" path that
11
+ * `questions` uses when asked to read rather than write.
12
+ *
13
+ * The property that makes that safe rather than merely cheap: **a verb cannot
14
+ * mint consent for itself.** Called against a session with no consent record,
15
+ * it refuses. There is deliberately no path from a click to a token.
16
+ *
17
+ * ## A ref, never a selector
18
+ *
19
+ * The element is named by a ref from a snapshot the calling agent actually
20
+ * saw. A raw selector would let an agent act on an element it never looked
21
+ * at, and a ref from a superseded snapshot refuses rather than resolving
22
+ * against whatever now matches — that is the same mistake, arriving later.
23
+ */
24
+ /**
25
+ * ## Why this is not the same tool as `browser_fill`
26
+ *
27
+ * The visible difference is that this appends and `fill` replaces. The
28
+ * difference that decides which one is correct for a real page is that **this
29
+ * one fires key events and `fill` fires none.** A field that opens an
30
+ * autocomplete on keydown, validates per character, or debounces a search as
31
+ * you type sees nothing at all from a `fill`. An agent that reaches for
32
+ * `fill` on a search box gets a page that was never typed into — a wrong
33
+ * answer produced by entirely correct tool code, which is why the schema
34
+ * prose below says so rather than describing only the tidy half.
35
+ */
36
+ import type { BrowserEvidenceReport } from "../browser/evidence.ts";
37
+ import { type BrowserGraphWrite } from "../browser/graph-write.ts";
38
+ import { type ToolDefinition } from "./kit.ts";
39
+ export interface BrowserTypeData {
40
+ readonly sessionId: string;
41
+ readonly ref: string;
42
+ readonly url: string;
43
+ readonly evidence: BrowserEvidenceReport;
44
+ /** Graph nodes this action's own requests reached, and any R4 edges it witnessed. */
45
+ readonly graph: BrowserGraphWrite;
46
+ }
47
+ export declare const browserTypeTool: ToolDefinition;
48
+ //# sourceMappingURL=browser-type.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-type.d.ts","sourceRoot":"","sources":["../../src/tools/browser-type.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAEpE,OAAO,EAAkB,KAAK,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAEnF,OAAO,EAAoC,KAAK,cAAc,EAAE,MAAM,UAAU,CAAC;AAGjF,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,QAAQ,EAAE,qBAAqB,CAAC;IACzC,qFAAqF;IACrF,QAAQ,CAAC,KAAK,EAAE,iBAAiB,CAAC;CACnC;AAyFD,eAAO,MAAM,eAAe,EAAE,cAiB7B,CAAC"}