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 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
- - Subagents follow Pi's trust decision for a project folder; Explore and Plan are read-only by their tools (`read`, `grep`, `find`, `ls`).
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.1:host-modules")]("@earendil-works/pi-coding-agent");
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.1:host-modules")]("@earendil-works/pi-tui");
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.1:host-modules")]("@sinclair/typebox");
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 import_pi_coding_agent7.ProjectTrustStore(import_pi_coding_agent7.getAgentDir()).get(cwd);
2386
+ return new import_pi_coding_agent8.ProjectTrustStore(import_pi_coding_agent8.getAgentDir()).get(cwd);
2173
2387
  }
2174
2388
  function defaultTrustIsAlways(cwd) {
2175
- return import_pi_coding_agent7.SettingsManager.create(cwd, import_pi_coding_agent7.getAgentDir(), { projectTrusted: false }).getDefaultProjectTrust() === "always";
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 (!import_pi_coding_agent7.hasTrustRequiringProjectResources(cwd))
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 import_pi_coding_agent7.hasTrustRequiringProjectResources(cwd) || savedDecision(cwd) === true || defaultTrustIsAlways(cwd);
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 import_pi_coding_agent7;
2416
+ var import_pi_coding_agent8;
2199
2417
  var init_project_trust = __esm(() => {
2200
- import_pi_coding_agent7 = __toESM(require_pi_coding_agent());
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
- import_node_path9.join(cwd, ".pi", "skills"),
2291
- import_node_path9.join(cwd, ".agents", "skills")
2509
+ import_node_path10.join(cwd, ".pi", "skills"),
2510
+ import_node_path10.join(cwd, ".agents", "skills")
2292
2511
  ] : [],
2293
- import_node_path9.join(import_pi_coding_agent8.getAgentDir(), "skills"),
2294
- import_node_path9.join(import_node_os4.homedir(), ".agents", "skills"),
2295
- import_node_path9.join(import_node_os4.homedir(), ".pi", "skills")
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(import_node_path9.join(root, `${name}.md`))?.trim();
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 (!import_node_fs8.existsSync(root))
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 = import_node_fs8.readdirSync(current, { withFileTypes: true });
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 = import_node_path9.join(current, entry.name);
2333
- const skillMd = import_node_path9.join(path, "SKILL.md");
2334
- const isSkillDir = import_node_fs8.existsSync(skillMd);
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 import_node_fs8, import_node_os4, import_node_path9, import_pi_coding_agent8;
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
- import_node_fs8 = require("fs");
2570
+ import_node_fs9 = require("fs");
2352
2571
  import_node_os4 = require("os");
2353
- import_node_path9 = require("path");
2354
- import_pi_coding_agent8 = __toESM(require_pi_coding_agent());
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 import_pi_coding_agent9.defineTool({
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 import_pi_coding_agent9, STRUCTURED_OUTPUT_TOOL_NAME = "StructuredOutput";
2628
+ var import_pi_coding_agent10, STRUCTURED_OUTPUT_TOOL_NAME = "StructuredOutput";
2410
2629
  var init_structured_output = __esm(() => {
2411
- import_pi_coding_agent9 = __toESM(require_pi_coding_agent());
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 = import_node_path10.basename(extPath);
2417
- const name = base === "index.ts" || base === "index.js" ? import_node_path10.basename(import_node_path10.dirname(extPath)) : base.replace(/\.(ts|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 = import_node_path10.resolve(extPath);
2422
- let dir = import_node_path10.dirname(extPath);
2640
+ const entry = import_node_path11.resolve(extPath);
2641
+ let dir = import_node_path11.dirname(extPath);
2423
2642
  for (;; ) {
2424
- if (import_node_path10.basename(dir) === "node_modules")
2643
+ if (import_node_path11.basename(dir) === "node_modules")
2425
2644
  return;
2426
2645
  let pkg;
2427
2646
  try {
2428
- pkg = JSON.parse(import_node_fs9.readFileSync(import_node_path10.join(dir, "package.json"), "utf-8"));
2647
+ pkg = JSON.parse(import_node_fs10.readFileSync(import_node_path11.join(dir, "package.json"), "utf-8"));
2429
2648
  } catch {
2430
- const parent = import_node_path10.dirname(dir);
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" && import_node_path10.resolve(dir, e) === entry)) {
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 = import_node_path10.isAbsolute(p) ? p : import_node_path10.resolve(cwd, p);
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(TOOL_TIMEOUT_CEILING, Math.max(0, Math.floor(n)));
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 import_node_path10.resolve(import_node_os5.homedir(), sessionDir.slice(2));
2758
- if (import_node_path10.isAbsolute(sessionDir))
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 import_node_path10.resolve(cwd, sessionDir);
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 = import_pi_coding_agent10.getAgentDir();
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 ? import_node_path10.dirname(import_node_path10.dirname(import_node_path10.dirname(agentConfig.sourcePath))) : configCwd;
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 = import_pi_coding_agent10.SettingsManager.create(configCwd, agentDir, { projectTrusted });
2852
- const loader = new import_pi_coding_agent10.DefaultResourceLoader({
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 ? import_pi_coding_agent10.SessionManager.open(options.resumeSessionFile, configuredSessionDir ?? defaultSessionDir) : persistSession ? import_pi_coding_agent10.SessionManager.create(effectiveCwd, configuredSessionDir ?? defaultSessionDir, {
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
- }) : import_pi_coding_agent10.SessionManager.inMemory(effectiveCwd);
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(() => import_pi_coding_agent10.createAgentSession(sessionOpts));
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 import_node_fs9, import_node_os5, import_node_path10, import_pi_coding_agent10, 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_CEILING = 86400, watchdogTiming, MAX_TOOL_RECOVERIES = 3, WATCHDOG_EXEMPT_TOOLS;
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
- import_node_fs9 = require("fs");
3408
+ import_node_fs10 = require("fs");
3190
3409
  import_node_os5 = require("os");
3191
- import_node_path10 = require("path");
3192
- import_pi_coding_agent10 = __toESM(require_pi_coding_agent());
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 (!import_node_fs10.existsSync(path))
3477
+ if (!import_node_fs11.existsSync(path))
3259
3478
  return `its session file is gone (${path})`;
3260
3479
  try {
3261
- if (import_node_fs10.statSync(path).size === 0)
3480
+ if (import_node_fs11.statSync(path).size === 0)
3262
3481
  return `its session file is empty (${path})`;
3263
- import_pi_coding_agent11.SessionManager.open(path);
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 import_node_fs10, import_pi_coding_agent11;
3488
+ var import_node_fs11, import_pi_coding_agent12;
3270
3489
  var init_session_file = __esm(() => {
3271
- import_node_fs10 = require("fs");
3272
- import_pi_coding_agent11 = __toESM(require_pi_coding_agent());
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" || !import_node_path11.isAbsolute(cwd)) {
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 = import_node_fs11.statSync(cwd).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 (!import_node_fs11.existsSync(entry.sessionFile))
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 && !import_node_fs11.existsSync(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 || !import_node_fs11.existsSync(record.worktree.path))
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, import_node_fs11, import_node_path11, 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;
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
- import_node_fs11 = require("fs");
4538
- import_node_path11 = require("path");
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.1:host-modules")]("typebox/value");
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 import_pi_coding_agent12 = __toESM(require_pi_coding_agent());
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 = import_pi_coding_agent12.buildSessionContext(ctx.sessionManager.getEntries(), ctx.sessionManager.getLeafId());
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(() => import_pi_coding_agent12.createAgentSession({
6186
+ const created = await runInChildSessionContext(() => import_pi_coding_agent13.createAgentSession({
5968
6187
  cwd: ctx.cwd,
5969
- sessionManager: import_pi_coding_agent12.SessionManager.inMemory(ctx.cwd, undefined, ctx.sessionManager.getBranch?.() ?? []),
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 import_node_fs12 = require("fs");
7250
- var import_node_path12 = require("path");
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
- import_node_fs12.writeFileSync(lockPath, `${process.pid}`, { flag: "wx" });
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(import_node_fs12.readFileSync(lockPath, "utf-8"), 10);
7272
- const age = Date.now() - import_node_fs12.statSync(lockPath).mtimeMs;
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
- import_node_fs12.unlinkSync(lockPath);
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
- import_node_fs12.unlinkSync(lockPath);
7506
+ import_node_fs13.unlinkSync(lockPath);
7288
7507
  } catch {}
7289
7508
  }
7290
7509
  function resolveStorePath(cwd, sessionId) {
7291
- return import_node_path12.join(cwd, ".pi", "subagent-schedules", `${sessionId}.json`);
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
- import_node_fs12.mkdirSync(import_node_path12.dirname(this.filePath), { recursive: true });
7527
+ import_node_fs13.mkdirSync(import_node_path13.dirname(this.filePath), { recursive: true });
7309
7528
  }
7310
7529
  load() {
7311
- if (!import_node_fs12.existsSync(this.filePath))
7530
+ if (!import_node_fs13.existsSync(this.filePath))
7312
7531
  return;
7313
7532
  let data;
7314
7533
  try {
7315
- data = JSON.parse(import_node_fs12.readFileSync(this.filePath, "utf-8"));
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
- import_node_fs12.renameSync(this.filePath, backup);
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
- import_node_fs12.writeFileSync(tmp, JSON.stringify(data, null, 2));
7334
- import_node_fs12.renameSync(tmp, this.filePath);
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 && import_node_fs12.existsSync(this.filePath)) {
7637
+ if (this.jobs.size === 0 && import_node_fs13.existsSync(this.filePath)) {
7419
7638
  try {
7420
- import_node_fs12.unlinkSync(this.filePath);
7639
+ import_node_fs13.unlinkSync(this.filePath);
7421
7640
  } catch {}
7422
7641
  }
7423
7642
  }
7424
7643
  }
7425
7644
 
7426
- // src/settings.ts
7427
- init_agent_types();
7428
- init_discovery_cache();
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.1:host-modules")] = (id) => {
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
- 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.
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.1",
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": [