s9n-devops-agent 1.3.1 → 1.3.4
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 +1 -1
- package/src/house-rules-manager.js +173 -6
- package/src/session-coordinator.js +78 -14
- package/start-devops-session.sh +67 -36
package/package.json
CHANGED
|
@@ -16,6 +16,7 @@ import path from 'path';
|
|
|
16
16
|
import crypto from 'crypto';
|
|
17
17
|
import { fileURLToPath } from 'url';
|
|
18
18
|
import { dirname } from 'path';
|
|
19
|
+
import { execSync } from 'child_process';
|
|
19
20
|
|
|
20
21
|
const __filename = fileURLToPath(import.meta.url);
|
|
21
22
|
const __dirname = dirname(__filename);
|
|
@@ -112,15 +113,63 @@ To prevent conflicts with other agents editing the same files, you MUST follow t
|
|
|
112
113
|
|
|
113
114
|
class HouseRulesManager {
|
|
114
115
|
constructor(projectRoot) {
|
|
115
|
-
|
|
116
|
+
const cwd = projectRoot || process.cwd();
|
|
117
|
+
|
|
118
|
+
// If we're running from within a DevOpsAgent directory, we need to find the parent project
|
|
119
|
+
if (cwd.includes('/DevOpsAgent') || cwd.includes('/CS_DevOpsAgent')) {
|
|
120
|
+
// Parse the path to find where the DevOpsAgent directory is
|
|
121
|
+
const pathParts = cwd.split(path.sep);
|
|
122
|
+
|
|
123
|
+
// Find the index of DevOpsAgent or CS_DevOpsAgent
|
|
124
|
+
let targetIndex = -1;
|
|
125
|
+
for (let i = pathParts.length - 1; i >= 0; i--) {
|
|
126
|
+
if (pathParts[i] === 'CS_DevOpsAgent' || pathParts[i] === 'DevOpsAgent') {
|
|
127
|
+
targetIndex = i;
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// If found, use the parent directory as the project root
|
|
133
|
+
if (targetIndex > 0) {
|
|
134
|
+
// Check if the parent directory is 'Scripts_Dev' or similar subdirectory
|
|
135
|
+
// If so, go up one more level to reach the actual project root
|
|
136
|
+
let parentIndex = targetIndex;
|
|
137
|
+
if (targetIndex > 1 && (pathParts[targetIndex - 1] === 'Scripts_Dev' ||
|
|
138
|
+
pathParts[targetIndex - 1] === 'scripts' ||
|
|
139
|
+
pathParts[targetIndex - 1] === 'tools')) {
|
|
140
|
+
parentIndex = targetIndex - 1;
|
|
141
|
+
}
|
|
142
|
+
this.projectRoot = pathParts.slice(0, parentIndex).join(path.sep);
|
|
143
|
+
} else {
|
|
144
|
+
// Fallback: try to use git to find the parent repo
|
|
145
|
+
try {
|
|
146
|
+
const gitRoot = execSync('git rev-parse --show-toplevel', { cwd, encoding: 'utf8' }).trim();
|
|
147
|
+
// Only use git root if it's not a DevOpsAgent directory
|
|
148
|
+
if (!gitRoot.includes('/DevOpsAgent') && !gitRoot.includes('/CS_DevOpsAgent')) {
|
|
149
|
+
this.projectRoot = gitRoot;
|
|
150
|
+
} else {
|
|
151
|
+
// Use parent of cwd
|
|
152
|
+
this.projectRoot = path.dirname(path.dirname(cwd));
|
|
153
|
+
}
|
|
154
|
+
} catch (err) {
|
|
155
|
+
// Default to parent of parent directory
|
|
156
|
+
this.projectRoot = path.dirname(path.dirname(cwd));
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
} else {
|
|
160
|
+
this.projectRoot = cwd;
|
|
161
|
+
}
|
|
162
|
+
|
|
116
163
|
this.houseRulesPath = null;
|
|
117
164
|
this.findHouseRulesFile();
|
|
118
165
|
}
|
|
119
166
|
|
|
120
167
|
/**
|
|
121
168
|
* Find existing house rules file
|
|
169
|
+
* Searches across the repository, excluding the DevOps agent directories
|
|
122
170
|
*/
|
|
123
171
|
findHouseRulesFile() {
|
|
172
|
+
// First try the standard locations
|
|
124
173
|
const possiblePaths = [
|
|
125
174
|
'houserules.md',
|
|
126
175
|
'HOUSERULES.md',
|
|
@@ -132,11 +181,81 @@ class HouseRulesManager {
|
|
|
132
181
|
for (const relativePath of possiblePaths) {
|
|
133
182
|
const fullPath = path.join(this.projectRoot, relativePath);
|
|
134
183
|
if (fs.existsSync(fullPath)) {
|
|
184
|
+
// NEVER use house rules from within DevOpsAgent directories
|
|
185
|
+
if (fullPath.includes('/DevOpsAgent/') || fullPath.includes('/CS_DevOpsAgent/')) {
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
|
|
135
189
|
this.houseRulesPath = fullPath;
|
|
190
|
+
// Only log if not running as CLI
|
|
191
|
+
if (!process.argv[1]?.endsWith('house-rules-manager.js')) {
|
|
192
|
+
console.log(`Found house rules at: ${fullPath}`);
|
|
193
|
+
}
|
|
136
194
|
return fullPath;
|
|
137
195
|
}
|
|
138
196
|
}
|
|
139
197
|
|
|
198
|
+
// If not found in standard locations, search the repository
|
|
199
|
+
// excluding DevOps agent directories
|
|
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
|
+
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Recursively search for house rules files
|
|
215
|
+
* @param {string} dir Directory to search
|
|
216
|
+
* @param {number} depth Current depth (to prevent infinite recursion)
|
|
217
|
+
* @returns {string|null} Path to house rules file or null
|
|
218
|
+
*/
|
|
219
|
+
searchForHouseRules(dir, depth = 0) {
|
|
220
|
+
// Limit search depth to prevent excessive recursion
|
|
221
|
+
if (depth > 5) return null;
|
|
222
|
+
|
|
223
|
+
try {
|
|
224
|
+
const files = fs.readdirSync(dir);
|
|
225
|
+
|
|
226
|
+
for (const file of files) {
|
|
227
|
+
const filePath = path.join(dir, file);
|
|
228
|
+
const stat = fs.statSync(filePath);
|
|
229
|
+
|
|
230
|
+
// Check if it's a house rules file
|
|
231
|
+
if (stat.isFile() && /^houserules\.md$/i.test(file)) {
|
|
232
|
+
// Skip if it's in a DevOps agent directory
|
|
233
|
+
if (!filePath.includes('DevOpsAgent') &&
|
|
234
|
+
!filePath.includes('CS_DevOpsAgent') &&
|
|
235
|
+
!filePath.includes('node_modules') &&
|
|
236
|
+
!filePath.includes('.git')) {
|
|
237
|
+
return filePath;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Recursively search subdirectories
|
|
242
|
+
if (stat.isDirectory() &&
|
|
243
|
+
!file.startsWith('.') &&
|
|
244
|
+
file !== 'node_modules' &&
|
|
245
|
+
file !== 'DevOpsAgent' &&
|
|
246
|
+
file !== 'CS_DevOpsAgent' &&
|
|
247
|
+
file !== '.git') {
|
|
248
|
+
const found = this.searchForHouseRules(filePath, depth + 1);
|
|
249
|
+
if (found) return found;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
} catch (err) {
|
|
253
|
+
// Ignore permission errors and continue searching
|
|
254
|
+
if (err.code !== 'EACCES' && err.code !== 'EPERM') {
|
|
255
|
+
console.error(`Error searching ${dir}:`, err.message);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
140
259
|
return null;
|
|
141
260
|
}
|
|
142
261
|
|
|
@@ -306,8 +425,24 @@ ${endMarker}`;
|
|
|
306
425
|
|
|
307
426
|
// Create backup if requested
|
|
308
427
|
if (backupExisting) {
|
|
309
|
-
|
|
428
|
+
// Create backup in DevopsAgent_Backups folder
|
|
429
|
+
const backupDir = path.join(this.projectRoot, 'DevopsAgent_Backups');
|
|
430
|
+
if (!fs.existsSync(backupDir)) {
|
|
431
|
+
fs.mkdirSync(backupDir, { recursive: true });
|
|
432
|
+
// Ensure backup folder is in gitignore
|
|
433
|
+
this.ensureBackupInGitignore();
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, -5);
|
|
437
|
+
const backupFileName = `houserules_backup_${timestamp}.md`;
|
|
438
|
+
const backupPath = path.join(backupDir, backupFileName);
|
|
439
|
+
|
|
310
440
|
fs.copyFileSync(this.houseRulesPath, backupPath);
|
|
441
|
+
|
|
442
|
+
// Only log if not running as CLI
|
|
443
|
+
if (!process.argv[1]?.endsWith('house-rules-manager.js')) {
|
|
444
|
+
console.log(`Backup created: ${backupPath}`);
|
|
445
|
+
}
|
|
311
446
|
}
|
|
312
447
|
|
|
313
448
|
// Build new content
|
|
@@ -367,6 +502,33 @@ ${endMarker}`;
|
|
|
367
502
|
};
|
|
368
503
|
}
|
|
369
504
|
|
|
505
|
+
/**
|
|
506
|
+
* Ensure backup folder is in gitignore
|
|
507
|
+
*/
|
|
508
|
+
ensureBackupInGitignore() {
|
|
509
|
+
const gitignorePath = path.join(this.projectRoot, '.gitignore');
|
|
510
|
+
const backupPattern = 'DevopsAgent_Backups/';
|
|
511
|
+
|
|
512
|
+
try {
|
|
513
|
+
if (fs.existsSync(gitignorePath)) {
|
|
514
|
+
const content = fs.readFileSync(gitignorePath, 'utf8');
|
|
515
|
+
|
|
516
|
+
// Check if pattern already exists
|
|
517
|
+
if (!content.includes(backupPattern)) {
|
|
518
|
+
// Add to gitignore
|
|
519
|
+
const updatedContent = content.trimEnd() + '\n\n# DevOps Agent backup files\n' + backupPattern + '\n';
|
|
520
|
+
fs.writeFileSync(gitignorePath, updatedContent);
|
|
521
|
+
}
|
|
522
|
+
} else {
|
|
523
|
+
// Create gitignore with the pattern
|
|
524
|
+
const content = '# DevOps Agent backup files\n' + backupPattern + '\n';
|
|
525
|
+
fs.writeFileSync(gitignorePath, content);
|
|
526
|
+
}
|
|
527
|
+
} catch (err) {
|
|
528
|
+
// Silently fail - not critical if gitignore can't be updated
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
370
532
|
/**
|
|
371
533
|
* Get status of house rules
|
|
372
534
|
*/
|
|
@@ -422,22 +584,27 @@ ${endMarker}`;
|
|
|
422
584
|
export default HouseRulesManager;
|
|
423
585
|
|
|
424
586
|
// CLI interface when run directly
|
|
425
|
-
if
|
|
587
|
+
// Check if this is the main module being run
|
|
588
|
+
const isMainModule = import.meta.url === `file://${process.argv[1]}` ||
|
|
589
|
+
process.argv[1]?.endsWith('house-rules-manager.js');
|
|
590
|
+
|
|
591
|
+
if (isMainModule) {
|
|
426
592
|
const manager = new HouseRulesManager();
|
|
427
593
|
const command = process.argv[2];
|
|
428
594
|
|
|
429
595
|
switch (command) {
|
|
430
596
|
case 'status':
|
|
431
|
-
|
|
597
|
+
// Output only the JSON for the bash script to parse
|
|
598
|
+
console.log(JSON.stringify(manager.getStatus()));
|
|
432
599
|
break;
|
|
433
600
|
|
|
434
601
|
case 'update':
|
|
435
602
|
manager.updateHouseRules().then(result => {
|
|
436
|
-
console.log(
|
|
603
|
+
console.log(JSON.stringify(result));
|
|
437
604
|
});
|
|
438
605
|
break;
|
|
439
606
|
|
|
440
607
|
default:
|
|
441
608
|
console.log('Usage: node house-rules-manager.js [status|update]');
|
|
442
609
|
}
|
|
443
|
-
}
|
|
610
|
+
}
|
|
@@ -81,6 +81,14 @@ class SessionCoordinator {
|
|
|
81
81
|
|
|
82
82
|
getRepoRoot() {
|
|
83
83
|
try {
|
|
84
|
+
// Check if we're in a submodule
|
|
85
|
+
const superproject = execSync('git rev-parse --show-superproject-working-tree', { encoding: 'utf8' }).trim();
|
|
86
|
+
if (superproject) {
|
|
87
|
+
// We're in a submodule, use the parent repository root
|
|
88
|
+
console.log(`${CONFIG.colors.dim}Running from submodule, using parent repository: ${superproject}${CONFIG.colors.reset}`);
|
|
89
|
+
return superproject;
|
|
90
|
+
}
|
|
91
|
+
// Not in a submodule, use current repository root
|
|
84
92
|
return execSync('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();
|
|
85
93
|
} catch (error) {
|
|
86
94
|
console.error('Error: Not in a git repository');
|
|
@@ -711,11 +719,47 @@ class SessionCoordinator {
|
|
|
711
719
|
const branchName = `${agentType}/${devInitials}/${sessionId}/${task.replace(/\s+/g, '-')}`;
|
|
712
720
|
|
|
713
721
|
try {
|
|
722
|
+
// Detect if we're in a submodule and get the parent repository
|
|
723
|
+
let repoRoot = process.cwd();
|
|
724
|
+
let isSubmodule = false;
|
|
725
|
+
let parentRemote = null;
|
|
726
|
+
|
|
727
|
+
try {
|
|
728
|
+
// Check if we're in a submodule
|
|
729
|
+
execSync('git rev-parse --show-superproject-working-tree', { stdio: 'pipe' });
|
|
730
|
+
const superproject = execSync('git rev-parse --show-superproject-working-tree', { encoding: 'utf8' }).trim();
|
|
731
|
+
|
|
732
|
+
if (superproject) {
|
|
733
|
+
isSubmodule = true;
|
|
734
|
+
// Get the parent repository's remote
|
|
735
|
+
parentRemote = execSync(`git -C "${superproject}" remote get-url origin`, { encoding: 'utf8' }).trim();
|
|
736
|
+
console.log(`\n${CONFIG.colors.yellow}Detected submodule - will configure worktree for parent repository${CONFIG.colors.reset}`);
|
|
737
|
+
console.log(`${CONFIG.colors.dim}Parent repository: ${superproject}${CONFIG.colors.reset}`);
|
|
738
|
+
console.log(`${CONFIG.colors.dim}Parent remote: ${parentRemote}${CONFIG.colors.reset}`);
|
|
739
|
+
}
|
|
740
|
+
} catch (e) {
|
|
741
|
+
// Not a submodule, continue normally
|
|
742
|
+
}
|
|
743
|
+
|
|
714
744
|
// Create worktree
|
|
715
745
|
console.log(`\n${CONFIG.colors.yellow}Creating worktree...${CONFIG.colors.reset}`);
|
|
716
746
|
execSync(`git worktree add -b ${branchName} "${worktreePath}" HEAD`, { stdio: 'pipe' });
|
|
717
747
|
console.log(`${CONFIG.colors.green}✓${CONFIG.colors.reset} Worktree created at: ${worktreePath}`);
|
|
718
748
|
|
|
749
|
+
// If we're in a submodule, set up the correct remote for the worktree
|
|
750
|
+
if (isSubmodule && parentRemote) {
|
|
751
|
+
console.log(`${CONFIG.colors.yellow}Configuring worktree to use parent repository remote...${CONFIG.colors.reset}`);
|
|
752
|
+
// Remove the default origin that points to the submodule
|
|
753
|
+
try {
|
|
754
|
+
execSync(`git -C "${worktreePath}" remote remove origin`, { stdio: 'pipe' });
|
|
755
|
+
} catch (e) {
|
|
756
|
+
// Origin might not exist, continue
|
|
757
|
+
}
|
|
758
|
+
// Add the parent repository as origin
|
|
759
|
+
execSync(`git -C "${worktreePath}" remote add origin ${parentRemote}`, { stdio: 'pipe' });
|
|
760
|
+
console.log(`${CONFIG.colors.green}✓${CONFIG.colors.reset} Worktree configured to push to parent repository`);
|
|
761
|
+
}
|
|
762
|
+
|
|
719
763
|
// Create session lock
|
|
720
764
|
const lockData = {
|
|
721
765
|
sessionId,
|
|
@@ -753,7 +797,7 @@ class SessionCoordinator {
|
|
|
753
797
|
branchName,
|
|
754
798
|
lockFile,
|
|
755
799
|
instructionsFile,
|
|
756
|
-
|
|
800
|
+
task
|
|
757
801
|
};
|
|
758
802
|
|
|
759
803
|
} catch (error) {
|
|
@@ -763,7 +807,7 @@ class SessionCoordinator {
|
|
|
763
807
|
}
|
|
764
808
|
|
|
765
809
|
/**
|
|
766
|
-
* Generate instructions for
|
|
810
|
+
* Generate instructions for the coding agent
|
|
767
811
|
*/
|
|
768
812
|
generateClaudeInstructions(sessionData) {
|
|
769
813
|
const { sessionId, worktreePath, branchName, task } = sessionData;
|
|
@@ -812,7 +856,7 @@ INSTRUCTIONS:
|
|
|
812
856
|
3. **Only proceed if no conflicts** - wait or choose different files if blocked
|
|
813
857
|
4. **Release files when done** - delete your declaration after edits
|
|
814
858
|
|
|
815
|
-
## Instructions for
|
|
859
|
+
## Instructions for Your Coding Agent
|
|
816
860
|
|
|
817
861
|
### Step 1: Navigate to Your Worktree
|
|
818
862
|
\`\`\`bash
|
|
@@ -874,11 +918,15 @@ The DevOps agent will automatically:
|
|
|
874
918
|
* Display instructions in a user-friendly format
|
|
875
919
|
*/
|
|
876
920
|
displayInstructions(instructions, sessionId, task) {
|
|
877
|
-
|
|
921
|
+
// Get the parent repository root (where the session was started from)
|
|
922
|
+
const parentRepoRoot = process.cwd();
|
|
923
|
+
const houseRulesPath = path.join(parentRepoRoot, 'houserules.md');
|
|
924
|
+
|
|
925
|
+
console.log(`\n${CONFIG.colors.bgGreen}${CONFIG.colors.bright} Instructions for Your Coding Agent ${CONFIG.colors.reset}\n`);
|
|
878
926
|
|
|
879
927
|
// Clean separator
|
|
880
928
|
console.log(`${CONFIG.colors.yellow}══════════════════════════════════════════════════════════════${CONFIG.colors.reset}`);
|
|
881
|
-
console.log(`${CONFIG.colors.bright}COPY AND PASTE THIS ENTIRE BLOCK INTO
|
|
929
|
+
console.log(`${CONFIG.colors.bright}COPY AND PASTE THIS ENTIRE BLOCK INTO YOUR CODING AGENT BEFORE YOUR PROMPT:${CONFIG.colors.reset}`);
|
|
882
930
|
console.log(`${CONFIG.colors.yellow}──────────────────────────────────────────────────────────────${CONFIG.colors.reset}`);
|
|
883
931
|
console.log();
|
|
884
932
|
|
|
@@ -888,11 +936,13 @@ The DevOps agent will automatically:
|
|
|
888
936
|
console.log(`- Working Directory: ${instructions.worktreePath}`);
|
|
889
937
|
console.log(`- Task: ${task || 'development'}`);
|
|
890
938
|
console.log(``);
|
|
939
|
+
console.log(`⚠️ IMPORTANT: DO NOT start working yet! Wait for the user's specific instructions.`);
|
|
940
|
+
console.log(``);
|
|
891
941
|
console.log(`CRITICAL FIRST STEP:`);
|
|
892
|
-
console.log(`1. Read and follow the house rules: cat "${
|
|
942
|
+
console.log(`1. Read and follow the house rules: cat "${houseRulesPath}"`);
|
|
893
943
|
console.log(`2. Switch to the working directory: cd "${instructions.worktreePath}"`);
|
|
894
944
|
console.log(``);
|
|
895
|
-
console.log(`FILE COORDINATION PROTOCOL (from house rules at ${
|
|
945
|
+
console.log(`FILE COORDINATION PROTOCOL (from house rules at ${houseRulesPath}):`);
|
|
896
946
|
console.log(`Before editing ANY files, you MUST:`);
|
|
897
947
|
console.log(`- Declare your intent in .file-coordination/active-edits/<agent>-${sessionId}.json`);
|
|
898
948
|
console.log(`- Check for conflicts with other agents`);
|
|
@@ -902,13 +952,17 @@ The DevOps agent will automatically:
|
|
|
902
952
|
console.log(`Write commit messages to: .devops-commit-${sessionId}.msg`);
|
|
903
953
|
console.log(`The DevOps agent will automatically commit and push changes.`);
|
|
904
954
|
console.log(``);
|
|
905
|
-
console.log(`Remember: ALWAYS check house rules first for
|
|
955
|
+
console.log(`Remember: ALWAYS check house rules first, then WAIT for user instructions!`);
|
|
906
956
|
console.log();
|
|
907
957
|
|
|
908
958
|
console.log(`${CONFIG.colors.yellow}══════════════════════════════════════════════════════════════${CONFIG.colors.reset}`);
|
|
959
|
+
console.log();
|
|
960
|
+
|
|
961
|
+
// Pause before continuing
|
|
962
|
+
console.log(`${CONFIG.colors.dim}Press Enter to start the DevOps agent monitoring...${CONFIG.colors.reset}`);
|
|
909
963
|
|
|
910
964
|
// Status info
|
|
911
|
-
console.log(
|
|
965
|
+
console.log(`${CONFIG.colors.green}✓ DevOps agent is starting...${CONFIG.colors.reset}`);
|
|
912
966
|
console.log(`${CONFIG.colors.dim}Full instructions saved to: ${CONFIG.instructionsDir}/${sessionId}.md${CONFIG.colors.reset}`);
|
|
913
967
|
}
|
|
914
968
|
|
|
@@ -1070,11 +1124,11 @@ The DevOps agent is monitoring this worktree for changes.
|
|
|
1070
1124
|
fs.writeFileSync(lockFile, JSON.stringify(session, null, 2));
|
|
1071
1125
|
|
|
1072
1126
|
const instructions = this.generateClaudeInstructions(session);
|
|
1073
|
-
|
|
1127
|
+
// Don't display instructions here - they'll be shown after agent starts
|
|
1074
1128
|
|
|
1075
1129
|
return {
|
|
1076
1130
|
...session,
|
|
1077
|
-
instructions: instructions
|
|
1131
|
+
instructions: instructions
|
|
1078
1132
|
};
|
|
1079
1133
|
}
|
|
1080
1134
|
|
|
@@ -1223,11 +1277,21 @@ The DevOps agent is monitoring this worktree for changes.
|
|
|
1223
1277
|
|
|
1224
1278
|
console.log(`\n${CONFIG.colors.yellow}Starting agent for session ${session.sessionId}...${CONFIG.colors.reset}`);
|
|
1225
1279
|
|
|
1226
|
-
//
|
|
1227
|
-
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
1228
|
-
|
|
1280
|
+
// Start the agent first
|
|
1229
1281
|
await this.startAgent(session.sessionId);
|
|
1230
1282
|
|
|
1283
|
+
// Wait for agent to initialize and show its interactive commands
|
|
1284
|
+
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
1285
|
+
|
|
1286
|
+
// Now display the instructions AFTER the agent is running
|
|
1287
|
+
console.log('\n'.repeat(2)); // Add some spacing
|
|
1288
|
+
// Create instructions object with worktreePath for display
|
|
1289
|
+
const instructionsForDisplay = {
|
|
1290
|
+
worktreePath: session.worktreePath,
|
|
1291
|
+
sessionId: session.sessionId
|
|
1292
|
+
};
|
|
1293
|
+
this.displayInstructions(instructionsForDisplay, session.sessionId, options.task || 'development');
|
|
1294
|
+
|
|
1231
1295
|
return session;
|
|
1232
1296
|
}
|
|
1233
1297
|
|
package/start-devops-session.sh
CHANGED
|
@@ -12,21 +12,27 @@
|
|
|
12
12
|
#
|
|
13
13
|
# ============================================================================
|
|
14
14
|
|
|
15
|
-
# Colors for output
|
|
16
|
-
RED
|
|
17
|
-
GREEN
|
|
18
|
-
YELLOW
|
|
19
|
-
BLUE
|
|
20
|
-
MAGENTA
|
|
21
|
-
BOLD
|
|
22
|
-
DIM
|
|
23
|
-
NC
|
|
24
|
-
BG_BLUE
|
|
25
|
-
BG_GREEN
|
|
26
|
-
BG_YELLOW
|
|
15
|
+
# Colors for output (using printf for better compatibility)
|
|
16
|
+
RED=$'\033[0;31m'
|
|
17
|
+
GREEN=$'\033[0;32m'
|
|
18
|
+
YELLOW=$'\033[1;33m'
|
|
19
|
+
BLUE=$'\033[0;36m'
|
|
20
|
+
MAGENTA=$'\033[0;35m'
|
|
21
|
+
BOLD=$'\033[1m'
|
|
22
|
+
DIM=$'\033[2m'
|
|
23
|
+
NC=$'\033[0m' # No Color
|
|
24
|
+
BG_BLUE=$'\033[44m'
|
|
25
|
+
BG_GREEN=$'\033[42m'
|
|
26
|
+
BG_YELLOW=$'\033[43m'
|
|
27
27
|
|
|
28
|
-
# Get the directory where this script is located
|
|
29
|
-
|
|
28
|
+
# Get the directory where this script is located (compatible with both bash and zsh)
|
|
29
|
+
if [[ -n "${BASH_SOURCE[0]}" ]]; then
|
|
30
|
+
# Running in bash
|
|
31
|
+
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
|
32
|
+
else
|
|
33
|
+
# Running in zsh
|
|
34
|
+
SCRIPT_DIR="${0:A:h}"
|
|
35
|
+
fi
|
|
30
36
|
SRC_DIR="$SCRIPT_DIR/src"
|
|
31
37
|
|
|
32
38
|
# Function to display copyright
|
|
@@ -64,10 +70,10 @@ display_instructions() {
|
|
|
64
70
|
local task="$4"
|
|
65
71
|
|
|
66
72
|
echo
|
|
67
|
-
echo -e "${BG_GREEN}${BOLD} Instructions for
|
|
73
|
+
echo -e "${BG_GREEN}${BOLD} Instructions for Your Coding Agent ${NC}"
|
|
68
74
|
echo
|
|
69
75
|
echo -e "${YELLOW}══════════════════════════════════════════════════════════════${NC}"
|
|
70
|
-
echo -e "${BOLD}COPY AND PASTE THIS ENTIRE BLOCK INTO
|
|
76
|
+
echo -e "${BOLD}COPY AND PASTE THIS ENTIRE BLOCK INTO YOUR CODING AGENT BEFORE YOUR PROMPT:${NC}"
|
|
71
77
|
echo -e "${YELLOW}──────────────────────────────────────────────────────────────${NC}"
|
|
72
78
|
echo
|
|
73
79
|
echo "I'm working in a DevOps-managed session with the following setup:"
|
|
@@ -154,7 +160,7 @@ create_new_session() {
|
|
|
154
160
|
echo -e "${YELLOW}Creating session for: ${task_name}${NC}"
|
|
155
161
|
|
|
156
162
|
# Run the session coordinator to create AND START the session
|
|
157
|
-
|
|
163
|
+
# Keep current directory to ensure session is created for the right repo
|
|
158
164
|
node "$SRC_DIR/session-coordinator.js" create-and-start --task "$task_name" --agent "$agent_type"
|
|
159
165
|
}
|
|
160
166
|
|
|
@@ -215,7 +221,7 @@ select_session() {
|
|
|
215
221
|
echo
|
|
216
222
|
echo -e "${GREEN}Using existing session: ${session_id}${NC}"
|
|
217
223
|
|
|
218
|
-
# Display instructions for
|
|
224
|
+
# Display instructions for coding agent IMMEDIATELY after selection
|
|
219
225
|
display_instructions "$session_id" "$worktree_path" "$branch_name" "$task"
|
|
220
226
|
|
|
221
227
|
# Add a pause and visual separator before starting the agent
|
|
@@ -228,7 +234,7 @@ select_session() {
|
|
|
228
234
|
echo -e "${YELLOW}═══════════════════════════════════════════════════════════${NC}"
|
|
229
235
|
|
|
230
236
|
# Start the agent for this session
|
|
231
|
-
|
|
237
|
+
# Keep current directory to ensure agent runs in the right repo
|
|
232
238
|
node "$SRC_DIR/session-coordinator.js" start "$session_id"
|
|
233
239
|
return 0
|
|
234
240
|
else
|
|
@@ -299,22 +305,46 @@ setup_house_rules() {
|
|
|
299
305
|
local HOUSERULES_PATH=""
|
|
300
306
|
local HOUSERULES_FOUND=false
|
|
301
307
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
308
|
+
# Function to search for house rules file
|
|
309
|
+
find_house_rules() {
|
|
310
|
+
local search_dir="$1"
|
|
311
|
+
local depth="${2:-0}"
|
|
312
|
+
|
|
313
|
+
# Limit search depth
|
|
314
|
+
if [[ $depth -gt 5 ]]; then
|
|
315
|
+
return 1
|
|
316
|
+
fi
|
|
317
|
+
|
|
318
|
+
# First check standard locations
|
|
319
|
+
for possible_path in "houserules.md" "HOUSERULES.md" ".github/HOUSERULES.md" "docs/houserules.md" "docs/HOUSERULES.md"; do
|
|
320
|
+
if [[ -f "$search_dir/$possible_path" ]]; then
|
|
321
|
+
echo "$search_dir/$possible_path"
|
|
322
|
+
return 0
|
|
323
|
+
fi
|
|
324
|
+
done
|
|
325
|
+
|
|
326
|
+
# If not found, search recursively (excluding DevOps directories)
|
|
327
|
+
while IFS= read -r -d '' file; do
|
|
328
|
+
local rel_path="${file#$search_dir/}"
|
|
329
|
+
if [[ ! "$file" =~ "DevOpsAgent" ]] &&
|
|
330
|
+
[[ ! "$file" =~ "CS_DevOpsAgent" ]] &&
|
|
331
|
+
[[ ! "$file" =~ "node_modules" ]] &&
|
|
332
|
+
[[ ! "$file" =~ ".git" ]]; then
|
|
333
|
+
echo "$file"
|
|
334
|
+
return 0
|
|
335
|
+
fi
|
|
336
|
+
done < <(find "$search_dir" -maxdepth 3 -type f \( -iname "houserules.md" -o -iname "HOUSERULES.md" \) -print0 2>/dev/null)
|
|
337
|
+
|
|
338
|
+
return 1
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
# Search for house rules file
|
|
342
|
+
if FOUND_PATH=$(find_house_rules "$ROOT"); then
|
|
343
|
+
HOUSERULES_PATH="$FOUND_PATH"
|
|
316
344
|
HOUSERULES_FOUND=true
|
|
317
|
-
|
|
345
|
+
# Make path relative for display
|
|
346
|
+
local REL_PATH="${FOUND_PATH#$ROOT/}"
|
|
347
|
+
echo -e "${GREEN}✓${NC} Found existing house rules at: $REL_PATH"
|
|
318
348
|
else
|
|
319
349
|
echo "No existing house rules found."
|
|
320
350
|
echo
|
|
@@ -358,7 +388,8 @@ setup_house_rules() {
|
|
|
358
388
|
|
|
359
389
|
# Run the actual setup inline (simplified version)
|
|
360
390
|
if [[ -f "$SCRIPT_DIR/scripts/setup-file-coordination.sh" ]]; then
|
|
361
|
-
|
|
391
|
+
# Pass the house rules path we already found!
|
|
392
|
+
HOUSERULES_PATH="$HOUSERULES_PATH" bash "$SCRIPT_DIR/scripts/setup-file-coordination.sh"
|
|
362
393
|
else
|
|
363
394
|
# Inline setup if script doesn't exist
|
|
364
395
|
mkdir -p "$COORD_DIR/active-edits" "$COORD_DIR/completed-edits"
|
|
@@ -399,7 +430,7 @@ main() {
|
|
|
399
430
|
echo
|
|
400
431
|
echo "This tool will:"
|
|
401
432
|
echo " 1. Help you create or select a session"
|
|
402
|
-
echo " 2. Generate instructions for
|
|
433
|
+
echo " 2. Generate instructions for your coding agent"
|
|
403
434
|
echo " 3. Start the DevOps agent to monitor changes"
|
|
404
435
|
echo
|
|
405
436
|
|