@pratikgajjar/pi-recall 0.1.1 → 0.2.2

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 CHANGED
@@ -8,23 +8,25 @@ It's a thin wrapper over the [`recall`](https://github.com/pratikgajjar/recall)
8
8
 
9
9
  _The agent calls `recall_search` to find a past conversation, then reads it in full with `recall_transcript` — no copy-paste._
10
10
 
11
- ## Prerequisites
12
-
13
- Install the `recall` CLI and build its index once:
11
+ ## Install
14
12
 
15
13
  ```bash
16
- go install github.com/pratikgajjar/recall@latest
17
- recall index # one-time, ~1 minute on real data
18
- recall doctor # confirm sources are detected
14
+ pi install npm:@pratikgajjar/pi-recall
19
15
  ```
20
16
 
21
- ## Install
17
+ The prebuilt `recall` binary for your platform ships inside the package, so
18
+ `pi install` / `pi update` keep the extension **and** the binary in lockstep —
19
+ no separate `go install` or `brew`. The extension resolves the binary in this
20
+ order: `--recall-bin` flag -> `RECALL_BIN` env -> bundled binary -> `recall` on `PATH`.
21
+
22
+ Then build the index once:
22
23
 
23
24
  ```bash
24
- pi install npm:@pratikgajjar/pi-recall
25
+ recall index # one-time, ~1 minute on real data
26
+ recall doctor # confirm sources are detected
25
27
  ```
26
28
 
27
- Or, for local development, drop it in `.pi/extensions/` or load it ad-hoc:
29
+ For local development, load the extension ad-hoc:
28
30
 
29
31
  ```bash
30
32
  pi -e ./packages/pi-recall/src/index.ts
@@ -43,13 +45,18 @@ All tools accept `repo` (pass `"."` for the current project), `source` (`cursor`
43
45
 
44
46
  ### Navigating large sessions
45
47
 
46
- Some sessions are huge (thousands of messages). `recall_transcript` takes two
47
- extra params to slice instead of dumping everything:
48
+ Some sessions are huge (thousands of messages). `recall_transcript` takes
49
+ three extra params to slice instead of dumping everything:
48
50
 
49
51
  - `range` — Python-style slice over the message list: `":100"` first 100,
50
52
  `"-50:"` last 50, `"305:315"` window. Negative indices count from the end.
51
53
  - `outline` — one line per message: `[N] role: first-line`. A cheap table of
52
54
  contents you can scan before slicing in.
55
+ - `role` — comma-separated allowlist: `"user,assistant"` (skip tool noise),
56
+ `"user"` (just the prompts), `"tool"`. Tool-related labels (`toolResult`,
57
+ `toolCall`, `function_call`, …) all collapse to `tool`. In long agent loops,
58
+ ~50% of messages are tool noise; in some, 98% — a 30k-msg session shrinks to
59
+ ~600 with `role="user"`.
53
60
 
54
61
  Every rendered message carries its own `## msg N/TOTAL role` header so any
55
62
  slice is self-locating. **Default-cap:** if a session has more than 200
Binary file
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pratikgajjar/pi-recall",
3
- "version": "0.1.1",
3
+ "version": "0.2.2",
4
4
  "description": "pi extension: search your past AI chat history (Cursor, Claude Code, Codex, pi) via the recall CLI",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -33,7 +33,8 @@
33
33
  "image": "https://raw.githubusercontent.com/pratikgajjar/recall/main/packages/pi-recall/assets/demo.png"
34
34
  },
35
35
  "files": [
36
- "src"
36
+ "src",
37
+ "bin"
37
38
  ],
