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,660 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Wogi Flow - Multi-Approach Validation
|
|
5
|
+
*
|
|
6
|
+
* Uses multi-trajectory validation approach:
|
|
7
|
+
* For complex tasks, generate multiple solution approaches,
|
|
8
|
+
* validate each, and select the best one.
|
|
9
|
+
*
|
|
10
|
+
* Modes:
|
|
11
|
+
* - "suggest" (default): Ask user before using extra tokens
|
|
12
|
+
* - "auto": Automatically use for high-complexity tasks
|
|
13
|
+
* - "off": Disabled
|
|
14
|
+
*
|
|
15
|
+
* This works in both normal and hybrid modes:
|
|
16
|
+
* - Normal: Claude generates N approaches, picks best after analysis
|
|
17
|
+
* - Hybrid: Generate N plans, execute best one with local LLM
|
|
18
|
+
*
|
|
19
|
+
* Usage as module:
|
|
20
|
+
* const { shouldUseMultiApproach, runMultiApproach } = require('./flow-multi-approach');
|
|
21
|
+
* if (shouldUseMultiApproach(complexity)) { ... }
|
|
22
|
+
*
|
|
23
|
+
* Usage as CLI:
|
|
24
|
+
* flow multi-approach "task description"
|
|
25
|
+
* flow multi-approach --analyze "task" # Just analyze, don't execute
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
const fs = require('fs');
|
|
29
|
+
const path = require('path');
|
|
30
|
+
const { getProjectRoot, getConfig, PATHS, colors, writeJson, ensureDir } = require('./flow-utils');
|
|
31
|
+
|
|
32
|
+
const PROJECT_ROOT = getProjectRoot();
|
|
33
|
+
const APPROACHES_DIR = path.join(PROJECT_ROOT, '.workflow', 'state', 'approaches');
|
|
34
|
+
|
|
35
|
+
// ============================================================
|
|
36
|
+
// Configuration
|
|
37
|
+
// ============================================================
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Default configuration for multi-approach
|
|
41
|
+
*/
|
|
42
|
+
const DEFAULT_CONFIG = {
|
|
43
|
+
enabled: true,
|
|
44
|
+
mode: 'suggest', // 'suggest', 'auto', 'off'
|
|
45
|
+
triggerOn: ['large', 'xl'], // Complexity levels that trigger
|
|
46
|
+
maxApproaches: 3, // Number of approaches to generate
|
|
47
|
+
validationGates: ['typecheck', 'lint'], // Gates to run on each approach
|
|
48
|
+
selectionStrategy: 'first-passing' // 'first-passing', 'best-score', 'user-choice'
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Get multi-approach config from project config
|
|
53
|
+
*/
|
|
54
|
+
function getMultiApproachConfig() {
|
|
55
|
+
const config = getConfig();
|
|
56
|
+
return {
|
|
57
|
+
...DEFAULT_CONFIG,
|
|
58
|
+
...(config.multiApproach || {})
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// ============================================================
|
|
63
|
+
// Complexity Integration
|
|
64
|
+
// ============================================================
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Check if multi-approach should be used for a given complexity
|
|
68
|
+
* @param {string|object} complexity - Complexity level string or complexity result object
|
|
69
|
+
* @returns {object} { shouldUse: boolean, reason: string, mode: string }
|
|
70
|
+
*/
|
|
71
|
+
function shouldUseMultiApproach(complexity) {
|
|
72
|
+
const config = getMultiApproachConfig();
|
|
73
|
+
|
|
74
|
+
// Check if enabled
|
|
75
|
+
if (!config.enabled || config.mode === 'off') {
|
|
76
|
+
return {
|
|
77
|
+
shouldUse: false,
|
|
78
|
+
reason: 'Multi-approach is disabled',
|
|
79
|
+
mode: 'off'
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Extract complexity level
|
|
84
|
+
const level = typeof complexity === 'string'
|
|
85
|
+
? complexity.toLowerCase()
|
|
86
|
+
: (complexity?.level || complexity?.complexity || 'medium').toLowerCase();
|
|
87
|
+
|
|
88
|
+
// Check if complexity triggers multi-approach
|
|
89
|
+
const triggers = config.triggerOn.map(t => t.toLowerCase());
|
|
90
|
+
const shouldTrigger = triggers.includes(level);
|
|
91
|
+
|
|
92
|
+
if (!shouldTrigger) {
|
|
93
|
+
return {
|
|
94
|
+
shouldUse: false,
|
|
95
|
+
reason: `Complexity "${level}" does not trigger multi-approach (triggers: ${triggers.join(', ')})`,
|
|
96
|
+
mode: config.mode
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
shouldUse: true,
|
|
102
|
+
reason: `Complexity "${level}" triggers multi-approach`,
|
|
103
|
+
mode: config.mode,
|
|
104
|
+
needsUserApproval: config.mode === 'suggest'
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// ============================================================
|
|
109
|
+
// Approach Generation
|
|
110
|
+
// ============================================================
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Approach template for generating diverse solutions
|
|
114
|
+
*/
|
|
115
|
+
const APPROACH_STRATEGIES = [
|
|
116
|
+
{
|
|
117
|
+
name: 'Direct',
|
|
118
|
+
description: 'Most straightforward implementation',
|
|
119
|
+
guidance: 'Implement the most direct, minimal solution. Prefer built-in features and existing utilities. Avoid abstractions unless necessary.'
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
name: 'Robust',
|
|
123
|
+
description: 'Focus on error handling and edge cases',
|
|
124
|
+
guidance: 'Focus on comprehensive error handling, validation, and edge cases. Add defensive checks. Consider what could go wrong.'
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
name: 'Reusable',
|
|
128
|
+
description: 'Maximize code reuse and patterns',
|
|
129
|
+
guidance: 'Focus on reusability and patterns. Extract shared logic. Consider how this might be extended later. Follow DRY principles.'
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
name: 'Performance',
|
|
133
|
+
description: 'Optimize for speed and efficiency',
|
|
134
|
+
guidance: 'Focus on performance. Consider caching, lazy loading, memoization. Avoid unnecessary computations or re-renders.'
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
name: 'Simple',
|
|
138
|
+
description: 'Minimize complexity and lines of code',
|
|
139
|
+
guidance: 'Minimize lines of code and complexity. Use concise patterns. Prefer clarity over cleverness. KISS principle.'
|
|
140
|
+
}
|
|
141
|
+
];
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Generate approach prompts for a task
|
|
145
|
+
* @param {object} task - Task description and context
|
|
146
|
+
* @param {number} count - Number of approaches to generate
|
|
147
|
+
* @returns {array} Array of approach configurations
|
|
148
|
+
*/
|
|
149
|
+
function generateApproachPrompts(task, count = 3) {
|
|
150
|
+
const strategies = APPROACH_STRATEGIES.slice(0, count);
|
|
151
|
+
|
|
152
|
+
return strategies.map((strategy, index) => ({
|
|
153
|
+
id: `approach-${index + 1}`,
|
|
154
|
+
name: strategy.name,
|
|
155
|
+
description: strategy.description,
|
|
156
|
+
prompt: buildApproachPrompt(task, strategy),
|
|
157
|
+
strategy
|
|
158
|
+
}));
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Build a prompt for a specific approach strategy
|
|
163
|
+
*/
|
|
164
|
+
function buildApproachPrompt(task, strategy) {
|
|
165
|
+
return `
|
|
166
|
+
## Approach: ${strategy.name}
|
|
167
|
+
|
|
168
|
+
${strategy.guidance}
|
|
169
|
+
|
|
170
|
+
### Task
|
|
171
|
+
${task.description || task}
|
|
172
|
+
|
|
173
|
+
### Context
|
|
174
|
+
${task.context || 'Use existing project patterns and conventions.'}
|
|
175
|
+
|
|
176
|
+
### Requirements
|
|
177
|
+
- Follow the "${strategy.name}" approach strictly
|
|
178
|
+
- Generate complete, working code
|
|
179
|
+
- Include necessary imports
|
|
180
|
+
- Follow project conventions
|
|
181
|
+
|
|
182
|
+
### Output Format
|
|
183
|
+
Provide the implementation with:
|
|
184
|
+
1. File path
|
|
185
|
+
2. Complete code
|
|
186
|
+
3. Brief explanation of approach
|
|
187
|
+
|
|
188
|
+
`.trim();
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// ============================================================
|
|
192
|
+
// Approach Execution & Validation
|
|
193
|
+
// ============================================================
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Approach result structure
|
|
197
|
+
*/
|
|
198
|
+
function createApproachResult(approach) {
|
|
199
|
+
return {
|
|
200
|
+
id: approach.id,
|
|
201
|
+
name: approach.name,
|
|
202
|
+
status: 'pending', // pending, generating, validating, passed, failed
|
|
203
|
+
code: null,
|
|
204
|
+
files: [],
|
|
205
|
+
validationResults: {},
|
|
206
|
+
score: 0,
|
|
207
|
+
errors: [],
|
|
208
|
+
startTime: null,
|
|
209
|
+
endTime: null
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Calculate score for an approach based on validation results
|
|
215
|
+
*/
|
|
216
|
+
function calculateApproachScore(result) {
|
|
217
|
+
let score = 0;
|
|
218
|
+
|
|
219
|
+
// Base score for completion
|
|
220
|
+
if (result.code) score += 10;
|
|
221
|
+
|
|
222
|
+
// Validation gates
|
|
223
|
+
for (const [gate, passed] of Object.entries(result.validationResults)) {
|
|
224
|
+
if (passed) score += 20;
|
|
225
|
+
else score -= 10;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Penalties
|
|
229
|
+
score -= result.errors.length * 5;
|
|
230
|
+
|
|
231
|
+
// Bonus for simplicity (fewer lines = higher score)
|
|
232
|
+
if (result.code) {
|
|
233
|
+
const lines = result.code.split('\n').length;
|
|
234
|
+
if (lines < 50) score += 10;
|
|
235
|
+
else if (lines < 100) score += 5;
|
|
236
|
+
else if (lines > 200) score -= 5;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return Math.max(0, score);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Select best approach from results
|
|
244
|
+
* @param {array} results - Array of approach results
|
|
245
|
+
* @param {string} strategy - Selection strategy
|
|
246
|
+
* @returns {object} Selected approach result
|
|
247
|
+
*/
|
|
248
|
+
function selectBestApproach(results, strategy = 'first-passing') {
|
|
249
|
+
const validResults = results.filter(r => r.status !== 'failed');
|
|
250
|
+
|
|
251
|
+
if (validResults.length === 0) {
|
|
252
|
+
return {
|
|
253
|
+
selected: null,
|
|
254
|
+
reason: 'No approaches passed validation'
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
switch (strategy) {
|
|
259
|
+
case 'first-passing':
|
|
260
|
+
// Return first approach that passed all gates
|
|
261
|
+
const passing = validResults.find(r => r.status === 'passed');
|
|
262
|
+
return {
|
|
263
|
+
selected: passing || validResults[0],
|
|
264
|
+
reason: passing
|
|
265
|
+
? `Selected first passing approach: ${passing.name}`
|
|
266
|
+
: `No fully passing approach, selected best available: ${validResults[0].name}`
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
case 'best-score':
|
|
270
|
+
// Sort by score and return highest
|
|
271
|
+
validResults.sort((a, b) => b.score - a.score);
|
|
272
|
+
return {
|
|
273
|
+
selected: validResults[0],
|
|
274
|
+
reason: `Selected highest scoring approach: ${validResults[0].name} (score: ${validResults[0].score})`
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
case 'user-choice':
|
|
278
|
+
// Return all for user to choose
|
|
279
|
+
return {
|
|
280
|
+
selected: null,
|
|
281
|
+
candidates: validResults,
|
|
282
|
+
reason: 'Awaiting user selection'
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
default:
|
|
286
|
+
return {
|
|
287
|
+
selected: validResults[0],
|
|
288
|
+
reason: `Default selection: ${validResults[0].name}`
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// ============================================================
|
|
294
|
+
// Multi-Approach Session Management
|
|
295
|
+
// ============================================================
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Create a new multi-approach session
|
|
299
|
+
*/
|
|
300
|
+
function createSession(task, approaches) {
|
|
301
|
+
const sessionId = `ma-${Date.now()}`;
|
|
302
|
+
|
|
303
|
+
return {
|
|
304
|
+
id: sessionId,
|
|
305
|
+
task: typeof task === 'string' ? { description: task } : task,
|
|
306
|
+
approaches: approaches.map(createApproachResult),
|
|
307
|
+
status: 'created', // created, generating, validating, selecting, complete, failed
|
|
308
|
+
selectedApproach: null,
|
|
309
|
+
createdAt: new Date().toISOString(),
|
|
310
|
+
updatedAt: new Date().toISOString()
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Save session to disk
|
|
316
|
+
*/
|
|
317
|
+
function saveSession(session) {
|
|
318
|
+
session.updatedAt = new Date().toISOString();
|
|
319
|
+
|
|
320
|
+
ensureDir(APPROACHES_DIR);
|
|
321
|
+
|
|
322
|
+
const sessionPath = path.join(APPROACHES_DIR, `${session.id}.json`);
|
|
323
|
+
// Use atomic writeJson to prevent data corruption
|
|
324
|
+
writeJson(sessionPath, session);
|
|
325
|
+
|
|
326
|
+
return sessionPath;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Load session from disk
|
|
331
|
+
*/
|
|
332
|
+
function loadSession(sessionId) {
|
|
333
|
+
const sessionPath = path.join(APPROACHES_DIR, `${sessionId}.json`);
|
|
334
|
+
|
|
335
|
+
if (!fs.existsSync(sessionPath)) {
|
|
336
|
+
return null;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
return JSON.parse(fs.readFileSync(sessionPath, 'utf-8'));
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* List recent sessions
|
|
344
|
+
*/
|
|
345
|
+
function listSessions(limit = 10) {
|
|
346
|
+
if (!fs.existsSync(APPROACHES_DIR)) {
|
|
347
|
+
return [];
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
return fs.readdirSync(APPROACHES_DIR)
|
|
351
|
+
.filter(f => f.endsWith('.json'))
|
|
352
|
+
.map(f => {
|
|
353
|
+
const session = JSON.parse(
|
|
354
|
+
fs.readFileSync(path.join(APPROACHES_DIR, f), 'utf-8')
|
|
355
|
+
);
|
|
356
|
+
return {
|
|
357
|
+
id: session.id,
|
|
358
|
+
task: session.task?.description?.slice(0, 50) + '...',
|
|
359
|
+
status: session.status,
|
|
360
|
+
selectedApproach: session.selectedApproach?.name,
|
|
361
|
+
createdAt: session.createdAt
|
|
362
|
+
};
|
|
363
|
+
})
|
|
364
|
+
.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt))
|
|
365
|
+
.slice(0, limit);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// ============================================================
|
|
369
|
+
// Main Entry Points
|
|
370
|
+
// ============================================================
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Analyze a task for multi-approach suitability
|
|
374
|
+
* Does not execute, just returns analysis
|
|
375
|
+
*/
|
|
376
|
+
function analyzeForMultiApproach(taskDescription, complexityLevel = null) {
|
|
377
|
+
// Try to assess complexity if not provided
|
|
378
|
+
let complexity = complexityLevel;
|
|
379
|
+
if (!complexity) {
|
|
380
|
+
try {
|
|
381
|
+
const { assessTaskComplexity } = require('./flow-complexity');
|
|
382
|
+
const result = assessTaskComplexity(taskDescription);
|
|
383
|
+
complexity = result.level;
|
|
384
|
+
} catch {
|
|
385
|
+
complexity = 'medium';
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
const shouldUse = shouldUseMultiApproach(complexity);
|
|
390
|
+
const config = getMultiApproachConfig();
|
|
391
|
+
|
|
392
|
+
// Generate approach previews
|
|
393
|
+
const approaches = generateApproachPrompts(taskDescription, config.maxApproaches);
|
|
394
|
+
|
|
395
|
+
return {
|
|
396
|
+
task: taskDescription,
|
|
397
|
+
complexity,
|
|
398
|
+
multiApproach: shouldUse,
|
|
399
|
+
config: {
|
|
400
|
+
mode: config.mode,
|
|
401
|
+
maxApproaches: config.maxApproaches,
|
|
402
|
+
triggerOn: config.triggerOn,
|
|
403
|
+
selectionStrategy: config.selectionStrategy
|
|
404
|
+
},
|
|
405
|
+
approaches: approaches.map(a => ({
|
|
406
|
+
id: a.id,
|
|
407
|
+
name: a.name,
|
|
408
|
+
description: a.description
|
|
409
|
+
}))
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* Start a multi-approach session for a task
|
|
415
|
+
* Returns session that can be executed step by step
|
|
416
|
+
*/
|
|
417
|
+
function startMultiApproach(taskDescription, options = {}) {
|
|
418
|
+
const config = getMultiApproachConfig();
|
|
419
|
+
|
|
420
|
+
const approaches = generateApproachPrompts(
|
|
421
|
+
taskDescription,
|
|
422
|
+
options.maxApproaches || config.maxApproaches
|
|
423
|
+
);
|
|
424
|
+
|
|
425
|
+
const session = createSession(taskDescription, approaches);
|
|
426
|
+
session.status = 'created';
|
|
427
|
+
session.config = config;
|
|
428
|
+
|
|
429
|
+
// Save session
|
|
430
|
+
saveSession(session);
|
|
431
|
+
|
|
432
|
+
return session;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Format analysis for display
|
|
437
|
+
*/
|
|
438
|
+
function formatAnalysis(analysis) {
|
|
439
|
+
let output = '';
|
|
440
|
+
|
|
441
|
+
output += `${colors.cyan}Multi-Approach Analysis${colors.reset}\n`;
|
|
442
|
+
output += `${'═'.repeat(50)}\n\n`;
|
|
443
|
+
|
|
444
|
+
// Task summary
|
|
445
|
+
output += `${colors.bold}Task:${colors.reset} ${analysis.task.slice(0, 100)}${analysis.task.length > 100 ? '...' : ''}\n`;
|
|
446
|
+
output += `${colors.bold}Complexity:${colors.reset} ${analysis.complexity}\n\n`;
|
|
447
|
+
|
|
448
|
+
// Multi-approach decision
|
|
449
|
+
if (analysis.multiApproach.shouldUse) {
|
|
450
|
+
output += `${colors.green}✓ Multi-approach recommended${colors.reset}\n`;
|
|
451
|
+
output += ` Reason: ${analysis.multiApproach.reason}\n`;
|
|
452
|
+
|
|
453
|
+
if (analysis.multiApproach.needsUserApproval) {
|
|
454
|
+
output += ` ${colors.yellow}Mode is "suggest" - will ask for approval${colors.reset}\n`;
|
|
455
|
+
}
|
|
456
|
+
} else {
|
|
457
|
+
output += `${colors.dim}○ Multi-approach not needed${colors.reset}\n`;
|
|
458
|
+
output += ` Reason: ${analysis.multiApproach.reason}\n`;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
output += '\n';
|
|
462
|
+
|
|
463
|
+
// Approaches
|
|
464
|
+
if (analysis.approaches.length > 0) {
|
|
465
|
+
output += `${colors.bold}Available Approaches (${analysis.approaches.length}):${colors.reset}\n`;
|
|
466
|
+
for (const approach of analysis.approaches) {
|
|
467
|
+
output += ` ${colors.cyan}${approach.name}${colors.reset}: ${approach.description}\n`;
|
|
468
|
+
}
|
|
469
|
+
output += '\n';
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// Config
|
|
473
|
+
output += `${colors.dim}Config: mode=${analysis.config.mode}, triggers=${analysis.config.triggerOn.join(',')}${colors.reset}\n`;
|
|
474
|
+
|
|
475
|
+
return output;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Format suggestion prompt for user
|
|
480
|
+
*/
|
|
481
|
+
function formatSuggestionPrompt(analysis) {
|
|
482
|
+
return `
|
|
483
|
+
${colors.yellow}Multi-Approach Suggestion${colors.reset}
|
|
484
|
+
|
|
485
|
+
This task has "${analysis.complexity}" complexity. Using multi-approach validation
|
|
486
|
+
could help find the best solution but will use more tokens.
|
|
487
|
+
|
|
488
|
+
${colors.bold}What multi-approach does:${colors.reset}
|
|
489
|
+
1. Generates ${analysis.config.maxApproaches} different solutions
|
|
490
|
+
2. Validates each through quality gates
|
|
491
|
+
3. Selects the best passing approach
|
|
492
|
+
|
|
493
|
+
${colors.bold}Approaches that would be tried:${colors.reset}
|
|
494
|
+
${analysis.approaches.map(a => ` • ${a.name}: ${a.description}`).join('\n')}
|
|
495
|
+
|
|
496
|
+
${colors.bold}Options:${colors.reset}
|
|
497
|
+
[Y] Yes, use multi-approach (more thorough)
|
|
498
|
+
[N] No, use single approach (faster, less tokens)
|
|
499
|
+
[A] Always use for this complexity level
|
|
500
|
+
[S] Show me more details
|
|
501
|
+
|
|
502
|
+
`.trim();
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// ============================================================
|
|
506
|
+
// CLI
|
|
507
|
+
// ============================================================
|
|
508
|
+
|
|
509
|
+
function showHelp() {
|
|
510
|
+
console.log(`
|
|
511
|
+
Wogi Flow - Multi-Approach Validation
|
|
512
|
+
|
|
513
|
+
Generate multiple solution approaches for complex tasks, validate each,
|
|
514
|
+
and select the best one.
|
|
515
|
+
|
|
516
|
+
Usage:
|
|
517
|
+
flow multi-approach "task description"
|
|
518
|
+
flow multi-approach --analyze "task" # Analyze without executing
|
|
519
|
+
flow multi-approach --list # List recent sessions
|
|
520
|
+
flow multi-approach --config # Show configuration
|
|
521
|
+
|
|
522
|
+
Options:
|
|
523
|
+
--analyze Just analyze, don't start session
|
|
524
|
+
--list List recent multi-approach sessions
|
|
525
|
+
--config Show current configuration
|
|
526
|
+
--json Output as JSON
|
|
527
|
+
--help, -h Show this help
|
|
528
|
+
|
|
529
|
+
Modes (configurable in config.json):
|
|
530
|
+
"suggest" Ask user before using extra tokens (default)
|
|
531
|
+
"auto" Automatically use for high-complexity tasks
|
|
532
|
+
"off" Disabled
|
|
533
|
+
|
|
534
|
+
Examples:
|
|
535
|
+
flow multi-approach "Implement user authentication with OAuth"
|
|
536
|
+
flow multi-approach --analyze "Refactor the payment module"
|
|
537
|
+
`);
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
function main() {
|
|
541
|
+
const args = process.argv.slice(2);
|
|
542
|
+
|
|
543
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
544
|
+
showHelp();
|
|
545
|
+
process.exit(0);
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
const jsonOutput = args.includes('--json');
|
|
549
|
+
|
|
550
|
+
if (args.includes('--list')) {
|
|
551
|
+
const sessions = listSessions();
|
|
552
|
+
if (jsonOutput) {
|
|
553
|
+
console.log(JSON.stringify(sessions, null, 2));
|
|
554
|
+
} else {
|
|
555
|
+
console.log(`${colors.cyan}Recent Multi-Approach Sessions${colors.reset}\n`);
|
|
556
|
+
if (sessions.length === 0) {
|
|
557
|
+
console.log(`${colors.dim}No sessions found.${colors.reset}`);
|
|
558
|
+
} else {
|
|
559
|
+
for (const s of sessions) {
|
|
560
|
+
const statusIcon = s.status === 'complete' ? colors.green + '✓' : colors.yellow + '○';
|
|
561
|
+
console.log(`${statusIcon} ${s.id}${colors.reset}`);
|
|
562
|
+
console.log(` Task: ${s.task}`);
|
|
563
|
+
console.log(` Status: ${s.status}`);
|
|
564
|
+
if (s.selectedApproach) {
|
|
565
|
+
console.log(` Selected: ${s.selectedApproach}`);
|
|
566
|
+
}
|
|
567
|
+
console.log('');
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
process.exit(0);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
if (args.includes('--config')) {
|
|
575
|
+
const config = getMultiApproachConfig();
|
|
576
|
+
if (jsonOutput) {
|
|
577
|
+
console.log(JSON.stringify(config, null, 2));
|
|
578
|
+
} else {
|
|
579
|
+
console.log(`${colors.cyan}Multi-Approach Configuration${colors.reset}\n`);
|
|
580
|
+
console.log(` Enabled: ${config.enabled}`);
|
|
581
|
+
console.log(` Mode: ${config.mode}`);
|
|
582
|
+
console.log(` Trigger on: ${config.triggerOn.join(', ')}`);
|
|
583
|
+
console.log(` Max approaches: ${config.maxApproaches}`);
|
|
584
|
+
console.log(` Selection: ${config.selectionStrategy}`);
|
|
585
|
+
}
|
|
586
|
+
process.exit(0);
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
// Get task description
|
|
590
|
+
const taskDescription = args
|
|
591
|
+
.filter(a => !a.startsWith('--'))
|
|
592
|
+
.join(' ');
|
|
593
|
+
|
|
594
|
+
if (!taskDescription) {
|
|
595
|
+
console.log(`${colors.red}Error: Please provide a task description${colors.reset}`);
|
|
596
|
+
showHelp();
|
|
597
|
+
process.exit(1);
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// Analyze or start session
|
|
601
|
+
if (args.includes('--analyze')) {
|
|
602
|
+
const analysis = analyzeForMultiApproach(taskDescription);
|
|
603
|
+
|
|
604
|
+
if (jsonOutput) {
|
|
605
|
+
console.log(JSON.stringify(analysis, null, 2));
|
|
606
|
+
} else {
|
|
607
|
+
console.log(formatAnalysis(analysis));
|
|
608
|
+
}
|
|
609
|
+
} else {
|
|
610
|
+
// Start a session
|
|
611
|
+
const session = startMultiApproach(taskDescription);
|
|
612
|
+
|
|
613
|
+
if (jsonOutput) {
|
|
614
|
+
console.log(JSON.stringify(session, null, 2));
|
|
615
|
+
} else {
|
|
616
|
+
console.log(`${colors.green}✓${colors.reset} Created multi-approach session: ${session.id}`);
|
|
617
|
+
console.log(` Status: ${session.status}`);
|
|
618
|
+
console.log(` Approaches: ${session.approaches.length}`);
|
|
619
|
+
console.log(`\n Session saved to: ${APPROACHES_DIR}/${session.id}.json`);
|
|
620
|
+
console.log(`\n${colors.dim}Note: This creates a session. Execution is handled by the orchestrator.${colors.reset}`);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// ============================================================
|
|
626
|
+
// Exports
|
|
627
|
+
// ============================================================
|
|
628
|
+
|
|
629
|
+
module.exports = {
|
|
630
|
+
// Configuration
|
|
631
|
+
getMultiApproachConfig,
|
|
632
|
+
DEFAULT_CONFIG,
|
|
633
|
+
|
|
634
|
+
// Decision making
|
|
635
|
+
shouldUseMultiApproach,
|
|
636
|
+
analyzeForMultiApproach,
|
|
637
|
+
|
|
638
|
+
// Approach generation
|
|
639
|
+
generateApproachPrompts,
|
|
640
|
+
APPROACH_STRATEGIES,
|
|
641
|
+
|
|
642
|
+
// Session management
|
|
643
|
+
createSession,
|
|
644
|
+
startMultiApproach,
|
|
645
|
+
saveSession,
|
|
646
|
+
loadSession,
|
|
647
|
+
listSessions,
|
|
648
|
+
|
|
649
|
+
// Validation & selection
|
|
650
|
+
calculateApproachScore,
|
|
651
|
+
selectBestApproach,
|
|
652
|
+
|
|
653
|
+
// Formatting
|
|
654
|
+
formatAnalysis,
|
|
655
|
+
formatSuggestionPrompt
|
|
656
|
+
};
|
|
657
|
+
|
|
658
|
+
if (require.main === module) {
|
|
659
|
+
main();
|
|
660
|
+
}
|