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
|
@@ -308,17 +308,48 @@ function updateScenarioProgress(scenarioIndex, scenarioTitle, passed) {
|
|
|
308
308
|
* @param {string} filePath - Path of the changed file
|
|
309
309
|
* @returns {boolean} True if added
|
|
310
310
|
*/
|
|
311
|
-
|
|
311
|
+
// In-process batch for trackChangedFile — accumulates changes and flushes once
|
|
312
|
+
let _pendingFiles = [];
|
|
313
|
+
let _flushScheduled = false;
|
|
314
|
+
|
|
315
|
+
function _flushPendingFiles() {
|
|
316
|
+
if (_pendingFiles.length === 0) return;
|
|
312
317
|
try {
|
|
313
318
|
const checkpoint = loadCheckpoint();
|
|
314
|
-
if (!checkpoint) return
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
checkpoint.changedFiles.
|
|
319
|
+
if (!checkpoint) { _pendingFiles = []; return; }
|
|
320
|
+
let changed = false;
|
|
321
|
+
for (const fp of _pendingFiles) {
|
|
322
|
+
if (!checkpoint.changedFiles.includes(fp)) {
|
|
323
|
+
checkpoint.changedFiles.push(fp);
|
|
324
|
+
changed = true;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
if (changed) {
|
|
318
328
|
checkpoint.lastUpdated = new Date().toISOString();
|
|
319
329
|
writeJson(CHECKPOINT_PATH, checkpoint);
|
|
320
330
|
}
|
|
331
|
+
} catch (err) {
|
|
332
|
+
if (process.env.DEBUG) {
|
|
333
|
+
console.error(`[checkpoint] Batch flush failed: ${err.message}`);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
_pendingFiles = [];
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Flush on process exit to ensure no data loss
|
|
340
|
+
process.on('exit', _flushPendingFiles);
|
|
321
341
|
|
|
342
|
+
function trackChangedFile(filePath) {
|
|
343
|
+
try {
|
|
344
|
+
if (!_pendingFiles.includes(filePath)) _pendingFiles.push(filePath);
|
|
345
|
+
// Schedule a single flush at end of event loop tick (batches multiple calls)
|
|
346
|
+
if (!_flushScheduled) {
|
|
347
|
+
_flushScheduled = true;
|
|
348
|
+
setImmediate(() => {
|
|
349
|
+
_flushScheduled = false;
|
|
350
|
+
_flushPendingFiles();
|
|
351
|
+
});
|
|
352
|
+
}
|
|
322
353
|
return true;
|
|
323
354
|
} catch (err) {
|
|
324
355
|
if (process.env.DEBUG) {
|
|
@@ -14,8 +14,9 @@
|
|
|
14
14
|
|
|
15
15
|
const fs = require('node:fs');
|
|
16
16
|
const path = require('node:path');
|
|
17
|
-
const { getConfig, getProjectRoot, writeJson, readJson, safeJsonParse } = require('./flow-utils');
|
|
17
|
+
const { getConfig, getProjectRoot, writeJson, readJson, safeJsonParse, PATHS } = require('./flow-utils');
|
|
18
18
|
const { getCommand } = require('./flow-script-resolver');
|
|
19
|
+
const { sanitizeShellArg } = require('./flow-security');
|
|
19
20
|
|
|
20
21
|
// v2.0: Import durable session for unified tracking
|
|
21
22
|
const durableSession = require('./flow-durable-session');
|
|
@@ -30,29 +31,6 @@ function getTaskConfig() {
|
|
|
30
31
|
return config.tasks || config.loops || {};
|
|
31
32
|
}
|
|
32
33
|
|
|
33
|
-
/**
|
|
34
|
-
* Sanitize a string for safe use in shell commands
|
|
35
|
-
* Only allows alphanumeric, underscore, hyphen, and dot characters
|
|
36
|
-
* @param {string} str - String to sanitize
|
|
37
|
-
* @returns {string} - Sanitized string
|
|
38
|
-
*/
|
|
39
|
-
function sanitizeShellArg(str) {
|
|
40
|
-
if (!str || typeof str !== 'string') return '';
|
|
41
|
-
// Only allow safe characters: alphanumeric, underscore, hyphen, dot
|
|
42
|
-
return str.replace(/[^a-zA-Z0-9_.-]/g, '');
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Escape a path for safe use in shell commands
|
|
47
|
-
* @param {string} p - Path to escape
|
|
48
|
-
* @returns {string} - Escaped path
|
|
49
|
-
*/
|
|
50
|
-
function escapeShellPath(p) {
|
|
51
|
-
if (!p || typeof p !== 'string') return '';
|
|
52
|
-
// Escape special shell characters in paths
|
|
53
|
-
return p.replace(/(["\s'$`\\!*?#~<>^()[\]{}|;&])/g, '\\$1');
|
|
54
|
-
}
|
|
55
|
-
|
|
56
34
|
/**
|
|
57
35
|
* Check if task enforcement is enabled
|
|
58
36
|
*/
|
|
@@ -382,6 +382,7 @@ function generateTemplate(file, type) {
|
|
|
382
382
|
function isStructuralLine(trimmed, type) {
|
|
383
383
|
// Import statements
|
|
384
384
|
if (trimmed.startsWith('import ') || trimmed.startsWith('const ') && trimmed.includes('require(')) return true;
|
|
385
|
+
const { PATHS } = require('./flow-utils');
|
|
385
386
|
if (trimmed.startsWith('from ')) return true;
|
|
386
387
|
|
|
387
388
|
// Export statements
|
|
@@ -13,11 +13,9 @@
|
|
|
13
13
|
|
|
14
14
|
const fs = require('node:fs');
|
|
15
15
|
const path = require('node:path');
|
|
16
|
-
const { getProjectRoot, readJson, info } = require('./flow-utils');
|
|
16
|
+
const { getProjectRoot, readJson, info, PATHS } = require('./flow-utils');
|
|
17
17
|
|
|
18
|
-
const
|
|
19
|
-
const TEMPLATES_DIR = path.join(PROJECT_ROOT, 'templates', 'hybrid');
|
|
20
|
-
const WORKFLOW_DIR = path.join(PROJECT_ROOT, '.workflow');
|
|
18
|
+
const TEMPLATES_DIR = path.join(PATHS.root, 'templates', 'hybrid');
|
|
21
19
|
|
|
22
20
|
// ============================================================
|
|
23
21
|
// Project Analyzer
|
|
@@ -139,7 +137,7 @@ class ProjectAnalyzer {
|
|
|
139
137
|
|
|
140
138
|
const componentDirs = ['src/components', 'components', 'app/components'];
|
|
141
139
|
for (const dir of componentDirs) {
|
|
142
|
-
if (fs.existsSync(path.join(
|
|
140
|
+
if (fs.existsSync(path.join(PATHS.root, dir))) {
|
|
143
141
|
this.patterns.components = this.findFilesWithExports(dir, /\.(tsx|jsx)$/);
|
|
144
142
|
console.log(` Components: ${this.patterns.components.length} found`);
|
|
145
143
|
break;
|
|
@@ -148,7 +146,7 @@ class ProjectAnalyzer {
|
|
|
148
146
|
|
|
149
147
|
const hookDirs = ['src/hooks', 'hooks', 'app/hooks'];
|
|
150
148
|
for (const dir of hookDirs) {
|
|
151
|
-
if (fs.existsSync(path.join(
|
|
149
|
+
if (fs.existsSync(path.join(PATHS.root, dir))) {
|
|
152
150
|
this.patterns.hooks = this.findFilesWithExports(dir, /^use.*\.(ts|tsx)$/);
|
|
153
151
|
console.log(` Hooks: ${this.patterns.hooks.length} found`);
|
|
154
152
|
break;
|
|
@@ -157,7 +155,7 @@ class ProjectAnalyzer {
|
|
|
157
155
|
|
|
158
156
|
const serviceDirs = ['src/services', 'services', 'src/api', 'api', 'src/lib'];
|
|
159
157
|
for (const dir of serviceDirs) {
|
|
160
|
-
if (fs.existsSync(path.join(
|
|
158
|
+
if (fs.existsSync(path.join(PATHS.root, dir))) {
|
|
161
159
|
this.patterns.services = this.findFilesWithExports(dir, /\.(ts|js)$/);
|
|
162
160
|
console.log(` Services: ${this.patterns.services.length} found`);
|
|
163
161
|
break;
|
|
@@ -166,7 +164,7 @@ class ProjectAnalyzer {
|
|
|
166
164
|
|
|
167
165
|
const utilDirs = ['src/utils', 'utils', 'src/lib/utils', 'lib/utils'];
|
|
168
166
|
for (const dir of utilDirs) {
|
|
169
|
-
if (fs.existsSync(path.join(
|
|
167
|
+
if (fs.existsSync(path.join(PATHS.root, dir))) {
|
|
170
168
|
this.patterns.utilities = this.findFilesWithExports(dir, /\.(ts|js)$/);
|
|
171
169
|
console.log(` Utilities: ${this.patterns.utilities.length} found`);
|
|
172
170
|
break;
|
|
@@ -176,7 +174,7 @@ class ProjectAnalyzer {
|
|
|
176
174
|
|
|
177
175
|
findFilesWithExports(dir, pattern) {
|
|
178
176
|
const results = [];
|
|
179
|
-
const fullDir = path.join(
|
|
177
|
+
const fullDir = path.join(PATHS.root, dir);
|
|
180
178
|
|
|
181
179
|
if (!fs.existsSync(fullDir)) return results;
|
|
182
180
|
|
|
@@ -191,7 +189,7 @@ class ProjectAnalyzer {
|
|
|
191
189
|
walkDir(filePath);
|
|
192
190
|
} else if (stat.isFile() && pattern.test(file)) {
|
|
193
191
|
const content = fs.readFileSync(filePath, 'utf-8');
|
|
194
|
-
const relativePath = path.relative(
|
|
192
|
+
const relativePath = path.relative(PATHS.root, filePath);
|
|
195
193
|
|
|
196
194
|
const exports = this.extractExports(content);
|
|
197
195
|
if (exports.length > 0) {
|
|
@@ -242,7 +240,7 @@ class ProjectAnalyzer {
|
|
|
242
240
|
}
|
|
243
241
|
|
|
244
242
|
extractImportPatterns() {
|
|
245
|
-
const tsconfigPath = path.join(
|
|
243
|
+
const tsconfigPath = path.join(PATHS.root, 'tsconfig.json');
|
|
246
244
|
if (fs.existsSync(tsconfigPath)) {
|
|
247
245
|
const tsconfig = readJson(tsconfigPath, null);
|
|
248
246
|
if (tsconfig) {
|
|
@@ -259,7 +257,7 @@ class ProjectAnalyzer {
|
|
|
259
257
|
}
|
|
260
258
|
|
|
261
259
|
loadPackageJson() {
|
|
262
|
-
const pkgPath = path.join(
|
|
260
|
+
const pkgPath = path.join(PATHS.root, 'package.json');
|
|
263
261
|
return readJson(pkgPath, null);
|
|
264
262
|
}
|
|
265
263
|
}
|
|
@@ -770,7 +768,7 @@ async function main() {
|
|
|
770
768
|
const generator = new TemplateGenerator(patterns);
|
|
771
769
|
generator.generateAll();
|
|
772
770
|
|
|
773
|
-
const stateDir = path.join(
|
|
771
|
+
const stateDir = path.join(PATHS.workflow, 'state');
|
|
774
772
|
if (!fs.existsSync(stateDir)) {
|
|
775
773
|
fs.mkdirSync(stateDir, { recursive: true });
|
|
776
774
|
}
|
package/scripts/flow-test-api.js
CHANGED
|
@@ -16,8 +16,6 @@
|
|
|
16
16
|
* const { runAPITests, parseAPIMap, executeAPITest, validateResponseSchema } = require('./flow-test-api');
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
'use strict';
|
|
20
|
-
|
|
21
19
|
const fs = require('node:fs');
|
|
22
20
|
const path = require('node:path');
|
|
23
21
|
const { spawn } = require('node:child_process');
|
|
@@ -32,8 +30,6 @@ try {
|
|
|
32
30
|
scenarioEngine = null;
|
|
33
31
|
}
|
|
34
32
|
|
|
35
|
-
const PROJECT_ROOT = getProjectRoot();
|
|
36
|
-
|
|
37
33
|
// ============================================================
|
|
38
34
|
// Constants
|
|
39
35
|
// ============================================================
|
|
@@ -609,7 +605,7 @@ async function startAPIServer(command, baseUrl, timeout = SERVER_READY_TIMEOUT)
|
|
|
609
605
|
const args = parts.slice(1);
|
|
610
606
|
|
|
611
607
|
const serverProcess = spawn(cmd, args, {
|
|
612
|
-
cwd:
|
|
608
|
+
cwd: PATHS.root,
|
|
613
609
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
614
610
|
detached: true,
|
|
615
611
|
env: { ...process.env, NODE_ENV: 'test' }
|
|
@@ -649,7 +645,7 @@ async function startAPIServer(command, baseUrl, timeout = SERVER_READY_TIMEOUT)
|
|
|
649
645
|
// Check if process already exited with error
|
|
650
646
|
const exitResult = await Promise.race([
|
|
651
647
|
processExited,
|
|
652
|
-
|
|
648
|
+
require('node:timers/promises').setTimeout(SERVER_POLL_INTERVAL, null)
|
|
653
649
|
]);
|
|
654
650
|
|
|
655
651
|
if (exitResult && exitResult.exitError) {
|
|
@@ -737,7 +733,7 @@ function loadTestData(taskId) {
|
|
|
737
733
|
const result = { setup: [], teardown: [], fixtures: {} };
|
|
738
734
|
|
|
739
735
|
// Check for task-specific fixtures
|
|
740
|
-
const taskFixturesPath = path.join(
|
|
736
|
+
const taskFixturesPath = path.join(PATHS.workflow, 'tests', 'generated', taskId, 'api-fixtures.json');
|
|
741
737
|
const taskFixtures = safeJsonParse(taskFixturesPath, null);
|
|
742
738
|
if (taskFixtures) {
|
|
743
739
|
if (taskFixtures.setup) result.setup = taskFixtures.setup;
|
|
@@ -746,7 +742,7 @@ function loadTestData(taskId) {
|
|
|
746
742
|
}
|
|
747
743
|
|
|
748
744
|
// Check for global fixtures
|
|
749
|
-
const globalFixturesPath = path.join(
|
|
745
|
+
const globalFixturesPath = path.join(PATHS.workflow, 'tests', 'api-fixtures.json');
|
|
750
746
|
const globalFixtures = safeJsonParse(globalFixturesPath, null);
|
|
751
747
|
if (globalFixtures) {
|
|
752
748
|
// Merge — task-specific takes precedence
|
|
@@ -978,7 +974,7 @@ function generateReport(taskId, testGroups, schemaInfo) {
|
|
|
978
974
|
* @returns {string} Path to the written report
|
|
979
975
|
*/
|
|
980
976
|
function writeReport(taskId, report) {
|
|
981
|
-
const verificationsDir =
|
|
977
|
+
const verificationsDir = PATHS.verifications;
|
|
982
978
|
ensureDir(verificationsDir);
|
|
983
979
|
|
|
984
980
|
const reportPath = path.join(verificationsDir, `${taskId}-api.json`);
|
|
@@ -1018,7 +1014,7 @@ function hasStateDependencies(taskId, endpoints) {
|
|
|
1018
1014
|
function loadOrGenerateScenarios(taskId, options = {}) {
|
|
1019
1015
|
const scenarios = [];
|
|
1020
1016
|
|
|
1021
|
-
const scenarioDir = path.join(
|
|
1017
|
+
const scenarioDir = path.join(PATHS.workflow, 'tests', 'generated', taskId);
|
|
1022
1018
|
const scenarioFile = path.join(scenarioDir, 'scenarios.json');
|
|
1023
1019
|
const predefined = safeJsonParse(scenarioFile, null);
|
|
1024
1020
|
if (predefined && Array.isArray(predefined.scenarios)) {
|
|
@@ -1032,7 +1028,7 @@ function loadOrGenerateScenarios(taskId, options = {}) {
|
|
|
1032
1028
|
return scenarios;
|
|
1033
1029
|
}
|
|
1034
1030
|
|
|
1035
|
-
const readyPath =
|
|
1031
|
+
const readyPath = PATHS.ready;
|
|
1036
1032
|
const readyData = safeJsonParse(readyPath, null);
|
|
1037
1033
|
if (!readyData) return scenarios;
|
|
1038
1034
|
|
|
@@ -1103,7 +1099,7 @@ async function runScenarioTests(taskId, scenarios, options = {}) {
|
|
|
1103
1099
|
};
|
|
1104
1100
|
|
|
1105
1101
|
if (!dryRun) {
|
|
1106
|
-
const verificationsDir =
|
|
1102
|
+
const verificationsDir = PATHS.verifications;
|
|
1107
1103
|
ensureDir(verificationsDir);
|
|
1108
1104
|
const reportPath = path.join(verificationsDir, `${taskId}-scenarios.json`);
|
|
1109
1105
|
try {
|
|
@@ -1170,7 +1166,7 @@ async function runAPITests(taskId, options = {}) {
|
|
|
1170
1166
|
// 2. Load OpenAPI spec if available
|
|
1171
1167
|
let openAPISpec = { endpoints: [], raw: null };
|
|
1172
1168
|
if (specFile) {
|
|
1173
|
-
const specPath = path.isAbsolute(specFile) ? specFile : path.join(
|
|
1169
|
+
const specPath = path.isAbsolute(specFile) ? specFile : path.join(PATHS.root, specFile);
|
|
1174
1170
|
openAPISpec = parseOpenAPISpec(specPath);
|
|
1175
1171
|
}
|
|
1176
1172
|
|
|
@@ -744,7 +744,7 @@ function runFailToPass(beforeResults, afterResults, matchedCriteria) {
|
|
|
744
744
|
* @returns {string} Path to saved report
|
|
745
745
|
*/
|
|
746
746
|
function generateDiscoveryReport(taskId, discoveryResults, gateResults) {
|
|
747
|
-
const verificationsDir =
|
|
747
|
+
const verificationsDir = PATHS.verifications;
|
|
748
748
|
|
|
749
749
|
// Ensure verifications directory exists
|
|
750
750
|
try {
|
|
@@ -16,15 +16,11 @@
|
|
|
16
16
|
* const { parseSpecCriteria, detectTestConventions, categoriseCriterion, generateTestScaffold } = require('./flow-test-generate');
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
'use strict';
|
|
20
|
-
|
|
21
19
|
const fs = require('node:fs');
|
|
22
20
|
const path = require('node:path');
|
|
23
|
-
const { getProjectRoot, safeJsonParse } = require('./flow-utils');
|
|
21
|
+
const { getProjectRoot, safeJsonParse, PATHS } = require('./flow-utils');
|
|
24
22
|
const { getConfig } = require('./flow-config-loader');
|
|
25
23
|
|
|
26
|
-
const PROJECT_ROOT = getProjectRoot();
|
|
27
|
-
|
|
28
24
|
// ============================================================
|
|
29
25
|
// Criterion Categorisation Keywords
|
|
30
26
|
// ============================================================
|
|
@@ -154,7 +150,7 @@ function parseSpecCriteria(specPath) {
|
|
|
154
150
|
* @returns {{ framework: string, importStyle: 'esm'|'cjs', fileExtension: string, hasDescribeBlocks: boolean, assertionLib: string }}
|
|
155
151
|
*/
|
|
156
152
|
function detectTestConventions(projectRoot) {
|
|
157
|
-
const root = projectRoot ||
|
|
153
|
+
const root = projectRoot || PATHS.root;
|
|
158
154
|
const result = {
|
|
159
155
|
framework: 'vitest',
|
|
160
156
|
importStyle: 'esm',
|
|
@@ -403,7 +399,7 @@ function escapeSingleQuotes(str) {
|
|
|
403
399
|
function ensureTestDir(taskId, outputDir) {
|
|
404
400
|
const config = getConfig();
|
|
405
401
|
const baseDir = outputDir || (config.testing && config.testing.generation && config.testing.generation.outputDir) || '.workflow/tests/generated';
|
|
406
|
-
const fullDir = path.join(
|
|
402
|
+
const fullDir = path.join(PATHS.root, baseDir, taskId);
|
|
407
403
|
|
|
408
404
|
if (!fs.existsSync(fullDir)) {
|
|
409
405
|
fs.mkdirSync(fullDir, { recursive: true });
|
|
@@ -552,7 +548,7 @@ if (require.main === module) {
|
|
|
552
548
|
}
|
|
553
549
|
|
|
554
550
|
// Parse spec
|
|
555
|
-
const specPath = path.join(
|
|
551
|
+
const specPath = path.join(PATHS.workflow, 'specs', `${taskId}.md`);
|
|
556
552
|
|
|
557
553
|
if (!fs.existsSync(specPath)) {
|
|
558
554
|
console.error(`Spec not found: ${specPath}`);
|
|
@@ -584,7 +580,7 @@ if (require.main === module) {
|
|
|
584
580
|
console.log('');
|
|
585
581
|
console.log(`Generated ${result.files.length} test file(s) with ${result.totalTests} total test(s):`);
|
|
586
582
|
for (const file of result.files) {
|
|
587
|
-
console.log(` ${path.relative(
|
|
583
|
+
console.log(` ${path.relative(PATHS.root, file.path)} (${file.category}: ${file.testCount} tests)`);
|
|
588
584
|
}
|
|
589
585
|
}
|
|
590
586
|
|
|
@@ -24,8 +24,6 @@
|
|
|
24
24
|
* buildEndpointPageMapping } = require('./flow-test-integrity');
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
|
-
'use strict';
|
|
28
|
-
|
|
29
27
|
const fs = require('node:fs');
|
|
30
28
|
const path = require('node:path');
|
|
31
29
|
const { getProjectRoot, PATHS, ensureDir, safeJsonParse } = require('./flow-utils');
|
|
@@ -34,8 +32,6 @@ const { loadProfile } = require('./flow-verification-profile');
|
|
|
34
32
|
const { parseAPIMap, executeAPITest, startAPIServer, stopAPIServer } = require('./flow-test-api');
|
|
35
33
|
const { startDevServer, stopDevServer, assertDataInTree, flattenTreeToText } = require('./flow-test-ui');
|
|
36
34
|
|
|
37
|
-
const PROJECT_ROOT = getProjectRoot();
|
|
38
|
-
|
|
39
35
|
// ============================================================
|
|
40
36
|
// Constants
|
|
41
37
|
// ============================================================
|
|
@@ -549,7 +545,7 @@ function generateIntegrityPlan(taskId) {
|
|
|
549
545
|
}
|
|
550
546
|
|
|
551
547
|
// Load task spec if available
|
|
552
|
-
const specPath = path.join(
|
|
548
|
+
const specPath = path.join(PATHS.workflow, 'specs', `${taskId}.json`);
|
|
553
549
|
const spec = safeJsonParse(specPath, null);
|
|
554
550
|
|
|
555
551
|
const mappings = buildEndpointPageMapping(endpoints, spec);
|
|
@@ -575,7 +571,7 @@ function generateIntegrityPlan(taskId) {
|
|
|
575
571
|
* @returns {string} Path to written report
|
|
576
572
|
*/
|
|
577
573
|
function writeIntegrityReport(taskId, results) {
|
|
578
|
-
const verificationsDir =
|
|
574
|
+
const verificationsDir = PATHS.verifications;
|
|
579
575
|
ensureDir(verificationsDir);
|
|
580
576
|
|
|
581
577
|
const reportPath = path.join(verificationsDir, `${taskId}-integrity.json`);
|
|
@@ -765,7 +761,7 @@ async function runIntegrityTests(taskId, options = {}) {
|
|
|
765
761
|
const endpoints = parseAPIMap(apiMapPath);
|
|
766
762
|
|
|
767
763
|
let spec = null;
|
|
768
|
-
const specPath = path.join(
|
|
764
|
+
const specPath = path.join(PATHS.workflow, 'specs', `${taskId}.json`);
|
|
769
765
|
if (fs.existsSync(specPath)) {
|
|
770
766
|
spec = safeJsonParse(specPath, null);
|
|
771
767
|
}
|
package/scripts/flow-test-ui.js
CHANGED
|
@@ -30,20 +30,16 @@
|
|
|
30
30
|
* checkStateCoverage, getPlaywrightMCPConfig } = require('./flow-test-ui');
|
|
31
31
|
*/
|
|
32
32
|
|
|
33
|
-
'use strict';
|
|
34
|
-
|
|
35
33
|
const { spawn } = require('node:child_process');
|
|
36
34
|
const fs = require('node:fs');
|
|
37
35
|
const path = require('node:path');
|
|
38
36
|
const http = require('node:http');
|
|
39
37
|
const https = require('node:https');
|
|
40
|
-
const { getProjectRoot } = require('./flow-paths');
|
|
38
|
+
const { getProjectRoot, PATHS } = require('./flow-paths');
|
|
41
39
|
const { getConfig } = require('./flow-config-loader');
|
|
42
40
|
const { ensureDir } = require('./flow-io');
|
|
43
41
|
const { loadProfile } = require('./flow-verification-profile');
|
|
44
42
|
|
|
45
|
-
const PROJECT_ROOT = getProjectRoot();
|
|
46
|
-
|
|
47
43
|
// ============================================================
|
|
48
44
|
// Constants
|
|
49
45
|
// ============================================================
|
|
@@ -119,7 +115,7 @@ async function startDevServer(command, baseUrl, timeout = DEFAULT_SERVER_TIMEOUT
|
|
|
119
115
|
let serverProcess;
|
|
120
116
|
try {
|
|
121
117
|
serverProcess = spawn(cmd, args, {
|
|
122
|
-
cwd:
|
|
118
|
+
cwd: PATHS.root,
|
|
123
119
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
124
120
|
detached: false,
|
|
125
121
|
shell: true
|
|
@@ -368,7 +364,7 @@ function loadTestFlows(taskId) {
|
|
|
368
364
|
const config = getConfig();
|
|
369
365
|
const testingConfig = config.testing || {};
|
|
370
366
|
const outputDir = (testingConfig.generation && testingConfig.generation.outputDir) || '.workflow/tests/generated';
|
|
371
|
-
const testDir = path.join(
|
|
367
|
+
const testDir = path.join(PATHS.root, outputDir, taskId);
|
|
372
368
|
|
|
373
369
|
if (!fs.existsSync(testDir)) {
|
|
374
370
|
return [];
|
|
@@ -510,7 +506,7 @@ function generateReport(taskId, assertions, stateCoverage, accessibility) {
|
|
|
510
506
|
* @returns {string} Path to the saved report file
|
|
511
507
|
*/
|
|
512
508
|
function saveReport(report) {
|
|
513
|
-
const verificationsDir =
|
|
509
|
+
const verificationsDir = PATHS.verifications;
|
|
514
510
|
ensureDir(verificationsDir);
|
|
515
511
|
|
|
516
512
|
const reportPath = path.join(verificationsDir, `${report.taskId}-ui.json`);
|
|
@@ -728,7 +724,7 @@ if (require.main === module) {
|
|
|
728
724
|
console.log(`Accessibility violations: ${report.accessibility.violations.length}`);
|
|
729
725
|
}
|
|
730
726
|
|
|
731
|
-
const reportPath = path.join(
|
|
727
|
+
const reportPath = path.join(PATHS.workflow, 'verifications', `${taskId}-ui.json`);
|
|
732
728
|
console.log(`Report: ${reportPath}`);
|
|
733
729
|
|
|
734
730
|
process.exit(report.summary.failed > 0 ? 1 : 0);
|
|
@@ -23,12 +23,10 @@
|
|
|
23
23
|
* const ready = await ensureDeps('ui');
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
|
-
'use strict';
|
|
27
|
-
|
|
28
26
|
const { execSync } = require('node:child_process');
|
|
29
27
|
const path = require('node:path');
|
|
30
28
|
const fs = require('node:fs');
|
|
31
|
-
const { getProjectRoot } = require('./flow-utils');
|
|
29
|
+
const { getProjectRoot, PATHS } = require('./flow-utils');
|
|
32
30
|
|
|
33
31
|
// ============================================================
|
|
34
32
|
// Dependency Definitions
|
|
@@ -29,7 +29,7 @@ const {
|
|
|
29
29
|
fileExists,
|
|
30
30
|
safeJsonParse,
|
|
31
31
|
printHeader,
|
|
32
|
-
printSection
|
|
32
|
+
printSection, PATHS
|
|
33
33
|
} = require('./flow-utils');
|
|
34
34
|
|
|
35
35
|
// ============================================================
|
|
@@ -91,9 +91,9 @@ const DEFAULT_TIERED_LEARNING_CONFIG = {
|
|
|
91
91
|
// Paths
|
|
92
92
|
// ============================================================
|
|
93
93
|
|
|
94
|
-
const PATTERNS_PATH = path.join(
|
|
95
|
-
const DECISIONS_PATH =
|
|
96
|
-
const FEEDBACK_PATH =
|
|
94
|
+
const PATTERNS_PATH = path.join(PATHS.state, 'learning-patterns.json');
|
|
95
|
+
const DECISIONS_PATH = PATHS.decisions;
|
|
96
|
+
const FEEDBACK_PATH = PATHS.feedbackPatterns;
|
|
97
97
|
|
|
98
98
|
// ============================================================
|
|
99
99
|
// Configuration
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
const fs = require('node:fs');
|
|
18
18
|
const path = require('node:path');
|
|
19
|
-
const { getProjectRoot, safeJsonParse } = require('./flow-utils');
|
|
19
|
+
const { getProjectRoot, safeJsonParse, PATHS } = require('./flow-utils');
|
|
20
20
|
|
|
21
21
|
// ============================================================================
|
|
22
22
|
// Constants
|
package/scripts/flow-tokens.js
CHANGED
|
@@ -20,16 +20,12 @@
|
|
|
20
20
|
* const { probeProject, loadProfile, getVerificationStrategy, hasCapability } = require('./flow-verification-profile');
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
|
-
'use strict';
|
|
24
|
-
|
|
25
23
|
const fs = require('node:fs');
|
|
26
24
|
const path = require('node:path');
|
|
27
25
|
const { spawnSync } = require('node:child_process');
|
|
28
26
|
const { getProjectRoot, PATHS, ensureDir, safeJsonParse } = require('./flow-utils');
|
|
29
27
|
const { getConfig } = require('./flow-config-loader');
|
|
30
28
|
|
|
31
|
-
const PROJECT_ROOT = getProjectRoot();
|
|
32
|
-
|
|
33
29
|
// ============================================================
|
|
34
30
|
// Constants
|
|
35
31
|
// ============================================================
|
|
@@ -127,7 +123,7 @@ const FRAMEWORK_PORTS = {
|
|
|
127
123
|
*/
|
|
128
124
|
function existsInProject(relativePath) {
|
|
129
125
|
try {
|
|
130
|
-
return fs.existsSync(path.join(
|
|
126
|
+
return fs.existsSync(path.join(PATHS.root, relativePath));
|
|
131
127
|
} catch (err) {
|
|
132
128
|
return false;
|
|
133
129
|
}
|
|
@@ -138,7 +134,7 @@ function existsInProject(relativePath) {
|
|
|
138
134
|
* @returns {object|null}
|
|
139
135
|
*/
|
|
140
136
|
function readPackageJson() {
|
|
141
|
-
const pkgPath = path.join(
|
|
137
|
+
const pkgPath = path.join(PATHS.root, 'package.json');
|
|
142
138
|
return safeJsonParse(pkgPath, null);
|
|
143
139
|
}
|
|
144
140
|
|
|
@@ -149,7 +145,7 @@ function readPackageJson() {
|
|
|
149
145
|
*/
|
|
150
146
|
function readProjectFile(relativePath) {
|
|
151
147
|
try {
|
|
152
|
-
return fs.readFileSync(path.join(
|
|
148
|
+
return fs.readFileSync(path.join(PATHS.root, relativePath), 'utf-8');
|
|
153
149
|
} catch (err) {
|
|
154
150
|
return null;
|
|
155
151
|
}
|
|
@@ -552,7 +548,7 @@ function detectFixtures() {
|
|
|
552
548
|
};
|
|
553
549
|
|
|
554
550
|
for (const fixtureDir of FIXTURE_DIRS) {
|
|
555
|
-
const fullPath = path.join(
|
|
551
|
+
const fullPath = path.join(PATHS.root, fixtureDir);
|
|
556
552
|
|
|
557
553
|
// Check if it's a file (e.g., prisma/seed.ts)
|
|
558
554
|
try {
|
|
@@ -602,7 +598,7 @@ function detectCI() {
|
|
|
602
598
|
for (const ci of CI_CONFIGS) {
|
|
603
599
|
if (ci.glob) {
|
|
604
600
|
// Directory-based detection (e.g., .github/workflows)
|
|
605
|
-
const dirPath = path.join(
|
|
601
|
+
const dirPath = path.join(PATHS.root, ci.glob);
|
|
606
602
|
try {
|
|
607
603
|
const stat = fs.statSync(dirPath);
|
|
608
604
|
if (stat.isDirectory()) {
|
|
@@ -779,7 +775,7 @@ function buildVerificationStrategy(profile) {
|
|
|
779
775
|
* @returns {Promise<object>} The complete verification profile
|
|
780
776
|
*/
|
|
781
777
|
async function probeProject(projectRoot) {
|
|
782
|
-
const root = projectRoot ||
|
|
778
|
+
const root = projectRoot || PATHS.root;
|
|
783
779
|
const pkg = readPackageJson();
|
|
784
780
|
|
|
785
781
|
// Run all detections
|