wogiflow 1.9.3 → 1.9.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.
@@ -1,53 +1,177 @@
1
1
  ---
2
- description: "View or modify workflow configuration"
2
+ description: "View or modify workflow configuration with natural language"
3
3
  ---
4
- View or modify workflow configuration.
4
+ Smart configuration management for WogiFlow.
5
5
 
6
- **View config:** `/wogi-config`
7
- Shows current settings from `.workflow/config.json`
6
+ ## Usage
8
7
 
9
- **Toggle settings:** `/wogi-config [setting] [on/off]`
8
+ `/wogi-config` Show current configuration overview
9
+ `/wogi-config [feature] [on/off]` — Toggle a feature
10
+ `/wogi-config [preset]` — Apply a preset
11
+ `/wogi-config show [key]` — Show specific config value
12
+ `/wogi-config set [key] [value]` — Set a specific config key
10
13
 
11
- Available settings:
12
- - `storybook on/off` - Auto-generate Storybook stories for new components
13
- - `hooks on/off` - Enable/disable pre-commit git hooks
14
- - `tests-before-commit on/off` - Run tests before each commit
14
+ ## How It Works
15
15
 
16
- Examples:
17
- ```
18
- /wogi-config
19
- Shows all current settings
16
+ 1. Read `.workflow/config-reference.json` for feature definitions, aliases, and presets
17
+ 2. Match the user's natural language to features or presets using aliases
18
+ 3. Apply all dependent config changes automatically
19
+ 4. Show what was changed with before/after values
20
+ 5. Save to `.workflow/config.json`
20
21
 
21
- /wogi-config storybook on
22
- → Enables Storybook auto-generation
23
- → Updates componentRules.autoGenerateStorybook: true
22
+ ## When the user says something like:
24
23
 
25
- /wogi-config hooks on
26
- Runs: ./scripts/flow setup-hooks install
24
+ - "enable testing" → Match feature `testing`, set `testing.enabled: true`, prompt for mode
25
+ - "make it strict" Match preset `strict`, apply all enforcement settings
26
+ - "turn on storybook" → Match feature `storybook`, set `componentReuse.autoGenerateStorybook: true`
27
+ - "enable TDD" → Match preset `tdd`, enable testing + TDD enforcement
28
+ - "I want full testing" → Match preset `full-testing`, enable all test modes
29
+ - "relax the enforcement" → Match preset `relaxed`, disable strict enforcement
30
+ - "enable parallel" → Match preset `parallel`, enable bulk orchestrator with worktrees
31
+ - "turn off hooks" → Match feature `hooks`, set `hooks.enabled: false`
32
+ - "enable research" → Match feature `research`, set `research.enabled: true`, prompt for depth
33
+ - "enable security scanning" → Match feature `security-scan`, set scanning options
27
34
 
28
- /wogi-config tests-before-commit on
29
- → Updates testing.runBeforeCommit: true
30
- ```
35
+ ## Implementation Steps
36
+
37
+ 1. Load `.workflow/config-reference.json`
38
+ 2. Load current `.workflow/config.json`
39
+ 3. Parse user intent from ARGUMENTS
40
+ 4. Match against features (by name or aliases) and presets (by name or aliases)
41
+ 5. Determine if enabling (`on`, `enable`, `true`, no qualifier) or disabling (`off`, `disable`, `false`, `turn off`)
42
+ 6. For features being **enabled**: apply `dependencies.sets` and ask `dependencies.prompts` if present
43
+ 7. For features being **disabled**: set the `configPath` key to `false`
44
+ 8. For presets: apply all `sets` values directly
45
+ 9. Deep-merge changes into config.json (preserve existing keys, only change specified ones)
46
+ 10. Save config.json
47
+ 11. Display summary:
48
+ ```
49
+ Configuration updated:
50
+
51
+ testing.enabled: false → true
52
+ testing.mode: (not set) → "auto"
53
+ testing.discovery.enabled: false → true
54
+
55
+ 3 settings changed.
56
+ ```
57
+
58
+ ## View Mode (no arguments)
59
+
60
+ When invoked without arguments, display a grouped overview by reading current `.workflow/config.json` and cross-referencing with `.workflow/config-reference.json`:
31
61
 
