@lincoln504/pi-research 1.7.9 → 1.7.10
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/README.md +5 -1
- package/agent-skill/pi-research/SKILL.md +1 -1
- package/dist/cli.mjs +24 -6
- package/docs/AGENT-SKILL.md +4 -2
- package/docs/ARCHITECTURE.md +1 -1
- package/docs/CHANGELOG.md +20 -0
- package/docs/PI-EXTENSION.md +4 -0
- package/docs/SDK.md +4 -2
- package/package.json +1 -1
- package/scripts/setup.cjs +1 -0
- package/src/core/pi-version.ts +9 -1
- package/src/infrastructure/browser/ensure-browser.ts +30 -6
package/README.md
CHANGED
|
@@ -49,7 +49,7 @@ npm install -g @lincoln504/pi-research
|
|
|
49
49
|
pi-research skill install
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
-
No extra setup is needed. The package ships ready-made bindings for every platform and declares no build step, so there is nothing to approve or compile. The stealth browser (1GB+ installed) is fetched by the `postinstall` script
|
|
52
|
+
No extra setup is needed. The package ships ready-made bindings for every platform and declares no build step, so there is nothing to approve or compile. The stealth browser (1GB+ installed) is fetched by the `postinstall` script whenever npm runs dependency install scripts — which is npm 10 through 11.19 (11.16–11.19 print a warning) — and that includes the npm bundled with the Node 22.22.2 floor this package requires (10.9.7) and the npm bundled with Node 24/25 (11.19.0), so expect the fetch during install. npm 12, the current npm, blocks dependency install scripts by default, and the browser is then fetched lazily on the first scrape instead. Either way the first scrape takes a few minutes until it is in place. Set `PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1` to defer the fetch deliberately.
|
|
53
53
|
|
|
54
54
|
The `@earendil-works/pi-*` host packages are **peer dependencies**. pi supplies its own copies when it loads this as an extension, and npm ≥7 installs them automatically for a standalone (global or project) install. An install that skips peers does not get them: `npm install --legacy-peer-deps`, yarn classic, and `pi install` itself (it passes that flag on purpose) are all in that group. The standalone engine and the agent-skill launcher then stop with a message naming the missing package; add it with:
|
|
55
55
|
|
|
@@ -61,6 +61,10 @@ Standalone use needs that package on disk because the CLI and SDK import it dire
|
|
|
61
61
|
|
|
62
62
|
In pi, the extension works out of the box on the session's model and pi's configuration. Standalone use ([agent skill](docs/AGENT-SKILL.md) or [SDK](docs/SDK.md)) needs a model configured. See [Configuration](docs/CONFIGURATION.md).
|
|
63
63
|
|
|
64
|
+
### Update
|
|
65
|
+
|
|
66
|
+
`pi update --extensions` moves every installed extension to its newest published version; `pi update npm:@lincoln504/pi-research` targets only this one. A versioned source (`npm:@lincoln504/pi-research@1.7.9`) is pinned and never updates — remove and reinstall it to move versions.
|
|
67
|
+
|
|
64
68
|
### Uninstall
|
|
65
69
|
|
|
66
70
|
`pi remove npm:@lincoln504/pi-research` removes the extension. `npm uninstall -g @lincoln504/pi-research` removes the standalone engine. npm 7+ no longer runs `preuninstall`, so nothing else is removed on its own: skill links into other agents (Claude Code, Codex, …), the state directory (`~/.pi/research/state`), and the cache (`~/.cache/pi-research`, including any downloaded embedding models) stay in place. Remove the skill links first with `pi-research skill uninstall` (or `/research-config` → Remove from External Agents), then remove the rest with `pi-research cleanup`: The shared stealth-browser cache (`~/.cache/camoufox`) is preserved unless `PI_RESEARCH_PURGE_BROWSERS=1`. See [AGENT-SKILL.md](docs/AGENT-SKILL.md#installation-flow) for the full picture.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: pi-research
|
|
3
3
|
description: "Multi-agent web research for any coding agent. Use for anything requiring current information from the internet — news, trends, product/service/company facts, statistics, people, places, events, APIs, library behavior, or 'what is X / how does X work' questions. Also use to search a local knowledge store of previously researched findings before doing live research. Powered by the pi-research engine (search, stealth scraping, security databases, Stack Exchange). Not for reading local files, running project commands, or analyzing this repository's own source."
|
|
4
4
|
license: MIT
|
|
5
|
-
metadata: { "author": "Lincoln Deen", "version": "1.7.
|
|
5
|
+
metadata: { "author": "Lincoln Deen", "version": "1.7.10", "package": "@lincoln504/pi-research", "engine": "pi-research-sdk", "openclaw": { "requires": { "bins": ["node"] } } }
|
|
6
6
|
allowed-tools: Bash(node:*)
|
|
7
7
|
---
|
|
8
8
|
|
package/dist/cli.mjs
CHANGED
|
@@ -16625,7 +16625,7 @@ init_logger();
|
|
|
16625
16625
|
import { spawn as spawn2 } from "node:child_process";
|
|
16626
16626
|
import { createRequire as createRequire6 } from "node:module";
|
|
16627
16627
|
import { createHash as createHash2 } from "node:crypto";
|
|
16628
|
-
import { existsSync as existsSync8, fstatSync, openSync as openSync4, closeSync as closeSync4, rmSync as rmSync2, readFileSync as readFileSync5 } from "node:fs";
|
|
16628
|
+
import { existsSync as existsSync8, fstatSync, openSync as openSync4, closeSync as closeSync4, rmSync as rmSync2, readFileSync as readFileSync5, createWriteStream } from "node:fs";
|
|
16629
16629
|
import { join as join12, dirname as dirname9 } from "node:path";
|
|
16630
16630
|
import { tmpdir as tmpdir2, platform as platform3, homedir as homedir5 } from "node:os";
|
|
16631
16631
|
var FETCH_TIMEOUT_MS = 45 * 60 * 1e3;
|
|
@@ -16671,18 +16671,36 @@ function runFetch() {
|
|
|
16671
16671
|
delete env["CAMOUFOX_INSTALL_DIR"];
|
|
16672
16672
|
delete env["PLAYWRIGHT_BROWSERS_PATH"];
|
|
16673
16673
|
logger.info(`[ensure-browser] Camoufox not found; fetching the browser (this runs once, ~1.3GB): ${process.execPath} ${cli} fetch`);
|
|
16674
|
-
const
|
|
16674
|
+
const outLogPath = join12(tmpdir2(), `pi-research-camoufox-fetch-${process.pid}-${Date.now()}.log`);
|
|
16675
|
+
const outStream = createWriteStream(outLogPath, { mode: 384 });
|
|
16676
|
+
const child = spawn2(process.execPath, [cli, "fetch"], { stdio: ["ignore", "pipe", "inherit"], env });
|
|
16677
|
+
if (child.stdout) {
|
|
16678
|
+
child.stdout.pipe(outStream);
|
|
16679
|
+
}
|
|
16675
16680
|
const timer = setTimeout(() => {
|
|
16676
16681
|
child.kill("SIGKILL");
|
|
16677
16682
|
reject(new Error(`camoufox fetch timed out after ${FETCH_TIMEOUT_MS}ms`));
|
|
16678
16683
|
}, FETCH_TIMEOUT_MS);
|
|
16679
|
-
|
|
16684
|
+
const finish = (err, ok) => {
|
|
16680
16685
|
clearTimeout(timer);
|
|
16681
|
-
|
|
16686
|
+
void outStream.close();
|
|
16687
|
+
if (err) reject(err);
|
|
16688
|
+
else resolve9(ok);
|
|
16689
|
+
};
|
|
16690
|
+
child.on("error", (err) => {
|
|
16691
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
16692
|
+
finish(new Error(`${message} (fetch output logged at ${outLogPath})`), false);
|
|
16682
16693
|
});
|
|
16683
16694
|
child.on("exit", (code) => {
|
|
16684
|
-
|
|
16685
|
-
|
|
16695
|
+
if (code === 0) {
|
|
16696
|
+
try {
|
|
16697
|
+
rmSync2(outLogPath, { force: true });
|
|
16698
|
+
} catch {
|
|
16699
|
+
}
|
|
16700
|
+
finish(null, true);
|
|
16701
|
+
} else {
|
|
16702
|
+
finish(new Error(`camoufox fetch exited with code ${code} (fetch output logged at ${outLogPath})`), false);
|
|
16703
|
+
}
|
|
16686
16704
|
});
|
|
16687
16705
|
});
|
|
16688
16706
|
}
|
package/docs/AGENT-SKILL.md
CHANGED
|
@@ -21,10 +21,12 @@ npm install -g @lincoln504/pi-research # the engine (puts `pi-research` on PAT
|
|
|
21
21
|
pi-research skill install # link the skill into every detected agent
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
npm 12, the current npm, blocks dependency install scripts by default — and
|
|
25
25
|
none are needed: the only native piece on the launch path is `impit`, which ships
|
|
26
26
|
prebuilt binaries, and the stealth browser self-provisions on its first use (the first
|
|
27
|
-
scrape takes a few minutes).
|
|
27
|
+
scrape takes a few minutes). On npm 10 through 11.19 the `postinstall` fetch runs
|
|
28
|
+
during install instead; that is the npm bundled with Node 24/25 (11.19.0) and with
|
|
29
|
+
the Node 22.22.2 floor (10.9.7). No approval is required (see the [README](../README.md#install)).
|
|
28
30
|
|
|
29
31
|
The global install also brings the `@earendil-works/pi-*` host packages in as peer
|
|
30
32
|
dependencies (npm ≥7 resolves them). If your install skips peers
|
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -387,7 +387,7 @@ warns on every startup when a host-provided package (`typebox`, `@sinclair/typeb
|
|
|
387
387
|
loader and create a second live module instance (`resource-loader.js`,
|
|
388
388
|
`collectExtensionPackageWarnings`; pi `docs/packages.md`). Under pi the host's own copy is used,
|
|
389
389
|
so the two agree on `Value.Check`/`Convert` by construction. `@earendil-works/pi-ai` and
|
|
390
|
-
`@earendil-works/pi-coding-agent` 1.0.0 through 1.0
|
|
390
|
+
`@earendil-works/pi-coding-agent` 1.0.0 through 1.1.0 all pin `1.3.27` (re-checked 2026-10-08 in
|
|
391
391
|
the installed packages' `package.json`), which is why the devDependency, and so every test run and
|
|
392
392
|
the type-check, stays on exactly that version: bump it in lockstep with the pi host, not
|
|
393
393
|
independently. A standalone CLI/SDK install resolves the peer automatically on npm >= 7; the
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,26 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.7.10] - 2026-10-08
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- **The pi host dev dependencies move 1.0.4 → 1.1.0** (`@earendil-works/pi-ai`, `pi-coding-agent`, `pi-tui`; the peer range stays `>=0.99.0 <2`). The 1.0.4 → 1.1.0 diff is additive for this package (declaration diff of the installed packages, 2026-10-08): `pi-coding-agent` adds `durationMs` on the tool render context and `tool_execution_end`, `aborted` on `agent_settled` events, and the `+name`/`-name` tool modifiers; `pi-ai` adds the Decisions-API classifier surface and an optional `AuthProvider.agentName`; `pi-tui` adds the OSC 7501 program-status helpers and `Text.setPaddingX`. `docs/extensions.md` is unchanged and nothing was removed or re-signed, so the 0.99.0 floor is unchanged too. `PI_TESTED_MAX_VERSION` moves to 1.1.0 (`src/core/pi-version.ts`), so a pi 1.1.x host runs without the "newer than the tested ceiling" notice; `npm audit` stays at 0 and type-check (TypeScript 6 and 7), lint and the full unit suite (3305) pass against 1.1.0.
|
|
13
|
+
- **The npm install-script boundary is corrected across every user-facing surface and CI comment.** npm 10 through 11.19 run dependency install scripts (11.16–11.19 print a warning); npm 12, the current npm, blocks them by default — the npm bundled with Node 24/25 is 11.19.0, which still runs them, so a stock Node install fetches the browser during install. The old "11.19+ skips install scripts" wording in `README.md`, `docs/AGENT-SKILL.md`, `docs/SDK.md`, the ES/JA/ZH docs and the `ci.yml` comments was wrong — verified against the npm 11.19.0 source (arborist skips a script only when it is explicitly denied; `strict-allow-scripts` is opt-in) and consistent with this repo's own earlier measurement that 11.16–11.19 "warn but still run". The stale "compile from source on Windows" / `better-sqlite3` 13 references that survived the 1.7.9 launcher swap are gone with it.
|
|
14
|
+
- **Update guidance is documented** (README and `docs/PI-EXTENSION.md`): `pi update --extensions` moves every installed extension to its newest published version, `pi update npm:@lincoln504/pi-research` targets only this one, and a versioned source (`npm:@lincoln504/pi-research@1.7.9`) is pinned and never updates — remove and reinstall it to move versions.
|
|
15
|
+
- **`setup.cjs` announces the ~1.3 GB fetch before it starts**, so the postinstall fetch that runs inside `pi install` / `pi update --extensions` on script-running npm (10–11.19) no longer looks like a hang.
|
|
16
|
+
- In-range dev refresh: `vite` 8.3.2 → 8.3.4.
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- **The in-host lazy browser fetch no longer writes raw to the terminal.** `ensureBrowserInstalled()` spawned its `camoufox fetch` child with `stdio: 'inherit'`; a child with an inherited fd 1 bypasses pi's JS-level stdout redirection (pi's `takeOverStdout` rewrites `process.stdout.write` for the TUI) and interleaves the download's progress with the host's output stream — in print/JSON/RPC modes stdout is the protocol itself, so raw child output could corrupt it. The child's stdout is now captured in a temp file (its path is logged on failure, the file is removed on success) and stderr stays inherited, so real errors remain visible. Pinned by a test asserting `stdio: ['ignore', 'pipe', 'inherit']` on the fetch child.
|
|
21
|
+
|
|
22
|
+
### Also shipped since 1.7.9
|
|
23
|
+
|
|
24
|
+
- **`source-map-js` 1.2.2** in the production tree clears GHSA-68fv-2mgg-jv7q from the audit gate (`npm audit`: 0).
|
|
25
|
+
- **The unit suite stops leaking throwaway tmpdirs.**
|
|
26
|
+
- **`docs/AUDIT-GATE.md` records** that a shipped host `npm-shrinkwrap.json` does not propagate a consumer-side `sharp` override (consumer advisory note).
|
|
27
|
+
|
|
8
28
|
## [1.7.9] - 2026-10-05
|
|
9
29
|
|
|
10
30
|
### Changed
|
package/docs/PI-EXTENSION.md
CHANGED
|
@@ -83,6 +83,10 @@ coding agents detected on this machine so they can run web research through the
|
|
|
83
83
|
CLI, and remove it again — with exact, manifest-tracked cleanup. See
|
|
84
84
|
[AGENT-SKILL.md](AGENT-SKILL.md) for the full installation flow.
|
|
85
85
|
|
|
86
|
+
### Update
|
|
87
|
+
|
|
88
|
+
`pi update --extensions` moves every installed extension to its newest published version; `pi update npm:@lincoln504/pi-research` targets only this one. A versioned source (`npm:@lincoln504/pi-research@1.7.9`) is pinned and never updates — remove and reinstall it to move versions.
|
|
89
|
+
|
|
86
90
|
### Lifecycle
|
|
87
91
|
|
|
88
92
|
- `activate` — registers commands, tools, the TUI controller, and initializes services.
|
package/docs/SDK.md
CHANGED
|
@@ -21,9 +21,11 @@ classic — the SDK cannot import them, so add the one it loads directly:
|
|
|
21
21
|
npm install @earendil-works/pi-coding-agent
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
npm 12, the current npm, blocks dependency install scripts by default. Nothing
|
|
25
25
|
here needs them: the only native piece on the launch path is `impit`, which ships
|
|
26
|
-
prebuilt binaries, and the stealth browser self-provisions on its first use.
|
|
26
|
+
prebuilt binaries, and the stealth browser self-provisions on its first use. On npm 10
|
|
27
|
+
through 11.19 the `postinstall` fetch runs during install instead; that is the npm
|
|
28
|
+
bundled with Node 24/25 (11.19.0) and with the Node 22.22.2 floor (10.9.7). (The
|
|
27
29
|
`npm approve-scripts better-sqlite3` + `npm rebuild` pair documented by earlier
|
|
28
30
|
releases repaired the old `camoufox-js` launcher, whose `better-sqlite3` binding came
|
|
29
31
|
from an install script — the 2026-10-05 move to `@camoufox/camoufox` removed that
|
package/package.json
CHANGED
package/scripts/setup.cjs
CHANGED
|
@@ -135,6 +135,7 @@ if (process.env.PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD === '1') {
|
|
|
135
135
|
return true;
|
|
136
136
|
};
|
|
137
137
|
|
|
138
|
+
console.log('pi-research: downloading the ~1.3 GB Camoufox browser — this can take several minutes on a slow link…');
|
|
138
139
|
const pkgRoot = layout.findPackageRoot(projectRoot);
|
|
139
140
|
const result = layout.provisionBrowser(cachePath, runFetch, (m) => console.log(m), pkgRoot ? layout.loadPin(pkgRoot) : null);
|
|
140
141
|
if (result.status === 'failed') {
|
package/src/core/pi-version.ts
CHANGED
|
@@ -122,8 +122,16 @@ export const PI_MIN_VERSION: SemverParts = { major: 0, minor: 99, patch: 0 };
|
|
|
122
122
|
* modes), the `builtin:<name>` naming for built-in extensions and tools, and
|
|
123
123
|
* `--no-extensions` now also disabling the built-in extensions. None of them
|
|
124
124
|
* change what this package does.
|
|
125
|
+
*
|
|
126
|
+
* 1.1.0 (2026-10-07) is additive for this package. Diffed against 1.0.4 on 2026-10-08:
|
|
127
|
+
* `@earendil-works/pi-coding-agent` adds `durationMs` on the tool render context and
|
|
128
|
+
* `tool_execution_end`, `aborted` on `agent_settled` events, and the `+name`/`-name`
|
|
129
|
+
* tool modifiers; `@earendil-works/pi-ai` adds the Decisions-API classifier surface
|
|
130
|
+
* and an optional `AuthProvider.agentName`; `@earendil-works/pi-tui` adds the OSC 7501
|
|
131
|
+
* program-status helpers and `Text.setPaddingX`. `docs/extensions.md` is unchanged,
|
|
132
|
+
* and nothing was removed or re-signed, so the 0.99.0 floor is unchanged too.
|
|
125
133
|
*/
|
|
126
|
-
export const PI_TESTED_MAX_VERSION: SemverParts = { major: 1, minor:
|
|
134
|
+
export const PI_TESTED_MAX_VERSION: SemverParts = { major: 1, minor: 1, patch: 0 };
|
|
127
135
|
|
|
128
136
|
export type PiCompatibilityLevel = 'ok' | 'unparseable' | 'too-old' | 'untested';
|
|
129
137
|
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
import { spawn } from 'node:child_process';
|
|
22
22
|
import { createRequire } from 'node:module';
|
|
23
23
|
import { createHash } from 'node:crypto';
|
|
24
|
-
import { existsSync, fstatSync, openSync, closeSync, rmSync, readFileSync } from 'node:fs';
|
|
24
|
+
import { existsSync, fstatSync, openSync, closeSync, rmSync, readFileSync, createWriteStream } from 'node:fs';
|
|
25
25
|
import { join, dirname } from 'node:path';
|
|
26
26
|
import { tmpdir, platform, homedir } from 'node:os';
|
|
27
27
|
import { logger } from '../../logger.ts';
|
|
@@ -89,6 +89,14 @@ const delay = (ms: number): Promise<void> => new Promise((r) => setTimeout(r, ms
|
|
|
89
89
|
* spawn error / timeout. Runs the CLI's JS entry with process.execPath and an argv array:
|
|
90
90
|
* no shell, so neither a spaced Windows path nor a metacharacter in an install directory
|
|
91
91
|
* can be reinterpreted.
|
|
92
|
+
*
|
|
93
|
+
* The child's stdout is captured in a temp file, not inherited: a child with an
|
|
94
|
+
* inherited fd 1 writes raw to the terminal, which inside a pi session bypasses the
|
|
95
|
+
* host's JS-level stdout redirection (pi redirects `process.stdout.write` for its TUI)
|
|
96
|
+
* and interleaves the download's progress with the host's output stream — in
|
|
97
|
+
* print/JSON/RPC modes stdout is the protocol itself, so raw child output corrupts it.
|
|
98
|
+
* The launcher's progress is noise either way; its errors go to stderr, which stays
|
|
99
|
+
* inherited and is therefore still visible.
|
|
92
100
|
*/
|
|
93
101
|
function runFetch(): Promise<boolean> {
|
|
94
102
|
return new Promise<boolean>((resolve, reject) => {
|
|
@@ -106,19 +114,35 @@ function runFetch(): Promise<boolean> {
|
|
|
106
114
|
delete env['PLAYWRIGHT_BROWSERS_PATH'];
|
|
107
115
|
logger.info(`[ensure-browser] Camoufox not found; fetching the browser (this runs once, ~1.3GB): ${process.execPath} ${cli} fetch`);
|
|
108
116
|
|
|
109
|
-
const
|
|
117
|
+
const outLogPath = join(tmpdir(), `pi-research-camoufox-fetch-${process.pid}-${Date.now()}.log`);
|
|
118
|
+
const outStream = createWriteStream(outLogPath, { mode: 0o600 });
|
|
119
|
+
const child = spawn(process.execPath, [cli, 'fetch'], { stdio: ['ignore', 'pipe', 'inherit'], env });
|
|
120
|
+
if (child.stdout) {
|
|
121
|
+
child.stdout.pipe(outStream);
|
|
122
|
+
}
|
|
110
123
|
const timer = setTimeout(() => {
|
|
111
124
|
child.kill('SIGKILL');
|
|
112
125
|
reject(new Error(`camoufox fetch timed out after ${FETCH_TIMEOUT_MS}ms`));
|
|
113
126
|
}, FETCH_TIMEOUT_MS);
|
|
114
127
|
|
|
115
|
-
|
|
128
|
+
const finish = (err: Error | null, ok: boolean): void => {
|
|
116
129
|
clearTimeout(timer);
|
|
117
|
-
|
|
130
|
+
void outStream.close();
|
|
131
|
+
if (err) reject(err);
|
|
132
|
+
else resolve(ok);
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
child.on('error', (err) => {
|
|
136
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
137
|
+
finish(new Error(`${message} (fetch output logged at ${outLogPath})`), false);
|
|
118
138
|
});
|
|
119
139
|
child.on('exit', (code) => {
|
|
120
|
-
|
|
121
|
-
|
|
140
|
+
if (code === 0) {
|
|
141
|
+
try { rmSync(outLogPath, { force: true }); } catch { /* best-effort */ }
|
|
142
|
+
finish(null, true);
|
|
143
|
+
} else {
|
|
144
|
+
finish(new Error(`camoufox fetch exited with code ${code} (fetch output logged at ${outLogPath})`), false);
|
|
145
|
+
}
|
|
122
146
|
});
|
|
123
147
|
});
|
|
124
148
|
}
|