wogiflow 2.4.2 → 2.4.3
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/docs/claude-code-compatibility.md +27 -0
- package/.claude/settings.json +1 -1
- package/.workflow/models/registry.json +1 -1
- package/package.json +4 -4
- package/scripts/MEMORY-ARCHITECTURE.md +1 -1
- package/scripts/base-workflow-step.js +136 -0
- package/scripts/flow-adaptive-learning.js +8 -9
- package/scripts/flow-aggregate.js +11 -6
- package/scripts/flow-api-index.js +4 -6
- package/scripts/flow-assumption-detector.js +0 -2
- package/scripts/flow-audit.js +15 -2
- package/scripts/flow-auto-context.js +8 -12
- package/scripts/flow-auto-learn.js +49 -49
- package/scripts/flow-background.js +5 -6
- package/scripts/flow-bridge-state.js +8 -10
- package/scripts/flow-bulk-loop.js +1 -3
- package/scripts/flow-bulk-orchestrator.js +1 -3
- package/scripts/flow-cascade-completion.js +0 -2
- package/scripts/flow-cascade.js +4 -4
- package/scripts/flow-checkpoint.js +10 -13
- package/scripts/flow-code-intelligence.js +10 -12
- package/scripts/flow-community-sync.js +4 -4
- package/scripts/flow-community.js +12 -20
- package/scripts/flow-config-defaults.js +0 -2
- package/scripts/flow-config-interactive.js +9 -5
- package/scripts/flow-config-loader.js +49 -92
- package/scripts/flow-config-substitution.js +0 -2
- package/scripts/flow-context-estimator.js +4 -4
- package/scripts/flow-context-init.js +10 -12
- package/scripts/flow-context-manager.js +0 -2
- package/scripts/flow-context-scoring.js +2 -2
- package/scripts/flow-contract-scan.js +6 -9
- package/scripts/flow-correct.js +29 -27
- package/scripts/flow-correction-detector.js +5 -1
- package/scripts/flow-damage-control.js +47 -54
- package/scripts/flow-decisions-merge.js +4 -14
- package/scripts/flow-diff.js +5 -8
- package/scripts/flow-done-gates.js +786 -0
- package/scripts/flow-done-report.js +123 -0
- package/scripts/flow-done.js +71 -717
- package/scripts/flow-entropy-monitor.js +1 -3
- package/scripts/flow-eval.js +5 -5
- package/scripts/flow-extraction-review.js +1 -0
- package/scripts/flow-failure-categories.js +0 -2
- package/scripts/flow-figma-confirm.js +5 -9
- package/scripts/flow-figma-generate.js +8 -10
- package/scripts/flow-figma-index.js +8 -10
- package/scripts/flow-figma-match.js +3 -5
- package/scripts/flow-figma-mcp-server.js +2 -4
- package/scripts/flow-figma-orchestrator.js +2 -3
- package/scripts/flow-figma-registry.js +2 -3
- package/scripts/flow-framework-resolver.js +0 -2
- package/scripts/flow-function-index.js +4 -6
- package/scripts/flow-gate-confidence.js +2 -2
- package/scripts/flow-gitignore.js +0 -2
- package/scripts/flow-guided-edit.js +5 -6
- package/scripts/flow-health.js +5 -6
- package/scripts/flow-hook-errors.js +6 -0
- package/scripts/flow-hook-status.js +263 -0
- package/scripts/flow-hooks.js +17 -29
- package/scripts/flow-http-client.js +9 -8
- package/scripts/flow-hybrid-interactive.js +7 -12
- package/scripts/flow-hybrid-test.js +12 -13
- package/scripts/flow-instruction-richness.js +1 -1
- package/scripts/flow-io.js +21 -4
- package/scripts/flow-knowledge-router.js +9 -3
- package/scripts/flow-learning-orchestrator.js +318 -13
- package/scripts/flow-links.js +5 -7
- package/scripts/flow-long-input-association.js +275 -0
- package/scripts/flow-long-input-chunking.js +1 -0
- package/scripts/flow-long-input-cli.js +0 -2
- package/scripts/flow-long-input-complexity.js +0 -2
- package/scripts/flow-long-input-constants.js +0 -2
- package/scripts/flow-long-input-contradictions.js +351 -0
- package/scripts/flow-long-input-detection.js +0 -2
- package/scripts/flow-long-input-passes.js +885 -0
- package/scripts/flow-long-input-stories.js +1 -1
- package/scripts/flow-long-input-voice.js +0 -2
- package/scripts/flow-long-input.js +425 -3005
- package/scripts/flow-loop-retry-learning.js +2 -3
- package/scripts/flow-lsp.js +3 -3
- package/scripts/flow-mcp-docs.js +3 -4
- package/scripts/flow-memory-db.js +6 -8
- package/scripts/flow-memory-sync.js +18 -11
- package/scripts/flow-metrics.js +1 -2
- package/scripts/flow-model-adapter.js +2 -3
- package/scripts/flow-model-config.js +72 -104
- package/scripts/flow-model-router.js +2 -2
- package/scripts/flow-model-types.js +0 -2
- package/scripts/flow-multi-approach.js +5 -6
- package/scripts/flow-orchestrate-context.js +3 -7
- package/scripts/flow-orchestrate-rollback.js +3 -8
- package/scripts/flow-orchestrate-state.js +8 -14
- package/scripts/flow-orchestrate-templates.js +2 -6
- package/scripts/flow-orchestrate-validator.js +5 -9
- package/scripts/flow-orchestrate.js +126 -103
- package/scripts/flow-output.js +0 -2
- package/scripts/flow-parallel.js +1 -1
- package/scripts/flow-paths.js +23 -2
- package/scripts/flow-pattern-enforcer.js +30 -28
- package/scripts/flow-pattern-extractor.js +3 -4
- package/scripts/flow-pending.js +0 -2
- package/scripts/flow-permissions.js +2 -3
- package/scripts/flow-plugin-registry.js +10 -12
- package/scripts/flow-prd-manager.js +1 -1
- package/scripts/flow-progress.js +7 -9
- package/scripts/flow-prompt-composer.js +3 -3
- package/scripts/flow-prompt-template.js +2 -2
- package/scripts/flow-providers.js +7 -4
- package/scripts/flow-registry-manager.js +7 -12
- package/scripts/flow-regression.js +9 -11
- package/scripts/flow-roadmap.js +2 -2
- package/scripts/flow-run-trace.js +16 -15
- package/scripts/flow-safety.js +2 -5
- package/scripts/flow-scanner-base.js +5 -7
- package/scripts/flow-scenario-engine.js +1 -5
- package/scripts/flow-security.js +29 -0
- package/scripts/flow-session-end.js +32 -41
- package/scripts/flow-session-learning.js +53 -49
- package/scripts/flow-setup-hooks.js +2 -3
- package/scripts/flow-skill-create.js +7 -12
- package/scripts/flow-skill-generator.js +12 -16
- package/scripts/flow-skill-learn.js +17 -8
- package/scripts/flow-skill-matcher.js +1 -2
- package/scripts/flow-spec-generator.js +2 -4
- package/scripts/flow-stack-wizard.js +5 -7
- package/scripts/flow-standards-learner.js +35 -16
- package/scripts/flow-start.js +2 -0
- package/scripts/flow-stats-collector.js +2 -2
- package/scripts/flow-status.js +10 -10
- package/scripts/flow-statusline-setup.js +2 -2
- package/scripts/flow-step-changelog.js +2 -3
- package/scripts/flow-step-comments.js +66 -81
- package/scripts/flow-step-complexity.js +50 -70
- package/scripts/flow-step-coverage.js +3 -5
- package/scripts/flow-step-knowledge.js +2 -3
- package/scripts/flow-step-pr-tests.js +64 -74
- package/scripts/flow-step-regression.js +3 -5
- package/scripts/flow-step-review.js +86 -103
- package/scripts/flow-step-security.js +111 -121
- package/scripts/flow-step-silent-failures.js +56 -83
- package/scripts/flow-step-simplifier.js +52 -70
- package/scripts/flow-story.js +4 -7
- package/scripts/flow-strict-adherence.js +3 -4
- package/scripts/flow-task-checkpoint.js +36 -5
- package/scripts/flow-task-enforcer.js +2 -24
- package/scripts/flow-tech-debt.js +1 -1
- package/scripts/flow-template-extractor.js +1 -0
- package/scripts/flow-templates.js +11 -13
- package/scripts/flow-test-api.js +9 -13
- package/scripts/flow-test-discovery.js +1 -1
- package/scripts/flow-test-generate.js +5 -9
- package/scripts/flow-test-integrity.js +3 -7
- package/scripts/flow-test-ui.js +5 -9
- package/scripts/flow-testing-deps.js +1 -3
- package/scripts/flow-tiered-learning.js +4 -4
- package/scripts/flow-todowrite-sync.js +1 -1
- package/scripts/flow-tokens.js +0 -2
- package/scripts/flow-verification-profile.js +6 -10
- package/scripts/flow-verify.js +12 -16
- package/scripts/flow-version-check.js +4 -12
- package/scripts/flow-webmcp-generator.js +3 -5
- package/scripts/flow-workflow-steps.js +0 -2
- package/scripts/flow-workflow.js +9 -11
- package/scripts/hooks/adapters/claude-code.js +2 -0
- package/scripts/hooks/core/config-change.js +1 -0
- package/scripts/hooks/core/extension-registry.js +0 -2
- package/scripts/hooks/core/instructions-loaded.js +1 -1
- package/scripts/hooks/core/observation-capture.js +5 -5
- package/scripts/hooks/core/phase-gate.js +5 -0
- package/scripts/hooks/core/post-compact.js +1 -12
- package/scripts/hooks/core/research-gate.js +2 -12
- package/scripts/hooks/core/routing-gate.js +6 -0
- package/scripts/hooks/core/task-completed.js +12 -0
- package/scripts/hooks/core/worktree-lifecycle.js +1 -1
- package/scripts/hooks/entry/claude-code/config-change.js +6 -29
- package/scripts/hooks/entry/claude-code/instructions-loaded.js +5 -30
- package/scripts/hooks/entry/claude-code/post-compact.js +4 -31
- package/scripts/hooks/entry/claude-code/post-tool-use.js +121 -172
- package/scripts/hooks/entry/claude-code/pre-tool-use.js +260 -361
- package/scripts/hooks/entry/claude-code/session-end.js +4 -28
- package/scripts/hooks/entry/claude-code/session-start.js +205 -243
- package/scripts/hooks/entry/claude-code/setup.js +8 -49
- package/scripts/hooks/entry/claude-code/stop.js +40 -72
- package/scripts/hooks/entry/claude-code/task-completed.js +4 -28
- package/scripts/hooks/entry/claude-code/user-prompt-submit.js +113 -195
- package/scripts/hooks/entry/claude-code/worktree-create.js +6 -25
- package/scripts/hooks/entry/claude-code/worktree-remove.js +6 -25
- package/scripts/hooks/entry/shared/hook-runner.js +99 -0
- package/scripts/hooks/entry/shared/read-stdin.js +0 -2
- package/scripts/registries/api-registry.js +0 -2
- package/scripts/registries/component-registry.js +5 -9
- package/scripts/registries/contract-scanner.js +2 -9
- package/scripts/registries/function-registry.js +0 -2
- package/scripts/registries/schema-registry.js +14 -18
- package/scripts/registries/service-registry.js +23 -27
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wogi Flow - Shared Hook Runner
|
|
3
|
+
*
|
|
4
|
+
* Wraps the common boilerplate shared across hook entry files:
|
|
5
|
+
* stdin reading, JSON parsing, adapter invocation, error handling, output formatting.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* const { runHook } = require('../shared/hook-runner');
|
|
9
|
+
* runHook('SessionEnd', async ({ input, parsedInput }) => {
|
|
10
|
+
* const result = handleSessionEnd(parsedInput);
|
|
11
|
+
* return result;
|
|
12
|
+
* }, { failMode: 'silent' });
|
|
13
|
+
*
|
|
14
|
+
* @param {string} eventName - Hook event name (e.g., 'SessionEnd', 'PostCompact')
|
|
15
|
+
* @param {Function} handler - Async function receiving { input, parsedInput, raw }
|
|
16
|
+
* Must return a result object for claudeCodeAdapter.transformResult()
|
|
17
|
+
* @param {object} [options]
|
|
18
|
+
* @param {'silent'|'warn'|'block'} [options.failMode='silent']
|
|
19
|
+
* - 'silent': swallow errors, output { continue: true }
|
|
20
|
+
* - 'warn': log to stderr, output { continue: true }
|
|
21
|
+
* - 'block': log to stderr, output deny/block result
|
|
22
|
+
* @param {boolean} [options.useStdoutWrite=false] - Use process.stdout.write instead of console.log
|
|
23
|
+
* @param {boolean} [options.skipAdapter=false] - If true, handler returns raw output (no adapter transform)
|
|
24
|
+
* @param {object} [options.failOutput] - Custom error output object (overrides default error response)
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
const { readHookInput } = require('./read-stdin');
|
|
28
|
+
const { claudeCodeAdapter } = require('../../adapters/claude-code');
|
|
29
|
+
|
|
30
|
+
async function runHook(eventName, handler, { failMode = 'silent', useStdoutWrite = false, skipAdapter = false, failOutput = null } = {}) {
|
|
31
|
+
const write = useStdoutWrite
|
|
32
|
+
? (data) => process.stdout.write(data)
|
|
33
|
+
: (data) => console.log(data);
|
|
34
|
+
|
|
35
|
+
process.stdin.setEncoding('utf8');
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
const { input, raw } = await readHookInput();
|
|
39
|
+
const parsedInput = input ? claudeCodeAdapter.parseInput(input) : {};
|
|
40
|
+
|
|
41
|
+
const result = await handler({ input: input ?? {}, parsedInput, raw });
|
|
42
|
+
|
|
43
|
+
// Handler can return { __raw: true, ...payload } to bypass adapter transform
|
|
44
|
+
if (result && result.__raw) {
|
|
45
|
+
const { __raw, ...payload } = result;
|
|
46
|
+
write(JSON.stringify(payload));
|
|
47
|
+
} else if (skipAdapter) {
|
|
48
|
+
write(JSON.stringify(result));
|
|
49
|
+
} else {
|
|
50
|
+
const output = claudeCodeAdapter.transformResult(eventName, result);
|
|
51
|
+
write(JSON.stringify(output));
|
|
52
|
+
}
|
|
53
|
+
process.exit(0);
|
|
54
|
+
} catch (err) {
|
|
55
|
+
const errorOutput = failOutput ?? { continue: true };
|
|
56
|
+
|
|
57
|
+
if (failMode === 'silent') {
|
|
58
|
+
// Swallow error, allow through
|
|
59
|
+
write(JSON.stringify(errorOutput));
|
|
60
|
+
process.exit(0);
|
|
61
|
+
} else if (failMode === 'warn') {
|
|
62
|
+
// Log error, allow through
|
|
63
|
+
if (process.env.DEBUG) {
|
|
64
|
+
console.error(`[${eventName}] Hook error: ${err.message}`);
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
const { logHookError } = require('../../../flow-hook-errors');
|
|
68
|
+
logHookError(eventName, err, { failMode: 'open', operation: eventName.toLowerCase() });
|
|
69
|
+
} catch (_logErr) {
|
|
70
|
+
console.error(`[WogiFlow] ${eventName} hook error: ${err.message}`);
|
|
71
|
+
}
|
|
72
|
+
write(JSON.stringify(errorOutput));
|
|
73
|
+
process.exit(0);
|
|
74
|
+
} else if (failMode === 'block') {
|
|
75
|
+
// Log error, deny/block
|
|
76
|
+
if (process.env.DEBUG) {
|
|
77
|
+
console.error(`[${eventName}] Hook error (blocking): ${err.message}`);
|
|
78
|
+
} else {
|
|
79
|
+
console.error(`[Wogi Flow Hook] Validation error occurred`);
|
|
80
|
+
}
|
|
81
|
+
const blockOutput = failOutput ?? {
|
|
82
|
+
continue: true,
|
|
83
|
+
hookSpecificOutput: {
|
|
84
|
+
hookEventName: eventName,
|
|
85
|
+
permissionDecision: 'deny',
|
|
86
|
+
permissionDecisionReason: `WogiFlow ${eventName} validation error. Please check your setup or use /wogi-start.`
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
write(JSON.stringify(blockOutput));
|
|
90
|
+
process.exit(0);
|
|
91
|
+
} else {
|
|
92
|
+
// Unknown failMode — default to silent behavior
|
|
93
|
+
write(JSON.stringify(errorOutput));
|
|
94
|
+
process.exit(0);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
module.exports = { runHook };
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* Component Registry Plugin
|
|
5
3
|
*
|
|
@@ -16,14 +14,12 @@
|
|
|
16
14
|
|
|
17
15
|
const fs = require('node:fs');
|
|
18
16
|
const path = require('node:path');
|
|
19
|
-
const { getProjectRoot, getConfig, color, success, warn } = require('../flow-utils');
|
|
17
|
+
const { getProjectRoot, getConfig, color, success, warn, PATHS } = require('../flow-utils');
|
|
20
18
|
const { RegistryPlugin } = require('../flow-registry-manager');
|
|
21
19
|
const { BaseScanner, PROJECT_ROOT } = require('../flow-scanner-base');
|
|
22
20
|
const { info } = require('../flow-output');
|
|
23
21
|
|
|
24
|
-
const
|
|
25
|
-
const STATE_DIR = path.join(WORKFLOW_DIR, 'state');
|
|
26
|
-
const INDEX_PATH = path.join(STATE_DIR, 'component-index.json');
|
|
22
|
+
const INDEX_PATH = path.join(PATHS.state, 'component-index.json');
|
|
27
23
|
|
|
28
24
|
// ============================================================
|
|
29
25
|
// Component Scanner (extends BaseScanner for directory walking)
|
|
@@ -284,13 +280,13 @@ class ComponentScanner extends BaseScanner {
|
|
|
284
280
|
|
|
285
281
|
save() {
|
|
286
282
|
this.prune();
|
|
287
|
-
fs.mkdirSync(
|
|
283
|
+
fs.mkdirSync(PATHS.state, { recursive: true });
|
|
288
284
|
fs.writeFileSync(INDEX_PATH, JSON.stringify(this.registry, null, 2));
|
|
289
285
|
success(`Saved to ${path.relative(PROJECT_ROOT, INDEX_PATH)}`);
|
|
290
286
|
}
|
|
291
287
|
|
|
292
288
|
generateMap() {
|
|
293
|
-
const MAP_PATH =
|
|
289
|
+
const MAP_PATH = PATHS.appMap;
|
|
294
290
|
|
|
295
291
|
// Check if app-map.md exists and has content
|
|
296
292
|
let existing = '';
|
|
@@ -381,7 +377,7 @@ class ComponentScanner extends BaseScanner {
|
|
|
381
377
|
*/
|
|
382
378
|
_mergeIntoAppMap(mapPath, existing) {
|
|
383
379
|
// Path containment check (defense-in-depth)
|
|
384
|
-
if (!mapPath.startsWith(
|
|
380
|
+
if (!mapPath.startsWith(PATHS.state)) {
|
|
385
381
|
warn('Write target outside state directory — skipping merge');
|
|
386
382
|
return;
|
|
387
383
|
}
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* Contract Surface Scanner
|
|
5
3
|
*
|
|
@@ -20,6 +18,7 @@
|
|
|
20
18
|
const fs = require('node:fs');
|
|
21
19
|
const path = require('node:path');
|
|
22
20
|
const { execSync } = require('node:child_process');
|
|
21
|
+
const { safeJsonParse } = require('../flow-io');
|
|
23
22
|
|
|
24
23
|
const CONTRACT_SURFACE_VERSION = '1.0.0';
|
|
25
24
|
|
|
@@ -598,13 +597,7 @@ function detectProjectType(projectRoot) {
|
|
|
598
597
|
}
|
|
599
598
|
|
|
600
599
|
// Read package.json for dependency analysis
|
|
601
|
-
|
|
602
|
-
try {
|
|
603
|
-
const pkgContent = fs.readFileSync(path.join(projectRoot, 'package.json'), 'utf-8');
|
|
604
|
-
pkg = JSON.parse(pkgContent);
|
|
605
|
-
} catch (err) {
|
|
606
|
-
// No package.json or invalid JSON
|
|
607
|
-
}
|
|
600
|
+
const pkg = safeJsonParse(path.join(projectRoot, 'package.json'), {});
|
|
608
601
|
|
|
609
602
|
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
610
603
|
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* Schema/Model Registry Plugin
|
|
5
3
|
*
|
|
@@ -14,12 +12,10 @@
|
|
|
14
12
|
const fs = require('node:fs');
|
|
15
13
|
const path = require('node:path');
|
|
16
14
|
const { RegistryPlugin } = require('../flow-registry-manager');
|
|
17
|
-
const { getProjectRoot, safeJsonParse: safeJsonParseFile } = require('../flow-utils');
|
|
15
|
+
const { getProjectRoot, safeJsonParse: safeJsonParseFile, PATHS } = require('../flow-utils');
|
|
18
16
|
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const INDEX_PATH = path.join(STATE_DIR, 'schema-index.json');
|
|
22
|
-
const MAP_PATH = path.join(STATE_DIR, 'schema-map.md');
|
|
17
|
+
const INDEX_PATH = path.join(PATHS.state, 'schema-index.json');
|
|
18
|
+
const MAP_PATH = path.join(PATHS.state, 'schema-map.md');
|
|
23
19
|
|
|
24
20
|
class SchemaRegistry extends RegistryPlugin {
|
|
25
21
|
static id = 'schemas';
|
|
@@ -44,7 +40,7 @@ class SchemaRegistry extends RegistryPlugin {
|
|
|
44
40
|
if (stack.orm) return true;
|
|
45
41
|
|
|
46
42
|
// Check package.json for ORM packages
|
|
47
|
-
const pkgPath = path.join(
|
|
43
|
+
const pkgPath = path.join(PATHS.root, 'package.json');
|
|
48
44
|
if (fs.existsSync(pkgPath)) {
|
|
49
45
|
try {
|
|
50
46
|
const pkg = safeJsonParseFile(pkgPath, {});
|
|
@@ -57,7 +53,7 @@ class SchemaRegistry extends RegistryPlugin {
|
|
|
57
53
|
}
|
|
58
54
|
|
|
59
55
|
// Check for Django models (manage.py + models.py)
|
|
60
|
-
if (fs.existsSync(path.join(
|
|
56
|
+
if (fs.existsSync(path.join(PATHS.root, 'manage.py'))) return true;
|
|
61
57
|
|
|
62
58
|
return false;
|
|
63
59
|
}
|
|
@@ -90,11 +86,11 @@ class SchemaRegistry extends RegistryPlugin {
|
|
|
90
86
|
const before = this.models.length;
|
|
91
87
|
this.models = this.models.filter(m => {
|
|
92
88
|
if (!m.file) return true;
|
|
93
|
-
return fs.existsSync(path.join(
|
|
89
|
+
return fs.existsSync(path.join(PATHS.root, m.file));
|
|
94
90
|
});
|
|
95
91
|
this.enums = this.enums.filter(e => {
|
|
96
92
|
if (!e.file) return true;
|
|
97
|
-
return fs.existsSync(path.join(
|
|
93
|
+
return fs.existsSync(path.join(PATHS.root, e.file));
|
|
98
94
|
});
|
|
99
95
|
const removed = before - this.models.length;
|
|
100
96
|
if (removed > 0) {
|
|
@@ -106,7 +102,7 @@ class SchemaRegistry extends RegistryPlugin {
|
|
|
106
102
|
|
|
107
103
|
save() {
|
|
108
104
|
const index = this._buildIndex();
|
|
109
|
-
fs.mkdirSync(
|
|
105
|
+
fs.mkdirSync(PATHS.state, { recursive: true });
|
|
110
106
|
fs.writeFileSync(INDEX_PATH, JSON.stringify(index, null, 2));
|
|
111
107
|
}
|
|
112
108
|
|
|
@@ -166,7 +162,7 @@ class SchemaRegistry extends RegistryPlugin {
|
|
|
166
162
|
|
|
167
163
|
lines.push(`---\n*Auto-generated by Schema Registry — ${getTodayDate()}*\n`);
|
|
168
164
|
|
|
169
|
-
fs.mkdirSync(
|
|
165
|
+
fs.mkdirSync(PATHS.state, { recursive: true });
|
|
170
166
|
fs.writeFileSync(MAP_PATH, lines.join('\n'));
|
|
171
167
|
}
|
|
172
168
|
|
|
@@ -179,8 +175,8 @@ class SchemaRegistry extends RegistryPlugin {
|
|
|
179
175
|
// ============================================================
|
|
180
176
|
|
|
181
177
|
_scanPrisma() {
|
|
182
|
-
const schemaDir = path.join(
|
|
183
|
-
const singleFile = path.join(
|
|
178
|
+
const schemaDir = path.join(PATHS.root, 'prisma', 'schema');
|
|
179
|
+
const singleFile = path.join(PATHS.root, 'prisma', 'schema.prisma');
|
|
184
180
|
|
|
185
181
|
let files = [];
|
|
186
182
|
|
|
@@ -199,7 +195,7 @@ class SchemaRegistry extends RegistryPlugin {
|
|
|
199
195
|
for (const file of files) {
|
|
200
196
|
try {
|
|
201
197
|
const content = fs.readFileSync(file, 'utf-8');
|
|
202
|
-
const relPath = path.relative(
|
|
198
|
+
const relPath = path.relative(PATHS.root, file);
|
|
203
199
|
this._parsePrismaFile(content, relPath);
|
|
204
200
|
} catch (err) {
|
|
205
201
|
// Skip unreadable files
|
|
@@ -327,7 +323,7 @@ class SchemaRegistry extends RegistryPlugin {
|
|
|
327
323
|
const entityFiles = [];
|
|
328
324
|
|
|
329
325
|
for (const dir of searchDirs) {
|
|
330
|
-
const fullDir = path.join(
|
|
326
|
+
const fullDir = path.join(PATHS.root, dir);
|
|
331
327
|
if (fs.existsSync(fullDir)) {
|
|
332
328
|
this._findTypeORMEntities(fullDir, entityFiles);
|
|
333
329
|
}
|
|
@@ -340,7 +336,7 @@ class SchemaRegistry extends RegistryPlugin {
|
|
|
340
336
|
// Use cached content from discovery phase to avoid N+1 reads
|
|
341
337
|
const filePath = typeof entry === 'string' ? entry : entry.path;
|
|
342
338
|
const content = typeof entry === 'string' ? fs.readFileSync(entry, 'utf-8') : entry.content;
|
|
343
|
-
const relPath = path.relative(
|
|
339
|
+
const relPath = path.relative(PATHS.root, filePath);
|
|
344
340
|
this._parseTypeORMFile(content, relPath);
|
|
345
341
|
} catch (_err) {
|
|
346
342
|
// Skip unreadable files
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* Architecture/Service Registry Plugin
|
|
5
3
|
*
|
|
@@ -15,12 +13,10 @@
|
|
|
15
13
|
const fs = require('node:fs');
|
|
16
14
|
const path = require('node:path');
|
|
17
15
|
const { RegistryPlugin } = require('../flow-registry-manager');
|
|
18
|
-
const { getProjectRoot, safeJsonParse: safeJsonParseFile } = require('../flow-utils');
|
|
16
|
+
const { getProjectRoot, safeJsonParse: safeJsonParseFile, PATHS } = require('../flow-utils');
|
|
19
17
|
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
const INDEX_PATH = path.join(STATE_DIR, 'service-index.json');
|
|
23
|
-
const MAP_PATH = path.join(STATE_DIR, 'service-map.md');
|
|
18
|
+
const INDEX_PATH = path.join(PATHS.state, 'service-index.json');
|
|
19
|
+
const MAP_PATH = path.join(PATHS.state, 'service-map.md');
|
|
24
20
|
|
|
25
21
|
// Decorator/annotation patterns per framework
|
|
26
22
|
const NESTJS_PATTERNS = {
|
|
@@ -62,7 +58,7 @@ class ServiceRegistry extends RegistryPlugin {
|
|
|
62
58
|
|
|
63
59
|
_getPackageJson() {
|
|
64
60
|
if (this._cachedPkg !== undefined) return this._cachedPkg;
|
|
65
|
-
const pkgPath = path.join(
|
|
61
|
+
const pkgPath = path.join(PATHS.root, 'package.json');
|
|
66
62
|
try {
|
|
67
63
|
this._cachedPkg = safeJsonParseFile(pkgPath, {});
|
|
68
64
|
} catch (_err) {
|
|
@@ -94,10 +90,10 @@ class ServiceRegistry extends RegistryPlugin {
|
|
|
94
90
|
}
|
|
95
91
|
|
|
96
92
|
// Check for Django (manage.py)
|
|
97
|
-
if (fs.existsSync(path.join(
|
|
93
|
+
if (fs.existsSync(path.join(PATHS.root, 'manage.py'))) return true;
|
|
98
94
|
|
|
99
95
|
// Check for Go (go.mod with net/http)
|
|
100
|
-
const goModPath = path.join(
|
|
96
|
+
const goModPath = path.join(PATHS.root, 'go.mod');
|
|
101
97
|
if (fs.existsSync(goModPath)) return true;
|
|
102
98
|
|
|
103
99
|
return false;
|
|
@@ -147,7 +143,7 @@ class ServiceRegistry extends RegistryPlugin {
|
|
|
147
143
|
const before = arr.length;
|
|
148
144
|
const pruned = arr.filter(item => {
|
|
149
145
|
if (!item.file) return true;
|
|
150
|
-
return fs.existsSync(path.join(
|
|
146
|
+
return fs.existsSync(path.join(PATHS.root, item.file));
|
|
151
147
|
});
|
|
152
148
|
removed += before - pruned.length;
|
|
153
149
|
arr.length = 0;
|
|
@@ -163,7 +159,7 @@ class ServiceRegistry extends RegistryPlugin {
|
|
|
163
159
|
|
|
164
160
|
save() {
|
|
165
161
|
const index = this._buildIndex();
|
|
166
|
-
fs.mkdirSync(
|
|
162
|
+
fs.mkdirSync(PATHS.state, { recursive: true });
|
|
167
163
|
fs.writeFileSync(INDEX_PATH, JSON.stringify(index, null, 2));
|
|
168
164
|
}
|
|
169
165
|
|
|
@@ -237,7 +233,7 @@ class ServiceRegistry extends RegistryPlugin {
|
|
|
237
233
|
|
|
238
234
|
lines.push(`---\n*Auto-generated by Service Registry — ${getTodayDate()}*\n`);
|
|
239
235
|
|
|
240
|
-
fs.mkdirSync(
|
|
236
|
+
fs.mkdirSync(PATHS.state, { recursive: true });
|
|
241
237
|
fs.writeFileSync(MAP_PATH, lines.join('\n'));
|
|
242
238
|
}
|
|
243
239
|
|
|
@@ -261,8 +257,8 @@ class ServiceRegistry extends RegistryPlugin {
|
|
|
261
257
|
// ignore
|
|
262
258
|
}
|
|
263
259
|
|
|
264
|
-
if (fs.existsSync(path.join(
|
|
265
|
-
if (fs.existsSync(path.join(
|
|
260
|
+
if (fs.existsSync(path.join(PATHS.root, 'manage.py'))) return 'django';
|
|
261
|
+
if (fs.existsSync(path.join(PATHS.root, 'go.mod'))) return 'go';
|
|
266
262
|
|
|
267
263
|
return null;
|
|
268
264
|
}
|
|
@@ -275,7 +271,7 @@ class ServiceRegistry extends RegistryPlugin {
|
|
|
275
271
|
const searchDirs = ['src', 'apps', 'libs'];
|
|
276
272
|
|
|
277
273
|
for (const dir of searchDirs) {
|
|
278
|
-
const fullDir = path.join(
|
|
274
|
+
const fullDir = path.join(PATHS.root, dir);
|
|
279
275
|
if (fs.existsSync(fullDir)) {
|
|
280
276
|
this._findNestJSFiles(fullDir);
|
|
281
277
|
}
|
|
@@ -291,7 +287,7 @@ class ServiceRegistry extends RegistryPlugin {
|
|
|
291
287
|
const fullPath = path.resolve(dir, entry.name);
|
|
292
288
|
|
|
293
289
|
// Ensure resolved path stays within project root
|
|
294
|
-
if (!fullPath.startsWith(
|
|
290
|
+
if (!fullPath.startsWith(PATHS.root)) continue;
|
|
295
291
|
|
|
296
292
|
if (entry.isDirectory()) {
|
|
297
293
|
this._findNestJSFiles(fullPath, depth + 1);
|
|
@@ -301,7 +297,7 @@ class ServiceRegistry extends RegistryPlugin {
|
|
|
301
297
|
!entry.name.endsWith('.d.ts')) {
|
|
302
298
|
try {
|
|
303
299
|
const content = fs.readFileSync(fullPath, 'utf-8');
|
|
304
|
-
const relPath = path.relative(
|
|
300
|
+
const relPath = path.relative(PATHS.root, fullPath);
|
|
305
301
|
|
|
306
302
|
if (content.includes('@Controller')) {
|
|
307
303
|
this._parseNestJSController(content, relPath);
|
|
@@ -430,7 +426,7 @@ class ServiceRegistry extends RegistryPlugin {
|
|
|
430
426
|
const searchDirs = ['src', 'routes', 'middleware', 'src/routes', 'src/middleware', 'lib', 'app', 'app/routes', 'app/api', 'server', 'api'];
|
|
431
427
|
|
|
432
428
|
for (const dir of searchDirs) {
|
|
433
|
-
const fullDir = path.join(
|
|
429
|
+
const fullDir = path.join(PATHS.root, dir);
|
|
434
430
|
if (fs.existsSync(fullDir)) {
|
|
435
431
|
this._findExpressFiles(fullDir);
|
|
436
432
|
}
|
|
@@ -446,14 +442,14 @@ class ServiceRegistry extends RegistryPlugin {
|
|
|
446
442
|
const fullPath = path.resolve(dir, entry.name);
|
|
447
443
|
|
|
448
444
|
// Ensure resolved path stays within project root
|
|
449
|
-
if (!fullPath.startsWith(
|
|
445
|
+
if (!fullPath.startsWith(PATHS.root)) continue;
|
|
450
446
|
|
|
451
447
|
if (entry.isDirectory()) {
|
|
452
448
|
this._findExpressFiles(fullPath, depth + 1);
|
|
453
449
|
} else if (entry.name.endsWith('.ts') || entry.name.endsWith('.js')) {
|
|
454
450
|
try {
|
|
455
451
|
const content = fs.readFileSync(fullPath, 'utf-8');
|
|
456
|
-
const relPath = path.relative(
|
|
452
|
+
const relPath = path.relative(PATHS.root, fullPath);
|
|
457
453
|
|
|
458
454
|
// Detect route handlers
|
|
459
455
|
if (content.match(/router\.(get|post|put|patch|delete)\s*\(/i) ||
|
|
@@ -506,7 +502,7 @@ class ServiceRegistry extends RegistryPlugin {
|
|
|
506
502
|
|
|
507
503
|
_scanDjango() {
|
|
508
504
|
// Find all apps by looking for views.py files
|
|
509
|
-
this._findDjangoFiles(
|
|
505
|
+
this._findDjangoFiles(PATHS.root, 0);
|
|
510
506
|
}
|
|
511
507
|
|
|
512
508
|
_findDjangoFiles(dir, depth) {
|
|
@@ -518,14 +514,14 @@ class ServiceRegistry extends RegistryPlugin {
|
|
|
518
514
|
const fullPath = path.resolve(dir, entry.name);
|
|
519
515
|
|
|
520
516
|
// Ensure resolved path stays within project root
|
|
521
|
-
if (!fullPath.startsWith(
|
|
517
|
+
if (!fullPath.startsWith(PATHS.root)) continue;
|
|
522
518
|
|
|
523
519
|
if (entry.isDirectory()) {
|
|
524
520
|
this._findDjangoFiles(fullPath, depth + 1);
|
|
525
521
|
} else if (entry.name === 'views.py' || entry.name === 'serializers.py') {
|
|
526
522
|
try {
|
|
527
523
|
const content = fs.readFileSync(fullPath, 'utf-8');
|
|
528
|
-
const relPath = path.relative(
|
|
524
|
+
const relPath = path.relative(PATHS.root, fullPath);
|
|
529
525
|
this._parseDjangoFile(content, relPath);
|
|
530
526
|
} catch (err) {
|
|
531
527
|
// Skip
|
|
@@ -570,7 +566,7 @@ class ServiceRegistry extends RegistryPlugin {
|
|
|
570
566
|
// ============================================================
|
|
571
567
|
|
|
572
568
|
_scanGo() {
|
|
573
|
-
this._findGoHandlers(
|
|
569
|
+
this._findGoHandlers(PATHS.root, 0);
|
|
574
570
|
}
|
|
575
571
|
|
|
576
572
|
_findGoHandlers(dir, depth) {
|
|
@@ -582,7 +578,7 @@ class ServiceRegistry extends RegistryPlugin {
|
|
|
582
578
|
const fullPath = path.resolve(dir, entry.name);
|
|
583
579
|
|
|
584
580
|
// Ensure resolved path stays within project root
|
|
585
|
-
if (!fullPath.startsWith(
|
|
581
|
+
if (!fullPath.startsWith(PATHS.root)) continue;
|
|
586
582
|
|
|
587
583
|
if (entry.isDirectory()) {
|
|
588
584
|
this._findGoHandlers(fullPath, depth + 1);
|
|
@@ -590,7 +586,7 @@ class ServiceRegistry extends RegistryPlugin {
|
|
|
590
586
|
try {
|
|
591
587
|
const content = fs.readFileSync(fullPath, 'utf-8');
|
|
592
588
|
if (content.includes('http.Handler') || content.includes('HandleFunc') || content.includes('gin.Context')) {
|
|
593
|
-
const relPath = path.relative(
|
|
589
|
+
const relPath = path.relative(PATHS.root, fullPath);
|
|
594
590
|
this._parseGoFile(content, relPath);
|
|
595
591
|
}
|
|
596
592
|
} catch (err) {
|