@apmantza/greedysearch-pi 2.1.2 → 2.1.4

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 CHANGED
@@ -1,6 +1,40 @@
1
1
  # Changelog
2
2
 
3
- ## [Unreleased]
3
+ ## [Unreleased]
4
+
5
+ ### Added
6
+
7
+ ### Changed
8
+
9
+ ### Fixed
10
+
11
+ ## [2.1.4] — 2026-07-04
12
+
13
+ ### Added
14
+
15
+ - **Changelog-driven release notes** (`scripts/changelog-extract.mjs`, `scripts/changelog-release.mjs`, `scripts/backfill-github-releases.mjs`, `.github/workflows/release.yml`) — GitHub releases now use curated CHANGELOG sections as the release body, with helper scripts for promoting `Unreleased`, extracting summary notes, and backfilling historical releases. The parser supports both current `## [x.y.z] — date` headings and legacy `## vx.y.z (date)` headings.
16
+
17
+ ### Changed
18
+
19
+ - **README simplified like pi-lens and package skill removed** (`README.md`, `docs/*.md`, `package.json`) — The root README is now a concise project overview with installation, quick usage, and links to focused docs for usage, research mode, runtime/Chrome, source fetching, development, and releases. The duplicated Pi skill file was removed so docs live in one place.
20
+ - **Normal all-engine config excludes Semantic Scholar** (`src/search/constants.mjs`, `~/.pi/greedyconfig`) — Default and local all-engine fan-out now use Perplexity, Google, ChatGPT, and Gemini while academic/research engines remain opt-in.
21
+
22
+ ### Fixed
23
+
24
+ - **Headless ChatGPT and Gemini extraction in all-mode** (`extractors/chatgpt.mjs`, `extractors/gemini.mjs`, `bin/search.mjs`) — ChatGPT now keeps its tab foregrounded during headless streaming, waits for streaming indicators to clear, and rejects repeated-domain citation stubs. Gemini now targets the latest `model-response`, avoids nested code-block copy buttons, and prefers a complete DOM fallback when clipboard copy captures only a snippet.
25
+ - **Research-mode floor and citation handling** (`src/search/research.mjs`, `src/search/simple-research.mjs`) — Explicit `breadth` / `iterations` values now bypass scale-aware overrides, duplicate fetch targets are skipped, cited-source URL checks only evaluate cited sources, and bot-protected HEAD responses are skipped instead of treated as dead links.
26
+ - **Fetcher return style consistency** (`src/fetcher.mjs`) — Multi-line formatting for the protocol-not-allowed return object in `isPrivateUrl` to match the project's code style conventions.
27
+
28
+ ## [2.1.3] — 2026-06-21
29
+
30
+ ### Fixed
31
+
32
+ - **Stale dependency resolution** — `jsdom` was installed at `24.1.3` despite `package.json` declaring `^29.1.1` (lockfile freeze). Fresh lockfile resolves all deps to latest within semver ranges. Updated `@sinclair/typebox` `^0.34.48` → `^0.34.49`.
33
+ - **Peer dep pin** — `@earendil-works/pi-coding-agent` peer dep changed from wildcard `*` to `^0.79.0` to pin compatible range against Pi `0.79.9`.
34
+
35
+ ### Changed
36
+
37
+ - **CI security audit** — Added `npm audit --omit=dev --audit-level=high` to GitHub Actions CI (matching pi-lens) to block pushes/PRs that introduce high/critical vulnerabilities in production dependencies.
4
38
 
5
39
  ## [2.1.2] — 2026-06-18
6
40
 
package/README.md CHANGED
@@ -1,14 +1,19 @@
1
+ <p align="center">
2
+ <img src="docs/banner.svg" alt="GreedySearch for Pi" width="1100">
3
+ </p>
4
+
1
5
  # GreedySearch for Pi
2
6
 
3
- ![GreedySearch](docs/banner.svg)
7
+ GreedySearch registers the `greedy_search` tool for Pi: headless-first,
8
+ no-API-key AI/web search through a dedicated Chrome profile.
4
9
 
5
- Multi-engine AI web search for Pi via browser automation.
10
+ ## What It Does
6
11
 
7
- - No API keys
8
- - Real browser results from configurable engines: Perplexity, Google AI, ChatGPT, Gemini, plus opt-in Semantic Scholar and Logically research engines
9
- - Research mode as the centerpiece: iterative planning, source fetching, citation audit, and structured bundles
10
- - Optional configurable synthesis with source grounding (Gemini by default)
11
- - Chrome runs headless by default no window, purely background
12
+ - Multi-engine search across Perplexity, Google AI, ChatGPT, and Gemini
13
+ - Source-grounded `engine: "all"` results with fetched source content
14
+ - Optional synthesis over engine answers and fetched sources
15
+ - Iterative `depth: "research"` runs with citation audit and research bundles
16
+ - Visible Chrome fallback for login/captcha/cookie setup when needed
12
17
 
