pi-goosedump 0.10.3 → 0.10.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/README.md +54 -74
- package/index.ts +30 -14
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,69 +1,62 @@
|
|
|
1
1
|
# pi-goosedump
|
|
2
2
|
|
|
3
|
-
`pi-goosedump`
|
|
4
|
-
entry expansion, and compaction
|
|
5
|
-
prefix
|
|
6
|
-
summaries.
|
|
3
|
+
`pi-goosedump` adds goosedump-backed session-history search, durable-memory
|
|
4
|
+
recall, entry expansion, and compaction to Pi. Its tools use the `goose_`
|
|
5
|
+
prefix.
|
|
7
6
|
|
|
8
|
-
##
|
|
7
|
+
## Install
|
|
9
8
|
|
|
10
|
-
```
|
|
9
|
+
```sh
|
|
11
10
|
pi install npm:pi-goosedump
|
|
12
11
|
```
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
and
|
|
17
|
-
|
|
13
|
+
The package installs `@jarkkojs/goosedump`, including native binaries for Linux
|
|
14
|
+
x64, macOS arm64, and Windows x64. If no compatible binary is available, the
|
|
15
|
+
extension keeps Pi's normal compaction behavior and its goosedump features
|
|
16
|
+
report that they are unavailable.
|
|
18
17
|
|
|
19
18
|
## Tools
|
|
20
19
|
|
|
21
|
-
-
|
|
22
|
-
|
|
23
|
-
-
|
|
24
|
-
|
|
25
|
-
-
|
|
26
|
-
|
|
27
|
-
with
|
|
28
|
-
-
|
|
29
|
-
the last N user turns verbatim
|
|
30
|
-
|
|
31
|
-
The read tools (`goose_search`, `goose_get`, `goose_grep`) each accept an
|
|
32
|
-
optional `provider` (default `pi`; also `claude`, `codex`, `crush`, `gemini`,
|
|
33
|
-
`goose`, `opencode`) and `session` id. `session` defaults to the current Pi
|
|
34
|
-
session for `pi` and is required otherwise. `scope` is `lineage` (default,
|
|
35
|
-
current branch) or `all`. Targets are always provider-qualified
|
|
36
|
-
(`provider:id`); a bare id is never sent to goosedump.
|
|
20
|
+
- **`goose_search`** ranks session messages and returns compact overviews with
|
|
21
|
+
entry IDs.
|
|
22
|
+
- **`goose_get`** expands entry IDs returned by `goose_search` or `goose_grep`.
|
|
23
|
+
- **`goose_grep`** filters session messages with a glob pattern.
|
|
24
|
+
- **`goose_recall`** searches memory harvested by earlier compactions. It
|
|
25
|
+
searches the current working directory by default and returns full entries
|
|
26
|
+
with provenance.
|
|
27
|
+
- **`goose_compact`** starts asynchronous compaction of the current Pi session.
|
|
28
|
+
Set `keep` to preserve the last N user turns verbatim.
|
|
37
29
|
|
|
38
|
-
|
|
30
|
+
The session-history tools accept an optional `provider` (`pi` by default),
|
|
31
|
+
`session`, and `scope` (`lineage` by default or `all`). The current Pi session
|
|
32
|
+
is used when both provider and session are omitted. Non-Pi providers require an
|
|
33
|
+
explicit session ID. Targets sent to goosedump are always provider-qualified.
|
|
34
|
+
|
|
35
|
+
Examples:
|
|
36
|
+
|
|
37
|
+
```text
|
|
39
38
|
goose_search({ query: "bug fix" })
|
|
40
|
-
goose_recall({ query: "prior architecture decision" })
|
|
41
39
|
goose_search({ query: "auth", scope: "all", page: 2 })
|
|
42
40
|
goose_get({ ids: ["entry-a", "entry-b"] })
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
goose_grep({ pattern: "*timeout*" })
|
|
42
|
+
goose_recall({ query: "prior architecture decision" })
|
|
45
43
|
goose_compact({ keep: 2 })
|
|
46
44
|
```
|
|
47
45
|
|
|
48
46
|
## Commands
|
|
49
47
|
|
|
50
|
-
- **`/goose-search [query]
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
summarized; with no argument goosedump summarizes up to Pi's token-based cut.
|
|
56
|
-
- **`/goose-settings`:** edit the global and project compaction settings.
|
|
48
|
+
- **`/goose-search [query]`** searches the current session. A bare command opens
|
|
49
|
+
an inline prompt; selecting a result expands it.
|
|
50
|
+
- **`/goose-compact [keep:N]`** compacts now. With `keep:N`, the last N user
|
|
51
|
+
turns remain verbatim; without it, Pi chooses the cut point.
|
|
52
|
+
- **`/goose-settings`** edits global and project compaction settings.
|
|
57
53
|
|
|
58
54
|
## Settings
|
|
59
55
|
|
|
60
|
-
|
|
56
|
+
Optional settings live under `goosedump` in:
|
|
61
57
|
|
|
62
|
-
- `~/.pi/agent/settings.json`
|
|
63
|
-
- `.pi/settings.json`
|
|
64
|
-
|
|
65
|
-
Project settings override global settings. All settings live in a `goosedump`
|
|
66
|
-
section and are optional (defaults shown):
|
|
58
|
+
- `~/.pi/agent/settings.json` for global settings.
|
|
59
|
+
- `.pi/settings.json` for project overrides.
|
|
67
60
|
|
|
68
61
|
```json
|
|
69
62
|
{
|
|
@@ -73,37 +66,24 @@ section and are optional (defaults shown):
|
|
|
73
66
|
}
|
|
74
67
|
```
|
|
75
68
|
|
|
76
|
-
`turnsBeforeCompact`
|
|
77
|
-
compaction
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
summary starts where the previous one left off); omitted on the first
|
|
94
|
-
compaction.
|
|
95
|
-
- `--until` is the first entry Pi is keeping (`firstKeptEntryId`).
|
|
96
|
-
|
|
97
|
-
goosedump composes the structured summary itself and emits a native Pi
|
|
98
|
-
compaction entry, from which the extension extracts the `summary` field. The
|
|
99
|
-
extension prepends Pi's previous compaction summary when present, so prior goals,
|
|
100
|
-
progress, and context survive incremental compactions. A `keep:N` override (via
|
|
101
|
-
`/goose-compact` or the `goose_compact` tool) replaces Pi's token-based cut with
|
|
102
|
-
a turn-based one: summarize everything before the Nth-from-last user entry in the
|
|
103
|
-
active, uncompacted history and keep the tail verbatim. Fewer than N active user
|
|
104
|
-
turns cancels with a notice. On completion Pi notifies the token reduction.
|
|
69
|
+
`turnsBeforeCompact` is an integer from 0 to 255. `0` disables scheduled
|
|
70
|
+
compaction. The countdown is restored when a session resumes and appears in the
|
|
71
|
+
footer as hexadecimal: `GD: 0A` means ten turns remain, `GD: 00` is ready to
|
|
72
|
+
compact, and `GD: --` is disabled. Clearing the project value restores the
|
|
73
|
+
global setting.
|
|
74
|
+
|
|
75
|
+
## Compaction behavior
|
|
76
|
+
|
|
77
|
+
The extension replaces Pi's normal summary during manual, scheduled, and
|
|
78
|
+
automatic compaction. It preserves the previous compaction summary and asks
|
|
79
|
+
goosedump to summarize only the newly compacted range. A `keep:N` request
|
|
80
|
+
instead keeps the last N active user turns; it is cancelled when no earlier
|
|
81
|
+
history is available to summarize.
|
|
82
|
+
|
|
83
|
+
Compactions with custom instructions continue to use Pi's normal compactor. If
|
|
84
|
+
goosedump fails, the extension reports the error and falls back to Pi. Successful
|
|
85
|
+
compactions report memory-learning warnings without discarding the summary.
|
|
105
86
|
|
|
106
87
|
## License
|
|
107
88
|
|
|
108
|
-
`pi-goosedump` is licensed under `Apache-2.0`. See [LICENSE](LICENSE)
|
|
109
|
-
information.
|
|
89
|
+
`pi-goosedump` is licensed under `Apache-2.0`. See [LICENSE](LICENSE).
|
package/index.ts
CHANGED
|
@@ -58,6 +58,11 @@ interface GoosedumpMessage {
|
|
|
58
58
|
content: string;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
interface GoosedumpCommandOutput {
|
|
62
|
+
stdout: string;
|
|
63
|
+
stderr: string;
|
|
64
|
+
}
|
|
65
|
+
|
|
61
66
|
interface GoosedumpMemoryHit {
|
|
62
67
|
hash: string;
|
|
63
68
|
kind: string;
|
|
@@ -67,6 +72,7 @@ interface GoosedumpMemoryHit {
|
|
|
67
72
|
context_id: string;
|
|
68
73
|
entry_id: string;
|
|
69
74
|
path: string;
|
|
75
|
+
source_path: string;
|
|
70
76
|
}
|
|
71
77
|
|
|
72
78
|
// A `content` part of a pi-native message line.
|
|
@@ -324,7 +330,8 @@ function parseMemoryHits(output: string): GoosedumpMemoryHit[] {
|
|
|
324
330
|
typeof item.provider === 'string' &&
|
|
325
331
|
typeof item.context_id === 'string' &&
|
|
326
332
|
typeof item.entry_id === 'string' &&
|
|
327
|
-
typeof item.path === 'string'
|
|
333
|
+
typeof item.path === 'string' &&
|
|
334
|
+
typeof item.source_path === 'string',
|
|
328
335
|
);
|
|
329
336
|
}
|
|
330
337
|
|
|
@@ -332,7 +339,7 @@ function formatMemoryHits(hits: GoosedumpMemoryHit[]): string {
|
|
|
332
339
|
return hits
|
|
333
340
|
.map(
|
|
334
341
|
(hit) =>
|
|
335
|
-
`[${hit.hash}] ${hit.kind} (${hit.provider}:${hit.context_id}/${hit.entry_id})\n${hit.text}`,
|
|
342
|
+
`[${hit.hash}] ${hit.kind} (${hit.provider}:${hit.context_id}/${hit.entry_id})\nWorking directory: ${hit.path}\nSource: ${hit.source_path}\n${hit.text}`,
|
|
336
343
|
)
|
|
337
344
|
.join('\n\n---\n\n');
|
|
338
345
|
}
|
|
@@ -394,7 +401,7 @@ function runGoosedump(args: string[]): string {
|
|
|
394
401
|
// Non-blocking variant for the compact path: goosedump compact runs an ML
|
|
395
402
|
// model and can take many seconds, so execFileSync would freeze Pi's event
|
|
396
403
|
// loop (and its compaction spinner). execFile keeps the loop free to render.
|
|
397
|
-
function runGoosedumpAsync(args: string[], signal?: AbortSignal): Promise<
|
|
404
|
+
function runGoosedumpAsync(args: string[], signal?: AbortSignal): Promise<GoosedumpCommandOutput> {
|
|
398
405
|
return new Promise((resolve, reject) => {
|
|
399
406
|
execFile(
|
|
400
407
|
process.execPath,
|
|
@@ -409,7 +416,7 @@ function runGoosedumpAsync(args: string[], signal?: AbortSignal): Promise<string
|
|
|
409
416
|
const message = stderr.trim() || err.message;
|
|
410
417
|
reject(new Error(message));
|
|
411
418
|
} else {
|
|
412
|
-
resolve(stdout);
|
|
419
|
+
resolve({ stdout, stderr });
|
|
413
420
|
}
|
|
414
421
|
},
|
|
415
422
|
);
|
|
@@ -475,12 +482,12 @@ async function goosedumpRecall(
|
|
|
475
482
|
query: string,
|
|
476
483
|
options: { provider?: string; path?: string; limit?: number } = {},
|
|
477
484
|
signal?: AbortSignal,
|
|
478
|
-
): Promise<GoosedumpMemoryHit[]> {
|
|
485
|
+
): Promise<{ hits: GoosedumpMemoryHit[]; warning: string }> {
|
|
479
486
|
const args = ['recall', query, '--limit', String(options.limit ?? 5)];
|
|
480
487
|
if (options.provider) args.push('--provider', options.provider);
|
|
481
488
|
if (options.path) args.push('--path', options.path);
|
|
482
489
|
const output = await runGoosedumpAsync(args, signal);
|
|
483
|
-
return parseMemoryHits(output);
|
|
490
|
+
return { hits: parseMemoryHits(output.stdout), warning: output.stderr.trim() };
|
|
484
491
|
}
|
|
485
492
|
|
|
486
493
|
// Resolve a goosedump 0.9 `provider:id` target. An explicit contextId is the
|
|
@@ -537,23 +544,25 @@ async function goosedumpCompact(
|
|
|
537
544
|
target: string,
|
|
538
545
|
options: { scope?: string; from?: string; until: string },
|
|
539
546
|
signal?: AbortSignal,
|
|
540
|
-
): Promise<string> {
|
|
547
|
+
): Promise<{ summary: string; warning: string }> {
|
|
541
548
|
const scope = options.scope ?? 'lineage';
|
|
542
549
|
const args = ['compact', target, '--scope', scope];
|
|
543
550
|
if (options.from) args.push('--from', options.from);
|
|
544
551
|
args.push('--until', options.until);
|
|
545
552
|
|
|
546
553
|
const output = await runGoosedumpAsync(args, signal);
|
|
547
|
-
for (const line of output.split('\n')) {
|
|
554
|
+
for (const line of output.stdout.split('\n')) {
|
|
548
555
|
if (!line) continue;
|
|
549
556
|
try {
|
|
550
557
|
const entry = JSON.parse(line) as PiEntryJson;
|
|
551
|
-
if (entry.type === 'compaction' && typeof entry.summary === 'string')
|
|
558
|
+
if (entry.type === 'compaction' && typeof entry.summary === 'string') {
|
|
559
|
+
return { summary: entry.summary, warning: output.stderr.trim() };
|
|
560
|
+
}
|
|
552
561
|
} catch {
|
|
553
562
|
continue;
|
|
554
563
|
}
|
|
555
564
|
}
|
|
556
|
-
return output.trim();
|
|
565
|
+
return { summary: output.stdout.trim(), warning: output.stderr.trim() };
|
|
557
566
|
}
|
|
558
567
|
|
|
559
568
|
export interface GoosedumpIntegrationOptions {
|
|
@@ -574,6 +583,7 @@ interface GoosedumpCompactionDetails {
|
|
|
574
583
|
from?: string;
|
|
575
584
|
until: string;
|
|
576
585
|
fileOps: unknown;
|
|
586
|
+
warning?: string;
|
|
577
587
|
}
|
|
578
588
|
|
|
579
589
|
export interface GoosedumpIntegration {
|
|
@@ -789,9 +799,9 @@ async function buildGoosedumpCompaction(
|
|
|
789
799
|
const range = buildCompactRange(branchEntries, firstKeptEntryId);
|
|
790
800
|
if (!range) return undefined;
|
|
791
801
|
|
|
792
|
-
const
|
|
793
|
-
if (!
|
|
794
|
-
const summary = mergeCompactionSummary(preparation.previousSummary,
|
|
802
|
+
const generated = await goosedumpCompact(target, range, signal);
|
|
803
|
+
if (!generated.summary) return undefined;
|
|
804
|
+
const summary = mergeCompactionSummary(preparation.previousSummary, generated.summary);
|
|
795
805
|
|
|
796
806
|
return {
|
|
797
807
|
summary,
|
|
@@ -804,6 +814,7 @@ async function buildGoosedumpCompaction(
|
|
|
804
814
|
from: range.from,
|
|
805
815
|
until: range.until,
|
|
806
816
|
fileOps: preparation.fileOps,
|
|
817
|
+
warning: generated.warning || undefined,
|
|
807
818
|
},
|
|
808
819
|
};
|
|
809
820
|
}
|
|
@@ -1390,7 +1401,7 @@ export function createGoosedumpIntegration(
|
|
|
1390
1401
|
async execute(_id, params, signal, _onUpdate, ctx): Promise<AgentToolResult<void>> {
|
|
1391
1402
|
if (!goosedumpAvailable) return goosedumpUnavailableResult();
|
|
1392
1403
|
try {
|
|
1393
|
-
const hits = await goosedumpRecall(
|
|
1404
|
+
const { hits, warning } = await goosedumpRecall(
|
|
1394
1405
|
params.query,
|
|
1395
1406
|
{
|
|
1396
1407
|
provider: params.provider,
|
|
@@ -1399,6 +1410,7 @@ export function createGoosedumpIntegration(
|
|
|
1399
1410
|
},
|
|
1400
1411
|
signal,
|
|
1401
1412
|
);
|
|
1413
|
+
if (warning && ctx.hasUI) ctx.ui.notify(warning, 'warning');
|
|
1402
1414
|
if (hits.length === 0) return textResult(`No durable memory for "${params.query}"`);
|
|
1403
1415
|
return textResult(formatMemoryHits(hits));
|
|
1404
1416
|
} catch (err) {
|
|
@@ -1680,6 +1692,10 @@ export function createGoosedumpIntegration(
|
|
|
1680
1692
|
if (ctx.hasUI) ctx.ui.notify(compaction.reason, 'info');
|
|
1681
1693
|
return { cancel: true };
|
|
1682
1694
|
}
|
|
1695
|
+
const warning = compaction?.details?.warning;
|
|
1696
|
+
if (warning && ctx.hasUI) {
|
|
1697
|
+
ctx.ui.notify(warning, 'warning');
|
|
1698
|
+
}
|
|
1683
1699
|
return compaction ? { compaction } : undefined;
|
|
1684
1700
|
} catch (err) {
|
|
1685
1701
|
if (event.signal.aborted) return { cancel: true };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-goosedump",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.5",
|
|
4
4
|
"description": "Pi extension for goosedump-backed session-history search, entry expansion, and compaction",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"compaction",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@earendil-works/pi-tui": "^0.78.0",
|
|
36
|
-
"@jarkkojs/goosedump": "^0.
|
|
36
|
+
"@jarkkojs/goosedump": "^0.10.5",
|
|
37
37
|
"@sinclair/typebox": "^0.34.49"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|