@zhushanwen/pi-subagent-workflow 8.7.0 → 8.8.1

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 (56) hide show
  1. package/README.md +5 -11
  2. package/package.json +8 -11
  3. package/skills/workflow-script-format/SKILL.md +32 -13
  4. package/src/host/__tests__/pi-host.test.ts +23 -2
  5. package/src/host/pi-host.ts +61 -6
  6. package/src/index.ts +155 -528
  7. package/src/injectors/__tests__/engine-awareness.test.ts +5 -3
  8. package/src/injectors/__tests__/engine-section-stability.test.ts +48 -33
  9. package/src/injectors/__tests__/model-list-injector.test.ts +18 -21
  10. package/src/injectors/__tests__/subagent-list-injector.test.ts +54 -14
  11. package/src/injectors/__tests__/workflow-list-injector.test.ts +26 -12
  12. package/src/injectors/engine-awareness.ts +80 -8
  13. package/src/injectors/model-list-injector.ts +15 -58
  14. package/src/injectors/resource-list-injector.ts +209 -0
  15. package/src/injectors/subagent-list-injector.ts +53 -224
  16. package/src/injectors/workflow-list-injector.ts +36 -196
  17. package/src/interface/__tests__/detectors.test.ts +46 -35
  18. package/src/interface/__tests__/subagent-tool-path-guard.test.ts +42 -26
  19. package/src/interface/__tests__/subagent-tool-prompt.test.ts +14 -3
  20. package/src/interface/__tests__/tool-workflow-run-builtin-name.test.ts +216 -0
  21. package/src/interface/__tests__/tool-workflow-script-generate.test.ts +17 -6
  22. package/src/interface/__tests__/tool-workflow-throw-paths.test.ts +38 -2
  23. package/src/interface/bg-notify-render.ts +7 -17
  24. package/src/interface/command-actions.ts +5 -15
  25. package/src/interface/commands.ts +116 -76
  26. package/src/interface/format.ts +354 -245
  27. package/src/interface/gui-mappers.ts +18 -22
  28. package/src/interface/helpers.ts +9 -130
  29. package/src/interface/list-component.ts +164 -117
  30. package/src/interface/list-shared.ts +3 -3
  31. package/src/interface/list-view.ts +130 -73
  32. package/src/interface/subagent-actions.ts +50 -675
  33. package/src/interface/subagent-tool-schema.ts +7 -9
  34. package/src/interface/subagent-tool.ts +5 -4
  35. package/src/interface/subagents.ts +9 -8
  36. package/src/interface/tool-render.ts +5 -15
  37. package/src/interface/tool-workflow-script.ts +34 -75
  38. package/src/interface/tool-workflow.ts +62 -96
  39. package/src/interface/tui-kit.ts +305 -0
  40. package/src/interface/views/WorkflowsView.ts +270 -207
  41. package/src/interface/views/__tests__/WorkflowsView-signature.test.ts +3 -3
  42. package/src/interface/views/__tests__/detail-content-session-file.test.ts +7 -4
  43. package/src/interface/views/detail-content.ts +16 -14
  44. package/src/interface/views/view-constants.ts +19 -0
  45. package/src/jsonl-run-store.ts +144 -228
  46. package/agents/analyst.md +0 -61
  47. package/agents/coder.md +0 -70
  48. package/agents/debugger.md +0 -67
  49. package/agents/doc-reviewer.md +0 -50
  50. package/agents/explorer.md +0 -64
  51. package/agents/general-purpose.md +0 -32
  52. package/agents/orchestrator.md +0 -63
  53. package/agents/planner.md +0 -54
  54. package/agents/researcher.md +0 -65
  55. package/agents/reviewer.md +0 -74
  56. package/src/interface/views/format.ts +0 -320
