ax-grep 0.1.1 → 0.1.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.
package/LICENSE CHANGED
File without changes
package/README.md CHANGED
@@ -16,24 +16,19 @@
16
16
 
17
17
  <img src="./docs/assets/ax-grep-search.png" alt="ax-grep auto search comparison image" width="920">
18
18
 
19
- Compact semantic trees and agent-ready page checks from HTML, URLs, WebViews, and live browser pages.
20
- It approximates the accessibility tree browsers expose, but can do it from
21
- static HTML before launching browser automation.
22
-
23
- The CLI defaults to `impit` for browser-like HTTP/2/TLS static fetches, detects
24
- hCaptcha, reCAPTCHA, and Cloudflare challenge markers, then tells agents when a
25
- browser is actually needed. In the local benchmark, the decision handoff used
26
- 15.4x less peak RAM on average and 3.0x fewer decision tokens on the content
27
- fixture than `agent-browser snapshot`.
28
-
29
- `--search` auto mode tries DuckDuckGo, Bing, and StartPage, records every
30
- engine attempt, and hands ranked source choices back to the agent.
19
+ Compact semantic trees and agent-ready page checks from HTML, URLs, WebViews,
20
+ and live browser pages. It approximates browser accessibility trees before
21
+ automation, defaults to `impit` for browser-like HTTP/2/TLS fetches, detects
22
+ major CAPTCHA and bot-challenge markers, saves 15.4x less peak RAM and 3.0x
23
+ fewer decision tokens in the local benchmark, and `--search` auto mode tries
24
+ DuckDuckGo, Bing, StartPage, and Google while recording every engine attempt.
31
25
 
32
26
  </div>
33
27
 
34
28
  ## 1. Try With A Prompt
35
29
 
36
- Paste this into a Codex session or subagent prompt before opening a browser:
30
+ Paste this into a Codex session or subagent prompt before opening a browser
31
+ (also works as guidance for Claude, Gemini, OpenRouter, and other agents):
37
32
 
38
33
  ```md
39
34
  Before opening a browser, inspect pages with ax-grep when possible.
@@ -52,7 +47,9 @@ not enough.
52
47
  curl -fsSL https://raw.githubusercontent.com/hmmhmmhm/ax-grep/main/skills.sh | sh
53
48
  ```
54
49
 
55
- This installs the Codex skill prompt only. Restart Codex if the new skill is not listed immediately.
50
+ This installs the Codex skill prompt only. The same prompt pattern can be pasted
51
+ into Claude, Gemini, OpenRouter, or other agent runners. Restart Codex if the
52
+ new skill is not listed immediately.
56
53
 
57
54
  ## 3. Try The CLI
58
55
 
@@ -107,3 +104,5 @@ const text = await page.evaluate(script);
107
104
  - [Agent handoff loop](./docs/agent-handoff.md)
108
105
  - [Benchmarks](./docs/benchmarks.md)
109
106
  - [Library API](./docs/library-api.md)
107
+ - [Server agent integration](./docs/server-agent.md)
108
+ - [WebView and in-page usage](./docs/webview.md)
package/dist/browser.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as SemanticTreeOptions, S as SemanticNode, aE as SemanticTreeChange, aF as SemanticTreeObserverOptions } from './types-gwHWhYmw.js';
1
+ import { a as SemanticTreeOptions, S as SemanticNode, aE as SemanticTreeChange, aF as SemanticTreeObserverOptions } from './types-K1hqb7Pq.js';
2
2
 
3
3
  declare function extractSemanticTree(options?: SemanticTreeOptions): SemanticNode;
4
4
 
