pumuki-ast-hooks 5.4.8 → 5.5.0
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pumuki-ast-hooks",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.5.0",
|
|
4
4
|
"description": "Enterprise-grade AST Intelligence System with multi-platform support (iOS, Android, Backend, Frontend) and Feature-First + DDD + Clean Architecture enforcement. Includes dynamic violations API for intelligent querying.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -18,8 +18,6 @@
|
|
|
18
18
|
const fs = require('fs');
|
|
19
19
|
const path = require('path');
|
|
20
20
|
const { execSync } = require('child_process');
|
|
21
|
-
const crypto = require('crypto');
|
|
22
|
-
const os = require('os');
|
|
23
21
|
const env = require('../../config/env');
|
|
24
22
|
|
|
25
23
|
// Removed global requires for performance (Lazy Loading)
|
|
@@ -56,165 +54,8 @@ function resolveRepoRoot() {
|
|
|
56
54
|
|
|
57
55
|
const REPO_ROOT = resolveRepoRoot();
|
|
58
56
|
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
const repoHash = crypto.createHash('md5').update(REPO_ROOT).digest('hex').substring(0, 8);
|
|
62
|
-
const MCP_LOCK_DIR = path.join(os.tmpdir(), `mcp-ast-intelligence-${repoHash}.lock`);
|
|
63
|
-
const MCP_LOCK_PID = path.join(MCP_LOCK_DIR, 'pid');
|
|
64
|
-
|
|
65
|
-
let MCP_IS_PRIMARY = true;
|
|
66
|
-
|
|
67
|
-
function logMcpError(context, error) {
|
|
68
|
-
const msg = error instanceof Error ? error.message : String(error);
|
|
69
|
-
process.stderr.write(`[MCP][ERROR] ${context}: ${msg}\n`);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function logMcpDebug(message) {
|
|
73
|
-
if (env.getBool('DEBUG', false)) {
|
|
74
|
-
process.stderr.write(`[MCP][DEBUG] ${message}\n`);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function isPidRunning(pid) {
|
|
79
|
-
if (!pid || !Number.isFinite(pid) || pid <= 0) return false;
|
|
80
|
-
try {
|
|
81
|
-
process.kill(pid, 0);
|
|
82
|
-
return true;
|
|
83
|
-
} catch (error) {
|
|
84
|
-
logMcpDebug(`isPidRunning(${pid}) = false: ${error.code || error.message}`);
|
|
85
|
-
return false;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function safeReadPid(filePath) {
|
|
90
|
-
try {
|
|
91
|
-
if (!fs.existsSync(filePath)) return null;
|
|
92
|
-
const raw = String(fs.readFileSync(filePath, 'utf8') || '').trim();
|
|
93
|
-
const pid = Number(raw);
|
|
94
|
-
if (!Number.isFinite(pid) || pid <= 0) return null;
|
|
95
|
-
return pid;
|
|
96
|
-
} catch (error) {
|
|
97
|
-
logMcpError('safeReadPid', error);
|
|
98
|
-
return null;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
function removeLockDir() {
|
|
103
|
-
try {
|
|
104
|
-
if (fs.existsSync(MCP_LOCK_PID)) {
|
|
105
|
-
fs.unlinkSync(MCP_LOCK_PID);
|
|
106
|
-
logMcpDebug('Removed lock PID file');
|
|
107
|
-
}
|
|
108
|
-
} catch (error) {
|
|
109
|
-
logMcpError('removeLockDir (pid file)', error);
|
|
110
|
-
}
|
|
111
|
-
try {
|
|
112
|
-
if (fs.existsSync(MCP_LOCK_DIR)) {
|
|
113
|
-
fs.rmdirSync(MCP_LOCK_DIR);
|
|
114
|
-
logMcpDebug('Removed lock directory');
|
|
115
|
-
}
|
|
116
|
-
} catch (error) {
|
|
117
|
-
logMcpError('removeLockDir (directory)', error);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function cleanupAndExit(code = 0) {
|
|
122
|
-
const myPid = process.pid;
|
|
123
|
-
const lockPid = safeReadPid(MCP_LOCK_PID);
|
|
124
|
-
|
|
125
|
-
if (lockPid === myPid) {
|
|
126
|
-
logMcpDebug(`Cleaning up lock (my pid=${myPid})`);
|
|
127
|
-
removeLockDir();
|
|
128
|
-
} else {
|
|
129
|
-
logMcpDebug(`Not cleaning lock (lockPid=${lockPid}, myPid=${myPid})`);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
process.exit(code);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function installStdioExitHandlers() {
|
|
136
|
-
const handleStdioTermination = (source) => (error) => {
|
|
137
|
-
if (error) {
|
|
138
|
-
const code = String(error.code || '').toUpperCase();
|
|
139
|
-
if (code === 'EPIPE' || code === 'ERR_STREAM_DESTROYED' || code === 'ECONNRESET') {
|
|
140
|
-
logMcpDebug(`STDIO ${source} closed (${code}), exiting cleanly`);
|
|
141
|
-
cleanupAndExit(0);
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
logMcpError(`STDIO ${source} error`, error);
|
|
145
|
-
} else {
|
|
146
|
-
logMcpDebug(`STDIO ${source} ended, exiting cleanly`);
|
|
147
|
-
}
|
|
148
|
-
cleanupAndExit(0);
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
try {
|
|
152
|
-
process.stdin.on('end', handleStdioTermination('stdin'));
|
|
153
|
-
process.stdin.on('close', handleStdioTermination('stdin'));
|
|
154
|
-
process.stdin.on('error', handleStdioTermination('stdin'));
|
|
155
|
-
} catch (error) {
|
|
156
|
-
logMcpError('installStdioExitHandlers (stdin)', error);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
try {
|
|
160
|
-
process.stdout.on('error', handleStdioTermination('stdout'));
|
|
161
|
-
process.stderr.on('error', handleStdioTermination('stderr'));
|
|
162
|
-
} catch (error) {
|
|
163
|
-
logMcpError('installStdioExitHandlers (stdout/stderr)', error);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
function acquireSingletonLock() {
|
|
168
|
-
// No need to create .audit_tmp since lock is in /tmp/
|
|
169
|
-
|
|
170
|
-
try {
|
|
171
|
-
fs.mkdirSync(MCP_LOCK_DIR);
|
|
172
|
-
} catch (error) {
|
|
173
|
-
const existingPid = safeReadPid(MCP_LOCK_PID);
|
|
174
|
-
|
|
175
|
-
if (existingPid && isPidRunning(existingPid)) {
|
|
176
|
-
process.stderr.write(`[MCP] Another instance is already running (pid ${existingPid}). Exiting.\n`);
|
|
177
|
-
process.exit(0);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
logMcpDebug(`Lock exists but PID ${existingPid || 'unknown'} is not running, cleaning up`);
|
|
181
|
-
removeLockDir();
|
|
182
|
-
|
|
183
|
-
try {
|
|
184
|
-
fs.mkdirSync(MCP_LOCK_DIR);
|
|
185
|
-
} catch (retryError) {
|
|
186
|
-
logMcpError('acquireSingletonLock (retry mkdir)', retryError);
|
|
187
|
-
process.stderr.write(`[MCP] Failed to acquire lock after cleanup. Exiting.\n`);
|
|
188
|
-
process.exit(1);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
try {
|
|
193
|
-
fs.writeFileSync(MCP_LOCK_PID, String(process.pid), { encoding: 'utf8' });
|
|
194
|
-
logMcpDebug(`Lock acquired, PID ${process.pid} written`);
|
|
195
|
-
} catch (error) {
|
|
196
|
-
logMcpError('acquireSingletonLock (write pid)', error);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
process.on('exit', () => {
|
|
200
|
-
const lockPid = safeReadPid(MCP_LOCK_PID);
|
|
201
|
-
if (lockPid === process.pid) {
|
|
202
|
-
removeLockDir();
|
|
203
|
-
}
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
process.on('SIGINT', () => cleanupAndExit(0));
|
|
207
|
-
process.on('SIGTERM', () => cleanupAndExit(0));
|
|
208
|
-
process.on('SIGHUP', () => cleanupAndExit(0));
|
|
209
|
-
|
|
210
|
-
return { acquired: true, pid: process.pid };
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
const singleton = acquireSingletonLock();
|
|
214
|
-
if (!singleton.acquired) {
|
|
215
|
-
process.exit(0);
|
|
216
|
-
}
|
|
217
|
-
installStdioExitHandlers();
|
|
57
|
+
// NO singleton lock - Windsurf manages process lifecycle
|
|
58
|
+
// Each project gets its own independent MCP process
|
|
218
59
|
|
|
219
60
|
// Lazy-loaded CompositionRoot - only initialized when first needed
|
|
220
61
|
let _compositionRoot = null;
|
|
@@ -1129,167 +970,163 @@ protocolHandler.start(handleMcpMessage);
|
|
|
1129
970
|
/**
|
|
1130
971
|
* Polling loop for background notifications and automations
|
|
1131
972
|
*/
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
if (
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
lastGitFlowNotification = now;
|
|
1158
|
-
}
|
|
973
|
+
setInterval(async () => {
|
|
974
|
+
try {
|
|
975
|
+
const now = Date.now();
|
|
976
|
+
const gitFlowService = getCompositionRoot().getGitFlowService();
|
|
977
|
+
const gitQuery = getCompositionRoot().getGitQueryAdapter();
|
|
978
|
+
const evidenceMonitor = getCompositionRoot().getEvidenceMonitor();
|
|
979
|
+
const orchestrator = getCompositionRoot().getOrchestrator();
|
|
980
|
+
|
|
981
|
+
const currentBranch = gitFlowService.getCurrentBranch();
|
|
982
|
+
const baseBranch = process.env.AST_BASE_BRANCH || 'develop';
|
|
983
|
+
const isProtectedBranch = ['main', 'master', baseBranch].includes(currentBranch);
|
|
984
|
+
|
|
985
|
+
const uncommittedChanges = gitQuery.getUncommittedChanges();
|
|
986
|
+
const hasUncommittedChanges = uncommittedChanges && uncommittedChanges.length > 0;
|
|
987
|
+
|
|
988
|
+
// 1. Protected Branch Guard
|
|
989
|
+
if (isProtectedBranch && hasUncommittedChanges) {
|
|
990
|
+
if (now - lastGitFlowNotification > NOTIFICATION_COOLDOWN) {
|
|
991
|
+
const state = gitQuery.getBranchState(currentBranch);
|
|
992
|
+
sendNotification(
|
|
993
|
+
'⚠️ Git Flow Violation',
|
|
994
|
+
`branch=${currentBranch} changes detected on protected branch. Create a feature branch.`,
|
|
995
|
+
'Basso'
|
|
996
|
+
);
|
|
997
|
+
lastGitFlowNotification = now;
|
|
1159
998
|
}
|
|
999
|
+
}
|
|
1160
1000
|
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
}
|
|
1169
|
-
lastEvidenceNotification = now;
|
|
1001
|
+
// 2. Evidence Freshness Guard
|
|
1002
|
+
if (evidenceMonitor.isStale() && (now - lastEvidenceNotification > NOTIFICATION_COOLDOWN)) {
|
|
1003
|
+
try {
|
|
1004
|
+
await evidenceMonitor.refresh();
|
|
1005
|
+
sendNotification('🔄 Evidence Auto-Updated', 'AI Evidence has been refreshed automatically', 'Purr');
|
|
1006
|
+
} catch (err) {
|
|
1007
|
+
sendNotification('⚠️ Evidence Stale', `Failed to auto-refresh evidence: ${err.message}`, 'Basso');
|
|
1170
1008
|
}
|
|
1009
|
+
lastEvidenceNotification = now;
|
|
1010
|
+
}
|
|
1171
1011
|
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
}
|
|
1012
|
+
// 3. Autonomous Orchestration
|
|
1013
|
+
if (orchestrator.shouldReanalyze()) {
|
|
1014
|
+
const decision = await orchestrator.analyzeContext();
|
|
1015
|
+
if (decision.action === 'auto-execute' && decision.platforms.length > 0) {
|
|
1016
|
+
try {
|
|
1017
|
+
await evidenceMonitor.refresh();
|
|
1018
|
+
sendNotification('✅ AI Start Executed', `Platforms: ${decision.platforms.map(p => p.platform.toUpperCase()).join(', ')}`, 'Glass');
|
|
1019
|
+
} catch (e) {
|
|
1020
|
+
sendNotification('❌ AI Start Error', `Failed to execute: ${e.message}`, 'Basso');
|
|
1182
1021
|
}
|
|
1183
1022
|
}
|
|
1184
|
-
|
|
1185
|
-
} catch (error) {
|
|
1186
|
-
if (process.env.DEBUG) console.error('[MCP] Polling loop error:', error);
|
|
1187
1023
|
}
|
|
1188
|
-
}, 30000);
|
|
1189
|
-
}
|
|
1190
1024
|
|
|
1191
|
-
|
|
1192
|
-
if (
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
return;
|
|
1196
|
-
}
|
|
1197
|
-
|
|
1198
|
-
const now = Date.now();
|
|
1199
|
-
if (now - lastAutoCommitTime < AUTO_COMMIT_INTERVAL) return;
|
|
1025
|
+
} catch (error) {
|
|
1026
|
+
if (process.env.DEBUG) console.error('[MCP] Polling loop error:', error);
|
|
1027
|
+
}
|
|
1028
|
+
}, 30000);
|
|
1200
1029
|
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1030
|
+
// AUTO-COMMIT: Only for project code changes (no node_modules, no library)
|
|
1031
|
+
setInterval(async () => {
|
|
1032
|
+
if (!AUTO_COMMIT_ENABLED) {
|
|
1033
|
+
return;
|
|
1034
|
+
}
|
|
1205
1035
|
|
|
1206
|
-
|
|
1207
|
-
|
|
1036
|
+
const now = Date.now();
|
|
1037
|
+
if (now - lastAutoCommitTime < AUTO_COMMIT_INTERVAL) return;
|
|
1208
1038
|
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1039
|
+
try {
|
|
1040
|
+
const gitFlowService = getCompositionRoot().getGitFlowService();
|
|
1041
|
+
const gitQuery = getCompositionRoot().getGitQueryAdapter();
|
|
1042
|
+
const gitCommand = getCompositionRoot().getGitCommandAdapter();
|
|
1212
1043
|
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
}
|
|
1044
|
+
const currentBranch = gitFlowService.getCurrentBranch();
|
|
1045
|
+
const isFeatureBranch = currentBranch.match(/^(feature|fix|hotfix)\//);
|
|
1216
1046
|
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
// Detect library installation path
|
|
1221
|
-
const libraryPath = getLibraryInstallPath();
|
|
1222
|
-
|
|
1223
|
-
// Filter changes: project code only
|
|
1224
|
-
const filesToCommit = uncommittedChanges.filter(file => {
|
|
1225
|
-
// Exclude noise
|
|
1226
|
-
if (file.startsWith('node_modules/') ||
|
|
1227
|
-
file.includes('package-lock.json') ||
|
|
1228
|
-
file.startsWith('.git/') ||
|
|
1229
|
-
file.startsWith('.cursor/') ||
|
|
1230
|
-
file.startsWith('.ast-intelligence/') ||
|
|
1231
|
-
file.startsWith('.vscode/') ||
|
|
1232
|
-
file.startsWith('.idea/')) {
|
|
1233
|
-
return false;
|
|
1234
|
-
}
|
|
1047
|
+
if (!isFeatureBranch) {
|
|
1048
|
+
return;
|
|
1049
|
+
}
|
|
1235
1050
|
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
}
|
|
1051
|
+
if (gitFlowService.isClean()) {
|
|
1052
|
+
return;
|
|
1053
|
+
}
|
|
1240
1054
|
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1055
|
+
// Get uncommitted changes
|
|
1056
|
+
const uncommittedChanges = gitQuery.getUncommittedChanges();
|
|
1057
|
+
|
|
1058
|
+
// Detect library installation path
|
|
1059
|
+
const libraryPath = getLibraryInstallPath();
|
|
1060
|
+
|
|
1061
|
+
// Filter changes: project code only
|
|
1062
|
+
const filesToCommit = uncommittedChanges.filter(file => {
|
|
1063
|
+
// Exclude noise
|
|
1064
|
+
if (file.startsWith('node_modules/') ||
|
|
1065
|
+
file.includes('package-lock.json') ||
|
|
1066
|
+
file.startsWith('.git/') ||
|
|
1067
|
+
file.startsWith('.cursor/') ||
|
|
1068
|
+
file.startsWith('.ast-intelligence/') ||
|
|
1069
|
+
file.startsWith('.vscode/') ||
|
|
1070
|
+
file.startsWith('.idea/')) {
|
|
1071
|
+
return false;
|
|
1072
|
+
}
|
|
1245
1073
|
|
|
1246
|
-
|
|
1247
|
-
|
|
1074
|
+
// Exclude library itself
|
|
1075
|
+
if (libraryPath && file.startsWith(libraryPath + '/')) {
|
|
1076
|
+
return false;
|
|
1248
1077
|
}
|
|
1249
1078
|
|
|
1250
|
-
//
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1079
|
+
// Code/Doc files only
|
|
1080
|
+
const codeExtensions = ['.ts', '.tsx', '.js', '.jsx', '.swift', '.kt', '.py', '.java', '.go', '.rs', '.md', '.json', '.yaml', '.yml'];
|
|
1081
|
+
return codeExtensions.some(ext => file.endsWith(ext));
|
|
1082
|
+
});
|
|
1254
1083
|
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1084
|
+
if (filesToCommit.length === 0) {
|
|
1085
|
+
return;
|
|
1086
|
+
}
|
|
1258
1087
|
|
|
1259
|
-
|
|
1260
|
-
|
|
1088
|
+
// Stage files
|
|
1089
|
+
filesToCommit.forEach(file => {
|
|
1090
|
+
gitCommand.add(file);
|
|
1091
|
+
});
|
|
1261
1092
|
|
|
1262
|
-
|
|
1263
|
-
|
|
1093
|
+
const branchType = currentBranch.split('/')[0];
|
|
1094
|
+
const branchName = currentBranch.split('/').slice(1).join('/');
|
|
1095
|
+
const commitMessage = `${branchType}(auto): ${branchName} - ${filesToCommit.length} files`;
|
|
1264
1096
|
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
try {
|
|
1268
|
-
gitCommand.push('origin', currentBranch);
|
|
1269
|
-
sendNotification('✅ Auto-Push', `Pushed to origin/${currentBranch}`, 'Glass');
|
|
1097
|
+
// Commit
|
|
1098
|
+
gitCommand.commit(commitMessage);
|
|
1270
1099
|
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
const branchState = gitQuery.getBranchState(currentBranch);
|
|
1100
|
+
sendNotification('✅ Auto-Commit', `${filesToCommit.length} files in ${currentBranch}`, 'Purr');
|
|
1101
|
+
lastAutoCommitTime = now;
|
|
1274
1102
|
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1103
|
+
if (AUTO_PUSH_ENABLED) {
|
|
1104
|
+
if (gitFlowService.isGitHubAvailable()) {
|
|
1105
|
+
try {
|
|
1106
|
+
gitCommand.push('origin', currentBranch);
|
|
1107
|
+
sendNotification('✅ Auto-Push', `Pushed to origin/${currentBranch}`, 'Glass');
|
|
1108
|
+
|
|
1109
|
+
if (AUTO_PR_ENABLED) {
|
|
1110
|
+
const baseBranch = process.env.AST_BASE_BRANCH || 'develop';
|
|
1111
|
+
const branchState = gitQuery.getBranchState(currentBranch);
|
|
1112
|
+
|
|
1113
|
+
if (branchState.ahead >= 3) {
|
|
1114
|
+
const prTitle = `Auto-PR: ${branchName}`;
|
|
1115
|
+
const prUrl = gitFlowService.createPullRequest(currentBranch, baseBranch, prTitle, 'Automated PR by Pumuki Git Flow');
|
|
1116
|
+
if (prUrl) {
|
|
1117
|
+
sendNotification('✅ Auto-PR Created', prTitle, 'Hero');
|
|
1281
1118
|
}
|
|
1282
1119
|
}
|
|
1283
|
-
}
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1120
|
+
}
|
|
1121
|
+
} catch (e) {
|
|
1122
|
+
if (!e.message.includes('No remote')) {
|
|
1123
|
+
sendNotification('⚠️ Auto-Push Failed', 'Push manual required', 'Basso');
|
|
1287
1124
|
}
|
|
1288
1125
|
}
|
|
1289
1126
|
}
|
|
1290
|
-
|
|
1291
|
-
} catch (error) {
|
|
1292
|
-
if (process.env.DEBUG) console.error('[MCP] Auto-commit error:', error);
|
|
1293
1127
|
}
|
|
1294
|
-
|
|
1295
|
-
}
|
|
1128
|
+
|
|
1129
|
+
} catch (error) {
|
|
1130
|
+
if (process.env.DEBUG) console.error('[MCP] Auto-commit error:', error);
|
|
1131
|
+
}
|
|
1132
|
+
}, AUTO_COMMIT_INTERVAL);
|