@pi-archimedes/subagent 2.1.0 → 2.2.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-archimedes/subagent",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "type": "module",
5
5
  "keywords": [
6
6
  "pi-package"
@@ -11,7 +11,7 @@
11
11
  ],
12
12
  "main": "./src/index.ts",
13
13
  "dependencies": {
14
- "@pi-archimedes/core": "2.1.0"
14
+ "@pi-archimedes/core": "2.2.0"
15
15
  },
16
16
  "peerDependencies": {
17
17
  "@earendil-works/pi-ai": ">=0.1.0",
@@ -24,6 +24,15 @@ import {
24
24
  setLocalConfig,
25
25
  type LocalConfig,
26
26
  } from "./local-config.js";
27
+ import {
28
+ visibleWidth,
29
+ padEnd,
30
+ wrapText,
31
+ hardTruncate,
32
+ renderHeader,
33
+ renderFooter,
34
+ wrapWithBorder,
35
+ } from "@pi-archimedes/core/overlay";
27
36
 
28
37
  // ── Screen constants ────────────────────────────────────────────────────────
29
38
 
@@ -151,55 +160,6 @@ function fuzzyFilter(items: AgentConfig[], query: string): AgentConfig[] {
151
160
  );
152
161
  }
153
162
 
154
- function wrapText(text: string, width: number): string[] {
155
- if (width <= 0) return [];
156
- const lines: string[] = [];
157
- const paragraphs = text.split("\n");
158
- for (const para of paragraphs) {
159
- if (para.length === 0) {
160
- lines.push("");
161
- continue;
162
- }
163
- const words = para.split(/(\s+)/).filter(Boolean);
164
- let current = "";
165
- for (const word of words) {
166
- const test = current === "" ? word : current + word;
167
- if (test.length > width && current.length > 0) {
168
- lines.push(current);
169
- current = word;
170
- } else {
171
- current = test;
172
- }
173
- }
174
- if (current) lines.push(current);
175
- }
176
- return lines;
177
- }
178
-
179
- function padEnd(text: string, width: number): string {
180
- if (width <= 0) return "";
181
- const vw = visibleWidth(text);
182
- if (vw >= width) return text;
183
- return text + " ".repeat(width - vw);
184
- }
185
-
186
- function visibleWidth(text: string): number {
187
- // Strip ANSI escape sequences for width calculation
188
- return text.replace(/\x1b\[[0-9;]*m/g, "").length;
189
- }
190
-
191
- function row(text: string, width: number, theme: Theme): string {
192
- return padEnd(text, width);
193
- }
194
-
195
- function renderHeader(text: string, width: number, theme: Theme): string {
196
- return theme.fg("accent", padEnd(text, width));
197
- }
198
-
199
- function renderFooter(text: string, width: number, theme: Theme): string {
200
- return theme.fg("dim", padEnd(text, width));
201
- }
202
-
203
163
  function scopeLabel(source: "global" | "user" | "project"): string {
204
164
  if (source === "global") return "home";
205
165
  return source === "user" ? "user" : "proj";
@@ -220,57 +180,6 @@ function filterModels(models: ModelInfo[], query: string): ModelInfo[] {
220
180
  );
221
181
  }
222
182
 
223
-
224
- // ── Border wrapper ────────────────────────────────────────────────────────────
225
-
226
- /** Hard-truncate by visible width — no "..." suffix. Strips ANSI, truncates, rebuilds. */
227
- function hardTruncate(text: string, maxVisible: number): string {
228
- if (visibleWidth(text) <= maxVisible) return text;
229
- // Strip ANSI codes, truncate, then re-apply any trailing reset codes
230
- const plain = text.replace(/\x1b\[[0-9;]*m/g, "");
231
- const truncated = plain.slice(0, maxVisible);
232
- // Restore any ANSI codes that were in the original up to this point
233
- let result = "";
234
- let plainPos = 0;
235
- let i = 0;
236
- let copiedSgr = false;
237
- while (i < text.length && plainPos < maxVisible) {
238
- if (text[i] === "\x1b" && text[i + 1] === "[") {
239
- // Copy the escape sequence
240
- let j = i;
241
- while (j < text.length && text[j] !== "m") j++;
242
- result += text.slice(i, j + 1);
243
- copiedSgr = true;
244
- i = j + 1;
245
- } else {
246
- result += text[i];
247
- plainPos++;
248
- i++;
249
- }
250
- }
251
- // Ensure styling doesn't bleed: append reset if we copied SGR and result doesn't end with one
252
- if (copiedSgr && !/\x1b\[0?m$/.test(result)) {
253
- result += "\x1b[0m";
254
- }
255
- return result;
256
- }
257
-
258
- function wrapWithBorder(lines: string[], width: number, theme: Theme): string[] {
259
- const innerWidth = Math.max(1, width - 2);
260
- const contentWidth = Math.max(1, innerWidth - 2); // minus 1 space padding each side
261
- const left = theme.fg("dim", "│");
262
- const right = theme.fg("dim", "│");
263
- const top = theme.fg("dim", `┌${"─".repeat(innerWidth)}┐`);
264
- const bottom = theme.fg("dim", `└${"─".repeat(innerWidth)}┘`);
265
- const result: string[] = [top];
266
- for (const line of lines) {
267
- const clamped = hardTruncate(line, contentWidth);
268
- const padded = " " + padEnd(clamped, contentWidth) + " ";
269
- result.push(left + padded + right);
270
- }
271
- result.push(bottom);
272
- return result;
273
- }
274
183
  // ── List screen ─────────────────────────────────────────────────────────────
275
184
 
276
185
  function renderList(state: ManagerState, width: number, theme: Theme): string[] {
package/src/index.ts CHANGED
@@ -4,6 +4,7 @@ import { Type } from "typebox";
4
4
  import { executeSubagent, executeParallel } from "./execute.js";
5
5
  // agent-manager.js lazy-loaded below to keep subagent tool registration fast
6
6
  import { renderSubagentResult } from "./render.js";
7
+ import { OVERLAY_CHROME } from "@pi-archimedes/core/overlay";
7
8
  import { discoverAgents, discoverAgentsAll, findAgent, formatAgentList } from "./agents.js";
8
9
  import { validateModel, firstError } from "./model-validation.js";
9
10
  import type {
@@ -346,7 +347,7 @@ export function registerAgentsCommand(pi: ExtensionAPI): void {
346
347
  (tui: TUI, theme: Theme, _keybindings, done: () => void) => {
347
348
  return createAgentManager(globalAgents, user, project, globalDir, userDir, projectDir, tui, theme, done, availableModels, availableTools);
348
349
  },
349
- { overlay: true, overlayOptions: { anchor: "center", width: 84, maxHeight: "80%" } },
350
+ { overlay: true, overlayOptions: OVERLAY_CHROME },
350
351
  );
351
352
  },
352
353
  });