32
- Output for view:
33
62
  ```
34
- ⚙️ Workflow Configuration
63
+ WogiFlow Configuration
35
64
 
36
- Quality Gates:
37
- feature: tests, appMapUpdate, requestLogEntry
38
- bugfix: tests, requestLogEntry
65
+ Enforcement:
66
+ strict mode .............. on
67
+ task gating .............. off
68
+ scope gating ............. off
69
+ routing gate ............. off
70
+ loop enforcement ......... off
39
71
 
40
72
  Testing:
41
- Run after task: off
42
- Run before commit: off
43
- Browser tests: off
73
+ enabled .................. off
74
+ mode ..................... (not set)
75
+ TDD ...................... off
76
+ discovery ................ off
77
+ scenarios ................ off
78
+ generation ............... off
79
+ webmcp ................... off
80
+
81
+ Research:
82
+ enabled .................. off
83
+ explore phase ............ off
84
+ research depth ........... (not set)
85
+ agents enabled ........... 0/5
86
+
87
+ Execution:
88
+ parallel ................. off
89
+ bulk orchestrator ........ off
90
+ spec mode ................ off
44
91
 
45
92
  Components:
46
- Auto Storybook: off
47
- Require app-map entry: on
93
+ reuse checking ........... off
94
+ auto storybook ........... off
48
95
 
49
96
  Hooks:
50
- Pre-commit: not installed
97
+ enabled .................. off
98
+ session context .......... off
99
+ validation ............... off
100
+ task completed ........... off
101
+
102
+ Automation:
103
+ auto-log ................. on (default)
104
+ auto-update-app-map ...... on (default)
105
+
106
+ Plugins:
107
+ enabled .................. off
108
+
109
+ Security:
110
+ scan before commit ....... off
111
+
112
+ Use /wogi-config [feature|preset] to change settings.
113
+ Available presets: strict, relaxed, fast, research-heavy, full-testing, tdd, parallel
114
+ ```
115
+
116
+ ## Deep-Merge Logic
117
+
118
+ When setting nested config keys:
119
+ ```javascript
120
+ // Set "testing.discovery.enabled" to true
121
+ // This should create the full path if it doesn't exist:
122
+ // { testing: { discovery: { enabled: true } } }
123
+ function deepSet(obj, path, value) {
124
+ const parts = path.split('.');
125
+ let current = obj;
126
+ for (let i = 0; i < parts.length - 1; i++) {
127
+ if (current[parts[i]] === undefined || current[parts[i]] === null) {
128
+ current[parts[i]] = {};
129
+ }
130
+ current = current[parts[i]];
131
+ }
132
+ current[parts[parts.length - 1]] = value;
133
+ }
134
+ ```
51
135
 
52
- Use /wogi-config [setting] on/off to change.
136
+ When reading nested config values:
137
+ ```javascript
138
+ function deepGet(obj, path) {
139
+ const parts = path.split('.');
140
+ let current = obj;
141
+ for (const part of parts) {
142
+ if (current === undefined || current === null) return undefined;
143
+ current = current[part];
144
+ }
145
+ return current;
146
+ }
53
147
  ```
148
+
149
+ ## Matching Algorithm
150
+
151
+ 1. Normalize user input to lowercase, trim whitespace
152
+ 2. Check for exact feature name match (e.g., "testing", "storybook", "tdd")
153
+ 3. Check for exact preset name match (e.g., "strict", "relaxed", "fast")
154
+ 4. Check feature aliases for substring/fuzzy match
155
+ 5. Check preset aliases for substring/fuzzy match
156
+ 6. If multiple matches, prefer exact name matches over alias matches
157
+ 7. If still ambiguous, list all matches and ask user to clarify
158
+
159
+ ## Disable Logic
160
+
161
+ When the user says "off", "disable", "turn off", or "false":
162
+ - For features: set the `configPath` to `false`. Do NOT apply `dependencies.sets` (those are for enabling).
163
+ - For presets: there is no "disable" — suggest the opposite preset (e.g., "strict" → suggest "relaxed")
164
+
165
+ ## Integration with Verification Profile
166
+
167
+ When enabling testing features, check if a verification profile exists:
168
+ - If yes: use detected values (framework, baseUrl, etc.) to auto-populate testing config
169
+ - If no: suggest running `/wogi-test --setup` after enabling
170
+
171
+ ## Multiple Features
172
+
173
+ The user can enable multiple features in one command:
174
+ - "enable testing and hooks" → Match both, apply both sets of dependencies
175
+ - "turn on storybook and tdd" → Match both features
176
+
177
+ ARGUMENTS: {args}
@@ -14,7 +14,8 @@ Run the WogiFlow Auto-Testing Suite — UI verification, API testing, data integ
14
14
  /wogi-test --ui # UI tests only
