pi-goosedump 0.2.2 → 0.3.1
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 +3 -0
- package/index.ts +89 -10
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -12,6 +12,9 @@ pi install npm:pi-goosedump
|
|
|
12
12
|
This installs `pi-goosedump` and its `@jarkkojs/goosedump` dependency, which
|
|
13
13
|
includes platform-specific native binaries for Linux, macOS, and Windows.
|
|
14
14
|
|
|
15
|
+
The upstream `@jarkkojs/goosedump` packages are licensed separately as
|
|
16
|
+
`Apache-2.0 AND LGPL-2.1-or-later`.
|
|
17
|
+
|
|
15
18
|
## Usage
|
|
16
19
|
|
|
17
20
|
Once installed, pi-goosedump registers a tool and a slash command:
|
package/index.ts
CHANGED
|
@@ -23,7 +23,7 @@ import { Type } from '@sinclair/typebox';
|
|
|
23
23
|
|
|
24
24
|
const require = createRequire(import.meta.url);
|
|
25
25
|
|
|
26
|
-
const GOOSEDUMP_VERSION = [0,
|
|
26
|
+
const GOOSEDUMP_VERSION = [0, 3, 1] as const;
|
|
27
27
|
|
|
28
28
|
interface GoosedumpListing {
|
|
29
29
|
id: string;
|
|
@@ -116,7 +116,7 @@ function parseMessages(output: string): GoosedumpMessage[] {
|
|
|
116
116
|
for (const line of lines) {
|
|
117
117
|
if (line.startsWith('results for ')) continue;
|
|
118
118
|
|
|
119
|
-
const entryMatch = line.match(/^entryId:\s+(\S+)\s+\((
|
|
119
|
+
const entryMatch = line.match(/^entryId:\s+(\S+)\s+\((.+?)\)(?:\s+\[[^\]]+\])?$/);
|
|
120
120
|
if (entryMatch) {
|
|
121
121
|
if (currentMsg) {
|
|
122
122
|
currentMsg.content = contentLines.join('\n').trim();
|
|
@@ -376,24 +376,103 @@ function buildCompactRange(
|
|
|
376
376
|
: { scope: 'lineage', until: firstKeptEntryId };
|
|
377
377
|
}
|
|
378
378
|
|
|
379
|
+
const GOOSEDUMP_NOTE =
|
|
380
|
+
'Use `goosedump` to search prior active-lineage work, decisions, and context from before this summary. Do not redo work already completed.';
|
|
381
|
+
const GOOSEDUMP_SEPARATOR = '\n\n---\n\n';
|
|
382
|
+
const GOOSEDUMP_HEADERS = [
|
|
383
|
+
'Session Goal',
|
|
384
|
+
'Files And Changes',
|
|
385
|
+
'Commits',
|
|
386
|
+
'Outstanding Context',
|
|
387
|
+
'User Preferences',
|
|
388
|
+
] as const;
|
|
389
|
+
|
|
390
|
+
function isGoosedumpSection(value: string): boolean {
|
|
391
|
+
return GOOSEDUMP_HEADERS.some((header) => value.startsWith(`[${header}]`));
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
function stripGoosedumpRecallNote(summary: string): string {
|
|
395
|
+
const idx = summary.lastIndexOf(GOOSEDUMP_NOTE);
|
|
396
|
+
if (idx < 0) return summary.trim();
|
|
397
|
+
return summary
|
|
398
|
+
.slice(0, idx)
|
|
399
|
+
.replace(/\s*(?:\n\n---\n\n)?\s*$/, '')
|
|
400
|
+
.trim();
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
function sectionOf(summary: string, header: string): string {
|
|
404
|
+
const tag = `[${header}]`;
|
|
405
|
+
const start = summary.indexOf(tag);
|
|
406
|
+
if (start < 0) return '';
|
|
407
|
+
|
|
408
|
+
const rest = summary.slice(start);
|
|
409
|
+
const nextHeader = GOOSEDUMP_HEADERS.filter((h) => h !== header)
|
|
410
|
+
.map((h) => rest.indexOf(`[${h}]`))
|
|
411
|
+
.filter((idx) => idx > 0);
|
|
412
|
+
const nextSeparator = rest.indexOf(GOOSEDUMP_SEPARATOR);
|
|
413
|
+
const candidates = [...nextHeader, ...(nextSeparator > 0 ? [nextSeparator] : [])].sort(
|
|
414
|
+
(a, b) => a - b,
|
|
415
|
+
);
|
|
416
|
+
const end = candidates[0];
|
|
417
|
+
return (end ? rest.slice(0, end) : rest).trim();
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
function briefOf(summary: string): string {
|
|
421
|
+
return stripGoosedumpRecallNote(summary)
|
|
422
|
+
.split(GOOSEDUMP_SEPARATOR)
|
|
423
|
+
.map((part) => part.trim())
|
|
424
|
+
.filter((part) => part && !isGoosedumpSection(part))
|
|
425
|
+
.join(GOOSEDUMP_SEPARATOR);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function mergeSection(header: string, previous: string, next: string): string {
|
|
429
|
+
if (header === 'Outstanding Context') return next;
|
|
430
|
+
if (!previous) return next;
|
|
431
|
+
if (!next) return previous;
|
|
432
|
+
|
|
433
|
+
const lines = [
|
|
434
|
+
...new Set(
|
|
435
|
+
[...previous.split('\n'), ...next.split('\n')].filter((line) => line.startsWith('- ')),
|
|
436
|
+
),
|
|
437
|
+
];
|
|
438
|
+
const cap = header === 'Session Goal' ? 8 : header === 'User Preferences' ? 15 : 10;
|
|
439
|
+
const capped = lines.length > cap ? lines.slice(-cap) : lines;
|
|
440
|
+
return capped.length > 0 ? `[${header}]\n${capped.join('\n')}` : '';
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
function capBriefTranscript(brief: string): string {
|
|
444
|
+
const lines = brief.split('\n');
|
|
445
|
+
if (lines.length <= 120) return brief;
|
|
446
|
+
const kept = lines.slice(-120);
|
|
447
|
+
const firstHeader = kept.findIndex((line) => /^\[(user|assistant)\]$/.test(line));
|
|
448
|
+
const clean = firstHeader > 0 ? kept.slice(firstHeader) : kept;
|
|
449
|
+
return `...(${lines.length - clean.length} earlier lines omitted)\n\n${clean.join('\n')}`;
|
|
450
|
+
}
|
|
451
|
+
|
|
379
452
|
function mergeWithPreviousSummary(
|
|
380
453
|
summary: string,
|
|
381
454
|
previousSummary: string | undefined,
|
|
382
455
|
): { summary: string; previousSummaryIncluded: boolean } {
|
|
383
|
-
const nextSummary = summary
|
|
384
|
-
const priorSummary = previousSummary
|
|
456
|
+
const nextSummary = stripGoosedumpRecallNote(summary);
|
|
457
|
+
const priorSummary = previousSummary ? stripGoosedumpRecallNote(previousSummary) : '';
|
|
385
458
|
|
|
386
459
|
if (!priorSummary) {
|
|
387
|
-
return { summary:
|
|
460
|
+
return { summary: summary.trim(), previousSummaryIncluded: false };
|
|
388
461
|
}
|
|
389
462
|
if (!nextSummary) {
|
|
390
|
-
return { summary:
|
|
463
|
+
return { summary: previousSummary?.trim() ?? '', previousSummaryIncluded: true };
|
|
391
464
|
}
|
|
392
465
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
466
|
+
const sections = GOOSEDUMP_HEADERS.map((header) =>
|
|
467
|
+
mergeSection(header, sectionOf(priorSummary, header), sectionOf(nextSummary, header)),
|
|
468
|
+
).filter(Boolean);
|
|
469
|
+
const brief = capBriefTranscript(
|
|
470
|
+
[briefOf(priorSummary), briefOf(nextSummary)].filter(Boolean).join('\n\n'),
|
|
471
|
+
);
|
|
472
|
+
const parts = [...sections, ...(brief ? [brief] : [])];
|
|
473
|
+
const merged = `${parts.join(GOOSEDUMP_SEPARATOR)}${GOOSEDUMP_SEPARATOR}${GOOSEDUMP_NOTE}`;
|
|
474
|
+
|
|
475
|
+
return { summary: merged.trim(), previousSummaryIncluded: true };
|
|
397
476
|
}
|
|
398
477
|
|
|
399
478
|
function buildGoosedumpCompaction(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-goosedump",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Coding agent context data browser plugin for pi",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"goosedump",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@earendil-works/pi-tui": "^0.78.0",
|
|
32
|
-
"@jarkkojs/goosedump": "^0.
|
|
32
|
+
"@jarkkojs/goosedump": "^0.3.2",
|
|
33
33
|
"@sinclair/typebox": "^0.34.49"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|