s9n-devops-agent 2.0.13 → 2.0.18-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.
- package/House_Rules_Contracts/API_CONTRACT.md +612 -0
- package/House_Rules_Contracts/DATABASE_SCHEMA_CONTRACT.md +373 -0
- package/House_Rules_Contracts/DEVOPS_AGENT_INSTRUCTIONS.md +743 -0
- package/House_Rules_Contracts/FEATURES_CONTRACT.md +655 -0
- package/House_Rules_Contracts/INFRA_CONTRACT.md +638 -0
- package/House_Rules_Contracts/README.md +671 -0
- package/House_Rules_Contracts/SQL_CONTRACT.json +346 -0
- package/House_Rules_Contracts/THIRD_PARTY_INTEGRATIONS.md +604 -0
- package/bin/cs-devops-agent +20 -2
- package/houserules.md +1412 -0
- package/houserules_structured.md +1442 -0
- package/package.json +6 -2
- package/scripts/generate-ai-commit.js +135 -0
- package/scripts/local-install.sh +42 -0
- package/src/agent-chat.js +457 -0
- package/src/credentials-manager.js +1 -1
- package/src/cs-devops-agent-worker.js +84 -4
- package/src/house-rules-manager.js +4 -14
- package/src/instruction-formatter.js +9 -1
- package/src/session-coordinator.js +170 -15
- package/src/setup-cs-devops-agent.js +214 -236
- package/src/worktree-manager.js +2 -1
- package/start-devops-session.sh +9 -2
|
@@ -729,8 +729,13 @@ async function commitOnce(repoRoot, msgPath) {
|
|
|
729
729
|
msg = rest.length > 0 ? `${msg}\n${rest.join('\n')}${infraDetails}` : `${msg}${infraDetails}`;
|
|
730
730
|
}
|
|
731
731
|
|
|
732
|
+
const REQUIRE_AI_COMMIT = (process.env.AC_AI_COMMIT || "false").toLowerCase() === "true";
|
|
733
|
+
|
|
734
|
+
// ...
|
|
735
|
+
|
|
732
736
|
let committed = false;
|
|
733
737
|
if (REQUIRE_MSG && conventionalHeaderOK(msg)) {
|
|
738
|
+
// (Existing commit logic...)
|
|
734
739
|
// Update infrastructure documentation before commit
|
|
735
740
|
if (infraChanges.hasInfraChanges) {
|
|
736
741
|
await updateInfrastructureDoc(infraChanges, msg);
|
|
@@ -753,6 +758,47 @@ async function commitOnce(repoRoot, msgPath) {
|
|
|
753
758
|
fs.writeFileSync(tmp, msg + "\n");
|
|
754
759
|
committed = (await run("git", ["commit", "-F", tmp])).ok;
|
|
755
760
|
try { fs.unlinkSync(tmp); } catch {}
|
|
761
|
+
} else if (REQUIRE_MSG && !conventionalHeaderOK(msg) && REQUIRE_AI_COMMIT) {
|
|
762
|
+
// AI COMMIT GENERATION
|
|
763
|
+
log("generating AI commit message...");
|
|
764
|
+
|
|
765
|
+
// Look for the script in scripts/ or ../scripts/
|
|
766
|
+
let scriptPath = path.join(process.cwd(), 'scripts', 'generate-ai-commit.js');
|
|
767
|
+
if (!fs.existsSync(scriptPath)) {
|
|
768
|
+
// Try looking relative to __dirname
|
|
769
|
+
scriptPath = path.resolve(__dirname, '..', 'scripts', 'generate-ai-commit.js');
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
if (fs.existsSync(scriptPath)) {
|
|
773
|
+
try {
|
|
774
|
+
const { stdout } = await execa('node', [scriptPath], {
|
|
775
|
+
stdio: 'inherit',
|
|
776
|
+
env: { ...process.env, GROQ_API_KEY: process.env.GROQ_API_KEY }
|
|
777
|
+
});
|
|
778
|
+
|
|
779
|
+
// Re-read message after generation
|
|
780
|
+
msg = readMsgFile(msgPath);
|
|
781
|
+
if (conventionalHeaderOK(msg)) {
|
|
782
|
+
// Recursive call or just proceed? Let's proceed with commit logic duplicated or simple recursion
|
|
783
|
+
// To avoid recursion complexity, let's just commit here
|
|
784
|
+
|
|
785
|
+
// ... Duplicated commit logic or recursive call
|
|
786
|
+
// Let's recursively call commitOnce to keep it clean (busy flag handles concurrency)
|
|
787
|
+
busy = false; // Reset busy temporarily
|
|
788
|
+
await commitOnce(repoRoot, msgPath);
|
|
789
|
+
return;
|
|
790
|
+
}
|
|
791
|
+
} catch (err) {
|
|
792
|
+
log(`AI generation failed: ${err.message}`);
|
|
793
|
+
}
|
|
794
|
+
} else {
|
|
795
|
+
log(`AI script not found at ${scriptPath}`);
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
if (!committed) {
|
|
799
|
+
log("message still not ready after AI attempt; skipping commit");
|
|
800
|
+
return;
|
|
801
|
+
}
|
|
756
802
|
} else if (!REQUIRE_MSG) {
|
|
757
803
|
committed = (await run("git", ["commit", "-m", "chore: cs-devops-agent"])).ok;
|
|
758
804
|
} else {
|
|
@@ -764,6 +810,16 @@ async function commitOnce(repoRoot, msgPath) {
|
|
|
764
810
|
if (CLEAR_MSG_WHEN === "commit") clearMsgFile(msgPath);
|
|
765
811
|
|
|
766
812
|
const sha = (await run("git", ["rev-parse", "--short", "HEAD"])).stdout.trim();
|
|
813
|
+
|
|
814
|
+
// VISIBLE NOTIFICATION FOR USER
|
|
815
|
+
console.log("\n" + "─".repeat(60));
|
|
816
|
+
console.log(`\x1b[32m✓ COMMITTED:\x1b[0m ${sha}`);
|
|
817
|
+
console.log(` Branch: ${await currentBranch()}`);
|
|
818
|
+
console.log(` Message: ${header}`);
|
|
819
|
+
console.log("");
|
|
820
|
+
console.log(`\x1b[36m💡 TO FINISH:\x1b[0m Type \x1b[1mexit\x1b[0m to close session and cleanup`);
|
|
821
|
+
console.log("─".repeat(60) + "\n");
|
|
822
|
+
|
|
767
823
|
log(`committed ${sha} on ${await currentBranch()}`);
|
|
768
824
|
|
|
769
825
|
if (PUSH) {
|
|
@@ -772,8 +828,13 @@ async function commitOnce(repoRoot, msgPath) {
|
|
|
772
828
|
if (ok) {
|
|
773
829
|
if (CLEAR_MSG_WHEN === "push") clearMsgFile(msgPath);
|
|
774
830
|
|
|
831
|
+
console.log(`\x1b[32m✓ PUSHED:\x1b[0m ${BRANCH} -> remote`);
|
|
832
|
+
console.log(""); // Empty line for spacing
|
|
833
|
+
|
|
775
834
|
// Handle Docker restart if configured
|
|
776
835
|
await handleDockerRestart();
|
|
836
|
+
} else {
|
|
837
|
+
console.log(`\x1b[31m✗ PUSH FAILED:\x1b[0m Check logs for details`);
|
|
777
838
|
}
|
|
778
839
|
}
|
|
779
840
|
} finally {
|
|
@@ -1564,6 +1625,23 @@ console.log();
|
|
|
1564
1625
|
],
|
|
1565
1626
|
})
|
|
1566
1627
|
.on("all", async (evt, p) => {
|
|
1628
|
+
// Check if file is in local_deploy or .file-coordination (internal agent files)
|
|
1629
|
+
if (p.includes('local_deploy/') || p.includes('.file-coordination/')) {
|
|
1630
|
+
return;
|
|
1631
|
+
}
|
|
1632
|
+
|
|
1633
|
+
// Check if file is ignored by git (respect .gitignore)
|
|
1634
|
+
try {
|
|
1635
|
+
// git check-ignore returns 0 if ignored, 1 if not ignored
|
|
1636
|
+
// We use quiet mode (-q) and ignore stdio
|
|
1637
|
+
execSync(`git check-ignore -q "${p}"`, { stdio: 'ignore' });
|
|
1638
|
+
// If we get here, exit code was 0, so file IS ignored
|
|
1639
|
+
if (DEBUG) console.log(`[debug] Ignoring gitignored file: ${p}`);
|
|
1640
|
+
return;
|
|
1641
|
+
} catch (e) {
|
|
1642
|
+
// Exit code 1 means NOT ignored (or other error). Proceed.
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1567
1645
|
const now = Date.now();
|
|
1568
1646
|
const isMsg = samePath(p, relMsg);
|
|
1569
1647
|
|
|
@@ -1618,8 +1696,10 @@ console.log();
|
|
|
1618
1696
|
// INTERACTIVE COMMAND INTERFACE - Handle user commands during execution
|
|
1619
1697
|
// ============================================================================
|
|
1620
1698
|
|
|
1621
|
-
// Extract session ID from branch name or message file
|
|
1699
|
+
// Extract session ID from environment, branch name, or message file
|
|
1622
1700
|
const sessionId = (() => {
|
|
1701
|
+
if (process.env.DEVOPS_SESSION_ID) return process.env.DEVOPS_SESSION_ID;
|
|
1702
|
+
|
|
1623
1703
|
const branch = STATIC_BRANCH || BRANCH;
|
|
1624
1704
|
const match = branch.match(/([a-z0-9]{4}-[a-z0-9]{4})/i);
|
|
1625
1705
|
if (match) return match[1];
|
|
@@ -1651,7 +1731,7 @@ console.log();
|
|
|
1651
1731
|
const rl = readline.createInterface({
|
|
1652
1732
|
input: input,
|
|
1653
1733
|
output: output,
|
|
1654
|
-
prompt: '[agent]
|
|
1734
|
+
prompt: '\\x1b[36m[agent] >\\x1b[0m ',
|
|
1655
1735
|
terminal: true
|
|
1656
1736
|
});
|
|
1657
1737
|
|
|
@@ -1754,7 +1834,7 @@ console.log();
|
|
|
1754
1834
|
case 'exit':
|
|
1755
1835
|
case 'quit':
|
|
1756
1836
|
case 'q':
|
|
1757
|
-
console.log("
|
|
1837
|
+
console.log("\\n\\x1b[35m[Session] Initiating clean shutdown...\\x1b[0m");
|
|
1758
1838
|
|
|
1759
1839
|
// Check for uncommitted changes
|
|
1760
1840
|
const uncommitted = await hasUncommittedChanges();
|
|
@@ -1995,7 +2075,7 @@ console.log();
|
|
|
1995
2075
|
}
|
|
1996
2076
|
}
|
|
1997
2077
|
|
|
1998
|
-
console.log("\
|
|
2078
|
+
console.log("\n\\x1b[35m[Session] Exiting worker process...\\x1b[0m");
|
|
1999
2079
|
rl.close();
|
|
2000
2080
|
process.exit(0);
|
|
2001
2081
|
break;
|
|
@@ -166,10 +166,10 @@ class HouseRulesManager {
|
|
|
166
166
|
|
|
167
167
|
/**
|
|
168
168
|
* Find existing house rules file
|
|
169
|
-
*
|
|
169
|
+
* STRICT MODE: Only searches in the project root
|
|
170
170
|
*/
|
|
171
171
|
findHouseRulesFile() {
|
|
172
|
-
//
|
|
172
|
+
// Standard locations in root only
|
|
173
173
|
const possiblePaths = [
|
|
174
174
|
'houserules.md',
|
|
175
175
|
'HOUSERULES.md',
|
|
@@ -195,18 +195,8 @@ class HouseRulesManager {
|
|
|
195
195
|
}
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
-
//
|
|
199
|
-
//
|
|
200
|
-
const foundPath = this.searchForHouseRules(this.projectRoot);
|
|
201
|
-
if (foundPath) {
|
|
202
|
-
this.houseRulesPath = foundPath;
|
|
203
|
-
// Only log if not running as CLI
|
|
204
|
-
if (!process.argv[1]?.endsWith('house-rules-manager.js')) {
|
|
205
|
-
console.log(`Found house rules at: ${foundPath}`);
|
|
206
|
-
}
|
|
207
|
-
return foundPath;
|
|
208
|
-
}
|
|
209
|
-
|
|
198
|
+
// STRICT MODE: Do not search recursively.
|
|
199
|
+
// If not found in root, return null.
|
|
210
200
|
return null;
|
|
211
201
|
}
|
|
212
202
|
|
|
@@ -151,7 +151,15 @@ export function formatInstructions(session, options = {}) {
|
|
|
151
151
|
lines.push('');
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
//
|
|
154
|
+
// STOP instruction
|
|
155
|
+
lines.push('━'.repeat(70));
|
|
156
|
+
lines.push('');
|
|
157
|
+
lines.push(`${colors.red}${status.warning} IMPORTANT: STOP HERE${colors.reset}`);
|
|
158
|
+
lines.push('');
|
|
159
|
+
lines.push(`${colors.bright}Do NOT start coding or making changes yet!${colors.reset}`);
|
|
160
|
+
lines.push(`${colors.dim}Follow the steps above in order when instructed.${colors.reset}`);
|
|
161
|
+
lines.push(`${colors.dim}Wait for further instructions from the user before proceeding.${colors.reset}`);
|
|
162
|
+
lines.push('');
|
|
155
163
|
lines.push('━'.repeat(70));
|
|
156
164
|
lines.push('');
|
|
157
165
|
lines.push(`${status.checkmark} ${colors.green}DevOps Agent is now monitoring this session...${colors.reset}`);
|
|
@@ -62,7 +62,7 @@ const CONFIG = {
|
|
|
62
62
|
// SESSION COORDINATOR CLASS
|
|
63
63
|
// ============================================================================
|
|
64
64
|
|
|
65
|
-
class SessionCoordinator {
|
|
65
|
+
export class SessionCoordinator {
|
|
66
66
|
constructor() {
|
|
67
67
|
this.repoRoot = this.getRepoRoot();
|
|
68
68
|
this.sessionsPath = path.join(this.repoRoot, CONFIG.sessionsDir);
|
|
@@ -265,20 +265,129 @@ class SessionCoordinator {
|
|
|
265
265
|
}
|
|
266
266
|
}
|
|
267
267
|
|
|
268
|
+
/**
|
|
269
|
+
* Initialize House Rules Contracts folder and files
|
|
270
|
+
*/
|
|
271
|
+
async initializeContractsFolder() {
|
|
272
|
+
const contractsDir = path.join(this.repoRoot, 'House_Rules_Contracts');
|
|
273
|
+
|
|
274
|
+
// Check if contracts folder already exists
|
|
275
|
+
if (fs.existsSync(contractsDir)) {
|
|
276
|
+
console.log(`${CONFIG.colors.dim}✓ Contracts folder already exists${CONFIG.colors.reset}`);
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
console.log(`\n${CONFIG.colors.blue}Creating contracts folder...${CONFIG.colors.reset}`);
|
|
281
|
+
|
|
282
|
+
try {
|
|
283
|
+
// Create contracts directory
|
|
284
|
+
fs.mkdirSync(contractsDir, { recursive: true });
|
|
285
|
+
|
|
286
|
+
// Find the npm package location to copy templates
|
|
287
|
+
const packageRoot = path.resolve(__dirname, '..');
|
|
288
|
+
const contractsTemplateDir = path.join(packageRoot, 'House_Rules_Contracts');
|
|
289
|
+
|
|
290
|
+
if (fs.existsSync(contractsTemplateDir)) {
|
|
291
|
+
// Copy all contract template files
|
|
292
|
+
const files = fs.readdirSync(contractsTemplateDir);
|
|
293
|
+
let copiedCount = 0;
|
|
294
|
+
|
|
295
|
+
for (const file of files) {
|
|
296
|
+
if (file.endsWith('.md') || file.endsWith('.json')) {
|
|
297
|
+
const srcPath = path.join(contractsTemplateDir, file);
|
|
298
|
+
const destPath = path.join(contractsDir, file);
|
|
299
|
+
const content = fs.readFileSync(srcPath, 'utf8');
|
|
300
|
+
fs.writeFileSync(destPath, content);
|
|
301
|
+
copiedCount++;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
console.log(`${CONFIG.colors.green}✓${CONFIG.colors.reset} Created contracts folder with ${copiedCount} template files`);
|
|
306
|
+
console.log(`${CONFIG.colors.dim} Location: ${contractsDir}${CONFIG.colors.reset}`);
|
|
307
|
+
console.log(`${CONFIG.colors.dim} Files: API_CONTRACT.md, DATABASE_SCHEMA_CONTRACT.md, SQL_CONTRACT.json, etc.${CONFIG.colors.reset}`);
|
|
308
|
+
} else {
|
|
309
|
+
// Fallback: create empty contracts folder with basic README
|
|
310
|
+
const readmeContent = `# House Rules Contracts\n\nThis folder contains contract files that document all project components.\n\nSee houserules.md for complete documentation on the Contract System.\n`;
|
|
311
|
+
fs.writeFileSync(path.join(contractsDir, 'README.md'), readmeContent);
|
|
312
|
+
console.log(`${CONFIG.colors.yellow}⚠ Created empty contracts folder (templates not found in package)${CONFIG.colors.reset}`);
|
|
313
|
+
console.log(`${CONFIG.colors.dim} You can manually populate contract files from the DevOps Agent repository${CONFIG.colors.reset}`);
|
|
314
|
+
}
|
|
315
|
+
} catch (err) {
|
|
316
|
+
console.log(`${CONFIG.colors.red}✗ Error creating contracts folder: ${err.message}${CONFIG.colors.reset}`);
|
|
317
|
+
console.log(`${CONFIG.colors.dim} You can manually create House_Rules_Contracts/ folder${CONFIG.colors.reset}`);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
268
321
|
/**
|
|
269
322
|
* Ensure house rules are set up for the project
|
|
270
323
|
*/
|
|
271
324
|
async ensureHouseRulesSetup() {
|
|
272
325
|
const houseRulesManager = new HouseRulesManager(this.repoRoot);
|
|
326
|
+
const houseRulesPath = path.join(this.repoRoot, 'houserules.md');
|
|
273
327
|
|
|
274
328
|
// Check if house rules exist
|
|
275
|
-
if (!
|
|
329
|
+
if (!fs.existsSync(houseRulesPath)) {
|
|
276
330
|
console.log(`\n${CONFIG.colors.yellow}House rules not found - creating default house rules...${CONFIG.colors.reset}`);
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
331
|
+
console.log(`\n${CONFIG.colors.bright}=== Folder Organization Strategy ===${CONFIG.colors.reset}`);
|
|
332
|
+
console.log();
|
|
333
|
+
console.log(`${CONFIG.colors.bright}Option 1: STRUCTURED Organization${CONFIG.colors.reset}`);
|
|
334
|
+
console.log(`${CONFIG.colors.dim} • NEW code follows a module-based structure:${CONFIG.colors.reset}`);
|
|
335
|
+
console.log(`${CONFIG.colors.dim} ModuleName/src/featurename/ (source code)${CONFIG.colors.reset}`);
|
|
336
|
+
console.log(`${CONFIG.colors.dim} ModuleName/test/featurename/ (tests)${CONFIG.colors.reset}`);
|
|
337
|
+
console.log(`${CONFIG.colors.dim} • Existing files stay where they are (no moving!)${CONFIG.colors.reset}`);
|
|
338
|
+
console.log(`${CONFIG.colors.dim} • Benefits: Better discoverability, clear ownership, scales well${CONFIG.colors.reset}`);
|
|
339
|
+
console.log(`${CONFIG.colors.dim} • Best for: Larger projects, teams, microservices${CONFIG.colors.reset}`);
|
|
340
|
+
console.log();
|
|
341
|
+
console.log(`${CONFIG.colors.bright}Option 2: FLEXIBLE Organization${CONFIG.colors.reset}`);
|
|
342
|
+
console.log(`${CONFIG.colors.dim} • Use any folder structure you prefer${CONFIG.colors.reset}`);
|
|
343
|
+
console.log(`${CONFIG.colors.dim} • No enforced patterns for new code${CONFIG.colors.reset}`);
|
|
344
|
+
console.log(`${CONFIG.colors.dim} • Benefits: Freedom, simplicity, less overhead${CONFIG.colors.reset}`);
|
|
345
|
+
console.log(`${CONFIG.colors.dim} • Best for: Small projects, prototypes, solo developers${CONFIG.colors.reset}`);
|
|
346
|
+
console.log();
|
|
347
|
+
console.log(`${CONFIG.colors.yellow}Note: Both include the full contract system for preventing duplicate work.${CONFIG.colors.reset}`);
|
|
348
|
+
|
|
349
|
+
const rl = readline.createInterface({
|
|
350
|
+
input: process.stdin,
|
|
351
|
+
output: process.stdout
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
const wantsStructure = await new Promise((resolve) => {
|
|
355
|
+
rl.question(`${CONFIG.colors.green}Use structured organization? (Y/n):${CONFIG.colors.reset} `, (answer) => {
|
|
356
|
+
rl.close();
|
|
357
|
+
resolve(answer.toLowerCase() !== 'n');
|
|
358
|
+
});
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
// Determine which template to copy
|
|
362
|
+
const templateName = wantsStructure ? 'houserules_structured.md' : 'houserules.md';
|
|
363
|
+
|
|
364
|
+
// Find the npm package location (where this script is running from)
|
|
365
|
+
// session-coordinator.js is in src/, so package root is one level up
|
|
366
|
+
const packageRoot = path.resolve(__dirname, '..');
|
|
367
|
+
const templatePath = path.join(packageRoot, templateName);
|
|
368
|
+
|
|
369
|
+
// Copy the template to the project root
|
|
370
|
+
try {
|
|
371
|
+
if (fs.existsSync(templatePath)) {
|
|
372
|
+
const templateContent = fs.readFileSync(templatePath, 'utf8');
|
|
373
|
+
fs.writeFileSync(houseRulesPath, templateContent);
|
|
374
|
+
console.log(`${CONFIG.colors.green}✓${CONFIG.colors.reset} House rules created at: ${CONFIG.colors.bright}${houseRulesPath}${CONFIG.colors.reset}`);
|
|
375
|
+
console.log(`${CONFIG.colors.dim}Using ${wantsStructure ? 'structured' : 'flexible'} organization template${CONFIG.colors.reset}`);
|
|
376
|
+
} else {
|
|
377
|
+
console.log(`${CONFIG.colors.yellow}⚠ Template not found, creating basic house rules...${CONFIG.colors.reset}`);
|
|
378
|
+
// Fallback to programmatic creation
|
|
379
|
+
const result = await houseRulesManager.updateHouseRules({ createIfMissing: true, backupExisting: false });
|
|
380
|
+
if (result.created) {
|
|
381
|
+
console.log(`${CONFIG.colors.green}✓${CONFIG.colors.reset} House rules created at: ${CONFIG.colors.bright}${result.path}${CONFIG.colors.reset}`);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
} catch (err) {
|
|
385
|
+
console.log(`${CONFIG.colors.red}✗ Error creating house rules: ${err.message}${CONFIG.colors.reset}`);
|
|
386
|
+
console.log(`${CONFIG.colors.dim}You can manually create houserules.md in your project root${CONFIG.colors.reset}`);
|
|
281
387
|
}
|
|
388
|
+
|
|
389
|
+
// Initialize contracts folder after house rules are created
|
|
390
|
+
await this.initializeContractsFolder();
|
|
282
391
|
} else {
|
|
283
392
|
// House rules exist - check if they need updating
|
|
284
393
|
const status = houseRulesManager.getStatus();
|
|
@@ -1014,7 +1123,44 @@ class SessionCoordinator {
|
|
|
1014
1123
|
|
|
1015
1124
|
const sessionId = this.generateSessionId();
|
|
1016
1125
|
const task = options.task || 'development';
|
|
1017
|
-
|
|
1126
|
+
|
|
1127
|
+
// If agent type wasn't provided, ask for it now
|
|
1128
|
+
let agentType = options.agent;
|
|
1129
|
+
if (!agentType) {
|
|
1130
|
+
const rl = readline.createInterface({
|
|
1131
|
+
input: process.stdin,
|
|
1132
|
+
output: process.stdout
|
|
1133
|
+
});
|
|
1134
|
+
|
|
1135
|
+
console.log(`\n${CONFIG.colors.blue}Select Agent Type:${CONFIG.colors.reset}`);
|
|
1136
|
+
console.log(` 1) Claude (default)`);
|
|
1137
|
+
console.log(` 2) Cline`);
|
|
1138
|
+
console.log(` 3) Cursor`);
|
|
1139
|
+
console.log(` 4) Copilot`);
|
|
1140
|
+
console.log(` 5) Warp`);
|
|
1141
|
+
console.log(` 6) Custom\n`);
|
|
1142
|
+
|
|
1143
|
+
const agentChoice = await new Promise(resolve => {
|
|
1144
|
+
rl.question('Agent [1]: ', resolve);
|
|
1145
|
+
});
|
|
1146
|
+
|
|
1147
|
+
switch(agentChoice.trim() || '1') {
|
|
1148
|
+
case '1': agentType = 'claude'; break;
|
|
1149
|
+
case '2': agentType = 'cline'; break;
|
|
1150
|
+
case '3': agentType = 'cursor'; break;
|
|
1151
|
+
case '4': agentType = 'copilot'; break;
|
|
1152
|
+
case '5': agentType = 'warp'; break;
|
|
1153
|
+
case '6':
|
|
1154
|
+
agentType = await new Promise(resolve => {
|
|
1155
|
+
rl.question('Enter agent name: ', resolve);
|
|
1156
|
+
});
|
|
1157
|
+
agentType = agentType.trim() || 'claude';
|
|
1158
|
+
break;
|
|
1159
|
+
default: agentType = 'claude';
|
|
1160
|
+
}
|
|
1161
|
+
rl.close();
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1018
1164
|
const devInitials = this.getDeveloperInitials();
|
|
1019
1165
|
|
|
1020
1166
|
console.log(`\n${CONFIG.colors.bgBlue}${CONFIG.colors.bright} Creating New Session ${CONFIG.colors.reset}`);
|
|
@@ -1405,6 +1551,11 @@ The DevOps agent will automatically:
|
|
|
1405
1551
|
console.log(``);
|
|
1406
1552
|
console.log(`Write commit messages to: .devops-commit-${sessionId}.msg`);
|
|
1407
1553
|
console.log(`The DevOps agent will automatically commit and push changes.`);
|
|
1554
|
+
console.log(``);
|
|
1555
|
+
console.log(`⛔ IMPORTANT: STOP HERE AND WAIT`);
|
|
1556
|
+
console.log(`Do NOT start coding or making changes yet!`);
|
|
1557
|
+
console.log(`Follow the steps above in order when instructed by the user.`);
|
|
1558
|
+
console.log(`Wait for further instructions before proceeding.`);
|
|
1408
1559
|
console.log();
|
|
1409
1560
|
|
|
1410
1561
|
console.log(`${CONFIG.colors.yellow}══════════════════════════════════════════════════════════════${CONFIG.colors.reset}`);
|
|
@@ -2173,7 +2324,8 @@ async function main() {
|
|
|
2173
2324
|
console.log(` 2) Cline`);
|
|
2174
2325
|
console.log(` 3) Cursor`);
|
|
2175
2326
|
console.log(` 4) Copilot`);
|
|
2176
|
-
console.log(` 5)
|
|
2327
|
+
console.log(` 5) Warp`);
|
|
2328
|
+
console.log(` 6) Custom\n`);
|
|
2177
2329
|
|
|
2178
2330
|
const agentChoice = await new Promise(resolve => {
|
|
2179
2331
|
rl.question('Agent [1]: ', resolve);
|
|
@@ -2185,7 +2337,8 @@ async function main() {
|
|
|
2185
2337
|
case '2': agent = 'cline'; break;
|
|
2186
2338
|
case '3': agent = 'cursor'; break;
|
|
2187
2339
|
case '4': agent = 'copilot'; break;
|
|
2188
|
-
case '5':
|
|
2340
|
+
case '5': agent = 'warp'; break;
|
|
2341
|
+
case '6':
|
|
2189
2342
|
const customAgent = await new Promise(resolve => {
|
|
2190
2343
|
rl.question('Enter agent name: ', resolve);
|
|
2191
2344
|
});
|
|
@@ -2221,7 +2374,7 @@ async function main() {
|
|
|
2221
2374
|
|
|
2222
2375
|
const agent = args.includes('--agent') ?
|
|
2223
2376
|
args[args.indexOf('--agent') + 1] :
|
|
2224
|
-
|
|
2377
|
+
undefined; // Pass undefined to trigger prompt in createSession
|
|
2225
2378
|
|
|
2226
2379
|
await coordinator.createAndStart({ task, agent });
|
|
2227
2380
|
break;
|
|
@@ -2301,8 +2454,10 @@ ${CONFIG.colors.yellow}Typical Workflow:${CONFIG.colors.reset}
|
|
|
2301
2454
|
}
|
|
2302
2455
|
}
|
|
2303
2456
|
|
|
2304
|
-
// Run the CLI
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2457
|
+
// Run the CLI only if executed directly
|
|
2458
|
+
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
|
2459
|
+
main().catch(err => {
|
|
2460
|
+
console.error(`${CONFIG.colors.red}Error: ${err.message}${CONFIG.colors.reset}`);
|
|
2461
|
+
process.exit(1);
|
|
2462
|
+
});
|
|
2463
|
+
}
|