15
15
  /wogi-test --api # API tests only
16
16
  /wogi-test --integrity # Data integrity chain only
17
- /wogi-test --setup # Configure testing (re-run detection)
17
+ /wogi-test --setup # Configure testing (re-run detection + probe profile)
18
+ /wogi-test --profile # Display current verification profile
18
19
  /wogi-test --generate wf-XXXXXXXX # Regenerate tests for a task
19
20
  ```
20
21
 
@@ -24,14 +25,14 @@ Run the WogiFlow Auto-Testing Suite — UI verification, API testing, data integ
24
25
 
25
26
  Parse `$ARGUMENTS` to extract:
26
27
  - **Task ID**: A `wf-XXXXXXXX` pattern → target task
27
- - **Flags**: `--ui`, `--api`, `--integrity`, `--all`, `--setup`, `--generate`
28
+ - **Flags**: `--ui`, `--api`, `--integrity`, `--all`, `--setup`, `--profile`, `--generate`
28
29
  - **No args**: Use current in-progress task from `ready.json`
29
30
 
30
31
  ```javascript
31
32
  // Pseudo-logic for argument parsing
32
33
  const args = '$ARGUMENTS'.trim().split(/\s+/);
33
34
  let taskId = null;
34
- let flags = { ui: false, api: false, integrity: false, all: false, setup: false, generate: false };
35
+ let flags = { ui: false, api: false, integrity: false, all: false, setup: false, profile: false, generate: false };
35
36
 
