@arhen/pi-core-subagent 1.3.27 → 1.3.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arhen/pi-core-subagent",
3
- "version": "1.3.27",
3
+ "version": "1.3.28",
4
4
  "type": "module",
5
5
  "description": "pi extension: fast in-process subagents with a dependency-graph scheduler (needs edges gate tasks and carry upstream output into dependent prompts), plus background runs, intercom and agent-to-agent mailbox. Leader defines agents inline.",
6
6
  "license": "MIT",
package/src/format.ts CHANGED
@@ -15,7 +15,7 @@ import {
15
15
  } from "./types.ts";
16
16
 
17
17
  /** Cap on a single child's final output (and on full-run summaries). */
18
- export const FINAL_OUTPUT_CAP = 24 * 1024;
18
+ const FINAL_OUTPUT_CAP = 24 * 1024;
19
19
 
20
20
  export function truncateText(text: string, max = FINAL_OUTPUT_CAP): string {
21
21
  if (Buffer.byteLength(text, "utf8") <= max) return text;
@@ -29,7 +29,7 @@ export function getFirstText(message: AssistantMessage): string {
29
29
  }
30
30
  return "";
31
31
  }
32
- export function fmtTokens(n: number): string {
32
+ function fmtTokens(n: number): string {
33
33
  return n >= 1000 ? `${(n / 1000).toFixed(1).replace(/\.0$/, "")}k` : String(n);
34
34
  }
35
35
  export function formatUsage(usage: UsageStats): string {
@@ -48,18 +48,18 @@ export function statusIcon(status: TaskStatus | RunStatus): string {
48
48
  if (status === "queued") return "○";
49
49
  return "•";
50
50
  }
51
- export function fmtDuration(ms: number | undefined): string {
51
+ function fmtDuration(ms: number | undefined): string {
52
52
  if (ms === undefined || !Number.isFinite(ms)) return "–";
53
53
  const s = Math.max(0, Math.round(ms / 1000));
54
54
  return s >= 60 ? `${Math.floor(s / 60)}m${s % 60}s` : `${s}s`;
55
55
  }
56
- export function taskTimer(task: TaskSnapshot): string {
56
+ function taskTimer(task: TaskSnapshot): string {
57
57
  if (task.startedAt === undefined) return "–";
58
58
  const end = task.endedAt ?? Date.now();
59
59
  const running = !TERMINAL.includes(task.status);
60
60
  return `${running ? "running " : ""}${fmtDuration(end - task.startedAt)}`;
61
61
  }
62
- export function taskStatsWithUsage(task: TaskSnapshot): string {
62
+ function taskStatsWithUsage(task: TaskSnapshot): string {
63
63
  const stats = `${task.toolCalls ?? 0} tools`;
64
64
  const usage = formatUsage(task.usage);
65
65
  return `${stats}${usage ? ` · ${usage}` : ""}`;
@@ -82,7 +82,7 @@ export function colorNums(text: string, theme: Theme): string {
82
82
  * Themed one-liner. Finished tasks dim entirely (stats included); live tasks
83
83
  * keep the agent name readable with themed numbers.
84
84
  */
85
- export function themedTaskLine(task: TaskSnapshot, theme: Theme, activity = ""): string {
85
+ function themedTaskLine(task: TaskSnapshot, theme: Theme, activity = ""): string {
86
86
  const tail = `${taskStatsWithUsage(task)} · ${taskTimer(task)}`;
87
87
  // Queued task with unmet needs: show the gate it's waiting on instead of empty stats.
88
88
  const gate =
@@ -101,7 +101,7 @@ export function themedTaskLine(task: TaskSnapshot, theme: Theme, activity = ""):
101
101
  * unknown/custom tools then read fine too. Add a case only if one reads badly.
102
102
  */
103
103
  // Order matters: the most specific arg wins (grep's pattern beats its path).
104
- export const ARG_KEYS = [
104
+ const ARG_KEYS = [
105
105
  "pattern",
106
106
  "query",
107
107
  "command",
@@ -132,7 +132,7 @@ export function activitySnippet(text: string): string {
132
132
  }
133
133
 
134
134
  /** Mailbox/intercom tools — while one is the task's last activity, the agent is "talking". */
135
- export const TALK_TOOLS = ["poll_agent_messages", "send_agent_message", "ask_parent", "notify_parent"];
135
+ const TALK_TOOLS = ["poll_agent_messages", "send_agent_message", "ask_parent", "notify_parent"];
136
136
  export function isTalking(task: TaskSnapshot): boolean {
137
137
  const a = task.lastActivity?.toLowerCase() ?? "";
138
138
  return TALK_TOOLS.some((t) => a.startsWith(t));
@@ -155,7 +155,7 @@ export function compactLines(run: RunSnapshot): string[] {
155
155
  * └─ ✓ reviewer · 6 tools · 44s
156
156
  * Static icons (no animation); latest activity + tool count + runtime per agent.
157
157
  */
158
- export const WIDGET_MAX_LINES = 10;
158
+ const WIDGET_MAX_LINES = 10;
159
159
 
160
160
  export class SubagentsWidget implements Component {
161
161
  constructor(
package/src/graph.ts CHANGED
@@ -85,7 +85,7 @@ export function applyUpstream(task: string, needs: string[], outputs: Map<string
85
85
  return `${blocks.join("\n\n")}\n\n---\n\n${body}`;
86
86
  }
87
87
 
88
- export async function mapWithConcurrency<T>(
88
+ async function mapWithConcurrency<T>(
89
89
  items: T[],
90
90
  concurrency: number,
91
91
  fn: (item: T, index: number) => Promise<void>,
package/src/index.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  /**
2
- * minimalist-subagentspi extension.
2
+ * pi-core-subagentin-process subagents.
3
3
  *
4
4
  * Fast in-process subagents (isolated AgentSessions, no process spawn).
5
5
  * Modes: single / parallel / chain. Background runs, cancel, intercom
6
6
  * (ask/notify/update the leader) and agent↔agent mailbox (send/poll).
7
7
  *
8
- * Context discipline: 6 slim parent tools, one-line catalog injected per
8
+ * Context discipline: 7 slim parent tools, one-line catalog injected per
9
9
  * request (cached), background completions notify with a 3-line summary
10
10
  * instead of full outputs, and run updates are throttled (no per-event
11
11
  * deep clones).
package/src/manager.ts CHANGED
@@ -47,21 +47,21 @@ import {
47
47
  export const DEFAULT_CONCURRENCY = 3;
48
48
  export const MAX_CONCURRENCY = 8;
49
49
  /** No default wall-clock cap: a subagent runs until its task is done, it stalls, or the user aborts. */
50
- export const DEFAULT_RUNTIME_MS = 0;
51
- export const DEFAULT_STALL_MS = 180_000; // 3 min: long model thinking streams emit no events, but they're not stalled.
52
- export const READONLY_TOOLS = ["read", "grep", "find", "ls"];
53
- export const WRITE_TOOLS = ["read", "grep", "find", "ls", "bash", "edit", "write"];
50
+ const DEFAULT_RUNTIME_MS = 0;
51
+ const DEFAULT_STALL_MS = 180_000; // 3 min: long model thinking streams emit no events, but they're not stalled.
52
+ const READONLY_TOOLS = ["read", "grep", "find", "ls"];
53
+ const WRITE_TOOLS = ["read", "grep", "find", "ls", "bash", "edit", "write"];
54
54
  const WIDGET_THROTTLE_MS = 150;
55
55
 
56
56
  // ── helpers ──────────────────────────────────────────────────────────────
57
57
 
58
- export function newId(prefix: string): string {
58
+ function newId(prefix: string): string {
59
59
  return `${prefix}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
60
60
  }
61
- export function emptyUsage(): UsageStats {
61
+ function emptyUsage(): UsageStats {
62
62
  return { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, turns: 0 };
63
63
  }
64
- export function aggregateUsage(tasks: TaskSnapshot[]): UsageStats {
64
+ function aggregateUsage(tasks: TaskSnapshot[]): UsageStats {
65
65
  const total = emptyUsage();
66
66
  for (const task of tasks) {
67
67
  total.input += task.usage.input;
@@ -73,7 +73,7 @@ export function aggregateUsage(tasks: TaskSnapshot[]): UsageStats {
73
73
  }
74
74
  return total;
75
75
  }
76
- export function getParentSessionFile(ctx: ExtensionContext): string | undefined {
76
+ function getParentSessionFile(ctx: ExtensionContext): string | undefined {
77
77
  try {
78
78
  return ctx.sessionManager.getSessionFile?.();
79
79
  } catch {
@@ -92,7 +92,7 @@ export function classifyFailure(
92
92
  if (stopReason === "aborted") return { status: "aborted", message: errorMessage || "Subagent was aborted." };
93
93
  return { status: "failed", message: errorMessage || `Subagent ended with stopReason "${stopReason}".` };
94
94
  }
95
- export function lastAssistantFailure(
95
+ function lastAssistantFailure(
96
96
  messages: AssistantMessage[] | undefined,
97
97
  ): { status: "failed" | "aborted"; message: string } | undefined {
98
98
  for (const message of [...(messages ?? [])].reverse()) {
@@ -101,12 +101,12 @@ export function lastAssistantFailure(
101
101
  }
102
102
  return undefined;
103
103
  }
104
- export function failureError(failure: { status: "failed" | "aborted"; message: string }): Error {
104
+ function failureError(failure: { status: "failed" | "aborted"; message: string }): Error {
105
105
  const error = new Error(failure.message);
106
106
  (error as Error & { subagentStatus?: string }).subagentStatus = failure.status;
107
107
  return error;
108
108
  }
109
- export function updateUsageFromMessage(task: TaskSnapshot, message: AssistantMessage): void {
109
+ function updateUsageFromMessage(task: TaskSnapshot, message: AssistantMessage): void {
110
110
  if (message?.role !== "assistant") return;
111
111
  task.usage.turns += 1;
112
112
  const usage = message.usage;
@@ -1080,7 +1080,6 @@ export class SubagentManager {
1080
1080
  s(cloneRun(run));
1081
1081
  }
1082
1082
 
1083
- /** Child→leader messages collected while the parent is parked in await_subagent. */
1084
1083
  /** Child→leader messages collected while the parent is parked in await_subagent. */
1085
1084
  private parked = new Map<string, { msgs: ParkedMsg[]; wake: () => void }>();
1086
1085