my-pi 0.0.2 → 0.0.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "my-pi",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "Personal pi coding agent wrapper with MCP tool integration",
5
5
  "keywords": [
6
6
  "cli",
@@ -1,33 +1,13 @@
1
- // Recall extension — search past Pi sessions via pirecall SQLite database
2
- // Gives the agent access to conversation history from previous sessions
1
+ // Recall extension — nudge the agent to use pirecall for past session context
2
+ // The model uses `npx pirecall` via bash directly no custom tools needed
3
3
 
4
- import {
5
- type ExtensionAPI,
6
- defineTool,
7
- } from '@mariozechner/pi-coding-agent';
8
- import { Type } from '@sinclair/typebox';
4
+ import type { ExtensionAPI } from '@mariozechner/pi-coding-agent';
9
5
  import { execFileSync } from 'node:child_process';
10
6
  import { existsSync } from 'node:fs';
11
7
  import { join } from 'node:path';
12
8
 
13
9
  const DEFAULT_DB_PATH = join(process.env.HOME!, '.pi', 'pirecall.db');
14
10
 
15
- function run_pirecall(
16
- args: string[],
17
- ): { ok: true; data: unknown } | { ok: false; error: string } {
18
- try {
19
- const output = execFileSync('npx', ['pirecall', ...args], {
20
- encoding: 'utf-8',
21
- timeout: 15_000,
22
- stdio: ['pipe', 'pipe', 'pipe'],
23
- });
24
- return { ok: true, data: JSON.parse(output) };
25
- } catch (err) {
26
- const message = err instanceof Error ? err.message : String(err);
27
- return { ok: false, error: message };
28
- }
29
- }
30
-
31
11
  // Default export for Pi Package / additionalExtensionPaths loading
32
12
  export default async function recall(pi: ExtensionAPI) {
33
13
  // Sync on startup if db exists
@@ -43,209 +23,32 @@ export default async function recall(pi: ExtensionAPI) {
43
23
  }
44
24
  }
45
25
 
46
- // ── Tool: recall (LLM-optimised context retrieval) ──
47
-
48
- pi.registerTool(
49
- defineTool({
50
- name: 'recall',
51
- label: 'Recall Past Sessions',
52
- description:
53
- 'Search past Pi agent sessions for relevant context. Returns conversation snippets matching the query. Use this when the user references prior work, asks "what did we do", or when you need context from a previous session.',
54
- parameters: Type.Object({
55
- query: Type.String({
56
- description:
57
- 'Search term supports FTS5 syntax: AND, OR, NOT, "exact phrase", prefix*',
58
- }),
59
- limit: Type.Optional(
60
- Type.Number({
61
- description: 'Maximum matches to return (default: 5)',
62
- }),
63
- ),
64
- context: Type.Optional(
65
- Type.Number({
66
- description:
67
- 'Messages before/after each match (default: 2)',
68
- }),
69
- ),
70
- project: Type.Optional(
71
- Type.String({
72
- description: 'Filter by project path (substring match)',
73
- }),
74
- ),
75
- }),
76
- execute: async (_id, params) => {
77
- const args = ['recall', params.query, '--json'];
78
- if (params.limit) args.push('--limit', String(params.limit));
79
- if (params.context)
80
- args.push('--context', String(params.context));
81
- if (params.project) args.push('--project', params.project);
82
-
83
- const result = run_pirecall(args);
84
-
85
- if (!result.ok) {
86
- return {
87
- content: [
88
- {
89
- type: 'text' as const,
90
- text: `Recall failed: ${result.error}`,
91
- },
92
- ],
93
- details: {},
94
- };
95
- }
96
-
97
- return {
98
- content: [
99
- {
100
- type: 'text' as const,
101
- text: JSON.stringify(result.data, null, 2),
102
- },
103
- ],
104
- details: {},
105
- };
106
- },
107
- }),
108
- );
109
-
110
- // ── Tool: recall_search (full-text search with more options) ──
111
-
112
- pi.registerTool(
113
- defineTool({
114
- name: 'recall_search',
115
- label: 'Search Past Sessions',
116
- description:
117
- 'Full-text search across all past session messages. More detailed than recall — returns individual message matches with metadata. Use for specific lookups.',
118
- parameters: Type.Object({
119
- query: Type.String({
120
- description:
121
- 'Search term — supports FTS5: AND, OR, NOT, "phrase", prefix*',
122
- }),
123
- limit: Type.Optional(
124
- Type.Number({
125
- description: 'Maximum results (default: 20)',
126
- }),
127
- ),
128
- project: Type.Optional(
129
- Type.String({
130
- description: 'Filter by project path',
131
- }),
132
- ),
133
- session: Type.Optional(
134
- Type.String({
135
- description: 'Filter by session ID (prefix match)',
136
- }),
137
- ),
138
- after: Type.Optional(
139
- Type.String({
140
- description:
141
- 'Only results after date (ISO format, e.g. 2026-04-06)',
142
- }),
143
- ),
144
- sort: Type.Optional(
145
- Type.String({
146
- description: 'Sort: relevance (default), time, time-asc',
147
- }),
148
- ),
149
- }),
150
- execute: async (_id, params) => {
151
- const args = ['search', params.query, '--json'];
152
- if (params.limit) args.push('--limit', String(params.limit));
153
- if (params.project) args.push('--project', params.project);
154
- if (params.session) args.push('--session', params.session);
155
- if (params.after) args.push('--after', params.after);
156
- if (params.sort) args.push('--sort', params.sort);
157
-
158
- const result = run_pirecall(args);
159
-
160
- if (!result.ok) {
161
- return {
162
- content: [
163
- {
164
- type: 'text' as const,
165
- text: `Search failed: ${result.error}`,
166
- },
167
- ],
168
- details: {},
169
- };
170
- }
171
-
172
- return {
173
- content: [
174
- {
175
- type: 'text' as const,
176
- text: JSON.stringify(result.data, null, 2),
177
- },
178
- ],
179
- details: {},
180
- };
181
- },
182
- }),
183
- );
184
-
185
- // ── Command: /recall (user-facing) ──
186
-
187
- pi.registerCommand('recall', {
188
- description:
189
- 'Search past sessions — /recall <query> [--limit N] [--project path]',
190
- handler: async (args, ctx) => {
191
- const query = args.trim();
192
- if (!query) {
193
- ctx.ui.notify('Usage: /recall <search query>', 'warning');
194
- return;
195
- }
196
-
197
- // Sync first
198
- ctx.ui.notify('Syncing sessions...');
199
- run_pirecall(['sync', '--json']);
200
-
201
- const result = run_pirecall([
202
- 'recall',
203
- query,
204
- '--json',
205
- '--limit',
206
- '5',
207
- '--context',
208
- '2',
209
- ]);
210
-
211
- if (!result.ok) {
212
- ctx.ui.notify(`Recall failed: ${result.error}`, 'error');
213
- return;
214
- }
215
-
216
- // Paste results into the editor for the user to send
217
- const data = result.data as {
218
- matches?: Array<{
219
- session_id: string;
220
- project: string;
221
- date: string;
222
- messages: Array<{
223
- role: string;
224
- text: string;
225
- }>;
226
- }>;
26
+ // System prompt hint so the model knows pirecall exists
27
+ pi.on(
28
+ 'before_agent_start',
29
+ async (event: { systemPrompt: string }) => {
30
+ return {
31
+ systemPrompt:
32
+ event.systemPrompt +
33
+ `
34
+
35
+ ## Session Recall
36
+
37
+ You have access to past Pi session history via \`npx pirecall\`. Use it when:
38
+ - The user references prior work ("what did we do", "last time", "remember when")
39
+ - You need context from a previous session about this project
40
+ - You want to avoid repeating work already done
41
+
42
+ Quick reference:
43
+ - \`npx pirecall recall "<query>" --json\` — LLM-optimised context retrieval with surrounding messages
44
+ - \`npx pirecall search "<query>" --json\` — full-text search (supports FTS5: AND, OR, NOT, "phrase", prefix*)
45
+ - \`npx pirecall search "<query>" --json --project my-pi\` — filter by project
46
+ - \`npx pirecall search "<query>" --json --after 2026-04-10\` — filter by date
47
+ - \`npx pirecall sessions --json\` — list recent sessions
48
+ - \`npx pirecall stats --json\` — database statistics
49
+
50
+ Always pass \`--json\` for structured output.`,
227
51
  };
228
-
229
- if (!data.matches || data.matches.length === 0) {
230
- ctx.ui.notify(`No results for "${query}"`, 'warning');
231
- return;
232
- }
233
-
234
- const formatted = data.matches
235
- .map((m) => {
236
- const msgs = m.messages
237
- .map(
238
- (msg) =>
239
- ` [${msg.role}] ${msg.text?.slice(0, 300) || '(empty)'}`,
240
- )
241
- .join('\n');
242
- return `## ${m.project} (${m.date})\nSession: ${m.session_id.slice(0, 8)}\n${msgs}`;
243
- })
244
- .join('\n\n---\n\n');
245
-
246
- ctx.ui.pasteToEditor(
247
- `Here is relevant context from past sessions about "${query}":\n\n${formatted}`,
248
- );
249
52
  },
250
- });
53
+ );
251
54
  }