pumuki-ast-hooks 5.3.14 → 5.3.16
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/README.md +73 -22
- package/docs/RELEASE_NOTES.md +36 -0
- package/docs/RELEASE_NOTES_5.3.4.md +170 -0
- package/package.json +4 -2
- package/scripts/hooks-system/.AI_TOKEN_STATUS.txt +1 -1
- package/scripts/hooks-system/.audit-reports/notifications.log +215 -0
- package/scripts/hooks-system/.audit-reports/token-monitor.log +645 -0
- package/scripts/hooks-system/application/services/installation/McpConfigurator.js +60 -68
- package/scripts/hooks-system/config/project.config.json +1 -51
- package/scripts/hooks-system/infrastructure/mcp/ast-intelligence-automation.js +24 -1
- package/scripts/hooks-system/infrastructure/shell/orchestrators/audit-orchestrator.sh +3 -3
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const { execSync } = require('child_process');
|
|
4
|
+
const crypto = require('crypto');
|
|
5
|
+
const os = require('os');
|
|
4
6
|
|
|
5
7
|
const COLORS = {
|
|
6
8
|
reset: '\x1b[0m',
|
|
@@ -9,6 +11,35 @@ const COLORS = {
|
|
|
9
11
|
cyan: '\x1b[36m'
|
|
10
12
|
};
|
|
11
13
|
|
|
14
|
+
function slugifyId(input) {
|
|
15
|
+
return String(input || '')
|
|
16
|
+
.trim()
|
|
17
|
+
.toLowerCase()
|
|
18
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
19
|
+
.replace(/^-+|-+$/g, '')
|
|
20
|
+
.slice(0, 48);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function computeRepoFingerprint(repoRoot) {
|
|
24
|
+
try {
|
|
25
|
+
const real = fs.realpathSync(repoRoot);
|
|
26
|
+
return crypto.createHash('sha1').update(real).digest('hex').slice(0, 8);
|
|
27
|
+
} catch {
|
|
28
|
+
return crypto.createHash('sha1').update(String(repoRoot || '')).digest('hex').slice(0, 8);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function computeServerIdForRepo(repoRoot) {
|
|
33
|
+
const legacyServerId = 'ast-intelligence-automation';
|
|
34
|
+
const forced = (process.env.MCP_SERVER_ID || '').trim();
|
|
35
|
+
if (forced.length > 0) return forced;
|
|
36
|
+
|
|
37
|
+
const repoName = path.basename(repoRoot || process.cwd());
|
|
38
|
+
const slug = slugifyId(repoName) || 'repo';
|
|
39
|
+
const fp = computeRepoFingerprint(repoRoot);
|
|
40
|
+
return `${legacyServerId}-${slug}-${fp}`;
|
|
41
|
+
}
|
|
42
|
+
|
|
12
43
|
class McpConfigurator {
|
|
13
44
|
constructor(targetRoot, hookSystemRoot, logger = null) {
|
|
14
45
|
this.targetRoot = targetRoot;
|
|
@@ -16,26 +47,32 @@ class McpConfigurator {
|
|
|
16
47
|
this.logger = logger;
|
|
17
48
|
}
|
|
18
49
|
|
|
50
|
+
getGlobalWindsurfConfigPath() {
|
|
51
|
+
return path.join(os.homedir(), '.codeium', 'windsurf', 'mcp_config.json');
|
|
52
|
+
}
|
|
53
|
+
|
|
19
54
|
configure() {
|
|
20
55
|
if (this.logger) this.logger.info('MCP_CONFIGURATION_STARTED');
|
|
56
|
+
|
|
21
57
|
let nodePath = process.execPath;
|
|
22
58
|
if (!nodePath || !fs.existsSync(nodePath)) {
|
|
23
59
|
try {
|
|
24
60
|
nodePath = execSync('which node', { encoding: 'utf-8' }).trim();
|
|
25
|
-
} catch
|
|
61
|
+
} catch {
|
|
26
62
|
nodePath = 'node';
|
|
27
63
|
}
|
|
28
64
|
}
|
|
29
65
|
|
|
66
|
+
const serverId = computeServerIdForRepo(this.targetRoot);
|
|
30
67
|
const mcpConfig = {
|
|
31
68
|
mcpServers: {
|
|
32
|
-
|
|
69
|
+
[serverId]: {
|
|
33
70
|
command: nodePath,
|
|
34
71
|
args: [
|
|
35
|
-
'
|
|
72
|
+
path.join(this.targetRoot, 'scripts/hooks-system/infrastructure/mcp/ast-intelligence-automation.js')
|
|
36
73
|
],
|
|
37
74
|
env: {
|
|
38
|
-
REPO_ROOT:
|
|
75
|
+
REPO_ROOT: this.targetRoot,
|
|
39
76
|
AUTO_COMMIT_ENABLED: 'false',
|
|
40
77
|
AUTO_PUSH_ENABLED: 'false',
|
|
41
78
|
AUTO_PR_ENABLED: 'false'
|
|
@@ -44,75 +81,30 @@ class McpConfigurator {
|
|
|
44
81
|
}
|
|
45
82
|
};
|
|
46
83
|
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
fs.mkdirSync(ide.configDir, { recursive: true });
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const mcpConfigPath = path.join(ide.configDir, 'mcp.json');
|
|
56
|
-
|
|
57
|
-
if (!fs.existsSync(mcpConfigPath)) {
|
|
58
|
-
const configToWrite = ide.name === 'Claude Desktop'
|
|
59
|
-
? this.adaptConfigForClaudeDesktop(mcpConfig)
|
|
60
|
-
: mcpConfig;
|
|
84
|
+
const globalConfigPath = this.getGlobalWindsurfConfigPath();
|
|
85
|
+
const globalConfigDir = path.dirname(globalConfigPath);
|
|
86
|
+
if (!fs.existsSync(globalConfigDir)) {
|
|
87
|
+
fs.mkdirSync(globalConfigDir, { recursive: true });
|
|
88
|
+
}
|
|
61
89
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
90
|
+
try {
|
|
91
|
+
if (!fs.existsSync(globalConfigPath)) {
|
|
92
|
+
fs.writeFileSync(globalConfigPath, JSON.stringify(mcpConfig, null, 2));
|
|
93
|
+
this.logSuccess(`Configured global Windsurf MCP at ${globalConfigPath}`);
|
|
94
|
+
if (this.logger) this.logger.info('MCP_GLOBAL_CONFIGURED', { path: globalConfigPath });
|
|
66
95
|
} else {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (!existing.mcpServers) {
|
|
70
|
-
existing.mcpServers = {};
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
existing.mcpServers['ast-intelligence-automation'] = mcpConfig.mcpServers['ast-intelligence-automation'];
|
|
74
|
-
|
|
75
|
-
fs.writeFileSync(mcpConfigPath, JSON.stringify(existing, null, 2));
|
|
76
|
-
this.logSuccess(`Updated ${ide.configPath} (merged configuration)`);
|
|
77
|
-
if (this.logger) this.logger.info('MCP_CONFIG_UPDATED', { ide: ide.name, path: ide.configPath });
|
|
78
|
-
configuredCount++;
|
|
79
|
-
} catch (mergeError) {
|
|
80
|
-
this.logWarning(`${ide.configPath} already exists and couldn't be merged, skipping`);
|
|
81
|
-
if (this.logger) this.logger.warn('MCP_CONFIG_MERGE_FAILED', { ide: ide.name, error: mergeError.message });
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
});
|
|
96
|
+
const existing = JSON.parse(fs.readFileSync(globalConfigPath, 'utf8'));
|
|
97
|
+
if (!existing.mcpServers) existing.mcpServers = {};
|
|
85
98
|
|
|
86
|
-
|
|
87
|
-
this.configureFallback(mcpConfig);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
99
|
+
existing.mcpServers[serverId] = mcpConfig.mcpServers[serverId];
|
|
90
100
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
fs.mkdirSync(cursorDir, { recursive: true });
|
|
95
|
-
}
|
|
96
|
-
const fallbackPath = path.join(cursorDir, 'mcp.json');
|
|
97
|
-
if (!fs.existsSync(fallbackPath)) {
|
|
98
|
-
fs.writeFileSync(fallbackPath, JSON.stringify(mcpConfig, null, 2));
|
|
99
|
-
this.logSuccess('Configured .cursor/mcp.json (generic fallback)');
|
|
100
|
-
this.logInfo('Note: MCP servers work with any MCP-compatible IDE');
|
|
101
|
-
if (this.logger) this.logger.info('MCP_FALLBACK_CONFIGURED', { path: fallbackPath });
|
|
102
|
-
} else {
|
|
103
|
-
try {
|
|
104
|
-
const existing = JSON.parse(fs.readFileSync(fallbackPath, 'utf8'));
|
|
105
|
-
if (!existing.mcpServers) {
|
|
106
|
-
existing.mcpServers = {};
|
|
107
|
-
}
|
|
108
|
-
existing.mcpServers['ast-intelligence-automation'] = mcpConfig.mcpServers['ast-intelligence-automation'];
|
|
109
|
-
fs.writeFileSync(fallbackPath, JSON.stringify(existing, null, 2));
|
|
110
|
-
this.logSuccess('Updated .cursor/mcp.json (merged configuration)');
|
|
111
|
-
if (this.logger) this.logger.info('MCP_FALLBACK_UPDATED', { path: fallbackPath });
|
|
112
|
-
} catch (mergeError) {
|
|
113
|
-
this.logWarning('.cursor/mcp.json exists and couldn\'t be merged, skipping');
|
|
114
|
-
if (this.logger) this.logger.warn('MCP_FALLBACK_MERGE_FAILED', { error: mergeError.message });
|
|
101
|
+
fs.writeFileSync(globalConfigPath, JSON.stringify(existing, null, 2));
|
|
102
|
+
this.logSuccess(`Updated global Windsurf MCP at ${globalConfigPath}`);
|
|
103
|
+
if (this.logger) this.logger.info('MCP_GLOBAL_UPDATED', { path: globalConfigPath });
|
|
115
104
|
}
|
|
105
|
+
} catch (mergeError) {
|
|
106
|
+
this.logWarning(`${globalConfigPath} exists but couldn't be merged, skipping`);
|
|
107
|
+
if (this.logger) this.logger.warn('MCP_GLOBAL_MERGE_FAILED', { error: mergeError.message });
|
|
116
108
|
}
|
|
117
109
|
}
|
|
118
110
|
|
|
@@ -10,57 +10,7 @@
|
|
|
10
10
|
"architecture": {
|
|
11
11
|
"pattern": "FEATURE_FIRST_CLEAN_DDD",
|
|
12
12
|
"strictMode": true,
|
|
13
|
-
"enforcement": "strict"
|
|
14
|
-
"ios": {
|
|
15
|
-
"architecturePattern": "FEATURE_FIRST_CLEAN_DDD",
|
|
16
|
-
"allowedPatterns": [
|
|
17
|
-
"MVP",
|
|
18
|
-
"MVVM",
|
|
19
|
-
"VIPER",
|
|
20
|
-
"HEXAGONAL",
|
|
21
|
-
"TCA"
|
|
22
|
-
],
|
|
23
|
-
"prohibitedPatterns": [
|
|
24
|
-
"MVVM-C",
|
|
25
|
-
"MVC"
|
|
26
|
-
],
|
|
27
|
-
"navigationPattern": "EVENT_DRIVEN",
|
|
28
|
-
"documentation": "docs/ARCHITECTURE.md"
|
|
29
|
-
},
|
|
30
|
-
"android": {
|
|
31
|
-
"architecturePattern": "FEATURE_FIRST_CLEAN_DDD",
|
|
32
|
-
"allowedPatterns": [
|
|
33
|
-
"MVVM",
|
|
34
|
-
"MVI",
|
|
35
|
-
"MVP"
|
|
36
|
-
],
|
|
37
|
-
"prohibitedPatterns": [
|
|
38
|
-
"MVC"
|
|
39
|
-
],
|
|
40
|
-
"composeOnly": true,
|
|
41
|
-
"hiltRequired": true
|
|
42
|
-
},
|
|
43
|
-
"frontend": {
|
|
44
|
-
"architecturePattern": "FEATURE_FIRST_CLEAN_DDD",
|
|
45
|
-
"allowedPatterns": [
|
|
46
|
-
"COMPONENT_BASED",
|
|
47
|
-
"ATOMIC_DESIGN"
|
|
48
|
-
],
|
|
49
|
-
"prohibitedPatterns": [
|
|
50
|
-
"MVC"
|
|
51
|
-
]
|
|
52
|
-
},
|
|
53
|
-
"backend": {
|
|
54
|
-
"architecturePattern": "FEATURE_FIRST_CLEAN_DDD",
|
|
55
|
-
"allowedPatterns": [
|
|
56
|
-
"HEXAGONAL",
|
|
57
|
-
"CLEAN",
|
|
58
|
-
"ONION"
|
|
59
|
-
],
|
|
60
|
-
"prohibitedPatterns": [
|
|
61
|
-
"MVC"
|
|
62
|
-
]
|
|
63
|
-
}
|
|
13
|
+
"enforcement": "strict"
|
|
64
14
|
},
|
|
65
15
|
"rules": {
|
|
66
16
|
"enabled": true,
|
|
@@ -28,7 +28,30 @@ const { execSync } = require('child_process');
|
|
|
28
28
|
const MCP_VERSION = '2024-11-05';
|
|
29
29
|
|
|
30
30
|
// Configuration - LAZY LOADING to avoid blocking MCP initialization
|
|
31
|
-
|
|
31
|
+
function safeGitRoot(startDir) {
|
|
32
|
+
try {
|
|
33
|
+
const out = execSync('git rev-parse --show-toplevel', {
|
|
34
|
+
cwd: startDir,
|
|
35
|
+
encoding: 'utf8',
|
|
36
|
+
stdio: ['ignore', 'pipe', 'ignore']
|
|
37
|
+
});
|
|
38
|
+
const root = String(out || '').trim();
|
|
39
|
+
return root || null;
|
|
40
|
+
} catch {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function resolveRepoRoot() {
|
|
46
|
+
const envRoot = (process.env.REPO_ROOT || '').trim() || null;
|
|
47
|
+
const cwdRoot = safeGitRoot(process.cwd());
|
|
48
|
+
// Prefer explicit REPO_ROOT to avoid cross-repo bleed when MCP server is launched from another workspace
|
|
49
|
+
if (envRoot) return envRoot;
|
|
50
|
+
if (cwdRoot) return cwdRoot;
|
|
51
|
+
return process.cwd();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const REPO_ROOT = resolveRepoRoot();
|
|
32
55
|
|
|
33
56
|
// Lazy-loaded CompositionRoot - only initialized when first needed
|
|
34
57
|
let _compositionRoot = null;
|
|
@@ -1026,11 +1026,11 @@ run_ast_intelligence() {
|
|
|
1026
1026
|
done
|
|
1027
1027
|
|
|
1028
1028
|
# Execute AST with proper error handling and NODE_PATH
|
|
1029
|
-
#
|
|
1029
|
+
# Change to HOOKS_SYSTEM_DIR so Node.js resolves modules correctly
|
|
1030
1030
|
if [[ -n "$node_path_value" ]]; then
|
|
1031
|
-
ast_output=$(cd "$
|
|
1031
|
+
ast_output=$(cd "$HOOKS_SYSTEM_DIR" && export NODE_PATH="$node_path_value" && export AUDIT_TMP="$TMP_DIR" && export AUDIT_LIBRARY="${AUDIT_LIBRARY:-false}" && "$node_bin" "${AST_DIR}/ast-intelligence.js" 2>&1) || ast_exit_code=$?
|
|
1032
1032
|
else
|
|
1033
|
-
ast_output=$(cd "$
|
|
1033
|
+
ast_output=$(cd "$HOOKS_SYSTEM_DIR" && export AUDIT_TMP="$TMP_DIR" && export AUDIT_LIBRARY="${AUDIT_LIBRARY:-false}" && "$node_bin" "${AST_DIR}/ast-intelligence.js" 2>&1) || ast_exit_code=$?
|
|
1034
1034
|
fi
|
|
1035
1035
|
|
|
1036
1036
|
# Check if AST script failed
|