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,308 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Wogi Flow - Task Queue Management
5
+ *
6
+ * CLI for managing multi-task queues.
7
+ * v2.1: Supports natural language parsing and automatic queue continuation.
8
+ *
9
+ * Commands:
10
+ * flow queue init <task-ids...> - Initialize queue with task IDs
11
+ * flow queue status - Show current queue status
12
+ * flow queue clear - Clear the queue
13
+ * flow queue parse "<text>" - Parse natural language for task IDs
14
+ * flow queue advance - Manually advance to next task
15
+ */
16
+
17
+ const fs = require('fs');
18
+ const path = require('path');
19
+ const {
20
+ PATHS,
21
+ fileExists,
22
+ color,
23
+ error,
24
+ getConfig
25
+ } = require('./flow-utils');
26
+
27
+ const {
28
+ initTaskQueue,
29
+ getQueueStatus,
30
+ advanceTaskQueue,
31
+ clearTaskQueue
32
+ } = require('./flow-durable-session');
33
+
34
+ /**
35
+ * Parse natural language input for task IDs
36
+ * Examples:
37
+ * "do story 1-3" → ["wf-001", "wf-002", "wf-003"]
38
+ * "wf-001, wf-002, wf-003" → ["wf-001", "wf-002", "wf-003"]
39
+ * "tasks 1, 2, 3" → gets from ready.json
40
+ */
41
+ function parseNaturalLanguage(input) {
42
+ const taskIds = [];
43
+
44
+ // Try to extract wf-* task IDs directly
45
+ const wfMatches = input.match(/wf-[a-f0-9]{8}(?:-\d{2})?/gi);
46
+ if (wfMatches && wfMatches.length > 0) {
47
+ return wfMatches.map(id => id.toLowerCase());
48
+ }
49
+
50
+ // Try range patterns like "1-3", "story 1-5"
51
+ const rangeMatch = input.match(/(\d+)\s*[-–]\s*(\d+)/);
52
+ if (rangeMatch) {
53
+ const start = parseInt(rangeMatch[1], 10);
54
+ const end = parseInt(rangeMatch[2], 10);
55
+ const count = Math.min(end - start + 1, 10); // Max 10 tasks
56
+
57
+ // Get tasks from ready.json
58
+ return getTasksFromReady(count);
59
+ }
60
+
61
+ // Try patterns like "3 tasks", "these 5 stories"
62
+ const countMatch = input.match(/(\d+)\s*(?:tasks?|stories?|features?)/i);
63
+ if (countMatch) {
64
+ const count = Math.min(parseInt(countMatch[1], 10), 10);
65
+ return getTasksFromReady(count);
66
+ }
67
+
68
+ // Try comma-separated numbers
69
+ const numbersMatch = input.match(/\d+(?:\s*,\s*\d+)+/);
70
+ if (numbersMatch) {
71
+ const numbers = numbersMatch[0].split(/\s*,\s*/).map(n => parseInt(n, 10));
72
+ return getTasksFromReady(numbers.length);
73
+ }
74
+
75
+ // "all ready tasks"
76
+ if (/all\s+(?:ready\s+)?tasks?/i.test(input)) {
77
+ return getTasksFromReady(10); // Max 10
78
+ }
79
+
80
+ return taskIds;
81
+ }
82
+
83
+ /**
84
+ * Get N tasks from ready.json sorted by priority
85
+ */
86
+ function getTasksFromReady(count) {
87
+ const readyPath = path.join(PATHS.state, 'ready.json');
88
+
89
+ if (!fileExists(readyPath)) {
90
+ return [];
91
+ }
92
+
93
+ try {
94
+ const data = JSON.parse(fs.readFileSync(readyPath, 'utf-8'));
95
+ const ready = data.ready || [];
96
+
97
+ // Sort by priority (P0 first)
98
+ const sorted = ready.sort((a, b) => {
99
+ const priorityA = a.priority || 'P2';
100
+ const priorityB = b.priority || 'P2';
101
+ return priorityA.localeCompare(priorityB);
102
+ });
103
+
104
+ // Return requested count
105
+ return sorted.slice(0, count).map(t => t.id);
106
+ } catch (err) {
107
+ console.error(error(`Failed to read ready.json: ${err.message}`));
108
+ return [];
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Show queue status
114
+ */
115
+ function showStatus() {
116
+ const status = getQueueStatus();
117
+
118
+ console.log('');
119
+ console.log(color('cyan', '📋 Task Queue Status'));
120
+ console.log(color('cyan', '─'.repeat(50)));
121
+
122
+ if (!status.enabled || status.tasks.length === 0) {
123
+ console.log(color('dim', 'No active queue.'));
124
+ console.log('');
125
+ console.log('Initialize a queue with:');
126
+ console.log(' flow queue init wf-001 wf-002 wf-003');
127
+ console.log(' flow queue parse "do story 1-3"');
128
+ return;
129
+ }
130
+
131
+ console.log(`Source: ${status.source || 'manual'}`);
132
+ console.log(`Queued at: ${status.queuedAt || 'N/A'}`);
133
+ console.log('');
134
+
135
+ console.log(color('white', `Tasks (${status.currentIndex + 1}/${status.tasks.length}):`));
136
+
137
+ status.tasks.forEach((taskId, i) => {
138
+ const isCompleted = status.completedTasks.includes(taskId);
139
+ const isCurrent = i === status.currentIndex;
140
+
141
+ let prefix = ' ';
142
+ let taskColor = 'dim';
143
+ let statusIcon = '○';
144
+
145
+ if (isCompleted) {
146
+ statusIcon = '✓';
147
+ taskColor = 'green';
148
+ } else if (isCurrent) {
149
+ statusIcon = '→';
150
+ taskColor = 'yellow';
151
+ prefix = '';
152
+ }
153
+
154
+ console.log(color(taskColor, `${prefix}${statusIcon} ${taskId}`));
155
+ });
156
+
157
+ console.log('');
158
+ console.log(color('dim', `Completed: ${status.completedTasks.length}/${status.tasks.length}`));
159
+ }
160
+
161
+ /**
162
+ * Initialize queue
163
+ */
164
+ function initQueue(taskIds, source = 'cli') {
165
+ if (taskIds.length === 0) {
166
+ console.log(error('No task IDs provided.'));
167
+ console.log('');
168
+ console.log('Usage:');
169
+ console.log(' flow queue init wf-001 wf-002 wf-003');
170
+ console.log(' flow queue init $(flow queue parse "do story 1-3")');
171
+ process.exit(1);
172
+ }
173
+
174
+ const config = getConfig();
175
+ const maxQueueSize = config.taskQueue?.maxQueueSize || 10;
176
+
177
+ if (taskIds.length > maxQueueSize) {
178
+ console.log(color('yellow', `Warning: Queue size limited to ${maxQueueSize} tasks.`));
179
+ taskIds = taskIds.slice(0, maxQueueSize);
180
+ }
181
+
182
+ initTaskQueue(taskIds, source);
183
+
184
+ console.log('');
185
+ console.log(color('green', '✓ Task queue initialized'));
186
+ console.log('');
187
+ console.log(`Tasks queued: ${taskIds.length}`);
188
+ taskIds.forEach((id, i) => {
189
+ console.log(color('dim', ` ${i + 1}. ${id}`));
190
+ });
191
+ console.log('');
192
+ console.log('Start the first task with:');
193
+ console.log(color('cyan', ` /wogi-start ${taskIds[0]}`));
194
+ }
195
+
196
+ /**
197
+ * Parse command and output task IDs
198
+ */
199
+ function parseCommand(input) {
200
+ const taskIds = parseNaturalLanguage(input);
201
+
202
+ if (taskIds.length === 0) {
203
+ console.log(error('Could not parse task IDs from input.'));
204
+ console.log('');
205
+ console.log('Supported formats:');
206
+ console.log(' "wf-001, wf-002, wf-003" - Direct task IDs');
207
+ console.log(' "story 1-3" or "tasks 1-5" - Range from ready queue');
208
+ console.log(' "3 tasks" or "these 5 stories" - Count from ready queue');
209
+ console.log(' "all ready tasks" - All from ready queue (max 10)');
210
+ process.exit(1);
211
+ }
212
+
213
+ // Output task IDs for use in other commands
214
+ console.log(taskIds.join(' '));
215
+ }
216
+
217
+ /**
218
+ * Clear the queue
219
+ */
220
+ function clearQueue() {
221
+ clearTaskQueue();
222
+ console.log(color('green', '✓ Task queue cleared'));
223
+ }
224
+
225
+ /**
226
+ * Advance to next task
227
+ */
228
+ function advance() {
229
+ const status = getQueueStatus();
230
+
231
+ if (!status.enabled || status.tasks.length === 0) {
232
+ console.log(error('No active queue.'));
233
+ process.exit(1);
234
+ }
235
+
236
+ if (status.currentIndex >= status.tasks.length - 1) {
237
+ console.log(color('yellow', 'Already at the last task in queue.'));
238
+ process.exit(0);
239
+ }
240
+
241
+ advanceTaskQueue();
242
+
243
+ const newStatus = getQueueStatus();
244
+ const nextTask = newStatus.tasks[newStatus.currentIndex];
245
+
246
+ console.log(color('green', '✓ Advanced to next task'));
247
+ console.log(`Next task: ${nextTask}`);
248
+ console.log('');
249
+ console.log('Start with:');
250
+ console.log(color('cyan', ` /wogi-start ${nextTask}`));
251
+ }
252
+
253
+ // Main
254
+ function main() {
255
+ const command = process.argv[2];
256
+ const args = process.argv.slice(3);
257
+
258
+ switch (command) {
259
+ case 'init':
260
+ initQueue(args, 'cli');
261
+ break;
262
+
263
+ case 'status':
264
+ showStatus();
265
+ break;
266
+
267
+ case 'clear':
268
+ clearQueue();
269
+ break;
270
+
271
+ case 'parse':
272
+ if (args.length === 0) {
273
+ console.log(error('Missing input string.'));
274
+ console.log('Usage: flow queue parse "do story 1-3"');
275
+ process.exit(1);
276
+ }
277
+ parseCommand(args.join(' '));
278
+ break;
279
+
280
+ case 'advance':
281
+ advance();
282
+ break;
283
+
284
+ default:
285
+ console.log('Wogi Flow - Task Queue Management');
286
+ console.log('');
287
+ console.log('Commands:');
288
+ console.log(' flow queue init <task-ids...> - Initialize queue with task IDs');
289
+ console.log(' flow queue status - Show current queue status');
290
+ console.log(' flow queue clear - Clear the queue');
291
+ console.log(' flow queue parse "<text>" - Parse natural language for task IDs');
292
+ console.log(' flow queue advance - Manually advance to next task');
293
+ console.log('');
294
+ console.log('Examples:');
295
+ console.log(' flow queue init wf-001 wf-002 wf-003');
296
+ console.log(' flow queue init $(flow queue parse "do story 1-3")');
297
+ console.log(' flow queue parse "work on tasks 1-5"');
298
+ console.log(' flow queue status');
299
+ break;
300
+ }
301
+ }
302
+
303
+ main();
304
+
305
+ module.exports = {
306
+ parseNaturalLanguage,
307
+ getTasksFromReady
308
+ };
@@ -0,0 +1,82 @@
1
+ #!/bin/bash
2
+
3
+ # Wogi Flow - Show Ready Tasks
4
+
5
+ set -e
6
+
7
+ WORKFLOW_DIR=".workflow"
8
+ READY_JSON="$WORKFLOW_DIR/state/ready.json"
9
+
10
+ # Colors
11
+ GREEN='\033[0;32m'
12
+ YELLOW='\033[1;33m'
13
+ CYAN='\033[0;36m'
14
+ RED='\033[0;31m'
15
+ NC='\033[0m'
16
+
17
+ if [ ! -f "$READY_JSON" ]; then
18
+ echo -e "${RED}Error: No ready.json found${NC}"
19
+ echo "Run: ./scripts/flow init"
20
+ exit 1
21
+ fi
22
+
23
+ echo -e "${CYAN}Task Queue${NC}"
24
+ echo "==========="
25
+ echo ""
26
+
27
+ READY_FILE="$READY_JSON" python3 << 'EOF'
28
+ import json, os
29
+
30
+ with open(os.environ['READY_FILE']) as f:
31
+ data = json.load(f)
32
+
33
+ # Ready tasks
34
+ ready = data.get('ready', [])
35
+ if ready:
36
+ print('\033[0;32m✓ READY\033[0m')
37
+ for task in ready:
38
+ if isinstance(task, dict):
39
+ priority = task.get('priority', '-')
40
+ print(f" [{priority}] {task.get('id', '?')}: {task.get('title', 'No title')}")
41
+ else:
42
+ print(f" • {task}")
43
+ print()
44
+
45
+ # In progress
46
+ in_progress = data.get('inProgress', [])
47
+ if in_progress:
48
+ print('\033[1;33m⏳ IN PROGRESS\033[0m')
49
+ for task in in_progress:
50
+ if isinstance(task, dict):
51
+ print(f" • {task.get('id', '?')}: {task.get('title', 'No title')}")
52
+ else:
53
+ print(f" • {task}")
54
+ print()
55
+
56
+ # Blocked
57
+ blocked = data.get('blocked', [])
58
+ if blocked:
59
+ print('\033[0;31m🚫 BLOCKED\033[0m')
60
+ for task in blocked:
61
+ if isinstance(task, dict):
62
+ reason = task.get('reason', 'Unknown')
63
+ print(f" • {task.get('id', '?')}: {reason}")
64
+ else:
65
+ print(f" • {task}")
66
+ print()
67
+
68
+ # Recently completed
69
+ completed = data.get('recentlyCompleted', [])
70
+ if completed:
71
+ print('\033[0;36m✅ RECENTLY COMPLETED\033[0m')
72
+ for task in completed[:5]: # Last 5
73
+ if isinstance(task, dict):
74
+ print(f" • {task.get('id', '?')}: {task.get('title', 'No title')}")
75
+ else:
76
+ print(f" • {task}")
77
+ print()
78
+
79
+ # Summary
80
+ total = len(ready) + len(in_progress) + len(blocked)
81
+ print(f"Total active: {total} ({len(ready)} ready, {len(in_progress)} in progress, {len(blocked)} blocked)")
82
+ EOF
@@ -0,0 +1,189 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Wogi Flow - Show Ready Tasks
5
+ *
6
+ * Displays tasks organized by status from ready.json
7
+ *
8
+ * Usage:
9
+ * flow ready Show tasks (human-readable)
10
+ * flow ready --json Output JSON for programmatic access
11
+ */
12
+
13
+ const {
14
+ PATHS,
15
+ fileExists,
16
+ getReadyData,
17
+ parseFlags,
18
+ outputJson,
19
+ color,
20
+ printSection,
21
+ error,
22
+ warn
23
+ } = require('./flow-utils');
24
+
25
+ /**
26
+ * Priority order for sorting (P0 highest, P4 lowest)
27
+ */
28
+ const PRIORITY_ORDER = { P0: 0, P1: 1, P2: 2, P3: 3, P4: 4 };
29
+
30
+ /**
31
+ * Sort tasks by priority, then by date
32
+ */
33
+ function sortByPriority(tasks) {
34
+ return [...tasks].sort((a, b) => {
35
+ // Handle both string and object tasks
36
+ const aPriority = typeof a === 'object' ? (a.priority || 'P2') : 'P2';
37
+ const bPriority = typeof b === 'object' ? (b.priority || 'P2') : 'P2';
38
+
39
+ const aOrder = PRIORITY_ORDER[aPriority] ?? 2;
40
+ const bOrder = PRIORITY_ORDER[bPriority] ?? 2;
41
+
42
+ if (aOrder !== bOrder) {
43
+ return aOrder - bOrder;
44
+ }
45
+
46
+ // Secondary sort by date (newer first) - ISO dates can be compared directly
47
+ const aDate = typeof a === 'object' ? (a.createdAt || '') : '';
48
+ const bDate = typeof b === 'object' ? (b.createdAt || '') : '';
49
+ // Direct comparison works for ISO 8601 dates (YYYY-MM-DD...)
50
+ if (bDate > aDate) return 1;
51
+ if (bDate < aDate) return -1;
52
+ return 0;
53
+ });
54
+ }
55
+
56
+ /**
57
+ * Format task for display
58
+ */
59
+ function formatTask(task) {
60
+ if (typeof task === 'object') {
61
+ const priority = task.priority || 'P2';
62
+ const id = task.id || '?';
63
+ const title = task.title || 'No title';
64
+ return { priority, id, title, raw: task };
65
+ }
66
+ return { priority: '-', id: task, title: '', raw: task };
67
+ }
68
+
69
+ function main() {
70
+ const { flags } = parseFlags(process.argv.slice(2));
71
+
72
+ if (!fileExists(PATHS.ready)) {
73
+ if (flags.json) {
74
+ outputJson({
75
+ success: false,
76
+ error: 'No ready.json found',
77
+ tasks: { ready: [], inProgress: [], blocked: [], recentlyCompleted: [] },
78
+ summary: { total: 0, ready: 0, inProgress: 0, blocked: 0 }
79
+ });
80
+ }
81
+ error('No ready.json found');
82
+ console.log('Run: ./scripts/flow init');
83
+ process.exit(1);
84
+ }
85
+
86
+ const data = getReadyData();
87
+
88
+ // Validate data structure and warn if corrupted
89
+ if (!data || typeof data !== 'object') {
90
+ warn('ready.json appears corrupted (not an object)');
91
+ } else {
92
+ // Check for expected arrays
93
+ const expectedArrays = ['ready', 'inProgress', 'blocked', 'recentlyCompleted'];
94
+ for (const key of expectedArrays) {
95
+ if (data[key] !== undefined && !Array.isArray(data[key])) {
96
+ warn(`ready.json: "${key}" should be an array but found ${typeof data[key]}`);
97
+ }
98
+ }
99
+ }
100
+
101
+ // Sort ready tasks by priority
102
+ const ready = sortByPriority(data.ready || []);
103
+ const inProgress = data.inProgress || [];
104
+ const blocked = data.blocked || [];
105
+ const completed = data.recentlyCompleted || [];
106
+
107
+ // Calculate summary
108
+ const summary = {
109
+ total: ready.length + inProgress.length + blocked.length,
110
+ ready: ready.length,
111
+ inProgress: inProgress.length,
112
+ blocked: blocked.length,
113
+ recentlyCompleted: completed.length
114
+ };
115
+
116
+ // JSON output - exit after to avoid human-readable output
117
+ if (flags.json) {
118
+ outputJson({
119
+ success: true,
120
+ tasks: {
121
+ ready,
122
+ inProgress,
123
+ blocked,
124
+ recentlyCompleted: completed
125
+ },
126
+ summary
127
+ });
128
+ return; // Exit early for JSON mode
129
+ }
130
+
131
+ // Human-readable output
132
+ printSection('Task Queue');
133
+ console.log('===========');
134
+ console.log('');
135
+
136
+ // Ready tasks (sorted by priority)
137
+ if (ready.length > 0) {
138
+ console.log(color('green', '✓ READY'));
139
+ for (const task of ready) {
140
+ const { priority, id, title } = formatTask(task);
141
+ const priorityColor = priority === 'P0' ? 'red' : priority === 'P1' ? 'yellow' : 'dim';
142
+ console.log(` ${color(priorityColor, `[${priority}]`)} ${id}: ${title}`);
143
+ }
144
+ console.log('');
145
+ }
146
+
147
+ // In progress
148
+ if (inProgress.length > 0) {
149
+ console.log(color('yellow', '⏳ IN PROGRESS'));
150
+ for (const task of inProgress) {
151
+ const { id, title } = formatTask(task);
152
+ console.log(` • ${id}: ${title}`);
153
+ }
154
+ console.log('');
155
+ }
156
+
157
+ // Blocked
158
+ if (blocked.length > 0) {
159
+ console.log(color('red', '🚫 BLOCKED'));
160
+ for (const task of blocked) {
161
+ if (typeof task === 'object') {
162
+ const reason = task.reason || task.blockedBy || 'Unknown';
163
+ console.log(` • ${task.id || '?'}: ${reason}`);
164
+ } else {
165
+ console.log(` • ${task}`);
166
+ }
167
+ }
168
+ console.log('');
169
+ }
170
+
171
+ // Recently completed
172
+ if (completed.length > 0) {
173
+ console.log(color('cyan', '✅ RECENTLY COMPLETED'));
174
+ for (const task of completed.slice(0, 5)) {
175
+ const { id, title } = formatTask(task);
176
+ console.log(` • ${id}: ${title}`);
177
+ }
178
+ console.log('');
179
+ }
180
+
181
+ // Summary
182
+ console.log(`Total active: ${summary.total} (${summary.ready} ready, ${summary.inProgress} in progress, ${summary.blocked} blocked)`);
183
+ }
184
+
185
+ if (require.main === module) {
186
+ main();
187
+ }
188
+
189
+ module.exports = { main, sortByPriority, PRIORITY_ORDER };