wogiflow 2.4.2 → 2.4.4
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/.claude/commands/wogi-start.md +124 -0
- package/.claude/docs/claude-code-compatibility.md +51 -0
- package/.claude/docs/explore-agents.md +11 -0
- package/.claude/settings.json +12 -1
- package/.workflow/models/registry.json +1 -1
- package/bin/flow +11 -1
- package/lib/workspace-contracts.js +599 -0
- package/lib/workspace-intelligence.js +600 -0
- package/lib/workspace-messages.js +441 -0
- package/lib/workspace-routing.js +485 -0
- package/lib/workspace-sync.js +339 -0
- package/lib/workspace.js +1073 -0
- package/package.json +4 -4
- package/scripts/MEMORY-ARCHITECTURE.md +1 -1
- package/scripts/base-workflow-step.js +136 -0
- package/scripts/flow-adaptive-learning.js +8 -9
- package/scripts/flow-aggregate.js +11 -6
- package/scripts/flow-api-index.js +4 -6
- package/scripts/flow-assumption-detector.js +0 -2
- package/scripts/flow-audit.js +15 -2
- package/scripts/flow-auto-context.js +8 -12
- package/scripts/flow-auto-learn.js +49 -49
- package/scripts/flow-background.js +5 -6
- package/scripts/flow-bridge-state.js +8 -10
- package/scripts/flow-bulk-loop.js +1 -3
- package/scripts/flow-bulk-orchestrator.js +1 -3
- package/scripts/flow-cascade-completion.js +0 -2
- package/scripts/flow-cascade.js +4 -4
- package/scripts/flow-checkpoint.js +10 -13
- package/scripts/flow-code-intelligence.js +10 -12
- package/scripts/flow-community-sync.js +4 -4
- package/scripts/flow-community.js +12 -20
- package/scripts/flow-config-defaults.js +28 -2
- package/scripts/flow-config-interactive.js +9 -5
- package/scripts/flow-config-loader.js +49 -92
- package/scripts/flow-config-substitution.js +0 -2
- package/scripts/flow-context-estimator.js +4 -4
- package/scripts/flow-context-init.js +10 -12
- package/scripts/flow-context-manager.js +0 -2
- package/scripts/flow-context-scoring.js +2 -2
- package/scripts/flow-contract-scan.js +6 -9
- package/scripts/flow-correct.js +29 -27
- package/scripts/flow-correction-detector.js +5 -1
- package/scripts/flow-damage-control.js +47 -54
- package/scripts/flow-decisions-merge.js +4 -14
- package/scripts/flow-diff.js +5 -8
- package/scripts/flow-done-gates.js +786 -0
- package/scripts/flow-done-report.js +123 -0
- package/scripts/flow-done.js +71 -717
- package/scripts/flow-entropy-monitor.js +1 -3
- package/scripts/flow-eval-calibration.js +257 -0
- package/scripts/flow-eval-judge.js +10 -1
- package/scripts/flow-eval.js +14 -5
- package/scripts/flow-extraction-review.js +1 -0
- package/scripts/flow-failure-categories.js +0 -2
- package/scripts/flow-figma-confirm.js +5 -9
- package/scripts/flow-figma-generate.js +8 -10
- package/scripts/flow-figma-index.js +8 -10
- package/scripts/flow-figma-match.js +3 -5
- package/scripts/flow-figma-mcp-server.js +2 -4
- package/scripts/flow-figma-orchestrator.js +2 -3
- package/scripts/flow-figma-registry.js +2 -3
- package/scripts/flow-framework-resolver.js +0 -2
- package/scripts/flow-function-index.js +4 -6
- package/scripts/flow-gate-confidence.js +2 -2
- package/scripts/flow-gitignore.js +0 -2
- package/scripts/flow-guided-edit.js +5 -6
- package/scripts/flow-health.js +5 -6
- package/scripts/flow-hook-errors.js +6 -0
- package/scripts/flow-hook-status.js +263 -0
- package/scripts/flow-hooks.js +17 -29
- package/scripts/flow-http-client.js +9 -8
- package/scripts/flow-hybrid-interactive.js +7 -12
- package/scripts/flow-hybrid-test.js +12 -13
- package/scripts/flow-instruction-richness.js +1 -1
- package/scripts/flow-io.js +21 -4
- package/scripts/flow-knowledge-router.js +9 -3
- package/scripts/flow-learning-orchestrator.js +318 -13
- package/scripts/flow-links.js +5 -7
- package/scripts/flow-long-input-association.js +275 -0
- package/scripts/flow-long-input-chunking.js +1 -0
- package/scripts/flow-long-input-cli.js +0 -2
- package/scripts/flow-long-input-complexity.js +0 -2
- package/scripts/flow-long-input-constants.js +0 -2
- package/scripts/flow-long-input-contradictions.js +351 -0
- package/scripts/flow-long-input-detection.js +0 -2
- package/scripts/flow-long-input-passes.js +885 -0
- package/scripts/flow-long-input-stories.js +1 -1
- package/scripts/flow-long-input-voice.js +0 -2
- package/scripts/flow-long-input.js +425 -3005
- package/scripts/flow-loop-retry-learning.js +2 -3
- package/scripts/flow-lsp.js +3 -3
- package/scripts/flow-mcp-docs.js +3 -4
- package/scripts/flow-memory-db.js +6 -8
- package/scripts/flow-memory-sync.js +18 -11
- package/scripts/flow-metrics.js +1 -2
- package/scripts/flow-model-adapter.js +2 -3
- package/scripts/flow-model-config.js +72 -104
- package/scripts/flow-model-router.js +2 -2
- package/scripts/flow-model-types.js +0 -2
- package/scripts/flow-multi-approach.js +5 -6
- package/scripts/flow-orchestrate-context.js +3 -7
- package/scripts/flow-orchestrate-rollback.js +3 -8
- package/scripts/flow-orchestrate-state.js +8 -14
- package/scripts/flow-orchestrate-templates.js +2 -6
- package/scripts/flow-orchestrate-validator.js +5 -9
- package/scripts/flow-orchestrate.js +126 -103
- package/scripts/flow-output.js +0 -2
- package/scripts/flow-parallel.js +1 -1
- package/scripts/flow-paths.js +23 -2
- package/scripts/flow-pattern-enforcer.js +30 -28
- package/scripts/flow-pattern-extractor.js +3 -4
- package/scripts/flow-pending.js +0 -2
- package/scripts/flow-permissions.js +2 -3
- package/scripts/flow-plugin-registry.js +10 -12
- package/scripts/flow-prd-manager.js +1 -1
- package/scripts/flow-progress.js +7 -9
- package/scripts/flow-prompt-composer.js +3 -3
- package/scripts/flow-prompt-template.js +2 -2
- package/scripts/flow-providers.js +7 -4
- package/scripts/flow-registry-manager.js +7 -12
- package/scripts/flow-regression.js +9 -11
- package/scripts/flow-roadmap.js +2 -2
- package/scripts/flow-run-trace.js +16 -15
- package/scripts/flow-safety.js +2 -5
- package/scripts/flow-scanner-base.js +5 -7
- package/scripts/flow-scenario-engine.js +1 -5
- package/scripts/flow-security.js +29 -0
- package/scripts/flow-session-end.js +32 -41
- package/scripts/flow-session-learning.js +53 -49
- package/scripts/flow-setup-hooks.js +2 -3
- package/scripts/flow-skill-create.js +7 -12
- package/scripts/flow-skill-generator.js +12 -16
- package/scripts/flow-skill-learn.js +17 -8
- package/scripts/flow-skill-matcher.js +1 -2
- package/scripts/flow-spec-generator.js +2 -4
- package/scripts/flow-stack-wizard.js +5 -7
- package/scripts/flow-standards-learner.js +35 -16
- package/scripts/flow-start.js +2 -0
- package/scripts/flow-stats-collector.js +2 -2
- package/scripts/flow-status.js +10 -10
- package/scripts/flow-statusline-setup.js +2 -2
- package/scripts/flow-step-changelog.js +2 -3
- package/scripts/flow-step-comments.js +66 -81
- package/scripts/flow-step-complexity.js +50 -70
- package/scripts/flow-step-coverage.js +3 -5
- package/scripts/flow-step-knowledge.js +2 -3
- package/scripts/flow-step-pr-tests.js +64 -74
- package/scripts/flow-step-regression.js +3 -5
- package/scripts/flow-step-review.js +86 -103
- package/scripts/flow-step-security.js +111 -121
- package/scripts/flow-step-silent-failures.js +56 -83
- package/scripts/flow-step-simplifier.js +52 -70
- package/scripts/flow-story.js +4 -7
- package/scripts/flow-strict-adherence.js +3 -4
- package/scripts/flow-task-checkpoint.js +36 -5
- package/scripts/flow-task-enforcer.js +2 -24
- package/scripts/flow-tech-debt.js +1 -1
- package/scripts/flow-template-extractor.js +1 -0
- package/scripts/flow-templates.js +11 -13
- package/scripts/flow-test-api.js +9 -13
- package/scripts/flow-test-discovery.js +1 -1
- package/scripts/flow-test-generate.js +5 -9
- package/scripts/flow-test-integrity.js +3 -7
- package/scripts/flow-test-ui.js +5 -9
- package/scripts/flow-testing-deps.js +1 -3
- package/scripts/flow-tiered-learning.js +4 -4
- package/scripts/flow-todowrite-sync.js +1 -1
- package/scripts/flow-tokens.js +0 -2
- package/scripts/flow-verification-profile.js +6 -10
- package/scripts/flow-verify.js +12 -16
- package/scripts/flow-version-check.js +4 -12
- package/scripts/flow-webmcp-generator.js +3 -5
- package/scripts/flow-workflow-steps.js +0 -2
- package/scripts/flow-workflow.js +9 -11
- package/scripts/hooks/adapters/claude-code.js +31 -0
- package/scripts/hooks/core/config-change.js +1 -0
- package/scripts/hooks/core/extension-registry.js +0 -2
- package/scripts/hooks/core/instructions-loaded.js +1 -1
- package/scripts/hooks/core/observation-capture.js +5 -5
- package/scripts/hooks/core/phase-gate.js +5 -0
- package/scripts/hooks/core/post-compact.js +1 -12
- package/scripts/hooks/core/research-gate.js +2 -12
- package/scripts/hooks/core/routing-gate.js +6 -0
- package/scripts/hooks/core/task-completed.js +12 -0
- package/scripts/hooks/core/task-created.js +83 -0
- package/scripts/hooks/core/worktree-lifecycle.js +1 -1
- package/scripts/hooks/entry/claude-code/config-change.js +6 -29
- package/scripts/hooks/entry/claude-code/instructions-loaded.js +5 -30
- package/scripts/hooks/entry/claude-code/post-compact.js +4 -31
- package/scripts/hooks/entry/claude-code/post-tool-use.js +121 -172
- package/scripts/hooks/entry/claude-code/pre-tool-use.js +260 -361
- package/scripts/hooks/entry/claude-code/session-end.js +4 -28
- package/scripts/hooks/entry/claude-code/session-start.js +205 -243
- package/scripts/hooks/entry/claude-code/setup.js +8 -49
- package/scripts/hooks/entry/claude-code/stop.js +40 -72
- package/scripts/hooks/entry/claude-code/task-completed.js +4 -28
- package/scripts/hooks/entry/claude-code/task-created.js +15 -0
- package/scripts/hooks/entry/claude-code/user-prompt-submit.js +113 -195
- package/scripts/hooks/entry/claude-code/worktree-create.js +6 -25
- package/scripts/hooks/entry/claude-code/worktree-remove.js +6 -25
- package/scripts/hooks/entry/shared/hook-runner.js +99 -0
- package/scripts/hooks/entry/shared/read-stdin.js +0 -2
- package/scripts/postinstall.js +2 -0
- package/scripts/registries/api-registry.js +0 -2
- package/scripts/registries/component-registry.js +5 -9
- package/scripts/registries/contract-scanner.js +2 -9
- package/scripts/registries/function-registry.js +0 -2
- package/scripts/registries/schema-registry.js +14 -18
- package/scripts/registries/service-registry.js +23 -27
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
2
|
/**
|
|
5
3
|
* Template Engine - Extracted from flow-orchestrate.js
|
|
6
4
|
*
|
|
@@ -11,7 +9,7 @@
|
|
|
11
9
|
|
|
12
10
|
const fs = require('node:fs');
|
|
13
11
|
const path = require('node:path');
|
|
14
|
-
const { getProjectRoot, colors, getConfig } = require('./flow-utils');
|
|
12
|
+
const { getProjectRoot, colors, getConfig, PATHS } = require('./flow-utils');
|
|
15
13
|
const {
|
|
16
14
|
getVerbosityGuidance,
|
|
17
15
|
loadPatterns,
|
|
@@ -19,8 +17,6 @@ const {
|
|
|
19
17
|
loadRelatedCode
|
|
20
18
|
} = require('./flow-instruction-richness');
|
|
21
19
|
|
|
22
|
-
const PROJECT_ROOT = getProjectRoot();
|
|
23
|
-
|
|
24
20
|
function log(color, ...args) {
|
|
25
21
|
console.log(colors[color] + args.join(' ') + colors.reset);
|
|
26
22
|
}
|
|
@@ -30,7 +26,7 @@ class TemplateEngine {
|
|
|
30
26
|
this.templatesDir = templatesDir;
|
|
31
27
|
this.cache = new Map();
|
|
32
28
|
this.richness = null; // Instruction richness settings
|
|
33
|
-
this.projectRoot =
|
|
29
|
+
this.projectRoot = PATHS.root;
|
|
34
30
|
this.projectContext = this.loadProjectContext();
|
|
35
31
|
}
|
|
36
32
|
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
2
|
/**
|
|
5
3
|
* Validator - Extracted from flow-orchestrate.js
|
|
6
4
|
*
|
|
@@ -11,11 +9,9 @@
|
|
|
11
9
|
const fs = require('node:fs');
|
|
12
10
|
const path = require('node:path');
|
|
13
11
|
const { execFileSync } = require('node:child_process');
|
|
14
|
-
const { getProjectRoot, colors } = require('./flow-utils');
|
|
12
|
+
const { getProjectRoot, colors, PATHS } = require('./flow-utils');
|
|
15
13
|
const { getExecParts } = require('./flow-script-resolver');
|
|
16
14
|
|
|
17
|
-
const PROJECT_ROOT = getProjectRoot();
|
|
18
|
-
|
|
19
15
|
function log(color, ...args) {
|
|
20
16
|
console.log(colors[color] + args.join(' ') + colors.reset);
|
|
21
17
|
}
|
|
@@ -34,7 +30,7 @@ class Validator {
|
|
|
34
30
|
* Essential for monorepos where tsconfig is in apps/web/, apps/api/, etc.
|
|
35
31
|
*/
|
|
36
32
|
static findTsConfigDir(filePath) {
|
|
37
|
-
if (!filePath) return
|
|
33
|
+
if (!filePath) return PATHS.root;
|
|
38
34
|
|
|
39
35
|
let dir = path.dirname(filePath);
|
|
40
36
|
while (dir && dir !== path.dirname(dir)) { // Stop at filesystem root
|
|
@@ -52,7 +48,7 @@ class Validator {
|
|
|
52
48
|
}
|
|
53
49
|
dir = path.dirname(dir);
|
|
54
50
|
}
|
|
55
|
-
return
|
|
51
|
+
return PATHS.root;
|
|
56
52
|
}
|
|
57
53
|
|
|
58
54
|
static typescriptCheck(filePath) {
|
|
@@ -67,8 +63,8 @@ class Validator {
|
|
|
67
63
|
return { success: true, message: 'TypeScript check skipped (no tsconfig.json)' };
|
|
68
64
|
}
|
|
69
65
|
|
|
70
|
-
if (cwd !==
|
|
71
|
-
log('dim', ` 📁 Running tsc from: ${path.relative(
|
|
66
|
+
if (cwd !== PATHS.root) {
|
|
67
|
+
log('dim', ` 📁 Running tsc from: ${path.relative(PATHS.root, cwd) || '.'}`);
|
|
72
68
|
}
|
|
73
69
|
|
|
74
70
|
// Use execFileSync with array args for safety
|
|
@@ -59,7 +59,7 @@ const {
|
|
|
59
59
|
} = require('./flow-export-scanner');
|
|
60
60
|
|
|
61
61
|
// Import utilities for consistent project root, colors, and config
|
|
62
|
-
const { getProjectRoot, colors, getConfig, writeJson, estimateTokens, error } = require('./flow-utils');
|
|
62
|
+
const { getProjectRoot, colors, getConfig, writeJson, estimateTokens, error, PATHS } = require('./flow-utils');
|
|
63
63
|
const { getPromptAdjustments, recordModelResult } = require('./flow-model-adapter');
|
|
64
64
|
|
|
65
65
|
// Import provider infrastructure for cloud executors
|
|
@@ -121,13 +121,9 @@ const {
|
|
|
121
121
|
// Configuration
|
|
122
122
|
// ============================================================
|
|
123
123
|
|
|
124
|
-
const PROJECT_ROOT = getProjectRoot();
|
|
125
|
-
|
|
126
124
|
// Set export scanner project root to match orchestrator's
|
|
127
|
-
setExportScannerRoot(
|
|
128
|
-
const
|
|
129
|
-
const STATE_DIR = path.join(WORKFLOW_DIR, 'state');
|
|
130
|
-
const TEMPLATES_DIR = path.join(PROJECT_ROOT, 'templates', 'hybrid');
|
|
125
|
+
setExportScannerRoot(PATHS.root);
|
|
126
|
+
const TEMPLATES_DIR = path.join(PATHS.root, 'templates', 'hybrid');
|
|
131
127
|
|
|
132
128
|
function log(color, ...args) {
|
|
133
129
|
console.log(colors[color] + args.join(' ') + colors.reset);
|
|
@@ -142,7 +138,7 @@ function log(color, ...args) {
|
|
|
142
138
|
* This helps the AI understand what failed and how to fix it
|
|
143
139
|
*/
|
|
144
140
|
function saveStructuredFailure(step, errorHistory, attempts, config) {
|
|
145
|
-
const failurePath = path.join(
|
|
141
|
+
const failurePath = path.join(PATHS.state, 'last-failure.json');
|
|
146
142
|
|
|
147
143
|
const failureInfo = {
|
|
148
144
|
timestamp: new Date().toISOString(),
|
|
@@ -183,7 +179,7 @@ function generateFixSuggestion(errorHistory) {
|
|
|
183
179
|
const errorCounts = {};
|
|
184
180
|
|
|
185
181
|
for (const e of errorHistory) {
|
|
186
|
-
errorCounts[e.category] = (errorCounts[e.category]
|
|
182
|
+
errorCounts[e.category] = (errorCounts[e.category] ?? 0) + 1;
|
|
187
183
|
}
|
|
188
184
|
|
|
189
185
|
const mostCommon = Object.entries(errorCounts)
|
|
@@ -206,7 +202,7 @@ function generateFixSuggestion(errorHistory) {
|
|
|
206
202
|
|
|
207
203
|
function loadHybridConfig() {
|
|
208
204
|
const config = getConfig();
|
|
209
|
-
const hybrid = config.hybrid
|
|
205
|
+
const hybrid = config.hybrid ?? {};
|
|
210
206
|
|
|
211
207
|
if (!hybrid.enabled) {
|
|
212
208
|
throw new Error('Hybrid mode is not enabled. Run /wogi-hybrid first.');
|
|
@@ -217,9 +213,9 @@ function loadHybridConfig() {
|
|
|
217
213
|
const isLocal = executorConfig.type !== 'cloud';
|
|
218
214
|
|
|
219
215
|
// Context window: config override > executor config > auto-detect later
|
|
220
|
-
const contextWindow = hybrid.executor?.contextWindow
|
|
221
|
-
hybrid.settings?.contextWindow
|
|
222
|
-
executorConfig.contextWindow
|
|
216
|
+
const contextWindow = hybrid.executor?.contextWindow ??
|
|
217
|
+
hybrid.settings?.contextWindow ??
|
|
218
|
+
executorConfig.contextWindow ??
|
|
223
219
|
null;
|
|
224
220
|
|
|
225
221
|
// For local LLMs: use full context (they're free!)
|
|
@@ -272,10 +268,10 @@ function loadHybridConfig() {
|
|
|
272
268
|
outputReserveMax,
|
|
273
269
|
|
|
274
270
|
// Instruction richness settings
|
|
275
|
-
instructionRichness: hybrid.settings?.instructionRichness
|
|
271
|
+
instructionRichness: hybrid.settings?.instructionRichness ?? {},
|
|
276
272
|
|
|
277
273
|
// Cloud provider reference (for model selection in setup wizard)
|
|
278
|
-
cloudProviders: hybrid.cloudProviders
|
|
274
|
+
cloudProviders: hybrid.cloudProviders ?? config.hybrid?.cloudProviders ?? {}
|
|
279
275
|
};
|
|
280
276
|
}
|
|
281
277
|
|
|
@@ -293,7 +289,7 @@ function loadHybridConfig() {
|
|
|
293
289
|
function getProjectContext() {
|
|
294
290
|
try {
|
|
295
291
|
const config = getConfig();
|
|
296
|
-
return config.hybrid?.projectContext
|
|
292
|
+
return config.hybrid?.projectContext ?? {};
|
|
297
293
|
} catch (err) {
|
|
298
294
|
return {};
|
|
299
295
|
}
|
|
@@ -312,7 +308,7 @@ function autoCorrectCode(code, filePath, projectConfig = null) {
|
|
|
312
308
|
}
|
|
313
309
|
|
|
314
310
|
// Load project context from config if not provided
|
|
315
|
-
const ctx = projectConfig?.projectContext
|
|
311
|
+
const ctx = projectConfig?.projectContext ?? getProjectContext();
|
|
316
312
|
|
|
317
313
|
let corrected = code;
|
|
318
314
|
const corrections = [];
|
|
@@ -343,7 +339,7 @@ function autoCorrectCode(code, filePath, projectConfig = null) {
|
|
|
343
339
|
}
|
|
344
340
|
|
|
345
341
|
// 2. Fix component paths based on config mappings
|
|
346
|
-
const componentPaths = ctx.componentPaths
|
|
342
|
+
const componentPaths = ctx.componentPaths ?? {};
|
|
347
343
|
|
|
348
344
|
// Build reverse mapping from shadcn-style to project paths
|
|
349
345
|
// @/components/ui/button → project's Button path
|
|
@@ -430,7 +426,7 @@ function autoCorrectCode(code, filePath, projectConfig = null) {
|
|
|
430
426
|
* @param {string} projectRoot - Root directory of the project
|
|
431
427
|
* @returns {string} - Framework name: 'styled-components', 'shadcn', 'mui', 'chakra', 'antd', or 'react'
|
|
432
428
|
*/
|
|
433
|
-
function detectUIFramework(projectRoot =
|
|
429
|
+
function detectUIFramework(projectRoot = PATHS.root) {
|
|
434
430
|
try {
|
|
435
431
|
const pkgJsonPath = path.join(projectRoot, 'package.json');
|
|
436
432
|
const pkgJson = readJson(pkgJsonPath, null);
|
|
@@ -459,7 +455,7 @@ function detectUIFramework(projectRoot = PROJECT_ROOT) {
|
|
|
459
455
|
* @param {string[]} componentDirs - Directories to scan (relative to projectRoot)
|
|
460
456
|
* @returns {Object} - Mapping of ComponentName → import path
|
|
461
457
|
*/
|
|
462
|
-
function scanComponentPaths(projectRoot =
|
|
458
|
+
function scanComponentPaths(projectRoot = PATHS.root, componentDirs = ['src/components']) {
|
|
463
459
|
const componentPaths = {};
|
|
464
460
|
|
|
465
461
|
for (const dir of componentDirs) {
|
|
@@ -527,7 +523,7 @@ function scanComponentPaths(projectRoot = PROJECT_ROOT, componentDirs = ['src/co
|
|
|
527
523
|
* @param {string} projectRoot - Root directory of the project
|
|
528
524
|
* @returns {Object} - projectContext configuration
|
|
529
525
|
*/
|
|
530
|
-
function generateProjectContext(projectRoot =
|
|
526
|
+
function generateProjectContext(projectRoot = PATHS.root) {
|
|
531
527
|
const uiFramework = detectUIFramework(projectRoot);
|
|
532
528
|
|
|
533
529
|
// Scan standard component directories
|
|
@@ -588,7 +584,7 @@ function logTokenMetrics(plan, executionResult, complexity) {
|
|
|
588
584
|
|
|
589
585
|
if (!logMetrics) return;
|
|
590
586
|
|
|
591
|
-
const metricsPath = path.join(
|
|
587
|
+
const metricsPath = path.join(PATHS.state, 'hybrid-metrics.json');
|
|
592
588
|
|
|
593
589
|
// Load existing metrics or create new array
|
|
594
590
|
const metrics = readJson(metricsPath, []);
|
|
@@ -599,16 +595,16 @@ function logTokenMetrics(plan, executionResult, complexity) {
|
|
|
599
595
|
planId: plan.planId || 'unknown',
|
|
600
596
|
task: plan.task || 'unknown',
|
|
601
597
|
complexity: {
|
|
602
|
-
level: complexity?.level
|
|
603
|
-
estimatedTokens: complexity?.estimatedTokens
|
|
604
|
-
reasoning: complexity?.reasoning
|
|
598
|
+
level: complexity?.level ?? 'unknown',
|
|
599
|
+
estimatedTokens: complexity?.estimatedTokens ?? 0,
|
|
600
|
+
reasoning: complexity?.reasoning ?? ''
|
|
605
601
|
},
|
|
606
602
|
execution: {
|
|
607
603
|
success: executionResult.success,
|
|
608
|
-
stepsCompleted: executionResult.steps?.filter(s => s.success).length
|
|
609
|
-
stepsTotal: executionResult.steps?.length
|
|
604
|
+
stepsCompleted: executionResult.steps?.filter(s => s.success).length ?? 0,
|
|
605
|
+
stepsTotal: executionResult.steps?.length ?? 0,
|
|
610
606
|
escalated: executionResult.escalateToCloud?.length > 0,
|
|
611
|
-
escalatedSteps: executionResult.escalateToCloud?.map(s => s.id)
|
|
607
|
+
escalatedSteps: executionResult.escalateToCloud?.map(s => s.id) ?? []
|
|
612
608
|
}
|
|
613
609
|
};
|
|
614
610
|
|
|
@@ -794,6 +790,45 @@ const compactionStrategies = {
|
|
|
794
790
|
return trimmed;
|
|
795
791
|
},
|
|
796
792
|
|
|
793
|
+
/**
|
|
794
|
+
* Truncate code blocks (``` markers) to maxLines per block
|
|
795
|
+
*/
|
|
796
|
+
truncateCodeBlocks(text, maxLines = 100) {
|
|
797
|
+
const codeBlockRegex = /```[\s\S]*?```/g;
|
|
798
|
+
return text.replace(codeBlockRegex, (match) => {
|
|
799
|
+
const content = match.slice(3, -3); // Remove ``` markers
|
|
800
|
+
if (content.split('\n').length > maxLines) {
|
|
801
|
+
const truncated = compactionStrategies.truncateFileContent(content, maxLines);
|
|
802
|
+
return '```' + truncated + '```';
|
|
803
|
+
}
|
|
804
|
+
return match;
|
|
805
|
+
});
|
|
806
|
+
},
|
|
807
|
+
|
|
808
|
+
/**
|
|
809
|
+
* Truncate {{currentContent}} template blocks exceeding charLimit
|
|
810
|
+
*/
|
|
811
|
+
truncateCurrentContent(text, charLimit = 5000, maxLines = 150) {
|
|
812
|
+
const currentContentMatch = text.match(/{{currentContent}}[\s\S]*?(?=##|$)/);
|
|
813
|
+
if (currentContentMatch && currentContentMatch[0].length > charLimit) {
|
|
814
|
+
const lines = currentContentMatch[0].split('\n');
|
|
815
|
+
const truncated = compactionStrategies.truncateFileContent(lines.slice(1).join('\n'), maxLines);
|
|
816
|
+
return text.replace(currentContentMatch[0], '{{currentContent}}\n' + truncated + '\n\n');
|
|
817
|
+
}
|
|
818
|
+
return text;
|
|
819
|
+
},
|
|
820
|
+
|
|
821
|
+
/**
|
|
822
|
+
* Aggressive last-resort truncation to fit within token budget
|
|
823
|
+
*/
|
|
824
|
+
aggressiveTruncate(text, availableTokens, estimateTokensFn) {
|
|
825
|
+
const tokens = estimateTokensFn(text);
|
|
826
|
+
if (tokens <= availableTokens) return text;
|
|
827
|
+
const ratio = availableTokens / tokens;
|
|
828
|
+
const targetLength = Math.floor(text.length * ratio * 0.9); // 10% safety margin
|
|
829
|
+
return text.slice(0, targetLength) + '\n\n[Content truncated to fit context window]';
|
|
830
|
+
},
|
|
831
|
+
|
|
797
832
|
/**
|
|
798
833
|
* Truncate search results array to prevent context overflow
|
|
799
834
|
* @param {Array} results - Array of search results with optional content
|
|
@@ -833,99 +868,84 @@ const compactionStrategies = {
|
|
|
833
868
|
};
|
|
834
869
|
|
|
835
870
|
/**
|
|
836
|
-
*
|
|
837
|
-
*
|
|
871
|
+
* Calculates available token budget after reserving output tokens.
|
|
872
|
+
* Caps reserve at 50% of context window to prevent zero-budget bugs.
|
|
838
873
|
*/
|
|
839
|
-
function
|
|
840
|
-
// Sanity check: never reserve more than 50% of context window
|
|
841
|
-
// This prevents the bug where maxTokens == contextWindow causing availableTokens = 0
|
|
874
|
+
function calcAvailableTokens(contextWindow, reserveForOutput) {
|
|
842
875
|
const maxReserve = Math.floor(contextWindow / 2);
|
|
843
876
|
if (reserveForOutput > maxReserve) {
|
|
844
877
|
log('dim', ` 📊 Capping output reserve from ${reserveForOutput} to ${maxReserve} tokens`);
|
|
845
878
|
reserveForOutput = maxReserve;
|
|
846
879
|
}
|
|
880
|
+
const available = contextWindow - reserveForOutput;
|
|
881
|
+
if (available < 1024) {
|
|
882
|
+
log('yellow', ` ⚠️ Warning: Very low available tokens (${available}). Context: ${contextWindow}, Reserve: ${reserveForOutput}`);
|
|
883
|
+
}
|
|
884
|
+
return available;
|
|
885
|
+
}
|
|
847
886
|
|
|
848
|
-
|
|
887
|
+
/**
|
|
888
|
+
* Builds a compaction result object.
|
|
889
|
+
*/
|
|
890
|
+
function compactionResult(prompt, wasCompacted, originalTokens, contextWindow) {
|
|
891
|
+
const finalTokens = estimateTokens(prompt);
|
|
892
|
+
return {
|
|
893
|
+
prompt,
|
|
894
|
+
wasCompacted,
|
|
895
|
+
originalTokens,
|
|
896
|
+
finalTokens,
|
|
897
|
+
usage: getContextUsage(finalTokens, contextWindow)
|
|
898
|
+
};
|
|
899
|
+
}
|
|
849
900
|
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
901
|
+
/**
|
|
902
|
+
* Ordered compaction pipeline — each step is tried in sequence.
|
|
903
|
+
* Each entry: { name, apply(text) → text, logLabel }
|
|
904
|
+
*/
|
|
905
|
+
const COMPACTION_PIPELINE = [
|
|
906
|
+
{ name: 'trimRetryErrors', apply: (t) => compactionStrategies.trimRetryErrors(t), logLabel: 'Trimmed retry errors' },
|
|
907
|
+
{ name: 'trimTemplateVerbosity', apply: (t) => compactionStrategies.trimTemplateVerbosity(t), logLabel: 'Trimmed template verbosity' },
|
|
908
|
+
{ name: 'truncateCodeBlocks', apply: (t) => compactionStrategies.truncateCodeBlocks(t, 100), logLabel: 'Truncated code blocks' },
|
|
909
|
+
{ name: 'truncateCurrentContent', apply: (t) => compactionStrategies.truncateCurrentContent(t), logLabel: 'Truncated currentContent blocks' },
|
|
910
|
+
];
|
|
854
911
|
|
|
912
|
+
/**
|
|
913
|
+
* Auto-compacts a prompt to fit within context window.
|
|
914
|
+
* Applies strategies in order: retry errors, template verbosity,
|
|
915
|
+
* code block truncation, currentContent truncation, aggressive truncation.
|
|
916
|
+
* Returns { prompt, wasCompacted, originalTokens, finalTokens, usage }
|
|
917
|
+
*/
|
|
918
|
+
function autoCompactPrompt(prompt, contextWindow, reserveForOutput = 2048) {
|
|
919
|
+
const availableTokens = calcAvailableTokens(contextWindow, reserveForOutput);
|
|
855
920
|
const originalTokens = estimateTokens(prompt);
|
|
856
921
|
|
|
857
922
|
if (originalTokens <= availableTokens) {
|
|
858
|
-
return
|
|
859
|
-
prompt,
|
|
860
|
-
wasCompacted: false,
|
|
861
|
-
originalTokens,
|
|
862
|
-
finalTokens: originalTokens,
|
|
863
|
-
usage: getContextUsage(originalTokens, contextWindow)
|
|
864
|
-
};
|
|
923
|
+
return compactionResult(prompt, false, originalTokens, contextWindow);
|
|
865
924
|
}
|
|
866
925
|
|
|
867
926
|
log('yellow', ` ⚠️ Prompt too large (${originalTokens.toLocaleString()} tokens), compacting...`);
|
|
868
927
|
|
|
869
928
|
let compacted = prompt;
|
|
870
929
|
|
|
871
|
-
//
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
// Strategy 2: Trim template verbosity
|
|
880
|
-
compacted = compactionStrategies.trimTemplateVerbosity(compacted);
|
|
881
|
-
tokens = estimateTokens(compacted);
|
|
882
|
-
if (tokens <= availableTokens) {
|
|
883
|
-
log('dim', ` 📦 Trimmed template verbosity: ${tokens.toLocaleString()} tokens`);
|
|
884
|
-
return { prompt: compacted, wasCompacted: true, originalTokens, finalTokens: tokens, usage: getContextUsage(tokens, contextWindow) };
|
|
885
|
-
}
|
|
886
|
-
|
|
887
|
-
// Strategy 3: Truncate file content in the prompt
|
|
888
|
-
// Find content between ``` markers and truncate
|
|
889
|
-
const codeBlockRegex = /```[\s\S]*?```/g;
|
|
890
|
-
compacted = compacted.replace(codeBlockRegex, (match) => {
|
|
891
|
-
const content = match.slice(3, -3); // Remove ``` markers
|
|
892
|
-
if (content.split('\n').length > 100) {
|
|
893
|
-
const truncated = compactionStrategies.truncateFileContent(content, 100);
|
|
894
|
-
return '```' + truncated + '```';
|
|
930
|
+
// Apply pipeline strategies in order, exit early if prompt fits
|
|
931
|
+
for (const step of COMPACTION_PIPELINE) {
|
|
932
|
+
compacted = step.apply(compacted);
|
|
933
|
+
const tokens = estimateTokens(compacted);
|
|
934
|
+
if (tokens <= availableTokens) {
|
|
935
|
+
log('dim', ` 📦 ${step.logLabel}: ${tokens.toLocaleString()} tokens`);
|
|
936
|
+
return compactionResult(compacted, true, originalTokens, contextWindow);
|
|
895
937
|
}
|
|
896
|
-
return match;
|
|
897
|
-
});
|
|
898
|
-
|
|
899
|
-
// Also check for {{currentContent}} style blocks
|
|
900
|
-
const currentContentMatch = compacted.match(/{{currentContent}}[\s\S]*?(?=##|$)/);
|
|
901
|
-
if (currentContentMatch && currentContentMatch[0].length > 5000) {
|
|
902
|
-
const lines = currentContentMatch[0].split('\n');
|
|
903
|
-
const truncated = compactionStrategies.truncateFileContent(lines.slice(1).join('\n'), 150);
|
|
904
|
-
compacted = compacted.replace(currentContentMatch[0], '{{currentContent}}\n' + truncated + '\n\n');
|
|
905
938
|
}
|
|
906
939
|
|
|
907
|
-
|
|
908
|
-
log('dim', ` 📦 Truncated file content: ${tokens.toLocaleString()} tokens`);
|
|
940
|
+
log('dim', ` 📦 Truncated file content: ${estimateTokens(compacted).toLocaleString()} tokens`);
|
|
909
941
|
|
|
910
|
-
//
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
const targetLength = Math.floor(compacted.length * ratio * 0.9); // 10% safety margin
|
|
914
|
-
compacted = compacted.slice(0, targetLength) + '\n\n[Content truncated to fit context window]';
|
|
915
|
-
tokens = estimateTokens(compacted);
|
|
916
|
-
log('yellow', ` ⚠️ Aggressive truncation: ${tokens.toLocaleString()} tokens`);
|
|
917
|
-
}
|
|
942
|
+
// Last resort: aggressive truncation
|
|
943
|
+
compacted = compactionStrategies.aggressiveTruncate(compacted, availableTokens, estimateTokens);
|
|
944
|
+
log('yellow', ` ⚠️ Aggressive truncation: ${estimateTokens(compacted).toLocaleString()} tokens`);
|
|
918
945
|
|
|
919
|
-
return
|
|
920
|
-
prompt: compacted,
|
|
921
|
-
wasCompacted: true,
|
|
922
|
-
originalTokens,
|
|
923
|
-
finalTokens: tokens,
|
|
924
|
-
usage: getContextUsage(tokens, contextWindow)
|
|
925
|
-
};
|
|
946
|
+
return compactionResult(compacted, true, originalTokens, contextWindow);
|
|
926
947
|
}
|
|
927
948
|
|
|
928
|
-
|
|
929
949
|
// TemplateEngine extracted to ./flow-orchestrate-templates.js
|
|
930
950
|
// Validator extracted to ./flow-orchestrate-validator.js
|
|
931
951
|
// RollbackManager extracted to ./flow-orchestrate-rollback.js
|
|
@@ -946,7 +966,7 @@ class Orchestrator {
|
|
|
946
966
|
this.completedSteps = new Set();
|
|
947
967
|
|
|
948
968
|
// Project context generator - generates once, reuses for all steps
|
|
949
|
-
this.contextGenerator = new ProjectContextGenerator(
|
|
969
|
+
this.contextGenerator = new ProjectContextGenerator(PATHS.root);
|
|
950
970
|
this.projectContext = null;
|
|
951
971
|
|
|
952
972
|
// Complexity assessment for the current plan
|
|
@@ -1161,7 +1181,7 @@ class Orchestrator {
|
|
|
1161
1181
|
|
|
1162
1182
|
// Load model profile for intelligent context loading
|
|
1163
1183
|
const modelProfile = getModelProfile(this.config.model, taskType);
|
|
1164
|
-
const profileRichness = getProfileBasedRichness(this.config.model, taskType, this.config.maxTokens
|
|
1184
|
+
const profileRichness = getProfileBasedRichness(this.config.model, taskType, this.config.maxTokens ?? 8192);
|
|
1165
1185
|
|
|
1166
1186
|
// Store for use during retries
|
|
1167
1187
|
result.taskType = taskType;
|
|
@@ -1199,7 +1219,7 @@ class Orchestrator {
|
|
|
1199
1219
|
file: step.params?.path || step.file || '',
|
|
1200
1220
|
action: step.action || templateName
|
|
1201
1221
|
};
|
|
1202
|
-
prompt = injectPatterns(prompt, taskContext,
|
|
1222
|
+
prompt = injectPatterns(prompt, taskContext, PATHS.root);
|
|
1203
1223
|
|
|
1204
1224
|
// PREPEND PROJECT CONTEXT - Local LLM tokens are FREE
|
|
1205
1225
|
// This gives the LLM comprehensive knowledge about types, theme, patterns
|
|
@@ -1279,10 +1299,10 @@ class Orchestrator {
|
|
|
1279
1299
|
try {
|
|
1280
1300
|
// Auto-compact prompt if needed
|
|
1281
1301
|
// Use config override, or LLM's detected context window, or conservative fallback
|
|
1282
|
-
const contextWindow = this.config.contextWindow
|
|
1302
|
+
const contextWindow = this.config.contextWindow ?? this.llm.contextWindow ?? 4096;
|
|
1283
1303
|
// Reserve configurable % of context for output, with configurable max
|
|
1284
|
-
const reserveRatio = this.config.outputReserveRatio
|
|
1285
|
-
const reserveMax = this.config.outputReserveMax
|
|
1304
|
+
const reserveRatio = this.config.outputReserveRatio ?? 0.3;
|
|
1305
|
+
const reserveMax = this.config.outputReserveMax ?? 4096;
|
|
1286
1306
|
const reserveForOutput = Math.min(reserveMax, Math.floor(contextWindow * reserveRatio));
|
|
1287
1307
|
const { prompt: compactedPrompt, wasCompacted, usage } = autoCompactPrompt(
|
|
1288
1308
|
prompt,
|
|
@@ -1657,7 +1677,10 @@ if (process.env.NODE_ENV === 'test') {
|
|
|
1657
1677
|
module.exports._test = {
|
|
1658
1678
|
autoCompactPrompt,
|
|
1659
1679
|
getContextUsage,
|
|
1660
|
-
compactionStrategies
|
|
1680
|
+
compactionStrategies,
|
|
1681
|
+
calcAvailableTokens,
|
|
1682
|
+
compactionResult,
|
|
1683
|
+
COMPACTION_PIPELINE
|
|
1661
1684
|
};
|
|
1662
1685
|
} else {
|
|
1663
1686
|
main().catch(err => {
|
package/scripts/flow-output.js
CHANGED
package/scripts/flow-parallel.js
CHANGED
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
|
|
37
37
|
const fs = require('node:fs');
|
|
38
38
|
const path = require('node:path');
|
|
39
|
-
const { getProjectRoot, getConfig, readJson, info } = require('./flow-utils');
|
|
39
|
+
const { getProjectRoot, getConfig, readJson, info, PATHS } = require('./flow-utils');
|
|
40
40
|
|
|
41
41
|
// ============================================================
|
|
42
42
|
// Configuration (uses centralized getConfig from flow-utils)
|
package/scripts/flow-paths.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* Wogi Flow - Path Constants and Utilities
|
|
5
3
|
*
|
|
@@ -152,6 +150,29 @@ const PATHS = {
|
|
|
152
150
|
modelsDir: path.join(WORKFLOW_DIR, 'models'),
|
|
153
151
|
modelRegistry: path.join(WORKFLOW_DIR, 'models', 'registry.json'),
|
|
154
152
|
modelStats: path.join(WORKFLOW_DIR, 'models', 'stats.json'),
|
|
153
|
+
modelStatsArchive: path.join(WORKFLOW_DIR, 'models', 'stats-archive'),
|
|
154
|
+
modelCapabilities: path.join(WORKFLOW_DIR, 'models', 'capabilities'),
|
|
155
|
+
communityScores: path.join(WORKFLOW_DIR, 'models', 'community-scores.json'),
|
|
156
|
+
communityRouting: path.join(WORKFLOW_DIR, 'models', 'community-routing.json'),
|
|
157
|
+
// Additional workflow directories (v1.9.8)
|
|
158
|
+
verifications: path.join(WORKFLOW_DIR, 'verifications'),
|
|
159
|
+
logs: path.join(WORKFLOW_DIR, 'logs'),
|
|
160
|
+
bridges: path.join(WORKFLOW_DIR, 'bridges'),
|
|
161
|
+
evals: path.join(WORKFLOW_DIR, 'evals'),
|
|
162
|
+
reviews: path.join(WORKFLOW_DIR, 'reviews'),
|
|
163
|
+
completed: path.join(WORKFLOW_DIR, 'completed'),
|
|
164
|
+
failureLearnings: path.join(WORKFLOW_DIR, 'failure-learnings'),
|
|
165
|
+
templates: path.join(WORKFLOW_DIR, 'templates'),
|
|
166
|
+
templatesExtracted: path.join(WORKFLOW_DIR, 'templates', 'extracted'),
|
|
167
|
+
templatesPrompts: path.join(WORKFLOW_DIR, 'templates', 'prompts'),
|
|
168
|
+
promptsFragments: path.join(WORKFLOW_DIR, 'prompts', 'fragments'),
|
|
169
|
+
promptsComposed: path.join(WORKFLOW_DIR, 'prompts', 'composed'),
|
|
170
|
+
testsGenerated: path.join(WORKFLOW_DIR, 'tests', 'generated'),
|
|
171
|
+
testsApiFixtures: path.join(WORKFLOW_DIR, 'tests', 'api-fixtures.json'),
|
|
172
|
+
longInputTmp: path.join(WORKFLOW_DIR, 'tmp', 'long-input'),
|
|
173
|
+
// State files (v1.9.8)
|
|
174
|
+
roadmap: path.join(STATE_DIR, 'roadmap.md'),
|
|
175
|
+
memoryDb: path.join(WORKFLOW_DIR, 'memory', 'local.db'),
|
|
155
176
|
};
|
|
156
177
|
|
|
157
178
|
// ============================================================
|