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.
- package/.workflow/agents/reviewer.md +81 -0
- package/.workflow/agents/security.md +94 -0
- package/.workflow/agents/story-writer.md +58 -0
- package/.workflow/bridges/base-bridge.js +395 -0
- package/.workflow/bridges/claude-bridge.js +434 -0
- package/.workflow/bridges/index.js +130 -0
- package/.workflow/lib/assumption-detector.js +481 -0
- package/.workflow/lib/config-substitution.js +371 -0
- package/.workflow/lib/failure-categories.js +478 -0
- package/.workflow/state/app-map.md.template +15 -0
- package/.workflow/state/architecture.md.template +24 -0
- package/.workflow/state/component-index.json.template +5 -0
- package/.workflow/state/decisions.md.template +15 -0
- package/.workflow/state/feedback-patterns.md.template +9 -0
- package/.workflow/state/knowledge-sync.json.template +6 -0
- package/.workflow/state/progress.md.template +14 -0
- package/.workflow/state/ready.json.template +7 -0
- package/.workflow/state/request-log.md.template +14 -0
- package/.workflow/state/session-state.json.template +11 -0
- package/.workflow/state/stack.md.template +33 -0
- package/.workflow/state/testing.md.template +36 -0
- package/.workflow/templates/claude-md.hbs +257 -0
- package/.workflow/templates/correction-report.md +67 -0
- package/.workflow/templates/gemini-md.hbs +52 -0
- package/README.md +1802 -0
- package/bin/flow +205 -0
- package/lib/index.js +33 -0
- package/lib/installer.js +467 -0
- package/lib/release-channel.js +269 -0
- package/lib/skill-registry.js +526 -0
- package/lib/upgrader.js +401 -0
- package/lib/utils.js +305 -0
- package/package.json +64 -0
- package/scripts/flow +985 -0
- package/scripts/flow-adaptive-learning.js +1259 -0
- package/scripts/flow-aggregate.js +488 -0
- package/scripts/flow-archive +133 -0
- package/scripts/flow-auto-context.js +1015 -0
- package/scripts/flow-auto-learn.js +615 -0
- package/scripts/flow-bridge.js +223 -0
- package/scripts/flow-browser-suggest.js +316 -0
- package/scripts/flow-bug.js +247 -0
- package/scripts/flow-cascade.js +711 -0
- package/scripts/flow-changelog +85 -0
- package/scripts/flow-checkpoint.js +483 -0
- package/scripts/flow-cli.js +403 -0
- package/scripts/flow-code-intelligence.js +760 -0
- package/scripts/flow-complexity.js +502 -0
- package/scripts/flow-config-set.js +152 -0
- package/scripts/flow-constants.js +157 -0
- package/scripts/flow-context +152 -0
- package/scripts/flow-context-init.js +482 -0
- package/scripts/flow-context-monitor.js +384 -0
- package/scripts/flow-context-scoring.js +886 -0
- package/scripts/flow-correct.js +458 -0
- package/scripts/flow-damage-control.js +985 -0
- package/scripts/flow-deps +101 -0
- package/scripts/flow-diff.js +700 -0
- package/scripts/flow-done +151 -0
- package/scripts/flow-done.js +489 -0
- package/scripts/flow-durable-session.js +1541 -0
- package/scripts/flow-entropy-monitor.js +345 -0
- package/scripts/flow-export-profile +349 -0
- package/scripts/flow-export-scanner.js +1046 -0
- package/scripts/flow-figma-confirm.js +400 -0
- package/scripts/flow-figma-extract.js +496 -0
- package/scripts/flow-figma-generate.js +683 -0
- package/scripts/flow-figma-index.js +909 -0
- package/scripts/flow-figma-match.js +617 -0
- package/scripts/flow-figma-mcp-server.js +518 -0
- package/scripts/flow-figma-pipeline.js +414 -0
- package/scripts/flow-file-ops.js +301 -0
- package/scripts/flow-gate-confidence.js +825 -0
- package/scripts/flow-guided-edit.js +659 -0
- package/scripts/flow-health +185 -0
- package/scripts/flow-health.js +413 -0
- package/scripts/flow-hooks.js +556 -0
- package/scripts/flow-http-client.js +249 -0
- package/scripts/flow-hybrid-detect.js +167 -0
- package/scripts/flow-hybrid-interactive.js +591 -0
- package/scripts/flow-hybrid-test.js +152 -0
- package/scripts/flow-import-profile +439 -0
- package/scripts/flow-init +253 -0
- package/scripts/flow-instruction-richness.js +827 -0
- package/scripts/flow-jira-integration.js +579 -0
- package/scripts/flow-knowledge-router.js +522 -0
- package/scripts/flow-knowledge-sync.js +589 -0
- package/scripts/flow-linear-integration.js +631 -0
- package/scripts/flow-links.js +774 -0
- package/scripts/flow-log-manager.js +559 -0
- package/scripts/flow-loop-enforcer.js +1246 -0
- package/scripts/flow-loop-retry-learning.js +630 -0
- package/scripts/flow-lsp.js +923 -0
- package/scripts/flow-map-index +348 -0
- package/scripts/flow-map-sync +201 -0
- package/scripts/flow-memory-blocks.js +668 -0
- package/scripts/flow-memory-compactor.js +350 -0
- package/scripts/flow-memory-db.js +1110 -0
- package/scripts/flow-memory-sync.js +484 -0
- package/scripts/flow-metrics.js +353 -0
- package/scripts/flow-migrate-ids.js +370 -0
- package/scripts/flow-model-adapter.js +802 -0
- package/scripts/flow-model-router.js +884 -0
- package/scripts/flow-models.js +1231 -0
- package/scripts/flow-morning.js +517 -0
- package/scripts/flow-multi-approach.js +660 -0
- package/scripts/flow-new-feature +86 -0
- package/scripts/flow-onboard +1042 -0
- package/scripts/flow-orchestrate-llm.js +459 -0
- package/scripts/flow-orchestrate.js +3592 -0
- package/scripts/flow-output.js +123 -0
- package/scripts/flow-parallel-detector.js +399 -0
- package/scripts/flow-parallel-dispatch.js +987 -0
- package/scripts/flow-parallel.js +428 -0
- package/scripts/flow-pattern-enforcer.js +600 -0
- package/scripts/flow-prd-manager.js +282 -0
- package/scripts/flow-progress.js +323 -0
- package/scripts/flow-project-analyzer.js +975 -0
- package/scripts/flow-prompt-composer.js +487 -0
- package/scripts/flow-providers.js +1381 -0
- package/scripts/flow-queue.js +308 -0
- package/scripts/flow-ready +82 -0
- package/scripts/flow-ready.js +189 -0
- package/scripts/flow-regression.js +396 -0
- package/scripts/flow-response-parser.js +450 -0
- package/scripts/flow-resume.js +284 -0
- package/scripts/flow-rules-sync.js +439 -0
- package/scripts/flow-run-trace.js +718 -0
- package/scripts/flow-safety.js +587 -0
- package/scripts/flow-search +104 -0
- package/scripts/flow-security.js +481 -0
- package/scripts/flow-session-end +106 -0
- package/scripts/flow-session-end.js +437 -0
- package/scripts/flow-session-state.js +671 -0
- package/scripts/flow-setup-hooks +216 -0
- package/scripts/flow-setup-hooks.js +377 -0
- package/scripts/flow-skill-create.js +329 -0
- package/scripts/flow-skill-creator.js +572 -0
- package/scripts/flow-skill-generator.js +1046 -0
- package/scripts/flow-skill-learn.js +880 -0
- package/scripts/flow-skill-matcher.js +578 -0
- package/scripts/flow-spec-generator.js +820 -0
- package/scripts/flow-stack-wizard.js +895 -0
- package/scripts/flow-standup +162 -0
- package/scripts/flow-start +74 -0
- package/scripts/flow-start.js +235 -0
- package/scripts/flow-status +110 -0
- package/scripts/flow-status.js +301 -0
- package/scripts/flow-step-browser.js +83 -0
- package/scripts/flow-step-changelog.js +217 -0
- package/scripts/flow-step-comments.js +306 -0
- package/scripts/flow-step-complexity.js +234 -0
- package/scripts/flow-step-coverage.js +218 -0
- package/scripts/flow-step-knowledge.js +193 -0
- package/scripts/flow-step-pr-tests.js +364 -0
- package/scripts/flow-step-regression.js +89 -0
- package/scripts/flow-step-review.js +516 -0
- package/scripts/flow-step-security.js +162 -0
- package/scripts/flow-step-silent-failures.js +290 -0
- package/scripts/flow-step-simplifier.js +346 -0
- package/scripts/flow-story +105 -0
- package/scripts/flow-story.js +500 -0
- package/scripts/flow-suspend.js +252 -0
- package/scripts/flow-sync-daemon.js +654 -0
- package/scripts/flow-task-analyzer.js +606 -0
- package/scripts/flow-team-dashboard.js +748 -0
- package/scripts/flow-team-sync.js +752 -0
- package/scripts/flow-team.js +977 -0
- package/scripts/flow-tech-options.js +528 -0
- package/scripts/flow-templates.js +812 -0
- package/scripts/flow-tiered-learning.js +728 -0
- package/scripts/flow-trace +204 -0
- package/scripts/flow-transcript-chunking.js +1106 -0
- package/scripts/flow-transcript-digest.js +7918 -0
- package/scripts/flow-transcript-language.js +465 -0
- package/scripts/flow-transcript-parsing.js +1085 -0
- package/scripts/flow-transcript-stories.js +2194 -0
- package/scripts/flow-update-map +224 -0
- package/scripts/flow-utils.js +2242 -0
- package/scripts/flow-verification.js +644 -0
- package/scripts/flow-verify.js +1177 -0
- package/scripts/flow-voice-input.js +638 -0
- package/scripts/flow-watch +168 -0
- package/scripts/flow-workflow-steps.js +521 -0
- package/scripts/flow-workflow.js +1029 -0
- package/scripts/flow-worktree.js +489 -0
- package/scripts/hooks/adapters/base-adapter.js +102 -0
- package/scripts/hooks/adapters/claude-code.js +359 -0
- package/scripts/hooks/adapters/index.js +79 -0
- package/scripts/hooks/core/component-check.js +341 -0
- package/scripts/hooks/core/index.js +35 -0
- package/scripts/hooks/core/loop-check.js +241 -0
- package/scripts/hooks/core/session-context.js +294 -0
- package/scripts/hooks/core/task-gate.js +177 -0
- package/scripts/hooks/core/validation.js +230 -0
- package/scripts/hooks/entry/claude-code/post-tool-use.js +65 -0
- package/scripts/hooks/entry/claude-code/pre-tool-use.js +89 -0
- package/scripts/hooks/entry/claude-code/session-end.js +87 -0
- package/scripts/hooks/entry/claude-code/session-start.js +46 -0
- package/scripts/hooks/entry/claude-code/stop.js +43 -0
- package/scripts/postinstall.js +139 -0
- package/templates/browser-test-flow.json +56 -0
- package/templates/bug-report.md +43 -0
- package/templates/component-detail.md +42 -0
- package/templates/component.stories.tsx +49 -0
- package/templates/context/constraints.md +83 -0
- package/templates/context/conventions.md +177 -0
- package/templates/context/stack.md +60 -0
- package/templates/correction-report.md +90 -0
- package/templates/feature-proposal.md +35 -0
- package/templates/hybrid/_base.md +254 -0
- package/templates/hybrid/_patterns.md +45 -0
- package/templates/hybrid/create-component.md +127 -0
- package/templates/hybrid/create-file.md +56 -0
- package/templates/hybrid/create-hook.md +145 -0
- package/templates/hybrid/create-service.md +70 -0
- package/templates/hybrid/fix-bug.md +33 -0
- package/templates/hybrid/modify-file.md +55 -0
- package/templates/story.md +68 -0
- package/templates/task.json +56 -0
- 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
|
+
}
|