pi-goosedump 0.10.7 → 0.10.9
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 +2 -2
- package/index.ts +62 -13
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -22,8 +22,8 @@ report that they are unavailable.
|
|
|
22
22
|
- **`goose_get`** expands entry IDs returned by `goose_search` or `goose_grep`.
|
|
23
23
|
- **`goose_grep`** filters session messages with a glob pattern.
|
|
24
24
|
- **`goose_recall`** searches memory harvested by earlier compactions. It
|
|
25
|
-
searches the current working directory by default and returns
|
|
26
|
-
with provenance.
|
|
25
|
+
searches the current working directory by default and returns remembered
|
|
26
|
+
excerpts with provenance within a 4,096-byte/token-safe output budget.
|
|
27
27
|
- **`goose_compact`** starts asynchronous compaction of the current Pi session.
|
|
28
28
|
Set `keep` to preserve the last N user turns verbatim.
|
|
29
29
|
|
package/index.ts
CHANGED
|
@@ -78,6 +78,13 @@ interface GoosedumpMemoryHit {
|
|
|
78
78
|
source_path: string;
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
+
const RECALL_TOKEN_BUDGET = 4096;
|
|
82
|
+
// Every non-empty token occupies at least one UTF-8 byte, so this byte cap is
|
|
83
|
+
// also a conservative hard cap on the number of tokens returned to Pi.
|
|
84
|
+
const RECALL_MAX_BYTES = RECALL_TOKEN_BUDGET;
|
|
85
|
+
const MEMORY_HIT_SEPARATOR = '\n\n---\n\n';
|
|
86
|
+
const MEMORY_TEXT_TRUNCATED = '\n[Entry text truncated]';
|
|
87
|
+
|
|
81
88
|
// A `content` part of a pi-native message line.
|
|
82
89
|
interface PiPartJson {
|
|
83
90
|
type: string;
|
|
@@ -395,13 +402,44 @@ function parseMemoryHits(output: string): GoosedumpMemoryHit[] {
|
|
|
395
402
|
);
|
|
396
403
|
}
|
|
397
404
|
|
|
398
|
-
function
|
|
399
|
-
|
|
400
|
-
.
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
+
function formatMemoryHit(hit: GoosedumpMemoryHit, maxBytes: number): string {
|
|
406
|
+
const provenance =
|
|
407
|
+
`[${hit.hash}] ${hit.kind} (${hit.provider}:${hit.context_id}/${hit.entry_id})\n` +
|
|
408
|
+
`Working directory: ${hit.path}\nSource: ${hit.source_path}\n`;
|
|
409
|
+
const full = `${provenance}${hit.text}`;
|
|
410
|
+
if (Buffer.byteLength(full) <= maxBytes) return full;
|
|
411
|
+
|
|
412
|
+
const provenanceBytes = Buffer.byteLength(provenance);
|
|
413
|
+
const markerBytes = Buffer.byteLength(MEMORY_TEXT_TRUNCATED);
|
|
414
|
+
if (provenanceBytes + markerBytes >= maxBytes) return utf8Prefix(provenance, maxBytes);
|
|
415
|
+
|
|
416
|
+
const textBytes = maxBytes - provenanceBytes - markerBytes;
|
|
417
|
+
return `${provenance}${utf8Prefix(hit.text, textBytes)}${MEMORY_TEXT_TRUNCATED}`;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
function formatMemoryHits(hits: GoosedumpMemoryHit[], maxBytes = RECALL_MAX_BYTES): string {
|
|
421
|
+
const formatted: string[] = [];
|
|
422
|
+
let remainingBytes = maxBytes;
|
|
423
|
+
const separatorBytes = Buffer.byteLength(MEMORY_HIT_SEPARATOR);
|
|
424
|
+
|
|
425
|
+
for (let index = 0; index < hits.length; index += 1) {
|
|
426
|
+
if (index > 0) {
|
|
427
|
+
if (remainingBytes < separatorBytes) break;
|
|
428
|
+
formatted.push(MEMORY_HIT_SEPARATOR);
|
|
429
|
+
remainingBytes -= separatorBytes;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
const remainingHits = hits.length - index;
|
|
433
|
+
const futureSeparators = separatorBytes * (remainingHits - 1);
|
|
434
|
+
const hitBytes = Math.floor((remainingBytes - futureSeparators) / remainingHits);
|
|
435
|
+
if (hitBytes <= 0) break;
|
|
436
|
+
|
|
437
|
+
const hit = formatMemoryHit(hits[index], hitBytes);
|
|
438
|
+
formatted.push(hit);
|
|
439
|
+
remainingBytes -= Buffer.byteLength(hit);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
return formatted.join('');
|
|
405
443
|
}
|
|
406
444
|
|
|
407
445
|
const ANSI_SGR = new RegExp(String.fromCharCode(27) + '\\[[0-9;]*m', 'g');
|
|
@@ -461,10 +499,14 @@ function runGoosedump(args: string[]): string {
|
|
|
461
499
|
// Non-blocking variant for the compact path: goosedump compact runs an ML
|
|
462
500
|
// model and can take many seconds, so execFileSync would freeze Pi's event
|
|
463
501
|
// loop (and its compaction spinner). execFile keeps the loop free to render.
|
|
464
|
-
function runGoosedumpAsync(
|
|
502
|
+
function runGoosedumpAsync(
|
|
503
|
+
args: string[],
|
|
504
|
+
signal?: AbortSignal,
|
|
505
|
+
executablePath = resolveNativeGoosedumpBinary(),
|
|
506
|
+
): Promise<GoosedumpCommandOutput> {
|
|
465
507
|
return new Promise((resolve, reject) => {
|
|
466
508
|
execFile(
|
|
467
|
-
|
|
509
|
+
executablePath,
|
|
468
510
|
args,
|
|
469
511
|
{
|
|
470
512
|
encoding: 'utf-8',
|
|
@@ -542,11 +584,12 @@ async function goosedumpRecall(
|
|
|
542
584
|
query: string,
|
|
543
585
|
options: { provider?: string; path?: string; limit?: number } = {},
|
|
544
586
|
signal?: AbortSignal,
|
|
587
|
+
executablePath?: string,
|
|
545
588
|
): Promise<{ hits: GoosedumpMemoryHit[]; warning: string }> {
|
|
546
589
|
const args = ['recall', query, '--limit', String(options.limit ?? 5)];
|
|
547
590
|
if (options.provider) args.push('--provider', options.provider);
|
|
548
591
|
if (options.path) args.push('--path', options.path);
|
|
549
|
-
const output = await runGoosedumpAsync(args, signal);
|
|
592
|
+
const output = await runGoosedumpAsync(args, signal, executablePath);
|
|
550
593
|
return { hits: parseMemoryHits(output.stdout), warning: output.stderr.trim() };
|
|
551
594
|
}
|
|
552
595
|
|
|
@@ -604,13 +647,14 @@ async function goosedumpCompact(
|
|
|
604
647
|
target: string,
|
|
605
648
|
options: { scope?: string; from?: string; until: string },
|
|
606
649
|
signal?: AbortSignal,
|
|
650
|
+
executablePath?: string,
|
|
607
651
|
): Promise<{ summary: string; warning: string }> {
|
|
608
652
|
const scope = options.scope ?? 'lineage';
|
|
609
653
|
const args = ['compact', target, '--scope', scope];
|
|
610
654
|
if (options.from) args.push('--from', options.from);
|
|
611
655
|
args.push('--until', options.until);
|
|
612
656
|
|
|
613
|
-
const output = await runGoosedumpAsync(args, signal);
|
|
657
|
+
const output = await runGoosedumpAsync(args, signal, executablePath);
|
|
614
658
|
for (const line of output.stdout.split('\n')) {
|
|
615
659
|
if (!line) continue;
|
|
616
660
|
try {
|
|
@@ -628,6 +672,7 @@ async function goosedumpCompact(
|
|
|
628
672
|
export interface GoosedumpIntegrationOptions {
|
|
629
673
|
registerTool?: boolean;
|
|
630
674
|
overrideDefaultCompaction?: boolean;
|
|
675
|
+
nativeExecutablePath?: string;
|
|
631
676
|
}
|
|
632
677
|
|
|
633
678
|
interface GoosedumpCompactRange {
|
|
@@ -930,6 +975,7 @@ async function buildGoosedumpCompaction(
|
|
|
930
975
|
reserveTokens: number,
|
|
931
976
|
keep?: number,
|
|
932
977
|
signal?: AbortSignal,
|
|
978
|
+
executablePath?: string,
|
|
933
979
|
): Promise<
|
|
934
980
|
CompactionResult<GoosedumpCompactionDetails> | { cancel: true; reason: string } | undefined
|
|
935
981
|
> {
|
|
@@ -947,7 +993,7 @@ async function buildGoosedumpCompaction(
|
|
|
947
993
|
const range = buildCompactRange(branchEntries, firstKeptEntryId);
|
|
948
994
|
if (!range) return undefined;
|
|
949
995
|
|
|
950
|
-
const generated = await goosedumpCompact(target, range, signal);
|
|
996
|
+
const generated = await goosedumpCompact(target, range, signal, executablePath);
|
|
951
997
|
if (!generated.summary) return undefined;
|
|
952
998
|
const summary = mergeCompactionSummary(
|
|
953
999
|
preparation.previousSummary,
|
|
@@ -1426,6 +1472,7 @@ export function createGoosedumpIntegration(
|
|
|
1426
1472
|
): GoosedumpIntegration {
|
|
1427
1473
|
const shouldRegisterTool = options.registerTool ?? true;
|
|
1428
1474
|
const shouldOverrideDefaultCompaction = options.overrideDefaultCompaction ?? true;
|
|
1475
|
+
const nativeExecutablePath = options.nativeExecutablePath;
|
|
1429
1476
|
|
|
1430
1477
|
let goosedumpAvailable = false;
|
|
1431
1478
|
let compactSettings = DEFAULT_GOOSEDUMP_SETTINGS;
|
|
@@ -1510,7 +1557,7 @@ export function createGoosedumpIntegration(
|
|
|
1510
1557
|
name: 'goose_recall',
|
|
1511
1558
|
label: 'goose_recall',
|
|
1512
1559
|
description:
|
|
1513
|
-
'Recall durable context harvested from earlier compactions. Searches the current project by default and returns
|
|
1560
|
+
'Recall durable context harvested from earlier compactions. Searches the current project by default and returns bounded remembered excerpts with provenance.',
|
|
1514
1561
|
promptSnippet: 'Recall durable context from earlier sessions',
|
|
1515
1562
|
promptGuidelines: [
|
|
1516
1563
|
'Use goose_recall for decisions, evidence, and context that may have disappeared from the current session.',
|
|
@@ -1553,6 +1600,7 @@ export function createGoosedumpIntegration(
|
|
|
1553
1600
|
limit: params.limit,
|
|
1554
1601
|
},
|
|
1555
1602
|
signal,
|
|
1603
|
+
nativeExecutablePath,
|
|
1556
1604
|
);
|
|
1557
1605
|
if (warning && ctx.hasUI) ctx.ui.notify(warning, 'warning');
|
|
1558
1606
|
if (hits.length === 0) return textResult(`No durable memory for "${params.query}"`);
|
|
@@ -1842,6 +1890,7 @@ export function createGoosedumpIntegration(
|
|
|
1842
1890
|
piReserveTokens(ctx.cwd),
|
|
1843
1891
|
keep,
|
|
1844
1892
|
event.signal,
|
|
1893
|
+
nativeExecutablePath,
|
|
1845
1894
|
);
|
|
1846
1895
|
if (compaction && 'cancel' in compaction) {
|
|
1847
1896
|
if (ctx.hasUI) ctx.ui.notify(compaction.reason, 'info');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-goosedump",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.9",
|
|
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.10.
|
|
36
|
+
"@jarkkojs/goosedump": "^0.10.9",
|
|
37
37
|
"@sinclair/typebox": "^0.34.49"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|