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,728 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Wogi Flow - Tiered Learning System
5
+ *
6
+ * Classifies learned patterns by confidence tiers and determines
7
+ * appropriate actions (auto-apply, apply with log, queue for review).
8
+ *
9
+ * Part of Phase 3: Intelligent Routing
10
+ *
11
+ * Usage:
12
+ * flow learning tiers Show patterns by tier
13
+ * flow learning stats Show learning statistics
14
+ * flow learning apply <pattern> Manually apply a pattern
15
+ * flow learning classify <pattern> Check tier for a pattern
16
+ */
17
+
18
+ const fs = require('fs');
19
+ const path = require('path');
20
+ const {
21
+ PROJECT_ROOT,
22
+ parseFlags,
23
+ outputJson,
24
+ color,
25
+ info,
26
+ warn,
27
+ error,
28
+ getConfig,
29
+ fileExists,
30
+ safeJsonParse,
31
+ printHeader,
32
+ printSection
33
+ } = require('./flow-utils');
34
+
35
+ // ============================================================
36
+ // Constants
37
+ // ============================================================
38
+
39
+ /**
40
+ * Learning tier definitions.
41
+ * Patterns are classified based on success rate and sample count.
42
+ */
43
+ const LEARNING_TIERS = {
44
+ AUTO_APPLY: {
45
+ name: 'Auto Apply',
46
+ description: 'High confidence - applied automatically',
47
+ minSuccessRate: 0.9,
48
+ minSamples: 5,
49
+ action: 'apply-silently',
50
+ color: 'green'
51
+ },
52
+ APPLY_WITH_LOG: {
53
+ name: 'Apply with Log',
54
+ description: 'Medium confidence - applied and logged',
55
+ minSuccessRate: 0.7,
56
+ minSamples: 3,
57
+ action: 'apply-and-log',
58
+ color: 'yellow'
59
+ },
60
+ QUEUE_FOR_REVIEW: {
61
+ name: 'Queue for Review',
62
+ description: 'Low confidence - requires human review',
63
+ minSuccessRate: 0,
64
+ minSamples: 0,
65
+ action: 'queue',
66
+ color: 'cyan'
67
+ }
68
+ };
69
+
70
+ /**
71
+ * Configuration constants for pattern tracking.
72
+ */
73
+ const MAX_PATTERN_HISTORY = 20;
74
+ const MAX_CONTEXT_LENGTH = 100;
75
+
76
+ /**
77
+ * Default tiered learning configuration.
78
+ * Can be overridden in .workflow/config.json under "tieredLearning" key.
79
+ */
80
+ const DEFAULT_TIERED_LEARNING_CONFIG = {
81
+ enabled: true,
82
+ tiers: {
83
+ autoApply: { minSuccessRate: 0.9, minSamples: 5 },
84
+ applyWithLog: { minSuccessRate: 0.7, minSamples: 3 }
85
+ },
86
+ logAppliedPatterns: true,
87
+ maxQueueSize: 50
88
+ };
89
+
90
+ // ============================================================
91
+ // Paths
92
+ // ============================================================
93
+
94
+ const PATTERNS_PATH = path.join(PROJECT_ROOT, '.workflow', 'state', 'learning-patterns.json');
95
+ const DECISIONS_PATH = path.join(PROJECT_ROOT, '.workflow', 'state', 'decisions.md');
96
+ const FEEDBACK_PATH = path.join(PROJECT_ROOT, '.workflow', 'state', 'feedback-patterns.md');
97
+
98
+ // ============================================================
99
+ // Configuration
100
+ // ============================================================
101
+
102
+ /**
103
+ * Get tiered learning configuration from config.json with defaults.
104
+ * @returns {Object} Tiered learning configuration
105
+ */
106
+ function getTieredLearningConfig() {
107
+ const config = getConfig();
108
+ const userConfig = config?.tieredLearning || {};
109
+
110
+ return {
111
+ ...DEFAULT_TIERED_LEARNING_CONFIG,
112
+ ...userConfig,
113
+ tiers: {
114
+ ...DEFAULT_TIERED_LEARNING_CONFIG.tiers,
115
+ ...(userConfig.tiers || {})
116
+ }
117
+ };
118
+ }
119
+
120
+ // ============================================================
121
+ // Pattern Storage
122
+ // ============================================================
123
+
124
+ /**
125
+ * Load learning patterns from storage.
126
+ * @returns {Object} Pattern data
127
+ */
128
+ function loadPatterns() {
129
+ const defaultPatterns = {
130
+ version: '1.0.0',
131
+ lastUpdated: new Date().toISOString(),
132
+ patterns: {},
133
+ applied: [],
134
+ queued: []
135
+ };
136
+
137
+ if (!fileExists(PATTERNS_PATH)) {
138
+ return defaultPatterns;
139
+ }
140
+
141
+ const loaded = safeJsonParse(PATTERNS_PATH);
142
+ return loaded || defaultPatterns;
143
+ }
144
+
145
+ /**
146
+ * Save learning patterns to storage.
147
+ * @param {Object} patterns - Pattern data to save
148
+ */
149
+ function savePatterns(patterns) {
150
+ patterns.lastUpdated = new Date().toISOString();
151
+
152
+ const dir = path.dirname(PATTERNS_PATH);
153
+ if (!fs.existsSync(dir)) {
154
+ fs.mkdirSync(dir, { recursive: true });
155
+ }
156
+
157
+ fs.writeFileSync(PATTERNS_PATH, JSON.stringify(patterns, null, 2));
158
+ }
159
+
160
+ // ============================================================
161
+ // Tier Classification
162
+ // ============================================================
163
+
164
+ /**
165
+ * Classify a pattern into a learning tier.
166
+ * @param {Object} stats - Pattern statistics
167
+ * @param {number} stats.successCount - Number of successful applications
168
+ * @param {number} stats.failCount - Number of failed applications
169
+ * @param {number} [stats.sampleCount] - Total samples (defaults to success + fail)
170
+ * @returns {Object} Tier classification result
171
+ */
172
+ function classifyPattern(stats) {
173
+ const config = getTieredLearningConfig();
174
+ const { tiers } = config;
175
+
176
+ const sampleCount = stats.sampleCount || (stats.successCount + stats.failCount);
177
+ const successRate = sampleCount > 0 ? stats.successCount / sampleCount : 0;
178
+
179
+ // Check AUTO_APPLY tier
180
+ if (successRate >= tiers.autoApply.minSuccessRate &&
181
+ sampleCount >= tiers.autoApply.minSamples) {
182
+ return {
183
+ tier: 'AUTO_APPLY',
184
+ ...LEARNING_TIERS.AUTO_APPLY,
185
+ successRate,
186
+ sampleCount,
187
+ meetsThreshold: true
188
+ };
189
+ }
190
+
191
+ // Check APPLY_WITH_LOG tier
192
+ if (successRate >= tiers.applyWithLog.minSuccessRate &&
193
+ sampleCount >= tiers.applyWithLog.minSamples) {
194
+ return {
195
+ tier: 'APPLY_WITH_LOG',
196
+ ...LEARNING_TIERS.APPLY_WITH_LOG,
197
+ successRate,
198
+ sampleCount,
199
+ meetsThreshold: true
200
+ };
201
+ }
202
+
203
+ // Default to QUEUE_FOR_REVIEW
204
+ return {
205
+ tier: 'QUEUE_FOR_REVIEW',
206
+ ...LEARNING_TIERS.QUEUE_FOR_REVIEW,
207
+ successRate,
208
+ sampleCount,
209
+ meetsThreshold: true
210
+ };
211
+ }
212
+
213
+ /**
214
+ * Get the action to take for a pattern based on its tier.
215
+ * @param {string} patternId - Pattern identifier
216
+ * @returns {Object} Action recommendation
217
+ */
218
+ function getPatternAction(patternId) {
219
+ const patterns = loadPatterns();
220
+ const pattern = patterns.patterns[patternId];
221
+
222
+ if (!pattern) {
223
+ return {
224
+ patternId,
225
+ exists: false,
226
+ action: 'none',
227
+ reason: 'Pattern not found'
228
+ };
229
+ }
230
+
231
+ const classification = classifyPattern(pattern.stats);
232
+
233
+ return {
234
+ patternId,
235
+ exists: true,
236
+ ...classification,
237
+ recommendation: classification.action
238
+ };
239
+ }
240
+
241
+ // ============================================================
242
+ // Pattern Management
243
+ // ============================================================
244
+
245
+ /**
246
+ * Record a pattern application result.
247
+ * @param {Object} params - Application parameters
248
+ * @param {string} params.patternId - Pattern identifier
249
+ * @param {boolean} params.success - Whether application was successful
250
+ * @param {string} [params.context] - Additional context
251
+ * @returns {Object} Updated pattern info
252
+ */
253
+ function recordPatternResult(params) {
254
+ const { patternId, success, context = '' } = params;
255
+ const patterns = loadPatterns();
256
+
257
+ // Initialize pattern if needed
258
+ if (!patterns.patterns[patternId]) {
259
+ patterns.patterns[patternId] = {
260
+ id: patternId,
261
+ createdAt: new Date().toISOString(),
262
+ stats: {
263
+ successCount: 0,
264
+ failCount: 0
265
+ },
266
+ history: []
267
+ };
268
+ }
269
+
270
+ const pattern = patterns.patterns[patternId];
271
+
272
+ // Update stats
273
+ if (success) {
274
+ pattern.stats.successCount++;
275
+ } else {
276
+ pattern.stats.failCount++;
277
+ }
278
+
279
+ // Add to history
280
+ pattern.history.push({
281
+ timestamp: new Date().toISOString(),
282
+ success,
283
+ context: context.slice(0, MAX_CONTEXT_LENGTH)
284
+ });
285
+
286
+ // Keep only most recent history entries
287
+ if (pattern.history.length > MAX_PATTERN_HISTORY) {
288
+ pattern.history = pattern.history.slice(-MAX_PATTERN_HISTORY);
289
+ }
290
+
291
+ pattern.lastUpdated = new Date().toISOString();
292
+
293
+ // Re-classify after update
294
+ const classification = classifyPattern(pattern.stats);
295
+ pattern.currentTier = classification.tier;
296
+
297
+ savePatterns(patterns);
298
+
299
+ return {
300
+ patternId,
301
+ stats: pattern.stats,
302
+ classification
303
+ };
304
+ }
305
+
306
+ /**
307
+ * Queue a pattern for review.
308
+ * @param {Object} params - Queue parameters
309
+ * @param {string} params.patternId - Pattern identifier
310
+ * @param {string} params.description - Pattern description
311
+ * @param {string} params.source - Where the pattern was detected
312
+ * @returns {Object} Queue result
313
+ */
314
+ function queueForReview(params) {
315
+ const { patternId, description, source } = params;
316
+ const config = getTieredLearningConfig();
317
+ const patterns = loadPatterns();
318
+
319
+ // Check if already queued
320
+ const existing = patterns.queued.find(q => q.patternId === patternId);
321
+ if (existing) {
322
+ existing.occurrences = (existing.occurrences || 1) + 1;
323
+ existing.lastSeen = new Date().toISOString();
324
+ savePatterns(patterns);
325
+ return { queued: false, reason: 'already queued', updated: true };
326
+ }
327
+
328
+ // Add to queue
329
+ patterns.queued.push({
330
+ patternId,
331
+ description,
332
+ source,
333
+ queuedAt: new Date().toISOString(),
334
+ occurrences: 1
335
+ });
336
+
337
+ // Enforce max queue size
338
+ if (patterns.queued.length > config.maxQueueSize) {
339
+ patterns.queued = patterns.queued.slice(-config.maxQueueSize);
340
+ }
341
+
342
+ savePatterns(patterns);
343
+
344
+ return { queued: true, patternId };
345
+ }
346
+
347
+ /**
348
+ * Apply a pattern (move from queue to applied).
349
+ * @param {string} patternId - Pattern to apply
350
+ * @returns {Object} Application result
351
+ */
352
+ function applyPattern(patternId) {
353
+ const patterns = loadPatterns();
354
+ const config = getTieredLearningConfig();
355
+
356
+ // Find in queue
357
+ const queueIndex = patterns.queued.findIndex(q => q.patternId === patternId);
358
+ let patternData = null;
359
+
360
+ if (queueIndex >= 0) {
361
+ patternData = patterns.queued.splice(queueIndex, 1)[0];
362
+ }
363
+
364
+ // Add to applied list
365
+ patterns.applied.push({
366
+ patternId,
367
+ appliedAt: new Date().toISOString(),
368
+ source: patternData?.source || 'manual',
369
+ description: patternData?.description || ''
370
+ });
371
+
372
+ // Initialize stats if not exists
373
+ if (!patterns.patterns[patternId]) {
374
+ patterns.patterns[patternId] = {
375
+ id: patternId,
376
+ createdAt: new Date().toISOString(),
377
+ stats: { successCount: 0, failCount: 0 },
378
+ history: [],
379
+ currentTier: 'QUEUE_FOR_REVIEW'
380
+ };
381
+ }
382
+
383
+ savePatterns(patterns);
384
+
385
+ // Log if configured
386
+ if (config.logAppliedPatterns) {
387
+ info(`Applied pattern: ${patternId}`);
388
+ }
389
+
390
+ return {
391
+ applied: true,
392
+ patternId,
393
+ wasQueued: queueIndex >= 0
394
+ };
395
+ }
396
+
397
+ /**
398
+ * Get patterns organized by tier.
399
+ * @returns {Object} Patterns grouped by tier
400
+ */
401
+ function getPatternsByTier() {
402
+ const patterns = loadPatterns();
403
+ const byTier = {
404
+ AUTO_APPLY: [],
405
+ APPLY_WITH_LOG: [],
406
+ QUEUE_FOR_REVIEW: []
407
+ };
408
+
409
+ for (const [id, pattern] of Object.entries(patterns.patterns)) {
410
+ const classification = classifyPattern(pattern.stats);
411
+ byTier[classification.tier].push({
412
+ id,
413
+ ...pattern,
414
+ classification
415
+ });
416
+ }
417
+
418
+ // Add queued patterns to QUEUE_FOR_REVIEW
419
+ for (const queued of patterns.queued) {
420
+ if (!byTier.QUEUE_FOR_REVIEW.find(p => p.id === queued.patternId)) {
421
+ byTier.QUEUE_FOR_REVIEW.push({
422
+ id: queued.patternId,
423
+ ...queued,
424
+ isQueued: true,
425
+ classification: {
426
+ tier: 'QUEUE_FOR_REVIEW',
427
+ ...LEARNING_TIERS.QUEUE_FOR_REVIEW
428
+ }
429
+ });
430
+ }
431
+ }
432
+
433
+ return byTier;
434
+ }
435
+
436
+ /**
437
+ * Get learning statistics summary.
438
+ * @returns {Object} Statistics summary
439
+ */
440
+ function getLearningStats() {
441
+ const patterns = loadPatterns();
442
+ const byTier = getPatternsByTier();
443
+
444
+ const totalPatterns = Object.keys(patterns.patterns).length;
445
+ const totalApplications = Object.values(patterns.patterns)
446
+ .reduce((sum, p) => sum + p.stats.successCount + p.stats.failCount, 0);
447
+
448
+ const totalSuccess = Object.values(patterns.patterns)
449
+ .reduce((sum, p) => sum + p.stats.successCount, 0);
450
+
451
+ return {
452
+ totalPatterns,
453
+ totalApplications,
454
+ overallSuccessRate: totalApplications > 0 ? totalSuccess / totalApplications : 0,
455
+ byTier: {
456
+ AUTO_APPLY: byTier.AUTO_APPLY.length,
457
+ APPLY_WITH_LOG: byTier.APPLY_WITH_LOG.length,
458
+ QUEUE_FOR_REVIEW: byTier.QUEUE_FOR_REVIEW.length
459
+ },
460
+ queued: patterns.queued.length,
461
+ applied: patterns.applied.length,
462
+ lastUpdated: patterns.lastUpdated
463
+ };
464
+ }
465
+
466
+ // ============================================================
467
+ // CLI Output
468
+ // ============================================================
469
+
470
+ /**
471
+ * Print patterns by tier.
472
+ */
473
+ function printTiers() {
474
+ const byTier = getPatternsByTier();
475
+ const config = getTieredLearningConfig();
476
+
477
+ printHeader('LEARNING TIERS');
478
+
479
+ printSection('Configuration');
480
+ console.log(` ${color('dim', 'Enabled:')} ${config.enabled ? color('green', 'Yes') : color('red', 'No')}`);
481
+ console.log(` ${color('dim', 'Auto-apply threshold:')} ${(config.tiers.autoApply.minSuccessRate * 100).toFixed(0)}% success, ${config.tiers.autoApply.minSamples}+ samples`);
482
+ console.log(` ${color('dim', 'Apply-with-log threshold:')} ${(config.tiers.applyWithLog.minSuccessRate * 100).toFixed(0)}% success, ${config.tiers.applyWithLog.minSamples}+ samples`);
483
+
484
+ for (const [tierName, tierInfo] of Object.entries(LEARNING_TIERS)) {
485
+ const patterns = byTier[tierName];
486
+ const tierColor = tierInfo.color;
487
+
488
+ printSection(`${tierInfo.name} (${patterns.length})`);
489
+ console.log(` ${color('dim', tierInfo.description)}`);
490
+
491
+ if (patterns.length === 0) {
492
+ console.log(` ${color('dim', 'No patterns in this tier')}`);
493
+ } else {
494
+ for (const pattern of patterns.slice(0, 10)) {
495
+ const rate = pattern.classification?.successRate || 0;
496
+ const samples = pattern.stats?.successCount + pattern.stats?.failCount || 0;
497
+ const rateStr = samples > 0 ? `${(rate * 100).toFixed(0)}%` : 'N/A';
498
+
499
+ console.log(` ${color(tierColor, '-')} ${pattern.id}`);
500
+ console.log(` ${color('dim', `Success: ${rateStr} | Samples: ${samples}`)}`);
501
+ }
502
+
503
+ if (patterns.length > 10) {
504
+ console.log(` ${color('dim', `... and ${patterns.length - 10} more`)}`);
505
+ }
506
+ }
507
+ }
508
+
509
+ console.log('');
510
+ }
511
+
512
+ /**
513
+ * Print learning statistics.
514
+ */
515
+ function printStats() {
516
+ const stats = getLearningStats();
517
+
518
+ printHeader('LEARNING STATISTICS');
519
+
520
+ printSection('Overview');
521
+ console.log(` ${color('dim', 'Total patterns:')} ${stats.totalPatterns}`);
522
+ console.log(` ${color('dim', 'Total applications:')} ${stats.totalApplications}`);
523
+ console.log(` ${color('dim', 'Overall success rate:')} ${(stats.overallSuccessRate * 100).toFixed(1)}%`);
524
+
525
+ printSection('By Tier');
526
+ console.log(` ${color('green', 'Auto Apply:')} ${stats.byTier.AUTO_APPLY}`);
527
+ console.log(` ${color('yellow', 'Apply with Log:')} ${stats.byTier.APPLY_WITH_LOG}`);
528
+ console.log(` ${color('cyan', 'Queue for Review:')} ${stats.byTier.QUEUE_FOR_REVIEW}`);
529
+
530
+ printSection('Queue');
531
+ console.log(` ${color('dim', 'Patterns queued:')} ${stats.queued}`);
532
+ console.log(` ${color('dim', 'Patterns applied:')} ${stats.applied}`);
533
+
534
+ console.log(`\n ${color('dim', `Last updated: ${stats.lastUpdated || 'never'}`)}`);
535
+ console.log('');
536
+ }
537
+
538
+ // ============================================================
539
+ // CLI Entry Point
540
+ // ============================================================
541
+
542
+ function showHelp() {
543
+ console.log(`
544
+ Wogi Flow - Tiered Learning System
545
+
546
+ Classify and manage learned patterns by confidence tier.
547
+
548
+ Usage:
549
+ flow learning tiers Show patterns by tier
550
+ flow learning stats Show learning statistics
551
+ flow learning apply <pattern> Manually apply a pattern
552
+ flow learning classify <pattern> Check tier for a pattern
553
+ flow learning record <pattern> Record a pattern result
554
+
555
+ Options:
556
+ --success Mark as successful (with record)
557
+ --fail Mark as failed (with record)
558
+ --json Output as JSON
559
+ --help, -h Show this help
560
+
561
+ Tiers:
562
+ AUTO_APPLY High confidence (90%+, 5+ samples) - applied automatically
563
+ APPLY_WITH_LOG Medium confidence (70%+, 3+ samples) - applied and logged
564
+ QUEUE_FOR_REVIEW Low confidence - requires human review
565
+
566
+ Examples:
567
+ flow learning tiers # Show all patterns by tier
568
+ flow learning stats # Show statistics
569
+ flow learning apply handle-async-errors # Apply a pattern
570
+ flow learning record my-pattern --success # Record successful application
571
+ `);
572
+ }
573
+
574
+ async function main() {
575
+ const args = process.argv.slice(2);
576
+ const { flags, positional } = parseFlags(args);
577
+ const command = positional[0] || 'tiers';
578
+
579
+ if (flags.help || flags.h) {
580
+ showHelp();
581
+ process.exit(0);
582
+ }
583
+
584
+ switch (command) {
585
+ case 'tiers':
586
+ if (flags.json) {
587
+ outputJson(getPatternsByTier());
588
+ } else {
589
+ printTiers();
590
+ }
591
+ break;
592
+
593
+ case 'stats':
594
+ case 'statistics':
595
+ if (flags.json) {
596
+ outputJson(getLearningStats());
597
+ } else {
598
+ printStats();
599
+ }
600
+ break;
601
+
602
+ case 'classify':
603
+ const patternToClassify = positional[1];
604
+ if (!patternToClassify) {
605
+ error('Please provide a pattern ID');
606
+ process.exit(1);
607
+ }
608
+ const action = getPatternAction(patternToClassify);
609
+ if (flags.json) {
610
+ outputJson(action);
611
+ } else {
612
+ if (!action.exists) {
613
+ warn(`Pattern '${patternToClassify}' not found`);
614
+ } else {
615
+ info(`Pattern: ${patternToClassify}`);
616
+ console.log(` Tier: ${color(action.color, action.tier)}`);
617
+ console.log(` Success rate: ${(action.successRate * 100).toFixed(1)}%`);
618
+ console.log(` Samples: ${action.sampleCount}`);
619
+ console.log(` Action: ${action.recommendation}`);
620
+ }
621
+ }
622
+ break;
623
+
624
+ case 'apply':
625
+ const patternToApply = positional[1];
626
+ if (!patternToApply) {
627
+ error('Please provide a pattern ID');
628
+ process.exit(1);
629
+ }
630
+ const applyResult = applyPattern(patternToApply);
631
+ if (flags.json) {
632
+ outputJson(applyResult);
633
+ } else {
634
+ if (applyResult.applied) {
635
+ info(`Applied pattern: ${patternToApply}`);
636
+ } else {
637
+ warn(`Could not apply pattern: ${patternToApply}`);
638
+ }
639
+ }
640
+ break;
641
+
642
+ case 'record':
643
+ const patternToRecord = positional[1];
644
+ if (!patternToRecord) {
645
+ error('Please provide a pattern ID');
646
+ process.exit(1);
647
+ }
648
+ if (!flags.success && !flags.fail) {
649
+ error('Please specify --success or --fail');
650
+ process.exit(1);
651
+ }
652
+ const recordResult = recordPatternResult({
653
+ patternId: patternToRecord,
654
+ success: flags.success === true,
655
+ context: flags.context || ''
656
+ });
657
+ if (flags.json) {
658
+ outputJson(recordResult);
659
+ } else {
660
+ info(`Recorded ${flags.success ? 'success' : 'failure'} for: ${patternToRecord}`);
661
+ console.log(` New tier: ${color(LEARNING_TIERS[recordResult.classification.tier].color, recordResult.classification.tier)}`);
662
+ console.log(` Success rate: ${(recordResult.classification.successRate * 100).toFixed(1)}%`);
663
+ }
664
+ break;
665
+
666
+ case 'queue':
667
+ const patternToQueue = positional[1];
668
+ if (!patternToQueue) {
669
+ error('Please provide a pattern ID');
670
+ process.exit(1);
671
+ }
672
+ const queueResult = queueForReview({
673
+ patternId: patternToQueue,
674
+ description: flags.description || '',
675
+ source: flags.source || 'manual'
676
+ });
677
+ if (flags.json) {
678
+ outputJson(queueResult);
679
+ } else {
680
+ if (queueResult.queued) {
681
+ info(`Queued for review: ${patternToQueue}`);
682
+ } else {
683
+ info(`Pattern already queued: ${patternToQueue} (updated occurrence count)`);
684
+ }
685
+ }
686
+ break;
687
+
688
+ default:
689
+ error(`Unknown command: ${command}`);
690
+ showHelp();
691
+ process.exit(1);
692
+ }
693
+ }
694
+
695
+ // ============================================================
696
+ // Exports
697
+ // ============================================================
698
+
699
+ module.exports = {
700
+ // Constants
701
+ LEARNING_TIERS,
702
+ DEFAULT_TIERED_LEARNING_CONFIG,
703
+
704
+ // Configuration
705
+ getTieredLearningConfig,
706
+
707
+ // Classification
708
+ classifyPattern,
709
+ getPatternAction,
710
+
711
+ // Pattern management
712
+ loadPatterns,
713
+ savePatterns,
714
+ recordPatternResult,
715
+ queueForReview,
716
+ applyPattern,
717
+
718
+ // Queries
719
+ getPatternsByTier,
720
+ getLearningStats
721
+ };
722
+
723
+ if (require.main === module) {
724
+ main().catch(err => {
725
+ error(err.message);
726
+ process.exit(1);
727
+ });
728
+ }