@agimon-ai/po-team 0.0.0-alpha.2 → 0.0.0-alpha.21

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 (120) hide show
  1. package/LICENSE +166 -5
  2. package/README.md +11 -12
  3. package/dist/{agentDiscovery-Whwzc4dP.cjs → agentDiscovery-DTTlM_LT.cjs} +246 -350
  4. package/dist/agentDiscovery-DTTlM_LT.cjs.map +1 -0
  5. package/dist/{agentDiscovery-ZQlFkKvB.mjs → agentDiscovery-ZNG8iZXV.mjs} +210 -279
  6. package/dist/agentDiscovery-ZNG8iZXV.mjs.map +1 -0
  7. package/dist/apiContracts.cjs +10 -3
  8. package/dist/apiContracts.cjs.map +1 -1
  9. package/dist/apiContracts.d.mts.map +1 -1
  10. package/dist/apiContracts.mjs +10 -3
  11. package/dist/apiContracts.mjs.map +1 -1
  12. package/dist/{externalProcessIpc-ojE0pvw0.cjs → atomicJson-DRT03Ql5.cjs} +155 -21
  13. package/dist/atomicJson-DRT03Ql5.cjs.map +1 -0
  14. package/dist/{externalProcessIpc-C-15lJrB.mjs → atomicJson-VVM1iAPu.mjs} +140 -12
  15. package/dist/atomicJson-VVM1iAPu.mjs.map +1 -0
  16. package/dist/{capabilityCeiling-CF7kAS18.mjs → capabilityCeiling-BaHT9v9S.mjs} +3 -3
  17. package/dist/capabilityCeiling-BaHT9v9S.mjs.map +1 -0
  18. package/dist/{capabilityCeiling-C-Y7H8oC.cjs → capabilityCeiling-CO3ZjYmY.cjs} +3 -3
  19. package/dist/capabilityCeiling-CO3ZjYmY.cjs.map +1 -0
  20. package/dist/capabilityCeiling.cjs +2 -2
  21. package/dist/capabilityCeiling.d.mts +2 -2
  22. package/dist/capabilityCeiling.mjs +2 -2
  23. package/dist/delegation.cjs +1 -1
  24. package/dist/delegation.cjs.map +1 -1
  25. package/dist/delegation.d.mts +1 -1
  26. package/dist/delegation.mjs +1 -1
  27. package/dist/delegation.mjs.map +1 -1
  28. package/dist/delegationApi.cjs +30 -30
  29. package/dist/delegationApi.d.mts +2 -2
  30. package/dist/delegationApi.mjs +1 -2
  31. package/dist/env.cjs +1 -1
  32. package/dist/env.d.mts +1 -1
  33. package/dist/env.mjs +1 -2
  34. package/dist/{environment-DrqhrxG_.mjs → environment-BtvJI2S-.mjs} +3 -3
  35. package/dist/environment-BtvJI2S-.mjs.map +1 -0
  36. package/dist/{environment-ma5oQ7uM.d.mts → environment-Bz1OlWIT.d.mts} +2 -2
  37. package/dist/{environment-ma5oQ7uM.d.mts.map → environment-Bz1OlWIT.d.mts.map} +1 -1
  38. package/dist/{environment-CaCW3SgT.cjs → environment-Cqs7vHJL.cjs} +3 -3
  39. package/dist/environment-Cqs7vHJL.cjs.map +1 -0
  40. package/dist/extensions/native.mjs +34 -12
  41. package/dist/extensions/native.mjs.map +1 -1
  42. package/dist/extensions/server.cjs +990 -786
  43. package/dist/extensions/server.cjs.map +1 -1
  44. package/dist/extensions/server.d.mts +2 -2
  45. package/dist/extensions/server.d.mts.map +1 -1
  46. package/dist/extensions/server.mjs +975 -772
  47. package/dist/extensions/server.mjs.map +1 -1
  48. package/dist/extensions/web.mjs +994 -807
  49. package/dist/extensions/web.mjs.map +1 -1
  50. package/dist/fablePlan.cjs +3 -3
  51. package/dist/fablePlan.d.mts +2 -2
  52. package/dist/fablePlan.mjs +1 -2
  53. package/dist/{fablePlanApi-CZ3uUcMi.d.mts → fablePlanApi-BTNKjLni.d.mts} +6 -6
  54. package/dist/{fablePlanApi-CZ3uUcMi.d.mts.map → fablePlanApi-BTNKjLni.d.mts.map} +1 -1
  55. package/dist/{fablePlanApi-wBu9bRXU.cjs → fablePlanApi-BhI4jnDP.cjs} +12 -12
  56. package/dist/fablePlanApi-BhI4jnDP.cjs.map +1 -0
  57. package/dist/{fablePlanApi-BsHhgVFV.mjs → fablePlanApi-DuMg43Hu.mjs} +5 -5
  58. package/dist/fablePlanApi-DuMg43Hu.mjs.map +1 -0
  59. package/dist/fablePlanApi.cjs +3 -3
  60. package/dist/fablePlanApi.d.mts +2 -2
  61. package/dist/fablePlanApi.mjs +1 -2
  62. package/dist/index.cjs +17 -8
  63. package/dist/index.cjs.map +1 -1
  64. package/dist/index.d.mts +5 -1
  65. package/dist/index.d.mts.map +1 -1
  66. package/dist/index.mjs +15 -5
  67. package/dist/index.mjs.map +1 -1
  68. package/dist/rolldown-runtime-VH7oDXx4.cjs +28 -0
  69. package/dist/runs/background/cliRunnerEntry.cjs +26 -25
  70. package/dist/runs/background/cliRunnerEntry.cjs.map +1 -1
  71. package/dist/runs/background/cliRunnerEntry.mjs +14 -14
  72. package/dist/runs/background/cliRunnerEntry.mjs.map +1 -1
  73. package/dist/runtimeSubagentPolicy.cjs +3 -3
  74. package/dist/runtimeSubagentPolicy.d.mts +2 -2
  75. package/dist/runtimeSubagentPolicy.mjs +1 -2
  76. package/dist/runtimeSubagentTool.cjs +7 -2
  77. package/dist/runtimeSubagentTool.d.mts +1 -1
  78. package/dist/runtimeSubagentTool.mjs +1 -2
  79. package/dist/{subagentPolicy-ALJam4GN.d.mts → subagentPolicy-BE-OZoa-.d.mts} +6 -6
  80. package/dist/subagentPolicy-BE-OZoa-.d.mts.map +1 -0
  81. package/dist/{subagentPolicy-DQRyKDH-.cjs → subagentPolicy-DIpaKHO8.cjs} +8 -8
  82. package/dist/subagentPolicy-DIpaKHO8.cjs.map +1 -0
  83. package/dist/{subagentPolicy-DxjsKeyj.mjs → subagentPolicy-LfcXuqO5.mjs} +5 -5
  84. package/dist/subagentPolicy-LfcXuqO5.mjs.map +1 -0
  85. package/dist/subagentPolicy.cjs +3 -3
  86. package/dist/subagentPolicy.d.mts +2 -2
  87. package/dist/subagentPolicy.mjs +1 -2
  88. package/dist/{subagentTool-Ca2zQXKw.cjs → subagentTool-BueNPGHo.cjs} +5 -16
  89. package/dist/subagentTool-BueNPGHo.cjs.map +1 -0
  90. package/dist/{subagentTool-BTssGLw8.d.mts → subagentTool-UdB3s6Mn.d.mts} +2 -11
  91. package/dist/subagentTool-UdB3s6Mn.d.mts.map +1 -0
  92. package/dist/{subagentTool-WOYrjxgT.mjs → subagentTool-a2oh2v5B.mjs} +5 -16
  93. package/dist/subagentTool-a2oh2v5B.mjs.map +1 -0
  94. package/dist/subagentTool.cjs +7 -2
  95. package/dist/subagentTool.d.mts +1 -1
  96. package/dist/subagentTool.mjs +1 -2
  97. package/dist/teamSnapshot.d.mts +1 -0
  98. package/dist/teamSnapshot.d.mts.map +1 -1
  99. package/dist/teamSnapshot.mjs +1 -2
  100. package/package.json +25 -24
  101. package/dist/agentDiscovery-Whwzc4dP.cjs.map +0 -1
  102. package/dist/agentDiscovery-ZQlFkKvB.mjs.map +0 -1
  103. package/dist/atomicJson-D0346bt5.cjs +0 -178
  104. package/dist/atomicJson-D0346bt5.cjs.map +0 -1
  105. package/dist/atomicJson-D2t0CDh9.mjs +0 -137
  106. package/dist/atomicJson-D2t0CDh9.mjs.map +0 -1
  107. package/dist/capabilityCeiling-C-Y7H8oC.cjs.map +0 -1
  108. package/dist/capabilityCeiling-CF7kAS18.mjs.map +0 -1
  109. package/dist/environment-CaCW3SgT.cjs.map +0 -1
  110. package/dist/environment-DrqhrxG_.mjs.map +0 -1
  111. package/dist/externalProcessIpc-C-15lJrB.mjs.map +0 -1
  112. package/dist/externalProcessIpc-ojE0pvw0.cjs.map +0 -1
  113. package/dist/fablePlanApi-BsHhgVFV.mjs.map +0 -1
  114. package/dist/fablePlanApi-wBu9bRXU.cjs.map +0 -1
  115. package/dist/subagentPolicy-ALJam4GN.d.mts.map +0 -1
  116. package/dist/subagentPolicy-DQRyKDH-.cjs.map +0 -1
  117. package/dist/subagentPolicy-DxjsKeyj.mjs.map +0 -1
  118. package/dist/subagentTool-BTssGLw8.d.mts.map +0 -1
  119. package/dist/subagentTool-Ca2zQXKw.cjs.map +0 -1
  120. package/dist/subagentTool-WOYrjxgT.mjs.map +0 -1