13
18
  ## Install
14
19
 
@@ -22,16 +27,12 @@ Or from git:
22
27
  pi install git:github.com/apmantza/GreedySearch-pi
23
28
  ```
24
29
 
25
- ## Tool
26
-
27
- - `greedy_search` — multi-engine AI web search, source-grounded synthesis, and deep research
28
-
29
- ## Quick usage
30
+ ## Quick Usage
30
31
 
31
32
  ```js
32
- greedy_search({ query: "React 19 changes" }); // all engines + fetched sources
33
- greedy_search({ query: "React 19 changes", synthesize: true }); // add configured synthesis
34
- greedy_search({ query: "Prisma vs Drizzle", engine: "perplexity" }); // individual engine
33
+ greedy_search({ query: "React 19 changes" });
34
+ greedy_search({ query: "React 19 changes", synthesize: true });
35
+ greedy_search({ query: "Prisma vs Drizzle", engine: "perplexity" });
35
36
  greedy_search({
36
37
  query: "Evaluate browser automation options for AI agents",
37
38
  depth: "research",
@@ -39,181 +40,32 @@ greedy_search({
39
40
  iterations: 2,
40
41
  maxSources: 8,
41
42
  });
42
- // Research mode writes a dataroom-style bundle under .pi/greedysearch-research/ by default.
43
- // Headless is the default — no window. To force visible Chrome:
44
- greedy_search({ query: "Visible browser setup", engine: "perplexity", visible: true });
45
- ```
46
-
47
- ## Parameters (`greedy_search`)
48
-
49
- ### Common
50
-
51
- - `query` (required)
52
- - `fullAnswer`: return full single-engine output instead of preview
53
- - `headless`: set to `false` to show Chrome window (default: `true`)
54
- - `visible` / `alwaysVisible`: set to `true` to always use visible Chrome for this search
55
-
56
- ### Normal search
57
-
58
- - `engine`: `all` (default web/search fan-out), `perplexity`, `google`, `chatgpt`, `gemini`; opt-in research engines: `semantic-scholar`, `logically`; `bing` still works for signed-in users
59
- - `synthesize`: for `engine: "all"`, synthesize fetched sources with the configured synthesizer (default false)
60
- - `synthesizer`: override the configured synthesis engine for this call (`gemini` default, `chatgpt` supported)
61
- - `depth`: legacy `fast`/`standard`/`deep` aliases are still accepted for compatibility; prefer `synthesize` for normal search
62
-
63
- ### Deep research
64
-
65
- - `depth`: set to `"research"` to run the iterative research workflow
66
- - `breadth`: number of research actions per round, 1-5 (default 3)
67
- - `iterations`: research rounds, 1-3 (default 2)
68
- - `maxSources`: fetched source cap for the final report, 3-12
69
- - `researchOutDir`: optional directory for the research bundle
70
- - `writeResearchBundle`: write the research bundle to disk (default true for research mode)
71
-
72
- Deep research uses the configured `~/.pi/greedyconfig.engines` list for child searches and Gemini for planning/final synthesis.
73
-
74
- ## Environment variables
75
-
76
- | Variable | Default | Description |
77
- | ------------------------------------ | ------------- | ------------------------------------------------------------- |
78
- | `GREEDY_SEARCH_VISIBLE` | (unset) | Set to `1` to show Chrome window instead of headless |
79
- | `GREEDY_SEARCH_ALWAYS_VISIBLE` | (unset) | Set to `1` to force visible Chrome for all GreedySearch runs |
80
- | `GREEDY_SEARCH_IDLE_TIMEOUT_MINUTES` | `5` | Minutes of inactivity before auto-killing GreedySearch Chrome |
81
- | `GREEDY_SEARCH_LOCALE` | `en` | Default result language (en, de, fr, es, ja, etc.) |
82
- | `CHROME_PATH` | auto-detected | Path to Chrome/Chromium executable |
83
-
84
- ## Search modes
85
-
86
- - **Individual engine search/research** — `engine: "perplexity" | "google" | "chatgpt" | "gemini" | "semantic-scholar" | "logically" | "bing"`; returns that engine's answer and sources.
87
- - **Grounded multi-engine search** — default `engine: "all"`; fans out to configured engines, ranks sources, fetches top source content, and reports confidence metadata.
88
- - **All + synthesis** — add `synthesize: true` (or CLI `--synthesize`) to ask the configured synthesizer to combine engine answers and fetched source evidence.
89
- - **Deep research** — `depth: "research"`; iterative action planning, direct URL fetches, fast multi-engine searches, source fetching, learning extraction, deterministic floor checks, citation audit, a final cited report, and a structured on-disk bundle.
90
-
91
- Legacy `depth: "fast" | "standard" | "deep"` values remain accepted for compatibility: `fast` skips source fetching; `standard`/`deep` request synthesis.
92
-
93
- Configure all-engine fan-out and synthesis in `~/.pi/greedyconfig`:
94
-
95
- ```json
96
- {
97
- "engines": ["perplexity", "google", "chatgpt", "gemini"],
98
- "synthesizer": "gemini"
99
- }
100
- ```
101
-
102
- Gemini is a normal search engine and can participate in `engine: "all"`. `semantic-scholar` and `logically` are opt-in academic/research engines; include them in `~/.pi/greedyconfig` only when you want the all-engine fan-out to include academic paper discovery or research-assistant workflows. Default `engine: "all"` excludes them because their results are noisy for casual web search — they shine in `depth: "research"` mode instead. Deep research child searches reuse the same configured `engines` list and keep query text on stdin; Gemini remains the research planner/final-report synthesizer. If `synthesize: true` and `"synthesizer": "gemini"`, Gemini runs once as a search engine and again as the synthesizer; set `"synthesizer": "chatgpt"` to separate those roles for normal all-search synthesis.
103
-
104
- Research bundles are written by default to `.pi/greedysearch-research/<timestamp>_<query>/` and include:
105
-
106
- ```text
107
- STATUS.md # floor status, open/closed question ledger, and gaps
108
- OUTLINE.md # bundle table of contents
109
- reports/SUMMARY.md # final cited report
110
- reports/CLAIMS.md # extracted claims mapped to source IDs
111
- reports/EVIDENCE.md # goal-based evidence extracted from fetched sources
112
- reports/GAPS.md # caveats and remaining uncertainties
113
- sources/ # fetched source markdown files
114
- data/manifest.json # run metadata, stop reason, floor checks, citation audit
115
- data/rounds.json # per-round actions/learnings/gaps
116
- data/sources.json # ranked source registry
117
- data/questions.json # STATUS-style question ledger with evidence/source IDs
118
- data/evidence.json # structured rational/evidence/summary per useful source
119
- ```
120
-
121
- CLI controls:
122
-
123
- ```bash
124
- node bin/search.mjs all --inline --stdin --depth research --breadth 3 --iterations 2 --max-sources 8 <<'EOF'
125
- Evaluate browser automation options for AI agents
126
- EOF
127
- node bin/search.mjs all "topic" --depth research --research-out-dir ./research-topic
128
- node bin/search.mjs all "topic" --depth research --no-research-bundle
129
43
  ```
130
44
 
131
- ## Runtime commands
45
+ Headless is the default. Use `visible: true` only when you need to establish a
46
+ session, solve a challenge, or inspect the browser:
132
47
 
133
- Inside Pi, prefer the extension commands (no package path needed):
134
-
135
- ```text
136
- /greedy-visible # launch visible Chrome for captcha/login/cookie setup
137
- /greedy-status # show GreedySearch Chrome status
138
- /greedy-kill # stop GreedySearch Chrome
139
- /set-greedy-locale # set default result language (de, fr, es, ja, etc.)
140
- ```
141
-
142
- Git install path:
143
-
144
- ```bash
145
- GS=~/.pi/agent/git/github.com/apmantza/GreedySearch-pi
146
- node "$GS/bin/launch.mjs" --status
147
- node "$GS/bin/visible.mjs" # visible mode
148
- node "$GS/bin/visible.mjs" --kill # strong visible/port cleanup
149
- node "$GS/bin/kill-visible.mjs" # same as visible.mjs --kill
150
- node "$GS/bin/cdp-visible.mjs" list # safe CDP: GreedySearch visible Chrome only
151
- node "$GS/bin/cdp-headless.mjs" list # safe CDP: GreedySearch headless Chrome only
152
- node "$GS/bin/cdp-greedy.mjs" list # safe CDP: any GreedySearch Chrome mode
153
- ```
154
-
155
- npm global install path:
156
-
157
- ```bash
158
- GS="$(npm root -g)/@apmantza/greedysearch-pi"
159
- node "$GS/bin/launch.mjs" --status
160
- node "$GS/bin/visible.mjs"
161
- node "$GS/bin/visible.mjs" --kill
162
- node "$GS/bin/kill-visible.mjs"
163
- node "$GS/bin/cdp-visible.mjs" list
164
- node "$GS/bin/cdp-headless.mjs" list
165
- node "$GS/bin/cdp-greedy.mjs" list
48
+ ```js
49
+ greedy_search({ query: "Visible setup", engine: "perplexity", visible: true });
166
50
  ```
167
51
 
168
- Chrome is auto-cleaned after 5 min idle. Override with `GREEDY_SEARCH_IDLE_TIMEOUT_MINUTES=10` or disable with `0`.
52
+ ## Documentation
169
53
 
170
- **CDP safety:** use `cdp-visible.mjs`, `cdp-headless.mjs`, or `cdp-greedy.mjs` for debugging. They always set `CDP_PROFILE_DIR` to the dedicated GreedySearch Chrome profile and never fall back to your main Chrome session. Avoid calling raw `bin/cdp.mjs` manually unless you explicitly set `CDP_PROFILE_DIR`.
54
+ - [Usage guide](docs/usage.md) tool parameters, search modes, and config
55
+ - [Research mode](docs/research.md) — iterative workflow and bundle layout
56
+ - [Runtime and Chrome](docs/runtime.md) — slash commands, env vars, CDP safety
57
+ - [Source fetching](docs/source-fetching.md) — supported source types and metadata
58
+ - [Development](docs/development.md) — project layout, tests, and smoke checks
59
+ - [Release workflow](docs/releases.md) — changelog scripts and GitHub releases
171
60
 
172
61
  ## Requirements
173
62
 
174
- - Chrome
63
+ - Chrome or Chromium
175
64
  - Node.js 20.11.0+
176
65
 
177
- ## Source fetching
178
-
179
- When using `engine: "all"`, top source content is fetched by default. Add `synthesize: true` to synthesize with the configured synthesizer:
180
-
181
- - **PDFs** — Direct PDF links are parsed to markdown text for source-grounded synthesis
182
- - **Semantic Scholar** — Discovers academic papers and prefers direct PDF/external paper links when available
183
- - **Reddit** — Uses Reddit's public `.json` API for posts and comments
184
- - **GitHub** — Uses GitHub REST API for repos, READMEs, and file trees
185
- - **General web** — Mozilla Readability extraction with browser fallback when needed
186
- - **Metadata** — title, author/byline, site name, publish date, language, excerpt
187
-
188
- ## Project layout
189
-
190
- - `bin/` — runtime CLIs (`search.mjs`, `launch.mjs`, `launch-visible.mjs`, `visible.mjs`, `kill-visible.mjs`, safe CDP wrappers, `cdp.mjs`)
191
- - `extractors/` — engine-specific automation + stealth/consent handling
192
- - `src/` — search pipeline, chrome management, source fetching, formatting
193
- - `skills/` — Pi skill metadata
194
-
195
- ## Testing
196
-
197
- Cross-platform test runner (Windows + Unix):
198
-
199
- ```bash
200
- npm test # run all tests
201
- npm run test:quick # skip slow tests
202
- npm run test:smoke # basic health check
203
- ```
204
-
205
- Full bash test suite (Unix only):
206
-
207
- ```bash
208
- npm run test:bash # comprehensive tests
209
- ./test.sh parallel # race condition tests
210
- ./test.sh flags # flag/option tests
211
- ```
212
-
213
- ## Changelog
214
-
215
- See `CHANGELOG.md`.
66
+ ## Contributing
216
67
 
217
- ## License
68
+ See [`CONTRIBUTING.md`](CONTRIBUTING.md) and [`AGENTS.md`](AGENTS.md) for the
69
+ extractor, recovery, and release checklists.
218
70
 
219
- MIT
71
+ GreedySearch is released under the [MIT License](LICENSE).
package/bin/search.mjs CHANGED
@@ -314,6 +314,8 @@ async function main() {
314
314
  const ENGINE_START_URLS = {
315
315
  perplexity: "https://www.perplexity.ai/",
316
316
  google: "https://www.google.com/",
317
+ chatgpt: "https://chatgpt.com/",
318
+ gemini: "https://gemini.google.com/app",
317
319
  "semantic-scholar": "https://www.semanticscholar.org/",
318
320
  semanticscholar: "https://www.semanticscholar.org/",
319
321
  s2: "https://www.semanticscholar.org/",
@@ -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,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.
@@ -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.