@neuralnomads/codenomad-dev 0.20.1-dev-20261019-e56b286a → 0.20.1-dev-20261019-e32d9331

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 (72) hide show
  1. package/dist/automation/browser-page.js +97 -0
  2. package/dist/automation/browser-page.js.map +1 -0
  3. package/dist/automation/browser-page.test.js +119 -0
  4. package/dist/automation/browser-page.test.js.map +1 -0
  5. package/dist/automation/page/actions.js +107 -83
  6. package/dist/automation/page/actions.js.map +1 -1
  7. package/dist/automation/page/input.js +130 -0
  8. package/dist/automation/page/input.js.map +1 -0
  9. package/dist/automation/page/input.test.js +71 -0
  10. package/dist/automation/page/input.test.js.map +1 -0
  11. package/dist/automation/page/keys.js +99 -0
  12. package/dist/automation/page/keys.js.map +1 -0
  13. package/dist/automation/page/keys.test.js +32 -0
  14. package/dist/automation/page/keys.test.js.map +1 -0
  15. package/dist/automation/page/parse.js +79 -0
  16. package/dist/automation/page/parse.js.map +1 -0
  17. package/dist/automation/page/protocol.js +143 -0
  18. package/dist/automation/page/protocol.js.map +1 -0
  19. package/dist/developer-cdp.js +7 -10
  20. package/dist/developer-cdp.js.map +1 -1
  21. package/dist/developer-cdp.test.js +49 -15
  22. package/dist/developer-cdp.test.js.map +1 -1
  23. package/dist/opencode/automation/desktop-plugin.js +10 -6
  24. package/dist/opencode/automation/desktop-plugin.js.map +1 -1
  25. package/dist/opencode/automation-plugin.js +33 -41
  26. package/dist/opencode/automation-plugin.js.map +1 -1
  27. package/dist/opencode/automation-plugin.test.js +42 -1
  28. package/dist/opencode/automation-plugin.test.js.map +1 -1
  29. package/dist/plugins/automation/plugin.mjs +230 -40
  30. package/dist/plugins/missions/plugin.mjs +21 -0
  31. package/dist/server/routes/automation-plugin.js +7 -5
  32. package/dist/server/routes/automation-plugin.js.map +1 -1
  33. package/dist/server/routes/automation-plugin.test.js +17 -4
  34. package/dist/server/routes/automation-plugin.test.js.map +1 -1
  35. package/package.json +1 -1
  36. package/public/assets/{App-z4rDGruy.js → App-DZMdkLQJ.js} +29 -29
  37. package/public/assets/App-DZMdkLQJ.js.map +1 -0
  38. package/public/assets/{FilesPanel-BR_6pmtI.js → FilesPanel-CgFgL4q7.js} +3 -3
  39. package/public/assets/FilesPanel-CgFgL4q7.js.map +1 -0
  40. package/public/assets/{StatusTab-7nJ4mv4I.js → StatusTab-CaQz8RwN.js} +2 -2
  41. package/public/assets/{StatusTab-7nJ4mv4I.js.map → StatusTab-CaQz8RwN.js.map} +1 -1
  42. package/public/assets/{client-state-CdvbHQef.js → client-state-DikXRKzG.js} +2 -2
  43. package/public/assets/{client-state-CdvbHQef.js.map → client-state-DikXRKzG.js.map} +1 -1
  44. package/public/assets/{client-state-Dy45bMLT.js → client-state-kpF1cbUu.js} +2 -2
  45. package/public/assets/{client-state-Dy45bMLT.js.map → client-state-kpF1cbUu.js.map} +1 -1
  46. package/public/assets/client-state-owner-commands-BMJJQYT-.js +2 -0
  47. package/public/assets/{client-state-owner-commands-CNRMpxmP.js.map → client-state-owner-commands-BMJJQYT-.js.map} +1 -1
  48. package/public/assets/{diff-viewer-DidBGGSg.js → diff-viewer-iFIylM56.js} +2 -2
  49. package/public/assets/{diff-viewer-DidBGGSg.js.map → diff-viewer-iFIylM56.js.map} +1 -1
  50. package/public/assets/{main-2ULMhXOZ.js → main-B0L3f7sD.js} +52 -52
  51. package/public/assets/main-B0L3f7sD.js.map +1 -0
  52. package/public/assets/{markdown-B2vmXRgM.js → markdown-Bh1QlJgA.js} +2 -2
  53. package/public/assets/{markdown-B2vmXRgM.js.map → markdown-Bh1QlJgA.js.map} +1 -1
  54. package/public/assets/{opener-startup-state-settings-card-Bj8IDBCX.js → opener-startup-state-settings-card-mzh22bq8.js} +2 -2
  55. package/public/assets/{opener-startup-state-settings-card-Bj8IDBCX.js.map → opener-startup-state-settings-card-mzh22bq8.js.map} +1 -1
  56. package/public/assets/{startup-state-settings-card-DAkduiFk.js → startup-state-settings-card-B1UMzsQK.js} +2 -2
  57. package/public/assets/{startup-state-settings-card-DAkduiFk.js.map → startup-state-settings-card-B1UMzsQK.js.map} +1 -1
  58. package/public/assets/{startup-state-settings-view-CQ6mkdWM.js → startup-state-settings-view-nZNbhUhQ.js} +2 -2
  59. package/public/assets/{startup-state-settings-view-CQ6mkdWM.js.map → startup-state-settings-view-nZNbhUhQ.js.map} +1 -1
  60. package/public/assets/{terminal-square-DeHY-xG8.js → terminal-square-CdJ4Gt6Y.js} +2 -2
  61. package/public/assets/{terminal-square-DeHY-xG8.js.map → terminal-square-CdJ4Gt6Y.js.map} +1 -1
  62. package/public/assets/{tool-call-DPmRZgHK.js → tool-call-C9ux0znU.js} +4 -4
  63. package/public/assets/{tool-call-DPmRZgHK.js.map → tool-call-C9ux0znU.js.map} +1 -1
  64. package/public/assets/{unified-picker-Dpt39UfN.js → unified-picker-DOP29DIt.js} +2 -2
  65. package/public/assets/{unified-picker-Dpt39UfN.js.map → unified-picker-DOP29DIt.js.map} +1 -1
  66. package/public/index.html +1 -1
  67. package/public/sw.js +1 -1
  68. package/public/sw.js.map +1 -1
  69. package/public/assets/App-z4rDGruy.js.map +0 -1
  70. package/public/assets/FilesPanel-BR_6pmtI.js.map +0 -1
  71. package/public/assets/client-state-owner-commands-CNRMpxmP.js +0 -2
  72. package/public/assets/main-2ULMhXOZ.js.map +0 -1
