harnery 0.31.5 → 0.32.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 (222) hide show
  1. package/dist/commander.d.ts.map +1 -1
  2. package/dist/commander.js +2 -0
  3. package/dist/commands/agents.d.ts +0 -9
  4. package/dist/commands/agents.d.ts.map +1 -1
  5. package/dist/commands/agents.js +70 -95
  6. package/dist/commands/browse-session.d.ts +21 -0
  7. package/dist/commands/browse-session.d.ts.map +1 -0
  8. package/dist/commands/browse-session.js +157 -0
  9. package/dist/commands/browse.d.ts.map +1 -1
  10. package/dist/commands/browse.js +205 -37
  11. package/dist/commands/checkpoint.js +1 -1
  12. package/dist/commands/deinit.d.ts.map +1 -1
  13. package/dist/commands/deinit.js +4 -0
  14. package/dist/commands/docs.d.ts.map +1 -1
  15. package/dist/commands/docs.js +40 -0
  16. package/dist/commands/doctor.d.ts.map +1 -1
  17. package/dist/commands/doctor.js +100 -17
  18. package/dist/commands/init.d.ts +1 -2
  19. package/dist/commands/init.d.ts.map +1 -1
  20. package/dist/commands/init.js +16 -5
  21. package/dist/commands/tunnel.d.ts.map +1 -1
  22. package/dist/commands/tunnel.js +2 -3
  23. package/dist/core/agents/canonical-emit.d.ts +1 -2
  24. package/dist/core/agents/canonical-emit.d.ts.map +1 -1
  25. package/dist/core/agents/canonical-emit.js +1 -2
  26. package/dist/core/agents/cli.js +123 -88
  27. package/dist/core/agents/coord-client.d.ts +11 -4
  28. package/dist/core/agents/coord-client.d.ts.map +1 -1
  29. package/dist/core/agents/coord-client.js +27 -9
  30. package/dist/core/agents/finalization.d.ts +68 -0
  31. package/dist/core/agents/finalization.d.ts.map +1 -0
  32. package/dist/core/agents/finalization.js +443 -0
  33. package/dist/core/agents/git-hook.d.ts +51 -0
  34. package/dist/core/agents/git-hook.d.ts.map +1 -0
  35. package/dist/core/agents/git-hook.js +118 -0
  36. package/dist/core/agents/render/prompt-context.d.ts +6 -5
  37. package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
  38. package/dist/core/agents/render/prompt-context.js +26 -13
  39. package/dist/core/agents/render/session-context.d.ts.map +1 -1
  40. package/dist/core/agents/render/session-context.js +15 -2
  41. package/dist/core/agents/rules/claim-conflict.js +3 -3
  42. package/dist/core/agents/rules/commit-conflict.d.ts +15 -6
  43. package/dist/core/agents/rules/commit-conflict.d.ts.map +1 -1
  44. package/dist/core/agents/rules/commit-conflict.js +21 -5
  45. package/dist/core/agents/rules/stop-hook.d.ts +3 -0
  46. package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
  47. package/dist/core/agents/rules/stop-hook.js +59 -23
  48. package/dist/core/agents/session-events.d.ts +8 -16
  49. package/dist/core/agents/session-events.d.ts.map +1 -1
  50. package/dist/core/agents/session-events.js +12 -26
  51. package/dist/core/agents/state/heartbeat-projector.d.ts +3 -0
  52. package/dist/core/agents/state/heartbeat-projector.d.ts.map +1 -1
  53. package/dist/core/agents/state/heartbeat-projector.js +44 -1
  54. package/dist/core/agents/state/heartbeat-writer.d.ts +32 -5
  55. package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
  56. package/dist/core/agents/state/heartbeat-writer.js +54 -17
  57. package/dist/core/agents/state/names.d.ts +22 -1
  58. package/dist/core/agents/state/names.d.ts.map +1 -1
  59. package/dist/core/agents/state/names.js +40 -2
  60. package/dist/core/config.d.ts +30 -2
  61. package/dist/core/config.d.ts.map +1 -1
  62. package/dist/core/config.js +74 -11
  63. package/dist/core/governor/planning.d.ts.map +1 -1
  64. package/dist/core/governor/planning.js +12 -13
  65. package/dist/core/hooks/adapter/detect.d.ts +2 -4
  66. package/dist/core/hooks/adapter/detect.d.ts.map +1 -1
  67. package/dist/core/hooks/adapter/detect.js +4 -14
  68. package/dist/core/hooks/adapter/output.d.ts +1 -1
  69. package/dist/core/hooks/adapter/output.d.ts.map +1 -1
  70. package/dist/core/hooks/adapter/output.js +5 -4
  71. package/dist/core/hooks/adapter/parse.d.ts +1 -1
  72. package/dist/core/hooks/adapter/parse.d.ts.map +1 -1
  73. package/dist/core/hooks/adapter/parse.js +22 -5
  74. package/dist/core/hooks/adapter/wiring.d.ts +23 -0
  75. package/dist/core/hooks/adapter/wiring.d.ts.map +1 -1
  76. package/dist/core/hooks/adapter/wiring.js +32 -0
  77. package/dist/core/hooks/cli.d.ts +1 -2
  78. package/dist/core/hooks/cli.d.ts.map +1 -1
  79. package/dist/core/hooks/cli.js +169 -27
  80. package/dist/core/hooks/codex-wsl-bridge.d.ts +46 -0
  81. package/dist/core/hooks/codex-wsl-bridge.d.ts.map +1 -0
  82. package/dist/core/hooks/codex-wsl-bridge.js +137 -0
  83. package/dist/core/hooks/effects/index.d.ts +1 -1
  84. package/dist/core/hooks/effects/index.js +3 -3
  85. package/dist/core/hooks/events/schema.d.ts +27 -0
  86. package/dist/core/hooks/events/schema.d.ts.map +1 -1
  87. package/dist/core/hooks/resolve/owner.d.ts +7 -1
  88. package/dist/core/hooks/resolve/owner.d.ts.map +1 -1
  89. package/dist/core/hooks/resolve/owner.js +15 -0
  90. package/dist/core/hooks/resolve/transcript.d.ts +44 -0
  91. package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
  92. package/dist/core/hooks/resolve/transcript.js +176 -1
  93. package/dist/core/hooks/session-name-presence.d.ts +30 -0
  94. package/dist/core/hooks/session-name-presence.d.ts.map +1 -0
  95. package/dist/core/hooks/session-name-presence.js +43 -0
  96. package/dist/core/hooks/unsafe-cross-shell.d.ts +13 -0
  97. package/dist/core/hooks/unsafe-cross-shell.d.ts.map +1 -0
  98. package/dist/core/hooks/unsafe-cross-shell.js +151 -0
  99. package/dist/core/work/state.d.ts +4 -5
  100. package/dist/core/work/state.d.ts.map +1 -1
  101. package/dist/core/work/state.js +5 -8
  102. package/dist/core/workflow/index.d.ts +1 -1
  103. package/dist/core/workflow/index.d.ts.map +1 -1
  104. package/dist/core/workflow/proof.d.ts +2 -2
  105. package/dist/core/workflow/proof.d.ts.map +1 -1
  106. package/dist/core/workflow/proof.js +2 -2
  107. package/dist/core/workflow/run-state.d.ts +2 -2
  108. package/dist/core/workflow/run-state.d.ts.map +1 -1
  109. package/dist/core/workflow/run-state.js +2 -2
  110. package/dist/core/workflow/types.d.ts +3 -3
  111. package/dist/core/workflow/types.d.ts.map +1 -1
  112. package/dist/core/workflow/workspaces/execution.d.ts +2 -2
  113. package/dist/core/workflow/workspaces/execution.d.ts.map +1 -1
  114. package/dist/core/workflow/workspaces/execution.js +5 -0
  115. package/dist/core/workflow/workspaces/index.d.ts +1 -1
  116. package/dist/core/workflow/workspaces/index.d.ts.map +1 -1
  117. package/dist/core/workflow/workspaces/local-git.d.ts.map +1 -1
  118. package/dist/core/workflow/workspaces/local-git.js +1 -2
  119. package/dist/core/workflow/workspaces/paths.d.ts +2 -2
  120. package/dist/core/workflow/workspaces/types.d.ts +0 -6
  121. package/dist/core/workflow/workspaces/types.d.ts.map +1 -1
  122. package/dist/core/workflow/workspaces/validate.d.ts +0 -2
  123. package/dist/core/workflow/workspaces/validate.d.ts.map +1 -1
  124. package/dist/core/workflow/workspaces/validate.js +0 -2
  125. package/dist/lib/browser/client.d.ts +118 -1
  126. package/dist/lib/browser/client.d.ts.map +1 -1
  127. package/dist/lib/browser/client.js +435 -6
  128. package/dist/lib/browser/geometry.d.ts.map +1 -1
  129. package/dist/lib/browser/geometry.js +180 -37
  130. package/dist/lib/browser/index.d.ts +5 -1
  131. package/dist/lib/browser/index.d.ts.map +1 -1
  132. package/dist/lib/browser/index.js +5 -1
  133. package/dist/lib/browser/netscape-cookies.d.ts +6 -0
  134. package/dist/lib/browser/netscape-cookies.d.ts.map +1 -0
  135. package/dist/lib/browser/netscape-cookies.js +31 -0
  136. package/dist/lib/browser/proxy.d.ts +24 -0
  137. package/dist/lib/browser/proxy.d.ts.map +1 -0
  138. package/dist/lib/browser/proxy.js +84 -0
  139. package/dist/lib/browser/runts.d.ts +6 -0
  140. package/dist/lib/browser/runts.d.ts.map +1 -1
  141. package/dist/lib/browser/runts.js +21 -4
  142. package/dist/lib/browser/session-control.d.ts +112 -0
  143. package/dist/lib/browser/session-control.d.ts.map +1 -0
  144. package/dist/lib/browser/session-control.js +670 -0
  145. package/dist/lib/docs-links.d.ts +108 -0
  146. package/dist/lib/docs-links.d.ts.map +1 -0
  147. package/dist/lib/docs-links.js +555 -0
  148. package/dist/lib/exec.d.ts +1 -1
  149. package/dist/lib/exec.js +1 -1
  150. package/dist/lib/identities/assume.d.ts +4 -2
  151. package/dist/lib/identities/assume.d.ts.map +1 -1
  152. package/dist/lib/identities/assume.js +15 -2
  153. package/dist/lib/instructions/git-hooks.d.ts +75 -0
  154. package/dist/lib/instructions/git-hooks.d.ts.map +1 -0
  155. package/dist/lib/instructions/git-hooks.js +238 -0
  156. package/dist/lib/instructions/splice.d.ts +10 -4
  157. package/dist/lib/instructions/splice.d.ts.map +1 -1
  158. package/dist/lib/instructions/splice.js +19 -11
  159. package/package.json +1 -1
  160. package/schemas/config.schema.json +32 -0
  161. package/src/commander.ts +2 -0
  162. package/src/commands/agents.ts +96 -115
  163. package/src/commands/browse-session.ts +245 -0
  164. package/src/commands/browse.ts +287 -44
  165. package/src/commands/checkpoint.ts +1 -1
  166. package/src/commands/deinit.ts +7 -1
  167. package/src/commands/docs.ts +56 -0
  168. package/src/commands/doctor.ts +100 -18
  169. package/src/commands/init.ts +17 -9
  170. package/src/commands/tunnel.ts +2 -5
  171. package/src/core/agents/canonical-emit.ts +1 -2
  172. package/src/core/agents/cli.ts +137 -88
  173. package/src/core/agents/coord-client.ts +38 -9
  174. package/src/core/agents/finalization.ts +595 -0
  175. package/src/core/agents/git-hook.ts +126 -0
  176. package/src/core/agents/render/prompt-context.ts +28 -13
  177. package/src/core/agents/render/session-context.ts +15 -2
  178. package/src/core/agents/rules/claim-conflict.ts +3 -3
  179. package/src/core/agents/rules/commit-conflict.ts +35 -8
  180. package/src/core/agents/rules/stop-hook.ts +71 -23
  181. package/src/core/agents/session-events.ts +14 -41
  182. package/src/core/agents/state/heartbeat-projector.ts +45 -1
  183. package/src/core/agents/state/heartbeat-writer.ts +78 -16
  184. package/src/core/agents/state/names.ts +54 -2
  185. package/src/core/config.ts +92 -12
  186. package/src/core/governor/planning.ts +17 -12
  187. package/src/core/hooks/adapter/detect.ts +4 -13
  188. package/src/core/hooks/adapter/output.ts +9 -4
  189. package/src/core/hooks/adapter/parse.ts +24 -5
  190. package/src/core/hooks/adapter/wiring.ts +43 -0
  191. package/src/core/hooks/cli.ts +201 -23
  192. package/src/core/hooks/codex-wsl-bridge.ts +188 -0
  193. package/src/core/hooks/effects/index.ts +5 -5
  194. package/src/core/hooks/events/schema.ts +27 -0
  195. package/src/core/hooks/resolve/owner.ts +22 -1
  196. package/src/core/hooks/resolve/transcript.ts +164 -1
  197. package/src/core/hooks/session-name-presence.ts +52 -0
  198. package/src/core/hooks/unsafe-cross-shell.ts +160 -0
  199. package/src/core/work/state.ts +8 -12
  200. package/src/core/workflow/engine.ts +2 -2
  201. package/src/core/workflow/index.ts +0 -1
  202. package/src/core/workflow/proof.ts +4 -4
  203. package/src/core/workflow/run-state.ts +5 -5
  204. package/src/core/workflow/types.ts +3 -3
  205. package/src/core/workflow/workspaces/execution.ts +11 -4
  206. package/src/core/workflow/workspaces/index.ts +0 -3
  207. package/src/core/workflow/workspaces/local-git.ts +1 -2
  208. package/src/core/workflow/workspaces/paths.ts +2 -2
  209. package/src/core/workflow/workspaces/types.ts +0 -9
  210. package/src/core/workflow/workspaces/validate.ts +1 -5
  211. package/src/lib/browser/client.ts +528 -6
  212. package/src/lib/browser/geometry.ts +197 -37
  213. package/src/lib/browser/index.ts +39 -0
  214. package/src/lib/browser/netscape-cookies.ts +39 -0
  215. package/src/lib/browser/proxy.ts +105 -0
  216. package/src/lib/browser/runts.ts +27 -3
  217. package/src/lib/browser/session-control.ts +892 -0
  218. package/src/lib/docs-links.ts +674 -0
  219. package/src/lib/exec.ts +1 -1
  220. package/src/lib/identities/assume.ts +22 -1
  221. package/src/lib/instructions/git-hooks.ts +259 -0
  222. package/src/lib/instructions/splice.ts +41 -11
