wogiflow 1.9.6 → 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.
Files changed (74) hide show
  1. package/.claude/commands/wogi-onboard.md +1 -1
  2. package/.claude/commands/wogi-research.md +70 -1
  3. package/.claude/commands/wogi-start.md +4 -3
  4. package/.claude/docs/config-reference.md +2 -2
  5. package/.claude/docs/knowledge-base/02-task-execution/03-verification.md +3 -3
  6. package/.claude/docs/knowledge-base/02-task-execution/05-session-review.md +1 -1
  7. package/.claude/docs/knowledge-base/02-task-execution/README.md +1 -1
  8. package/.claude/docs/knowledge-base/02-task-execution/trade-offs.md +1 -1
  9. package/.claude/docs/knowledge-base/configuration/README.md +1 -1
  10. package/.claude/docs/knowledge-base/configuration/all-options.md +2 -2
  11. package/.workflow/templates/claude-md.hbs +3 -6
  12. package/lib/utils.js +1 -1
  13. package/package.json +2 -5
  14. package/scripts/flow-config-defaults.js +1 -1
  15. package/scripts/flow-consistency-check.js +0 -4
  16. package/scripts/flow-context-estimator.js +4 -20
  17. package/scripts/flow-correct.js +2 -1
  18. package/scripts/flow-decision-tracker.js +2 -2
  19. package/scripts/flow-done.js +123 -6
  20. package/scripts/flow-entropy-monitor.js +3 -24
  21. package/scripts/flow-export-scanner.js +3 -3
  22. package/scripts/flow-health.js +3 -2
  23. package/scripts/flow-hybrid-test.js +2 -3
  24. package/scripts/flow-long-input-stories.js +4 -6
  25. package/scripts/flow-long-input.js +5 -8
  26. package/scripts/flow-memory-compactor.js +1 -13
  27. package/scripts/flow-memory-db.js +1 -1
  28. package/scripts/flow-memory-sync.js +1 -17
  29. package/scripts/flow-orchestrate-llm.js +3 -7
  30. package/scripts/flow-orchestrate.js +2 -13
  31. package/scripts/flow-pattern-extractor.js +3 -17
  32. package/scripts/flow-peer-review.js +4 -12
  33. package/scripts/flow-plugin-registry.js +2 -2
  34. package/scripts/flow-project-analyzer.js +4 -4
  35. package/scripts/flow-providers.js +2 -7
  36. package/scripts/flow-safety.js +6 -10
  37. package/scripts/flow-script-resolver.js +4 -16
  38. package/scripts/flow-skill-freshness.js +3 -12
  39. package/scripts/flow-skill-generator.js +14 -24
  40. package/scripts/flow-strict-adherence.js +2 -2
  41. package/scripts/flow-task-analyzer.js +3 -3
  42. package/scripts/flow-test-discovery.js +3 -3
  43. package/scripts/flow-utils.js +1 -0
  44. package/scripts/flow-webmcp-generator.js +1 -1
  45. package/scripts/flow-workflow-steps.js +31 -23
  46. package/scripts/hooks/core/component-check.js +22 -7
  47. package/scripts/hooks/core/observation-capture.js +7 -4
  48. package/scripts/hooks/core/task-gate.js +2 -2
  49. package/scripts/hooks/entry/claude-code/post-tool-use.js +10 -8
  50. package/scripts/hooks/entry/claude-code/pre-tool-use.js +34 -41
  51. package/scripts/hooks/entry/claude-code/session-start.js +4 -12
  52. package/scripts/hooks/entry/shared/read-stdin.js +33 -0
  53. package/.claude/rules/_internal/README.md +0 -64
  54. package/.claude/rules/_internal/document-structure.md +0 -77
  55. package/.claude/rules/_internal/dual-repo-management.md +0 -174
  56. package/.claude/rules/_internal/feature-refactoring-cleanup.md +0 -87
  57. package/.claude/rules/_internal/github-releases.md +0 -71
  58. package/.claude/rules/_internal/model-management.md +0 -35
  59. package/.claude/rules/_internal/self-maintenance.md +0 -87
  60. package/.claude/rules/architecture/component-reuse.md +0 -38
  61. package/.claude/rules/code-style/naming-conventions.md +0 -52
  62. package/.claude/rules/operations/git-workflows.md +0 -92
  63. package/.claude/rules/security/security-patterns.md +0 -176
  64. package/.claude/skills/figma-analyzer/knowledge/learnings.md +0 -11
  65. package/.workflow/specs/architecture.md.template +0 -24
  66. package/.workflow/specs/stack.md.template +0 -33
  67. package/.workflow/specs/testing.md.template +0 -36
  68. package/scripts/flow-done +0 -151
  69. package/scripts/flow-file-ops.js +0 -307
  70. package/scripts/flow-health +0 -185
  71. package/scripts/flow-ready +0 -82
  72. package/scripts/flow-start +0 -74
  73. package/scripts/flow-status +0 -110
  74. package/scripts/flow-story +0 -105
