pi-subagents 0.56.0 → 0.58.0

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.
Files changed (108) hide show
  1. package/CHANGELOG.md +92 -0
  2. package/agents/claude-code-writer.md +15 -0
  3. package/agents/claude-code.md +15 -0
  4. package/agents/codex-exec-writer.md +15 -0
  5. package/agents/codex-exec.md +15 -0
  6. package/agents/cursor-agent-writer.md +14 -0
  7. package/agents/cursor-agent.md +14 -0
  8. package/docs/agents.md +124 -21
  9. package/docs/configuration.md +37 -0
  10. package/docs/extension-api.md +41 -2
  11. package/docs/models.md +3 -3
  12. package/docs/observability.md +8 -7
  13. package/docs/tool-reference.md +14 -3
  14. package/docs/workflows.md +44 -0
  15. package/package.json +1 -1
  16. package/skills/pi-subagents/SKILL.md +2 -0
  17. package/skills/pi-subagents/references/execution-controls.md +2 -2
  18. package/skills/pi-subagents/references/management-authoring-rpc.md +1 -0
  19. package/skills/pi-subagents/references/prompting-and-roles.md +2 -2
  20. package/src/agents/agent-management.ts +36 -5
  21. package/src/agents/agent-refinements.ts +4 -4
  22. package/src/agents/agent-serializer.ts +5 -0
  23. package/src/agents/agents.ts +257 -51
  24. package/src/agents/builtin-names.ts +6 -0
  25. package/src/agents/runtime-agent-events.ts +70 -0
  26. package/src/agents/runtime-agent-registry.ts +18 -4
  27. package/src/api/agents.ts +10 -5
  28. package/src/api/preflight.ts +28 -3
  29. package/src/extension/config.ts +70 -0
  30. package/src/extension/doctor.ts +3 -3
  31. package/src/extension/index.ts +33 -8
  32. package/src/extension/public-execution.ts +29 -13
  33. package/src/extension/rpc.ts +55 -19
  34. package/src/extension/schemas.ts +6 -5
  35. package/src/extension/tool-description.ts +18 -12
  36. package/src/inspectors/herdr/actions.ts +2 -1
  37. package/src/inspectors/herdr/inspector-runner.ts +2 -10
  38. package/src/inspectors/herdr/session-roots-codec.ts +42 -0
  39. package/src/integrations/herdr-status.ts +51 -3
  40. package/src/runs/background/active-async-capacity.ts +77 -10
  41. package/src/runs/background/async-execution.ts +127 -19
  42. package/src/runs/background/async-job-tracker.ts +5 -0
  43. package/src/runs/background/async-resume.ts +6 -2
  44. package/src/runs/background/async-retention.ts +20 -3
  45. package/src/runs/background/async-status.ts +7 -0
  46. package/src/runs/background/chain-append.ts +2 -0
  47. package/src/runs/background/chain-root-attachment.ts +15 -1
  48. package/src/runs/background/fleet-view.ts +16 -10
  49. package/src/runs/background/inspect-rpc.ts +8 -8
  50. package/src/runs/background/notify.ts +26 -3
  51. package/src/runs/background/result-delivery-ownership.ts +45 -0
  52. package/src/runs/background/result-files.ts +27 -14
  53. package/src/runs/background/result-watcher.ts +36 -15
  54. package/src/runs/background/run-status.ts +33 -6
  55. package/src/runs/background/scheduled-runs.ts +7 -1
  56. package/src/runs/background/subagent-runner.ts +239 -56
  57. package/src/runs/background/wait-completions.ts +4 -0
  58. package/src/runs/foreground/execution.ts +92 -11
  59. package/src/runs/foreground/foreground-control.ts +6 -0
  60. package/src/runs/foreground/foreground-history.ts +22 -1
  61. package/src/runs/foreground/subagent-executor.ts +322 -102
  62. package/src/runs/foreground/workflow-detach-reconcile.ts +144 -18
  63. package/src/runs/shared/child-protocol.ts +21 -7
  64. package/src/runs/shared/claude-code-adapter.ts +129 -0
  65. package/src/runs/shared/codex-exec-adapter.ts +129 -0
  66. package/src/runs/shared/completion-guard.ts +4 -3
  67. package/src/runs/shared/cursor-agent-adapter.ts +114 -0
  68. package/src/runs/shared/dynamic-fanout.ts +3 -3
  69. package/src/runs/shared/external-cli-contract.ts +167 -0
  70. package/src/runs/shared/external-cli-preflight.ts +122 -0
  71. package/src/runs/shared/external-cli-runner.ts +348 -55
  72. package/src/runs/shared/fast-mode-extension.ts +5 -5
  73. package/src/runs/shared/launch-cwd.ts +16 -0
  74. package/src/runs/shared/long-running-guard.ts +2 -1
  75. package/src/runs/shared/mcp-config-sources.ts +386 -0
  76. package/src/runs/shared/mcp-direct-tool-allowlist.ts +155 -42
  77. package/src/runs/shared/model-exclusions.ts +69 -7
  78. package/src/runs/shared/model-fallback.ts +39 -5
  79. package/src/runs/shared/mutation-evidence.ts +7 -2
  80. package/src/runs/shared/nested-events.ts +3 -1
  81. package/src/runs/shared/nested-render.ts +2 -2
  82. package/src/runs/shared/parallel-utils.ts +8 -1
  83. package/src/runs/shared/pi-args.ts +61 -6
  84. package/src/runs/shared/process-signal.ts +13 -0
  85. package/src/runs/shared/run-history.ts +21 -1
  86. package/src/runs/shared/single-output.ts +17 -0
  87. package/src/runs/shared/subagent-prompt-runtime.ts +85 -9
  88. package/src/shared/fork-context.ts +21 -0
  89. package/src/shared/formatters.ts +13 -1
  90. package/src/shared/launch-contract.ts +4 -0
  91. package/src/shared/pruned-fork.ts +450 -0
  92. package/src/shared/session-file-trust.ts +19 -0
  93. package/src/shared/session-tokens.ts +14 -3
  94. package/src/shared/settings.ts +10 -2
  95. package/src/shared/shortcuts.ts +17 -0
  96. package/src/shared/types.ts +160 -10
  97. package/src/shared/utils.ts +6 -29
  98. package/src/shared/workflow-child-permit.ts +116 -0
  99. package/src/slash/delegation-adapters.ts +0 -1
  100. package/src/slash/slash-commands.ts +8 -6
  101. package/src/slash/subagents-admin.ts +3 -0
  102. package/src/tui/fleet-status.ts +27 -10
  103. package/src/tui/fleet-transcript.ts +11 -5
  104. package/src/tui/fleet.ts +28 -13
  105. package/src/tui/render.ts +55 -21
  106. package/src/workflows/scripted-workflow.ts +299 -31
  107. package/src/workflows/workflow-child-summary.ts +117 -0
  108. package/src/workflows/workflow-receipt.ts +155 -5
