@d3ara1n/pi-subagent 0.5.0 → 0.6.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 CHANGED
@@ -64,7 +64,7 @@ Edit `~/.pi/agent/settings.json`:
64
64
  ```json
65
65
  {
66
66
  "subagent": {
67
- "timeout": 600,
67
+ "timeout": 1500,
68
68
  "maxConcurrency": 4,
69
69
  "maxDepth": 3,
70
70
  "maxTurns": 0,
@@ -80,7 +80,7 @@ Edit `~/.pi/agent/settings.json`:
80
80
  }
81
81
  ```
82
82
 
83
- All fields are optional. Defaults: `timeout: 600` (seconds; 10 min; roles that can `delegate` get 2× automatically when no per-role timeout is set), `maxConcurrency: 4`, `maxDepth: 3`, `maxTurns: 0` (unlimited), `maxCost: 0` (unlimited), `history.enabled: true`, `summary.role: "utility"`, `summary.enabled: true`.
83
+ All fields are optional. Defaults: `timeout: 1500` (seconds; 25 min; roles that can `delegate` get 2× automatically when no per-role timeout is set), `maxConcurrency: 4`, `maxDepth: 3`, `maxTurns: 0` (unlimited), `maxCost: 0` (unlimited), `history.enabled: true`, `summary.role: "utility"`, `summary.enabled: true`.
84
84
 
85
85
  ### Agent Overrides
86
86
 
