pi-spark 0.9.1 → 0.9.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.
@@ -1,5 +1,5 @@
1
1
  import { clampThinkingLevel, getSupportedThinkingLevels, StringEnum } from "@earendil-works/pi-ai";
2
- import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, truncateHead } from "@earendil-works/pi-coding-agent";
2
+ import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, keyText, truncateHead } from "@earendil-works/pi-coding-agent";
3
3
  import { Container, Spacer, Text } from "@earendil-works/pi-tui";
4
4
  import { Type } from "typebox";
5
5
 
@@ -54,8 +54,8 @@ export default function (pi: ExtensionAPI) {
54
54
  parameters: Type.Object({
55
55
  action: StringEnum(["list", "current"] as const, {
56
56
  description:
57
- "\"list\" returns all currently usable models with metadata; " +
58
- "\"current\" returns the active model with metadata and thinking level.",
57
+ "\"current\" returns the active model with metadata and thinking level; " +
58
+ "\"list\" returns all currently usable models with metadata.",
59
59
  }),
60
60
  provider: Type.Optional(Type.String({
61
61
  description: "For list: filter by provider, case-insensitive substring (e.g., \"vercel\", \"moonshot\")",
@@ -107,7 +107,7 @@ export default function (pi: ExtensionAPI) {
107
107
  const models = details.models ?? [];
108
108
  const total = details.total ?? models.length;
109
109
 
110
- if (expanded) {
110
+ if (models.length > 0 && expanded) {
111
111
  models.forEach((model) => {
112
112
  container.addChild(new Text(theme.fg("muted", formatModel(model.provider, model.id)), 0, 0));
113
113
  });
@@ -115,15 +115,17 @@ export default function (pi: ExtensionAPI) {
115
115
  container.addChild(new Spacer(1));
116
116
  }
117
117
 
118
- const summary = `${models.length !== total ? `${models.length} of ` : ""}${total} ${filtered ? "matched" : "available"} model${total === 1 ? "" : "s"} listed`;
119
- container.addChild(new Text(theme.fg("muted", summary) + (details.truncation?.truncated ? theme.fg("warning", " (truncated)") : ""), 0, 0));
118
+ const summary = total > 0 ? `${models.length !== total ? `${models.length} of ` : ""}${total} ${filtered ? "matched" : "available"} model${total === 1 ? "" : "s"} listed` : `0 models ${filtered ? "matched" : "available"}`;
119
+ const truncatedHint = details.truncation?.truncated ? theme.fg("warning", " (truncated)") : "";
120
+ const expandHint = models.length > 0 && !expanded ? theme.fg("dim", ` (${keyText("app.tools.expand")} to expand)`) : "";
121
+ container.addChild(new Text(theme.fg("muted", summary) + truncatedHint + expandHint, 0, 0));
120
122
 
121
123
  return container;
122
124
  },
123
125
  async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
124
126
  if (params.action === "current") {
125
127
  const model = ctx.model;
126
- if (!model) throw new Error("No model is currently selected.");
128
+ if (!model) throw new Error("No model is currently selected");
127
129
 
128
130
  const thinkingLevel = pi.getThinkingLevel();
129
131
  const current = { model: toMetadata(model), thinkingLevel };
@@ -147,7 +149,7 @@ export default function (pi: ExtensionAPI) {
147
149
 
148
150
  if (total === 0) {
149
151
  return {
150
- content: [{ type: "text", text: `0 models ${filtered ? "matched" : "available"}.` }],
152
+ content: [{ type: "text", text: `0 models ${filtered ? "matched" : "available"}` }],
151
153
  details: { action: "list", models: [], total } satisfies ModelToolDetails,
152
154
  };
153
155
  }
@@ -155,7 +157,7 @@ export default function (pi: ExtensionAPI) {
155
157
  // Convert from 1-indexed offset to 0-indexed array access.
156
158
  const startIndex = params.offset ? Math.max(0, params.offset - 1) : 0;
157
159
  if (startIndex >= total) {
158
- throw new Error(`Offset ${params.offset} is beyond end of list (${total} models total).`);
160
+ throw new Error(`Offset ${params.offset} is beyond end of list (${total} models total)`);
159
161
  }
160
162
 
161
163
  const endIndex = params.limit !== undefined ? Math.min(startIndex + params.limit, total) : total;
@@ -72,12 +72,12 @@ export default function (pi: ExtensionAPI) {
72
72
  },
73
73
  async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
74
74
  const name = sanitizeText(params.name);
75
- if (!name) throw new Error("Session name was empty after normalization. Provide a short, non-empty phrase.");
75
+ if (!name) throw new Error("Session name was empty after normalization; provide a short, non-empty phrase");
76
76
 
77
77
  const previous = pi.getSessionName() ?? null;
78
78
  if (previous === name) {
79
79
  return {
80
- content: [{ type: "text", text: `Session is already named "${name}". No change.` }],
80
+ content: [{ type: "text", text: `Session is already named "${name}"; no change` }],
81
81
  details: { changed: false, previous },
82
82
  };
83
83
  }
@@ -85,7 +85,7 @@ export default function (pi: ExtensionAPI) {
85
85
  pi.setSessionName(name);
86
86
 
87
87
  return {
88
- content: [{ type: "text", text: `${previous ? `Renamed session from "${previous}" to "${name}".` : `Named session "${name}".`}` }],
88
+ content: [{ type: "text", text: `${previous ? `Renamed session from "${previous}" to "${name}"` : `Named session "${name}"`}` }],
89
89
  details: { changed: true, previous },
90
90
  };
91
91
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-spark",
3
- "version": "0.9.1",
3
+ "version": "0.9.3",
4
4
  "description": "A small, opinionated collection of pi extensions",
5
5
  "keywords": [
6
6
  "pi-coding-agent",