@descryy/mcp 0.5.0 → 0.7.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 (260) hide show
  1. package/dist/action-handshake.d.ts +8 -75
  2. package/dist/action-handshake.d.ts.map +1 -1
  3. package/dist/action-handshake.js +9 -79
  4. package/dist/action-handshake.js.map +1 -1
  5. package/dist/bin/descry-mcp.d.ts +4 -15
  6. package/dist/bin/descry-mcp.d.ts.map +1 -1
  7. package/dist/bin/descry-mcp.js +12 -42
  8. package/dist/bin/descry-mcp.js.map +1 -1
  9. package/dist/browser/driver.d.ts +62 -178
  10. package/dist/browser/driver.d.ts.map +1 -1
  11. package/dist/browser/driver.js +14 -46
  12. package/dist/browser/driver.js.map +1 -1
  13. package/dist/browser/evidence.d.ts +11 -35
  14. package/dist/browser/evidence.d.ts.map +1 -1
  15. package/dist/browser/evidence.js +25 -51
  16. package/dist/browser/evidence.js.map +1 -1
  17. package/dist/browser/fake-driver.d.ts +12 -16
  18. package/dist/browser/fake-driver.d.ts.map +1 -1
  19. package/dist/browser/fake-driver.js +24 -17
  20. package/dist/browser/fake-driver.js.map +1 -1
  21. package/dist/browser/graph-write.d.ts +4 -45
  22. package/dist/browser/graph-write.d.ts.map +1 -1
  23. package/dist/browser/graph-write.js +8 -53
  24. package/dist/browser/graph-write.js.map +1 -1
  25. package/dist/browser/playwright-driver.d.ts +17 -67
  26. package/dist/browser/playwright-driver.d.ts.map +1 -1
  27. package/dist/browser/playwright-driver.js +169 -166
  28. package/dist/browser/playwright-driver.js.map +1 -1
  29. package/dist/browser/provider.d.ts +5 -34
  30. package/dist/browser/provider.d.ts.map +1 -1
  31. package/dist/browser/provider.js +4 -24
  32. package/dist/browser/provider.js.map +1 -1
  33. package/dist/browser/registry.d.ts +26 -106
  34. package/dist/browser/registry.d.ts.map +1 -1
  35. package/dist/browser/registry.js +20 -77
  36. package/dist/browser/registry.js.map +1 -1
  37. package/dist/browser/scenario-resolve.d.ts +10 -44
  38. package/dist/browser/scenario-resolve.d.ts.map +1 -1
  39. package/dist/browser/scenario-resolve.js +10 -41
  40. package/dist/browser/scenario-resolve.js.map +1 -1
  41. package/dist/browser/scenario-runner.d.ts +12 -70
  42. package/dist/browser/scenario-runner.d.ts.map +1 -1
  43. package/dist/browser/scenario-runner.js +33 -91
  44. package/dist/browser/scenario-runner.js.map +1 -1
  45. package/dist/browser/stack-parser.d.ts +4 -28
  46. package/dist/browser/stack-parser.d.ts.map +1 -1
  47. package/dist/browser/stack-parser.js +12 -39
  48. package/dist/browser/stack-parser.js.map +1 -1
  49. package/dist/browser/tool-support.d.ts +20 -67
  50. package/dist/browser/tool-support.d.ts.map +1 -1
  51. package/dist/browser/tool-support.js +22 -66
  52. package/dist/browser/tool-support.js.map +1 -1
  53. package/dist/browser/url-scheme.d.ts +14 -0
  54. package/dist/browser/url-scheme.d.ts.map +1 -0
  55. package/dist/browser/url-scheme.js +38 -0
  56. package/dist/browser/url-scheme.js.map +1 -0
  57. package/dist/cancellation.d.ts +11 -46
  58. package/dist/cancellation.d.ts.map +1 -1
  59. package/dist/cancellation.js +11 -46
  60. package/dist/cancellation.js.map +1 -1
  61. package/dist/capped.d.ts +17 -0
  62. package/dist/capped.d.ts.map +1 -0
  63. package/dist/capped.js +15 -0
  64. package/dist/capped.js.map +1 -0
  65. package/dist/disclosure-ledger.d.ts +6 -30
  66. package/dist/disclosure-ledger.d.ts.map +1 -1
  67. package/dist/disclosure-ledger.js +4 -26
  68. package/dist/disclosure-ledger.js.map +1 -1
  69. package/dist/index.d.ts +10 -26
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js +7 -17
  72. package/dist/index.js.map +1 -1
  73. package/dist/module-trust.d.ts +24 -0
  74. package/dist/module-trust.d.ts.map +1 -0
  75. package/dist/module-trust.js +60 -0
  76. package/dist/module-trust.js.map +1 -0
  77. package/dist/path-confinement.d.ts +31 -0
  78. package/dist/path-confinement.d.ts.map +1 -0
  79. package/dist/path-confinement.js +44 -0
  80. package/dist/path-confinement.js.map +1 -0
  81. package/dist/protocol.d.ts +10 -53
  82. package/dist/protocol.d.ts.map +1 -1
  83. package/dist/protocol.js +14 -60
  84. package/dist/protocol.js.map +1 -1
  85. package/dist/registry.d.ts +10 -58
  86. package/dist/registry.d.ts.map +1 -1
  87. package/dist/registry.js +38 -90
  88. package/dist/registry.js.map +1 -1
  89. package/dist/render.d.ts +79 -11
  90. package/dist/render.d.ts.map +1 -1
  91. package/dist/render.js +126 -14
  92. package/dist/render.js.map +1 -1
  93. package/dist/runtime-registry.d.ts +8 -49
  94. package/dist/runtime-registry.d.ts.map +1 -1
  95. package/dist/runtime-registry.js +72 -63
  96. package/dist/runtime-registry.js.map +1 -1
  97. package/dist/scenarios/index.d.ts +1 -1
  98. package/dist/scenarios/index.d.ts.map +1 -1
  99. package/dist/scenarios/index.js +1 -1
  100. package/dist/scenarios/index.js.map +1 -1
  101. package/dist/scenarios/parse.d.ts +4 -18
  102. package/dist/scenarios/parse.d.ts.map +1 -1
  103. package/dist/scenarios/parse.js +14 -34
  104. package/dist/scenarios/parse.js.map +1 -1
  105. package/dist/scenarios/scenario.d.ts +18 -74
  106. package/dist/scenarios/scenario.d.ts.map +1 -1
  107. package/dist/scenarios/scenario.js +7 -34
  108. package/dist/scenarios/scenario.js.map +1 -1
  109. package/dist/scenarios/storage.d.ts +11 -41
  110. package/dist/scenarios/storage.d.ts.map +1 -1
  111. package/dist/scenarios/storage.js +57 -47
  112. package/dist/scenarios/storage.js.map +1 -1
  113. package/dist/server.d.ts.map +1 -1
  114. package/dist/server.js +55 -13
  115. package/dist/server.js.map +1 -1
  116. package/dist/session.d.ts +69 -239
  117. package/dist/session.d.ts.map +1 -1
  118. package/dist/session.js +76 -231
  119. package/dist/session.js.map +1 -1
  120. package/dist/tools/analyze.d.ts +27 -101
  121. package/dist/tools/analyze.d.ts.map +1 -1
  122. package/dist/tools/analyze.js +58 -148
  123. package/dist/tools/analyze.js.map +1 -1
  124. package/dist/tools/browser-click.d.ts +3 -21
  125. package/dist/tools/browser-click.d.ts.map +1 -1
  126. package/dist/tools/browser-click.js +10 -31
  127. package/dist/tools/browser-click.js.map +1 -1
  128. package/dist/tools/browser-close-session.d.ts +4 -13
  129. package/dist/tools/browser-close-session.d.ts.map +1 -1
  130. package/dist/tools/browser-close-session.js +4 -13
  131. package/dist/tools/browser-close-session.js.map +1 -1
  132. package/dist/tools/browser-fill.d.ts +5 -36
  133. package/dist/tools/browser-fill.d.ts.map +1 -1
  134. package/dist/tools/browser-fill.js +9 -44
  135. package/dist/tools/browser-fill.js.map +1 -1
  136. package/dist/tools/browser-navigate.d.ts +6 -27
  137. package/dist/tools/browser-navigate.d.ts.map +1 -1
  138. package/dist/tools/browser-navigate.js +6 -23
  139. package/dist/tools/browser-navigate.js.map +1 -1
  140. package/dist/tools/browser-run-scenario.d.ts +5 -31
  141. package/dist/tools/browser-run-scenario.d.ts.map +1 -1
  142. package/dist/tools/browser-run-scenario.js +10 -46
  143. package/dist/tools/browser-run-scenario.js.map +1 -1
  144. package/dist/tools/browser-save-scenario.d.ts +3 -28
  145. package/dist/tools/browser-save-scenario.d.ts.map +1 -1
  146. package/dist/tools/browser-save-scenario.js +102 -55
  147. package/dist/tools/browser-save-scenario.js.map +1 -1
  148. package/dist/tools/browser-snapshot.d.ts +6 -39
  149. package/dist/tools/browser-snapshot.d.ts.map +1 -1
  150. package/dist/tools/browser-snapshot.js +4 -31
  151. package/dist/tools/browser-snapshot.js.map +1 -1
  152. package/dist/tools/browser-start-session.d.ts +4 -23
  153. package/dist/tools/browser-start-session.d.ts.map +1 -1
  154. package/dist/tools/browser-start-session.js +38 -51
  155. package/dist/tools/browser-start-session.js.map +1 -1
  156. package/dist/tools/browser-type.d.ts +5 -35
  157. package/dist/tools/browser-type.d.ts.map +1 -1
  158. package/dist/tools/browser-type.js +10 -45
  159. package/dist/tools/browser-type.js.map +1 -1
  160. package/dist/tools/contracts.d.ts +17 -63
  161. package/dist/tools/contracts.d.ts.map +1 -1
  162. package/dist/tools/contracts.js +91 -47
  163. package/dist/tools/contracts.js.map +1 -1
  164. package/dist/tools/cross-pr.d.ts +56 -15
  165. package/dist/tools/cross-pr.d.ts.map +1 -1
  166. package/dist/tools/cross-pr.js +141 -38
  167. package/dist/tools/cross-pr.js.map +1 -1
  168. package/dist/tools/git-diff.d.ts +18 -2
  169. package/dist/tools/git-diff.d.ts.map +1 -1
  170. package/dist/tools/git-diff.js +143 -23
  171. package/dist/tools/git-diff.js.map +1 -1
  172. package/dist/tools/git-history.d.ts +5 -16
  173. package/dist/tools/git-history.d.ts.map +1 -1
  174. package/dist/tools/git-history.js +3 -10
  175. package/dist/tools/git-history.js.map +1 -1
  176. package/dist/tools/history.d.ts +4 -33
  177. package/dist/tools/history.d.ts.map +1 -1
  178. package/dist/tools/history.js +6 -31
  179. package/dist/tools/history.js.map +1 -1
  180. package/dist/tools/impact.d.ts +7 -51
  181. package/dist/tools/impact.d.ts.map +1 -1
  182. package/dist/tools/impact.js +15 -67
  183. package/dist/tools/impact.js.map +1 -1
  184. package/dist/tools/index.d.ts +3 -8
  185. package/dist/tools/index.d.ts.map +1 -1
  186. package/dist/tools/index.js +3 -8
  187. package/dist/tools/index.js.map +1 -1
  188. package/dist/tools/kit.d.ts +66 -113
  189. package/dist/tools/kit.d.ts.map +1 -1
  190. package/dist/tools/kit.js +60 -28
  191. package/dist/tools/kit.js.map +1 -1
  192. package/dist/tools/link-workspace.d.ts +7 -45
  193. package/dist/tools/link-workspace.d.ts.map +1 -1
  194. package/dist/tools/link-workspace.js +10 -48
  195. package/dist/tools/link-workspace.js.map +1 -1
  196. package/dist/tools/lookup.d.ts +4 -14
  197. package/dist/tools/lookup.d.ts.map +1 -1
  198. package/dist/tools/lookup.js +4 -14
  199. package/dist/tools/lookup.js.map +1 -1
  200. package/dist/tools/mark-incident.d.ts +7 -54
  201. package/dist/tools/mark-incident.d.ts.map +1 -1
  202. package/dist/tools/mark-incident.js +15 -68
  203. package/dist/tools/mark-incident.js.map +1 -1
  204. package/dist/tools/observe-runtime.d.ts +27 -210
  205. package/dist/tools/observe-runtime.d.ts.map +1 -1
  206. package/dist/tools/observe-runtime.js +258 -436
  207. package/dist/tools/observe-runtime.js.map +1 -1
  208. package/dist/tools/observe-tests.d.ts +9 -88
  209. package/dist/tools/observe-tests.d.ts.map +1 -1
  210. package/dist/tools/observe-tests.js +34 -108
  211. package/dist/tools/observe-tests.js.map +1 -1
  212. package/dist/tools/pr-analysis.d.ts +18 -2
  213. package/dist/tools/pr-analysis.d.ts.map +1 -1
  214. package/dist/tools/pr-analysis.js +73 -23
  215. package/dist/tools/pr-analysis.js.map +1 -1
  216. package/dist/tools/pre-push.d.ts +94 -9
  217. package/dist/tools/pre-push.d.ts.map +1 -1
  218. package/dist/tools/pre-push.js +139 -34
  219. package/dist/tools/pre-push.js.map +1 -1
  220. package/dist/tools/propagation.d.ts +11 -53
  221. package/dist/tools/propagation.d.ts.map +1 -1
  222. package/dist/tools/propagation.js +14 -57
  223. package/dist/tools/propagation.js.map +1 -1
  224. package/dist/tools/questions.d.ts +13 -63
  225. package/dist/tools/questions.d.ts.map +1 -1
  226. package/dist/tools/questions.js +33 -105
  227. package/dist/tools/questions.js.map +1 -1
  228. package/dist/tools/refusal-fetch.d.ts +4 -40
  229. package/dist/tools/refusal-fetch.d.ts.map +1 -1
  230. package/dist/tools/refusal-fetch.js +4 -40
  231. package/dist/tools/refusal-fetch.js.map +1 -1
  232. package/dist/tools/runtime-incident.d.ts +4 -63
  233. package/dist/tools/runtime-incident.d.ts.map +1 -1
  234. package/dist/tools/runtime-incident.js +10 -87
  235. package/dist/tools/runtime-incident.js.map +1 -1
  236. package/dist/tools/scope.d.ts +7 -25
  237. package/dist/tools/scope.d.ts.map +1 -1
  238. package/dist/tools/scope.js +17 -20
  239. package/dist/tools/scope.js.map +1 -1
  240. package/dist/tools/similar-incidents.d.ts +11 -86
  241. package/dist/tools/similar-incidents.d.ts.map +1 -1
  242. package/dist/tools/similar-incidents.js +7 -71
  243. package/dist/tools/similar-incidents.js.map +1 -1
  244. package/dist/tools/validate.d.ts +31 -47
  245. package/dist/tools/validate.d.ts.map +1 -1
  246. package/dist/tools/validate.js +133 -61
  247. package/dist/tools/validate.js.map +1 -1
  248. package/dist/tools/verification-status.d.ts +9 -64
  249. package/dist/tools/verification-status.d.ts.map +1 -1
  250. package/dist/tools/verification-status.js +9 -62
  251. package/dist/tools/verification-status.js.map +1 -1
  252. package/dist/tools/verify-claim.d.ts +5 -52
  253. package/dist/tools/verify-claim.d.ts.map +1 -1
  254. package/dist/tools/verify-claim.js +6 -56
  255. package/dist/tools/verify-claim.js.map +1 -1
  256. package/dist/transport.d.ts +15 -52
  257. package/dist/transport.d.ts.map +1 -1
  258. package/dist/transport.js +16 -60
  259. package/dist/transport.js.map +1 -1
  260. package/package.json +33 -16
