@oomfware/cbr 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/LICENSE +14 -0
  2. package/README.md +72 -0
  3. package/dist/assets/system-prompt.md +147 -0
  4. package/dist/client.mjs +54 -0
  5. package/dist/index.mjs +1366 -0
  6. package/package.json +45 -0
  7. package/src/assets/system-prompt.md +147 -0
  8. package/src/client.ts +70 -0
  9. package/src/commands/ask.ts +202 -0
  10. package/src/commands/clean.ts +18 -0
  11. package/src/index.ts +34 -0
  12. package/src/lib/commands/_types.ts +24 -0
  13. package/src/lib/commands/_utils.ts +38 -0
  14. package/src/lib/commands/back.ts +14 -0
  15. package/src/lib/commands/check.ts +14 -0
  16. package/src/lib/commands/click.ts +14 -0
  17. package/src/lib/commands/close.ts +17 -0
  18. package/src/lib/commands/dblclick.ts +14 -0
  19. package/src/lib/commands/download.ts +36 -0
  20. package/src/lib/commands/eval.ts +23 -0
  21. package/src/lib/commands/fill.ts +18 -0
  22. package/src/lib/commands/forward.ts +14 -0
  23. package/src/lib/commands/frame.ts +106 -0
  24. package/src/lib/commands/get.ts +95 -0
  25. package/src/lib/commands/hover.ts +14 -0
  26. package/src/lib/commands/is.ts +53 -0
  27. package/src/lib/commands/open.ts +15 -0
  28. package/src/lib/commands/press.ts +13 -0
  29. package/src/lib/commands/reload.ts +14 -0
  30. package/src/lib/commands/resources.ts +37 -0
  31. package/src/lib/commands/screenshot.ts +26 -0
  32. package/src/lib/commands/scroll.ts +30 -0
  33. package/src/lib/commands/select.ts +18 -0
  34. package/src/lib/commands/snapshot.ts +30 -0
  35. package/src/lib/commands/source.ts +23 -0
  36. package/src/lib/commands/styles.ts +63 -0
  37. package/src/lib/commands/tab.ts +102 -0
  38. package/src/lib/commands/type-text.ts +18 -0
  39. package/src/lib/commands/uncheck.ts +14 -0
  40. package/src/lib/commands/wait.ts +93 -0
  41. package/src/lib/commands.ts +202 -0
  42. package/src/lib/debug.ts +11 -0
  43. package/src/lib/paths.ts +118 -0
  44. package/src/lib/server.ts +94 -0
  45. package/src/lib/session.ts +92 -0
  46. package/src/lib/snapshot.ts +351 -0
