browser-pilot-cli 0.1.4 → 0.1.5

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 (3) hide show
  1. package/README.md +12 -1
  2. package/dist/cli.js +47 -11
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -96,8 +96,10 @@ The daemon maintains a single CDP WebSocket connection. A pulsing blue glow arou
96
96
  |---------|---------|-------------|
97
97
  | `bp open <url>` | snapshot | Navigate to URL |
98
98
  | `bp snapshot` | snapshot | Get interactive elements |
99
- | `bp click <ref>` | snapshot | Click element by ref number |
99
+ | `bp click <ref>` | snapshot | Click element by ref number (`--double`, `--right`) |
100
+ | `bp click 0 --xy x,y` | snapshot | Click at viewport coordinates (canvas, maps) |
100
101
  | `bp type <ref> <text>` | snapshot | Type into element (`--clear`, `--submit`) |
102
+ | `bp keyboard <text>` | snapshot | Type via keyboard events (`--click`, `--clear`) |
101
103
  | `bp press <key>` | snapshot | Press key (Enter, Escape, Control+a, Meta+c) |
102
104
  | `bp eval [js]` | value | Run JavaScript (escape hatch for anything) |
103
105
 
@@ -211,6 +213,15 @@ bp upload ~/Downloads/photo.jpg # auto-finds file input, triggers upload
211
213
  bp type 3 "new content" --clear # replace content in a rich text editor
