maskweaver 0.9.4 → 0.9.6

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 (229) hide show
  1. package/README.ko.md +638 -592
  2. package/README.md +671 -667
  3. package/dist/cli/doctor.js +5 -21
  4. package/dist/cli/install.d.ts +0 -8
  5. package/dist/cli/install.js +0 -39
  6. package/dist/context/config.d.ts +0 -22
  7. package/dist/context/config.js +0 -28
  8. package/dist/context/feature.d.ts +0 -39
  9. package/dist/context/feature.js +0 -77
  10. package/dist/context/files.d.ts +0 -13
  11. package/dist/context/files.js +1 -24
  12. package/dist/context/index.d.ts +0 -7
  13. package/dist/context/index.js +0 -12
  14. package/dist/context/project.d.ts +0 -21
  15. package/dist/context/project.js +0 -30
  16. package/dist/context/types.d.ts +0 -48
  17. package/dist/context/types.js +0 -12
  18. package/dist/context/utils.d.ts +0 -18
  19. package/dist/context/utils.js +0 -27
  20. package/dist/core/engine/promptBuilder.d.ts +0 -17
  21. package/dist/core/engine/promptBuilder.js +0 -28
  22. package/dist/core/index.d.ts +0 -6
  23. package/dist/core/index.js +0 -9
  24. package/dist/core/loader/MaskLoader.d.ts +0 -23
  25. package/dist/core/loader/MaskLoader.js +0 -29
  26. package/dist/core/schema/types.d.ts +0 -47
  27. package/dist/core/schema/types.js +0 -6
  28. package/dist/core/schema/validator.d.ts +0 -14
  29. package/dist/core/schema/validator.js +0 -18
  30. package/dist/i18n/index.d.ts +0 -18
  31. package/dist/i18n/index.js +4 -23
  32. package/dist/index.d.ts +0 -8
  33. package/dist/index.js +0 -8
  34. package/dist/lib.d.ts +0 -5
  35. package/dist/lib.js +0 -12
  36. package/dist/memory/chunking.d.ts +0 -22
  37. package/dist/memory/chunking.js +2 -37
  38. package/dist/memory/core.d.ts +0 -29
  39. package/dist/memory/core.js +1 -52
  40. package/dist/memory/index.d.ts +0 -5
  41. package/dist/memory/index.js +0 -10
  42. package/dist/memory/indexer.d.ts +0 -21
  43. package/dist/memory/indexer.js +0 -44
  44. package/dist/memory/providers/examples.d.ts +0 -5
  45. package/dist/memory/providers/examples.js +4 -64
  46. package/dist/memory/providers/factory.d.ts +0 -44
  47. package/dist/memory/providers/factory.js +0 -46
  48. package/dist/memory/providers/index.d.ts +0 -26
  49. package/dist/memory/providers/index.js +0 -28
  50. package/dist/memory/providers/ollama.d.ts +0 -6
  51. package/dist/memory/providers/ollama.js +1 -8
  52. package/dist/memory/providers/openai.d.ts +0 -6
  53. package/dist/memory/providers/openai.js +1 -8
  54. package/dist/memory/providers/openrouter.d.ts +0 -6
  55. package/dist/memory/providers/openrouter.js +0 -8
  56. package/dist/memory/providers/text-only.d.ts +0 -13
  57. package/dist/memory/providers/text-only.js +0 -17
  58. package/dist/memory/providers/types.d.ts +0 -39
  59. package/dist/memory/providers/types.js +0 -7
  60. package/dist/memory/providers/voyage.d.ts +0 -22
  61. package/dist/memory/providers/voyage.js +1 -24
  62. package/dist/memory/search/hybrid.d.ts +0 -12
  63. package/dist/memory/search/hybrid.js +1 -22
  64. package/dist/memory/store/sqlite.d.ts +0 -72
  65. package/dist/memory/store/sqlite.js +4 -127
  66. package/dist/plugin/config/index.d.ts +0 -112
  67. package/dist/plugin/config/index.js +0 -115
  68. package/dist/plugin/index.d.ts +0 -13
  69. package/dist/plugin/index.js +1 -123
  70. package/dist/plugin/tools/command-registry.d.ts +0 -6
  71. package/dist/plugin/tools/command-registry.js +0 -14
  72. package/dist/plugin/tools/context.d.ts +0 -12
  73. package/dist/plugin/tools/context.js +0 -58
  74. package/dist/plugin/tools/maskSave.d.ts +0 -3
  75. package/dist/plugin/tools/maskSave.js +0 -3
  76. package/dist/plugin/tools/memoryGet.d.ts +0 -3
  77. package/dist/plugin/tools/memoryGet.js +0 -3
  78. package/dist/plugin/tools/memoryIndexer.d.ts +0 -3
  79. package/dist/plugin/tools/memoryIndexer.js +0 -10
  80. package/dist/plugin/tools/memorySearch.d.ts +0 -31
  81. package/dist/plugin/tools/memorySearch.js +0 -79
  82. package/dist/plugin/tools/memoryWrite.d.ts +0 -8
  83. package/dist/plugin/tools/memoryWrite.js +0 -32
  84. package/dist/plugin/tools/retrospect.d.ts +0 -3
  85. package/dist/plugin/tools/retrospect.js +0 -3
  86. package/dist/plugin/tools/slashcommand.d.ts +0 -11
  87. package/dist/plugin/tools/slashcommand.js +0 -38
  88. package/dist/plugin/tools/squad.d.ts +0 -12
  89. package/dist/plugin/tools/squad.js +11 -83
  90. package/dist/plugin/tools/weave.d.ts +0 -6
  91. package/dist/plugin/tools/weave.js +0 -78
  92. package/dist/plugin/types.d.ts +0 -20
  93. package/dist/plugin/types.js +0 -7
  94. package/dist/retrospect/index.d.ts +0 -7
  95. package/dist/retrospect/index.js +0 -9
  96. package/dist/retrospect/mask-save.d.ts +0 -12
  97. package/dist/retrospect/mask-save.js +1 -80
  98. package/dist/retrospect/retrospect.d.ts +0 -18
  99. package/dist/retrospect/retrospect.js +0 -63
  100. package/dist/retrospect/strategies/base.d.ts +0 -15
  101. package/dist/retrospect/strategies/base.js +0 -7
  102. package/dist/retrospect/strategies/deep.d.ts +0 -12
  103. package/dist/retrospect/strategies/deep.js +0 -24
  104. package/dist/retrospect/strategies/index.d.ts +0 -12
  105. package/dist/retrospect/strategies/index.js +0 -12
  106. package/dist/retrospect/strategies/quick.d.ts +0 -12
  107. package/dist/retrospect/strategies/quick.js +0 -19
  108. package/dist/retrospect/strategies/standard.d.ts +0 -12
  109. package/dist/retrospect/strategies/standard.js +0 -15
  110. package/dist/retrospect/types.d.ts +0 -7
  111. package/dist/retrospect/types.js +0 -7
  112. package/dist/shared/config.d.ts +0 -105
  113. package/dist/shared/config.js +0 -33
  114. package/dist/shared/errors.d.ts +0 -18
  115. package/dist/shared/errors.js +0 -19
  116. package/dist/shared/generate-agents.d.ts +0 -69
  117. package/dist/shared/generate-agents.js +2 -86
  118. package/dist/shared/image.d.ts +0 -67
  119. package/dist/shared/image.js +6 -104
  120. package/dist/shared/index.d.ts +0 -5
  121. package/dist/shared/index.js +0 -7
  122. package/dist/shared/model-registry.d.ts +0 -72
  123. package/dist/shared/model-registry.js +5 -95
  124. package/dist/shared/types.d.ts +0 -15
  125. package/dist/shared/types.js +0 -3
  126. package/dist/shared-context/dag.d.ts +0 -105
  127. package/dist/shared-context/dag.js +3 -114
  128. package/dist/shared-context/index.d.ts +0 -5
  129. package/dist/shared-context/index.js +0 -15
  130. package/dist/shared-context/logger.d.ts +0 -37
  131. package/dist/shared-context/logger.js +0 -41
  132. package/dist/shared-context/parallel-executor.d.ts +0 -54
  133. package/dist/shared-context/parallel-executor.js +4 -56
  134. package/dist/shared-context/session.d.ts +0 -56
  135. package/dist/shared-context/session.js +0 -47
  136. package/dist/shared-context/squad.d.ts +0 -68
  137. package/dist/shared-context/squad.js +0 -63
  138. package/dist/shared-context/storage.d.ts +0 -132
  139. package/dist/shared-context/storage.js +0 -116
  140. package/dist/shared-context/task.d.ts +0 -120
  141. package/dist/shared-context/task.js +0 -152
  142. package/dist/shared-context/test/dag.test.js +9 -14
  143. package/dist/shared-context/test/logger.test.d.ts +0 -8
  144. package/dist/shared-context/test/logger.test.js +0 -52
  145. package/dist/shared-context/test/session.test.d.ts +0 -7
  146. package/dist/shared-context/test/session.test.js +0 -63
  147. package/dist/shared-context/test/squad.test.d.ts +0 -10
  148. package/dist/shared-context/test/squad.test.js +2 -68
  149. package/dist/shared-context/test/storage.test.d.ts +0 -8
  150. package/dist/shared-context/test/storage.test.js +0 -68
  151. package/dist/shared-context/test/task.test.d.ts +0 -7
  152. package/dist/shared-context/test/task.test.js +0 -54
  153. package/dist/shared-context/test/watchdog.test.d.ts +0 -7
  154. package/dist/shared-context/test/watchdog.test.js +3 -58
  155. package/dist/shared-context/types.d.ts +0 -215
  156. package/dist/shared-context/types.js +0 -125
  157. package/dist/shared-context/watchdog.d.ts +0 -127
  158. package/dist/shared-context/watchdog.js +0 -148
  159. package/dist/shared-context/worktree.d.ts +0 -68
  160. package/dist/shared-context/worktree.js +2 -34
  161. package/dist/verify/budget.d.ts +0 -29
  162. package/dist/verify/budget.js +0 -34
  163. package/dist/verify/critical-files.d.ts +0 -17
  164. package/dist/verify/critical-files.js +0 -37
  165. package/dist/verify/escalation.d.ts +0 -20
  166. package/dist/verify/escalation.js +0 -22
  167. package/dist/verify/index.d.ts +0 -5
  168. package/dist/verify/index.js +0 -11
  169. package/dist/verify/prompts.d.ts +0 -20
  170. package/dist/verify/prompts.js +0 -20
  171. package/dist/verify/types.d.ts +0 -26
  172. package/dist/verify/types.js +1 -12
  173. package/dist/verify/verifier.d.ts +0 -29
  174. package/dist/verify/verifier.js +0 -54
  175. package/dist/version.d.ts +1 -16
  176. package/dist/version.js +1 -16
  177. package/dist/weave/bridge.d.ts +0 -35
  178. package/dist/weave/bridge.js +0 -51
  179. package/dist/weave/environment/detector.d.ts +0 -6
  180. package/dist/weave/environment/detector.js +4 -45
  181. package/dist/weave/environment/index.d.ts +0 -19
  182. package/dist/weave/environment/index.js +1 -39
  183. package/dist/weave/environment/issues.d.ts +0 -35
  184. package/dist/weave/environment/issues.js +0 -59
  185. package/dist/weave/git.d.ts +0 -8
  186. package/dist/weave/git.js +0 -8
  187. package/dist/weave/index.d.ts +0 -13
  188. package/dist/weave/index.js +2 -28
  189. package/dist/weave/knowledge/global.d.ts +0 -39
  190. package/dist/weave/knowledge/global.js +2 -78
  191. package/dist/weave/loop.js +0 -3
  192. package/dist/weave/orchestrator.d.ts +0 -69
  193. package/dist/weave/orchestrator.js +1 -101
  194. package/dist/weave/phase-manager.d.ts +0 -64
  195. package/dist/weave/phase-manager.js +0 -89
  196. package/dist/weave/security/secret-scan.d.ts +0 -14
  197. package/dist/weave/security/secret-scan.js +0 -19
  198. package/dist/weave/stages/build.js +0 -15
  199. package/dist/weave/stages/execute.d.ts +0 -42
  200. package/dist/weave/stages/execute.js +4 -86
  201. package/dist/weave/stages/handoff.d.ts +0 -7
  202. package/dist/weave/stages/handoff.js +0 -43
  203. package/dist/weave/stages/index.d.ts +0 -3
  204. package/dist/weave/stages/index.js +0 -3
  205. package/dist/weave/stages/intake.d.ts +0 -8
  206. package/dist/weave/stages/intake.js +5 -65
  207. package/dist/weave/stages/map.d.ts +0 -1
  208. package/dist/weave/stages/openspec.d.ts +0 -1
  209. package/dist/weave/stages/plan.d.ts +0 -11
  210. package/dist/weave/stages/plan.js +1 -53
  211. package/dist/weave/stages/refine.d.ts +0 -7
  212. package/dist/weave/stages/refine.js +0 -7
  213. package/dist/weave/stages/research.d.ts +0 -6
  214. package/dist/weave/stages/research.js +0 -6
  215. package/dist/weave/stages/spec.d.ts +0 -12
  216. package/dist/weave/stages/spec.js +0 -17
  217. package/dist/weave/types.d.ts +0 -20
  218. package/dist/weave/types.js +0 -5
  219. package/dist/weave/verification/commands.d.ts +0 -12
  220. package/dist/weave/verification/commands.js +0 -19
  221. package/dist/weave/verification/index.d.ts +0 -6
  222. package/dist/weave/verification/index.js +1 -19
  223. package/dist/weave/verification/playwright.d.ts +0 -47
  224. package/dist/weave/verification/playwright.js +1 -90
  225. package/dist/weave/worktree.d.ts +0 -16
  226. package/dist/weave/worktree.js +0 -23
  227. package/dist/weave/yaml-repair.d.ts +0 -39
  228. package/dist/weave/yaml-repair.js +13 -116
  229. package/package.json +1 -1
