s9n-devops-agent 2.0.9 → 2.0.11-dev.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.
@@ -27,6 +27,7 @@ import path from 'path';
27
27
  import { execSync } from 'child_process';
28
28
  import { fileURLToPath } from 'url';
29
29
  import { dirname } from 'path';
30
+ import { credentialsManager } from './credentials-manager.js';
30
31
  import {
31
32
  colors,
32
33
  status,
@@ -113,9 +114,116 @@ function backupFile(filePath) {
113
114
  return null;
114
115
  }
115
116
 
116
- // ============================================================================
117
+ function setupFolderStructure(projectRoot) {
118
+ log.header();
119
+ log.title('📂 Checking Folder Structure');
120
+
121
+ // Folders defined in folders.md
122
+ const standardFolders = [
123
+ 'src',
124
+ 'test',
125
+ 'docs',
126
+ 'scripts',
127
+ 'deploy_test',
128
+ 'product_requirement_docs',
129
+ 'infrastructure'
130
+ ];
131
+
132
+ const missingFolders = standardFolders.filter(folder => !fs.existsSync(path.join(projectRoot, folder)));
133
+
134
+ if (missingFolders.length === 0) {
135
+ log.info('Standard folder structure already exists.');
136
+ return;
137
+ }
138
+
139
+ log.info('Found missing standard folders:');
140
+ missingFolders.forEach(folder => console.log(` - ${folder}/`));
141
+ console.log();
142
+
143
+ explain(`
144
+ ${colors.bright}Recommended Structure:${colors.reset}
145
+ Standard folders help organize your code, tests, and documentation.
146
+ This structure is compatible with the DevOps Agent's automation tools.
147
+ `);
148
+
149
+ // We can't use await here because this function is synchronous in the flow,
150
+ // but the main flow is async. We should probably make this async or use prompt from ui-utils.
151
+ // However, looking at the code structure, helper functions are sync or async.
152
+ // Let's return the missing folders and handle the prompt in the main function or make this async.
153
+ return missingFolders;
154
+ }
155
+
156
+ function checkContractsExist(projectRoot) {
157
+ const contractsDir = path.join(projectRoot, 'House_Rules_Contracts');
158
+ if (!fs.existsSync(contractsDir)) return false;
159
+
160
+ const requiredContracts = [
161
+ 'FEATURES_CONTRACT.md',
162
+ 'API_CONTRACT.md',
163
+ 'DATABASE_SCHEMA_CONTRACT.md',
164
+ 'SQL_CONTRACT.json',
165
+ 'THIRD_PARTY_INTEGRATIONS.md',
166
+ 'INFRA_CONTRACT.md'
167
+ ];
168
+
169
+ return requiredContracts.every(file => fs.existsSync(path.join(contractsDir, file)));
170
+ }
171
+
172
+ async function generateContracts(projectRoot) {
173
+ log.header();
174
+ log.title('📜 Generating Contracts');
175
+
176
+ const scriptsDir = path.join(projectRoot, 'scripts', 'contract-automation');
177
+ const generateScript = path.join(scriptsDir, 'generate-contracts.js');
178
+ const analyzeScript = path.join(scriptsDir, 'analyze-with-llm.js');
179
+
180
+ if (!fs.existsSync(generateScript)) {
181
+ log.error('Contract generation scripts not found!');
182
+ return;
183
+ }
184
+
185
+ try {
186
+ // 1. Run local scan
187
+ info('Running local codebase scan...');
188
+ execSync(`node "${generateScript}"`, { cwd: projectRoot, stdio: 'inherit' });
189
+ success('Scan complete.');
190
+
191
+ // 2. Run LLM analysis if key exists
192
+ if (credentialsManager.hasGroqApiKey()) {
193
+ info('Enhancing contracts with AI analysis...');
194
+ try {
195
+ // Inject env for the child process
196
+ const env = { ...process.env };
197
+ credentialsManager.injectEnv(); // Ensure current process has it
198
+ // Note: execSync inherits env by default, but explicit is safer if we modified it
199
+ if (!env.GROQ_API_KEY && credentialsManager.getGroqApiKey()) {
200
+ env.GROQ_API_KEY = credentialsManager.getGroqApiKey();
201
+ env.OPENAI_API_KEY = credentialsManager.getGroqApiKey();
202
+ }
203
+
204
+ execSync(`node "${analyzeScript}" --scan-results=House_Rules_Contracts/contract-scan-results.json`, {
205
+ cwd: projectRoot,
206
+ stdio: 'inherit',
207
+ env
208
+ });
209
+ success('AI analysis complete.');
210
+ } catch (err) {
211
+ warn(`AI analysis failed: ${err.message}`);
212
+ warn('Contracts generated but without AI enhancements.');
213
+ }
214
+ } else {
215
+ warn('Skipping AI analysis (no Groq API Key).');
216
+ warn('Run "s9n-devops-agent creds set-groq-key <key>" later to enable this.');
217
+ }
218
+
219
+ } catch (error) {
220
+ log.error(`Contract generation failed: ${error.message}`);
221
+ }
222
+ }
223
+
224
+ // ===========================================================================
117
225
  // SETUP FUNCTIONS
118
- // ============================================================================
226
+ // ===========================================================================
119
227
 
120
228
  async function setupNpmPackages(projectRoot) {
121
229
  log.header();
@@ -976,6 +1084,37 @@ ${colors.bright}How:${colors.reset} Creates branches like dev_abc_2025-10-31
976
1084
  tip(`Your branches will be named: ${colors.cyan}dev_${initials}_YYYY-MM-DD${colors.reset}`);
977
1085
  console.log();
978
1086
 
1087
+ // Groq API Key Setup
1088
+ sectionTitle('Groq API Key (Contract Automation)');
1089
+ explain(`
1090
+ ${colors.bright}What:${colors.reset} API Key for Groq (llama-3.1-70b-versatile)
1091
+ ${colors.bright}Why:${colors.reset} Required for AI-Optimized Contract Automation System
1092
+ ${colors.bright}Security:${colors.reset} Stored locally in ${colors.yellow}local_deploy/credentials.json${colors.reset} (gitignored)
1093
+ `);
1094
+
1095
+ const hasKey = credentialsManager.hasGroqApiKey();
1096
+ let groqKey = null;
1097
+
1098
+ if (hasKey) {
1099
+ info('Groq API Key is already configured.');
1100
+ const update = await confirm('Do you want to update it?', false);
1101
+ if (update) {
1102
+ groqKey = await prompt('Enter your Groq API Key');
1103
+ }
1104
+ } else {
1105
+ groqKey = await prompt('Enter your Groq API Key (leave empty to skip)');
1106
+ }
1107
+
1108
+ if (groqKey && groqKey.trim()) {
1109
+ credentialsManager.setGroqApiKey(groqKey.trim());
1110
+ success('Groq API Key saved securely.');
1111
+ } else if (!hasKey) {
1112
+ warn('Skipping Groq API Key setup.');
1113
+ warn('NOTE: Contract Automation features (analyze-with-llm.js) will NOT work without this key.');
1114
+ }
1115
+
1116
+ console.log();
1117
+
979
1118
  // Confirm before proceeding
980
1119
  drawSection('Configuration Summary', [
981
1120
  `${status.folder} Branch prefix: ${colors.cyan}dev_${initials}_${colors.reset}`,
@@ -983,7 +1122,9 @@ ${colors.bright}How:${colors.reset} Creates branches like dev_abc_2025-10-31
983
1122
  `${status.checkmark} VS Code settings and tasks`,
984
1123
  `${status.checkmark} NPM packages and scripts`,
985
1124
  `${status.checkmark} Commit message files`,
986
- `${status.checkmark} House rules for AI agents`
1125
+ `${status.checkmark} House rules for AI agents`,
1126
+ `${status.folder} Standard folder structure check`,
1127
+ `${status.checkmark} Contract files check`
987
1128
  ]);
988
1129
  console.log();
989
1130
 
@@ -999,6 +1140,37 @@ ${colors.bright}How:${colors.reset} Creates branches like dev_abc_2025-10-31
999
1140
  console.log();
1000
1141
 
1001
1142
  try {
1143
+ // Check and setup folder structure first
1144
+ const missingFolders = setupFolderStructure(projectRoot);
1145
+ if (missingFolders && missingFolders.length > 0) {
1146
+ const createFolders = await confirm('Create missing standard folders?', true);
1147
+ if (createFolders) {
1148
+ missingFolders.forEach(folder => {
1149
+ ensureDirectoryExists(path.join(projectRoot, folder));
1150
+ log.success(`Created ${folder}/`);
1151
+ });
1152
+ } else {
1153
+ log.warn('Skipping folder creation.');
1154
+ }
1155
+ }
1156
+
1157
+ // Check for contracts
1158
+ if (!checkContractsExist(projectRoot)) {
1159
+ log.header();
1160
+ log.title('📜 Contract Files Missing');
1161
+ explain(`
1162
+ ${colors.bright}Contract System:${colors.reset}
1163
+ This project uses a Contract System to coordinate multiple AI agents.
1164
+ It seems like this is a fresh setup or contracts are missing.
1165
+ We can scan your codebase and generate them now.
1166
+ `);
1167
+
1168
+ const shouldGenerate = await confirm('Generate contract files now?', true);
1169
+ if (shouldGenerate) {
1170
+ await generateContracts(projectRoot);
1171
+ }
1172
+ }
1173
+
1002
1174
  // Run setup steps
1003
1175
  const packageJson = await setupNpmPackages(projectRoot);
1004
1176
  setupVSCodeSettings(projectRoot, initials);