@@ -0,0 +1,143 @@
1
+ /** Protocol primitives shared by the page engine's actions. */
2
+ /** An element handle passed to a page function, as opposed to a plain value. */
3
+ export class Handle {
4
+ constructor(objectId) {
5
+ this.objectId = objectId;
6
+ }
7
+ }
8
+ export const OBJECT_GROUP = "codenomad-automation";
9
+ export const VALUE_LIMIT = 200;
10
+ export function gone(ref) {
11
+ return new Error(`${ref} is no longer in the page; inspect again`);
12
+ }
13
+ export async function resolveElement(session, ref, backendNodeId) {
14
+ let result;
15
+ try {
16
+ result = await session.channel.send("DOM.resolveNode", { backendNodeId, objectGroup: OBJECT_GROUP });
17
+ }
18
+ catch {
19
+ throw gone(ref);
20
+ }
21
+ await session.checkpoint();
22
+ const objectId = result.object?.objectId;
23
+ if (typeof objectId !== "string")
24
+ throw gone(ref);
25
+ return objectId;
26
+ }
27
+ /** Runs a fixed page function on an element; inputs travel as protocol arguments, never as source.
28
+ * `byValue: false` returns another element handle. */
29
+ export async function callOn(session, ref, objectId, body, args, byValue = true) {
30
+ const result = await session.channel.send("Runtime.callFunctionOn", {
31
+ objectId,
32
+ functionDeclaration: pageFunction(body, session.markAutomation),
33
+ arguments: args.map(value => value instanceof Handle ? { objectId: value.objectId } : { value }),
34
+ returnByValue: byValue,
35
+ objectGroup: OBJECT_GROUP,
36
+ });
37
+ await session.checkpoint();
38
+ const failure = result.exceptionDetails;
39
+ if (failure)
40
+ throw pageError(ref, String(failure.exception?.description ?? failure.text ?? ""));
41
+ const value = result.result;
42
+ if (!byValue) {
43
+ if (typeof value?.objectId !== "string")
44
+ throw gone(ref);
45
+ return value.objectId;
46
+ }
47
+ return value?.value;
48
+ }
49
+ export async function releaseObjects(session) {
50
+ await session.channel.send("Runtime.releaseObjectGroup", { objectGroup: OBJECT_GROUP }).catch(() => undefined);
51
+ }
52
+ function pageFunction(body, mark) {
53
+ const element = `const element = this.nodeType === Node.ELEMENT_NODE ? this : this.parentElement;
54
+ if (!(element instanceof Element) || !element.isConnected) throw new Error("codenomad:gone");`;
55
+ return mark
56
+ ? `function (...args) { ${element} globalThis.__codenomadAutomationDepth = (globalThis.__codenomadAutomationDepth || 0) + 1;
57
+ try { return (() => { ${body} })(); } finally { globalThis.__codenomadAutomationDepth--; } }`
58
+ : `function (...args) { ${element} ${body} }`;
59
+ }
60
+ function pageError(ref, description) {
61
+ const [code, detail = ""] = /codenomad:([a-z-]+)(?::(.*))?/.exec(description.split("\n", 1)[0])?.slice(1) ?? [];
62
+ const quoted = JSON.stringify(detail.slice(0, VALUE_LIMIT));
63
+ switch (code) {
64
+ case "gone": return gone(ref);
65
+ case "not-select": return new Error(`${ref} is not a native select; click it to open its menu, then click the option`);
66
+ case "is-select": return new Error(`${ref} is a native select; use select with its option labels`);
67
+ case "no-option": return new Error(`No option ${quoted} in ${ref}; inspect it to see its options`);
68
+ case "option-disabled": return new Error(`Option ${quoted} of ${ref} is disabled`);
69
+ case "single": return new Error(`${ref} takes exactly one value`);
70
+ case "disabled": return new Error(`${ref} is disabled`);
71
+ case "readonly": return new Error(`${ref} is read-only`);
72
+ case "not-editable": return new Error(`${ref} is not a text field`);
73
+ case "not-text": return new Error(`${ref} is not a text field; use click`);
74
+ case "unfocusable": return new Error(`${ref} cannot take focus (hidden, disabled or behind a dialog); reveal it, then inspect again`);
75
+ case "invalid-value": return new Error(`${quoted} is not a valid value for ${ref}`);
76
+ default: return new Error(`The page rejected the action on ${ref}: ${description.split("\n", 1)[0].slice(0, VALUE_LIMIT)}`);
77
+ }
78
+ }
79
+ /** Marks trusted input (DevTools mouse/keyboard events) in the CodeNomad window. A lease, not a
80
+ * counter: if the clearing call is lost with the connection, the mark still expires. */
81
+ export async function markedInput(session, run) {
82
+ const held = new Map();
83
+ let point = { x: 0, y: 0 };
84
+ let attempted = false;
85
+ const dispatch = async (method, params) => {
86
+ let timestamp;
87
+ if (session.markAutomation) {
88
+ const result = await session.channel.send("Runtime.evaluate", { expression: MARK_INPUT, returnByValue: true });
89
+ const stamp = result.result?.value;
90
+ if (typeof stamp !== "number" || !Number.isFinite(stamp) || stamp <= 0)
91
+ throw new Error("Cannot establish automation input provenance");
92
+ timestamp = stamp;
93
+ }
94
+ const mouse = method === "Input.dispatchMouseEvent";
95
+ if (mouse && typeof params.x === "number" && typeof params.y === "number")
96
+ point = { x: params.x, y: params.y };
97
+ const id = mouse ? `mouse:${params.button}` : `key:${params.code}`;
98
+ const down = mouse ? params.type === "mousePressed" : params.type === "keyDown" || params.type === "rawKeyDown";
99
+ const up = mouse ? params.type === "mouseReleased" : params.type === "keyUp";
100
+ if (down)
101
+ held.set(id, { method, params: { ...params, type: mouse ? "mouseReleased" : "keyUp", buttons: 0, modifiers: 0,
102
+ ...(timestamp === undefined ? {} : { timestamp }) } });
103
+ attempted = true;
104
+ await session.channel.send(method, { ...params,
105
+ ...(timestamp === undefined || !["Input.dispatchMouseEvent", "Input.dispatchKeyEvent"].includes(method) ? {} : { timestamp }) });
106
+ if (up)
107
+ held.delete(id);
108
+ await session.checkpoint();
109
+ };
110
+ try {
111
+ return await run(dispatch);
112
+ }
113
+ catch (error) {
114
+ if (attempted && error instanceof Error && /timed out|timeout/i.test(error.message)) {
115
+ throw new Error("Input timed out: its outcome is unknown. The page was busy and the input may still be delivered; inspect before retrying.");
116
+ }
117
+ throw error;
118
+ }
119
+ finally {
120
+ // Failure may be after admission but before acknowledgement/checkpoint. Release
121
+ // anything potentially held, without a failed checkpoint suppressing cleanup.
122
+ for (const release of [...held.values()].reverse()) {
123
+ try {
124
+ // A frozen page can time out this write too. The release retains the
125
+ // original press's timestamp, so provenance never depends on the timeout.
126
+ if (session.markAutomation)
127
+ await session.channel.send("Runtime.evaluate", { expression: MARK_INPUT, returnByValue: true }).catch(() => undefined);
128
+ const { text: _text, unmodifiedText: _unmodified, ...params } = release.params;
129
+ await session.channel.send(release.method, { ...params, ...(release.method === "Input.dispatchMouseEvent" ? point : {}) });
130
+ }
131
+ catch { /* Best effort, exact original channel only; never retry the action. */ }
132
+ }
133
+ if (session.markAutomation)
134
+ await session.channel.send("Runtime.evaluate", { expression: UNMARK_INPUT, returnByValue: true }).catch(() => undefined);
135
+ }
136
+ }
137
+ export const INPUT_MARK_LEASE_MS = 15_000;
138
+ // CDP timestamps use epoch seconds; DOM event.timeStamp uses the page's monotonic
139
+ // origin. Reading both in the page keeps delayed input within its original interval.
140
+ const MARK_INPUT = `globalThis.__codenomadAutomationInputUntil = performance.now() + ${INPUT_MARK_LEASE_MS}; Date.now() / 1000`;
141
+ // Keep the interval's end for events queued before a stalled renderer recovered.
142
+ const UNMARK_INPUT = "globalThis.__codenomadAutomationInputUntil = Math.min(globalThis.__codenomadAutomationInputUntil || 0, performance.now()); true";
143
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../../src/automation/page/protocol.ts"],"names":[],"mappings":"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","sourcesContent":["/** Protocol primitives shared by the page engine's actions. */\n\n/** One page's protocol connection, whatever carries it (DevTools socket or a native pipe). */\nexport interface PageChannel {\n send(method: string, params?: Record<string, unknown>): Promise<Record<string, unknown>>\n}\n\nexport interface PageSession {\n channel: PageChannel\n /** Throws once the page changed since the operation began; runs between protocol steps. */\n checkpoint(): Promise<void>\n /** The trusted CodeNomad window: page-side automation and trusted input are marked so they\n * never count as a human answer (`form-answer-interaction.ts`). Never set this in a user's web page. */\n markAutomation: boolean\n}\n\n/** An element handle passed to a page function, as opposed to a plain value. */\nexport class Handle {\n constructor(readonly objectId: string) {}\n}\n\nexport const OBJECT_GROUP = \"codenomad-automation\"\nexport const VALUE_LIMIT = 200\n\nexport function gone(ref: string): Error {\n return new Error(`${ref} is no longer in the page; inspect again`)\n}\n\nexport async function resolveElement(session: PageSession, ref: string, backendNodeId: number): Promise<string> {\n let result: Record<string, unknown>\n try {\n result = await session.channel.send(\"DOM.resolveNode\", { backendNodeId, objectGroup: OBJECT_GROUP })\n } catch {\n throw gone(ref)\n }\n await session.checkpoint()\n const objectId = (result.object as { objectId?: unknown } | undefined)?.objectId\n if (typeof objectId !== \"string\") throw gone(ref)\n return objectId\n}\n\n/** Runs a fixed page function on an element; inputs travel as protocol arguments, never as source.\n * `byValue: false` returns another element handle. */\nexport async function callOn(session: PageSession, ref: string, objectId: string, body: string, args: unknown[], byValue = true): Promise<unknown> {\n const result = await session.channel.send(\"Runtime.callFunctionOn\", {\n objectId,\n functionDeclaration: pageFunction(body, session.markAutomation),\n arguments: args.map(value => value instanceof Handle ? { objectId: value.objectId } : { value }),\n returnByValue: byValue,\n objectGroup: OBJECT_GROUP,\n })\n await session.checkpoint()\n const failure = result.exceptionDetails as { exception?: { description?: unknown }; text?: unknown } | undefined\n if (failure) throw pageError(ref, String(failure.exception?.description ?? failure.text ?? \"\"))\n const value = result.result as { value?: unknown; objectId?: unknown } | undefined\n if (!byValue) {\n if (typeof value?.objectId !== \"string\") throw gone(ref)\n return value.objectId\n }\n return value?.value\n}\n\nexport async function releaseObjects(session: PageSession): Promise<void> {\n await session.channel.send(\"Runtime.releaseObjectGroup\", { objectGroup: OBJECT_GROUP }).catch(() => undefined)\n}\n\nfunction pageFunction(body: string, mark: boolean): string {\n const element = `const element = this.nodeType === Node.ELEMENT_NODE ? this : this.parentElement;\n if (!(element instanceof Element) || !element.isConnected) throw new Error(\"codenomad:gone\");`\n return mark\n ? `function (...args) { ${element} globalThis.__codenomadAutomationDepth = (globalThis.__codenomadAutomationDepth || 0) + 1;\n try { return (() => { ${body} })(); } finally { globalThis.__codenomadAutomationDepth--; } }`\n : `function (...args) { ${element} ${body} }`\n}\n\nfunction pageError(ref: string, description: string): Error {\n const [code, detail = \"\"] = /codenomad:([a-z-]+)(?::(.*))?/.exec(description.split(\"\\n\", 1)[0])?.slice(1) ?? []\n const quoted = JSON.stringify(detail.slice(0, VALUE_LIMIT))\n switch (code) {\n case \"gone\": return gone(ref)\n case \"not-select\": return new Error(`${ref} is not a native select; click it to open its menu, then click the option`)\n case \"is-select\": return new Error(`${ref} is a native select; use select with its option labels`)\n case \"no-option\": return new Error(`No option ${quoted} in ${ref}; inspect it to see its options`)\n case \"option-disabled\": return new Error(`Option ${quoted} of ${ref} is disabled`)\n case \"single\": return new Error(`${ref} takes exactly one value`)\n case \"disabled\": return new Error(`${ref} is disabled`)\n case \"readonly\": return new Error(`${ref} is read-only`)\n case \"not-editable\": return new Error(`${ref} is not a text field`)\n case \"not-text\": return new Error(`${ref} is not a text field; use click`)\n case \"unfocusable\": return new Error(`${ref} cannot take focus (hidden, disabled or behind a dialog); reveal it, then inspect again`)\n case \"invalid-value\": return new Error(`${quoted} is not a valid value for ${ref}`)\n default: return new Error(`The page rejected the action on ${ref}: ${description.split(\"\\n\", 1)[0].slice(0, VALUE_LIMIT)}`)\n }\n}\n\n/** Marks trusted input (DevTools mouse/keyboard events) in the CodeNomad window. A lease, not a\n * counter: if the clearing call is lost with the connection, the mark still expires. */\nexport async function markedInput<T>(session: PageSession, run: (dispatch: (method: string, params: Record<string, unknown>) => Promise<void>) => Promise<T>): Promise<T> {\n const held = new Map<string, { method: string; params: Record<string, unknown> }>()\n let point = { x: 0, y: 0 }\n let attempted = false\n const dispatch = async (method: string, params: Record<string, unknown>) => {\n let timestamp: number | undefined\n if (session.markAutomation) {\n const result = await session.channel.send(\"Runtime.evaluate\", { expression: MARK_INPUT, returnByValue: true })\n const stamp = (result.result as { value?: unknown } | undefined)?.value\n if (typeof stamp !== \"number\" || !Number.isFinite(stamp) || stamp <= 0) throw new Error(\"Cannot establish automation input provenance\")\n timestamp = stamp\n }\n const mouse = method === \"Input.dispatchMouseEvent\"\n if (mouse && typeof params.x === \"number\" && typeof params.y === \"number\") point = { x: params.x, y: params.y }\n const id = mouse ? `mouse:${params.button}` : `key:${params.code}`\n const down = mouse ? params.type === \"mousePressed\" : params.type === \"keyDown\" || params.type === \"rawKeyDown\"\n const up = mouse ? params.type === \"mouseReleased\" : params.type === \"keyUp\"\n if (down) held.set(id, { method, params: { ...params, type: mouse ? \"mouseReleased\" : \"keyUp\", buttons: 0, modifiers: 0,\n ...(timestamp === undefined ? {} : { timestamp }) } })\n attempted = true\n await session.channel.send(method, { ...params,\n ...(timestamp === undefined || ![\"Input.dispatchMouseEvent\", \"Input.dispatchKeyEvent\"].includes(method) ? {} : { timestamp }) })\n if (up) held.delete(id)\n await session.checkpoint()\n }\n try {\n return await run(dispatch)\n } catch (error) {\n if (attempted && error instanceof Error && /timed out|timeout/i.test(error.message)) {\n throw new Error(\"Input timed out: its outcome is unknown. The page was busy and the input may still be delivered; inspect before retrying.\")\n }\n throw error\n } finally {\n // Failure may be after admission but before acknowledgement/checkpoint. Release\n // anything potentially held, without a failed checkpoint suppressing cleanup.\n for (const release of [...held.values()].reverse()) {\n try {\n // A frozen page can time out this write too. The release retains the\n // original press's timestamp, so provenance never depends on the timeout.\n if (session.markAutomation) await session.channel.send(\"Runtime.evaluate\", { expression: MARK_INPUT, returnByValue: true }).catch(() => undefined)\n const { text: _text, unmodifiedText: _unmodified, ...params } = release.params\n await session.channel.send(release.method, { ...params, ...(release.method === \"Input.dispatchMouseEvent\" ? point : {}) })\n } catch { /* Best effort, exact original channel only; never retry the action. */ }\n }\n if (session.markAutomation) await session.channel.send(\"Runtime.evaluate\", { expression: UNMARK_INPUT, returnByValue: true }).catch(() => undefined)\n }\n}\n\nexport const INPUT_MARK_LEASE_MS = 15_000\n// CDP timestamps use epoch seconds; DOM event.timeStamp uses the page's monotonic\n// origin. Reading both in the page keeps delayed input within its original interval.\nconst MARK_INPUT = `globalThis.__codenomadAutomationInputUntil = performance.now() + ${INPUT_MARK_LEASE_MS}; Date.now() / 1000`\n// Keep the interval's end for events queued before a stalled renderer recovered.\nconst UNMARK_INPUT = \"globalThis.__codenomadAutomationInputUntil = Math.min(globalThis.__codenomadAutomationInputUntil || 0, performance.now()); true\"\n"]}
@@ -1,5 +1,5 @@
1
1
  import { WebSocket } from "undici";
