@ronkovic/aad 0.3.9 → 0.4.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 (114) hide show
  1. package/README.md +292 -12
  2. package/package.json +6 -1
  3. package/src/__tests__/e2e/pipeline-e2e.test.ts +1 -0
  4. package/src/__tests__/e2e/resume-e2e.test.ts +2 -0
  5. package/src/__tests__/integration/pipeline.test.ts +1 -0
  6. package/src/modules/claude-provider/__tests__/claude-sdk-real-env.test.ts +1 -1
  7. package/src/modules/claude-provider/__tests__/claude-sdk.adapter.test.ts +2 -0
  8. package/src/modules/claude-provider/__tests__/provider-registry.test.ts +1 -0
  9. package/src/modules/cli/__tests__/cleanup.test.ts +72 -0
  10. package/src/modules/cli/__tests__/resume.test.ts +1 -0
  11. package/src/modules/cli/__tests__/run.test.ts +1 -0
  12. package/src/modules/cli/commands/__tests__/task-dispatch-handler.test.ts +145 -0
  13. package/src/modules/cli/commands/cleanup.ts +26 -11
  14. package/src/modules/cli/commands/resume.ts +3 -2
  15. package/src/modules/cli/commands/run.ts +57 -7
  16. package/src/modules/cli/commands/task-dispatch-handler.ts +73 -3
  17. package/src/modules/dashboard/__tests__/api-graph.test.ts +332 -0
  18. package/src/modules/dashboard/__tests__/api-timeline.test.ts +461 -0
  19. package/src/modules/dashboard/routes/sse.ts +3 -2
  20. package/src/modules/dashboard/server.ts +1 -0
  21. package/src/modules/dashboard/services/sse-broadcaster.ts +29 -0
  22. package/src/modules/dashboard/ui/dashboard.html +143 -18
  23. package/src/modules/git-workspace/__tests__/branch-manager.test.ts +52 -0
  24. package/src/modules/git-workspace/__tests__/dependency-installer.test.ts +77 -0
  25. package/src/modules/git-workspace/__tests__/git-exec.test.ts +26 -0
  26. package/src/modules/git-workspace/__tests__/merge-service.test.ts +19 -0
  27. package/src/modules/git-workspace/__tests__/pr-manager.test.ts +80 -0
  28. package/src/modules/git-workspace/__tests__/template-copy.test.ts +189 -0
  29. package/src/modules/git-workspace/__tests__/worktree-cleanup.test.ts +29 -2
  30. package/src/modules/git-workspace/__tests__/worktree-manager.test.ts +64 -4
  31. package/src/modules/git-workspace/branch-manager.ts +24 -3
  32. package/src/modules/git-workspace/dependency-installer.ts +113 -0
  33. package/src/modules/git-workspace/git-exec.ts +3 -2
  34. package/src/modules/git-workspace/index.ts +10 -1
  35. package/src/modules/git-workspace/merge-service.ts +36 -2
  36. package/src/modules/git-workspace/pr-manager.ts +278 -0
  37. package/src/modules/git-workspace/template-copy.ts +302 -0
  38. package/src/modules/git-workspace/worktree-manager.ts +37 -11
  39. package/src/modules/planning/__tests__/planning-service.test.ts +1 -0
  40. package/src/modules/planning/__tests__/planning.service.test.ts +149 -0
  41. package/src/modules/planning/__tests__/project-detection.test.ts +7 -1
  42. package/src/modules/planning/planning.service.ts +16 -2
  43. package/src/modules/planning/project-detection.ts +4 -1
  44. package/src/modules/process-manager/__tests__/process-manager.test.ts +1 -0
  45. package/src/modules/task-execution/__tests__/executor.test.ts +86 -0
  46. package/src/modules/task-execution/__tests__/tester-verify.test.ts +4 -3
  47. package/src/modules/task-execution/executor.ts +87 -4
  48. package/src/modules/task-execution/phases/implementer-green.ts +22 -5
  49. package/src/modules/task-execution/phases/merge.ts +44 -2
  50. package/src/modules/task-execution/phases/tester-red.ts +22 -5
  51. package/src/modules/task-execution/phases/tester-verify.ts +22 -6
  52. package/src/modules/task-queue/dispatcher.ts +50 -1
  53. package/src/shared/__tests__/prerequisites.test.ts +176 -0
  54. package/src/shared/config.ts +6 -0
  55. package/src/shared/prerequisites.ts +190 -0
  56. package/src/shared/types.ts +13 -0
  57. package/templates/CLAUDE.md +122 -0
  58. package/templates/settings.json +117 -0
  59. package/src/modules/persistence/__tests__/.tmp-stores-test-81991/progress.json +0 -10
  60. package/src/modules/persistence/__tests__/.tmp-stores-test-81991/queue/completed/task-getall-2.json +0 -10
  61. package/src/modules/persistence/__tests__/.tmp-stores-test-81991/queue/pending/task-1.json +0 -13
  62. package/src/modules/persistence/__tests__/.tmp-stores-test-81991/queue/pending/task-getall-1.json +0 -10
  63. package/src/modules/persistence/__tests__/.tmp-stores-test-81991/queue/pending/task-status-change.json +0 -10
  64. package/src/modules/persistence/__tests__/.tmp-stores-test-81991/workers/worker-1.json +0 -5
  65. package/src/modules/persistence/__tests__/.tmp-stores-test-81991/workers/worker-2.json +0 -5
  66. package/src/modules/persistence/__tests__/.tmp-stores-test-82469/progress.json +0 -10
  67. package/src/modules/persistence/__tests__/.tmp-stores-test-82469/queue/completed/task-getall-2.json +0 -10
  68. package/src/modules/persistence/__tests__/.tmp-stores-test-82469/queue/pending/task-1.json +0 -13
  69. package/src/modules/persistence/__tests__/.tmp-stores-test-82469/queue/pending/task-getall-1.json +0 -10
  70. package/src/modules/persistence/__tests__/.tmp-stores-test-82469/queue/pending/task-status-change.json +0 -10
  71. package/src/modules/persistence/__tests__/.tmp-stores-test-82469/workers/worker-1.json +0 -5
  72. package/src/modules/persistence/__tests__/.tmp-stores-test-82469/workers/worker-2.json +0 -5
  73. package/src/modules/persistence/__tests__/.tmp-stores-test-85301/progress.json +0 -10
  74. package/src/modules/persistence/__tests__/.tmp-stores-test-85301/queue/completed/task-getall-2.json +0 -10
  75. package/src/modules/persistence/__tests__/.tmp-stores-test-85301/queue/pending/task-1.json +0 -13
  76. package/src/modules/persistence/__tests__/.tmp-stores-test-85301/queue/pending/task-getall-1.json +0 -10
  77. package/src/modules/persistence/__tests__/.tmp-stores-test-85301/queue/pending/task-status-change.json +0 -10
  78. package/src/modules/persistence/__tests__/.tmp-stores-test-85301/workers/worker-1.json +0 -5
  79. package/src/modules/persistence/__tests__/.tmp-stores-test-85301/workers/worker-2.json +0 -5
  80. package/src/modules/persistence/__tests__/.tmp-stores-test-85759/progress.json +0 -10
  81. package/src/modules/persistence/__tests__/.tmp-stores-test-85759/queue/completed/task-getall-2.json +0 -10
  82. package/src/modules/persistence/__tests__/.tmp-stores-test-85759/queue/pending/task-1.json +0 -13
  83. package/src/modules/persistence/__tests__/.tmp-stores-test-85759/queue/pending/task-getall-1.json +0 -10
  84. package/src/modules/persistence/__tests__/.tmp-stores-test-85759/queue/pending/task-status-change.json +0 -10
  85. package/src/modules/persistence/__tests__/.tmp-stores-test-85759/workers/worker-1.json +0 -5
  86. package/src/modules/persistence/__tests__/.tmp-stores-test-85759/workers/worker-2.json +0 -5
  87. package/src/modules/persistence/__tests__/.tmp-stores-test-86184/progress.json +0 -10
  88. package/src/modules/persistence/__tests__/.tmp-stores-test-86184/queue/completed/task-getall-2.json +0 -10
  89. package/src/modules/persistence/__tests__/.tmp-stores-test-86184/queue/pending/task-1.json +0 -13
  90. package/src/modules/persistence/__tests__/.tmp-stores-test-86184/queue/pending/task-getall-1.json +0 -10
  91. package/src/modules/persistence/__tests__/.tmp-stores-test-86184/queue/pending/task-status-change.json +0 -10
  92. package/src/modules/persistence/__tests__/.tmp-stores-test-86184/workers/worker-1.json +0 -5
  93. package/src/modules/persistence/__tests__/.tmp-stores-test-86184/workers/worker-2.json +0 -5
  94. package/src/modules/persistence/__tests__/.tmp-stores-test-88026/progress.json +0 -10
  95. package/src/modules/persistence/__tests__/.tmp-stores-test-88026/queue/completed/task-getall-2.json +0 -10
  96. package/src/modules/persistence/__tests__/.tmp-stores-test-88026/queue/pending/task-1.json +0 -13
  97. package/src/modules/persistence/__tests__/.tmp-stores-test-88026/queue/pending/task-getall-1.json +0 -10
  98. package/src/modules/persistence/__tests__/.tmp-stores-test-88026/queue/pending/task-status-change.json +0 -10
  99. package/src/modules/persistence/__tests__/.tmp-stores-test-88026/workers/worker-1.json +0 -5
  100. package/src/modules/persistence/__tests__/.tmp-stores-test-88026/workers/worker-2.json +0 -5
  101. package/src/modules/persistence/__tests__/.tmp-stores-test-89475/progress.json +0 -10
  102. package/src/modules/persistence/__tests__/.tmp-stores-test-89475/queue/completed/task-getall-2.json +0 -10
  103. package/src/modules/persistence/__tests__/.tmp-stores-test-89475/queue/pending/task-1.json +0 -13
  104. package/src/modules/persistence/__tests__/.tmp-stores-test-89475/queue/pending/task-getall-1.json +0 -10
  105. package/src/modules/persistence/__tests__/.tmp-stores-test-89475/queue/pending/task-status-change.json +0 -10
  106. package/src/modules/persistence/__tests__/.tmp-stores-test-89475/workers/worker-1.json +0 -5
  107. package/src/modules/persistence/__tests__/.tmp-stores-test-89475/workers/worker-2.json +0 -5
  108. package/src/modules/persistence/__tests__/.tmp-stores-test-89924/progress.json +0 -10
  109. package/src/modules/persistence/__tests__/.tmp-stores-test-89924/queue/completed/task-getall-2.json +0 -10
  110. package/src/modules/persistence/__tests__/.tmp-stores-test-89924/queue/pending/task-1.json +0 -13
  111. package/src/modules/persistence/__tests__/.tmp-stores-test-89924/queue/pending/task-getall-1.json +0 -10
  112. package/src/modules/persistence/__tests__/.tmp-stores-test-89924/queue/pending/task-status-change.json +0 -10
  113. package/src/modules/persistence/__tests__/.tmp-stores-test-89924/workers/worker-1.json +0 -5
  114. package/src/modules/persistence/__tests__/.tmp-stores-test-89924/workers/worker-2.json +0 -5