@@ -1,85 +1,8 @@
1
- import "./atomicJson-D2t0CDh9.mjs";
2
- import * as fs from "node:fs";
3
1
  import * as path from "node:path";
4
- import { loadHarnessState, loadMajorModesConfig, resolvePackageConfigurations } from "@agimon-ai/po-config";
2
+ import { getOrThrow, readTextIfExists } from "@agimon-ai/po-core/platform";
3
+ import * as fs from "node:fs";
5
4
  import * as os from "node:os";
6
5
  import { piAgentDirectory } from "@agimon-ai/po-core/piSettings";
7
- //#region src/schemas/team/packageConfig.ts
8
- const PO_TEAM_PACKAGE = "@agimon-ai/po-team";
9
- const TEAM_CONFIG_KEYS = ["models", "excludeTools"];
10
- const TEAM_MODEL_KEYS = ["model", "thinking"];
11
- const THINKING_VALUES = /* @__PURE__ */ new Set([
12
- "off",
13
- "minimal",
14
- "low",
15
- "medium",
16
- "high",
17
- "xhigh",
18
- "max"
19
- ]);
20
- function isRecord(value) {
21
- return typeof value === "object" && value !== null && !Array.isArray(value);
22
- }
23
- function assertKnownKeys(value, keys, location) {
24
- const unsupported = Object.keys(value).filter((key) => !keys.includes(key));
25
- if (unsupported.length > 0) throw new Error(`${location} has unsupported field(s): ${unsupported.join(", ")}`);
26
- }
27
- /** Validate and normalize one Team-owned package configuration mapping. */
28
- function parseTeamPackageConfig(value, location) {
29
- if (!isRecord(value)) throw new Error(`${location} must be a mapping`);
30
- assertKnownKeys(value, TEAM_CONFIG_KEYS, location);
31
- const hasModels = Object.hasOwn(value, "models");
32
- const hasExcludeTools = Object.hasOwn(value, "excludeTools");
33
- if (!hasModels && !hasExcludeTools) throw new Error(`${location} must define models or excludeTools`);
34
- let models;
35
- if (hasModels) {
36
- if (!Array.isArray(value.models) || value.models.length === 0) throw new Error(`${location}.models must be a non-empty array`);
37
- models = value.models.map((entry, index) => {
38
- const entryLocation = `${location}.models[${index}]`;
39
- if (!isRecord(entry)) throw new Error(`${entryLocation} must be a mapping`);
40
- assertKnownKeys(entry, TEAM_MODEL_KEYS, entryLocation);
41
- if (typeof entry.model !== "string" || !entry.model.trim()) throw new Error(`${entryLocation}.model must be a non-empty string`);
42
- if (entry.thinking !== void 0 && (typeof entry.thinking !== "string" || !THINKING_VALUES.has(entry.thinking))) throw new Error(`${entryLocation}.thinking must be one of: ${[...THINKING_VALUES].join(", ")}`);
43
- return {
44
- model: entry.model.trim(),
45
- ...entry.thinking ? { thinking: entry.thinking } : {}
46
- };
47
- });
48
- }
49
- let excludeTools;
50
- if (hasExcludeTools) {
51
- if (!Array.isArray(value.excludeTools) || value.excludeTools.length === 0) throw new Error(`${location}.excludeTools must be a non-empty array`);
52
- excludeTools = [...new Set(value.excludeTools.map((entry, index) => {
53
- if (typeof entry !== "string" || !entry.trim()) throw new Error(`${location}.excludeTools[${index}] must be a non-empty string`);
54
- return entry.trim();
55
- }))];
56
- }
57
- return {
58
- ...models ? { models } : {},
59
- ...excludeTools ? { excludeTools } : {}
60
- };
61
- }
62
- /** Merge Team configurations contributed by selected layers in selection order. */
63
- function mergeTeamPackageConfigurations(entries) {
64
- let models;
65
- const excludeTools = /* @__PURE__ */ new Set();
66
- let hasExcludeTools = false;
67
- for (const entry of entries) {
68
- const location = `Package "${entry.specifier}" config in layer "${entry.layer}" of .po/modes.yaml`;
69
- const next = parseTeamPackageConfig(entry.config, location);
70
- if (next.models) models = next.models.map((model) => ({ ...model }));
71
- if (next.excludeTools) {
72
- hasExcludeTools = true;
73
- for (const tool of next.excludeTools) excludeTools.add(tool);
74
- }
75
- }
76
- if (!models && !hasExcludeTools) return void 0;
77
- return {
78
- ...models ? { models } : {},
79
- ...hasExcludeTools ? { excludeTools: [...excludeTools] } : {}
80
- };
81
- }
82
- //#endregion
83
6
  //#region src/services/agentFrontmatter/index.ts