@@ -1,34 +1,11 @@
1
1
  /**
2
- * `browser_save_scenario` — an explored session becomes a durable, repeatable
3
- * scenario.
4
- *
5
- * ## Everything goes out through `writeScenario`
6
- *
7
- * There is deliberately no private path to disk here. `writeScenario`
8
- * validates on the way *out* as well as in, and that is not redundant: a
9
- * scenario is written once and read on every push afterwards, so a fault saved
10
- * today surfaces during a check somebody is waiting on, long after the session
11
- * that could have explained it is gone. A tool that serialized its own JSON
12
- * would be a second writer with a first writer's rules, and the second one is
13
- * the one that ships a file nothing can read.
14
- *
15
- * ## A step carries no ref, and this schema offers no way to send one
16
- *
17
- * The ref refusal is enforced twice on purpose. The format module rejects a
18
- * step carrying a `ref` **by name**, with the reason in the message; this
19
- * schema does not declare the field at all. A caller working from a
20
- * `browser_snapshot` reply has the three durable fields already — every
21
- * snapshot element carries `role`, `name` and `selector` — so the natural
22
- * thing to copy is the right thing to store.
23
- *
24
- * ## What the session supplies
25
- *
26
- * The consented origin (a scenario may not be saved pointing somewhere this
27
- * session was never allowed to drive), the URL to start from, and the
28
- * provenance pair. The steps are the caller's: this server has no exploration
29
- * planner and does not pretend to have recorded intent it never saw.
2
+ * `browser_save_scenario`: an explored session becomes a durable scenario,
3
+ * written only through `writeScenario` (validates in and out — no private
4
+ * disk path here). A step can't carry a `ref`: the schema omits the field entirely and the format module also rejects one by name.
30
5
  */
