wogiflow 1.9.7 → 1.9.8
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/lib/utils.js +1 -1
- package/package.json +2 -5
- package/scripts/flow-consistency-check.js +0 -4
- package/scripts/flow-context-estimator.js +4 -20
- package/scripts/flow-correct.js +2 -1
- package/scripts/flow-decision-tracker.js +2 -2
- package/scripts/flow-done.js +4 -4
- package/scripts/flow-entropy-monitor.js +3 -24
- package/scripts/flow-export-scanner.js +3 -3
- package/scripts/flow-health.js +3 -2
- package/scripts/flow-hybrid-test.js +2 -3
- package/scripts/flow-long-input-stories.js +4 -6
- package/scripts/flow-long-input.js +5 -8
- package/scripts/flow-memory-compactor.js +1 -13
- package/scripts/flow-memory-db.js +1 -1
- package/scripts/flow-memory-sync.js +1 -17
- package/scripts/flow-orchestrate-llm.js +3 -7
- package/scripts/flow-orchestrate.js +2 -13
- package/scripts/flow-pattern-extractor.js +3 -17
- package/scripts/flow-peer-review.js +4 -12
- package/scripts/flow-plugin-registry.js +2 -2
- package/scripts/flow-project-analyzer.js +4 -4
- package/scripts/flow-providers.js +2 -7
- package/scripts/flow-safety.js +6 -10
- package/scripts/flow-script-resolver.js +4 -16
- package/scripts/flow-skill-freshness.js +3 -12
- package/scripts/flow-skill-generator.js +14 -24
- package/scripts/flow-strict-adherence.js +2 -2
- package/scripts/flow-task-analyzer.js +3 -3
- package/scripts/flow-test-discovery.js +3 -3
- package/scripts/flow-utils.js +1 -0
- package/scripts/flow-webmcp-generator.js +1 -1
- package/scripts/flow-workflow-steps.js +31 -23
- package/scripts/hooks/core/component-check.js +22 -7
- package/scripts/hooks/core/observation-capture.js +7 -4
- package/scripts/hooks/core/task-gate.js +2 -2
- package/scripts/hooks/entry/claude-code/post-tool-use.js +10 -8
- package/scripts/hooks/entry/claude-code/pre-tool-use.js +6 -40
- package/scripts/hooks/entry/claude-code/session-start.js +4 -12
- package/scripts/hooks/entry/shared/read-stdin.js +33 -0
- package/scripts/flow-done +0 -151
- package/scripts/flow-file-ops.js +0 -307
- package/scripts/flow-health +0 -185
- package/scripts/flow-ready +0 -82
- package/scripts/flow-start +0 -74
- package/scripts/flow-status +0 -110
- package/scripts/flow-story +0 -105
package/lib/utils.js
CHANGED
|
@@ -40,7 +40,7 @@ function findProjectRoot() {
|
|
|
40
40
|
/**
|
|
41
41
|
* Safely parse JSON content with prototype pollution protection
|
|
42
42
|
*
|
|
43
|
-
* Note: For parsing JSON files, use
|
|
43
|
+
* Note: For parsing JSON files, use safeJsonParse from flow-utils.js
|
|
44
44
|
* or safeReadJson from this module instead.
|
|
45
45
|
*
|
|
46
46
|
* @param {string} content - JSON string to parse
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wogiflow",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.8",
|
|
4
4
|
"description": "AI-powered development workflow management system with multi-model support",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -9,8 +9,6 @@
|
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
11
|
"flow": "./scripts/flow",
|
|
12
|
-
"test": "node mcp-memory-server/test.js",
|
|
13
|
-
"memory-server": "node mcp-memory-server/index.js",
|
|
14
12
|
"postinstall": "node scripts/postinstall.js",
|
|
15
13
|
"preuninstall": "node scripts/preuninstall.js"
|
|
16
14
|
},
|
|
@@ -58,10 +56,9 @@
|
|
|
58
56
|
},
|
|
59
57
|
"homepage": "https://github.com/Tomer-Wogi/WogiFlow#readme",
|
|
60
58
|
"dependencies": {
|
|
61
|
-
"sql.js": "^1.
|
|
59
|
+
"sql.js": "^1.14.1"
|
|
62
60
|
},
|
|
63
61
|
"optionalDependencies": {
|
|
64
|
-
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
65
62
|
"@xenova/transformers": "^2.15.0"
|
|
66
63
|
},
|
|
67
64
|
"engines": {
|
|
@@ -511,10 +511,6 @@ function runConsistencyCheck(options = {}) {
|
|
|
511
511
|
}
|
|
512
512
|
}
|
|
513
513
|
|
|
514
|
-
// TODO: Implement crossMapConsistency check (config key exists but check is not yet implemented)
|
|
515
|
-
// This would verify that components referenced in one map exist in others
|
|
516
|
-
// (e.g., a function used by a component is also in function-map)
|
|
517
|
-
|
|
518
514
|
// Determine overall status
|
|
519
515
|
const mode = consistencyConfig.mode || 'warn';
|
|
520
516
|
const orphanMode = consistencyConfig.orphanMode || 'warn';
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
const fs = require('fs');
|
|
15
15
|
const path = require('path');
|
|
16
|
-
const { getConfig, PATHS, safeJsonParse } = require('./flow-utils');
|
|
16
|
+
const { getConfig, PATHS, safeJsonParse, validateTaskId } = require('./flow-utils');
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* Default estimation config (can be overridden in config.json)
|
|
@@ -33,20 +33,6 @@ const DEFAULT_REFACTOR_KEYWORDS = [
|
|
|
33
33
|
'restructure', 'rearchitect', 'modernize', 'upgrade'
|
|
34
34
|
];
|
|
35
35
|
|
|
36
|
-
// Valid task ID pattern — enforces wf-[8 hex] format and prevents path traversal
|
|
37
|
-
// Also accepts legacy TASK-NNN/BUG-NNN and sub-tasks wf-XXXXXXXX-NN
|
|
38
|
-
const VALID_TASK_ID_PATTERN = /^(wf-[a-f0-9]{8}(-\d{2})?|(TASK|BUG)-\d{3,})$/i;
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Validate task ID format — must be wf-[8 hex chars] or legacy TASK-NNN/BUG-NNN.
|
|
42
|
-
* Also prevents path traversal attacks.
|
|
43
|
-
* @param {string} taskId - Task ID to validate
|
|
44
|
-
* @returns {boolean} True if valid
|
|
45
|
-
*/
|
|
46
|
-
function isValidTaskId(taskId) {
|
|
47
|
-
return typeof taskId === 'string' && VALID_TASK_ID_PATTERN.test(taskId);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
36
|
/**
|
|
51
37
|
* Get smart compaction config from config.json
|
|
52
38
|
* @returns {Object} Smart compaction configuration
|
|
@@ -90,7 +76,7 @@ function getSmartCompactionConfig() {
|
|
|
90
76
|
*/
|
|
91
77
|
function readSpecFile(taskId) {
|
|
92
78
|
// Validate taskId to prevent path traversal (Security Rule)
|
|
93
|
-
if (!
|
|
79
|
+
if (!validateTaskId(taskId).valid) {
|
|
94
80
|
return null;
|
|
95
81
|
}
|
|
96
82
|
|
|
@@ -476,7 +462,7 @@ if (require.main === module) {
|
|
|
476
462
|
const taskId = args[1];
|
|
477
463
|
|
|
478
464
|
// Validate taskId to prevent path traversal
|
|
479
|
-
if (!
|
|
465
|
+
if (!validateTaskId(taskId).valid) {
|
|
480
466
|
console.error(`Invalid task ID format: ${taskId}`);
|
|
481
467
|
console.error('Task IDs must contain only alphanumeric characters, hyphens, and underscores.');
|
|
482
468
|
process.exit(1);
|
|
@@ -521,7 +507,7 @@ if (require.main === module) {
|
|
|
521
507
|
const taskId = args[1];
|
|
522
508
|
|
|
523
509
|
// Validate taskId to prevent path traversal
|
|
524
|
-
if (!
|
|
510
|
+
if (!validateTaskId(taskId).valid) {
|
|
525
511
|
console.error(`Invalid task ID format: ${taskId}`);
|
|
526
512
|
console.error('Task IDs must contain only alphanumeric characters, hyphens, and underscores.');
|
|
527
513
|
process.exit(1);
|
|
@@ -775,8 +761,6 @@ module.exports = {
|
|
|
775
761
|
formatEstimationResult,
|
|
776
762
|
extractCriteriaCount,
|
|
777
763
|
extractFileCount,
|
|
778
|
-
isValidTaskId,
|
|
779
|
-
VALID_TASK_ID_PATTERN,
|
|
780
764
|
// Finding-level estimation (for review-fix sessions)
|
|
781
765
|
estimateFindingContextCost,
|
|
782
766
|
calculateDynamicBatchSize,
|
package/scripts/flow-correct.js
CHANGED
|
@@ -23,6 +23,7 @@ const {
|
|
|
23
23
|
dirExists,
|
|
24
24
|
readFile,
|
|
25
25
|
writeFile,
|
|
26
|
+
getConfig,
|
|
26
27
|
color,
|
|
27
28
|
success,
|
|
28
29
|
warn,
|
|
@@ -35,7 +36,7 @@ const {
|
|
|
35
36
|
|
|
36
37
|
function getCorrectionsDir() {
|
|
37
38
|
try {
|
|
38
|
-
const config =
|
|
39
|
+
const config = getConfig();
|
|
39
40
|
const detailPath = config?.corrections?.detailPath;
|
|
40
41
|
if (detailPath) {
|
|
41
42
|
return path.isAbsolute(detailPath) ? detailPath : path.join(PROJECT_ROOT, detailPath);
|
|
@@ -22,10 +22,10 @@
|
|
|
22
22
|
|
|
23
23
|
const fs = require('fs');
|
|
24
24
|
const path = require('path');
|
|
25
|
-
const crypto = require('crypto');
|
|
26
25
|
const {
|
|
27
26
|
PATHS,
|
|
28
27
|
getConfig,
|
|
28
|
+
generateHashId,
|
|
29
29
|
success,
|
|
30
30
|
warn,
|
|
31
31
|
error,
|
|
@@ -163,7 +163,7 @@ function recordAmendment(params) {
|
|
|
163
163
|
}
|
|
164
164
|
|
|
165
165
|
// Generate amendment record
|
|
166
|
-
const id =
|
|
166
|
+
const id = generateHashId('amend', '', '');
|
|
167
167
|
const amendment = {
|
|
168
168
|
id,
|
|
169
169
|
timestamp: new Date().toISOString(),
|
package/scripts/flow-done.js
CHANGED
|
@@ -210,7 +210,7 @@ function checkOutstandingFindings() {
|
|
|
210
210
|
*/
|
|
211
211
|
function runQualityGates(taskId, taskType) {
|
|
212
212
|
// Validate taskId before using in any path construction
|
|
213
|
-
if (taskId && !validateTaskId(taskId)) {
|
|
213
|
+
if (taskId && !validateTaskId(taskId).valid) {
|
|
214
214
|
console.log(color('red', `Invalid task ID format: ${String(taskId).slice(0, 30)}`));
|
|
215
215
|
return { passed: false, failed: ['invalidTaskId'], errors: { invalidTaskId: 'Task ID failed validation' } };
|
|
216
216
|
}
|
|
@@ -670,7 +670,7 @@ function runQualityGates(taskId, taskType) {
|
|
|
670
670
|
}
|
|
671
671
|
} else if (gate === 'generatedTestsPass') {
|
|
672
672
|
if (config.testing?.enabled && config.testing?.generation?.autoGenerate) {
|
|
673
|
-
if (!validateTaskId(taskId)) {
|
|
673
|
+
if (!validateTaskId(taskId).valid) {
|
|
674
674
|
console.log(` ${color('yellow', '⚠')} generatedTestsPass (invalid task ID)`);
|
|
675
675
|
} else {
|
|
676
676
|
const testDir = path.join(PATHS.workflow, 'tests', 'generated', taskId);
|
|
@@ -727,7 +727,7 @@ function runQualityGates(taskId, taskType) {
|
|
|
727
727
|
const gateModes = isUI ? ['ui', 'full', 'auto'] : ['api', 'full', 'auto'];
|
|
728
728
|
const testingMode = config.testing?.mode || 'off';
|
|
729
729
|
if (config.testing?.enabled && gateModes.includes(testingMode)) {
|
|
730
|
-
if (!validateTaskId(taskId)) {
|
|
730
|
+
if (!validateTaskId(taskId).valid) {
|
|
731
731
|
console.log(` ${color('yellow', '⚠')} ${gate} (invalid task ID)`);
|
|
732
732
|
} else {
|
|
733
733
|
try {
|
|
@@ -778,7 +778,7 @@ function runQualityGates(taskId, taskType) {
|
|
|
778
778
|
}
|
|
779
779
|
|
|
780
780
|
// Also check scenario verification results if available
|
|
781
|
-
if (!isUI && validateTaskId(taskId)) {
|
|
781
|
+
if (!isUI && validateTaskId(taskId).valid) {
|
|
782
782
|
const scenarioReportPath = path.join(PATHS.workflow, 'verifications', `${taskId}-scenarios.json`);
|
|
783
783
|
if (fs.existsSync(scenarioReportPath)) {
|
|
784
784
|
try {
|
|
@@ -17,40 +17,19 @@
|
|
|
17
17
|
const fs = require('fs');
|
|
18
18
|
const path = require('path');
|
|
19
19
|
const memoryDb = require('./flow-memory-db');
|
|
20
|
+
const { getConfig } = require('./flow-config-loader');
|
|
21
|
+
const { color } = require('./flow-output');
|
|
20
22
|
|
|
21
23
|
// ============================================================
|
|
22
24
|
// Configuration
|
|
23
25
|
// ============================================================
|
|
24
26
|
|
|
25
27
|
const PROJECT_ROOT = process.env.WOGI_PROJECT_ROOT || process.cwd();
|
|
26
|
-
const CONFIG_PATH = path.join(PROJECT_ROOT, '.workflow', 'config.json');
|
|
27
|
-
|
|
28
|
-
function loadConfig() {
|
|
29
|
-
try {
|
|
30
|
-
if (fs.existsSync(CONFIG_PATH)) {
|
|
31
|
-
return JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf-8'));
|
|
32
|
-
}
|
|
33
|
-
} catch {}
|
|
34
|
-
return {};
|
|
35
|
-
}
|
|
36
28
|
|
|
37
29
|
// ============================================================
|
|
38
30
|
// Output Formatting
|
|
39
31
|
// ============================================================
|
|
40
32
|
|
|
41
|
-
function color(c, text) {
|
|
42
|
-
const colors = {
|
|
43
|
-
red: '\x1b[31m',
|
|
44
|
-
green: '\x1b[32m',
|
|
45
|
-
yellow: '\x1b[33m',
|
|
46
|
-
blue: '\x1b[34m',
|
|
47
|
-
cyan: '\x1b[36m',
|
|
48
|
-
gray: '\x1b[90m',
|
|
49
|
-
reset: '\x1b[0m'
|
|
50
|
-
};
|
|
51
|
-
return `${colors[c] || ''}${text}${colors.reset}`;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
33
|
function formatEntropy(entropy) {
|
|
55
34
|
if (entropy < 0.4) return color('green', `${entropy} (healthy)`);
|
|
56
35
|
if (entropy < 0.7) return color('yellow', `${entropy} (moderate)`);
|
|
@@ -299,7 +278,7 @@ async function showPromotionCandidates(config) {
|
|
|
299
278
|
|
|
300
279
|
async function main() {
|
|
301
280
|
const args = process.argv.slice(2);
|
|
302
|
-
const config =
|
|
281
|
+
const config = getConfig();
|
|
303
282
|
|
|
304
283
|
try {
|
|
305
284
|
if (args.includes('--auto')) {
|
|
@@ -16,10 +16,10 @@
|
|
|
16
16
|
|
|
17
17
|
const fs = require('fs');
|
|
18
18
|
const path = require('path');
|
|
19
|
-
const {
|
|
19
|
+
const { PATHS, getConfig } = require('./flow-utils');
|
|
20
20
|
|
|
21
|
-
// Default to
|
|
22
|
-
let PROJECT_ROOT =
|
|
21
|
+
// Default to PATHS.root from flow-utils, can be overridden via setProjectRoot() or CLI arg
|
|
22
|
+
let PROJECT_ROOT = PATHS.root;
|
|
23
23
|
let CONFIG_PATH = path.join(PROJECT_ROOT, '.workflow/config.json');
|
|
24
24
|
let CACHE_PATH = path.join(PROJECT_ROOT, '.workflow/state/export-map.json');
|
|
25
25
|
const CACHE_MAX_AGE_MS = 5 * 60 * 1000; // 5 minutes
|
package/scripts/flow-health.js
CHANGED
|
@@ -38,7 +38,8 @@ const {
|
|
|
38
38
|
checkSpecMigration,
|
|
39
39
|
safeJsonParse,
|
|
40
40
|
meetsVersion,
|
|
41
|
-
getFdCommand
|
|
41
|
+
getFdCommand,
|
|
42
|
+
getConfig
|
|
42
43
|
} = require('./flow-utils');
|
|
43
44
|
|
|
44
45
|
const { execSync, execFileSync } = require('child_process');
|
|
@@ -128,7 +129,7 @@ function main() {
|
|
|
128
129
|
let cliType = 'claude-code'; // default
|
|
129
130
|
if (fileExists(PATHS.config)) {
|
|
130
131
|
try {
|
|
131
|
-
const config =
|
|
132
|
+
const config = getConfig();
|
|
132
133
|
cliType = config.cli?.type || 'claude-code';
|
|
133
134
|
} catch {}
|
|
134
135
|
}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
const fs = require('fs');
|
|
10
10
|
const path = require('path');
|
|
11
11
|
const { spawnSync } = require('child_process');
|
|
12
|
-
const { getProjectRoot } = require('./flow-utils');
|
|
12
|
+
const { getProjectRoot, getConfig } = require('./flow-utils');
|
|
13
13
|
|
|
14
14
|
const PROJECT_ROOT = getProjectRoot();
|
|
15
15
|
const TESTS = [];
|
|
@@ -52,8 +52,7 @@ test('Config file exists', () => {
|
|
|
52
52
|
});
|
|
53
53
|
|
|
54
54
|
test('Config has hybrid section', () => {
|
|
55
|
-
const
|
|
56
|
-
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
55
|
+
const config = getConfig();
|
|
57
56
|
if (!config.hybrid) {
|
|
58
57
|
throw new Error('hybrid section missing from config');
|
|
59
58
|
}
|
|
@@ -13,10 +13,8 @@
|
|
|
13
13
|
|
|
14
14
|
const fs = require('fs');
|
|
15
15
|
const path = require('path');
|
|
16
|
-
const crypto = require('crypto');
|
|
17
|
-
|
|
18
16
|
// Import safe utilities
|
|
19
|
-
const { safeJsonParse, writeJson, generateTaskId, withLock, PATHS } = require('./flow-utils');
|
|
17
|
+
const { safeJsonParse, writeJson, generateTaskId, generateHashId, withLock, PATHS } = require('./flow-utils');
|
|
20
18
|
|
|
21
19
|
// Utility: ISO timestamp
|
|
22
20
|
function now() {
|
|
@@ -95,7 +93,7 @@ const SCENARIO_PATTERNS = [
|
|
|
95
93
|
* Generate unique story ID
|
|
96
94
|
*/
|
|
97
95
|
function generateStoryId() {
|
|
98
|
-
return 'story
|
|
96
|
+
return generateHashId('story', '', '');
|
|
99
97
|
}
|
|
100
98
|
|
|
101
99
|
/**
|
|
@@ -1063,14 +1061,14 @@ function resetPresentation() {
|
|
|
1063
1061
|
* Generate unique edit session ID
|
|
1064
1062
|
*/
|
|
1065
1063
|
function generateEditSessionId() {
|
|
1066
|
-
return 'edit
|
|
1064
|
+
return generateHashId('edit', '', '');
|
|
1067
1065
|
}
|
|
1068
1066
|
|
|
1069
1067
|
/**
|
|
1070
1068
|
* Generate unique change ID
|
|
1071
1069
|
*/
|
|
1072
1070
|
function generateChangeId() {
|
|
1073
|
-
return 'change
|
|
1071
|
+
return generateHashId('change', '', '');
|
|
1074
1072
|
}
|
|
1075
1073
|
|
|
1076
1074
|
/**
|
|
@@ -15,8 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
const fs = require('fs');
|
|
17
17
|
const path = require('path');
|
|
18
|
-
const
|
|
19
|
-
const { estimateTokens } = require('./flow-utils');
|
|
18
|
+
const { estimateTokens, generateHashId, getConfig } = require('./flow-utils');
|
|
20
19
|
|
|
21
20
|
// Import extracted modules (renamed from transcript-* to long-input-*)
|
|
22
21
|
const transcriptParsing = require('./flow-long-input-parsing');
|
|
@@ -106,8 +105,6 @@ const {
|
|
|
106
105
|
const TMP_DIR = path.join(process.cwd(), '.workflow', 'tmp', 'long-input');
|
|
107
106
|
const STATE_DIR = TMP_DIR; // Alias for backward compatibility during migration
|
|
108
107
|
const ACTIVE_DIGEST_FILE = path.join(TMP_DIR, 'active-digest.json');
|
|
109
|
-
const CONFIG_FILE = path.join(process.cwd(), '.workflow', 'config.json');
|
|
110
|
-
|
|
111
108
|
// Colors for CLI output
|
|
112
109
|
const c = {
|
|
113
110
|
reset: '\x1b[0m',
|
|
@@ -124,7 +121,7 @@ const c = {
|
|
|
124
121
|
*/
|
|
125
122
|
function loadConfig() {
|
|
126
123
|
try {
|
|
127
|
-
const config =
|
|
124
|
+
const config = getConfig();
|
|
128
125
|
return config.longInputGate || config.transcriptDigestion || {};
|
|
129
126
|
} catch (_err) {
|
|
130
127
|
return {};
|
|
@@ -135,7 +132,7 @@ function loadConfig() {
|
|
|
135
132
|
* Generate unique digest ID
|
|
136
133
|
*/
|
|
137
134
|
function generateDigestId() {
|
|
138
|
-
return 'digest
|
|
135
|
+
return generateHashId('digest', '', '');
|
|
139
136
|
}
|
|
140
137
|
|
|
141
138
|
/**
|
|
@@ -860,7 +857,7 @@ function resolveOrphan(orphan, topics) {
|
|
|
860
857
|
function createTopicFromOrphans(orphans, _existingTopics) {
|
|
861
858
|
// Guard against empty orphans array
|
|
862
859
|
if (!orphans || orphans.length === 0) {
|
|
863
|
-
const topicId = 't-auto
|
|
860
|
+
const topicId = generateHashId('t-auto', '', '');
|
|
864
861
|
return {
|
|
865
862
|
id: topicId,
|
|
866
863
|
title: 'Miscellaneous',
|
|
@@ -875,7 +872,7 @@ function createTopicFromOrphans(orphans, _existingTopics) {
|
|
|
875
872
|
};
|
|
876
873
|
}
|
|
877
874
|
|
|
878
|
-
const topicId = 't-auto
|
|
875
|
+
const topicId = generateHashId('t-auto', '', '');
|
|
879
876
|
|
|
880
877
|
// Extract common keywords from orphans
|
|
881
878
|
const allWords = orphans.flatMap(o =>
|
|
@@ -20,6 +20,7 @@ const fs = require('fs');
|
|
|
20
20
|
const path = require('path');
|
|
21
21
|
const memoryDb = require('./flow-memory-db');
|
|
22
22
|
const { getConfig, PROJECT_ROOT } = require('./flow-config-loader');
|
|
23
|
+
const { color } = require('./flow-output');
|
|
23
24
|
|
|
24
25
|
// ============================================================
|
|
25
26
|
// Configuration
|
|
@@ -37,19 +38,6 @@ function loadConfig() {
|
|
|
37
38
|
// Output Formatting
|
|
38
39
|
// ============================================================
|
|
39
40
|
|
|
40
|
-
function color(c, text) {
|
|
41
|
-
const colors = {
|
|
42
|
-
red: '\x1b[31m',
|
|
43
|
-
green: '\x1b[32m',
|
|
44
|
-
yellow: '\x1b[33m',
|
|
45
|
-
blue: '\x1b[34m',
|
|
46
|
-
cyan: '\x1b[36m',
|
|
47
|
-
gray: '\x1b[90m',
|
|
48
|
-
reset: '\x1b[0m'
|
|
49
|
-
};
|
|
50
|
-
return `${colors[c] || ''}${text}${colors.reset}`;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
41
|
function formatEntropy(entropy) {
|
|
54
42
|
if (entropy < 0.4) return color('green', `${entropy}`);
|
|
55
43
|
if (entropy < 0.7) return color('yellow', `${entropy}`);
|
|
@@ -21,6 +21,7 @@ const fs = require('fs');
|
|
|
21
21
|
const path = require('path');
|
|
22
22
|
const memoryDb = require('./flow-memory-db');
|
|
23
23
|
const { getConfig, PROJECT_ROOT } = require('./flow-config-loader');
|
|
24
|
+
const { color } = require('./flow-output');
|
|
24
25
|
|
|
25
26
|
// Lazy-load to avoid circular dependency
|
|
26
27
|
let _syncDecisionsToRules = null;
|
|
@@ -48,23 +49,6 @@ function loadConfig() {
|
|
|
48
49
|
}
|
|
49
50
|
}
|
|
50
51
|
|
|
51
|
-
// ============================================================
|
|
52
|
-
// Output Formatting
|
|
53
|
-
// ============================================================
|
|
54
|
-
|
|
55
|
-
function color(c, text) {
|
|
56
|
-
const colors = {
|
|
57
|
-
red: '\x1b[31m',
|
|
58
|
-
green: '\x1b[32m',
|
|
59
|
-
yellow: '\x1b[33m',
|
|
60
|
-
blue: '\x1b[34m',
|
|
61
|
-
cyan: '\x1b[36m',
|
|
62
|
-
gray: '\x1b[90m',
|
|
63
|
-
reset: '\x1b[0m'
|
|
64
|
-
};
|
|
65
|
-
return `${colors[c] || ''}${text}${colors.reset}`;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
52
|
// ============================================================
|
|
69
53
|
// Pattern Analysis
|
|
70
54
|
// ============================================================
|
|
@@ -21,14 +21,10 @@ const {
|
|
|
21
21
|
// Logging Helper
|
|
22
22
|
// ============================================================
|
|
23
23
|
|
|
24
|
-
const colors =
|
|
25
|
-
reset: '\x1b[0m',
|
|
26
|
-
cyan: '\x1b[36m',
|
|
27
|
-
dim: '\x1b[2m'
|
|
28
|
-
};
|
|
24
|
+
const { colors } = require('./flow-output');
|
|
29
25
|
|
|
30
|
-
function log(
|
|
31
|
-
console.log(colors[
|
|
26
|
+
function log(colorName, ...args) {
|
|
27
|
+
console.log((colors[colorName] || '') + args.join(' ') + colors.reset);
|
|
32
28
|
}
|
|
33
29
|
|
|
34
30
|
// ============================================================
|
|
@@ -6,14 +6,9 @@
|
|
|
6
6
|
* Executes plans created by Claude using a local LLM.
|
|
7
7
|
* Updates all Wogi Flow state files after each step.
|
|
8
8
|
*
|
|
9
|
-
* LIMITATION: The --resume flag is documented but not yet implemented.
|
|
10
|
-
* Checkpoint data is saved but recovery logic needs completion.
|
|
11
|
-
* TODO: Implement resume from checkpoint functionality.
|
|
12
|
-
*
|
|
13
9
|
* Usage:
|
|
14
|
-
* flow-orchestrate <plan.json>
|
|
15
|
-
* flow-orchestrate --
|
|
16
|
-
* flow-orchestrate --rollback # Rollback last execution
|
|
10
|
+
* flow-orchestrate <plan.json> # Execute a plan
|
|
11
|
+
* flow-orchestrate --rollback # Rollback last execution
|
|
17
12
|
*/
|
|
18
13
|
|
|
19
14
|
const fs = require('fs');
|
|
@@ -3146,7 +3141,6 @@ Wogi Flow Hybrid Orchestrator
|
|
|
3146
3141
|
|
|
3147
3142
|
Usage:
|
|
3148
3143
|
flow-orchestrate <plan.json> Execute a plan file
|
|
3149
|
-
flow-orchestrate --resume Resume from checkpoint
|
|
3150
3144
|
flow-orchestrate --rollback Rollback last execution
|
|
3151
3145
|
flow-orchestrate --help Show this help
|
|
3152
3146
|
|
|
@@ -3167,11 +3161,6 @@ Examples:
|
|
|
3167
3161
|
process.exit(0);
|
|
3168
3162
|
}
|
|
3169
3163
|
|
|
3170
|
-
if (args.includes('--resume')) {
|
|
3171
|
-
log('yellow', 'Resume not yet implemented');
|
|
3172
|
-
process.exit(1);
|
|
3173
|
-
}
|
|
3174
|
-
|
|
3175
3164
|
const planPath = args[0];
|
|
3176
3165
|
if (!planPath) {
|
|
3177
3166
|
console.error('Usage: flow-orchestrate <plan.json>');
|
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
const fs = require('fs');
|
|
38
38
|
const path = require('path');
|
|
39
39
|
const { execSync, execFileSync } = require('child_process');
|
|
40
|
-
const crypto = require('crypto');
|
|
41
40
|
const { resolvePatterns } = require('./flow-framework-resolver');
|
|
41
|
+
const { getProjectRoot, generateHashId } = require('./flow-utils');
|
|
42
42
|
|
|
43
43
|
// ============================================================================
|
|
44
44
|
// Constants
|
|
@@ -107,25 +107,11 @@ const c = {
|
|
|
107
107
|
// Utility Functions
|
|
108
108
|
// ============================================================================
|
|
109
109
|
|
|
110
|
-
/**
|
|
111
|
-
* Get project root directory
|
|
112
|
-
*/
|
|
113
|
-
function getProjectRoot() {
|
|
114
|
-
try {
|
|
115
|
-
return execSync('git rev-parse --show-toplevel', {
|
|
116
|
-
encoding: 'utf-8',
|
|
117
|
-
stdio: ['pipe', 'pipe', 'pipe']
|
|
118
|
-
}).trim();
|
|
119
|
-
} catch {
|
|
120
|
-
return process.cwd();
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
110
|
/**
|
|
125
111
|
* Generate unique pattern ID
|
|
126
112
|
*/
|
|
127
113
|
function generatePatternId() {
|
|
128
|
-
return 'pat
|
|
114
|
+
return generateHashId('pat', '', '');
|
|
129
115
|
}
|
|
130
116
|
|
|
131
117
|
/**
|
|
@@ -420,7 +406,7 @@ function createPattern(category, subcategory, name, options = {}) {
|
|
|
420
406
|
*/
|
|
421
407
|
function createConflict(patternA, patternB, options = {}) {
|
|
422
408
|
return {
|
|
423
|
-
id: 'conf
|
|
409
|
+
id: generateHashId('conf', '', ''),
|
|
424
410
|
category: patternA.category,
|
|
425
411
|
subcategory: patternA.subcategory,
|
|
426
412
|
description: options.description || `Conflicting ${patternA.subcategory} patterns`,
|
|
@@ -22,7 +22,8 @@ const {
|
|
|
22
22
|
success,
|
|
23
23
|
warn,
|
|
24
24
|
error,
|
|
25
|
-
info
|
|
25
|
+
info,
|
|
26
|
+
validateTaskId
|
|
26
27
|
} = require('./flow-utils');
|
|
27
28
|
|
|
28
29
|
const {
|
|
@@ -91,14 +92,6 @@ function getStagedChanges() {
|
|
|
91
92
|
}
|
|
92
93
|
}
|
|
93
94
|
|
|
94
|
-
/**
|
|
95
|
-
* Validate taskId format — must be wf-[8 hex chars] or legacy TASK-NNN/BUG-NNN.
|
|
96
|
-
* Also prevents command injection and path traversal.
|
|
97
|
-
*/
|
|
98
|
-
function isValidTaskId(taskId) {
|
|
99
|
-
return /^(wf-[a-f0-9]{8}(-\d{2})?|(TASK|BUG)-\d{3,})$/i.test(taskId);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
95
|
/**
|
|
103
96
|
* Validate commit hash format
|
|
104
97
|
*/
|
|
@@ -111,7 +104,7 @@ function isValidCommitHash(hash) {
|
|
|
111
104
|
*/
|
|
112
105
|
function getTaskChanges(taskId) {
|
|
113
106
|
// Validate taskId to prevent command injection
|
|
114
|
-
if (!
|
|
107
|
+
if (!validateTaskId(taskId).valid) {
|
|
115
108
|
warn(`Invalid task ID format: ${taskId}`);
|
|
116
109
|
return getStagedChanges();
|
|
117
110
|
}
|
|
@@ -504,8 +497,7 @@ module.exports = {
|
|
|
504
497
|
compareFindings,
|
|
505
498
|
formatResults,
|
|
506
499
|
IMPROVEMENT_PROMPT,
|
|
507
|
-
// Security validation functions
|
|
508
|
-
isValidTaskId,
|
|
500
|
+
// Security validation functions (validateTaskId imported from flow-utils)
|
|
509
501
|
isValidCommitHash,
|
|
510
502
|
isValidGlob,
|
|
511
503
|
isValidFilePath
|
|
@@ -21,6 +21,7 @@ const path = require('path');
|
|
|
21
21
|
const {
|
|
22
22
|
getProjectRoot,
|
|
23
23
|
safeJsonParse,
|
|
24
|
+
getConfig,
|
|
24
25
|
writeJson,
|
|
25
26
|
fileExists,
|
|
26
27
|
isPathWithinProject,
|
|
@@ -47,8 +48,7 @@ const PROJECT_ROOT = getProjectRoot();
|
|
|
47
48
|
* @returns {Object} Plugin configuration
|
|
48
49
|
*/
|
|
49
50
|
function getPluginConfig() {
|
|
50
|
-
const
|
|
51
|
-
const config = safeJsonParse(configPath, {});
|
|
51
|
+
const config = getConfig();
|
|
52
52
|
return config.plugins || {
|
|
53
53
|
enabled: true,
|
|
54
54
|
registryPath: '.workflow/state/plugin-registry.json',
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
const fs = require('fs');
|
|
14
14
|
const path = require('path');
|
|
15
|
-
const { getProjectRoot, safeJsonParse } = require('./flow-utils');
|
|
15
|
+
const { getProjectRoot, safeJsonParse, getConfig } = require('./flow-utils');
|
|
16
16
|
|
|
17
17
|
const PROJECT_ROOT = process.argv[2] || getProjectRoot();
|
|
18
18
|
|
|
@@ -802,8 +802,8 @@ function updateConfig(analysis) {
|
|
|
802
802
|
}
|
|
803
803
|
|
|
804
804
|
try {
|
|
805
|
-
const config =
|
|
806
|
-
if (!config) return false;
|
|
805
|
+
const config = getConfig();
|
|
806
|
+
if (!config || Object.keys(config).length === 0) return false;
|
|
807
807
|
|
|
808
808
|
// Ensure hybrid section exists
|
|
809
809
|
if (!config.hybrid) config.hybrid = {};
|
|
@@ -1227,7 +1227,7 @@ if (require.main === module) {
|
|
|
1227
1227
|
clearContextCache();
|
|
1228
1228
|
|
|
1229
1229
|
// Also generate codebase insights during full analysis
|
|
1230
|
-
const config =
|
|
1230
|
+
const config = getConfig();
|
|
1231
1231
|
if (config.codebaseInsights?.enabled !== false) {
|
|
1232
1232
|
saveCodebaseInsights();
|
|
1233
1233
|
}
|