@@ -701,7 +701,7 @@ Display:
701
701
  for (const reqs of [featureReqs, bugfixReqs, refactorReqs]) {
702
702
  reqs.push('requestLogEntry');
703
703
  }
704
- featureReqs.push('appMapUpdate');
704
+ featureReqs.push('registryUpdate');
705
705
 
706
706
  config.qualityGates = {
707
707
  feature: { require: featureReqs },
@@ -25,6 +25,46 @@ This command is **automatically triggered** (when strict mode is enabled) for:
25
25
  5. **Integration Questions**: "How to integrate X with Y?"
26
26
  6. **Comparison Questions**: "What can we learn from X?", "How does X compare to Y?"
27
27
 
28
+ ## Step 0: Config Loading (MANDATORY — before all phases)
29
+
30
+ Before ANY research phase, read the project's config to determine depth, format, and verification requirements:
31
+
32
+ ```bash
33
+ cat .workflow/config.json | grep -A 30 '"research"'
34
+ ```
35
+
36
+ **Extract and apply these settings:**
37
+
38
+ 1. **Determine depth** (in priority order):
39
+ - CLI flag (`--deep`, `--quick`, etc.) → use that depth
40
+ - If auto-triggered (no flag): classify question type and look up `research.triggers`:
41
+ - Capability question ("Does X support Y?") → `triggers.capabilityQuestions` (default: `"standard"`)
42
+ - Feasibility question ("Is it possible to...") → `triggers.feasibilityQuestions` (default: `"deep"`)
43
+ - Existence question ("Is there a...") → `triggers.existenceQuestions` (default: `"standard"`)
44
+ - Architecture question ("How does X work?") → `triggers.architectureQuestions` (default: `"deep"`)
45
+ - Integration question ("How to integrate X with Y?") → `triggers.integrationQuestions` (default: `"deep"`)
46
+ - Comparison question ("How does X compare to Y?") → `triggers.comparisonQuestions` (default: `"deep"`)
47
+ - Fallback: `research.defaultDepth` (default: `"standard"`)
48
+
49
+ 2. **Apply format flags** from config:
50
+ - `requireVerificationFormat: true` → ALL assumptions must have `[VERIFIED]`/`[UNVERIFIED]` markers
51
+ - `requireCitations: true` → ALL claims must have an Evidence Chain entry
52
+ - `assumptionTracking: true` → Assumption Stack table is MANDATORY in output
53
+ - `negativeEvidenceRule: true` → Negative claims require exhaustive search evidence
54
+
55
+ 3. **Display header block** (MANDATORY):
56
+ ```markdown
57
+ ## Research Report
58
+ **Question:** [the question]
59
+ **Depth:** [resolved depth from step 1]
60
+ **Flow:** [Standard/Comparison]
61
+ **Config applied:** requireVerification=[yes/no], citations=[yes/no], assumptionTracking=[yes/no]
62
+ ```
63
+
64
+ **If config.json has no `research` section or is unreadable**: use defaults (depth: standard, all format flags: true).
65
+
66
+ ---
67
+
28
68
  ## Research Protocol Phases
29
69
 
30
70
  There are two flows depending on question type:
@@ -199,6 +239,7 @@ In `.workflow/config.json`:
199
239
  "enabled": true,
200
240
  "defaultDepth": "standard",
201
241
  "autoTrigger": true,
242
+ "requireVerificationFormat": true,
202
243
  "maxTokensPerDepth": {
203
244
  "quick": 5000,
204
245
  "standard": 20000,
@@ -210,7 +251,15 @@ In `.workflow/config.json`:
210
251
  "cacheExpiryHours": 24,
211
252
  "budgetMode": "soft",
212
253
  "negativeEvidenceRule": true,
213
- "assumptionTracking": true
254
+ "assumptionTracking": true,
255
+ "triggers": {
256
+ "capabilityQuestions": "standard",
257
+ "feasibilityQuestions": "deep",
258
+ "existenceQuestions": "standard",
259
+ "architectureQuestions": "deep",
260
+ "integrationQuestions": "deep",
261
+ "comparisonQuestions": "deep"
262
+ }
214
263
  }
215
264
  }