212
214
  ```
213
215
 
216
+ For canvas-based editors (Google Docs, Google Sheets, Figma), use `bp keyboard` which sends real keyboard events:
217
+
218
+ ```bash
219
+ bp keyboard "Hello Docs!" --click ".kix-appview-editor" # Google Docs
220
+ bp press Meta+b # toggle bold
221
+ bp keyboard "bold text"
222
+ bp click 0 --xy 400,300 # click canvas area
223
+ ```
224
+
214
225
  Shadow DOM elements are traversed automatically — no special commands needed. Elements inside open shadow roots (even deeply nested) appear in snapshots and can be clicked/typed normally.
215
226
 
216
227
  For `<select>` dropdowns (shown as `combobox`), use `bp eval`:
package/dist/cli.js CHANGED
@@ -4,6 +4,7 @@
4
4
  import { Command } from "commander";
5
5
  import { writeFileSync as writeFileSync3, readFileSync as readFileSync5, existsSync as existsSync6 } from "fs";
6
6
  import { resolve as resolvePath } from "path";
7
+ import { createRequire } from "module";
7
8
 
8
9
  // src/session.ts
9
10
  import { spawn } from "child_process";
@@ -542,8 +543,10 @@ async function resolveTarget(transport, sessionId, target, targetId) {
542
543
  }
543
544
 
544
545
  // src/cli.ts
546
+ var require2 = createRequire(import.meta.url);
547
+ var PKG_VERSION = require2("../package.json").version;
545
548
  var program = new Command();
546
- program.name("bp").description("Control your browser from the command line").version("0.1.0").option("--human", "force human-readable output (default when TTY)").addHelpText("after", `
549
+ program.name("bp").description("Control your browser from the command line").version(PKG_VERSION).option("--human", "force human-readable output (default when TTY)").addHelpText("after", `
547
550
  Workflow:
548
551
  bp connect # one-time setup (click Allow in Chrome)
549
552
  bp open <url> # navigate \u2014 returns snapshot with [ref] numbers
@@ -659,7 +662,30 @@ var KEY_DEFS = {
659
662
  home: { key: "Home", code: "Home", keyCode: 36 },
660
663
  end: { key: "End", code: "End", keyCode: 35 },
661
664
  pageup: { key: "PageUp", code: "PageUp", keyCode: 33 },
662
- pagedown: { key: "PageDown", code: "PageDown", keyCode: 34 }
665
+ pagedown: { key: "PageDown", code: "PageDown", keyCode: 34 },
666
+ // Digits
667
+ "0": { key: "0", code: "Digit0", keyCode: 48 },
668
+ "1": { key: "1", code: "Digit1", keyCode: 49 },
669
+ "2": { key: "2", code: "Digit2", keyCode: 50 },
670
+ "3": { key: "3", code: "Digit3", keyCode: 51 },
671
+ "4": { key: "4", code: "Digit4", keyCode: 52 },
672
+ "5": { key: "5", code: "Digit5", keyCode: 53 },
673
+ "6": { key: "6", code: "Digit6", keyCode: 54 },
674
+ "7": { key: "7", code: "Digit7", keyCode: 55 },
675
+ "8": { key: "8", code: "Digit8", keyCode: 56 },
676
+ "9": { key: "9", code: "Digit9", keyCode: 57 },
677
+ // Punctuation
678
+ "-": { key: "-", code: "Minus", keyCode: 189 },
679
+ "=": { key: "=", code: "Equal", keyCode: 187 },
680
+ "[": { key: "[", code: "BracketLeft", keyCode: 219 },
681
+ "]": { key: "]", code: "BracketRight", keyCode: 221 },
682
+ "\\": { key: "\\", code: "Backslash", keyCode: 220 },
683
+ ";": { key: ";", code: "Semicolon", keyCode: 186 },
684
+ "'": { key: "'", code: "Quote", keyCode: 222 },
685
+ ",": { key: ",", code: "Comma", keyCode: 188 },
686
+ ".": { key: ".", code: "Period", keyCode: 190 },
687
+ "/": { key: "/", code: "Slash", keyCode: 191 },
688
+ "`": { key: "`", code: "Backquote", keyCode: 192 }
663
689
  };
664
690
  var MOD_DEFS = {
665
691
  control: { key: "Control", code: "ControlLeft", keyCode: 17, mask: 2 },
@@ -761,6 +787,7 @@ Examples:
761
787
  bp click 0 --xy 400,300 # click at coordinates (ref ignored)
762
788
  bp click 0 --xy 400,300 --double # double-click at coordinates
763
789
  bp click 0 --xy 400,300 --right # right-click at coordinates`).action(action(async (ref, opts) => {
790
+ if (opts.double && opts.right) throw new Error("--double and --right are mutually exclusive");
764
791
  const limit = parseLimit(opts.limit);
765
792
  await withPilot(async ({ transport, sessionId, state }) => {
766
793
  if (opts.xy) {
@@ -848,6 +875,13 @@ program.command("type <ref> <text>").description("Type text into element and ret
848
875
  emitSnapshot(await snap(transport, sessionId, state.activeTargetId, limit));
849
876
  });
850
877
  }));
878
+ function charToCode(char) {
879
+ const kd = KEY_DEFS[char];
880
+ if (kd) return kd;
881
+ if (/^[a-zA-Z]$/.test(char)) return { key: char, code: `Key${char.toUpperCase()}`, keyCode: char.toUpperCase().charCodeAt(0) };
882
+ if (char === " ") return { key: " ", code: "Space", keyCode: 32 };
883
+ return { key: char, code: "", keyCode: char.charCodeAt(0) };
884
+ }
851
885
  async function typeViaKeyboard(t, sid, text) {
852
886
  for (const char of text) {
853
887
  if (char === "\n") {
@@ -855,10 +889,9 @@ async function typeViaKeyboard(t, sid, text) {
855
889
  } else if (char === " ") {
856
890
  await dispatchKey(t, sid, "Tab");
857
891
  } else if (char.charCodeAt(0) >= 32 && char.charCodeAt(0) <= 126) {
858
- const code = char === " " ? "Space" : `Key${char.toUpperCase()}`;
859
- const keyCode = char.toUpperCase().charCodeAt(0);
860
- await t.send("Input.dispatchKeyEvent", { type: "keyDown", key: char, code, windowsVirtualKeyCode: keyCode, text: char }, sid);
861
- await t.send("Input.dispatchKeyEvent", { type: "keyUp", key: char, code, windowsVirtualKeyCode: keyCode }, sid);
892
+ const { key, code, keyCode } = charToCode(char);
893
+ await t.send("Input.dispatchKeyEvent", { type: "keyDown", key, code, windowsVirtualKeyCode: keyCode, text: char }, sid);
894
+ await t.send("Input.dispatchKeyEvent", { type: "keyUp", key, code, windowsVirtualKeyCode: keyCode }, sid);
862
895
  } else {
863
896
  await t.send("Input.insertText", { text: char }, sid);
864
897
  }
@@ -890,19 +923,22 @@ Examples:
890
923
  await new Promise((r) => setTimeout(r, 300));
891
924
  }
892
925
  if (opts.clear) {
893
- await dispatchKey(transport, sessionId, "Meta+a");
926
+ const selectAllMod = process.platform === "darwin" ? "Meta" : "Control";
927
+ await dispatchKey(transport, sessionId, `${selectAllMod}+a`);
894
928
  await dispatchKey(transport, sessionId, "Delete");
895
929
  }
896
930
  if (opts.delay) {
897
931
  const delay = parseInt(opts.delay, 10);
932
+ if (isNaN(delay) || delay < 0) throw new Error("--delay must be a non-negative number");
898
933
  for (const char of text) {
899
934
  if (char === "\n") {
900
935
  await dispatchKey(transport, sessionId, "Enter");
936
+ } else if (char === " ") {
937
+ await dispatchKey(transport, sessionId, "Tab");
901
938
  } else if (char.charCodeAt(0) >= 32 && char.charCodeAt(0) <= 126) {
902
- const code = char === " " ? "Space" : `Key${char.toUpperCase()}`;
903
- const keyCode = char.toUpperCase().charCodeAt(0);
904
- await transport.send("Input.dispatchKeyEvent", { type: "keyDown", key: char, code, windowsVirtualKeyCode: keyCode, text: char }, sessionId);
905
- await transport.send("Input.dispatchKeyEvent", { type: "keyUp", key: char, code, windowsVirtualKeyCode: keyCode }, sessionId);
939
+ const { key, code, keyCode } = charToCode(char);
940
+ await transport.send("Input.dispatchKeyEvent", { type: "keyDown", key, code, windowsVirtualKeyCode: keyCode, text: char }, sessionId);
941
+ await transport.send("Input.dispatchKeyEvent", { type: "keyUp", key, code, windowsVirtualKeyCode: keyCode }, sessionId);
906
942
  } else {
907
943
  await transport.send("Input.insertText", { text: char }, sessionId);
908
944
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "browser-pilot-cli",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "CLI tool to control your browser via Chrome DevTools Protocol",
5
5
  "type": "module",
6
6
  "bin": {