@lincoln504/pi-research 1.6.2 → 1.6.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/README.md +8 -3
- package/agent-skill/pi-research/README.md +4 -0
- package/agent-skill/pi-research/SKILL.md +1 -1
- package/dist/cli.mjs +9 -6
- package/docs/AGENT-SKILL.md +4 -0
- package/docs/CHANGELOG.md +35 -0
- package/docs/SDK.md +13 -0
- package/package.json +1 -1
- package/src/cli.ts +10 -5
- package/src/infrastructure/file-lock-service.ts +18 -10
- package/src/web-research/browser-search.ts +3 -2
package/README.md
CHANGED
|
@@ -44,7 +44,13 @@ npm install -g @lincoln504/pi-research
|
|
|
44
44
|
pi-research skill install
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
On npm 12 or newer,
|
|
47
|
+
On npm 12 or newer, allow the one install script search depends on before installing:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npm config set allow-scripts=better-sqlite3 --location=user
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
npm 12 stopped running dependency install scripts by default, and the stealth browser's SQLite module is built by one. Skipped, the install still succeeds with a warning — but every search fails with a missing-module error. The config covers both installs; for the standalone install, `--allow-scripts=better-sqlite3` on the `npm install -g` line also works. The bare flag allows nothing, and `pi install` accepts only the config form.
|
|
48
54
|
|
|
49
55
|
In pi it 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). The first install downloads the stealth browser engine, which takes a few minutes.
|
|
50
56
|
|
|
@@ -63,11 +69,10 @@ Three depth levels (normal, deep, ultra) set the team size and number of rounds.
|
|
|
63
69
|
- Keeping a persistent and searchable knowledge store of findings, scoped globally or per project.
|
|
64
70
|
- Building agent systems that find and read web content, or populating a dataset of web sources.
|
|
65
71
|
|
|
66
|
-
### Why
|
|
72
|
+
### Why
|
|
67
73
|
|
|
68
74
|
- **No quota and no monthly fee.** Most AI search providers cap free searches and then charge, with results served from their index on their servers. pi-research searches and scrapes locally through DuckDuckGo in a stealth browser.
|
|
69
75
|
- **The index is local.** Every finding can be saved to a local [LanceDB](https://lancedb.com) knowledge store that seeds future runs, so repeat questions get faster and cheaper answers.
|
|
70
|
-
- **Cited reports rather than raw dumps.** Each run returns one sourced Markdown report instead of raw web content pasted into the conversation. Context efficient and easy to verify.
|
|
71
76
|
- **Read-only by design.** The research agent cannot run shell commands or write, edit, or delete anything — the right shape for an agent whose whole job is reading untrusted web pages. Prompt injection picked up mid-run has nothing to act on.
|
|
72
77
|
- **Search a little or a lot.** Depth levels range from a quick pass to a large-scale investigation.
|
|
73
78
|
|
|
@@ -47,6 +47,10 @@ npm install -g @lincoln504/pi-research
|
|
|
47
47
|
node "<skill_dir>/scripts/run.mjs" status # verify detection
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
+
On npm 12 or newer, first run `npm config set allow-scripts=better-sqlite3 --location=user`:
|
|
51
|
+
npm 12 blocks the install script that builds the stealth browser's SQLite module, and
|
|
52
|
+
without it every search fails with a missing-module error.
|
|
53
|
+
|
|
50
54
|
### Install the skill
|
|
51
55
|
|
|
52
56
|
Recommended. From the pi extension, run `/research-config` and choose
|
|
@@ -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.6.
|
|
5
|
+
metadata: { "author": "Lincoln Deen", "version": "1.6.4", "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
|
@@ -6831,7 +6831,7 @@ var init_file_lock_service = __esm({
|
|
|
6831
6831
|
const errnoError = error;
|
|
6832
6832
|
if (errnoError.code === "EEXIST") {
|
|
6833
6833
|
contentionCount++;
|
|
6834
|
-
let
|
|
6834
|
+
let awaitingReclaim = false;
|
|
6835
6835
|
try {
|
|
6836
6836
|
const rawContent = await fs7.readFile(this.lockFilePath, "utf-8");
|
|
6837
6837
|
const parsed = this._parseLockContent(rawContent);
|
|
@@ -6843,7 +6843,7 @@ var init_file_lock_service = __esm({
|
|
|
6843
6843
|
}
|
|
6844
6844
|
lastSeenUuid = lockUuid;
|
|
6845
6845
|
lastSeenMtime = stats.mtimeMs;
|
|
6846
|
-
|
|
6846
|
+
awaitingReclaim = this.lockTimeout > 0 && (parsed?.pid ?? null) === null && lockAge <= this._unidentifiedStaleThreshold();
|
|
6847
6847
|
if (lockUuid === this.lockUuid) {
|
|
6848
6848
|
try {
|
|
6849
6849
|
await fs7.unlink(this.lockFilePath);
|
|
@@ -6880,7 +6880,6 @@ var init_file_lock_service = __esm({
|
|
|
6880
6880
|
}
|
|
6881
6881
|
const stalledFor = Date.now() - lastProgressAt;
|
|
6882
6882
|
const waitedFor = Date.now() - startTime;
|
|
6883
|
-
const awaitingReclaim = this.lockTimeout > 0 && reclaimEligibleAt !== null && Date.now() < reclaimEligibleAt;
|
|
6884
6883
|
if (stalledFor >= this.lockTimeout && !awaitingReclaim || waitedFor >= this.acquireCeilingMs) {
|
|
6885
6884
|
metrics.observe("state_lock_acquire_duration_ms", waitedFor, { status: "timeout" });
|
|
6886
6885
|
metrics.increment("state_lock_acquire_total", 1, { status: "timeout" });
|
|
@@ -17557,7 +17556,7 @@ async function performSearch(queries, config, signal, onProgress, container = ge
|
|
|
17557
17556
|
if (isNativeBindingError(sampleWorkerError)) {
|
|
17558
17557
|
metrics.increment("browser_search_total_failures_total", 1, { cause: "native_binding" });
|
|
17559
17558
|
throw new Error(
|
|
17560
|
-
`Search completely failed: ${reason}, all with a missing native module. This is an incomplete install, not a network problem: the browser engine's native dependencies were never built. npm 12 does not run dependency install scripts by default \u2014 reinstall allowing
|
|
17559
|
+
`Search completely failed: ${reason}, all with a missing native module. This is an incomplete install, not a network problem: the browser engine's native dependencies were never built. npm 12 does not run dependency install scripts by default \u2014 reinstall allowing the script (global install: npm install -g @lincoln504/pi-research --allow-scripts=better-sqlite3; project install: npm approve-scripts better-sqlite3, then npm rebuild better-sqlite3), then retry.` + (sampleWorkerError ? ` Last worker error: ${sampleWorkerError}` : "")
|
|
17561
17560
|
);
|
|
17562
17561
|
}
|
|
17563
17562
|
throw new Error(
|
|
@@ -26753,10 +26752,14 @@ async function cmdStatus(json) {
|
|
|
26753
26752
|
installed: browserInstalled,
|
|
26754
26753
|
nativeDepsOk: nativeDeps.ok,
|
|
26755
26754
|
nativeDepsError: nativeDeps.ok ? null : nativeDeps.error,
|
|
26756
|
-
|
|
26755
|
+
// --allow-scripts is a package-name LIST, not a boolean: the bare flag is
|
|
26756
|
+
// accepted and silently allows nothing (measured on npm 12.0.2). It is
|
|
26757
|
+
// also global/one-off only — a project-scoped install rejects it with
|
|
26758
|
+
// EALLOWSCRIPTS, where `npm approve-scripts` is the supported route.
|
|
26759
|
+
nativeDepsFix: nativeDeps.ok ? null : "Reinstall allowing the dependency install script: npm install -g @lincoln504/pi-research --allow-scripts=better-sqlite3 (npm 12 blocks dependency install scripts by default). For a project-scoped install: npm approve-scripts better-sqlite3, then npm rebuild better-sqlite3.",
|
|
26757
26760
|
// Same remedy the health check prints, so both surfaces name one command.
|
|
26758
26761
|
fix: browserInstalled ? null : "npx camoufox-js fetch",
|
|
26759
|
-
note: browserInstalled ? null : "Stealth browser not installed \u2014 scraping falls back to plain fetch, which some sites block. npm
|
|
26762
|
+
note: browserInstalled ? null : "Stealth browser not installed \u2014 scraping falls back to plain fetch, which some sites block. npm 12 blocks install scripts by default, which skips this package's postinstall; the engine is fetched on first use instead."
|
|
26760
26763
|
},
|
|
26761
26764
|
knowledgeStoreMode: cfg.KNOWLEDGE_STORE_MODE,
|
|
26762
26765
|
defaultDepth: cfg.DEFAULT_RESEARCH_DEPTH,
|
package/docs/AGENT-SKILL.md
CHANGED
|
@@ -21,6 +21,10 @@ 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
|
+
On npm 12 or newer, first run `npm config set allow-scripts=better-sqlite3 --location=user`:
|
|
25
|
+
npm 12 blocks the install script that builds the stealth browser's SQLite module, and
|
|
26
|
+
without it every search fails with a missing-module error (see the [README](../README.md#install)).
|
|
27
|
+
|
|
24
28
|
`skill install` targets only agents already set up under `$HOME`, never overwrites a
|
|
25
29
|
different skill in the slot, and records what it created so `pi-research skill uninstall`
|
|
26
30
|
removes exactly that. Run `pi-research skill status` to see where it is installed.
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,41 @@ 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.6.4] - 2026-08-26
|
|
9
|
+
|
|
10
|
+
The npm 12 install remedy shipped in 1.6.2 was put through real installs in
|
|
11
|
+
disposable npm 12.0.2 containers and found not to work: the bare `--allow-scripts`
|
|
12
|
+
flag every surface recommended is accepted by npm and allows nothing.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- **`status` and the total-search-failure error printed a repair command that repairs nothing.** Measured per npm version against a scripted tarball: npm ≤11.15 runs dependency install scripts silently, 11.16–11.19 warn but still run them, and npm 12 blocks them — so the 1.6.2 claim that "npm 11.19+ blocks" was wrong on version, and the remedy was worse than wrong on form: `--allow-scripts` is a comma-separated package-name list, so the bare flag is accepted and allows nothing — the install stays broken. The flag is also global-install-only: a project-scoped install (the SDK path, and what `pi install` runs underneath) rejects it with `EALLOWSCRIPTS`. And after a blocked install, approving and rerunning `npm install` does not rebuild the already-extracted package. Both surfaces now print commands measured to work — `--allow-scripts=better-sqlite3` for a global install; `npm approve-scripts better-sqlite3` then `npm rebuild better-sqlite3` for a project-scoped one (`src/cli.ts`, `src/web-research/browser-search.ts`).
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- **Install docs lead with the one form measured to cover every install path** — `npm config set allow-scripts=better-sqlite3 --location=user`, verified against a fresh `pi install` and a project install — and the npm 12 note now appears on every surface that shows an install command (README, SDK, agent-skill docs, and the shipped skill README) rather than the README alone, with the wording tightened.
|
|
21
|
+
|
|
22
|
+
### Verified
|
|
23
|
+
|
|
24
|
+
- Each printed command form measured on real installs in npm 12.0.2 containers: the global flag form builds the binding, the user-level config form covers global, project, and `pi install`, and the approve + rebuild flow repairs an already-blocked install.
|
|
25
|
+
- 2938 unit tests over 233 files, lint, and type-check green.
|
|
26
|
+
|
|
27
|
+
## [1.6.3] - 2026-08-25
|
|
28
|
+
|
|
29
|
+
A unit test that had already been granted CI-jitter headroom twice went red a third
|
|
30
|
+
time — and this time the timing signature (rejection 10008ms into a 10000ms window)
|
|
31
|
+
identified a real race in the lock acquire loop rather than a slow runner.
|
|
32
|
+
|
|
33
|
+
### Fixed
|
|
34
|
+
|
|
35
|
+
- **A waiter gave up on a torn lock at the exact moment its reclaim window opened.** The acquire loop's reclaim decision measures the lock's age at `fs.stat` time, but the stall-check exemption that keeps a waiter alive until that reclaim ("never give up on a lock we are about to be allowed to take") compared a fresh `Date.now()` against the window. For the few milliseconds between the stat and the stall check the two clocks could disagree, and a retry tick landing astride the window boundary satisfied neither: not yet reclaimable by its stat, no longer awaited by the clock. Since a torn, pid-less lock never shows progress, the long-expired stall bound then fired, and a wait that had correctly outlasted it was abandoned right as the recovery became permitted — in production, a knowledge-store init failing at the moment it could have recovered. Both judgments now derive from the same observation, so every tick that can read the lock either reclaims it or keeps waiting; the try-take exclusion and the absolute ceiling are unchanged (`src/infrastructure/file-lock-service.ts`).
|
|
36
|
+
- **The test's forensic comment blamed scheduler jitter for all three CI failures.** True for the first two (which failed at the stall bound); wrong for this one (which failed at the window boundary). The record now distinguishes the two mechanisms (`test/unit/infrastructure/file-lock-progress-aware-wait.test.ts`).
|
|
37
|
+
- **A browser-config test deleted the whole suite's shared log directory as its own cleanup.** `unit-env.ts` routes every unit worker's log into `<tmpdir>/pi-research-test/`; the profile-containment test nested its scratch path inside that directory and removed the shared parent recursively — destroying the live log out from under every parallel worker, and racing the lazy logger re-creating the file mid-removal, which is an `ENOTEMPTY` crash of the cleanup itself (seen on macos-latest CI on this release's first tag). The test now creates its own `mkdtemp` directory and removes only that (`test/unit/infrastructure/browser-config.test.ts`).
|
|
38
|
+
|
|
39
|
+
### Verified
|
|
40
|
+
|
|
41
|
+
- 2938 unit tests over 233 files, lint, type-check, and the full CI matrix green on the fix commit — including the ubuntu-latest job that caught the failure.
|
|
42
|
+
|
|
8
43
|
## [1.6.2] - 2026-08-24
|
|
9
44
|
|
|
10
45
|
An agent-skill run reported that every search had failed and concluded it had hit an
|
package/docs/SDK.md
CHANGED
|
@@ -13,6 +13,19 @@ run the `pi` extension, which keeps its own private copy your scripts can't impo
|
|
|
13
13
|
npm install @lincoln504/pi-research
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
On npm 12 or newer, allow the one install script search depends on before installing:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm config set allow-scripts=better-sqlite3 --location=user
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
npm 12 blocks dependency install scripts by default, and a project-scoped install
|
|
23
|
+
rejects the `--allow-scripts` flag — hence the config form. Skipped, the install
|
|
24
|
+
succeeds but every search fails with a missing-module error. To repair an install
|
|
25
|
+
that already ran blocked: `npm approve-scripts better-sqlite3` (pins the approval
|
|
26
|
+
in your project's `allowScripts` field), then `npm rebuild better-sqlite3` —
|
|
27
|
+
rerunning `npm install` does not rebuild the already-extracted package.
|
|
28
|
+
|
|
16
29
|
Then pick the model: pass `model` to `initResearchSDK`, or set `PI_RESEARCH_MODEL`
|
|
17
30
|
(env or `~/.pi/research/config.env`). The SDK never follows the model selected
|
|
18
31
|
inside the pi extension; only when neither is set does it fall back to the first
|
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -793,9 +793,10 @@ async function cmdStatus(json?: boolean): Promise<number> {
|
|
|
793
793
|
const paths = resolvedConfigPaths();
|
|
794
794
|
const cfg = getConfig(process.cwd(), 'cli');
|
|
795
795
|
// The stealth browser is installed by this package's `postinstall`
|
|
796
|
-
// (scripts/setup.cjs), which npm
|
|
797
|
-
//
|
|
798
|
-
//
|
|
796
|
+
// (scripts/setup.cjs), which npm 12 BLOCKS BY DEFAULT (11.16–11.19 only warn
|
|
797
|
+
// and still run it — measured per version against a scripted tarball) — npm
|
|
798
|
+
// prints "packages had install scripts blocked" and carries on, so the
|
|
799
|
+
// browser is simply absent on an otherwise successful install.
|
|
799
800
|
// A missing browser DEGRADES capability rather than breaking the tool — the fetch
|
|
800
801
|
// path still serves most pages — so it is reported alongside `ready` rather than
|
|
801
802
|
// folded into it. isBrowserAvailable() is a resolve + existsSync; it never launches
|
|
@@ -827,14 +828,18 @@ async function cmdStatus(json?: boolean): Promise<number> {
|
|
|
827
828
|
installed: browserInstalled,
|
|
828
829
|
nativeDepsOk: nativeDeps.ok,
|
|
829
830
|
nativeDepsError: nativeDeps.ok ? null : nativeDeps.error,
|
|
831
|
+
// --allow-scripts is a package-name LIST, not a boolean: the bare flag is
|
|
832
|
+
// accepted and silently allows nothing (measured on npm 12.0.2). It is
|
|
833
|
+
// also global/one-off only — a project-scoped install rejects it with
|
|
834
|
+
// EALLOWSCRIPTS, where `npm approve-scripts` is the supported route.
|
|
830
835
|
nativeDepsFix: nativeDeps.ok
|
|
831
836
|
? null
|
|
832
|
-
: 'Reinstall allowing dependency install
|
|
837
|
+
: 'Reinstall allowing the dependency install script: npm install -g @lincoln504/pi-research --allow-scripts=better-sqlite3 (npm 12 blocks dependency install scripts by default). For a project-scoped install: npm approve-scripts better-sqlite3, then npm rebuild better-sqlite3.',
|
|
833
838
|
// Same remedy the health check prints, so both surfaces name one command.
|
|
834
839
|
fix: browserInstalled ? null : 'npx camoufox-js fetch',
|
|
835
840
|
note: browserInstalled
|
|
836
841
|
? null
|
|
837
|
-
: 'Stealth browser not installed — scraping falls back to plain fetch, which some sites block. npm
|
|
842
|
+
: 'Stealth browser not installed — scraping falls back to plain fetch, which some sites block. npm 12 blocks install scripts by default, which skips this package\'s postinstall; the engine is fetched on first use instead.',
|
|
838
843
|
},
|
|
839
844
|
knowledgeStoreMode: cfg.KNOWLEDGE_STORE_MODE,
|
|
840
845
|
defaultDepth: cfg.DEFAULT_RESEARCH_DEPTH,
|
|
@@ -694,12 +694,13 @@ export class FileLockService implements IService {
|
|
|
694
694
|
const errnoError = error as NodeJS.ErrnoException;
|
|
695
695
|
if (errnoError.code === 'EEXIST') {
|
|
696
696
|
contentionCount++;
|
|
697
|
-
//
|
|
698
|
-
//
|
|
697
|
+
// Whether THIS tick judged the contended lock not-yet-eligible for the
|
|
698
|
+
// pid-less reclaim — i.e. we are waiting for a recovery we will be allowed
|
|
699
|
+
// to perform. Scoped per observation: a tick that could not read the lock
|
|
699
700
|
// learned nothing, and an eligibility carried over from an earlier one is
|
|
700
701
|
// no longer evidence of anything. See the stall check below for why the
|
|
701
702
|
// stall bound must not fire before this moment.
|
|
702
|
-
let
|
|
703
|
+
let awaitingReclaim = false;
|
|
703
704
|
// Read lock content to verify ownership and liveness before considering stale
|
|
704
705
|
try {
|
|
705
706
|
const rawContent = await fs.readFile(this.lockFilePath, 'utf-8');
|
|
@@ -720,17 +721,26 @@ export class FileLockService implements IService {
|
|
|
720
721
|
// A lock with no readable pid is judged purely on age (see
|
|
721
722
|
// _shouldReclaim), and its mtime never moves again — so it can never
|
|
722
723
|
// show progress and the stall bound is guaranteed to expire first.
|
|
723
|
-
//
|
|
724
|
-
// stall bound rather than abandoning the recovery at 20s.
|
|
724
|
+
// Mark this tick as awaiting that reclaim so the wait below can outlast
|
|
725
|
+
// the stall bound rather than abandoning the recovery at 20s.
|
|
726
|
+
//
|
|
727
|
+
// Judged from the SAME lockAge observation _shouldReclaim will use, not
|
|
728
|
+
// from a fresh Date.now() at the stall check: the two clocks disagreed
|
|
729
|
+
// for the few ms between the stat and that check, and a tick landing
|
|
730
|
+
// astride the window boundary judged the lock not-yet-reclaimable here
|
|
731
|
+
// yet no-longer-awaited there — giving up at the exact moment the
|
|
732
|
+
// window opened (ubuntu CI, 2026-08-24: rejected 10008ms into a
|
|
733
|
+
// 10000ms window). The complement of _shouldReclaim's strict > means
|
|
734
|
+
// one of the two branches now holds on every readable tick.
|
|
725
735
|
//
|
|
726
736
|
// Deliberately NOT extended to a live owner: there the heartbeat is the
|
|
727
737
|
// designed progress signal, its absence past lockTimeout is real evidence
|
|
728
738
|
// of a wedge, and reporting that to the caller promptly beats waiting out
|
|
729
739
|
// a two-to-four-minute live-owner threshold on a lock we may well never
|
|
730
740
|
// be handed.
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
741
|
+
awaitingReclaim = this.lockTimeout > 0
|
|
742
|
+
&& (parsed?.pid ?? null) === null
|
|
743
|
+
&& lockAge <= this._unidentifiedStaleThreshold();
|
|
734
744
|
|
|
735
745
|
if (lockUuid === this.lockUuid) {
|
|
736
746
|
// This is our own lock — a previous attempt was interrupted. Reclaim.
|
|
@@ -802,8 +812,6 @@ export class FileLockService implements IService {
|
|
|
802
812
|
// on the spot rather than wait for anything, and the run semaphore's slot
|
|
803
813
|
// files carry a TEN-MINUTE unidentified window, so honouring eligibility
|
|
804
814
|
// there would turn "is this slot free right now" into a ten-minute block.
|
|
805
|
-
const awaitingReclaim =
|
|
806
|
-
this.lockTimeout > 0 && reclaimEligibleAt !== null && Date.now() < reclaimEligibleAt;
|
|
807
815
|
if ((stalledFor >= this.lockTimeout && !awaitingReclaim) || waitedFor >= this.acquireCeilingMs) {
|
|
808
816
|
metrics.observe('state_lock_acquire_duration_ms', waitedFor, { status: 'timeout' });
|
|
809
817
|
metrics.increment('state_lock_acquire_total', 1, { status: 'timeout' });
|
|
@@ -333,8 +333,9 @@ export async function performSearch(
|
|
|
333
333
|
`Search completely failed: ${reason}, all with a missing native module. ` +
|
|
334
334
|
`This is an incomplete install, not a network problem: the browser engine's ` +
|
|
335
335
|
`native dependencies were never built. npm 12 does not run dependency install ` +
|
|
336
|
-
`scripts by default — reinstall allowing
|
|
337
|
-
|
|
336
|
+
`scripts by default — reinstall allowing the script (global install: ` +
|
|
337
|
+
`npm install -g @lincoln504/pi-research --allow-scripts=better-sqlite3; ` +
|
|
338
|
+
`project install: npm approve-scripts better-sqlite3, then npm rebuild better-sqlite3), then retry.` +
|
|
338
339
|
(sampleWorkerError ? ` Last worker error: ${sampleWorkerError}` : '')
|
|
339
340
|
);
|
|
340
341
|
}
|