@narumitw/pi-subagents 3.1.1 → 3.2.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/README.md +14 -2
- package/dist/index.ts +31 -6
- package/dist/index.ts.map +2 -2
- package/docs/tools.md +6 -1
- package/package.json +7 -7
- package/src/process.ts +3 -2
- package/src/runtime.ts +4 -0
- package/src/tools.ts +1 -1
- package/src/types.ts +11 -1
- package/src/widget.ts +19 -3
package/README.md
CHANGED
|
@@ -62,6 +62,12 @@ Call `subagent_spawn` with a self-contained task and only the work tools that ta
|
|
|
62
62
|
The call returns a `jobId` immediately, and the job continues in the background.
|
|
63
63
|
Continue useful main-agent work until the result is required or a completion arrives.
|
|
64
64
|
|
|
65
|
+
In TUI mode, each active-job row shows a preview of its existing `task` after the job ID; no new parameter is required.
|
|
66
|
+
The preview removes terminal controls, collapses whitespace, and uses at most 40 terminal columns, including an ellipsis when shortened.
|
|
67
|
+
It describes the assigned task, not live child activity; the full task sent to the child is unchanged.
|
|
68
|
+
Task text is visible in this local widget, but `subagent_inspect` continues to omit it.
|
|
69
|
+
Rows are clipped to the available terminal width, so trailing state, timing, or tools can be hidden on narrow terminals.
|
|
70
|
+
|
|
65
71
|
Use messaging only when needed:
|
|
66
72
|
|
|
67
73
|
- Call `subagent_send` with `recipient: jobId` to ask an active child a question.
|
|
@@ -125,7 +131,7 @@ The package intentionally registers and publishes no skill; the repository-only
|
|
|
125
131
|
```ts
|
|
126
132
|
{
|
|
127
133
|
task: string;
|
|
128
|
-
tools?: Array<"read" | "bash" | "powershell" | "edit" | "write" | "grep" | "find" | "ls">;
|
|
134
|
+
tools?: Array<"read" | "bash" | "powershell" | "edit" | "write" | "grep" | "find" | "ls" | "codemode">;
|
|
129
135
|
skills?: string[];
|
|
130
136
|
extensions?: Array<{ path: string; tools: string[] }>;
|
|
131
137
|
thinkingLevel?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
|
|
@@ -133,11 +139,17 @@ The package intentionally registers and publishes no skill; the repository-only
|
|
|
133
139
|
}
|
|
134
140
|
```
|
|
135
141
|
|
|
136
|
-
The optional `tools` list selects Pi core work tools.
|
|
142
|
+
The optional `tools` list selects Pi core work tools and the built-in `codemode` tool.
|
|
137
143
|
Omitting it selects `read`, `grep`, `find`, and `ls`, while an empty list gives the child no core work tools.
|
|
138
144
|
The runtime always adds `subagent_send` and child `subagent_wait` and removes duplicate names.
|
|
139
145
|
Adding `edit` or `write` lets the child modify files, while `bash` or `powershell` grants unrestricted command execution.
|
|
140
146
|
|
|
147
|
+
Add `"codemode"` explicitly to let the child run JavaScript that calls its selected tools and communication tools, including parallel calls and output filtering.
|
|
148
|
+
For example, `tools: ["read", "grep", "codemode"]` enables scripted read and search operations without shell or file-mutation tools.
|
|
149
|
+
The runtime loads Pi's built-in codemode extension and verifies tool readiness before sending the task; it does not enable automatic extension or MCP discovery.
|
|
150
|
+
Codemode follows Pi's effective `codemode` settings and also provides Pi's `models` API for classifier and image calls using child-visible credentials.
|
|
151
|
+
Those model calls can send data to providers and incur costs.
|
|
152
|
+
|
|
141
153
|
The optional `skills` list attaches local Pi skills through progressive disclosure without injecting their full bodies or adding tools.
|
|
142
154
|
Every attached skill path must contain at least one loadable skill, every non-ignored declared skill must load successfully, and skill names must be unique across attachments.
|
|
143
155
|
|
package/dist/index.ts
CHANGED
|
@@ -156,6 +156,7 @@ function buildPiArgs(request) {
|
|
|
156
156
|
"-e",
|
|
157
157
|
childCommunicationBridgePath()
|
|
158
158
|
];
|
|
159
|
+
if (request.tools.includes("codemode")) args.push("-e", "builtin:codemode");
|
|
159
160
|
for (const extension of request.extensions) args.push("-e", extension.path);
|
|
160
161
|
if (requiresReadinessAttestation(request)) args.push("-e", childReadinessProbePath());
|
|
161
162
|
for (const skill of request.skills) args.push("--skill", skill);
|
|
@@ -202,7 +203,7 @@ function childReadinessProbePath() {
|
|
|
202
203
|
return fileURLToPath(new URL("./child-readiness-probe.ts", import.meta.url));
|
|
203
204
|
}
|
|
204
205
|
function requiresReadinessAttestation(request) {
|
|
205
|
-
return request.extensions.length > 0;
|
|
206
|
+
return request.tools.includes("codemode") || request.extensions.length > 0;
|
|
206
207
|
}
|
|
207
208
|
function selectedChildTools(request) {
|
|
208
209
|
return [
|
|
@@ -1200,7 +1201,17 @@ var TERMINAL_JOB_STATES = /* @__PURE__ */ new Set([
|
|
|
1200
1201
|
"timed_out",
|
|
1201
1202
|
"cancelled"
|
|
1202
1203
|
]);
|
|
1203
|
-
var CHILD_CORE_TOOL_NAMES = [
|
|
1204
|
+
var CHILD_CORE_TOOL_NAMES = [
|
|
1205
|
+
"read",
|
|
1206
|
+
"bash",
|
|
1207
|
+
"powershell",
|
|
1208
|
+
"edit",
|
|
1209
|
+
"write",
|
|
1210
|
+
"grep",
|
|
1211
|
+
"find",
|
|
1212
|
+
"ls",
|
|
1213
|
+
"codemode"
|
|
1214
|
+
];
|
|
1204
1215
|
var DEFAULT_SUBAGENT_TOOLS = ["read", "grep", "find", "ls"];
|
|
1205
1216
|
var SUBAGENT_THINKING_LEVELS = [
|
|
1206
1217
|
"off",
|
|
@@ -1762,6 +1773,7 @@ var SubagentRuntime = class {
|
|
|
1762
1773
|
const now = this.now();
|
|
1763
1774
|
return [...this.jobs.values()].filter((job) => !isTerminal(job.state)).sort((left, right) => left.createdAt - right.createdAt).map((job) => ({
|
|
1764
1775
|
jobId: job.jobId,
|
|
1776
|
+
task: job.taskText,
|
|
1765
1777
|
state: job.state,
|
|
1766
1778
|
elapsedMs: Math.max(0, now - (job.startedAt ?? job.createdAt)),
|
|
1767
1779
|
...job.timeout !== void 0 ? { timeout: job.timeout } : {},
|
|
@@ -1803,6 +1815,7 @@ var SubagentRuntime = class {
|
|
|
1803
1815
|
...input.timeout !== void 0 ? { timeout: input.timeout } : {},
|
|
1804
1816
|
controller,
|
|
1805
1817
|
tools: effectiveTools,
|
|
1818
|
+
taskText: input.task,
|
|
1806
1819
|
terminal,
|
|
1807
1820
|
resolveTerminal,
|
|
1808
1821
|
controlReady,
|
|
@@ -2282,7 +2295,7 @@ function registerSubagentTools(pi, dependencies = {}) {
|
|
|
2282
2295
|
if (ctx.cwd !== cwd || ctx.isProjectTrusted() !== projectTrusted) {
|
|
2283
2296
|
throw new Error("Subagent spawn context changed during attachment validation; retry the request.");
|
|
2284
2297
|
}
|
|
2285
|
-
if (attachments.extensions.length > 0) {
|
|
2298
|
+
if (tools.includes("codemode") || attachments.extensions.length > 0) {
|
|
2286
2299
|
assertChildBootstrapCapacity([.../* @__PURE__ */ new Set([...attachments.effectiveTools, ...CHILD_COMMUNICATION_TOOL_NAMES])]);
|
|
2287
2300
|
}
|
|
2288
2301
|
const model = resolveChildModel(ctx, attachments.extensions.length > 0);
|
|
@@ -2518,10 +2531,11 @@ function toolResult(value) {
|
|
|
2518
2531
|
}
|
|
2519
2532
|
|
|
2520
2533
|
// src/widget.ts
|
|
2521
|
-
import { truncateToWidth } from "@earendil-works/pi-tui";
|
|
2534
|
+
import { stripTerminalSequences, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
2522
2535
|
var SUBAGENT_WIDGET_KEY = "subagents";
|
|
2523
2536
|
var SUBAGENT_WIDGET_REFRESH_INTERVAL_MS = 1e3;
|
|
2524
2537
|
var WIDGET_OPTIONS = { placement: "aboveEditor" };
|
|
2538
|
+
var TASK_PREVIEW_WIDTH = 40;
|
|
2525
2539
|
function createSubagentWidgetController(runtime) {
|
|
2526
2540
|
let activeSession;
|
|
2527
2541
|
let refreshTimer;
|
|
@@ -2590,19 +2604,30 @@ function renderJob(job, theme) {
|
|
|
2590
2604
|
const symbol = theme.fg(running ? "accent" : "dim", running ? "\u25B6 " : "\u25CB ");
|
|
2591
2605
|
const state = theme.fg(running ? "accent" : "muted", job.state);
|
|
2592
2606
|
const jobId = sanitizeLabel(job.jobId);
|
|
2607
|
+
const taskText = sanitizeTask(job.task);
|
|
2608
|
+
const task = stripTerminalSequences(truncateToWidth(taskText, TASK_PREVIEW_WIDTH, "\u2026"));
|
|
2609
|
+
const preview = visibleWidth(task) > 0 ? ` \xB7 ${theme.fg("text", task)}` : "";
|
|
2593
2610
|
const tools = job.tools.length > 0 ? job.tools.map(sanitizeLabel).join(", ") : "none";
|
|
2594
2611
|
const timeout = job.timeout === void 0 ? "no timeout" : formatSeconds(job.timeout);
|
|
2595
2612
|
const detail = ` \xB7 ${formatSeconds(Math.floor(job.elapsedMs / 1e3))} / ${timeout} \xB7 tools: ${tools}`;
|
|
2596
|
-
return `${symbol}${theme.fg("text", jobId)} \xB7 ${state}${theme.fg("muted", detail)}`;
|
|
2613
|
+
return `${symbol}${theme.fg("text", jobId)}${preview} \xB7 ${state}${theme.fg("muted", detail)}`;
|
|
2597
2614
|
}
|
|
2598
2615
|
function widgetValue(jobs) {
|
|
2599
2616
|
return jobs.map(
|
|
2600
|
-
(job) => `${job.jobId}\0${job.state}\0${Math.floor(job.elapsedMs / 1e3)}\0${job.timeout ?? ""}\0${job.tools.join(",")}`
|
|
2617
|
+
(job) => `${job.jobId}\0${job.task}\0${job.state}\0${Math.floor(job.elapsedMs / 1e3)}\0${job.timeout ?? ""}\0${job.tools.join(",")}`
|
|
2601
2618
|
).join("\n");
|
|
2602
2619
|
}
|
|
2603
2620
|
function cloneDisplayJob(job) {
|
|
2604
2621
|
return { ...job, tools: [...job.tools] };
|
|
2605
2622
|
}
|
|
2623
|
+
function sanitizeTask(value) {
|
|
2624
|
+
const text = value.replace(
|
|
2625
|
+
// biome-ignore lint/suspicious/noControlCharactersInRegex: Remove untrusted terminal escape sequences before display.
|
|
2626
|
+
/(?:\u001b\[|\u009b)[0-?]*[ -/]*[@-~]|(?:\u001b[\]PX^_]|[\u0090\u0098\u009d-\u009f])[^\u0007\u001b\u0080-\u009f]*(?:\u0007|\u001b\\|\u009c)|\u001b[ -/]*[0-~]/gu,
|
|
2627
|
+
""
|
|
2628
|
+
);
|
|
2629
|
+
return sanitizeLabel(text.replace(/\p{Bidi_Control}/gu, ""));
|
|
2630
|
+
}
|
|
2606
2631
|
function sanitizeLabel(value) {
|
|
2607
2632
|
return sanitizeTerminalText(value).replace(/\s+/gu, " ").trim();
|
|
2608
2633
|
}
|