maskweaver 0.9.3 → 0.9.5

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 (246) hide show
  1. package/README.ko.md +279 -325
  2. package/README.md +109 -113
  3. package/assets/commands/meta/commands.json +34 -34
  4. package/assets/commands/weave-agents.md +12 -52
  5. package/assets/commands/weave-approve.md +12 -51
  6. package/assets/commands/weave-archive.md +21 -0
  7. package/assets/commands/weave-build.md +20 -89
  8. package/assets/commands/weave-craft.md +22 -43
  9. package/assets/commands/weave-help.md +37 -106
  10. package/assets/commands/weave-init.md +26 -108
  11. package/assets/commands/weave-interview.md +13 -111
  12. package/assets/commands/weave-map.md +13 -99
  13. package/assets/commands/weave-prepare.md +23 -69
  14. package/assets/commands/weave-refine-plan.md +26 -59
  15. package/assets/commands/weave-repair.md +22 -70
  16. package/assets/commands/weave-status.md +22 -155
  17. package/assets/commands/weave-troubleshoot.md +11 -47
  18. package/assets/commands/weave-verify.md +23 -44
  19. package/assets/commands/weave-worktree.md +27 -69
  20. package/dist/cli/doctor.js +5 -21
  21. package/dist/cli/install.d.ts +0 -8
  22. package/dist/cli/install.js +0 -39
  23. package/dist/context/config.d.ts +0 -22
  24. package/dist/context/config.js +0 -28
  25. package/dist/context/feature.d.ts +0 -39
  26. package/dist/context/feature.js +0 -77
  27. package/dist/context/files.d.ts +0 -13
  28. package/dist/context/files.js +1 -24
  29. package/dist/context/index.d.ts +0 -7
  30. package/dist/context/index.js +0 -12
  31. package/dist/context/project.d.ts +0 -21
  32. package/dist/context/project.js +0 -30
  33. package/dist/context/types.d.ts +0 -48
  34. package/dist/context/types.js +0 -12
  35. package/dist/context/utils.d.ts +0 -18
  36. package/dist/context/utils.js +0 -27
  37. package/dist/core/engine/promptBuilder.d.ts +0 -17
  38. package/dist/core/engine/promptBuilder.js +0 -28
  39. package/dist/core/index.d.ts +0 -6
  40. package/dist/core/index.js +0 -9
  41. package/dist/core/loader/MaskLoader.d.ts +0 -23
  42. package/dist/core/loader/MaskLoader.js +0 -29
  43. package/dist/core/schema/types.d.ts +0 -47
  44. package/dist/core/schema/types.js +0 -6
  45. package/dist/core/schema/validator.d.ts +0 -14
  46. package/dist/core/schema/validator.js +0 -18
  47. package/dist/i18n/index.d.ts +0 -18
  48. package/dist/i18n/index.js +4 -23
  49. package/dist/index.d.ts +0 -8
  50. package/dist/index.js +0 -8
  51. package/dist/lib.d.ts +0 -5
  52. package/dist/lib.js +0 -12
  53. package/dist/memory/chunking.d.ts +0 -22
  54. package/dist/memory/chunking.js +2 -37
  55. package/dist/memory/core.d.ts +0 -29
  56. package/dist/memory/core.js +1 -52
  57. package/dist/memory/index.d.ts +0 -5
  58. package/dist/memory/index.js +0 -10
  59. package/dist/memory/indexer.d.ts +0 -21
  60. package/dist/memory/indexer.js +0 -44
  61. package/dist/memory/providers/examples.d.ts +0 -5
  62. package/dist/memory/providers/examples.js +4 -64
  63. package/dist/memory/providers/factory.d.ts +0 -44
  64. package/dist/memory/providers/factory.js +0 -46
  65. package/dist/memory/providers/index.d.ts +0 -26
  66. package/dist/memory/providers/index.js +0 -28
  67. package/dist/memory/providers/ollama.d.ts +0 -6
  68. package/dist/memory/providers/ollama.js +1 -8
  69. package/dist/memory/providers/openai.d.ts +0 -6
  70. package/dist/memory/providers/openai.js +1 -8
  71. package/dist/memory/providers/openrouter.d.ts +0 -6
  72. package/dist/memory/providers/openrouter.js +0 -8
  73. package/dist/memory/providers/text-only.d.ts +0 -13
  74. package/dist/memory/providers/text-only.js +0 -17
  75. package/dist/memory/providers/types.d.ts +0 -39
  76. package/dist/memory/providers/types.js +0 -7
  77. package/dist/memory/providers/voyage.d.ts +0 -22
  78. package/dist/memory/providers/voyage.js +1 -24
  79. package/dist/memory/search/hybrid.d.ts +0 -12
  80. package/dist/memory/search/hybrid.js +1 -22
  81. package/dist/memory/store/sqlite.d.ts +0 -72
  82. package/dist/memory/store/sqlite.js +4 -127
  83. package/dist/plugin/config/index.d.ts +0 -112
  84. package/dist/plugin/config/index.js +0 -115
  85. package/dist/plugin/index.d.ts +0 -13
  86. package/dist/plugin/index.js +1 -124
  87. package/dist/plugin/tools/command-registry.d.ts +0 -6
  88. package/dist/plugin/tools/command-registry.js +0 -14
  89. package/dist/plugin/tools/context.d.ts +0 -12
  90. package/dist/plugin/tools/context.js +0 -58
  91. package/dist/plugin/tools/maskSave.d.ts +0 -3
  92. package/dist/plugin/tools/maskSave.js +0 -3
  93. package/dist/plugin/tools/memoryGet.d.ts +0 -3
  94. package/dist/plugin/tools/memoryGet.js +0 -3
  95. package/dist/plugin/tools/memoryIndexer.d.ts +0 -3
  96. package/dist/plugin/tools/memoryIndexer.js +0 -10
  97. package/dist/plugin/tools/memorySearch.d.ts +0 -31
  98. package/dist/plugin/tools/memorySearch.js +0 -79
  99. package/dist/plugin/tools/memoryWrite.d.ts +0 -8
  100. package/dist/plugin/tools/memoryWrite.js +0 -32
  101. package/dist/plugin/tools/retrospect.d.ts +0 -3
  102. package/dist/plugin/tools/retrospect.js +0 -3
  103. package/dist/plugin/tools/slashcommand.d.ts +0 -11
  104. package/dist/plugin/tools/slashcommand.js +0 -38
  105. package/dist/plugin/tools/squad.d.ts +0 -12
  106. package/dist/plugin/tools/squad.js +11 -83
  107. package/dist/plugin/tools/weave.d.ts +0 -6
  108. package/dist/plugin/tools/weave.js +0 -78
  109. package/dist/plugin/types.d.ts +0 -20
  110. package/dist/plugin/types.js +0 -7
  111. package/dist/retrospect/index.d.ts +0 -7
  112. package/dist/retrospect/index.js +0 -9
  113. package/dist/retrospect/mask-save.d.ts +0 -12
  114. package/dist/retrospect/mask-save.js +1 -80
  115. package/dist/retrospect/retrospect.d.ts +0 -18
  116. package/dist/retrospect/retrospect.js +0 -63
  117. package/dist/retrospect/strategies/base.d.ts +0 -15
  118. package/dist/retrospect/strategies/base.js +0 -7
  119. package/dist/retrospect/strategies/deep.d.ts +0 -12
  120. package/dist/retrospect/strategies/deep.js +0 -24
  121. package/dist/retrospect/strategies/index.d.ts +0 -12
  122. package/dist/retrospect/strategies/index.js +0 -12
  123. package/dist/retrospect/strategies/quick.d.ts +0 -12
  124. package/dist/retrospect/strategies/quick.js +0 -19
  125. package/dist/retrospect/strategies/standard.d.ts +0 -12
  126. package/dist/retrospect/strategies/standard.js +0 -15
  127. package/dist/retrospect/types.d.ts +0 -7
  128. package/dist/retrospect/types.js +0 -7
  129. package/dist/shared/config.d.ts +0 -105
  130. package/dist/shared/config.js +0 -33
  131. package/dist/shared/errors.d.ts +0 -18
  132. package/dist/shared/errors.js +0 -19
  133. package/dist/shared/generate-agents.d.ts +0 -69
  134. package/dist/shared/generate-agents.js +2 -86
  135. package/dist/shared/image.d.ts +0 -67
  136. package/dist/shared/image.js +6 -104
  137. package/dist/shared/index.d.ts +0 -5
  138. package/dist/shared/index.js +0 -7
  139. package/dist/shared/model-registry.d.ts +0 -72
  140. package/dist/shared/model-registry.js +5 -95
  141. package/dist/shared/types.d.ts +0 -15
  142. package/dist/shared/types.js +0 -3
  143. package/dist/shared-context/dag.d.ts +0 -105
  144. package/dist/shared-context/dag.js +3 -114
  145. package/dist/shared-context/index.d.ts +0 -5
  146. package/dist/shared-context/index.js +0 -15
  147. package/dist/shared-context/logger.d.ts +0 -37
  148. package/dist/shared-context/logger.js +0 -41
  149. package/dist/shared-context/parallel-executor.d.ts +0 -54
  150. package/dist/shared-context/parallel-executor.js +4 -56
  151. package/dist/shared-context/session.d.ts +0 -56
  152. package/dist/shared-context/session.js +0 -47
  153. package/dist/shared-context/squad.d.ts +0 -68
  154. package/dist/shared-context/squad.js +0 -63
  155. package/dist/shared-context/storage.d.ts +0 -132
  156. package/dist/shared-context/storage.js +0 -116
  157. package/dist/shared-context/task.d.ts +0 -120
  158. package/dist/shared-context/task.js +0 -152
  159. package/dist/shared-context/test/dag.test.js +9 -14
  160. package/dist/shared-context/test/logger.test.d.ts +0 -8
  161. package/dist/shared-context/test/logger.test.js +0 -52
  162. package/dist/shared-context/test/session.test.d.ts +0 -7
  163. package/dist/shared-context/test/session.test.js +0 -63
  164. package/dist/shared-context/test/squad.test.d.ts +0 -10
  165. package/dist/shared-context/test/squad.test.js +2 -68
  166. package/dist/shared-context/test/storage.test.d.ts +0 -8
  167. package/dist/shared-context/test/storage.test.js +0 -68
  168. package/dist/shared-context/test/task.test.d.ts +0 -7
  169. package/dist/shared-context/test/task.test.js +0 -54
  170. package/dist/shared-context/test/watchdog.test.d.ts +0 -7
  171. package/dist/shared-context/test/watchdog.test.js +3 -58
  172. package/dist/shared-context/types.d.ts +0 -215
  173. package/dist/shared-context/types.js +0 -125
  174. package/dist/shared-context/watchdog.d.ts +0 -127
  175. package/dist/shared-context/watchdog.js +0 -148
  176. package/dist/shared-context/worktree.d.ts +0 -68
  177. package/dist/shared-context/worktree.js +2 -34
  178. package/dist/verify/budget.d.ts +0 -29
  179. package/dist/verify/budget.js +0 -34
  180. package/dist/verify/critical-files.d.ts +0 -17
  181. package/dist/verify/critical-files.js +0 -37
  182. package/dist/verify/escalation.d.ts +0 -20
  183. package/dist/verify/escalation.js +0 -22
  184. package/dist/verify/index.d.ts +0 -5
  185. package/dist/verify/index.js +0 -11
  186. package/dist/verify/prompts.d.ts +0 -20
  187. package/dist/verify/prompts.js +0 -20
  188. package/dist/verify/types.d.ts +0 -26
  189. package/dist/verify/types.js +1 -12
  190. package/dist/verify/verifier.d.ts +0 -29
  191. package/dist/verify/verifier.js +0 -54
  192. package/dist/version.d.ts +1 -16
  193. package/dist/version.js +1 -16
  194. package/dist/weave/bridge.d.ts +0 -35
  195. package/dist/weave/bridge.js +0 -51
  196. package/dist/weave/environment/detector.d.ts +0 -6
  197. package/dist/weave/environment/detector.js +4 -45
  198. package/dist/weave/environment/index.d.ts +0 -19
  199. package/dist/weave/environment/index.js +1 -39
  200. package/dist/weave/environment/issues.d.ts +0 -35
  201. package/dist/weave/environment/issues.js +0 -59
  202. package/dist/weave/git.d.ts +0 -8
  203. package/dist/weave/git.js +0 -8
  204. package/dist/weave/index.d.ts +0 -13
  205. package/dist/weave/index.js +2 -28
  206. package/dist/weave/knowledge/global.d.ts +0 -39
  207. package/dist/weave/knowledge/global.js +2 -78
  208. package/dist/weave/loop.js +0 -3
  209. package/dist/weave/orchestrator.d.ts +0 -69
  210. package/dist/weave/orchestrator.js +1 -101
  211. package/dist/weave/phase-manager.d.ts +0 -64
  212. package/dist/weave/phase-manager.js +0 -89
  213. package/dist/weave/security/secret-scan.d.ts +0 -14
  214. package/dist/weave/security/secret-scan.js +0 -19
  215. package/dist/weave/stages/build.js +0 -15
  216. package/dist/weave/stages/execute.d.ts +0 -42
  217. package/dist/weave/stages/execute.js +4 -86
  218. package/dist/weave/stages/handoff.d.ts +0 -7
  219. package/dist/weave/stages/handoff.js +0 -43
  220. package/dist/weave/stages/index.d.ts +0 -3
  221. package/dist/weave/stages/index.js +0 -3
  222. package/dist/weave/stages/intake.d.ts +0 -8
  223. package/dist/weave/stages/intake.js +5 -65
  224. package/dist/weave/stages/map.d.ts +0 -1
  225. package/dist/weave/stages/openspec.d.ts +0 -1
  226. package/dist/weave/stages/plan.d.ts +0 -11
  227. package/dist/weave/stages/plan.js +1 -53
  228. package/dist/weave/stages/refine.d.ts +0 -7
  229. package/dist/weave/stages/refine.js +0 -7
  230. package/dist/weave/stages/research.d.ts +0 -6
  231. package/dist/weave/stages/research.js +0 -6
  232. package/dist/weave/stages/spec.d.ts +0 -12
  233. package/dist/weave/stages/spec.js +0 -17
  234. package/dist/weave/types.d.ts +0 -20
  235. package/dist/weave/types.js +0 -5
  236. package/dist/weave/verification/commands.d.ts +0 -12
  237. package/dist/weave/verification/commands.js +0 -19
  238. package/dist/weave/verification/index.d.ts +0 -6
  239. package/dist/weave/verification/index.js +1 -19
  240. package/dist/weave/verification/playwright.d.ts +0 -47
  241. package/dist/weave/verification/playwright.js +1 -90
  242. package/dist/weave/worktree.d.ts +0 -16
  243. package/dist/weave/worktree.js +0 -23
  244. package/dist/weave/yaml-repair.d.ts +0 -39
  245. package/dist/weave/yaml-repair.js +13 -116
  246. package/package.json +1 -1
