@bacnh85/pi-serena 0.3.1 → 0.4.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 (4) hide show
  1. package/README.md +2 -1
  2. package/index.ts +13 -14
  3. package/package.json +1 -1
  4. package/worker.ts +17 -1
package/README.md CHANGED
@@ -46,7 +46,6 @@ After install or update, restart Pi or run `/reload` in an existing Pi session.
46
46
  - `serena_replace_content`
47
47
  - `serena_restart_language_server`
48
48
  - `serena_get_current_config`
49
- - `serena_check_onboarding_performed`
50
49
  - `serena_onboarding`
51
50
  - `serena_list_memories`
52
51
  - `serena_read_memory`
@@ -55,6 +54,8 @@ After install or update, restart Pi or run `/reload` in an existing Pi session.
55
54
 
56
55
  All tool outputs are truncated to 50KB / 2000 lines to match Pi-friendly output limits. Most tools accept optional `timeout_ms`.
57
56
 
57
+ When a worker request exceeds the configured timeout, the Python bridge process is automatically killed and a fresh worker is started for the next call. This prevents cascading timeouts from blocking future requests.
58
+
58
59
  ### Pattern search
59
60
 
60
61
  Use the Pi-facing `pattern` field with `serena_search_for_pattern`:
package/index.ts CHANGED
@@ -150,6 +150,9 @@ export function normalizeSearchPatternParams(params: Record<string, unknown>): R
150
150
  normalized.substring_pattern = normalized.pattern;
151
151
  }
152
152
  delete normalized.pattern;
153
+ // The Python SearchForPatternTool.apply() does not accept a multiline parameter.
154
+ // Strip it here to avoid TypeError when the parameter description says "when supported by Serena".
155
+ delete normalized.multiline;
153
156
  return normalized;
154
157
  }
155
158
 
@@ -206,8 +209,16 @@ function truncateText(text: string): string {
206
209
  }
207
210
 
208
211
  function resultText(response: SerenaWorkerResponse): string {
209
- const text = !response.ok ? `Error: ${response.error ?? "Unknown Serena error"}` : typeof response.result === "string" ? response.result : JSON.stringify(response, null, 2);
210
- return truncateText(text);
212
+ if (!response.ok) {
213
+ return `Error: ${response.error ?? "Unknown Serena error"}`;
214
+ }
215
+ // For search results, show a friendly empty-state instead of raw "{}".
216
+ if (response.tool === "search_for_pattern") {
217
+ if (response.result == null || (typeof response.result === "object" && Object.keys(response.result as object).length === 0)) {
218
+ return "No results found.";
219
+ }
220
+ }
221
+ return typeof response.result === "string" ? response.result : JSON.stringify(response, null, 2);
211
222
  }
212
223
 
213
224
  export default function serenaToolsExtension(pi: ExtensionAPI) {
@@ -423,18 +434,6 @@ export default function serenaToolsExtension(pi: ExtensionAPI) {
423
434
  },
424
435
  });
425
436
 
426
- pi.registerTool({
427
- name: "serena_check_onboarding_performed",
428
- label: "Serena Check Onboarding",
429
- description: "Check whether Serena onboarding memories exist for this project.",
430
- promptSnippet: "Check whether project onboarding was already performed",
431
- promptGuidelines: ["Use serena_check_onboarding_performed before relying on Serena project memories."],
432
- parameters: emptyToolSchema,
433
- async execute(_id, params, _signal, _onUpdate, ctx) {
434
- return callSerena(ctx, "check_onboarding_performed", params);
435
- },
436
- });
437
-
438
437
  pi.registerTool({
439
438
  name: "serena_onboarding",
440
439
  label: "Serena Onboarding",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bacnh85/pi-serena",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "Pi extension that provides Serena semantic code tools through a persistent worker.",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
package/worker.ts CHANGED
@@ -272,7 +272,13 @@ export class SerenaWorkerClient {
272
272
  return new Promise((resolve, reject) => {
273
273
  const timer = setTimeout(() => {
274
274
  this.pending.delete(id);
275
- reject(new Error(`Serena worker request timed out: ${payload.action ?? "unknown"}`));
275
+ // Kill and reset worker so subsequent requests don't pile up.
276
+ // The next request() call triggers ensureStarted() which spawns a fresh worker.
277
+ this.killAndReset();
278
+ reject(new Error(
279
+ `Serena worker request timed out: ${payload.action ?? "unknown"}. ` +
280
+ `Worker has been restarted; retry if needed.`
281
+ ));
276
282
  }, timeoutMs);
277
283
  this.pending.set(id, { resolve, reject, timer });
278
284
  this.process!.stdin.write(`${JSON.stringify(request)}\n`);
@@ -353,6 +359,16 @@ export class SerenaWorkerClient {
353
359
  }
354
360
  }
355
361
 
362
+ private killAndReset(): void {
363
+ if (this.process) {
364
+ this.process.kill();
365
+ this.process = undefined;
366
+ this.onStatus?.(undefined);
367
+ }
368
+ this.failAll(new Error("Serena worker killed due to timeout, restarted"));
369
+ this.buffer = "";
370
+ }
371
+
356
372
  private failAll(error: Error): void {
357
373
  for (const [id, pending] of this.pending) {
358
374
  clearTimeout(pending.timer);