@bacnh85/pi-subagent 0.4.1 → 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.
@@ -7,134 +7,10 @@
7
7
 
8
8
  import { getMarkdownTheme } from "@earendil-works/pi-coding-agent";
9
9
  import { matchesKey, Key, truncateToWidth, Markdown } from "@earendil-works/pi-tui";
10
- import type { Message } from "@earendil-works/pi-ai";
11
10
 
12
- import { type SubAgentResult, isFailedResult, getResultOutput, getFinalOutput } from "./runner.ts";
13
- import { formatUsageStats } from "./render.ts";
11
+ import { isFailedResult, getFinalOutput } from "./runner.ts";
12
+ import { formatToolCall, getDisplayItems, formatUsageStats } from "./render.ts";
14
13
  import type { SubagentThread } from "./threads.ts";
15
- import * as os from "node:os";
16
-
17
- // ---------------------------------------------------------------------------
18
- // Safe type guards for tool-call arguments
19
- // ---------------------------------------------------------------------------
20
-
21
- function asString(value: unknown, fallback = "..."): string {
22
- return typeof value === "string" ? value : fallback;
23
- }
24
-
25
- function asNumber(value: unknown): number | undefined {
26
- return typeof value === "number" && Number.isFinite(value) ? value : undefined;
27
- }
28
-
29
- function asRecord(value: unknown): Record<string, unknown> {
30
- return value && typeof value === "object" && !Array.isArray(value)
31
- ? (value as Record<string, unknown>)
32
- : {};
33
- }
34
-
35
- // ---------------------------------------------------------------------------
36
- // Tool-call formatting (same as render.ts)
37
- // ---------------------------------------------------------------------------
38
-
39
- function formatToolCall(
40
- toolName: string,
41
- args: Record<string, unknown>,
42
- themeFg: (color: string, text: string) => string,
43
- ): string {
44
- const shortenPath = (p: string) => {
45
- const home = os.homedir();
46
- return p.startsWith(home) ? `~${p.slice(home.length)}` : p;
47
- };
48
-
49
- switch (toolName) {
50
- case "bash": {
51
- const command = asString(args.command);
52
- const preview = command.length > 60 ? `${command.slice(0, 60)}...` : command;
53
- return themeFg("muted", "$ ") + themeFg("toolOutput", preview);
54
- }
55
- case "read": {
56
- const rawPath = asString(args.file_path ?? args.path);
57
- const filePath = shortenPath(rawPath);
58
- const offset = asNumber(args.offset);
59
- const limit = asNumber(args.limit);
60
- let text = themeFg("accent", filePath);
61
- if (offset !== undefined || limit !== undefined) {
62
- const startLine = offset ?? 1;
63
- const endLine = limit !== undefined ? startLine + limit - 1 : "";
64
- text += themeFg("warning", `:${startLine}${endLine ? `-${endLine}` : ""}`);
65
- }
66
- return themeFg("muted", "read ") + text;
67
- }
68
- case "write": {
69
- const rawPath = asString(args.file_path ?? args.path);
70
- const filePath = shortenPath(rawPath);
71
- const content = asString(args.content, "");
72
- const lines = content.split("\n").length;
73
- let text = themeFg("muted", "write ") + themeFg("accent", filePath);
74
- if (lines > 1) text += themeFg("dim", ` (${lines} lines)`);
75
- return text;
76
- }
77
- case "edit": {
78
- const rawPath = asString(args.file_path ?? args.path);
79
- return themeFg("muted", "edit ") + themeFg("accent", shortenPath(rawPath));
80
- }
81
- case "ls": {
82
- const rawPath = asString(args.path, ".");
83
- return themeFg("muted", "ls ") + themeFg("accent", shortenPath(rawPath));
84
- }
85
- case "find": {
86
- const pattern = asString(args.pattern, "*");
87
- const rawPath = asString(args.path, ".");
88
- return (
89
- themeFg("muted", "find ") +
90
- themeFg("accent", pattern) +
91
- themeFg("dim", ` in ${shortenPath(rawPath)}`)
92
- );
93
- }
94
- case "grep": {
95
- const pattern = asString(args.pattern);
96
- const rawPath = asString(args.path, ".");
97
- return (
98
- themeFg("muted", "grep ") +
99
- themeFg("accent", `/${pattern}/`) +
100
- themeFg("dim", ` in ${shortenPath(rawPath)}`)
101
- );
102
- }
103
- default: {
104
- const argsStr = JSON.stringify(args);
105
- const preview = argsStr.length > 50 ? `${argsStr.slice(0, 50)}...` : argsStr;
106
- return themeFg("accent", toolName) + themeFg("dim", ` ${preview}`);
107
- }
108
- }
109
- }
110
-
111
- // ---------------------------------------------------------------------------
112
- // Display helpers
113
- // ---------------------------------------------------------------------------
114
-
115
- type DisplayItem =
116
- | { type: "text"; text: string }
117
- | { type: "toolCall"; name: string; args: Record<string, unknown> };
118
-
119
- function getDisplayItems(messages: Message[]): DisplayItem[] {
120
- const items: DisplayItem[] = [];
121
- for (const msg of messages) {
122
- if (msg.role === "assistant") {
123
- for (const part of msg.content) {
124
- if (part.type === "text" && part.text.trim()) {
125
- items.push({ type: "text", text: part.text });
126
- } else if (part.type === "toolCall") {
127
- items.push({
128
- type: "toolCall",
129
- name: part.name,
130
- args: asRecord(part.arguments),
131
- });
132
- }
133
- }
134
- }
135
- }
136
- return items;
137
- }
138
14
 
