@esso0428/pi-subagents 0.15.0 → 0.15.1

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/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  /**
2
3
  * pi-agents — A pi extension providing Claude Code-style autonomous sub-agents.
3
4
  *
@@ -9,29 +10,33 @@
9
10
  * Commands:
10
11
  * /agents — Interactive agent management menu
11
12
  */
12
- import { existsSync, mkdirSync, readFileSync, unlinkSync } from "node:fs";
13
- import { join } from "node:path";
14
- import { defineTool, getAgentDir, getSettingsListTheme } from "@earendil-works/pi-coding-agent";
15
- import { Container, Key, matchesKey, SettingsList, Spacer, Text } from "@earendil-works/pi-tui";
16
- import { Type } from "@sinclair/typebox";
17
- import { AgentManager } from "./agent-manager.js";
18
- import { getAgentConversation, getDefaultMaxTurns, getGraceTurns, normalizeMaxTurns, SUBAGENT_TOOL_NAMES, setDefaultMaxTurns, setGraceTurns, steerAgent } from "./agent-runner.js";
19
- import { applyNicoOverrides, BUILTIN_TOOL_NAMES, getAgentConfig, getAllTypes, getAvailableTypes, isDefaultsDisabled, registerAgents, resolveType, setDefaultsDisabled } from "./agent-types.js";
20
- import { registerRpcHandlers } from "./cross-extension-rpc.js";
21
- import { loadCustomAgents } from "./custom-agents.js";
22
- import { isModelInScope, readEnabledModels, resolveEnabledModels } from "./enabled-models.js";
23
- import { GroupJoinManager } from "./group-join.js";
24
- import { resolveAgentInvocationConfig, resolveJoinMode } from "./invocation-config.js";
25
- import { resolveModel } from "./model-resolver.js";
26
- import { createOutputFilePath, streamToOutputFile, writeInitialEntry } from "./output-file.js";
27
- import { SubagentScheduler } from "./schedule.js";
28
- import { resolveStorePath, ScheduleStore } from "./schedule-store.js";
29
- import { applyAndEmitLoaded, saveAndEmitChanged } from "./settings.js";
30
- import { getStatusNote } from "./status-note.js";
31
- import { AgentWidget, buildInvocationTags, describeActivity, fgPreservingNestedStyles, formatDuration, formatMs, formatTokens, formatTurns, getDisplayName, getPromptModeLabel, SPINNER, } from "./ui/agent-widget.js";
32
- import { FleetList } from "./ui/fleet-list.js";
33
- import { showSchedulesMenu } from "./ui/schedule-menu.js";
34
- import { addUsage, getLifetimeTotal, getSessionContextPercent } from "./usage.js";
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.renderRunningAgentStatus = renderRunningAgentStatus;
15
+ exports.default = default_1;
16
+ const node_fs_1 = require("node:fs");
17
+ const node_path_1 = require("node:path");
18
+ const pi_coding_agent_1 = require("@earendil-works/pi-coding-agent");
19
+ const pi_tui_1 = require("@earendil-works/pi-tui");
20
+ const typebox_1 = require("@sinclair/typebox");
21
+ const agent_manager_js_1 = require("./agent-manager.js");
22
+ const agent_runner_js_1 = require("./agent-runner.js");
23
+ const agent_types_js_1 = require("./agent-types.js");
24
+ const cross_extension_rpc_js_1 = require("./cross-extension-rpc.js");
25
+ const custom_agents_js_1 = require("./custom-agents.js");
26
+ const enabled_models_js_1 = require("./enabled-models.js");
27
+ const group_join_js_1 = require("./group-join.js");
28
+ const invocation_config_js_1 = require("./invocation-config.js");
29
+ const model_resolver_js_1 = require("./model-resolver.js");
30
+ const output_file_js_1 = require("./output-file.js");
31
+ const schedule_js_1 = require("./schedule.js");
32
+ const schedule_store_js_1 = require("./schedule-store.js");
33
+ const settings_js_1 = require("./settings.js");
34
+ const status_note_js_1 = require("./status-note.js");
35
+ const agent_widget_js_1 = require("./ui/agent-widget.js");
36
+ const fleet_list_js_1 = require("./ui/fleet-list.js");
37
+ const markdown_result_js_1 = require("./ui/markdown-result.js");
38
+ const schedule_menu_js_1 = require("./ui/schedule-menu.js");
39
+ const usage_js_1 = require("./usage.js");
35
40
  // ---- Shared helpers ----
36
41
  /** Tool execute return value for a text response. */
37
42
  function textResult(msg, details) {
@@ -69,16 +74,16 @@ function abortable(promise, signal) {
69
74
  });
70
75
  });
71
76
  }