2
- import { performAction, snapshotPage } from "./automation/page/actions";
2
+ import { bindRefs, performAction, snapshotPage } from "./automation/page/actions";
3
3
  import { RefTable } from "./automation/page/refs";
4
4
  import { SnapshotScopeError } from "./automation/page/snapshot";
5
5
  const DEFAULT_TIMEOUT_MS = 5_000;
@@ -56,15 +56,12 @@ export class DeveloperCdp {
56
56
  };
57
57
  });
58
58
  }
59
- async act(action) {
60
- return this.exclusive(action.runId, async () => {
61
- const state = await this.ensure(action);
62
- const epoch = state.navigationEpoch;
63
- const backendNodeId = this.refs.resolve(action.ref, this.generation(state));
64
- const session = this.session(state, epoch, "Page changed during action; inspect again");
65
- return performAction(session, action.kind === "click" ? { kind: "click", ref: action.ref, backendNodeId }
66
- : action.kind === "type" ? { kind: "type", ref: action.ref, backendNodeId, text: action.text, clear: action.clear }
67
- : { kind: "select", ref: action.ref, backendNodeId, values: action.values });
59
+ async act(identity, action) {
60
+ return this.exclusive(identity.runId, async () => {
61
+ const state = await this.ensure(identity);
62
+ const epoch = state.navigationEpoch, generation = this.generation(state);
63
+ const page = bindRefs(action, ref => this.refs.resolve(ref, generation));
64
+ return performAction(this.session(state, epoch, "Page changed during action; inspect again"), page);
68
65
  });
69
66
  }
70
67
  /** Refs belong to one target and navigation epoch. */
@@ -1 +1 @@
1
- {"version":3,"file":"developer-cdp.js","sourceRoot":"","sources":["../src/developer-cdp.ts"],"names":[],"mappings":"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","sourcesContent":["import { WebSocket } from \"undici\"\nimport { performAction, snapshotPage, type PageActionResult, type PageSession } from \"./automation/page/actions\"\nimport { RefTable } from \"./automation/page/refs\"\nimport { SnapshotScopeError } from \"./automation/page/snapshot\"\n\nconst DEFAULT_TIMEOUT_MS = 5_000\nconst DEFAULT_MAX_SCREENSHOT_BYTES = 5 * 1024 * 1024\nconst DIAGNOSTIC_LIMIT = 1_000\nconst DIAGNOSTIC_TEXT_LIMIT = 512\nconst DISCOVERY_TEXT_LIMIT = 256 * 1024\nconst DISCOVERY_TARGET_LIMIT = 64\nconst DISCOVERY_PROBE_CONCURRENCY = 4\nconst CONTEXT_EXPRESSION = `(() => {\n const root = document.querySelector('[data-tab-visible=\"true\"][data-instance-id]');\n const pane = root?.querySelector('.session-cache-pane[data-session-active=\"true\"][data-session-id]');\n return {\n windowId: window.__CODENOMAD_WINDOW_ID__ ?? null,\n instanceId: root?.getAttribute('data-instance-id') ?? null,\n sessionId: pane?.getAttribute('data-session-id') ?? null,\n };\n})()`\n\nexport interface DeveloperCdpSelection {\n endpoint: string\n runId: string\n windowId: string\n sessionId?: string\n}\n\nexport interface DeveloperCdpIdentity extends DeveloperCdpSelection {\n instanceId?: string\n}\n\nexport interface DeveloperCdpContext {\n windowId: string\n instanceId: string | null\n sessionId: string | null\n}\n\nexport interface DeveloperCdpDiagnostic {\n level: \"log\" | \"warning\" | \"error\"\n text: string\n}\n\nexport interface DeveloperCdpInspection {\n target: { id: string; title: string; url: string }\n context: DeveloperCdpContext\n /** Indented accessibility outline with refs (`automation/page/snapshot.ts`). */\n snapshot: string\n /** Lines that hide part of the page; inspect their ref to expand them. */\n collapsed: number\n diagnostics: DeveloperCdpDiagnostic[]\n}\n\n/** A full inspection, or one limited to a ref's subtree and/or matching text. */\nexport interface DeveloperCdpInspectOptions {\n ref?: string\n query?: string\n}\n\nexport type DeveloperCdpAction =\n | (DeveloperCdpIdentity & { kind: \"click\"; ref: string })\n | (DeveloperCdpIdentity & { kind: \"type\"; ref: string; text: string; clear: boolean })\n | (DeveloperCdpIdentity & { kind: \"select\"; ref: string; values: string[] })\n\nexport interface DeveloperCdpScreenshot {\n mediaType: \"image/png\"\n data: string\n bytes: number\n}\n\ninterface CdpSocket {\n onopen: ((event: unknown) => void) | null\n onmessage: ((event: { data: unknown }) => void) | null\n onclose: ((event: unknown) => void) | null\n onerror: ((event: unknown) => void) | null\n send(data: string): void\n close(): void\n}\n\ninterface DeveloperCdpDependencies {\n fetch: typeof globalThis.fetch\n connect: (url: string) => CdpSocket\n timeoutMs: number\n maxScreenshotBytes: number\n}\n\ninterface CdpTarget {\n id: string\n title: string\n type: string\n url: string\n webSocketDebuggerUrl: string\n}\n\ninterface CdpResponse {\n id?: number\n method?: string\n params?: Record<string, unknown>\n result?: Record<string, unknown>\n error?: { code?: number; message?: string }\n}\n\ninterface PendingCommand {\n resolve: (value: Record<string, unknown>) => void\n reject: (error: Error) => void\n timer: NodeJS.Timeout\n}\n\ninterface RunState {\n endpoint: string\n windowId: string\n sessionId?: string\n instanceId?: string\n context?: DeveloperCdpContext\n target?: CdpTarget\n socket?: CdpSocket\n open?: Promise<void>\n /** Distinguishes this run's refs from an earlier state's on the same target. */\n stamp: number\n nextCommandId: number\n navigationEpoch: number\n pending: Map<number, PendingCommand>\n diagnostics: DeveloperCdpDiagnostic[]\n}\n\nexport class DeveloperCdp {\n private readonly dependencies: DeveloperCdpDependencies\n private readonly runs = new Map<string, RunState>()\n private readonly operations = new Map<string, Promise<void>>()\n /** Shared by runs so a ref name is never reused for another element. */\n private readonly refs = new RefTable()\n private stamps = 0\n\n constructor(dependencies: Partial<DeveloperCdpDependencies> = {}) {\n this.dependencies = {\n fetch: globalThis.fetch,\n connect: (url) => new WebSocket(url) as unknown as CdpSocket,\n timeoutMs: DEFAULT_TIMEOUT_MS,\n maxScreenshotBytes: DEFAULT_MAX_SCREENSHOT_BYTES,\n ...dependencies,\n }\n }\n\n async inspect(identity: DeveloperCdpIdentity, options: DeveloperCdpInspectOptions = {}): Promise<DeveloperCdpInspection> {\n return this.exclusive(identity.runId, async () => {\n const state = await this.ensure(identity)\n const generation = this.generation(state)\n const root = options.ref === undefined ? undefined : this.refs.resolve(options.ref, generation)\n let snapshot\n try {\n snapshot = await snapshotPage(this.session(state, state.navigationEpoch, \"Page changed during inspection; inspect again\"),\n () => this.refs.issuer(generation), { rootBackendNodeId: root, query: options.query })\n } catch (error) {\n if (error instanceof SnapshotScopeError) throw new Error(`${options.ref} is no longer in the page; inspect again`)\n throw error\n }\n return {\n target: { id: state.target!.id, title: state.target!.title, url: state.target!.url },\n context: state.context!,\n snapshot: snapshot.text,\n collapsed: snapshot.collapsed,\n diagnostics: state.diagnostics.splice(0),\n }\n })\n }\n\n async act(action: DeveloperCdpAction): Promise<PageActionResult> {\n return this.exclusive(action.runId, async () => {\n const state = await this.ensure(action)\n const epoch = state.navigationEpoch\n const backendNodeId = this.refs.resolve(action.ref, this.generation(state))\n const session = this.session(state, epoch, \"Page changed during action; inspect again\")\n return performAction(session, action.kind === \"click\" ? { kind: \"click\", ref: action.ref, backendNodeId }\n : action.kind === \"type\" ? { kind: \"type\", ref: action.ref, backendNodeId, text: action.text, clear: action.clear }\n : { kind: \"select\", ref: action.ref, backendNodeId, values: action.values })\n })\n }\n\n /** Refs belong to one target and navigation epoch. */\n private generation(state: RunState): string {\n return `${state.stamp}\\0${state.target!.id}\\0${state.navigationEpoch}`\n }\n\n private session(state: RunState, epoch: number, message: string): PageSession {\n return {\n channel: { send: (method, params) => this.command(state, method, params) },\n checkpoint: () => this.assertContextCurrent(state, epoch, message),\n markAutomation: true,\n }\n }\n\n async screenshot(identity: DeveloperCdpIdentity): Promise<DeveloperCdpScreenshot> {\n return this.exclusive(identity.runId, async () => {\n const state = await this.ensure(identity)\n const epoch = state.navigationEpoch\n const result = await this.command(state, \"Page.captureScreenshot\", {\n format: \"png\",\n fromSurface: true,\n captureBeyondViewport: false,\n })\n await this.assertContextCurrent(state, epoch, \"Page changed during screenshot; capture again\")\n if (typeof result.data !== \"string\") throw new Error(\"Chrome returned an invalid screenshot\")\n const bytes = Buffer.from(result.data, \"base64\").byteLength\n if (bytes > this.dependencies.maxScreenshotBytes) {\n throw new Error(`Screenshot exceeds ${this.dependencies.maxScreenshotBytes} byte limit`)\n }\n return { mediaType: \"image/png\", data: result.data, bytes }\n })\n }\n\n close(runId?: string): void {\n for (const [id, state] of this.runs) {\n if (runId && id !== runId) continue\n this.disconnect(state, new Error(\"Developer CDP controller closed\"))\n this.runs.delete(id)\n }\n }\n\n async context(selection: DeveloperCdpSelection): Promise<DeveloperCdpContext> {\n return this.exclusive(selection.runId, async () => (await this.ensure(selection)).context!)\n }\n\n\n private async ensure(identity: DeveloperCdpSelection | DeveloperCdpIdentity): Promise<RunState> {\n if (!identity.runId.trim()) throw new Error(\"runId is required\")\n const endpoint = discoveryUrl(identity.endpoint)\n for (const [runId, previous] of this.runs) {\n if (runId === identity.runId) continue\n this.disconnect(previous, new Error(\"Developer run was replaced\"))\n this.runs.delete(runId)\n }\n let state = this.runs.get(identity.runId)\n if (!state || state.endpoint !== endpoint || state.windowId !== identity.windowId || state.sessionId !== identity.sessionId\n || (\"instanceId\" in identity && state.instanceId !== identity.instanceId)) {\n if (state) this.disconnect(state, new Error(\"CDP endpoint changed\"))\n state = this.newState(endpoint, identity.windowId, identity.sessionId, \"instanceId\" in identity ? identity.instanceId : undefined)\n this.runs.set(identity.runId, state)\n }\n return this.ensureTarget(state)\n }\n\n private newState(endpoint: string, windowId: string, sessionId?: string, instanceId?: string): RunState {\n return {\n endpoint,\n windowId,\n sessionId,\n instanceId,\n stamp: ++this.stamps,\n nextCommandId: 0,\n navigationEpoch: 0,\n pending: new Map(),\n diagnostics: [],\n }\n }\n\n private async ensureTarget(state: RunState): Promise<RunState> {\n const response = await this.dependencies.fetch(state.endpoint, {\n signal: AbortSignal.timeout(this.dependencies.timeoutMs),\n })\n if (!response.ok) throw new Error(`Chrome target discovery failed (HTTP ${response.status})`)\n const contentLength = Number(response.headers.get(\"content-length\"))\n if (Number.isFinite(contentLength) && contentLength > DISCOVERY_TEXT_LIMIT) {\n throw new Error(\"Chrome target discovery response is too large\")\n }\n const text = await response.text()\n if (Buffer.byteLength(text) > DISCOVERY_TEXT_LIMIT) throw new Error(\"Chrome target discovery response is too large\")\n let candidates: unknown\n try { candidates = JSON.parse(text) } catch { throw new Error(\"Chrome target discovery returned invalid JSON\") }\n if (!Array.isArray(candidates)) throw new Error(\"Chrome target discovery returned invalid JSON\")\n const targets = candidates.slice(0, DISCOVERY_TARGET_LIMIT).filter(isTarget).filter((target) => target.type === \"page\")\n let target = state.target && targets.find((candidate) => candidate.id === state.target!.id)\n if (!target) {\n this.disconnect(state, new Error(\"Chrome target was replaced\"))\n target = await this.discoverTarget(state, targets)\n }\n\n const replaced = state.target?.id !== target.id || state.target.webSocketDebuggerUrl !== target.webSocketDebuggerUrl\n if (replaced) this.disconnect(state, new Error(\"Chrome target was replaced\"))\n state.target = target\n if (!state.socket) await this.connect(state, target)\n else await state.open\n const context = await this.readContext(state)\n if (!this.matchesContext(state, context)) {\n this.invalidateRefs(state)\n state.instanceId = undefined\n this.disconnect(state, new Error(\"CodeNomad window or active session changed; inspect again\"))\n throw new Error(\"CodeNomad window or active session changed; inspect again\")\n }\n state.context = context\n return state\n }\n\n private async discoverTarget(state: RunState, targets: CdpTarget[]): Promise<CdpTarget> {\n const matches: CdpTarget[] = []\n for (let index = 0; index < targets.length && matches.length < 2; index += DISCOVERY_PROBE_CONCURRENCY) {\n const batch = await Promise.all(targets.slice(index, index + DISCOVERY_PROBE_CONCURRENCY).map(async (target) => {\n const probe = this.newState(state.endpoint, state.windowId, state.sessionId, state.instanceId)\n probe.target = target\n try {\n await this.connect(probe, target)\n return this.matchesContext(state, await this.readContext(probe)) ? target : undefined\n } catch {\n // Targets can disappear while Chromium's target list is being inspected.\n return undefined\n } finally {\n this.disconnect(probe, new Error(\"CDP target probe completed\"))\n }\n }))\n matches.push(...batch.filter((target): target is CdpTarget => Boolean(target)))\n }\n if (matches.length === 0) throw new Error(\"No CodeNomad page matches the selected window and OpenCode session\")\n if (matches.length > 1) throw new Error(\"Multiple CodeNomad pages match the selected window and OpenCode session\")\n return matches[0]\n }\n\n private async readContext(state: RunState): Promise<DeveloperCdpContext> {\n const response = await this.command(state, \"Runtime.evaluate\", {\n expression: CONTEXT_EXPRESSION,\n returnByValue: true,\n })\n const value = (response.result as { value?: unknown } | undefined)?.value as Partial<DeveloperCdpContext> | undefined\n const optionalId = (id: unknown) => id === null || (typeof id === \"string\" && id.length <= 256)\n if (!value || typeof value.windowId !== \"string\" || value.windowId.length > 256\n || !optionalId(value.instanceId) || !optionalId(value.sessionId)) {\n throw new Error(\"CodeNomad page has no valid window context\")\n }\n return { windowId: value.windowId, instanceId: value.instanceId!, sessionId: value.sessionId! }\n }\n\n private matchesContext(state: RunState, context: DeveloperCdpContext): boolean {\n return context.windowId === state.windowId && (state.sessionId === undefined || context.sessionId === state.sessionId)\n && (state.instanceId === undefined || context.instanceId === state.instanceId)\n }\n\n private async connect(state: RunState, target: CdpTarget): Promise<void> {\n const socket = this.dependencies.connect(target.webSocketDebuggerUrl)\n state.socket = socket\n state.open = new Promise<void>((resolve, reject) => {\n const fail = (error: Error) => {\n clearTimeout(timer)\n if (state.socket === socket) {\n this.disconnect(state, error)\n } else socket.close()\n reject(error)\n }\n const timer = setTimeout(() => fail(new Error(\"CDP WebSocket connection timed out\")), this.dependencies.timeoutMs)\n socket.onopen = () => { clearTimeout(timer); resolve() }\n socket.onerror = () => fail(new Error(\"CDP WebSocket connection failed\"))\n })\n socket.onmessage = (event) => this.onMessage(state, socket, event.data)\n socket.onclose = () => {\n if (state.socket !== socket) return\n state.socket = undefined\n state.open = undefined\n this.invalidateRefs(state)\n this.rejectPending(state, new Error(\"CDP WebSocket closed\"))\n }\n await state.open\n await this.command(state, \"Page.enable\")\n await this.command(state, \"Runtime.enable\")\n await this.command(state, \"Accessibility.enable\")\n }\n\n private command(\n state: RunState,\n method: string,\n params?: Record<string, unknown>,\n ): Promise<Record<string, unknown>> {\n if (!state.socket) return Promise.reject(new Error(\"CDP WebSocket is not connected\"))\n const id = ++state.nextCommandId\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n state.pending.delete(id)\n reject(new Error(`CDP command ${method} timed out`))\n }, this.dependencies.timeoutMs)\n state.pending.set(id, { resolve, reject, timer })\n state.socket!.send(JSON.stringify({ id, method, ...(params ? { params } : {}) }))\n })\n }\n\n private onMessage(state: RunState, socket: CdpSocket, data: unknown): void {\n if (state.socket !== socket) return\n let message: CdpResponse\n try {\n const text = typeof data === \"string\" ? data : Buffer.from(data as ArrayBuffer).toString(\"utf8\")\n message = JSON.parse(text) as CdpResponse\n } catch {\n return\n }\n if (typeof message.id === \"number\") {\n const pending = state.pending.get(message.id)\n if (!pending) return\n clearTimeout(pending.timer)\n state.pending.delete(message.id)\n if (message.error) pending.reject(new Error(message.error.message ?? `CDP error ${message.error.code ?? \"unknown\"}`))\n else pending.resolve(message.result ?? {})\n return\n }\n if (message.method === \"Page.frameNavigated\") {\n this.invalidateRefs(state)\n return\n }\n const diagnostic = readDiagnostic(message)\n if (diagnostic) {\n state.diagnostics.push(diagnostic)\n if (state.diagnostics.length > DIAGNOSTIC_LIMIT) state.diagnostics.splice(0, state.diagnostics.length - DIAGNOSTIC_LIMIT)\n }\n }\n\n private async assertContextCurrent(state: RunState, epoch: number, message: string): Promise<void> {\n if (state.navigationEpoch !== epoch || !state.socket) {\n throw new Error(message)\n }\n const context = await this.readContext(state)\n if (!this.matchesContext(state, context)) {\n this.invalidateRefs(state)\n state.context = context\n throw new Error(message)\n }\n if (state.navigationEpoch !== epoch || !state.socket) {\n throw new Error(message)\n }\n state.context = context\n }\n\n private exclusive<T>(runId: string, operation: () => Promise<T>): Promise<T> {\n const previous = this.operations.get(runId) ?? Promise.resolve()\n const queued = previous.catch(() => undefined).then(operation)\n const tail = queued.then(() => undefined, () => undefined)\n this.operations.set(runId, tail)\n return queued.finally(() => {\n if (this.operations.get(runId) === tail) this.operations.delete(runId)\n })\n }\n\n /** A new epoch makes every ref issued before it stale. */\n private invalidateRefs(state: RunState): void {\n state.navigationEpoch++\n }\n\n private disconnect(state: RunState, error: Error): void {\n const socket = state.socket\n state.socket = undefined\n state.open = undefined\n this.invalidateRefs(state)\n this.rejectPending(state, error)\n socket?.close()\n }\n\n private rejectPending(state: RunState, error: Error): void {\n for (const pending of state.pending.values()) {\n clearTimeout(pending.timer)\n pending.reject(error)\n }\n state.pending.clear()\n }\n}\n\nfunction discoveryUrl(endpoint: string): string {\n let url: URL\n try {\n url = new URL(endpoint)\n } catch {\n throw new Error(\"CDP endpoint must be an HTTP or HTTPS URL\")\n }\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") {\n throw new Error(\"CDP endpoint must be an HTTP or HTTPS URL\")\n }\n if (url.hostname !== \"127.0.0.1\") throw new Error(\"CDP endpoint must use the IPv4 loopback address\")\n if (url.username || url.password) throw new Error(\"CDP endpoint must not contain credentials\")\n return new URL(\"/json/list\", url).href\n}\n\nfunction isTarget(value: unknown): value is CdpTarget {\n const target = value as Partial<CdpTarget> | null\n return !!target\n && typeof target.id === \"string\"\n && typeof target.title === \"string\"\n && typeof target.type === \"string\"\n && typeof target.url === \"string\"\n && typeof target.webSocketDebuggerUrl === \"string\"\n && isLoopbackWebSocketUrl(target.webSocketDebuggerUrl)\n}\n\nfunction isLoopbackWebSocketUrl(value: string): boolean {\n try {\n const url = new URL(value)\n return (url.protocol === \"ws:\" || url.protocol === \"wss:\")\n && url.hostname === \"127.0.0.1\"\n && !url.username\n && !url.password\n } catch {\n return false\n }\n}\n\nfunction readDiagnostic(message: CdpResponse): DeveloperCdpDiagnostic | undefined {\n if (message.method === \"Runtime.consoleAPICalled\") {\n const params = message.params as { type?: unknown; args?: Array<{ value?: unknown; description?: unknown }> } | undefined\n const text = params?.args?.map((arg) => String(arg.value ?? arg.description ?? \"\")).join(\" \") ?? \"\"\n const level = params?.type === \"error\" || params?.type === \"assert\" ? \"error\"\n : params?.type === \"warning\" ? \"warning\" : \"log\"\n return { level, text: boundedText(text) }\n }\n if (message.method === \"Runtime.exceptionThrown\") {\n const params = message.params as { exceptionDetails?: { text?: unknown; exception?: { description?: unknown } } } | undefined\n const detail = params?.exceptionDetails\n return { level: \"error\", text: boundedText(String(detail?.exception?.description ?? detail?.text ?? \"Runtime exception\")) }\n }\n return undefined\n}\n\nfunction boundedText(text: string): string {\n return text.length > DIAGNOSTIC_TEXT_LIMIT ? `${text.slice(0, DIAGNOSTIC_TEXT_LIMIT - 3)}...` : text\n}\n"]}
1
+ {"version":3,"file":"developer-cdp.js","sourceRoot":"","sources":["../src/developer-cdp.ts"],"names":[],"mappings":"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","sourcesContent":["import { WebSocket } from \"undici\"\nimport { bindRefs, performAction, snapshotPage, type PageActionResult, type PageSession } from \"./automation/page/actions\"\nimport type { RefAction } from \"./automation/page/parse\"\nimport { RefTable } from \"./automation/page/refs\"\nimport { SnapshotScopeError } from \"./automation/page/snapshot\"\n\nconst DEFAULT_TIMEOUT_MS = 5_000\nconst DEFAULT_MAX_SCREENSHOT_BYTES = 5 * 1024 * 1024\nconst DIAGNOSTIC_LIMIT = 1_000\nconst DIAGNOSTIC_TEXT_LIMIT = 512\nconst DISCOVERY_TEXT_LIMIT = 256 * 1024\nconst DISCOVERY_TARGET_LIMIT = 64\nconst DISCOVERY_PROBE_CONCURRENCY = 4\nconst CONTEXT_EXPRESSION = `(() => {\n const root = document.querySelector('[data-tab-visible=\"true\"][data-instance-id]');\n const pane = root?.querySelector('.session-cache-pane[data-session-active=\"true\"][data-session-id]');\n return {\n windowId: window.__CODENOMAD_WINDOW_ID__ ?? null,\n instanceId: root?.getAttribute('data-instance-id') ?? null,\n sessionId: pane?.getAttribute('data-session-id') ?? null,\n };\n})()`\n\nexport interface DeveloperCdpSelection {\n endpoint: string\n runId: string\n windowId: string\n sessionId?: string\n}\n\nexport interface DeveloperCdpIdentity extends DeveloperCdpSelection {\n instanceId?: string\n}\n\nexport interface DeveloperCdpContext {\n windowId: string\n instanceId: string | null\n sessionId: string | null\n}\n\nexport interface DeveloperCdpDiagnostic {\n level: \"log\" | \"warning\" | \"error\"\n text: string\n}\n\nexport interface DeveloperCdpInspection {\n target: { id: string; title: string; url: string }\n context: DeveloperCdpContext\n /** Indented accessibility outline with refs (`automation/page/snapshot.ts`). */\n snapshot: string\n /** Lines that hide part of the page; inspect their ref to expand them. */\n collapsed: number\n diagnostics: DeveloperCdpDiagnostic[]\n}\n\n/** A full inspection, or one limited to a ref's subtree and/or matching text. */\nexport interface DeveloperCdpInspectOptions {\n ref?: string\n query?: string\n}\n\nexport interface DeveloperCdpScreenshot {\n mediaType: \"image/png\"\n data: string\n bytes: number\n}\n\ninterface CdpSocket {\n onopen: ((event: unknown) => void) | null\n onmessage: ((event: { data: unknown }) => void) | null\n onclose: ((event: unknown) => void) | null\n onerror: ((event: unknown) => void) | null\n send(data: string): void\n close(): void\n}\n\ninterface DeveloperCdpDependencies {\n fetch: typeof globalThis.fetch\n connect: (url: string) => CdpSocket\n timeoutMs: number\n maxScreenshotBytes: number\n}\n\ninterface CdpTarget {\n id: string\n title: string\n type: string\n url: string\n webSocketDebuggerUrl: string\n}\n\ninterface CdpResponse {\n id?: number\n method?: string\n params?: Record<string, unknown>\n result?: Record<string, unknown>\n error?: { code?: number; message?: string }\n}\n\ninterface PendingCommand {\n resolve: (value: Record<string, unknown>) => void\n reject: (error: Error) => void\n timer: NodeJS.Timeout\n}\n\ninterface RunState {\n endpoint: string\n windowId: string\n sessionId?: string\n instanceId?: string\n context?: DeveloperCdpContext\n target?: CdpTarget\n socket?: CdpSocket\n open?: Promise<void>\n /** Distinguishes this run's refs from an earlier state's on the same target. */\n stamp: number\n nextCommandId: number\n navigationEpoch: number\n pending: Map<number, PendingCommand>\n diagnostics: DeveloperCdpDiagnostic[]\n}\n\nexport class DeveloperCdp {\n private readonly dependencies: DeveloperCdpDependencies\n private readonly runs = new Map<string, RunState>()\n private readonly operations = new Map<string, Promise<void>>()\n /** Shared by runs so a ref name is never reused for another element. */\n private readonly refs = new RefTable()\n private stamps = 0\n\n constructor(dependencies: Partial<DeveloperCdpDependencies> = {}) {\n this.dependencies = {\n fetch: globalThis.fetch,\n connect: (url) => new WebSocket(url) as unknown as CdpSocket,\n timeoutMs: DEFAULT_TIMEOUT_MS,\n maxScreenshotBytes: DEFAULT_MAX_SCREENSHOT_BYTES,\n ...dependencies,\n }\n }\n\n async inspect(identity: DeveloperCdpIdentity, options: DeveloperCdpInspectOptions = {}): Promise<DeveloperCdpInspection> {\n return this.exclusive(identity.runId, async () => {\n const state = await this.ensure(identity)\n const generation = this.generation(state)\n const root = options.ref === undefined ? undefined : this.refs.resolve(options.ref, generation)\n let snapshot\n try {\n snapshot = await snapshotPage(this.session(state, state.navigationEpoch, \"Page changed during inspection; inspect again\"),\n () => this.refs.issuer(generation), { rootBackendNodeId: root, query: options.query })\n } catch (error) {\n if (error instanceof SnapshotScopeError) throw new Error(`${options.ref} is no longer in the page; inspect again`)\n throw error\n }\n return {\n target: { id: state.target!.id, title: state.target!.title, url: state.target!.url },\n context: state.context!,\n snapshot: snapshot.text,\n collapsed: snapshot.collapsed,\n diagnostics: state.diagnostics.splice(0),\n }\n })\n }\n\n async act(identity: DeveloperCdpIdentity, action: RefAction): Promise<PageActionResult> {\n return this.exclusive(identity.runId, async () => {\n const state = await this.ensure(identity)\n const epoch = state.navigationEpoch, generation = this.generation(state)\n const page = bindRefs(action, ref => this.refs.resolve(ref, generation))\n return performAction(this.session(state, epoch, \"Page changed during action; inspect again\"), page)\n })\n }\n\n /** Refs belong to one target and navigation epoch. */\n private generation(state: RunState): string {\n return `${state.stamp}\\0${state.target!.id}\\0${state.navigationEpoch}`\n }\n\n private session(state: RunState, epoch: number, message: string): PageSession {\n return {\n channel: { send: (method, params) => this.command(state, method, params) },\n checkpoint: () => this.assertContextCurrent(state, epoch, message),\n markAutomation: true,\n }\n }\n\n async screenshot(identity: DeveloperCdpIdentity): Promise<DeveloperCdpScreenshot> {\n return this.exclusive(identity.runId, async () => {\n const state = await this.ensure(identity)\n const epoch = state.navigationEpoch\n const result = await this.command(state, \"Page.captureScreenshot\", {\n format: \"png\",\n fromSurface: true,\n captureBeyondViewport: false,\n })\n await this.assertContextCurrent(state, epoch, \"Page changed during screenshot; capture again\")\n if (typeof result.data !== \"string\") throw new Error(\"Chrome returned an invalid screenshot\")\n const bytes = Buffer.from(result.data, \"base64\").byteLength\n if (bytes > this.dependencies.maxScreenshotBytes) {\n throw new Error(`Screenshot exceeds ${this.dependencies.maxScreenshotBytes} byte limit`)\n }\n return { mediaType: \"image/png\", data: result.data, bytes }\n })\n }\n\n close(runId?: string): void {\n for (const [id, state] of this.runs) {\n if (runId && id !== runId) continue\n this.disconnect(state, new Error(\"Developer CDP controller closed\"))\n this.runs.delete(id)\n }\n }\n\n async context(selection: DeveloperCdpSelection): Promise<DeveloperCdpContext> {\n return this.exclusive(selection.runId, async () => (await this.ensure(selection)).context!)\n }\n\n\n private async ensure(identity: DeveloperCdpSelection | DeveloperCdpIdentity): Promise<RunState> {\n if (!identity.runId.trim()) throw new Error(\"runId is required\")\n const endpoint = discoveryUrl(identity.endpoint)\n for (const [runId, previous] of this.runs) {\n if (runId === identity.runId) continue\n this.disconnect(previous, new Error(\"Developer run was replaced\"))\n this.runs.delete(runId)\n }\n let state = this.runs.get(identity.runId)\n if (!state || state.endpoint !== endpoint || state.windowId !== identity.windowId || state.sessionId !== identity.sessionId\n || (\"instanceId\" in identity && state.instanceId !== identity.instanceId)) {\n if (state) this.disconnect(state, new Error(\"CDP endpoint changed\"))\n state = this.newState(endpoint, identity.windowId, identity.sessionId, \"instanceId\" in identity ? identity.instanceId : undefined)\n this.runs.set(identity.runId, state)\n }\n return this.ensureTarget(state)\n }\n\n private newState(endpoint: string, windowId: string, sessionId?: string, instanceId?: string): RunState {\n return {\n endpoint,\n windowId,\n sessionId,\n instanceId,\n stamp: ++this.stamps,\n nextCommandId: 0,\n navigationEpoch: 0,\n pending: new Map(),\n diagnostics: [],\n }\n }\n\n private async ensureTarget(state: RunState): Promise<RunState> {\n const response = await this.dependencies.fetch(state.endpoint, {\n signal: AbortSignal.timeout(this.dependencies.timeoutMs),\n })\n if (!response.ok) throw new Error(`Chrome target discovery failed (HTTP ${response.status})`)\n const contentLength = Number(response.headers.get(\"content-length\"))\n if (Number.isFinite(contentLength) && contentLength > DISCOVERY_TEXT_LIMIT) {\n throw new Error(\"Chrome target discovery response is too large\")\n }\n const text = await response.text()\n if (Buffer.byteLength(text) > DISCOVERY_TEXT_LIMIT) throw new Error(\"Chrome target discovery response is too large\")\n let candidates: unknown\n try { candidates = JSON.parse(text) } catch { throw new Error(\"Chrome target discovery returned invalid JSON\") }\n if (!Array.isArray(candidates)) throw new Error(\"Chrome target discovery returned invalid JSON\")\n const targets = candidates.slice(0, DISCOVERY_TARGET_LIMIT).filter(isTarget).filter((target) => target.type === \"page\")\n let target = state.target && targets.find((candidate) => candidate.id === state.target!.id)\n if (!target) {\n this.disconnect(state, new Error(\"Chrome target was replaced\"))\n target = await this.discoverTarget(state, targets)\n }\n\n const replaced = state.target?.id !== target.id || state.target.webSocketDebuggerUrl !== target.webSocketDebuggerUrl\n if (replaced) this.disconnect(state, new Error(\"Chrome target was replaced\"))\n state.target = target\n if (!state.socket) await this.connect(state, target)\n else await state.open\n const context = await this.readContext(state)\n if (!this.matchesContext(state, context)) {\n this.invalidateRefs(state)\n state.instanceId = undefined\n this.disconnect(state, new Error(\"CodeNomad window or active session changed; inspect again\"))\n throw new Error(\"CodeNomad window or active session changed; inspect again\")\n }\n state.context = context\n return state\n }\n\n private async discoverTarget(state: RunState, targets: CdpTarget[]): Promise<CdpTarget> {\n const matches: CdpTarget[] = []\n for (let index = 0; index < targets.length && matches.length < 2; index += DISCOVERY_PROBE_CONCURRENCY) {\n const batch = await Promise.all(targets.slice(index, index + DISCOVERY_PROBE_CONCURRENCY).map(async (target) => {\n const probe = this.newState(state.endpoint, state.windowId, state.sessionId, state.instanceId)\n probe.target = target\n try {\n await this.connect(probe, target)\n return this.matchesContext(state, await this.readContext(probe)) ? target : undefined\n } catch {\n // Targets can disappear while Chromium's target list is being inspected.\n return undefined\n } finally {\n this.disconnect(probe, new Error(\"CDP target probe completed\"))\n }\n }))\n matches.push(...batch.filter((target): target is CdpTarget => Boolean(target)))\n }\n if (matches.length === 0) throw new Error(\"No CodeNomad page matches the selected window and OpenCode session\")\n if (matches.length > 1) throw new Error(\"Multiple CodeNomad pages match the selected window and OpenCode session\")\n return matches[0]\n }\n\n private async readContext(state: RunState): Promise<DeveloperCdpContext> {\n const response = await this.command(state, \"Runtime.evaluate\", {\n expression: CONTEXT_EXPRESSION,\n returnByValue: true,\n })\n const value = (response.result as { value?: unknown } | undefined)?.value as Partial<DeveloperCdpContext> | undefined\n const optionalId = (id: unknown) => id === null || (typeof id === \"string\" && id.length <= 256)\n if (!value || typeof value.windowId !== \"string\" || value.windowId.length > 256\n || !optionalId(value.instanceId) || !optionalId(value.sessionId)) {\n throw new Error(\"CodeNomad page has no valid window context\")\n }\n return { windowId: value.windowId, instanceId: value.instanceId!, sessionId: value.sessionId! }\n }\n\n private matchesContext(state: RunState, context: DeveloperCdpContext): boolean {\n return context.windowId === state.windowId && (state.sessionId === undefined || context.sessionId === state.sessionId)\n && (state.instanceId === undefined || context.instanceId === state.instanceId)\n }\n\n private async connect(state: RunState, target: CdpTarget): Promise<void> {\n const socket = this.dependencies.connect(target.webSocketDebuggerUrl)\n state.socket = socket\n state.open = new Promise<void>((resolve, reject) => {\n const fail = (error: Error) => {\n clearTimeout(timer)\n if (state.socket === socket) {\n this.disconnect(state, error)\n } else socket.close()\n reject(error)\n }\n const timer = setTimeout(() => fail(new Error(\"CDP WebSocket connection timed out\")), this.dependencies.timeoutMs)\n socket.onopen = () => { clearTimeout(timer); resolve() }\n socket.onerror = () => fail(new Error(\"CDP WebSocket connection failed\"))\n })\n socket.onmessage = (event) => this.onMessage(state, socket, event.data)\n socket.onclose = () => {\n if (state.socket !== socket) return\n state.socket = undefined\n state.open = undefined\n this.invalidateRefs(state)\n this.rejectPending(state, new Error(\"CDP WebSocket closed\"))\n }\n await state.open\n await this.command(state, \"Page.enable\")\n await this.command(state, \"Runtime.enable\")\n await this.command(state, \"Accessibility.enable\")\n }\n\n private command(\n state: RunState,\n method: string,\n params?: Record<string, unknown>,\n ): Promise<Record<string, unknown>> {\n if (!state.socket) return Promise.reject(new Error(\"CDP WebSocket is not connected\"))\n const id = ++state.nextCommandId\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n state.pending.delete(id)\n reject(new Error(`CDP command ${method} timed out`))\n }, this.dependencies.timeoutMs)\n state.pending.set(id, { resolve, reject, timer })\n state.socket!.send(JSON.stringify({ id, method, ...(params ? { params } : {}) }))\n })\n }\n\n private onMessage(state: RunState, socket: CdpSocket, data: unknown): void {\n if (state.socket !== socket) return\n let message: CdpResponse\n try {\n const text = typeof data === \"string\" ? data : Buffer.from(data as ArrayBuffer).toString(\"utf8\")\n message = JSON.parse(text) as CdpResponse\n } catch {\n return\n }\n if (typeof message.id === \"number\") {\n const pending = state.pending.get(message.id)\n if (!pending) return\n clearTimeout(pending.timer)\n state.pending.delete(message.id)\n if (message.error) pending.reject(new Error(message.error.message ?? `CDP error ${message.error.code ?? \"unknown\"}`))\n else pending.resolve(message.result ?? {})\n return\n }\n if (message.method === \"Page.frameNavigated\") {\n this.invalidateRefs(state)\n return\n }\n const diagnostic = readDiagnostic(message)\n if (diagnostic) {\n state.diagnostics.push(diagnostic)\n if (state.diagnostics.length > DIAGNOSTIC_LIMIT) state.diagnostics.splice(0, state.diagnostics.length - DIAGNOSTIC_LIMIT)\n }\n }\n\n private async assertContextCurrent(state: RunState, epoch: number, message: string): Promise<void> {\n if (state.navigationEpoch !== epoch || !state.socket) {\n throw new Error(message)\n }\n const context = await this.readContext(state)\n if (!this.matchesContext(state, context)) {\n this.invalidateRefs(state)\n state.context = context\n throw new Error(message)\n }\n if (state.navigationEpoch !== epoch || !state.socket) {\n throw new Error(message)\n }\n state.context = context\n }\n\n private exclusive<T>(runId: string, operation: () => Promise<T>): Promise<T> {\n const previous = this.operations.get(runId) ?? Promise.resolve()\n const queued = previous.catch(() => undefined).then(operation)\n const tail = queued.then(() => undefined, () => undefined)\n this.operations.set(runId, tail)\n return queued.finally(() => {\n if (this.operations.get(runId) === tail) this.operations.delete(runId)\n })\n }\n\n /** A new epoch makes every ref issued before it stale. */\n private invalidateRefs(state: RunState): void {\n state.navigationEpoch++\n }\n\n private disconnect(state: RunState, error: Error): void {\n const socket = state.socket\n state.socket = undefined\n state.open = undefined\n this.invalidateRefs(state)\n this.rejectPending(state, error)\n socket?.close()\n }\n\n private rejectPending(state: RunState, error: Error): void {\n for (const pending of state.pending.values()) {\n clearTimeout(pending.timer)\n pending.reject(error)\n }\n state.pending.clear()\n }\n}\n\nfunction discoveryUrl(endpoint: string): string {\n let url: URL\n try {\n url = new URL(endpoint)\n } catch {\n throw new Error(\"CDP endpoint must be an HTTP or HTTPS URL\")\n }\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") {\n throw new Error(\"CDP endpoint must be an HTTP or HTTPS URL\")\n }\n if (url.hostname !== \"127.0.0.1\") throw new Error(\"CDP endpoint must use the IPv4 loopback address\")\n if (url.username || url.password) throw new Error(\"CDP endpoint must not contain credentials\")\n return new URL(\"/json/list\", url).href\n}\n\nfunction isTarget(value: unknown): value is CdpTarget {\n const target = value as Partial<CdpTarget> | null\n return !!target\n && typeof target.id === \"string\"\n && typeof target.title === \"string\"\n && typeof target.type === \"string\"\n && typeof target.url === \"string\"\n && typeof target.webSocketDebuggerUrl === \"string\"\n && isLoopbackWebSocketUrl(target.webSocketDebuggerUrl)\n}\n\nfunction isLoopbackWebSocketUrl(value: string): boolean {\n try {\n const url = new URL(value)\n return (url.protocol === \"ws:\" || url.protocol === \"wss:\")\n && url.hostname === \"127.0.0.1\"\n && !url.username\n && !url.password\n } catch {\n return false\n }\n}\n\nfunction readDiagnostic(message: CdpResponse): DeveloperCdpDiagnostic | undefined {\n if (message.method === \"Runtime.consoleAPICalled\") {\n const params = message.params as { type?: unknown; args?: Array<{ value?: unknown; description?: unknown }> } | undefined\n const text = params?.args?.map((arg) => String(arg.value ?? arg.description ?? \"\")).join(\" \") ?? \"\"\n const level = params?.type === \"error\" || params?.type === \"assert\" ? \"error\"\n : params?.type === \"warning\" ? \"warning\" : \"log\"\n return { level, text: boundedText(text) }\n }\n if (message.method === \"Runtime.exceptionThrown\") {\n const params = message.params as { exceptionDetails?: { text?: unknown; exception?: { description?: unknown } } } | undefined\n const detail = params?.exceptionDetails\n return { level: \"error\", text: boundedText(String(detail?.exception?.description ?? detail?.text ?? \"Runtime exception\")) }\n }\n return undefined\n}\n\nfunction boundedText(text: string): string {\n return text.length > DIAGNOSTIC_TEXT_LIMIT ? `${text.slice(0, DIAGNOSTIC_TEXT_LIMIT - 3)}...` : text\n}\n"]}
@@ -52,6 +52,9 @@ class FakeChrome {
52
52
  this.sockets.push(socket);
53
53
  return socket;
54
54
  };
55
+ /** Visible box of every element, or none; and the element hit at its centre. */
56
+ this.quads = [];
57
+ this.hit = 42;
55
58
  }
56
59
  receive(socket, command) {
57
60
  this.commands.push(command);
@@ -59,15 +62,24 @@ class FakeChrome {
59
62
  this.deferred.set(command.method, { socket, command });
60
63
  return;
61
64
  }
62
- queueMicrotask(() => socket.respond(command, this.result(command.method)));
65
+ queueMicrotask(() => socket.respond(command, command.method === "Runtime.evaluate" && String(command.params?.expression).includes("__codenomadAutomationInputUntil")
66
+ ? { result: { value: 1_700_000_000 } } : this.result(command.method)));
63
67
  }
64
68
  result(method) {
65
69
  if (method === "Accessibility.getFullAXTree")
66
70
  return {
67
71
  nodes: this.axNodes,
68
72
  };
73
+ if (method === "DOM.getContentQuads")
74
+ return { quads: this.quads };
75
+ if (method === "DOM.getNodeForLocation")
76
+ return { backendNodeId: this.hit };
77
+ if (method === "Page.getLayoutMetrics")
78
+ return { cssLayoutViewport: { clientWidth: 800, clientHeight: 600 } };
69
79
  if (method === "Runtime.evaluate")
70
80
  return { result: { value: this.context } };
81
+ if (method === "Runtime.callFunctionOn")
82
+ return { result: { value: this.functionResult } };
71
83
  if (method === "Page.captureScreenshot")
72
84
  return { data: this.screenshotData };
73
85
  if (method === "DOM.resolveNode")
@@ -99,7 +111,7 @@ describe("DeveloperCdp", () => {
99
111
  try {
100
112
  const first = await client.inspect(window);
101
113
  chrome.context = { ...chrome.context, sessionId: "another-session", instanceId: "another-project" };
102
- await client.act({ ...window, kind: "click", ref: refOf(first) });
114
+ await client.act(window, { action: "click", ref: refOf(first) });
103
115
  assert.equal((await client.inspect(window)).context.sessionId, "another-session");
104
116
  chrome.context = { windowId: "window-1", sessionId: null, instanceId: null };
105
117
  assert.equal((await client.inspect(window)).context.sessionId, null);
@@ -158,7 +170,7 @@ describe("DeveloperCdp", () => {
158
170
  assert.equal(second.target.id, "two");
159
171
  assert.equal(oldSocket.closed, true);
160
172
  assert.equal(chrome.sockets.length, 4);
161
- await assert.rejects(client.act({ ...identity, kind: "click", ref: oldRef }), /stale ref/);
173
+ await assert.rejects(client.act(identity, { action: "click", ref: oldRef }), /stale ref/);
162
174
  });
163
175
  it("refreshes target metadata without reconnecting", async () => {
164
176
  const chrome = new FakeChrome();
@@ -170,13 +182,35 @@ describe("DeveloperCdp", () => {
170
182
  assert.equal(inspection.target.url, "http://app.test/current");
171
183
  assert.equal(chrome.sockets.length, 2);
172
184
  });
173
- it("activates clicks through the resolved accessibility node", async () => {
185
+ it("clicks a visible element with marked real pointer input at its visible centre", async () => {
174
186
  const chrome = new FakeChrome();
187
+ chrome.quads = [[100, 40, 300, 40, 300, 80, 100, 80]];
175
188
  const client = chrome.client();
176
189
  const inspection = await client.inspect(identity);
177
- await client.act({ ...identity, kind: "click", ref: refOf(inspection) });
190
+ chrome.commands.length = 0;
191
+ await client.act(identity, { action: "click", ref: refOf(inspection) });
192
+ const sequence = chrome.commands.filter(command => command.method === "Input.dispatchMouseEvent"
193
+ || (command.method === "Runtime.evaluate" && /__codenomadAutomationInputUntil/.test(String(command.params?.expression))))
194
+ .map(command => command.method === "Runtime.evaluate" ? (/Math.min/.test(String(command.params.expression)) ? "unmark" : "mark")
195
+ : `${command.params.type}@${command.params.x},${command.params.y}`);
196
+ assert.deepEqual(sequence, ["mark", "mouseMoved@200,60", "mark", "mousePressed@200,60", "mark", "mouseReleased@200,60", "unmark"], "every trusted event in the CodeNomad window is marked, and the mark is cleared");
197
+ });
198
+ it("refuses a covered element and activates a box-less one programmatically", async () => {
199
+ const chrome = new FakeChrome();
200
+ chrome.quads = [[0, 0, 10, 0, 10, 10, 0, 10]];
201
+ chrome.hit = 7;
202
+ const client = chrome.client();
203
+ const inspection = await client.inspect(identity);
204
+ chrome.commands.length = 0;
205
+ chrome.functionResult = "div \"Overlay\"";
206
+ await assert.rejects(client.act(identity, { action: "click", ref: refOf(inspection) }), /is covered by div "Overlay"; close or move it first/);
207
+ assert.equal(chrome.commands.some(command => command.method === "Input.dispatchMouseEvent"), false);
208
+ chrome.functionResult = undefined;
209
+ chrome.quads = [];
210
+ chrome.commands.length = 0;
211
+ await client.act(identity, { action: "click", ref: refOf(inspection) });
178
212
  assert.equal(chrome.commands.some((command) => command.method === "Input.dispatchMouseEvent"), false);
179
- assert.equal(chrome.commands.find((command) => command.method === "Runtime.callFunctionOn")?.params?.objectId, "node-1");
213
+ assert.equal(chrome.commands.filter((command) => command.method === "Runtime.callFunctionOn").at(-1)?.params?.objectId, "node-1");
180
214
  });
181
215
  it("retries a failed WebSocket connection", async () => {
182
216
  const chrome = new FakeChrome();
@@ -207,14 +241,14 @@ describe("DeveloperCdp", () => {
207
241
  const client = chrome.client();
208
242
  const inspection = await client.inspect(identity);
209
243
  chrome.sockets.at(-1).emit("Page.frameNavigated", { frame: { id: "main" } });
210
- await assert.rejects(client.act({ ...identity, kind: "type", ref: refOf(inspection), text: "hello", clear: true }), /stale ref/);
244
+ await assert.rejects(client.act(identity, { action: "type", ref: refOf(inspection), text: "hello", clear: true }), /stale ref/);
211
245
  });
212
246
  it("invalidates refs when the target socket reconnects", async () => {
213
247
  const chrome = new FakeChrome();
214
248
  const client = chrome.client();
215
249
  const inspection = await client.inspect(identity);
216
250
  chrome.sockets.at(-1).close();
217
- await assert.rejects(client.act({ ...identity, kind: "click", ref: refOf(inspection) }), /stale ref/);
251
+ await assert.rejects(client.act(identity, { action: "click", ref: refOf(inspection) }), /stale ref/);
218
252
  assert.equal(chrome.sockets.length, 3);
219
253
  });
220
254
  it("rejects actions after the visible OpenCode session changes", async () => {
@@ -222,7 +256,7 @@ describe("DeveloperCdp", () => {
222
256
  const client = chrome.client();
223
257
  const inspection = await client.inspect(identity);
224
258
  chrome.context = { ...chrome.context, sessionId: "session-2" };
225
- await assert.rejects(client.act({ ...identity, kind: "click", ref: refOf(inspection) }), /active session changed/);
259
+ await assert.rejects(client.act(identity, { action: "click", ref: refOf(inspection) }), /active session changed/);
226
260
  assert.equal(chrome.commands.some((command) => command.method === "Input.dispatchMouseEvent"), false);
227
261
  });
228
262
  it("invalidates refs and pending commands when an open socket errors", async () => {
@@ -232,7 +266,7 @@ describe("DeveloperCdp", () => {
232
266
  const oldRef = refOf(inspection);
233
267
  const socket = chrome.sockets.at(-1);
234
268
  socket.onerror?.({});
235
- await assert.rejects(client.act({ ...identity, kind: "click", ref: oldRef }), /stale ref/);
269
+ await assert.rejects(client.act(identity, { action: "click", ref: oldRef }), /stale ref/);
236
270
  assert.equal(socket.closed, true);
237
271
  });
238
272
  it("rejects non-loopback WebSocket targets", async () => {
@@ -246,7 +280,7 @@ describe("DeveloperCdp", () => {
246
280
  const client = chrome.client();
247
281
  const inspection = await client.inspect(identity);
248
282
  chrome.deferred.set("DOM.resolveNode", undefined);
249
- const action = client.act({ ...identity, kind: "click", ref: refOf(inspection) });
283
+ const action = client.act(identity, { action: "click", ref: refOf(inspection) });
250
284
  while (!chrome.deferred.get("DOM.resolveNode"))
251
285
  await new Promise((resolve) => setImmediate(resolve));
252
286
  const deferred = chrome.deferred.get("DOM.resolveNode");
@@ -260,7 +294,7 @@ describe("DeveloperCdp", () => {
260
294
  const client = chrome.client();
261
295
  const inspection = await client.inspect(identity);
262
296
  chrome.deferred.set("DOM.resolveNode", undefined);
263
- const action = client.act({ ...identity, kind: "click", ref: refOf(inspection) });
297
+ const action = client.act(identity, { action: "click", ref: refOf(inspection) });
264
298
  while (!chrome.deferred.get("DOM.resolveNode"))
265
299
  await new Promise((resolve) => setImmediate(resolve));
266
300
  chrome.context = { ...chrome.context, instanceId: "workspace-2" };
@@ -304,7 +338,7 @@ describe("DeveloperCdp", () => {
304
338
  const save = /button "Save" \[(e\d+)\]/.exec(full.snapshot)[1];
305
339
  const scoped = await client.inspect(identity, { ref: dialog });
306
340
  assert.equal(scoped.snapshot, `- dialog "Rename" [${dialog}]\n - textbox "Title" [${/textbox "Title" \[(e\d+)\]/.exec(full.snapshot)[1]}] value="Old"`);
307
- await client.act({ ...identity, kind: "click", ref: save });
341
+ await client.act(identity, { action: "click", ref: save });
308
342
  assert.match((await client.inspect(identity, { query: "save" })).snapshot, new RegExp(`button "Save" \\[${save}\\]`));
309
343
  assert.equal(/button "Save" \[(e\d+)\]/.exec((await client.inspect(identity)).snapshot)[1], save);
310
344
  // A later inspection of the same page never invalidates an earlier ref; a node that
@@ -313,9 +347,9 @@ describe("DeveloperCdp", () => {
313
347
  chrome.axNodes[0] = { ...chrome.axNodes[0], childIds: ["toolbar"] };
314
348
  await client.inspect(identity);
315
349
  await assert.rejects(client.inspect(identity, { ref: dialog }), /is no longer in the page/);
316
- await client.act({ ...identity, kind: "click", ref: dialog });
350
+ await client.act(identity, { action: "click", ref: dialog });
317
351
  chrome.sockets.at(-1).emit("Page.frameNavigated", { frame: { id: "main" } });
318
- await assert.rejects(client.act({ ...identity, kind: "click", ref: save }), /stale ref/);
352
+ await assert.rejects(client.act(identity, { action: "click", ref: save }), /stale ref/);
319
353
  });
320
354
  it("closes active target connections", async () => {
321
355
  const chrome = new FakeChrome();