pi-goosedump 0.9.0 → 0.9.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.
Files changed (3) hide show
  1. package/README.md +2 -2
  2. package/index.ts +40 -13
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -72,8 +72,8 @@ section and are optional (defaults shown):
72
72
 
73
73
  `turnsBeforeCompact` sets how many LLM turns elapse before goosedump triggers
74
74
  compaction, as an integer 0–255. `0` disables the counter; when enabled, the
75
- footer status shows `GD: XX` counting down in hex (e.g. `GD: 0A`), or just
76
- `GD` when disabled.
75
+ footer status shows `GD: XX` counting down in hex (e.g. `GD: 0A`), or
76
+ `GD: 00` when the counter is disabled.
77
77
 
78
78
  ### Compaction flow
79
79
 
package/index.ts CHANGED
@@ -12,7 +12,7 @@ import type {
12
12
 
13
13
  import { defineTool, getSettingsListTheme } from '@earendil-works/pi-coding-agent';
14
14
 
15
- import { execFileSync } from 'node:child_process';
15
+ import { execFile, execFileSync } from 'node:child_process';
16
16
  import {
17
17
  closeSync,
18
18
  existsSync,
@@ -262,6 +262,30 @@ function runGoosedump(args: string[]): string {
262
262
  }
263
263
  }
264
264
 
265
+ // Non-blocking variant for the compact path: goosedump compact runs an ML
266
+ // model and can take many seconds, so execFileSync would freeze Pi's event
267
+ // loop (and its compaction spinner). execFile keeps the loop free to render.
268
+ function runGoosedumpAsync(args: string[]): Promise<string> {
269
+ return new Promise((resolve, reject) => {
270
+ execFile(
271
+ 'node',
272
+ [resolveGoosedumpBinary(), ...args],
273
+ {
274
+ encoding: 'utf-8',
275
+ maxBuffer: 16 * 1024 * 1024,
276
+ },
277
+ (err, stdout, stderr) => {
278
+ if (err) {
279
+ const message = stderr.trim() || err.message;
280
+ reject(new Error(message));
281
+ } else {
282
+ resolve(stdout);
283
+ }
284
+ },
285
+ );
286
+ });
287
+ }
288
+
265
289
  // Read only the first line of a file without loading the whole transcript.
266
290
  function readFirstLine(path: string): string | null {
267
291
  const fd = openSync(path, 'r');
@@ -329,16 +353,16 @@ function resolveTarget(
329
353
  return null;
330
354
  }
331
355
 
332
- function goosedumpCompact(
356
+ async function goosedumpCompact(
333
357
  target: string,
334
358
  options: { scope?: string; from?: string; until: string },
335
- ): string {
359
+ ): Promise<string> {
336
360
  const scope = options.scope ?? 'lineage';
337
361
  const args = ['compact', target, '--scope', scope];
338
362
  if (options.from) args.push('--from', options.from);
339
363
  args.push('--until', options.until);
340
364
 
341
- const output = runGoosedump(args);
365
+ const output = await runGoosedumpAsync(args);
342
366
  for (const line of output.split('\n')) {
343
367
  if (!line) continue;
344
368
  try {
@@ -475,7 +499,7 @@ function buildCompactRange(
475
499
  : { scope: 'lineage', until: firstKeptEntryId };
476
500
  }
477
501
 
478
- function buildGoosedumpCompaction(
502
+ async function buildGoosedumpCompaction(
479
503
  target: string,
480
504
  preparation: {
481
505
  firstKeptEntryId: string;
@@ -485,7 +509,9 @@ function buildGoosedumpCompaction(
485
509
  },
486
510
  branchEntries: SessionEntry[],
487
511
  keep?: number,
488
- ): CompactionResult<GoosedumpCompactionDetails> | { cancel: true; reason: string } | undefined {
512
+ ): Promise<
513
+ CompactionResult<GoosedumpCompactionDetails> | { cancel: true; reason: string } | undefined
514
+ > {
489
515
  // A `keep:N` override replaces Pi's token-based cut with a turn-based one:
490
516
  // summarize everything before the Nth-from-last user entry and keep the tail.
491
517
  let firstKeptEntryId = preparation.firstKeptEntryId;
@@ -500,7 +526,7 @@ function buildGoosedumpCompaction(
500
526
  const range = buildCompactRange(branchEntries, firstKeptEntryId);
501
527
  if (!range) return undefined;
502
528
 
503
- const summary = goosedumpCompact(target, range);
529
+ const summary = await goosedumpCompact(target, range);
504
530
  if (!summary) return undefined;
505
531
 
506
532
  return {
@@ -934,11 +960,12 @@ export function createGoosedumpIntegration(
934
960
 
935
961
  function updateStatus(ctx: ExtensionContext): void {
936
962
  if (!goosedumpAvailable) return;
937
- const showCount = shouldOverrideDefaultCompaction && compactSettings.turnsBeforeCompact > 0;
938
- const suffix = showCount
939
- ? `: ${Math.max(0, turnsRemaining).toString(16).toUpperCase().padStart(2, '0')}`
940
- : '';
941
- ctx.ui.setStatus('goosedump', ctx.ui.theme.fg('text', `GD${suffix}`));
963
+ const active = shouldOverrideDefaultCompaction && compactSettings.turnsBeforeCompact > 0;
964
+ const count = active ? Math.max(0, turnsRemaining) : 0;
965
+ ctx.ui.setStatus(
966
+ 'goosedump',
967
+ ctx.ui.theme.fg('text', `GD: ${count.toString(16).toUpperCase().padStart(2, '0')}`),
968
+ );
942
969
  }
943
970
 
944
971
  function noteCompletedTurn(ctx: ExtensionContext): void {
@@ -1312,7 +1339,7 @@ export function createGoosedumpIntegration(
1312
1339
 
1313
1340
  try {
1314
1341
  const keep = pendingKeep ?? undefined;
1315
- const compaction = buildGoosedumpCompaction(
1342
+ const compaction = await buildGoosedumpCompaction(
1316
1343
  target,
1317
1344
  event.preparation,
1318
1345
  event.branchEntries,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-goosedump",
3
- "version": "0.9.0",
3
+ "version": "0.9.1",
4
4
  "description": "Pi extension for goosedump-backed session-history search, entry expansion, and compaction",
5
5
  "keywords": [
6
6
  "compaction",