pi-subagents 0.8.3 → 0.8.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 +7 -0
- package/artifacts.ts +21 -0
- package/index.ts +14 -2
- package/jsonl-writer.ts +10 -1
- package/package.json +1 -1
- package/types.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.8.4] - 2026-02-13
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- JSONL artifact files no longer written by default — they duplicated pi's own session files and were the sole cause of `subagent-artifacts` directories growing to 10+ GB. Changed `includeJsonl` default from `true` to `false`. `_output.md` and `_meta.json` still capture the useful data.
|
|
9
|
+
- Artifact cleanup now covers session-based directories, not just the temp dir. Previously `cleanupOldArtifacts` only ran on `os.tmpdir()/pi-subagent-artifacts` at startup, while sync runs (the common path) wrote to `<session-dir>/subagent-artifacts/` which was never cleaned. Now scans all `~/.pi/agent/sessions/*/subagent-artifacts/` dirs on startup and cleans the current session's artifacts dir on session lifecycle events.
|
|
10
|
+
- JSONL writer now enforces a 50 MB size cap (`maxBytes` on `JsonlWriterDeps`) as defense-in-depth for users who opt into JSONL. Silently stops writing at the cap without pausing the source stream, so the progress tracker keeps working.
|
|
11
|
+
|
|
5
12
|
## [0.8.3] - 2026-02-11
|
|
6
13
|
|
|
7
14
|
### Added
|
package/artifacts.ts
CHANGED
|
@@ -69,3 +69,24 @@ export function cleanupOldArtifacts(dir: string, maxAgeDays: number): void {
|
|
|
69
69
|
|
|
70
70
|
fs.writeFileSync(markerPath, String(now));
|
|
71
71
|
}
|
|
72
|
+
|
|
73
|
+
export function cleanupAllArtifactDirs(maxAgeDays: number): void {
|
|
74
|
+
cleanupOldArtifacts(TEMP_ARTIFACTS_DIR, maxAgeDays);
|
|
75
|
+
|
|
76
|
+
const sessionsBase = path.join(os.homedir(), ".pi", "agent", "sessions");
|
|
77
|
+
if (!fs.existsSync(sessionsBase)) return;
|
|
78
|
+
|
|
79
|
+
let dirs: string[];
|
|
80
|
+
try {
|
|
81
|
+
dirs = fs.readdirSync(sessionsBase);
|
|
82
|
+
} catch {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
for (const dir of dirs) {
|
|
87
|
+
const artifactsDir = path.join(sessionsBase, dir, "subagent-artifacts");
|
|
88
|
+
try {
|
|
89
|
+
cleanupOldArtifacts(artifactsDir, maxAgeDays);
|
|
90
|
+
} catch {}
|
|
91
|
+
}
|
|
92
|
+
}
|
package/index.ts
CHANGED
|
@@ -22,7 +22,7 @@ import { type AgentConfig, type AgentScope, discoverAgents, discoverAgentsAll }
|
|
|
22
22
|
import { resolveExecutionAgentScope } from "./agent-scope.js";
|
|
23
23
|
import { cleanupOldChainDirs, getStepAgents, isParallelStep, resolveStepBehavior, type ChainStep, type SequentialStep } from "./settings.js";
|
|
24
24
|
import { ChainClarifyComponent, type ChainClarifyResult, type ModelInfo } from "./chain-clarify.js";
|
|
25
|
-
import { cleanupOldArtifacts, getArtifactsDir } from "./artifacts.js";
|
|
25
|
+
import { cleanupAllArtifactDirs, cleanupOldArtifacts, getArtifactsDir } from "./artifacts.js";
|
|
26
26
|
import {
|
|
27
27
|
type AgentProgress,
|
|
28
28
|
type ArtifactConfig,
|
|
@@ -78,7 +78,7 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
|
|
|
78
78
|
const asyncByDefault = config.asyncByDefault === true;
|
|
79
79
|
|
|
80
80
|
const tempArtifactsDir = getArtifactsDir(null);
|
|
81
|
-
|
|
81
|
+
cleanupAllArtifactDirs(DEFAULT_ARTIFACT_CONFIG.cleanupDays);
|
|
82
82
|
let baseCwd = process.cwd();
|
|
83
83
|
let currentSessionId: string | null = null;
|
|
84
84
|
const asyncJobs = new Map<string, AsyncJobState>();
|
|
@@ -1143,9 +1143,19 @@ MANAGEMENT (use action field — omit agent/task/chain/tasks):
|
|
|
1143
1143
|
}
|
|
1144
1144
|
});
|
|
1145
1145
|
|
|
1146
|
+
const cleanupSessionArtifacts = (ctx: ExtensionContext) => {
|
|
1147
|
+
try {
|
|
1148
|
+
const sessionFile = ctx.sessionManager.getSessionFile();
|
|
1149
|
+
if (sessionFile) {
|
|
1150
|
+
cleanupOldArtifacts(getArtifactsDir(sessionFile), DEFAULT_ARTIFACT_CONFIG.cleanupDays);
|
|
1151
|
+
}
|
|
1152
|
+
} catch {}
|
|
1153
|
+
};
|
|
1154
|
+
|
|
1146
1155
|
pi.on("session_start", (_event, ctx) => {
|
|
1147
1156
|
baseCwd = ctx.cwd;
|
|
1148
1157
|
currentSessionId = ctx.sessionManager.getSessionFile() ?? `session-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
1158
|
+
cleanupSessionArtifacts(ctx);
|
|
1149
1159
|
for (const timer of cleanupTimers.values()) clearTimeout(timer);
|
|
1150
1160
|
cleanupTimers.clear();
|
|
1151
1161
|
asyncJobs.clear();
|
|
@@ -1158,6 +1168,7 @@ MANAGEMENT (use action field — omit agent/task/chain/tasks):
|
|
|
1158
1168
|
pi.on("session_switch", (_event, ctx) => {
|
|
1159
1169
|
baseCwd = ctx.cwd;
|
|
1160
1170
|
currentSessionId = ctx.sessionManager.getSessionFile() ?? `session-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
1171
|
+
cleanupSessionArtifacts(ctx);
|
|
1161
1172
|
for (const timer of cleanupTimers.values()) clearTimeout(timer);
|
|
1162
1173
|
cleanupTimers.clear();
|
|
1163
1174
|
asyncJobs.clear();
|
|
@@ -1170,6 +1181,7 @@ MANAGEMENT (use action field — omit agent/task/chain/tasks):
|
|
|
1170
1181
|
pi.on("session_branch", (_event, ctx) => {
|
|
1171
1182
|
baseCwd = ctx.cwd;
|
|
1172
1183
|
currentSessionId = ctx.sessionManager.getSessionFile() ?? `session-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
1184
|
+
cleanupSessionArtifacts(ctx);
|
|
1173
1185
|
for (const timer of cleanupTimers.values()) clearTimeout(timer);
|
|
1174
1186
|
cleanupTimers.clear();
|
|
1175
1187
|
asyncJobs.clear();
|
package/jsonl-writer.ts
CHANGED
|
@@ -11,8 +11,11 @@ export interface JsonlWriteStream {
|
|
|
11
11
|
end(callback?: () => void): void;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
const DEFAULT_MAX_JSONL_BYTES = 50 * 1024 * 1024;
|
|
15
|
+
|
|
14
16
|
export interface JsonlWriterDeps {
|
|
15
17
|
createWriteStream?: (filePath: string) => JsonlWriteStream;
|
|
18
|
+
maxBytes?: number;
|
|
16
19
|
}
|
|
17
20
|
|
|
18
21
|
export interface JsonlWriter {
|
|
@@ -45,12 +48,18 @@ export function createJsonlWriter(
|
|
|
45
48
|
|
|
46
49
|
let backpressured = false;
|
|
47
50
|
let closed = false;
|
|
51
|
+
let bytesWritten = 0;
|
|
52
|
+
const maxBytes = deps.maxBytes ?? DEFAULT_MAX_JSONL_BYTES;
|
|
48
53
|
|
|
49
54
|
return {
|
|
50
55
|
writeLine(line: string) {
|
|
51
56
|
if (!stream || closed || !line.trim()) return;
|
|
57
|
+
const chunk = `${line}\n`;
|
|
58
|
+
const chunkBytes = Buffer.byteLength(chunk, "utf-8");
|
|
59
|
+
if (bytesWritten + chunkBytes > maxBytes) return;
|
|
52
60
|
try {
|
|
53
|
-
const ok = stream.write(
|
|
61
|
+
const ok = stream.write(chunk);
|
|
62
|
+
bytesWritten += chunkBytes;
|
|
54
63
|
if (!ok && !backpressured) {
|
|
55
64
|
backpressured = true;
|
|
56
65
|
source.pause();
|
package/package.json
CHANGED
package/types.ts
CHANGED