@@ -9,6 +9,7 @@ import * as os from "node:os";
9
9
  import * as path from "node:path";
10
10
  import { fileURLToPath } from "node:url";
11
11
  import type { AcceptanceInput, AcceptanceRole, AgentRunnerConfig, OutputMode, ToolBudgetConfig, TurnBudgetConfig } from "../shared/types.ts";
12
+ import { CODE_OWNED_EXTERNAL_CLI_ADAPTER_LABEL, isCodeOwnedExternalCliAdapterId, parseExternalCliCapabilityNarrowing, validateCodeOwnedProfileRunner } from "../runs/shared/external-cli-contract.ts";
12
13
  import { getAgentDir, getProjectConfigDir } from "../shared/utils.ts";
13
14
  import { KNOWN_FIELDS } from "./agent-serializer.ts";
14
15
  import { parseChain, parseJsonChain } from "./chain-serializer.ts";
@@ -61,6 +62,7 @@ export interface BuiltinAgentOverrideBase {
61
62
  thinking?: string | false;
62
63
  systemPromptMode: SystemPromptMode;
63
64
  inheritProjectContext: boolean;
65
+ inheritGlobalContext: boolean;
64
66
  inheritSkills: boolean;
65
67
  defaultContext?: AgentDefaultContext;
66
68
  acceptanceRole?: AcceptanceRole;
@@ -72,6 +74,7 @@ export interface BuiltinAgentOverrideBase {
72
74
  mcpDirectTools?: string[];
73
75
  extensions?: string[];
74
76
  subagentOnlyExtensions?: string[];
77
+ mutationTools?: string[];
75
78
  completionGuard?: boolean;
76
79
  toolBudget?: ToolBudgetConfig;
77
80
  }
@@ -88,6 +91,7 @@ interface BuiltinAgentOverrideConfig {
88
91
  thinking?: string | false;
89
92
  systemPromptMode?: SystemPromptMode;
90
93
  inheritProjectContext?: boolean;
94
+ inheritGlobalContext?: boolean;
91
95
  inheritSkills?: boolean;
92
96
  defaultContext?: AgentDefaultContext | false;
93
97
  acceptanceRole?: AcceptanceRole | false;
@@ -97,6 +101,7 @@ interface BuiltinAgentOverrideConfig {
97
101
  tools?: string[] | false | "inherit";
98
102
  extensions?: string[] | false;
99
103
  subagentOnlyExtensions?: string[] | false;
104
+ mutationTools?: string[] | false;
100
105
  completionGuard?: boolean;
101
106
  toolBudget?: ToolBudgetConfig | false;
102
107
  }
@@ -134,6 +139,7 @@ export interface AgentConfig {
134
139
  thinking?: string | false;
135
140
  systemPromptMode: SystemPromptMode;
136
141
  inheritProjectContext: boolean;
142
+ inheritGlobalContext: boolean;
137
143
  inheritSkills: boolean;
138
144
  defaultContext?: AgentDefaultContext;
139
145
  defaultAsync?: boolean;
@@ -151,6 +157,7 @@ export interface AgentConfig {
151
157
  extensions?: string[];
152
158
  extensionsFromDefault?: boolean;
153
159
  subagentOnlyExtensions?: string[];
160
+ mutationTools?: string[];
154
161
  output?: string;
155
162
  outputMode?: OutputMode;
156
163
  defaultReads?: string[];
@@ -262,14 +269,72 @@ export function findBlockingAgentDiagnostic(name: string, agent: AgentConfig | r
262
269
  return !agents.length || (match && agentDefinitionPriority(match) > highestPriority) ? match : undefined;
263
270
  }
264
271
 
265
- interface AgentDiscoveryResult {
272
+ export type AgentDefinitionDirectoryState = "absent" | "empty" | "candidates" | "unreadable" | "not-directory";
273
+
274
+ /** A definition directory actually inspected during one agent-discovery operation. */
275
+ export interface AgentDefinitionDirectoryReport {
276
+ source: AgentSource;
277
+ path: string;
278
+ state: AgentDefinitionDirectoryState;
279
+ candidateCount?: number;
280
+ }
281
+
282
+ /**
283
+ * Filesystem provenance for a failed agent resolution. Context is created from
284
+ * the discovery result that supplied the effective agents; callers must not
285
+ * pair arbitrary agent arrays with these directory reports.
286
+ */
287
+ export interface UnknownAgentDiagnosticContext {
288
+ cwd: string;
289
+ scope: AgentScope;
290
+ directories: readonly AgentDefinitionDirectoryReport[];
291
+ agents: readonly AgentConfig[];
292
+ }
293
+
294
+ export interface AgentDiscoveryResult {
266
295
  agents: AgentConfig[];
267
296
  agentDiagnostics?: AgentDiscoveryDiagnostic[];
268
297
  projectAgentsDir: string | null;
298
+ cwd: string;
299
+ scope: AgentScope;
300
+ directories: readonly AgentDefinitionDirectoryReport[];
269
301
  modelScope?: ModelScopeConfig;
270
302
  maxThinking?: ThinkingLevel;
271
303
  }
272
304
 
305
+ /** Create formatter input from the exact discovery operation used for resolution. */
306
+ export function unknownAgentDiagnosticContext(discovered: Pick<AgentDiscoveryResult, "cwd" | "scope" | "directories" | "agents">): UnknownAgentDiagnosticContext {
307
+ return {
308
+ cwd: discovered.cwd,
309
+ scope: discovered.scope,
310
+ directories: discovered.directories,
311
+ agents: discovered.agents,
312
+ };
313
+ }
314
+
315
+ /** Render local discovery evidence without exposing filesystem error details. */
316
+ export function formatUnknownAgentError(name: string, context: UnknownAgentDiagnosticContext, prefix = "Unknown agent"): string {
317
+ const directories = context.directories.map((directory) => {
318
+ const state = directory.state === "candidates"
319
+ ? `${directory.candidateCount ?? 0} candidate${directory.candidateCount === 1 ? "" : "s"}`
320
+ : directory.state === "empty" ? "present but empty"
321
+ : directory.state === "not-directory" ? "not a directory"
322
+ : directory.state;
323
+ return `- ${directory.source}: ${directory.path} (${state})`;
324
+ });
325
+ const agents = [...context.agents]
326
+ .sort((left, right) => left.name.localeCompare(right.name) || left.source.localeCompare(right.source))
327
+ .map((agent) => `- ${agent.name} (${agent.source})`);
328
+ return [
329
+ `${prefix}: ${name}`,
330
+ `Effective cwd: ${path.resolve(context.cwd)}`,
331
+ "Consulted agent-definition directories:",
332
+ ...(directories.length ? directories : ["- (none)"]),
333
+ "Discovered agents:",
334
+ ...(agents.length ? agents : ["- (none)"]),
335
+ ].join("\n");
336
+ }
337
+
273
338
  function getUserChainDir(): string {
274
339
  return path.join(getAgentDir(), "chains");
275
340
  }
@@ -381,6 +446,10 @@ function resolveSettingsPackageRoot(source: string, baseDir: string): string | u
381
446
  if (normalized === "." || normalized === ".." || normalized.startsWith("./") || normalized.startsWith("../")) {
382
447
  return path.resolve(baseDir, normalized);
383
448
  }
449
+ if (/^https?:\/\//i.test(trimmed)) {
450
+ const parsed = parseGitPackagePath(`git:${trimmed}`);
451
+ return parsed ? path.join(baseDir, "git", parsed.host, parsed.repoPath) : undefined;
452
+ }
384
453
  return undefined;
385
454
  }
386
455
 
@@ -647,6 +716,7 @@ function cloneOverrideBase(agent: AgentConfig): BuiltinAgentOverrideBase {
647
716
  ...(agent.thinking !== undefined ? { thinking: agent.thinking } : {}),
648
717
  systemPromptMode: agent.systemPromptMode,
649
718
  inheritProjectContext: agent.inheritProjectContext,
719
+ inheritGlobalContext: agent.inheritGlobalContext,
650
720
  inheritSkills: agent.inheritSkills,
651
721
  ...(agent.defaultContext !== undefined ? { defaultContext: agent.defaultContext } : {}),
652
722
  ...(agent.acceptanceRole !== undefined ? { acceptanceRole: agent.acceptanceRole } : {}),
@@ -658,6 +728,7 @@ function cloneOverrideBase(agent: AgentConfig): BuiltinAgentOverrideBase {
658
728
  ...(agent.mcpDirectTools ? { mcpDirectTools: [...agent.mcpDirectTools] } : {}),
659
729
  ...(!agent.extensionsFromDefault && agent.extensions ? { extensions: [...agent.extensions] } : {}),
660
730
  ...(agent.subagentOnlyExtensions ? { subagentOnlyExtensions: [...agent.subagentOnlyExtensions] } : {}),
731
+ ...(agent.mutationTools ? { mutationTools: [...agent.mutationTools] } : {}),
661
732
  ...(agent.completionGuard !== undefined ? { completionGuard: agent.completionGuard } : {}),
662
733
  ...(agent.toolBudget !== undefined ? { toolBudget: agent.toolBudget } : {}),
663
734
  };
@@ -678,6 +749,7 @@ function cloneOverrideValue(override: BuiltinAgentOverrideConfig): BuiltinAgentO
678
749
  ...(override.thinking !== undefined ? { thinking: override.thinking } : {}),
679
750
  ...(override.systemPromptMode !== undefined ? { systemPromptMode: override.systemPromptMode } : {}),
680
751
  ...(override.inheritProjectContext !== undefined ? { inheritProjectContext: override.inheritProjectContext } : {}),
752
+ ...(override.inheritGlobalContext !== undefined ? { inheritGlobalContext: override.inheritGlobalContext } : {}),
681
753
  ...(override.inheritSkills !== undefined ? { inheritSkills: override.inheritSkills } : {}),
682
754
  ...(override.defaultContext !== undefined ? { defaultContext: override.defaultContext } : {}),
683
755
  ...(override.acceptanceRole !== undefined ? { acceptanceRole: override.acceptanceRole } : {}),
@@ -687,6 +759,7 @@ function cloneOverrideValue(override: BuiltinAgentOverrideConfig): BuiltinAgentO
687
759
  ...(override.tools !== undefined ? { tools: Array.isArray(override.tools) ? [...override.tools] : override.tools } : {}),
688
760
  ...(override.extensions !== undefined ? { extensions: override.extensions === false ? false : [...override.extensions] } : {}),
689
761
  ...(override.subagentOnlyExtensions !== undefined ? { subagentOnlyExtensions: override.subagentOnlyExtensions === false ? false : [...override.subagentOnlyExtensions] } : {}),
762
+ ...(override.mutationTools !== undefined ? { mutationTools: override.mutationTools === false ? false : [...override.mutationTools] } : {}),
690
763
  ...(override.completionGuard !== undefined ? { completionGuard: override.completionGuard } : {}),
691
764
  ...(override.toolBudget !== undefined ? { toolBudget: override.toolBudget === false ? false : { ...override.toolBudget, ...(Array.isArray(override.toolBudget.block) ? { block: [...override.toolBudget.block] } : {}) } } : {}),
692
765
  };
@@ -736,7 +809,7 @@ export function findNearestProjectRoot(cwd: string): string | null {
736
809
  return findProjectRootCandidates(cwd)[0] ?? null;
737
810
  }
738
811
 
739
- function findConfiguredProjectRoot(cwd: string): string | null {
812
+ export function findConfiguredProjectRoot(cwd: string): string | null {
740
813
  const candidates = findProjectRootCandidates(cwd);
741
814
  const nearestRoot = candidates[0];
742
815
  if (!nearestRoot) return null;
@@ -895,6 +968,14 @@ function parseBuiltinOverrideEntry(
895
968
  }
896
969
  }
897
970
 
971
+ if ("inheritGlobalContext" in input) {
972
+ if (typeof input.inheritGlobalContext === "boolean") {
973
+ override.inheritGlobalContext = input.inheritGlobalContext;
974
+ } else {
975
+ throw new Error(`Builtin override '${name}' in '${filePath}' has invalid 'inheritGlobalContext'; expected a boolean.`);
976
+ }
977
+ }
978
+
898
979
  if ("inheritSkills" in input) {
899
980
  if (typeof input.inheritSkills === "boolean") {
900
981
  override.inheritSkills = input.inheritSkills;
@@ -974,6 +1055,9 @@ function parseBuiltinOverrideEntry(
974
1055
  const subagentOnlyExtensions = parseOverrideStringArrayOrFalse(input.subagentOnlyExtensions, { filePath, name, field: "subagentOnlyExtensions" });
975
1056
  if (subagentOnlyExtensions !== undefined) override.subagentOnlyExtensions = subagentOnlyExtensions;
976
1057
 
1058
+ const mutationTools = parseOverrideStringArrayOrFalse(input.mutationTools, { filePath, name, field: "mutationTools" });
1059
+ if (mutationTools !== undefined) override.mutationTools = mutationTools;
1060
+
977
1061
  return Object.keys(override).length > 0 ? override : undefined;
978
1062
  }
979
1063
 
@@ -1209,6 +1293,7 @@ function applyBuiltinOverride(
1209
1293
  if (override.thinking !== undefined) { if (override.thinking === false) delete next.thinking; else next.thinking = override.thinking; }
1210
1294
  if (override.systemPromptMode !== undefined) next.systemPromptMode = override.systemPromptMode;
1211
1295
  if (override.inheritProjectContext !== undefined) next.inheritProjectContext = override.inheritProjectContext;
1296
+ if (override.inheritGlobalContext !== undefined) next.inheritGlobalContext = override.inheritGlobalContext;
1212
1297
  if (override.inheritSkills !== undefined) next.inheritSkills = override.inheritSkills;
1213
1298
  if (override.defaultContext !== undefined) { if (override.defaultContext === false) delete next.defaultContext; else next.defaultContext = override.defaultContext; }
1214
1299
  if (override.acceptanceRole !== undefined) { if (override.acceptanceRole === false) delete next.acceptanceRole; else next.acceptanceRole = override.acceptanceRole; }
@@ -1218,6 +1303,7 @@ function applyBuiltinOverride(
1218
1303
  if (override.tools !== undefined) applyToolsOverride(next, override.tools);
1219
1304
  if (override.extensions !== undefined) { if (override.extensions === false) delete next.extensions; else next.extensions = [...override.extensions]; }
1220
1305
  if (override.subagentOnlyExtensions !== undefined) { if (override.subagentOnlyExtensions === false) delete next.subagentOnlyExtensions; else next.subagentOnlyExtensions = [...override.subagentOnlyExtensions]; }
1306
+ if (override.mutationTools !== undefined) { if (override.mutationTools === false) delete next.mutationTools; else next.mutationTools = [...override.mutationTools]; }
1221
1307
  if (override.completionGuard !== undefined) next.completionGuard = override.completionGuard;
1222
1308
  if (override.toolBudget !== undefined) { if (override.toolBudget === false) delete next.toolBudget; else next.toolBudget = override.toolBudget; }
1223
1309
 
@@ -1355,6 +1441,9 @@ function applyCustomAgentOverride(
1355
1441
  if (override.inheritProjectContext !== undefined) {
1356
1442
  fill("inheritProjectContext", ["inheritProjectContext"], override.inheritProjectContext);
1357
1443
  }
1444
+ if (override.inheritGlobalContext !== undefined) {
1445
+ fill("inheritGlobalContext", ["inheritGlobalContext"], override.inheritGlobalContext);
1446
+ }
1358
1447
  if (override.inheritSkills !== undefined) {
1359
1448
  fill("inheritSkills", ["inheritSkills"], override.inheritSkills);
1360
1449
  }
@@ -1386,6 +1475,9 @@ function applyCustomAgentOverride(
1386
1475
  override.subagentOnlyExtensions === false ? undefined : [...override.subagentOnlyExtensions],
1387
1476
  );
1388
1477
  }
1478
+ if (override.mutationTools !== undefined) {
1479
+ fill("mutationTools", ["mutationTools"], override.mutationTools === false ? undefined : [...override.mutationTools]);
1480
+ }
1389
1481
  if (override.completionGuard !== undefined) {
1390
1482
  fill("completionGuard", ["completionGuard"], override.completionGuard);
1391
1483
  }
@@ -1425,7 +1517,7 @@ function applyCustomAgentOverrides(
1425
1517
 
1426
1518
  export function buildBuiltinOverrideConfig(
1427
1519
  base: BuiltinAgentOverrideBase,
1428
- draft: Pick<AgentConfig, "model" | "modelProvider" | "fallbackModels" | "fast" | "thinking" | "systemPromptMode" | "inheritProjectContext" | "inheritSkills" | "defaultContext" | "acceptanceRole" | "disabled" | "systemPrompt" | "skills" | "tools" | "mcpDirectTools" | "extensions" | "subagentOnlyExtensions" | "completionGuard" | "toolBudget"> & Partial<Pick<AgentConfig, "description" | "output" | "outputMode" | "defaultReads">>,
1520
+ draft: Pick<AgentConfig, "model" | "modelProvider" | "fallbackModels" | "fast" | "thinking" | "systemPromptMode" | "inheritProjectContext" | "inheritGlobalContext" | "inheritSkills" | "defaultContext" | "acceptanceRole" | "disabled" | "systemPrompt" | "skills" | "tools" | "mcpDirectTools" | "extensions" | "subagentOnlyExtensions" | "mutationTools" | "completionGuard" | "toolBudget"> & Partial<Pick<AgentConfig, "description" | "output" | "outputMode" | "defaultReads">>,
1429
1521
  ): BuiltinAgentOverrideConfig | undefined {
1430
1522
  const override: BuiltinAgentOverrideConfig = {};
1431
1523
 
@@ -1443,6 +1535,7 @@ export function buildBuiltinOverrideConfig(
1443
1535
  if (draft.thinking !== base.thinking) override.thinking = draft.thinking ?? false;
1444
1536
  if (draft.systemPromptMode !== base.systemPromptMode) override.systemPromptMode = draft.systemPromptMode;
1445
1537
  if (draft.inheritProjectContext !== base.inheritProjectContext) override.inheritProjectContext = draft.inheritProjectContext;
1538
+ if (draft.inheritGlobalContext !== base.inheritGlobalContext) override.inheritGlobalContext = draft.inheritGlobalContext;
1446
1539
  if (draft.inheritSkills !== base.inheritSkills) override.inheritSkills = draft.inheritSkills;
1447
1540
  if (draft.defaultContext !== base.defaultContext) override.defaultContext = draft.defaultContext ?? false;
1448
1541
  if (draft.acceptanceRole !== base.acceptanceRole) override.acceptanceRole = draft.acceptanceRole ?? false;
@@ -1457,6 +1550,7 @@ export function buildBuiltinOverrideConfig(
1457
1550
  if (!arraysEqual(draft.subagentOnlyExtensions, base.subagentOnlyExtensions)) {
1458
1551
  override.subagentOnlyExtensions = draft.subagentOnlyExtensions ? [...draft.subagentOnlyExtensions] : false;
1459
1552
  }
1553
+ if (!arraysEqual(draft.mutationTools, base.mutationTools)) override.mutationTools = draft.mutationTools ? [...draft.mutationTools] : false;
1460
1554
  if ((draft.completionGuard !== false) !== (base.completionGuard !== false)) {
1461
1555
  override.completionGuard = draft.completionGuard !== false;
1462
1556
  }
@@ -1598,9 +1692,22 @@ function shouldPruneDiscoveryDir(rootDir: string, dir: string, dirName: string):
1598
1692
  return path.resolve(dir) !== path.resolve(rootDir) && isDiscoveryNestedProjectRoot(dir);
1599
1693
  }
1600
1694
 
1601
- function listFilesRecursive(dir: string, predicate: (fileName: string) => boolean, rootDir = dir): string[] {
1695
+ function listFilesRecursive(
1696
+ dir: string,
1697
+ predicate: (fileName: string) => boolean,
1698
+ rootDir = dir,
1699
+ visitedDirectories = new Set<string>(),
1700
+ ): string[] {
1602
1701
  const files: string[] = [];
1603
1702
  if (!fs.existsSync(dir)) return files;
1703
+ let realDir: string;
1704
+ try {
1705
+ realDir = fs.realpathSync(dir);
1706
+ } catch {
1707
+ return files;
1708
+ }
1709
+ if (visitedDirectories.has(realDir)) return files;
1710
+ visitedDirectories.add(realDir);
1604
1711
 
1605
1712
  let entries: fs.Dirent[];
1606
1713
  try {
@@ -1611,9 +1718,17 @@ function listFilesRecursive(dir: string, predicate: (fileName: string) => boolea
1611
1718
 
1612
1719
  for (const entry of entries) {
1613
1720
  const filePath = path.join(dir, entry.name);
1614
- if (entry.isDirectory()) {
1721
+ let isDirectory = entry.isDirectory();
1722
+ if (entry.isSymbolicLink()) {
1723
+ try {
1724
+ isDirectory = fs.statSync(filePath).isDirectory();
1725
+ } catch {
1726
+ isDirectory = false;
1727
+ }
1728
+ }
1729
+ if (isDirectory) {
1615
1730
  if (!shouldPruneDiscoveryDir(rootDir, filePath, entry.name)) {
1616
- files.push(...listFilesRecursive(filePath, predicate, rootDir));
1731
+ files.push(...listFilesRecursive(filePath, predicate, rootDir, visitedDirectories));
1617
1732
  }
1618
1733
  continue;
1619
1734
  }
@@ -1624,6 +1739,81 @@ function listFilesRecursive(dir: string, predicate: (fileName: string) => boolea
1624
1739
  return files;
1625
1740
  }
1626
1741
 
1742
+ export interface AgentDefinitionInspection {
1743
+ files: string[];
1744
+ state: AgentDefinitionDirectoryState;
1745
+ }
1746
+
1747
+ /** Narrow filesystem seam so unavailable paths can be tested without permissions. */
1748
+ export interface AgentDefinitionInspectionFs {
1749
+ existsSync(filePath: string): boolean;
1750
+ realpathSync?(filePath: string): string;
1751
+ statSync(filePath: string): { isDirectory(): boolean };
1752
+ readdirSync(dir: string): fs.Dirent[];
1753
+ }
1754
+
1755
+ const DEFAULT_AGENT_DEFINITION_INSPECTION_FS: AgentDefinitionInspectionFs = {
1756
+ existsSync: fs.existsSync,
1757
+ realpathSync: fs.realpathSync,
1758
+ statSync: fs.statSync,
1759
+ readdirSync: (dir) => fs.readdirSync(dir, { withFileTypes: true }),
1760
+ };
1761
+
1762
+ /**
1763
+ * Inspect one agent-definition directory while retaining traversal failure
1764
+ * state. A nested unreadable directory makes the whole inspection unavailable,
1765
+ * preventing a partial traversal from being reported as empty or complete.
1766
+ */
1767
+ export function inspectAgentDefinitionDirectory(dir: string, operations: AgentDefinitionInspectionFs = DEFAULT_AGENT_DEFINITION_INSPECTION_FS): AgentDefinitionInspection {
1768
+ const root = path.resolve(dir);
1769
+ try {
1770
+ if (!operations.existsSync(root)) return { files: [], state: "absent" };
1771
+ if (!operations.statSync(root).isDirectory()) return { files: [], state: "not-directory" };
1772
+ } catch {
1773
+ return { files: [], state: "unreadable" };
1774
+ }
1775
+ const files: string[] = [];
1776
+ let unreadable = false;
1777
+ const visitedDirectories = new Set<string>();
1778
+ const visit = (current: string): void => {
1779
+ let realDir: string;
1780
+ try {
1781
+ realDir = operations.realpathSync?.(current) ?? path.resolve(current);
1782
+ } catch {
1783
+ unreadable = true;
1784
+ return;
1785
+ }
1786
+ if (visitedDirectories.has(realDir)) return;
1787
+ visitedDirectories.add(realDir);
1788
+
1789
+ let entries: fs.Dirent[];
1790
+ try {
1791
+ entries = operations.readdirSync(current).sort((a, b) => a.name.localeCompare(b.name));
1792
+ } catch {
1793
+ unreadable = true;
1794
+ return;
1795
+ }
1796
+ for (const entry of entries) {
1797
+ const filePath = path.join(current, entry.name);
1798
+ let isDirectory = entry.isDirectory();
1799
+ if (entry.isSymbolicLink()) {
1800
+ try {
1801
+ isDirectory = operations.statSync(filePath).isDirectory();
1802
+ } catch {
1803
+ isDirectory = false;
1804
+ }
1805
+ }
1806
+ if (isDirectory) {
1807
+ if (!shouldPruneDiscoveryDir(root, filePath, entry.name)) visit(filePath);
1808
+ continue;
1809
+ }
1810
+ if ((entry.isFile() || entry.isSymbolicLink()) && entry.name.endsWith(".md") && !entry.name.endsWith(".chain.md") && !isLegacyAgentSkillPath(root, filePath)) files.push(filePath);
1811
+ }
1812
+ };
1813
+ visit(root);
1814
+ return { files, state: unreadable ? "unreadable" : files.length ? "candidates" : "empty" };
1815
+ }
1816
+
1627
1817
  function isLegacyAgentSkillPath(rootDir: string, filePath: string): boolean {
1628
1818
  const relative = path.relative(rootDir, filePath);
1629
1819
  const parts = relative.split(path.sep).map((part) => part.toLowerCase());
@@ -1682,24 +1872,29 @@ function parseAgentRunnerFrontmatter(raw: string | undefined, agentName: string)
1682
1872
  if (runner.args !== undefined && (!Array.isArray(runner.args) || runner.args.some((arg) => typeof arg !== "string"))) {
1683
1873
  throw new Error(`Agent '${agentName}' external-cli runner args must be an array of strings.`);
1684
1874
  }
1875
+ if (runner.adapter !== undefined && !isCodeOwnedExternalCliAdapterId(runner.adapter)) throw new Error(`Agent '${agentName}' external-cli runner adapter must be ${CODE_OWNED_EXTERNAL_CLI_ADAPTER_LABEL}.`);
1876
+ if (runner.adapter !== undefined && Array.isArray(runner.args) && runner.args.length > 0) throw new Error(`Agent '${agentName}' ${runner.adapter} adapter owns its argv; runner args are not supported.`);
1685
1877
  if (runner.promptDelivery !== undefined && runner.promptDelivery !== "stdin") {
1686
1878
  throw new Error(`Agent '${agentName}' external-cli runner promptDelivery must be 'stdin'.`);
1687
1879
  }
1688
- const supported = new Set(["type", "command", "args", "promptDelivery"]);
1880
+ const capabilities = parseExternalCliCapabilityNarrowing(runner.capabilities, `Agent '${agentName}' external-cli runner capabilities`);
1881
+ const supported = new Set(["type", "adapter", "command", "args", "promptDelivery", "capabilities"]);
1689
1882
  const unknown = Object.keys(runner).filter((key) => !supported.has(key));
1690
1883
  if (unknown.length > 0) throw new Error(`Agent '${agentName}' external-cli runner has unsupported fields: ${unknown.join(", ")}.`);
1691
1884
  const runnerArgs = Array.isArray(runner.args) ? runner.args.filter((arg): arg is string => typeof arg === "string") : undefined;
1692
1885
  return {
1693
1886
  type: "external-cli",
1887
+ ...(isCodeOwnedExternalCliAdapterId(runner.adapter) ? { adapter: runner.adapter } : {}),
1694
1888
  command: runner.command.trim(),
1695
1889
  ...(runnerArgs?.length ? { args: runnerArgs } : {}),
1696
1890
  ...(runner.promptDelivery ? { promptDelivery: "stdin" as const } : {}),
1891
+ ...(capabilities ? { capabilities } : {}),
1697
1892
  };
1698
1893
  }
1699
1894
 
1700
1895
  function validateExternalRunnerProfile(frontmatter: Record<string, string>, agentName: string, runner: AgentRunnerConfig | undefined): void {
1701
1896
  if (runner?.type !== "external-cli" && runner?.type !== "external-job") return;
1702
- const unsupported = ["tools", "model", "fallbackModels", "thinking", "extensions", "subagentOnlyExtensions", "maxSubagentDepth", "completionGuard", "skills", "skill", "skillPath", "toolBudget", "permission", "permissions"]
1897
+ const unsupported = ["tools", "model", "fallbackModels", "thinking", "extensions", "subagentOnlyExtensions", "mutationTools", "maxSubagentDepth", "completionGuard", "skills", "skill", "skillPath", "toolBudget", "permission", "permissions"]
1703
1898
  .filter((field) => frontmatter[field] !== undefined);
1704
1899
  if (unsupported.length > 0) {
1705
1900
  throw new Error(`Agent '${agentName}' uses runner.type='${runner.type}' and declares unsupported Pi-only fields: ${unsupported.join(", ")}.`);
@@ -1724,9 +1919,9 @@ interface AgentDefinitionFile {
1724
1919
  content: string;
1725
1920
  }
1726
1921
 
1727
- function readAgentDefinitionFiles(dir: string): AgentDefinitionFile[] {
1922
+ function readAgentDefinitionFiles(dir: string, inspection = inspectAgentDefinitionDirectory(dir)): AgentDefinitionFile[] {
1728
1923
  const files: AgentDefinitionFile[] = [];
1729
- for (const filePath of listFilesRecursive(dir, (fileName) => fileName.endsWith(".md") && !fileName.endsWith(".chain.md"))) {
1924
+ for (const filePath of inspection.files) {
1730
1925
  if (isLegacyAgentSkillPath(dir, filePath)) {
1731
1926
  continue;
1732
1927
  }
@@ -1783,6 +1978,8 @@ function loadAgentsFromDefinitionFiles(files: AgentDefinitionFile[], source: Age
1783
1978
  const mcpDirectTools = parsedTools.mcpDirectTools ?? [];
1784
1979
  const defaultReads = parseFrontmatterList(frontmatter.defaultReads);
1785
1980
  const aliases = normalizeAgentAliases(parseFrontmatterList(frontmatter.aliases ?? frontmatter.alias), runtimeName);
1981
+ const profileError = validateCodeOwnedProfileRunner({ name: runtimeName, localName, aliases, runner });
1982
+ if (profileError) throw new Error(profileError);
1786
1983
  const skillStr = frontmatter.skill || frontmatter.skills;
1787
1984
  const skills = parseFrontmatterList(skillStr);
1788
1985
  const skillPath = parseFrontmatterList(frontmatter.skillPath);
@@ -1797,6 +1994,7 @@ function loadAgentsFromDefinitionFiles(files: AgentDefinitionFile[], source: Age
1797
1994
  : frontmatter.inheritProjectContext === "false"
1798
1995
  ? false
1799
1996
  : defaultInheritProjectContext(localName);
1997
+ const inheritGlobalContext = frontmatter.inheritGlobalContext === "true";
1800
1998
  const inheritSkills = frontmatter.inheritSkills === "true"
1801
1999
  ? true
1802
2000
  : frontmatter.inheritSkills === "false"
@@ -1850,6 +2048,7 @@ function loadAgentsFromDefinitionFiles(files: AgentDefinitionFile[], source: Age
1850
2048
 
1851
2049
  const extensions = resolveAgentRelativeExtensionPaths(parseFrontmatterList(frontmatter.extensions), filePath);
1852
2050
  const subagentOnlyExtensions = resolveAgentRelativeExtensionPaths(parseFrontmatterList(frontmatter.subagentOnlyExtensions), filePath);
2051
+ const mutationTools = parseFrontmatterList(frontmatter.mutationTools);
1853
2052
  let fast: boolean | undefined;
1854
2053
  if (frontmatter.fast !== undefined) {
1855
2054
  if (frontmatter.fast === "true") fast = true;
@@ -1906,6 +2105,7 @@ function loadAgentsFromDefinitionFiles(files: AgentDefinitionFile[], source: Age
1906
2105
  ...(frontmatter.thinking !== undefined ? { thinking: frontmatter.thinking === "false" ? false : frontmatter.thinking } : {}),
1907
2106
  systemPromptMode,
1908
2107
  inheritProjectContext,
2108
+ inheritGlobalContext,
1909
2109
  inheritSkills,
1910
2110
  ...(defaultContext !== undefined ? { defaultContext } : {}),
1911
2111
  ...(defaultAsync !== undefined ? { defaultAsync } : {}),
@@ -1922,6 +2122,7 @@ function loadAgentsFromDefinitionFiles(files: AgentDefinitionFile[], source: Age
1922
2122
  ...(skillPath?.length ? { skillPath } : {}),
1923
2123
  ...(extensions !== undefined ? { extensions } : {}),
1924
2124
  ...(subagentOnlyExtensions !== undefined ? { subagentOnlyExtensions } : {}),
2125
+ ...(mutationTools?.length ? { mutationTools } : {}),
1925
2126
  ...(frontmatter.output !== undefined ? { output: frontmatter.output } : {}),
1926
2127
  ...(outputMode !== undefined ? { outputMode } : {}),
1927
2128
  ...(defaultReads?.length ? { defaultReads } : {}),
@@ -1944,8 +2145,17 @@ function loadAgentsFromDefinitionFiles(files: AgentDefinitionFile[], source: Age
1944
2145
  return { agents, diagnostics };
1945
2146
  }
1946
2147
 
1947
- function loadAgentsFromDir(dir: string, source: AgentSource, discoveryPriority?: number, packageSource?: Omit<PackageSubagentPath, "dir">): { agents: AgentConfig[]; diagnostics: AgentDiscoveryDiagnostic[] } {
1948
- return loadAgentsFromDefinitionFiles(readAgentDefinitionFiles(dir), source, discoveryPriority, packageSource);
2148
+ function loadAgentsFromDir(dir: string, source: AgentSource, discoveryPriority?: number, packageSource?: Omit<PackageSubagentPath, "dir">, inspection = inspectAgentDefinitionDirectory(dir)): { agents: AgentConfig[]; diagnostics: AgentDiscoveryDiagnostic[] } {
2149
+ return loadAgentsFromDefinitionFiles(readAgentDefinitionFiles(dir, inspection), source, discoveryPriority, packageSource);
2150
+ }
2151
+
2152
+ function reportAgentDefinitionDirectory(source: AgentSource, dir: string, inspection: AgentDefinitionInspection): AgentDefinitionDirectoryReport {
2153
+ return {
2154
+ source,
2155
+ path: path.resolve(dir),
2156
+ state: inspection.state,
2157
+ ...(inspection.state === "candidates" ? { candidateCount: inspection.files.length } : {}),
2158
+ };
1949
2159
  }
1950
2160
 
1951
2161
  function loadChainsFromDir(dir: string, source: AgentSource): { chains: ChainConfig[]; diagnostics: ChainDiscoveryDiagnostic[] } {
@@ -1982,20 +2192,18 @@ function isDirectory(p: string): boolean {
1982
2192
  }
1983
2193
  }
1984
2194
 
1985
- function resolveNearestProjectAgentDirs(cwd: string): { readDirs: string[]; preferredDir: string | null } {
2195
+ function resolveNearestProjectAgentDirs(cwd: string): { readDirs: string[]; candidateDirs: string[]; preferredDir: string | null } {
1986
2196
  const projectRoot = findConfiguredProjectRoot(cwd);
1987
- if (!projectRoot) return { readDirs: [], preferredDir: null };
2197
+ if (!projectRoot) return { readDirs: [], candidateDirs: [], preferredDir: null };
1988
2198
 
1989
2199
  const legacyDir = path.join(projectRoot, ".agents");
1990
2200
  const preferredDir = path.join(getProjectConfigDir(projectRoot), "agents");
2201
+ const candidateDirs = [legacyDir, preferredDir];
1991
2202
  const readDirs: string[] = [];
1992
2203
  if (isDirectory(legacyDir)) readDirs.push(legacyDir);
1993
2204
  if (isDirectory(preferredDir)) readDirs.push(preferredDir);
1994
2205
 
1995
- return {
1996
- readDirs,
1997
- preferredDir,
1998
- };
2206
+ return { readDirs, candidateDirs, preferredDir };
1999
2207
  }
2000
2208
 
2001
2209
  function resolveNearestProjectChainDirs(cwd: string): { readDirs: string[]; preferredDir: string | null } {
@@ -2009,7 +2217,9 @@ function resolveNearestProjectChainDirs(cwd: string): { readDirs: string[]; pref
2009
2217
  };
2010
2218
  }
2011
2219
  const BUILTIN_AGENTS_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..", "agents");
2012
- const BUILTIN_AGENT_DEFINITION_FILES = readAgentDefinitionFiles(BUILTIN_AGENTS_DIR);
2220
+ // Candidate files and inspection state must describe the same cached builtin scan.
2221
+ const BUILTIN_AGENT_DEFINITION_INSPECTION = inspectAgentDefinitionDirectory(BUILTIN_AGENTS_DIR);
2222
+ const BUILTIN_AGENT_DEFINITION_FILES = readAgentDefinitionFiles(BUILTIN_AGENTS_DIR, BUILTIN_AGENT_DEFINITION_INSPECTION);
2013
2223
 
2014
2224
  export const EXTRA_AGENT_DIRS_ENV = "PI_SUBAGENT_EXTRA_AGENT_DIRS";
2015
2225
 
@@ -2028,11 +2238,12 @@ function extraUserAgentDirs(): string[] {
2028
2238
  }
2029
2239
 
2030
2240
  export function discoverAgents(cwd: string, scope: AgentScope): AgentDiscoveryResult {
2241
+ const effectiveCwd = path.resolve(cwd);
2031
2242
  const userDirOld = path.join(getAgentDir(), "agents");
2032
2243
  const userDirNew = path.join(os.homedir(), ".agents");
2033
- const { readDirs: projectAgentDirs, preferredDir: projectAgentsDir } = resolveNearestProjectAgentDirs(cwd);
2244
+ const { readDirs: projectAgentDirs, candidateDirs: projectCandidateDirs, preferredDir: projectAgentsDir } = resolveNearestProjectAgentDirs(effectiveCwd);
2034
2245
  const userSettingsPath = getUserAgentSettingsPath();
2035
- const projectSettingsPath = getProjectAgentSettingsPath(cwd);
2246
+ const projectSettingsPath = getProjectAgentSettingsPath(effectiveCwd);
2036
2247
  const userSettings = scope === "project" ? EMPTY_SUBAGENT_SETTINGS : readSubagentSettings(userSettingsPath);
2037
2248
  const projectSettings = scope === "user" ? EMPTY_SUBAGENT_SETTINGS : readSubagentSettings(projectSettingsPath);
2038
2249
  const defaultProvider = resolveSubagentDefaultProvider(userSettings, projectSettings, projectSettingsPath);
@@ -2041,65 +2252,60 @@ export function discoverAgents(cwd: string, scope: AgentScope): AgentDiscoveryRe
2041
2252
  const maxThinking = resolveSubagentMaxThinking(userSettings, projectSettings, projectSettingsPath);
2042
2253
  const defaultExtensions = resolveSubagentDefaultExtensions(userSettings, projectSettings, projectSettingsPath);
2043
2254
  const modelScope = projectSettings.modelScope ?? userSettings.modelScope;
2044
- const packageSubagentPaths = collectPackageSubagentPaths(cwd, {
2255
+ const packageSubagentPaths = collectPackageSubagentPaths(effectiveCwd, {
2045
2256
  includeUser: scope !== "project",
2046
2257
  includeProject: scope !== "user",
2047
2258
  });
2259
+ const directories: AgentDefinitionDirectoryReport[] = [reportAgentDefinitionDirectory("builtin", BUILTIN_AGENTS_DIR, BUILTIN_AGENT_DEFINITION_INSPECTION)];
2048
2260
 
2049
2261
  const builtinLoaded = loadAgentsFromDefinitionFiles(BUILTIN_AGENT_DEFINITION_FILES, "builtin");
2050
2262
  const builtinAgents = applyBuiltinOverrides(
2051
2263
  applySubagentDefaults(builtinLoaded.agents, defaultModel, defaultProvider, defaultThinking, defaultExtensions),
2052
- userSettings,
2053
- projectSettings,
2054
- userSettingsPath,
2055
- projectSettingsPath,
2264
+ userSettings, projectSettings, userSettingsPath, projectSettingsPath,
2056
2265
  );
2057
2266
 
2058
- const userLoaded = scope === "project" ? [] : [...extraUserAgentDirs(), userDirOld, userDirNew]
2059
- .map((dir, discoveryPriority) => loadAgentsFromDir(dir, "user", discoveryPriority));
2267
+ const userLoaded = scope === "project" ? [] : [...extraUserAgentDirs(), userDirOld, userDirNew].map((dir, discoveryPriority) => {
2268
+ const inspection = inspectAgentDefinitionDirectory(dir);
2269
+ directories.push(reportAgentDefinitionDirectory("user", dir, inspection));
2270
+ return loadAgentsFromDir(dir, "user", discoveryPriority, undefined, inspection);
2271
+ });
2060
2272
  const userAgents = applyCustomAgentOverrides(
2061
2273
  applySubagentDefaults(userLoaded.flatMap((loaded) => loaded.agents), defaultModel, defaultProvider, defaultThinking, defaultExtensions),
2062
- userSettings,
2063
- projectSettings,
2064
- userSettingsPath,
2065
- projectSettingsPath,
2274
+ userSettings, projectSettings, userSettingsPath, projectSettingsPath,
2066
2275
  );
2067
2276
 
2068
- const projectLoaded = scope === "user" ? [] : projectAgentDirs.map((dir) => loadAgentsFromDir(dir, "project", dir === projectAgentsDir ? 1 : 0));
2277
+ // Report both legacy and preferred project definition paths only after the
2278
+ // existing configured-root resolver found a root; never synthesize cwd paths.
2279
+ const projectInspections = scope === "user" ? new Map<string, AgentDefinitionInspection>() : new Map(projectCandidateDirs.map((dir) => [dir, inspectAgentDefinitionDirectory(dir)]));
2280
+ if (scope !== "user") for (const dir of projectCandidateDirs) directories.push(reportAgentDefinitionDirectory("project", dir, projectInspections.get(dir)!));
2281
+ const projectLoaded = scope === "user" ? [] : projectAgentDirs.map((dir) => loadAgentsFromDir(dir, "project", dir === projectAgentsDir ? 1 : 0, undefined, projectInspections.get(dir)!));
2069
2282
  const projectAgents = applyCustomAgentOverrides(
2070
2283
  applySubagentDefaults(projectLoaded.flatMap((loaded) => loaded.agents), defaultModel, defaultProvider, defaultThinking, defaultExtensions),
2071
- userSettings,
2072
- projectSettings,
2073
- userSettingsPath,
2074
- projectSettingsPath,
2284
+ userSettings, projectSettings, userSettingsPath, projectSettingsPath,
2075
2285
  );
2076
- const packageLoaded = packageSubagentPaths.agents.map((entry, index) => loadAgentsFromDir(entry.dir, "package", packageSubagentPaths.agents.length - index, entry));
2286
+
2287
+ const packageLoaded = packageSubagentPaths.agents.map((entry, index) => {
2288
+ const inspection = inspectAgentDefinitionDirectory(entry.dir);
2289
+ directories.push(reportAgentDefinitionDirectory("package", entry.dir, inspection));
2290
+ return loadAgentsFromDir(entry.dir, "package", packageSubagentPaths.agents.length - index, entry, inspection);
2291
+ });
2077
2292
  const packageMap = new Map<string, AgentConfig>();
2078
- for (const loaded of packageLoaded) {
2079
- for (const agent of loaded.agents) {
2080
- if (!packageMap.has(agent.name)) packageMap.set(agent.name, agent);
2081
- }
2082
- }
2293
+ for (const loaded of packageLoaded) for (const agent of loaded.agents) if (!packageMap.has(agent.name)) packageMap.set(agent.name, agent);
2083
2294
  const packageAgents = applyCustomAgentOverrides(
2084
2295
  applySubagentDefaults(Array.from(packageMap.values()), defaultModel, defaultProvider, defaultThinking, defaultExtensions),
2085
- userSettings,
2086
- projectSettings,
2087
- userSettingsPath,
2088
- projectSettingsPath,
2296
+ userSettings, projectSettings, userSettingsPath, projectSettingsPath,
2089
2297
  );
2090
2298
  const agents = applySubagentMaxThinking(
2091
- mergeAgentsForScope(scope, userAgents, projectAgents, builtinAgents, packageAgents)
2092
- .filter((agent) => agent.disabled !== true),
2299
+ mergeAgentsForScope(scope, userAgents, projectAgents, builtinAgents, packageAgents).filter((agent) => agent.disabled !== true),
2093
2300
  maxThinking,
2094
2301
  );
2095
-
2096
2302
  const agentDiagnostics = [
2097
2303
  ...builtinLoaded.diagnostics,
2098
2304
  ...userLoaded.flatMap((loaded) => loaded.diagnostics),
2099
2305
  ...projectLoaded.flatMap((loaded) => loaded.diagnostics),
2100
2306
  ...packageLoaded.flatMap((loaded) => loaded.diagnostics),
2101
2307
  ];
2102
- return { agents, agentDiagnostics, projectAgentsDir, ...(modelScope !== undefined ? { modelScope } : {}), ...(maxThinking !== undefined ? { maxThinking } : {}) };
2308
+ return { agents, agentDiagnostics, projectAgentsDir, cwd: effectiveCwd, scope, directories, ...(modelScope !== undefined ? { modelScope } : {}), ...(maxThinking !== undefined ? { maxThinking } : {}) };
2103
2309
  }
2104
2310
 
2105
2311
  export function discoverAgentsAll(cwd: string): {
@@ -1,5 +1,11 @@
1
1
  export const BUILTIN_AGENT_NAMES = [
2
2
  "advisor",
3
+ "claude-code",
4
+ "claude-code-writer",
5
+ "codex-exec",
6
+ "codex-exec-writer",
7
+ "cursor-agent",
8
+ "cursor-agent-writer",
3
9
  "delegate",
4
10
  "oracle",
5
11
  "researcher",