@@ -0,0 +1,332 @@
1
+ import { describe, test, expect } from "bun:test";
2
+ import type { StateAggregator } from "../services/state-aggregator";
3
+
4
+ /**
5
+ * テストケース: /api/graph エンドポイント
6
+ *
7
+ * DAG (Directed Acyclic Graph) 可視化用のタスク依存関係グラフを返す
8
+ * - nodes: タスクのリスト (id, status)
9
+ * - edges: 依存関係のリスト (from → to)
10
+ */
11
+ describe("GET /api/graph - Task Dependency Graph", () => {
12
+ /**
13
+ * テストケース 1: 空のグラフ (タスクなし)
14
+ *
15
+ * 期待値:
16
+ * - nodes: 空配列
17
+ * - edges: 空配列
18
+ */
19
+ test("returns empty graph when no tasks exist", async () => {
20
+ const mockAggregator: StateAggregator = {
21
+ getGraph: async () => ({
22
+ nodes: [],
23
+ edges: [],
24
+ }),
25
+ } as any;
26
+
27
+ const result = await mockAggregator.getGraph();
28
+
29
+ expect(result.nodes).toEqual([]);
30
+ expect(result.edges).toEqual([]);
31
+ });
32
+
33
+ /**
34
+ * テストケース 2: 単一タスク (依存関係なし)
35
+ *
36
+ * グラフ構造:
37
+ *
38
+ * [task-1]
39
+ *
40
+ * 期待値:
41
+ * - nodes: 1つのノード
42
+ * - edges: 空配列
43
+ */
44
+ test("returns single node with no edges for independent task", async () => {
45
+ const mockAggregator: StateAggregator = {
46
+ getGraph: async () => ({
47
+ nodes: [
48
+ { id: "task-1", status: "pending" },
49
+ ],
50
+ edges: [],
51
+ }),
52
+ } as any;
53
+
54
+ const result = await mockAggregator.getGraph();
55
+
56
+ expect(result.nodes).toHaveLength(1);
57
+ expect(result.nodes[0]).toEqual({ id: "task-1", status: "pending" });
58
+ expect(result.edges).toEqual([]);
59
+ });
60
+
61
+ /**
62
+ * テストケース 3: 線形依存 (task-1 → task-2 → task-3)
63
+ *
64
+ * グラフ構造:
65
+ *
66
+ * [task-1] → [task-2] → [task-3]
67
+ *
68
+ * 依存関係:
69
+ * - task-2 depends_on task-1
70
+ * - task-3 depends_on task-2
71
+ */
72
+ test("returns linear dependency chain", async () => {
73
+ const mockAggregator: StateAggregator = {
74
+ getGraph: async () => ({
75
+ nodes: [
76
+ { id: "task-1", status: "completed" },
77
+ { id: "task-2", status: "running" },
78
+ { id: "task-3", status: "pending" },
79
+ ],
80
+ edges: [
81
+ { from: "task-1", to: "task-2" },
82
+ { from: "task-2", to: "task-3" },
83
+ ],
84
+ }),
85
+ } as any;
86
+
87
+ const result = await mockAggregator.getGraph();
88
+
89
+ expect(result.nodes).toHaveLength(3);
90
+ expect(result.edges).toHaveLength(2);
91
+
92
+ // エッジの正確性を検証
93
+ expect(result.edges).toContainEqual({ from: "task-1", to: "task-2" });
94
+ expect(result.edges).toContainEqual({ from: "task-2", to: "task-3" });
95
+
96
+ // ステータスの検証
97
+ const task1 = result.nodes.find((n) => n.id === "task-1");
98
+ const task2 = result.nodes.find((n) => n.id === "task-2");
99
+ const task3 = result.nodes.find((n) => n.id === "task-3");
100
+
101
+ expect(task1?.status).toBe("completed");
102
+ expect(task2?.status).toBe("running");
103
+ expect(task3?.status).toBe("pending");
104
+ });
105
+
106
+ /**
107
+ * テストケース 4: 並列タスク (task-1, task-2 独立、両方が task-3 に依存される)
108
+ *
109
+ * グラフ構造:
110
+ *
111
+ * [task-1] ─┐
112
+ * ├→ [task-3]
113
+ * [task-2] ─┘
114
+ *
115
+ * 依存関係:
116
+ * - task-3 depends_on [task-1, task-2]
117
+ */
118
+ test("returns parallel tasks converging into single task", async () => {
119
+ const mockAggregator: StateAggregator = {
120
+ getGraph: async () => ({
121
+ nodes: [
122
+ { id: "task-1", status: "completed" },
123
+ { id: "task-2", status: "completed" },
124
+ { id: "task-3", status: "running" },
125
+ ],
126
+ edges: [
127
+ { from: "task-1", to: "task-3" },
128
+ { from: "task-2", to: "task-3" },
129
+ ],
130
+ }),
131
+ } as any;
132
+
133
+ const result = await mockAggregator.getGraph();
134
+
135
+ expect(result.nodes).toHaveLength(3);
136
+ expect(result.edges).toHaveLength(2);
137
+
138
+ // task-3 は task-1 と task-2 両方に依存
139
+ const edgesToTask3 = result.edges.filter((e) => e.to === "task-3");
140
+ expect(edgesToTask3).toHaveLength(2);
141
+
142
+ expect(edgesToTask3).toContainEqual({ from: "task-1", to: "task-3" });
143
+ expect(edgesToTask3).toContainEqual({ from: "task-2", to: "task-3" });
144
+
145
+ // task-1, task-2 は並列実行可能 (互いに依存しない)
146
+ const edgesBetween1And2 = result.edges.filter(
147
+ (e) =>
148
+ (e.from === "task-1" && e.to === "task-2") ||
149
+ (e.from === "task-2" && e.to === "task-1")
150
+ );
151
+ expect(edgesBetween1And2).toHaveLength(0);
152
+ });
153
+
154
+ /**
155
+ * テストケース 5: ダイヤモンド依存 (task-1 → task-2,3 → task-4)
156
+ *
157
+ * グラフ構造:
158
+ *
159
+ * [task-1]
160
+ * ↙ ↘
161
+ * [task-2] [task-3]
162
+ * ↘ ↙
163
+ * [task-4]
164
+ *
165
+ * 依存関係:
166
+ * - task-2 depends_on task-1
167
+ * - task-3 depends_on task-1
168
+ * - task-4 depends_on [task-2, task-3]
169
+ */
170
+ test("returns diamond dependency graph", async () => {
171
+ const mockAggregator: StateAggregator = {
172
+ getGraph: async () => ({
173
+ nodes: [
174
+ { id: "task-1", status: "completed" },
175
+ { id: "task-2", status: "running" },
176
+ { id: "task-3", status: "running" },
177
+ { id: "task-4", status: "pending" },
178
+ ],
179
+ edges: [
180
+ { from: "task-1", to: "task-2" },
181
+ { from: "task-1", to: "task-3" },
182
+ { from: "task-2", to: "task-4" },
183
+ { from: "task-3", to: "task-4" },
184
+ ],
185
+ }),
186
+ } as any;
187
+
188
+ const result = await mockAggregator.getGraph();
189
+
190
+ expect(result.nodes).toHaveLength(4);
191
+ expect(result.edges).toHaveLength(4);
192
+
193
+ // task-1 は task-2, task-3 に分岐
194
+ const edgesFromTask1 = result.edges.filter((e) => e.from === "task-1");
195
+ expect(edgesFromTask1).toHaveLength(2);
196
+ expect(edgesFromTask1).toContainEqual({ from: "task-1", to: "task-2" });
197
+ expect(edgesFromTask1).toContainEqual({ from: "task-1", to: "task-3" });
198
+
199
+ // task-4 は task-2, task-3 からマージ
200
+ const edgesToTask4 = result.edges.filter((e) => e.to === "task-4");
201
+ expect(edgesToTask4).toHaveLength(2);
202
+ expect(edgesToTask4).toContainEqual({ from: "task-2", to: "task-4" });
203
+ expect(edgesToTask4).toContainEqual({ from: "task-3", to: "task-4" });
204
+
205
+ // ステータス検証: task-1完了、task-2/3実行中、task-4保留
206
+ expect(result.nodes.find((n) => n.id === "task-1")?.status).toBe("completed");
207
+ expect(result.nodes.find((n) => n.id === "task-2")?.status).toBe("running");
208
+ expect(result.nodes.find((n) => n.id === "task-3")?.status).toBe("running");
209
+ expect(result.nodes.find((n) => n.id === "task-4")?.status).toBe("pending");
210
+ });
211
+
212
+ /**
213
+ * テストケース 6: 複雑なグラフ (多段階並列依存)
214
+ *
215
+ * グラフ構造:
216
+ *
217
+ * [task-1] → [task-2] ─┐
218
+ * ├→ [task-5]
219
+ * [task-3] → [task-4] ─┘
220
+ *
221
+ * 依存関係:
222
+ * - task-2 depends_on task-1
223
+ * - task-4 depends_on task-3
224
+ * - task-5 depends_on [task-2, task-4]
225
+ */
226
+ test("returns complex multi-level parallel graph", async () => {
227
+ const mockAggregator: StateAggregator = {
228
+ getGraph: async () => ({
229
+ nodes: [
230
+ { id: "task-1", status: "completed" },
231
+ { id: "task-2", status: "completed" },
232
+ { id: "task-3", status: "completed" },
233
+ { id: "task-4", status: "running" },
234
+ { id: "task-5", status: "pending" },
235
+ ],
236
+ edges: [
237
+ { from: "task-1", to: "task-2" },
238
+ { from: "task-3", to: "task-4" },
239
+ { from: "task-2", to: "task-5" },
240
+ { from: "task-4", to: "task-5" },
241
+ ],
242
+ }),
243
+ } as any;
244
+
245
+ const result = await mockAggregator.getGraph();
246
+
247
+ expect(result.nodes).toHaveLength(5);
248
+ expect(result.edges).toHaveLength(4);
249
+
250
+ // task-1, task-3 は並列実行可能な起点
251
+ const rootTasks = result.nodes.filter(
252
+ (node) => !result.edges.some((edge) => edge.to === node.id)
253
+ );
254
+ expect(rootTasks).toHaveLength(2);
255
+ expect(rootTasks.map((t) => t.id).sort()).toEqual(["task-1", "task-3"]);
256
+
257
+ // task-5 は最終的な合流点
258
+ const edgesToTask5 = result.edges.filter((e) => e.to === "task-5");
259
+ expect(edgesToTask5).toHaveLength(2);
260
+ });
261
+
262
+ /**
263
+ * テストケース 7: タスクステータスのバリエーション検証
264
+ *
265
+ * 全ステータス (pending, running, completed, failed) を含むグラフ
266
+ */
267
+ test("returns graph with all task status types", async () => {
268
+ const mockAggregator: StateAggregator = {
269
+ getGraph: async () => ({
270
+ nodes: [
271
+ { id: "task-1", status: "completed" },
272
+ { id: "task-2", status: "running" },
273
+ { id: "task-3", status: "pending" },
274
+ { id: "task-4", status: "failed" },
275
+ ],
276
+ edges: [
277
+ { from: "task-1", to: "task-2" },
278
+ { from: "task-1", to: "task-4" },
279
+ ],
280
+ }),
281
+ } as any;
282
+
283
+ const result = await mockAggregator.getGraph();
284
+
285
+ expect(result.nodes).toHaveLength(4);
286
+
287
+ const statuses = result.nodes.map((n) => n.status).sort();
288
+ expect(statuses).toEqual(["completed", "failed", "pending", "running"]);
289
+
290
+ // 各ステータスのノードが存在することを確認
291
+ expect(result.nodes.some((n) => n.status === "completed")).toBe(true);
292
+ expect(result.nodes.some((n) => n.status === "running")).toBe(true);
293
+ expect(result.nodes.some((n) => n.status === "pending")).toBe(true);
294
+ expect(result.nodes.some((n) => n.status === "failed")).toBe(true);
295
+ });
296
+
297
+ /**
298
+ * テストケース 8: グラフ構造の整合性検証
299
+ *
300
+ * - 全エッジの from/to が nodes に存在することを確認
301
+ * - 自己参照エッジがないことを確認
302
+ */
303
+ test("validates graph structure integrity", async () => {
304
+ const mockAggregator: StateAggregator = {
305
+ getGraph: async () => ({
306
+ nodes: [
307
+ { id: "task-1", status: "completed" },
308
+ { id: "task-2", status: "running" },
309
+ { id: "task-3", status: "pending" },
310
+ ],
311
+ edges: [
312
+ { from: "task-1", to: "task-2" },
313
+ { from: "task-2", to: "task-3" },
314
+ ],
315
+ }),
316
+ } as any;
317
+
318
+ const result = await mockAggregator.getGraph();
319
+
320
+ const nodeIds = new Set(result.nodes.map((n) => n.id));
321
+
322
+ // 全エッジの from/to が nodes に存在
323
+ for (const edge of result.edges) {
324
+ expect(nodeIds.has(edge.from)).toBe(true);
325
+ expect(nodeIds.has(edge.to)).toBe(true);
326
+ }
327
+
328
+ // 自己参照エッジがない
329
+ const selfReferentialEdges = result.edges.filter((e) => e.from === e.to);
330
+ expect(selfReferentialEdges).toHaveLength(0);
331
+ });
332
+ });