139
15
  // ---------------------------------------------------------------------------
140
16
  // Theme types
@@ -103,14 +103,4 @@ export const threadStore = new ThreadStore();
103
103
  // ID generation (UUID v4 style, good enough for in-memory use)
104
104
  // ---------------------------------------------------------------------------
105
105
 
106
- function cryptoGenId(): string {
107
- if (typeof crypto !== "undefined" && crypto.randomUUID) {
108
- return crypto.randomUUID();
109
- }
110
- // Fallback for environments without crypto (very unlikely in Node)
111
- return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
112
- const r = (Math.random() * 16) | 0;
113
- const v = c === "x" ? r : (r & 0x3) | 0x8;
114
- return v.toString(16);
115
- });
116
- }
106
+ const cryptoGenId = () => crypto.randomUUID();
package/package.json CHANGED
@@ -1,49 +1,69 @@
1
1
  {
2
2
  "name": "@bacnh85/pi-subagent",
3
- "version": "0.4.1",
4
- "description": "Minimal-overhead sub-agent extension for pi. Delegate tasks to specialized agents with isolated context using the pi SDK in-process.",
3
+ "version": "0.6.1",
4
+ "description": "In-process subagents for Pi with isolated SDK sessions, parallel and chained delegation, and inspectable threads.",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
- "publishConfig": {
8
- "access": "public"
9
- },
10
- "homepage": "https://github.com/bacnh85/skills#readme",
7
+ "publishConfig": { "access": "public" },
8
+ "homepage": "https://github.com/bacnh85/pi-extensions/tree/main/pi-subagent",
11
9
  "repository": {
12
10
  "type": "git",
13
- "url": "git+https://github.com/bacnh85/skills.git",
14
- "directory": "extensions/pi-subagent"
15
- },
16
- "bugs": {
17
- "url": "https://github.com/bacnh85/skills/issues"
11
+ "url": "git+https://github.com/bacnh85/pi-extensions.git",
12
+ "directory": "pi-subagent"
18
13
  },
14
+ "bugs": { "url": "https://github.com/bacnh85/pi-extensions/issues" },
19
15
  "keywords": [
20
16
  "pi-package",
21
17
  "pi-extension",
22
18
  "subagent",
23
19
  "sub-agent",
24
20
  "delegation",
25
- "parallel"
21
+ "parallel",
22
+ "chain",
23
+ "security"
26
24
  ],
27
25
  "files": [
28
26
  "README.md",
29
- "index.ts",
30
- "agents.ts",
31
- "runner.ts",
32
- "render.ts",
33
- "threads.ts",
34
- "thread-viewer.ts",
27
+ "agent-format.md",
28
+ "CHANGELOG.md",
35
29
  "agents/",
36
- "agent-format.md"
30
+ "extensions/index.ts",
31
+ "extensions/agents.ts",
32
+ "extensions/model.ts",
33
+ "extensions/runner.ts",
34
+ "extensions/service.ts",
35
+ "extensions/render.ts",
36
+ "extensions/threads.ts",
37
+ "extensions/thread-viewer.ts",
38
+ "extensions/security.ts",
39
+ "extensions/package.json"
37
40
  ],
38
- "pi": {
39
- "extensions": [
40
- "./index.ts"
41
- ]
41
+ "pi": { "extensions": ["./extensions/index.ts"] },
42
+ "engines": {
43
+ "node": ">=20.18"
44
+ },
45
+ "scripts": {
46
+ "test": "cd extensions && mocha",
47
+ "typecheck": "tsc --noEmit",
48
+ "check": "npm run typecheck && npm test"
42
49
  },
43
50
  "peerDependencies": {
44
- "@earendil-works/pi-coding-agent": "*",
45
- "@earendil-works/pi-ai": "*",
46
- "@earendil-works/pi-agent-core": "*",
47
- "@earendil-works/pi-tui": "*"
51
+ "@earendil-works/pi-coding-agent": ">=0.80.0 <0.81.0",
52
+ "@earendil-works/pi-ai": ">=0.80.0 <0.81.0",
53
+ "@earendil-works/pi-agent-core": ">=0.80.0 <0.81.0",
54
+ "@earendil-works/pi-tui": ">=0.80.0 <0.81.0",
55
+ "typebox": ">=1.3.0 <2.0.0"
56
+ },
57
+ "devDependencies": {
58
+ "@earendil-works/pi-agent-core": "^0.80.2",
59
+ "@earendil-works/pi-ai": "^0.80.2",
60
+ "@earendil-works/pi-coding-agent": "^0.80.2",
61
+ "@earendil-works/pi-tui": "^0.80.2",
62
+ "@types/mocha": "^10.0.10",
63
+ "@types/node": "^20.19.43",
64
+ "mocha": "^10.8.2",
65
+ "tsx": "^4.22.4",
66
+ "typescript": "^5.9.3",
67
+ "typebox": "^1.3.1"
48
68
  }
49
69
  }