package/README.md CHANGED
@@ -4,7 +4,7 @@ Pi 的 subagent + workflow 合并包:任务委派 + 多 agent 编排(chain /
4
4
 
5
5
  ## 内置 Agents
6
6
 
7
- 按「读/写 × 视角」正交切分,9 个角色零重叠:
7
+ 按「读/写 × 视角」正交切分,10 个角色零重叠(C1 起随 `@zhushanwen/subagent-core` 的 `agents/` 资产分发,`<available_subagents>` 的 `<location>` 指向 core 包目录):
8
8
 
9
9
  | Agent | 角色 | 读/写 |
10
10
  |-------|------|-------|
@@ -12,6 +12,7 @@ Pi 的 subagent + workflow 合并包:任务委派 + 多 agent 编排(chain /
12
12
  | `planner` | 复杂任务拆解为有序实施计划(合并需求澄清) | 只读产文档 |
13
13
  | `coder` | 代码实现、修改、测试(唯一改代码的角色) | 可改 |
14
14
  | `reviewer` | 代码审查与需求验收(含 git diff) | 只读 |
15
+ | `doc-reviewer` | 文档审查(四遍方法论,事实锚点核实;spec / 设计文档) | 只读 |
15
16
  | `debugger` | 运行时故障诊断,钉根因 | 只读* |
16
17
  | `analyst` | 深度项目分析,产出给人读的报告 | 只读 |
17
18
  | `researcher` | 外部资料调研(依赖 tavily skill) | 只读 |
@@ -30,19 +31,12 @@ Pi 的 subagent + workflow 合并包:任务委派 + 多 agent 编排(chain /
30
31
 
31
32
  ## Orchestrator 协调器模式
32
33
 
33
- 主 agent 禁用 bash / read / write / edit 等执行工具,只保留协调类工具,被迫作为纯协调器:拆解任务 → 委派 subagent → 汇总结果。orchestrator agent 自身也可递归委派子 orchestrator,实现分层任务拆解(深度受 `Depth: N/10` 护栏保护)。
34
+ orchestrator 是纯协调器角色:拆解任务 → 委派 subagent → 汇总结果,自身不做执行类工作。orchestrator agent 自身也可递归委派子 orchestrator,实现分层任务拆解(深度受 `Depth: N/10` 护栏保护)。
34
35
 
35
- 可用工具 5 个:`todo`、`goal_control`、`workflow`、`subagent`、`ask_user`(`ask_user` 由 `@zhushanwen/pi-ask-user` 提供,未安装时 orchestrator 遇歧义会明示停止而非猜测)。
36
-
37
- ### 启动命令
36
+ **工具约束变化(C1/D-5)**:内置模板不再携带 `tools:` frontmatter 白名单,subagent 不再以 `--tools` 白名单启动——工具约束回归宿主默认工具面,orchestrator 靠角色职责(职责边界段)约束自身只做协调。想要白名单的用户在 `<workspace>/.agents/agents/` 放同名 `.md` 覆写(project 级源稳定遮蔽内置,是唯一逃生门),或沿用 pi CLI 的 `--tools` 白名单(临时验证):
38
37
 
39
38
  ```bash
40
- # 方式一:CLI 工具白名单(临时验证最快)
41
39
  pi --tools todo,goal_control,workflow,subagent,ask_user
42
-
43
- # 方式二:白名单 + 注入 orchestrator 的 system prompt(推荐,主进程也具备协调器视角)
44
- pi --tools todo,goal_control,workflow,subagent,ask_user \
45
- --append-system-prompt "$(cat ~/.pi/agent/npm/node_modules/@zhushanwen/pi-subagent-workflow/agents/orchestrator.md)"
46
40
  ```
47
41
 
48
42
  > **依赖**:需先安装本包及相关扩展
@@ -59,7 +53,7 @@ pi --tools todo,goal_control,workflow,subagent,ask_user \
59
53
 
60
54
  ## Workflow 生命周期(one-shot)
61
55
 
62
- Workflow run 是一次性执行,状态机两态:`running → done`(`done` 唯一终态,reason 区分 completed / aborted / failed / budget_limited / time_limited)。`workflow` tool 仅 3 个 action:`run` / `status` / `abort`。
56
+ Workflow run 是一次性执行,状态机两态:`running → done`(`done` 唯一终态,reason 区分 completed / aborted / failed / budget_limited / time_limited)。`workflow` tool 仅 3 个 action:`run` / `status` / `abort`。run 的 `name` 接受 `<available_workflows>` 列出的 workflow 名(内置 chain / parallel / map-reduce / scatter-gather / review-fix-loop 或已保存脚本)或 `.js` 绝对路径。
63
57
 
64
58
  Runs are one-shot: there is no pause/resume — to stop a run early use abort; for a fresh result start a new run.
65
59
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhushanwen/pi-subagent-workflow",
3
- "version": "8.7.0",
3
+ "version": "8.8.1",
4
4
  "type": "module",
5
5
  "main": "index.ts",
6
6
  "description": "Unified subagent execution and multi-agent workflow orchestration for Pi — spawned-process agent runtime with sync/background modes, stateful workflow management with persistence, state machine, and execution tracing.",
@@ -19,7 +19,6 @@
19
19
  },
20
20
  "files": [
21
21
  "index.ts",
22
- "agents/",
23
22
  "skills/",
24
23
  "scripts/",
25
24
  "relay/",
@@ -51,24 +50,22 @@
51
50
  ],
52
51
  "skills": [
53
52
  "./skills"
54
- ],
55
- "agents": [
56
- "./agents"
57
53
  ]
58
54
  },
59
55
  "dependencies": {
60
- "@xyz-agent/session-delivery": "0.3.0",
61
- "@zhushanwen/pi-extension-logger": "0.3.0",
62
- "@xyz-agent/extension-protocol": "0.7.0",
63
- "@zhushanwen/subagent-core": "0.2.0"
56
+ "@xyz-agent/extension-protocol": "0.8.1",
57
+ "@xyz-agent/session-delivery": "0.3.1",
58
+ "@zhushanwen/pi-ext-guards": "0.2.1",
59
+ "@zhushanwen/pi-extension-logger": "0.4.1",
60
+ "@zhushanwen/subagent-core": "0.5.1"
64
61
  },
65
62
  "peerDependencies": {
66
63
  "@earendil-works/pi-ai": "^0.84.4",
67
64
  "@earendil-works/pi-coding-agent": "^0.84.4",
68
65
  "@earendil-works/pi-tui": "^0.84.4",
69
66
  "typebox": "*",
70
- "@zhushanwen/pi-pending-notifications": "0.5.0",
71
- "@zhushanwen/pi-structured-output": "5.1.0"
67
+ "@zhushanwen/pi-pending-notifications": "0.5.3",
68
+ "@zhushanwen/pi-structured-output": "5.1.3"
72
69
  },
73
70
  "peerDependenciesMeta": {
74
71
  "@earendil-works/pi-coding-agent": {
@@ -39,13 +39,22 @@ This is enforced by `lintScript`:
39
39
 
40
40
  ## Required: Meta Declaration
41
41
 
42
- Every script MUST declare `meta` at the top level:
42
+ Every script MUST declare its metadata as a `/* @pi-meta */` YAML block comment at the top level — NOT a `const meta` variable:
43
43
 
44
44
  ```javascript
45
- const meta = { name: 'workflow-name', description: '...', phases: ['phase1', 'phase2'] };
45
+ /* @pi-meta
46
+ name: workflow-name
47
+ description: One-line description of what the workflow does
48
+ phases: ['phase1', 'phase2']
49
+ */
46
50
  ```
47
51
 
48
- `name` must match the filename stem. `phases` is for display only.
52
+ - `name` must match the filename stem. `phases` is for display only.
53
+ - Optional fields: `parameters` (JSON Schema for `$ARGS`) and `usage` (markdown).
54
+ - The YAML body starts on the line after `/* @pi-meta`; the closing `*/` must sit alone at column 0.
55
+ - `generate` round-trip-validates the YAML and reports line/col on error (common pitfall: patternProperties regex must use double backslash `\\d`, not `\d`).
56
+
57
+ > **Legacy `const meta = { ... }` (transition only):** `generate` still accepts a legacy top-level `const meta` during the transition window, but the core discovery chain does NOT recognize it (no legacy fallback) — such scripts stay invisible to discovery and get no metadata injection. Always use `/* @pi-meta */` for new scripts.
49
58
 
50
59
  ## [MANDATORY] Display: description + phase
51
60
 
@@ -59,11 +68,11 @@ TUI `/workflows` 视图按**运行时 `phase()` 调用**分组(非 `meta.phase
59
68
  ### Minimal 示例(三者齐备)
60
69
 
61
70
  ```javascript
62
- const meta = {
63
- name: 'review-fix',
64
- description: 'review then fix',
65
- phases: ['review', 'fix'],
66
- };
71
+ /* @pi-meta
72
+ name: review-fix
73
+ description: review then fix
74
+ phases: ['review', 'fix']
75
+ */
67
76
 
68
77
  phase('review');
69
78
  const r = await agent({ prompt: 'review diff', description: 'review-diff' });
@@ -79,11 +88,17 @@ return { done: true };
79
88
  // ❌ agent() 无 description → TUI 显示 unnamed agent
80
89
  await agent({ prompt: 'review diff' });
81
90
 
82
- // ❌ meta.phases 用对象数组 → 引擎忽略,全部归入 (unnamed)
83
- const meta = { name: 'x', phases: [{ title: 'review' }, { title: 'fix' }] };
91
+ // ❌ phases 用对象数组 → 引擎忽略,全部归入 (unnamed)
92
+ /* @pi-meta
93
+ name: x
94
+ phases: [{ title: 'review' }, { title: 'fix' }]
95
+ */
84
96
 
85
97
  // ❌ 声明了 phases 但从不 phase() 调用 → 运行时分组失效
86
- const meta = { name: 'x', phases: ['review', 'fix'] };
98
+ /* @pi-meta
99
+ name: x
100
+ phases: ['review', 'fix']
101
+ */
87
102
  // ... 直接 await agent(...) 从不调 phase('review') / phase('fix')
88
103
  ```
89
104
 
@@ -201,7 +216,7 @@ const results = await parallel(
201
216
  );
202
217
  ```
203
218
 
204
- > 内置通用编排 workflow(chain / parallel / scatter-gather / map-reduce,可直接 `workflow run`,用 `agent()` 自包含实现)见 `extensions/universal/subagent-workflow/workflows/`。本段教 `workflow()` 嵌套 API,workflows 目录是开箱即用的通用编排工具(用 `agent()` 而非 `workflow()` 嵌套)。
219
+ > 内置通用编排 workflow(chain / parallel / scatter-gather / map-reduce / review-fix-loop,可直接 `workflow run`,用 `agent()` 自包含实现)见 `extensions/universal/subagent-workflow/workflows/`。本段教 `workflow()` 嵌套 API,workflows 目录是开箱即用的通用编排工具(用 `agent()` 而非 `workflow()` 嵌套)。
205
220
 
206
221
  ### Other globals
207
222
 
@@ -249,7 +264,11 @@ agent({ prompt: '...', description: 'review-business-logic' });
249
264
  ## Complete Example
250
265
 
251
266
  ```javascript
252
- const meta = { name: 'review-fix-loop', description: 'Loop: review → fix → commit until clean', phases: ['review-fix'] };
267
+ /* @pi-meta
268
+ name: review-fix-loop
269
+ description: "Loop: review → fix → commit until clean"
270
+ phases: ['review-fix']
271
+ */
253
272
 
254
273
  const MAX_ROUNDS = 10;
255
274
  let round = 0;
@@ -12,7 +12,9 @@
12
12
  // mock 返回 {count: n} 形状直接验证「适配读 .count」;session-delivery mock
13
13
  // 验证 createDelivery 透传(参数 + 返回句柄)。
14
14
 
15
- import { join } from "node:path";
15
+ import { join, dirname } from "node:path";
16
+ import { createRequire } from "node:module";
17
+ import { existsSync } from "node:fs";
16
18
 
17
19
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
18
20
 
@@ -72,17 +74,36 @@ describe("createPiHostServices.discoveryRoots(与现推导逐项一致)", ()
72
74
  vi.mocked(getAgentDir).mockReturnValue(AGENT_DIR);
73
75
  }
74
76
 
75
- it("agents 三根:顺序与 source 标签 = user-pi → npm → npm-dev", () => {
77
+ it("agents 四根:user-pi → npm → npm-dev → core 包父目录(C5⑥,source npm 追加末位)", () => {
76
78
  stubAgentDir();
77
79
  const roots = createPiHostServices().discoveryRoots?.().agents;
78
80
 
81
+ // 期望的 core 注入根用与 pi-host.ts 相同的锚点解析(./workflows/* 子入口在
82
+ // workspace 与 npm dist 双形态同径;探针证据见 probe-c5.md P1/P3)
83
+ const require = createRequire(import.meta.url);
84
+ const anchor = require.resolve("@zhushanwen/subagent-core/workflows/README.md");
85
+ const coreParent = dirname(dirname(dirname(anchor)));
86
+
79
87
  expect(roots).toEqual([
80
88
  { dir: join(AGENT_DIR, "agents"), source: "user-pi" },
81
89
  { dir: join(AGENT_DIR, "npm", "node_modules"), source: "npm" },
82
90
  { dir: join(AGENT_DIR, "extensions"), source: "npm-dev" },
91
+ // C5⑥:core 包一级父目录(npm 槽语义:一级子项 = 包目录,无 pi manifest 扫
92
+ // agents/ 约定目录);追加在既有 npm 根之后——同标签靠后者胜(新版遮蔽旧残留)
93
+ { dir: coreParent, source: "npm" },
83
94
  ]);
84
95
  });
85
96
 
97
+ it("agents 第 4 根指向 core 包的父目录(其下 subagent-core/agents/ 存在 10 内置角色)", () => {
98
+ stubAgentDir();
99
+ const roots = createPiHostServices().discoveryRoots?.().agents;
100
+ const coreRoot = roots?.[3];
101
+
102
+ expect(coreRoot?.source).toBe("npm");
103
+ // 便捷断言:core 包根(注入 dir 的子目录)下 agents/ 真实存在
104
+ expect(existsSync(join(coreRoot!.dir, "subagent-core", "agents"))).toBe(true);
105
+ });
106
+
86
107
  it("workflows 三根:与 agents 同构,末级目录名切换为 workflows", () => {
87
108
  stubAgentDir();
88
109
  const roots = createPiHostServices().discoveryRoots?.().workflows;
@@ -16,7 +16,9 @@
16
16
  // buildScanTargets、orchestration/skill-discovery.ts resolveSkillPath 的现推导
17
17
  // 逐项一致(user-pi / npm / npm-dev 字面即现 ResourceSource 标签)。
18
18
  // project/workspace 根不在壳侧提供——core 消费方按 workspaceRoot 自行推导
19
- // (u0-data-discovery 波次接注入消费)。
19
+ // (u0-data-discovery 波次接注入消费)。C5⑥ 起 agents kind 追加第 4 根:
20
+ // core 包一级父目录(source "npm")——core agents/ 资产进 pi 发现面,见
21
+ // corePackageNpmRoot 注释。
20
22
  // - countActiveFromEntries 适配:pi 侧真函数返回 CountActiveResult 对象,core
21
23
  // 端口契约是 number(core 消费面只读 .count,notify-ports.ts 契约注释)——
22
24
  // foundation 单元登记给本单元的适配责任。
@@ -25,23 +27,63 @@
25
27
  // 是结构超集成员,多不碍兼容)——结构兼容由本注入点 typecheck 守护,上游签名
26
28
  // 漂移即红(notify-ports.ts「闭包红线」段)。
27
29
 
28
- import { join } from "node:path";
30
+ import { createRequire } from "node:module";
31
+ import { dirname, join } from "node:path";
29
32
 
30
33
  import { getAgentDir } from "@earendil-works/pi-coding-agent";
31
34
  import { getLogger } from "@zhushanwen/pi-extension-logger";
32
35
  import { countActiveFromEntries } from "@zhushanwen/pi-pending-notifications";
33
36
  import { createDelivery } from "@xyz-agent/session-delivery";
34
37
 
35
- import type { DiscoveryRoot, HostServices } from "@zhushanwen/subagent-core/core/host-services.ts";
36
- import type { LogLevel } from "@zhushanwen/subagent-core/core/logger.ts";
37
- import type { NotifyDomainPorts } from "@zhushanwen/subagent-core/core/notify-ports.ts";
38
+ import type { DiscoveryRoot, HostServices } from "@zhushanwen/subagent-core";
39
+ import type { LogLevel } from "@zhushanwen/subagent-core";
40
+ import type { NotifyDomainPorts } from "@zhushanwen/subagent-core";
41
+ import { toErrorMessage } from "@zhushanwen/pi-ext-guards";
42
+
43
+ /**
44
+ * core 包(@zhushanwen/subagent-core)agents/ 资产进 pi 发现面的注入根(C5⑥,
45
+ * convergence §5.4 检查点 2;探针证据 docs/design/subagent-core-convergence.probe-c5.md)。
46
+ *
47
+ * 解析锚点 = `@zhushanwen/subagent-core/workflows/README.md`:`./workflows/*` 子入口
48
+ * 在 workspace TS 直引与 npm dist 两种发布形态下同径(publishConfig 保留该子入口),
49
+ * README.md 是两形态都必在的资产文件。core 包根 = 锚点上两级;npm 槽注入其一级
50
+ * 父目录——npm 槽语义:dir 下一级子项 = 包目录,core 无 pi manifest → 扫 agents/
51
+ * 约定目录命中 10 内置角色。
52
+ *
53
+ * 布局覆盖(探针 P2-P5 实测):dev workspace(core 在仓库 packages/ 下)与发布态
54
+ * 嵌套布局(core 在本包 node_modules 内)下这是唯一命中通路;发布态平铺布局
55
+ * (core 与本包同层)下既有 npm 根已命中,本注入是幂等兜底(重复发现被 core
56
+ * realpath 去重吸收)。
57
+ *
58
+ * 每次调用现解析(不 memo):发现调用点稀疏(session_start + 缓存 miss),解析
59
+ * 成本可忽略;失败(异常布局/解析器不可用)降级为不注入并 warn——绝不因资产
60
+ * 接线失败阻断发现主链。
61
+ */
62
+ function corePackageNpmRoot(): string | undefined {
63
+ try {
64
+ // createRequire 锚定本模块(jiti 加载器下 import.meta.url 可用;不可用则随
65
+ // catch 降级)。require.resolve 沿 pi-sw 自身的依赖解析链——workspace 与发布态
66
+ // 都从本包出发命中 core。
67
+ const require = createRequire(import.meta.url);
68
+ const anchor = require.resolve("@zhushanwen/subagent-core/workflows/README.md");
69
+ return dirname(dirname(dirname(anchor)));
70
+ } catch (err) {
71
+ // getLogger 惰性调用(catch 是冷路径——测试环境对 pi-extension-logger 的
72
+ // module-level mock 可能返回 undefined,模块级持有会在 import 期踩 undefined)
73
+ getLogger("pi-host").warn(
74
+ "[pi-host] core 包 agents/ 注入根解析失败——10 内置角色可能不可发现",
75
+ { reason: toErrorMessage(err) },
76
+ );
77
+ return undefined;
78
+ }
79
+ }
38
80
 
39
81
  /** agents/workflows 共享的 agentDir 派生根(末级目录名由 kind 决定)。
40
82
  * 顺序与 source 标签逐项对齐 resource-discovery.ts buildScanTargets 的
41
83
  * user-pi → npm → npm-dev 段(根列表按优先级低→高排列,D2 语义边界)。 */
42
84
  function agentDirKindRoots(kind: "agents" | "workflows"): DiscoveryRoot[] {
43
85
  const agentDir = getAgentDir();
44
- return [
86
+ const roots: DiscoveryRoot[] = [
45
87
  // 1. user .pi/agent/<kind>/
46
88
  { dir: join(agentDir, kind), source: "user-pi" },
47
89
  // 2. npm global: agentDir/npm/node_modules/*/<pkg>/
@@ -49,6 +91,19 @@ function agentDirKindRoots(kind: "agents" | "workflows"): DiscoveryRoot[] {
49
91
  // 3. npm dev symlink: agentDir/extensions/*/<pkg>/
50
92
  { dir: join(agentDir, "extensions"), source: "npm-dev" },
51
93
  ];
94
+ // 4. core 包根(C5⑥,仅 agents kind):追加在既有 npm 根之后——同标签多根依注入
95
+ // 序扫描 + last-writer-wins,core(随本包依赖分发的新模板)遮蔽同 agentDir 内
96
+ // 旧版残留副本;序位仍在 user 级之上、npm-dev/project 级之下(红线 1)。
97
+ // workflows kind 刻意不注入:<available_workflows> 的 <location> 是 CA2 快照
98
+ // 不豁免面(红线 8 豁免仅限 10 内置 agent 角色路径前缀),注入会翻转内置
99
+ // workflow 的胜出路径。
100
+ if (kind === "agents") {
101
+ const coreNpmRoot = corePackageNpmRoot();
102
+ if (coreNpmRoot !== undefined) {
103
+ roots.push({ dir: coreNpmRoot, source: "npm" });
104
+ }
105
+ }
106
+ return roots;
52
107
  }
53
108
 
54
109
  /** skills 的 agentDir 派生根。对齐 skill-discovery.ts resolveSkillPath 的两处