pumuki-ast-hooks 5.5.0 → 5.5.1

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.5.0",
3
+ "version": "5.5.1",
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": {
@@ -967,166 +967,172 @@ async function handleMcpMessage(message) {
967
967
  // Start protocol handler
968
968
  protocolHandler.start(handleMcpMessage);
969
969
 
970
+ // Log MCP ready
971
+ process.stderr.write(`[MCP] Server ready for ${REPO_ROOT}\n`);
972
+
970
973
  /**
971
974
  * Polling loop for background notifications and automations
975
+ * IMPORTANT: Delayed start to avoid blocking MCP initialization handshake
972
976
  */
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;
998
- }
999
- }
1000
-
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');
977
+ setTimeout(() => {
978
+ setInterval(async () => {
979
+ try {
980
+ const now = Date.now();
981
+ const gitFlowService = getCompositionRoot().getGitFlowService();
982
+ const gitQuery = getCompositionRoot().getGitQueryAdapter();
983
+ const evidenceMonitor = getCompositionRoot().getEvidenceMonitor();
984
+ const orchestrator = getCompositionRoot().getOrchestrator();
985
+
986
+ const currentBranch = gitFlowService.getCurrentBranch();
987
+ const baseBranch = process.env.AST_BASE_BRANCH || 'develop';
988
+ const isProtectedBranch = ['main', 'master', baseBranch].includes(currentBranch);
989
+
990
+ const uncommittedChanges = gitQuery.getUncommittedChanges();
991
+ const hasUncommittedChanges = uncommittedChanges && uncommittedChanges.length > 0;
992
+
993
+ // 1. Protected Branch Guard
994
+ if (isProtectedBranch && hasUncommittedChanges) {
995
+ if (now - lastGitFlowNotification > NOTIFICATION_COOLDOWN) {
996
+ const state = gitQuery.getBranchState(currentBranch);
997
+ sendNotification(
998
+ '⚠️ Git Flow Violation',
999
+ `branch=${currentBranch} changes detected on protected branch. Create a feature branch.`,
1000
+ 'Basso'
1001
+ );
1002
+ lastGitFlowNotification = now;
1003
+ }
1008
1004
  }
1009
- lastEvidenceNotification = now;
1010
- }
1011
1005
 
1012
- // 3. Autonomous Orchestration
1013
- if (orchestrator.shouldReanalyze()) {
1014
- const decision = await orchestrator.analyzeContext();
1015
- if (decision.action === 'auto-execute' && decision.platforms.length > 0) {
1006
+ // 2. Evidence Freshness Guard
1007
+ if (evidenceMonitor.isStale() && (now - lastEvidenceNotification > NOTIFICATION_COOLDOWN)) {
1016
1008
  try {
1017
1009
  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');
1010
+ sendNotification('🔄 Evidence Auto-Updated', 'AI Evidence has been refreshed automatically', 'Purr');
1011
+ } catch (err) {
1012
+ sendNotification('⚠️ Evidence Stale', `Failed to auto-refresh evidence: ${err.message}`, 'Basso');
1021
1013
  }
1014
+ lastEvidenceNotification = now;
1022
1015
  }
1023
- }
1024
1016
 
1025
- } catch (error) {
1026
- if (process.env.DEBUG) console.error('[MCP] Polling loop error:', error);
1027
- }
1028
- }, 30000);
1017
+ // 3. Autonomous Orchestration
1018
+ if (orchestrator.shouldReanalyze()) {
1019
+ const decision = await orchestrator.analyzeContext();
1020
+ if (decision.action === 'auto-execute' && decision.platforms.length > 0) {
1021
+ try {
1022
+ await evidenceMonitor.refresh();
1023
+ sendNotification('✅ AI Start Executed', `Platforms: ${decision.platforms.map(p => p.platform.toUpperCase()).join(', ')}`, 'Glass');
1024
+ } catch (e) {
1025
+ sendNotification('❌ AI Start Error', `Failed to execute: ${e.message}`, 'Basso');
1026
+ }
1027
+ }
1028
+ }
1029
1029
 
1030
- // AUTO-COMMIT: Only for project code changes (no node_modules, no library)
1031
- setInterval(async () => {
1032
- if (!AUTO_COMMIT_ENABLED) {
1033
- return;
1034
- }
1030
+ } catch (error) {
1031
+ if (process.env.DEBUG) console.error('[MCP] Polling loop error:', error);
1032
+ }
1033
+ }, 30000);
1035
1034
 
1036
- const now = Date.now();
1037
- if (now - lastAutoCommitTime < AUTO_COMMIT_INTERVAL) return;
1035
+ // AUTO-COMMIT: Only for project code changes (no node_modules, no library)
1036
+ setInterval(async () => {
1037
+ if (!AUTO_COMMIT_ENABLED) {
1038
+ return;
1039
+ }
1038
1040
 
1039
- try {
1040
- const gitFlowService = getCompositionRoot().getGitFlowService();
1041
- const gitQuery = getCompositionRoot().getGitQueryAdapter();
1042
- const gitCommand = getCompositionRoot().getGitCommandAdapter();
1041
+ const now = Date.now();
1042
+ if (now - lastAutoCommitTime < AUTO_COMMIT_INTERVAL) return;
1043
1043
 
1044
- const currentBranch = gitFlowService.getCurrentBranch();
1045
- const isFeatureBranch = currentBranch.match(/^(feature|fix|hotfix)\//);
1044
+ try {
1045
+ const gitFlowService = getCompositionRoot().getGitFlowService();
1046
+ const gitQuery = getCompositionRoot().getGitQueryAdapter();
1047
+ const gitCommand = getCompositionRoot().getGitCommandAdapter();
1046
1048
 
1047
- if (!isFeatureBranch) {
1048
- return;
1049
- }
1049
+ const currentBranch = gitFlowService.getCurrentBranch();
1050
+ const isFeatureBranch = currentBranch.match(/^(feature|fix|hotfix)\//);
1050
1051
 
1051
- if (gitFlowService.isClean()) {
1052
- return;
1053
- }
1052
+ if (!isFeatureBranch) {
1053
+ return;
1054
+ }
1054
1055
 
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;
1056
+ if (gitFlowService.isClean()) {
1057
+ return;
1072
1058
  }
1073
1059
 
1074
- // Exclude library itself
1075
- if (libraryPath && file.startsWith(libraryPath + '/')) {
1076
- return false;
1060
+ // Get uncommitted changes
1061
+ const uncommittedChanges = gitQuery.getUncommittedChanges();
1062
+
1063
+ // Detect library installation path
1064
+ const libraryPath = getLibraryInstallPath();
1065
+
1066
+ // Filter changes: project code only
1067
+ const filesToCommit = uncommittedChanges.filter(file => {
1068
+ // Exclude noise
1069
+ if (file.startsWith('node_modules/') ||
1070
+ file.includes('package-lock.json') ||
1071
+ file.startsWith('.git/') ||
1072
+ file.startsWith('.cursor/') ||
1073
+ file.startsWith('.ast-intelligence/') ||
1074
+ file.startsWith('.vscode/') ||
1075
+ file.startsWith('.idea/')) {
1076
+ return false;
1077
+ }
1078
+
1079
+ // Exclude library itself
1080
+ if (libraryPath && file.startsWith(libraryPath + '/')) {
1081
+ return false;
1082
+ }
1083
+
1084
+ // Code/Doc files only
1085
+ const codeExtensions = ['.ts', '.tsx', '.js', '.jsx', '.swift', '.kt', '.py', '.java', '.go', '.rs', '.md', '.json', '.yaml', '.yml'];
1086
+ return codeExtensions.some(ext => file.endsWith(ext));
1087
+ });
1088
+
1089
+ if (filesToCommit.length === 0) {
1090
+ return;
1077
1091
  }
1078
1092
 
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
- });
1093
+ // Stage files
1094
+ filesToCommit.forEach(file => {
1095
+ gitCommand.add(file);
1096
+ });
1083
1097
 
1084
- if (filesToCommit.length === 0) {
1085
- return;
1086
- }
1098
+ const branchType = currentBranch.split('/')[0];
1099
+ const branchName = currentBranch.split('/').slice(1).join('/');
1100
+ const commitMessage = `${branchType}(auto): ${branchName} - ${filesToCommit.length} files`;
1087
1101
 
1088
- // Stage files
1089
- filesToCommit.forEach(file => {
1090
- gitCommand.add(file);
1091
- });
1102
+ // Commit
1103
+ gitCommand.commit(commitMessage);
1092
1104
 
1093
- const branchType = currentBranch.split('/')[0];
1094
- const branchName = currentBranch.split('/').slice(1).join('/');
1095
- const commitMessage = `${branchType}(auto): ${branchName} - ${filesToCommit.length} files`;
1105
+ sendNotification('✅ Auto-Commit', `${filesToCommit.length} files in ${currentBranch}`, 'Purr');
1106
+ lastAutoCommitTime = now;
1096
1107
 
1097
- // Commit
1098
- gitCommand.commit(commitMessage);
1108
+ if (AUTO_PUSH_ENABLED) {
1109
+ if (gitFlowService.isGitHubAvailable()) {
1110
+ try {
1111
+ gitCommand.push('origin', currentBranch);
1112
+ sendNotification('✅ Auto-Push', `Pushed to origin/${currentBranch}`, 'Glass');
1099
1113
 
1100
- sendNotification('✅ Auto-Commit', `${filesToCommit.length} files in ${currentBranch}`, 'Purr');
1101
- lastAutoCommitTime = now;
1114
+ if (AUTO_PR_ENABLED) {
1115
+ const baseBranch = process.env.AST_BASE_BRANCH || 'develop';
1116
+ const branchState = gitQuery.getBranchState(currentBranch);
1102
1117
 
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');
1118
+ if (branchState.ahead >= 3) {
1119
+ const prTitle = `Auto-PR: ${branchName}`;
1120
+ const prUrl = gitFlowService.createPullRequest(currentBranch, baseBranch, prTitle, 'Automated PR by Pumuki Git Flow');
1121
+ if (prUrl) {
1122
+ sendNotification('✅ Auto-PR Created', prTitle, 'Hero');
1123
+ }
1118
1124
  }
1119
1125
  }
1120
- }
1121
- } catch (e) {
1122
- if (!e.message.includes('No remote')) {
1123
- sendNotification('⚠️ Auto-Push Failed', 'Push manual required', 'Basso');
1126
+ } catch (e) {
1127
+ if (!e.message.includes('No remote')) {
1128
+ sendNotification('⚠️ Auto-Push Failed', 'Push manual required', 'Basso');
1129
+ }
1124
1130
  }
1125
1131
  }
1126
1132
  }
1127
- }
1128
1133
 
1129
- } catch (error) {
1130
- if (process.env.DEBUG) console.error('[MCP] Auto-commit error:', error);
1131
- }
1132
- }, AUTO_COMMIT_INTERVAL);
1134
+ } catch (error) {
1135
+ if (process.env.DEBUG) console.error('[MCP] Auto-commit error:', error);
1136
+ }
1137
+ }, AUTO_COMMIT_INTERVAL);
1138
+ }, 2000); // Delay 2 seconds to allow MCP handshake to complete first