@monoes/monobrowse 1.0.2 → 1.0.3

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 (272) hide show
  1. package/dist/src/__tests__/output.test.d.ts +2 -0
  2. package/dist/src/__tests__/output.test.d.ts.map +1 -0
  3. package/dist/src/__tests__/output.test.js +54 -0
  4. package/dist/src/__tests__/output.test.js.map +1 -0
  5. package/dist/src/__tests__/ref-cache.test.d.ts +2 -0
  6. package/dist/src/__tests__/ref-cache.test.d.ts.map +1 -0
  7. package/dist/src/__tests__/ref-cache.test.js +109 -0
  8. package/dist/src/__tests__/ref-cache.test.js.map +1 -0
  9. package/dist/src/browser/action-builder/analyzer.d.ts +0 -0
  10. package/dist/src/browser/action-builder/analyzer.d.ts.map +0 -0
  11. package/dist/src/browser/action-builder/analyzer.js +0 -0
  12. package/dist/src/browser/action-builder/analyzer.js.map +0 -0
  13. package/dist/src/browser/action-builder/types.d.ts +0 -0
  14. package/dist/src/browser/action-builder/types.d.ts.map +0 -0
  15. package/dist/src/browser/action-builder/types.js +0 -0
  16. package/dist/src/browser/action-builder/types.js.map +0 -0
  17. package/dist/src/browser/actions.d.ts +0 -0
  18. package/dist/src/browser/actions.d.ts.map +0 -0
  19. package/dist/src/browser/actions.js +0 -0
  20. package/dist/src/browser/actions.js.map +0 -0
  21. package/dist/src/browser/adapters/gemini.d.ts +0 -0
  22. package/dist/src/browser/adapters/gemini.d.ts.map +0 -0
  23. package/dist/src/browser/adapters/gemini.js +0 -0
  24. package/dist/src/browser/adapters/gemini.js.map +0 -0
  25. package/dist/src/browser/adapters/google.d.ts +0 -0
  26. package/dist/src/browser/adapters/google.d.ts.map +0 -0
  27. package/dist/src/browser/adapters/google.js +0 -0
  28. package/dist/src/browser/adapters/google.js.map +0 -0
  29. package/dist/src/browser/adapters/index.d.ts +0 -0
  30. package/dist/src/browser/adapters/index.d.ts.map +0 -0
  31. package/dist/src/browser/adapters/index.js +0 -0
  32. package/dist/src/browser/adapters/index.js.map +0 -0
  33. package/dist/src/browser/adapters/instagram.d.ts +0 -0
  34. package/dist/src/browser/adapters/instagram.d.ts.map +0 -0
  35. package/dist/src/browser/adapters/instagram.js +0 -0
  36. package/dist/src/browser/adapters/instagram.js.map +0 -0
  37. package/dist/src/browser/adapters/linkedin.d.ts +0 -0
  38. package/dist/src/browser/adapters/linkedin.d.ts.map +0 -0
  39. package/dist/src/browser/adapters/linkedin.js +0 -0
  40. package/dist/src/browser/adapters/linkedin.js.map +0 -0
  41. package/dist/src/browser/adapters/microsoft.d.ts +0 -0
  42. package/dist/src/browser/adapters/microsoft.d.ts.map +0 -0
  43. package/dist/src/browser/adapters/microsoft.js +0 -0
  44. package/dist/src/browser/adapters/microsoft.js.map +0 -0
  45. package/dist/src/browser/adapters/x.d.ts +0 -0
  46. package/dist/src/browser/adapters/x.d.ts.map +0 -0
  47. package/dist/src/browser/adapters/x.js +0 -0
  48. package/dist/src/browser/adapters/x.js.map +0 -0
  49. package/dist/src/browser/batch.d.ts +0 -0
  50. package/dist/src/browser/batch.d.ts.map +0 -0
  51. package/dist/src/browser/batch.js +0 -0
  52. package/dist/src/browser/batch.js.map +0 -0
  53. package/dist/src/browser/browser.d.ts +0 -0
  54. package/dist/src/browser/browser.d.ts.map +0 -0
  55. package/dist/src/browser/browser.js +0 -0
  56. package/dist/src/browser/browser.js.map +0 -0
  57. package/dist/src/browser/cdp.d.ts +0 -0
  58. package/dist/src/browser/cdp.d.ts.map +0 -0
  59. package/dist/src/browser/cdp.js +0 -0
  60. package/dist/src/browser/cdp.js.map +0 -0
  61. package/dist/src/browser/console-log.d.ts +0 -0
  62. package/dist/src/browser/console-log.d.ts.map +0 -0
  63. package/dist/src/browser/console-log.js +0 -0
  64. package/dist/src/browser/console-log.js.map +0 -0
  65. package/dist/src/browser/dashboard/api-types.d.ts +0 -0
  66. package/dist/src/browser/dashboard/api-types.d.ts.map +0 -0
  67. package/dist/src/browser/dashboard/api-types.js +0 -0
  68. package/dist/src/browser/dashboard/api-types.js.map +0 -0
  69. package/dist/src/browser/dashboard/server.d.ts +0 -0
  70. package/dist/src/browser/dashboard/server.d.ts.map +0 -0
  71. package/dist/src/browser/dashboard/server.js +0 -0
  72. package/dist/src/browser/dashboard/server.js.map +0 -0
  73. package/dist/src/browser/dashboard/ui.html +0 -0
  74. package/dist/src/browser/dialog.d.ts +0 -0
  75. package/dist/src/browser/dialog.d.ts.map +0 -0
  76. package/dist/src/browser/dialog.js +0 -0
  77. package/dist/src/browser/dialog.js.map +0 -0
  78. package/dist/src/browser/emulation.d.ts +0 -0
  79. package/dist/src/browser/emulation.d.ts.map +0 -0
  80. package/dist/src/browser/emulation.js +0 -0
  81. package/dist/src/browser/emulation.js.map +0 -0
  82. package/dist/src/browser/find.d.ts +0 -0
  83. package/dist/src/browser/find.d.ts.map +0 -0
  84. package/dist/src/browser/find.js +0 -0
  85. package/dist/src/browser/find.js.map +0 -0
  86. package/dist/src/browser/har.d.ts +0 -0
  87. package/dist/src/browser/har.d.ts.map +0 -0
  88. package/dist/src/browser/har.js +0 -0
  89. package/dist/src/browser/har.js.map +0 -0
  90. package/dist/src/browser/index.d.ts +1 -0
  91. package/dist/src/browser/index.d.ts.map +1 -1
  92. package/dist/src/browser/index.js +1 -0
  93. package/dist/src/browser/index.js.map +1 -1
  94. package/dist/src/browser/network.d.ts +0 -0
  95. package/dist/src/browser/network.d.ts.map +0 -0
  96. package/dist/src/browser/network.js +0 -0
  97. package/dist/src/browser/network.js.map +0 -0
  98. package/dist/src/browser/pdf.d.ts +0 -0
  99. package/dist/src/browser/pdf.d.ts.map +0 -0
  100. package/dist/src/browser/pdf.js +0 -0
  101. package/dist/src/browser/pdf.js.map +0 -0
  102. package/dist/src/browser/profiler.d.ts +0 -0
  103. package/dist/src/browser/profiler.d.ts.map +0 -0
  104. package/dist/src/browser/profiler.js +0 -0
  105. package/dist/src/browser/profiler.js.map +0 -0
  106. package/dist/src/browser/record.d.ts +0 -0
  107. package/dist/src/browser/record.d.ts.map +0 -0
  108. package/dist/src/browser/record.js +0 -0
  109. package/dist/src/browser/record.js.map +0 -0
  110. package/dist/src/browser/ref-cache.d.ts +21 -0
  111. package/dist/src/browser/ref-cache.d.ts.map +1 -0
  112. package/dist/src/browser/ref-cache.js +70 -0
  113. package/dist/src/browser/ref-cache.js.map +1 -0
  114. package/dist/src/browser/screenshot.d.ts +0 -0
  115. package/dist/src/browser/screenshot.d.ts.map +0 -0
  116. package/dist/src/browser/screenshot.js +0 -0
  117. package/dist/src/browser/screenshot.js.map +0 -0
  118. package/dist/src/browser/session.d.ts +0 -0
  119. package/dist/src/browser/session.d.ts.map +0 -0
  120. package/dist/src/browser/session.js +0 -0
  121. package/dist/src/browser/session.js.map +0 -0
  122. package/dist/src/browser/snapshot.d.ts +0 -0
  123. package/dist/src/browser/snapshot.d.ts.map +0 -0
  124. package/dist/src/browser/snapshot.js +0 -0
  125. package/dist/src/browser/snapshot.js.map +0 -0
  126. package/dist/src/browser/storage.d.ts +0 -0
  127. package/dist/src/browser/storage.d.ts.map +0 -0
  128. package/dist/src/browser/storage.js +0 -0
  129. package/dist/src/browser/storage.js.map +0 -0
  130. package/dist/src/browser/tabs.d.ts +1 -1
  131. package/dist/src/browser/tabs.d.ts.map +1 -1
  132. package/dist/src/browser/tabs.js +20 -4
  133. package/dist/src/browser/tabs.js.map +1 -1
  134. package/dist/src/browser/trace.d.ts +0 -0
  135. package/dist/src/browser/trace.d.ts.map +0 -0
  136. package/dist/src/browser/trace.js +0 -0
  137. package/dist/src/browser/trace.js.map +0 -0
  138. package/dist/src/browser/types.d.ts +0 -0
  139. package/dist/src/browser/types.d.ts.map +0 -0
  140. package/dist/src/browser/types.js +0 -0
  141. package/dist/src/browser/types.js.map +0 -0
  142. package/dist/src/browser/vitals.d.ts +0 -0
  143. package/dist/src/browser/vitals.d.ts.map +0 -0
  144. package/dist/src/browser/vitals.js +0 -0
  145. package/dist/src/browser/vitals.js.map +0 -0
  146. package/dist/src/browser/wait.d.ts +0 -0
  147. package/dist/src/browser/wait.d.ts.map +0 -0
  148. package/dist/src/browser/wait.js +0 -0
  149. package/dist/src/browser/wait.js.map +0 -0
  150. package/dist/src/cli/action.d.ts +0 -0
  151. package/dist/src/cli/action.d.ts.map +1 -1
  152. package/dist/src/cli/action.js +87 -2
  153. package/dist/src/cli/action.js.map +1 -1
  154. package/dist/src/cli/commands.d.ts +0 -0
  155. package/dist/src/cli/commands.d.ts.map +1 -1
  156. package/dist/src/cli/commands.js +32 -3
  157. package/dist/src/cli/commands.js.map +1 -1
  158. package/dist/src/cli/output.d.ts +0 -0
  159. package/dist/src/cli/output.d.ts.map +0 -0
  160. package/dist/src/cli/output.js +0 -0
  161. package/dist/src/cli/output.js.map +0 -0
  162. package/dist/src/cli/platform.d.ts +0 -0
  163. package/dist/src/cli/platform.d.ts.map +0 -0
  164. package/dist/src/cli/platform.js +0 -0
  165. package/dist/src/cli/platform.js.map +0 -0
  166. package/dist/src/cli/types.d.ts +0 -0
  167. package/dist/src/cli/types.d.ts.map +0 -0
  168. package/dist/src/cli/types.js +0 -0
  169. package/dist/src/cli/types.js.map +0 -0
  170. package/dist/src/cli.d.ts +0 -0
  171. package/dist/src/cli.d.ts.map +0 -0
  172. package/dist/src/cli.js.map +0 -0
  173. package/dist/src/index.d.ts +0 -0
  174. package/dist/src/index.d.ts.map +0 -0
  175. package/dist/src/index.js +0 -0
  176. package/dist/src/index.js.map +0 -0
  177. package/dist/tsconfig.tsbuildinfo +1 -1
  178. package/package.json +1 -1
  179. package/src/__tests__/output.test.ts +62 -0
  180. package/src/__tests__/ref-cache.test.ts +134 -0
  181. package/src/browser/action-builder/analyzer.ts +0 -0
  182. package/src/browser/action-builder/types.ts +0 -0
  183. package/src/browser/actions.ts +0 -0
  184. package/src/browser/adapters/gemini.ts +0 -0
  185. package/src/browser/adapters/google.ts +0 -0
  186. package/src/browser/adapters/index.ts +0 -0
  187. package/src/browser/adapters/instagram.ts +0 -0
  188. package/src/browser/adapters/linkedin.ts +0 -0
  189. package/src/browser/adapters/microsoft.ts +0 -0
  190. package/src/browser/adapters/x.ts +0 -0
  191. package/src/browser/batch.ts +0 -0
  192. package/src/browser/browser.ts +0 -0
  193. package/src/browser/cdp.ts +0 -0
  194. package/src/browser/console-log.ts +0 -0
  195. package/src/browser/dashboard/api-types.ts +0 -0
  196. package/src/browser/dashboard/server.ts +0 -0
  197. package/src/browser/dashboard/ui.html +0 -0
  198. package/src/browser/dialog.ts +0 -0
  199. package/src/browser/emulation.ts +0 -0
  200. package/src/browser/find.ts +0 -0
  201. package/src/browser/har.ts +0 -0
  202. package/src/browser/index.ts +1 -0
  203. package/src/browser/network.ts +0 -0
  204. package/src/browser/pdf.ts +0 -0
  205. package/src/browser/profiler.ts +0 -0
  206. package/src/browser/record.ts +0 -0
  207. package/src/browser/ref-cache.ts +90 -0
  208. package/src/browser/screenshot.ts +0 -0
  209. package/src/browser/session.ts +0 -0
  210. package/src/browser/snapshot.ts +0 -0
  211. package/src/browser/storage.ts +0 -0
  212. package/src/browser/tabs.ts +36 -7
  213. package/src/browser/trace.ts +0 -0
  214. package/src/browser/types.ts +0 -0
  215. package/src/browser/vitals.ts +0 -0
  216. package/src/browser/wait.ts +0 -0
  217. package/src/cli/action.ts +85 -3
  218. package/src/cli/commands.ts +35 -3
  219. package/src/cli/output.ts +0 -0
  220. package/src/cli/platform.ts +0 -0
  221. package/src/cli/types.ts +0 -0
  222. package/src/cli.ts +0 -0
  223. package/src/index.ts +0 -0
  224. package/dist/package.json +0 -71
  225. package/dist/src/browser/playbook/browser-handlers.d.ts +0 -3
  226. package/dist/src/browser/playbook/browser-handlers.d.ts.map +0 -1
  227. package/dist/src/browser/playbook/browser-handlers.js +0 -377
  228. package/dist/src/browser/playbook/browser-handlers.js.map +0 -1
  229. package/dist/src/browser/playbook/builtin-handlers.d.ts +0 -3
  230. package/dist/src/browser/playbook/builtin-handlers.d.ts.map +0 -1
  231. package/dist/src/browser/playbook/builtin-handlers.js +0 -364
  232. package/dist/src/browser/playbook/builtin-handlers.js.map +0 -1
  233. package/dist/src/browser/playbook/index.d.ts +0 -3
  234. package/dist/src/browser/playbook/index.d.ts.map +0 -1
  235. package/dist/src/browser/playbook/index.js +0 -3
  236. package/dist/src/browser/playbook/index.js.map +0 -1
  237. package/dist/src/browser/playbook/store.d.ts +0 -8
  238. package/dist/src/browser/playbook/store.d.ts.map +0 -1
  239. package/dist/src/browser/playbook/store.js +0 -87
  240. package/dist/src/browser/playbook/store.js.map +0 -1
  241. package/dist/src/browser/workflow/builtin-handlers.d.ts +0 -3
  242. package/dist/src/browser/workflow/builtin-handlers.d.ts.map +0 -1
  243. package/dist/src/browser/workflow/builtin-handlers.js +0 -343
  244. package/dist/src/browser/workflow/builtin-handlers.js.map +0 -1
  245. package/dist/src/browser/workflow/engine.d.ts +0 -10
  246. package/dist/src/browser/workflow/engine.d.ts.map +0 -1
  247. package/dist/src/browser/workflow/engine.js +0 -174
  248. package/dist/src/browser/workflow/engine.js.map +0 -1
  249. package/dist/src/browser/workflow/expression.d.ts +0 -4
  250. package/dist/src/browser/workflow/expression.d.ts.map +0 -1
  251. package/dist/src/browser/workflow/expression.js +0 -89
  252. package/dist/src/browser/workflow/expression.js.map +0 -1
  253. package/dist/src/browser/workflow/index.d.ts +0 -6
  254. package/dist/src/browser/workflow/index.d.ts.map +0 -1
  255. package/dist/src/browser/workflow/index.js +0 -6
  256. package/dist/src/browser/workflow/index.js.map +0 -1
  257. package/dist/src/browser/workflow/store.d.ts +0 -8
  258. package/dist/src/browser/workflow/store.d.ts.map +0 -1
  259. package/dist/src/browser/workflow/store.js +0 -87
  260. package/dist/src/browser/workflow/store.js.map +0 -1
  261. package/dist/src/browser/workflow/types.d.ts +0 -62
  262. package/dist/src/browser/workflow/types.d.ts.map +0 -1
  263. package/dist/src/browser/workflow/types.js +0 -2
  264. package/dist/src/browser/workflow/types.js.map +0 -1
  265. package/dist/src/cli/playbook.d.ts +0 -3
  266. package/dist/src/cli/playbook.d.ts.map +0 -1
  267. package/dist/src/cli/playbook.js +0 -265
  268. package/dist/src/cli/playbook.js.map +0 -1
  269. package/dist/src/cli/workflow.d.ts +0 -2
  270. package/dist/src/cli/workflow.d.ts.map +0 -1
  271. package/dist/src/cli/workflow.js +0 -3
  272. package/dist/src/cli/workflow.js.map +0 -1
