wogiflow 1.0.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 (221) hide show
  1. package/.workflow/agents/reviewer.md +81 -0
  2. package/.workflow/agents/security.md +94 -0
  3. package/.workflow/agents/story-writer.md +58 -0
  4. package/.workflow/bridges/base-bridge.js +395 -0
  5. package/.workflow/bridges/claude-bridge.js +434 -0
  6. package/.workflow/bridges/index.js +130 -0
  7. package/.workflow/lib/assumption-detector.js +481 -0
  8. package/.workflow/lib/config-substitution.js +371 -0
  9. package/.workflow/lib/failure-categories.js +478 -0
  10. package/.workflow/state/app-map.md.template +15 -0
  11. package/.workflow/state/architecture.md.template +24 -0
  12. package/.workflow/state/component-index.json.template +5 -0
  13. package/.workflow/state/decisions.md.template +15 -0
  14. package/.workflow/state/feedback-patterns.md.template +9 -0
  15. package/.workflow/state/knowledge-sync.json.template +6 -0
  16. package/.workflow/state/progress.md.template +14 -0
  17. package/.workflow/state/ready.json.template +7 -0
  18. package/.workflow/state/request-log.md.template +14 -0
  19. package/.workflow/state/session-state.json.template +11 -0
  20. package/.workflow/state/stack.md.template +33 -0
  21. package/.workflow/state/testing.md.template +36 -0
  22. package/.workflow/templates/claude-md.hbs +257 -0
  23. package/.workflow/templates/correction-report.md +67 -0
  24. package/.workflow/templates/gemini-md.hbs +52 -0
  25. package/README.md +1802 -0
  26. package/bin/flow +205 -0
  27. package/lib/index.js +33 -0
  28. package/lib/installer.js +467 -0
  29. package/lib/release-channel.js +269 -0
  30. package/lib/skill-registry.js +526 -0
  31. package/lib/upgrader.js +401 -0
  32. package/lib/utils.js +305 -0
  33. package/package.json +64 -0
  34. package/scripts/flow +985 -0
  35. package/scripts/flow-adaptive-learning.js +1259 -0
  36. package/scripts/flow-aggregate.js +488 -0
  37. package/scripts/flow-archive +133 -0
  38. package/scripts/flow-auto-context.js +1015 -0
  39. package/scripts/flow-auto-learn.js +615 -0
  40. package/scripts/flow-bridge.js +223 -0
  41. package/scripts/flow-browser-suggest.js +316 -0
  42. package/scripts/flow-bug.js +247 -0
  43. package/scripts/flow-cascade.js +711 -0
  44. package/scripts/flow-changelog +85 -0
  45. package/scripts/flow-checkpoint.js +483 -0
  46. package/scripts/flow-cli.js +403 -0
  47. package/scripts/flow-code-intelligence.js +760 -0
  48. package/scripts/flow-complexity.js +502 -0
  49. package/scripts/flow-config-set.js +152 -0
  50. package/scripts/flow-constants.js +157 -0
  51. package/scripts/flow-context +152 -0
  52. package/scripts/flow-context-init.js +482 -0
  53. package/scripts/flow-context-monitor.js +384 -0
  54. package/scripts/flow-context-scoring.js +886 -0
  55. package/scripts/flow-correct.js +458 -0
  56. package/scripts/flow-damage-control.js +985 -0
  57. package/scripts/flow-deps +101 -0
  58. package/scripts/flow-diff.js +700 -0
  59. package/scripts/flow-done +151 -0
  60. package/scripts/flow-done.js +489 -0
  61. package/scripts/flow-durable-session.js +1541 -0
  62. package/scripts/flow-entropy-monitor.js +345 -0
  63. package/scripts/flow-export-profile +349 -0
  64. package/scripts/flow-export-scanner.js +1046 -0
  65. package/scripts/flow-figma-confirm.js +400 -0
  66. package/scripts/flow-figma-extract.js +496 -0
  67. package/scripts/flow-figma-generate.js +683 -0
  68. package/scripts/flow-figma-index.js +909 -0
  69. package/scripts/flow-figma-match.js +617 -0
  70. package/scripts/flow-figma-mcp-server.js +518 -0
  71. package/scripts/flow-figma-pipeline.js +414 -0
  72. package/scripts/flow-file-ops.js +301 -0
  73. package/scripts/flow-gate-confidence.js +825 -0
  74. package/scripts/flow-guided-edit.js +659 -0
  75. package/scripts/flow-health +185 -0
  76. package/scripts/flow-health.js +413 -0
  77. package/scripts/flow-hooks.js +556 -0
  78. package/scripts/flow-http-client.js +249 -0
  79. package/scripts/flow-hybrid-detect.js +167 -0
  80. package/scripts/flow-hybrid-interactive.js +591 -0
  81. package/scripts/flow-hybrid-test.js +152 -0
  82. package/scripts/flow-import-profile +439 -0
  83. package/scripts/flow-init +253 -0
  84. package/scripts/flow-instruction-richness.js +827 -0
  85. package/scripts/flow-jira-integration.js +579 -0
  86. package/scripts/flow-knowledge-router.js +522 -0
  87. package/scripts/flow-knowledge-sync.js +589 -0
  88. package/scripts/flow-linear-integration.js +631 -0
  89. package/scripts/flow-links.js +774 -0
  90. package/scripts/flow-log-manager.js +559 -0
  91. package/scripts/flow-loop-enforcer.js +1246 -0
  92. package/scripts/flow-loop-retry-learning.js +630 -0
  93. package/scripts/flow-lsp.js +923 -0
  94. package/scripts/flow-map-index +348 -0
  95. package/scripts/flow-map-sync +201 -0
  96. package/scripts/flow-memory-blocks.js +668 -0
  97. package/scripts/flow-memory-compactor.js +350 -0
  98. package/scripts/flow-memory-db.js +1110 -0
  99. package/scripts/flow-memory-sync.js +484 -0
  100. package/scripts/flow-metrics.js +353 -0
  101. package/scripts/flow-migrate-ids.js +370 -0
  102. package/scripts/flow-model-adapter.js +802 -0
  103. package/scripts/flow-model-router.js +884 -0
  104. package/scripts/flow-models.js +1231 -0
  105. package/scripts/flow-morning.js +517 -0
  106. package/scripts/flow-multi-approach.js +660 -0
  107. package/scripts/flow-new-feature +86 -0
  108. package/scripts/flow-onboard +1042 -0
  109. package/scripts/flow-orchestrate-llm.js +459 -0
  110. package/scripts/flow-orchestrate.js +3592 -0
  111. package/scripts/flow-output.js +123 -0
  112. package/scripts/flow-parallel-detector.js +399 -0
  113. package/scripts/flow-parallel-dispatch.js +987 -0
  114. package/scripts/flow-parallel.js +428 -0
  115. package/scripts/flow-pattern-enforcer.js +600 -0
  116. package/scripts/flow-prd-manager.js +282 -0
  117. package/scripts/flow-progress.js +323 -0
  118. package/scripts/flow-project-analyzer.js +975 -0
  119. package/scripts/flow-prompt-composer.js +487 -0
  120. package/scripts/flow-providers.js +1381 -0
  121. package/scripts/flow-queue.js +308 -0
  122. package/scripts/flow-ready +82 -0
  123. package/scripts/flow-ready.js +189 -0
  124. package/scripts/flow-regression.js +396 -0
  125. package/scripts/flow-response-parser.js +450 -0
  126. package/scripts/flow-resume.js +284 -0
  127. package/scripts/flow-rules-sync.js +439 -0
  128. package/scripts/flow-run-trace.js +718 -0
  129. package/scripts/flow-safety.js +587 -0
  130. package/scripts/flow-search +104 -0
  131. package/scripts/flow-security.js +481 -0
  132. package/scripts/flow-session-end +106 -0
  133. package/scripts/flow-session-end.js +437 -0
  134. package/scripts/flow-session-state.js +671 -0
  135. package/scripts/flow-setup-hooks +216 -0
  136. package/scripts/flow-setup-hooks.js +377 -0
  137. package/scripts/flow-skill-create.js +329 -0
  138. package/scripts/flow-skill-creator.js +572 -0
  139. package/scripts/flow-skill-generator.js +1046 -0
  140. package/scripts/flow-skill-learn.js +880 -0
  141. package/scripts/flow-skill-matcher.js +578 -0
  142. package/scripts/flow-spec-generator.js +820 -0
  143. package/scripts/flow-stack-wizard.js +895 -0
  144. package/scripts/flow-standup +162 -0
  145. package/scripts/flow-start +74 -0
  146. package/scripts/flow-start.js +235 -0
  147. package/scripts/flow-status +110 -0
  148. package/scripts/flow-status.js +301 -0
  149. package/scripts/flow-step-browser.js +83 -0
  150. package/scripts/flow-step-changelog.js +217 -0
  151. package/scripts/flow-step-comments.js +306 -0
  152. package/scripts/flow-step-complexity.js +234 -0
  153. package/scripts/flow-step-coverage.js +218 -0
  154. package/scripts/flow-step-knowledge.js +193 -0
  155. package/scripts/flow-step-pr-tests.js +364 -0
  156. package/scripts/flow-step-regression.js +89 -0
  157. package/scripts/flow-step-review.js +516 -0
  158. package/scripts/flow-step-security.js +162 -0
  159. package/scripts/flow-step-silent-failures.js +290 -0
  160. package/scripts/flow-step-simplifier.js +346 -0
  161. package/scripts/flow-story +105 -0
  162. package/scripts/flow-story.js +500 -0
  163. package/scripts/flow-suspend.js +252 -0
  164. package/scripts/flow-sync-daemon.js +654 -0
  165. package/scripts/flow-task-analyzer.js +606 -0
  166. package/scripts/flow-team-dashboard.js +748 -0
  167. package/scripts/flow-team-sync.js +752 -0
  168. package/scripts/flow-team.js +977 -0
  169. package/scripts/flow-tech-options.js +528 -0
  170. package/scripts/flow-templates.js +812 -0
  171. package/scripts/flow-tiered-learning.js +728 -0
  172. package/scripts/flow-trace +204 -0
  173. package/scripts/flow-transcript-chunking.js +1106 -0
  174. package/scripts/flow-transcript-digest.js +7918 -0
  175. package/scripts/flow-transcript-language.js +465 -0
  176. package/scripts/flow-transcript-parsing.js +1085 -0
  177. package/scripts/flow-transcript-stories.js +2194 -0
  178. package/scripts/flow-update-map +224 -0
  179. package/scripts/flow-utils.js +2242 -0
  180. package/scripts/flow-verification.js +644 -0
  181. package/scripts/flow-verify.js +1177 -0
  182. package/scripts/flow-voice-input.js +638 -0
  183. package/scripts/flow-watch +168 -0
  184. package/scripts/flow-workflow-steps.js +521 -0
  185. package/scripts/flow-workflow.js +1029 -0
  186. package/scripts/flow-worktree.js +489 -0
  187. package/scripts/hooks/adapters/base-adapter.js +102 -0
  188. package/scripts/hooks/adapters/claude-code.js +359 -0
  189. package/scripts/hooks/adapters/index.js +79 -0
  190. package/scripts/hooks/core/component-check.js +341 -0
  191. package/scripts/hooks/core/index.js +35 -0
  192. package/scripts/hooks/core/loop-check.js +241 -0
  193. package/scripts/hooks/core/session-context.js +294 -0
  194. package/scripts/hooks/core/task-gate.js +177 -0
  195. package/scripts/hooks/core/validation.js +230 -0
  196. package/scripts/hooks/entry/claude-code/post-tool-use.js +65 -0
  197. package/scripts/hooks/entry/claude-code/pre-tool-use.js +89 -0
  198. package/scripts/hooks/entry/claude-code/session-end.js +87 -0
  199. package/scripts/hooks/entry/claude-code/session-start.js +46 -0
  200. package/scripts/hooks/entry/claude-code/stop.js +43 -0
  201. package/scripts/postinstall.js +139 -0
  202. package/templates/browser-test-flow.json +56 -0
  203. package/templates/bug-report.md +43 -0
  204. package/templates/component-detail.md +42 -0
  205. package/templates/component.stories.tsx +49 -0
  206. package/templates/context/constraints.md +83 -0
  207. package/templates/context/conventions.md +177 -0
  208. package/templates/context/stack.md +60 -0
  209. package/templates/correction-report.md +90 -0
  210. package/templates/feature-proposal.md +35 -0
  211. package/templates/hybrid/_base.md +254 -0
  212. package/templates/hybrid/_patterns.md +45 -0
  213. package/templates/hybrid/create-component.md +127 -0
  214. package/templates/hybrid/create-file.md +56 -0
  215. package/templates/hybrid/create-hook.md +145 -0
  216. package/templates/hybrid/create-service.md +70 -0
  217. package/templates/hybrid/fix-bug.md +33 -0
  218. package/templates/hybrid/modify-file.md +55 -0
  219. package/templates/story.md +68 -0
  220. package/templates/task.json +56 -0
  221. package/templates/trace.md +69 -0