216
265
  ```
@@ -269,6 +318,26 @@ When `research.requireCitations` is enabled and `research.autoTrigger` is true:
269
318
  - Claims without citations are flagged
270
319
  - Negative claims require exhaustive search evidence
271
320
 
321
+ ## Output Checklist (MANDATORY — self-verify before presenting)
322
+
323
+ Before presenting ANY research report, verify ALL of these are present. If any is missing, add it before outputting.
324
+
325
+ | # | Check | Required When |
326
+ |---|-------|---------------|
327
+ | 1 | **Header block** with Question, Depth, Flow, Config applied | Always |
328
+ | 2 | **Conclusion** section with direct answer | Always |
329
+ | 3 | **Assumption Stack** table with `[VERIFIED]`/`[UNVERIFIED]` markers | `assumptionTracking: true` (default) |
330
+ | 4 | **Evidence Chain** table with Claim, Source Type, Source Location, Confidence | `requireCitations: true` (default) |
331
+ | 5 | **Confidence level** (HIGH/MEDIUM/LOW) | Always |
332
+ | 6 | **Searches Performed** list (web + local) | Always |
333
+ | 7 | **Negative Evidence format** for any "X doesn't exist" claims | `negativeEvidenceRule: true` (default) |
334
+ | 8 | **Comparison table** (External Feature / Local Equivalent / Status) | Comparison flow only |
335
+ | 9 | **Recommendation Verification** (EXISTS/PARTIAL/MISSING markers) | Comparison flow only |
336
+
337
+ **Self-check prompt**: "Have I included all mandatory sections per config? Is every assumption marked? Is every claim cited?"
338
+
339
+ If the report is missing any required section, DO NOT present it — add the missing section first.
340
+
272
341
  ## CLI Compatibility
273
342
 
274
343
  This command currently supports Claude Code only.
@@ -302,7 +302,7 @@ If violations found: fix, re-run, only proceed when all pass. Violations auto-re
302
302
  **First**: Run `node node_modules/wogiflow/scripts/flow-spec-verifier.js verify wf-XXXXXXXX` — verify all spec deliverables exist. If missing → STOP, create them.
303
303
 
304
304
  **Then**: Check `config.qualityGates` for task type. Gates are type-specific:
305
- - **feature**: loopComplete, tests, appMapUpdate, requestLogEntry, integrationWiring, standardsCompliance
305
+ - **feature**: loopComplete, tests, registryUpdate, requestLogEntry, integrationWiring, standardsCompliance
306
306
  - **bugfix**: loopComplete, tests, requestLogEntry, standardsCompliance, learningEnforcement
307
307
  - **refactor**: loopComplete, tests, noNewFeatures, smokeTest, standardsCompliance
308
308
  - **chore**: requestLogEntry, outstandingFindings
@@ -311,7 +311,8 @@ If violations found: fix, re-run, only proceed when all pass. Violations auto-re
311
311
 
312
312
  **Fallback behavior**: Task types not listed above (docs, style, test, perf, etc.) inherit the **feature** gates. This is intentional — feature gates are the most comprehensive and serve as a safe default.
313
313
 
314
- **Key automated gates** (v1.9.2):
314
+ **Key automated gates** (v1.9.7):
315
+ - `registryUpdate` → runs `flow registry-manager scan` on ALL active registries (app-map, function-map, api-map, schema-map, service-map). Auto-updates maps when new entries found. Replaces old `appMapUpdate` no-op gate.
315
316
  - `integrationWiring` → calls `verifyWiring()` — checks created files are imported/used
316
317
  - `standardsCompliance` → calls `runTaskStandardsCheck()` — checks naming, security, decisions.md rules
317
318
  - `outstandingFindings` → reads `last-review.json` — blocks if unresolved critical/high findings exist
@@ -328,7 +329,7 @@ Reflection: "Have I introduced any bugs or regressions?"
328
329
  1. Reflection: "Does this match what the user asked for?"
329
330
  2. Close out all TodoWrite items for this task
330
331
  3. Move task to recentlyCompleted in ready.json
331
- 4. Update request-log.md, app-map.md, function-map.md, api-map.md as needed
332
+ 4. Registry maps auto-updated by `registryUpdate` quality gate (runs `flow registry-manager scan` on all active registries — app-map, function-map, api-map, schema-map, service-map)
332
333
  5. If `config.webmcp.enabled` and UI files created: run `node node_modules/wogiflow/scripts/flow-webmcp-generator.js scan`
333
334
  6. Commit: `feat: Complete wf-XXXXXXXX - [title]`
334
335
  7. Show completion summary
@@ -163,7 +163,7 @@ Customize which checks are required per task type.
163
163
  {
164
164
  "qualityGates": {
165
165
  "feature": {
166
- "require": ["loopComplete", "tests", "appMapUpdate", "requestLogEntry"],
166
+ "require": ["loopComplete", "tests", "registryUpdate", "requestLogEntry"],
167
167
  "optional": ["review"]
168
168
  },
169
169
  "bugfix": {
@@ -174,7 +174,7 @@ Customize which checks are required per task type.
174
174
  }
175
175
  ```