72
- export function renderRunningAgentStatus(frame, statsText, activity, theme) {
73
- const container = new Container();
74
- container.addChild(new Text(theme.fg("accent", frame) + (statsText ? " " + statsText : ""), 0, 0));
75
- container.addChild(new Text(theme.fg("dim", ` ⎿ ${activity}`), 0, 0));
77
+ function renderRunningAgentStatus(frame, statsText, activity, theme) {
78
+ const container = new pi_tui_1.Container();
79
+ container.addChild(new pi_tui_1.Text(theme.fg("accent", frame) + (statsText ? " " + statsText : ""), 0, 0));
80
+ container.addChild(new pi_tui_1.Text(theme.fg("dim", ` ⎿ ${activity}`), 0, 0));
76
81
  return container;
77
82
  }
78
83
  /** Format an agent's lifetime token total, or "" when zero. */
79
84
  function formatLifetimeTokens(o) {
80
- const t = getLifetimeTotal(o.lifetimeUsage);
81
- return t > 0 ? formatTokens(t) : "";
85
+ const t = (0, usage_js_1.getLifetimeTotal)(o.lifetimeUsage);
86
+ return t > 0 ? (0, agent_widget_js_1.formatTokens)(t) : "";
82
87
  }
83
88
  /**
84
89
  * Create an AgentActivity state and spawn callbacks for tracking tool usage.
@@ -122,7 +127,7 @@ function createActivityTracker(maxTurns, onStreamUpdate) {
122
127
  state.session = session;
123
128
  },
124
129
  onAssistantUsage: (usage) => {
125
- addUsage(state.lifetimeUsage, usage);
130
+ (0, usage_js_1.addUsage)(state.lifetimeUsage, usage);
126
131
  onStreamUpdate?.();
127
132
  },
128
133
  };
@@ -163,8 +168,8 @@ function escapeXml(s) {
163
168
  function formatTaskNotification(record, resultMaxLen) {
164
169
  const status = getStatusLabel(record.status, record.error);
165
170
  const durationMs = record.completedAt ? record.completedAt - record.startedAt : 0;
166
- const totalTokens = getLifetimeTotal(record.lifetimeUsage);
167
- const contextPercent = getSessionContextPercent(record.session);
171
+ const totalTokens = (0, usage_js_1.getLifetimeTotal)(record.lifetimeUsage);
172
+ const contextPercent = (0, usage_js_1.getSessionContextPercent)(record.session);
168
173
  const ctxXml = contextPercent !== null ? `<context_percent>${Math.round(contextPercent)}</context_percent>` : "";
169
174
  const compactXml = record.compactionCount ? `<compactions>${record.compactionCount}</compactions>` : "";
170
175
  const resultPreview = record.result
@@ -178,7 +183,7 @@ function formatTaskNotification(record, resultMaxLen) {
178
183
  record.toolCallId ? `<tool-use-id>${escapeXml(record.toolCallId)}</tool-use-id>` : null,
179
184
  record.outputFile ? `<output-file>${escapeXml(record.outputFile)}</output-file>` : null,
180
185
  `<status>${escapeXml(status)}</status>`,
181
- `<summary>Agent "${escapeXml(record.description)}" ${record.status}${getStatusNote(record.status)}</summary>`,
186
+ `<summary>Agent "${escapeXml(record.description)}" ${record.status}${(0, status_note_js_1.getStatusNote)(record.status)}</summary>`,
182
187
  `<result>${escapeXml(resultPreview)}</result>`,
183
188
  `<usage><total_tokens>${totalTokens}</total_tokens><tool_uses>${record.toolUses}</tool_uses>${ctxXml}${compactXml}<duration_ms>${durationMs}</duration_ms></usage>`,
184
189
  `</task-notification>`,
@@ -199,9 +204,11 @@ function buildDetails(base, record, activity, overrides) {
199
204
  ...overrides,
200
205
  };
201
206
  }
207
+ /** Maximum expanded notification body retained in message details. */
208
+ const MAX_NOTIFICATION_RESULT_TEXT_LENGTH = 20_000;
202
209
  /** Build notification details for the custom message renderer. */
203
210
  function buildNotificationDetails(record, resultMaxLen, activity) {
204
- const totalTokens = getLifetimeTotal(record.lifetimeUsage);
211
+ const totalTokens = (0, usage_js_1.getLifetimeTotal)(record.lifetimeUsage);
205
212
  return {
206
213
  id: record.id,
207
214
  description: record.description,
@@ -213,6 +220,11 @@ function buildNotificationDetails(record, resultMaxLen, activity) {
213
220
  durationMs: record.completedAt ? record.completedAt - record.startedAt : 0,
214
221
  outputFile: record.outputFile,
215
222
  error: record.error,
223
+ resultText: record.result
224
+ ? record.result.length > MAX_NOTIFICATION_RESULT_TEXT_LENGTH
225
+ ? record.result.slice(0, MAX_NOTIFICATION_RESULT_TEXT_LENGTH) + "…"
226
+ : record.result
227
+ : undefined,
216
228
  resultPreview: record.result
217
229
  ? record.result.length > resultMaxLen
218
230
  ? record.result.slice(0, resultMaxLen) + "…"
@@ -220,7 +232,7 @@ function buildNotificationDetails(record, resultMaxLen, activity) {
220
232
  : "No output.",
221
233
  };
222
234
  }
223
- export default function (pi) {
235
+ function default_1(pi) {
224
236
  // ---- Register custom notification renderer ----
225
237
  pi.registerMessageRenderer("subagent-notification", (message, { expanded }, theme) => {
226
238
  const d = message.details;
@@ -237,40 +249,49 @@ export default function (pi) {
237
249
  // Line 2: stats
238
250
  const parts = [];
239
251
  if (d.turnCount > 0)
240
- parts.push(formatTurns(d.turnCount, d.maxTurns));
252
+ parts.push((0, agent_widget_js_1.formatTurns)(d.turnCount, d.maxTurns));
241
253
  if (d.toolUses > 0)
242
254
  parts.push(`${d.toolUses} tool use${d.toolUses === 1 ? "" : "s"}`);
243
255
  if (d.totalTokens > 0)
244
- parts.push(formatTokens(d.totalTokens));
256
+ parts.push((0, agent_widget_js_1.formatTokens)(d.totalTokens));
245
257
  if (d.durationMs > 0)
246
- parts.push(formatMs(d.durationMs));
258
+ parts.push((0, agent_widget_js_1.formatMs)(d.durationMs));
247
259
  if (parts.length) {
248
260
  line += "\n " + parts.map(p => theme.fg("dim", p)).join(" " + theme.fg("dim", "·") + " ");
249
261
  }
250
- // Line 3: result preview (collapsed) or full (expanded)
251
- if (expanded) {
252
- const lines = d.resultPreview.split("\n").slice(0, 30);
253
- for (const l of lines)
254
- line += "\n" + theme.fg("dim", ` ${l}`);
255
- }
256
- else {
262
+ if (!expanded) {
263
+ // Collapsed previews intentionally remain compact plain text.
257
264
  const preview = d.resultPreview.split("\n")[0]?.slice(0, 80) ?? "";
258
265
  line += "\n " + theme.fg("dim", `⎿ ${preview}`);
266
+ if (d.outputFile) {
267
+ line += "\n " + theme.fg("muted", `transcript: ${d.outputFile}`);
268
+ }
269
+ return line;
259
270
  }
260
- // Line 4: output file link (if present)
271
+ const container = new pi_tui_1.Container();
272
+ container.addChild(new pi_tui_1.Text(line, 0, 0));
273
+ container.addChild((0, markdown_result_js_1.createMarkdownResult)(d.resultText ?? d.resultPreview, theme, 30));
261
274
  if (d.outputFile) {
262
- line += "\n " + theme.fg("muted", `transcript: ${d.outputFile}`);
275
+ container.addChild(new pi_tui_1.Text(theme.fg("muted", ` transcript: ${d.outputFile}`), 0, 0));
263
276
  }
264
- return line;
277
+ return container;
265
278
  }
266
279
  const all = [d, ...(d.others ?? [])];
267
- return new Text(all.map(renderOne).join("\n"), 0, 0);
280
+ if (!expanded)
281
+ return new pi_tui_1.Text(all.map(renderOne).join("\n"), 0, 0);
282
+ const container = new pi_tui_1.Container();
283
+ all.forEach((item, index) => {
284
+ if (index > 0)
285
+ container.addChild(new pi_tui_1.Spacer(1));
286
+ container.addChild(renderOne(item));
287
+ });
288
+ return container;
268
289
  });
269
290
  /** Reload agents from project/global custom agent dirs and merge with defaults (called on init and each Agent invocation). */
270
291
  const reloadCustomAgents = () => {
271
- const userAgents = loadCustomAgents(process.cwd());
272
- registerAgents(userAgents);
273
- applyNicoOverrides();
292
+ const userAgents = (0, custom_agents_js_1.loadCustomAgents)(process.cwd());
293
+ (0, agent_types_js_1.registerAgents)(userAgents);
294
+ (0, agent_types_js_1.applyNicoOverrides)();
274
295
  };
275
296
  // Initial load
276
297
  reloadCustomAgents();
@@ -322,7 +343,7 @@ export default function (pi) {
322
343
  widget.update();
323
344
  }
324
345
  // ---- Group join manager ----
325
- const groupJoin = new GroupJoinManager((records, partial) => {
346
+ const groupJoin = new group_join_js_1.GroupJoinManager((records, partial) => {
326
347
  for (const r of records) {
327
348
  agentActivity.delete(r.id);
328
349
  widget.markFinished(r.id);
@@ -362,7 +383,7 @@ export default function (pi) {
362
383
  // tokens is omitted when nothing was ever produced (e.g. agent errored before
363
384
  // any message_end fired), preserving prior payload shape.
364
385
  const u = record.lifetimeUsage;
365
- const total = getLifetimeTotal(u);
386
+ const total = (0, usage_js_1.getLifetimeTotal)(u);
366
387
  const tokens = total > 0
367
388
  ? { input: u.input, output: u.output, total }
368
389
  : undefined;
@@ -379,7 +400,7 @@ export default function (pi) {
379
400
  };
380
401
  }
381
402
  // Background completion: route through group join or send individual nudge
382
- const manager = new AgentManager((record) => {
403
+ const manager = new agent_manager_js_1.AgentManager((record) => {
383
404
  // Emit lifecycle event based on terminal status
384
405
  const isError = record.status === "error" || record.status === "stopped" || record.status === "aborted";
385
406
  const eventData = buildEventData(record);
@@ -468,14 +489,14 @@ export default function (pi) {
468
489
  // Session-scoped: store is constructed inside session_start once sessionId
469
490
  // is available. Mirrors pi-chonky-tasks's session-scoped task store —
470
491
  // schedules reset on /new, restore on /resume.
471
- const scheduler = new SubagentScheduler();
492
+ const scheduler = new schedule_js_1.SubagentScheduler();
472
493
  function startScheduler(ctx) {
473
494
  try {
474
495
  const sessionId = ctx.sessionManager?.getSessionId?.();
475
496
  if (!sessionId)
476
497
  return; // sessionId not yet available — try again on next event
477
- const path = resolveStorePath(ctx.cwd, sessionId);
478
- const store = new ScheduleStore(path);
498
+ const path = (0, schedule_store_js_1.resolveStorePath)(ctx.cwd, sessionId);
499
+ const store = new schedule_store_js_1.ScheduleStore(path);
479
500
  scheduler.start(pi, ctx, manager, store);
480
501
  pi.events.emit("subagents:scheduler_ready", { sessionId, jobCount: store.list().length });
481
502
  }
@@ -494,7 +515,7 @@ export default function (pi) {
494
515
  // Guard mirrors the `!scheduler.isActive()` pattern below: session_start
495
516
  // fires once per activation, but a double-bind must not leak listeners.
496
517
  if (!rpcHandle) {
497
- rpcHandle = registerRpcHandlers({
518
+ rpcHandle = (0, cross_extension_rpc_js_1.registerRpcHandlers)({
498
519
  events: pi.events,
499
520
  pi,
500
521
  getCtx: () => currentCtx,
@@ -540,10 +561,10 @@ export default function (pi) {
540
561
  // everything else; "off" = hide the widget entirely. Read live at render time.
541
562
  let widgetMode = "background";
542
563
  function getWidgetMode() { return widgetMode; }
543
- const widget = new AgentWidget(manager, agentActivity, getWidgetMode);
564
+ const widget = new agent_widget_js_1.AgentWidget(manager, agentActivity, getWidgetMode);
544
565
  function setWidgetMode(m) { widgetMode = m; widget.update(); }
545
566
  // Claude Code-style FleetView: navigable list of main + subagents below the editor.
546
- const fleet = new FleetList(manager, agentActivity);
567
+ const fleet = new fleet_list_js_1.FleetList(manager, agentActivity);
547
568
  let fleetViewEnabled = true;
548
569
  function isFleetViewEnabled() { return fleetViewEnabled; }
549
570
  function setFleetViewEnabled(b) { fleetViewEnabled = b; fleet.setEnabled(b); }
@@ -584,7 +605,7 @@ export default function (pi) {
584
605
  // State lives in agent-types.ts (isDefaultsDisabled) because registerAgents
585
606
  // needs it; this wrapper just re-registers after flipping it.
586
607
  function setDisableDefaultAgents(b) {
587
- setDefaultsDisabled(b);
608
+ (0, agent_types_js_1.setDefaultsDisabled)(b);
588
609
  reloadCustomAgents(); // re-register with new setting
589
610
  }
590
611
  // ---- Agent tool description mode ----
@@ -647,15 +668,15 @@ export default function (pi) {
647
668
  const tools = cfg?.builtinToolNames;
648
669
  if (!tools || tools.length === 0)
649
670
  return "*";
650
- const isFullSet = tools.length === BUILTIN_TOOL_NAMES.length
651
- && BUILTIN_TOOL_NAMES.every((t) => tools.includes(t));
671
+ const isFullSet = tools.length === agent_types_js_1.BUILTIN_TOOL_NAMES.length
672
+ && agent_types_js_1.BUILTIN_TOOL_NAMES.every((t) => tools.includes(t));
652
673
  return isFullSet ? "*" : tools.join(", ");
653
674
  };
654
675
  /** Build the full type list text dynamically from available agents only. */
655
676
  const buildTypeListText = () => {
656
- const available = getAvailableTypes();
677
+ const available = (0, agent_types_js_1.getAvailableTypes)();
657
678
  return available.map((name) => {
658
- const cfg = getAgentConfig(name);
679
+ const cfg = (0, agent_types_js_1.getAgentConfig)(name);
659
680
  const modelSuffix = cfg?.model ? ` (${getModelLabelFromConfig(cfg.model)})` : "";
660
681
  const toolsSuffix = ` (Tools: ${formatToolsSuffix(cfg)})`;
661
682
  return `- ${name}: ${cfg?.description ?? name}${modelSuffix}${toolsSuffix}`;
@@ -667,8 +688,8 @@ export default function (pi) {
667
688
  return (match ? match[0] : text).replace(/\s+/g, " ").trim();
668
689
  };
669
690
  /** Compact type list: one line per agent, first sentence only. */
670
- const buildCompactTypeListText = () => getAvailableTypes().map((name) => {
671
- const cfg = getAgentConfig(name);
691
+ const buildCompactTypeListText = () => (0, agent_types_js_1.getAvailableTypes)().map((name) => {
692
+ const cfg = (0, agent_types_js_1.getAgentConfig)(name);
672
693
  return `- ${name}: ${firstSentence(cfg?.description ?? name)} (Tools: ${formatToolsSuffix(cfg)})`;
673
694
  }).join("\n");
674
695
  /** Derive a short model label from a model string. */
@@ -681,10 +702,10 @@ export default function (pi) {
681
702
  // Apply persisted settings on startup and emit `subagents:settings_loaded`.
682
703
  // Global + project merged; missing → defaults; corrupt file emits a warning
683
704
  // to stderr and falls back to defaults.
684
- applyAndEmitLoaded({
705
+ (0, settings_js_1.applyAndEmitLoaded)({
685
706
  setMaxConcurrent: (n) => manager.setMaxConcurrent(n),
686
- setDefaultMaxTurns,
687
- setGraceTurns,
707
+ setDefaultMaxTurns: agent_runner_js_1.setDefaultMaxTurns,
708
+ setGraceTurns: agent_runner_js_1.setGraceTurns,
688
709
  setDefaultJoinMode,
689
710
  setSchedulingEnabled,
690
711
  setScopeModels: setScopeModelsEnabled,
@@ -701,7 +722,7 @@ export default function (pi) {
701
722
  // preserves Type.Object's inference when present and produces a
702
723
  // `schedule`-free schema when absent — zero LLM-context cost in disabled mode.
703
724
  const scheduleParamShape = {
704
- schedule: Type.Optional(Type.String({
725
+ schedule: typebox_1.Type.Optional(typebox_1.Type.String({
705
726
  description: 'Opt-in only — fire later instead of now. Omit to run immediately (the default, almost always correct). ' +
706
727
  'Formats: 6-field cron ("0 0 9 * * 1" = 9am Mon), interval ("5m"/"1h"), one-shot ("+10m" or ISO). ' +
707
728
  'Forces run_in_background; incompatible with inherit_context and resume. Returns job ID.',
@@ -717,7 +738,7 @@ export default function (pi) {
717
738
  const compactAgentToolDescription = `Launch an autonomous agent for complex, multi-step tasks. Agent types:
718
739
  ${buildCompactTypeListText()}
719
740
 
720
- Custom agents: .pi/agents/<name>.md (project) or ${getAgentDir()}/agents/<name>.md (global).
741
+ Custom agents: .pi/agents/<name>.md (project) or ${(0, pi_coding_agent_1.getAgentDir)()}/agents/<name>.md (global).
721
742
 
722
743
  Notes:
723
744
  - description: 3-5 words (shown in UI). Prompts must be self-contained — the agent has not seen this conversation.
@@ -730,7 +751,7 @@ Notes:
730
751
  Available agent types and the tools they have access to:
731
752
  ${buildTypeListText()}
732
753
 
733
- Custom agents can be defined in .pi/agents/<name>.md (project) or ${getAgentDir()}/agents/<name>.md (global) — they are picked up automatically. Project-level agents override global ones. Creating a .md file with the same name as a default agent overrides it.
754
+ Custom agents can be defined in .pi/agents/<name>.md (project) or ${(0, pi_coding_agent_1.getAgentDir)()}/agents/<name>.md (global) — they are picked up automatically. Project-level agents override global ones. Creating a .md file with the same name as a default agent overrides it.
734
755
 
735
756
  When using the Agent tool, specify a subagent_type parameter to select which agent type to use.
736
757
 
@@ -775,7 +796,7 @@ Terse command-style prompts produce shallow, generic work.
775
796
  const vars = {
776
797
  typeList: buildTypeListText,
777
798
  compactTypeList: buildCompactTypeListText,
778
- agentDir: getAgentDir,
799
+ agentDir: pi_coding_agent_1.getAgentDir,
779
800
  scheduleGuideline: () => scheduleGuideline,
780
801
  };
781
802
  // Replacement callback (not a string) — agent descriptions may contain `$&` etc.
@@ -788,13 +809,13 @@ Terse command-style prompts produce shallow, generic work.
788
809
  };
789
810
  const loadCustomToolDescription = () => {
790
811
  for (const path of [
791
- join(process.cwd(), ".pi", "agent-tool-description.md"),
792
- join(getAgentDir(), "agent-tool-description.md"),
812
+ (0, node_path_1.join)(process.cwd(), ".pi", "agent-tool-description.md"),
813
+ (0, node_path_1.join)((0, pi_coding_agent_1.getAgentDir)(), "agent-tool-description.md"),
793
814
  ]) {
794
815
  try {
795
- if (!existsSync(path))
816
+ if (!(0, node_fs_1.existsSync)(path))
796
817
  continue;
797
- const text = readFileSync(path, "utf-8").trim();
818
+ const text = (0, node_fs_1.readFileSync)(path, "utf-8").trim();
798
819
  if (text)
799
820
  return renderToolDescriptionTemplate(text);
800
821
  console.warn(`[pi-subagents] ${path} is empty — ignoring`);
@@ -817,8 +838,8 @@ Terse command-style prompts produce shallow, generic work.
817
838
  }
818
839
  return fullAgentToolDescription;
819
840
  })();
820
- pi.registerTool(defineTool({
821
- name: SUBAGENT_TOOL_NAMES.AGENT,
841
+ pi.registerTool((0, pi_coding_agent_1.defineTool)({
842
+ name: agent_runner_js_1.SUBAGENT_TOOL_NAMES.AGENT,
822
843
  label: "Agent",
823
844
  description: agentToolDescription,
824
845
  promptSnippet: "Launch autonomous sub-agents for complex multi-step tasks",
@@ -828,54 +849,54 @@ Terse command-style prompts produce shallow, generic work.
828
849
  "When an agent runs in the background, you will be notified on completion — do not poll or sleep waiting for it. Continue with other work instead.",
829
850
  "Trust but verify: an agent's summary describes intent, not outcome. When an agent writes or edits code, check the actual changes before reporting work as done.",
830
851
  ],
831
- parameters: Type.Object({
832
- prompt: Type.String({
852
+ parameters: typebox_1.Type.Object({
853
+ prompt: typebox_1.Type.String({
833
854
  description: "The task for the agent to perform.",
834
855
  }),
835
- description: Type.String({
856
+ description: typebox_1.Type.String({
836
857
  description: "A short (3-5 word) description of the task (shown in UI).",
837
858
  }),
838
- subagent_type: Type.String({
839
- description: `The type of specialized agent to use. Available types: ${getAvailableTypes().join(", ")}. Custom agents from .pi/agents/*.md (project) or ${getAgentDir()}/agents/*.md (global) are also available.`,
859
+ subagent_type: typebox_1.Type.String({
860
+ description: `The type of specialized agent to use. Available types: ${(0, agent_types_js_1.getAvailableTypes)().join(", ")}. Custom agents from .pi/agents/*.md (project) or ${(0, pi_coding_agent_1.getAgentDir)()}/agents/*.md (global) are also available.`,
840
861
  }),
841
- model: Type.Optional(Type.String({
862
+ model: typebox_1.Type.Optional(typebox_1.Type.String({
842
863
  description: 'Optional model override. Accepts "provider/modelId" or fuzzy name (e.g. "haiku", "sonnet"). Omit to use the agent type\'s default.',
843
864
  })),
844
- thinking: Type.Optional(Type.String({
865
+ thinking: typebox_1.Type.Optional(typebox_1.Type.String({
845
866
  description: `Thinking level: ${THINKING_LEVELS.join(", ")}. Overrides agent default.`,
846
867
  })),
847
- max_turns: Type.Optional(Type.Number({
868
+ max_turns: typebox_1.Type.Optional(typebox_1.Type.Number({
848
869
  description: "Maximum number of agentic turns before stopping. Omit for unlimited (default).",
849
870
  minimum: 1,
850
871
  })),
851
- run_in_background: Type.Optional(Type.Boolean({
872
+ run_in_background: typebox_1.Type.Optional(typebox_1.Type.Boolean({
852
873
  description: "Set to true to run in background. Returns agent ID immediately. You will be notified on completion.",
853
874
  })),
854
- resume: Type.Optional(Type.String({
875
+ resume: typebox_1.Type.Optional(typebox_1.Type.String({
855
876
  description: "Optional agent ID to resume from. Continues from previous context.",
856
877
  })),
857
- isolated: Type.Optional(Type.Boolean({
878
+ isolated: typebox_1.Type.Optional(typebox_1.Type.Boolean({
858
879
  description: "If true, agent gets no extension/MCP tools — only built-in tools.",
859
880
  })),
860
- inherit_context: Type.Optional(Type.Boolean({
881
+ inherit_context: typebox_1.Type.Optional(typebox_1.Type.Boolean({
861
882
  description: "If true, fork parent conversation into the agent. Default: false (fresh context).",
862
883
  })),
863
- isolation: Type.Optional(Type.Literal("worktree", {
884
+ isolation: typebox_1.Type.Optional(typebox_1.Type.Literal("worktree", {
864
885
  description: 'Set to "worktree" to run the agent in a temporary git worktree (isolated copy of the repo). Changes are saved to a branch on completion.',
865
886
  })),
866
887
  ...scheduleParam,
867
888
  }),
868
889
  // ---- Custom rendering: Claude Code style ----
869
890
  renderCall(args, theme) {
870
- const displayName = args.subagent_type ? getDisplayName(args.subagent_type) : "Agent";
891
+ const displayName = args.subagent_type ? (0, agent_widget_js_1.getDisplayName)(args.subagent_type) : "Agent";
871
892
  const desc = args.description ?? "";
872
- return new Text("▸ " + theme.fg("toolTitle", theme.bold(displayName)) + (desc ? " " + theme.fg("muted", desc) : ""), 0, 0);
893
+ return new pi_tui_1.Text("▸ " + theme.fg("toolTitle", theme.bold(displayName)) + (desc ? " " + theme.fg("muted", desc) : ""), 0, 0);
873
894
  },
874
895
  renderResult(result, { expanded, isPartial }, theme) {
875
896
  const details = result.details;
876
897
  if (!details) {
877
898
  const text = result.content[0]?.type === "text" ? result.content[0].text : "";
878
- return new Text(text, 0, 0);
899
+ return new pi_tui_1.Text(text, 0, 0);
879
900
  }
880
901
  // Helper: build "haiku · thinking: high · ↻5≤30 · 3 tool uses · 33.8k tokens" stats string
881
902
  const stats = (d) => {
@@ -885,27 +906,27 @@ Terse command-style prompts produce shallow, generic work.
885
906
  if (d.tags)
886
907
  parts.push(...d.tags);
887
908
  if (d.turnCount != null && d.turnCount > 0) {
888
- parts.push(formatTurns(d.turnCount, d.maxTurns));
909
+ parts.push((0, agent_widget_js_1.formatTurns)(d.turnCount, d.maxTurns));
889
910
  }
890
911
  if (d.toolUses > 0)
891
912
  parts.push(`${d.toolUses} tool use${d.toolUses === 1 ? "" : "s"}`);
892
913
  if (d.tokens)
893
914
  parts.push(d.tokens);
894
- return parts.map(p => fgPreservingNestedStyles(theme, "dim", p)).join(" " + theme.fg("dim", "·") + " ");
915
+ return parts.map(p => (0, agent_widget_js_1.fgPreservingNestedStyles)(theme, "dim", p)).join(" " + theme.fg("dim", "·") + " ");
895
916
  };
896
917
  // ---- While running (streaming) ----
897
918
  if (isPartial || details.status === "running") {
898
- const frame = SPINNER[details.spinnerFrame ?? 0];
919
+ const frame = agent_widget_js_1.SPINNER[details.spinnerFrame ?? 0];
899
920
  const s = stats(details);
900
921
  return renderRunningAgentStatus(frame, s, details.activity ?? "thinking…", theme);
901
922
  }
902
923
  // ---- Background agent launched ----
903
924
  if (details.status === "background") {
904
- return new Text(theme.fg("dim", ` ⎿ Running in background (ID: ${details.agentId})`), 0, 0);
925
+ return new pi_tui_1.Text(theme.fg("dim", ` ⎿ Running in background (ID: ${details.agentId})`), 0, 0);
905
926
  }
906
927
  // ---- Completed / Steered ----
907
928
  if (details.status === "completed" || details.status === "steered") {
908
- const duration = formatMs(details.durationMs);
929
+ const duration = (0, agent_widget_js_1.formatMs)(details.durationMs);
909
930
  const isSteered = details.status === "steered";
910
931
  const icon = isSteered ? theme.fg("warning", "✓") : theme.fg("success", "✓");
911
932
  const s = stats(details);
@@ -913,28 +934,28 @@ Terse command-style prompts produce shallow, generic work.
913
934
  line += " " + theme.fg("dim", "·") + " " + theme.fg("dim", duration);
914
935
  if (expanded) {
915
936
  const resultText = result.content[0]?.type === "text" ? result.content[0].text : "";
937
+ const container = new pi_tui_1.Container();
938
+ container.addChild(new pi_tui_1.Text(line, 0, 0));
916
939
  if (resultText) {
917
- const lines = resultText.split("\n").slice(0, 50);
918
- for (const l of lines) {
919
- line += "\n" + theme.fg("dim", ` ${l}`);
920
- }
940
+ container.addChild((0, markdown_result_js_1.createMarkdownResult)(resultText, theme, 50));
921
941
  if (resultText.split("\n").length > 50) {
922
- line += "\n" + theme.fg("muted", " ... (use get_subagent_result with verbose for full output)");
942
+ container.addChild(new pi_tui_1.Text(theme.fg("muted", " ... (use get_subagent_result with verbose for full output)"), 0, 0));
923
943
  }
924
944
  }
945
+ return container;
925
946
  }
926
947
  else {
927
948
  const doneText = isSteered ? "Wrapped up (turn limit)" : "Done";
928
949
  line += "\n" + theme.fg("dim", ` ⎿ ${doneText}`);
929
950
  }
930
- return new Text(line, 0, 0);
951
+ return new pi_tui_1.Text(line, 0, 0);
931
952
  }
932
953
  // ---- Stopped (user-initiated abort) ----
933
954
  if (details.status === "stopped") {
934
955
  const s = stats(details);
935
956
  let line = theme.fg("dim", "■") + (s ? " " + s : "");
936
957
  line += "\n" + theme.fg("dim", " ⎿ Stopped");
937
- return new Text(line, 0, 0);
958
+ return new pi_tui_1.Text(line, 0, 0);
938
959
  }
939
960
  // ---- Error / Aborted (hard max_turns) ----
940
961
  const s = stats(details);
@@ -945,7 +966,7 @@ Terse command-style prompts produce shallow, generic work.
945
966
  else {
946
967
  line += "\n" + theme.fg("warning", " ⎿ Aborted (max turns exceeded)");
947
968
  }
948
- return new Text(line, 0, 0);
969
+ return new pi_tui_1.Text(line, 0, 0);
949
970
  },
950
971
  // ---- Execute ----
951
972
  execute: async (toolCallId, params, signal, onUpdate, ctx) => {
@@ -954,17 +975,17 @@ Terse command-style prompts produce shallow, generic work.
954
975
  // Reload custom agents so new project/global .md files are picked up without restart
955
976
  reloadCustomAgents();
956
977
  const rawType = params.subagent_type;
957
- const resolved = resolveType(rawType);
978
+ const resolved = (0, agent_types_js_1.resolveType)(rawType);
958
979
  const subagentType = resolved ?? "general-purpose";
959
980
  const fellBack = resolved === undefined;
960
- const displayName = getDisplayName(subagentType);
981
+ const displayName = (0, agent_widget_js_1.getDisplayName)(subagentType);
961
982
  // Get agent config (if any)
962
- const customConfig = getAgentConfig(subagentType);
963
- const resolvedConfig = resolveAgentInvocationConfig(customConfig, params);
983
+ const customConfig = (0, agent_types_js_1.getAgentConfig)(subagentType);
984
+ const resolvedConfig = (0, invocation_config_js_1.resolveAgentInvocationConfig)(customConfig, params);
964
985
  // Resolve model from agent config first; tool-call params only fill gaps.
965
986
  let model = ctx.model;
966
987
  if (resolvedConfig.modelInput) {
967
- const resolved = resolveModel(resolvedConfig.modelInput, ctx.modelRegistry);
988
+ const resolved = (0, model_resolver_js_1.resolveModel)(resolvedConfig.modelInput, ctx.modelRegistry);
968
989
  if (typeof resolved === "string") {
969
990
  if (resolvedConfig.modelFromParams)
970
991
  return textResult(resolved);
@@ -984,8 +1005,8 @@ Terse command-style prompts produce shallow, generic work.
984
1005
  // user authored/installed this agent or chose the parent's model; trust it).
985
1006
  // See SubagentsSettings.scopeModels docstring for the full policy.
986
1007
  if (isScopeModelsEnabled() && model) {
987
- const allowed = resolveEnabledModels(readEnabledModels(ctx.cwd), ctx.modelRegistry, ctx.cwd);
988
- if (allowed && !isModelInScope(model, allowed)) {
1008
+ const allowed = (0, enabled_models_js_1.resolveEnabledModels)((0, enabled_models_js_1.readEnabledModels)(ctx.cwd), ctx.modelRegistry, ctx.cwd);
1009
+ if (allowed && !(0, enabled_models_js_1.isModelInScope)(model, allowed)) {
989
1010
  if (resolvedConfig.modelFromParams) {
990
1011
  const list = [...allowed].sort().map(m => ` ${m}`).join("\n");
991
1012
  return textResult(`Model not in scope: "${resolvedConfig.modelInput}".\n\n` +
@@ -1011,29 +1032,29 @@ Terse command-style prompts produce shallow, generic work.
1011
1032
  const attachTranscript = (rec, agentId) => {
1012
1033
  if (!rec || !outputTranscript)
1013
1034
  return;
1014
- rec.outputFile = createOutputFilePath(ctx.cwd, agentId, ctx.sessionManager.getSessionId());
1015
- writeInitialEntry(rec.outputFile, agentId, params.prompt, ctx.cwd);
1035
+ rec.outputFile = (0, output_file_js_1.createOutputFilePath)(ctx.cwd, agentId, ctx.sessionManager.getSessionId());
1036
+ (0, output_file_js_1.writeInitialEntry)(rec.outputFile, agentId, params.prompt, ctx.cwd);
1016
1037
  };
1017
1038
  const parentModelId = ctx.model?.id;
1018
1039
  const effectiveModelId = model?.id;
1019
1040
  const modelName = effectiveModelId && effectiveModelId !== parentModelId
1020
1041
  ? (model?.name ?? effectiveModelId).replace(/^Claude\s+/i, "").toLowerCase()
1021
1042
  : undefined;
1022
- const effectiveMaxTurns = normalizeMaxTurns(resolvedConfig.maxTurns ?? getDefaultMaxTurns());
1043
+ const effectiveMaxTurns = (0, agent_runner_js_1.normalizeMaxTurns)(resolvedConfig.maxTurns ?? (0, agent_runner_js_1.getDefaultMaxTurns)());
1023
1044
  const agentInvocation = {
1024
1045
  modelName,
1025
1046
  thinking,
1026
1047
  // Explicit value only — the default fallback would just add noise.
1027
1048
  // Normalize so `0` (unlimited) doesn't surface as a misleading "max turns: 0".
1028
- maxTurns: normalizeMaxTurns(resolvedConfig.maxTurns),
1049
+ maxTurns: (0, agent_runner_js_1.normalizeMaxTurns)(resolvedConfig.maxTurns),
1029
1050
  isolated,
1030
1051
  inheritContext,
1031
1052
  runInBackground,
1032
1053
  isolation,
1033
1054
  };
1034
1055
  // Tool-result render shows the mode label too; viewer's header already does.
1035
- const modeLabel = getPromptModeLabel(subagentType);
1036
- const { tags: invocationTags } = buildInvocationTags(agentInvocation);
1056
+ const modeLabel = (0, agent_widget_js_1.getPromptModeLabel)(subagentType);
1057
+ const { tags: invocationTags } = (0, agent_widget_js_1.buildInvocationTags)(agentInvocation);
1037
1058
  const agentTags = modeLabel ? [modeLabel, ...invocationTags] : invocationTags;
1038
1059
  const detailBase = {
1039
1060
  displayName,
@@ -1113,7 +1134,7 @@ Terse command-style prompts produce shallow, generic work.
1113
1134
  origBgOnSession(session);
1114
1135
  const rec = manager.getRecord(id);
1115
1136
  if (rec?.outputFile) {
1116
- rec.outputCleanup = streamToOutputFile(session, rec.outputFile, id, ctx.cwd);
1137
+ rec.outputCleanup = (0, output_file_js_1.streamToOutputFile)(session, rec.outputFile, id, ctx.cwd);
1117
1138
  }
1118
1139
  };
1119
1140
  try {
@@ -1135,7 +1156,7 @@ Terse command-style prompts produce shallow, generic work.
1135
1156
  }
1136
1157
  // Set output file + join mode synchronously after spawn, before the
1137
1158
  // event loop yields — onSessionCreated is async so this is safe.
1138
- const joinMode = resolveJoinMode(defaultJoinMode, true);
1159
+ const joinMode = (0, invocation_config_js_1.resolveJoinMode)(defaultJoinMode, true);
1139
1160
  const record = manager.getRecord(id);
1140
1161
  if (record && joinMode) {
1141
1162
  record.joinMode = joinMode;
@@ -1190,8 +1211,8 @@ Terse command-style prompts produce shallow, generic work.
1190
1211
  maxTurns: fgState.maxTurns,
1191
1212
  durationMs: Date.now() - startedAt,
1192
1213
  status: "running",
1193
- activity: describeActivity(fgState.activeTools, fgState.responseText),
1194
- spinnerFrame: spinnerFrame % SPINNER.length,
1214
+ activity: (0, agent_widget_js_1.describeActivity)(fgState.activeTools, fgState.responseText),
1215
+ spinnerFrame: spinnerFrame % agent_widget_js_1.SPINNER.length,
1195
1216
  };
1196
1217
  onUpdate?.({
1197
1218
  content: [{ type: "text", text: `${fgState.toolUses} tool uses...` }],
@@ -1219,7 +1240,7 @@ Terse command-style prompts produce shallow, generic work.
1219
1240
  if (fgId) {
1220
1241
  const rec = manager.getRecord(fgId);
1221
1242
  if (rec?.outputFile) {
1222
- rec.outputCleanup = streamToOutputFile(session, rec.outputFile, fgId, ctx.cwd);
1243
+ rec.outputCleanup = (0, output_file_js_1.streamToOutputFile)(session, rec.outputFile, fgId, ctx.cwd);
1223
1244
  }
1224
1245
  }
1225
1246
  };
@@ -1267,7 +1288,7 @@ Terse command-style prompts produce shallow, generic work.
1267
1288
  // "general-purpose" may itself be unregistered (defaults disabled, no
1268
1289
  // user override) — getConfig then uses the hardcoded fallback config.
1269
1290
  const fallbackNote = fellBack
1270
- ? `Note: Unknown agent type "${rawType}" — using ${resolveType("general-purpose") ? "general-purpose" : "the fallback agent config"}.\n\n`
1291
+ ? `Note: Unknown agent type "${rawType}" — using ${(0, agent_types_js_1.resolveType)("general-purpose") ? "general-purpose" : "the fallback agent config"}.\n\n`
1271
1292
  : "";
1272
1293
  if (record.status === "error") {
1273
1294
  // Error headline + any partial output the run produced before failing.
@@ -1277,24 +1298,24 @@ Terse command-style prompts produce shallow, generic work.
1277
1298
  const statsParts = [`${record.toolUses} tool uses`];
1278
1299
  if (tokenText)
1279
1300
  statsParts.push(tokenText);
1280
- return textResult(`${fallbackNote}Agent completed in ${formatMs(durationMs)} (${statsParts.join(", ")})${getStatusNote(record.status)}.\n\n` +
1301
+ return textResult(`${fallbackNote}Agent completed in ${(0, agent_widget_js_1.formatMs)(durationMs)} (${statsParts.join(", ")})${(0, status_note_js_1.getStatusNote)(record.status)}.\n\n` +
1281
1302
  (record.result?.trim() || "No output."), details);
1282
1303
  },
1283
1304
  }));
1284
1305
  // ---- get_subagent_result tool ----
1285
- pi.registerTool(defineTool({
1286
- name: SUBAGENT_TOOL_NAMES.GET_RESULT,
1306
+ pi.registerTool((0, pi_coding_agent_1.defineTool)({
1307
+ name: agent_runner_js_1.SUBAGENT_TOOL_NAMES.GET_RESULT,
1287
1308
  label: "Get Agent Result",
1288
1309
  description: "Check status and retrieve results from a background agent. Use the agent ID returned by Agent with run_in_background.",
1289
1310
  promptSnippet: "Check status and retrieve results from a background agent",
1290
- parameters: Type.Object({
1291
- agent_id: Type.String({
1311
+ parameters: typebox_1.Type.Object({
1312
+ agent_id: typebox_1.Type.String({
1292
1313
  description: "The agent ID to check.",
1293
1314
  }),
1294
- wait: Type.Optional(Type.Boolean({
1315
+ wait: typebox_1.Type.Optional(typebox_1.Type.Boolean({
1295
1316
  description: "If true, wait for the agent to complete before returning. Default: false.",
1296
1317
  })),
1297
- verbose: Type.Optional(Type.Boolean({
1318
+ verbose: typebox_1.Type.Optional(typebox_1.Type.Boolean({
1298
1319
  description: "If true, include the agent's full conversation (messages + tool calls). Default: false.",
1299
1320
  })),
1300
1321
  }),
@@ -1315,10 +1336,10 @@ Terse command-style prompts produce shallow, generic work.
1315
1336
  if (record.promise)
1316
1337
  await abortable(record.promise, signal);
1317
1338
  }
1318
- const displayName = getDisplayName(record.type);
1319
- const duration = formatDuration(record.startedAt, record.completedAt);
1339
+ const displayName = (0, agent_widget_js_1.getDisplayName)(record.type);
1340
+ const duration = (0, agent_widget_js_1.formatDuration)(record.startedAt, record.completedAt);
1320
1341
  const tokens = formatLifetimeTokens(record);
1321
- const contextPercent = getSessionContextPercent(record.session);
1342
+ const contextPercent = (0, usage_js_1.getSessionContextPercent)(record.session);
1322
1343
  const statsParts = [`Tool uses: ${record.toolUses}`];
1323
1344
  if (tokens)
1324
1345
  statsParts.push(tokens);
@@ -1328,7 +1349,7 @@ Terse command-style prompts produce shallow, generic work.
1328
1349
  statsParts.push(`Compactions: ${record.compactionCount}`);
1329
1350
  statsParts.push(`Duration: ${duration}`);
1330
1351
  let output = `Agent: ${record.id}\n` +
1331
- `Type: ${displayName} | Status: ${record.status}${getStatusNote(record.status)} | ${statsParts.join(" | ")}\n` +
1352
+ `Type: ${displayName} | Status: ${record.status}${(0, status_note_js_1.getStatusNote)(record.status)} | ${statsParts.join(" | ")}\n` +
1332
1353
  `Description: ${record.description}\n\n`;
1333
1354
  if (record.status === "running") {
1334
1355
  output += "Agent is still running. Use wait: true or check back later.";
@@ -1346,7 +1367,7 @@ Terse command-style prompts produce shallow, generic work.
1346
1367
  }
1347
1368
  // Verbose: include full conversation
1348
1369
  if (params.verbose && record.session) {
1349
- const conversation = getAgentConversation(record.session);
1370
+ const conversation = (0, agent_runner_js_1.getAgentConversation)(record.session);
1350
1371
  if (conversation) {
1351
1372
  output += `\n\n--- Agent Conversation ---\n${conversation}`;
1352
1373
  }
@@ -1355,17 +1376,17 @@ Terse command-style prompts produce shallow, generic work.
1355
1376
  },
1356
1377
  }));
1357
1378
  // ---- steer_subagent tool ----
1358
- pi.registerTool(defineTool({
1359
- name: SUBAGENT_TOOL_NAMES.STEER,
1379
+ pi.registerTool((0, pi_coding_agent_1.defineTool)({
1380
+ name: agent_runner_js_1.SUBAGENT_TOOL_NAMES.STEER,
1360
1381
  label: "Steer Agent",
1361
1382
  description: "Send a steering message to a running agent. The message will interrupt the agent after its current tool execution " +
1362
1383
  "and be injected into its conversation, allowing you to redirect its work mid-run. Only works on running agents.",
1363
1384
  promptSnippet: "Send a steering message to redirect a running background agent",
1364
- parameters: Type.Object({
1365
- agent_id: Type.String({
1385
+ parameters: typebox_1.Type.Object({
1386
+ agent_id: typebox_1.Type.String({
1366
1387
  description: "The agent ID to steer (must be currently running).",
1367
1388
  }),
1368
- message: Type.String({
1389
+ message: typebox_1.Type.String({
1369
1390
  description: "The steering message to send. This will appear as a user message in the agent's conversation.",
1370
1391
  }),
1371
1392
  }),
@@ -1386,10 +1407,10 @@ Terse command-style prompts produce shallow, generic work.
1386
1407
  return textResult(`Steering message queued for agent ${record.id}. It will be delivered once the session initializes.`);
1387
1408
  }
1388
1409
  try {
1389
- await steerAgent(record.session, params.message);
1410
+ await (0, agent_runner_js_1.steerAgent)(record.session, params.message);
1390
1411
  pi.events.emit("subagents:steered", { id: record.id, message: params.message });
1391
1412
  const tokens = formatLifetimeTokens(record);
1392
- const contextPercent = getSessionContextPercent(record.session);
1413
+ const contextPercent = (0, usage_js_1.getSessionContextPercent)(record.session);
1393
1414
  const stateParts = [];
1394
1415
  if (tokens)
1395
1416
  stateParts.push(tokens);
@@ -1407,30 +1428,30 @@ Terse command-style prompts produce shallow, generic work.
1407
1428
  },
1408
1429
  }));
1409
1430
  // ---- /agents interactive menu ----
1410
- const projectAgentsDir = () => join(process.cwd(), ".pi", "agents");
1411
- const workspaceAgentsDir = () => join(process.cwd(), ".agents", "agents");
1412
- const personalAgentsDir = () => join(getAgentDir(), "agents");
1431
+ const projectAgentsDir = () => (0, node_path_1.join)(process.cwd(), ".pi", "agents");
1432
+ const workspaceAgentsDir = () => (0, node_path_1.join)(process.cwd(), ".agents", "agents");
1433
+ const personalAgentsDir = () => (0, node_path_1.join)((0, pi_coding_agent_1.getAgentDir)(), "agents");
1413
1434
  /** Find the file path of a custom agent by name, in discovery-precedence order (project, workspace, then global). */
1414
1435
  function findAgentFile(name) {
1415
- const projectPath = join(projectAgentsDir(), `${name}.md`);
1416
- if (existsSync(projectPath))
1436
+ const projectPath = (0, node_path_1.join)(projectAgentsDir(), `${name}.md`);
1437
+ if ((0, node_fs_1.existsSync)(projectPath))
1417
1438
  return { path: projectPath, location: "project" };
1418
- const workspacePath = join(workspaceAgentsDir(), `${name}.md`);
1419
- if (existsSync(workspacePath))
1439
+ const workspacePath = (0, node_path_1.join)(workspaceAgentsDir(), `${name}.md`);
1440
+ if ((0, node_fs_1.existsSync)(workspacePath))
1420
1441
  return { path: workspacePath, location: "workspace" };
1421
- const personalPath = join(personalAgentsDir(), `${name}.md`);
1422
- if (existsSync(personalPath))
1442
+ const personalPath = (0, node_path_1.join)(personalAgentsDir(), `${name}.md`);
1443
+ if ((0, node_fs_1.existsSync)(personalPath))
1423
1444
  return { path: personalPath, location: "personal" };
1424
1445
  return undefined;
1425
1446
  }
1426
1447
  function getModelLabel(type, registry) {
1427
- const cfg = getAgentConfig(type);
1448
+ const cfg = (0, agent_types_js_1.getAgentConfig)(type);
1428
1449
  if (!cfg?.model)
1429
1450
  return "inherit"; // no model configured → really inherits parent
1430
1451
  const label = getModelLabelFromConfig(cfg.model);
1431
1452
  if (!registry)
1432
1453
  return label;
1433
- const resolved = resolveModel(cfg.model, registry);
1454
+ const resolved = (0, model_resolver_js_1.resolveModel)(cfg.model, registry);
1434
1455
  // Configured but unresolvable: the runtime silently falls back to the parent
1435
1456
  // model, so flag it (and the fallback) rather than hiding the config.
1436
1457
  if (typeof resolved === "string")
@@ -1446,7 +1467,7 @@ Terse command-style prompts produce shallow, generic work.
1446
1467
  }
1447
1468
  async function showAgentsMenu(ctx) {
1448
1469
  reloadCustomAgents();
1449
- const allNames = getAllTypes();
1470
+ const allNames = (0, agent_types_js_1.getAllTypes)();
1450
1471
  // Build select options
1451
1472
  const options = [];
1452
1473
  // Running agents entry (only if there are active agents)
@@ -1488,7 +1509,7 @@ Terse command-style prompts produce shallow, generic work.
1488
1509
  await showAgentsMenu(ctx);
1489
1510
  }
1490
1511
  else if (choice.startsWith("Scheduled jobs (")) {
1491
- await showSchedulesMenu(ctx, scheduler);
1512
+ await (0, schedule_menu_js_1.showSchedulesMenu)(ctx, scheduler);
1492
1513
  await showAgentsMenu(ctx);
1493
1514
  }
1494
1515
  else if (choice === "Create new agent") {
@@ -1500,7 +1521,7 @@ Terse command-style prompts produce shallow, generic work.
1500
1521
  }
1501
1522
  }
1502
1523
  async function showAllAgentsList(ctx) {
1503
- const allNames = getAllTypes();
1524
+ const allNames = (0, agent_types_js_1.getAllTypes)();
1504
1525
  if (allNames.length === 0) {
1505
1526
  ctx.ui.notify("No agents.", "info");
1506
1527
  return;
@@ -1521,7 +1542,7 @@ Terse command-style prompts produce shallow, generic work.
1521
1542
  // full description renders below the highlighted row via SettingsList,
1522
1543
  // exactly like the Settings menu — so long descriptions never wrap the list.
1523
1544
  const items = allNames.map(name => {
1524
- const cfg = getAgentConfig(name);
1545
+ const cfg = (0, agent_types_js_1.getAgentConfig)(name);
1525
1546
  const disabled = cfg?.enabled === false;
1526
1547
  const model = getModelLabel(name, ctx.modelRegistry);
1527
1548
  return {
@@ -1534,22 +1555,22 @@ Terse command-style prompts produce shallow, generic work.
1534
1555
  values: [model],
1535
1556
  };
1536
1557
  });
1537
- const hasCustom = allNames.some(n => { const c = getAgentConfig(n); return c && !c.isDefault && c.enabled !== false; });
1538
- const hasDisabled = allNames.some(n => getAgentConfig(n)?.enabled === false);
1558
+ const hasCustom = allNames.some(n => { const c = (0, agent_types_js_1.getAgentConfig)(n); return c && !c.isDefault && c.enabled !== false; });
1559
+ const hasDisabled = allNames.some(n => (0, agent_types_js_1.getAgentConfig)(n)?.enabled === false);
1539
1560
  const legendParts = [];
1540
1561
  if (hasCustom)
1541
1562
  legendParts.push("• = project ◦ = global");
1542
1563
  if (hasDisabled)
1543
1564
  legendParts.push("✕ = disabled");
1544
1565
  const selected = await ctx.ui.custom((_tui, _theme, _kb, done) => {
1545
- const slTheme = getSettingsListTheme();
1546
- const list = new SettingsList(items, Math.min(items.length, 12), slTheme, id => done(id), // Enter/Space on a row → return that agent's name
1566
+ const slTheme = (0, pi_coding_agent_1.getSettingsListTheme)();
1567
+ const list = new pi_tui_1.SettingsList(items, Math.min(items.length, 12), slTheme, id => done(id), // Enter/Space on a row → return that agent's name
1547
1568
  () => done(undefined));
1548
- const container = new Container();
1549
- container.addChild(new Text("Agent types", 0, 0));
1569
+ const container = new pi_tui_1.Container();
1570
+ container.addChild(new pi_tui_1.Text("Agent types", 0, 0));
1550
1571
  if (legendParts.length)
1551
- container.addChild(new Text(slTheme.hint(legendParts.join(" ")), 0, 0));
1552
- container.addChild(new Spacer(1));
1572
+ container.addChild(new pi_tui_1.Text(slTheme.hint(legendParts.join(" ")), 0, 0));
1573
+ container.addChild(new pi_tui_1.Spacer(1));
1553
1574
  container.addChild(list);
1554
1575
  return {
1555
1576
  render: (w) => container.render(w),
@@ -1557,7 +1578,7 @@ Terse command-style prompts produce shallow, generic work.
1557
1578
  handleInput: (data) => list.handleInput?.(data),
1558
1579
  };
1559
1580
  });
1560
- if (selected && getAgentConfig(selected)) {
1581
+ if (selected && (0, agent_types_js_1.getAgentConfig)(selected)) {
1561
1582
  await showAgentDetail(ctx, selected);
1562
1583
  await showAllAgentsList(ctx);
1563
1584
  }
@@ -1569,8 +1590,8 @@ Terse command-style prompts produce shallow, generic work.
1569
1590
  return;
1570
1591
  }
1571
1592
  const options = agents.map(a => {
1572
- const dn = getDisplayName(a.type);
1573
- const dur = formatDuration(a.startedAt, a.completedAt);
1593
+ const dn = (0, agent_widget_js_1.getDisplayName)(a.type);
1594
+ const dur = (0, agent_widget_js_1.formatDuration)(a.startedAt, a.completedAt);
1574
1595
  return `${dn} (${a.description}) · ${a.toolUses} tools · ${a.status} · ${dur}`;
1575
1596
  });
1576
1597
  const choice = await ctx.ui.select("Running agents", options);
@@ -1605,7 +1626,7 @@ Terse command-style prompts produce shallow, generic work.
1605
1626
  });
1606
1627
  }
1607
1628
  async function showAgentDetail(ctx, name) {
1608
- const cfg = getAgentConfig(name);
1629
+ const cfg = (0, agent_types_js_1.getAgentConfig)(name);
1609
1630
  if (!cfg) {
1610
1631
  ctx.ui.notify(`Agent config not found for "${name}".`, "warning");
1611
1632
  return;
@@ -1636,7 +1657,7 @@ Terse command-style prompts produce shallow, generic work.
1636
1657
  if (!choice || choice === "Back")
1637
1658
  return;
1638
1659
  if (choice === "Edit" && file) {
1639
- const content = readFileSync(file.path, "utf-8");
1660
+ const content = (0, node_fs_1.readFileSync)(file.path, "utf-8");
1640
1661
  const edited = await ctx.ui.editor(`Edit ${name}`, content);
1641
1662
  if (edited !== undefined && edited !== content) {
1642
1663
  const { writeFileSync } = await import("node:fs");
@@ -1649,7 +1670,7 @@ Terse command-style prompts produce shallow, generic work.
1649
1670
  if (file) {
1650
1671
  const confirmed = await ctx.ui.confirm("Delete agent", `Delete ${name} from ${file.location} (${file.path})?`);
1651
1672
  if (confirmed) {
1652
- unlinkSync(file.path);
1673
+ (0, node_fs_1.unlinkSync)(file.path);
1653
1674
  reloadCustomAgents();
1654
1675
  ctx.ui.notify(`Deleted ${file.path}`, "info");
1655
1676
  }
@@ -1658,7 +1679,7 @@ Terse command-style prompts produce shallow, generic work.
1658
1679
  else if (choice === "Reset to default" && file) {
1659
1680
  const confirmed = await ctx.ui.confirm("Reset to default", `Delete override ${file.path} and restore embedded default?`);
1660
1681
  if (confirmed) {
1661
- unlinkSync(file.path);
1682
+ (0, node_fs_1.unlinkSync)(file.path);
1662
1683
  reloadCustomAgents();
1663
1684
  ctx.ui.notify(`Restored default ${name}`, "info");
1664
1685
  }
@@ -1682,9 +1703,9 @@ Terse command-style prompts produce shallow, generic work.
1682
1703
  if (!location)
1683
1704
  return;
1684
1705
  const targetDir = location.startsWith("Project") ? projectAgentsDir() : personalAgentsDir();
1685
- mkdirSync(targetDir, { recursive: true });
1686
- const targetPath = join(targetDir, `${name}.md`);
1687
- if (existsSync(targetPath)) {
1706
+ (0, node_fs_1.mkdirSync)(targetDir, { recursive: true });
1707
+ const targetPath = (0, node_path_1.join)(targetDir, `${name}.md`);
1708
+ if ((0, node_fs_1.existsSync)(targetPath)) {
1688
1709
  const overwrite = await ctx.ui.confirm("Overwrite", `${targetPath} already exists. Overwrite?`);
1689
1710
  if (!overwrite)
1690
1711
  return;
@@ -1737,7 +1758,7 @@ Terse command-style prompts produce shallow, generic work.
1737
1758
  const file = findAgentFile(name);
1738
1759
  if (file) {
1739
1760
  // Existing file — set enabled: false in frontmatter (idempotent)
1740
- const content = readFileSync(file.path, "utf-8");
1761
+ const content = (0, node_fs_1.readFileSync)(file.path, "utf-8");
1741
1762
  if (content.includes("\nenabled: false\n")) {
1742
1763
  ctx.ui.notify(`${name} is already disabled.`, "info");
1743
1764
  return;
@@ -1757,8 +1778,8 @@ Terse command-style prompts produce shallow, generic work.
1757
1778
  if (!location)
1758
1779
  return;
1759
1780
  const targetDir = location.startsWith("Project") ? projectAgentsDir() : personalAgentsDir();
1760
- mkdirSync(targetDir, { recursive: true });
1761
- const targetPath = join(targetDir, `${name}.md`);
1781
+ (0, node_fs_1.mkdirSync)(targetDir, { recursive: true });
1782
+ const targetPath = (0, node_path_1.join)(targetDir, `${name}.md`);
1762
1783
  const { writeFileSync } = await import("node:fs");
1763
1784
  writeFileSync(targetPath, "---\nenabled: false\n---\n", "utf-8");
1764
1785
  reloadCustomAgents();
@@ -1769,12 +1790,12 @@ Terse command-style prompts produce shallow, generic work.
1769
1790
  const file = findAgentFile(name);
1770
1791
  if (!file)
1771
1792
  return;
1772
- const content = readFileSync(file.path, "utf-8");
1793
+ const content = (0, node_fs_1.readFileSync)(file.path, "utf-8");
1773
1794
  const updated = content.replace(/^(---\n)enabled: false\n/, "$1");
1774
1795
  const { writeFileSync } = await import("node:fs");
1775
1796
  // If the file was just a stub ("---\n---\n"), delete it to restore the built-in default
1776
1797
  if (updated.trim() === "---\n---" || updated.trim() === "---\n---\n") {
1777
- unlinkSync(file.path);
1798
+ (0, node_fs_1.unlinkSync)(file.path);
1778
1799
  reloadCustomAgents();
1779
1800
  ctx.ui.notify(`Enabled ${name} (removed ${file.path})`, "info");
1780
1801
  }
@@ -1812,9 +1833,9 @@ Terse command-style prompts produce shallow, generic work.
1812
1833
  const name = await ctx.ui.input("Agent name (filename, no spaces)");
1813
1834
  if (!name)
1814
1835
  return;
1815
- mkdirSync(targetDir, { recursive: true });
1816
- const targetPath = join(targetDir, `${name}.md`);
1817
- if (existsSync(targetPath)) {
1836
+ (0, node_fs_1.mkdirSync)(targetDir, { recursive: true });
1837
+ const targetPath = (0, node_path_1.join)(targetDir, `${name}.md`);
1838
+ if ((0, node_fs_1.existsSync)(targetPath)) {
1818
1839
  const overwrite = await ctx.ui.confirm("Overwrite", `${targetPath} already exists. Overwrite?`);
1819
1840
  if (!overwrite)
1820
1841
  return;
@@ -1868,7 +1889,7 @@ Write the file using the write tool. Only write the file, nothing else.`;
1868
1889
  return;
1869
1890
  }
1870
1891
  reloadCustomAgents();
1871
- if (existsSync(targetPath)) {
1892
+ if ((0, node_fs_1.existsSync)(targetPath)) {
1872
1893
  ctx.ui.notify(`Created ${targetPath}`, "info");
1873
1894
  }
1874
1895
  else {
@@ -1890,7 +1911,7 @@ Write the file using the write tool. Only write the file, nothing else.`;
1890
1911
  return;
1891
1912
  let tools;
1892
1913
  if (toolChoice === "all") {
1893
- tools = BUILTIN_TOOL_NAMES.join(", ");
1914
+ tools = agent_types_js_1.BUILTIN_TOOL_NAMES.join(", ");
1894
1915
  }
1895
1916
  else if (toolChoice === "none") {
1896
1917
  tools = "none";
@@ -1899,7 +1920,7 @@ Write the file using the write tool. Only write the file, nothing else.`;
1899
1920
  tools = "read, bash, grep, find, ls";
1900
1921
  }
1901
1922
  else {
1902
- const customTools = await ctx.ui.input("Tools (comma-separated)", BUILTIN_TOOL_NAMES.join(", "));
1923
+ const customTools = await ctx.ui.input("Tools (comma-separated)", agent_types_js_1.BUILTIN_TOOL_NAMES.join(", "));
1903
1924
  if (!customTools)
1904
1925
  return;
1905
1926
  tools = customTools;
@@ -1947,9 +1968,9 @@ prompt_mode: replace
1947
1968
 
1948
1969
  ${systemPrompt}
1949
1970
  `;
1950
- mkdirSync(targetDir, { recursive: true });
1951
- const targetPath = join(targetDir, `${name}.md`);
1952
- if (existsSync(targetPath)) {
1971
+ (0, node_fs_1.mkdirSync)(targetDir, { recursive: true });
1972
+ const targetPath = (0, node_path_1.join)(targetDir, `${name}.md`);
1973
+ if ((0, node_fs_1.existsSync)(targetPath)) {
1953
1974
  const overwrite = await ctx.ui.confirm("Overwrite", `${targetPath} already exists. Overwrite?`);
1954
1975
  if (!overwrite)
1955
1976
  return;
@@ -1964,12 +1985,12 @@ ${systemPrompt}
1964
1985
  maxConcurrent: manager.getMaxConcurrent(),
1965
1986
  // 0 = unlimited — per SubagentsSettings.defaultMaxTurns docstring and
1966
1987
  // normalizeMaxTurns() in agent-runner.ts (which maps 0 → undefined).
1967
- defaultMaxTurns: getDefaultMaxTurns() ?? 0,
1968
- graceTurns: getGraceTurns(),
1988
+ defaultMaxTurns: (0, agent_runner_js_1.getDefaultMaxTurns)() ?? 0,
1989
+ graceTurns: (0, agent_runner_js_1.getGraceTurns)(),
1969
1990
  defaultJoinMode: getDefaultJoinMode(),
1970
1991
  schedulingEnabled: isSchedulingEnabled(),
1971
1992
  scopeModels: isScopeModelsEnabled(),
1972
- disableDefaultAgents: isDefaultsDisabled(),
1993
+ disableDefaultAgents: (0, agent_types_js_1.isDefaultsDisabled)(),
1973
1994
  toolDescriptionMode: getToolDescriptionMode(),
1974
1995
  fleetView: isFleetViewEnabled(),
1975
1996
  widgetMode: getWidgetMode(),
@@ -1980,8 +2001,8 @@ ${systemPrompt}
1980
2001
  async function showSettings(ctx) {
1981
2002
  function buildItems() {
1982
2003
  const mc = manager.getMaxConcurrent();
1983
- const dmt = getDefaultMaxTurns() ?? 0;
1984
- const gt = getGraceTurns();
2004
+ const dmt = (0, agent_runner_js_1.getDefaultMaxTurns)() ?? 0;
2005
+ const gt = (0, agent_runner_js_1.getGraceTurns)();
1985
2006
  return [
1986
2007
  {
1987
2008
  id: "maxConcurrent",
@@ -2029,7 +2050,7 @@ ${systemPrompt}
2029
2050
  id: "disableDefaultAgents",
2030
2051
  label: "Disable defaults",
2031
2052
  description: "Hide built-in agents (general-purpose, Explore, Plan) — custom agents are unaffected",
2032
- currentValue: isDefaultsDisabled() ? "on" : "off",
2053
+ currentValue: (0, agent_types_js_1.isDefaultsDisabled)() ? "on" : "off",
2033
2054
  values: ["on", "off"],
2034
2055
  },
2035
2056
  {
@@ -2073,18 +2094,18 @@ ${systemPrompt}
2073
2094
  else if (id === "defaultMaxTurns") {
2074
2095
  const n = parseInt(value, 10);
2075
2096
  if (n === 0) {
2076
- setDefaultMaxTurns(undefined);
2097
+ (0, agent_runner_js_1.setDefaultMaxTurns)(undefined);
2077
2098
  notifyApplied(ctx, "Default max turns set to unlimited");
2078
2099
  }
2079
2100
  else if (n >= 1) {
2080
- setDefaultMaxTurns(n);
2101
+ (0, agent_runner_js_1.setDefaultMaxTurns)(n);
2081
2102
  notifyApplied(ctx, `Default max turns set to ${n}`);
2082
2103
  }
2083
2104
  }
2084
2105
  else if (id === "graceTurns") {
2085
2106
  const n = parseInt(value, 10);
2086
2107
  if (n >= 1) {
2087
- setGraceTurns(n);
2108
+ (0, agent_runner_js_1.setGraceTurns)(n);
2088
2109
  notifyApplied(ctx, `Grace turns set to ${n}`);
2089
2110
  }
2090
2111
  }
@@ -2139,26 +2160,26 @@ ${systemPrompt}
2139
2160
  let currentIndex = 0;
2140
2161
  const result = await ctx.ui.custom((_tui, _theme, _kb, done) => {
2141
2162
  const items = buildItems();
2142
- list = new SettingsList(items, items.length + 2, getSettingsListTheme(), (id, newValue) => {
2163
+ list = new pi_tui_1.SettingsList(items, items.length + 2, (0, pi_coding_agent_1.getSettingsListTheme)(), (id, newValue) => {
2143
2164
  applyValue(id, newValue);
2144
2165
  }, () => done(undefined));
2145
- const container = new Container();
2146
- container.addChild(new Text("⚙ Subagent Settings", 0, 0));
2147
- container.addChild(new Spacer(1));
2166
+ const container = new pi_tui_1.Container();
2167
+ container.addChild(new pi_tui_1.Text("⚙ Subagent Settings", 0, 0));
2168
+ container.addChild(new pi_tui_1.Spacer(1));
2148
2169
  container.addChild(list);
2149
2170
  return {
2150
2171
  render: (w) => container.render(w),
2151
2172
  invalidate: () => container.invalidate(),
2152
2173
  handleInput: (data) => {
2153
2174
  // Track navigation so Enter knows the current field
2154
- if (matchesKey(data, "up")) {
2175
+ if ((0, pi_tui_1.matchesKey)(data, "up")) {
2155
2176
  currentIndex = Math.max(0, currentIndex - 1);
2156
2177
  }
2157
- else if (matchesKey(data, "down")) {
2178
+ else if ((0, pi_tui_1.matchesKey)(data, "down")) {
2158
2179
  currentIndex = Math.min(items.length - 1, currentIndex + 1);
2159
2180
  }
2160
2181
  // Enter on numeric field → close and prompt for typed input
2161
- if (matchesKey(data, Key.enter) && NUMERIC_IDS.has(items[currentIndex].id)) {
2182
+ if ((0, pi_tui_1.matchesKey)(data, pi_tui_1.Key.enter) && NUMERIC_IDS.has(items[currentIndex].id)) {
2162
2183
  done(items[currentIndex].id);
2163
2184
  return;
2164
2185
  }
@@ -2171,8 +2192,8 @@ ${systemPrompt}
2171
2192
  const current = result === "maxConcurrent"
2172
2193
  ? String(manager.getMaxConcurrent())
2173
2194
  : result === "defaultMaxTurns"
2174
- ? String(getDefaultMaxTurns() ?? 0)
2175
- : String(getGraceTurns());
2195
+ ? String((0, agent_runner_js_1.getDefaultMaxTurns)() ?? 0)
2196
+ : String((0, agent_runner_js_1.getGraceTurns)());
2176
2197
  const label = result === "maxConcurrent"
2177
2198
  ? "Max concurrency (1+)"
2178
2199
  : result === "defaultMaxTurns"
@@ -2199,7 +2220,7 @@ ${systemPrompt}
2199
2220
  // to warning so users aren't silently reverted on restart. Event fires regardless
2200
2221
  // of outcome so listeners see the in-memory change.
2201
2222
  function notifyApplied(ctx, successMsg) {
2202
- const { message, level } = saveAndEmitChanged(snapshotSettings(), successMsg, (event, payload) => pi.events.emit(event, payload));
2223
+ const { message, level } = (0, settings_js_1.saveAndEmitChanged)(snapshotSettings(), successMsg, (event, payload) => pi.events.emit(event, payload));
2203
2224
  ctx.ui.notify(message, level);
2204
2225
  }
2205
2226
  pi.registerCommand("agents", {