@@ -0,0 +1,428 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Wogi Flow - Parallel Execution Module
5
+ *
6
+ * Enables parallel task execution with dependency detection and worktree isolation.
7
+ *
8
+ * Features:
9
+ * - Detects independent tasks that can run in parallel
10
+ * - Manages concurrent execution with configurable limits
11
+ * - Integrates with worktree isolation for safe parallel execution
12
+ * - Provides progress visibility for all running tasks
13
+ *
14
+ * Usage:
15
+ * const { canRunInParallel, executeParallel, detectDependencies } = require('./flow-parallel');
16
+ *
17
+ * if (canRunInParallel(tasks)) {
18
+ * await executeParallel(tasks, { maxConcurrent: 3 });
19
+ * }
20
+ */
21
+
22
+ const fs = require('fs');
23
+ const path = require('path');
24
+ const { getProjectRoot, getConfig } = require('./flow-utils');
25
+
26
+ // ============================================================
27
+ // Configuration (uses centralized getConfig from flow-utils)
28
+ // ============================================================
29
+
30
+ /**
31
+ * Get parallel execution config
32
+ * Merges defaults with config.json parallel section
33
+ */
34
+ function getParallelConfig() {
35
+ const config = getConfig();
36
+ return {
37
+ ...getDefaultConfig(),
38
+ ...(config.parallel || {})
39
+ };
40
+ }
41
+
42
+ function getDefaultConfig() {
43
+ return {
44
+ enabled: true,
45
+ maxConcurrent: 3,
46
+ autoApprove: false,
47
+ requireWorktree: true,
48
+ showProgress: true
49
+ };
50
+ }
51
+
52
+ // ============================================================
53
+ // Dependency Detection
54
+ // ============================================================
55
+
56
+ /**
57
+ * Detect dependencies between tasks
58
+ *
59
+ * @param {Array} tasks - Array of task objects with { id, dependencies, files }
60
+ * @returns {Object} Dependency graph { taskId: [dependsOn...] }
61
+ */
62
+ function detectDependencies(tasks) {
63
+ const dependencies = {};
64
+
65
+ for (const task of tasks) {
66
+ dependencies[task.id] = [];
67
+
68
+ // Explicit dependencies from task definition
69
+ if (task.dependencies && Array.isArray(task.dependencies)) {
70
+ dependencies[task.id].push(...task.dependencies);
71
+ }
72
+
73
+ // File-based dependency detection
74
+ if (task.files && Array.isArray(task.files)) {
75
+ for (const otherTask of tasks) {
76
+ if (otherTask.id === task.id) continue;
77
+
78
+ // Check if this task modifies files that the other task depends on
79
+ if (otherTask.files && Array.isArray(otherTask.files)) {
80
+ const overlap = task.files.some(f => otherTask.files.includes(f));
81
+ if (overlap && !dependencies[task.id].includes(otherTask.id)) {
82
+ // Only add dependency if order matters (task comes after otherTask in list)
83
+ const taskIndex = tasks.findIndex(t => t.id === task.id);
84
+ const otherIndex = tasks.findIndex(t => t.id === otherTask.id);
85
+ if (otherIndex < taskIndex) {
86
+ dependencies[task.id].push(otherTask.id);
87
+ }
88
+ }
89
+ }
90
+ }
91
+ }
92
+ }
93
+
94
+ return dependencies;
95
+ }
96
+
97
+ /**
98
+ * Find tasks that can run in parallel (no unmet dependencies)
99
+ *
100
+ * @param {Array} tasks - Array of task objects
101
+ * @param {Set} completed - Set of completed task IDs
102
+ * @param {Object} dependencies - Dependency graph
103
+ * @returns {Array} Tasks that can run now
104
+ */
105
+ function findParallelizable(tasks, completed = new Set(), dependencies = null) {
106
+ const deps = dependencies || detectDependencies(tasks);
107
+ const parallelizable = [];
108
+
109
+ for (const task of tasks) {
110
+ if (completed.has(task.id)) continue;
111
+
112
+ const taskDeps = deps[task.id] || [];
113
+ const unmetDeps = taskDeps.filter(d => !completed.has(d));
114
+
115
+ if (unmetDeps.length === 0) {
116
+ parallelizable.push(task);
117
+ }
118
+ }
119
+
120
+ return parallelizable;
121
+ }
122
+
123
+ /**
124
+ * Check if tasks can run in parallel
125
+ *
126
+ * @param {Array} tasks - Tasks to check
127
+ * @returns {boolean} True if at least 2 tasks can run in parallel
128
+ */
129
+ function canRunInParallel(tasks) {
130
+ if (!tasks || tasks.length < 2) return false;
131
+
132
+ const parallelizable = findParallelizable(tasks);
133
+ return parallelizable.length >= 2;
134
+ }
135
+
136
+ // ============================================================
137
+ // Progress Tracking
138
+ // ============================================================
139
+
140
+ /**
141
+ * Create a progress tracker for parallel execution
142
+ */
143
+ function createProgressTracker(tasks) {
144
+ const state = {
145
+ total: tasks.length,
146
+ completed: 0,
147
+ inProgress: new Set(),
148
+ results: {},
149
+ startTime: Date.now()
150
+ };
151
+
152
+ return {
153
+ start(taskId) {
154
+ state.inProgress.add(taskId);
155
+ this.render();
156
+ },
157
+
158
+ complete(taskId, result) {
159
+ state.inProgress.delete(taskId);
160
+ state.completed++;
161
+ state.results[taskId] = result;
162
+ this.render();
163
+ },
164
+
165
+ fail(taskId, error) {
166
+ state.inProgress.delete(taskId);
167
+ state.results[taskId] = { success: false, error: error.message };
168
+ this.render();
169
+ },
170
+
171
+ render() {
172
+ const elapsed = Math.round((Date.now() - state.startTime) / 1000);
173
+ const percent = Math.round((state.completed / state.total) * 100);
174
+ const bar = 'ā–ˆ'.repeat(Math.round(percent / 5)) + 'ā–‘'.repeat(20 - Math.round(percent / 5));
175
+
176
+ console.log('\n' + '─'.repeat(60));
177
+ console.log(`ā± Elapsed: ${elapsed}s | Progress: ${state.completed}/${state.total} (${percent}%)`);
178
+ console.log(`[${bar}]`);
179
+
180
+ if (state.inProgress.size > 0) {
181
+ console.log(`šŸ”„ Running: ${[...state.inProgress].join(', ')}`);
182
+ }
183
+ console.log('─'.repeat(60));
184
+ },
185
+
186
+ getSummary() {
187
+ const successful = Object.values(state.results).filter(r => r.success).length;
188
+ const failed = Object.values(state.results).filter(r => !r.success).length;
189
+ const elapsed = Math.round((Date.now() - state.startTime) / 1000);
190
+
191
+ return {
192
+ total: state.total,
193
+ completed: state.completed,
194
+ successful,
195
+ failed,
196
+ elapsed,
197
+ results: state.results
198
+ };
199
+ }
200
+ };
201
+ }
202
+
203
+ // ============================================================
204
+ // Parallel Execution
205
+ // ============================================================
206
+
207
+ /**
208
+ * Execute tasks in parallel with dependency awareness
209
+ *
210
+ * @param {Array} tasks - Tasks to execute
211
+ * @param {Function} executor - Async function(task) to execute each task
212
+ * @param {Object} options - Execution options
213
+ * @returns {Object} Execution results
214
+ */
215
+ async function executeParallel(tasks, executor, options = {}) {
216
+ const config = getParallelConfig();
217
+ const {
218
+ maxConcurrent = config.maxConcurrent,
219
+ showProgress = config.showProgress,
220
+ onStart,
221
+ onComplete,
222
+ onError
223
+ } = options;
224
+
225
+ const dependencies = detectDependencies(tasks);
226
+ const finished = new Set(); // All tasks that have run (success or failure)
227
+ const succeeded = new Set(); // Only tasks that succeeded
228
+ const tracker = showProgress ? createProgressTracker(tasks) : null;
229
+
230
+ // Process tasks in waves (respecting dependencies)
231
+ while (finished.size < tasks.length) {
232
+ // Use 'succeeded' for dependency checking - tasks with failed dependencies won't run
233
+ const parallelizable = findParallelizable(tasks, succeeded, dependencies)
234
+ .filter(t => !finished.has(t.id)); // Don't re-run finished tasks
235
+
236
+ if (parallelizable.length === 0) {
237
+ // Check if we're stuck due to failed dependencies or circular deps
238
+ const remaining = tasks.filter(t => !finished.has(t.id));
239
+ if (remaining.length > 0) {
240
+ // Check if remaining tasks have unmet dependencies due to failures
241
+ const blockedByFailure = remaining.filter(t => {
242
+ const taskDeps = dependencies[t.id] || [];
243
+ return taskDeps.some(d => finished.has(d) && !succeeded.has(d));
244
+ });
245
+
246
+ if (blockedByFailure.length > 0) {
247
+ // Tasks are blocked because their dependencies failed
248
+ console.warn(`\nāš ļø ${blockedByFailure.length} task(s) skipped due to failed dependencies:`);
249
+ blockedByFailure.forEach(t => {
250
+ const failedDeps = (dependencies[t.id] || []).filter(d => finished.has(d) && !succeeded.has(d));
251
+ console.warn(` ${t.id} (blocked by: ${failedDeps.join(', ')})`);
252
+ finished.add(t.id); // Mark as finished (skipped)
253
+ });
254
+ continue; // Try next wave
255
+ }
256
+
257
+ // No tasks blocked by failure - must be circular dependency
258
+ throw new Error(`Circular dependency detected among: ${remaining.map(t => t.id).join(', ')}`);
259
+ }
260
+ break;
261
+ }
262
+
263
+ // Execute up to maxConcurrent tasks at once
264
+ const batch = parallelizable.slice(0, maxConcurrent);
265
+ const promises = batch.map(async (task) => {
266
+ try {
267
+ if (tracker) tracker.start(task.id);
268
+ if (onStart) onStart(task);
269
+ } catch (callbackError) {
270
+ // Don't let callback errors prevent task execution
271
+ console.warn(`Callback error for ${task.id}: ${callbackError.message}`);
272
+ }
273
+
274
+ try {
275
+ const result = await executor(task);
276
+ finished.add(task.id);
277
+ succeeded.add(task.id);
278
+
279
+ try {
280
+ if (tracker) tracker.complete(task.id, result);
281
+ if (onComplete) onComplete(task, result);
282
+ } catch (callbackError) {
283
+ console.warn(`Completion callback error for ${task.id}: ${callbackError.message}`);
284
+ }
285
+
286
+ return { taskId: task.id, success: true, result };
287
+ } catch (error) {
288
+ finished.add(task.id); // Mark as finished but NOT succeeded
289
+
290
+ try {
291
+ if (tracker) tracker.fail(task.id, error);
292
+ if (onError) onError(task, error);
293
+ } catch (callbackError) {
294
+ console.warn(`Error callback error for ${task.id}: ${callbackError.message}`);
295
+ }
296
+
297
+ return { taskId: task.id, success: false, error: error.message };
298
+ }
299
+ });
300
+
301
+ // Use allSettled to prevent one failure from killing all tasks
302
+ const results = await Promise.allSettled(promises);
303
+
304
+ // Handle any unexpected rejections (shouldn't happen but safety first)
305
+ for (const result of results) {
306
+ if (result.status === 'rejected') {
307
+ console.error(`Unexpected rejection in parallel execution: ${result.reason}`);
308
+ }
309
+ }
310
+ }
311
+
312
+ return tracker ? tracker.getSummary() : { finished: finished.size, succeeded: succeeded.size };
313
+ }
314
+
315
+ /**
316
+ * Check if user approval is needed for parallel execution
317
+ */
318
+ function needsApproval(tasks, config = null) {
319
+ const cfg = config || getParallelConfig();
320
+
321
+ if (!cfg.enabled) return { needed: false, reason: 'parallel-disabled' };
322
+ if (cfg.autoApprove) return { needed: false, reason: 'auto-approved' };
323
+ if (tasks.length < 2) return { needed: false, reason: 'single-task' };
324
+
325
+ const parallelizable = findParallelizable(tasks);
326
+ if (parallelizable.length < 2) return { needed: false, reason: 'dependencies' };
327
+
328
+ return {
329
+ needed: true,
330
+ reason: 'manual-approval-required',
331
+ tasks: parallelizable.map(t => t.id),
332
+ message: `${parallelizable.length} tasks can run in parallel. Approve parallel execution?`
333
+ };
334
+ }
335
+
336
+ // ============================================================
337
+ // Exports
338
+ // ============================================================
339
+
340
+ // Alias for backward compatibility - some modules expect loadConfig
341
+ function loadConfig() {
342
+ return getParallelConfig();
343
+ }
344
+
345
+ module.exports = {
346
+ // Configuration
347
+ loadConfig,
348
+ getParallelConfig,
349
+ getDefaultConfig,
350
+
351
+ // Dependency detection
352
+ detectDependencies,
353
+ findParallelizable,
354
+ canRunInParallel,
355
+
356
+ // Execution
357
+ executeParallel,
358
+ createProgressTracker,
359
+ needsApproval
360
+ };
361
+
362
+ // ============================================================
363
+ // CLI
364
+ // ============================================================
365
+
366
+ if (require.main === module) {
367
+ const args = process.argv.slice(2);
368
+ const command = args[0];
369
+
370
+ switch (command) {
371
+ case 'config': {
372
+ const config = getParallelConfig();
373
+ console.log('\nšŸ“Š Parallel Execution Configuration:\n');
374
+ console.log(JSON.stringify(config, null, 2));
375
+ break;
376
+ }
377
+
378
+ case 'check': {
379
+ // Load tasks from ready.json and check for parallelizable ones
380
+ const readyPath = path.join(getProjectRoot(), '.workflow', 'state', 'ready.json');
381
+ if (!fs.existsSync(readyPath)) {
382
+ console.log('No ready.json found');
383
+ process.exit(1);
384
+ }
385
+
386
+ const ready = JSON.parse(fs.readFileSync(readyPath, 'utf-8'));
387
+ const tasks = (ready.tasks || []).filter(t => t.status === 'pending' || t.status === 'ready');
388
+
389
+ if (tasks.length === 0) {
390
+ console.log('No tasks ready for execution');
391
+ process.exit(0);
392
+ }
393
+
394
+ const deps = detectDependencies(tasks);
395
+ const parallelizable = findParallelizable(tasks);
396
+
397
+ console.log('\nšŸ“‹ Task Analysis:\n');
398
+ console.log(`Total tasks: ${tasks.length}`);
399
+ console.log(`Can run in parallel: ${parallelizable.length}`);
400
+ console.log(`\nParallelizable tasks:`);
401
+ parallelizable.forEach(t => console.log(` - ${t.id}: ${t.title || t.description || 'No description'}`));
402
+
403
+ console.log('\nDependency graph:');
404
+ for (const [taskId, taskDeps] of Object.entries(deps)) {
405
+ if (taskDeps.length > 0) {
406
+ console.log(` ${taskId} depends on: ${taskDeps.join(', ')}`);
407
+ }
408
+ }
409
+ break;
410
+ }
411
+
412
+ default:
413
+ console.log(`
414
+ Wogi Flow - Parallel Execution
415
+
416
+ Usage:
417
+ node flow-parallel.js <command>
418
+
419
+ Commands:
420
+ config Show parallel execution configuration
421
+ check Analyze tasks for parallel execution potential
422
+
423
+ Examples:
424
+ node flow-parallel.js config
425
+ node flow-parallel.js check
426
+ `);
427
+ }
428
+ }