@@ -1,6 +1,6 @@
1
- import { mkdirSync } from "node:fs";
1
+ import { chmodSync, mkdirSync, statSync, writeFileSync } from "node:fs";
2
2
  import { homedir } from "node:os";
3
- import { resolve } from "node:path";
3
+ import { dirname, resolve } from "node:path";
4
4
  import axe from "axe-core";
5
5
  import { chromium, } from "playwright";
6
6
  import { buildAssertCheck } from "./asserts.js";
@@ -10,6 +10,14 @@ import { buildClearLayoutAnnotationsScript, buildLayoutAnnotateScript, buildOver
10
10
  import { buildClearRuntsAnnotationsScript, buildRuntsAnnotateScript, buildRuntsCheck, } from "./runts.js";
11
11
  import { buildClearTargetSizeAnnotationsScript, buildTargetSizeAnnotateScript, buildTargetSizeCheck, } from "./target-size.js";
12
12
  import { buildAnnotateScript, buildClearAnnotationsScript, buildVisibilityCheck, } from "./visibility.js";
13
+ export class BrowserSessionActionError extends Error {
14
+ code;
15
+ constructor(code, message) {
16
+ super(message);
17
+ this.code = code;
18
+ this.name = "BrowserSessionActionError";
19
+ }
20
+ }
13
21
  const DEFAULT_PROFILE = resolve(homedir(), ".cache", "harnery", "browser-profile");
14
22
  // Bound how many Chromium processes SPAWN at the same moment. When many Browser
15
23
  // instances open at once — a full test suite, a fan-out of browse calls — the
@@ -17,8 +25,10 @@ const DEFAULT_PROFILE = resolve(homedir(), ".cache", "harnery", "browser-profile
17
25
  // resources and Chromium launch dies with an unhandled ENOENT that a per-call
18
26
  // retry can't catch. Serializing only the brief launch phase (never the
19
27
  // browser's lifetime, so N browsers still run concurrently) removes the burst
20
- // that causes it. Overridable via HARNERY_MAX_BROWSER_LAUNCHES.
21
- const MAX_CONCURRENT_LAUNCHES = Math.max(1, Number.parseInt(process.env.HARNERY_MAX_BROWSER_LAUNCHES ?? "3", 10) || 3);
28
+ // that causes it. The default stays at one because even a three-process burst
29
+ // can exhaust Bun/Playwright's IPC sockets under a full suite; callers with
30
+ // more headroom can opt into a higher value via HARNERY_MAX_BROWSER_LAUNCHES.
31
+ const MAX_CONCURRENT_LAUNCHES = Math.max(1, Number.parseInt(process.env.HARNERY_MAX_BROWSER_LAUNCHES ?? "1", 10) || 1);
22
32
  let activeLaunches = 0;
23
33
  const launchWaiters = [];
24
34
  async function acquireLaunchSlot() {
@@ -42,6 +52,12 @@ export class Browser {
42
52
  opts;
43
53
  context = null;
44
54
  page = null;
55
+ pageIndexes = new Map();
56
+ pageRecency = new Map();
57
+ pageNavigations = new Map();
58
+ nextPageIndex = 0;
59
+ recencyClock = 0;
60
+ sessionRevision = 0;
45
61
  profileDir;
46
62
  consoleEvents = [];
47
63
  pageErrors = [];
@@ -52,6 +68,8 @@ export class Browser {
52
68
  }
53
69
  /** Lazy: caller-side helper to find the active page if mid-flow. */
54
70
  get currentPage() {
71
+ if (!this.page || this.page.isClosed())
72
+ this.selectMostRecentPage();
55
73
  if (!this.page) {
56
74
  throw new Error("Browser not opened. Call open() first.");
57
75
  }
@@ -72,6 +90,7 @@ export class Browser {
72
90
  ...(this.opts.launchArgs && this.opts.launchArgs.length > 0
73
91
  ? { args: this.opts.launchArgs }
74
92
  : {}),
93
+ ...(this.opts.proxy ? { proxy: this.opts.proxy } : {}),
75
94
  ...(this.opts.recordHarPath
76
95
  ? { recordHar: { path: this.opts.recordHarPath, mode: "full" } }
77
96
  : {}),
@@ -101,8 +120,10 @@ export class Browser {
101
120
  });
102
121
  }
103
122
  const pages = this.context.pages();
104
- this.page = pages[0] ?? (await this.context.newPage());
105
- this.attachDiagnosticListeners(this.page);
123
+ const firstPage = pages[0] ?? (await this.context.newPage());
124
+ for (const page of this.context.pages())
125
+ this.trackPage(page, page === firstPage);
126
+ this.context.on("page", (page) => this.trackPage(page, true));
106
127
  }
107
128
  /**
108
129
  * Open the browser, retrying a few times on a transient startup failure.
@@ -141,6 +162,10 @@ export class Browser {
141
162
  }
142
163
  this.context = null;
143
164
  this.page = null;
165
+ this.pageIndexes.clear();
166
+ this.pageRecency.clear();
167
+ this.nextPageIndex = 0;
168
+ this.recencyClock = 0;
144
169
  this.consoleEvents = [];
145
170
  this.pageErrors = [];
146
171
  this.failedRequests = [];
@@ -197,6 +222,78 @@ export class Browser {
197
222
  });
198
223
  });
199
224
  }
225
+ trackPage(page, makeActive) {
226
+ if (!this.pageIndexes.has(page)) {
227
+ this.pageIndexes.set(page, this.nextPageIndex++);
228
+ this.pageNavigations.set(page, {
229
+ sequence: 0,
230
+ occurred_at: null,
231
+ url: page.url(),
232
+ type: "unknown",
233
+ });
234
+ this.attachDiagnosticListeners(page);
235
+ page.on("domcontentloaded", () => this.recordDocumentNavigation(page));
236
+ page.once("close", () => {
237
+ this.pageRecency.delete(page);
238
+ this.pageNavigations.delete(page);
239
+ if (this.page === page)
240
+ this.selectMostRecentPage();
241
+ });
242
+ }
243
+ if (makeActive)
244
+ this.setActivePage(page);
245
+ }
246
+ setActivePage(page) {
247
+ if (page.isClosed())
248
+ return;
249
+ this.page = page;
250
+ this.pageRecency.set(page, ++this.recencyClock);
251
+ }
252
+ recordDocumentNavigation(page) {
253
+ if (page.isClosed())
254
+ return;
255
+ const previous = this.pageNavigations.get(page);
256
+ this.pageNavigations.set(page, {
257
+ sequence: (previous?.sequence ?? 0) + 1,
258
+ occurred_at: new Date().toISOString(),
259
+ url: page.url(),
260
+ type: "unknown",
261
+ });
262
+ }
263
+ async describeNavigation(page) {
264
+ const current = this.pageNavigations.get(page) ?? {
265
+ sequence: 0,
266
+ occurred_at: null,
267
+ url: page.url(),
268
+ type: "unknown",
269
+ };
270
+ const type = await page
271
+ .evaluate(() => {
272
+ const entry = performance.getEntriesByType("navigation")[0];
273
+ const observed = entry?.type;
274
+ return observed === "navigate" ||
275
+ observed === "reload" ||
276
+ observed === "back_forward" ||
277
+ observed === "prerender"
278
+ ? observed
279
+ : "unknown";
280
+ })
281
+ .catch(() => current.type);
282
+ const latest = this.pageNavigations.get(page);
283
+ if (latest?.sequence === current.sequence) {
284
+ const updated = { ...latest, type };
285
+ this.pageNavigations.set(page, updated);
286
+ return updated;
287
+ }
288
+ return latest ?? current;
289
+ }
290
+ selectMostRecentPage() {
291
+ const surviving = [...this.pageIndexes.keys()].filter((page) => !page.isClosed());
292
+ surviving.sort((a, b) => (this.pageRecency.get(b) ?? 0) - (this.pageRecency.get(a) ?? 0));
293
+ this.page = surviving[0] ?? null;
294
+ if (this.page)
295
+ this.pageRecency.set(this.page, ++this.recencyClock);
296
+ }
200
297
  /**
201
298
  * Snapshot of every event captured since `open()`. Returned objects are
202
299
  * copies, so callers can safely store them after `close()`.
@@ -456,6 +553,317 @@ export class Browser {
456
553
  }
457
554
  });
458
555
  }
556
+ async sessionStatus() {
557
+ const tabs = await this.sessionTabs();
558
+ const active = tabs.find((tab) => tab.active);
559
+ if (!active)
560
+ throw new BrowserSessionActionError("no_active_tab", "No active browser tab.");
561
+ return {
562
+ phase: "ready",
563
+ active_tab: active.index,
564
+ tab_count: tabs.length,
565
+ revision: this.sessionRevision,
566
+ navigation: active.navigation,
567
+ };
568
+ }
569
+ async sessionTabs() {
570
+ this.selectMostRecentPageIfNeeded();
571
+ const pages = [...this.pageIndexes.entries()]
572
+ .filter(([page]) => !page.isClosed())
573
+ .sort((a, b) => a[1] - b[1]);
574
+ return await Promise.all(pages.map(async ([page, index]) => ({
575
+ index,
576
+ title: await page.title().catch(() => ""),
577
+ url: page.url(),
578
+ active: page === this.page,
579
+ revision: this.sessionRevision,
580
+ navigation: await this.describeNavigation(page),
581
+ })));
582
+ }
583
+ async sessionSelectTab(index) {
584
+ const page = this.pageForIndex(index);
585
+ await page.bringToFront();
586
+ this.setActivePage(page);
587
+ this.sessionRevision++;
588
+ return this.describeTab(page);
589
+ }
590
+ async sessionOpenTab(url) {
591
+ if (!this.context)
592
+ throw new BrowserSessionActionError("not_ready", "Browser is not open.");
593
+ const previous = this.page;
594
+ const page = await this.context.newPage();
595
+ this.trackPage(page, true);
596
+ try {
597
+ await page.goto(url, { waitUntil: this.opts.waitUntil ?? "load" });
598
+ this.sessionRevision++;
599
+ return await this.describeTab(page);
600
+ }
601
+ catch (error) {
602
+ await page.close().catch(() => { });
603
+ if (previous && !previous.isClosed())
604
+ this.setActivePage(previous);
605
+ throw error;
606
+ }
607
+ }
608
+ async sessionCloseTab(index) {
609
+ const surviving = [...this.pageIndexes.keys()].filter((page) => !page.isClosed());
610
+ if (surviving.length <= 1) {
611
+ throw new BrowserSessionActionError("final_tab", "The final browser tab cannot be closed.");
612
+ }
613
+ const page = this.pageForIndex(index);
614
+ await page.close();
615
+ this.selectMostRecentPageIfNeeded();
616
+ this.sessionRevision++;
617
+ return this.describeTab(this.currentPage);
618
+ }
619
+ async sessionGoto(url) {
620
+ const page = this.currentPage;
621
+ await page.goto(url, { waitUntil: this.opts.waitUntil ?? "load" });
622
+ this.sessionRevision++;
623
+ return this.describeTab(page);
624
+ }
625
+ async sessionReload() {
626
+ const page = this.currentPage;
627
+ await page.reload({ waitUntil: this.opts.waitUntil ?? "load" });
628
+ this.sessionRevision++;
629
+ return this.describeTab(page);
630
+ }
631
+ async sessionClick(locator) {
632
+ const target = await this.strictSessionLocator(locator);
633
+ await target.click();
634
+ this.sessionRevision++;
635
+ return { revision: this.sessionRevision };
636
+ }
637
+ async sessionFill(locator, value) {
638
+ const target = await this.strictSessionLocator(locator);
639
+ await target.fill(value);
640
+ this.sessionRevision++;
641
+ return { revision: this.sessionRevision };
642
+ }
643
+ async sessionPress(key) {
644
+ await this.currentPage.keyboard.press(key);
645
+ this.sessionRevision++;
646
+ return { revision: this.sessionRevision };
647
+ }
648
+ async sessionWait(locator) {
649
+ const target = this.sessionLocator(locator);
650
+ await target.first().waitFor({ state: "visible" });
651
+ await this.requireStrictLocator(target);
652
+ this.sessionRevision++;
653
+ return { revision: this.sessionRevision };
654
+ }
655
+ async sessionInspect(locator) {
656
+ const page = this.currentPage;
657
+ const tabIndex = this.pageIndexes.get(page);
658
+ if (tabIndex === undefined) {
659
+ throw new BrowserSessionActionError("no_active_tab", "No active browser tab.");
660
+ }
661
+ const rawText = locator
662
+ ? await (await this.strictSessionLocator(locator)).innerText()
663
+ : await page.locator("body").innerText();
664
+ const textResult = truncateUtf8(rawText, 256 * 1024);
665
+ const observed = await page.evaluate(() => {
666
+ const visible = (element) => {
667
+ const style = getComputedStyle(element);
668
+ const rect = element.getBoundingClientRect();
669
+ return (style.display !== "none" &&
670
+ style.visibility !== "hidden" &&
671
+ Number(style.opacity) > 0 &&
672
+ rect.width > 0 &&
673
+ rect.height > 0);
674
+ };
675
+ const named = (element) => {
676
+ const aria = element.getAttribute("aria-label")?.trim();
677
+ if (aria)
678
+ return aria;
679
+ const labelledBy = element.getAttribute("aria-labelledby");
680
+ if (labelledBy) {
681
+ const text = labelledBy
682
+ .split(/\s+/)
683
+ .map((id) => document.getElementById(id)?.textContent?.trim() ?? "")
684
+ .filter(Boolean)
685
+ .join(" ");
686
+ if (text)
687
+ return text;
688
+ }
689
+ if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {
690
+ const label = element.labels?.[0]?.textContent?.trim();
691
+ if (label)
692
+ return label;
693
+ return element.placeholder?.trim() ?? "";
694
+ }
695
+ if (element instanceof HTMLSelectElement) {
696
+ return element.labels?.[0]?.textContent?.trim() ?? "";
697
+ }
698
+ return element.textContent?.replace(/\s+/g, " ").trim().slice(0, 200) ?? "";
699
+ };
700
+ const describe = (element) => {
701
+ const tag = element.tagName.toLowerCase();
702
+ const role = element.getAttribute("role")?.trim();
703
+ let kind = role || tag;
704
+ if (element instanceof HTMLAnchorElement)
705
+ kind = "link";
706
+ if (element instanceof HTMLButtonElement)
707
+ kind = "button";
708
+ const attributes = {};
709
+ const type = element.getAttribute("type")?.trim();
710
+ if (type)
711
+ attributes.type = type;
712
+ const name = element.getAttribute("name")?.trim();
713
+ if (name)
714
+ attributes.name = name;
715
+ const autocomplete = element.getAttribute("autocomplete")?.trim();
716
+ if (autocomplete)
717
+ attributes.autocomplete = autocomplete;
718
+ if (element instanceof HTMLAnchorElement && element.href) {
719
+ try {
720
+ const href = new URL(element.href);
721
+ href.username = "";
722
+ href.password = "";
723
+ href.search = "";
724
+ href.hash = "";
725
+ attributes.href = href.toString();
726
+ }
727
+ catch {
728
+ // Ignore malformed link targets.
729
+ }
730
+ }
731
+ if ("disabled" in element && element.disabled) {
732
+ attributes.disabled = true;
733
+ }
734
+ if ((element instanceof HTMLInputElement && element.type !== "hidden") ||
735
+ element instanceof HTMLTextAreaElement ||
736
+ element instanceof HTMLSelectElement) {
737
+ return {
738
+ kind,
739
+ name: named(element),
740
+ attributes,
741
+ has_value: element.value.length > 0,
742
+ };
743
+ }
744
+ return { kind, name: named(element), attributes };
745
+ };
746
+ const selector = [
747
+ "a[href]",
748
+ "button",
749
+ "input:not([type=hidden])",
750
+ "select",
751
+ "textarea",
752
+ '[role="button"]',
753
+ '[role="link"]',
754
+ '[role="checkbox"]',
755
+ '[role="radio"]',
756
+ '[role="textbox"]',
757
+ '[role="combobox"]',
758
+ ].join(",");
759
+ const controls = Array.from(document.querySelectorAll(selector))
760
+ .filter(visible)
761
+ .slice(0, 500)
762
+ .map(describe);
763
+ const focus = document.activeElement;
764
+ return {
765
+ controls,
766
+ focus: focus && focus !== document.body && visible(focus) ? describe(focus) : null,
767
+ };
768
+ });
769
+ return {
770
+ active_tab: tabIndex,
771
+ url: page.url(),
772
+ title: await page.title(),
773
+ text: textResult.text,
774
+ controls: observed.controls,
775
+ focus: observed.focus,
776
+ revision: this.sessionRevision,
777
+ navigation: await this.describeNavigation(page),
778
+ truncated: textResult.truncated,
779
+ };
780
+ }
781
+ async sessionScreenshot(outInput) {
782
+ const out = resolve(outInput);
783
+ let parent;
784
+ try {
785
+ parent = statSync(dirname(out));
786
+ }
787
+ catch {
788
+ throw new BrowserSessionActionError("screenshot_parent_missing", "Screenshot parent directory must already exist.");
789
+ }
790
+ if (!parent.isDirectory()) {
791
+ throw new BrowserSessionActionError("screenshot_parent_invalid", "Screenshot parent is not a directory.");
792
+ }
793
+ const buffer = await this.currentPage.screenshot({ type: "png", fullPage: true });
794
+ if (buffer.length < 24 || buffer.toString("ascii", 1, 4) !== "PNG") {
795
+ throw new BrowserSessionActionError("screenshot_invalid", "Browser returned an invalid PNG.");
796
+ }
797
+ try {
798
+ writeFileSync(out, buffer, { flag: "wx", mode: 0o600 });
799
+ chmodSync(out, 0o600);
800
+ }
801
+ catch (error) {
802
+ if (error.code === "EEXIST") {
803
+ throw new BrowserSessionActionError("screenshot_exists", "Screenshot output already exists.");
804
+ }
805
+ throw error;
806
+ }
807
+ this.sessionRevision++;
808
+ return {
809
+ path: out,
810
+ width: buffer.readUInt32BE(16),
811
+ height: buffer.readUInt32BE(20),
812
+ revision: this.sessionRevision,
813
+ };
814
+ }
815
+ sessionLocator(locator) {
816
+ const page = this.currentPage;
817
+ switch (locator.kind) {
818
+ case "selector":
819
+ return page.locator(locator.value);
820
+ case "role":
821
+ return page.getByRole(locator.value, {
822
+ ...(locator.name === undefined ? {} : { name: locator.name, exact: !locator.partial }),
823
+ });
824
+ case "label":
825
+ return page.getByLabel(locator.value, { exact: !locator.partial });
826
+ case "text":
827
+ return page.getByText(locator.value, { exact: !locator.partial });
828
+ }
829
+ }
830
+ async strictSessionLocator(locator) {
831
+ return this.requireStrictLocator(this.sessionLocator(locator));
832
+ }
833
+ async requireStrictLocator(locator) {
834
+ const count = await locator.count();
835
+ if (count === 0) {
836
+ throw new BrowserSessionActionError("locator_not_found", "Locator matched no elements.");
837
+ }
838
+ if (count !== 1) {
839
+ throw new BrowserSessionActionError("locator_ambiguous", `Locator matched ${count} elements; refine it before acting.`);
840
+ }
841
+ return locator;
842
+ }
843
+ pageForIndex(index) {
844
+ const entry = [...this.pageIndexes.entries()].find(([page, pageIndex]) => pageIndex === index && !page.isClosed());
845
+ if (!entry)
846
+ throw new BrowserSessionActionError("tab_not_found", "Browser tab was not found.");
847
+ return entry[0];
848
+ }
849
+ async describeTab(page) {
850
+ const index = this.pageIndexes.get(page);
851
+ if (index === undefined || page.isClosed()) {
852
+ throw new BrowserSessionActionError("tab_not_found", "Browser tab was not found.");
853
+ }
854
+ return {
855
+ index,
856
+ title: await page.title().catch(() => ""),
857
+ url: page.url(),
858
+ active: page === this.page,
859
+ revision: this.sessionRevision,
860
+ navigation: await this.describeNavigation(page),
861
+ };
862
+ }
863
+ selectMostRecentPageIfNeeded() {
864
+ if (!this.page || this.page.isClosed())
865
+ this.selectMostRecentPage();
866
+ }
459
867
  /**
460
868
  * Run occlusion checks on one or more selectors. For each, samples a grid
461
869
  * of points inside the element's bounding rect and uses
@@ -589,6 +997,12 @@ export class Browser {
589
997
  throw new Error("Browser not opened. Call open() first.");
590
998
  await this.context.addInitScript(script);
591
999
  }
1000
+ /** Snapshot all cookies in the live persistent context. */
1001
+ async cookies() {
1002
+ if (!this.context)
1003
+ throw new Error("Browser not opened. Call open() first.");
1004
+ return this.context.cookies();
1005
+ }
592
1006
  /**
593
1007
  * Sync cookies from the live context back into the jar (if one was provided),
594
1008
  * then tear everything down. Safe to call multiple times.
@@ -610,6 +1024,12 @@ export class Browser {
610
1024
  await this.context.close().catch(() => { });
611
1025
  this.context = null;
612
1026
  this.page = null;
1027
+ this.pageIndexes.clear();
1028
+ this.pageRecency.clear();
1029
+ this.pageNavigations.clear();
1030
+ this.nextPageIndex = 0;
1031
+ this.recencyClock = 0;
1032
+ this.sessionRevision = 0;
613
1033
  }
614
1034
  }
615
1035
  // ---------------------------------------------------------------------------
@@ -655,3 +1075,12 @@ function normalizeSameSite(s) {
655
1075
  return "None";
656
1076
  return undefined;
657
1077
  }
1078
+ function truncateUtf8(value, maxBytes) {
1079
+ const buffer = Buffer.from(value, "utf8");
1080
+ if (buffer.length <= maxBytes)
1081
+ return { text: value, truncated: false };
1082
+ let end = maxBytes;
1083
+ while (end > 0 && (buffer[end] & 0xc0) === 0x80)
1084
+ end--;
1085
+ return { text: buffer.subarray(0, end).toString("utf8"), truncated: true };
1086
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"geometry.d.ts","sourceRoot":"","sources":["../../../src/lib/browser/geometry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"geometry.d.ts","sourceRoot":"","sources":["../../../src/lib/browser/geometry.ts"],"names":[],"mappings":"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"}