@@ -1,54 +1,10 @@
1
- /**
2
- * Task Management
3
- *
4
- * Tasks are the atomic units of work within a squad.
5
- * "Make the implicit explicit" - Eric Evans
6
- *
7
- * This module embodies the Task aggregate, ensuring domain invariants:
8
- * - A task always belongs to exactly one squad
9
- * - Task count per squad is bounded (LIMITS.maxTasksPerSquad)
10
- * - Task identity is immutable once assigned
11
- *
12
- * @author Kent Beck's Dummy Human
13
- */
14
1
  import { randomUUID } from "crypto";
15
2
  import { LIMITS, validateCreateTaskOptions, validateTaskResult } from "./types.js";
16
3
  import { getSquad, updateSquadState } from "./squad.js";
17
4
  import { logEvent } from "./logger.js";
18
5
  import { ValidationError, StorageError } from "../shared/errors.js";
19
- // ============================================================================
20
- // Task Assignment - The heart of work distribution
21
- // ============================================================================
22
- /**
23
- * Assign a new task to an agent within a squad.
24
- *
25
- * This is a domain operation that enforces invariants:
26
- * 1. The target squad must exist
27
- * 2. The squad's task capacity must not be exceeded
28
- * 3. Task options must be valid at the boundary
29
- *
30
- * The task starts in "pending" status, awaiting execution.
31
- *
32
- * @param session - The parent session containing the squad
33
- * @param squadId - ID of the squad to assign the task to
34
- * @param options - Task creation options (assignee, description, priority, etc.)
35
- * @returns The newly created TaskState
36
- * @throws {StorageError} If the squad doesn't exist
37
- * @throws {ValidationError} If task limit is exceeded or options are invalid
38
- *
39
- * @example
40
- * const task = await assignTask(session, "squad-a1b2c3d4", {
41
- * assignee: "worker-1",
42
- * description: "Implement user login form",
43
- * priority: "high",
44
- * dependencies: ["task-setup"]
45
- * });
46
- * console.log(`Assigned task ${task.taskId} to ${task.assignee}`);
47
- */
48
6
  export async function assignTask(session, squadId, options) {
49
- // Validate at boundary - Parse, don't validate
50
7
  const validatedOptions = validateCreateTaskOptions(options);
51
- // Retrieve the squad - domain aggregate root
52
8
  const squad = await getSquad(session, squadId);
53
9
  if (!squad) {
54
10
  throw new StorageError(`Squad not found: ${squadId}`, {
@@ -56,7 +12,6 @@ export async function assignTask(session, squadId, options) {
56
12
  sessionId: session.manifest.sessionId,
57
13
  });
58
14
  }
59
- // Enforce domain invariant: task capacity
60
15
  if (squad.state.tasks.length >= LIMITS.maxTasksPerSquad) {
61
16
  throw new ValidationError("Maximum tasks per squad exceeded", {
62
17
  squadId,
@@ -64,7 +19,6 @@ export async function assignTask(session, squadId, options) {
64
19
  current: squad.state.tasks.length,
65
20
  });
66
21
  }
67
- // Create the task entity with identity
68
22
  const taskId = `task-${randomUUID().slice(0, 8)}`;
69
23
  const now = new Date().toISOString();
70
24
  const task = {
@@ -76,12 +30,10 @@ export async function assignTask(session, squadId, options) {
76
30
  dependencies: validatedOptions.dependencies,
77
31
  createdAt: now,
78
32
  };
79
- // Update squad aggregate - append task to collection
80
33
  const updatedTasks = [...squad.state.tasks, task];
81
34
  await updateSquadState(session, squadId, {
82
35
  tasks: updatedTasks,
83
36
  });
84
- // Emit domain event for observability
85
37
  await logEvent(session, squadId, {
86
38
  type: "task_assigned",
87
39
  taskId: task.taskId,
@@ -90,29 +42,7 @@ export async function assignTask(session, squadId, options) {
90
42
  });
91
43
  return task;
92
44
  }
93
- // ============================================================================
94
- // Task Query - Domain Entity Lookup
95
- // ============================================================================
96
- /**
97
- * Get a specific task from a squad by taskId.
98
- *
99
- * "Make implicit concepts explicit" - Eric Evans
100
- * Task lookup is a first-class domain operation, not hidden in aggregate traversal.
101
- *
102
- * @param session - Parent session
103
- * @param squadId - Squad containing the task
104
- * @param taskId - Task ID to find
105
- * @returns TaskState or null if not found (no error thrown for missing task)
106
- * @throws {StorageError} If the squad doesn't exist
107
- *
108
- * @example
109
- * const task = await getTask(session, "squad-a1b2c3d4", "task-12345678");
110
- * if (task) {
111
- * console.log(`Task ${task.taskId} is ${task.status}`);
112
- * }
113
- */
114
45
  export async function getTask(session, squadId, taskId) {
115
- // Retrieve the squad aggregate
116
46
  const squad = await getSquad(session, squadId);
117
47
  if (!squad) {
118
48
  throw new StorageError(`Squad not found: ${squadId}`, {
@@ -120,45 +50,10 @@ export async function getTask(session, squadId, taskId) {
120
50
  sessionId: session.manifest.sessionId,
121
51
  });
122
52
  }
123
- // Search for task within the squad's task collection
124
53
  const task = squad.state.tasks.find((t) => t.taskId === taskId);
125
- // Return null for not found (expected case, not an error)
126
54
  return task ?? null;
127
55
  }
128
- // ============================================================================
129
- // Task Update - State Transition through Aggregate Root
130
- // ============================================================================
131
- /**
132
- * Update a task's status and optionally record progress.
133
- * This is the primary way to advance task lifecycle.
134
- *
135
- * DDD Principle: All state mutations go through the Aggregate Root (Squad).
136
- * "Make implicit concepts explicit" - Eric Evans
137
- *
138
- * @param session - Parent session
139
- * @param squadId - Squad containing the task
140
- * @param taskId - Task to update
141
- * @param updates - Partial updates (status, result, etc.)
142
- * @returns Updated TaskState
143
- * @throws {StorageError} If squad or task not found
144
- *
145
- * @example
146
- * // Start a task
147
- * const updated = await updateTask(session, squadId, taskId, {
148
- * status: "active",
149
- * startedAt: new Date().toISOString()
150
- * });
151
- *
152
- * @example
153
- * // Complete a task with result
154
- * const completed = await updateTask(session, squadId, taskId, {
155
- * status: "completed",
156
- * completedAt: new Date().toISOString(),
157
- * result: { success: true, output: "Feature implemented" }
158
- * });
159
- */
160
56
  export async function updateTask(session, squadId, taskId, updates) {
161
- // Retrieve the squad aggregate root
162
57
  const squad = await getSquad(session, squadId);
163
58
  if (!squad) {
164
59
  throw new StorageError(`Squad not found: ${squadId}`, {
@@ -166,7 +61,6 @@ export async function updateTask(session, squadId, taskId, updates) {
166
61
  sessionId: session.manifest.sessionId,
167
62
  });
168
63
  }
169
- // Find the task within the aggregate
170
64
  const taskIndex = squad.state.tasks.findIndex((t) => t.taskId === taskId);
171
65
  if (taskIndex === -1) {
172
66
  throw new StorageError(`Task not found: ${taskId}`, {
@@ -177,19 +71,15 @@ export async function updateTask(session, squadId, taskId, updates) {
177
71
  }
178
72
  const existingTask = squad.state.tasks[taskIndex];
179
73
  const previousStatus = existingTask.status;
180
- // Apply updates via spread - immutable update pattern
181
74
  const updatedTask = {
182
75
  ...existingTask,
183
76
  ...updates,
184
77
  };
185
- // Update the tasks array immutably
186
78
  const updatedTasks = [...squad.state.tasks];
187
79
  updatedTasks[taskIndex] = updatedTask;
188
- // Persist through aggregate root
189
80
  await updateSquadState(session, squadId, {
190
81
  tasks: updatedTasks,
191
82
  });
192
- // Log status change as domain event (only if status actually changed)
193
83
  if (updates.status && updates.status !== previousStatus) {
194
84
  if (updates.status === "completed") {
195
85
  await logEvent(session, squadId, {
@@ -200,8 +90,6 @@ export async function updateTask(session, squadId, taskId, updates) {
200
90
  });
201
91
  }
202
92
  else {
203
- // Generic status change - use error event type for now
204
- // (Could extend LogEvent union for task_status_changed)
205
93
  await logEvent(session, squadId, {
206
94
  type: "error",
207
95
  message: `Task ${taskId} status changed: ${previousStatus} -> ${updates.status}`,
@@ -210,49 +98,9 @@ export async function updateTask(session, squadId, taskId, updates) {
210
98
  }
211
99
  return updatedTask;
212
100
  }
213
- // ============================================================================
214
- // Task Completion - Explicit Domain Operation
215
- // ============================================================================
216
- /**
217
- * Complete a task with a result.
218
- *
219
- * "Make implicit concepts explicit" - Eric Evans
220
- * Task completion is a first-class domain operation with its own semantics.
221
- *
222
- * This is a convenience wrapper around updateTask() that:
223
- * - Validates the TaskResult at the boundary
224
- * - Sets the appropriate status based on result.success
225
- * - Records completedAt timestamp
226
- *
227
- * @param session - Parent session
228
- * @param squadId - Squad containing the task
229
- * @param taskId - Task to complete
230
- * @param result - TaskResult with success/failure info
231
- * @returns Updated TaskState
232
- * @throws {StorageError} If squad or task not found
233
- * @throws {ValidationError} If result is invalid
234
- *
235
- * @example
236
- * // Success case
237
- * const completed = await completeTask(session, squadId, taskId, {
238
- * success: true,
239
- * output: { files: ["src/auth/login.ts"] },
240
- * metrics: { duration: 45000, tokensUsed: 1500 }
241
- * });
242
- *
243
- * @example
244
- * // Failure case
245
- * const failed = await completeTask(session, squadId, taskId, {
246
- * success: false,
247
- * error: { code: "TIMEOUT", message: "Task exceeded timeout" }
248
- * });
249
- */
250
101
  export async function completeTask(session, squadId, taskId, result) {
251
- // Validate at boundary
252
102
  const validatedResult = validateTaskResult(result);
253
- // Determine status from result
254
103
  const status = validatedResult.success ? "completed" : "failed";
255
- // Delegate to updateTask with appropriate fields
256
104
  return updateTask(session, squadId, taskId, {
257
105
  status,
258
106
  completedAt: new Date().toISOString(),
@@ -1,8 +1,6 @@
1
- // src/shared-context/test/dag.test.ts
2
1
  import { describe, test, expect } from 'vitest';
3
2
  import { buildDAG, getReadyTasks, areDependenciesMet, validateDependencies, } from '../dag.js';
4
3
  import { ValidationError } from '../../shared/errors.js';
5
- // Helper to create a TaskState object for tests
6
4
  const createTask = (taskId, dependencies = [], status = 'pending', priority = 'medium') => ({
7
5
  taskId,
8
6
  assignee: 'test-assignee',
@@ -25,7 +23,7 @@ describe('DAG Module', () => {
25
23
  expect(dag.waves).toEqual([
26
24
  { waveIndex: 0, taskIds: ['A', 'B', 'C'].sort() },
27
25
  ]);
28
- expect(dag.criticalPath.length).toBe(1); // Any single task is critical path
26
+ expect(dag.criticalPath.length).toBe(1);
29
27
  expect(dag.parallelismFactor).toBeCloseTo(3);
30
28
  });
31
29
  test('should correctly build DAG for linear dependencies (A->B->C)', () => {
@@ -58,16 +56,15 @@ describe('DAG Module', () => {
58
56
  { waveIndex: 1, taskIds: ['B', 'C'].sort() },
59
57
  { waveIndex: 2, taskIds: ['D'] },
60
58
  ]);
61
- // Critical path can be A->B->D or A->C->D, both have length 3
62
59
  expect(dag.criticalPath.length).toBe(3);
63
60
  expect(dag.criticalPath[0]).toBe('A');
64
61
  expect(['B', 'C']).toContain(dag.criticalPath[1]);
65
62
  expect(dag.criticalPath[2]).toBe('D');
66
- expect(dag.parallelismFactor).toBeCloseTo(4 / 3); // 4 tasks / 3 waves
63
+ expect(dag.parallelismFactor).toBeCloseTo(4 / 3);
67
64
  });
68
65
  test('should detect a cycle and throw ValidationError (A->B->C->A)', () => {
69
66
  const tasks = [
70
- createTask('A', ['C']), // A depends on C
67
+ createTask('A', ['C']),
71
68
  createTask('B', ['A']),
72
69
  createTask('C', ['B']),
73
70
  ];
@@ -100,7 +97,7 @@ describe('DAG Module', () => {
100
97
  test('should throw ValidationError for dangling dependencies', () => {
101
98
  const tasks = [
102
99
  createTask('A'),
103
- createTask('B', ['X']), // X does not exist
100
+ createTask('B', ['X']),
104
101
  ];
105
102
  expect(() => buildDAG(tasks)).toThrow(ValidationError);
106
103
  expect(() => buildDAG(tasks)).toThrow("Invalid dependencies: Task B depends on non-existent task X");
@@ -120,8 +117,8 @@ describe('DAG Module', () => {
120
117
  { waveIndex: 1, taskIds: ['B', 'D'].sort() },
121
118
  { waveIndex: 2, taskIds: ['E'] },
122
119
  ]);
123
- expect(dag.criticalPath.length).toBe(3); // A->B->E or C->D->E
124
- expect(dag.criticalPath[0]).toBe('A'); // or C
120
+ expect(dag.criticalPath.length).toBe(3);
121
+ expect(dag.criticalPath[0]).toBe('A');
125
122
  expect(['B', 'D']).toContain(dag.criticalPath[1]);
126
123
  expect(dag.criticalPath[2]).toBe('E');
127
124
  expect(dag.parallelismFactor).toBeCloseTo(5 / 3);
@@ -216,11 +213,9 @@ describe('DAG Module', () => {
216
213
  test('should return false if a dependency does not exist (handled by validateDependencies)', () => {
217
214
  const tasks = [
218
215
  createTask('A', [], 'completed'),
219
- createTask('C', ['A', 'X']), // X does not exist
216
+ createTask('C', ['A', 'X']),
220
217
  ];
221
218
  const taskC = tasks[1];
222
- // This function assumes valid dependencies. If a dependency is missing,
223
- // find will return undefined, and (undefined && undefined.status === 'completed') will be false.
224
219
  expect(areDependenciesMet(taskC, tasks)).toBe(false);
225
220
  });
226
221
  });
@@ -247,8 +242,8 @@ describe('DAG Module', () => {
247
242
  test('should return valid false and errors for tasks with non-existent dependencies', () => {
248
243
  const tasks = [
249
244
  createTask('A'),
250
- createTask('B', ['A', 'X']), // X does not exist
251
- createTask('C', ['Y']), // Y does not exist
245
+ createTask('B', ['A', 'X']),
246
+ createTask('C', ['Y']),
252
247
  ];
253
248
  const result = validateDependencies(tasks);
254
249
  expect(result.valid).toBe(false);
@@ -1,9 +1 @@
1
- /**
2
- * Logger Unit Tests
3
- *
4
- * Tests for logEvent and readLog functions
5
- * Following Red-Green-Refactor cycle
6
- *
7
- * @author Kent Beck's TDD Approach
8
- */
9
1
  export {};
@@ -1,11 +1,3 @@
1
- /**
2
- * Logger Unit Tests
3
- *
4
- * Tests for logEvent and readLog functions
5
- * Following Red-Green-Refactor cycle
6
- *
7
- * @author Kent Beck's TDD Approach
8
- */
9
1
  import { describe, test, expect, beforeEach, afterEach } from "vitest";
10
2
  import { tmpdir } from "os";
11
3
  import { join } from "path";
@@ -14,26 +6,18 @@ import { existsSync } from "fs";
14
6
  import { logEvent, readLog } from "../logger.js";
15
7
  import { FileStorageAdapter } from "../storage.js";
16
8
  import { createSession } from "../session.js";
17
- // ============================================================================
18
- // Test Setup
19
- // ============================================================================
20
9
  let tempDir;
21
10
  let storage;
22
11
  beforeEach(async () => {
23
- // Create unique temp directory for each test
24
12
  tempDir = join(tmpdir(), `logger-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
25
13
  await mkdir(tempDir, { recursive: true });
26
14
  storage = new FileStorageAdapter(tempDir);
27
15
  });
28
16
  afterEach(async () => {
29
- // Clean up temp directory
30
17
  if (existsSync(tempDir)) {
31
18
  await rm(tempDir, { recursive: true, force: true });
32
19
  }
33
20
  });
34
- // ============================================================================
35
- // Helper Functions
36
- // ============================================================================
37
21
  async function createTestSession() {
38
22
  return createSession(storage, {
39
23
  goal: "Test goal",
@@ -41,35 +25,26 @@ async function createTestSession() {
41
25
  });
42
26
  }
43
27
  async function createSquadDir(session, squadId) {
44
- // Use mkdir directly with absolute path to avoid ensureDir's path handling issues
45
28
  const fullPath = storage.getFullPath(`${session.sessionPath}/squads/${squadId}`);
46
29
  await mkdir(fullPath, { recursive: true });
47
30
  }
48
- // ============================================================================
49
- // logEvent Tests
50
- // ============================================================================
51
31
  describe("logEvent", () => {
52
32
  test("should create log.jsonl file after logging an event", async () => {
53
- // Arrange
54
33
  const session = await createTestSession();
55
34
  const squadId = "squad-001";
56
35
  await createSquadDir(session, squadId);
57
- // Act
58
36
  await logEvent(session, squadId, {
59
37
  type: "squad_started",
60
38
  squadId,
61
39
  operator: "operator-agent",
62
40
  });
63
- // Assert
64
41
  const logPath = storage.getFullPath(`${session.sessionPath}/squads/${squadId}/log.jsonl`);
65
42
  expect(existsSync(logPath)).toBe(true);
66
43
  });
67
44
  test("should append multiple events in order", async () => {
68
- // Arrange
69
45
  const session = await createTestSession();
70
46
  const squadId = "squad-002";
71
47
  await createSquadDir(session, squadId);
72
- // Act - Log three events
73
48
  await logEvent(session, squadId, {
74
49
  type: "squad_started",
75
50
  squadId,
@@ -87,7 +62,6 @@ describe("logEvent", () => {
87
62
  assignee: "worker-agent",
88
63
  result: { success: true },
89
64
  });
90
- // Assert - Read and verify order
91
65
  const events = await readLog(session, squadId);
92
66
  expect(events).toHaveLength(3);
93
67
  expect(events[0].type).toBe("squad_started");
@@ -95,39 +69,32 @@ describe("logEvent", () => {
95
69
  expect(events[2].type).toBe("task_completed");
96
70
  });
97
71
  test("should auto-generate ts field with ISO timestamp", async () => {
98
- // Arrange
99
72
  const session = await createTestSession();
100
73
  const squadId = "squad-003";
101
74
  await createSquadDir(session, squadId);
102
75
  const beforeTime = new Date().toISOString();
103
- // Act
104
76
  await logEvent(session, squadId, {
105
77
  type: "error",
106
78
  message: "Something went wrong",
107
79
  source: "test-agent",
108
80
  });
109
81
  const afterTime = new Date().toISOString();
110
- // Assert
111
82
  const events = await readLog(session, squadId);
112
83
  expect(events).toHaveLength(1);
113
84
  expect(events[0].ts).toBeDefined();
114
85
  expect(typeof events[0].ts).toBe("string");
115
- // Verify ts is between before and after
116
86
  expect(events[0].ts >= beforeTime).toBe(true);
117
87
  expect(events[0].ts <= afterTime).toBe(true);
118
88
  });
119
89
  test("should preserve all event properties", async () => {
120
- // Arrange
121
90
  const session = await createTestSession();
122
91
  const squadId = "squad-004";
123
92
  await createSquadDir(session, squadId);
124
- // Act
125
93
  await logEvent(session, squadId, {
126
94
  type: "context_updated",
127
95
  key: "shared-data",
128
96
  updatedBy: "agent-x",
129
97
  });
130
- // Assert
131
98
  const events = await readLog(session, squadId);
132
99
  expect(events).toHaveLength(1);
133
100
  const event = events[0];
@@ -136,16 +103,11 @@ describe("logEvent", () => {
136
103
  expect(event.updatedBy).toBe("agent-x");
137
104
  });
138
105
  });
139
- // ============================================================================
140
- // readLog Tests
141
- // ============================================================================
142
106
  describe("readLog", () => {
143
107
  test("should return all logged events", async () => {
144
- // Arrange
145
108
  const session = await createTestSession();
146
109
  const squadId = "squad-005";
147
110
  await createSquadDir(session, squadId);
148
- // Log events
149
111
  await logEvent(session, squadId, {
150
112
  type: "squad_started",
151
113
  squadId,
@@ -156,42 +118,30 @@ describe("readLog", () => {
156
118
  squadId,
157
119
  finalStatus: "completed",
158
120
  });
159
- // Act
160
121
  const events = await readLog(session, squadId);
161
- // Assert
162
122
  expect(events).toHaveLength(2);
163
123
  expect(events[0].type).toBe("squad_started");
164
124
  expect(events[1].type).toBe("squad_completed");
165
125
  });
166
126
  test("should return empty array for empty log", async () => {
167
- // Arrange
168
127
  const session = await createTestSession();
169
128
  const squadId = "squad-006";
170
129
  await createSquadDir(session, squadId);
171
- // Create an empty log file
172
130
  const logPath = `${session.sessionPath}/squads/${squadId}/log.jsonl`;
173
131
  await writeFile(storage.getFullPath(logPath), "");
174
- // Act
175
132
  const events = await readLog(session, squadId);
176
- // Assert
177
133
  expect(events).toEqual([]);
178
134
  });
179
135
  test("should return empty array when log file does not exist", async () => {
180
- // Arrange
181
136
  const session = await createTestSession();
182
137
  const squadId = "nonexistent-squad";
183
- // Intentionally NOT creating the squad directory
184
- // Act
185
138
  const events = await readLog(session, squadId);
186
- // Assert
187
139
  expect(events).toEqual([]);
188
140
  });
189
141
  test("should correctly parse all LogEvent types", async () => {
190
- // Arrange
191
142
  const session = await createTestSession();
192
143
  const squadId = "squad-007";
193
144
  await createSquadDir(session, squadId);
194
- // Log all event types
195
145
  await logEvent(session, squadId, {
196
146
  type: "squad_started",
197
147
  squadId,
@@ -222,9 +172,7 @@ describe("readLog", () => {
222
172
  type: "error",
223
173
  message: "Oops",
224
174
  });
225
- // Act
226
175
  const events = await readLog(session, squadId);
227
- // Assert
228
176
  expect(events).toHaveLength(6);
229
177
  expect(events.map((e) => e.type)).toEqual([
230
178
  "squad_started",
@@ -1,8 +1 @@
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
  export {};