84
7
  /**
85
8
  * Parsing the YAML frontmatter block at the head of an agent or chain file.
@@ -309,29 +232,105 @@ function getConfigDirName(environment = process.env) {
309
232
  function getProjectConfigDir(projectRoot, environment = process.env) {
310
233
  return path.join(projectRoot, getConfigDirName(environment));
311
234
  }
312
- /** Read a JSON settings file as an object, retaining strict path-specific errors. */
313
- function readSettingsFileStrict(filePath) {
314
- if (!fs.existsSync(filePath)) return {};
315
- let raw;
235
+ /** The user-level agent directory Po runs with, from Po's own resolver. */
236
+ function getAgentDir(environment = process.env) {
237
+ return piAgentDirectory(environment, environment.HOME ?? os.homedir());
238
+ }
239
+ //#endregion
240
+ //#region src/services/agentProjectRoot/sync.ts
241
+ /** @deprecated Node-only shim. */
242
+ /**
243
+ * Locating the project root that agent configuration hangs off.
244
+ *
245
+ * A project root is any ancestor of the working directory that carries a config
246
+ * directory or a legacy `.agents` directory. There can be several: a package
247
+ * inside a monorepo and the monorepo itself both qualify. Which one wins is a
248
+ * setting, because both answers are legitimate. Teams that keep one shared set
249
+ * of agents at the repository root want `git-root`, teams that give each package
250
+ * its own want `nearest`, and neither can be inferred from the tree alone.
251
+ *
252
+ * DESIGN PATTERNS:
253
+ * - Candidates are collected once, nearest first, then a policy picks from them.
254
+ * Separating collection from policy is what lets `git-root` be answered
255
+ * without a second walk
256
+ * - Path derivation goes through `shared/configDir.ts`, so a rebranded build
257
+ * that renames its config directory needs no change here
258
+ *
259
+ * AVOID:
260
+ * - Hardcoding the config directory name; it is discovered, not assumed
261
+ * - Treating the nearest candidate as the project root without reading the
262
+ * setting first
263
+ */
264
+ /** Stable cache identity for equivalent absolute, relative, and symlinked cwd spellings. */
265
+ function canonicalizeDiscoveryCwd$1(cwd) {
266
+ const resolved = path.resolve(cwd);
316
267
  try {
317
- raw = fs.readFileSync(filePath, "utf-8");
318
- } catch (error) {
319
- const message = error instanceof Error ? error.message : String(error);
320
- throw new Error(`Failed to read settings file '${filePath}': ${message}`, { cause: error });
268
+ return fs.realpathSync.native(resolved);
269
+ } catch {
270
+ return resolved;
321
271
  }
322
- let parsed;
323
- try {
324
- parsed = JSON.parse(raw);
325
- } catch (error) {
326
- const message = error instanceof Error ? error.message : String(error);
327
- throw new Error(`Failed to parse settings file '${filePath}': ${message}`, { cause: error });
272
+ }
273
+ //#endregion
274
+ //#region src/services/agentMemory/index.ts
275
+ /** Tools that let an agent append to its own memory file. */
276
+ const WRITE_TOOLS = /* @__PURE__ */ new Set([
277
+ "edit",
278
+ "write",
279
+ "bash"
280
+ ]);
281
+ function unquoteFrontmatterValue(value) {
282
+ const trimmed = value.trim();
283
+ if (trimmed.startsWith("\"") && trimmed.endsWith("\"") || trimmed.startsWith("'") && trimmed.endsWith("'")) return trimmed.slice(1, -1);
284
+ return trimmed;
285
+ }
286
+ function parseMemoryScope(value) {
287
+ return value === "project" || value === "user" ? value : void 0;
288
+ }
289
+ function parseMemoryBoolean(value) {
290
+ if (value === "true") return true;
291
+ if (value === "false") return false;
292
+ }
293
+ function parsePositiveInteger(value) {
294
+ if (value === void 0) return void 0;
295
+ const parsed = Number(value);
296
+ return Number.isInteger(parsed) && parsed > 0 ? parsed : void 0;
297
+ }
298
+ /** Split a `memory` frontmatter block into key/value pairs, either spelling. */
299
+ function readMemoryEntries(raw) {
300
+ const entries = /* @__PURE__ */ new Map();
301
+ const inlineObject = raw.trim().match(/^\{(.*)\}$/s);
302
+ const parts = inlineObject?.[1] !== void 0 ? inlineObject[1].split(",") : raw.split("\n");
303
+ for (const part of parts) {
304
+ const match = part.trim().match(/^([\w-]+)\s*:\s*(.*)$/);
305
+ if (!match?.[1] || match[2] === void 0) continue;
306
+ entries.set(match[1], unquoteFrontmatterValue(match[2]));
328
307
  }
329
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error(`Settings file '${filePath}' must contain a JSON object.`);
330
- return parsed;
308
+ return entries;
331
309
  }
332
- /** The user-level agent directory Po runs with, from Po's own resolver. */
333
- function getAgentDir(environment = process.env) {
334
- return piAgentDirectory(environment, environment.HOME ?? os.homedir());
310
+ /**
311
+ * Parse a `memory` frontmatter block, or undefined when it declares nothing.
312
+ *
313
+ * Accepts both the inline `{ scope: project }` form and the indented block form,
314
+ * because agent files in the wild use each.
315
+ */
316
+ function parseMemoryFrontmatter(raw) {
317
+ if (!raw) return void 0;
318
+ const entries = readMemoryEntries(raw);
319
+ const enabled = parseMemoryBoolean(entries.get("enabled"));
320
+ const scope = parseMemoryScope(entries.get("scope"));
321
+ const maxEntries = parsePositiveInteger(entries.get("maxEntries"));
322
+ if (enabled === void 0 && scope === void 0 && maxEntries === void 0) return void 0;
323
+ const config = {};
324
+ if (enabled !== void 0) config.enabled = enabled;
325
+ if (scope !== void 0) config.scope = scope;
326
+ if (maxEntries !== void 0) config.maxEntries = maxEntries;
327
+ return config;
328
+ }
329
+ /** Whether an agent can write files this run. An unset `tools` inherits the builtins. */
330
+ function agentHasWriteTools(agent) {
331
+ const tools = agent.tools;
332
+ if (!tools) return true;
333
+ return tools.some((tool) => WRITE_TOOLS.has(tool));
335
334
  }
336
335
  //#endregion
337
336
  //#region src/services/agentProjectRoot/index.ts
@@ -349,7 +348,7 @@ function getAgentDir(environment = process.env) {
349
348
  * - Candidates are collected once, nearest first, then a policy picks from them.
350
349
  * Separating collection from policy is what lets `git-root` be answered
351
350
  * without a second walk
352
- * - Path derivation goes through `shared/configDir.ts`, so a rebranded build
351
+ * - Path derivation uses injected directory settings, so a rebranded build
353
352
  * that renames its config directory needs no change here
354
353
  *
355
354
  * AVOID:
@@ -357,6 +356,25 @@ function getAgentDir(environment = process.env) {
357
356
  * - Treating the nearest candidate as the project root without reading the
358
357
  * setting first
359
358
  */
359
+ async function readSettingsFile(io, filePath) {
360
+ let raw;
361
+ try {
362
+ raw = await readTextIfExists(io.fs, filePath, io.context);
363
+ } catch (error) {
364
+ const message = error instanceof Error ? error.message : String(error);
365
+ throw new Error(`Failed to read settings file '${filePath}': ${message}`, { cause: error });
366
+ }
367
+ if (raw === void 0) return {};
368
+ let parsed;
369
+ try {
370
+ parsed = JSON.parse(raw);
371
+ } catch (error) {
372
+ const message = error instanceof Error ? error.message : String(error);
373
+ throw new Error(`Failed to parse settings file '${filePath}': ${message}`, { cause: error });
374
+ }
375
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error(`Settings file '${filePath}' must contain a JSON object.`);
376
+ return parsed;
377
+ }
360
378
  const SETTINGS_FILE_NAME = "settings.json";
361
379
  const GIT_DIR_NAME$1 = ".git";
362
380
  /**
@@ -370,32 +388,33 @@ const AGENTS_DIR_NAME = "agents";
370
388
  const SUBAGENTS_SETTINGS_KEY$1 = "subagents";
371
389
  const PROJECT_ROOT_RESOLUTION_KEY = "projectRootResolution";
372
390
  /** Stable cache identity for equivalent absolute, relative, and symlinked cwd spellings. */
373
- function canonicalizeDiscoveryCwd(cwd) {
391
+ async function canonicalizeDiscoveryCwd(io, cwd) {
374
392
  const resolved = path.resolve(cwd);
375
393
  try {
376
- return fs.realpathSync.native(resolved);
394
+ return getOrThrow(await io.fs.canonicalPath(resolved, io.context));
377
395
  } catch {
378
396
  return resolved;
379
397
  }
380
398
  }
381
399
  /** Whether a path exists and is a directory. Any failure reads as "no". */
382
- function isDirectory$1(dirPath) {
400
+ async function isDirectory(io, dirPath) {
383
401
  try {
384
- return fs.statSync(dirPath).isDirectory();
402
+ const canonical = getOrThrow(await io.fs.canonicalPath(dirPath, io.context));
403
+ return getOrThrow(await io.fs.fileInfo(canonical, io.context)).kind === "directory";
385
404
  } catch {
386
405
  return false;
387
406
  }
388
407
  }
389
408
  /** True when `dir` carries either marker that makes it a project root. */
390
- function isProjectRootCandidate(dir, environment = process.env) {
391
- return isDirectory$1(getProjectConfigDir(dir, environment)) || isDirectory$1(path.join(dir, DOT_AGENTS_DIR_NAME));
409
+ async function isProjectRootCandidate(io, dir) {
410
+ return await isDirectory(io, path.join(dir, io.configDirName)) || await isDirectory(io, path.join(dir, DOT_AGENTS_DIR_NAME));
392
411
  }
393
412
  /** Every project root above `cwd`, nearest first. */
394
- function findProjectRootCandidates(cwd, environment = process.env) {
413
+ async function findProjectRootCandidates(io, cwd) {
395
414
  const roots = [];
396
415
  let currentDir = cwd;
397
416
  while (true) {
398
- if (isProjectRootCandidate(currentDir, environment)) roots.push(currentDir);
417
+ if (await isProjectRootCandidate(io, currentDir)) roots.push(currentDir);
399
418
  const parentDir = path.dirname(currentDir);
400
419
  if (parentDir === currentDir) return roots;
401
420
  currentDir = parentDir;
@@ -407,10 +426,11 @@ function findProjectRootCandidates(cwd, environment = process.env) {
407
426
  * Existence is enough: a worktree or submodule has a `.git` file rather than a
408
427
  * directory, and both are real repository roots.
409
428
  */
410
- function findNearestGitRoot(cwd) {
429
+ async function findNearestGitRoot(io, cwd) {
411
430
  let currentDir = cwd;
412
431
  while (true) {
413
- if (fs.existsSync(path.join(currentDir, GIT_DIR_NAME$1))) return currentDir;
432
+ const gitMarker = await io.fs.exists(path.join(currentDir, GIT_DIR_NAME$1), io.context);
433
+ if (gitMarker.ok && gitMarker.value) return currentDir;
414
434
  const parentDir = path.dirname(currentDir);
415
435
  if (parentDir === currentDir) return null;
416
436
  currentDir = parentDir;
@@ -422,10 +442,9 @@ function findNearestGitRoot(cwd) {
422
442
  * Deliberately throws on an unrecognised value rather than falling back: a typo
423
443
  * here silently changes which agents the whole session sees.
424
444
  */
425
- function readProjectRootResolution(projectRoot, environment = process.env) {
426
- const settingsPath = path.join(getProjectConfigDir(projectRoot, environment), SETTINGS_FILE_NAME);
427
- if (!fs.existsSync(settingsPath)) return void 0;
428
- const subagents = readSettingsFileStrict(settingsPath)[SUBAGENTS_SETTINGS_KEY$1];
445
+ async function readProjectRootResolution(io, projectRoot) {
446
+ const settingsPath = path.join(projectRoot, io.configDirName, SETTINGS_FILE_NAME);
447
+ const subagents = (await readSettingsFile(io, settingsPath))[SUBAGENTS_SETTINGS_KEY$1];
429
448
  if (!subagents || typeof subagents !== "object" || Array.isArray(subagents)) return void 0;
430
449
  const value = subagents[PROJECT_ROOT_RESOLUTION_KEY];
431
450
  if (value === void 0) return void 0;
@@ -439,15 +458,15 @@ function readProjectRootResolution(projectRoot, environment = process.env) {
439
458
  * of its monorepo's shared agents, and from the git root second so a repository
440
459
  * can claim its packages without editing each one.
441
460
  */
442
- function findConfiguredProjectRoot(cwd, environment = process.env) {
443
- const candidates = findProjectRootCandidates(cwd, environment);
461
+ async function findConfiguredProjectRoot(io, cwd) {
462
+ const candidates = await findProjectRootCandidates(io, cwd);
444
463
  const nearestRoot = candidates[0];
445
464
  if (!nearestRoot) return null;
446
- const nearestMode = readProjectRootResolution(nearestRoot, environment);
465
+ const nearestMode = await readProjectRootResolution(io, nearestRoot);
447
466
  if (nearestMode === "nearest") return nearestRoot;
448
- const gitRoot = findNearestGitRoot(cwd);
467
+ const gitRoot = await findNearestGitRoot(io, cwd);
449
468
  const gitProjectRoot = gitRoot ? candidates.find((candidate) => path.resolve(candidate) === path.resolve(gitRoot)) : void 0;
450
- if (gitProjectRoot && (nearestMode === "git-root" || readProjectRootResolution(gitProjectRoot, environment) === "git-root")) return gitProjectRoot;
469
+ if (gitProjectRoot && (nearestMode === "git-root" || await readProjectRootResolution(io, gitProjectRoot) === "git-root")) return gitProjectRoot;
451
470
  return nearestRoot;
452
471
  }
453
472
  /**
@@ -458,17 +477,17 @@ function findConfiguredProjectRoot(cwd, environment = process.env) {
458
477
  * working after the move. Returned unfiltered because the caller reads each
459
478
  * directory anyway and a missing one costs nothing.
460
479
  */
461
- function userAgentDirs(environment = process.env) {
462
- return [path.join(getAgentDir(environment), AGENTS_DIR_NAME), path.join(environment.HOME ?? os.homedir(), DOT_AGENTS_DIR_NAME)];
480
+ function userAgentDirs(io) {
481
+ return [path.join(piAgentDirectory(io.environment, io.homeDirectory), AGENTS_DIR_NAME), path.join(io.homeDirectory, DOT_AGENTS_DIR_NAME)];
463
482
  }
464
483
  /** The user-level settings file. Always resolvable, unlike the project one. */
465
- function getUserAgentSettingsPath(environment = process.env) {
466
- return path.join(getAgentDir(environment), SETTINGS_FILE_NAME);
484
+ function getUserAgentSettingsPath(io) {
485
+ return path.join(piAgentDirectory(io.environment, io.homeDirectory), SETTINGS_FILE_NAME);
467
486
  }
468
487
  /** The project settings file, or null when `cwd` sits under no project root. */
469
- function getProjectAgentSettingsPath(cwd, environment = process.env) {
470
- const projectRoot = findConfiguredProjectRoot(cwd, environment);
471
- return projectRoot ? path.join(getProjectConfigDir(projectRoot, environment), SETTINGS_FILE_NAME) : null;
488
+ async function getProjectAgentSettingsPath(io, cwd) {
489
+ const projectRoot = await findConfiguredProjectRoot(io, cwd);
490
+ return projectRoot ? path.join(projectRoot, io.configDirName, SETTINGS_FILE_NAME) : null;
472
491
  }
473
492
  /**
474
493
  * Project agent directories for `cwd`.
@@ -478,85 +497,23 @@ function getProjectAgentSettingsPath(cwd, environment = process.env) {
478
497
  * `preferredDir` is where a newly created agent should be written, and is
479
498
  * returned whether or not it exists yet.
480
499
  */
481
- function resolveNearestProjectAgentDirs(cwd, environment = process.env) {
482
- const projectRoot = findConfiguredProjectRoot(cwd, environment);
500
+ async function resolveNearestProjectAgentDirs(io, cwd) {
501
+ const projectRoot = await findConfiguredProjectRoot(io, cwd);
483
502
  if (!projectRoot) return {
484
503
  readDirs: [],
485
504
  preferredDir: null
486
505
  };
487
506
  const legacyDir = path.join(projectRoot, DOT_AGENTS_DIR_NAME);
488
- const preferredDir = path.join(getProjectConfigDir(projectRoot, environment), AGENTS_DIR_NAME);
507
+ const preferredDir = path.join(projectRoot, io.configDirName, AGENTS_DIR_NAME);
489
508
  const readDirs = [];
490
- if (isDirectory$1(legacyDir)) readDirs.push(legacyDir);
491
- if (isDirectory$1(preferredDir)) readDirs.push(preferredDir);
509
+ if (await isDirectory(io, legacyDir)) readDirs.push(legacyDir);
510
+ if (await isDirectory(io, preferredDir)) readDirs.push(preferredDir);
492
511
  return {
493
512
  readDirs,
494
513
  preferredDir
495
514
  };
496
515
  }
497
516
  //#endregion
498
- //#region src/services/agentMemory/index.ts
499
- /** Tools that let an agent append to its own memory file. */
500
- const WRITE_TOOLS = /* @__PURE__ */ new Set([
501
- "edit",
502
- "write",
503
- "bash"
504
- ]);
505
- function unquoteFrontmatterValue(value) {
506
- const trimmed = value.trim();
507
- if (trimmed.startsWith("\"") && trimmed.endsWith("\"") || trimmed.startsWith("'") && trimmed.endsWith("'")) return trimmed.slice(1, -1);
508
- return trimmed;
509
- }
510
- function parseMemoryScope(value) {
511
- return value === "project" || value === "user" ? value : void 0;
512
- }
513
- function parseMemoryBoolean(value) {
514
- if (value === "true") return true;
515
- if (value === "false") return false;
516
- }
517
- function parsePositiveInteger(value) {
518
- if (value === void 0) return void 0;
519
- const parsed = Number(value);
520
- return Number.isInteger(parsed) && parsed > 0 ? parsed : void 0;
521
- }
522
- /** Split a `memory` frontmatter block into key/value pairs, either spelling. */
523
- function readMemoryEntries(raw) {
524
- const entries = /* @__PURE__ */ new Map();
525
- const inlineObject = raw.trim().match(/^\{(.*)\}$/s);
526
- const parts = inlineObject?.[1] !== void 0 ? inlineObject[1].split(",") : raw.split("\n");
527
- for (const part of parts) {
528
- const match = part.trim().match(/^([\w-]+)\s*:\s*(.*)$/);
529
- if (!match?.[1] || match[2] === void 0) continue;
530
- entries.set(match[1], unquoteFrontmatterValue(match[2]));
531
- }
532
- return entries;
533
- }
534
- /**
535
- * Parse a `memory` frontmatter block, or undefined when it declares nothing.
536
- *
537
- * Accepts both the inline `{ scope: project }` form and the indented block form,
538
- * because agent files in the wild use each.
539
- */
540
- function parseMemoryFrontmatter(raw) {
541
- if (!raw) return void 0;
542
- const entries = readMemoryEntries(raw);
543
- const enabled = parseMemoryBoolean(entries.get("enabled"));
544
- const scope = parseMemoryScope(entries.get("scope"));
545
- const maxEntries = parsePositiveInteger(entries.get("maxEntries"));
546
- if (enabled === void 0 && scope === void 0 && maxEntries === void 0) return void 0;
547
- const config = {};
548
- if (enabled !== void 0) config.enabled = enabled;
549
- if (scope !== void 0) config.scope = scope;
550
- if (maxEntries !== void 0) config.maxEntries = maxEntries;
551
- return config;
552
- }
553
- /** Whether an agent can write files this run. An unset `tools` inherits the builtins. */
554
- function agentHasWriteTools(agent) {
555
- const tools = agent.tools;
556
- if (!tools) return true;
557
- return tools.some((tool) => WRITE_TOOLS.has(tool));
558
- }
559
- //#endregion
560
517
  //#region src/services/agentSettings/index.ts
561
518
  const SUBAGENTS_SETTINGS_KEY = "subagents";
562
519
  const AGENT_OVERRIDES_KEY = "agentOverrides";
@@ -748,9 +705,9 @@ function parseToolBudgetOverride(value, name, filePath) {
748
705
  return budget;
749
706
  }
750
707
  /** Read and validate one settings file's `subagents` block. */
751
- function readSubagentSettings(filePath) {
708
+ async function readSubagentSettings(io, filePath) {
752
709
  if (!filePath) return EMPTY_SUBAGENT_SETTINGS;
753
- const subagentsObject = readObjectField(readSettingsFileStrict(filePath), SUBAGENTS_SETTINGS_KEY);
710
+ const subagentsObject = readObjectField(await readSettingsFile(io, filePath), SUBAGENTS_SETTINGS_KEY);
754
711
  if (!subagentsObject) return EMPTY_SUBAGENT_SETTINGS;
755
712
  let disableBuiltins;
756
713
  if ("disableBuiltins" in subagentsObject) {
@@ -1116,16 +1073,9 @@ const LEGACY_AGENTS_DIR_NAME = ".agents";
1116
1073
  const LEGACY_SKILLS_DIR_NAME = "skills";
1117
1074
  const AGENT_FILE_EXTENSION = ".md";
1118
1075
  const CHAIN_FILE_EXTENSION = ".chain.md";
1119
- function isDirectory(target) {
1120
- try {
1121
- return fs.statSync(target).isDirectory();
1122
- } catch {
1123
- return false;
1124
- }
1125
- }
1126
1076
  /** A directory that owns its own agent configuration is a separate project. */
1127
- function isDiscoveryNestedProjectRoot(dir, environment) {
1128
- return isDirectory(getProjectConfigDir(dir, environment)) || isDirectory(path.join(dir, LEGACY_AGENTS_DIR_NAME));
1077
+ async function isDiscoveryNestedProjectRoot(io, dir) {
1078
+ return await isDirectory(io, path.join(dir, io.configDirName)) || await isDirectory(io, path.join(dir, LEGACY_AGENTS_DIR_NAME));
1129
1079
  }
1130
1080
  /**
1131
1081
  * Decide whether the walk should skip a subdirectory.
@@ -1134,10 +1084,11 @@ function isDiscoveryNestedProjectRoot(dir, environment) {
1134
1084
  * belong to that project, not to the one being scanned. The root itself is
1135
1085
  * exempt: scanning a project's own agent directory must not prune it.
1136
1086
  */
1137
- function shouldPruneDiscoveryDir(rootDir, dir, dirName, environment) {
1087
+ async function shouldPruneDiscoveryDir(io, rootDir, dir, dirName) {
1138
1088
  if (DISCOVERY_PRUNED_DIR_NAMES.has(dirName)) return true;
1139
- if (fs.existsSync(path.join(dir, GIT_DIR_NAME))) return true;
1140
- return path.resolve(dir) !== path.resolve(rootDir) && isDiscoveryNestedProjectRoot(dir, environment);
1089
+ const gitMarker = await io.fs.exists(path.join(dir, GIT_DIR_NAME), io.context);
1090
+ if (gitMarker.ok && gitMarker.value) return true;
1091
+ return path.resolve(dir) !== path.resolve(rootDir) && await isDiscoveryNestedProjectRoot(io, dir);
1141
1092
  }
1142
1093
  /**
1143
1094
  * Collect matching files under `dir`, sorted so discovery order is stable.
@@ -1145,24 +1096,19 @@ function shouldPruneDiscoveryDir(rootDir, dir, dirName, environment) {
1145
1096
  * Symlinked entries are followed as files, because staging an agent by symlink
1146
1097
  * is a supported way to share one definition across projects.
1147
1098
  */
1148
- function listFilesRecursive(dir, predicate, rootDir = dir, environment = process.env) {
1099
+ async function listFilesRecursive(io, dir, predicate, rootDir = dir) {
1149
1100
  const files = [];
1150
- if (!fs.existsSync(dir)) return files;
1151
- let entries;
1152
- try {
1153
- entries = fs.readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
1154
- } catch {
1155
- return files;
1156
- }
1101
+ const result = await io.fs.listDir(dir, io.context);
1102
+ if (!result.ok) return files;
1103
+ const entries = result.value.sort((a, b) => a.name.localeCompare(b.name));
1157
1104
  for (const entry of entries) {
1158
1105
  const filePath = path.join(dir, entry.name);
1159
- if (entry.isDirectory()) {
1160
- if (!shouldPruneDiscoveryDir(rootDir, filePath, entry.name, environment)) files.push(...listFilesRecursive(filePath, predicate, rootDir, environment));
1106
+ if (entry.kind === "directory") {
1107
+ if (!await shouldPruneDiscoveryDir(io, rootDir, filePath, entry.name)) files.push(...await listFilesRecursive(io, filePath, predicate, rootDir));
1161
1108
  continue;
1162
1109
  }
1163
- if (!entry.isFile() && !entry.isSymbolicLink()) continue;
1164
- if (!predicate(entry.name)) continue;
1165
- files.push(filePath);
1110
+ if (entry.kind !== "file" && entry.kind !== "symlink") continue;
1111
+ if (predicate(entry.name)) files.push(filePath);
1166
1112
  }
1167
1113
  return files;
1168
1114
  }
@@ -1206,13 +1152,15 @@ function isAgentFileName(fileName) {
1206
1152
  * The returned configs carry only what the file itself declared. Settings
1207
1153
  * defaults, builtin overrides, and cross-source precedence are the caller's job.
1208
1154
  */
1209
- function loadAgentsFromDir(dir, source, environment = process.env) {
1155
+ async function loadAgentsFromDir(io, dir, source) {
1210
1156
  const agents = [];
1211
- for (const filePath of listFilesRecursive(dir, isAgentFileName, dir, environment)) {
1157
+ for (const filePath of await listFilesRecursive(io, dir, isAgentFileName, dir)) {
1212
1158
  if (isLegacyAgentSkillPath(dir, filePath)) continue;
1213
1159
  let content;
1214
1160
  try {
1215
- content = fs.readFileSync(filePath, "utf-8");
1161
+ const text = await readTextIfExists(io.fs, filePath, io.context);
1162
+ if (text === void 0) continue;
1163
+ content = text;
1216
1164
  } catch {
1217
1165
  continue;
1218
1166
  }
@@ -1273,7 +1221,7 @@ function loadAgentsFromDir(dir, source, environment = process.env) {
1273
1221
  * Read from the environment on every call rather than captured once, because a
1274
1222
  * host can stage a plugin directory after this module is first imported.
1275
1223
  */
1276
- function pluginAgentDirs(environment = process.env) {
1224
+ function pluginAgentDirs(environment) {
1277
1225
  return (environment["PI_SUBAGENT_EXTRA_AGENT_DIRS"] ?? "").split(path.delimiter).map((directory) => directory.trim()).filter((directory) => directory.length > 0);
1278
1226
  }
1279
1227
  //#endregion
@@ -1381,8 +1329,6 @@ const MAX_CACHED_DISCOVERIES = 64;
1381
1329
  const FINGERPRINT_FIELD_SEPARATOR = ":";
1382
1330
  const FINGERPRINT_ENTRY_SEPARATOR = "|";
1383
1331
  const MISSING_SOURCE_MARKER = "-";
1384
- const MAJOR_MODES_CONFIG_RELATIVE_PATH = path.join(".po", "modes.yaml");
1385
- const THINKING_SUFFIX = /:(?:off|minimal|low|medium|high|xhigh|max)$/;
1386
1332
  /**
1387
1333
  * Merge the sources into one list, later sources shadowing earlier ones.
1388
1334
  *
@@ -1398,37 +1344,21 @@ function mergeAgentsForScope(scope, userAgents, projectAgents, pluginAgents = []
1398
1344
  return [...byName.values()];
1399
1345
  }
1400
1346
  /** Size and mtime of one path, or a marker when it does not exist. */
1401
- function stampOf(target) {
1347
+ async function stampOf(io, target) {
1402
1348
  try {
1403
- const stat = fs.statSync(target);
1349
+ const canonical = getOrThrow(await io.fs.canonicalPath(target, io.context));
1350
+ const stat = getOrThrow(await io.fs.fileInfo(canonical, io.context));
1404
1351
  return `${target}${FINGERPRINT_FIELD_SEPARATOR}${stat.mtimeMs}${FINGERPRINT_FIELD_SEPARATOR}${stat.size}`;
1405
1352
  } catch {
1406
1353
  return `${target}${FINGERPRINT_FIELD_SEPARATOR}${MISSING_SOURCE_MARKER}`;
1407
1354
  }
1408
1355
  }
1409
- /** Resolve Team-owned package configuration from the current parent harness state. */
1410
- function resolveActiveTeamPackageConfig(environment = process.env) {
1411
- const harness = loadHarnessState(environment).state;
1412
- if (!harness.root) return void 0;
1413
- const layers = loadMajorModesConfig(harness.root, environment.HOME);
1414
- const config = mergeTeamPackageConfigurations(resolvePackageConfigurations(layers, harness.layers, PO_TEAM_PACKAGE));
1415
- return config ? {
1416
- config,
1417
- path: path.join(harness.root, MAJOR_MODES_CONFIG_RELATIVE_PATH)
1418
- } : void 0;
1419
- }
1420
- function teamModelSpecs(config) {
1421
- if (!config?.models) return void 0;
1422
- return config.models.map(({ model, thinking }) => thinking ? `${model.replace(THINKING_SUFFIX, "")}:${thinking}` : model);
1423
- }
1424
- /** Resolve Team's ordered package model policy without merging it into an agent definition. */
1425
- function resolveActiveTeamModelSpecs(environment = process.env) {
1426
- return teamModelSpecs(resolveActiveTeamPackageConfig(environment)?.config);
1427
- }
1428
1356
  var AgentDiscoveryService = class {
1429
- environment;
1430
- constructor(environment = process.env) {
1431
- this.environment = environment;
1357
+ io;
1358
+ agentConfig;
1359
+ constructor(io, agentConfig) {
1360
+ this.io = io;
1361
+ this.agentConfig = agentConfig;
1432
1362
  }
1433
1363
  cache = new LruCache(MAX_CACHED_DISCOVERIES);
1434
1364
  /**
@@ -1441,23 +1371,25 @@ var AgentDiscoveryService = class {
1441
1371
  now() {
1442
1372
  return Date.now();
1443
1373
  }
1444
- discover(cwd, scope) {
1374
+ async discover(cwd, scope) {
1445
1375
  const resolvedCwd = path.resolve(cwd);
1446
- const canonicalCwd = canonicalizeDiscoveryCwd(resolvedCwd);
1376
+ const canonicalCwd = await canonicalizeDiscoveryCwd(this.io, resolvedCwd);
1447
1377
  const key = `${scope}${FINGERPRINT_ENTRY_SEPARATOR}${canonicalCwd}`;
1448
1378
  const cached = this.cache.get(key);
1449
1379
  const timestamp = this.now();
1450
- if (cached && cached.expiresAt > timestamp && cached.fingerprint === this.fingerprint(canonicalCwd)) return cloneResult(cached.result);
1451
- const result = this.load(resolvedCwd, scope);
1380
+ const team = await this.agentConfig?.currentOrUndefined();
1381
+ if (cached && cached.team === team && cached.expiresAt > timestamp && cached.fingerprint === await this.fingerprint(canonicalCwd)) return cloneResult(cached.result);
1382
+ const result = await this.load(resolvedCwd, scope, team);
1452
1383
  this.cache.set(key, {
1453
1384
  result,
1454
1385
  expiresAt: timestamp + this.ttlMs,
1455
- fingerprint: this.fingerprint(canonicalCwd)
1386
+ fingerprint: await this.fingerprint(canonicalCwd),
1387
+ team
1456
1388
  });
1457
1389
  return cloneResult(result);
1458
1390
  }
1459
- find(cwd, scope, name) {
1460
- return this.discover(cwd, scope).agents.find((agent) => agent.name === name);
1391
+ async find(cwd, scope, name) {
1392
+ return (await this.discover(cwd, scope)).agents.find((agent) => agent.name === name);
1461
1393
  }
1462
1394
  invalidate() {
1463
1395
  this.cache.clear();
@@ -1469,43 +1401,42 @@ var AgentDiscoveryService = class {
1469
1401
  * from the same directory read overlapping sources, and computing one stamp
1470
1402
  * keeps the stat count fixed regardless of how many scopes are queried.
1471
1403
  */
1472
- fingerprint(cwd) {
1473
- const harness = loadHarnessState(this.environment).state;
1404
+ async fingerprint(cwd) {
1474
1405
  const sources = [
1475
- getUserAgentSettingsPath(this.environment),
1476
- getProjectAgentSettingsPath(cwd, this.environment) ?? MISSING_SOURCE_MARKER,
1477
- ...userAgentDirs(this.environment),
1478
- ...resolveNearestProjectAgentDirs(cwd, this.environment).readDirs,
1479
- ...pluginAgentDirs(this.environment)
1406
+ getUserAgentSettingsPath(this.io),
1407
+ await getProjectAgentSettingsPath(this.io, cwd) ?? MISSING_SOURCE_MARKER,
1408
+ ...userAgentDirs(this.io),
1409
+ ...(await resolveNearestProjectAgentDirs(this.io, cwd)).readDirs,
1410
+ ...pluginAgentDirs(this.io.environment)
1480
1411
  ];
1481
- if (harness.root) sources.push(path.join(harness.root, MAJOR_MODES_CONFIG_RELATIVE_PATH));
1482
- return [...sources.map(stampOf), `active-layers${FINGERPRINT_FIELD_SEPARATOR}${harness.layers.join(",")}`].join(FINGERPRINT_ENTRY_SEPARATOR);
1412
+ return (await Promise.all(sources.map((target) => stampOf(this.io, target)))).join(FINGERPRINT_ENTRY_SEPARATOR);
1483
1413
  }
1484
1414
  /**
1485
1415
  * The uncached read. Protected so a test can count how often it actually runs,
1486
1416
  * which is the only direct way to assert that the cache is doing its job.
1487
1417
  */
1488
- load(cwd, scope) {
1489
- const userSettingsPath = getUserAgentSettingsPath(this.environment);
1490
- const projectSettingsPath = getProjectAgentSettingsPath(cwd, this.environment);
1491
- const userSettings = scope === "project" ? EMPTY_SUBAGENT_SETTINGS : readSubagentSettings(userSettingsPath);
1492
- const projectSettings = scope === "user" ? EMPTY_SUBAGENT_SETTINGS : readSubagentSettings(projectSettingsPath);
1418
+ async load(cwd, scope, team) {
1419
+ const userSettingsPath = getUserAgentSettingsPath(this.io);
1420
+ const projectSettingsPath = await getProjectAgentSettingsPath(this.io, cwd);
1421
+ const userSettings = scope === "project" ? EMPTY_SUBAGENT_SETTINGS : await readSubagentSettings(this.io, userSettingsPath);
1422
+ const projectSettings = scope === "user" ? EMPTY_SUBAGENT_SETTINGS : await readSubagentSettings(this.io, projectSettingsPath);
1493
1423
  const legacyDefaultModel = resolveSubagentDefaultModel(userSettings, projectSettings, userSettingsPath, projectSettingsPath);
1494
- const teamPackage = resolveActiveTeamPackageConfig(this.environment);
1495
- const packagePrimaryModel = teamModelSpecs(teamPackage?.config)?.[0];
1496
- const defaultModel = packagePrimaryModel && teamPackage ? {
1424
+ const packagePrimaryModel = team?.models?.[0];
1425
+ const defaultModel = packagePrimaryModel && team ? {
1497
1426
  type: "packages.team.defaultModel",
1498
1427
  scope: "package",
1499
- path: teamPackage.path,
1428
+ path: team.path ?? "",
1500
1429
  model: packagePrimaryModel
1501
1430
  } : legacyDefaultModel;
1502
1431
  const defaultThinking = resolveSubagentDefaultThinking(userSettings, projectSettings, projectSettingsPath);
1503
1432
  const defaultExtensions = resolveSubagentDefaultExtensions(userSettings, projectSettings, projectSettingsPath);
1504
1433
  const resolve = (agents) => applyCustomAgentOverrides(applySubagentDefaults(agents, defaultModel, defaultThinking, defaultExtensions), userSettings, projectSettings, userSettingsPath, projectSettingsPath);
1505
- const plugin = resolve(pluginAgentDirs(this.environment).flatMap((directory) => loadAgentsFromDir(directory, "plugin", this.environment)));
1434
+ const projectDirs = await resolveNearestProjectAgentDirs(this.io, cwd);
1435
+ const loadDirs = async (dirs, source) => resolve((await Promise.all(dirs.map((dir) => loadAgentsFromDir(this.io, dir, source)))).flat());
1436
+ const plugin = await loadDirs(pluginAgentDirs(this.io.environment), "plugin");
1506
1437
  return {
1507
- agents: mergeAgentsForScope(scope, scope === "project" ? [] : resolve(userAgentDirs(this.environment).flatMap((directory) => loadAgentsFromDir(directory, "user", this.environment))), scope === "user" ? [] : resolve(resolveNearestProjectAgentDirs(cwd, this.environment).readDirs.flatMap((directory) => loadAgentsFromDir(directory, "project", this.environment))), plugin).filter((agent) => agent.disabled !== true),
1508
- projectAgentsDir: resolveNearestProjectAgentDirs(cwd, this.environment).preferredDir,
1438
+ agents: mergeAgentsForScope(scope, scope === "project" ? [] : await loadDirs(userAgentDirs(this.io), "user"), scope === "user" ? [] : await loadDirs(projectDirs.readDirs, "project"), plugin).filter((agent) => agent.disabled !== true),
1439
+ projectAgentsDir: projectDirs.preferredDir,
1509
1440
  modelScope: projectSettings.modelScope ?? userSettings.modelScope
1510
1441
  };
1511
1442
  }
@@ -1524,6 +1455,6 @@ function cloneResult(result) {
1524
1455
  };
1525
1456
  }
1526
1457
  //#endregion
1527
- export { agentHasWriteTools as a, getProjectConfigDir as c, LruCache as i, resolveActiveTeamModelSpecs as n, canonicalizeDiscoveryCwd as o, resolveActiveTeamPackageConfig as r, getAgentDir as s, AgentDiscoveryService as t };
1458
+ export { getAgentDir as a, canonicalizeDiscoveryCwd$1 as i, LruCache as n, getConfigDirName as o, agentHasWriteTools as r, getProjectConfigDir as s, AgentDiscoveryService as t };
1528
1459
 
1529
- //# sourceMappingURL=agentDiscovery-ZQlFkKvB.mjs.map
1460
+ //# sourceMappingURL=agentDiscovery-ZNG8iZXV.mjs.map