38
39
  "publishConfig": {
39
40
  "access": "public"
package/src/index.ts CHANGED
@@ -8,11 +8,33 @@
8
8
  */
9
9
 
10
10
  import { execFile } from "node:child_process";
11
+ import { chmodSync, existsSync, statSync } from "node:fs";
11
12
  import { homedir } from "node:os";
13
+ import { dirname, join } from "node:path";
14
+ import { fileURLToPath } from "node:url";
12
15
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
13
16
  import { Text } from "@earendil-works/pi-tui";
14
17
  import { Type } from "typebox";
15
18
 
19
+ // Resolve the prebuilt binary bundled in this package's bin/ directory. The
20
+ // release pipeline drops one binary per platform (recall-<os>-<arch>); we pick
21
+ // the one matching the host. Returns undefined when none is present (e.g. a
22
+ // source checkout), so the caller falls back to `recall` on PATH.
23
+ function resolveBundledBin(): string | undefined {
24
+ const name = `recall-${process.platform}-${process.arch}`;
25
+ const binPath = join(dirname(fileURLToPath(import.meta.url)), "..", "bin", name);
26
+ if (!existsSync(binPath)) return undefined;
27
+ // npm has historically lost the +x bit on extracted tarball binaries;
28
+ // restore it best-effort so the first call succeeds.
29
+ try {
30
+ const mode = statSync(binPath).mode;
31
+ if (!(mode & 0o111)) chmodSync(binPath, 0o755);
32
+ } catch {
33
+ /* best effort */
34
+ }
35
+ return binPath;
36
+ }
37
+
16
38
  const DEFAULT_SEARCH_LIMIT = 15;
17
39
  const DEFAULT_SESSIONS_LIMIT = 20;
18
40
  const DEFAULT_RELATED_LIMIT = 10;
@@ -89,11 +111,12 @@ export default function recallExtension(pi: ExtensionAPI) {
89
111
  }
90
112
 
91
113
  function resolveBin(): string {
92
- return (
93
- (pi.getFlag("recall-bin") as string | undefined) ??
94
- process.env.RECALL_BIN ??
95
- "recall"
96
- );
114
+ // Precedence: explicit flag -> env override -> binary bundled in this
115
+ // package's bin/ (shipped by the release pipeline) -> `recall` on PATH.
116
+ const flag = pi.getFlag("recall-bin") as string | undefined;
117
+ if (flag) return flag;
118
+ if (process.env.RECALL_BIN) return process.env.RECALL_BIN;
119
+ return resolveBundledBin() ?? "recall";
97
120
  }
98
121
 
99
122
  function runRecall(args: string[], signal?: AbortSignal): Promise<RunResult> {
@@ -350,6 +373,12 @@ export default function recallExtension(pi: ExtensionAPI) {
350
373
  "One line per message ([N] role: first-line). Use to navigate a large session before slicing in with 'range'.",
351
374
  }),
352
375
  ),
376
+ role: Type.Optional(
377
+ Type.String({
378
+ description:
379
+ "Comma-separated roles to keep: 'user', 'assistant', 'tool'. Tool-related roles (toolResult, toolCall, function_call, etc.) collapse to 'tool'. Use 'user,assistant' to skip tool noise (~50% of long agent loops are tool messages).",
380
+ }),
381
+ ),
353
382
  });
354
383
 
355
384
  // Above this many messages, recall_transcript called without 'range' or
@@ -384,10 +413,11 @@ export default function recallExtension(pi: ExtensionAPI) {
384
413
  });
385
414
  const cmd = params.session_id ? ["show", params.session_id] : ["last", ...filterArgs];
386
415
 
387
- // Honor an explicit slice as-is.
388
- if (params.range || params.outline) {
416
+ // Honor an explicit slice as-is (range / outline / role all count).
417
+ if (params.range || params.outline || params.role) {
389
418
  if (params.range) cmd.push("--range", params.range);
390
419
  if (params.outline) cmd.push("--outline");
420
+ if (params.role) cmd.push("--role", params.role);
391
421
  const res = await runRecall(cmd, signal);
392
422
  if (!res.ok) {
393
423
  const msg = res.stderr || res.stdout.trim() || `recall exited with code ${res.code}`;