package/dist/browser.js CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
package/dist/cli.d.ts CHANGED
File without changes
package/dist/cli.js CHANGED
@@ -135,7 +135,7 @@ var hiddenAgentPageCheckPaths = [
135
135
  var defaultTimeoutMs = 15e3;
136
136
  var defaultUserAgent = "ax-grep/0.1 (+https://github.com/hmmhmmhm/ax-grep)";
137
137
  var defaultFetcher = "impit";
138
- var autoSearchEngines = ["duckduckgo", "bing", "startpage"];
138
+ var autoSearchEngines = ["duckduckgo", "bing", "startpage", "google"];
139
139
  function envelopeAgentCanReadCurrentPayload(envelope) {
140
140
  const agent = envelope.agent;
141
141
  return agent?.needsBrowserHtml === false && agent.primaryAction?.action === "read-content" && actionExecution(agent.primaryAction) === "read-current";
@@ -944,8 +944,8 @@ function parseMode(value) {
944
944
  throw new UsageError(`--mode must be compact, interactive, or full`);
945
945
  }
946
946
  function parseSearchEngine(value) {
947
- if (value === "auto" || value === "bing" || value === "duckduckgo" || value === "startpage") return value;
948
- throw new UsageError(`--engine must be auto, bing, duckduckgo, or startpage`);
947
+ if (value === "auto" || value === "bing" || value === "duckduckgo" || value === "startpage" || value === "google") return value;
948
+ throw new UsageError(`--engine must be auto, bing, duckduckgo, startpage, or google`);
949
949
  }
950
950
  function parseSearchLang(value) {
951
951
  const normalized = value.trim().toLowerCase();
@@ -973,6 +973,13 @@ function searchUrl(query, engine, lang, region) {
973
973
  if (region) url2.searchParams.set("region", region);
974
974
  return url2.toString();
975
975
  }
976
+ if (engine === "google") {
977
+ const url2 = new URL("https://www.google.com/search");
978
+ url2.searchParams.set("q", query);
979
+ if (lang) url2.searchParams.set("hl", lang);
980
+ if (region) url2.searchParams.set("gl", region);
981
+ return url2.toString();
982
+ }
976
983
  const url = new URL("https://duckduckgo.com/html/");
977
984
  url.searchParams.set("q", query);
978
985
  if (lang && region) url.searchParams.set("kl", `${region.toLowerCase()}-${lang}`);
@@ -1010,7 +1017,7 @@ Fetch a page and print a compact semantic accessibility-like tree.
1010
1017
 
1011
1018
  Options:
1012
1019
  --search <query> Search the web and analyze the result page.
1013
- --engine <name> Search engine for --search: auto, duckduckgo, bing, or startpage. Default: auto.
1020
+ --engine <name> Search engine for --search: auto, duckduckgo, bing, startpage, or google. Default: auto.
1014
1021
  --lang <code> Search language hint, e.g. en, ko, ja, zh-cn.
1015
1022
  --region <code> Search region hint, e.g. US, KR, JP, CN.
1016
1023
  --open-result <n|best> With --search, fetch and analyze the selected result.
@@ -4511,6 +4518,7 @@ function detectSearchEngine(url) {
4511
4518
  if (hostname.endsWith("bing.com")) return "bing";
4512
4519
  if (hostname.endsWith("duckduckgo.com")) return "duckduckgo";
4513
4520
  if (hostname.endsWith("startpage.com")) return "startpage";
4521
+ if (hostname.endsWith("google.com")) return "google";
4514
4522
  if (hostname.endsWith("search.yahoo.co.jp")) return "yahoo-japan";
4515
4523
  if (looksLikeGenericSearchUrl(url)) return "generic";
4516
4524
  return null;
@@ -4539,6 +4547,9 @@ function isResultCard(element, engine) {
4539
4547
  if (engine === "duckduckgo") {
4540
4548
  return hasClass(element, "result") || hasClass(element, "web-result") || hasClass(element, "result__body");
4541
4549
  }
4550
+ if (engine === "google") {
4551
+ return hasClass(element, "g") || hasClass(element, "MjjYud") || element.name === "div" && findElement(element.children, (child) => /^h[1-6]$/.test(child.name)) !== void 0;
4552
+ }
4542
4553
  if (engine === "yahoo-japan") return hasClass(element, "sw-Card") || hasClass(element, "algo") || hasClass(element, "SearchResult");
4543
4554
  if (engine === "generic") {
4544
4555
  return hasClass(element, "result") || hasClass(element, "search-result") || element.name === "li" && findElement(element.children, (child) => child.name === "a") !== void 0 && findElement(element.children, (child) => child.name === "p") !== void 0;
@@ -4566,7 +4577,7 @@ function resultFromCard(card, baseUrl, engine, rank) {
4566
4577
  return withResultDateHint(result);
4567
4578
  }
4568
4579
  function resultTitleLink(card, engine) {
4569
- if (engine === "baidu" || engine === "bing" || engine === "yahoo-japan") {
4580
+ if (engine === "baidu" || engine === "bing" || engine === "google" || engine === "yahoo-japan") {
4570
4581
  const heading2 = findElement(card.children, (element) => /^h[1-6]$/.test(element.name));
4571
4582
  const headingLink = heading2 ? firstUsefulAnchor(heading2, "https://example.invalid") : void 0;
4572
4583
  if (headingLink) return headingLink;
@@ -13661,6 +13672,10 @@ function summarizeBrowserHtmlReasonCode(needsBrowserHtml, analysis, primaryActio
13661
13672
  if (analysis.diagnostics.some((diagnostic) => diagnostic.code === "HCAPTCHA_CHALLENGE")) return "hcaptcha";
13662
13673
  if (analysis.diagnostics.some((diagnostic) => diagnostic.code === "RECAPTCHA_CHALLENGE")) return "recaptcha";
13663
13674
  if (analysis.diagnostics.some((diagnostic) => diagnostic.code === "CLOUDFLARE_CHALLENGE")) return "cloudflare-challenge";
13675
+ if (analysis.diagnostics.some((diagnostic) => diagnostic.code === "AKAMAI_CHALLENGE")) return "akamai-challenge";
13676
+ if (analysis.diagnostics.some((diagnostic) => diagnostic.code === "DATADOME_CHALLENGE")) return "datadome-challenge";
13677
+ if (analysis.diagnostics.some((diagnostic) => diagnostic.code === "PERIMETERX_CHALLENGE")) return "perimeterx-challenge";
13678
+ if (analysis.diagnostics.some((diagnostic) => diagnostic.code === "KASADA_CHALLENGE")) return "kasada-challenge";
13664
13679
  if (error?.code === "NO_INSPECTABLE_CONTENT") return "no-inspectable-content";
13665
13680
  if (error?.code === "HTTP_ERROR") return "http-error";
13666
13681
  if (error?.code === "FETCH_FAILED" || error?.code === "TIMEOUT") return "fetch-error";
@@ -16330,6 +16345,34 @@ function detectBarrierDiagnostics(fetched, tree, content) {
16330
16345
  message: "The page appears to contain a Cloudflare challenge."
16331
16346
  });
16332
16347
  }
16348
+ if (/(akamai|akamai bot manager|bm-verify|_abck|ak_bmsc|sensor_data|abck)/i.test(challengeHaystack)) {
16349
+ diagnostics.push({
16350
+ severity: "warning",
16351
+ code: "AKAMAI_CHALLENGE",
16352
+ message: "The page appears to contain an Akamai bot challenge."
16353
+ });
16354
+ }
16355
+ if (/(datadome|captcha-delivery\.com|geo\.captcha-delivery\.com|ddcid|dd_r)/i.test(challengeHaystack)) {
16356
+ diagnostics.push({
16357
+ severity: "warning",
16358
+ code: "DATADOME_CHALLENGE",
16359
+ message: "The page appears to contain a DataDome challenge."
16360
+ });
16361
+ }
16362
+ if (/(perimeterx|px-captcha|_px|pxvid|px3)/i.test(challengeHaystack)) {
16363
+ diagnostics.push({
16364
+ severity: "warning",
16365
+ code: "PERIMETERX_CHALLENGE",
16366
+ message: "The page appears to contain a PerimeterX challenge."
16367
+ });
16368
+ }
16369
+ if (/(kasada|x-kpsdk|kpsdk|ips\.js)/i.test(challengeHaystack)) {
16370
+ diagnostics.push({
16371
+ severity: "warning",
16372
+ code: "KASADA_CHALLENGE",
16373
+ message: "The page appears to contain a Kasada challenge."
16374
+ });
16375
+ }
16333
16376
  if (/(captcha|verify you are human|unusual traffic|checking your browser|just a moment|cf-browser-verification|cloudflare|access denied|request blocked|please wait for verification|please wait|enable javascript|enable java script|자바스크립트|봇이 아닙니다|자동입력|보안문자)/i.test(challengeHaystack)) {
16334
16377
  diagnostics.push({
16335
16378
  severity: "warning",
@@ -16369,7 +16412,7 @@ function dedupeDiagnostics(diagnostics) {
16369
16412
  });
16370
16413
  }
16371
16414
  function isChallengeDiagnosticCode(code) {
16372
- return code === "CHALLENGE_LIKELY" || code === "HCAPTCHA_CHALLENGE" || code === "RECAPTCHA_CHALLENGE" || code === "CLOUDFLARE_CHALLENGE";
16415
+ return code === "CHALLENGE_LIKELY" || code === "HCAPTCHA_CHALLENGE" || code === "RECAPTCHA_CHALLENGE" || code === "CLOUDFLARE_CHALLENGE" || code === "AKAMAI_CHALLENGE" || code === "DATADOME_CHALLENGE" || code === "PERIMETERX_CHALLENGE" || code === "KASADA_CHALLENGE";
16373
16416
  }
16374
16417
  function looksLikeKnownSearchUrl(url) {
16375
16418
  try {
@@ -21972,7 +22015,7 @@ function inferSearchResultCommandContext(url) {
21972
22015
  }
21973
22016
  if (hostname.endsWith("google.com")) {
21974
22017
  const query = parsed.searchParams.get("q");
21975
- return query ? { query } : void 0;
22018
+ return query ? { query, engine: "google" } : void 0;
21976
22019
  }
21977
22020
  if (hostname.endsWith("baidu.com")) {
21978
22021
  const query = parsed.searchParams.get("wd") ?? parsed.searchParams.get("word");
@@ -22296,7 +22339,7 @@ function parseArgMetadata(argv) {
22296
22339
  }
22297
22340
  if (arg === "--engine") {
22298
22341
  const value = argv[index + 1];
22299
- if (value === "auto" || value === "bing" || value === "duckduckgo" || value === "startpage") metadata.searchEngine = value;
22342
+ if (value === "auto" || value === "bing" || value === "duckduckgo" || value === "startpage" || value === "google") metadata.searchEngine = value;
22300
22343
  index += 1;
22301
22344
  continue;
22302
22345
  }