@apmantza/greedysearch-pi 2.1.3 → 2.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.
- package/CHANGELOG.md +48 -1
- package/README.md +52 -175
- package/bin/search.mjs +2 -0
- package/docs/analysis.md +233 -0
- package/docs/banner.svg +86 -0
- package/docs/development.md +63 -0
- package/docs/inspiration2.md +190 -0
- package/docs/releases.md +88 -0
- package/docs/research.md +82 -0
- package/docs/runtime.md +65 -0
- package/docs/source-fetching.md +33 -0
- package/docs/stealthbrowsermcp.md +807 -0
- package/docs/usage.md +69 -0
- package/extractors/chatgpt.mjs +127 -23
- package/extractors/common.mjs +116 -28
- package/extractors/gemini.mjs +63 -38
- package/package.json +13 -7
- package/scripts/backfill-github-releases.mjs +139 -0
- package/scripts/changelog-extract.mjs +48 -0
- package/scripts/changelog-release.mjs +65 -0
- package/scripts/check-lockfile.mjs +45 -0
- package/scripts/lib/changelog.mjs +168 -0
- package/scripts/lint.mjs +62 -0
- package/scripts/run-tests.ps1 +179 -0
- package/scripts/stealth-check.mjs +663 -0
- package/src/fetcher.mjs +9 -5
- package/src/search/constants.mjs +1 -1
- package/src/search/research.mjs +57 -11
- package/src/search/simple-research.mjs +4 -1
- package/test.mjs +16 -3
- package/skills/greedy-search/skill.md +0 -20
package/docs/banner.svg
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 480" width="1200" height="480">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
4
|
+
<stop offset="0%" style="stop-color:#0d1117"/>
|
|
5
|
+
<stop offset="50%" style="stop-color:#161b22"/>
|
|
6
|
+
<stop offset="100%" style="stop-color:#0d1117"/>
|
|
7
|
+
</linearGradient>
|
|
8
|
+
|
|
9
|
+
<linearGradient id="title" x1="0%" y1="0%" x2="100%" y2="0%">
|
|
10
|
+
<stop offset="0%" style="stop-color:#58a6ff"/>
|
|
11
|
+
<stop offset="50%" style="stop-color:#bc8cff"/>
|
|
12
|
+
<stop offset="100%" style="stop-color:#3fb950"/>
|
|
13
|
+
</linearGradient>
|
|
14
|
+
|
|
15
|
+
<linearGradient id="piGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
16
|
+
<stop offset="0%" style="stop-color:#8b5cf6"/>
|
|
17
|
+
<stop offset="100%" style="stop-color:#a78bfa"/>
|
|
18
|
+
</linearGradient>
|
|
19
|
+
|
|
20
|
+
<filter id="glow" x="-20%" y="-20%" width="140%" height="140%">
|
|
21
|
+
<feGaussianBlur stdDeviation="6" result="blur"/>
|
|
22
|
+
<feComposite in="SourceGraphic" in2="blur" operator="over"/>
|
|
23
|
+
</filter>
|
|
24
|
+
|
|
25
|
+
<pattern id="dots" width="20" height="20" patternUnits="userSpaceOnUse">
|
|
26
|
+
<circle cx="2" cy="2" r="0.8" fill="#30363d" opacity="0.4"/>
|
|
27
|
+
</pattern>
|
|
28
|
+
</defs>
|
|
29
|
+
|
|
30
|
+
<!-- Background -->
|
|
31
|
+
<rect width="1200" height="480" fill="url(#bg)"/>
|
|
32
|
+
<rect width="1200" height="480" fill="url(#dots)"/>
|
|
33
|
+
|
|
34
|
+
<circle cx="1050" cy="100" r="300" fill="#bc8cff" opacity="0.03"/>
|
|
35
|
+
<circle cx="1150" cy="400" r="200" fill="#3fb950" opacity="0.03"/>
|
|
36
|
+
|
|
37
|
+
<!-- ===== PI LOGO (left) ===== -->
|
|
38
|
+
<g transform="translate(60, 140)">
|
|
39
|
+
<circle cx="60" cy="60" r="72" fill="none" stroke="#8b5cf6" stroke-width="2" opacity="0.3"/>
|
|
40
|
+
<circle cx="60" cy="60" r="62" fill="none" stroke="#8b5cf6" stroke-width="1" opacity="0.1"/>
|
|
41
|
+
<g transform="translate(18, 18) scale(2.6)">
|
|
42
|
+
<path fill="#8b5cf6" fill-rule="evenodd" d="M0 0H15V10H10V15H5V20H0ZM5 5V10H10V5Z"/>
|
|
43
|
+
<rect x="15" y="10" width="5" height="10" fill="#8b5cf6"/>
|
|
44
|
+
</g>
|
|
45
|
+
</g>
|
|
46
|
+
|
|
47
|
+
<!-- ===== TITLE ===== -->
|
|
48
|
+
<text x="240" y="195" font-family="'Segoe UI', -apple-system, system-ui, sans-serif" font-size="72" font-weight="700" letter-spacing="-1.5" fill="url(#title)" filter="url(#glow)">
|
|
49
|
+
GreedySearch
|
|
50
|
+
</text>
|
|
51
|
+
|
|
52
|
+
<!-- ===== "No API keys" badge ===== -->
|
|
53
|
+
<g transform="translate(240, 218)">
|
|
54
|
+
<rect x="0" y="0" width="155" height="28" rx="14" fill="#1f6feb" opacity="0.15"/>
|
|
55
|
+
<rect x="0" y="0" width="155" height="28" rx="14" fill="none" stroke="#1f6feb" stroke-width="1" opacity="0.3"/>
|
|
56
|
+
<text x="77" y="19" font-family="'Segoe UI', -apple-system, system-ui, sans-serif" font-size="13" font-weight="600" fill="#58a6ff" text-anchor="middle">🔑 No API keys</text>
|
|
57
|
+
</g>
|
|
58
|
+
|
|
59
|
+
<!-- ===== TAGLINE ===== -->
|
|
60
|
+
<text x="240" y="280" font-family="'Segoe UI', -apple-system, system-ui, sans-serif" font-size="20" font-weight="400" fill="#8b949e" letter-spacing="0.3">
|
|
61
|
+
Multi-engine AI search via browser automation.
|
|
62
|
+
</text>
|
|
63
|
+
|
|
64
|
+
<!-- ===== ENGINE PILLS ===== -->
|
|
65
|
+
<g transform="translate(240, 310)">
|
|
66
|
+
<!-- Perplexity -->
|
|
67
|
+
<rect x="0" y="0" width="115" height="30" rx="15" fill="#00c8b4" opacity="0.12"/>
|
|
68
|
+
<rect x="0" y="0" width="115" height="30" rx="15" fill="none" stroke="#00c8b4" stroke-width="1" opacity="0.3"/>
|
|
69
|
+
<text x="57" y="20" font-family="'Segoe UI', -apple-system, system-ui, sans-serif" font-size="13" font-weight="600" fill="#00c8b4" text-anchor="middle">Perplexity</text>
|
|
70
|
+
|
|
71
|
+
<!-- Bing -->
|
|
72
|
+
<rect x="130" y="0" width="115" height="30" rx="15" fill="#00a4ef" opacity="0.12"/>
|
|
73
|
+
<rect x="130" y="0" width="115" height="30" rx="15" fill="none" stroke="#00a4ef" stroke-width="1" opacity="0.3"/>
|
|
74
|
+
<text x="187" y="20" font-family="'Segoe UI', -apple-system, system-ui, sans-serif" font-size="13" font-weight="600" fill="#00a4ef" text-anchor="middle">Bing Copilot</text>
|
|
75
|
+
|
|
76
|
+
<!-- Google AI -->
|
|
77
|
+
<rect x="260" y="0" width="115" height="30" rx="15" fill="#fbbc04" opacity="0.12"/>
|
|
78
|
+
<rect x="260" y="0" width="115" height="30" rx="15" fill="none" stroke="#fbbc04" stroke-width="1" opacity="0.3"/>
|
|
79
|
+
<text x="317" y="20" font-family="'Segoe UI', -apple-system, system-ui, sans-serif" font-size="13" font-weight="600" fill="#fbbc04" text-anchor="middle">Google AI</text>
|
|
80
|
+
|
|
81
|
+
<!-- Gemini -->
|
|
82
|
+
<rect x="390" y="0" width="100" height="30" rx="15" fill="#8b5cf6" opacity="0.12"/>
|
|
83
|
+
<rect x="390" y="0" width="100" height="30" rx="15" fill="none" stroke="#8b5cf6" stroke-width="1" opacity="0.3"/>
|
|
84
|
+
<text x="440" y="20" font-family="'Segoe UI', -apple-system, system-ui, sans-serif" font-size="13" font-weight="600" fill="#a78bfa" text-anchor="middle">Gemini</text>
|
|
85
|
+
</g>
|
|
86
|
+
</svg>
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Development
|
|
2
|
+
|
|
3
|
+
## Project Layout
|
|
4
|
+
|
|
5
|
+
- `index.ts` — Pi extension entrypoint.
|
|
6
|
+
- `src/tools/greedy-search-handler.ts` — Pi tool registration/handler.
|
|
7
|
+
- `bin/search.mjs` — CLI orchestration.
|
|
8
|
+
- `extractors/` — engine-specific browser automation.
|
|
9
|
+
- `src/search/` — search pipeline, Chrome lifecycle, recovery, synthesis,
|
|
10
|
+
source ranking, and research orchestration.
|
|
11
|
+
- `test.mjs`, `test-suite/`, `test/` — unit and smoke tests.
|
|
12
|
+
|
|
13
|
+
Pi loads this extension through `jiti`; TypeScript does not need to be
|
|
14
|
+
precompiled for Pi runtime.
|
|
15
|
+
|
|
16
|
+
## Checks
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm run check:lockfile
|
|
20
|
+
npm run lint
|
|
21
|
+
node test.mjs unit
|
|
22
|
+
npm pack --dry-run --json
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Jiti load check:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
node - <<'NODE'
|
|
29
|
+
import { createJiti } from 'file:///C:/Users/R3LiC/AppData/Roaming/npm/node_modules/@earendil-works/pi-coding-agent/node_modules/jiti/lib/jiti.mjs';
|
|
30
|
+
const jiti = createJiti(import.meta.url, { interopDefault: true });
|
|
31
|
+
const mod = await jiti.import('./index.ts');
|
|
32
|
+
console.log('jiti ok', typeof mod.default);
|
|
33
|
+
NODE
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Useful Headless Smoke Checks
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
node bin/launch.mjs --kill || node bin/kill-visible.mjs
|
|
40
|
+
node bin/search.mjs all --inline --stdin --full <<'EOF'
|
|
41
|
+
TypeScript 5.8 5.9 Node.js ESM module-resolution changes
|
|
42
|
+
EOF
|
|
43
|
+
|
|
44
|
+
node bin/search.mjs all --inline --stdin --depth research \
|
|
45
|
+
--breadth 1 --iterations 1 --max-sources 3 <<'EOF'
|
|
46
|
+
Node.js native TypeScript type stripping for CLI authors
|
|
47
|
+
EOF
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Extractor Notes
|
|
51
|
+
|
|
52
|
+
When adding or changing an extractor:
|
|
53
|
+
|
|
54
|
+
1. Reuse `extractors/common.mjs` utilities.
|
|
55
|
+
2. Prefer single in-browser polling evals over Node-side CDP polling loops.
|
|
56
|
+
3. Use language-agnostic selectors and data attributes where possible.
|
|
57
|
+
4. Avoid matching English UI strings except as a last resort.
|
|
58
|
+
5. Register new engines in both `src/search/constants.mjs` and `bin/search.mjs`
|
|
59
|
+
when they need all-mode pre-seeding.
|
|
60
|
+
6. Update `README.md`, `docs/`, `src/tools/greedy-search-handler.ts`, and
|
|
61
|
+
`CHANGELOG.md`.
|
|
62
|
+
|
|
63
|
+
See [`AGENTS.md`](../AGENTS.md) for the full extractor and recovery guide.
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# Inspiration: Browser Automation Patterns from the Ecosystem
|
|
2
|
+
|
|
3
|
+
This document captures patterns and ideas from two open-source browser automation
|
|
4
|
+
projects that could inform future improvements to GreedySearch-pi. Kameleo is
|
|
5
|
+
omitted — its anti-detection engine is commercial and C++-level, not applicable
|
|
6
|
+
to our JS-level CDP approach.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 1. [chrome-devtools-axi](https://github.com/kunchenguid/chrome-devtools-axi)
|
|
11
|
+
|
|
12
|
+
A wrapper around `chrome-devtools-mcp` (Google's official MCP server) with TOON
|
|
13
|
+
encoding, accessibility tree snapshots, contextual suggestions, and a persistent
|
|
14
|
+
bridge architecture. Designed as an Agent Skill (AXI-compliant).
|
|
15
|
+
|
|
16
|
+
### Notable patterns
|
|
17
|
+
|
|
18
|
+
#### Generation-based stale ref detection
|
|
19
|
+
|
|
20
|
+
Every accessibility tree snapshot carries a `g<N>:` generation prefix that bumps
|
|
21
|
+
on each capture. When an agent passes a stale ref back (e.g. `@g1:5` after the
|
|
22
|
+
page re-rendered), the action fails loudly with `STALE_REF` instead of silently
|
|
23
|
+
no-op'ing. The agent then re-snapshots and retries.
|
|
24
|
+
|
|
25
|
+
**Applicability to GreedySearch-pi:** We don't use accessibility refs, but the
|
|
26
|
+
generation-counter concept could help with the ChatGPT copy-button race
|
|
27
|
+
condition. Currently, `document.querySelectorAll('[data-testid="copy-turn-action-button"]')`
|
|
28
|
+
can pick the wrong button when the assistant response hasn't rendered its own
|
|
29
|
+
copy button yet. A generation counter on the assistant message element would let
|
|
30
|
+
us verify we're clicking the right generation's button.
|
|
31
|
+
|
|
32
|
+
#### Named session isolation (`CHROME_DEVTOOLS_AXI_SESSION`)
|
|
33
|
+
|
|
34
|
+
Each session name gets its own bridge process, port (auto-derived from the name),
|
|
35
|
+
and on-disk state. In isolated mode each bridge also launches its own Chrome,
|
|
36
|
+
so concurrent sessions share neither browser state nor stale-ref tracking.
|
|
37
|
+
|
|
38
|
+
**Applicability to GreedySearch-pi:** Could support concurrent GreedySearch
|
|
39
|
+
users on a shared machine without port conflicts. Currently we use a single
|
|
40
|
+
Chrome profile at `<tmp>/greedysearch-chrome-profile` on port 9222. Named
|
|
41
|
+
sessions would let multiple Pi agents run searches simultaneously.
|
|
42
|
+
|
|
43
|
+
#### Persistent bridge server (one per user session)
|
|
44
|
+
|
|
45
|
+
A detached process keeps the MCP session alive across commands, so Chrome
|
|
46
|
+
doesn't restart every invocation. Writes a PID file to `~/.chrome-devtools-axi/bridge.pid`,
|
|
47
|
+
recycles stale CDP targets after a deep health check, and reaps child processes
|
|
48
|
+
on stop.
|
|
49
|
+
|
|
50
|
+
**Applicability to GreedySearch-pi:** We already have per-tab daemons in
|
|
51
|
+
`bin/cdp.mjs` that hold CDP sessions open. The difference is per-tab vs
|
|
52
|
+
per-user-session. A per-user bridge could reduce Chrome launch overhead when
|
|
53
|
+
switching between engines, but our current model (one Chrome instance, multiple
|
|
54
|
+
tabs) already achieves this.
|
|
55
|
+
|
|
56
|
+
#### Multi-step script execution (`run` command)
|
|
57
|
+
|
|
58
|
+
Accepts multi-step scripts from stdin, executing them sequentially against the
|
|
59
|
+
same browser session. Each step is a CLI command (open, click, fill, eval, etc.).
|
|
60
|
+
|
|
61
|
+
**Applicability to GreedySearch-pi:** Our research mode already orchestrates
|
|
62
|
+
multi-step workflows (plan → search → fetch → synthesize). The `run` pattern
|
|
63
|
+
is cleaner for ad-hoc multi-step tasks but our orchestration is purpose-built
|
|
64
|
+
for research.
|
|
65
|
+
|
|
66
|
+
#### `CHROME_DEVTOOLS_AXI_BROWSER_URL` for external Chrome
|
|
67
|
+
|
|
68
|
+
Connects to an existing Chrome instance instead of launching one. Accepts both
|
|
69
|
+
`http://` URLs (fetches `/json/version` to discover WebSocket URL) and `ws://`
|
|
70
|
+
endpoints directly. Supports authenticated WebSocket endpoints via
|
|
71
|
+
`CHROME_DEVTOOLS_AXI_WS_HEADERS`.
|
|
72
|
+
|
|
73
|
+
**Applicability to GreedySearch-pi:** We already support `CDP_PROFILE_DIR` for
|
|
74
|
+
targeting our own Chrome profile. The WebSocket auth header support could be
|
|
75
|
+
useful for connecting to remote browser instances (BrowserBase, Browserless,
|
|
76
|
+
etc.) in a future cloud mode.
|
|
77
|
+
|
|
78
|
+
#### `CHROME_DEVTOOLS_AXI_CHANNEL` for release channel selection
|
|
79
|
+
|
|
80
|
+
Picks which installed Chrome release channel to target — `stable` (default),
|
|
81
|
+
`beta`, `canary`, or `dev`. Used by `--autoConnect` and launch modes.
|
|
82
|
+
|
|
83
|
+
**Applicability to GreedySearch-pi:** Could let users test against Chrome Beta
|
|
84
|
+
or Canary to catch anti-bot changes before they hit stable.
|
|
85
|
+
|
|
86
|
+
### What's not applicable
|
|
87
|
+
|
|
88
|
+
- **TOON encoding** — compact structured output format. We use JSON for
|
|
89
|
+
structured data and plain text for answers. Not needed.
|
|
90
|
+
- **Lighthouse / performance / heap snapshots** — performance auditing is
|
|
91
|
+
outside GreedySearch's scope.
|
|
92
|
+
- **chrome-devtools-mcp dependency** — wrapping MCP would mean losing control
|
|
93
|
+
over our extraction pipelines, stealth patches, and multi-engine
|
|
94
|
+
parallelization. Not worth it.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## 2. [faster-chrome-devtools-skill](https://github.com/zeke/faster-chrome-devtools-skill)
|
|
99
|
+
|
|
100
|
+
A Pi-compatible Agent Skill wrapping CDP in a zero-dependency Node.js script.
|
|
101
|
+
Shares the same ancestor (`chrome-cdp-skill` by pasky) as our `bin/cdp.mjs`.
|
|
102
|
+
WebSocket client from scratch (RFC 6455), background daemon, accessibility
|
|
103
|
+
snapshots, Cloudflare Browser Run support.
|
|
104
|
+
|
|
105
|
+
### Notable patterns
|
|
106
|
+
|
|
107
|
+
#### Daemon-level Runtime.enable workaround (`captureMainContext`)
|
|
108
|
+
|
|
109
|
+
**Already implemented in GreedySearch-pi.** Our `bin/cdp.mjs` has the exact
|
|
110
|
+
pattern: briefly enable `Runtime` at daemon start (50-100ms), capture the main
|
|
111
|
+
execution context ID, immediately disable, then pass `contextId` explicitly on
|
|
112
|
+
every `Runtime.evaluate` call. This avoids the persistent `Runtime.enable`
|
|
113
|
+
detection vector that Cloudflare/DataDome watch for (the browser auto-serializes
|
|
114
|
+
console objects when Runtime is active, triggering proxy traps in anti-bot
|
|
115
|
+
scripts).
|
|
116
|
+
|
|
117
|
+
Our implementation is in `bin/cdp.mjs` — `captureMainContext()` function with
|
|
118
|
+
detailed comments citing rebrowser.net and the detection mechanism.
|
|
119
|
+
|
|
120
|
+
#### `loadall` command (repeated click-until-gone)
|
|
121
|
+
|
|
122
|
+
Repeatedly clicks a CSS selector (e.g. "Load more") at a configurable interval
|
|
123
|
+
until the element disappears from the DOM. Has a 5-minute hard deadline and
|
|
124
|
+
interval clamping (100ms–30s).
|
|
125
|
+
|
|
126
|
+
**Applicability to GreedySearch-pi:** Could be useful for infinite-scroll result
|
|
127
|
+
pages in research mode. Some search engines (Bing, Google) paginate results
|
|
128
|
+
behind "Show more" buttons. A `loadall`-style helper in `extractors/common.mjs`
|
|
129
|
+
would let extractors scroll through all results before extracting.
|
|
130
|
+
|
|
131
|
+
#### Compact accessibility tree mode
|
|
132
|
+
|
|
133
|
+
`shouldShowAxNode()` filters out `InlineTextBox` nodes and empty/trivial nodes
|
|
134
|
+
from snapshot output, producing a much more compact tree.
|
|
135
|
+
|
|
136
|
+
**Applicability to GreedySearch-pi:** Minor UX improvement for our `snap`
|
|
137
|
+
command output. Not a priority.
|
|
138
|
+
|
|
139
|
+
#### `browserraw` / `browse` level commands
|
|
140
|
+
|
|
141
|
+
Sends browser-level CDP commands (no sessionId) for things like
|
|
142
|
+
`Browser.setDownloadBehavior`, `Browser.grantPermissions`, etc.
|
|
143
|
+
|
|
144
|
+
**Applicability to GreedySearch-pi:** Could be useful for PDF download in
|
|
145
|
+
research mode when fetching academic papers. Currently we fetch via HTTP; a
|
|
146
|
+
browser-level download handler would let us capture PDFs that require
|
|
147
|
+
JavaScript rendering.
|
|
148
|
+
|
|
149
|
+
#### Cloudflare Browser Run support
|
|
150
|
+
|
|
151
|
+
Connects to Cloudflare's remote browser service via `wss://` endpoints with
|
|
152
|
+
authentication headers. Uses `lab=true` by default for Chrome beta features.
|
|
153
|
+
|
|
154
|
+
**Applicability to GreedySearch-pi:** Future direction — running GreedySearch
|
|
155
|
+
in the cloud without a local Chrome instance. The WebSocket auth header pattern
|
|
156
|
+
(`CHROME_DEVTOOLS_AXI_WS_HEADERS`) from chrome-devtools-axi complements this.
|
|
157
|
+
|
|
158
|
+
#### `--ws-endpoint` / `--http-endpoint` env vars
|
|
159
|
+
|
|
160
|
+
Cleaner than our `CDP_PROFILE_DIR` approach for specifying which Chrome to
|
|
161
|
+
connect to. `CDP_WS_ENDPOINT` and `CDP_HTTP_ENDPOINT` env vars with explicit
|
|
162
|
+
`--ws-endpoint` / `--http-endpoint` CLI flags.
|
|
163
|
+
|
|
164
|
+
**Applicability to GreedySearch-pi:** Could simplify our connection logic.
|
|
165
|
+
Currently we derive the WebSocket URL from `DevToolsActivePort` in the profile
|
|
166
|
+
directory. Accepting an explicit endpoint would be more flexible.
|
|
167
|
+
|
|
168
|
+
### What's not applicable
|
|
169
|
+
|
|
170
|
+
- **Hand-rolled RFC 6455 WebSocket client** — unnecessary since Node.js 22+
|
|
171
|
+
has built-in `WebSocket`. We use the native one.
|
|
172
|
+
- **General-purpose browser skill** — it's designed for ad-hoc browsing, not
|
|
173
|
+
multi-engine search. No clipboard interception, no stream detection, no
|
|
174
|
+
source extraction.
|
|
175
|
+
- **Per-tab daemon model** — same as ours. No improvement to adopt.
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## Summary of actionable ideas
|
|
180
|
+
|
|
181
|
+
| Idea | Source | Priority | Effort |
|
|
182
|
+
|------|--------|----------|--------|
|
|
183
|
+
| Generation counters for stale-ref detection | chrome-devtools-axi | Medium | Small |
|
|
184
|
+
| Named session isolation | chrome-devtools-axi | Low | Medium |
|
|
185
|
+
| `loadall` helper for infinite-scroll pages | faster-chrome-devtools-skill | Medium | Small |
|
|
186
|
+
| Browser-level CDP for PDF download | faster-chrome-devtools-skill | Low | Small |
|
|
187
|
+
| Explicit WS endpoint env vars | faster-chrome-devtools-skill | Low | Small |
|
|
188
|
+
| Remote browser auth headers | both | Low | Medium |
|
|
189
|
+
| Release channel selection | chrome-devtools-axi | Low | Small |
|
|
190
|
+
| Runtime.enable workaround | faster-chrome-devtools-skill | ✅ Already done | — |
|
package/docs/releases.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Release Workflow
|
|
2
|
+
|
|
3
|
+
Releases are automated from `package.json` versions and `CHANGELOG.md` sections.
|
|
4
|
+
The curated changelog entry is the source of truth for GitHub release notes.
|
|
5
|
+
|
|
6
|
+
## Cut a Release
|
|
7
|
+
|
|
8
|
+
1. Bump `package.json`.
|
|
9
|
+
2. Add entries under `## [Unreleased]`.
|
|
10
|
+
3. Promote the changelog section:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm run changelog:release
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Or with explicit values:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
node scripts/changelog-release.mjs 2.2.0 --date 2026-07-03
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
4. Run checks:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm run check:lockfile
|
|
26
|
+
npm run lint
|
|
27
|
+
node test.mjs unit
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
5. Commit and push to `master`.
|
|
31
|
+
|
|
32
|
+
## Changelog Scripts
|
|
33
|
+
|
|
34
|
+
- `npm run changelog:check` — verifies `## [Unreleased]` has releaseable
|
|
35
|
+
entries.
|
|
36
|
+
- `npm run changelog:release` — moves `Unreleased` into the current
|
|
37
|
+
`package.json` version and opens a fresh empty `Unreleased` section.
|
|
38
|
+
- `npm run changelog:extract -- <version>` — prints release notes for a
|
|
39
|
+
version.
|
|
40
|
+
- `npm run release:backfill-notes` — dry-run GitHub release-body backfill.
|
|
41
|
+
|
|
42
|
+
The parser supports both current headings like:
|
|
43
|
+
|
|
44
|
+
```markdown
|
|
45
|
+
## [2.1.3] — 2026-06-21
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
and older headings like:
|
|
49
|
+
|
|
50
|
+
```markdown
|
|
51
|
+
## v1.8.5 (2026-04-29)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
so historical releases can be backfilled from the same changelog.
|
|
55
|
+
|
|
56
|
+
## GitHub Release Notes
|
|
57
|
+
|
|
58
|
+
`.github/workflows/release.yml` extracts release notes with:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
node scripts/changelog-extract.mjs "$VERSION" --summary -o RELEASE_NOTES.md
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
and passes `RELEASE_NOTES.md` to `softprops/action-gh-release`. GitHub release
|
|
65
|
+
bodies therefore match the curated changelog summary instead of generated PR
|
|
66
|
+
or commit-title notes.
|
|
67
|
+
|
|
68
|
+
## Backfill Existing Releases
|
|
69
|
+
|
|
70
|
+
Preview the update plan:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
npm run release:backfill-notes
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Apply it with the GitHub CLI authenticated:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
node scripts/backfill-github-releases.mjs --apply
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Limit to specific tags:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
node scripts/backfill-github-releases.mjs --apply --only v2.1.3,v2.1.2
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Use `--full` to write the full changelog prose instead of the summarized body.
|
package/docs/research.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Research Mode
|
|
2
|
+
|
|
3
|
+
Set `depth: "research"` to run GreedySearch's iterative research workflow.
|
|
4
|
+
|
|
5
|
+
```js
|
|
6
|
+
greedy_search({
|
|
7
|
+
query: "Evaluate browser automation options for AI agents",
|
|
8
|
+
depth: "research",
|
|
9
|
+
breadth: 3,
|
|
10
|
+
iterations: 2,
|
|
11
|
+
maxSources: 8,
|
|
12
|
+
});
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Workflow
|
|
16
|
+
|
|
17
|
+
Research mode performs:
|
|
18
|
+
|
|
19
|
+
1. Query complexity classification when breadth/iterations are not explicit.
|
|
20
|
+
2. Action planning with Gemini.
|
|
21
|
+
3. Fast all-engine child searches using the configured engine list.
|
|
22
|
+
4. Direct URL fetches when useful.
|
|
23
|
+
5. Source ranking, dedupe, and source-content fetching.
|
|
24
|
+
6. Evidence and learning extraction.
|
|
25
|
+
7. Final cited synthesis.
|
|
26
|
+
8. Citation audit, URL reachability checks, and deterministic floor checks.
|
|
27
|
+
|
|
28
|
+
Simple questions may take a single-pass path. Explicit `breadth` or
|
|
29
|
+
`iterations` values always override classifier suggestions.
|
|
30
|
+
|
|
31
|
+
## Bundle Layout
|
|
32
|
+
|
|
33
|
+
Research bundles are written by default under
|
|
34
|
+
`.pi/greedysearch-research/<timestamp>_<query>/`.
|
|
35
|
+
|
|
36
|
+
```text
|
|
37
|
+
STATUS.md # floor status, question ledger, and gaps
|
|
38
|
+
OUTLINE.md # bundle table of contents
|
|
39
|
+
provenance.md # run metadata and verification summary
|
|
40
|
+
reports/SUMMARY.md # final cited report
|
|
41
|
+
reports/CLAIMS.md # claims mapped to source IDs
|
|
42
|
+
reports/EVIDENCE.md # extracted source evidence
|
|
43
|
+
reports/GAPS.md # caveats and remaining uncertainties
|
|
44
|
+
sources/ # fetched source markdown files
|
|
45
|
+
data/manifest.json # metadata, stop reason, floor checks, citation audit
|
|
46
|
+
data/rounds.json # per-round actions/learnings/gaps
|
|
47
|
+
data/sources.json # ranked source registry
|
|
48
|
+
data/questions.json # open/closed question ledger
|
|
49
|
+
data/evidence.json # structured evidence per useful source
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## CLI
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
node bin/search.mjs all --inline --stdin --depth research \
|
|
56
|
+
--breadth 3 --iterations 2 --max-sources 8 <<'EOF'
|
|
57
|
+
Evaluate browser automation options for AI agents
|
|
58
|
+
EOF
|
|
59
|
+
|
|
60
|
+
node bin/search.mjs all --inline --stdin --depth research \
|
|
61
|
+
--research-out-dir ./research-topic <<'EOF'
|
|
62
|
+
Topic
|
|
63
|
+
EOF
|
|
64
|
+
|
|
65
|
+
node bin/search.mjs all --inline --stdin --depth research \
|
|
66
|
+
--no-research-bundle <<'EOF'
|
|
67
|
+
Topic
|
|
68
|
+
EOF
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Verification
|
|
72
|
+
|
|
73
|
+
The provenance sidecar records:
|
|
74
|
+
|
|
75
|
+
- sources consulted, fetched, and cited;
|
|
76
|
+
- primary/official source counts;
|
|
77
|
+
- citation audit status;
|
|
78
|
+
- citation URL reachability;
|
|
79
|
+
- floor checks and overall status.
|
|
80
|
+
|
|
81
|
+
Bot-protected or HEAD-disallowing hosts are skipped in URL reachability rather
|
|
82
|
+
than marked dead when they return common anti-bot statuses such as 403.
|
package/docs/runtime.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Runtime and Chrome
|
|
2
|
+
|
|
3
|
+
GreedySearch uses a dedicated Chrome profile and debug port. It must not attach
|
|
4
|
+
to your normal Chrome profile.
|
|
5
|
+
|
|
6
|
+
- Profile: OS temp directory `greedysearch-chrome-profile`
|
|
7
|
+
- Port: `9222`
|
|
8
|
+
- Default mode: headless
|
|
9
|
+
|
|
10
|
+
## Pi Commands
|
|
11
|
+
|
|
12
|
+
```text
|
|
13
|
+
/greedy-visible # launch visible Chrome for captcha/login/cookie setup
|
|
14
|
+
/greedy-status # show GreedySearch Chrome status
|
|
15
|
+
/greedy-kill # stop GreedySearch Chrome
|
|
16
|
+
/set-greedy-locale # set default result language
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Environment Variables
|
|
20
|
+
|
|
21
|
+
- `GREEDY_SEARCH_VISIBLE` — set `1` to show Chrome instead of headless.
|
|
22
|
+
- `GREEDY_SEARCH_ALWAYS_VISIBLE` — set `1` to force visible mode for all runs.
|
|
23
|
+
- `GREEDY_SEARCH_IDLE_TIMEOUT_MINUTES` — headless idle cleanup timeout;
|
|
24
|
+
default `5`.
|
|
25
|
+
- `GREEDY_SEARCH_LOCALE` — default result language; default `en`.
|
|
26
|
+
- `CHROME_PATH` — Chrome/Chromium executable path; auto-detected by default.
|
|
27
|
+
|
|
28
|
+
## Runtime Helpers
|
|
29
|
+
|
|
30
|
+
Git install path:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
GS=~/.pi/agent/git/github.com/apmantza/GreedySearch-pi
|
|
34
|
+
node "$GS/bin/launch.mjs" --status
|
|
35
|
+
node "$GS/bin/visible.mjs"
|
|
36
|
+
node "$GS/bin/visible.mjs" --kill
|
|
37
|
+
node "$GS/bin/kill-visible.mjs"
|
|
38
|
+
node "$GS/bin/cdp-visible.mjs" list
|
|
39
|
+
node "$GS/bin/cdp-headless.mjs" list
|
|
40
|
+
node "$GS/bin/cdp-greedy.mjs" list
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
npm global install path:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
GS="$(npm root -g)/@apmantza/greedysearch-pi"
|
|
47
|
+
node "$GS/bin/launch.mjs" --status
|
|
48
|
+
node "$GS/bin/visible.mjs"
|
|
49
|
+
node "$GS/bin/visible.mjs" --kill
|
|
50
|
+
node "$GS/bin/kill-visible.mjs"
|
|
51
|
+
node "$GS/bin/cdp-visible.mjs" list
|
|
52
|
+
node "$GS/bin/cdp-headless.mjs" list
|
|
53
|
+
node "$GS/bin/cdp-greedy.mjs" list
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## CDP Safety
|
|
57
|
+
|
|
58
|
+
Use only the safe wrappers for manual debugging:
|
|
59
|
+
|
|
60
|
+
- `bin/cdp-visible.mjs` — refuses unless GreedySearch Chrome is visible.
|
|
61
|
+
- `bin/cdp-headless.mjs` — refuses unless GreedySearch Chrome is headless.
|
|
62
|
+
- `bin/cdp-greedy.mjs` — attaches only to the GreedySearch Chrome profile.
|
|
63
|
+
|
|
64
|
+
Avoid raw `bin/cdp.mjs` unless `CDP_PROFILE_DIR` explicitly points at the
|
|
65
|
+
GreedySearch profile.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Source Fetching
|
|
2
|
+
|
|
3
|
+
For `engine: "all"`, GreedySearch ranks discovered sources and fetches top source
|
|
4
|
+
content by default. `synthesize: true` then asks the configured synthesizer to
|
|
5
|
+
combine engine answers with fetched evidence.
|
|
6
|
+
|
|
7
|
+
## Supported Sources
|
|
8
|
+
|
|
9
|
+
- **PDFs** — direct PDF links are parsed into markdown text.
|
|
10
|
+
- **Semantic Scholar** — academic paper URLs and direct PDFs are preferred when
|
|
11
|
+
the engine is used directly or opted into the fan-out.
|
|
12
|
+
- **Reddit** — public `.json` API for posts and comments.
|
|
13
|
+
- **GitHub** — REST API for repos, READMEs, file trees, and raw file content.
|
|
14
|
+
- **General web** — Readability extraction with browser fallback.
|
|
15
|
+
|
|
16
|
+
## Metadata
|
|
17
|
+
|
|
18
|
+
Fetched sources include the best available:
|
|
19
|
+
|
|
20
|
+
- title;
|
|
21
|
+
- final URL;
|
|
22
|
+
- status/content type;
|
|
23
|
+
- byline and site name;
|
|
24
|
+
- publish or modified date;
|
|
25
|
+
- language;
|
|
26
|
+
- excerpt/snippet;
|
|
27
|
+
- trimmed markdown/plain text content.
|
|
28
|
+
|
|
29
|
+
## Security
|
|
30
|
+
|
|
31
|
+
Fetchers reject private/internal URLs and re-check the final redirected URL to
|
|
32
|
+
avoid SSRF bypasses. GitHub and Reddit URLs use dedicated fetchers where
|
|
33
|
+
possible to avoid fragile page scraping.
|