opensec-pi-subagents 0.20.1 → 0.20.2
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 +6 -0
- package/README.md +2 -1
- package/dist-bun/core.cjs +308 -286
- package/dist-bun/index.js +1 -1
- package/docs/workflows.md +2 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.20.2] - 2026-10-16
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- **Every project is trusted again by default**, as before 0.20.1: subagents load a project's `.pi` extensions and settings, and the extension uses its agents, skills, workflows and `subagents.json`, whatever Pi decided for the folder. To follow Pi's project trust decision instead (0.20.1's behaviour), set `"projectTrust": "pi"` in the global `~/.pi/agent/subagents.json`.
|
|
15
|
+
|
|
10
16
|
## [0.20.1] - 2026-10-16
|
|
11
17
|
|
|
12
18
|
### Fixed
|
package/README.md
CHANGED
|
@@ -115,10 +115,11 @@ locations are those of `@tintinweb/pi-subagents`.
|
|
|
115
115
|
|
|
116
116
|
Based on `@tintinweb/pi-subagents` 0.19:
|
|
117
117
|
|
|
118
|
+
- **0.20.2:** every project is trusted by default, as before 0.20.1. To have subagents follow Pi's project trust decision, set `"projectTrust": "pi"` in `~/.pi/agent/subagents.json`.
|
|
118
119
|
- **0.20.1:**
|
|
119
120
|
- Resume works for as long as an agent's session file exists, not 10 minutes, and after a restart; worktree agents resume in their worktree; `max_turns` and the tool watchdog apply to resumed runs.
|
|
120
121
|
- An agent whose tool ignores a stop is still stopped and frees its slot; three ways to crash Pi are fixed.
|
|
121
|
-
-
|
|
122
|
+
- Explore and Plan are read-only by their tools (`read`, `grep`, `find`, `ls`).
|
|
122
123
|
- Worktree cleanup no longer loses ignored output, nested repositories or stashes; timed-out gates end their whole process tree.
|
|
123
124
|
- Much less work per frame: one refresh timer that stops while idle, an incremental transcript viewer, a widget that formats only the rows it shows.
|
|
124
125
|
- **Tool time limits:** `bash` calls of subagents and of the main agent get `toolTimeoutSeconds` (default 1200 s), and a watchdog stops other hung tools.
|
package/dist-bun/core.cjs
CHANGED
|
@@ -77,17 +77,17 @@ var __esm = (fn, res, err) => () => {
|
|
|
77
77
|
|
|
78
78
|
// pi-host:@earendil-works/pi-coding-agent
|
|
79
79
|
var require_pi_coding_agent = __commonJS(function(exports2, module2) {
|
|
80
|
-
module2.exports = globalThis[Symbol.for("opensec-pi-subagents@0.20.
|
|
80
|
+
module2.exports = globalThis[Symbol.for("opensec-pi-subagents@0.20.2:host-modules")]("@earendil-works/pi-coding-agent");
|
|
81
81
|
});
|
|
82
82
|
|
|
83
83
|
// pi-host:@earendil-works/pi-tui
|
|
84
84
|
var require_pi_tui = __commonJS(function(exports2, module2) {
|
|
85
|
-
module2.exports = globalThis[Symbol.for("opensec-pi-subagents@0.20.
|
|
85
|
+
module2.exports = globalThis[Symbol.for("opensec-pi-subagents@0.20.2:host-modules")]("@earendil-works/pi-tui");
|
|
86
86
|
});
|
|
87
87
|
|
|
88
88
|
// pi-host:@sinclair/typebox
|
|
89
89
|
var require_typebox = __commonJS(function(exports2, module2) {
|
|
90
|
-
module2.exports = globalThis[Symbol.for("opensec-pi-subagents@0.20.
|
|
90
|
+
module2.exports = globalThis[Symbol.for("opensec-pi-subagents@0.20.2:host-modules")]("@sinclair/typebox");
|
|
91
91
|
});
|
|
92
92
|
|
|
93
93
|
// src/abortable.ts
|
|
@@ -2158,8 +2158,222 @@ var init_nested_tools = __esm(() => {
|
|
|
2158
2158
|
NESTED_TOOL_NAMES = ["Agent", "get_subagent_result", "steer_subagent"];
|
|
2159
2159
|
});
|
|
2160
2160
|
|
|
2161
|
+
// src/settings.ts
|
|
2162
|
+
function sanitize(raw) {
|
|
2163
|
+
if (!raw || typeof raw !== "object")
|
|
2164
|
+
return {};
|
|
2165
|
+
const r = raw;
|
|
2166
|
+
const out = {};
|
|
2167
|
+
if (Number.isInteger(r.maxConcurrent) && r.maxConcurrent >= 1 && r.maxConcurrent <= MAX_CONCURRENT_CEILING) {
|
|
2168
|
+
out.maxConcurrent = r.maxConcurrent;
|
|
2169
|
+
}
|
|
2170
|
+
if (Number.isInteger(r.maxConcurrentForeground) && r.maxConcurrentForeground >= 0 && r.maxConcurrentForeground <= MAX_CONCURRENT_CEILING) {
|
|
2171
|
+
out.maxConcurrentForeground = r.maxConcurrentForeground;
|
|
2172
|
+
}
|
|
2173
|
+
if (Number.isInteger(r.defaultMaxTurns) && r.defaultMaxTurns >= 0 && r.defaultMaxTurns <= MAX_TURNS_CEILING) {
|
|
2174
|
+
out.defaultMaxTurns = r.defaultMaxTurns;
|
|
2175
|
+
}
|
|
2176
|
+
if (Number.isInteger(r.graceTurns) && r.graceTurns >= 1 && r.graceTurns <= GRACE_TURNS_CEILING) {
|
|
2177
|
+
out.graceTurns = r.graceTurns;
|
|
2178
|
+
}
|
|
2179
|
+
if (Number.isInteger(r.toolTimeoutSeconds) && r.toolTimeoutSeconds >= 0 && r.toolTimeoutSeconds <= TOOL_TIMEOUT_CEILING) {
|
|
2180
|
+
out.toolTimeoutSeconds = r.toolTimeoutSeconds;
|
|
2181
|
+
}
|
|
2182
|
+
if (Number.isInteger(r.maxSubagentDepth) && r.maxSubagentDepth >= 0 && r.maxSubagentDepth <= SUBAGENT_DEPTH_CEILING) {
|
|
2183
|
+
out.maxSubagentDepth = r.maxSubagentDepth;
|
|
2184
|
+
}
|
|
2185
|
+
if (typeof r.defaultJoinMode === "string" && VALID_JOIN_MODES.has(r.defaultJoinMode)) {
|
|
2186
|
+
out.defaultJoinMode = r.defaultJoinMode;
|
|
2187
|
+
}
|
|
2188
|
+
if (typeof r.backgroundByDefault === "boolean") {
|
|
2189
|
+
out.backgroundByDefault = r.backgroundByDefault;
|
|
2190
|
+
}
|
|
2191
|
+
if (typeof r.schedulingEnabled === "boolean") {
|
|
2192
|
+
out.schedulingEnabled = r.schedulingEnabled;
|
|
2193
|
+
}
|
|
2194
|
+
if (typeof r.scopeModels === "boolean") {
|
|
2195
|
+
out.scopeModels = r.scopeModels;
|
|
2196
|
+
}
|
|
2197
|
+
if (typeof r.strictAgentFiles === "boolean") {
|
|
2198
|
+
out.strictAgentFiles = r.strictAgentFiles;
|
|
2199
|
+
}
|
|
2200
|
+
if (r.projectTrust === "full" || r.projectTrust === "pi") {
|
|
2201
|
+
out.projectTrust = r.projectTrust;
|
|
2202
|
+
}
|
|
2203
|
+
if (typeof r.disableDefaultAgents === "boolean") {
|
|
2204
|
+
out.disableDefaultAgents = r.disableDefaultAgents;
|
|
2205
|
+
}
|
|
2206
|
+
if (typeof r.toolDescriptionMode === "string" && VALID_TOOL_DESCRIPTION_MODES.has(r.toolDescriptionMode)) {
|
|
2207
|
+
out.toolDescriptionMode = r.toolDescriptionMode;
|
|
2208
|
+
}
|
|
2209
|
+
if (typeof r.fleetView === "boolean") {
|
|
2210
|
+
out.fleetView = r.fleetView;
|
|
2211
|
+
}
|
|
2212
|
+
if (typeof r.agentMentions === "boolean") {
|
|
2213
|
+
out.agentMentions = r.agentMentions ? "model" : "off";
|
|
2214
|
+
} else if (typeof r.agentMentions === "string" && VALID_AGENT_MENTION_MODES.has(r.agentMentions)) {
|
|
2215
|
+
out.agentMentions = r.agentMentions;
|
|
2216
|
+
}
|
|
2217
|
+
if (typeof r.rememberAgents === "boolean") {
|
|
2218
|
+
out.rememberAgents = r.rememberAgents;
|
|
2219
|
+
}
|
|
2220
|
+
if (typeof r.widgetMode === "string" && VALID_WIDGET_MODES.has(r.widgetMode)) {
|
|
2221
|
+
out.widgetMode = r.widgetMode;
|
|
2222
|
+
}
|
|
2223
|
+
if (typeof r.outputTranscript === "boolean") {
|
|
2224
|
+
out.outputTranscript = r.outputTranscript;
|
|
2225
|
+
}
|
|
2226
|
+
if (typeof r.worktreeIsolation === "boolean") {
|
|
2227
|
+
out.worktreeIsolation = r.worktreeIsolation;
|
|
2228
|
+
}
|
|
2229
|
+
if (typeof r.reportUsage === "boolean") {
|
|
2230
|
+
out.reportUsage = r.reportUsage;
|
|
2231
|
+
}
|
|
2232
|
+
if (typeof r.showCost === "boolean") {
|
|
2233
|
+
out.showCost = r.showCost;
|
|
2234
|
+
}
|
|
2235
|
+
if (typeof r.showModel === "boolean") {
|
|
2236
|
+
out.showModel = r.showModel;
|
|
2237
|
+
}
|
|
2238
|
+
if (typeof r.viewerMarkdown === "string" && VALID_VIEWER_MARKDOWN_MODES.has(r.viewerMarkdown)) {
|
|
2239
|
+
out.viewerMarkdown = r.viewerMarkdown;
|
|
2240
|
+
}
|
|
2241
|
+
if (typeof r.workflowsEnabled === "boolean") {
|
|
2242
|
+
out.workflowsEnabled = r.workflowsEnabled;
|
|
2243
|
+
}
|
|
2244
|
+
if (r.fallbackSubagent === false) {
|
|
2245
|
+
out.fallbackSubagent = NO_FALLBACK;
|
|
2246
|
+
} else if (typeof r.fallbackSubagent === "string" && r.fallbackSubagent.trim()) {
|
|
2247
|
+
out.fallbackSubagent = r.fallbackSubagent.trim();
|
|
2248
|
+
}
|
|
2249
|
+
return out;
|
|
2250
|
+
}
|
|
2251
|
+
function globalPath() {
|
|
2252
|
+
return import_node_path9.join(import_pi_coding_agent7.getAgentDir(), "subagents.json");
|
|
2253
|
+
}
|
|
2254
|
+
function projectPath(cwd) {
|
|
2255
|
+
return import_node_path9.join(cwd, ".pi", "subagents.json");
|
|
2256
|
+
}
|
|
2257
|
+
function readSettingsFile(path) {
|
|
2258
|
+
if (!import_node_fs8.existsSync(path))
|
|
2259
|
+
return {};
|
|
2260
|
+
try {
|
|
2261
|
+
return readParsedSettings(path);
|
|
2262
|
+
} catch (err) {
|
|
2263
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
2264
|
+
console.warn(`[pi-subagents] Ignoring malformed settings at ${path}: ${reason}`);
|
|
2265
|
+
return {};
|
|
2266
|
+
}
|
|
2267
|
+
}
|
|
2268
|
+
function globalProjectTrustMode() {
|
|
2269
|
+
return readSettingsFile(globalPath()).projectTrust ?? "full";
|
|
2270
|
+
}
|
|
2271
|
+
function loadSettings(cwd = process.cwd(), project = true) {
|
|
2272
|
+
return { ...readSettingsFile(globalPath()), ...project ? readSettingsFile(projectPath(cwd)) : {} };
|
|
2273
|
+
}
|
|
2274
|
+
function saveSettings(s, cwd = process.cwd()) {
|
|
2275
|
+
const path = projectPath(cwd);
|
|
2276
|
+
try {
|
|
2277
|
+
import_node_fs8.mkdirSync(import_node_path9.dirname(path), { recursive: true });
|
|
2278
|
+
import_node_fs8.writeFileSync(path, JSON.stringify(s, null, 2), "utf-8");
|
|
2279
|
+
return true;
|
|
2280
|
+
} catch {
|
|
2281
|
+
return false;
|
|
2282
|
+
}
|
|
2283
|
+
}
|
|
2284
|
+
function applySettings(s, appliers) {
|
|
2285
|
+
if (typeof s.maxConcurrent === "number")
|
|
2286
|
+
appliers.setMaxConcurrent(s.maxConcurrent);
|
|
2287
|
+
if (typeof s.maxConcurrentForeground === "number") {
|
|
2288
|
+
appliers.setMaxConcurrentForeground(s.maxConcurrentForeground);
|
|
2289
|
+
}
|
|
2290
|
+
if (typeof s.defaultMaxTurns === "number")
|
|
2291
|
+
appliers.setDefaultMaxTurns(s.defaultMaxTurns);
|
|
2292
|
+
if (typeof s.graceTurns === "number")
|
|
2293
|
+
appliers.setGraceTurns(s.graceTurns);
|
|
2294
|
+
if (typeof s.toolTimeoutSeconds === "number")
|
|
2295
|
+
appliers.setToolTimeoutSeconds(s.toolTimeoutSeconds);
|
|
2296
|
+
if (typeof s.maxSubagentDepth === "number")
|
|
2297
|
+
appliers.setMaxSubagentDepth(s.maxSubagentDepth);
|
|
2298
|
+
if (typeof s.fallbackSubagent === "string")
|
|
2299
|
+
appliers.setFallbackSubagent(s.fallbackSubagent);
|
|
2300
|
+
if (s.defaultJoinMode)
|
|
2301
|
+
appliers.setDefaultJoinMode(s.defaultJoinMode);
|
|
2302
|
+
if (typeof s.backgroundByDefault === "boolean")
|
|
2303
|
+
appliers.setBackgroundByDefault(s.backgroundByDefault);
|
|
2304
|
+
if (typeof s.schedulingEnabled === "boolean")
|
|
2305
|
+
appliers.setSchedulingEnabled(s.schedulingEnabled);
|
|
2306
|
+
if (typeof s.scopeModels === "boolean")
|
|
2307
|
+
appliers.setScopeModels(s.scopeModels);
|
|
2308
|
+
if (typeof s.strictAgentFiles === "boolean")
|
|
2309
|
+
appliers.setStrictAgentFiles(s.strictAgentFiles);
|
|
2310
|
+
if (typeof s.disableDefaultAgents === "boolean")
|
|
2311
|
+
appliers.setDisableDefaultAgents(s.disableDefaultAgents);
|
|
2312
|
+
if (s.toolDescriptionMode)
|
|
2313
|
+
appliers.setToolDescriptionMode(s.toolDescriptionMode);
|
|
2314
|
+
if (typeof s.fleetView === "boolean")
|
|
2315
|
+
appliers.setFleetView(s.fleetView);
|
|
2316
|
+
if (s.agentMentions)
|
|
2317
|
+
appliers.setAgentMentions(s.agentMentions);
|
|
2318
|
+
if (typeof s.rememberAgents === "boolean")
|
|
2319
|
+
appliers.setRememberAgents(s.rememberAgents);
|
|
2320
|
+
if (s.widgetMode)
|
|
2321
|
+
appliers.setWidgetMode(s.widgetMode);
|
|
2322
|
+
if (typeof s.outputTranscript === "boolean")
|
|
2323
|
+
appliers.setOutputTranscript(s.outputTranscript);
|
|
2324
|
+
if (typeof s.worktreeIsolation === "boolean")
|
|
2325
|
+
appliers.setWorktreeIsolation(s.worktreeIsolation);
|
|
2326
|
+
if (typeof s.reportUsage === "boolean")
|
|
2327
|
+
appliers.setReportUsage(s.reportUsage);
|
|
2328
|
+
if (typeof s.showCost === "boolean")
|
|
2329
|
+
appliers.setShowCost(s.showCost);
|
|
2330
|
+
if (typeof s.showModel === "boolean")
|
|
2331
|
+
appliers.setShowModel(s.showModel);
|
|
2332
|
+
if (s.viewerMarkdown)
|
|
2333
|
+
appliers.setViewerMarkdown(s.viewerMarkdown);
|
|
2334
|
+
if (typeof s.workflowsEnabled === "boolean")
|
|
2335
|
+
appliers.setWorkflowsEnabled(s.workflowsEnabled);
|
|
2336
|
+
}
|
|
2337
|
+
function persistToastFor(successMsg, persisted) {
|
|
2338
|
+
return persisted ? { message: successMsg, level: "info" } : { message: `${successMsg} (session only; failed to persist)`, level: "warning" };
|
|
2339
|
+
}
|
|
2340
|
+
function applyAndEmitLoaded(appliers, emit, cwd = process.cwd(), project = true) {
|
|
2341
|
+
const settings = loadSettings(cwd, project);
|
|
2342
|
+
applySettings(settings, appliers);
|
|
2343
|
+
emit("subagents:settings_loaded", { settings });
|
|
2344
|
+
return settings;
|
|
2345
|
+
}
|
|
2346
|
+
function saveAndEmitChanged(snapshot, successMsg, emit, cwd = process.cwd()) {
|
|
2347
|
+
const persisted = saveSettings(snapshot, cwd);
|
|
2348
|
+
emit("subagents:settings_changed", { settings: snapshot, persisted });
|
|
2349
|
+
return persistToastFor(successMsg, persisted);
|
|
2350
|
+
}
|
|
2351
|
+
var import_node_fs8, import_node_path9, import_pi_coding_agent7, VALID_JOIN_MODES, VALID_TOOL_DESCRIPTION_MODES, VALID_WIDGET_MODES, VALID_VIEWER_MARKDOWN_MODES, VALID_AGENT_MENTION_MODES, MAX_CONCURRENT_CEILING = 1024, MAX_TURNS_CEILING = 1e4, GRACE_TURNS_CEILING = 1000, TOOL_TIMEOUT_CEILING = 86400, SUBAGENT_DEPTH_CEILING = 16, readParsedSettings;
|
|
2352
|
+
var init_settings = __esm(() => {
|
|
2353
|
+
init_agent_types();
|
|
2354
|
+
init_discovery_cache();
|
|
2355
|
+
import_node_fs8 = require("fs");
|
|
2356
|
+
import_node_path9 = require("path");
|
|
2357
|
+
import_pi_coding_agent7 = __toESM(require_pi_coding_agent());
|
|
2358
|
+
VALID_JOIN_MODES = new Set(["async", "group", "smart"]);
|
|
2359
|
+
VALID_TOOL_DESCRIPTION_MODES = new Set(["full", "compact", "custom"]);
|
|
2360
|
+
VALID_WIDGET_MODES = new Set(["all", "background", "off"]);
|
|
2361
|
+
VALID_VIEWER_MARKDOWN_MODES = new Set(["off", "assistant", "all"]);
|
|
2362
|
+
VALID_AGENT_MENTION_MODES = new Set(["model", "direct", "off"]);
|
|
2363
|
+
readParsedSettings = createDiscoveryCache((path) => sanitize(JSON.parse(import_node_fs8.readFileSync(path, "utf-8"))), 64);
|
|
2364
|
+
});
|
|
2365
|
+
|
|
2161
2366
|
// src/project-trust.ts
|
|
2367
|
+
function followsPiTrust() {
|
|
2368
|
+
try {
|
|
2369
|
+
return globalProjectTrustMode() === "pi";
|
|
2370
|
+
} catch {
|
|
2371
|
+
return false;
|
|
2372
|
+
}
|
|
2373
|
+
}
|
|
2162
2374
|
function isProjectTrustedBy(ctx) {
|
|
2375
|
+
if (!followsPiTrust())
|
|
2376
|
+
return true;
|
|
2163
2377
|
if (typeof ctx?.isProjectTrusted !== "function")
|
|
2164
2378
|
return true;
|
|
2165
2379
|
try {
|
|
@@ -2169,14 +2383,16 @@ function isProjectTrustedBy(ctx) {
|
|
|
2169
2383
|
}
|
|
2170
2384
|
}
|
|
2171
2385
|
function savedDecision(cwd) {
|
|
2172
|
-
return new
|
|
2386
|
+
return new import_pi_coding_agent8.ProjectTrustStore(import_pi_coding_agent8.getAgentDir()).get(cwd);
|
|
2173
2387
|
}
|
|
2174
2388
|
function defaultTrustIsAlways(cwd) {
|
|
2175
|
-
return
|
|
2389
|
+
return import_pi_coding_agent8.SettingsManager.create(cwd, import_pi_coding_agent8.getAgentDir(), { projectTrusted: false }).getDefaultProjectTrust() === "always";
|
|
2176
2390
|
}
|
|
2177
2391
|
function predictProjectTrust(cwd) {
|
|
2392
|
+
if (!followsPiTrust())
|
|
2393
|
+
return true;
|
|
2178
2394
|
try {
|
|
2179
|
-
if (!
|
|
2395
|
+
if (!import_pi_coding_agent8.hasTrustRequiringProjectResources(cwd))
|
|
2180
2396
|
return true;
|
|
2181
2397
|
const saved = savedDecision(cwd);
|
|
2182
2398
|
if (saved !== null)
|
|
@@ -2187,17 +2403,20 @@ function predictProjectTrust(cwd) {
|
|
|
2187
2403
|
}
|
|
2188
2404
|
}
|
|
2189
2405
|
function isProjectCodeTrusted(trusted, cwd) {
|
|
2406
|
+
if (!followsPiTrust())
|
|
2407
|
+
return true;
|
|
2190
2408
|
if (!trusted)
|
|
2191
2409
|
return false;
|
|
2192
2410
|
try {
|
|
2193
|
-
return
|
|
2411
|
+
return import_pi_coding_agent8.hasTrustRequiringProjectResources(cwd) || savedDecision(cwd) === true || defaultTrustIsAlways(cwd);
|
|
2194
2412
|
} catch {
|
|
2195
2413
|
return false;
|
|
2196
2414
|
}
|
|
2197
2415
|
}
|
|
2198
|
-
var
|
|
2416
|
+
var import_pi_coding_agent8;
|
|
2199
2417
|
var init_project_trust = __esm(() => {
|
|
2200
|
-
|
|
2418
|
+
init_settings();
|
|
2419
|
+
import_pi_coding_agent8 = __toESM(require_pi_coding_agent());
|
|
2201
2420
|
});
|
|
2202
2421
|
|
|
2203
2422
|
// src/prompts.ts
|
|
@@ -2287,12 +2506,12 @@ function loadSkillContent(name, cwd, project) {
|
|
|
2287
2506
|
}
|
|
2288
2507
|
const roots = [
|
|
2289
2508
|
...project ? [
|
|
2290
|
-
|
|
2291
|
-
|
|
2509
|
+
import_node_path10.join(cwd, ".pi", "skills"),
|
|
2510
|
+
import_node_path10.join(cwd, ".agents", "skills")
|
|
2292
2511
|
] : [],
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2512
|
+
import_node_path10.join(import_pi_coding_agent9.getAgentDir(), "skills"),
|
|
2513
|
+
import_node_path10.join(import_node_os4.homedir(), ".agents", "skills"),
|
|
2514
|
+
import_node_path10.join(import_node_os4.homedir(), ".pi", "skills")
|
|
2296
2515
|
];
|
|
2297
2516
|
for (const root of roots) {
|
|
2298
2517
|
const content = findInRoot(root, name);
|
|
@@ -2304,13 +2523,13 @@ function loadSkillContent(name, cwd, project) {
|
|
|
2304
2523
|
function findInRoot(root, name) {
|
|
2305
2524
|
if (isSymlink(root))
|
|
2306
2525
|
return;
|
|
2307
|
-
const flat = safeReadFile(
|
|
2526
|
+
const flat = safeReadFile(import_node_path10.join(root, `${name}.md`))?.trim();
|
|
2308
2527
|
if (flat !== undefined)
|
|
2309
2528
|
return flat;
|
|
2310
2529
|
return findSkillDirectory(root, name);
|
|
2311
2530
|
}
|
|
2312
2531
|
function findSkillDirectory(root, name) {
|
|
2313
|
-
if (!
|
|
2532
|
+
if (!import_node_fs9.existsSync(root))
|
|
2314
2533
|
return;
|
|
2315
2534
|
const queue = [root];
|
|
2316
2535
|
while (queue.length > 0) {
|
|
@@ -2319,7 +2538,7 @@ function findSkillDirectory(root, name) {
|
|
|
2319
2538
|
continue;
|
|
2320
2539
|
let entries;
|
|
2321
2540
|
try {
|
|
2322
|
-
entries =
|
|
2541
|
+
entries = import_node_fs9.readdirSync(current, { withFileTypes: true });
|
|
2323
2542
|
} catch {
|
|
2324
2543
|
continue;
|
|
2325
2544
|
}
|
|
@@ -2329,9 +2548,9 @@ function findSkillDirectory(root, name) {
|
|
|
2329
2548
|
continue;
|
|
2330
2549
|
if (entry.name.startsWith(".") || entry.name === "node_modules")
|
|
2331
2550
|
continue;
|
|
2332
|
-
const path =
|
|
2333
|
-
const skillMd =
|
|
2334
|
-
const isSkillDir =
|
|
2551
|
+
const path = import_node_path10.join(current, entry.name);
|
|
2552
|
+
const skillMd = import_node_path10.join(path, "SKILL.md");
|
|
2553
|
+
const isSkillDir = import_node_fs9.existsSync(skillMd);
|
|
2335
2554
|
if (isSkillDir) {
|
|
2336
2555
|
if (entry.name === name) {
|
|
2337
2556
|
const content = safeReadFile(skillMd)?.trim();
|
|
@@ -2345,13 +2564,13 @@ function findSkillDirectory(root, name) {
|
|
|
2345
2564
|
}
|
|
2346
2565
|
return;
|
|
2347
2566
|
}
|
|
2348
|
-
var
|
|
2567
|
+
var import_node_fs9, import_node_os4, import_node_path10, import_pi_coding_agent9;
|
|
2349
2568
|
var init_skill_loader = __esm(() => {
|
|
2350
2569
|
init_memory();
|
|
2351
|
-
|
|
2570
|
+
import_node_fs9 = require("fs");
|
|
2352
2571
|
import_node_os4 = require("os");
|
|
2353
|
-
|
|
2354
|
-
|
|
2572
|
+
import_node_path10 = require("path");
|
|
2573
|
+
import_pi_coding_agent9 = __toESM(require_pi_coding_agent());
|
|
2355
2574
|
});
|
|
2356
2575
|
|
|
2357
2576
|
// src/structured-output.ts
|
|
@@ -2359,7 +2578,7 @@ function createStructuredCapture() {
|
|
|
2359
2578
|
return { called: false };
|
|
2360
2579
|
}
|
|
2361
2580
|
function createStructuredOutputTool(compiled, capture) {
|
|
2362
|
-
return
|
|
2581
|
+
return import_pi_coding_agent10.defineTool({
|
|
2363
2582
|
name: STRUCTURED_OUTPUT_TOOL_NAME,
|
|
2364
2583
|
label: "Structured Output",
|
|
2365
2584
|
description: "Report your final answer. Call this exactly once, with the complete result, and put everything the " + "caller needs inside the arguments \u2014 text written outside this call is discarded. If a call is " + "rejected for not matching the schema, fix the reported fields and call it again.",
|
|
@@ -2406,35 +2625,35 @@ function structuredRetryPrompt(capture) {
|
|
|
2406
2625
|
|
|
2407
2626
|
Call ${STRUCTURED_OUTPUT_TOOL_NAME} now with your complete final answer. Do not reply with prose.`;
|
|
2408
2627
|
}
|
|
2409
|
-
var
|
|
2628
|
+
var import_pi_coding_agent10, STRUCTURED_OUTPUT_TOOL_NAME = "StructuredOutput";
|
|
2410
2629
|
var init_structured_output = __esm(() => {
|
|
2411
|
-
|
|
2630
|
+
import_pi_coding_agent10 = __toESM(require_pi_coding_agent());
|
|
2412
2631
|
});
|
|
2413
2632
|
|
|
2414
2633
|
// src/agent-runner.ts
|
|
2415
2634
|
function extensionCanonicalName(extPath) {
|
|
2416
|
-
const base =
|
|
2417
|
-
const name = base === "index.ts" || base === "index.js" ?
|
|
2635
|
+
const base = import_node_path11.basename(extPath);
|
|
2636
|
+
const name = base === "index.ts" || base === "index.js" ? import_node_path11.basename(import_node_path11.dirname(extPath)) : base.replace(/\.(ts|js)$/, "");
|
|
2418
2637
|
return name.toLowerCase();
|
|
2419
2638
|
}
|
|
2420
2639
|
function extensionPackageName(extPath) {
|
|
2421
|
-
const entry =
|
|
2422
|
-
let dir =
|
|
2640
|
+
const entry = import_node_path11.resolve(extPath);
|
|
2641
|
+
let dir = import_node_path11.dirname(extPath);
|
|
2423
2642
|
for (;; ) {
|
|
2424
|
-
if (
|
|
2643
|
+
if (import_node_path11.basename(dir) === "node_modules")
|
|
2425
2644
|
return;
|
|
2426
2645
|
let pkg;
|
|
2427
2646
|
try {
|
|
2428
|
-
pkg = JSON.parse(
|
|
2647
|
+
pkg = JSON.parse(import_node_fs10.readFileSync(import_node_path11.join(dir, "package.json"), "utf-8"));
|
|
2429
2648
|
} catch {
|
|
2430
|
-
const parent =
|
|
2649
|
+
const parent = import_node_path11.dirname(dir);
|
|
2431
2650
|
if (parent === dir)
|
|
2432
2651
|
return;
|
|
2433
2652
|
dir = parent;
|
|
2434
2653
|
continue;
|
|
2435
2654
|
}
|
|
2436
2655
|
const entries = pkg.pi?.extensions;
|
|
2437
|
-
if (typeof pkg.name === "string" && Array.isArray(entries) && entries.some((e) => typeof e === "string" &&
|
|
2656
|
+
if (typeof pkg.name === "string" && Array.isArray(entries) && entries.some((e) => typeof e === "string" && import_node_path11.resolve(dir, e) === entry)) {
|
|
2438
2657
|
const short = pkg.name.startsWith("@") ? pkg.name.slice(pkg.name.indexOf("/") + 1) : pkg.name;
|
|
2439
2658
|
return short.toLowerCase();
|
|
2440
2659
|
}
|
|
@@ -2470,7 +2689,7 @@ function parseExtensionsSpec(entries, cwd) {
|
|
|
2470
2689
|
if (p === "~" || p.startsWith("~/") || p.startsWith("~\\")) {
|
|
2471
2690
|
p = import_node_os5.homedir() + p.slice(1);
|
|
2472
2691
|
}
|
|
2473
|
-
const abs =
|
|
2692
|
+
const abs = import_node_path11.isAbsolute(p) ? p : import_node_path11.resolve(cwd, p);
|
|
2474
2693
|
paths.push(abs);
|
|
2475
2694
|
names.add(extensionCanonicalName(abs));
|
|
2476
2695
|
}
|
|
@@ -2604,7 +2823,7 @@ function getToolTimeoutSeconds() {
|
|
|
2604
2823
|
return toolTimeoutSeconds;
|
|
2605
2824
|
}
|
|
2606
2825
|
function setToolTimeoutSeconds(n) {
|
|
2607
|
-
toolTimeoutSeconds = Math.min(
|
|
2826
|
+
toolTimeoutSeconds = Math.min(TOOL_TIMEOUT_CEILING2, Math.max(0, Math.floor(n)));
|
|
2608
2827
|
}
|
|
2609
2828
|
function formatDuration(seconds) {
|
|
2610
2829
|
if (seconds < 120)
|
|
@@ -2754,10 +2973,10 @@ function resolveConfiguredSessionDir(sessionDir, cwd) {
|
|
|
2754
2973
|
if (!sessionDir)
|
|
2755
2974
|
return;
|
|
2756
2975
|
if (sessionDir === "~" || sessionDir.startsWith("~/"))
|
|
2757
|
-
return
|
|
2758
|
-
if (
|
|
2976
|
+
return import_node_path11.resolve(import_node_os5.homedir(), sessionDir.slice(2));
|
|
2977
|
+
if (import_node_path11.isAbsolute(sessionDir))
|
|
2759
2978
|
return sessionDir;
|
|
2760
|
-
return
|
|
2979
|
+
return import_node_path11.resolve(cwd, sessionDir);
|
|
2761
2980
|
}
|
|
2762
2981
|
async function runAgent(ctx, type, prompt, options) {
|
|
2763
2982
|
const config = getConfig(type);
|
|
@@ -2810,12 +3029,12 @@ async function runAgent(ctx, type, prompt, options) {
|
|
|
2810
3029
|
systemPrompt = buildAgentPrompt({ ...fallback, name: type }, effectiveCwd, env, parentSystemPrompt, extras);
|
|
2811
3030
|
}
|
|
2812
3031
|
const noSkills = skills === false || Array.isArray(skills);
|
|
2813
|
-
const agentDir =
|
|
3032
|
+
const agentDir = import_pi_coding_agent11.getAgentDir();
|
|
2814
3033
|
const { extNames, narrowing } = parseExtSelectors(options.isolated ? [] : agentConfig?.extSelectors ?? []);
|
|
2815
3034
|
const noExtensions = extensions === false;
|
|
2816
3035
|
let extensionEntries = Array.isArray(extensions) ? extensions : undefined;
|
|
2817
3036
|
if (extensionEntries && agentConfig?.source === "project" && extensionEntries.some(isExtensionPathEntry)) {
|
|
2818
|
-
const projectRoot = agentConfig.sourcePath ?
|
|
3037
|
+
const projectRoot = agentConfig.sourcePath ? import_node_path11.dirname(import_node_path11.dirname(import_node_path11.dirname(agentConfig.sourcePath))) : configCwd;
|
|
2819
3038
|
if (!isProjectCodeTrusted(projectTrusted, projectRoot)) {
|
|
2820
3039
|
for (const entry of extensionEntries.filter(isExtensionPathEntry)) {
|
|
2821
3040
|
options.onToolActivity?.({
|
|
@@ -2848,8 +3067,8 @@ async function runAgent(ctx, type, prompt, options) {
|
|
|
2848
3067
|
};
|
|
2849
3068
|
};
|
|
2850
3069
|
const toolScopeGuard = noExtensions ? undefined : createToolScopeGuard();
|
|
2851
|
-
const settingsManager =
|
|
2852
|
-
const loader = new
|
|
3070
|
+
const settingsManager = import_pi_coding_agent11.SettingsManager.create(configCwd, agentDir, { projectTrusted });
|
|
3071
|
+
const loader = new import_pi_coding_agent11.DefaultResourceLoader({
|
|
2853
3072
|
cwd: configCwd,
|
|
2854
3073
|
agentDir,
|
|
2855
3074
|
settingsManager,
|
|
@@ -2960,9 +3179,9 @@ async function runAgent(ctx, type, prompt, options) {
|
|
|
2960
3179
|
const configuredSessionDir = resolveConfiguredSessionDir(agentConfig?.sessionDir, effectiveCwd);
|
|
2961
3180
|
const defaultSessionDir = process.env.PI_CODING_AGENT_SESSION_DIR ?? settingsManager.getSessionDir?.();
|
|
2962
3181
|
const persistSession = agentConfig?.persistSession ?? rememberAgents;
|
|
2963
|
-
const sessionManager = options.resumeSessionFile ?
|
|
3182
|
+
const sessionManager = options.resumeSessionFile ? import_pi_coding_agent11.SessionManager.open(options.resumeSessionFile, configuredSessionDir ?? defaultSessionDir) : persistSession ? import_pi_coding_agent11.SessionManager.create(effectiveCwd, configuredSessionDir ?? defaultSessionDir, {
|
|
2964
3183
|
parentSession: ctx.sessionManager?.getSessionFile?.()
|
|
2965
|
-
}) :
|
|
3184
|
+
}) : import_pi_coding_agent11.SessionManager.inMemory(effectiveCwd);
|
|
2966
3185
|
const parentModelRuntime = ctx.modelRegistry.runtime;
|
|
2967
3186
|
const sessionOpts = {
|
|
2968
3187
|
cwd: effectiveCwd,
|
|
@@ -2982,7 +3201,7 @@ async function runAgent(ctx, type, prompt, options) {
|
|
|
2982
3201
|
if (thinkingLevel) {
|
|
2983
3202
|
sessionOpts.thinkingLevel = thinkingLevel;
|
|
2984
3203
|
}
|
|
2985
|
-
const { session } = await runInChildSessionContext(() =>
|
|
3204
|
+
const { session } = await runInChildSessionContext(() => import_pi_coding_agent11.createAgentSession(sessionOpts));
|
|
2986
3205
|
const baseSessionName = agentConfig?.name ?? type;
|
|
2987
3206
|
session.setSessionName(options.agentId ? `${baseSessionName}#${options.agentId.slice(0, 8)}` : baseSessionName);
|
|
2988
3207
|
await session.bindExtensions({
|
|
@@ -3175,7 +3394,7 @@ ${toolCalls.join(`
|
|
|
3175
3394
|
|
|
3176
3395
|
`);
|
|
3177
3396
|
}
|
|
3178
|
-
var
|
|
3397
|
+
var import_node_fs10, import_node_os5, import_node_path11, import_pi_coding_agent11, SUBAGENT_TOOL_NAMES, EXCLUDED_TOOL_NAMES, TOOL_SCOPE_GUARD_NAME = "subagent-tool-scope", TOOL_SCOPE_GUARD_PATH, defaultMaxTurns, rememberAgents = true, graceTurns = 5, toolTimeoutSeconds = 1200, TOOL_TIMEOUT_CEILING2 = 86400, watchdogTiming, MAX_TOOL_RECOVERIES = 3, WATCHDOG_EXEMPT_TOOLS;
|
|
3179
3398
|
var init_agent_runner = __esm(() => {
|
|
3180
3399
|
init_agent_types();
|
|
3181
3400
|
init_child_context();
|
|
@@ -3186,10 +3405,10 @@ var init_agent_runner = __esm(() => {
|
|
|
3186
3405
|
init_project_trust();
|
|
3187
3406
|
init_skill_loader();
|
|
3188
3407
|
init_structured_output();
|
|
3189
|
-
|
|
3408
|
+
import_node_fs10 = require("fs");
|
|
3190
3409
|
import_node_os5 = require("os");
|
|
3191
|
-
|
|
3192
|
-
|
|
3410
|
+
import_node_path11 = require("path");
|
|
3411
|
+
import_pi_coding_agent11 = __toESM(require_pi_coding_agent());
|
|
3193
3412
|
SUBAGENT_TOOL_NAMES = {
|
|
3194
3413
|
AGENT: "Agent",
|
|
3195
3414
|
WORKFLOW: "SubagentWorkflow",
|
|
@@ -3255,33 +3474,33 @@ var init_mention = __esm(() => {
|
|
|
3255
3474
|
|
|
3256
3475
|
// src/session-file.ts
|
|
3257
3476
|
function sessionFileProblem(path) {
|
|
3258
|
-
if (!
|
|
3477
|
+
if (!import_node_fs11.existsSync(path))
|
|
3259
3478
|
return `its session file is gone (${path})`;
|
|
3260
3479
|
try {
|
|
3261
|
-
if (
|
|
3480
|
+
if (import_node_fs11.statSync(path).size === 0)
|
|
3262
3481
|
return `its session file is empty (${path})`;
|
|
3263
|
-
|
|
3482
|
+
import_pi_coding_agent12.SessionManager.open(path);
|
|
3264
3483
|
} catch (err) {
|
|
3265
3484
|
return `its session file cannot be read: ${err instanceof Error ? err.message : String(err)}`;
|
|
3266
3485
|
}
|
|
3267
3486
|
return;
|
|
3268
3487
|
}
|
|
3269
|
-
var
|
|
3488
|
+
var import_node_fs11, import_pi_coding_agent12;
|
|
3270
3489
|
var init_session_file = __esm(() => {
|
|
3271
|
-
|
|
3272
|
-
|
|
3490
|
+
import_node_fs11 = require("fs");
|
|
3491
|
+
import_pi_coding_agent12 = __toESM(require_pi_coding_agent());
|
|
3273
3492
|
});
|
|
3274
3493
|
|
|
3275
3494
|
// src/agent-manager.ts
|
|
3276
3495
|
function assertValidSpawnCwd(cwd) {
|
|
3277
3496
|
if (cwd == null)
|
|
3278
3497
|
return;
|
|
3279
|
-
if (typeof cwd !== "string" || !
|
|
3498
|
+
if (typeof cwd !== "string" || !import_node_path12.isAbsolute(cwd)) {
|
|
3280
3499
|
throw new Error(`SpawnOptions.cwd must be an absolute path: "${String(cwd)}"`);
|
|
3281
3500
|
}
|
|
3282
3501
|
let isDirectory = false;
|
|
3283
3502
|
try {
|
|
3284
|
-
isDirectory =
|
|
3503
|
+
isDirectory = import_node_fs12.statSync(cwd).isDirectory();
|
|
3285
3504
|
} catch {
|
|
3286
3505
|
throw new Error(`SpawnOptions.cwd does not exist: "${cwd}"`);
|
|
3287
3506
|
}
|
|
@@ -4114,7 +4333,7 @@ class AgentManager {
|
|
|
4114
4333
|
}
|
|
4115
4334
|
const problem = sessionFileProblem(entry.sessionFile);
|
|
4116
4335
|
if (problem) {
|
|
4117
|
-
if (!
|
|
4336
|
+
if (!import_node_fs12.existsSync(entry.sessionFile))
|
|
4118
4337
|
this.tombstones.delete(entry.id);
|
|
4119
4338
|
throw new Error(`Cannot resume agent ${entry.id}: ${problem}.`);
|
|
4120
4339
|
}
|
|
@@ -4172,7 +4391,7 @@ class AgentManager {
|
|
|
4172
4391
|
}
|
|
4173
4392
|
async prepareResume(record, options) {
|
|
4174
4393
|
const worktree = record.worktree;
|
|
4175
|
-
if (worktree?.path && !
|
|
4394
|
+
if (worktree?.path && !import_node_fs12.existsSync(worktree.path)) {
|
|
4176
4395
|
if (!isWorktreeIsolationEnabled()) {
|
|
4177
4396
|
throw new Error(`Cannot resume agent ${record.id}: it ran in a git worktree, and worktree isolation is turned off in this project.`);
|
|
4178
4397
|
}
|
|
@@ -4189,7 +4408,7 @@ class AgentManager {
|
|
|
4189
4408
|
async finishResumedWorktree(record) {
|
|
4190
4409
|
const pi = this.pi;
|
|
4191
4410
|
const repo = record.baseCwd;
|
|
4192
|
-
if (!record.worktree?.path || !pi || !repo || !
|
|
4411
|
+
if (!record.worktree?.path || !pi || !repo || !import_node_fs12.existsSync(record.worktree.path))
|
|
4193
4412
|
return;
|
|
4194
4413
|
const prior = record.worktreeResult;
|
|
4195
4414
|
try {
|
|
@@ -4526,7 +4745,7 @@ class AgentManager {
|
|
|
4526
4745
|
await Promise.all(sessions.map((session) => shutdownChildSession(session)));
|
|
4527
4746
|
}
|
|
4528
4747
|
}
|
|
4529
|
-
var import_node_crypto,
|
|
4748
|
+
var import_node_crypto, import_node_fs12, import_node_path12, DEFAULT_MAX_CONCURRENT = 10, DEFAULT_MAX_CONCURRENT_FOREGROUND = 0, MAX_TOMBSTONES = 100, CHILD_SHUTDOWN_TIMEOUT_MS = 3000, DEFAULT_STOP_GRACE_MS = 20000, INLINE_STOP_WAIT_MS = 3000, DEFAULT_SESSION_RELEASE_MS = 60000;
|
|
4530
4749
|
var init_agent_manager = __esm(() => {
|
|
4531
4750
|
init_agent_runner();
|
|
4532
4751
|
init_mention();
|
|
@@ -4534,8 +4753,8 @@ var init_agent_manager = __esm(() => {
|
|
|
4534
4753
|
init_usage();
|
|
4535
4754
|
init_worktree();
|
|
4536
4755
|
import_node_crypto = require("crypto");
|
|
4537
|
-
|
|
4538
|
-
|
|
4756
|
+
import_node_fs12 = require("fs");
|
|
4757
|
+
import_node_path12 = require("path");
|
|
4539
4758
|
});
|
|
4540
4759
|
|
|
4541
4760
|
// src/ui/refresh-ticker.ts
|
|
@@ -5569,7 +5788,7 @@ var init_conversation_viewer = __esm(() => {
|
|
|
5569
5788
|
|
|
5570
5789
|
// pi-host:typebox/value
|
|
5571
5790
|
var require_value = __commonJS(function(exports2, module2) {
|
|
5572
|
-
module2.exports = globalThis[Symbol.for("opensec-pi-subagents@0.20.
|
|
5791
|
+
module2.exports = globalThis[Symbol.for("opensec-pi-subagents@0.20.2:host-modules")]("typebox/value");
|
|
5573
5792
|
});
|
|
5574
5793
|
|
|
5575
5794
|
// src/index.ts
|
|
@@ -5935,7 +6154,7 @@ init_mention();
|
|
|
5935
6154
|
// src/mention-clone.ts
|
|
5936
6155
|
init_child_context();
|
|
5937
6156
|
init_mention();
|
|
5938
|
-
var
|
|
6157
|
+
var import_pi_coding_agent13 = __toESM(require_pi_coding_agent());
|
|
5939
6158
|
async function runMentionClone(opts) {
|
|
5940
6159
|
const { ctx, type, message, agentTool, signal: stop, onUsage } = opts;
|
|
5941
6160
|
if (stop?.aborted)
|
|
@@ -5962,11 +6181,11 @@ async function runMentionClone(opts) {
|
|
|
5962
6181
|
stop?.addEventListener("abort", onStop, { once: true });
|
|
5963
6182
|
try {
|
|
5964
6183
|
const parentModelRuntime = ctx.modelRegistry.runtime;
|
|
5965
|
-
const conversation =
|
|
6184
|
+
const conversation = import_pi_coding_agent13.buildSessionContext(ctx.sessionManager.getEntries(), ctx.sessionManager.getLeafId());
|
|
5966
6185
|
const thinkingLevel = ctx.thinkingLevel;
|
|
5967
|
-
const created = await runInChildSessionContext(() =>
|
|
6186
|
+
const created = await runInChildSessionContext(() => import_pi_coding_agent13.createAgentSession({
|
|
5968
6187
|
cwd: ctx.cwd,
|
|
5969
|
-
sessionManager:
|
|
6188
|
+
sessionManager: import_pi_coding_agent13.SessionManager.inMemory(ctx.cwd, undefined, ctx.sessionManager.getBranch?.() ?? []),
|
|
5970
6189
|
model: ctx.model,
|
|
5971
6190
|
...thinkingLevel && { thinkingLevel },
|
|
5972
6191
|
modelRegistry: ctx.modelRegistry,
|
|
@@ -7246,8 +7465,8 @@ class SubagentScheduler {
|
|
|
7246
7465
|
}
|
|
7247
7466
|
|
|
7248
7467
|
// src/schedule-store.ts
|
|
7249
|
-
var
|
|
7250
|
-
var
|
|
7468
|
+
var import_node_fs13 = require("fs");
|
|
7469
|
+
var import_node_path13 = require("path");
|
|
7251
7470
|
var LOCK_RETRY_MS = 50;
|
|
7252
7471
|
var DEFAULT_LOCK_WAIT_MS = 5000;
|
|
7253
7472
|
var LOCK_STALE_MS = 30000;
|
|
@@ -7262,16 +7481,16 @@ function isProcessRunning(pid) {
|
|
|
7262
7481
|
function tryAcquireLock(lockPath) {
|
|
7263
7482
|
for (let i = 0;i < 3; i++) {
|
|
7264
7483
|
try {
|
|
7265
|
-
|
|
7484
|
+
import_node_fs13.writeFileSync(lockPath, `${process.pid}`, { flag: "wx" });
|
|
7266
7485
|
return true;
|
|
7267
7486
|
} catch (e) {
|
|
7268
7487
|
if (e.code !== "EEXIST")
|
|
7269
7488
|
throw e;
|
|
7270
7489
|
try {
|
|
7271
|
-
const pid = parseInt(
|
|
7272
|
-
const age = Date.now() -
|
|
7490
|
+
const pid = parseInt(import_node_fs13.readFileSync(lockPath, "utf-8"), 10);
|
|
7491
|
+
const age = Date.now() - import_node_fs13.statSync(lockPath).mtimeMs;
|
|
7273
7492
|
if (!pid || !isProcessRunning(pid) || age > LOCK_STALE_MS) {
|
|
7274
|
-
|
|
7493
|
+
import_node_fs13.unlinkSync(lockPath);
|
|
7275
7494
|
continue;
|
|
7276
7495
|
}
|
|
7277
7496
|
} catch {
|
|
@@ -7284,11 +7503,11 @@ function tryAcquireLock(lockPath) {
|
|
|
7284
7503
|
}
|
|
7285
7504
|
function releaseLock(lockPath) {
|
|
7286
7505
|
try {
|
|
7287
|
-
|
|
7506
|
+
import_node_fs13.unlinkSync(lockPath);
|
|
7288
7507
|
} catch {}
|
|
7289
7508
|
}
|
|
7290
7509
|
function resolveStorePath(cwd, sessionId) {
|
|
7291
|
-
return
|
|
7510
|
+
return import_node_path13.join(cwd, ".pi", "subagent-schedules", `${sessionId}.json`);
|
|
7292
7511
|
}
|
|
7293
7512
|
|
|
7294
7513
|
class ScheduleStore {
|
|
@@ -7305,18 +7524,18 @@ class ScheduleStore {
|
|
|
7305
7524
|
this.load();
|
|
7306
7525
|
}
|
|
7307
7526
|
ensureDir() {
|
|
7308
|
-
|
|
7527
|
+
import_node_fs13.mkdirSync(import_node_path13.dirname(this.filePath), { recursive: true });
|
|
7309
7528
|
}
|
|
7310
7529
|
load() {
|
|
7311
|
-
if (!
|
|
7530
|
+
if (!import_node_fs13.existsSync(this.filePath))
|
|
7312
7531
|
return;
|
|
7313
7532
|
let data;
|
|
7314
7533
|
try {
|
|
7315
|
-
data = JSON.parse(
|
|
7534
|
+
data = JSON.parse(import_node_fs13.readFileSync(this.filePath, "utf-8"));
|
|
7316
7535
|
} catch (err) {
|
|
7317
7536
|
const backup = `${this.filePath}.corrupt`;
|
|
7318
7537
|
try {
|
|
7319
|
-
|
|
7538
|
+
import_node_fs13.renameSync(this.filePath, backup);
|
|
7320
7539
|
console.warn(`[pi-subagents] Schedule file ${this.filePath} is not valid JSON (${err instanceof Error ? err.message : String(err)}); moved it to ${backup}.`);
|
|
7321
7540
|
} catch (moveErr) {
|
|
7322
7541
|
console.warn(`[pi-subagents] Schedule file ${this.filePath} is not valid JSON and could not be moved aside:`, moveErr);
|
|
@@ -7330,8 +7549,8 @@ class ScheduleStore {
|
|
|
7330
7549
|
save() {
|
|
7331
7550
|
const data = { version: 1, jobs: [...this.jobs.values()] };
|
|
7332
7551
|
const tmp = this.filePath + ".tmp";
|
|
7333
|
-
|
|
7334
|
-
|
|
7552
|
+
import_node_fs13.writeFileSync(tmp, JSON.stringify(data, null, 2));
|
|
7553
|
+
import_node_fs13.renameSync(tmp, this.filePath);
|
|
7335
7554
|
}
|
|
7336
7555
|
underLock(fn) {
|
|
7337
7556
|
try {
|
|
@@ -7415,214 +7634,17 @@ class ScheduleStore {
|
|
|
7415
7634
|
return this.withLock(() => this.jobs.delete(id));
|
|
7416
7635
|
}
|
|
7417
7636
|
deleteFileIfEmpty() {
|
|
7418
|
-
if (this.jobs.size === 0 &&
|
|
7637
|
+
if (this.jobs.size === 0 && import_node_fs13.existsSync(this.filePath)) {
|
|
7419
7638
|
try {
|
|
7420
|
-
|
|
7639
|
+
import_node_fs13.unlinkSync(this.filePath);
|
|
7421
7640
|
} catch {}
|
|
7422
7641
|
}
|
|
7423
7642
|
}
|
|
7424
7643
|
}
|
|
7425
7644
|
|
|
7426
|
-
// src/
|
|
7427
|
-
|
|
7428
|
-
|
|
7429
|
-
var import_node_fs13 = require("fs");
|
|
7430
|
-
var import_node_path13 = require("path");
|
|
7431
|
-
var import_pi_coding_agent13 = __toESM(require_pi_coding_agent());
|
|
7432
|
-
var VALID_JOIN_MODES = new Set(["async", "group", "smart"]);
|
|
7433
|
-
var VALID_TOOL_DESCRIPTION_MODES = new Set(["full", "compact", "custom"]);
|
|
7434
|
-
var VALID_WIDGET_MODES = new Set(["all", "background", "off"]);
|
|
7435
|
-
var VALID_VIEWER_MARKDOWN_MODES = new Set(["off", "assistant", "all"]);
|
|
7436
|
-
var VALID_AGENT_MENTION_MODES = new Set(["model", "direct", "off"]);
|
|
7437
|
-
var MAX_CONCURRENT_CEILING = 1024;
|
|
7438
|
-
var MAX_TURNS_CEILING = 1e4;
|
|
7439
|
-
var GRACE_TURNS_CEILING = 1000;
|
|
7440
|
-
var TOOL_TIMEOUT_CEILING2 = 86400;
|
|
7441
|
-
var SUBAGENT_DEPTH_CEILING = 16;
|
|
7442
|
-
function sanitize(raw) {
|
|
7443
|
-
if (!raw || typeof raw !== "object")
|
|
7444
|
-
return {};
|
|
7445
|
-
const r = raw;
|
|
7446
|
-
const out = {};
|
|
7447
|
-
if (Number.isInteger(r.maxConcurrent) && r.maxConcurrent >= 1 && r.maxConcurrent <= MAX_CONCURRENT_CEILING) {
|
|
7448
|
-
out.maxConcurrent = r.maxConcurrent;
|
|
7449
|
-
}
|
|
7450
|
-
if (Number.isInteger(r.maxConcurrentForeground) && r.maxConcurrentForeground >= 0 && r.maxConcurrentForeground <= MAX_CONCURRENT_CEILING) {
|
|
7451
|
-
out.maxConcurrentForeground = r.maxConcurrentForeground;
|
|
7452
|
-
}
|
|
7453
|
-
if (Number.isInteger(r.defaultMaxTurns) && r.defaultMaxTurns >= 0 && r.defaultMaxTurns <= MAX_TURNS_CEILING) {
|
|
7454
|
-
out.defaultMaxTurns = r.defaultMaxTurns;
|
|
7455
|
-
}
|
|
7456
|
-
if (Number.isInteger(r.graceTurns) && r.graceTurns >= 1 && r.graceTurns <= GRACE_TURNS_CEILING) {
|
|
7457
|
-
out.graceTurns = r.graceTurns;
|
|
7458
|
-
}
|
|
7459
|
-
if (Number.isInteger(r.toolTimeoutSeconds) && r.toolTimeoutSeconds >= 0 && r.toolTimeoutSeconds <= TOOL_TIMEOUT_CEILING2) {
|
|
7460
|
-
out.toolTimeoutSeconds = r.toolTimeoutSeconds;
|
|
7461
|
-
}
|
|
7462
|
-
if (Number.isInteger(r.maxSubagentDepth) && r.maxSubagentDepth >= 0 && r.maxSubagentDepth <= SUBAGENT_DEPTH_CEILING) {
|
|
7463
|
-
out.maxSubagentDepth = r.maxSubagentDepth;
|
|
7464
|
-
}
|
|
7465
|
-
if (typeof r.defaultJoinMode === "string" && VALID_JOIN_MODES.has(r.defaultJoinMode)) {
|
|
7466
|
-
out.defaultJoinMode = r.defaultJoinMode;
|
|
7467
|
-
}
|
|
7468
|
-
if (typeof r.backgroundByDefault === "boolean") {
|
|
7469
|
-
out.backgroundByDefault = r.backgroundByDefault;
|
|
7470
|
-
}
|
|
7471
|
-
if (typeof r.schedulingEnabled === "boolean") {
|
|
7472
|
-
out.schedulingEnabled = r.schedulingEnabled;
|
|
7473
|
-
}
|
|
7474
|
-
if (typeof r.scopeModels === "boolean") {
|
|
7475
|
-
out.scopeModels = r.scopeModels;
|
|
7476
|
-
}
|
|
7477
|
-
if (typeof r.strictAgentFiles === "boolean") {
|
|
7478
|
-
out.strictAgentFiles = r.strictAgentFiles;
|
|
7479
|
-
}
|
|
7480
|
-
if (typeof r.disableDefaultAgents === "boolean") {
|
|
7481
|
-
out.disableDefaultAgents = r.disableDefaultAgents;
|
|
7482
|
-
}
|
|
7483
|
-
if (typeof r.toolDescriptionMode === "string" && VALID_TOOL_DESCRIPTION_MODES.has(r.toolDescriptionMode)) {
|
|
7484
|
-
out.toolDescriptionMode = r.toolDescriptionMode;
|
|
7485
|
-
}
|
|
7486
|
-
if (typeof r.fleetView === "boolean") {
|
|
7487
|
-
out.fleetView = r.fleetView;
|
|
7488
|
-
}
|
|
7489
|
-
if (typeof r.agentMentions === "boolean") {
|
|
7490
|
-
out.agentMentions = r.agentMentions ? "model" : "off";
|
|
7491
|
-
} else if (typeof r.agentMentions === "string" && VALID_AGENT_MENTION_MODES.has(r.agentMentions)) {
|
|
7492
|
-
out.agentMentions = r.agentMentions;
|
|
7493
|
-
}
|
|
7494
|
-
if (typeof r.rememberAgents === "boolean") {
|
|
7495
|
-
out.rememberAgents = r.rememberAgents;
|
|
7496
|
-
}
|
|
7497
|
-
if (typeof r.widgetMode === "string" && VALID_WIDGET_MODES.has(r.widgetMode)) {
|
|
7498
|
-
out.widgetMode = r.widgetMode;
|
|
7499
|
-
}
|
|
7500
|
-
if (typeof r.outputTranscript === "boolean") {
|
|
7501
|
-
out.outputTranscript = r.outputTranscript;
|
|
7502
|
-
}
|
|
7503
|
-
if (typeof r.worktreeIsolation === "boolean") {
|
|
7504
|
-
out.worktreeIsolation = r.worktreeIsolation;
|
|
7505
|
-
}
|
|
7506
|
-
if (typeof r.reportUsage === "boolean") {
|
|
7507
|
-
out.reportUsage = r.reportUsage;
|
|
7508
|
-
}
|
|
7509
|
-
if (typeof r.showCost === "boolean") {
|
|
7510
|
-
out.showCost = r.showCost;
|
|
7511
|
-
}
|
|
7512
|
-
if (typeof r.showModel === "boolean") {
|
|
7513
|
-
out.showModel = r.showModel;
|
|
7514
|
-
}
|
|
7515
|
-
if (typeof r.viewerMarkdown === "string" && VALID_VIEWER_MARKDOWN_MODES.has(r.viewerMarkdown)) {
|
|
7516
|
-
out.viewerMarkdown = r.viewerMarkdown;
|
|
7517
|
-
}
|
|
7518
|
-
if (typeof r.workflowsEnabled === "boolean") {
|
|
7519
|
-
out.workflowsEnabled = r.workflowsEnabled;
|
|
7520
|
-
}
|
|
7521
|
-
if (r.fallbackSubagent === false) {
|
|
7522
|
-
out.fallbackSubagent = NO_FALLBACK;
|
|
7523
|
-
} else if (typeof r.fallbackSubagent === "string" && r.fallbackSubagent.trim()) {
|
|
7524
|
-
out.fallbackSubagent = r.fallbackSubagent.trim();
|
|
7525
|
-
}
|
|
7526
|
-
return out;
|
|
7527
|
-
}
|
|
7528
|
-
function globalPath() {
|
|
7529
|
-
return import_node_path13.join(import_pi_coding_agent13.getAgentDir(), "subagents.json");
|
|
7530
|
-
}
|
|
7531
|
-
function projectPath(cwd) {
|
|
7532
|
-
return import_node_path13.join(cwd, ".pi", "subagents.json");
|
|
7533
|
-
}
|
|
7534
|
-
var readParsedSettings = createDiscoveryCache((path) => sanitize(JSON.parse(import_node_fs13.readFileSync(path, "utf-8"))), 64);
|
|
7535
|
-
function readSettingsFile(path) {
|
|
7536
|
-
if (!import_node_fs13.existsSync(path))
|
|
7537
|
-
return {};
|
|
7538
|
-
try {
|
|
7539
|
-
return readParsedSettings(path);
|
|
7540
|
-
} catch (err) {
|
|
7541
|
-
const reason = err instanceof Error ? err.message : String(err);
|
|
7542
|
-
console.warn(`[pi-subagents] Ignoring malformed settings at ${path}: ${reason}`);
|
|
7543
|
-
return {};
|
|
7544
|
-
}
|
|
7545
|
-
}
|
|
7546
|
-
function loadSettings(cwd = process.cwd(), project = true) {
|
|
7547
|
-
return { ...readSettingsFile(globalPath()), ...project ? readSettingsFile(projectPath(cwd)) : {} };
|
|
7548
|
-
}
|
|
7549
|
-
function saveSettings(s, cwd = process.cwd()) {
|
|
7550
|
-
const path = projectPath(cwd);
|
|
7551
|
-
try {
|
|
7552
|
-
import_node_fs13.mkdirSync(import_node_path13.dirname(path), { recursive: true });
|
|
7553
|
-
import_node_fs13.writeFileSync(path, JSON.stringify(s, null, 2), "utf-8");
|
|
7554
|
-
return true;
|
|
7555
|
-
} catch {
|
|
7556
|
-
return false;
|
|
7557
|
-
}
|
|
7558
|
-
}
|
|
7559
|
-
function applySettings(s, appliers) {
|
|
7560
|
-
if (typeof s.maxConcurrent === "number")
|
|
7561
|
-
appliers.setMaxConcurrent(s.maxConcurrent);
|
|
7562
|
-
if (typeof s.maxConcurrentForeground === "number") {
|
|
7563
|
-
appliers.setMaxConcurrentForeground(s.maxConcurrentForeground);
|
|
7564
|
-
}
|
|
7565
|
-
if (typeof s.defaultMaxTurns === "number")
|
|
7566
|
-
appliers.setDefaultMaxTurns(s.defaultMaxTurns);
|
|
7567
|
-
if (typeof s.graceTurns === "number")
|
|
7568
|
-
appliers.setGraceTurns(s.graceTurns);
|
|
7569
|
-
if (typeof s.toolTimeoutSeconds === "number")
|
|
7570
|
-
appliers.setToolTimeoutSeconds(s.toolTimeoutSeconds);
|
|
7571
|
-
if (typeof s.maxSubagentDepth === "number")
|
|
7572
|
-
appliers.setMaxSubagentDepth(s.maxSubagentDepth);
|
|
7573
|
-
if (typeof s.fallbackSubagent === "string")
|
|
7574
|
-
appliers.setFallbackSubagent(s.fallbackSubagent);
|
|
7575
|
-
if (s.defaultJoinMode)
|
|
7576
|
-
appliers.setDefaultJoinMode(s.defaultJoinMode);
|
|
7577
|
-
if (typeof s.backgroundByDefault === "boolean")
|
|
7578
|
-
appliers.setBackgroundByDefault(s.backgroundByDefault);
|
|
7579
|
-
if (typeof s.schedulingEnabled === "boolean")
|
|
7580
|
-
appliers.setSchedulingEnabled(s.schedulingEnabled);
|
|
7581
|
-
if (typeof s.scopeModels === "boolean")
|
|
7582
|
-
appliers.setScopeModels(s.scopeModels);
|
|
7583
|
-
if (typeof s.strictAgentFiles === "boolean")
|
|
7584
|
-
appliers.setStrictAgentFiles(s.strictAgentFiles);
|
|
7585
|
-
if (typeof s.disableDefaultAgents === "boolean")
|
|
7586
|
-
appliers.setDisableDefaultAgents(s.disableDefaultAgents);
|
|
7587
|
-
if (s.toolDescriptionMode)
|
|
7588
|
-
appliers.setToolDescriptionMode(s.toolDescriptionMode);
|
|
7589
|
-
if (typeof s.fleetView === "boolean")
|
|
7590
|
-
appliers.setFleetView(s.fleetView);
|
|
7591
|
-
if (s.agentMentions)
|
|
7592
|
-
appliers.setAgentMentions(s.agentMentions);
|
|
7593
|
-
if (typeof s.rememberAgents === "boolean")
|
|
7594
|
-
appliers.setRememberAgents(s.rememberAgents);
|
|
7595
|
-
if (s.widgetMode)
|
|
7596
|
-
appliers.setWidgetMode(s.widgetMode);
|
|
7597
|
-
if (typeof s.outputTranscript === "boolean")
|
|
7598
|
-
appliers.setOutputTranscript(s.outputTranscript);
|
|
7599
|
-
if (typeof s.worktreeIsolation === "boolean")
|
|
7600
|
-
appliers.setWorktreeIsolation(s.worktreeIsolation);
|
|
7601
|
-
if (typeof s.reportUsage === "boolean")
|
|
7602
|
-
appliers.setReportUsage(s.reportUsage);
|
|
7603
|
-
if (typeof s.showCost === "boolean")
|
|
7604
|
-
appliers.setShowCost(s.showCost);
|
|
7605
|
-
if (typeof s.showModel === "boolean")
|
|
7606
|
-
appliers.setShowModel(s.showModel);
|
|
7607
|
-
if (s.viewerMarkdown)
|
|
7608
|
-
appliers.setViewerMarkdown(s.viewerMarkdown);
|
|
7609
|
-
if (typeof s.workflowsEnabled === "boolean")
|
|
7610
|
-
appliers.setWorkflowsEnabled(s.workflowsEnabled);
|
|
7611
|
-
}
|
|
7612
|
-
function persistToastFor(successMsg, persisted) {
|
|
7613
|
-
return persisted ? { message: successMsg, level: "info" } : { message: `${successMsg} (session only; failed to persist)`, level: "warning" };
|
|
7614
|
-
}
|
|
7615
|
-
function applyAndEmitLoaded(appliers, emit, cwd = process.cwd(), project = true) {
|
|
7616
|
-
const settings = loadSettings(cwd, project);
|
|
7617
|
-
applySettings(settings, appliers);
|
|
7618
|
-
emit("subagents:settings_loaded", { settings });
|
|
7619
|
-
return settings;
|
|
7620
|
-
}
|
|
7621
|
-
function saveAndEmitChanged(snapshot, successMsg, emit, cwd = process.cwd()) {
|
|
7622
|
-
const persisted = saveSettings(snapshot, cwd);
|
|
7623
|
-
emit("subagents:settings_changed", { settings: snapshot, persisted });
|
|
7624
|
-
return persistToastFor(successMsg, persisted);
|
|
7625
|
-
}
|
|
7645
|
+
// src/index.ts
|
|
7646
|
+
init_settings();
|
|
7647
|
+
|
|
7626
7648
|
// src/ui/agent-mention.ts
|
|
7627
7649
|
init_mention();
|
|
7628
7650
|
function mentionRoster(manager, types, displayNameOf = (type) => type) {
|
package/dist-bun/index.js
CHANGED
|
@@ -16,7 +16,7 @@ const hostModules = {
|
|
|
16
16
|
"@sinclair/typebox": host__sinclair_typebox,
|
|
17
17
|
"typebox/value": host_typebox_value,
|
|
18
18
|
};
|
|
19
|
-
globalThis[Symbol.for("opensec-pi-subagents@0.20.
|
|
19
|
+
globalThis[Symbol.for("opensec-pi-subagents@0.20.2:host-modules")] = (id) => {
|
|
20
20
|
const mod = hostModules[id];
|
|
21
21
|
if (mod === undefined) throw new Error(`opensec-pi-subagents: host module ${id} is not available`);
|
|
22
22
|
return mod;
|
package/docs/workflows.md
CHANGED
|
@@ -124,7 +124,7 @@ A script you will run more than once belongs somewhere durable. Copy it out of t
|
|
|
124
124
|
|
|
125
125
|
First hit wins, in that order, so a project file shadows a same-named global one.
|
|
126
126
|
|
|
127
|
-
|
|
127
|
+
With `"projectTrust": "pi"` in the global subagents.json (the default, `"full"`, uses them in every project), the two project locations are used only when Pi trusts the project to run its own code: the folder was trusted at Pi's prompt (or by `defaultProjectTrust`, or a CLI flag), or `/trust` recorded it. Pi trusts a folder without asking when it holds nothing Pi gates, and `.pi/workflows` is not gated, so a cloned repo that ships only workflows does not get them run by name until you run `/trust`. A refused name says so and runs nothing.
|
|
128
128
|
|
|
129
129
|
The file must carry an `export const meta = { name, description }` declaration. Those are ordinary directories that may hold anything, so that declaration is what marks a file as a workflow — name something else and you are told it is not a workflow rather than getting a parse error from halfway through it. Nothing in the file is executed to decide that.
|
|
130
130
|
|
|
@@ -288,7 +288,7 @@ The child runs in the *same* worker and vm context under its own globals, so it
|
|
|
288
288
|
|---|---|
|
|
289
289
|
| An inline script, as run | `<tmp>/pi-subagents-<uid>/<encoded-cwd>/<session>/tasks/<run id>.workflow.js` |
|
|
290
290
|
| The resume journal | the same directory, `<run id>.workflow.jsonl` |
|
|
291
|
-
| Saved workflows | `.pi/workflows/` → `.agents/workflows/` → `<agent dir>/workflows/`, first hit wins (project locations only in a project trusted to run its code) |
|
|
291
|
+
| Saved workflows | `.pi/workflows/` → `.agents/workflows/` → `<agent dir>/workflows/`, first hit wins (with `projectTrust: "pi"`, project locations only in a project trusted to run its code) |
|
|
292
292
|
|
|
293
293
|
The first two are scratch: temp storage, wiped by a reboot or a temp sweep. Only the third is durable, and copying a script there is a manual step.
|
|
294
294
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opensec-pi-subagents",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.2",
|
|
4
4
|
"description": "OpenSec Subagents for Pi: specialized agents in separate sessions that inherit the parent's model and thinking level. Bun build, for Pi-Bolt.",
|
|
5
5
|
"author": "OpenSec",
|
|
6
6
|
"contributors": [
|