@@ -92,7 +92,7 @@ Override, disable, or add subagent roles via `agentOverrides`. Built-in and cust
92
92
  "agentOverrides": {
93
93
  "worker": {
94
94
  "role": "heavy",
95
- "timeout": 600,
95
+ "timeout": 1500,
96
96
  "maxTurns": 50,
97
97
  "maxCost": 1.0
98
98
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@d3ara1n/pi-subagent",
3
- "version": "0.5.0",
3
+ "version": "0.6.1",
4
4
  "type": "module",
5
5
  "description": "Role-based subagent orchestration for pi — delegates tasks to specialized pi child processes with configurable model roles",
6
6
  "main": "src/index.ts",
@@ -31,7 +31,8 @@
31
31
  "pi": {
32
32
  "extensions": [
33
33
  "./src/index.ts"
34
- ]
34
+ ],
35
+ "image": "https://raw.githubusercontent.com/d3ara1n/pi-extensions/main/packages/pi-subagent/preview.png"
35
36
  },
36
37
  "repository": {
37
38
  "type": "git",
package/preview.png ADDED
Binary file
package/src/index.ts CHANGED
@@ -686,27 +686,32 @@ export default function subagentExtension(pi: ExtensionAPI) {
686
686
  const stats = formatUsageStats(r.usage, r.model);
687
687
  const usageLine = [secs != null ? `${secs}s` : null, stats].filter(Boolean).join(" \u00b7 ");
688
688
 
689
- // Result line content (shared between collapsed and expanded).
690
- let resultContent: string | undefined;
691
- let resultCol: ThemeColor | undefined;
689
+ // resultline: fixed line on terminal frames `<icon> <content>` colored by outcome.
690
+ // success AI summary, else first line of output (truncated), else a placeholder — never blank.
691
+ // error/timeout/budget errorMessage (or a default label).
692
+ let resultline: string | undefined;
692
693
  if (!isRunning) {
693
694
  if (isFailedState) {
694
- resultContent = r.errorMessage || (isTimeout ? "Timed out" : isBudget ? "Budget exceeded" : "failed");
695
- resultCol = isTimeout || isBudget ? "warning" : "error";
695
+ const content = r.errorMessage || (isTimeout ? "Timed out" : isBudget ? "Budget exceeded" : "failed");
696
+ const col: ThemeColor = isTimeout || isBudget ? "warning" : "error";
697
+ resultline = `${icon} ${theme.fg(col, content)}`;
696
698
  } else {
697
- resultContent = r.summary || undefined;
698
- resultCol = "text";
699
+ // success fallback chain: summary output first line → placeholder.
700
+ const firstLine = r.output.trim().split("\n")[0] ?? "";
701
+ const preview = firstLine.length > 70 ? `${firstLine.slice(0, 70)}...` : firstLine;
702
+ const content = r.summary || preview;
703
+ const col: ThemeColor = content ? "text" : "muted";
704
+ resultline = `${icon} ${theme.fg(col, content || "(no output)")}`;
699
705
  }
700
706
  }
701
707
 
702
708
  if (expanded) {
703
709
  const container = new Container();
704
710
 
705
- // Header: taskline (+ error line on failure; success has no summary line here
706
- // — full output below makes it redundant).
711
+ // Header: taskline + resultline (summary on success, error message on failure).
707
712
  container.addChild(new Text(taskline, 0, 0));
708
- if (resultContent) {
709
- container.addChild(new Text(`${icon} ${theme.fg(resultCol!, resultContent)}`, 0, 0));
713
+ if (resultline) {
714
+ container.addChild(new Text(resultline, 0, 0));
710
715
  }
711
716
 
712
717
  // Input block: reference files + context char count + task full text,
@@ -745,14 +750,19 @@ export default function subagentExtension(pi: ExtensionAPI) {
745
750
  }
746
751
  }
747
752
 
748
- // Full output (terminal runs only).
749
- if (!isRunning && r.output.trim()) {
753
+ // Full output (terminal runs only). Always render the slot — show a
754
+ // placeholder when empty so the user never thinks output was lost.
755
+ if (!isRunning) {
750
756
  container.addChild(new Spacer(1));
751
- container.addChild(new Markdown(r.output.trim(), 0, 0, mdTheme));
752
- if (r.outputMethod === "compressed") {
753
- container.addChild(new Text(theme.fg("muted", "(output compressed by summary model \u2014 full text in history)"), 0, 0));
754
- } else if (r.outputMethod === "truncated") {
755
- container.addChild(new Text(theme.fg("muted", "(output truncated \u2014 full text in history)"), 0, 0));
757
+ if (r.output.trim()) {
758
+ container.addChild(new Markdown(r.output.trim(), 0, 0, mdTheme));
759
+ if (r.outputMethod === "compressed") {
760
+ container.addChild(new Text(theme.fg("muted", "(output compressed by summary model \u2014 full text in history)"), 0, 0));
761
+ } else if (r.outputMethod === "truncated") {
762
+ container.addChild(new Text(theme.fg("muted", "(output truncated \u2014 full text in history)"), 0, 0));
763
+ }
764
+ } else {
765
+ container.addChild(new Text(theme.fg("muted", "(no output \u2014 the run produced no text)"), 0, 0));
756
766
  }
757
767
  }
758
768
 
@@ -768,8 +778,8 @@ export default function subagentExtension(pi: ExtensionAPI) {
768
778
  // Collapsed view.
769
779
  let text = taskline;
770
780
  if (!isRunning) {
771
- // Result line (shared computation above).
772
- if (resultContent) text += `\n${icon} ${theme.fg(resultCol!, resultContent)}`;
781
+ // resultline (shared computation above).
782
+ if (resultline) text += `\n${resultline}`;
773
783
  } else if (!r.queued) {
774
784
  // Running (not queued): show recent activity only.
775
785
  const activity = displayItems.filter((item) => item.type === "toolCall" || item.type === "thinking");
package/src/types.ts CHANGED
@@ -35,7 +35,7 @@ export interface SubagentSummaryConfig {
35
35
  }
36
36
 
37
37
  export const DEFAULT_CONFIG: SubagentConfig = {
38
- timeout: 600,
38
+ timeout: 1500,
39
39
  maxConcurrency: 4,
40
40
  maxDepth: 3,
41
41
  maxTurns: 0,
@@ -151,14 +151,14 @@ export interface SubagentResult {
151
151
  /** Real-time activity log: thinking blocks and tool calls in arrival order. */
152
152
  activityLog: ActivityEntry[];
153
153
 
154
- // ── TUI 渲染辅助字段(非子进程产出,由 execute 层填入)──────────
155
- /** 运行开始墙钟时间;仅 queued/running 帧存在,供 TUI 实时算耗时。终态帧无此字段。 */
154
+ // ── TUI rendering helpers (not produced by the child; filled in by the execute layer) ──
155
+ /** Wall-clock start time; present only on queued/running frames so the TUI can compute live elapsed time. Absent on terminal frames. */
156
156
  startTime?: number;
157
- /** 终态总耗时(ms),由 execute 在结束时写入;覆盖整个 delegate 区间(含 fallback 重试)。 */
157
+ /** Total elapsed time (ms) for terminal frames, written by execute when the run ends; spans the whole delegate interval (incl. fallback retries). */
158
158
  elapsedMs?: number;
159
- /** delegate 传入的引用文件路径(params.files),展开视图渲染用。 */
159
+ /** Reference file paths passed to delegate (params.files); used by the expanded view. */
160
160
  files?: string[];
161
- /** delegate 传入的额外上下文(params.context),展开视图渲染用。 */
161
+ /** Extra context passed to delegate (params.context); used by the expanded view. */
162
162
  context?: string;
163
163
  }
164
164
 
package/src/utils.ts CHANGED
@@ -32,12 +32,13 @@ export function formatUsageStats(usage: SubagentResult["usage"], model?: string)
32
32
  }
33
33
 
34
34
  /**
35
- * 计算用于展示的运行耗时(秒)。
36
- * - 运行中(exitCode === -1 且有 startTime):基于墙钟实时计算;
37
- * - 终态(exitCode !== -1 且有 elapsedMs):冻结值;
38
- * - queued 或字段缺失:undefined(调用方应跳过耗时展示)。
35
+ * Display elapsed time in seconds.
36
+ * - Running (exitCode === -1 with startTime): live wall-clock value.
37
+ * - Terminal (exitCode !== -1 with elapsedMs): frozen value.
38
+ * - Queued or fields missing: undefined (caller should skip the elapsed display).
39
39
  *
40
- * 用结构子集而非 SubagentResult,便于在无需引入完整类型的纯工具上下文中复用与测试。
40
+ * Takes a structural subset rather than the full SubagentResult so it can be reused
41
+ * and tested in pure-helper contexts without importing the full type.
41
42
  */
42
43
  export function elapsedSeconds(r: {
43
44
  exitCode: number;
@@ -193,7 +194,10 @@ export function isProviderError(result: SubagentResult): boolean {
193
194
  return /429|quota|rate.?limit|auth|timeout|exhausted|unavailable|503|server error|temporary|declined|overloaded|econnreset|socket hang up|epipe|network|connection/i.test(haystack);
194
195
  }
195
196
 
196
- /** Shape-based preview for tools we don't have a dedicated formatter for. */
197
+ /**
198
+ * Shape-based preview for tools we don't have a dedicated formatter for.
199
+ * @internal — exported for testing; used internally by {@link formatToolCall}.
200
+ */
197
201
  export function previewArgs(args: Record<string, unknown>): string {
198
202
  const command = args.command as string | undefined;
199
203
  if (command) return `$ ${command.length > 60 ? command.slice(0, 60) + "..." : command}`;