File without changes
File without changes
@@ -20,3 +20,4 @@ export * from './trace.js';
20
20
  export * from './profiler.js';
21
21
  export * from './vitals.js';
22
22
  export * from './har.js';
23
+ export * from './ref-cache.js';
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,90 @@
1
+ /**
2
+ * AX-tree ref cache persistence.
3
+ *
4
+ * `snapshot` and `find` are separate CLI invocations — each starts a fresh
5
+ * node process, so the in-memory ElementRef Map built by captureSnapshot()
6
+ * does not survive between them. This module persists a lightweight lookup
7
+ * index (ref -> role/name/nodeId/backendDOMNodeId, i.e. everything CDP needs
8
+ * to re-target an element) to disk so a later process can rehydrate it.
9
+ *
10
+ * The full AX-tree text/dump is intentionally NOT persisted — only the
11
+ * per-ref index, to keep the file small.
12
+ */
13
+ import { readFile, writeFile, mkdir, rm } from 'fs/promises';
14
+ import { join } from 'path';
15
+ import type { ElementRef } from './types.js';
16
+
17
+ const CACHE_DIR = join(process.cwd(), '.monomind', 'monobrowse');
18
+ const CACHE_FILE = join(CACHE_DIR, 'ax-snapshot.json');
19
+
20
+ /** Snapshot older than this is flagged as possibly stale (page may have changed). */
21
+ export const REF_CACHE_STALE_MS = 30_000;
22
+
23
+ interface RefCacheFile {
24
+ targetId: string;
25
+ url: string;
26
+ savedAt: number;
27
+ refs: ElementRef[];
28
+ }
29
+
30
+ export interface RefCacheEntry {
31
+ refs: Map<string, ElementRef>;
32
+ url: string;
33
+ savedAt: number;
34
+ ageMs: number;
35
+ stale: boolean;
36
+ }
37
+
38
+ /** Persist the current ref index for a target so a later CLI process can read it back. */
39
+ export async function saveRefCache(
40
+ targetId: string,
41
+ url: string,
42
+ refs: Map<string, ElementRef>
43
+ ): Promise<void> {
44
+ try {
45
+ await mkdir(CACHE_DIR, { recursive: true });
46
+ const data: RefCacheFile = {
47
+ targetId,
48
+ url,
49
+ savedAt: Date.now(),
50
+ refs: [...refs.values()],
51
+ };
52
+ await writeFile(CACHE_FILE, JSON.stringify(data));
53
+ } catch {
54
+ // Best-effort — persistence failure just means cross-process rehydration
55
+ // won't work; in-process (same run) behavior is unaffected.
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Load the persisted ref index, scoped to the given targetId (a cache from a
61
+ * different tab/target is ignored). Returns null if no usable cache exists —
62
+ * callers fall back to an empty in-memory Map, matching prior behavior.
63
+ */
64
+ export async function loadRefCache(targetId: string): Promise<RefCacheEntry | null> {
65
+ try {
66
+ const raw = await readFile(CACHE_FILE, 'utf8');
67
+ const data: RefCacheFile = JSON.parse(raw);
68
+ if (!data || !Array.isArray(data.refs) || data.targetId !== targetId) return null;
69
+
70
+ const refs = new Map<string, ElementRef>();
71
+ for (const ref of data.refs) {
72
+ if (ref && typeof ref.ref === 'string') refs.set(ref.ref, ref);
73
+ }
74
+ if (refs.size === 0) return null;
75
+
76
+ const ageMs = Date.now() - data.savedAt;
77
+ return { refs, url: data.url, savedAt: data.savedAt, ageMs, stale: ageMs > REF_CACHE_STALE_MS };
78
+ } catch {
79
+ return null;
80
+ }
81
+ }
82
+
83
+ /** Drop the persisted ref index — call whenever refs are invalidated (navigation, tab switch, close). */
84
+ export async function clearRefCache(): Promise<void> {
85
+ try {
86
+ await rm(CACHE_FILE, { force: true });
87
+ } catch {
88
+ // Nothing to clear, or not writable — non-fatal.
89
+ }
90
+ }
File without changes
File without changes
File without changes
File without changes
@@ -25,13 +25,42 @@ export async function activateTab(client: CdpClient, oldSessionId: string, targe
25
25
  }
26
26
 
27
27
  export async function switchToFrame(
28
- _client: CdpClient,
29
- _sessionId: string,
30
- _frameSelector: string
28
+ client: CdpClient,
29
+ sessionId: string,
30
+ frameSelector: string
31
31
  ): Promise<string | null> {
32
- throw new Error(
33
- 'switchToFrame is not yet implemented. ' +
34
- 'For same-origin frames, CDP commands already apply to the whole page. ' +
35
- 'For cross-origin (OOPIF) frames, call Target.attachToTarget with the frame target ID.'
32
+ const { result } = await client.send<{ result: { result: { value: string | null } } }>(
33
+ 'Runtime.evaluate',
34
+ {
35
+ expression: `(() => {
36
+ const el = document.querySelector(${JSON.stringify(frameSelector)});
37
+ if (!el || el.tagName !== 'IFRAME') return null;
38
+ return el.src || null;
39
+ })()`,
40
+ returnByValue: true,
41
+ },
42
+ sessionId
36
43
  );
44
+ const frameSrc = result?.result?.value ?? null;
45
+
46
+ const { frameTree } = await client.send<{
47
+ frameTree: { childFrames?: Array<{ frame: { id: string; url: string; securityOrigin: string } }> };
48
+ }>('Page.getFrameTree', {}, sessionId);
49
+
50
+ const match = frameTree.childFrames?.find(
51
+ (cf) => cf.frame.url === frameSrc || cf.frame.id === frameSelector
52
+ );
53
+ if (!match) return frameSrc;
54
+
55
+ const targets = await client.send<{ targetInfos: Array<{ targetId: string; type: string; url: string }> }>(
56
+ 'Target.getTargets', {}
57
+ );
58
+ const oopif = targets.targetInfos.find(
59
+ (t) => t.type === 'iframe' && t.url === match.frame.url
60
+ );
61
+ if (oopif) {
62
+ await client.send('Target.attachToTarget', { targetId: oopif.targetId, flatten: true });
63
+ }
64
+
65
+ return frameSrc;
37
66
  }
File without changes
File without changes
File without changes
File without changes
package/src/cli/action.ts CHANGED
@@ -4,7 +4,7 @@ import { readdir, readFile, writeFile, mkdir } from 'node:fs/promises';
4
4
  import { existsSync } from 'node:fs';
5
5
  import { join } from 'node:path';
6
6
  import { analyzePageForAction, type AnalyzerPage } from '../index.js';
7
- import type { ActionDef } from '../index.js';
7
+ import type { ActionDef, StepDef } from '../index.js';
8
8
 
9
9
  async function readAction(filePath: string): Promise<ActionDef> {
10
10
  return JSON.parse(await readFile(filePath, 'utf8')) as ActionDef;
@@ -96,8 +96,90 @@ export function createActionCommand(): Command {
96
96
  if (eq > 0) params[pair.slice(0, eq)] = pair.slice(eq + 1);
97
97
  }
98
98
  console.log(`Running action: ${actionId} with account: ${opts.account}`);
99
- console.log('Params:', params);
100
- console.log('(Action runner not yet implemented — use browse playbook run for full execution)');
99
+
100
+ const custom = await getCustomActions();
101
+ const def = custom.find(a => a.id === actionId);
102
+ if (!def) {
103
+ console.error(`Action not found in custom actions: ${actionId}`);
104
+ console.error('Built-in actions require adapter step definitions — use "action build" to create a custom action.');
105
+ process.exit(1);
106
+ }
107
+
108
+ const { connectToTarget } = await import('../browser/browser.js');
109
+ const { openUrl } = await import('../browser/browser.js');
110
+ const { clickElement, fillElement, evaluateJs } = await import('../browser/actions.js');
111
+ const { findBySelector } = await import('../browser/find.js');
112
+ const { waitFor } = await import('../browser/wait.js');
113
+ const port = parseInt(process.env.MONOBROWSE_PORT ?? '9222', 10);
114
+ const { client, sessionId } = await connectToTarget(port);
115
+ const refs = new Map<string, import('../browser/types.js').ElementRef>();
116
+
117
+ const interpolate = (s: string) =>
118
+ s.replace(/\{\{(\w+)\}\}/g, (_, k: string) => params[k] ?? `{{${k}}}`);
119
+
120
+ async function runSteps(steps: StepDef[]): Promise<void> {
121
+ for (const step of steps) {
122
+ switch (step.type) {
123
+ case 'navigate':
124
+ await openUrl(client, sessionId, interpolate(step.url));
125
+ console.log(` navigate → ${step.url}`);
126
+ break;
127
+ case 'find': {
128
+ for (const sel of step.selectors) {
129
+ const found = await findBySelector(client, sessionId, refs, interpolate(sel)).catch(() => null);
130
+ if (found) { refs.set(step.as, found); break; }
131
+ }
132
+ console.log(` find → ${step.as}`);
133
+ break;
134
+ }
135
+ case 'click': {
136
+ const ref = refs.get(step.target);
137
+ if (!ref) throw new Error(`Element "${step.target}" not found`);
138
+ await clickElement(client, sessionId, ref);
139
+ console.log(` click → ${step.target}`);
140
+ break;
141
+ }
142
+ case 'type': {
143
+ const ref = refs.get(step.target);
144
+ if (!ref) throw new Error(`Element "${step.target}" not found`);
145
+ await fillElement(client, sessionId, ref, interpolate(step.text));
146
+ console.log(` type → ${step.target}`);
147
+ break;
148
+ }
149
+ case 'wait':
150
+ if (step.condition === 'network_idle') {
151
+ await waitFor(client, sessionId, { load: 'networkidle', timeout: step.timeout });
152
+ } else if (step.condition === 'selector' && step.selector) {
153
+ await waitFor(client, sessionId, { selector: step.selector, timeout: step.timeout });
154
+ } else if (step.condition === 'duration') {
155
+ await new Promise(r => setTimeout(r, step.timeout ?? 1000));
156
+ }
157
+ console.log(` wait → ${step.condition}`);
158
+ break;
159
+ case 'extract': {
160
+ const ref = refs.get(step.target);
161
+ if (!ref) throw new Error(`Element "${step.target}" not found`);
162
+ const val = step.attribute
163
+ ? await evaluateJs(client, sessionId, `document.querySelector('[data-ref="${ref.ref}"]')?.getAttribute('${step.attribute}')`)
164
+ : await evaluateJs(client, sessionId, `document.querySelector('[data-ref="${ref.ref}"]')?.textContent`);
165
+ console.log(` extract → ${step.as}: ${val}`);
166
+ break;
167
+ }
168
+ case 'condition': {
169
+ const result = await evaluateJs(client, sessionId, step.expression);
170
+ if (result) {
171
+ await runSteps(step.then);
172
+ } else if (step.else) {
173
+ await runSteps(step.else);
174
+ }
175
+ break;
176
+ }
177
+ }
178
+ }
179
+ }
180
+
181
+ await runSteps(def.steps);
182
+ console.log(`\nAction ${actionId} completed successfully.`);
101
183
  });
102
184
 
103
185
  cmd
@@ -36,10 +36,27 @@ async function ensureConnected(port: number, targetId?: string) {
36
36
  _sessionId = conn.sessionId;
37
37
  _targetId = conn.target.id;
38
38
  _refs = new Map();
39
+ await hydrateRefsFromCache(browser, _targetId);
39
40
  }
40
41
  return { client: _client!, sessionId: _sessionId, targetId: _targetId };
41
42
  }
42
43
 
44
+ // Each CLI invocation is a fresh process, so the in-memory _refs Map built by
45
+ // a prior `snapshot` command is gone by the time a later `find`/`click`/etc.
46
+ // command runs. Rehydrate it from the on-disk ref cache (written by
47
+ // captureSnapshot call sites below) so refs resolved by a previous process
48
+ // remain usable. Falls back silently to an empty Map if no cache exists.
49
+ async function hydrateRefsFromCache(browser: Awaited<ReturnType<typeof getBrowser>>, targetId: string): Promise<void> {
50
+ const cached = await browser.loadRefCache(targetId);
51
+ if (!cached) return;
52
+ _refs = cached.refs;
53
+ if (cached.stale) {
54
+ output.printWarning(
55
+ `AX ref cache is ${Math.round(cached.ageMs / 1000)}s old — page may have changed since the last snapshot; re-run snapshot if refs don't resolve as expected`
56
+ );
57
+ }
58
+ }
59
+
43
60
  // URL patterns that signal an unambiguous login/auth wall.
44
61
  // Excludes 'auth', 'oauth', 'sso', 'saml' — their callback/ACS/token paths
45
62
  // (/auth/callback, /sso/callback, /saml/acs) are completion endpoints, not walls.
@@ -154,6 +171,18 @@ async function switchToHeaded(url: string, port: number): Promise<void> {
154
171
  }
155
172
  }
