pi-subagents 0.24.3 → 0.24.4
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 +18 -5
- package/README.md +3 -1
- package/package.json +4 -8
- package/src/agents/agent-management.ts +5 -0
- package/src/agents/agent-serializer.ts +2 -0
- package/src/agents/agents.ts +30 -6
- package/src/agents/skills.ts +25 -23
- package/src/extension/config.ts +16 -0
- package/src/extension/index.ts +7 -23
- package/src/intercom/intercom-bridge.ts +2 -1
- package/src/runs/background/async-execution.ts +6 -3
- package/src/runs/background/async-job-tracker.ts +16 -8
- package/src/runs/background/subagent-runner.ts +18 -7
- package/src/runs/foreground/execution.ts +17 -5
- package/src/runs/foreground/subagent-executor.ts +4 -4
- package/src/runs/shared/completion-guard.ts +23 -1
- package/src/runs/shared/mcp-direct-tool-allowlist.ts +365 -0
- package/src/runs/shared/parallel-utils.ts +1 -0
- package/src/runs/shared/pi-args.ts +5 -0
- package/src/runs/shared/run-history.ts +12 -7
- package/src/runs/shared/single-output.ts +12 -2
- package/src/shared/artifacts.ts +2 -2
- package/src/shared/utils.ts +11 -1
- package/src/tui/render.ts +148 -144
|
@@ -2,6 +2,7 @@ import * as fs from "node:fs";
|
|
|
2
2
|
import * as os from "node:os";
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { resolveMcpDirectToolNames } from "./mcp-direct-tool-allowlist.ts";
|
|
5
6
|
|
|
6
7
|
const THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh"];
|
|
7
8
|
const TASK_ARG_LIMIT = 8000;
|
|
@@ -27,6 +28,7 @@ interface BuildPiArgsInput {
|
|
|
27
28
|
extensions?: string[];
|
|
28
29
|
systemPrompt?: string | null;
|
|
29
30
|
mcpDirectTools?: string[];
|
|
31
|
+
cwd?: string;
|
|
30
32
|
promptFileStem?: string;
|
|
31
33
|
intercomSessionName?: string;
|
|
32
34
|
orchestratorIntercomTarget?: string;
|
|
@@ -80,6 +82,9 @@ export function buildPiArgs(input: BuildPiArgsInput): BuildPiArgsResult {
|
|
|
80
82
|
}
|
|
81
83
|
}
|
|
82
84
|
if (builtinTools.length > 0) {
|
|
85
|
+
if (input.mcpDirectTools?.length) {
|
|
86
|
+
builtinTools.push(...resolveMcpDirectToolNames(input.mcpDirectTools, input.cwd));
|
|
87
|
+
}
|
|
83
88
|
args.push("--tools", builtinTools.join(","));
|
|
84
89
|
}
|
|
85
90
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
|
-
import * as os from "node:os";
|
|
3
2
|
import * as path from "node:path";
|
|
3
|
+
import { getAgentDir } from "../../shared/utils.ts";
|
|
4
4
|
|
|
5
5
|
export interface RunEntry {
|
|
6
6
|
agent: string;
|
|
@@ -11,10 +11,13 @@ export interface RunEntry {
|
|
|
11
11
|
exit?: number;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
const HISTORY_PATH = path.join(os.homedir(), ".pi", "agent", "run-history.jsonl");
|
|
15
14
|
const ROTATE_READ_THRESHOLD = 1200;
|
|
16
15
|
const ROTATE_KEEP = 1000;
|
|
17
16
|
|
|
17
|
+
function getHistoryPath(): string {
|
|
18
|
+
return path.join(getAgentDir(), "run-history.jsonl");
|
|
19
|
+
}
|
|
20
|
+
|
|
18
21
|
export function recordRun(agent: string, task: string, exitCode: number, durationMs: number): void {
|
|
19
22
|
try {
|
|
20
23
|
const entry: RunEntry = {
|
|
@@ -25,18 +28,20 @@ export function recordRun(agent: string, task: string, exitCode: number, duratio
|
|
|
25
28
|
duration: durationMs,
|
|
26
29
|
...(exitCode !== 0 ? { exit: exitCode } : {}),
|
|
27
30
|
};
|
|
28
|
-
|
|
29
|
-
fs.
|
|
31
|
+
const historyPath = getHistoryPath();
|
|
32
|
+
fs.mkdirSync(path.dirname(historyPath), { recursive: true });
|
|
33
|
+
fs.appendFileSync(historyPath, `${JSON.stringify(entry)}\n`);
|
|
30
34
|
} catch {
|
|
31
35
|
// Best-effort — never crash the execution flow for history recording
|
|
32
36
|
}
|
|
33
37
|
}
|
|
34
38
|
|
|
35
39
|
export function loadRunsForAgent(agent: string): RunEntry[] {
|
|
36
|
-
|
|
40
|
+
const historyPath = getHistoryPath();
|
|
41
|
+
if (!fs.existsSync(historyPath)) return [];
|
|
37
42
|
let raw: string;
|
|
38
43
|
try {
|
|
39
|
-
raw = fs.readFileSync(
|
|
44
|
+
raw = fs.readFileSync(historyPath, "utf-8");
|
|
40
45
|
} catch {
|
|
41
46
|
return [];
|
|
42
47
|
}
|
|
@@ -45,7 +50,7 @@ export function loadRunsForAgent(agent: string): RunEntry[] {
|
|
|
45
50
|
|
|
46
51
|
if (lines.length > ROTATE_READ_THRESHOLD) {
|
|
47
52
|
lines = lines.slice(-ROTATE_KEEP);
|
|
48
|
-
try { fs.writeFileSync(
|
|
53
|
+
try { fs.writeFileSync(historyPath, `${lines.join("\n")}\n`, "utf-8"); } catch {}
|
|
49
54
|
}
|
|
50
55
|
|
|
51
56
|
return lines
|
|
@@ -8,12 +8,22 @@ export interface SingleOutputSnapshot {
|
|
|
8
8
|
size?: number;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
export function normalizeSingleOutputOverride(
|
|
12
|
+
output: string | boolean | undefined,
|
|
13
|
+
defaultOutput: string | undefined,
|
|
14
|
+
): string | false | undefined {
|
|
15
|
+
if (output === false || output === "false") return false;
|
|
16
|
+
if (output === true || output === "true") return defaultOutput;
|
|
17
|
+
if (typeof output === "string" && output.length > 0) return output;
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
|
|
11
21
|
export function resolveSingleOutputPath(
|
|
12
|
-
output: string |
|
|
22
|
+
output: string | boolean | undefined,
|
|
13
23
|
runtimeCwd: string,
|
|
14
24
|
requestedCwd?: string,
|
|
15
25
|
): string | undefined {
|
|
16
|
-
if (typeof output !== "string" || !output) return undefined;
|
|
26
|
+
if (typeof output !== "string" || !output || output === "false" || output === "true") return undefined;
|
|
17
27
|
if (path.isAbsolute(output)) return output;
|
|
18
28
|
const baseCwd = requestedCwd
|
|
19
29
|
? (path.isAbsolute(requestedCwd) ? requestedCwd : path.resolve(runtimeCwd, requestedCwd))
|
package/src/shared/artifacts.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
|
-
import * as os from "node:os";
|
|
3
2
|
import * as path from "node:path";
|
|
4
3
|
import { TEMP_ARTIFACTS_DIR, type ArtifactPaths } from "./types.ts";
|
|
4
|
+
import { getAgentDir } from "./utils.ts";
|
|
5
5
|
const CLEANUP_MARKER_FILE = ".last-cleanup";
|
|
6
6
|
|
|
7
7
|
export function getArtifactsDir(sessionFile: string | null): string {
|
|
@@ -74,7 +74,7 @@ export function cleanupOldArtifacts(dir: string, maxAgeDays: number): void {
|
|
|
74
74
|
export function cleanupAllArtifactDirs(maxAgeDays: number): void {
|
|
75
75
|
cleanupOldArtifacts(TEMP_ARTIFACTS_DIR, maxAgeDays);
|
|
76
76
|
|
|
77
|
-
const sessionsBase = path.join(
|
|
77
|
+
const sessionsBase = path.join(getAgentDir(), "sessions");
|
|
78
78
|
if (!fs.existsSync(sessionsBase)) return;
|
|
79
79
|
|
|
80
80
|
let dirs: string[];
|
package/src/shared/utils.ts
CHANGED
|
@@ -13,6 +13,13 @@ import type { AgentProgress, AsyncStatus, Details, DisplayItem, ErrorInfo, Singl
|
|
|
13
13
|
// File System Utilities
|
|
14
14
|
// ============================================================================
|
|
15
15
|
|
|
16
|
+
export function getAgentDir(): string {
|
|
17
|
+
const configured = process.env.PI_CODING_AGENT_DIR;
|
|
18
|
+
if (configured === "~") return os.homedir();
|
|
19
|
+
if (configured?.startsWith("~/")) return path.join(os.homedir(), configured.slice(2));
|
|
20
|
+
return configured || path.join(os.homedir(), ".pi", "agent");
|
|
21
|
+
}
|
|
22
|
+
|
|
16
23
|
const statusCache = new Map<string, { mtime: number; status: AsyncStatus }>();
|
|
17
24
|
|
|
18
25
|
function getErrorMessage(error: unknown): string {
|
|
@@ -182,8 +189,11 @@ export function getFinalOutput(messages: Message[]): string {
|
|
|
182
189
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
183
190
|
const msg = messages[i];
|
|
184
191
|
if (msg.role === "assistant") {
|
|
192
|
+
const hasAssistantError = ("errorMessage" in msg && typeof msg.errorMessage === "string" && msg.errorMessage.length > 0)
|
|
193
|
+
|| ("stopReason" in msg && msg.stopReason === "error");
|
|
194
|
+
if (hasAssistantError) continue;
|
|
185
195
|
for (const part of msg.content) {
|
|
186
|
-
if (part.type === "text") return part.text;
|
|
196
|
+
if (part.type === "text" && part.text.trim().length > 0) return part.text;
|
|
187
197
|
}
|
|
188
198
|
}
|
|
189
199
|
}
|