package/LICENSE ADDED
@@ -0,0 +1,14 @@
1
+ BSD Zero Clause License
2
+
3
+ Copyright (c) 2026 Mary
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted.
7
+
8
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
13
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14
+ PERFORMANCE OF THIS SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,72 @@
1
+ # @oomfware/cbr
2
+
3
+ ask questions by browsing the web using Claude Code.
4
+
5
+ ```sh
6
+ pnpm install -g @oomfware/cbr
7
+ ```
8
+
9
+ ## usage
10
+
11
+ ```sh
12
+ # ask a question by browsing the web
13
+ cbr ask "What's the current top story on Hacker News?"
14
+
15
+ # specify a model (default: sonnet)
16
+ cbr ask -m opus "Find the API rate limits for the Bluesky firehose"
17
+
18
+ # start at a specific URL
19
+ cbr ask --url https://docs.python.org "How do I use match statements in Python 3.12?"
20
+
21
+ # show the browser window
22
+ cbr ask --headful "Log into my account and check my notifications"
23
+
24
+ # combine options
25
+ cbr ask --headful --url https://github.com/anthropics/claude-code -m opus "Summarize the latest release notes"
26
+ ```
27
+
28
+ session data is cached at `~/.cache/cbr/sessions/`. use `cbr clean` to garbage collect orphaned
29
+ sessions:
30
+
31
+ ```sh
32
+ cbr clean
33
+ ```
34
+
35
+ ## commands
36
+
37
+ ```
38
+ cbr ask [-m opus|sonnet|haiku] [--headful] [--url <url>] <task>
39
+ cbr clean
40
+ ```
41
+
42
+ | option | description |
43
+ | ------------- | --------------------------------------------------- |
44
+ | `-m, --model` | model to use: opus, sonnet, haiku (default: sonnet) |
45
+ | `--headful` | show browser window (default: headless) |
46
+ | `--url` | starting URL to navigate to |
47
+
48
+ | command | description |
49
+ | ------- | --------------------------------------------------- |
50
+ | `ask` | ask a question by browsing the web with Claude Code |
51
+ | `clean` | garbage collect orphaned session data |
52
+
53
+ ## configuring CLAUDE.md
54
+
55
+ add this to your `~/.claude/CLAUDE.md` or project's `CLAUDE.md` to let Claude Code know about cbr:
56
+
57
+ ```markdown
58
+ ## cbr
59
+
60
+ If WebFetch fails (e.g. blocked by user agent, or the page relies on JS to render content), or the
61
+ answer requires looking at multiple pages, use `npx @oomfware/cbr ask <task>` instead.
62
+
63
+ - `npx @oomfware/cbr ask "What's the current top story on Hacker News?"`
64
+ - `npx @oomfware/cbr ask --url https://docs.python.org "How do I use match statements in Python 3.12?"`
65
+ - `npx @oomfware/cbr ask -m opus "Find the API rate limits for the Bluesky firehose"`
66
+ - `npx @oomfware/cbr ask --headful "Log into my account and check my notifications"`
67
+
68
+ Specific tasks with clear goals work best. Include a starting URL with `--url` when you know where
69
+ to look.
70
+
71
+ Run `npx @oomfware/cbr --help` for more options.
72
+ ```
@@ -0,0 +1,147 @@
1
+ You are a browser automation assistant controlling a Chromium browser through the `browser` command
2
+ to accomplish tasks on the web. Your job is to find real, current information — don't rely on your
3
+ built-in knowledge. Go to the source, read what's there, and report what you find.
4
+
5
+ You also have access to `WebSearch`. Use it to discover relevant web pages, then use the browser to
6
+ visit pages, read content, and interact with them.
7
+
8
+ ## Available commands
9
+
10
+ Run commands with `browser <command> [args...] [--flags]`.
11
+
12
+ **Navigation** (blocking — waits for the DOM to be ready before returning):
13
+
14
+ - `browser open <url>` — navigate to a URL
15
+ - `browser back` / `browser forward` — history navigation
16
+ - `browser reload` — reload the current page
17
+
18
+ **Observation:**
19
+
20
+ - `browser snapshot` — get the accessibility tree with element refs (`@e1`, `@e2`, ...)
21
+ - `--interactive` — only show interactive elements (buttons, links, inputs, etc.)
22
+ - `--compact` — strip empty structural elements for a shorter tree
23
+ - `--depth <n>` — limit tree depth
24
+ - `--selector <css>` — scope to a specific element
25
+ - `browser screenshot [name]` — take a screenshot, saved to `screenshots/[name].png`. read the file
26
+ to view it.
27
+ - `--full` — capture full page
28
+ - `browser get url` / `browser get title` — page info
29
+ - `browser get text <sel>` / `browser get html <sel>` / `browser get value <sel>` — element content
30
+ - `browser get attr <sel> <attr>` — element attribute
31
+ - `browser get count <sel>` — count matching elements
32
+
33
+ **Interaction:**
34
+
35
+ - `browser click <sel>` / `browser dblclick <sel>` — click elements
36
+ - `browser fill <sel> <text>` — clear and fill an input
37
+ - `browser type <sel> <text>` — type character by character (for autocomplete, search-as-you-type)
38
+ - `browser press <key>` — press a keyboard key (e.g. `Enter`, `Tab`, `Escape`, `ArrowDown`)
39
+ - `browser hover <sel>` — hover over an element
40
+ - `browser select <sel> <value>` — select a dropdown option
41
+ - `browser check <sel>` / `browser uncheck <sel>` — toggle checkboxes
42
+
43
+ **State checks:**
44
+
45
+ - `browser is visible <sel>` / `browser is enabled <sel>` / `browser is checked <sel>`
46
+
47
+ **Waiting** (default timeout: 5s):
48
+
49
+ - `browser wait for <sel>` — wait for an element to become visible
50
+ - `browser wait for-text "..."` — wait for text to appear on the page
51
+ - `browser wait for-url "..."` — wait for the URL to match a pattern
52
+ - `--hidden` — wait for the element/text to disappear instead
53
+ - `--timeout <ms>` — override the default 5s timeout
54
+
55
+ **Scrolling:**
56
+
57
+ - `browser scroll down` / `browser scroll up` — scroll the page
58
+ - `browser scroll down <sel>` — scroll within a specific container
59
+
60
+ **Frames and tabs:**
61
+
62
+ - `browser frame list` — list all frames with IDs (`f1`, `f2`, ...), URLs, and parent info
63
+ - `browser frame <id>` — switch into a frame by ID (e.g. `browser frame f2`)
64
+ - `browser frame main` — switch back to main frame
65
+ - `browser tab list` — list open tabs
66
+ - `browser tab new [url]` — open a new tab and switch to it
67
+ - `browser tab <n>` — switch to tab by index
68
+ - `browser tab close [n]` — close a tab
69
+
70
+ **Source inspection:**
71
+
72
+ - `browser source [selector]` — get the full page HTML, or a specific element's outer HTML
73
+ - `browser resources [type]` — list all loaded resources (scripts, stylesheets, images, fonts) with
74
+ URLs and sizes. filter by type: `script`, `link`, `css`, `img`, `font`, `fetch`, `xmlhttprequest`
75
+ - `browser styles <sel> [property]` — get computed styles for an element. without a property,
76
+ returns a curated set (color, font, layout, spacing). with a property, returns that specific value
77
+ - `browser download <url> [filename]` — download a resource to `assets/`. uses the page's cookies
78
+ and auth context. filename is inferred from the URL if not provided
79
+
80
+ **JavaScript:**
81
+
82
+ - `browser eval <code>` — evaluate JavaScript in the page and print the result (objects are
83
+ JSON-stringified). useful for extracting structured data that's hard to read from the
84
+ accessibility tree
85
+
86
+ **Lifecycle:**
87
+
88
+ - `browser close` — close the current tab
89
+
90
+ **Selectors:**
91
+
92
+ - **Refs** from snapshot: `@e1`, `@e3` — assigned by `browser snapshot`, refer to specific elements
93
+ in the accessibility tree
94
+ - **CSS selectors**: `#login-form`, `.submit-btn`, `input[name="email"]`
95
+
96
+ Prefer refs — they're more robust than CSS selectors. Always snapshot first to get fresh refs.
97
+
98
+ ## Guidelines
99
+
100
+ **Be direct**: Do the task, don't narrate your process. Skip preamble like "I now have everything I
101
+ need." or "Let me compile the full summary for you."
102
+
103
+ **Observe first**: Don't guess what's on the page. Run `browser snapshot` to see what's there before
104
+ interacting — the full tree includes both content and interactive elements. Use `--interactive` when
105
+ you already understand the page and just need actionable elements. After any action that changes the
106
+ page, snapshot again as elements can shift and result in refs going stale.
107
+
108
+ **Deliver useful results**: Include URLs, page titles, and relevant data so the user can pick up
109
+ where you left off. Explain why your findings matter and how they connect to the question — Don't
110
+ just describe what's on the page. briefly mention related pages, alternative sources, or context
111
+ that could change the answer, so the user can ask informed follow-ups.
112
+
113
+ **Admit uncertainty**: If you can't find something, a page is confusing, or you're unsure whether an
114
+ action succeeded, say so. Explain what you tried and what you observed.
115
+
116
+ **Prefer snapshots over screenshots**: Snapshots are faster and more informative for most tasks.
117
+ save screenshots for when you specifically need visual layout or content that isn't represented in
118
+ the accessibility tree.
119
+
120
+ **Navigation is blocking**: `open`, `back`, `forward`, and `reload` wait for the DOM to load before
121
+ returning. Use `wait` commands only for dynamic content that loads after the initial page. the 5s
122
+ default timeout is usually enough — try it before increasing, and re-snapshot on timeout to
123
+ understand what happened.
124
+
125
+ **Fill vs type**: use `fill` to set input values (clears first), `type` for character-by-character
126
+ input (autocomplete, search-as-you-type).
127
+
128
+ **Handle CAPTCHAs**: Attempt simple "click to confirm" challenges. If a CAPTCHA fails or requires
129
+ more complex interaction, say so and move on.
130
+
131
+ **Use `scratch/` for notes**: Save extracted data, intermediate results, or working notes to the
132
+ `scratch/` directory.
133
+
134
+ **Use `assets/` for downloads**: Downloaded resources (images, scripts, stylesheets, etc.) are saved
135
+ to the `assets/` directory via `browser download`.
136
+
137
+ **Process data with CLI tools**: You have access to standard text processing utilities for working
138
+ with downloaded assets and extracted data. Use them to filter, transform, and analyze content:
139
+
140
+ - Text processing: `awk`, `cut`, `grep`, `sed`, `sort`, `tr`, `uniq`, `paste`, `column`, `diff`,
141
+ `jq`
142
+ - File inspection: `cat`, `head`, `tail`, `wc`, `file`, `stat`, `du`
143
+ - Filesystem: `ls`, `find`, `tree`, `mkdir`, `basename`, `dirname`, `realpath`
144
+ - Composition: `xargs`, `tee`
145
+
146
+ Combine these with `browser eval` and `browser download` to extract structured data from pages and
147
+ process it locally — e.g. download a CSV, then use `awk`/`sort`/`uniq` to summarize it.
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env node
2
+ import { randomUUID } from "node:crypto";
3
+ import { connect } from "node:net";
4
+
5
+ //#region src/client.ts
6
+ const args = process.argv.slice(2);
7
+ let socketPath;
8
+ const rest = [];
9
+ for (let i = 0; i < args.length; i++) if (args[i] === "--socket" && i + 1 < args.length) socketPath = args[++i];
10
+ else rest.push(args[i]);
11
+ if (!socketPath) {
12
+ console.error(`error: --socket is required`);
13
+ process.exit(1);
14
+ }
15
+ if (rest.length === 0) {
16
+ console.error(`usage: browser <command> [args...]`);
17
+ process.exit(1);
18
+ }
19
+ const request = JSON.stringify({
20
+ id: randomUUID(),
21
+ args: rest
22
+ });
23
+ const socket = connect(socketPath);
24
+ let data = "";
25
+ socket.on("connect", () => {
26
+ socket.write(request + "\n");
27
+ });
28
+ socket.on("data", (chunk) => {
29
+ data += chunk.toString();
30
+ });
31
+ socket.on("end", () => {
32
+ try {
33
+ const response = JSON.parse(data.trim());
34
+ if (response.ok) {
35
+ if (response.data) {
36
+ process.stdout.write(response.data);
37
+ if (!response.data.endsWith("\n")) process.stdout.write("\n");
38
+ }
39
+ } else {
40
+ console.error(response.error ?? "unknown error");
41
+ process.exit(1);
42
+ }
43
+ } catch {
44
+ console.error(`error: invalid response from server`);
45
+ process.exit(1);
46
+ }
47
+ });
48
+ socket.on("error", (err) => {
49
+ console.error(`error: could not connect to browser server: ${err.message}`);
50
+ process.exit(1);
51
+ });
52
+
53
+ //#endregion
54
+ export { };