156
173
 
174
+ /**
175
+ * Sanitize an image-format flag. The host CLI (monomind) defines a GLOBAL
176
+ * --format flag for output shaping (text|json|table, default 'text') that
177
+ * leaks into subcommand flags — so ctx.flags.format arrives as 'text' even
178
+ * when the user never passed it, and Chrome rejects it with
179
+ * "CDP error -32602: Invalid image format". Only trust values that are real
180
+ * image formats; otherwise fall back to the subcommand's own default.
181
+ */
182
+ function imageFormat<T extends string>(value: unknown, allowed: readonly T[], fallback: T): T {
183
+ return allowed.includes(value as T) ? (value as T) : fallback;
184
+ }
185
+
157
186
  function print(msg: string) {
158
187
  process.stdout.write(msg + '\n');
159
188
  }
@@ -266,6 +295,7 @@ const snapshotCommand: Command = {
266
295
  });
267
296
 
268
297
  _refs = result.refs;
298
+ await browser.saveRefCache(_targetId, result.url, _refs);
269
299
 
270
300
  const applyOutputLimits = (text: string): string => {
271
301
  let out = text;
@@ -545,7 +575,7 @@ const screenshotCommand: Command = {
545
575
  result = await browser.captureScreenshot(client, sessionId, {
546
576
  path: ctx.args[0] as string,
547
577
  fullPage: ctx.flags.full as boolean,
548
- format: ctx.flags.format as 'png' | 'jpeg' | 'webp',
578
+ format: imageFormat(ctx.flags.format, ['png', 'jpeg', 'webp'] as const, 'png'),
549
579
  quality: ctx.flags.quality as number,
550
580
  annotate,
551
581
  refs: annotate ? _refs : undefined,
@@ -918,6 +948,7 @@ const stateCommand: Command = {
918
948
  await browser.clearLocalStorage(c, sid);
919
949
  await browser.clearSessionStorage(c, sid);
920
950
  _refs = new Map();
951
+ await browser.clearRefCache();
921
952
  output.printSuccess('Browser state cleared (cookies, localStorage, sessionStorage, refs)');
922
953
  return { success: true };
923
954
  }
@@ -2228,6 +2259,7 @@ const diffCommand: Command = {
2228
2259
  const snap2 = await browser.captureSnapshot(client, sessionId, { interactiveOnly: ctx.flags.interactive as boolean });
2229
2260
 
2230
2261
  _refs = snap2.refs;
2262
+ await browser.saveRefCache(_targetId, snap2.url, _refs);
2231
2263
 
2232
2264
  // Text diff
2233
2265
  const lines1 = snap1.text.split('\n');
@@ -2496,7 +2528,7 @@ const recordCommand: Command = {
2496
2528
  switch (action) {
2497
2529
  case 'start':
2498
2530
  await browser.startRecording(client, sessionId, {
2499
- format: ctx.flags.format as 'jpeg' | 'png',
2531
+ format: imageFormat(ctx.flags.format, ['jpeg', 'png'] as const, 'jpeg'),
2500
2532
  quality: ctx.flags.quality as number,
2501
2533
  });
2502
2534
  output.printSuccess('Recording started');
@@ -2515,7 +2547,7 @@ const recordCommand: Command = {
2515
2547
  output.printInfo(`Previous recording saved: ${prevPath}`);
2516
2548
  }
2517
2549
  await browser.startRecording(client, sessionId, {
2518
- format: ctx.flags.format as 'jpeg' | 'png',
2550
+ format: imageFormat(ctx.flags.format, ['jpeg', 'png'] as const, 'jpeg'),
2519
2551
  quality: ctx.flags.quality as number,
2520
2552
  });
2521
2553
  output.printSuccess('Recording restarted');
package/src/cli/output.ts CHANGED
File without changes
File without changes
package/src/cli/types.ts CHANGED
File without changes
package/src/cli.ts CHANGED
File without changes
package/src/index.ts CHANGED
File without changes
package/dist/package.json DELETED
@@ -1,71 +0,0 @@
1
- {
2
- "name": "@monoes/monobrowse",
3
- "version": "1.0.1",
4
- "description": "Native browser automation via Chrome DevTools Protocol — the engine powering monomind browse",
5
- "type": "module",
6
- "bin": {
7
- "monobrowse": "./src/cli.js"
8
- },
9
- "main": "./src/index.js",
10
- "types": "./src/index.d.ts",
11
- "exports": {
12
- ".": {
13
- "types": "./src/index.d.ts",
14
- "import": "./src/index.js"
15
- },
16
- "./cli": {
17
- "types": "./src/cli.d.ts",
18
- "import": "./src/cli.js"
19
- },
20
- "./cli/commands": {
21
- "types": "./src/cli/commands.d.ts",
22
- "import": "./src/cli/commands.js"
23
- },
24
- "./cli/types": {
25
- "types": "./src/cli/types.d.ts",
26
- "import": "./src/cli/types.js"
27
- }
28
- },
29
- "files": [
30
- "dist",
31
- "src"
32
- ],
33
- "engines": {
34
- "node": ">=18.0.0"
35
- },
36
- "keywords": [
37
- "browser-automation",
38
- "cdp",
39
- "chrome-devtools-protocol",
40
- "monomind",
41
- "web-scraping",
42
- "accessibility"
43
- ],
44
- "author": {
45
- "name": "nokhodian",
46
- "email": "nokhodian@gmail.com",
47
- "url": "https://github.com/nokhodian"
48
- },
49
- "license": "MIT",
50
- "repository": {
51
- "type": "git",
52
- "url": "https://github.com/monoes/monomind.git",
53
- "directory": "packages/@monoes/monobrowse"
54
- },
55
- "dependencies": {
56
- "commander": "^12.1.0",
57
- "ws": "^8.21.0"
58
- },
59
- "peerDependencies": {
60
- "@anthropic-ai/sdk": ">=0.20.0"
61
- },
62
- "peerDependenciesMeta": {
63
- "@anthropic-ai/sdk": {
64
- "optional": true
65
- }
66
- },
67
- "devDependencies": {
68
- "@anthropic-ai/sdk": "^0.39.0",
69
- "typescript": "^5.8.3"
70
- }
71
- }
@@ -1,3 +0,0 @@
1
- import type { NodeHandler } from '@monoes/monoplaybook';
2
- export declare function createBrowserHandlers(): Map<string, NodeHandler>;
3
- //# sourceMappingURL=browser-handlers.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"browser-handlers.d.ts","sourceRoot":"","sources":["../../../../src/browser/playbook/browser-handlers.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,WAAW,EAAQ,MAAM,sBAAsB,CAAC;AAkI9D,wBAAgB,qBAAqB,IAAI,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CA2ShE"}