pi-goosedump 0.9.13 → 0.10.0

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 +3 -0
  2. package/index.ts +108 -0
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -20,6 +20,8 @@ If the goosedump binary cannot be resolved, the extension disables itself.
20
20
 
21
21
  - **goose_search:** ranks messages by query relevance; returns compact entry
22
22
  overviews with IDs.
23
+ - **goose_recall:** searches durable memory harvested from earlier compactions,
24
+ scoped to the current working directory by default.
23
25
  - **goose_get:** expands specific entry IDs to their full content.
24
26
  - **goose_grep:** filters messages by glob pattern; returns compact entries
25
27
  with IDs.
@@ -35,6 +37,7 @@ current branch) or `all`. Targets are always provider-qualified
35
37
 
36
38
  ```
37
39
  goose_search({ query: "bug fix" })
40
+ goose_recall({ query: "prior architecture decision" })
38
41
  goose_search({ query: "auth", scope: "all", page: 2 })
39
42
  goose_get({ ids: ["entry-a", "entry-b"] })
40
43
  goose_get({ ids: ["entry-a"], provider: "claude", session: "1f6b1eba-…" })
package/index.ts CHANGED
@@ -55,6 +55,17 @@ interface GoosedumpMessage {
55
55
  content: string;
56
56
  }
57
57
 
58
+ interface GoosedumpMemoryHit {
59
+ hash: string;
60
+ kind: string;
61
+ text: string;
62
+ score: number;
63
+ provider: string;
64
+ context_id: string;
65
+ entry_id: string;
66
+ path: string;
67
+ }
68
+
58
69
  // A `content` part of a pi-native message line.
59
70
  interface PiPartJson {
60
71
  type: string;
@@ -234,6 +245,32 @@ function parsePiMessages(output: string): GoosedumpMessage[] {
234
245
  return messages;
235
246
  }
236
247
 
248
+ function parseMemoryHits(output: string): GoosedumpMemoryHit[] {
249
+ const value = JSON.parse(output) as unknown;
250
+ if (!Array.isArray(value)) throw new Error('goosedump recall returned invalid JSON');
251
+ return value.filter(
252
+ (item): item is GoosedumpMemoryHit =>
253
+ isRecord(item) &&
254
+ typeof item.hash === 'string' &&
255
+ typeof item.kind === 'string' &&
256
+ typeof item.text === 'string' &&
257
+ typeof item.score === 'number' &&
258
+ typeof item.provider === 'string' &&
259
+ typeof item.context_id === 'string' &&
260
+ typeof item.entry_id === 'string' &&
261
+ typeof item.path === 'string',
262
+ );
263
+ }
264
+
265
+ function formatMemoryHits(hits: GoosedumpMemoryHit[]): string {
266
+ return hits
267
+ .map(
268
+ (hit) =>
269
+ `[${hit.hash}] ${hit.kind} (${hit.provider}:${hit.context_id}/${hit.entry_id})\n${hit.text}`,
270
+ )
271
+ .join('\n\n---\n\n');
272
+ }
273
+
237
274
  const ANSI_SGR = new RegExp(String.fromCharCode(27) + '\\[[0-9;]*m', 'g');
238
275
 
239
276
  function compactLine(content: string): string {
@@ -367,6 +404,18 @@ function goosedumpShow(
367
404
  return parsePiMessages(runGoosedump(args));
368
405
  }
369
406
 
407
+ async function goosedumpRecall(
408
+ query: string,
409
+ options: { provider?: string; path?: string; limit?: number } = {},
410
+ signal?: AbortSignal,
411
+ ): Promise<GoosedumpMemoryHit[]> {
412
+ const args = ['recall', query, '--limit', String(options.limit ?? 5)];
413
+ if (options.provider) args.push('--provider', options.provider);
414
+ if (options.path) args.push('--path', options.path);
415
+ const output = await runGoosedumpAsync(args, signal);
416
+ return parseMemoryHits(output);
417
+ }
418
+
370
419
  // Resolve a goosedump 0.9 `provider:id` target. An explicit contextId is the
371
420
  // target id already; for pi it falls back to the current session. Other
372
421
  // providers have no current session and require an explicit id.
@@ -1169,6 +1218,65 @@ export function createGoosedumpIntegration(
1169
1218
 
1170
1219
  function register(pi: ExtensionAPI): void {
1171
1220
  if (shouldRegisterTool) {
1221
+ pi.registerTool(
1222
+ defineTool({
1223
+ name: 'goose_recall',
1224
+ label: 'goose_recall',
1225
+ description:
1226
+ 'Recall durable context harvested from earlier compactions. Searches the current project by default and returns full remembered entries with provenance.',
1227
+ promptSnippet: 'Recall durable context from earlier sessions',
1228
+ promptGuidelines: [
1229
+ 'Use goose_recall for decisions, evidence, and context that may have disappeared from the current session.',
1230
+ 'Results include their original provider, session, entry, and working-directory provenance.',
1231
+ 'The current project is searched by default; set allProjects only when cross-project context is appropriate.',
1232
+ ],
1233
+ parameters: Type.Object({
1234
+ query: Type.String({ description: 'Persistent-memory search query' }),
1235
+ provider: Type.Optional(
1236
+ Type.Union(
1237
+ GOOSE_PROVIDERS.map((provider) => Type.Literal(provider)),
1238
+ {
1239
+ description: 'Optional source-provider filter',
1240
+ },
1241
+ ),
1242
+ ),
1243
+ allProjects: Type.Optional(
1244
+ Type.Boolean({
1245
+ default: false,
1246
+ description: 'Search memory from every working directory',
1247
+ }),
1248
+ ),
1249
+ limit: Type.Optional(
1250
+ Type.Integer({
1251
+ minimum: 1,
1252
+ maximum: 20,
1253
+ default: 5,
1254
+ description: 'Maximum remembered entries to return',
1255
+ }),
1256
+ ),
1257
+ }),
1258
+ async execute(_id, params, signal, _onUpdate, ctx): Promise<AgentToolResult<void>> {
1259
+ if (!goosedumpAvailable) return goosedumpUnavailableResult();
1260
+ try {
1261
+ const hits = await goosedumpRecall(
1262
+ params.query,
1263
+ {
1264
+ provider: params.provider,
1265
+ path: params.allProjects ? undefined : ctx.cwd,
1266
+ limit: params.limit,
1267
+ },
1268
+ signal,
1269
+ );
1270
+ if (hits.length === 0) return textResult(`No durable memory for "${params.query}"`);
1271
+ return textResult(formatMemoryHits(hits));
1272
+ } catch (err) {
1273
+ const message = err instanceof Error ? err.message : String(err);
1274
+ return textResult(`goosedump error: ${message}`);
1275
+ }
1276
+ },
1277
+ }),
1278
+ );
1279
+
1172
1280
  pi.registerTool(
1173
1281
  defineTool({
1174
1282
  name: 'goose_search',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-goosedump",
3
- "version": "0.9.13",
3
+ "version": "0.10.0",
4
4
  "description": "Pi extension for goosedump-backed session-history search, entry expansion, and compaction",
5
5
  "keywords": [
6
6
  "compaction",