wogiflow 2.4.1 → 2.4.3
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/docs/claude-code-compatibility.md +27 -0
- package/.claude/settings.json +1 -1
- package/.workflow/models/registry.json +1 -1
- 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 +0 -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.js +5 -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 +2 -0
- package/scripts/hooks/core/commit-log-gate.js +21 -10
- 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-gate.js +27 -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/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/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
|
@@ -39,10 +39,6 @@ const {
|
|
|
39
39
|
// Configuration
|
|
40
40
|
// ============================================================
|
|
41
41
|
|
|
42
|
-
const PROJECT_ROOT = getProjectRoot();
|
|
43
|
-
const WORKFLOW_DIR = path.join(PROJECT_ROOT, '.workflow');
|
|
44
|
-
const STATE_DIR = path.join(WORKFLOW_DIR, 'state');
|
|
45
|
-
|
|
46
42
|
// ============================================================
|
|
47
43
|
// Pattern Extraction
|
|
48
44
|
// ============================================================
|
|
@@ -50,7 +46,7 @@ const STATE_DIR = path.join(WORKFLOW_DIR, 'state');
|
|
|
50
46
|
/**
|
|
51
47
|
* Load all patterns from decisions.md
|
|
52
48
|
*/
|
|
53
|
-
function loadDecisionPatterns(projectRoot =
|
|
49
|
+
function loadDecisionPatterns(projectRoot = PATHS.root) {
|
|
54
50
|
const decisionsPath = path.join(projectRoot, '.workflow', 'state', 'decisions.md');
|
|
55
51
|
|
|
56
52
|
// Read file directly in try-catch (no pre-check to avoid TOCTOU race condition)
|
|
@@ -93,7 +89,7 @@ function loadDecisionPatterns(projectRoot = PROJECT_ROOT) {
|
|
|
93
89
|
/**
|
|
94
90
|
* Load components from app-map.md
|
|
95
91
|
*/
|
|
96
|
-
function loadAppMapComponents(projectRoot =
|
|
92
|
+
function loadAppMapComponents(projectRoot = PATHS.root) {
|
|
97
93
|
const appMapPath = path.join(projectRoot, '.workflow', 'state', 'app-map.md');
|
|
98
94
|
|
|
99
95
|
// Read file directly in try-catch (no pre-check to avoid TOCTOU race condition)
|
|
@@ -205,7 +201,7 @@ function loadSkillPatterns(projectRoot, fileExtension, taskDescription = '') {
|
|
|
205
201
|
/**
|
|
206
202
|
* Extract patterns relevant to a specific task
|
|
207
203
|
*/
|
|
208
|
-
function extractRelevantPatterns(task, projectRoot =
|
|
204
|
+
function extractRelevantPatterns(task, projectRoot = PATHS.root) {
|
|
209
205
|
const relevant = {
|
|
210
206
|
decisions: [],
|
|
211
207
|
components: [],
|
|
@@ -329,7 +325,7 @@ function formatPatternsForPrompt(relevantPatterns, config = {}) {
|
|
|
329
325
|
/**
|
|
330
326
|
* Inject patterns into a prompt
|
|
331
327
|
*/
|
|
332
|
-
function injectPatterns(prompt, task, projectRoot =
|
|
328
|
+
function injectPatterns(prompt, task, projectRoot = PATHS.root) {
|
|
333
329
|
const config = getConfig();
|
|
334
330
|
const enforcement = config.enforcement || {};
|
|
335
331
|
|
|
@@ -483,7 +479,7 @@ function validateCitations(code, patterns) {
|
|
|
483
479
|
/**
|
|
484
480
|
* Generate session start summary showing loaded patterns
|
|
485
481
|
*/
|
|
486
|
-
function generateSessionSummary(projectRoot =
|
|
482
|
+
function generateSessionSummary(projectRoot = PATHS.root) {
|
|
487
483
|
const decisions = loadDecisionPatterns(projectRoot);
|
|
488
484
|
const components = loadAppMapComponents(projectRoot);
|
|
489
485
|
const config = getConfig();
|
|
@@ -601,16 +597,18 @@ ${userReason ? `**Reason**: ${userReason}` : ''}
|
|
|
601
597
|
|
|
602
598
|
/**
|
|
603
599
|
* Add a cross-session rule to decisions.md
|
|
604
|
-
*
|
|
600
|
+
* Routes through the learning orchestrator for centralized locking and dedup.
|
|
605
601
|
*/
|
|
606
602
|
function addCrossSessionRuleToDecisions(rule, category) {
|
|
607
|
-
const decisionsPath = path.join(PATHS.state, 'decisions.md');
|
|
608
|
-
|
|
609
603
|
try {
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
604
|
+
const { modifyDecisions } = require('./flow-learning-orchestrator');
|
|
605
|
+
|
|
606
|
+
// modifyDecisions is async; fire-and-forget for sync callers
|
|
607
|
+
const result = modifyDecisions((currentContent) => {
|
|
608
|
+
let content = currentContent;
|
|
609
|
+
|
|
610
|
+
if (!content) {
|
|
611
|
+
content = `# Project Decisions
|
|
614
612
|
|
|
615
613
|
This document captures project-level coding rules and patterns.
|
|
616
614
|
|
|
@@ -629,16 +627,12 @@ This document captures project-level coding rules and patterns.
|
|
|
629
627
|
## General
|
|
630
628
|
|
|
631
629
|
`;
|
|
632
|
-
writeFile(decisionsPath, template);
|
|
633
630
|
}
|
|
634
631
|
|
|
635
|
-
let content = readFile(decisionsPath, '');
|
|
636
|
-
|
|
637
632
|
const sectionHeader = `## ${category}`;
|
|
638
633
|
const sectionIndex = content.indexOf(sectionHeader);
|
|
639
634
|
|
|
640
635
|
if (sectionIndex === -1) {
|
|
641
|
-
// Category doesn't exist - add it with the rule
|
|
642
636
|
content += `\n${sectionHeader}\n\n${rule}\n`;
|
|
643
637
|
} else {
|
|
644
638
|
const afterSection = content.slice(sectionIndex + sectionHeader.length);
|
|
@@ -652,9 +646,17 @@ This document captures project-level coding rules and patterns.
|
|
|
652
646
|
}
|
|
653
647
|
}
|
|
654
648
|
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
649
|
+
return { content, entryText: rule.slice(0, 100) };
|
|
650
|
+
}, { caller: 'flow-pattern-enforcer/addCrossSessionRule' });
|
|
651
|
+
|
|
652
|
+
// Handle async result for sync callers
|
|
653
|
+
if (result && result.then) {
|
|
654
|
+
result.catch(_err => {
|
|
655
|
+
if (process.env.DEBUG) console.error(`[DEBUG] addCrossSessionRuleToDecisions: ${_err.message}`);
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
return { success: true };
|
|
658
660
|
} catch (err) {
|
|
659
661
|
return { success: false, error: err.message };
|
|
660
662
|
}
|
|
@@ -662,7 +664,7 @@ This document captures project-level coding rules and patterns.
|
|
|
662
664
|
|
|
663
665
|
/**
|
|
664
666
|
* Add a cross-session rule to .claude/rules/ directory
|
|
665
|
-
* Uses
|
|
667
|
+
* Uses PATHS.root for consistent path resolution
|
|
666
668
|
*/
|
|
667
669
|
function addCrossSessionRuleToClaudeRules(pattern, category) {
|
|
668
670
|
try {
|
|
@@ -682,14 +684,14 @@ function addCrossSessionRuleToClaudeRules(pattern, category) {
|
|
|
682
684
|
};
|
|
683
685
|
|
|
684
686
|
const subdir = categoryToDir[category] || 'general';
|
|
685
|
-
// Use
|
|
686
|
-
const rulesDir = path.join(
|
|
687
|
+
// Use PATHS.root instead of process.cwd() for consistent path resolution
|
|
688
|
+
const rulesDir = path.join(PATHS.root, '.claude', 'rules', subdir);
|
|
687
689
|
|
|
688
690
|
// Validate path is within project (defense in depth)
|
|
689
691
|
// Use path.sep check to prevent prefix-matching attacks (e.g., /project vs /project-evil)
|
|
690
692
|
const resolvedRulesDir = path.resolve(rulesDir);
|
|
691
|
-
const normalizedRoot =
|
|
692
|
-
if (!resolvedRulesDir.startsWith(normalizedRoot) && resolvedRulesDir !==
|
|
693
|
+
const normalizedRoot = PATHS.root.endsWith(path.sep) ? PATHS.root : PATHS.root + path.sep;
|
|
694
|
+
if (!resolvedRulesDir.startsWith(normalizedRoot) && resolvedRulesDir !== PATHS.root) {
|
|
693
695
|
return { success: false, error: 'Invalid rules directory: outside project' };
|
|
694
696
|
}
|
|
695
697
|
|
|
@@ -38,7 +38,7 @@ const fs = require('node:fs');
|
|
|
38
38
|
const path = require('node:path');
|
|
39
39
|
const { execSync, execFileSync } = require('node:child_process');
|
|
40
40
|
const { resolvePatterns } = require('./flow-framework-resolver');
|
|
41
|
-
const { getProjectRoot, generateHashId, readJson } = require('./flow-utils');
|
|
41
|
+
const { getProjectRoot, generateHashId, readJson, safeJsonParse, PATHS } = require('./flow-utils');
|
|
42
42
|
|
|
43
43
|
// ============================================================================
|
|
44
44
|
// Constants
|
|
@@ -217,9 +217,8 @@ function detectFramework(projectRoot) {
|
|
|
217
217
|
|
|
218
218
|
if (fs.existsSync(packageJsonPath)) {
|
|
219
219
|
try {
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
if (!pkg || typeof pkg !== 'object' || Array.isArray(pkg)) return null;
|
|
220
|
+
const pkg = safeJsonParse(packageJsonPath, null);
|
|
221
|
+
if (!pkg) return null;
|
|
223
222
|
const deps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) };
|
|
224
223
|
|
|
225
224
|
// Check for frameworks
|
package/scripts/flow-pending.js
CHANGED
|
@@ -20,7 +20,7 @@ const fs = require('node:fs');
|
|
|
20
20
|
const path = require('node:path');
|
|
21
21
|
const {
|
|
22
22
|
getProjectRoot,
|
|
23
|
-
safeJsonParse
|
|
23
|
+
safeJsonParse, PATHS
|
|
24
24
|
} = require('./flow-utils')
|
|
25
25
|
const { color, printHeader, printSection, success } = require('./flow-output');;
|
|
26
26
|
|
|
@@ -28,8 +28,7 @@ const { color, printHeader, printSection, success } = require('./flow-output');;
|
|
|
28
28
|
// Configuration
|
|
29
29
|
// ============================================================
|
|
30
30
|
|
|
31
|
-
const
|
|
32
|
-
const PERMISSIONS_PATH = path.join(PROJECT_ROOT, '.workflow', 'state', 'permissions.json');
|
|
31
|
+
const PERMISSIONS_PATH = path.join(PATHS.state, 'permissions.json');
|
|
33
32
|
|
|
34
33
|
// In-memory session permissions (cleared on process exit or explicit clear)
|
|
35
34
|
const sessionPermissions = new Map();
|
|
@@ -26,7 +26,7 @@ const {
|
|
|
26
26
|
fileExists,
|
|
27
27
|
isPathWithinProject,
|
|
28
28
|
color,
|
|
29
|
-
printHeader
|
|
29
|
+
printHeader, PATHS
|
|
30
30
|
} = require('./flow-utils');
|
|
31
31
|
|
|
32
32
|
// Dangerous keys that must never be used as plugin names or metadata keys
|
|
@@ -41,8 +41,6 @@ const VALID_FLOW_PHASES = new Set(['exploring', 'coding', 'validating', 'complet
|
|
|
41
41
|
// Configuration
|
|
42
42
|
// ============================================================
|
|
43
43
|
|
|
44
|
-
const PROJECT_ROOT = getProjectRoot();
|
|
45
|
-
|
|
46
44
|
/**
|
|
47
45
|
* Get plugin config from workflow config
|
|
48
46
|
* @returns {Object} Plugin configuration
|
|
@@ -68,10 +66,10 @@ function getPluginConfig() {
|
|
|
68
66
|
function getRegistryPath() {
|
|
69
67
|
const pluginConfig = getPluginConfig();
|
|
70
68
|
const registryRelPath = pluginConfig.registryPath || '.workflow/state/plugin-registry.json';
|
|
71
|
-
const resolved = path.resolve(
|
|
69
|
+
const resolved = path.resolve(PATHS.root, registryRelPath);
|
|
72
70
|
if (!isPathWithinProject(resolved)) {
|
|
73
71
|
console.error(`[plugin-registry] Unsafe registryPath in config: ${registryRelPath}`);
|
|
74
|
-
return path.join(
|
|
72
|
+
return path.join(PATHS.state, 'plugin-registry.json');
|
|
75
73
|
}
|
|
76
74
|
return resolved;
|
|
77
75
|
}
|
|
@@ -134,8 +132,8 @@ function discoverMcpTools(pluginName) {
|
|
|
134
132
|
|
|
135
133
|
// Strategy 1: Check Claude Code's MCP settings for matching servers
|
|
136
134
|
const settingsLocations = [
|
|
137
|
-
path.join(
|
|
138
|
-
path.join(
|
|
135
|
+
path.join(PATHS.root, '.claude', 'settings.local.json'),
|
|
136
|
+
path.join(PATHS.root, '.claude', 'settings.json')
|
|
139
137
|
];
|
|
140
138
|
|
|
141
139
|
for (const settingsPath of settingsLocations) {
|
|
@@ -163,7 +161,7 @@ function discoverMcpTools(pluginName) {
|
|
|
163
161
|
}
|
|
164
162
|
|
|
165
163
|
// Strategy 2: Check cached MCP tools from flow-mcp-docs
|
|
166
|
-
const mcpCachePath = path.join(
|
|
164
|
+
const mcpCachePath = path.join(PATHS.state, 'mcp-tools.json');
|
|
167
165
|
if (fileExists(mcpCachePath)) {
|
|
168
166
|
try {
|
|
169
167
|
const mcpCache = safeJsonParse(mcpCachePath, { allTools: [] });
|
|
@@ -210,8 +208,8 @@ function scanUnregisteredMcpServers() {
|
|
|
210
208
|
const seen = new Set(); // Dedup across multiple settings files
|
|
211
209
|
|
|
212
210
|
const settingsLocations = [
|
|
213
|
-
path.join(
|
|
214
|
-
path.join(
|
|
211
|
+
path.join(PATHS.root, '.claude', 'settings.local.json'),
|
|
212
|
+
path.join(PATHS.root, '.claude', 'settings.json')
|
|
215
213
|
];
|
|
216
214
|
|
|
217
215
|
// Internal/built-in servers that should not be auto-registered as plugins
|
|
@@ -263,8 +261,8 @@ function scanUnregisteredMcpServers() {
|
|
|
263
261
|
function deactivateStaleMcpPlugins() {
|
|
264
262
|
const registry = readRegistry();
|
|
265
263
|
const settingsLocations = [
|
|
266
|
-
path.join(
|
|
267
|
-
path.join(
|
|
264
|
+
path.join(PATHS.root, '.claude', 'settings.local.json'),
|
|
265
|
+
path.join(PATHS.root, '.claude', 'settings.json')
|
|
268
266
|
];
|
|
269
267
|
|
|
270
268
|
const availableServers = new Set();
|
package/scripts/flow-progress.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Provides visual feedback during hybrid execution.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
const readline = require('node:readline');
|
|
9
|
+
const readline = require('node:readline/promises');
|
|
10
10
|
const { colors } = require('./flow-utils');
|
|
11
11
|
|
|
12
12
|
const symbols = {
|
|
@@ -230,12 +230,9 @@ async function prompt(question) {
|
|
|
230
230
|
output: process.stdout
|
|
231
231
|
});
|
|
232
232
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
resolve(answer.trim());
|
|
237
|
-
});
|
|
238
|
-
});
|
|
233
|
+
const answer = await rl.question(question);
|
|
234
|
+
rl.close();
|
|
235
|
+
return answer.trim();
|
|
239
236
|
}
|
|
240
237
|
|
|
241
238
|
function formatResults(results) {
|
|
@@ -288,14 +285,15 @@ if (require.main === module) {
|
|
|
288
285
|
|
|
289
286
|
const spinner = new Spinner('Detecting providers...');
|
|
290
287
|
spinner.start();
|
|
291
|
-
|
|
288
|
+
const { setTimeout: sleep } = require('node:timers/promises');
|
|
289
|
+
await sleep(2000);
|
|
292
290
|
spinner.stop('Providers detected', true);
|
|
293
291
|
|
|
294
292
|
console.log('\nProgress bar:');
|
|
295
293
|
const bar = new ProgressBar(10);
|
|
296
294
|
for (let i = 0; i <= 10; i++) {
|
|
297
295
|
bar.update(i, `Step ${i}/10`);
|
|
298
|
-
await
|
|
296
|
+
await sleep(200);
|
|
299
297
|
}
|
|
300
298
|
bar.complete('All steps done');
|
|
301
299
|
|
|
@@ -29,7 +29,7 @@ const {
|
|
|
29
29
|
printHeader,
|
|
30
30
|
printSection,
|
|
31
31
|
isPathWithinProject,
|
|
32
|
-
estimateTokens
|
|
32
|
+
estimateTokens, PATHS
|
|
33
33
|
} = require('./flow-utils');
|
|
34
34
|
|
|
35
35
|
// Smart Context System integration
|
|
@@ -49,8 +49,8 @@ try {
|
|
|
49
49
|
// Constants
|
|
50
50
|
// ============================================================
|
|
51
51
|
|
|
52
|
-
const FRAGMENTS_DIR = path.join(
|
|
53
|
-
const COMPOSED_DIR = path.join(
|
|
52
|
+
const FRAGMENTS_DIR = path.join(PATHS.workflow, 'prompts', 'fragments');
|
|
53
|
+
const COMPOSED_DIR = path.join(PATHS.workflow, 'prompts', 'composed');
|
|
54
54
|
|
|
55
55
|
// Model to CLI mapping (Claude Code only)
|
|
56
56
|
const MODEL_CLI_MAP = {
|
|
@@ -25,7 +25,7 @@ const {
|
|
|
25
25
|
// Constants
|
|
26
26
|
// ============================================================
|
|
27
27
|
|
|
28
|
-
const TEMPLATES_DIR =
|
|
28
|
+
const TEMPLATES_DIR = PATHS.templatesPrompts;
|
|
29
29
|
|
|
30
30
|
// Model family to template file mapping
|
|
31
31
|
const MODEL_TEMPLATE_MAP = {
|
|
@@ -387,7 +387,7 @@ function getAgentModel(taskType, options = {}) {
|
|
|
387
387
|
* @returns {number} Score 0-10, or 0 if not found
|
|
388
388
|
*/
|
|
389
389
|
function getCapabilityScore(modelFamily, taskType) {
|
|
390
|
-
const capDir =
|
|
390
|
+
const capDir = PATHS.modelCapabilities;
|
|
391
391
|
|
|
392
392
|
// Map model family to capability file
|
|
393
393
|
const fileMap = {
|
|
@@ -24,12 +24,9 @@ const fs = require('node:fs');
|
|
|
24
24
|
const path = require('node:path');
|
|
25
25
|
const https = require('node:https');
|
|
26
26
|
const http = require('node:http');
|
|
27
|
-
const { getProjectRoot, getConfig, colors: c, estimateTokens } = require('./flow-utils');
|
|
27
|
+
const { getProjectRoot, getConfig, colors: c, estimateTokens, PATHS } = require('./flow-utils');
|
|
28
28
|
const { success: printSuccess, error: printError } = require('./flow-output');
|
|
29
29
|
|
|
30
|
-
const PROJECT_ROOT = getProjectRoot();
|
|
31
|
-
const WORKFLOW_DIR = path.join(PROJECT_ROOT, '.workflow');
|
|
32
|
-
|
|
33
30
|
/**
|
|
34
31
|
* Provider types
|
|
35
32
|
*/
|
|
@@ -918,6 +915,12 @@ async function detectProviders() {
|
|
|
918
915
|
// Not available
|
|
919
916
|
}
|
|
920
917
|
|
|
918
|
+
// NOTE: When CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1 (Claude Code 2.1.83+), cloud provider
|
|
919
|
+
// API keys are stripped from subprocess environments. Since hybrid mode invokes this
|
|
920
|
+
// script via the Bash tool (a subprocess), no cloud providers will be detected.
|
|
921
|
+
// Workaround: pass API keys via config.json hybrid.providers[].apiKey instead of env vars.
|
|
922
|
+
// Local providers (Ollama, LM Studio) are unaffected (they use localhost HTTP, no keys).
|
|
923
|
+
|
|
921
924
|
// Check Anthropic (cloud - if key present)
|
|
922
925
|
if (process.env.ANTHROPIC_API_KEY) {
|
|
923
926
|
available.push({
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
'use strict';
|
|
4
|
-
|
|
5
3
|
/**
|
|
6
4
|
* Wogi Flow - Registry Manager
|
|
7
5
|
*
|
|
@@ -18,12 +16,9 @@
|
|
|
18
16
|
|
|
19
17
|
const fs = require('node:fs');
|
|
20
18
|
const path = require('node:path');
|
|
21
|
-
const { getProjectRoot, getConfig, safeJsonParse, color, success, warn, error, info } = require('./flow-utils');
|
|
19
|
+
const { getProjectRoot, getConfig, safeJsonParse, color, success, warn, error, info, PATHS } = require('./flow-utils');
|
|
22
20
|
|
|
23
|
-
const
|
|
24
|
-
const WORKFLOW_DIR = path.join(PROJECT_ROOT, '.workflow');
|
|
25
|
-
const STATE_DIR = path.join(WORKFLOW_DIR, 'state');
|
|
26
|
-
const MANIFEST_PATH = path.join(STATE_DIR, 'registry-manifest.json');
|
|
21
|
+
const MANIFEST_PATH = path.join(PATHS.state, 'registry-manifest.json');
|
|
27
22
|
const REGISTRIES_DIR = path.join(__dirname, 'registries');
|
|
28
23
|
|
|
29
24
|
// ============================================================
|
|
@@ -268,7 +263,7 @@ class RegistryManager {
|
|
|
268
263
|
// Detect stack
|
|
269
264
|
try {
|
|
270
265
|
const { detectStack } = require('./flow-context-init');
|
|
271
|
-
this.stack = detectStack(
|
|
266
|
+
this.stack = detectStack(PATHS.root);
|
|
272
267
|
} catch (err) {
|
|
273
268
|
this.stack = null;
|
|
274
269
|
}
|
|
@@ -355,7 +350,7 @@ class RegistryManager {
|
|
|
355
350
|
};
|
|
356
351
|
|
|
357
352
|
try {
|
|
358
|
-
fs.mkdirSync(
|
|
353
|
+
fs.mkdirSync(PATHS.state, { recursive: true });
|
|
359
354
|
fs.writeFileSync(MANIFEST_PATH, JSON.stringify(manifest, null, 2));
|
|
360
355
|
} catch (err) {
|
|
361
356
|
warn(`Failed to write manifest: ${err.message}`);
|
|
@@ -440,7 +435,7 @@ function printStatus(manager) {
|
|
|
440
435
|
if (fs.existsSync(MANIFEST_PATH)) {
|
|
441
436
|
try {
|
|
442
437
|
const manifest = safeJsonParse(MANIFEST_PATH, {});
|
|
443
|
-
console.log(` Manifest: ${path.relative(
|
|
438
|
+
console.log(` Manifest: ${path.relative(PATHS.root, MANIFEST_PATH)}`);
|
|
444
439
|
console.log(` Generated: ${manifest.generatedAt || 'unknown'}`);
|
|
445
440
|
console.log(` Version: ${manifest.version || 'unknown'}`);
|
|
446
441
|
console.log(` Registries: ${(manifest.registries || []).length}`);
|
|
@@ -482,7 +477,7 @@ async function main() {
|
|
|
482
477
|
}
|
|
483
478
|
|
|
484
479
|
console.log('');
|
|
485
|
-
success(`Manifest saved to ${path.relative(
|
|
480
|
+
success(`Manifest saved to ${path.relative(PATHS.root, MANIFEST_PATH)}`);
|
|
486
481
|
console.log('');
|
|
487
482
|
break;
|
|
488
483
|
}
|
|
@@ -493,7 +488,7 @@ async function main() {
|
|
|
493
488
|
|
|
494
489
|
case 'manifest':
|
|
495
490
|
manager.generateManifest();
|
|
496
|
-
success(`Manifest saved to ${path.relative(
|
|
491
|
+
success(`Manifest saved to ${path.relative(PATHS.root, MANIFEST_PATH)}`);
|
|
497
492
|
break;
|
|
498
493
|
|
|
499
494
|
case 'status':
|
|
@@ -17,12 +17,10 @@
|
|
|
17
17
|
const fs = require('node:fs');
|
|
18
18
|
const path = require('node:path');
|
|
19
19
|
const { execFileSync } = require('node:child_process');
|
|
20
|
-
const { getProjectRoot, colors, getConfig, safeJsonParse } = require('./flow-utils');
|
|
20
|
+
const { getProjectRoot, colors, getConfig, safeJsonParse, PATHS } = require('./flow-utils');
|
|
21
21
|
const { getExecParts, getCommand } = require('./flow-script-resolver');
|
|
22
22
|
|
|
23
|
-
const
|
|
24
|
-
const STATE_DIR = path.join(PROJECT_ROOT, '.workflow', 'state');
|
|
25
|
-
const READY_PATH = path.join(STATE_DIR, 'ready.json');
|
|
23
|
+
const READY_PATH = PATHS.ready;
|
|
26
24
|
const SAFE_PATH = /^[a-zA-Z0-9_.\-/]+$/;
|
|
27
25
|
|
|
28
26
|
function log(color, ...args) {
|
|
@@ -56,8 +54,8 @@ function findTestFiles(taskId, taskData) {
|
|
|
56
54
|
if (taskData?.testFiles) {
|
|
57
55
|
for (const tf of taskData.testFiles) {
|
|
58
56
|
if (typeof tf === 'string' && SAFE_PATH.test(tf) && !tf.includes('..')) {
|
|
59
|
-
const resolved = path.resolve(
|
|
60
|
-
if (resolved.startsWith(
|
|
57
|
+
const resolved = path.resolve(PATHS.root, tf);
|
|
58
|
+
if (resolved.startsWith(PATHS.root + path.sep) || resolved === PATHS.root) {
|
|
61
59
|
testFiles.push(tf);
|
|
62
60
|
}
|
|
63
61
|
}
|
|
@@ -80,14 +78,14 @@ function findTestFiles(taskId, taskData) {
|
|
|
80
78
|
];
|
|
81
79
|
|
|
82
80
|
for (const pattern of testPatterns) {
|
|
83
|
-
if (fs.existsSync(path.join(
|
|
81
|
+
if (fs.existsSync(path.join(PATHS.root, pattern))) {
|
|
84
82
|
testFiles.push(pattern);
|
|
85
83
|
}
|
|
86
84
|
}
|
|
87
85
|
}
|
|
88
86
|
|
|
89
87
|
// Also look in request-log for files changed
|
|
90
|
-
const logPath =
|
|
88
|
+
const logPath = PATHS.requestLog;
|
|
91
89
|
if (fs.existsSync(logPath)) {
|
|
92
90
|
let logContent;
|
|
93
91
|
try {
|
|
@@ -111,7 +109,7 @@ function findTestFiles(taskId, taskData) {
|
|
|
111
109
|
`${base}.spec${ext}`,
|
|
112
110
|
];
|
|
113
111
|
for (const pattern of testPatterns) {
|
|
114
|
-
if (fs.existsSync(path.join(
|
|
112
|
+
if (fs.existsSync(path.join(PATHS.root, pattern))) {
|
|
115
113
|
testFiles.push(pattern);
|
|
116
114
|
}
|
|
117
115
|
}
|
|
@@ -147,7 +145,7 @@ function runTaskTests(taskId, taskData) {
|
|
|
147
145
|
}
|
|
148
146
|
const { cmd, args } = runner;
|
|
149
147
|
execFileSync(cmd, args, {
|
|
150
|
-
cwd:
|
|
148
|
+
cwd: PATHS.root,
|
|
151
149
|
stdio: 'pipe',
|
|
152
150
|
timeout: 60000 // 1 minute timeout per task
|
|
153
151
|
});
|
|
@@ -173,7 +171,7 @@ function runTaskTests(taskId, taskData) {
|
|
|
173
171
|
* @returns {{ cmd: string, args: string[] }}
|
|
174
172
|
*/
|
|
175
173
|
function detectTestRunner(testFiles) {
|
|
176
|
-
const packageJson = path.join(
|
|
174
|
+
const packageJson = path.join(PATHS.root, 'package.json');
|
|
177
175
|
|
|
178
176
|
if (fs.existsSync(packageJson)) {
|
|
179
177
|
try {
|
package/scripts/flow-roadmap.js
CHANGED
|
@@ -46,7 +46,7 @@ const MIN_ITEM_TITLE_LENGTH = 2; // Minimum length for a valid item title
|
|
|
46
46
|
// Paths
|
|
47
47
|
// Note: .workflow/roadmap.md is for USER project roadmaps managed by this module.
|
|
48
48
|
// WogiFlow's own internal roadmap is at .workflow/roadmap/roadmap.md (separate file).
|
|
49
|
-
const ROADMAP_PATH = path.join(
|
|
49
|
+
const ROADMAP_PATH = path.join(PATHS.workflow, 'roadmap.md');
|
|
50
50
|
const TEMPLATE_PATH = path.join(__dirname, '..', 'templates', 'roadmap.md');
|
|
51
51
|
|
|
52
52
|
// ============================================================
|
|
@@ -487,7 +487,7 @@ function validateItem(item) {
|
|
|
487
487
|
|
|
488
488
|
// Check if dependency is in ready.json as completed
|
|
489
489
|
let inReadyCompleted = false;
|
|
490
|
-
const readyPath =
|
|
490
|
+
const readyPath = PATHS.ready;
|
|
491
491
|
if (fileExists(readyPath)) {
|
|
492
492
|
const ready = safeJsonParse(readyPath, {});
|
|
493
493
|
const completed = ready.recentlyCompleted || [];
|
|
@@ -18,14 +18,12 @@
|
|
|
18
18
|
|
|
19
19
|
const fs = require('node:fs');
|
|
20
20
|
const path = require('node:path');
|
|
21
|
-
const { readJson } = require('./flow-io');
|
|
21
|
+
const { readJson, safeJsonParse, safeJsonParseString } = require('./flow-io');
|
|
22
22
|
const crypto = require('node:crypto');
|
|
23
|
-
const { getProjectRoot, colors: c } = require('./flow-utils');
|
|
23
|
+
const { getProjectRoot, colors: c, PATHS } = require('./flow-utils');
|
|
24
24
|
const { success: printSuccess } = require('./flow-output');
|
|
25
25
|
|
|
26
|
-
const
|
|
27
|
-
const WORKFLOW_DIR = path.join(PROJECT_ROOT, '.workflow');
|
|
28
|
-
const RUNS_DIR = path.join(WORKFLOW_DIR, 'runs');
|
|
26
|
+
const RUNS_DIR = PATHS.runs;
|
|
29
27
|
|
|
30
28
|
// Event types
|
|
31
29
|
const EVENT_TYPES = {
|
|
@@ -282,16 +280,17 @@ function endRun(runId, status = 'completed') {
|
|
|
282
280
|
*/
|
|
283
281
|
function generateSummary(runId) {
|
|
284
282
|
const runDir = path.join(RUNS_DIR, runId);
|
|
285
|
-
const manifest =
|
|
286
|
-
|
|
287
|
-
|
|
283
|
+
const manifest = safeJsonParse(path.join(runDir, 'manifest.json'), null);
|
|
284
|
+
if (!manifest) return;
|
|
285
|
+
|
|
288
286
|
const tracePath = path.join(runDir, 'trace.jsonl');
|
|
289
287
|
|
|
290
288
|
const events = fs.existsSync(tracePath)
|
|
291
289
|
? fs.readFileSync(tracePath, 'utf-8')
|
|
292
290
|
.split('\n')
|
|
293
291
|
.filter(line => line.trim())
|
|
294
|
-
.map(line =>
|
|
292
|
+
.map(line => safeJsonParseString(line, null))
|
|
293
|
+
.filter(Boolean)
|
|
295
294
|
: [];
|
|
296
295
|
|
|
297
296
|
const durationSec = manifest.durationMs
|
|
@@ -421,7 +420,7 @@ function updateIndex(runId, manifest) {
|
|
|
421
420
|
});
|
|
422
421
|
|
|
423
422
|
// Load config for retention settings
|
|
424
|
-
const configPath = path.join(
|
|
423
|
+
const configPath = path.join(PATHS.workflow, 'config.json');
|
|
425
424
|
const config = readJson(configPath, {});
|
|
426
425
|
const maxRuns = config.traces?.runs?.maxRuns || 100;
|
|
427
426
|
|
|
@@ -453,16 +452,18 @@ function inspectRun(runId) {
|
|
|
453
452
|
throw new Error(`Run not found: ${runId}`);
|
|
454
453
|
}
|
|
455
454
|
|
|
456
|
-
const manifest =
|
|
457
|
-
|
|
458
|
-
|
|
455
|
+
const manifest = safeJsonParse(path.join(runDir, 'manifest.json'), null);
|
|
456
|
+
if (!manifest) {
|
|
457
|
+
throw new Error(`Could not read manifest for run: ${runId}`);
|
|
458
|
+
}
|
|
459
459
|
|
|
460
460
|
const tracePath = path.join(runDir, 'trace.jsonl');
|
|
461
461
|
const events = fs.existsSync(tracePath)
|
|
462
462
|
? fs.readFileSync(tracePath, 'utf-8')
|
|
463
463
|
.split('\n')
|
|
464
464
|
.filter(line => line.trim())
|
|
465
|
-
.map(line =>
|
|
465
|
+
.map(line => safeJsonParseString(line, null))
|
|
466
|
+
.filter(Boolean)
|
|
466
467
|
: [];
|
|
467
468
|
|
|
468
469
|
const summaryPath = path.join(runDir, 'summary.md');
|
|
@@ -477,7 +478,7 @@ function inspectRun(runId) {
|
|
|
477
478
|
* Cleanup old runs based on retention policy
|
|
478
479
|
*/
|
|
479
480
|
function cleanupRuns() {
|
|
480
|
-
const configPath = path.join(
|
|
481
|
+
const configPath = path.join(PATHS.workflow, 'config.json');
|
|
481
482
|
const cleanupConfig = readJson(configPath, {});
|
|
482
483
|
const retentionDays = cleanupConfig.traces?.runs?.retentionDays || 30;
|
|
483
484
|
const maxRuns = cleanupConfig.traces?.runs?.maxRuns || 100;
|
package/scripts/flow-safety.js
CHANGED
|
@@ -19,12 +19,9 @@
|
|
|
19
19
|
|
|
20
20
|
const fs = require('node:fs');
|
|
21
21
|
const path = require('node:path');
|
|
22
|
-
const { getProjectRoot, getConfig, colors: c } = require('./flow-utils');
|
|
22
|
+
const { getProjectRoot, getConfig, colors: c, PATHS } = require('./flow-utils');
|
|
23
23
|
const { success: printSuccess, error: printError } = require('./flow-output');
|
|
24
24
|
|
|
25
|
-
const PROJECT_ROOT = getProjectRoot();
|
|
26
|
-
const WORKFLOW_DIR = path.join(PROJECT_ROOT, '.workflow');
|
|
27
|
-
|
|
28
25
|
/**
|
|
29
26
|
* Custom error for safety violations
|
|
30
27
|
*/
|
|
@@ -213,7 +210,7 @@ class SafetyGuard {
|
|
|
213
210
|
|
|
214
211
|
// Normalize path
|
|
215
212
|
const normalizedPath = filePath.startsWith('/')
|
|
216
|
-
? path.relative(
|
|
213
|
+
? path.relative(PATHS.root, filePath)
|
|
217
214
|
: filePath;
|
|
218
215
|
|
|
219
216
|
// Check deny list first (takes precedence)
|