6
+ import { unlink } from "node:fs/promises";
31
7
  import { gitHead } from "@descryy/core";
8
+ import { resolveTarget } from "../browser/scenario-resolve.js";
32
9
  import { browserAnswer, useSession, withinConsent } from "../browser/tool-support.js";
33
10
  import { SCENARIO_SCHEMA_VERSION, scenarioPath, writeScenario } from "../scenarios/index.js";
34
11
  import { optionalString, requiredString, ToolInputError } from "./kit.js";
@@ -43,7 +20,13 @@ const TARGET_SCHEMA = {
43
20
  properties: {
44
21
  role: { type: "string", description: "The element's ARIA role, as browser_snapshot reported it." },
45
22
  name: { type: "string", description: "The element's accessible name, as browser_snapshot reported it." },
46
- selector: { type: "string", description: "The selector browser_snapshot reported for it." },
23
+ selector: {
24
+ type: ["string", "null"],
25
+ description: "The selector browser_snapshot reported for it, or null when the element carries no id, test " +
26
+ "attribute or name and its position was the only thing distinguishing it. A null selector cannot be " +
27
+ "saved — a step naming one is refused, by name, rather than stored to fail at replay. Add a " +
28
+ "data-testid to the element and re-explore.",
29
+ },
47
30
  },
48
31
  required: ["role", "name", "selector"],
49
32
  additionalProperties: false,
@@ -126,6 +109,49 @@ const SCHEMA = {
126
109
  required: ["sessionId", "name", "steps", "assertions"],
127
110
  additionalProperties: false,
128
111
  };
112
+ function findNullSelectorTarget(args) {
113
+ function scan(key, label) {
114
+ const raw = args[key];
115
+ if (!Array.isArray(raw))
116
+ return null;
117
+ for (const [index, item] of raw.entries()) {
118
+ if (typeof item !== "object" || item === null)
119
+ continue;
120
+ const target = item["target"];
121
+ if (typeof target !== "object" || target === null)
122
+ continue;
123
+ const fields = target;
124
+ if (fields["selector"] === null) {
125
+ return {
126
+ where: `${label} ${index}`,
127
+ role: typeof fields["role"] === "string" ? fields["role"] : "",
128
+ name: typeof fields["name"] === "string" ? fields["name"] : "",
129
+ };
130
+ }
131
+ }
132
+ return null;
133
+ }
134
+ return scan("steps", "step") ?? scan("assertions", "assertion");
135
+ }
136
+ /** Every stored target, resolved against a fresh snapshot — makes "validated before written" true for replay, not just serialisation. `writeScenario` only proves the file parses back; it never sees a page. */
137
+ function collectUnresolvedTargets(scenario, freshSnapshot) {
138
+ const failures = [];
139
+ scenario.steps.forEach((step, index) => {
140
+ if (step.target === null)
141
+ return;
142
+ const result = resolveTarget(`step ${index}`, step.target, freshSnapshot);
143
+ if (!result.resolved)
144
+ failures.push(result.failure.message);
145
+ });
146
+ scenario.assertions.forEach((assertion, index) => {
147
+ if (assertion.target === null)
148
+ return;
149
+ const result = resolveTarget(`assertion ${index}`, assertion.target, freshSnapshot);
150
+ if (!result.resolved)
151
+ failures.push(result.failure.message);
152
+ });
153
+ return failures;
154
+ }
129
155
  function readObjectArray(args, key) {
130
156
  const raw = args[key];
131
157
  if (raw === undefined || raw === null) {
@@ -137,14 +163,7 @@ function readObjectArray(args, key) {
137
163
  }
138
164
  return raw;
139
165
  }
140
- /**
141
- * Shape the caller's arguments into a `Scenario` **without validating them**.
142
- *
143
- * Deliberate: `writeScenario` is the validator, and a second one here would be
144
- * a second set of rules to keep in step with the first. Everything a caller
145
- * got wrong comes back through the format module's own messages, which are the
146
- * ones the file's future readers will see.
147
- */
166
+ /** Shapes args into a `Scenario` without validating — `writeScenario` is the validator, so a caller's mistakes surface through its own messages, not a second set of rules here. */
148
167
  function shape(args, name, targetUrl, savedAtCommit) {
149
168
  const steps = readObjectArray(args, "steps").map((step) => ({
150
169
  action: step["action"],
@@ -169,16 +188,7 @@ function shape(args, name, targetUrl, savedAtCommit) {
169
188
  assertions,
170
189
  };
171
190
  }
172
- /**
173
- * The commit this scenario was authored against.
174
- *
175
- * Provenance only — nothing expires on it and nothing refuses because of it.
176
- * It exists so a replay failure can say *the scenario was written against a
177
- * different revision of this application*, which is usually the answer to "why
178
- * did this break". A directory that is not a git checkout records the empty
179
- * string and the reply says so, rather than a plausible-looking placeholder
180
- * that a later reader would try to `git show`.
181
- */
191
+ /** Provenance only — nothing expires or refuses on it. Says *"written against a different revision"* on replay failure. A non-git directory records "" and says so, rather than a placeholder a reader would try to `git show`. */
182
192
  async function commitOf(repoPath) {
183
193
  try {
184
194
  return await gitHead(repoPath);
@@ -219,10 +229,26 @@ async function run(args, ctx) {
219
229
  data: blank(sessionId, name),
220
230
  });
221
231
  }
232
+ // B1: an element with no id/test attribute/name comes back with
233
+ // `selector: null` rather than a fabricated value (rule 2). Refused here,
234
+ // by name, before reaching the format module's generic message.
235
+ const nullSelector = findNullSelectorTarget(args);
236
+ if (nullSelector !== null) {
237
+ return browserAnswer({
238
+ ctx,
239
+ state: "refused",
240
+ headline: `${nullSelector.where}'s target has no stable selector.`,
241
+ notes: [
242
+ `The element with role "${nullSelector.role}" and name "${nullSelector.name}" has no stable selector ` +
243
+ "— it carries no id, test attribute or name, and its position is the only thing distinguishing it. " +
244
+ "Add a data-testid to make it addressable. Nothing was written.",
245
+ ],
246
+ data: blank(sessionId, name),
247
+ });
248
+ }
222
249
  const scenario = shape(args, name, targetUrl, await commitOf(ctx.session.repoPath));
223
250
  try {
224
- // The one write path. `writeScenario` validates on the way out, so an
225
- // artifact that this reader could not read back never reaches disk.
251
+ // The one write path: `writeScenario` validates on the way out, so an unreadable artifact never reaches disk.
226
252
  await writeScenario(ctx.session.repoPath, scenario);
227
253
  }
228
254
  catch (error) {
@@ -239,6 +265,26 @@ async function run(args, ctx) {
239
265
  data: blank(sessionId, name),
240
266
  });
241
267
  }
268
+ // The check the description claims: a fresh snapshot of the page just
269
+ // recorded on, every descriptor re-run through `resolveTarget`.
270
+ // `writeScenario` can't prove replay works — it never sees a page. Would have caught B1.
271
+ const freshSnapshot = await entry.page.snapshot();
272
+ const unresolved = collectUnresolvedTargets(scenario, freshSnapshot);
273
+ if (unresolved.length > 0) {
274
+ await unlink(scenarioPath(ctx.session.repoPath, name)).catch(() => { });
275
+ return browserAnswer({
276
+ ctx,
277
+ state: "refused",
278
+ headline: `Scenario "${name}" was not saved — ${unresolved.length} of its step(s)/assertion(s) do not resolve against the page it was just recorded on.`,
279
+ notes: [
280
+ ...unresolved,
281
+ "Nothing was written. A scenario whose file parses correctly but whose steps do not resolve against " +
282
+ "the page it claims to describe is worse than one that was never saved — it looks replayable and " +
283
+ "is not.",
284
+ ],
285
+ data: blank(sessionId, name),
286
+ });
287
+ }
242
288
  const path = scenarioPath(ctx.session.repoPath, name);
243
289
  return browserAnswer({
244
290
  ctx,
@@ -282,17 +328,18 @@ export const browserSaveScenarioTool = {
282
328
  "descry/scenarios/ that browser_run_scenario replays and a pre-push check can run with no agent in the " +
283
329
  "loop. Steps name their elements by role, name and selector together, never by a snapshot ref, because a " +
284
330
  "ref means nothing in a later session. Assertions are required and may be empty; an empty one is stored " +
285
- "honestly and replays as unverified rather than passed. The file is validated before it is written, so " +
286
- "a scenario that could not be read back is refused now rather than during a check somebody is waiting on.",
331
+ "honestly and replays as unverified rather than passed. Before this call reports success, every step and " +
332
+ "assertion is re-resolved against a fresh snapshot of the page it was just recorded on — a scenario whose " +
333
+ "steps do not actually resolve is refused and deleted now, rather than discovered during a check " +
334
+ "somebody is waiting on. A step naming an element with no id, test attribute or name is refused too: such " +
335
+ "an element has no selector that would survive to a later session.",
287
336
  class: "action",
288
337
  tier: "evidence",
289
338
  version: "1.0.0",
290
339
  inputSchema: SCHEMA,
291
340
  run,
292
- // Undefined, for the reason the verbs have and one of its own: this call
293
- // writes into the repository the developer already pointed Descry at, in a
294
- // path they name, and the session it records was confirmed at
295
- // browser_start_session.
341
+ // Undefined: this writes into the repo the developer already pointed
342
+ // Descry at, and the session was already confirmed at browser_start_session.
296
343
  describeAction: () => undefined,
297
344
  };
298
345
  //# sourceMappingURL=browser-save-scenario.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"browser-save-scenario.js","sourceRoot":"","sources":["../../src/tools/browser-save-scenario.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"browser-save-scenario.js","sourceRoot":"","sources":["../../src/tools/browser-save-scenario.ts"],"names":[],"mappings":"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"}
@@ -1,26 +1,7 @@
1
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.
2
+ * `browser_snapshot`: page elements as refs, budget-fit from day one —
3
+ * `get_git_diff` hit 228,860 then 84,516 chars unbounded, paid for twice.
4
+ * `totalElements` is always the real, uncapped count — never confused with a shortened list.
24
5
  */
25
6
  import type { BrowserEvidenceReport } from "../browser/evidence.ts";
26
7
  import { type BrowserGraphWrite } from "../browser/graph-write.ts";
@@ -32,29 +13,15 @@ export interface BrowserPageData {
32
13
  readonly url: string;
33
14
  readonly title: string;
34
15
  readonly elements: readonly SnapshotElement[];
35
- /**
36
- * How many elements the page has. **Never the number in `elements`** when
37
- * the two differ — that is the whole point of carrying it.
38
- */
16
+ /** How many elements the page has — never the number in `elements` when they differ; that's the whole point. */
39
17
  readonly totalElements: number;
40
18
  readonly evidence: BrowserEvidenceReport;
41
19
  /** Graph nodes this page's own requests reached, and any R4 edges witnessed. §5.3's "any graph node reached, surfaced in the same reply". */
42
20
  readonly graph: BrowserGraphWrite;
43
21
  }
44
- /**
45
- * What `browser_snapshot` returns. An alias of the shared page shape, so
46
- * `browser_navigate` — which answers the same question — cannot drift from it.
47
- */
22
+ /** What `browser_snapshot` returns — aliased so `browser_navigate` (same question) can't drift from it. */
48
23
  export type BrowserSnapshotData = BrowserPageData;
49
- /**
50
- * Shrink by dropping elements from the end of the window, never by dropping
51
- * the count or the evidence.
52
- *
53
- * Evidence stays because it is the part a caller cannot re-request by paging —
54
- * the observations were drained when this reply was built, and a second
55
- * snapshot would return a different set. Elements can always be asked for
56
- * again with `startAt`, so they are what gives way.
57
- */
24
+ /** Shrinks by dropping elements from the end, never the count or evidence. Evidence can't be re-requested (drained when built); elements can, via `startAt`. */
58
25
  export declare function fitSnapshot(data: BrowserSnapshotData, budgetBytes: number): ReplyFit<BrowserSnapshotData>;
59
26
  export declare const browserSnapshotTool: ToolDefinition;
60
27
  //# sourceMappingURL=browser-snapshot.d.ts.map
@@ -1 +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"}
1
+ {"version":3,"file":"browser-snapshot.d.ts","sourceRoot":"","sources":["../../src/tools/browser-snapshot.ts"],"names":[],"mappings":"AAAA;;;;GAIG;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,gHAAgH;IAChH,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,2GAA2G;AAC3G,MAAM,MAAM,mBAAmB,GAAG,eAAe,CAAC;AA6ElD,gKAAgK;AAChK,wBAAgB,WAAW,CAAC,IAAI,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,GAAG,QAAQ,CAAC,mBAAmB,CAAC,CAwBzG;AAED,eAAO,MAAM,mBAAmB,EAAE,cAajC,CAAC"}
@@ -1,26 +1,7 @@
1
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.
2
+ * `browser_snapshot`: page elements as refs, budget-fit from day one —
3
+ * `get_git_diff` hit 228,860 then 84,516 chars unbounded, paid for twice.
4
+ * `totalElements` is always the real, uncapped count — never confused with a shortened list.
24
5
  */
25
6
  import { browserAnswer, observeAndCorrelate, useSession } from "../browser/tool-support.js";
26
7
  import { NO_GRAPH_WRITE } from "../browser/graph-write.js";
@@ -90,15 +71,7 @@ async function run(args, ctx) {
90
71
  fitToBudget: (budgetBytes) => fitSnapshot(data, budgetBytes),
91
72
  });
92
73
  }
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
- */
74
+ /** Shrinks by dropping elements from the end, never the count or evidence. Evidence can't be re-requested (drained when built); elements can, via `startAt`. */
102
75
  export function fitSnapshot(data, budgetBytes) {
103
76
  const fits = (elements) => Buffer.byteLength(JSON.stringify({ ...data, elements }), "utf8") <= budgetBytes;
104
77
  if (fits(data.elements))
@@ -1 +1 @@
1
- {"version":3,"file":"browser-snapshot.js","sourceRoot":"","sources":["../../src/tools/browser-snapshot.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"browser-snapshot.js","sourceRoot":"","sources":["../../src/tools/browser-snapshot.ts"],"names":[],"mappings":"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"}
@@ -1,27 +1,8 @@
1
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
- */
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. */
25
6
  import type { BrowserEvidenceReport } from "../browser/evidence.ts";
26
7
  import { type BrowserGraphWrite } from "../browser/graph-write.ts";
27
8
  import { type ToolDefinition } from "./kit.ts";
@@ -1 +1 @@
1
- {"version":3,"file":"browser-start-session.d.ts","sourceRoot":"","sources":["../../src/tools/browser-start-session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,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;AA8RD,eAAO,MAAM,uBAAuB,EAAE,cAsBrC,CAAC"}
1
+ {"version":3,"file":"browser-start-session.d.ts","sourceRoot":"","sources":["../../src/tools/browser-start-session.ts"],"names":[],"mappings":"AAAA;;;;6DAI6D;AAG7D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAEpE,OAAO,EAAkB,KAAK,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAQnF,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;AA0RD,eAAO,MAAM,uBAAuB,EAAE,cAgCrC,CAAC"}
@@ -1,32 +1,14 @@
1
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
- */
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. */
25
6
  import { CANCELLED_STATE, cancellationHeadline, cancellationNotes } from "../cancellation.js";
26
7
  import { browserAnswer, emptyEvidence, observeAndCorrelate } from "../browser/tool-support.js";
27
8
  import { NO_GRAPH_WRITE } from "../browser/graph-write.js";
28
9
  import { isAbsolute, join } from "node:path";
29
10
  import { loadStackParser, StackParserLoadError } from "../browser/stack-parser.js";
11
+ import { checkUrlScheme } from "../browser/url-scheme.js";
30
12
  import { optionalBoolean, optionalEnum, optionalString, requiredString, ToolInputError } from "./kit.js";
31
13
  const SCHEMA = {
32
14
  type: "object",
@@ -96,15 +78,9 @@ const SCHEMA = {
96
78
  additionalProperties: false,
97
79
  };
98
80
  const SAFETY_LEVELS = ["readOnly", "write", "destructiveWithApproval"];
99
- /**
100
- * Read the profile, do not re-derive it.
101
- *
102
- * Only the two fields this surface actually consults are read; everything
103
- * else a caller sends is carried by the profile it came from and is none of
104
- * this tool's business. `additionalProperties: true` on the schema is what
105
- * lets a caller pass the same object it passes `observe_runtime` rather than
106
- * trimming a second copy of it.
107
- */
81
+ /** Reads the profile, doesn't re-derive it — only the 2 fields this surface consults.
82
+ * `additionalProperties: true` lets a caller pass the same object it gives
83
+ * `observe_runtime` without trimming a second copy. */
108
84
  function readProfile(args) {
109
85
  const raw = args["environment"];
110
86
  if (raw === undefined || raw === null)
@@ -133,13 +109,20 @@ function readStackParserSpec(args) {
133
109
  }
134
110
  function parseTarget(args) {
135
111
  const raw = requiredString(args, "targetUrl");
112
+ let url;
136
113
  try {
137
- return new URL(raw);
114
+ url = new URL(raw);
138
115
  }
139
116
  catch {
140
117
  throw new ToolInputError(`"targetUrl" must be an absolute URL including scheme — got "${raw}". A bare host or path cannot be ` +
141
118
  "opened, and cannot be turned into the origin this session's consent is bound to.");
142
119
  }
120
+ // file:/data: (untrusted schemes) resolve to origin "null", collapsing
121
+ // tool-support.ts's same-origin containment — see url-scheme.ts.
122
+ const scheme = checkUrlScheme(url);
123
+ if (!scheme.allowed)
124
+ throw new ToolInputError(scheme.reason);
125
+ return url;
143
126
  }
144
127
  function cancelledBeforeLaunch(ctx, target, safetyLevel) {
145
128
  return browserAnswer({
@@ -167,10 +150,9 @@ async function run(args, ctx) {
167
150
  const parserSpec = readStackParserSpec(args);
168
151
  const documentRoot = optionalString(args, "documentRoot");
169
152
  const backend = ctx.session.browserBackend();
170
- // Before anything launches. A browser opened for a caller who has already
171
- // gone is one nothing will ever close: the session id goes back in a reply
172
- // the server suppresses, so no `browser_close_session` can name it and the
173
- // five-minute idle reaper is the only thing left that would.
153
+ // Before anything launches — a browser opened for a caller who's already gone is
154
+ // one nothing will ever close (its session id never reaches a suppressed reply);
155
+ // only the 5-minute idle reaper would eventually catch it.
174
156
  if (ctx.signal.aborted)
175
157
  return cancelledBeforeLaunch(ctx, target, null);
176
158
  if (!backend.available) {
@@ -182,10 +164,9 @@ async function run(args, ctx) {
182
164
  data: { sessionId: "", url: target.href, title: "", consentedOrigin: target.origin, safetyLevel: null, totalElements: 0, evidence: emptyEvidence(), graph: NO_GRAPH_WRITE },
183
165
  });
184
166
  }
185
- // The parser is loaded before anything launches. A parser that will not
186
- // import is a refusal the caller can fix, and finding that out after a
187
- // browser is open would mean either tearing it down again or running a
188
- // session that quietly cannot write the edge it was opened for.
167
+ // Parser loaded before anything launches — a bad parser is a fixable refusal here;
168
+ // discovering it after a browser is open means tearing it down or running a
169
+ // session that silently can't write the edge it opened for.
189
170
  let parser;
190
171
  try {
191
172
  parser = parserSpec === null ? undefined : await loadStackParser(parserSpec);
@@ -201,10 +182,9 @@ async function run(args, ctx) {
201
182
  data: { sessionId: "", url: target.href, title: "", consentedOrigin: target.origin, safetyLevel: null, totalElements: 0, evidence: emptyEvidence(), graph: NO_GRAPH_WRITE },
202
183
  });
203
184
  }
204
- // Trap A, closed here rather than left to a caller to get right silently.
205
- // The origin being driven maps to the directory that actually serves its
206
- // scripts; `documentRoot` overrides the repository root for exactly the
207
- // `public/` case the schema describes.
185
+ // Closed here rather than left to a caller: the origin driven must map to
186
+ // the directory actually serving its scripts — `documentRoot` overrides the repo
187
+ // root for the `public/` case the schema describes.
208
188
  const servedFrom = documentRoot === undefined
209
189
  ? ctx.session.repoPath
210
190
  : isAbsolute(documentRoot)
@@ -223,8 +203,8 @@ async function run(args, ctx) {
223
203
  if (!opened.opened) {
224
204
  const notes = opened.kind === "atCapacity"
225
205
  ? [opened.reason]
226
- : // The remedy travels verbatim. A refusal that says "could not launch"
227
- // and stops is one the developer has to go and research.
206
+ : // Remedy travels verbatim — "could not launch" and stopping there is a
207
+ // refusal the developer has to go research themselves.
228
208
  [opened.message, `Remedy: ${opened.remedy}`, `Expected the browser at ${opened.expectedExecutablePath}.`];
229
209
  return browserAnswer({
230
210
  ctx,
@@ -234,10 +214,9 @@ async function run(args, ctx) {
234
214
  data: { sessionId: "", url: target.href, title: "", consentedOrigin: target.origin, safetyLevel: profile?.safetyLevel ?? null, totalElements: 0, evidence: emptyEvidence(), graph: NO_GRAPH_WRITE },
235
215
  });
236
216
  }
237
- // The race that is actually lost in practice: the caller cancelled while
238
- // Chromium was starting, so the launch succeeded on behalf of nobody. This
239
- // closes the session it just opened — the one resource this call started,
240
- // and the only one it may tear down.
217
+ // The race actually lost in practice: caller cancelled while Chromium was
218
+ // starting, so the launch succeeded for nobody. Closes the session just opened
219
+ // — the one resource this call started, the only one it may tear down.
241
220
  if (ctx.signal.aborted) {
242
221
  await ctx.session.browserSessions().close(opened.entry.sessionId);
243
222
  return cancelledBeforeLaunch(ctx, target, profile?.safetyLevel ?? null);
@@ -298,6 +277,14 @@ export const browserStartSessionTool = {
298
277
  run,
299
278
  describeAction(args) {
300
279
  const target = parseTarget(args);
280
+ // Same parse the run path uses to enforce the gate (`mutationRefusal` in
281
+ // `tool-support.ts`) — read here, not re-derived, so what's confirmed matches
282
+ // what's enforced.
283
+ const safetyLevel = readProfile(args)?.safetyLevel;
284
+ if (safetyLevel === "readOnly") {
285
+ return (`Descry may navigate and snapshot anywhere on ${target.origin}. Clicking, typing and filling will be ` +
286
+ `refused. It may not leave that origin.`);
287
+ }
301
288
  return (`Launch a browser and open ${target.href}. For as long as the session lives, Descry may navigate, ` +
302
289
  `click, type and fill anywhere on ${target.origin} without asking again — including actions that ` +
303
290
  "change data in that application. It may not leave that origin.");