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.
- package/.claude/commands/wogi-onboard.md +1 -1
- package/.claude/commands/wogi-research.md +70 -1
- package/.claude/commands/wogi-start.md +4 -3
- package/.claude/docs/config-reference.md +2 -2
- package/.claude/docs/knowledge-base/02-task-execution/03-verification.md +3 -3
- package/.claude/docs/knowledge-base/02-task-execution/05-session-review.md +1 -1
- package/.claude/docs/knowledge-base/02-task-execution/README.md +1 -1
- package/.claude/docs/knowledge-base/02-task-execution/trade-offs.md +1 -1
- package/.claude/docs/knowledge-base/configuration/README.md +1 -1
- package/.claude/docs/knowledge-base/configuration/all-options.md +2 -2
- package/.workflow/templates/claude-md.hbs +3 -6
- package/lib/utils.js +1 -1
- package/package.json +2 -5
- package/scripts/flow-config-defaults.js +1 -1
- package/scripts/flow-consistency-check.js +0 -4
- package/scripts/flow-context-estimator.js +4 -20
- package/scripts/flow-correct.js +2 -1
- package/scripts/flow-decision-tracker.js +2 -2
- package/scripts/flow-done.js +123 -6
- package/scripts/flow-entropy-monitor.js +3 -24
- package/scripts/flow-export-scanner.js +3 -3
- package/scripts/flow-health.js +3 -2
- package/scripts/flow-hybrid-test.js +2 -3
- package/scripts/flow-long-input-stories.js +4 -6
- package/scripts/flow-long-input.js +5 -8
- package/scripts/flow-memory-compactor.js +1 -13
- package/scripts/flow-memory-db.js +1 -1
- package/scripts/flow-memory-sync.js +1 -17
- package/scripts/flow-orchestrate-llm.js +3 -7
- package/scripts/flow-orchestrate.js +2 -13
- package/scripts/flow-pattern-extractor.js +3 -17
- package/scripts/flow-peer-review.js +4 -12
- package/scripts/flow-plugin-registry.js +2 -2
- package/scripts/flow-project-analyzer.js +4 -4
- package/scripts/flow-providers.js +2 -7
- package/scripts/flow-safety.js +6 -10
- package/scripts/flow-script-resolver.js +4 -16
- package/scripts/flow-skill-freshness.js +3 -12
- package/scripts/flow-skill-generator.js +14 -24
- package/scripts/flow-strict-adherence.js +2 -2
- package/scripts/flow-task-analyzer.js +3 -3
- package/scripts/flow-test-discovery.js +3 -3
- package/scripts/flow-utils.js +1 -0
- package/scripts/flow-webmcp-generator.js +1 -1
- package/scripts/flow-workflow-steps.js +31 -23
- package/scripts/hooks/core/component-check.js +22 -7
- package/scripts/hooks/core/observation-capture.js +7 -4
- package/scripts/hooks/core/task-gate.js +2 -2
- package/scripts/hooks/entry/claude-code/post-tool-use.js +10 -8
- package/scripts/hooks/entry/claude-code/pre-tool-use.js +34 -41
- package/scripts/hooks/entry/claude-code/session-start.js +4 -12
- package/scripts/hooks/entry/shared/read-stdin.js +33 -0
- package/.claude/rules/_internal/README.md +0 -64
- package/.claude/rules/_internal/document-structure.md +0 -77
- package/.claude/rules/_internal/dual-repo-management.md +0 -174
- package/.claude/rules/_internal/feature-refactoring-cleanup.md +0 -87
- package/.claude/rules/_internal/github-releases.md +0 -71
- package/.claude/rules/_internal/model-management.md +0 -35
- package/.claude/rules/_internal/self-maintenance.md +0 -87
- package/.claude/rules/architecture/component-reuse.md +0 -38
- package/.claude/rules/code-style/naming-conventions.md +0 -52
- package/.claude/rules/operations/git-workflows.md +0 -92
- package/.claude/rules/security/security-patterns.md +0 -176
- package/.claude/skills/figma-analyzer/knowledge/learnings.md +0 -11
- package/.workflow/specs/architecture.md.template +0 -24
- package/.workflow/specs/stack.md.template +0 -33
- package/.workflow/specs/testing.md.template +0 -36
- package/scripts/flow-done +0 -151
- package/scripts/flow-file-ops.js +0 -307
- package/scripts/flow-health +0 -185
- package/scripts/flow-ready +0 -82
- package/scripts/flow-start +0 -74
- package/scripts/flow-status +0 -110
- package/scripts/flow-story +0 -105
|
@@ -701,7 +701,7 @@ Display:
|
|
|
701
701
|
for (const reqs of [featureReqs, bugfixReqs, refactorReqs]) {
|
|
702
702
|
reqs.push('requestLogEntry');
|
|
703
703
|
}
|
|
704
|
-
featureReqs.push('
|
|
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,
|
|
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.
|
|
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.
|
|
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", "
|
|
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`, `
|
|
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", "
|
|
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
|
-
| `
|
|
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
|
-
|
|
137
|
+
✓ registryUpdate (auto-scanned: app-map.md updated)
|
|
138
138
|
|
|
139
139
|
All gates passed!
|
|
140
140
|
```
|
|
@@ -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", "
|
|
144
|
+
"require": ["tests", "lint", "typecheck", "registryUpdate", "requestLogEntry", "review"]
|
|
145
145
|
}
|
|
146
146
|
}
|
|
147
147
|
}
|
|
@@ -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", "
|
|
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`, `
|
|
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.
|
|
214
|
-
3.
|
|
215
|
-
4.
|
|
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
|
|
43
|
+
* Note: For parsing JSON files, use safeJsonParse from flow-utils.js
|
|
44
44
|
* or safeReadJson from this module instead.
|
|
45
45
|
*
|
|
46
46
|
* @param {string} content - JSON string to parse
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wogiflow",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.8",
|
|
4
4
|
"description": "AI-powered development workflow management system with multi-model support",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -9,8 +9,6 @@
|
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
11
|
"flow": "./scripts/flow",
|
|
12
|
-
"test": "node mcp-memory-server/test.js",
|
|
13
|
-
"memory-server": "node mcp-memory-server/index.js",
|
|
14
12
|
"postinstall": "node scripts/postinstall.js",
|
|
15
13
|
"preuninstall": "node scripts/preuninstall.js"
|
|
16
14
|
},
|
|
@@ -58,10 +56,9 @@
|
|
|
58
56
|
},
|
|
59
57
|
"homepage": "https://github.com/Tomer-Wogi/WogiFlow#readme",
|
|
60
58
|
"dependencies": {
|
|
61
|
-
"sql.js": "^1.
|
|
59
|
+
"sql.js": "^1.14.1"
|
|
62
60
|
},
|
|
63
61
|
"optionalDependencies": {
|
|
64
|
-
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
65
62
|
"@xenova/transformers": "^2.15.0"
|
|
66
63
|
},
|
|
67
64
|
"engines": {
|
|
@@ -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', '
|
|
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 (!
|
|
79
|
+
if (!validateTaskId(taskId).valid) {
|
|
94
80
|
return null;
|
|
95
81
|
}
|
|
96
82
|
|
|
@@ -476,7 +462,7 @@ if (require.main === module) {
|
|
|
476
462
|
const taskId = args[1];
|
|
477
463
|
|
|
478
464
|
// Validate taskId to prevent path traversal
|
|
479
|
-
if (!
|
|
465
|
+
if (!validateTaskId(taskId).valid) {
|
|
480
466
|
console.error(`Invalid task ID format: ${taskId}`);
|
|
481
467
|
console.error('Task IDs must contain only alphanumeric characters, hyphens, and underscores.');
|
|
482
468
|
process.exit(1);
|
|
@@ -521,7 +507,7 @@ if (require.main === module) {
|
|
|
521
507
|
const taskId = args[1];
|
|
522
508
|
|
|
523
509
|
// Validate taskId to prevent path traversal
|
|
524
|
-
if (!
|
|
510
|
+
if (!validateTaskId(taskId).valid) {
|
|
525
511
|
console.error(`Invalid task ID format: ${taskId}`);
|
|
526
512
|
console.error('Task IDs must contain only alphanumeric characters, hyphens, and underscores.');
|
|
527
513
|
process.exit(1);
|
|
@@ -775,8 +761,6 @@ module.exports = {
|
|
|
775
761
|
formatEstimationResult,
|
|
776
762
|
extractCriteriaCount,
|
|
777
763
|
extractFileCount,
|
|
778
|
-
isValidTaskId,
|
|
779
|
-
VALID_TASK_ID_PATTERN,
|
|
780
764
|
// Finding-level estimation (for review-fix sessions)
|
|
781
765
|
estimateFindingContextCost,
|
|
782
766
|
calculateDynamicBatchSize,
|
package/scripts/flow-correct.js
CHANGED
|
@@ -23,6 +23,7 @@ const {
|
|
|
23
23
|
dirExists,
|
|
24
24
|
readFile,
|
|
25
25
|
writeFile,
|
|
26
|
+
getConfig,
|
|
26
27
|
color,
|
|
27
28
|
success,
|
|
28
29
|
warn,
|
|
@@ -35,7 +36,7 @@ const {
|
|
|
35
36
|
|
|
36
37
|
function getCorrectionsDir() {
|
|
37
38
|
try {
|
|
38
|
-
const config =
|
|
39
|
+
const config = getConfig();
|
|
39
40
|
const detailPath = config?.corrections?.detailPath;
|
|
40
41
|
if (detailPath) {
|
|
41
42
|
return path.isAbsolute(detailPath) ? detailPath : path.join(PROJECT_ROOT, detailPath);
|
|
@@ -22,10 +22,10 @@
|
|
|
22
22
|
|
|
23
23
|
const fs = require('fs');
|
|
24
24
|
const path = require('path');
|
|
25
|
-
const crypto = require('crypto');
|
|
26
25
|
const {
|
|
27
26
|
PATHS,
|
|
28
27
|
getConfig,
|
|
28
|
+
generateHashId,
|
|
29
29
|
success,
|
|
30
30
|
warn,
|
|
31
31
|
error,
|
|
@@ -163,7 +163,7 @@ function recordAmendment(params) {
|
|
|
163
163
|
}
|
|
164
164
|
|
|
165
165
|
// Generate amendment record
|
|
166
|
-
const id =
|
|
166
|
+
const id = generateHashId('amend', '', '');
|
|
167
167
|
const amendment = {
|
|
168
168
|
id,
|
|
169
169
|
timestamp: new Date().toISOString(),
|
package/scripts/flow-done.js
CHANGED
|
@@ -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
|
-
|
|
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 =
|
|
281
|
+
const config = getConfig();
|
|
303
282
|
|
|
304
283
|
try {
|
|
305
284
|
if (args.includes('--auto')) {
|