36
37
  for (const arg of args) {
37
38
  if (/^wf-[a-f0-9]{8}$/i.test(arg)) {
@@ -41,6 +42,7 @@ for (const arg of args) {
41
42
  else if (arg === '--integrity') flags.integrity = true;
42
43
  else if (arg === '--all') flags.all = true;
43
44
  else if (arg === '--setup') flags.setup = true;
45
+ else if (arg === '--profile') flags.profile = true;
44
46
  else if (arg === '--generate') flags.generate = true;
45
47
  }
46
48
  ```
@@ -51,14 +53,14 @@ If no task ID provided, read `.workflow/state/ready.json` and use the first task
51
53
 
52
54
  Read config via:
53
55
  ```bash
54
- node -e "const { getConfig } = require('wogiflow/scripts/flow-utils'); const c = getConfig(); console.log(JSON.stringify(c.testing || {}))"
56
+ node -e "const { getConfig } = require('./scripts/flow-utils'); const c = getConfig(); console.log(JSON.stringify(c.testing || {}))"
55
57
  ```
56
58
 
57
59
  If `config.testing.enabled` is `false` (or not set), **auto-trigger the setup flow** — do NOT just show info and stop. The user ran `/wogi-test` because they want to test. Guide them through setup seamlessly:
58
60
 
59
61
  **Step 2a: Detect project type**
60
62
  ```bash
61
- node -e "const { detectProjectType } = require('wogiflow/scripts/flow-project-analyzer'); const r = detectProjectType(); console.log(JSON.stringify(r))"
63
+ node -e "const { detectProjectType } = require('./scripts/flow-project-analyzer'); const r = detectProjectType(); console.log(JSON.stringify(r))"
62
64
  ```
63
65
 
64
66
  **Step 2b: Show detection results and ask ONE question**
@@ -88,10 +90,11 @@ Shall I enable testing and install what's needed? [Y/n/customize]
88
90
  - **Yes (or enter)** → Proceed to auto-configure:
89
91
  1. Determine mode from detection: hasUI+hasAPI → `"full"`, hasUI only → `"ui"`, hasAPI only → `"api"`, neither → `"unit"`
90
92
  2. Update `.workflow/config.json`: set `testing.enabled: true`, `testing.mode`, and `testing.detected` fields
91
- 3. Check dependencies: `node -e "const d = require('wogiflow/scripts/flow-testing-deps'); console.log(JSON.stringify(d.checkDeps('[mode]')))"`
92
- 4. If deps missing → install them: `node -e "const d = require('wogiflow/scripts/flow-testing-deps'); console.log(JSON.stringify(d.installDeps('[mode]')))"`
93
+ 3. Check dependencies: `node -e "const d = require('./scripts/flow-testing-deps'); console.log(JSON.stringify(d.checkDeps('[mode]')))"`
94
+ 4. If deps missing → install them: `node -e "const d = require('./scripts/flow-testing-deps'); console.log(JSON.stringify(d.installDeps('[mode]')))"`
93
95
  5. If UI mode → also configure Playwright MCP in settings (show user the MCP config to add)
94
- 6. Show confirmation and **continue to Step 5 (run tests)**
96
+ 6. Generate verification profile: `node -e "const { probeProject } = require('./scripts/flow-verification-profile'); probeProject().then(() => console.log('Profile generated')).catch(err => console.error(err.message))"`
97
+ 7. Show confirmation and **continue to Step 5 (run tests)**
95
98
 
96
99
  - **Customize** → Ask for:
97
100
  - Preferred mode (ui/api/full/unit)
@@ -107,6 +110,24 @@ Shall I enable testing and install what's needed? [Y/n/customize]
107
110
 
108
111
  **IMPORTANT**: After successful setup, do NOT stop. Continue directly to Step 5 and run the tests the user originally asked for. The whole point is that `/wogi-test` works in one invocation even on first use.
109
112
 
113
+ ### Step 2.5: Handle `--profile` Flag (Display Verification Profile)
114
+
115
+ If `--profile` was passed, display the current verification profile and **STOP**:
116
+
117
+ ```bash
118
+ node -e "
119
+ const { loadProfile } = require('./scripts/flow-verification-profile');
120
+ const profile = loadProfile();
121
+ if (!profile) {
122
+ console.log('No verification profile found. Run: /wogi-test --setup');
123
+ } else {
124
+ console.log(JSON.stringify(profile, null, 2));
125
+ }
126
+ "
127
+ ```
128
+
129
+ Format the output as a readable summary showing detected capabilities (test runner, E2E, API, Docker, database, CI, etc.) and the recommended verification strategy per task type.
130
+
110
131
  ### Step 3: Handle `--setup` Flag (Reconfigure)
111
132
 
112
133
  If `--setup` was passed, this is an explicit reconfiguration request. Use the same flow as Step 2 (auto-setup), but ALWAYS run it even if testing is already enabled. This lets users:
@@ -114,7 +135,22 @@ If `--setup` was passed, this is an explicit reconfiguration request. Use the sa
114
135
  - Re-detect after adding backend/frontend to their project
115
136
  - Install missing deps after a fresh `npm install` that lost node_modules
116
137
 
117
- After reconfiguration, show confirmation:
138
+ After reconfiguration, also regenerate the verification profile:
139
+ ```bash
140
+ node -e "
141
+ const { probeProject } = require('./scripts/flow-verification-profile');
142
+ probeProject().then(p => console.log(JSON.stringify({ success: true, detected: {
143
+ testRunner: p.testRunner.framework || 'none',
144
+ e2e: p.e2e.framework || 'none',
145
+ api: p.api.detected,
146
+ docker: p.docker.available,
147
+ database: p.database.type || 'none',
148
+ ci: p.ci.platform || 'none'
149
+ }}))).catch(err => console.error(JSON.stringify({ error: err.message })));
150
+ "
151
+ ```
152
+
153
+ Show confirmation:
118
154
  ```
119
155
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
120
156
  Testing Reconfigured ✓
@@ -124,6 +160,7 @@ Mode: [mode] (was: [old mode])
124
160
  UI provider: playwright-mcp
125
161
  API provider: direct-http (zero deps)
126
162
  Dependencies: all installed ✓
163
+ Verification profile: regenerated ✓
127
164
 
128
165
  Run /wogi-test to execute tests.
129
166
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
@@ -135,7 +172,7 @@ If `--generate` was passed:
135
172
 
136
173
  ```bash
137
174
  node -e "
138
- const { generateTestScaffold } = require('wogiflow/scripts/flow-test-generate');
175
+ const { generateTestScaffold } = require('./scripts/flow-test-generate');
139
176
  const result = generateTestScaffold('TASK_ID');
140
177
  console.log(JSON.stringify(result, null, 2));
141
178
  "
@@ -158,7 +195,7 @@ Determine which test types to run:
158
195
  #### Run UI Tests
159
196
  ```bash
160
197
  node -e "
161
- const { runUITests } = require('wogiflow/scripts/flow-test-ui');
198
+ const { runUITests } = require('./scripts/flow-test-ui');
162
199
  runUITests('TASK_ID').then(r => console.log(JSON.stringify(r))).catch(err => console.error(JSON.stringify({error: err.message})));
163
200
  "
164
201
  ```
@@ -166,7 +203,7 @@ runUITests('TASK_ID').then(r => console.log(JSON.stringify(r))).catch(err => con
166
203
  #### Run API Tests
167
204
  ```bash
168
205
  node -e "
169
- const { runAPITests } = require('wogiflow/scripts/flow-test-api');
206
+ const { runAPITests } = require('./scripts/flow-test-api');
170
207
  runAPITests('TASK_ID').then(r => console.log(JSON.stringify(r))).catch(err => console.error(JSON.stringify({error: err.message})));
171
208
  "
172
209
  ```
@@ -174,7 +211,7 @@ runAPITests('TASK_ID').then(r => console.log(JSON.stringify(r))).catch(err => co
174
211
  #### Run Integrity Tests
175
212
  ```bash
176
213
  node -e "
177
- const { runIntegrityTests } = require('wogiflow/scripts/flow-test-integrity');
214
+ const { runIntegrityTests } = require('./scripts/flow-test-integrity');
178
215
  runIntegrityTests('TASK_ID').then(r => console.log(JSON.stringify(r))).catch(err => console.error(JSON.stringify({error: err.message})));
179
216
  "
180
217
  ```
@@ -241,3 +278,5 @@ Generated Tests: [passed]/[total] passed
241
278
  - All test scripts gracefully handle missing dependencies and report what's needed
242
279
  - Reports are saved to `.workflow/verifications/` for quality gate consumption
243
280
  - The quality gates `generatedTestsPass`, `uiVerification`, and `apiVerification` in `flow-done.js` will automatically run these same tests when closing a task via `/wogi-start`
281
+ - **Verification Profile**: The `--setup` flag (and first-time auto-setup) generates a verification profile at `.workflow/state/verification-profile.json`. This profile auto-detects test runners, E2E frameworks, OpenAPI specs, Docker, databases, CI config, and more. Test scripts (`flow-test-api.js`, `flow-test-ui.js`, `flow-test-integrity.js`) read from this profile to provide smart defaults (base URLs, start commands, spec files) instead of using hardcoded values. Explicit `config.json` overrides always take precedence over profile-detected values.
282
+ - Use `--profile` to display the current verification profile without running tests
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wogiflow",
3
- "version": "1.9.3",
3
+ "version": "1.9.4",
4
4
  "description": "AI-powered development workflow management system with multi-model support",
5
5
  "main": "lib/index.js",
6
6
  "bin": {
@@ -36,6 +36,14 @@ const { autoArchiveIfNeeded } = require('./flow-log-manager');
36
36
  // v1.9.0 regression testing (legacy - now in workflow steps)
37
37
  const { runRegressionTests } = require('./flow-regression');
38
38
 
39
+ // v1.10 smart test discovery + SWE-bench dual gate
40
+ let testDiscovery;
41
+ try {
42
+ testDiscovery = require('./flow-test-discovery');
43
+ } catch (err) {
44
+ testDiscovery = null;
45
+ }
46
+
39
47
  // v2.2 modular workflow steps
40
48
  const { runSteps, getAllSteps } = require('./flow-workflow-steps');
41
49
 
@@ -110,6 +118,9 @@ try {
110
118
  hypothesisGenerator = null;
111
119
  }
112
120
 
121
+ // v5.2 verification profiles
122
+ const { loadProfile: loadVerificationProfile } = require('./flow-verification-profile');
123
+
113
124
  // Path for last failure artifact
114
125
  const LAST_FAILURE_PATH = path.join(PATHS.state, 'last-failure.json');
115
126
 
@@ -197,6 +208,9 @@ function runQualityGates(taskId, taskType) {
197
208
  console.log(color('yellow', 'Running quality gates...'));
198
209
  console.log('');
199
210
 
211
+ // Load verification profile — warn if missing and testing gates are configured
212
+ const verificationProfile = loadVerificationProfile();
213
+
200
214
  const config = getConfig();
201
215
  // Use task-type-specific gates, fall back to feature gates, then empty
202
216
  const normalizedType = (taskType || 'feature').toLowerCase();
@@ -206,6 +220,15 @@ function runQualityGates(taskId, taskType) {
206
220
  const failed = [];
207
221
  const errors = {}; // Store error output for correction artifact
208
222
 
223
+ // Warn if testing gates are present but no verification profile exists
224
+ if (!verificationProfile) {
225
+ const hasTestingGates = gates.some(g => ['generatedTestsPass', 'uiVerification', 'apiVerification'].includes(g));
226
+ if (hasTestingGates && config.testing?.enabled) {
227
+ console.log(color('yellow', ' Note: No verification profile found. Run --setup to auto-detect project test infrastructure.'));
228
+ console.log('');
229
+ }
230
+ }
231
+
209
232
  // Cache outstanding findings result — used by both outstandingFindings and preRelease gates
210
233
  let cachedOutstandingFindings = null;
211
234
  function getOutstandingFindings() {
@@ -621,10 +644,63 @@ function runQualityGates(taskId, taskType) {
621
644
  } catch (err) {
622
645
  console.log(` ${color('yellow', '⚠')} ${gate} (error: ${err.message})`);
623
646
  }
647
+
648
+ // Also check scenario verification results if available
649
+ if (!isUI && validateTaskId(taskId)) {
650
+ const scenarioReportPath = path.join(PATHS.workflow, 'verifications', `${taskId}-scenarios.json`);
651
+ if (fs.existsSync(scenarioReportPath)) {
652
+ try {
653
+ const scenarioReport = safeJsonParse(scenarioReportPath, null);
654
+ if (scenarioReport && scenarioReport.summary) {
655
+ const ss = scenarioReport.summary;
656
+ if (ss.failed === 0 && ss.total > 0) {
657
+ console.log(` ${color('green', '✓')} scenarioVerification (${ss.passed}/${ss.total} scenarios passed)`);
658
+ } else if (ss.failed > 0) {
659
+ console.log(` ${color('red', '✗')} scenarioVerification (${ss.failed} scenarios failed)`);
660
+ const failedScenarios = (scenarioReport.scenarios || []).filter(s => !s.passed);
661
+ for (const sc of failedScenarios.slice(0, 5)) {
662
+ console.log(color('dim', ` - ${sc.name || 'unnamed scenario'}: ${sc.error || 'assertions failed'}`));
663
+ }
664
+ }
665
+ }
666
+ } catch (err) {
667
+ // Non-fatal — scenario report parsing failed
668
+ }
669
+ }
670
+ }
624
671
  }
625
672
  } else {
626
673
  console.log(` ${color('dim', '·')} ${gate} (testing disabled or mode excludes ${isUI ? 'UI' : 'API'})`);
627
674
  }
675
+ } else if (gate === 'testDiscovery') {
676
+ // v1.10: Smart test discovery + SWE-bench dual gate
677
+ const discoveryConfig = config.testing?.discovery || {};
678
+ if (discoveryConfig.enabled) {
679
+ if (testDiscovery && typeof testDiscovery.runTestDiscoveryGate === 'function') {
680
+ try {
681
+ console.log(' Running test discovery gate...');
682
+ const discoveryResult = testDiscovery.runTestDiscoveryGate(taskId, PATHS.root);
683
+ if (discoveryResult.passed) {
684
+ console.log(` ${color('green', '✓')} testDiscovery (${discoveryResult.message})`);
685
+ } else {
686
+ console.log(` ${color('red', '✗')} testDiscovery (${discoveryResult.message})`);
687
+ if (discoveryResult.report?.passToPass?.failed) {
688
+ for (const f of discoveryResult.report.passToPass.failed.slice(0, 5)) {
689
+ console.log(color('dim', ` - ${f}`));
690
+ }
691
+ }
692
+ errors.testDiscovery = discoveryResult.message;
693
+ failed.push('testDiscovery');
694
+ }
695
+ } catch (err) {
696
+ console.log(` ${color('yellow', '⚠')} testDiscovery (error: ${truncateOutput(err.message, 3, 200)})`);
697
+ }
698
+ } else {
699
+ console.log(` ${color('yellow', '⚠')} testDiscovery (module not available — install flow-test-discovery.js)`);
700
+ }
701
+ } else {
702
+ console.log(` ${color('dim', '·')} testDiscovery (disabled — set testing.discovery.enabled in config)`);
703
+ }
628
704
  } else {
629
705
  console.log(` ${color('yellow', '○')} ${gate} (manual check)`);
630
706
  }