@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/CHANGELOG.md +5 -0
- package/README.md +2 -2
- package/dist/agent-manager.js +23 -19
- package/dist/agent-runner.js +85 -66
- package/dist/agent-types.js +45 -27
- package/dist/context.js +6 -2
- package/dist/cross-extension-rpc.js +9 -5
- package/dist/custom-agents.js +18 -15
- package/dist/default-agents.js +4 -1
- package/dist/enabled-models.js +16 -11
- package/dist/env.js +4 -1
- package/dist/group-join.js +5 -1
- package/dist/index.js +235 -214
- package/dist/invocation-config.js +6 -2
- package/dist/memory.js +34 -24
- package/dist/model-resolver.js +4 -1
- package/dist/nico-overrides.js +20 -14
- package/dist/output-file.js +21 -15
- package/dist/prompts.js +4 -1
- package/dist/schedule-store.js +21 -16
- package/dist/schedule.js +12 -8
- package/dist/settings.js +23 -15
- package/dist/skill-loader.js +23 -20
- package/dist/status-note.js +4 -1
- package/dist/types.d.ts +1 -0
- package/dist/types.js +4 -1
- package/dist/ui/agent-widget.js +37 -23
- package/dist/ui/conversation-viewer.js +43 -39
- package/dist/ui/fleet-list.js +30 -24
- package/dist/ui/markdown-result.d.ts +3 -0
- package/dist/ui/markdown-result.js +53 -0
- package/dist/ui/schedule-menu.js +4 -1
- package/dist/ui/viewer-keys.js +10 -7
- package/dist/usage.js +10 -4
- package/dist/worktree.js +31 -26
- package/package.json +1 -1
- package/src/agent-runner.ts +11 -3
- package/src/index.ts +34 -16
- package/src/types.ts +1 -0
- package/src/ui/markdown-result.ts +56 -0
- package/test/ui/markdown-result.test.ts +45 -0
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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
251
|
-
|
|
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
|
-
|
|
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
|
-
|
|
275
|
+
container.addChild(new pi_tui_1.Text(theme.fg("muted", ` transcript: ${d.outputFile}`), 0, 0));
|
|
263
276
|
}
|
|
264
|
-
return
|
|
277
|
+
return container;
|
|
265
278
|
}
|
|
266
279
|
const all = [d, ...(d.others ?? [])];
|
|
267
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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", {
|