s9n-devops-agent 1.7.4 → 2.0.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/README.md +126 -454
- package/README.v1.md +529 -0
- package/bin/cs-devops-agent +31 -13
- package/docs/FILE_COORDINATION_GUIDE.md +481 -0
- package/docs/MULTI_AGENT_WORKFLOWS.md +692 -0
- package/docs/V2_FINAL_SUMMARY.md +526 -0
- package/docs/V2_QUICK_REFERENCE.md +447 -0
- package/docs/V2_STATUS_REPORT.md +324 -0
- package/package.json +1 -1
- package/src/help-system.js +475 -0
- package/src/instruction-formatter.js +346 -0
- package/src/setup-cs-devops-agent.js +91 -55
- package/src/tutorial-mode.js +550 -0
- package/src/ui-utils.js +509 -0
- package/start-devops-session.sh +71 -31
package/src/ui-utils.js
ADDED
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ============================================================================
|
|
5
|
+
* UI UTILITIES - Rich Formatting for DevOps Agent v2.0
|
|
6
|
+
* ============================================================================
|
|
7
|
+
*
|
|
8
|
+
* Provides consistent, beautiful UI components across the application:
|
|
9
|
+
* - Box drawing with headers and borders
|
|
10
|
+
* - Color-coded status indicators
|
|
11
|
+
* - Progress displays
|
|
12
|
+
* - Formatted lists
|
|
13
|
+
* - Help dialogs
|
|
14
|
+
* - Error messages with guidance
|
|
15
|
+
*
|
|
16
|
+
* ============================================================================
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import readline from 'readline';
|
|
20
|
+
|
|
21
|
+
// ============================================================================
|
|
22
|
+
// COLORS & STYLES
|
|
23
|
+
// ============================================================================
|
|
24
|
+
|
|
25
|
+
export const colors = {
|
|
26
|
+
reset: '\x1b[0m',
|
|
27
|
+
bright: '\x1b[1m',
|
|
28
|
+
dim: '\x1b[2m',
|
|
29
|
+
|
|
30
|
+
// Foreground colors
|
|
31
|
+
black: '\x1b[30m',
|
|
32
|
+
red: '\x1b[31m',
|
|
33
|
+
green: '\x1b[32m',
|
|
34
|
+
yellow: '\x1b[33m',
|
|
35
|
+
blue: '\x1b[34m',
|
|
36
|
+
magenta: '\x1b[35m',
|
|
37
|
+
cyan: '\x1b[36m',
|
|
38
|
+
white: '\x1b[37m',
|
|
39
|
+
|
|
40
|
+
// Background colors
|
|
41
|
+
bgBlack: '\x1b[40m',
|
|
42
|
+
bgRed: '\x1b[41m',
|
|
43
|
+
bgGreen: '\x1b[42m',
|
|
44
|
+
bgYellow: '\x1b[43m',
|
|
45
|
+
bgBlue: '\x1b[44m',
|
|
46
|
+
bgMagenta: '\x1b[45m',
|
|
47
|
+
bgCyan: '\x1b[46m',
|
|
48
|
+
bgWhite: '\x1b[47m',
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// Box drawing characters
|
|
52
|
+
export const box = {
|
|
53
|
+
topLeft: '┌',
|
|
54
|
+
topRight: '┐',
|
|
55
|
+
bottomLeft: '└',
|
|
56
|
+
bottomRight: '┘',
|
|
57
|
+
horizontal: '─',
|
|
58
|
+
vertical: '│',
|
|
59
|
+
leftT: '├',
|
|
60
|
+
rightT: '┤',
|
|
61
|
+
topT: '┬',
|
|
62
|
+
bottomT: '┴',
|
|
63
|
+
cross: '┼',
|
|
64
|
+
|
|
65
|
+
// Double lines
|
|
66
|
+
doubleTopLeft: '╔',
|
|
67
|
+
doubleTopRight: '╗',
|
|
68
|
+
doubleBottomLeft: '╚',
|
|
69
|
+
doubleBottomRight: '╝',
|
|
70
|
+
doubleHorizontal: '═',
|
|
71
|
+
doubleVertical: '║',
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// Status indicators
|
|
75
|
+
export const status = {
|
|
76
|
+
active: '🟢',
|
|
77
|
+
paused: '🟡',
|
|
78
|
+
stopped: '🔴',
|
|
79
|
+
success: '✅',
|
|
80
|
+
warning: '⚠️',
|
|
81
|
+
error: '❌',
|
|
82
|
+
info: 'ℹ️',
|
|
83
|
+
question: '❓',
|
|
84
|
+
rocket: '🚀',
|
|
85
|
+
folder: '📁',
|
|
86
|
+
file: '📄',
|
|
87
|
+
lock: '🔒',
|
|
88
|
+
unlock: '🔓',
|
|
89
|
+
branch: '🌿',
|
|
90
|
+
commit: '📝',
|
|
91
|
+
merge: '🔀',
|
|
92
|
+
robot: '🤖',
|
|
93
|
+
book: '📖',
|
|
94
|
+
chart: '📊',
|
|
95
|
+
clock: '🕐',
|
|
96
|
+
checkmark: '✓',
|
|
97
|
+
xmark: '✗',
|
|
98
|
+
arrow: '→',
|
|
99
|
+
point: '•',
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// ============================================================================
|
|
103
|
+
// BOX DRAWING FUNCTIONS
|
|
104
|
+
// ============================================================================
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Draw a header box with title
|
|
108
|
+
*/
|
|
109
|
+
export function drawHeader(title, options = {}) {
|
|
110
|
+
const width = options.width || 70;
|
|
111
|
+
const padding = Math.floor((width - title.length - 2) / 2);
|
|
112
|
+
const leftPad = ' '.repeat(padding);
|
|
113
|
+
const rightPad = ' '.repeat(width - title.length - padding - 2);
|
|
114
|
+
|
|
115
|
+
console.log();
|
|
116
|
+
console.log(box.doubleTopLeft + box.doubleHorizontal.repeat(width) + box.doubleTopRight);
|
|
117
|
+
console.log(box.doubleVertical + leftPad + title + rightPad + box.doubleVertical);
|
|
118
|
+
console.log(box.doubleBottomLeft + box.doubleHorizontal.repeat(width) + box.doubleBottomRight);
|
|
119
|
+
console.log();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Draw a section box
|
|
124
|
+
*/
|
|
125
|
+
export function drawSection(title, content, options = {}) {
|
|
126
|
+
const width = options.width || 70;
|
|
127
|
+
|
|
128
|
+
// Title line
|
|
129
|
+
console.log();
|
|
130
|
+
console.log(box.topLeft + box.horizontal + ` ${title} ` + box.horizontal.repeat(width - title.length - 3) + box.topRight);
|
|
131
|
+
|
|
132
|
+
// Content
|
|
133
|
+
if (Array.isArray(content)) {
|
|
134
|
+
content.forEach(line => {
|
|
135
|
+
const padded = line + ' '.repeat(width - stripAnsi(line).length);
|
|
136
|
+
console.log(box.vertical + ' ' + padded + box.vertical);
|
|
137
|
+
});
|
|
138
|
+
} else {
|
|
139
|
+
const lines = content.split('\n');
|
|
140
|
+
lines.forEach(line => {
|
|
141
|
+
const padded = line + ' '.repeat(width - stripAnsi(line).length);
|
|
142
|
+
console.log(box.vertical + ' ' + padded + box.vertical);
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Bottom
|
|
147
|
+
console.log(box.bottomLeft + box.horizontal.repeat(width + 2) + box.bottomRight);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Draw a simple box
|
|
152
|
+
*/
|
|
153
|
+
export function drawBox(content, options = {}) {
|
|
154
|
+
const width = options.width || 70;
|
|
155
|
+
|
|
156
|
+
console.log();
|
|
157
|
+
console.log(box.topLeft + box.horizontal.repeat(width + 2) + box.topRight);
|
|
158
|
+
|
|
159
|
+
if (Array.isArray(content)) {
|
|
160
|
+
content.forEach(line => {
|
|
161
|
+
const padded = line + ' '.repeat(width - stripAnsi(line).length);
|
|
162
|
+
console.log(box.vertical + ' ' + padded + ' ' + box.vertical);
|
|
163
|
+
});
|
|
164
|
+
} else {
|
|
165
|
+
const lines = content.split('\n');
|
|
166
|
+
lines.forEach(line => {
|
|
167
|
+
const padded = line + ' '.repeat(width - stripAnsi(line).length);
|
|
168
|
+
console.log(box.vertical + ' ' + padded + ' ' + box.vertical);
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
console.log(box.bottomLeft + box.horizontal.repeat(width + 2) + box.bottomRight);
|
|
173
|
+
console.log();
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Strip ANSI color codes for length calculation
|
|
178
|
+
*/
|
|
179
|
+
function stripAnsi(str) {
|
|
180
|
+
return str.replace(/\x1b\[[0-9;]*m/g, '');
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// ============================================================================
|
|
184
|
+
// FORMATTED OUTPUT
|
|
185
|
+
// ============================================================================
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Print success message
|
|
189
|
+
*/
|
|
190
|
+
export function success(message) {
|
|
191
|
+
console.log(`${colors.green}${status.checkmark}${colors.reset} ${message}`);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Print error message
|
|
196
|
+
*/
|
|
197
|
+
export function error(message) {
|
|
198
|
+
console.log(`${colors.red}${status.xmark}${colors.reset} ${message}`);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Print warning message
|
|
203
|
+
*/
|
|
204
|
+
export function warn(message) {
|
|
205
|
+
console.log(`${colors.yellow}${status.warning}${colors.reset} ${message}`);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Print info message
|
|
210
|
+
*/
|
|
211
|
+
export function info(message) {
|
|
212
|
+
console.log(`${colors.cyan}${status.info}${colors.reset} ${message}`);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Print a section title
|
|
217
|
+
*/
|
|
218
|
+
export function sectionTitle(title) {
|
|
219
|
+
console.log();
|
|
220
|
+
console.log(`${colors.bright}${colors.cyan}${title}${colors.reset}`);
|
|
221
|
+
console.log(colors.dim + '─'.repeat(title.length) + colors.reset);
|
|
222
|
+
console.log();
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Print an explanation
|
|
227
|
+
*/
|
|
228
|
+
export function explain(text) {
|
|
229
|
+
const lines = text.split('\n');
|
|
230
|
+
lines.forEach(line => {
|
|
231
|
+
console.log(`${colors.dim}${line}${colors.reset}`);
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Print a tip
|
|
237
|
+
*/
|
|
238
|
+
export function tip(message) {
|
|
239
|
+
console.log(`${colors.cyan}💡 Tip:${colors.reset} ${colors.dim}${message}${colors.reset}`);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// ============================================================================
|
|
243
|
+
// INTERACTIVE PROMPTS
|
|
244
|
+
// ============================================================================
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Prompt user for input
|
|
248
|
+
*/
|
|
249
|
+
export async function prompt(question, defaultValue = null) {
|
|
250
|
+
const rl = readline.createInterface({
|
|
251
|
+
input: process.stdin,
|
|
252
|
+
output: process.stdout
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
return new Promise((resolve) => {
|
|
256
|
+
const promptText = defaultValue
|
|
257
|
+
? `${question} ${colors.dim}[${defaultValue}]${colors.reset}: `
|
|
258
|
+
: `${question}: `;
|
|
259
|
+
|
|
260
|
+
rl.question(promptText, (answer) => {
|
|
261
|
+
rl.close();
|
|
262
|
+
resolve(answer.trim() || defaultValue);
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Prompt for yes/no confirmation
|
|
269
|
+
*/
|
|
270
|
+
export async function confirm(question, defaultYes = true) {
|
|
271
|
+
const rl = readline.createInterface({
|
|
272
|
+
input: process.stdin,
|
|
273
|
+
output: process.stdout
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
const suffix = defaultYes ? '[Y/n]' : '[y/N]';
|
|
277
|
+
|
|
278
|
+
return new Promise((resolve) => {
|
|
279
|
+
rl.question(`${question} ${colors.dim}${suffix}${colors.reset}: `, (answer) => {
|
|
280
|
+
rl.close();
|
|
281
|
+
const cleaned = answer.trim().toLowerCase();
|
|
282
|
+
|
|
283
|
+
if (cleaned === '') {
|
|
284
|
+
resolve(defaultYes);
|
|
285
|
+
} else {
|
|
286
|
+
resolve(cleaned === 'y' || cleaned === 'yes');
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Prompt for choice from list
|
|
294
|
+
*/
|
|
295
|
+
export async function choose(question, choices, options = {}) {
|
|
296
|
+
console.log();
|
|
297
|
+
console.log(`${colors.bright}${question}${colors.reset}`);
|
|
298
|
+
console.log();
|
|
299
|
+
|
|
300
|
+
choices.forEach((choice, index) => {
|
|
301
|
+
const num = index + 1;
|
|
302
|
+
if (typeof choice === 'object') {
|
|
303
|
+
console.log(` ${colors.bright}${num})${colors.reset} ${choice.label}`);
|
|
304
|
+
if (choice.description) {
|
|
305
|
+
console.log(` ${colors.dim}${choice.description}${colors.reset}`);
|
|
306
|
+
}
|
|
307
|
+
} else {
|
|
308
|
+
console.log(` ${colors.bright}${num})${colors.reset} ${choice}`);
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
console.log();
|
|
313
|
+
|
|
314
|
+
const rl = readline.createInterface({
|
|
315
|
+
input: process.stdin,
|
|
316
|
+
output: process.stdout
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
return new Promise((resolve) => {
|
|
320
|
+
const promptText = options.defaultChoice
|
|
321
|
+
? `Your choice ${colors.dim}[${options.defaultChoice}]${colors.reset}: `
|
|
322
|
+
: 'Your choice: ';
|
|
323
|
+
|
|
324
|
+
rl.question(promptText, (answer) => {
|
|
325
|
+
rl.close();
|
|
326
|
+
const cleaned = answer.trim() || options.defaultChoice;
|
|
327
|
+
const num = parseInt(cleaned);
|
|
328
|
+
|
|
329
|
+
if (num >= 1 && num <= choices.length) {
|
|
330
|
+
resolve(num - 1);
|
|
331
|
+
} else {
|
|
332
|
+
console.log(`${colors.red}Invalid choice. Please try again.${colors.reset}`);
|
|
333
|
+
resolve(choose(question, choices, options));
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// ============================================================================
|
|
340
|
+
// PROGRESS & STATUS
|
|
341
|
+
// ============================================================================
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Show a progress step
|
|
345
|
+
*/
|
|
346
|
+
export function progressStep(step, total, message) {
|
|
347
|
+
console.log(`${colors.cyan}[${step}/${total}]${colors.reset} ${message}`);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Show loading spinner (returns function to stop it)
|
|
352
|
+
*/
|
|
353
|
+
export function spinner(message) {
|
|
354
|
+
const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
355
|
+
let index = 0;
|
|
356
|
+
|
|
357
|
+
process.stdout.write(`${message} ${frames[0]}`);
|
|
358
|
+
|
|
359
|
+
const interval = setInterval(() => {
|
|
360
|
+
index = (index + 1) % frames.length;
|
|
361
|
+
process.stdout.write(`\r${message} ${frames[index]}`);
|
|
362
|
+
}, 80);
|
|
363
|
+
|
|
364
|
+
return () => {
|
|
365
|
+
clearInterval(interval);
|
|
366
|
+
process.stdout.write(`\r${message} ${colors.green}${status.checkmark}${colors.reset}\n`);
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// ============================================================================
|
|
371
|
+
// HELP DISPLAY
|
|
372
|
+
// ============================================================================
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Display contextual help
|
|
376
|
+
*/
|
|
377
|
+
export function showHelp(topic, content) {
|
|
378
|
+
console.log();
|
|
379
|
+
console.log(box.doubleTopLeft + box.doubleHorizontal.repeat(68) + box.doubleTopRight);
|
|
380
|
+
console.log(box.doubleVertical + ` ${status.question} Help: ${topic}` + ' '.repeat(68 - topic.length - 11) + box.doubleVertical);
|
|
381
|
+
console.log(box.doubleBottomLeft + box.doubleHorizontal.repeat(68) + box.doubleBottomRight);
|
|
382
|
+
console.log();
|
|
383
|
+
|
|
384
|
+
if (typeof content === 'object') {
|
|
385
|
+
Object.entries(content).forEach(([section, text]) => {
|
|
386
|
+
console.log(`${colors.bright}${colors.cyan}${section.toUpperCase()}:${colors.reset}`);
|
|
387
|
+
console.log(text);
|
|
388
|
+
console.log();
|
|
389
|
+
});
|
|
390
|
+
} else {
|
|
391
|
+
console.log(content);
|
|
392
|
+
console.log();
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
console.log(`${colors.dim}[Press any key to continue]${colors.reset}`);
|
|
396
|
+
|
|
397
|
+
return new Promise((resolve) => {
|
|
398
|
+
process.stdin.setRawMode(true);
|
|
399
|
+
process.stdin.resume();
|
|
400
|
+
process.stdin.once('data', () => {
|
|
401
|
+
process.stdin.setRawMode(false);
|
|
402
|
+
process.stdin.pause();
|
|
403
|
+
resolve();
|
|
404
|
+
});
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// ============================================================================
|
|
409
|
+
// ERROR DISPLAY WITH GUIDANCE
|
|
410
|
+
// ============================================================================
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Display error with actionable guidance
|
|
414
|
+
*/
|
|
415
|
+
export function showError(errorMessage, guidance) {
|
|
416
|
+
console.log();
|
|
417
|
+
console.log(`${colors.red}${status.error} Error: ${errorMessage}${colors.reset}`);
|
|
418
|
+
console.log();
|
|
419
|
+
|
|
420
|
+
if (guidance.what) {
|
|
421
|
+
console.log(`${colors.bright}💡 What happened?${colors.reset}`);
|
|
422
|
+
console.log(` ${guidance.what}`);
|
|
423
|
+
console.log();
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
if (guidance.why) {
|
|
427
|
+
console.log(`${colors.bright}🔍 Why did this happen?${colors.reset}`);
|
|
428
|
+
if (Array.isArray(guidance.why)) {
|
|
429
|
+
guidance.why.forEach(reason => {
|
|
430
|
+
console.log(` ${status.point} ${reason}`);
|
|
431
|
+
});
|
|
432
|
+
} else {
|
|
433
|
+
console.log(` ${guidance.why}`);
|
|
434
|
+
}
|
|
435
|
+
console.log();
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
if (guidance.fix) {
|
|
439
|
+
console.log(`${colors.bright}${colors.green}🔧 How to fix:${colors.reset}`);
|
|
440
|
+
if (Array.isArray(guidance.fix)) {
|
|
441
|
+
guidance.fix.forEach((step, index) => {
|
|
442
|
+
console.log(` ${index + 1}. ${step}`);
|
|
443
|
+
});
|
|
444
|
+
} else {
|
|
445
|
+
console.log(` ${guidance.fix}`);
|
|
446
|
+
}
|
|
447
|
+
console.log();
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
if (guidance.learn) {
|
|
451
|
+
console.log(`${colors.dim}📚 Learn more: ${guidance.learn}${colors.reset}`);
|
|
452
|
+
console.log();
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// ============================================================================
|
|
457
|
+
// WELCOME BANNER
|
|
458
|
+
// ============================================================================
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Display welcome banner
|
|
462
|
+
*/
|
|
463
|
+
export function showWelcome(version = '2.0.0') {
|
|
464
|
+
console.log();
|
|
465
|
+
console.log(box.doubleTopLeft + box.doubleHorizontal.repeat(68) + box.doubleTopRight);
|
|
466
|
+
console.log(box.doubleVertical + ' ' + box.doubleVertical);
|
|
467
|
+
console.log(box.doubleVertical + ` ${status.robot} ${colors.bright}Welcome to DevOps Agent${colors.reset}` + ' '.repeat(36) + box.doubleVertical);
|
|
468
|
+
console.log(box.doubleVertical + ' ' + box.doubleVertical);
|
|
469
|
+
console.log(box.doubleVertical + ` ${colors.dim}AI-Powered Git Workflow Automation${colors.reset}` + ' '.repeat(30) + box.doubleVertical);
|
|
470
|
+
console.log(box.doubleVertical + ` ${colors.dim}Version ${version}${colors.reset}` + ' '.repeat(52 - version.length) + box.doubleVertical);
|
|
471
|
+
console.log(box.doubleVertical + ' ' + box.doubleVertical);
|
|
472
|
+
console.log(box.doubleBottomLeft + box.doubleHorizontal.repeat(68) + box.doubleBottomRight);
|
|
473
|
+
console.log();
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* Display copyright
|
|
478
|
+
*/
|
|
479
|
+
export function showCopyright() {
|
|
480
|
+
console.log();
|
|
481
|
+
console.log(`${colors.dim}Copyright © 2024 SecondBrain Labs. All rights reserved.${colors.reset}`);
|
|
482
|
+
console.log(`${colors.dim}Licensed under the MIT License${colors.reset}`);
|
|
483
|
+
console.log();
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
export default {
|
|
487
|
+
colors,
|
|
488
|
+
box,
|
|
489
|
+
status,
|
|
490
|
+
drawHeader,
|
|
491
|
+
drawSection,
|
|
492
|
+
drawBox,
|
|
493
|
+
success,
|
|
494
|
+
error,
|
|
495
|
+
warn,
|
|
496
|
+
info,
|
|
497
|
+
sectionTitle,
|
|
498
|
+
explain,
|
|
499
|
+
tip,
|
|
500
|
+
prompt,
|
|
501
|
+
confirm,
|
|
502
|
+
choose,
|
|
503
|
+
progressStep,
|
|
504
|
+
spinner,
|
|
505
|
+
showHelp,
|
|
506
|
+
showError,
|
|
507
|
+
showWelcome,
|
|
508
|
+
showCopyright,
|
|
509
|
+
};
|
package/start-devops-session.sh
CHANGED
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env zsh
|
|
2
2
|
|
|
3
3
|
# ============================================================================
|
|
4
|
-
# INTERACTIVE DEVOPS SESSION STARTER
|
|
4
|
+
# INTERACTIVE DEVOPS SESSION STARTER (v2.0)
|
|
5
5
|
# ============================================================================
|
|
6
6
|
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
7
|
+
# Enhanced user experience for starting DevOps agent sessions.
|
|
8
|
+
#
|
|
9
|
+
# What this does:
|
|
10
|
+
# - Guides you through creating or resuming sessions
|
|
11
|
+
# - Generates beautiful instructions for your AI assistant
|
|
12
|
+
# - Monitors your session automatically
|
|
13
|
+
#
|
|
14
|
+
# Why it matters:
|
|
15
|
+
# - Simple, visual interface
|
|
16
|
+
# - No manual git commands needed
|
|
17
|
+
# - Automatic conflict detection
|
|
18
|
+
#
|
|
19
|
+
# Usage: ./start-devops-session.sh
|
|
13
20
|
# ============================================================================
|
|
14
21
|
|
|
15
22
|
# Colors for output (using printf for better compatibility)
|
|
@@ -56,9 +63,11 @@ show_copyright() {
|
|
|
56
63
|
# Function to display header
|
|
57
64
|
show_header() {
|
|
58
65
|
echo
|
|
59
|
-
echo -e "${
|
|
60
|
-
echo -e "${
|
|
61
|
-
echo -e "${
|
|
66
|
+
echo -e "${BLUE}╔══════════════════════════════════════════════════════════════════╗${NC}"
|
|
67
|
+
echo -e "${BLUE}║${NC}${BOLD} DevOps Agent Session Manager v2.0 ${NC}${BLUE}║${NC}"
|
|
68
|
+
echo -e "${BLUE}╚══════════════════════════════════════════════════════════════════╝${NC}"
|
|
69
|
+
echo
|
|
70
|
+
echo -e "${DIM}Intelligent Git automation with AI agent coordination${NC}"
|
|
62
71
|
echo
|
|
63
72
|
}
|
|
64
73
|
|
|
@@ -109,27 +118,48 @@ list_sessions() {
|
|
|
109
118
|
|
|
110
119
|
# Function to create a new session
|
|
111
120
|
create_new_session() {
|
|
112
|
-
echo
|
|
121
|
+
echo
|
|
122
|
+
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
123
|
+
echo -e "${BOLD}📝 Create New Session${NC}"
|
|
124
|
+
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
125
|
+
echo
|
|
126
|
+
echo -e "${DIM}What:${NC} Your session gets an isolated workspace"
|
|
127
|
+
echo -e "${DIM}Why:${NC} Prevents conflicts with other AI agents"
|
|
128
|
+
echo -e "${DIM}How:${NC} Creates git worktree + branch + file locks"
|
|
113
129
|
echo
|
|
114
130
|
|
|
115
131
|
# Ask for task name
|
|
116
|
-
echo -
|
|
132
|
+
echo -e "${BOLD}Task/Feature Name:${NC}"
|
|
133
|
+
echo -e "${DIM}Examples: implement-auth, build-api, fix-login-bug${NC}"
|
|
134
|
+
echo -n "➜ "
|
|
117
135
|
read task_name
|
|
118
136
|
|
|
119
137
|
if [[ -z "$task_name" ]]; then
|
|
120
138
|
task_name="development"
|
|
139
|
+
echo -e "${YELLOW}Using default: development${NC}"
|
|
121
140
|
fi
|
|
122
141
|
|
|
142
|
+
echo
|
|
143
|
+
|
|
123
144
|
# Ask for agent type
|
|
124
|
-
echo -
|
|
125
|
-
|
|
145
|
+
echo -e "${BOLD}AI Agent Type:${NC}"
|
|
146
|
+
echo -e " ${GREEN}1)${NC} Claude (Anthropic)"
|
|
147
|
+
echo -e " ${GREEN}2)${NC} Cursor"
|
|
148
|
+
echo -e " ${GREEN}3)${NC} GitHub Copilot"
|
|
149
|
+
echo -e " ${GREEN}4)${NC} Cline (VS Code)"
|
|
150
|
+
echo -n "➜ Your choice [1-4, default: 1]: "
|
|
151
|
+
read agent_choice
|
|
126
152
|
|
|
127
|
-
|
|
128
|
-
agent_type="
|
|
129
|
-
|
|
153
|
+
case "$agent_choice" in
|
|
154
|
+
2) agent_type="cursor" ;;
|
|
155
|
+
3) agent_type="copilot" ;;
|
|
156
|
+
4) agent_type="cline" ;;
|
|
157
|
+
*) agent_type="claude" ;;
|
|
158
|
+
esac
|
|
130
159
|
|
|
131
160
|
echo
|
|
132
|
-
echo -e "${
|
|
161
|
+
echo -e "${GREEN}✓${NC} Creating session: ${BOLD}${task_name}${NC} (Agent: ${BLUE}${agent_type}${NC})"
|
|
162
|
+
echo
|
|
133
163
|
|
|
134
164
|
# Run the session coordinator to create AND START the session
|
|
135
165
|
# Keep current directory to ensure session is created for the right repo
|
|
@@ -138,9 +168,12 @@ create_new_session() {
|
|
|
138
168
|
|
|
139
169
|
# Function to prompt for session selection
|
|
140
170
|
select_session() {
|
|
141
|
-
echo -e "${BOLD}Select an Option:${NC}"
|
|
142
171
|
echo
|
|
143
|
-
echo "
|
|
172
|
+
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
173
|
+
echo -e "${BOLD}🚀 Session Selection${NC}"
|
|
174
|
+
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
175
|
+
echo
|
|
176
|
+
echo " ${BOLD}${GREEN}N)${NC} Create a ${BOLD}new${NC} session"
|
|
144
177
|
|
|
145
178
|
# List existing sessions
|
|
146
179
|
local sessions_dir="local_deploy/session-locks"
|
|
@@ -166,9 +199,11 @@ select_session() {
|
|
|
166
199
|
fi
|
|
167
200
|
|
|
168
201
|
echo
|
|
169
|
-
echo -e " ${BOLD}
|
|
202
|
+
echo -e " ${BOLD}${RED}Q)${NC} Quit - Exit the session manager"
|
|
170
203
|
echo
|
|
171
|
-
echo -
|
|
204
|
+
echo -e "${DIM}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
205
|
+
echo
|
|
206
|
+
echo -n "➜ Your choice: "
|
|
172
207
|
read choice
|
|
173
208
|
|
|
174
209
|
# Handle the choice
|
|
@@ -224,15 +259,18 @@ select_session() {
|
|
|
224
259
|
fi
|
|
225
260
|
|
|
226
261
|
echo
|
|
227
|
-
echo -e "${GREEN}
|
|
262
|
+
echo -e "${GREEN}✓${NC} Resuming session: ${BOLD}${session_id}${NC}"
|
|
263
|
+
echo -e "${DIM}Task: ${task}${NC}"
|
|
228
264
|
|
|
229
265
|
# Instructions will be displayed by the session coordinator
|
|
230
266
|
# No need to display them here to avoid duplication
|
|
231
267
|
|
|
232
268
|
echo
|
|
233
|
-
echo -e "${
|
|
234
|
-
echo -e "${BOLD}Starting DevOps Agent${NC}"
|
|
235
|
-
echo -e "${
|
|
269
|
+
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
270
|
+
echo -e "${BOLD}🤖 Starting DevOps Agent Monitoring${NC}"
|
|
271
|
+
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
272
|
+
echo
|
|
273
|
+
echo -e "${DIM}Press Ctrl+C to stop monitoring${NC}"
|
|
236
274
|
|
|
237
275
|
# Start the agent for this session
|
|
238
276
|
# Keep current directory to ensure agent runs in the right repo
|
|
@@ -335,12 +373,14 @@ main() {
|
|
|
335
373
|
# Check and setup house rules on first run
|
|
336
374
|
setup_house_rules "$REPO_ROOT"
|
|
337
375
|
|
|
338
|
-
echo -e "${BOLD}Welcome to DevOps Agent
|
|
376
|
+
echo -e "${BOLD}Welcome to DevOps Agent${NC}"
|
|
377
|
+
echo
|
|
378
|
+
echo -e "${GREEN}✓${NC} Isolated workspaces for each AI agent"
|
|
379
|
+
echo -e "${GREEN}✓${NC} Automatic git commits and pushes"
|
|
380
|
+
echo -e "${GREEN}✓${NC} File coordination prevents conflicts"
|
|
381
|
+
echo -e "${GREEN}✓${NC} Beautiful instructions for your agent"
|
|
339
382
|
echo
|
|
340
|
-
echo "
|
|
341
|
-
echo " 1. Help you create or select a session"
|
|
342
|
-
echo " 2. Generate instructions for your coding agent"
|
|
343
|
-
echo " 3. Start the DevOps agent to monitor changes"
|
|
383
|
+
echo -e "${DIM}💡 New to DevOps Agent? Run: s9n-devops-agent tutorial${NC}"
|
|
344
384
|
echo
|
|
345
385
|
|
|
346
386
|
# Main selection loop
|