@@ -1,10 +1,3 @@
1
- /**
2
- * Session Management Tests
3
- *
4
- * "Make it work, make it right, make it fast." - Kent Beck
5
- *
6
- * Red-Green-Refactor cycle for session.ts
7
- */
8
1
  import { describe, test, expect, beforeEach, afterEach } from "vitest";
9
2
  import { mkdtemp, rm } from "fs/promises";
10
3
  import { existsSync } from "fs";
@@ -16,80 +9,59 @@ describe("Session Management", () => {
16
9
  let tempDir;
17
10
  let storage;
18
11
  beforeEach(async () => {
19
- // 각 테스트마다 깨끗한 임시 디렉토리 생성
20
12
  tempDir = await mkdtemp(join(tmpdir(), "session-test-"));
21
13
  storage = new FileStorageAdapter(tempDir);
22
14
  });
23
15
  afterEach(async () => {
24
- // 테스트 후 정리
25
16
  await rm(tempDir, { recursive: true, force: true });
26
17
  });
27
- // ==========================================================================
28
- // createSession Tests
29
- // ==========================================================================
30
18
  describe("createSession", () => {
31
19
  test("should generate UUID format sessionId", async () => {
32
- // Arrange
33
20
  const options = {
34
21
  goal: "Test goal",
35
22
  createdBy: "test-agent",
36
23
  };
37
- // Act
38
24
  const session = await createSession(storage, options);
39
- // Assert - UUID v4 format: 8-4-4-4-12 hex characters
40
25
  const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
41
26
  expect(session.manifest.sessionId).toMatch(uuidRegex);
42
27
  });
43
28
  test("should create manifest.json file", async () => {
44
- // Arrange
45
29
  const options = {
46
30
  goal: "Build feature X",
47
31
  createdBy: "operator-1",
48
32
  };
49
- // Act
50
33
  const session = await createSession(storage, options);
51
- // Assert
52
34
  const manifestPath = join(tempDir, "shared", session.manifest.sessionId, "manifest.json");
53
35
  expect(existsSync(manifestPath)).toBe(true);
54
36
  });
55
37
  test("should create events/ directory", async () => {
56
- // Arrange
57
38
  const options = {
58
39
  goal: "Test events dir",
59
40
  createdBy: "test-agent",
60
41
  };
61
- // Act
62
42
  const session = await createSession(storage, options);
63
- // Assert
64
43
  const eventsPath = join(tempDir, "shared", session.manifest.sessionId, "events");
65
44
  expect(existsSync(eventsPath)).toBe(true);
66
45
  });
67
46
  test("should create squads/ directory", async () => {
68
- // Arrange
69
47
  const options = {
70
48
  goal: "Test squads dir",
71
49
  createdBy: "test-agent",
72
50
  };
73
- // Act
74
51
  const session = await createSession(storage, options);
75
- // Assert
76
52
  const squadsPath = join(tempDir, "shared", session.manifest.sessionId, "squads");
77
53
  expect(existsSync(squadsPath)).toBe(true);
78
54
  });
79
55
  test("should store goal and createdBy in manifest", async () => {
80
- // Arrange
81
56
  const options = {
82
57
  goal: "Implement user authentication",
83
58
  createdBy: "orchestrator-alpha",
84
59
  };
85
- // Act
86
60
  const session = await createSession(storage, options);
87
- // Assert
88
61
  expect(session.manifest.goal).toBe("Implement user authentication");
89
62
  expect(session.manifest.createdBy).toBe("orchestrator-alpha");
90
63
  });
91
64
  test("should store constraints in manifest when provided", async () => {
92
- // Arrange
93
65
  const options = {
94
66
  goal: "Time-boxed task",
95
67
  createdBy: "test-agent",
@@ -98,62 +70,47 @@ describe("Session Management", () => {
98
70
  tokenBudget: 50000,
99
71
  },
100
72
  };
101
- // Act
102
73
  const session = await createSession(storage, options);
103
- // Assert
104
74
  expect(session.manifest.constraints).toBeDefined();
105
75
  expect(session.manifest.constraints?.timeout).toBe("30m");
106
76
  expect(session.manifest.constraints?.tokenBudget).toBe(50000);
107
77
  });
108
78
  test("should initialize version to 1", async () => {
109
- // Arrange
110
79
  const options = {
111
80
  goal: "Test version",
112
81
  createdBy: "test-agent",
113
82
  };
114
- // Act
115
83
  const session = await createSession(storage, options);
116
- // Assert
117
84
  expect(session.manifest.version).toBe(1);
118
85
  });
119
86
  test("should initialize squads as empty array", async () => {
120
- // Arrange
121
87
  const options = {
122
88
  goal: "Test squads init",
123
89
  createdBy: "test-agent",
124
90
  };
125
- // Act
126
91
  const session = await createSession(storage, options);
127
- // Assert
128
92
  expect(session.manifest.squads).toEqual([]);
129
93
  });
130
94
  test("should set createdAt as ISO timestamp", async () => {
131
- // Arrange
132
95
  const beforeCreate = new Date().toISOString();
133
96
  const options = {
134
97
  goal: "Test timestamp",
135
98
  createdBy: "test-agent",
136
99
  };
137
- // Act
138
100
  const session = await createSession(storage, options);
139
101
  const afterCreate = new Date().toISOString();
140
- // Assert - createdAt should be between before and after
141
102
  expect(session.manifest.createdAt >= beforeCreate).toBe(true);
142
103
  expect(session.manifest.createdAt <= afterCreate).toBe(true);
143
104
  });
144
105
  test("should return correct sessionPath", async () => {
145
- // Arrange
146
106
  const options = {
147
107
  goal: "Test session path",
148
108
  createdBy: "test-agent",
149
109
  };
150
- // Act
151
110
  const session = await createSession(storage, options);
152
- // Assert
153
111
  expect(session.sessionPath).toBe(`shared/${session.manifest.sessionId}`);
154
112
  });
155
113
  test("should persist manifest that can be read back", async () => {
156
- // Arrange
157
114
  const options = {
158
115
  goal: "Persistence test",
159
116
  createdBy: "test-agent",
@@ -161,57 +118,42 @@ describe("Session Management", () => {
161
118
  timeout: "1h",
162
119
  },
163
120
  };
164
- // Act
165
121
  const session = await createSession(storage, options);
166
122
  const readManifest = await storage.read(`${session.sessionPath}/manifest.json`);
167
- // Assert
168
123
  expect(readManifest).not.toBeNull();
169
124
  expect(readManifest?.sessionId).toBe(session.manifest.sessionId);
170
125
  expect(readManifest?.goal).toBe("Persistence test");
171
126
  expect(readManifest?.constraints?.timeout).toBe("1h");
172
127
  });
173
128
  });
174
- // ==========================================================================
175
- // loadSession Tests
176
- // ==========================================================================
177
129
  describe("loadSession", () => {
178
130
  test("should load existing session successfully", async () => {
179
- // Arrange - 먼저 세션 생성
180
131
  const options = {
181
132
  goal: "Load test",
182
133
  createdBy: "creator-agent",
183
134
  };
184
135
  const created = await createSession(storage, options);
185
- // Act - 세션 로드
186
136
  const loaded = await loadSession(storage, created.manifest.sessionId);
187
- // Assert
188
137
  expect(loaded).not.toBeNull();
189
138
  expect(loaded?.manifest.sessionId).toBe(created.manifest.sessionId);
190
139
  expect(loaded?.manifest.goal).toBe("Load test");
191
140
  expect(loaded?.manifest.createdBy).toBe("creator-agent");
192
141
  });
193
142
  test("should return null for non-existent session", async () => {
194
- // Arrange - 존재하지 않는 sessionId
195
143
  const fakeSessionId = "00000000-0000-0000-0000-000000000000";
196
- // Act
197
144
  const result = await loadSession(storage, fakeSessionId);
198
- // Assert
199
145
  expect(result).toBeNull();
200
146
  });
201
147
  test("should return correct sessionPath", async () => {
202
- // Arrange
203
148
  const options = {
204
149
  goal: "Path test",
205
150
  createdBy: "test-agent",
206
151
  };
207
152
  const created = await createSession(storage, options);
208
- // Act
209
153
  const loaded = await loadSession(storage, created.manifest.sessionId);
210
- // Assert
211
154
  expect(loaded?.sessionPath).toBe(`shared/${created.manifest.sessionId}`);
212
155
  });
213
156
  test("should load session with constraints", async () => {
214
- // Arrange
215
157
  const options = {
216
158
  goal: "Constraints load test",
217
159
  createdBy: "test-agent",
@@ -221,22 +163,17 @@ describe("Session Management", () => {
221
163
  },
222
164
  };
223
165
  const created = await createSession(storage, options);
224
- // Act
225
166
  const loaded = await loadSession(storage, created.manifest.sessionId);
226
- // Assert
227
167
  expect(loaded?.manifest.constraints?.timeout).toBe("2h");
228
168
  expect(loaded?.manifest.constraints?.tokenBudget).toBe(100000);
229
169
  });
230
170
  test("should return storage adapter reference", async () => {
231
- // Arrange
232
171
  const options = {
233
172
  goal: "Storage ref test",
234
173
  createdBy: "test-agent",
235
174
  };
236
175
  const created = await createSession(storage, options);
237
- // Act
238
176
  const loaded = await loadSession(storage, created.manifest.sessionId);
239
- // Assert
240
177
  expect(loaded?.storage).toBe(storage);
241
178
  });
242
179
  });
@@ -1,11 +1 @@
1
- /**
2
- * Squad Management Tests
3
- *
4
- * Kent Beck의 TDD 원칙:
5
- * - 작고 명확한 테스트
6
- * - 하나의 테스트는 하나의 행동만 검증
7
- * - Red-Green-Refactor 사이클
8
- *
9
- * @author Kent Beck's Dummy Human
10
- */
11
1
  export {};
@@ -1,13 +1,3 @@
1
- /**
2
- * Squad Management Tests
3
- *
4
- * Kent Beck의 TDD 원칙:
5
- * - 작고 명확한 테스트
6
- * - 하나의 테스트는 하나의 행동만 검증
7
- * - Red-Green-Refactor 사이클
8
- *
9
- * @author Kent Beck's Dummy Human
10
- */
11
1
  import { describe, test, expect, beforeEach, afterEach } from "vitest";
12
2
  import { mkdtemp, rm } from "fs/promises";
13
3
  import { tmpdir } from "os";
@@ -17,14 +7,10 @@ import { FileStorageAdapter } from "../storage.js";
17
7
  import { createSession } from "../session.js";
18
8
  import { createSquad, getSquad, updateSquadState } from "../squad.js";
19
9
  import { LIMITS } from "../types.js";
20
- // ============================================================================
21
- // Test Fixtures
22
- // ============================================================================
23
10
  let tempDir;
24
11
  let storage;
25
12
  let session;
26
13
  beforeEach(async () => {
27
- // Arrange: 각 테스트 전에 깨끗한 임시 디렉토리 생성
28
14
  tempDir = await mkdtemp(join(tmpdir(), "squad-test-"));
29
15
  storage = new FileStorageAdapter(tempDir);
30
16
  session = await createSession(storage, {
@@ -33,48 +19,37 @@ beforeEach(async () => {
33
19
  });
34
20
  });
35
21
  afterEach(async () => {
36
- // Cleanup: 테스트 후 임시 디렉토리 정리
37
22
  if (tempDir && existsSync(tempDir)) {
38
23
  await rm(tempDir, { recursive: true, force: true });
39
24
  }
40
25
  });
41
- // ============================================================================
42
- // createSquad Tests
43
- // ============================================================================
44
26
  describe("createSquad", () => {
45
27
  test("should create spec.json and state.json files", async () => {
46
- // Act
47
28
  const { spec, state } = await createSquad(session, {
48
29
  mission: "Implement feature X",
49
30
  operator: "operator-agent",
50
31
  });
51
- // Assert: 파일 생성 확인
52
32
  const squadPath = `${session.sessionPath}/squads/${spec.squadId}`;
53
33
  expect(storage.exists(`${squadPath}/spec.json`)).toBe(true);
54
34
  expect(storage.exists(`${squadPath}/state.json`)).toBe(true);
55
35
  });
56
36
  test("should add squadId to manifest.squads array", async () => {
57
- // Act
58
37
  const { spec } = await createSquad(session, {
59
38
  mission: "Implement feature X",
60
39
  operator: "operator-agent",
61
40
  });
62
- // Assert: manifest에 squadId 추가 확인
63
41
  expect(session.manifest.squads).toContain(spec.squadId);
64
42
  expect(session.manifest.squads.length).toBe(1);
65
43
  });
66
44
  test("should create scratch/ directory", async () => {
67
- // Act
68
45
  const { spec } = await createSquad(session, {
69
46
  mission: "Implement feature X",
70
47
  operator: "operator-agent",
71
48
  });
72
- // Assert: scratch 디렉토리 생성 확인
73
49
  const scratchPath = `${session.sessionPath}/squads/${spec.squadId}/scratch`;
74
50
  expect(existsSync(storage.getFullPath(scratchPath))).toBe(true);
75
51
  });
76
52
  test("should return spec with correct properties", async () => {
77
- // Arrange
78
53
  const options = {
79
54
  mission: "Implement OAuth login",
80
55
  operator: "operator-alpha",
@@ -88,9 +63,7 @@ describe("createSquad", () => {
88
63
  directories: ["src/auth/"],
89
64
  },
90
65
  };
91
- // Act
92
66
  const { spec } = await createSquad(session, options);
93
- // Assert: spec 속성 검증
94
67
  expect(spec.squadId).toMatch(/^squad-[a-f0-9]{8}$/);
95
68
  expect(spec.mission).toBe(options.mission);
96
69
  expect(spec.operator).toBe(options.operator);
@@ -101,12 +74,10 @@ describe("createSquad", () => {
101
74
  expect(spec.createdAt).toBeDefined();
102
75
  });
103
76
  test("should return state with initial values", async () => {
104
- // Act
105
77
  const { state } = await createSquad(session, {
106
78
  mission: "Test mission",
107
79
  operator: "operator",
108
80
  });
109
- // Assert: 초기 상태 검증
110
81
  expect(state.status).toBe("pending");
111
82
  expect(state.progress).toBe(0);
112
83
  expect(state.tasks).toEqual([]);
@@ -114,35 +85,29 @@ describe("createSquad", () => {
114
85
  expect(state.updatedAt).toBeDefined();
115
86
  });
116
87
  test("should use default maxWorkers from LIMITS when not specified", async () => {
117
- // Act
118
88
  const { spec } = await createSquad(session, {
119
89
  mission: "Test mission",
120
90
  operator: "operator",
121
91
  });
122
- // Assert
123
92
  expect(spec.constraints?.maxWorkers).toBe(LIMITS.maxWorkersPerSquad);
124
93
  });
125
94
  test("should throw error when maxSquadsPerSession limit is reached", async () => {
126
- // Arrange: 최대 개수만큼 Squad 생성
127
95
  for (let i = 0; i < LIMITS.maxSquadsPerSession; i++) {
128
96
  await createSquad(session, {
129
97
  mission: `Mission ${i}`,
130
98
  operator: "operator",
131
99
  });
132
100
  }
133
- // Act & Assert: 한도 초과 시 에러
134
101
  await expect(createSquad(session, {
135
102
  mission: "One too many",
136
103
  operator: "operator",
137
104
  })).rejects.toThrow("Maximum squads per session exceeded");
138
105
  });
139
106
  test("should persist spec.json with correct data", async () => {
140
- // Act
141
107
  const { spec } = await createSquad(session, {
142
108
  mission: "Persisted mission",
143
109
  operator: "persistent-operator",
144
110
  });
145
- // Assert: 파일에서 직접 읽어서 검증
146
111
  const squadPath = `${session.sessionPath}/squads/${spec.squadId}`;
147
112
  const savedSpec = await storage.read(`${squadPath}/spec.json`);
148
113
  expect(savedSpec).not.toBeNull();
@@ -150,129 +115,98 @@ describe("createSquad", () => {
150
115
  expect(savedSpec?.operator).toBe("persistent-operator");
151
116
  });
152
117
  });
153
- // ============================================================================
154
- // getSquad Tests
155
- // ============================================================================
156
118
  describe("getSquad", () => {
157
119
  test("should return squad when it exists", async () => {
158
- // Arrange
159
120
  const created = await createSquad(session, {
160
121
  mission: "Find me",
161
122
  operator: "operator",
162
123
  });
163
- // Act
164
124
  const retrieved = await getSquad(session, created.spec.squadId);
165
- // Assert
166
125
  expect(retrieved).not.toBeNull();
167
126
  expect(retrieved?.spec.squadId).toBe(created.spec.squadId);
168
127
  expect(retrieved?.spec.mission).toBe("Find me");
169
128
  expect(retrieved?.state.status).toBe("pending");
170
129
  });
171
130
  test("should return null when squad does not exist", async () => {
172
- // Act
173
131
  const result = await getSquad(session, "squad-nonexistent");
174
- // Assert
175
132
  expect(result).toBeNull();
176
133
  });
177
134
  test("should return both spec and state", async () => {
178
- // Arrange
179
135
  const created = await createSquad(session, {
180
136
  mission: "Dual return test",
181
137
  operator: "operator",
182
138
  });
183
- // Act
184
139
  const result = await getSquad(session, created.spec.squadId);
185
- // Assert
186
140
  expect(result).toHaveProperty("spec");
187
141
  expect(result).toHaveProperty("state");
188
142
  expect(result?.spec.squadId).toBe(result?.state.squadId);
189
143
  });
190
144
  });
191
- // ============================================================================
192
- // updateSquadState Tests
193
- // ============================================================================
194
145
  describe("updateSquadState", () => {
195
146
  test("should update state and reflect changes on subsequent get", async () => {
196
- // Arrange
197
147
  const { spec } = await createSquad(session, {
198
148
  mission: "Update me",
199
149
  operator: "operator",
200
150
  });
201
- // Act
202
151
  await updateSquadState(session, spec.squadId, {
203
152
  status: "active",
204
153
  progress: 50,
205
154
  });
206
- // Assert: 업데이트된 값 확인
207
155
  const retrieved = await getSquad(session, spec.squadId);
208
156
  expect(retrieved?.state.status).toBe("active");
209
157
  expect(retrieved?.state.progress).toBe(50);
210
158
  });
211
159
  test("should automatically update updatedAt timestamp", async () => {
212
- // Arrange
213
160
  const { spec, state: initialState } = await createSquad(session, {
214
161
  mission: "Timestamp test",
215
162
  operator: "operator",
216
163
  });
217
164
  const initialUpdatedAt = initialState.updatedAt;
218
- // 시간 차이를 위해 약간 대기
219
165
  await new Promise((resolve) => setTimeout(resolve, 10));
220
- // Act
221
166
  const updatedState = await updateSquadState(session, spec.squadId, {
222
167
  progress: 25,
223
168
  });
224
- // Assert: updatedAt이 갱신됨
225
169
  expect(updatedState.updatedAt).not.toBe(initialUpdatedAt);
226
170
  expect(new Date(updatedState.updatedAt).getTime()).toBeGreaterThan(new Date(initialUpdatedAt).getTime());
227
171
  });
228
172
  test("should throw error when squad does not exist", async () => {
229
- // Act & Assert
230
173
  await expect(updateSquadState(session, "squad-nonexistent", { status: "active" })).rejects.toThrow("Squad not found: squad-nonexistent");
231
174
  });
232
175
  test("should preserve unmodified fields", async () => {
233
- // Arrange
234
176
  const { spec } = await createSquad(session, {
235
177
  mission: "Preserve fields",
236
178
  operator: "operator",
237
179
  });
238
- // Act: status만 업데이트
239
180
  await updateSquadState(session, spec.squadId, { status: "active" });
240
- // Assert: 다른 필드는 유지
241
181
  const retrieved = await getSquad(session, spec.squadId);
242
182
  expect(retrieved?.state.status).toBe("active");
243
- expect(retrieved?.state.progress).toBe(0); // 초기값 유지
244
- expect(retrieved?.state.tasks).toEqual([]); // 초기값 유지
183
+ expect(retrieved?.state.progress).toBe(0);
184
+ expect(retrieved?.state.tasks).toEqual([]);
245
185
  });
246
186
  test("should return the updated state", async () => {
247
- // Arrange
248
187
  const { spec } = await createSquad(session, {
249
188
  mission: "Return value test",
250
189
  operator: "operator",
251
190
  });
252
- // Act
253
191
  const result = await updateSquadState(session, spec.squadId, {
254
192
  status: "completed",
255
193
  progress: 100,
256
194
  });
257
- // Assert
258
195
  expect(result.status).toBe("completed");
259
196
  expect(result.progress).toBe(100);
260
197
  expect(result.squadId).toBe(spec.squadId);
261
198
  });
262
199
  test("should update sharedContext", async () => {
263
- // Arrange
264
200
  const { spec } = await createSquad(session, {
265
201
  mission: "Shared context test",
266
202
  operator: "operator",
267
203
  });
268
- // Act
269
204
  await updateSquadState(session, spec.squadId, {
270
205
  sharedContext: {
271
206
  apiEndpoint: "https://api.example.com",
272
207
  authToken: "secret",
273
208
  },
274
209
  });
275
- // Assert
276
210
  const retrieved = await getSquad(session, spec.squadId);
277
211
  expect(retrieved?.state.sharedContext).toEqual({
278
212
  apiEndpoint: "https://api.example.com",
@@ -1,9 +1 @@
1
- /**
2
- * Storage Adapter Unit Tests
3
- *
4
- * "First make it work, then make it right, then make it fast."
5
- * - Kent Beck
6
- *
7
- * @author Kent Beck's Dummy Human
8
- */
9
1
  export {};