pi-goosedump 0.8.0 → 0.8.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 +2 -3
- package/index.ts +87 -51
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -86,13 +86,12 @@ current session to its goosedump id and runs `goosedump compact <id>` with Pi's
|
|
|
86
86
|
compaction range (`--from`, `--until`, and `--scope`) so the generated summary
|
|
87
87
|
matches the entries Pi is about to replace.
|
|
88
88
|
|
|
89
|
-
|
|
90
|
-
when
|
|
89
|
+
An optional goosedump counter can also trigger compaction. `0` disables the counter;
|
|
90
|
+
when it fires, it resets to its configured value.
|
|
91
91
|
|
|
92
92
|
```json
|
|
93
93
|
{
|
|
94
94
|
"goosedump": {
|
|
95
|
-
"stepsBeforeCompact": 0,
|
|
96
95
|
"turnsBeforeCompact": 0
|
|
97
96
|
}
|
|
98
97
|
}
|
package/index.ts
CHANGED
|
@@ -19,9 +19,13 @@ import { homedir } from 'node:os';
|
|
|
19
19
|
import { basename, dirname, extname, isAbsolute, join, relative } from 'node:path';
|
|
20
20
|
|
|
21
21
|
import {
|
|
22
|
+
type Component,
|
|
23
|
+
Input,
|
|
22
24
|
Key,
|
|
23
25
|
SettingsList,
|
|
24
26
|
type SettingItem,
|
|
27
|
+
decodeKittyPrintable,
|
|
28
|
+
getKeybindings,
|
|
25
29
|
matchesKey,
|
|
26
30
|
truncateToWidth,
|
|
27
31
|
visibleWidth,
|
|
@@ -31,7 +35,7 @@ import { Type } from '@sinclair/typebox';
|
|
|
31
35
|
|
|
32
36
|
const require = createRequire(import.meta.url);
|
|
33
37
|
|
|
34
|
-
const GOOSEDUMP_VERSION = [0, 8,
|
|
38
|
+
const GOOSEDUMP_VERSION = [0, 8, 2] as const;
|
|
35
39
|
|
|
36
40
|
// One element of goosedump 0.8's `list` JSON output.
|
|
37
41
|
interface ListEntryJson {
|
|
@@ -119,7 +123,6 @@ interface CompactJson {
|
|
|
119
123
|
}
|
|
120
124
|
|
|
121
125
|
interface GoosedumpSettings {
|
|
122
|
-
stepsBeforeCompact: number;
|
|
123
126
|
turnsBeforeCompact: number;
|
|
124
127
|
}
|
|
125
128
|
|
|
@@ -127,12 +130,9 @@ type SettingsScope = 'global' | 'project';
|
|
|
127
130
|
type GoosedumpSettingKey = keyof GoosedumpSettings;
|
|
128
131
|
|
|
129
132
|
const DEFAULT_GOOSEDUMP_SETTINGS: GoosedumpSettings = {
|
|
130
|
-
stepsBeforeCompact: 0,
|
|
131
133
|
turnsBeforeCompact: 0,
|
|
132
134
|
};
|
|
133
135
|
|
|
134
|
-
const COMPACT_SETTING_VALUES = ['0', '5', '10', '20', '50', '100'];
|
|
135
|
-
|
|
136
136
|
function piAgentDir(): string {
|
|
137
137
|
return process.env.PI_CODING_AGENT_DIR ?? join(homedir(), '.pi', 'agent');
|
|
138
138
|
}
|
|
@@ -165,11 +165,9 @@ function readGoosedumpSettingsFrom(path: string): Partial<GoosedumpSettings> {
|
|
|
165
165
|
if (!isRecord(raw)) return {};
|
|
166
166
|
|
|
167
167
|
const settings: Partial<GoosedumpSettings> = {};
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
settings[key] = value;
|
|
172
|
-
}
|
|
168
|
+
const value = raw.turnsBeforeCompact;
|
|
169
|
+
if (typeof value === 'number' && Number.isSafeInteger(value) && value >= 0) {
|
|
170
|
+
settings.turnsBeforeCompact = value;
|
|
173
171
|
}
|
|
174
172
|
return settings;
|
|
175
173
|
}
|
|
@@ -747,6 +745,64 @@ function buildGoosedumpCompaction(
|
|
|
747
745
|
};
|
|
748
746
|
}
|
|
749
747
|
|
|
748
|
+
function isControlChar(char: string): boolean {
|
|
749
|
+
const code = char.charCodeAt(0);
|
|
750
|
+
return code < 32 || code === 0x7f || (code >= 0x80 && code <= 0x9f);
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
class NumberInputSubmenu implements Component {
|
|
754
|
+
private readonly input = new Input();
|
|
755
|
+
private readonly hint: (text: string) => string;
|
|
756
|
+
private readonly onSubmitValue: (value: string) => void;
|
|
757
|
+
private readonly onCancelEdit: () => void;
|
|
758
|
+
private readonly title: string;
|
|
759
|
+
|
|
760
|
+
constructor(
|
|
761
|
+
title: string,
|
|
762
|
+
initialValue: string,
|
|
763
|
+
onSubmit: (value: string) => void,
|
|
764
|
+
onCancel: () => void,
|
|
765
|
+
) {
|
|
766
|
+
this.title = title;
|
|
767
|
+
this.onSubmitValue = onSubmit;
|
|
768
|
+
this.onCancelEdit = onCancel;
|
|
769
|
+
this.input.setValue(initialValue);
|
|
770
|
+
this.hint = getSettingsListTheme().hint;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
handleInput(data: string): void {
|
|
774
|
+
const kb = getKeybindings();
|
|
775
|
+
if (kb.matches(data, 'tui.select.confirm') || data === '\n') {
|
|
776
|
+
const digits = this.input.getValue().replace(/\D/g, '');
|
|
777
|
+
const parsed = Number(digits);
|
|
778
|
+
this.onSubmitValue(digits !== '' && Number.isSafeInteger(parsed) ? String(parsed) : '0');
|
|
779
|
+
return;
|
|
780
|
+
}
|
|
781
|
+
if (kb.matches(data, 'tui.select.cancel')) {
|
|
782
|
+
this.onCancelEdit();
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
const kittyChar = decodeKittyPrintable(data);
|
|
786
|
+
const printable = kittyChar ?? (data.length === 1 && !isControlChar(data) ? data : undefined);
|
|
787
|
+
if (printable !== undefined && !/^[0-9]$/.test(printable)) return;
|
|
788
|
+
this.input.handleInput(data);
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
invalidate(): void {
|
|
792
|
+
this.input.invalidate();
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
render(width: number): string[] {
|
|
796
|
+
return [
|
|
797
|
+
this.hint(` ${this.title}`),
|
|
798
|
+
'',
|
|
799
|
+
...this.input.render(width),
|
|
800
|
+
'',
|
|
801
|
+
this.hint(' enter submit · esc cancel · digits only'),
|
|
802
|
+
];
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
|
|
750
806
|
async function runSessionBrowser(
|
|
751
807
|
ctx: ExtensionContext,
|
|
752
808
|
listings: GoosedumpListing[],
|
|
@@ -757,7 +813,6 @@ async function runSessionBrowser(
|
|
|
757
813
|
const LIST_VIEWPORT = 18;
|
|
758
814
|
const COMPACT_VIEWPORT = 18;
|
|
759
815
|
const location = ctx.cwd;
|
|
760
|
-
const settingValues = COMPACT_SETTING_VALUES;
|
|
761
816
|
|
|
762
817
|
function locationListings(): GoosedumpListing[] {
|
|
763
818
|
return listings.filter((listing) => listing.cwd === location);
|
|
@@ -777,8 +832,7 @@ async function runSessionBrowser(
|
|
|
777
832
|
|
|
778
833
|
function settingLabel(scope: SettingsScope, key: GoosedumpSettingKey): string {
|
|
779
834
|
const scopeLabel = scope === 'global' ? 'Global' : 'Project';
|
|
780
|
-
|
|
781
|
-
return `${scopeLabel} ${keyLabel}`;
|
|
835
|
+
return `${scopeLabel} ${key}`;
|
|
782
836
|
}
|
|
783
837
|
|
|
784
838
|
function buildSettingItems(): SettingItem[] {
|
|
@@ -786,18 +840,19 @@ async function runSessionBrowser(
|
|
|
786
840
|
const project = readScopedGoosedumpSettings(location, 'project');
|
|
787
841
|
const settingsByScope = { global, project } satisfies Record<SettingsScope, GoosedumpSettings>;
|
|
788
842
|
|
|
789
|
-
return (['global', 'project'] as const).
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
843
|
+
return (['global', 'project'] as const).map((scope) => ({
|
|
844
|
+
id: `${scope}:turnsBeforeCompact`,
|
|
845
|
+
label: settingLabel(scope, 'turnsBeforeCompact'),
|
|
846
|
+
description: 'LLM turns before goosedump starts compaction; 0 disables this trigger.',
|
|
847
|
+
currentValue: String(settingsByScope[scope].turnsBeforeCompact),
|
|
848
|
+
submenu: (currentValue, done) =>
|
|
849
|
+
new NumberInputSubmenu(
|
|
850
|
+
settingLabel(scope, 'turnsBeforeCompact'),
|
|
851
|
+
currentValue,
|
|
852
|
+
(value) => done(value),
|
|
853
|
+
() => done(),
|
|
854
|
+
),
|
|
855
|
+
}));
|
|
801
856
|
}
|
|
802
857
|
|
|
803
858
|
await ctx.ui.custom<void>(
|
|
@@ -835,8 +890,7 @@ async function runSessionBrowser(
|
|
|
835
890
|
tui.requestRender();
|
|
836
891
|
},
|
|
837
892
|
() => {
|
|
838
|
-
|
|
839
|
-
tui.requestRender();
|
|
893
|
+
done(undefined);
|
|
840
894
|
},
|
|
841
895
|
);
|
|
842
896
|
}
|
|
@@ -892,15 +946,13 @@ async function runSessionBrowser(
|
|
|
892
946
|
const effective = resolveGoosedumpSettings(location);
|
|
893
947
|
lines.push(
|
|
894
948
|
makeRow(
|
|
895
|
-
dim(
|
|
896
|
-
`Effective: steps=${formatCompactSetting(effective.stepsBeforeCompact)} turns=${formatCompactSetting(effective.turnsBeforeCompact)}`,
|
|
897
|
-
),
|
|
949
|
+
dim(`Effective: turns=${formatCompactSetting(effective.turnsBeforeCompact)}`),
|
|
898
950
|
innerW,
|
|
899
951
|
border,
|
|
900
952
|
),
|
|
901
953
|
);
|
|
902
954
|
lines.push(
|
|
903
|
-
makeRow(dim('tab switch ↑↓ select enter/space
|
|
955
|
+
makeRow(dim('tab switch ↑↓ select enter/space edit esc close'), innerW, border),
|
|
904
956
|
);
|
|
905
957
|
lines.push(`${borderFg('╰')}${borderFg('─'.repeat(width - 2))}${borderFg('╯')}`);
|
|
906
958
|
return lines;
|
|
@@ -1051,10 +1103,6 @@ async function runSessionBrowser(
|
|
|
1051
1103
|
}
|
|
1052
1104
|
|
|
1053
1105
|
if (tab === 'settings') {
|
|
1054
|
-
if (matchesKey(data, Key.escape) || matchesKey(data, Key.ctrl('c'))) {
|
|
1055
|
-
done(undefined);
|
|
1056
|
-
return;
|
|
1057
|
-
}
|
|
1058
1106
|
settingsList.handleInput(data);
|
|
1059
1107
|
tui.requestRender();
|
|
1060
1108
|
return;
|
|
@@ -1152,19 +1200,17 @@ export function createGoosedumpIntegration(
|
|
|
1152
1200
|
let goosedumpAvailable = false;
|
|
1153
1201
|
let compactSettings = DEFAULT_GOOSEDUMP_SETTINGS;
|
|
1154
1202
|
let settingsSignature = '';
|
|
1155
|
-
let stepsRemaining = 0;
|
|
1156
1203
|
let turnsRemaining = 0;
|
|
1157
1204
|
let counterTriggered = false;
|
|
1158
1205
|
let compactionQueued = false;
|
|
1159
1206
|
|
|
1160
1207
|
function compactSettingsSignature(settings: GoosedumpSettings): string {
|
|
1161
|
-
return
|
|
1208
|
+
return String(settings.turnsBeforeCompact);
|
|
1162
1209
|
}
|
|
1163
1210
|
|
|
1164
1211
|
function resetCompactCounters(cwd: string): void {
|
|
1165
1212
|
compactSettings = resolveGoosedumpSettings(cwd);
|
|
1166
1213
|
settingsSignature = compactSettingsSignature(compactSettings);
|
|
1167
|
-
stepsRemaining = compactSettings.stepsBeforeCompact;
|
|
1168
1214
|
turnsRemaining = compactSettings.turnsBeforeCompact;
|
|
1169
1215
|
counterTriggered = false;
|
|
1170
1216
|
}
|
|
@@ -1175,15 +1221,6 @@ export function createGoosedumpIntegration(
|
|
|
1175
1221
|
if (nextSignature !== settingsSignature) resetCompactCounters(cwd);
|
|
1176
1222
|
}
|
|
1177
1223
|
|
|
1178
|
-
function noteCompletedStep(ctx: ExtensionContext): void {
|
|
1179
|
-
if (!goosedumpAvailable || !shouldOverrideDefaultCompaction) return;
|
|
1180
|
-
reloadCompactSettings(ctx.cwd);
|
|
1181
|
-
if (compactSettings.stepsBeforeCompact === 0) return;
|
|
1182
|
-
|
|
1183
|
-
stepsRemaining -= 1;
|
|
1184
|
-
if (stepsRemaining <= 0) counterTriggered = true;
|
|
1185
|
-
}
|
|
1186
|
-
|
|
1187
1224
|
function noteCompletedTurn(ctx: ExtensionContext): void {
|
|
1188
1225
|
if (!goosedumpAvailable || !shouldOverrideDefaultCompaction) return;
|
|
1189
1226
|
reloadCompactSettings(ctx.cwd);
|
|
@@ -1193,6 +1230,9 @@ export function createGoosedumpIntegration(
|
|
|
1193
1230
|
}
|
|
1194
1231
|
|
|
1195
1232
|
if (!counterTriggered || compactionQueued) return;
|
|
1233
|
+
// ctx.compact() uses manual compaction semantics and aborts the current run.
|
|
1234
|
+
// Wait until no queued work remains before triggering plugin-driven compaction.
|
|
1235
|
+
if (ctx.hasPendingMessages()) return;
|
|
1196
1236
|
|
|
1197
1237
|
resetCompactCounters(ctx.cwd);
|
|
1198
1238
|
compactionQueued = true;
|
|
@@ -1509,10 +1549,6 @@ export function createGoosedumpIntegration(
|
|
|
1509
1549
|
}
|
|
1510
1550
|
});
|
|
1511
1551
|
|
|
1512
|
-
pi.on('tool_execution_end', async (_event, ctx) => {
|
|
1513
|
-
noteCompletedStep(ctx);
|
|
1514
|
-
});
|
|
1515
|
-
|
|
1516
1552
|
pi.on('turn_end', async (_event, ctx) => {
|
|
1517
1553
|
noteCompletedTurn(ctx);
|
|
1518
1554
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-goosedump",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.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.8.
|
|
32
|
+
"@jarkkojs/goosedump": "^0.8.2",
|
|
33
33
|
"@sinclair/typebox": "^0.34.49"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|