@zhushanwen/pi-subagent-workflow 7.4.0 → 8.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 (166) hide show
  1. package/README.md +15 -0
  2. package/package.json +7 -4
  3. package/scripts/rfl.mjs +308 -0
  4. package/skills/workflow-script-format/SKILL.md +1 -1
  5. package/src/execution/__tests__/__fixtures__/truncline.snapshot.json +1 -0
  6. package/src/execution/__tests__/ask-user-transit-e2e.test.ts +10 -4
  7. package/src/execution/__tests__/before-agent-start-injection.test.ts +132 -0
  8. package/src/execution/__tests__/bg-notify-render.test.ts +15 -15
  9. package/src/execution/__tests__/chatmode-first-round-closure-service.test.ts +365 -0
  10. package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +190 -0
  11. package/src/execution/__tests__/chatmode-round-notify-real-chain.test.ts +215 -0
  12. package/src/execution/__tests__/conversation-wiring.test.ts +198 -0
  13. package/src/execution/__tests__/crash-recovery.test.ts +8 -2
  14. package/src/execution/__tests__/delivery-methods.test.ts +385 -0
  15. package/src/execution/__tests__/epipe-fallback.test.ts +241 -0
  16. package/src/execution/__tests__/execute-and-await-worktree.test.ts +49 -2
  17. package/src/execution/__tests__/execute-nesting.test.ts +20 -72
  18. package/src/execution/__tests__/execution-record.test.ts +199 -0
  19. package/src/execution/__tests__/finalize-record.test.ts +197 -15
  20. package/src/execution/__tests__/format.test.ts +131 -7
  21. package/src/execution/__tests__/gc-timer.test.ts +184 -0
  22. package/src/execution/__tests__/get-record-for-action-restart.test.ts +254 -0
  23. package/src/execution/__tests__/helpers/spawn-mock.ts +37 -10
  24. package/src/execution/__tests__/index-session-start-identity.test.ts +371 -0
  25. package/src/execution/__tests__/index-session-start.test.ts +257 -5
  26. package/src/execution/__tests__/lifecycle-manager-lock.test.ts +211 -0
  27. package/src/execution/__tests__/lifecycle-manager.test.ts +337 -0
  28. package/src/execution/__tests__/lifecycle-predicates.test.ts +116 -0
  29. package/src/execution/__tests__/list-component.test.ts +59 -5
  30. package/src/execution/__tests__/list-fields.test.ts +109 -0
  31. package/src/execution/__tests__/model-resolver.test.ts +38 -1
  32. package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +287 -0
  33. package/src/execution/__tests__/nested-visibility.test.ts +325 -0
  34. package/src/execution/__tests__/notifier-flush.test.ts +209 -7
  35. package/src/execution/__tests__/one-shot-upgrade.test.ts +205 -0
  36. package/src/execution/__tests__/parent-child-matrix.test.ts +336 -0
  37. package/src/execution/__tests__/record-store.test.ts +442 -54
  38. package/src/execution/__tests__/recursive-visibility-baseline.test.ts +11 -12
  39. package/src/execution/__tests__/recursive-visibility-env.test.ts +18 -20
  40. package/src/execution/__tests__/resource-policy.test.ts +109 -0
  41. package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +267 -0
  42. package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +253 -0
  43. package/src/execution/__tests__/run-spawn-edges.test.ts +18 -25
  44. package/src/execution/__tests__/run-spawn-integration.test.ts +29 -25
  45. package/src/execution/__tests__/run-spawn-resume.test.ts +322 -0
  46. package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +14 -11
  47. package/src/execution/__tests__/session-pending.test.ts +61 -2
  48. package/src/execution/__tests__/session-reconstructor.test.ts +4 -4
  49. package/src/execution/__tests__/session-runner-epipe.test.ts +178 -0
  50. package/src/execution/__tests__/session-runner-schema-env.test.ts +15 -21
  51. package/src/execution/__tests__/session-start-reaper.test.ts +10 -8
  52. package/src/execution/__tests__/spawn-args.test.ts +127 -49
  53. package/src/execution/__tests__/spawn-worktree-guidance.test.ts +1 -0
  54. package/src/execution/__tests__/spawned-children.test.ts +92 -0
  55. package/src/execution/__tests__/status-refactor.test.ts +345 -0
  56. package/src/execution/__tests__/stdin-writer.test.ts +97 -0
  57. package/src/execution/__tests__/subagent-service-message-close.test.ts +629 -0
  58. package/src/execution/__tests__/subagent-service-parent-guard.test.ts +180 -0
  59. package/src/execution/__tests__/subagent-service.test.ts +49 -11
  60. package/src/execution/__tests__/timeout-integration.test.ts +27 -13
  61. package/src/execution/__tests__/tool-action.test.ts +12 -10
  62. package/src/execution/__tests__/truncline-snapshot.test.ts +81 -0
  63. package/src/execution/__tests__/turn-limiter-semantics.test.ts +194 -0
  64. package/src/execution/__tests__/worktree-manager.test.ts +300 -90
  65. package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +17 -13
  66. package/src/execution/__tests__/worktree-reconcile.integration.test.ts +181 -0
  67. package/src/execution/__tests__/worktree-registry.test.ts +72 -34
  68. package/src/execution/agent-result-mapper.ts +4 -1
  69. package/src/execution/argv-mirror.ts +21 -2
  70. package/src/execution/channel-registry-access.ts +3 -1
  71. package/src/execution/execution-record.ts +126 -9
  72. package/src/execution/finalize-record.ts +99 -13
  73. package/src/execution/idle-gc.ts +47 -0
  74. package/src/execution/lifecycle-manager.ts +491 -0
  75. package/src/execution/lifecycle-predicates.ts +65 -0
  76. package/src/execution/manifest-store.ts +61 -16
  77. package/src/execution/model-resolver.ts +26 -5
  78. package/src/execution/notifier.ts +69 -12
  79. package/src/execution/pi-invocation.ts +21 -1
  80. package/src/execution/record-entry.ts +118 -0
  81. package/src/execution/record-store.ts +844 -108
  82. package/src/execution/session-pending.ts +121 -49
  83. package/src/execution/session-reconstructor.ts +224 -7
  84. package/src/execution/session-runner.ts +713 -316
  85. package/src/execution/sessions-index.ts +304 -0
  86. package/src/execution/stdin-writer.ts +93 -7
  87. package/src/execution/stream-sink.ts +20 -3
  88. package/src/execution/subagent-service.ts +917 -138
  89. package/src/execution/temp-prompt.ts +8 -3
  90. package/src/execution/turn-limiter.ts +14 -0
  91. package/src/execution/types.ts +218 -19
  92. package/src/execution/worktree-manager.ts +449 -59
  93. package/src/execution/worktree-registry.ts +97 -29
  94. package/src/index.ts +318 -20
  95. package/src/injectors/subagent-list-injector.ts +26 -8
  96. package/src/injectors/workflow-list-injector.ts +25 -8
  97. package/src/interface/__tests__/subagent-tool-prompt.test.ts +17 -4
  98. package/src/interface/__tests__/tool-render.test.ts +10 -8
  99. package/src/interface/__tests__/tool-workflow-script-generate.test.ts +103 -26
  100. package/src/interface/__tests__/tool-workflow-throw-paths.test.ts +179 -0
  101. package/src/interface/bg-notify-render.ts +32 -8
  102. package/src/interface/command-actions.ts +26 -7
  103. package/src/interface/commands.ts +21 -22
  104. package/src/interface/format.ts +53 -20
  105. package/src/interface/gui-mappers.ts +6 -8
  106. package/src/interface/helpers.ts +170 -10
  107. package/src/interface/list-component.ts +53 -14
  108. package/src/interface/subagent-actions.ts +235 -17
  109. package/src/interface/subagent-tool.ts +81 -16
  110. package/src/interface/subagents.ts +2 -1
  111. package/src/interface/tool-render.ts +21 -27
  112. package/src/interface/tool-workflow-script.ts +29 -33
  113. package/src/interface/tool-workflow.ts +67 -100
  114. package/src/interface/views/WorkflowsView.ts +89 -32
  115. package/src/interface/views/__tests__/WorkflowsView-signature.test.ts +264 -0
  116. package/src/interface/views/detail-content.ts +1 -1
  117. package/src/interface/views/format.ts +3 -3
  118. package/src/orchestration/__tests__/__fixtures__/worker-template.snapshot.txt +333 -0
  119. package/src/orchestration/__tests__/args-validator.test.ts +1 -1
  120. package/src/orchestration/__tests__/config-loader.test.ts +38 -0
  121. package/src/orchestration/__tests__/error-recovery-handlers.test.ts +394 -4
  122. package/src/orchestration/__tests__/error-recovery-workflow-call.test.ts +4 -4
  123. package/src/orchestration/__tests__/execute-agent-call.test.ts +144 -1
  124. package/src/orchestration/__tests__/jsonl-run-store-loadall-sources.test.ts +171 -0
  125. package/src/orchestration/__tests__/jsonl-run-store-session-file.test.ts +820 -19
  126. package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +0 -2
  127. package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +96 -0
  128. package/src/orchestration/__tests__/lifecycle.test.ts +332 -149
  129. package/src/orchestration/__tests__/review-fix-loop-e2e.test.ts +1108 -19
  130. package/src/orchestration/__tests__/skill-discovery.test.ts +130 -61
  131. package/src/orchestration/__tests__/test-mocks.ts +197 -0
  132. package/src/orchestration/__tests__/worker-returnmeta-passthrough.test.ts +164 -0
  133. package/src/orchestration/__tests__/worker-script-template-snapshot.test.ts +110 -0
  134. package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +0 -2
  135. package/src/orchestration/__tests__/workflow-script-lint-memo.test.ts +110 -0
  136. package/src/orchestration/__tests__/workflows-e2e.test.ts +38 -40
  137. package/src/orchestration/agent-opts-resolver.ts +4 -1
  138. package/src/orchestration/args-validator.ts +2 -2
  139. package/src/orchestration/config-loader.ts +30 -1
  140. package/src/orchestration/error-recovery.ts +137 -30
  141. package/src/orchestration/execute-agent-call.ts +44 -10
  142. package/src/orchestration/jsonl-run-store.ts +397 -71
  143. package/src/orchestration/launcher.ts +7 -1
  144. package/src/orchestration/lifecycle.ts +145 -133
  145. package/src/orchestration/models/__tests__/trace.test.ts +408 -0
  146. package/src/orchestration/models/budget.ts +1 -1
  147. package/src/orchestration/models/run-runtime.ts +15 -17
  148. package/src/orchestration/models/run-spec.ts +2 -2
  149. package/src/orchestration/models/run-state.ts +3 -3
  150. package/src/orchestration/models/trace.ts +95 -15
  151. package/src/orchestration/models/types.ts +8 -9
  152. package/src/orchestration/models/workflow-run.ts +50 -71
  153. package/src/orchestration/models/workflow-script.ts +32 -1
  154. package/src/orchestration/skill-discovery.ts +30 -0
  155. package/src/orchestration/worker-handle.ts +1 -1
  156. package/src/orchestration/worker-host.ts +1 -1
  157. package/src/orchestration/worker-script-builder.ts +38 -11
  158. package/src/shared/__tests__/agent-ref.test.ts +34 -0
  159. package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +280 -0
  160. package/src/shared/__tests__/resource-discovery.test.ts +79 -0
  161. package/src/shared/__tests__/schema-jsonify.test.ts +81 -0
  162. package/src/shared/agent-ref.ts +22 -1
  163. package/src/shared/resource-discovery.ts +162 -59
  164. package/src/shared/schema-jsonify.ts +56 -0
  165. package/workflows/review-fix-loop-utils.cjs +542 -32
  166. package/workflows/review-fix-loop.js +462 -109