176
176
 
177
- **Available gates**: `loopComplete`, `tests`, `generatedTestsPass`, `uiVerification`, `apiVerification`, `appMapUpdate`, `requestLogEntry`, `integrationWiring`, `standardsCompliance`, `outstandingFindings`, `preRelease`, `noNewFeatures`, `smokeTest`, `learningEnforcement`, `review`, `docs`, `webmcpVerification`
177
+ **Available gates**: `loopComplete`, `tests`, `generatedTestsPass`, `uiVerification`, `apiVerification`, `registryUpdate`, `requestLogEntry`, `integrationWiring`, `standardsCompliance`, `outstandingFindings`, `preRelease`, `noNewFeatures`, `smokeTest`, `learningEnforcement`, `review`, `docs`, `webmcpVerification`
178
178
 
179
179
  **Task types**: `feature`, `bugfix`, `refactor`, `chore`, `release`, `fix`
180
180
 
@@ -62,7 +62,7 @@ Quality gates are requirements that must pass before a task can be completed.
62
62
  {
63
63
  "qualityGates": {
64
64
  "feature": {
65
- "require": ["tests", "appMapUpdate", "requestLogEntry"],
65
+ "require": ["tests", "registryUpdate", "requestLogEntry"],
66
66
  "optional": ["review", "docs"]
67
67
  },
68
68
  "bugfix": {
@@ -84,7 +84,7 @@ Quality gates are requirements that must pass before a task can be completed.
84
84
  | `tests` | npm test passes |
85
85
  | `lint` | npm run lint passes (with auto-fix) |
86
86
  | `typecheck` | npm run typecheck passes |
87
- | `appMapUpdate` | New components added to app-map.md |
87
+ | `registryUpdate` | All registry maps (app-map, function-map, api-map, schema-map, service-map) auto-scanned |
88
88
  | `requestLogEntry` | Task logged in request-log.md |
89
89
  | `noNewFeatures` | (Refactor) No new functionality added |
90
90
  | `integrationWiring` | Created files are imported/used somewhere (not orphaned) |
@@ -134,7 +134,7 @@ Running quality gates...
134
134
  ✓ lint passed (auto-fixed)
135
135
  ✓ typecheck passed
136
136
  ✓ requestLogEntry (found in request-log)
137
- appMapUpdate (verify manually if components created)
137
+ registryUpdate (auto-scanned: app-map.md updated)
138
138
 
139
139
  All gates passed!
140
140
  ```
@@ -196,7 +196,7 @@ Session review can be added to quality gates:
196
196
  {
197
197
  "qualityGates": {
198
198
  "feature": {
199
- "require": ["tests", "sessionReview", "appMapUpdate"]
199
+ "require": ["tests", "sessionReview", "registryUpdate"]
200
200
  }
201
201
  }
202
202
  }
@@ -122,7 +122,7 @@ Comprehensive code review before finalizing changes.
122
122
  },
123
123
  "qualityGates": {
124
124
  "feature": {
125
- "require": ["tests", "appMapUpdate", "requestLogEntry"]
125
+ "require": ["tests", "registryUpdate", "requestLogEntry"]
126
126
  }
127
127
  }
128
128
  }
@@ -141,7 +141,7 @@ Every configuration decision in WogiFlow involves trade-offs. Understanding thes
141
141
  {
142
142
  "qualityGates": {
143
143
  "feature": {
144
- "require": ["tests", "lint", "typecheck", "appMapUpdate", "requestLogEntry", "review"]
144
+ "require": ["tests", "lint", "typecheck", "registryUpdate", "requestLogEntry", "review"]
145
145
  }
146
146
  }
147
147
  }
@@ -127,7 +127,7 @@ cat .workflow/config.json
127
127
  },
128
128
  "qualityGates": {
129
129
  "feature": {
130
- "require": ["tests", "appMapUpdate", "requestLogEntry", "review"]
130
+ "require": ["tests", "registryUpdate", "requestLogEntry", "review"]
131
131
  }
132
132
  }
133
133
  }
@@ -410,7 +410,7 @@ Per-task-type quality requirements that must pass before task completion.
410
410
  "qualityGates": {
411
411
  "preTaskBaseline": { "enabled": false },
412
412
  "feature": {
413
- "require": ["loopComplete", "tests", "appMapUpdate", "requestLogEntry", "integrationWiring", "standardsCompliance"],
413
+ "require": ["loopComplete", "tests", "registryUpdate", "requestLogEntry", "integrationWiring", "standardsCompliance"],
414
414
  "optional": ["review", "docs", "webmcpVerification"]
415
415
  },
416
416
  "bugfix": {
@@ -433,7 +433,7 @@ Per-task-type quality requirements that must pass before task completion.
433
433
  | `qualityGates.bugfix.require` | string[] | See above | Required gates for bugfix tasks |
434
434
  | `qualityGates.refactor.require` | string[] | See above | Required gates for refactor tasks |
435
435
 
436
- Available gate values: `loopComplete`, `tests`, `appMapUpdate`, `requestLogEntry`, `integrationWiring`, `standardsCompliance`, `learningEnforcement`, `resolutionPopulated`, `noNewFeatures`, `smokeTest`, `review`, `docs`, `webmcpVerification`.
436
+ Available gate values: `loopComplete`, `tests`, `registryUpdate`, `requestLogEntry`, `integrationWiring`, `standardsCompliance`, `learningEnforcement`, `resolutionPopulated`, `noNewFeatures`, `smokeTest`, `review`, `docs`, `webmcpVerification`.
437
437
 
438
438
  ---
439
439
 
@@ -210,12 +210,9 @@ When creating tasks programmatically, always call `generateTaskId(title)` — ne
210
210
 
211
211
  ### After Completing:
212
212
  1. Update `request-log.md` with tags
213
- 2. Update `app-map.md` if components created/deleted/renamed
214
- 3. Update `function-map.md` if utilities created/deleted/renamed — run `npx flow function-index scan`
215
- 4. Update `api-map.md` if endpoints created/deleted/renamed — run `npx flow api-index scan`
216
- 5. Update other active registry maps if relevant — run `npx flow registry-manager scan`
217
- 6. Run quality gates (lint, typecheck, test)
218
- 7. Provide completion report
213
+ 2. Registry maps (app-map, function-map, api-map, schema-map, service-map) are **auto-updated** by the `registryUpdate` quality gate — it runs `flow registry-manager scan` on all active registries
214
+ 3. Run quality gates (lint, typecheck, test)
215
+ 4. Provide completion report
219
216
 
220
217
  ## Auto-Validation (CRITICAL)
221
218
 
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 safeJsonParseFile from flow-file-ops.js
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.6",
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.10.0"
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": {
@@ -302,7 +302,7 @@ const CONFIG_DEFAULTS = {
302
302
  qualityGates: {
303
303
  preTaskBaseline: { enabled: false },
304
304
  feature: {
305
- require: ['loopComplete', 'tests', 'generatedTestsPass', 'uiVerification', 'apiVerification', 'appMapUpdate', 'requestLogEntry', 'integrationWiring', 'standardsCompliance'],
305
+ require: ['loopComplete', 'tests', 'generatedTestsPass', 'uiVerification', 'apiVerification', 'registryUpdate', 'requestLogEntry', 'integrationWiring', 'standardsCompliance'],
306
306
  optional: ['review', 'docs', 'webmcpVerification']
307
307
  },
308
308
  bugfix: {
@@ -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 (!isValidTaskId(taskId)) {
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 (!isValidTaskId(taskId)) {
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 (!isValidTaskId(taskId)) {
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,
@@ -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 = JSON.parse(fs.readFileSync(PATHS.config, 'utf-8'));
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 = `amend-${crypto.randomBytes(4).toString('hex')}`;
166
+ const id = generateHashId('amend', '', '');
167
167
  const amendment = {
168
168
  id,
169
169
  timestamp: new Date().toISOString(),
@@ -121,6 +121,20 @@ try {
121
121
  // v5.2 verification profiles
122
122
  const { loadProfile: loadVerificationProfile } = require('./flow-verification-profile');
123
123
 
124
+ // v1.9.7 registry map update gate — lazy-loaded to avoid startup cost
125
+ // Loaded inside the registryUpdate gate branch only
126
+ let _registryManagerModule = undefined; // undefined = not yet loaded, null = load failed
127
+ function getRegistryManager() {
128
+ if (_registryManagerModule === undefined) {
129
+ try {
130
+ _registryManagerModule = require('./flow-registry-manager');
131
+ } catch (err) {
132
+ _registryManagerModule = null;
133
+ }
134
+ }
135
+ return _registryManagerModule;
136
+ }
137
+
124
138
  // Path for last failure artifact
125
139
  const LAST_FAILURE_PATH = path.join(PATHS.state, 'last-failure.json');
126
140
 
@@ -196,7 +210,7 @@ function checkOutstandingFindings() {
196
210
  */
197
211
  function runQualityGates(taskId, taskType) {
198
212
  // Validate taskId before using in any path construction
199
- if (taskId && !validateTaskId(taskId)) {
213
+ if (taskId && !validateTaskId(taskId).valid) {
200
214
  console.log(color('red', `Invalid task ID format: ${String(taskId).slice(0, 30)}`));
201
215
  return { passed: false, failed: ['invalidTaskId'], errors: { invalidTaskId: 'Task ID failed validation' } };
202
216
  }
@@ -338,8 +352,111 @@ function runQualityGates(taskId, taskType) {
338
352
  if (process.env.DEBUG) console.error(`[DEBUG] requestLogEntry check: ${err.message}`);
339
353
  console.log(` ${color('yellow', '○')} requestLogEntry (could not check)`);
340
354
  }
341
- } else if (gate === 'appMapUpdate') {
342
- console.log(` ${color('yellow', '○')} appMapUpdate (verify manually if components created)`);
355
+ } else if (gate === 'appMapUpdate' || gate === 'registryUpdate') {
356
+ // v1.9.7: Programmatic registry scan — replaces manual "verify manually" no-op.
357
+ // Runs flow-registry-manager scan on all active registries, comparing modified files
358
+ // against registry entries to detect missing registrations.
359
+ // v1.9.8: Deprecation warning for old gate name
360
+ if (gate === 'appMapUpdate') {
361
+ console.log(` ${color('yellow', '⚠')} appMapUpdate is deprecated — update config.json qualityGates to use 'registryUpdate'`);
362
+ }
363
+ const registryMod = getRegistryManager();
364
+ if (registryMod) {
365
+ try {
366
+ console.log(' Running registry update check...');
367
+ const modifiedFiles = getModifiedFiles();
368
+
369
+ // Get map file timestamps BEFORE scan (to detect changes)
370
+ const mapFiles = ['app-map.md', 'function-map.md', 'api-map.md', 'schema-map.md', 'service-map.md'];
371
+ const beforeHashes = {};
372
+ for (const mf of mapFiles) {
373
+ const mapPath = path.join(PATHS.state, mf);
374
+ try {
375
+ beforeHashes[mf] = fs.existsSync(mapPath) ? fs.statSync(mapPath).mtimeMs : 0;
376
+ } catch (err) {
377
+ beforeHashes[mf] = 0;
378
+ }
379
+ }
380
+
381
+ // Detect active plugins to check if scan is needed (lightweight, no async)
382
+ const { RegistryManager } = registryMod;
383
+ const manager = new RegistryManager();
384
+ manager.loadPlugins();
385
+ manager.detectStack();
386
+ manager.activatePlugins();
387
+
388
+ // Only scan if there are active plugins
389
+ if (manager.activePlugins.length > 0) {
390
+ // scanAll is async but we need sync behavior in quality gates
391
+ // Use spawnSync to run the scan as a child process
392
+ // v1.9.8: Added cwd, write JSON to stderr to avoid stdout pollution from require() side-effects
393
+ const scanResult = spawnSync('node', [
394
+ '-e',
395
+ `const {RegistryManager} = require(${JSON.stringify(path.join(__dirname, 'flow-registry-manager'))});
396
+ const m = new RegistryManager(); m.loadPlugins(); m.detectStack(); m.activatePlugins();
397
+ m.scanAll().then(r => { process.stderr.write('SCAN_RESULT:' + JSON.stringify(r)); process.exit(0); })
398
+ .catch(err => { process.stderr.write('SCAN_RESULT:' + JSON.stringify({error: err.message})); process.exit(1); });`
399
+ ], {
400
+ encoding: 'utf-8',
401
+ stdio: ['pipe', 'pipe', 'pipe'],
402
+ timeout: 30000,
403
+ cwd: process.cwd()
404
+ });
405
+
406
+ if (scanResult.status === 0) {
407
+ // Extract scan result from stderr (after SCAN_RESULT: marker) to avoid stdout pollution
408
+ const stderrOutput = scanResult.stderr || '';
409
+ const markerIdx = stderrOutput.indexOf('SCAN_RESULT:');
410
+ const jsonStr = markerIdx >= 0 ? stderrOutput.slice(markerIdx + 'SCAN_RESULT:'.length) : '{}';
411
+ const results = safeJsonParseString(jsonStr, {});
412
+
413
+ // Check which map files were updated
414
+ const updatedMaps = [];
415
+ for (const mf of mapFiles) {
416
+ const mapPath = path.join(PATHS.state, mf);
417
+ try {
418
+ const afterMtime = fs.existsSync(mapPath) ? fs.statSync(mapPath).mtimeMs : 0;
419
+ if (afterMtime > beforeHashes[mf]) {
420
+ updatedMaps.push(mf);
421
+ }
422
+ } catch (err) {
423
+ // ignore
424
+ }
425
+ }
426
+
427
+ // Check if modified files include patterns that should be in registries
428
+ const relevantExtensions = ['.js', '.ts', '.jsx', '.tsx', '.vue', '.svelte'];
429
+ const codeFiles = modifiedFiles.filter(f => relevantExtensions.some(ext => f.endsWith(ext)));
430
+ const nonTestFiles = codeFiles.filter(f => !f.includes('test') && !f.includes('spec') && !f.includes('__test'));
431
+
432
+ const activeIds = manager.activePlugins.map(p => p.constructor.id);
433
+ const scanSummary = Object.entries(results)
434
+ .filter(([id, r]) => r.success && !r.empty)
435
+ .map(([id]) => id);
436
+
437
+ if (updatedMaps.length > 0) {
438
+ console.log(` ${color('green', '✓')} registryUpdate (auto-scanned: ${updatedMaps.join(', ')} updated)`);
439
+ } else if (scanSummary.length > 0) {
440
+ console.log(` ${color('green', '✓')} registryUpdate (scanned ${activeIds.join(', ')} — maps already current)`);
441
+ } else if (nonTestFiles.length === 0) {
442
+ console.log(` ${color('green', '✓')} registryUpdate (no registrable code files modified)`);
443
+ } else {
444
+ console.log(` ${color('green', '✓')} registryUpdate (scanned — no new entries found)`);
445
+ }
446
+ } else {
447
+ console.log(` ${color('yellow', '⚠')} registryUpdate (scan error — degraded to manual check)`);
448
+ if (process.env.DEBUG) console.error(`[DEBUG] registry scan stderr: ${scanResult.stderr}`);
449
+ }
450
+ } else {
451
+ console.log(` ${color('green', '✓')} registryUpdate (no active registry plugins)`);
452
+ }
453
+ } catch (err) {
454
+ // Graceful degradation — don't block task completion on scan errors
455
+ console.log(` ${color('yellow', '⚠')} registryUpdate (error: ${truncateOutput(err.message, 3, 200)} — verify manually)`);
456
+ }
457
+ } else {
458
+ console.log(` ${color('yellow', '⚠')} registryUpdate (registry manager not available — verify manually)`);
459
+ }
343
460
  } else if (gate === 'loopComplete') {
344
461
  // v2.1: Explicit loop completion check
345
462
  const activeLoop = getActiveLoop();
@@ -553,7 +670,7 @@ function runQualityGates(taskId, taskType) {
553
670
  }
554
671
  } else if (gate === 'generatedTestsPass') {
555
672
  if (config.testing?.enabled && config.testing?.generation?.autoGenerate) {
556
- if (!validateTaskId(taskId)) {
673
+ if (!validateTaskId(taskId).valid) {
557
674
  console.log(` ${color('yellow', '⚠')} generatedTestsPass (invalid task ID)`);
558
675
  } else {
559
676
  const testDir = path.join(PATHS.workflow, 'tests', 'generated', taskId);
@@ -610,7 +727,7 @@ function runQualityGates(taskId, taskType) {
610
727
  const gateModes = isUI ? ['ui', 'full', 'auto'] : ['api', 'full', 'auto'];
611
728
  const testingMode = config.testing?.mode || 'off';
612
729
  if (config.testing?.enabled && gateModes.includes(testingMode)) {
613
- if (!validateTaskId(taskId)) {
730
+ if (!validateTaskId(taskId).valid) {
614
731
  console.log(` ${color('yellow', '⚠')} ${gate} (invalid task ID)`);
615
732
  } else {
616
733
  try {
@@ -661,7 +778,7 @@ function runQualityGates(taskId, taskType) {
661
778
  }
662
779
 
663
780
  // Also check scenario verification results if available
664
- if (!isUI && validateTaskId(taskId)) {
781
+ if (!isUI && validateTaskId(taskId).valid) {
665
782
  const scenarioReportPath = path.join(PATHS.workflow, 'verifications', `${taskId}-scenarios.json`);
666
783
  if (fs.existsSync(scenarioReportPath)) {
667
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 = loadConfig();
281
+ const config = getConfig();
303
282
 
304
283
  try {
305
284
  if (args.includes('--auto')) {