s9n-devops-agent 2.0.18-dev.1 → 2.0.18-dev.12
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 +1 -0
- package/bin/cs-devops-agent +16 -20
- package/docs/RELEASE_NOTES.md +15 -0
- package/package.json +1 -1
- package/scripts/deploy-local.sh +100 -0
- package/src/agent-chat.js +299 -36
- package/src/credentials-manager.js +28 -6
- package/src/cs-devops-agent-worker.js +456 -87
- package/src/kora-skills.json +47 -0
- package/src/session-coordinator.js +499 -70
- package/src/setup-cs-devops-agent.js +298 -42
- package/src/ui-utils.js +1 -1
- package/start-devops-session.sh +4 -27
|
@@ -28,6 +28,7 @@ import { execSync } from 'child_process';
|
|
|
28
28
|
import { fileURLToPath } from 'url';
|
|
29
29
|
import { dirname } from 'path';
|
|
30
30
|
import { credentialsManager } from './credentials-manager.js';
|
|
31
|
+
import { SessionCoordinator } from './session-coordinator.js';
|
|
31
32
|
import {
|
|
32
33
|
colors,
|
|
33
34
|
status,
|
|
@@ -41,6 +42,7 @@ import {
|
|
|
41
42
|
error as errorMsg,
|
|
42
43
|
confirm,
|
|
43
44
|
prompt as uiPrompt,
|
|
45
|
+
choose,
|
|
44
46
|
progressStep,
|
|
45
47
|
drawSection
|
|
46
48
|
} from './ui-utils.js';
|
|
@@ -149,20 +151,165 @@ This structure is compatible with the DevOps Agent's automation tools.
|
|
|
149
151
|
return missingFolders;
|
|
150
152
|
}
|
|
151
153
|
|
|
152
|
-
function checkContractsExist(projectRoot) {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
154
|
+
async function checkContractsExist(projectRoot) {
|
|
155
|
+
// Search recursively for contract folders and files
|
|
156
|
+
try {
|
|
157
|
+
const requiredContracts = [
|
|
158
|
+
'FEATURES_CONTRACT.md',
|
|
159
|
+
'API_CONTRACT.md',
|
|
160
|
+
'DATABASE_SCHEMA_CONTRACT.md',
|
|
161
|
+
'SQL_CONTRACT.json',
|
|
162
|
+
'THIRD_PARTY_INTEGRATIONS.md',
|
|
163
|
+
'INFRA_CONTRACT.md'
|
|
164
|
+
];
|
|
165
|
+
|
|
166
|
+
// Map to hold found files for each type
|
|
167
|
+
const contractMap = {};
|
|
168
|
+
requiredContracts.forEach(c => contractMap[c] = []);
|
|
169
|
+
|
|
170
|
+
// Find all files that look like contracts
|
|
171
|
+
// We look for files containing "CONTRACT" in the name, excluding typical ignores
|
|
172
|
+
// Use -iname for case-insensitive matching
|
|
173
|
+
const findCommand = `find "${projectRoot}" -type f \\( -iname "*CONTRACT*.md" -o -iname "*CONTRACT*.json" \\) -not -path "*/node_modules/*" -not -path "*/.git/*" -not -path "*/local_deploy/*"`;
|
|
174
|
+
|
|
175
|
+
let files = [];
|
|
176
|
+
try {
|
|
177
|
+
const output = execSync(findCommand, { encoding: 'utf8' }).trim();
|
|
178
|
+
files = output.split('\n').filter(Boolean);
|
|
179
|
+
} catch (e) {
|
|
180
|
+
// find might fail if no matches or other issues, just treat as empty
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Categorize found files
|
|
184
|
+
for (const file of files) {
|
|
185
|
+
const basename = path.basename(file).toUpperCase();
|
|
186
|
+
|
|
187
|
+
// Skip files in the target directory itself (House_Rules_Contracts) to avoid self-merging if we run this multiple times
|
|
188
|
+
// actually we SHOULD include them to see if we have them, but valid if we are merging duplicates from elsewhere
|
|
189
|
+
|
|
190
|
+
let matched = false;
|
|
191
|
+
|
|
192
|
+
if (basename.includes('FEATURE')) contractMap['FEATURES_CONTRACT.md'].push(file);
|
|
193
|
+
else if (basename.includes('API')) contractMap['API_CONTRACT.md'].push(file);
|
|
194
|
+
else if (basename.includes('DATABASE') || basename.includes('SCHEMA')) contractMap['DATABASE_SCHEMA_CONTRACT.md'].push(file);
|
|
195
|
+
else if (basename.includes('SQL')) contractMap['SQL_CONTRACT.json'].push(file);
|
|
196
|
+
else if (basename.includes('INFRA')) contractMap['INFRA_CONTRACT.md'].push(file);
|
|
197
|
+
else if (basename.includes('THIRD') || basename.includes('INTEGRATION')) contractMap['THIRD_PARTY_INTEGRATIONS.md'].push(file);
|
|
198
|
+
else {
|
|
199
|
+
// Fallback or ignore
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const targetDir = path.join(projectRoot, 'House_Rules_Contracts');
|
|
204
|
+
let hasChanges = false;
|
|
205
|
+
|
|
206
|
+
// Process each contract type
|
|
207
|
+
let scatteredCount = 0;
|
|
208
|
+
let centralCount = 0;
|
|
209
|
+
let missingCount = 0;
|
|
210
|
+
|
|
211
|
+
// Print summary header
|
|
212
|
+
console.log(`\n${colors.bright}Contract Search Results:${colors.reset}`);
|
|
213
|
+
|
|
214
|
+
for (const [type, foundFiles] of Object.entries(contractMap)) {
|
|
215
|
+
// Filter out unique paths (resolve them)
|
|
216
|
+
const uniqueFiles = [...new Set(foundFiles.map(f => path.resolve(f)))];
|
|
217
|
+
const isCentral = fs.existsSync(path.join(targetDir, type));
|
|
218
|
+
|
|
219
|
+
let statusIcon = '';
|
|
220
|
+
let statusText = '';
|
|
221
|
+
|
|
222
|
+
if (isCentral) {
|
|
223
|
+
statusIcon = colors.green + '✓' + colors.reset;
|
|
224
|
+
statusText = colors.green + 'Present (Central)' + colors.reset;
|
|
225
|
+
centralCount++;
|
|
226
|
+
} else if (uniqueFiles.length > 0) {
|
|
227
|
+
statusIcon = colors.yellow + '⚠️' + colors.reset;
|
|
228
|
+
statusText = colors.yellow + `Found ${uniqueFiles.length} scattered file(s)` + colors.reset;
|
|
229
|
+
scatteredCount++;
|
|
230
|
+
} else {
|
|
231
|
+
statusIcon = colors.red + '✗' + colors.reset;
|
|
232
|
+
statusText = colors.red + 'Missing' + colors.reset;
|
|
233
|
+
missingCount++;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
console.log(` ${statusIcon} ${type.padEnd(30)} : ${statusText}`);
|
|
237
|
+
|
|
238
|
+
if (uniqueFiles.length > 0 && !isCentral) {
|
|
239
|
+
// Show locations for scattered files
|
|
240
|
+
uniqueFiles.forEach(f => console.log(` ${colors.dim}- ${path.relative(projectRoot, f)}${colors.reset}`));
|
|
241
|
+
|
|
242
|
+
const shouldMerge = await confirm(` Merge/Copy ${uniqueFiles.length} file(s) to House_Rules_Contracts/${type}?`, true);
|
|
243
|
+
|
|
244
|
+
if (shouldMerge) {
|
|
245
|
+
ensureDirectoryExists(targetDir);
|
|
246
|
+
const targetPath = path.join(targetDir, type);
|
|
247
|
+
|
|
248
|
+
let mergedContent = '';
|
|
249
|
+
// Handle JSON vs MD
|
|
250
|
+
if (type.endsWith('.json')) {
|
|
251
|
+
// For JSON, we try to merge arrays/objects or just list them
|
|
252
|
+
const mergedJson = [];
|
|
253
|
+
for (const file of uniqueFiles) {
|
|
254
|
+
try {
|
|
255
|
+
const content = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
256
|
+
mergedJson.push({ source: path.relative(projectRoot, file), content });
|
|
257
|
+
} catch (e) {
|
|
258
|
+
log.warn(`Skipping invalid JSON in ${path.basename(file)}`);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
mergedContent = JSON.stringify(mergedJson, null, 2);
|
|
262
|
+
} else {
|
|
263
|
+
// Markdown
|
|
264
|
+
mergedContent = `# Merged ${type}\n\nGenerated on ${new Date().toISOString()}\n\n`;
|
|
265
|
+
for (const file of uniqueFiles) {
|
|
266
|
+
const content = fs.readFileSync(file, 'utf8');
|
|
267
|
+
mergedContent += `\n<!-- SOURCE: ${path.relative(projectRoot, file)} -->\n`;
|
|
268
|
+
mergedContent += `## Source: ${path.basename(file)}\n(Path: ${path.relative(projectRoot, file)})\n\n`;
|
|
269
|
+
mergedContent += `${content}\n\n---\n`;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
fs.writeFileSync(targetPath, mergedContent);
|
|
274
|
+
log.success(` Merged into ${path.relative(projectRoot, targetPath)}`);
|
|
275
|
+
hasChanges = true;
|
|
276
|
+
centralCount++; // Now it's central
|
|
277
|
+
scatteredCount--;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
console.log(); // Spacing
|
|
283
|
+
|
|
284
|
+
// Final check logic
|
|
285
|
+
const result = {
|
|
286
|
+
missingCount,
|
|
287
|
+
scatteredCount,
|
|
288
|
+
centralCount,
|
|
289
|
+
valid: missingCount === 0
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
if (missingCount === 0) {
|
|
293
|
+
if (hasChanges) log.success('Contracts consolidated and verified.');
|
|
294
|
+
else log.info('All required contracts are present.');
|
|
295
|
+
return result;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (scatteredCount > 0) {
|
|
299
|
+
log.warn(`${scatteredCount} contract types exist but are not centralized.`);
|
|
300
|
+
log.warn('We recommend merging them, but you can proceed without it.');
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (missingCount > 0) {
|
|
304
|
+
log.warn(`${missingCount} contract types are completely missing.`);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return result;
|
|
308
|
+
|
|
309
|
+
} catch (error) {
|
|
310
|
+
log.warn(`Error searching for contracts: ${error.message}`);
|
|
311
|
+
return { missingCount: 1, scatteredCount: 0, valid: false }; // Fallback
|
|
312
|
+
}
|
|
166
313
|
}
|
|
167
314
|
|
|
168
315
|
async function generateContracts(projectRoot) {
|
|
@@ -834,30 +981,50 @@ async function setupEnvFile(projectRoot) {
|
|
|
834
981
|
log.info('Creating .env file');
|
|
835
982
|
}
|
|
836
983
|
|
|
837
|
-
// Check
|
|
984
|
+
// Check if OPENAI_API_KEY is already present in memory (from credentials.json)
|
|
985
|
+
const existingKey = credentialsManager.getGroqApiKey();
|
|
986
|
+
|
|
987
|
+
// Check for OPENAI_API_KEY in .env content
|
|
838
988
|
if (!envContent.includes('OPENAI_API_KEY=')) {
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
${colors.bright}Groq API Key Setup${colors.reset}
|
|
842
|
-
The contract automation features use Groq LLM (via OpenAI compatibility).
|
|
843
|
-
You can enter your API key now, or set it later in the .env file.
|
|
844
|
-
`);
|
|
845
|
-
|
|
846
|
-
const apiKey = await prompt('Enter Groq API Key (leave empty to skip)');
|
|
847
|
-
|
|
848
|
-
if (apiKey) {
|
|
989
|
+
if (existingKey) {
|
|
990
|
+
log.info('Found existing Groq API Key in credentials store.');
|
|
849
991
|
const newLine = envContent.endsWith('\n') || envContent === '' ? '' : '\n';
|
|
850
|
-
envContent += `${newLine}# Groq API Key for Contract Automation\nOPENAI_API_KEY=${
|
|
992
|
+
envContent += `${newLine}# Groq API Key for Contract Automation\nOPENAI_API_KEY=${existingKey}\n`;
|
|
851
993
|
fs.writeFileSync(envPath, envContent);
|
|
852
|
-
log.success('
|
|
994
|
+
log.success('Restored OPENAI_API_KEY to .env');
|
|
853
995
|
} else {
|
|
854
|
-
log
|
|
855
|
-
|
|
856
|
-
|
|
996
|
+
console.log();
|
|
997
|
+
explain(`
|
|
998
|
+
${colors.bright}Groq API Key Setup${colors.reset}
|
|
999
|
+
The contract automation features use Groq LLM (via OpenAI compatibility).
|
|
1000
|
+
You can enter your API key now, or set it later in the .env file.
|
|
1001
|
+
`);
|
|
1002
|
+
|
|
1003
|
+
const apiKey = await prompt('Enter Groq API Key (leave empty to skip)');
|
|
1004
|
+
|
|
1005
|
+
if (apiKey) {
|
|
1006
|
+
const newLine = envContent.endsWith('\n') || envContent === '' ? '' : '\n';
|
|
1007
|
+
envContent += `${newLine}# Groq API Key for Contract Automation\nOPENAI_API_KEY=${apiKey}\n`;
|
|
1008
|
+
fs.writeFileSync(envPath, envContent);
|
|
1009
|
+
|
|
1010
|
+
// Also save to credentials manager for persistence across updates
|
|
1011
|
+
credentialsManager.setGroqApiKey(apiKey);
|
|
1012
|
+
|
|
1013
|
+
log.success('Added OPENAI_API_KEY to .env');
|
|
1014
|
+
} else {
|
|
1015
|
+
log.warn('Skipped Groq API Key. Contract automation features may not work.');
|
|
1016
|
+
if (!fs.existsSync(envPath)) {
|
|
1017
|
+
fs.writeFileSync(envPath, '# Environment Variables\n');
|
|
1018
|
+
}
|
|
857
1019
|
}
|
|
858
1020
|
}
|
|
859
1021
|
} else {
|
|
860
1022
|
log.info('OPENAI_API_KEY is already configured in .env');
|
|
1023
|
+
// Ensure it's backed up in credentials manager if it exists in .env
|
|
1024
|
+
const match = envContent.match(/OPENAI_API_KEY=(.+)/);
|
|
1025
|
+
if (match && match[1] && !existingKey) {
|
|
1026
|
+
credentialsManager.setGroqApiKey(match[1].trim());
|
|
1027
|
+
}
|
|
861
1028
|
}
|
|
862
1029
|
}
|
|
863
1030
|
|
|
@@ -950,17 +1117,15 @@ ${colors.dim}This takes about 2 minutes.${colors.reset}
|
|
|
950
1117
|
const projectRoot = providedRoot ? path.resolve(providedRoot) : findProjectRoot();
|
|
951
1118
|
log.info(`Project root: ${projectRoot}`);
|
|
952
1119
|
|
|
953
|
-
//
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
// log.warn('ScriptCS_DevOpsAgent folder not found. Assuming global install or custom setup.');
|
|
957
|
-
// }
|
|
1120
|
+
// Initialize coordinator to access settings
|
|
1121
|
+
const coordinator = new SessionCoordinator();
|
|
1122
|
+
const currentSettings = coordinator.loadSettings();
|
|
958
1123
|
|
|
959
1124
|
// Get developer initials
|
|
960
1125
|
console.log();
|
|
961
1126
|
sectionTitle('Developer Identification');
|
|
962
1127
|
|
|
963
|
-
let initials = providedInitials;
|
|
1128
|
+
let initials = providedInitials || currentSettings.developerInitials;
|
|
964
1129
|
|
|
965
1130
|
if (!initials) {
|
|
966
1131
|
explain(`
|
|
@@ -995,6 +1160,7 @@ ${colors.bright}How:${colors.reset} Creates branches like dev_abc_2025-10-31
|
|
|
995
1160
|
sectionTitle('Primary AI Assistant');
|
|
996
1161
|
|
|
997
1162
|
let agentName = providedAgent;
|
|
1163
|
+
const defaultAgent = currentSettings.preferences?.primaryAgent || 'Claude';
|
|
998
1164
|
|
|
999
1165
|
if (!agentName) {
|
|
1000
1166
|
explain(`
|
|
@@ -1003,16 +1169,52 @@ ${colors.bright}Why:${colors.reset} Customizes file names (e.g., .warp-commit-ms
|
|
|
1003
1169
|
`);
|
|
1004
1170
|
|
|
1005
1171
|
if (skipPrompts) {
|
|
1006
|
-
agentName =
|
|
1172
|
+
agentName = defaultAgent; // Default if skipping prompts
|
|
1007
1173
|
} else {
|
|
1008
|
-
agentName = await prompt(
|
|
1009
|
-
agentName = agentName.trim() ||
|
|
1174
|
+
agentName = await prompt(`Primary AI Assistant? [${defaultAgent}]`, defaultAgent);
|
|
1175
|
+
agentName = agentName.trim() || defaultAgent;
|
|
1010
1176
|
}
|
|
1011
1177
|
}
|
|
1012
1178
|
|
|
1013
1179
|
success(`Using assistant: ${colors.cyan}${agentName}${colors.reset}`);
|
|
1014
1180
|
console.log();
|
|
1015
1181
|
|
|
1182
|
+
// Ask to save settings if changed or not saved
|
|
1183
|
+
if (!skipPrompts && (initials !== currentSettings.developerInitials || agentName !== currentSettings.preferences?.primaryAgent)) {
|
|
1184
|
+
console.log();
|
|
1185
|
+
sectionTitle('Save Preferences');
|
|
1186
|
+
explain(`
|
|
1187
|
+
${colors.bright}Save these settings for future sessions?${colors.reset}
|
|
1188
|
+
• ${colors.bright}Global:${colors.reset} Saves to ~/.devops-agent/settings.json (applies to all projects)
|
|
1189
|
+
• ${colors.bright}Project:${colors.reset} Saves to local_deploy/project-settings.json (this project only)
|
|
1190
|
+
`);
|
|
1191
|
+
|
|
1192
|
+
const saveChoice = await choose('Where should we save these settings?', [
|
|
1193
|
+
'Global (User Profile)',
|
|
1194
|
+
'Project (Local Only)',
|
|
1195
|
+
'Do not save'
|
|
1196
|
+
], { defaultChoice: '1' });
|
|
1197
|
+
|
|
1198
|
+
if (saveChoice === 0) {
|
|
1199
|
+
// Global
|
|
1200
|
+
const globalSettings = coordinator.loadGlobalSettings();
|
|
1201
|
+
globalSettings.developerInitials = initials;
|
|
1202
|
+
globalSettings.preferences = globalSettings.preferences || {};
|
|
1203
|
+
globalSettings.preferences.primaryAgent = agentName;
|
|
1204
|
+
globalSettings.configured = true;
|
|
1205
|
+
coordinator.saveGlobalSettings(globalSettings);
|
|
1206
|
+
log.success('Settings saved globally.');
|
|
1207
|
+
} else if (saveChoice === 1) {
|
|
1208
|
+
// Project
|
|
1209
|
+
const projectSettings = coordinator.loadProjectSettings();
|
|
1210
|
+
projectSettings.preferences = projectSettings.preferences || {};
|
|
1211
|
+
projectSettings.developerInitials = initials; // Allow project overrides
|
|
1212
|
+
projectSettings.preferences.primaryAgent = agentName;
|
|
1213
|
+
coordinator.saveProjectSettings(projectSettings);
|
|
1214
|
+
log.success('Settings saved to project.');
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1016
1218
|
// Groq API Key Setup
|
|
1017
1219
|
sectionTitle('Groq API Key (Contract Automation)');
|
|
1018
1220
|
|
|
@@ -1093,16 +1295,23 @@ ${colors.bright}Security:${colors.reset} Stored locally in ${colors.yellow}local
|
|
|
1093
1295
|
}
|
|
1094
1296
|
|
|
1095
1297
|
// Check for contracts
|
|
1096
|
-
|
|
1298
|
+
const contractStatus = await checkContractsExist(projectRoot);
|
|
1299
|
+
|
|
1300
|
+
if (contractStatus.missingCount > 0) {
|
|
1097
1301
|
log.header();
|
|
1098
1302
|
log.title('📜 Contract Files Missing');
|
|
1099
1303
|
|
|
1304
|
+
console.log(`${colors.red}Found ${contractStatus.missingCount} missing contract types.${colors.reset}`);
|
|
1305
|
+
if (contractStatus.scatteredCount > 0) {
|
|
1306
|
+
console.log(`${colors.yellow}Note: ${contractStatus.scatteredCount} contract types were found but are scattered/unmerged.${colors.reset}`);
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1100
1309
|
if (!skipPrompts) {
|
|
1101
1310
|
explain(`
|
|
1102
1311
|
${colors.bright}Contract System:${colors.reset}
|
|
1103
1312
|
This project uses a Contract System to coordinate multiple AI agents.
|
|
1104
|
-
|
|
1105
|
-
|
|
1313
|
+
Since required contracts are missing, we should generate them to ensure
|
|
1314
|
+
all agents understand the project structure and rules.
|
|
1106
1315
|
`);
|
|
1107
1316
|
}
|
|
1108
1317
|
|
|
@@ -1110,6 +1319,10 @@ We can scan your codebase and generate them now.
|
|
|
1110
1319
|
if (shouldGenerate) {
|
|
1111
1320
|
await generateContracts(projectRoot);
|
|
1112
1321
|
}
|
|
1322
|
+
} else if (contractStatus.scatteredCount > 0) {
|
|
1323
|
+
// All present, but some scattered. The checkContractsExist function already asked to merge.
|
|
1324
|
+
// We don't need to do anything else here.
|
|
1325
|
+
log.info('All contracts present (some were found in scattered locations).');
|
|
1113
1326
|
}
|
|
1114
1327
|
|
|
1115
1328
|
// Run setup steps
|
|
@@ -1130,6 +1343,49 @@ We can scan your codebase and generate them now.
|
|
|
1130
1343
|
log.success('Created .env file');
|
|
1131
1344
|
}
|
|
1132
1345
|
}
|
|
1346
|
+
|
|
1347
|
+
// Initialize SessionCoordinator for versioning and house rules setup
|
|
1348
|
+
// const coordinator = new SessionCoordinator(); // Already initialized at top
|
|
1349
|
+
|
|
1350
|
+
// Ensure House Rules are set up
|
|
1351
|
+
if (!skipPrompts) {
|
|
1352
|
+
log.header();
|
|
1353
|
+
log.title('🏠 House Rules Setup');
|
|
1354
|
+
await coordinator.ensureHouseRulesSetup();
|
|
1355
|
+
} else {
|
|
1356
|
+
// In non-interactive mode, ensure defaults if missing
|
|
1357
|
+
// ensureHouseRulesSetup has internal logic, but we might want to skip the prompt
|
|
1358
|
+
// Since we can't easily force defaults without modifying coordinator, we'll skip for now
|
|
1359
|
+
// or we could check if it exists and warn
|
|
1360
|
+
if (!fs.existsSync(path.join(projectRoot, 'houserules.md'))) {
|
|
1361
|
+
log.warn('House rules missing. Run setup interactively to configure folder structure.');
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1365
|
+
// Check/Setup versioning strategy
|
|
1366
|
+
if (!skipPrompts) {
|
|
1367
|
+
const settings = coordinator.loadProjectSettings();
|
|
1368
|
+
if (!settings.versioningStrategy?.configured) {
|
|
1369
|
+
log.header();
|
|
1370
|
+
log.title('📅 Project Versioning Strategy');
|
|
1371
|
+
await coordinator.ensureProjectSetup();
|
|
1372
|
+
} else {
|
|
1373
|
+
// Optional reconfigure
|
|
1374
|
+
log.info('Versioning strategy is already configured.');
|
|
1375
|
+
const reconfigure = await confirm('Do you want to reconfigure versioning?', false);
|
|
1376
|
+
if (reconfigure) {
|
|
1377
|
+
await coordinator.ensureProjectSetup({ force: true });
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
} else {
|
|
1381
|
+
// In non-interactive mode, we only ensure if missing (and hope it doesn't block or has defaults)
|
|
1382
|
+
// Actually promptForStartingVersion is interactive-only, so we skip if missing in non-interactive
|
|
1383
|
+
// or we could force defaults. For now, we skip to avoid hanging.
|
|
1384
|
+
const settings = coordinator.loadProjectSettings();
|
|
1385
|
+
if (!settings.versioningStrategy?.configured) {
|
|
1386
|
+
log.warn('Skipping versioning setup (interactive-only). Run setup without --yes to configure.');
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1133
1389
|
|
|
1134
1390
|
// Clean up DevOpsAgent files to avoid duplicates
|
|
1135
1391
|
cleanupDevOpsAgentFiles(projectRoot, agentName);
|
package/src/ui-utils.js
CHANGED
|
@@ -478,7 +478,7 @@ export function showWelcome(version = '2.0.0') {
|
|
|
478
478
|
*/
|
|
479
479
|
export function showCopyright() {
|
|
480
480
|
console.log();
|
|
481
|
-
console.log(`${colors.dim}Copyright ©
|
|
481
|
+
console.log(`${colors.dim}Copyright © 2025 SeKondBrain AI Labs Limited. All rights reserved.${colors.reset}`);
|
|
482
482
|
console.log(`${colors.dim}Licensed under the MIT License${colors.reset}`);
|
|
483
483
|
console.log();
|
|
484
484
|
}
|
package/start-devops-session.sh
CHANGED
|
@@ -50,7 +50,7 @@ show_copyright() {
|
|
|
50
50
|
echo " CS_DevOpsAgent - Intelligent Git Automation System"
|
|
51
51
|
echo " Version 1.7.2 | Build 20251010.03"
|
|
52
52
|
echo " "
|
|
53
|
-
echo " Copyright (c)
|
|
53
|
+
echo " Copyright (c) 2025 SeKondBrain AI Labs Limited"
|
|
54
54
|
echo " Author: Sachin Dev Duggal"
|
|
55
55
|
echo " "
|
|
56
56
|
echo " Licensed under the MIT License"
|
|
@@ -394,32 +394,9 @@ main() {
|
|
|
394
394
|
echo -e "${DIM}💡 New to DevOps Agent? Run: s9n-devops-agent tutorial${NC}"
|
|
395
395
|
echo
|
|
396
396
|
|
|
397
|
-
#
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
# After agent exits, ask if they want to continue or exit
|
|
401
|
-
echo
|
|
402
|
-
echo -e "${YELLOW}═══════════════════════════════════════════════════════════${NC}"
|
|
403
|
-
echo -e "${BOLD}Agent has stopped.${NC}"
|
|
404
|
-
echo -e "${YELLOW}═══════════════════════════════════════════════════════════${NC}"
|
|
405
|
-
echo
|
|
406
|
-
echo -e "Would you like to:"
|
|
407
|
-
echo -e " ${BOLD}1)${NC} Select another session"
|
|
408
|
-
echo -e " ${BOLD}2)${NC} Exit the session manager"
|
|
409
|
-
echo
|
|
410
|
-
echo -n "Your choice [1/2]: "
|
|
411
|
-
read continue_choice
|
|
412
|
-
|
|
413
|
-
if [[ "$continue_choice" == "2" ]]; then
|
|
414
|
-
echo
|
|
415
|
-
echo -e "${GREEN}Goodbye! Thank you for using DevOps Session Manager.${NC}"
|
|
416
|
-
exit 0
|
|
417
|
-
fi
|
|
418
|
-
echo
|
|
419
|
-
echo -e "${BLUE}Returning to session selection...${NC}"
|
|
420
|
-
echo
|
|
421
|
-
fi
|
|
422
|
-
done
|
|
397
|
+
# Run Kora (Smart Assistant)
|
|
398
|
+
# This replaces the old menu system with the unified chat interface
|
|
399
|
+
node "$SRC_DIR/agent-chat.js" "$@"
|
|
423
400
|
}
|
|
424
401
|
|
|
425
402
|
# Handle Ctrl+C gracefully
|