@openlines/opl-pi-sht 0.1.20 → 0.1.21

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.
@@ -198,7 +198,8 @@ export default function (pi: ExtensionAPI) {
198
198
  const msg = entry.message;
199
199
  if (msg.role !== "toolResult" || msg.toolName !== "todo") continue;
200
200
  const details = msg.details as TodoDetails | undefined;
201
- if (details) {
201
+ // Malformed results exist in real sessions (e.g. schema-rejected calls leave details: {}).
202
+ if (details && Array.isArray(details.todos) && typeof details.nextId === "number") {
202
203
  todos.length = 0;
203
204
  todos.push(...details.todos);
204
205
  nextId = details.nextId;
@@ -353,16 +354,17 @@ export default function (pi: ExtensionAPI) {
353
354
  },
354
355
 
355
356
  renderCall(args, theme, _context) {
356
- let text = theme.fg("toolTitle", theme.bold("todo ")) + theme.fg("muted", args.action);
357
- if (args.text) text += ` ${theme.fg("dim", `"${args.text}"`)}`;
358
- if (args.id !== undefined) text += ` ${theme.fg("accent", `#${args.id}`)}`;
357
+ // args can arrive partial (streaming) or malformed (schema-rejected calls still render).
358
+ let text = theme.fg("toolTitle", theme.bold("todo ")) + theme.fg("muted", String(args?.action ?? ""));
359
+ if (args?.text) text += ` ${theme.fg("dim", `"${args.text}"`)}`;
360
+ if (args?.id !== undefined) text += ` ${theme.fg("accent", `#${args.id}`)}`;
359
361
  return new Text(text, 0, 0);
360
362
  },
361
363
 
362
364
  renderResult(result, { expanded }, theme, _context) {
363
365
  const details = result.details as TodoDetails | undefined;
364
- if (!details) {
365
- const text = result.content[0];
366
+ if (!details || !Array.isArray(details.todos)) {
367
+ const text = Array.isArray(result.content) ? result.content[0] : undefined;
366
368
  return new Text(text?.type === "text" ? text.text : "", 0, 0);
367
369
  }
368
370
  if (details.error) return new Text(theme.fg("error", `Error: ${details.error}`), 0, 0);
@@ -383,6 +385,7 @@ export default function (pi: ExtensionAPI) {
383
385
  }
384
386
  case "add": {
385
387
  const added = todoList[todoList.length - 1];
388
+ if (!added) return new Text(theme.fg("error", "todo add returned an empty list"), 0, 0);
386
389
  return new Text(
387
390
  theme.fg("success", "✓ Added ") + theme.fg("accent", `#${added.id}`) + " " + theme.fg("muted", added.text),
388
391
  0, 0,
@@ -396,6 +399,10 @@ export default function (pi: ExtensionAPI) {
396
399
  case "clear":
397
400
  return new Text(theme.fg("success", "✓ ") + theme.fg("muted", "Cleared all todos"), 0, 0);
398
401
  }
402
+ // Fallback: switch above must never fall through. Returning undefined here
403
+ // makes pi wrap it in a MouseRegion with an undefined child and crashes the TUI.
404
+ const fb = result.content[0];
405
+ return new Text(theme.fg("error", String(fb?.type === "text" ? fb.text : "Unknown todo result")), 0, 0);
399
406
  },
400
407
  });
401
408
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openlines/opl-pi-sht",
3
- "version": "0.1.20",
3
+ "version": "0.1.21",
4
4
  "description": "opl-pi-sht (shouldHaveThat) Pi coding-agent extension kit: token-efficient context, safe modes, fingerprinted /init, model benchmarking, web access, and browser automation.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -47,7 +47,7 @@
47
47
  "test:opl-input": "bun test tests/opl-input-style.test.mjs && OPL_EXTENSION=opl-input bun test tests/extension-smoke.test.mjs",
48
48
  "test:opl-modes": "bun test tests/opl-modes-helpers.test.mjs && OPL_EXTENSION=opl-modes bun test tests/extension-smoke.test.mjs",
49
49
  "test:opl-questionnaire": "OPL_EXTENSION=opl-questionnaire bun test tests/extension-smoke.test.mjs",
50
- "test:opl-todo": "bun test tests/opl-todo-config.test.mjs && OPL_EXTENSION=opl-todo bun test tests/extension-smoke.test.mjs",
50
+ "test:opl-todo": "bun test tests/opl-todo-config.test.mjs tests/opl-todo-render.test.mjs && OPL_EXTENSION=opl-todo bun test tests/extension-smoke.test.mjs",
51
51
  "test:opl-webaccess": "bun test tests/opl-webaccess-helpers.test.mjs && OPL_EXTENSION=opl-webaccess bun test tests/extension-smoke.test.mjs",
52
52
  "test:opl-simplebench": "bun test tests/opl-simplebench.test.ts && OPL_EXTENSION=opl-simplebench bun test tests/extension-smoke.test.mjs",
53
53
  "test:opl-ctxtrim": "bun test tests/opl-ctxtrim.test.ts && OPL_EXTENSION=opl-ctxtrim bun test tests/extension-smoke.test.mjs"