pi-goosedump 0.13.7 → 0.13.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.
Files changed (2) hide show
  1. package/dist/index.ts +73 -19
  2. package/package.json +2 -2
package/dist/index.ts CHANGED
@@ -725,6 +725,7 @@ import {
725
725
  mkdirSync,
726
726
  readFileSync as readFileSync3,
727
727
  renameSync,
728
+ statSync as statSync2,
728
729
  unlinkSync,
729
730
  writeFileSync
730
731
  } from "node:fs";
@@ -851,7 +852,26 @@ function validateGoosedumpSettings(path) {
851
852
  }
852
853
  var isNumberValue = (value) => typeof value === "number";
853
854
  var isBooleanValue = (value) => typeof value === "boolean";
855
+ var settingsCache = null;
856
+ function settingsStamp(path) {
857
+ try {
858
+ const stat = statSync2(path);
859
+ return `${stat.mtimeMs}:${stat.size}:${stat.ino}`;
860
+ } catch {
861
+ return "missing";
862
+ }
863
+ }
854
864
  function resolveWorkspaceSettings(cwd, includeProject) {
865
+ const globalPath = globalSettingsPath();
866
+ const projectPath = includeProject ? projectSettingsPath(cwd) : undefined;
867
+ const key = `${globalPath}|${settingsStamp(globalPath)}|${projectPath ?? ""}|${projectPath ? settingsStamp(projectPath) : ""}`;
868
+ if (settingsCache?.key === key)
869
+ return settingsCache.value;
870
+ const value = computeWorkspaceSettings(cwd, includeProject);
871
+ settingsCache = { key, value };
872
+ return value;
873
+ }
874
+ function computeWorkspaceSettings(cwd, includeProject) {
855
875
  const globalObj = readJsonObject(globalSettingsPath());
856
876
  const projectObj = includeProject ? readJsonObject(projectSettingsPath(cwd)) : undefined;
857
877
  const goosedump = {
@@ -905,6 +925,7 @@ function updateScopedGoosedumpSetting(cwd, scope, update) {
905
925
  delete root.goosedump;
906
926
  else
907
927
  root.goosedump = next;
928
+ settingsCache = null;
908
929
  writeJsonObjectAtomically(path, root);
909
930
  }
910
931
  function readScopedGoosedumpSettings(cwd, scope) {
@@ -983,12 +1004,22 @@ function latestCompaction(branchEntries) {
983
1004
  }
984
1005
  return;
985
1006
  }
1007
+
1008
+ class BranchPositions {
1009
+ positions = new Map;
1010
+ constructor(branchEntries) {
1011
+ branchEntries.forEach((entry, index) => this.positions.set(entry.id, index));
1012
+ }
1013
+ boundaryStartIndex(compaction) {
1014
+ const kept = this.positions.get(compaction.firstKeptEntryId);
1015
+ if (kept !== undefined)
1016
+ return kept;
1017
+ const own = this.positions.get(compaction.id);
1018
+ return own !== undefined ? own + 1 : 0;
1019
+ }
1020
+ }
986
1021
  function compactionBoundaryStartIndex(branchEntries, compaction) {
987
- const keptIndex = branchEntries.findIndex((entry) => entry.id === compaction.firstKeptEntryId);
988
- if (keptIndex >= 0)
989
- return keptIndex;
990
- const compactionIndex = branchEntries.findIndex((entry) => entry.id === compaction.id);
991
- return compactionIndex >= 0 ? compactionIndex + 1 : 0;
1022
+ return new BranchPositions(branchEntries).boundaryStartIndex(compaction);
992
1023
  }
993
1024
  function activeHistoryStartIndex(branchEntries) {
994
1025
  const compaction = latestCompaction(branchEntries);
@@ -1022,12 +1053,13 @@ function buildCompactRange(branchEntries, firstKeptEntryId) {
1022
1053
  const untilIndex = branchEntries.findIndex((entry) => entry.id === firstKeptEntryId);
1023
1054
  if (untilIndex < 0)
1024
1055
  return;
1056
+ const positions = new BranchPositions(branchEntries);
1025
1057
  let from;
1026
1058
  for (let i = Math.min(untilIndex - 1, branchEntries.length - 1);i >= 0; i -= 1) {
1027
1059
  const entry = branchEntries[i];
1028
1060
  if (!isCompactionEntry(entry))
1029
1061
  continue;
1030
- const boundaryStart = compactionBoundaryStartIndex(branchEntries, entry);
1062
+ const boundaryStart = positions.boundaryStartIndex(entry);
1031
1063
  if (boundaryStart < untilIndex) {
1032
1064
  from = branchEntries[boundaryStart]?.id;
1033
1065
  break;
@@ -2406,6 +2438,7 @@ ${formattedContent}` : summary;
2406
2438
  var renderGooseSessionsResult = renderGooseDumpSessionsResult;
2407
2439
 
2408
2440
  // src/tools.ts
2441
+ var MAX_ENTRY_IDS = 50;
2409
2442
  function memoryDisabledResult() {
2410
2443
  return textResult(MEMORY_DISABLED_MESSAGE);
2411
2444
  }
@@ -2600,6 +2633,7 @@ ${text}`);
2600
2633
  registerPair("goosedump_get", "goose_get", Type3.Object({
2601
2634
  ids: Type3.Array(Type3.String(), {
2602
2635
  minItems: 1,
2636
+ maxItems: MAX_ENTRY_IDS,
2603
2637
  description: PARAM_DESCRIPTIONS.entryIds
2604
2638
  }),
2605
2639
  ...historyBranchParams()
@@ -3025,12 +3059,13 @@ async function runSettingsEditor(ctx) {
3025
3059
  async function runSearchPanel(ctx, query, executablePath) {
3026
3060
  const OVERLAY_WIDTH = 84;
3027
3061
  const VIEWPORT = 18;
3028
- const PAGE_SIZE = 5;
3062
+ const MAX_PAGES = 10;
3029
3063
  const wrapWidth = OVERLAY_WIDTH - 4;
3030
3064
  await ctx.ui.custom((tui, theme, _kb, done) => {
3031
3065
  const target = currentSessionTarget(ctx);
3032
3066
  const colors = overlayColors(theme);
3033
3067
  let entries = [];
3068
+ const snippets = new WeakMap;
3034
3069
  let error = null;
3035
3070
  let mode = "results";
3036
3071
  let selected = 0;
@@ -3038,9 +3073,11 @@ async function runSearchPanel(ctx, query, executablePath) {
3038
3073
  let detailLines = [];
3039
3074
  let detailScroll = 0;
3040
3075
  let detailEntry = null;
3076
+ let truncated = false;
3077
+ const controller = new AbortController;
3041
3078
  async function runSearch() {
3042
3079
  try {
3043
- const first = await goosedumpSearch(target, query, { scope: "lineage", page: 1 }, undefined, executablePath);
3080
+ const first = await goosedumpSearch(target, query, { scope: "lineage", page: 1 }, controller.signal, executablePath);
3044
3081
  if (first.length === 0) {
3045
3082
  entries = [];
3046
3083
  error = `No results for "${query}"`;
@@ -3048,22 +3085,34 @@ async function runSearchPanel(ctx, query, executablePath) {
3048
3085
  scroll = 0;
3049
3086
  return;
3050
3087
  }
3088
+ const search = (page) => goosedumpSearch(target, query, { scope: "lineage", page }, controller.signal, executablePath);
3051
3089
  const all = [...first];
3052
- for (let page = 2;page <= 10; page += 1) {
3053
- const result = await goosedumpSearch(target, query, { scope: "lineage", page }, undefined, executablePath);
3054
- if (result.length === 0)
3055
- break;
3056
- all.push(...result);
3057
- if (result.length < PAGE_SIZE)
3058
- break;
3090
+ let lastPage = 1;
3091
+ let complete = false;
3092
+ const second = await search(2);
3093
+ if (second.length < first.length) {
3094
+ all.push(...second);
3095
+ complete = true;
3096
+ } else {
3097
+ all.push(...second);
3098
+ const rest = await Promise.all(Array.from({ length: MAX_PAGES - 2 }, (_unused, index) => search(index + 3)));
3099
+ for (const [index, page] of rest.entries()) {
3100
+ all.push(...page);
3101
+ lastPage = index + 3;
3102
+ if (page.length < first.length) {
3103
+ complete = true;
3104
+ break;
3105
+ }
3106
+ }
3059
3107
  }
3108
+ truncated = !complete && lastPage >= MAX_PAGES;
3060
3109
  entries = all;
3061
3110
  error = null;
3062
3111
  selected = 0;
3063
3112
  scroll = 0;
3064
3113
  } catch (err) {
3065
3114
  entries = [];
3066
- error = err instanceof Error ? err.message : String(err);
3115
+ error = controller.signal.aborted ? "Search cancelled." : err instanceof Error ? err.message : String(err);
3067
3116
  } finally {
3068
3117
  tui.requestRender();
3069
3118
  }
@@ -3075,7 +3124,7 @@ async function runSearchPanel(ctx, query, executablePath) {
3075
3124
  }
3076
3125
  async function loadDetail(id) {
3077
3126
  try {
3078
- const messages = await goosedumpShow(target, { ids: [id] }, undefined, executablePath);
3127
+ const messages = await goosedumpShow(target, { ids: [id] }, controller.signal, executablePath);
3079
3128
  const msg = messages.length > 0 ? messages[0] : null;
3080
3129
  detailEntry = msg;
3081
3130
  const entryHeader = msg ? `${colors.accent(colors.bold(`[${msg.id}]`))} ${colors.muted(`${msg.role}:`)}` : "";
@@ -3106,11 +3155,15 @@ async function runSearchPanel(ctx, query, executablePath) {
3106
3155
  }
3107
3156
  return [
3108
3157
  header,
3109
- ...overlayViewport(colors, width, entries, scroll, VIEWPORT, "↑↓ navigate enter expand esc close", (count) => `entr${count === 1 ? "y" : "ies"}`, (entry, absolute) => {
3158
+ ...overlayViewport(colors, width, entries, scroll, VIEWPORT, truncated ? `first ${entries.length} results ↑↓ navigate enter expand esc close` : "↑↓ navigate enter expand esc close", (count) => `entr${count === 1 ? "y" : "ies"}`, (entry, absolute) => {
3110
3159
  const isSelected = absolute === selected;
3111
3160
  const cursor = isSelected ? colors.accent(colors.bold("▶")) : " ";
3112
3161
  const idText = isSelected ? colors.accent(colors.bold(entry.id)) : colors.text(entry.id);
3113
- const snippet = compactLine(entry.content);
3162
+ let snippet = snippets.get(entry);
3163
+ if (snippet === undefined) {
3164
+ snippet = Buffer.from(compactLine(entry.content), "utf16le").toString("utf16le");
3165
+ snippets.set(entry, snippet);
3166
+ }
3114
3167
  return ` ${cursor} ${idText} ${colors.muted(entry.role)} ${colors.dim(snippet)}`;
3115
3168
  }),
3116
3169
  overlayFooter(colors, width)
@@ -3123,6 +3176,7 @@ async function runSearchPanel(ctx, query, executablePath) {
3123
3176
  tui.requestRender();
3124
3177
  return;
3125
3178
  }
3179
+ controller.abort();
3126
3180
  done(undefined);
3127
3181
  return;
3128
3182
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-goosedump",
3
- "version": "0.13.7",
3
+ "version": "0.13.9",
4
4
  "description": "Pi extension for goosedump session search, durable memory, session management, and compaction",
5
5
  "keywords": [
6
6
  "compaction",
@@ -37,7 +37,7 @@
37
37
  "ci:test": "npm test"
38
38
  },
39
39
  "dependencies": {
40
- "@jarkkojs/goosedump": "^0.13.7"
40
+ "@jarkkojs/goosedump": "^0.13.9"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@earendil-works/pi-coding-agent": "^0.84.2",