@zhushanwen/pi-subagent-workflow 0.1.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 (143) hide show
  1. package/agents/context-builder.md +17 -0
  2. package/agents/general-purpose.md +16 -0
  3. package/agents/oracle.md +17 -0
  4. package/agents/planner.md +17 -0
  5. package/agents/researcher.md +17 -0
  6. package/agents/reviewer.md +17 -0
  7. package/agents/scout.md +17 -0
  8. package/agents/worker.md +16 -0
  9. package/examples/README.md +43 -0
  10. package/examples/chain.example.js +92 -0
  11. package/examples/map-reduce.example.js +99 -0
  12. package/examples/parallel.example.js +82 -0
  13. package/examples/scatter-gather.example.js +106 -0
  14. package/index.ts +1 -0
  15. package/package.json +66 -0
  16. package/skills/workflow-script-format/SKILL.md +328 -0
  17. package/src/execution/__tests__/agent-registry.test.ts +164 -0
  18. package/src/execution/__tests__/agent-result-mapper.test.ts +128 -0
  19. package/src/execution/__tests__/alive-store.test.ts +147 -0
  20. package/src/execution/__tests__/bg-notify-render.test.ts +256 -0
  21. package/src/execution/__tests__/concurrency-pool.test.ts +217 -0
  22. package/src/execution/__tests__/config.test.ts +110 -0
  23. package/src/execution/__tests__/crash-recovery.test.ts +311 -0
  24. package/src/execution/__tests__/execute-nesting.test.ts +359 -0
  25. package/src/execution/__tests__/execute-options-mapper.test.ts +138 -0
  26. package/src/execution/__tests__/execution-record.test.ts +959 -0
  27. package/src/execution/__tests__/finalized-marker.test.ts +82 -0
  28. package/src/execution/__tests__/format-schema-instruction.test.ts +135 -0
  29. package/src/execution/__tests__/format.test.ts +320 -0
  30. package/src/execution/__tests__/helpers/mock-extension-api.ts +30 -0
  31. package/src/execution/__tests__/list-component.test.ts +347 -0
  32. package/src/execution/__tests__/model-resolver.test.ts +356 -0
  33. package/src/execution/__tests__/output-collector.test.ts +61 -0
  34. package/src/execution/__tests__/path-encoding.test.ts +75 -0
  35. package/src/execution/__tests__/pi-invocation.test.ts +73 -0
  36. package/src/execution/__tests__/record-store.test.ts +545 -0
  37. package/src/execution/__tests__/run-spawn-edges.test.ts +439 -0
  38. package/src/execution/__tests__/run-spawn-integration.test.ts +897 -0
  39. package/src/execution/__tests__/sdk-contract.test.ts +272 -0
  40. package/src/execution/__tests__/session-context-resolver.test.ts +167 -0
  41. package/src/execution/__tests__/session-file-gc.test.ts +247 -0
  42. package/src/execution/__tests__/session-reconstructor.test.ts +359 -0
  43. package/src/execution/__tests__/session-runner-schema-env.test.ts +314 -0
  44. package/src/execution/__tests__/session-start-reaper.test.ts +227 -0
  45. package/src/execution/__tests__/spawn-args.test.ts +244 -0
  46. package/src/execution/__tests__/spawn-event-adapter.test.ts +167 -0
  47. package/src/execution/__tests__/subagent-service.test.ts +678 -0
  48. package/src/execution/__tests__/subprocess-agent-runner.test.ts +389 -0
  49. package/src/execution/__tests__/temp-prompt.test.ts +53 -0
  50. package/src/execution/__tests__/timeout-integration.test.ts +381 -0
  51. package/src/execution/__tests__/tombstone-store.test.ts +73 -0
  52. package/src/execution/__tests__/tool-action.test.ts +330 -0
  53. package/src/execution/__tests__/turn-limiter.test.ts +65 -0
  54. package/src/execution/__tests__/worktree-manager.test.ts +423 -0
  55. package/src/execution/__tests__/worktree-registry.test.ts +161 -0
  56. package/src/execution/agent-registry.ts +252 -0
  57. package/src/execution/agent-result-mapper.ts +84 -0
  58. package/src/execution/alive-store.ts +92 -0
  59. package/src/execution/best-effort.ts +30 -0
  60. package/src/execution/concurrency-pool.ts +84 -0
  61. package/src/execution/config.ts +73 -0
  62. package/src/execution/execute-options-mapper.ts +86 -0
  63. package/src/execution/execution-record.ts +778 -0
  64. package/src/execution/finalized-marker.ts +51 -0
  65. package/src/execution/model-config-service.ts +225 -0
  66. package/src/execution/model-resolver.ts +247 -0
  67. package/src/execution/notifier.ts +168 -0
  68. package/src/execution/output-collector.ts +88 -0
  69. package/src/execution/path-encoding.ts +34 -0
  70. package/src/execution/pi-invocation.ts +70 -0
  71. package/src/execution/record-store.ts +350 -0
  72. package/src/execution/session-context-resolver.ts +64 -0
  73. package/src/execution/session-file-gc.ts +98 -0
  74. package/src/execution/session-reconstructor.ts +450 -0
  75. package/src/execution/session-runner.ts +725 -0
  76. package/src/execution/spawn-event-adapter.ts +150 -0
  77. package/src/execution/subagent-service.ts +973 -0
  78. package/src/execution/subprocess-agent-runner.ts +108 -0
  79. package/src/execution/temp-prompt.ts +57 -0
  80. package/src/execution/tombstone-store.ts +72 -0
  81. package/src/execution/turn-limiter.ts +88 -0
  82. package/src/execution/types.ts +634 -0
  83. package/src/execution/worktree-manager.ts +285 -0
  84. package/src/execution/worktree-registry.ts +144 -0
  85. package/src/index.ts +454 -0
  86. package/src/interface/bg-notify-render.ts +286 -0
  87. package/src/interface/commands.ts +157 -0
  88. package/src/interface/format.ts +501 -0
  89. package/src/interface/gui-adapter.ts +136 -0
  90. package/src/interface/helpers.ts +110 -0
  91. package/src/interface/list-component.ts +643 -0
  92. package/src/interface/list-shared.ts +84 -0
  93. package/src/interface/list-view.ts +373 -0
  94. package/src/interface/reentry-guard.ts +30 -0
  95. package/src/interface/subagent-actions.ts +294 -0
  96. package/src/interface/subagent-tool.ts +294 -0
  97. package/src/interface/subagents.ts +30 -0
  98. package/src/interface/tool-render.ts +333 -0
  99. package/src/interface/tool-workflow-script.ts +351 -0
  100. package/src/interface/tool-workflow.ts +485 -0
  101. package/src/interface/views/WorkflowsView.ts +944 -0
  102. package/src/interface/views/detail-content.ts +298 -0
  103. package/src/interface/views/format.ts +320 -0
  104. package/src/orchestration/__tests__/concurrency-gate.test.ts +125 -0
  105. package/src/orchestration/__tests__/config-loader.test.ts +381 -0
  106. package/src/orchestration/__tests__/error-recovery-handlers.test.ts +332 -0
  107. package/src/orchestration/__tests__/error-recovery-workflow-call.test.ts +166 -0
  108. package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +248 -0
  109. package/src/orchestration/__tests__/lifecycle.test.ts +385 -0
  110. package/src/orchestration/__tests__/script-lint.test.ts +347 -0
  111. package/src/orchestration/__tests__/worker-script-builder.test.ts +42 -0
  112. package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +319 -0
  113. package/src/orchestration/agent-opts-resolver.ts +128 -0
  114. package/src/orchestration/concurrency-gate.ts +69 -0
  115. package/src/orchestration/config-loader.ts +313 -0
  116. package/src/orchestration/error-recovery.ts +578 -0
  117. package/src/orchestration/execute-agent-call.ts +174 -0
  118. package/src/orchestration/jsonl-run-store.ts +292 -0
  119. package/src/orchestration/launcher.ts +368 -0
  120. package/src/orchestration/lifecycle.ts +373 -0
  121. package/src/orchestration/models/__tests__/budget.test.ts +367 -0
  122. package/src/orchestration/models/agent-call.ts +76 -0
  123. package/src/orchestration/models/budget.ts +148 -0
  124. package/src/orchestration/models/ports.ts +165 -0
  125. package/src/orchestration/models/run-runtime.ts +91 -0
  126. package/src/orchestration/models/run-spec.ts +54 -0
  127. package/src/orchestration/models/run-state.ts +44 -0
  128. package/src/orchestration/models/trace.ts +102 -0
  129. package/src/orchestration/models/types.ts +242 -0
  130. package/src/orchestration/models/workflow-run.ts +275 -0
  131. package/src/orchestration/models/workflow-script-registry.ts +32 -0
  132. package/src/orchestration/models/workflow-script.ts +90 -0
  133. package/src/orchestration/node-ops.ts +192 -0
  134. package/src/orchestration/script-lint.ts +387 -0
  135. package/src/orchestration/skill-discovery.ts +60 -0
  136. package/src/orchestration/worker-handle.ts +115 -0
  137. package/src/orchestration/worker-host.ts +93 -0
  138. package/src/orchestration/worker-script-builder.ts +281 -0
  139. package/src/orchestration/workflow-files.ts +85 -0
  140. package/src/orchestration/workflow-script-registry-impl.ts +128 -0
  141. package/src/shared/__tests__/resource-discovery.test.ts +226 -0
  142. package/src/shared/agent-event.ts +13 -0
  143. package/src/shared/resource-discovery.ts +535 -0
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Workflow Extension — WorkflowScriptRegistryImpl
3
+ *
4
+ * WorkflowScriptRegistry port 的 Infra 实现。
5
+ *
6
+ * 职责:扫描 .pi/workflows/ + ~/.pi/agent/workflows/ 目录,按 regex 提取
7
+ * meta(不执行用户代码),按 tmp>project>user 优先级去重,60s TTL 缓存。
8
+ *
9
+ * 层归属:Infra(D-12)。implements Engine 层的 WorkflowScriptRegistry port。
10
+ *
11
+ * 设计:
12
+ * - WorkflowScriptRegistryImpl 是 port 的实现,但底层扫描/缓存/去重仍委托
13
+ * config-loader.ts 的 loadWorkflows/getWorkflow/invalidateCache 自由函数
14
+ * (config-loader 是稳定 Infra 工具,registry 在其上包装为 WorkflowScript 实体)。
15
+ * - 返回 WorkflowScript 实体(而非裸 CachedWorkflowMeta)。
16
+ * - get(name) 精确匹配;fuzzy 匹配由 Interface 层 tool 负责。
17
+ */
18
+
19
+ import { readFileSync } from "node:fs";
20
+
21
+ import {
22
+ type WorkflowMeta,
23
+ WorkflowScript,
24
+ type WorkflowSource,
25
+ } from "./models/workflow-script.ts";
26
+ import type { WorkflowScriptRegistry } from "./models/workflow-script-registry.ts";
27
+ import {
28
+ discoverWorkflows,
29
+ getWorkflow,
30
+ invalidateCache,
31
+ loadWorkflows,
32
+ type WorkflowScanConfig,
33
+ } from "./config-loader.ts";
34
+
35
+ // ── WorkflowScriptRegistryImpl ───────────────────────────────
36
+
37
+ /**
38
+ * WorkflowScriptRegistry port 的 Infra 实现。
39
+ *
40
+ * @param config 可选扫描配置。传入时 registry 只扫 config 声明的目录
41
+ * (测试隔离用);省略时走生产默认(全局 ~/.pi/agent/* 目录)。
42
+ */
43
+ export class WorkflowScriptRegistryImpl implements WorkflowScriptRegistry {
44
+ constructor(private readonly config?: WorkflowScanConfig) {}
45
+
46
+ /**
47
+ * 扫描所有 workflow 脚本(project + user + tmp),按 tmp>project>user 优先级
48
+ * 去重,返回 WorkflowScript 实体数组(含 available=false 的解析失败项)。
49
+ *
50
+ * 60s TTL 缓存——同 workspace 60s 内重复调用走缓存。
51
+ */
52
+ async loadAll(): Promise<WorkflowScript[]> {
53
+ const metas = this.config
54
+ ? await discoverWorkflows(this.config)
55
+ : await loadWorkflows();
56
+ return metas.map((m) => this.toScript(m));
57
+ }
58
+
59
+ /**
60
+ * 按名查单个脚本。精确匹配。
61
+ * 返回 undefined 当 name 不存在。
62
+ *
63
+ * 注:fuzzy 匹配由 Interface 层 tool-workflow负责——registry 只做精确查。
64
+ *
65
+ * 性能注记:无 config(生产路径)时走 getWorkflow 的 60s TTL 单条缓存。
66
+ * 有 config(测试隔离)时退化为每次 discoverWorkflows 全扫——测试场景
67
+ * 可接受,生产路径不受影响。
68
+ */
69
+ async get(name: string): Promise<WorkflowScript | undefined> {
70
+ const meta = this.config
71
+ ? (await discoverWorkflows(this.config)).find((w) => w.name === name)
72
+ : await getWorkflow(name);
73
+ return meta ? this.toScript(meta) : undefined;
74
+ }
75
+
76
+ /** 失效缓存——下次 loadAll/get 重新扫描文件系统。 */
77
+ invalidate(): void {
78
+ invalidateCache();
79
+ }
80
+
81
+ /**
82
+ * 把 CachedWorkflowMeta 转换为 WorkflowScript 实体。
83
+ *
84
+ * 字段映射:
85
+ * - name/path/source 直接传
86
+ * - meta 拆为 WorkflowMeta(name/description/phases)
87
+ * - sourceCode 在此 readFile 填充(FR-2:registry 是唯一读文件处,扫描+缓存+去重;
88
+ * 60s TTL 缓存避免重复读)。caller(launcher.runAndWait / tool-workflow.actionRun)
89
+ * 直接用 script.validate / script.toExecutable,不再各自 readFile。
90
+ * - available:meta 提取失败(config-loader 标 available=false)或文件不可读时为 false
91
+ */
92
+ private toScript(m: {
93
+ name: string;
94
+ description: string;
95
+ phases: (string | { title: string; detail?: string })[];
96
+ path: string;
97
+ available: boolean;
98
+ source: WorkflowSource;
99
+ }): WorkflowScript {
100
+ const meta: WorkflowMeta = {
101
+ name: m.name,
102
+ description: m.description,
103
+ phases: m.phases,
104
+ };
105
+ // FR-2: registry 是唯一读文件处。readFileSync 填 sourceCode —— 这样 launcher/tool
106
+ // 直接调 toExecutable/validate 即可,无需各自 readFile(避免重复读,60s TTL 缓存生效)。
107
+ let sourceCode = "";
108
+ let available = m.available;
109
+ if (available) {
110
+ try {
111
+ sourceCode = readFileSync(m.path, "utf-8");
112
+ } catch {
113
+ // 文件不可读(race condition 删除、权限等)——标 available=false,
114
+ // 与 meta 提取失败的现有语义一致(loader "never throws")。
115
+ sourceCode = "";
116
+ available = false;
117
+ }
118
+ }
119
+ return new WorkflowScript({
120
+ name: m.name,
121
+ source: m.source,
122
+ path: m.path,
123
+ sourceCode,
124
+ meta,
125
+ available,
126
+ });
127
+ }
128
+ }
@@ -0,0 +1,226 @@
1
+ // src/shared/__tests__/resource-discovery.test.ts
2
+ //
3
+ // 统一资源发现模块测试(ADR-031)。
4
+ // 验证:扫描源覆盖、优先级合并、manifest 校验、约定目录 fallback。
5
+ import * as fs from "node:fs";
6
+ import * as os from "node:os";
7
+ import * as path from "node:path";
8
+
9
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
10
+
11
+ import {
12
+ discoverResources,
13
+ discoverResourcesSync,
14
+ findWorkspaceRoot,
15
+ processPackageSync,
16
+ } from "../resource-discovery.ts";
17
+
18
+ // ============================================================
19
+ // helpers
20
+ // ============================================================
21
+
22
+ function tmpWorkspace(): string {
23
+ return fs.mkdtempSync(path.join(os.tmpdir(), "res-disc-test-"));
24
+ }
25
+
26
+ function writeFile(dir: string, name: string, content: string): string {
27
+ fs.mkdirSync(dir, { recursive: true });
28
+ const filePath = path.join(dir, name);
29
+ fs.writeFileSync(filePath, content, "utf-8");
30
+ return filePath;
31
+ }
32
+
33
+ function writePackageJson(pkgDir: string, pi: Record<string, unknown>): void {
34
+ fs.mkdirSync(pkgDir, { recursive: true });
35
+ fs.writeFileSync(
36
+ path.join(pkgDir, "package.json"),
37
+ JSON.stringify({ name: "test-pkg", pi }),
38
+ "utf-8",
39
+ );
40
+ }
41
+
42
+ // ============================================================
43
+ // findWorkspaceRoot
44
+ // ============================================================
45
+
46
+ describe("findWorkspaceRoot", () => {
47
+ it("returns cwd when no marker found", () => {
48
+ const ws = tmpWorkspace();
49
+ expect(findWorkspaceRoot(ws)).toBe(ws);
50
+ fs.rmSync(ws, { recursive: true, force: true });
51
+ });
52
+
53
+ it("finds .git root", () => {
54
+ const ws = tmpWorkspace();
55
+ fs.mkdirSync(path.join(ws, ".git"));
56
+ const sub = path.join(ws, "sub", "deep");
57
+ fs.mkdirSync(sub, { recursive: true });
58
+ expect(findWorkspaceRoot(sub)).toBe(ws);
59
+ fs.rmSync(ws, { recursive: true, force: true });
60
+ });
61
+ });
62
+
63
+ // ============================================================
64
+ // discoverResourcesSync — 扫描源覆盖 + 优先级
65
+ // ============================================================
66
+
67
+ describe("discoverResourcesSync", () => {
68
+ let ws: string;
69
+ let agentDir: string;
70
+
71
+ beforeEach(() => {
72
+ ws = tmpWorkspace();
73
+ agentDir = path.join(ws, ".fake-agent");
74
+ });
75
+ afterEach(() => {
76
+ fs.rmSync(ws, { recursive: true, force: true });
77
+ });
78
+
79
+ it("discovers agents from project .pi/agents/", () => {
80
+ writeFile(path.join(ws, ".pi", "agents"), "worker.md", "body");
81
+ const result = discoverResourcesSync({ kind: "agents", workspaceRoot: ws, agentDir });
82
+ expect(result.map((r) => path.basename(r.path))).toEqual(["worker.md"]);
83
+ expect(result[0]?.available).toBe(true);
84
+ });
85
+
86
+ it("discovers workflows from project .pi/workflows/", () => {
87
+ writeFile(path.join(ws, ".pi", "workflows"), "build.js", "const meta={name:'build'};");
88
+ const result = discoverResourcesSync({ kind: "workflows", workspaceRoot: ws, agentDir });
89
+ expect(result.map((r) => path.basename(r.path))).toEqual(["build.js"]);
90
+ });
91
+
92
+ it("project .agents overrides project .pi on name clash (priority)", () => {
93
+ writeFile(path.join(ws, ".pi", "agents"), "worker.md", "pi-body");
94
+ writeFile(path.join(ws, ".agents", "agents"), "worker.md", "agents-body");
95
+ const result = discoverResourcesSync({ kind: "agents", workspaceRoot: ws, agentDir });
96
+ expect(result).toHaveLength(1);
97
+ expect(result[0]?.source).toBe("project-agents");
98
+ });
99
+
100
+ it("includes tmp source for workflows when includeTmp=true", () => {
101
+ writeFile(path.join(ws, ".pi", "workflows", ".tmp"), "temp.js", "const meta={name:'temp'};");
102
+ const result = discoverResourcesSync({
103
+ kind: "workflows",
104
+ workspaceRoot: ws,
105
+ agentDir,
106
+ includeTmp: true,
107
+ });
108
+ expect(result.map((r) => path.basename(r.path))).toEqual(["temp.js"]);
109
+ expect(result[0]?.source).toBe("project-pi-tmp");
110
+ });
111
+
112
+ it("excludes tmp source when includeTmp omitted", () => {
113
+ writeFile(path.join(ws, ".pi", "workflows", ".tmp"), "temp.js", "x");
114
+ const result = discoverResourcesSync({ kind: "workflows", workspaceRoot: ws, agentDir });
115
+ expect(result).toEqual([]);
116
+ });
117
+
118
+ it("ignores _ prefix and .chain.md files", () => {
119
+ const dir = path.join(ws, ".pi", "agents");
120
+ writeFile(dir, "real.md", "body");
121
+ writeFile(dir, "_skip.md", "ignored");
122
+ writeFile(dir, "trace.chain.md", "ignored");
123
+ const result = discoverResourcesSync({ kind: "agents", workspaceRoot: ws, agentDir });
124
+ expect(result.map((r) => path.basename(r.path))).toEqual(["real.md"]);
125
+ });
126
+
127
+ it("nonexistent directories are silently skipped", () => {
128
+ const result = discoverResourcesSync({ kind: "agents", workspaceRoot: ws, agentDir });
129
+ expect(result).toEqual([]);
130
+ });
131
+ });
132
+
133
+ // ============================================================
134
+ // processPackageSync — manifest 校验
135
+ // ============================================================
136
+
137
+ describe("processPackageSync", () => {
138
+ let pkgDir: string;
139
+
140
+ beforeEach(() => {
141
+ pkgDir = tmpWorkspace();
142
+ });
143
+ afterEach(() => {
144
+ fs.rmSync(pkgDir, { recursive: true, force: true });
145
+ });
146
+
147
+ it("loads from manifest directory declaration", () => {
148
+ writeFile(path.join(pkgDir, "agents"), "worker.md", "body");
149
+ writePackageJson(pkgDir, { agents: ["./agents"] });
150
+ const result = processPackageSync(pkgDir, "agents");
151
+ expect(result).toHaveLength(1);
152
+ expect(result[0]?.available).toBe(true);
153
+ });
154
+
155
+ it("loads from manifest file declaration", () => {
156
+ writeFile(pkgDir, "worker.md", "body");
157
+ writePackageJson(pkgDir, { agents: ["./worker.md"] });
158
+ const result = processPackageSync(pkgDir, "agents");
159
+ expect(result).toHaveLength(1);
160
+ expect(result[0]?.available).toBe(true);
161
+ });
162
+
163
+ it("manifest path not exists → available=false, no fallback", () => {
164
+ writePackageJson(pkgDir, { agents: ["./nonexistent"] });
165
+ const result = processPackageSync(pkgDir, "agents");
166
+ expect(result).toHaveLength(1);
167
+ expect(result[0]?.available).toBe(false);
168
+ // 不 fallback 到约定目录
169
+ writeFile(path.join(pkgDir, "agents"), "hidden.md", "body");
170
+ const result2 = processPackageSync(pkgDir, "agents");
171
+ expect(result2).toHaveLength(1);
172
+ expect(result2[0]?.available).toBe(false);
173
+ });
174
+
175
+ it("no manifest → fallback to convention dir", () => {
176
+ writeFile(path.join(pkgDir, "agents"), "worker.md", "body");
177
+ // 无 package.json 或无 pi.agents
178
+ const result = processPackageSync(pkgDir, "agents");
179
+ expect(result).toHaveLength(1);
180
+ expect(result[0]?.available).toBe(true);
181
+ });
182
+
183
+ it("no manifest and no convention dir → empty", () => {
184
+ writePackageJson(pkgDir, { extensions: ["./index.ts"] });
185
+ const result = processPackageSync(pkgDir, "agents");
186
+ expect(result).toEqual([]);
187
+ });
188
+ });
189
+
190
+ // ============================================================
191
+ // discoverResources (async) — 基本冒烟
192
+ // ============================================================
193
+
194
+ describe("discoverResources (async)", () => {
195
+ let ws: string;
196
+
197
+ beforeEach(() => {
198
+ ws = tmpWorkspace();
199
+ });
200
+ afterEach(() => {
201
+ fs.rmSync(ws, { recursive: true, force: true });
202
+ });
203
+
204
+ it("discovers agents from project .pi/agents/ (async)", async () => {
205
+ writeFile(path.join(ws, ".pi", "agents"), "worker.md", "body");
206
+ const result = await discoverResources({
207
+ kind: "agents",
208
+ workspaceRoot: ws,
209
+ agentDir: path.join(ws, ".fake-agent"),
210
+ });
211
+ expect(result).toHaveLength(1);
212
+ expect(result[0]?.available).toBe(true);
213
+ });
214
+
215
+ it("discovers workflows with tmp source (async)", async () => {
216
+ writeFile(path.join(ws, ".pi", "workflows"), "build.js", "x");
217
+ writeFile(path.join(ws, ".pi", "workflows", ".tmp"), "temp.js", "x");
218
+ const result = await discoverResources({
219
+ kind: "workflows",
220
+ workspaceRoot: ws,
221
+ agentDir: path.join(ws, ".fake-agent"),
222
+ includeTmp: true,
223
+ });
224
+ expect(result).toHaveLength(2);
225
+ });
226
+ });
@@ -0,0 +1,13 @@
1
+ // src/shared/agent-event.ts
2
+ //
3
+ // AgentEvent 类型唯一出口(两包合并后 import 收口)。
4
+ //
5
+ // 合并前 AgentEvent 分别定义在 execution/types.ts(subagents 侧)和
6
+ // orchestration/live/types.ts(workflow 侧)——两份定义完全一致但独立维护。
7
+ // 合并后本文件是单一 source of truth——re-export execution/types.ts 的 AgentEvent,
8
+ // orchestration 层通过本文件引用(替代 orchestration/live/types.ts 的旧副本)。
9
+ //
10
+ // wave-3 删 orchestration/live/types.ts 后,AgentEvent 的唯一定义在 execution/types.ts。
11
+ // 本 re-export 保持「shared/ 是类型共享层」的架构约定。
12
+
13
+ export type { AgentEvent } from "../execution/types.ts";