@@ -0,0 +1,171 @@
1
+ // src/orchestration/__tests__/jsonl-run-store-loadall-sources.test.ts
2
+ //
3
+ // loadAll entry 源扫描(collectEntrySources + loadRunFromStateFile)定向用例(R2-TC S4)。
4
+ //
5
+ // 防的 bug:loadAll 的多 run 重建 / 损坏 state 文件降级。W17 已覆盖单 run 的 entry 重建、
6
+ // link 兼容与读序优先级;本文件补齐三块未定向覆盖的分支:
7
+ // 1. 多 run 并存(多个 workflow-record entry run + link run 同批重建,无丢失)
8
+ // 2. 损坏 state 文件降级(末行非 JSON / 空文件 / link 指向不存在路径 / link data 缺 runId)
9
+ // ——单文件失败返回 null 跳过,不崩 loadAll、不阻断同批其余 run 重建
10
+ // 3. 同 runId 多条 record entry 末条胜出在多 run 场景下不串扰
11
+ //
12
+ // 不 mock collectEntrySources:走 loadAll 真实通路(ctx.sessionManager.getEntries 返回
13
+ // seed entries,loadRunFromStateFile 读真实临时文件)。record entry 一律经真实 save 产出
14
+ //(deserializeRun 的快照 schema 以真实 serializeRun 为准,手工拼快照会绕开 schema 契约)。
15
+
16
+ import * as fs from "node:fs";
17
+ import * as os from "node:os";
18
+ import * as path from "node:path";
19
+
20
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
21
+
22
+ import type { CustomEntry } from "@earendil-works/pi-coding-agent";
23
+
24
+ import { Budget } from "../models/budget.ts";
25
+ import { Trace } from "../models/trace.ts";
26
+ import type { ExecutionTraceNode } from "../models/types.ts";
27
+ import type { RunSpec } from "../models/run-spec.ts";
28
+ import { WorkflowRun } from "../models/workflow-run.ts";
29
+ import { JsonlRunStore } from "../jsonl-run-store.ts";
30
+ import { mkCtx, mkPi } from "./test-mocks.ts";
31
+
32
+ function makeSpec(): RunSpec {
33
+ return {
34
+ scriptSource: "module.exports = async () => {};",
35
+ args: {},
36
+ scriptName: "test-script",
37
+ scriptPath: "/tmp/test.js",
38
+ description: "test",
39
+ };
40
+ }
41
+
42
+ function makeTraceNode(stepIndex: number): ExecutionTraceNode {
43
+ return { stepIndex, agent: "worker", task: "do thing", model: "default", status: "pending" };
44
+ }
45
+
46
+ /** running → done 的完整生命周期 save(终态快照可被 deserializeRun 重建)。 */
47
+ async function saveDoneRun(
48
+ sessionDir: string,
49
+ entries: CustomEntry[],
50
+ runId: string,
51
+ ): Promise<void> {
52
+ const store = new JsonlRunStore({ sessionDir, pi: mkPi(entries) });
53
+ const run = makeRunningRun(runId);
54
+ await store.save(run);
55
+ run.transition("done", "completed");
56
+ await store.save(run);
57
+ }
58
+
59
+ function makeRunningRun(runId: string): WorkflowRun {
60
+ const trace = new Trace();
61
+ trace.append(makeTraceNode(0));
62
+ return WorkflowRun.reconstruct(runId, makeSpec(), {
63
+ status: "running",
64
+ budget: new Budget(),
65
+ calls: new Map(),
66
+ trace,
67
+ errorLogs: [],
68
+ }, { startedAt: new Date().toISOString() });
69
+ }
70
+
71
+ /** 手工构造旧 workflow-state-link 指针 entry(loadAll 的 link 兼容输入)。 */
72
+ function linkEntry(runId: string, statePath: string): CustomEntry {
73
+ return {
74
+ type: "custom",
75
+ customType: "workflow-state-link",
76
+ data: { runId, path: statePath },
77
+ id: `seed-link-${runId}`,
78
+ parentId: null,
79
+ timestamp: new Date().toISOString(),
80
+ };
81
+ }
82
+
83
+ describe("loadAll entry 源扫描:多 run 重建与损坏 state 降级(R2-TC S4)", () => {
84
+ let tmpDir: string;
85
+
86
+ beforeEach(() => {
87
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "wf-loadall-src-"));
88
+ });
89
+
90
+ afterEach(() => {
91
+ fs.rmSync(tmpDir, { recursive: true, force: true });
92
+ });
93
+
94
+ it("多 run 并存:2 个 entry run + 1 个 link run 同批全部重建(无丢失)", async () => {
95
+ // run-a/run-b 经真实 save 通路产出终态 entry(快照形态可信)
96
+ const entries: CustomEntry[] = [];
97
+ await saveDoneRun(tmpDir, entries, "run-a");
98
+ await saveDoneRun(tmpDir, entries, "run-b");
99
+
100
+ // run-c:旧 link 形态(state 文件完好,无 record entry)
101
+ const storeC = new JsonlRunStore({ sessionDir: tmpDir });
102
+ const runC = makeRunningRun("run-c");
103
+ await storeC.save(runC);
104
+ runC.transition("done", "completed");
105
+ await storeC.save(runC);
106
+ const linkPath = path.join(tmpDir, "workflow-state", "run-c.jsonl");
107
+ expect(fs.existsSync(linkPath)).toBe(true);
108
+ const seedEntries: CustomEntry[] = [...entries, linkEntry("run-c", linkPath)];
109
+
110
+ const store = new JsonlRunStore({ sessionDir: tmpDir, ctx: mkCtx(seedEntries) });
111
+ const loaded = await store.loadAll();
112
+ expect(loaded.map((r) => r.runId).sort()).toEqual(["run-a", "run-b", "run-c"]);
113
+ });
114
+
115
+ it("损坏 state 文件(末行非 JSON)→ 该 run 跳过不崩,同批其余 run(entry run)正常返回", async () => {
116
+ const entries: CustomEntry[] = [];
117
+ await saveDoneRun(tmpDir, entries, "run-good");
118
+
119
+ const corruptPath = path.join(tmpDir, "workflow-state", "run-corrupt.jsonl");
120
+ fs.mkdirSync(path.dirname(corruptPath), { recursive: true });
121
+ fs.writeFileSync(corruptPath, "{truncated-not-json\n", "utf8");
122
+
123
+ const seedEntries: CustomEntry[] = [...entries, linkEntry("run-corrupt", corruptPath)];
124
+ const store = new JsonlRunStore({ sessionDir: tmpDir, ctx: mkCtx(seedEntries) });
125
+ const loaded = await store.loadAll();
126
+ expect(loaded.map((r) => r.runId)).toEqual(["run-good"]);
127
+ });
128
+
129
+ it("损坏形态族:空文件 / link 指向不存在路径 / link data 缺 runId → 均降级跳过,loadAll 不抛", async () => {
130
+ const emptyPath = path.join(tmpDir, "workflow-state", "run-empty.jsonl");
131
+ fs.mkdirSync(path.dirname(emptyPath), { recursive: true });
132
+ fs.writeFileSync(emptyPath, "", "utf8");
133
+ const missingPath = path.join(tmpDir, "workflow-state", "run-missing.jsonl");
134
+
135
+ const malformedLink = linkEntry("run-bad", emptyPath);
136
+ (malformedLink.data as Record<string, unknown>).runId = undefined; // 缺 runId 的坏指针
137
+
138
+ // 对照组:一条合法 record entry run 应正常重建(真实 save 产出)
139
+ const entries: CustomEntry[] = [];
140
+ await saveDoneRun(tmpDir, entries, "run-seeded");
141
+
142
+ const seedEntries: CustomEntry[] = [
143
+ ...entries,
144
+ linkEntry("run-empty", emptyPath),
145
+ linkEntry("run-missing", missingPath),
146
+ malformedLink,
147
+ ];
148
+ const store = new JsonlRunStore({ sessionDir: tmpDir, ctx: mkCtx(seedEntries) });
149
+ const loaded = await store.loadAll();
150
+ expect(loaded.map((r) => r.runId)).toEqual(["run-seeded"]);
151
+ });
152
+
153
+ it("同 runId 多条 record entry 末条胜出(running→done 收敛)+ 另一 run 不受影响(混合批不串扰)", async () => {
154
+ const entries: CustomEntry[] = [];
155
+ // run-x:两条 entry(running 中间态 + done 终态),末条胜出
156
+ const storeX = new JsonlRunStore({ sessionDir: tmpDir, pi: mkPi(entries) });
157
+ const runX = makeRunningRun("run-x");
158
+ await storeX.save(runX);
159
+ runX.transition("done", "completed");
160
+ await storeX.save(runX);
161
+ // run-y:done 终态
162
+ await saveDoneRun(tmpDir, entries, "run-y");
163
+
164
+ const store = new JsonlRunStore({ sessionDir: tmpDir, ctx: mkCtx(entries) });
165
+ const loaded = await store.loadAll();
166
+ const byId = new Map(loaded.map((r) => [r.runId, r]));
167
+ expect(loaded).toHaveLength(2);
168
+ expect(byId.get("run-x")?.state.status).toBe("done");
169
+ expect(byId.get("run-y")?.state.status).toBe("done");
170
+ });
171
+ });