s9n-devops-agent 1.3.4 → 1.4.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.
@@ -53,21 +53,43 @@ To prevent conflicts with other agents editing the same files, you MUST follow t
53
53
 
54
54
  ## Testing Policy (Required)
55
55
 
56
+ ### Test-Driven Development (TDD) Requirements
57
+
58
+ **CRITICAL: For ALL new features and copied code (except infrastructure):**
59
+ 1. **WRITE THE TEST FIRST** - Before implementing any new functionality
60
+ 2. **RED-GREEN-REFACTOR** cycle:
61
+ - RED: Write a failing test that defines expected behavior
62
+ - GREEN: Write minimal code to make the test pass
63
+ - REFACTOR: Improve the code while keeping tests green
64
+
65
+ ### When Tests Are MANDATORY:
66
+ - **New Features**: Test MUST be written BEFORE implementation code
67
+ - **Copied/Adapted Code**: Test MUST verify the adaptation works correctly
68
+ - **Bug Fixes**: Test MUST reproduce the bug first (fail), then pass after fix
69
+ - **API Changes**: Test MUST cover new endpoints/methods
70
+ - **Business Logic**: Test MUST validate all logic paths
71
+
72
+ ### When Tests Are OPTIONAL:
73
+ - **Pure Infrastructure Code**: Build scripts, deployment configs
74
+ - **Configuration Files**: Unless they contain logic
75
+ - **Documentation**: README files, comments
76
+ - **Generated Code**: Auto-generated files (but test the generator!)
77
+
56
78
  Goal: Every bug fix and feature ships with an executable test.
57
79
 
58
80
  Location: test_cases/<area>/<component>/.
59
81
 
60
- DoD: (1) failing test reproduces bug (red), (2) fix makes it pass (green), (3) tests wired into CI and local runner.
82
+ DoD: (1) failing test defines behavior (red), (2) implementation makes it pass (green), (3) tests wired into CI and local runner.
61
83
 
62
84
  Naming: YYYYMMDD_<short-slug>_spec.(py|ts|js|go|rb|java)
63
85
 
64
- Non-duplication: Extend existing tests for the same bug.
86
+ Non-duplication: Extend existing tests for the same functionality.
65
87
 
66
88
  Determinism: No flaky/random tests; use seeds and fake timers.
67
89
 
68
90
  ## Test Generation Rules (for Claude / code assistants)
69
91
 
70
- Always write the failing test first.
92
+ **ALWAYS write the test BEFORE the implementation code.**
71
93
 
72
94
  Infer <area>/<component> from changed paths.
73
95
 
@@ -77,6 +99,47 @@ Use native runners per language (pytest, vitest/jest, go test, rspec, JUnit).
77
99
 
78
100
  Add short "why it failed before the fix" note in the test.
79
101
 
102
+ ## TDD Workflow for New Features
103
+
104
+ ### Step 1: Write the Test First
105
+ Before writing ANY implementation code:
106
+ 1. Create test file in `test_cases/<area>/<component>/`
107
+ 2. Define expected behavior through test assertions
108
+ 3. Run test to ensure it FAILS (Red phase)
109
+ 4. Commit the failing test with message: `test: add failing test for <feature>`
110
+
111
+ ### Step 2: Implement Minimal Code
112
+ 1. Write ONLY enough code to make the test pass
113
+ 2. Don't add extra features or optimizations yet
114
+ 3. Run test to ensure it PASSES (Green phase)
115
+ 4. Commit implementation with message: `feat: implement <feature> to pass test`
116
+
117
+ ### Step 3: Refactor (if needed)
118
+ 1. Improve code quality, performance, or structure
119
+ 2. Ensure tests still pass after each change
120
+ 3. Commit refactoring with message: `refactor: improve <aspect> of <feature>`
121
+
122
+ ### Example TDD Flow for Agents:
123
+ ```bash
124
+ # 1. First, declare your intent to edit test and implementation files
125
+ echo '{"files": ["test_cases/session/coordinator/test_new_feature.js", "src/new_feature.js"]}' > .file-coordination/active-edits/claude-session.json
126
+
127
+ # 2. Write the test FIRST
128
+ # Create: test_cases/session/coordinator/20241003_new_feature_spec.js
129
+
130
+ # 3. Run test to verify it fails
131
+ npm test test_cases/session/coordinator/20241003_new_feature_spec.js
132
+
133
+ # 4. NOW write the implementation
134
+ # Create/modify: src/new_feature.js
135
+
136
+ # 5. Run test to verify it passes
137
+ npm test test_cases/session/coordinator/20241003_new_feature_spec.js
138
+
139
+ # 6. Release your file locks
140
+ rm .file-coordination/active-edits/claude-session.json
141
+ ```
142
+
80
143
  ## Test Case Template
81
144
  ```
82
145
  # Test Case: <human title>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "s9n-devops-agent",
3
- "version": "1.3.4",
3
+ "version": "1.4.0",
4
4
  "description": "CS_DevOpsAgent - Intelligent Git Automation System with multi-agent support and session management",
5
5
  "type": "module",
6
6
  "main": "src/cs-devops-agent-worker.js",
@@ -1454,7 +1454,31 @@ console.log();
1454
1454
  ignoreInitial: true,
1455
1455
  usePolling: USE_POLLING,
1456
1456
  interval: 500,
1457
- ignored: ["**/__pycache__/**", "**/*.pyc", "**/.DS_Store", "**/logs/**"],
1457
+ ignored: [
1458
+ "**/__pycache__/**",
1459
+ "**/*.pyc",
1460
+ "**/.DS_Store",
1461
+ "**/logs/**",
1462
+ "**/node_modules/**",
1463
+ "**/.git/**",
1464
+ "**/local_deploy/**",
1465
+ "**/dist/**",
1466
+ "**/build/**",
1467
+ "**/coverage/**",
1468
+ "**/.next/**",
1469
+ "**/.nuxt/**",
1470
+ "**/tmp/**",
1471
+ "**/temp/**",
1472
+ "**/.cache/**",
1473
+ "**/vendor/**",
1474
+ "**/.vscode/**",
1475
+ "**/.idea/**",
1476
+ "**/*.log",
1477
+ "**/*.lock",
1478
+ "**/package-lock.json",
1479
+ "**/yarn.lock",
1480
+ "**/pnpm-lock.yaml"
1481
+ ],
1458
1482
  })
1459
1483
  .on("all", async (evt, p) => {
1460
1484
  const now = Date.now();
@@ -46,7 +46,7 @@ export async function isDockerComposeAvailable() {
46
46
  }
47
47
 
48
48
  /**
49
- * Find docker-compose files in the project
49
+ * Find docker-compose files in the project, parent directory, and parent/Infrastructure
50
50
  */
51
51
  export function findDockerComposeFiles(projectPath) {
52
52
  const possibleFiles = [
@@ -60,14 +60,30 @@ export function findDockerComposeFiles(projectPath) {
60
60
  'docker-compose.local.yaml'
61
61
  ];
62
62
 
63
+ const searchLocations = [
64
+ { path: projectPath, label: 'project directory' },
65
+ { path: path.dirname(projectPath), label: 'parent directory' },
66
+ { path: path.join(path.dirname(projectPath), 'Infrastructure'), label: 'parent/Infrastructure' },
67
+ { path: path.join(path.dirname(projectPath), 'infrastructure'), label: 'parent/infrastructure' }
68
+ ];
69
+
63
70
  const found = [];
64
- for (const file of possibleFiles) {
65
- const filePath = path.join(projectPath, file);
66
- if (fs.existsSync(filePath)) {
67
- found.push({
68
- name: file,
69
- path: filePath
70
- });
71
+
72
+ for (const location of searchLocations) {
73
+ // Check if location exists
74
+ if (!fs.existsSync(location.path)) {
75
+ continue;
76
+ }
77
+
78
+ for (const file of possibleFiles) {
79
+ const filePath = path.join(location.path, file);
80
+ if (fs.existsSync(filePath)) {
81
+ found.push({
82
+ name: file,
83
+ path: filePath,
84
+ location: location.label
85
+ });
86
+ }
71
87
  }
72
88
  }
73
89
 
@@ -529,6 +529,228 @@ ${endMarker}`;
529
529
  }
530
530
  }
531
531
 
532
+ /**
533
+ * Initial setup - prompt for folder structure preference and copy appropriate files
534
+ */
535
+ async initialSetup() {
536
+ // Check if house rules already exist
537
+ if (this.houseRulesPath && fs.existsSync(this.houseRulesPath)) {
538
+ return {
539
+ alreadyExists: true,
540
+ path: this.houseRulesPath,
541
+ message: 'House rules already exist'
542
+ };
543
+ }
544
+
545
+ // Import readline for interactive prompts
546
+ const readline = await import('readline');
547
+ const rl = readline.createInterface({
548
+ input: process.stdin,
549
+ output: process.stdout
550
+ });
551
+
552
+ return new Promise((resolve) => {
553
+ console.log('\n📋 House Rules Setup');
554
+ console.log('━'.repeat(60));
555
+ console.log('\nWould you like to enforce a structured folder organization?');
556
+ console.log('\n ✅ YES - Get comprehensive folder structure with guidelines');
557
+ console.log(' • Modular organization (/ModuleName/src/featurename/)');
558
+ console.log(' • Best for: New projects, large applications');
559
+ console.log(' • Includes: houserules + folders.md guide');
560
+ console.log('\n ❌ NO - Use flexible structure (organize your own way)');
561
+ console.log(' • No enforced folder structure');
562
+ console.log(' • Best for: Existing projects, quick setup');
563
+ console.log(' • Includes: Core house rules only');
564
+ console.log();
565
+
566
+ rl.question('Do you want structured folder organization? (Y/N) [N]: ', (answer) => {
567
+ const wantStructure = answer.trim().toLowerCase() === 'y' || answer.trim().toLowerCase() === 'yes';
568
+ rl.close();
569
+
570
+ try {
571
+ const result = this.setupHouseRules(wantStructure);
572
+ console.log();
573
+ console.log(`${wantStructure ? '📁' : '📄'} House rules setup complete!`);
574
+ console.log(` Location: ${result.houseRulesPath}`);
575
+
576
+ if (wantStructure) {
577
+ console.log(` Folder guide: ${result.foldersPath}`);
578
+ console.log();
579
+ console.log('💡 TIP: Open folders.md to customize your project structure');
580
+ }
581
+
582
+ if (result.infrastructurePath) {
583
+ console.log(` Infrastructure docs: ${result.infrastructurePath}`);
584
+ }
585
+
586
+ console.log();
587
+ resolve(result);
588
+ } catch (error) {
589
+ console.error('❌ Failed to setup house rules:', error.message);
590
+ resolve({ success: false, error: error.message });
591
+ }
592
+ });
593
+ });
594
+ }
595
+
596
+ /**
597
+ * Setup house rules by copying appropriate template
598
+ */
599
+ setupHouseRules(withStructure = false) {
600
+ // Determine source and target paths
601
+ const agentRoot = path.join(__dirname, '..');
602
+ const sourceFileName = withStructure ? 'houserules_structured.md' : 'houserules_core.md';
603
+ const sourcePath = path.join(agentRoot, sourceFileName);
604
+ const targetPath = path.join(this.projectRoot, 'houserules.md');
605
+
606
+ // Verify source file exists
607
+ if (!fs.existsSync(sourcePath)) {
608
+ throw new Error(`Source house rules template not found: ${sourcePath}`);
609
+ }
610
+
611
+ // Copy house rules
612
+ fs.copyFileSync(sourcePath, targetPath);
613
+ this.houseRulesPath = targetPath;
614
+
615
+ const result = {
616
+ success: true,
617
+ withStructure,
618
+ houseRulesPath: targetPath
619
+ };
620
+
621
+ // If structured, also copy folders.md
622
+ if (withStructure) {
623
+ const foldersSrc = path.join(agentRoot, 'folders.md');
624
+ const foldersDest = path.join(this.projectRoot, 'folders.md');
625
+
626
+ if (fs.existsSync(foldersSrc)) {
627
+ fs.copyFileSync(foldersSrc, foldersDest);
628
+ result.foldersPath = foldersDest;
629
+ }
630
+ }
631
+
632
+ // Always create infrastructure directory and template
633
+ const infraDir = path.join(this.projectRoot, 'infrastructure');
634
+ if (!fs.existsSync(infraDir)) {
635
+ fs.mkdirSync(infraDir, { recursive: true });
636
+ }
637
+
638
+ const infraDocPath = path.join(infraDir, 'infrastructure.md');
639
+ if (!fs.existsSync(infraDocPath)) {
640
+ const infraTemplate = this.getInfrastructureTemplate();
641
+ fs.writeFileSync(infraDocPath, infraTemplate);
642
+ result.infrastructurePath = infraDocPath;
643
+ }
644
+
645
+ return result;
646
+ }
647
+
648
+ /**
649
+ * Get infrastructure.md template content
650
+ */
651
+ getInfrastructureTemplate() {
652
+ return `# Infrastructure Documentation
653
+
654
+ **IMPORTANT**: This file documents all infrastructure resources for this project.
655
+ Always read this file before creating new servers, instances, or Docker containers.
656
+
657
+ ## Overview
658
+ Last Updated: ${new Date().toISOString()}
659
+
660
+ ## Docker Containers
661
+
662
+ ### Example Container
663
+ - **Name**: example-service
664
+ - **Image**: nginx:latest
665
+ - **Ports**: 8080:80
666
+ - **Purpose**: Example web server
667
+ - **Dependencies**: None
668
+ - **Configuration**:
669
+ - Environment: \`ENV=production\`
670
+ - Volumes: \`./data:/usr/share/nginx/html\`
671
+
672
+ ## Servers / Instances
673
+
674
+ ### Example Server
675
+ - **Name**: api-server
676
+ - **Type**: AWS EC2 t2.micro
677
+ - **IP/Domain**: api.example.com
678
+ - **Purpose**: REST API backend
679
+ - **Access**: SSH key required
680
+ - **Dependencies**: PostgreSQL database
681
+
682
+ ## Databases
683
+
684
+ ### Example Database
685
+ - **Name**: main-db
686
+ - **Type**: PostgreSQL 14
687
+ - **Host**: localhost:5432
688
+ - **Purpose**: Application data storage
689
+ - **Backup Schedule**: Daily at 2 AM UTC
690
+
691
+ ## Services / APIs
692
+
693
+ ### Example Service
694
+ - **Name**: auth-service
695
+ - **Type**: OAuth2 Provider
696
+ - **Endpoint**: https://auth.example.com
697
+ - **Purpose**: User authentication
698
+ - **API Keys**: Stored in environment variables
699
+
700
+ ## Network Configuration
701
+
702
+ - **VPC/Network**: default
703
+ - **Subnets**:
704
+ - Public: 10.0.1.0/24
705
+ - Private: 10.0.2.0/24
706
+ - **Security Groups**:
707
+ - web-sg: Allows 80, 443
708
+ - api-sg: Allows 8080
709
+
710
+ ## Monitoring & Logging
711
+
712
+ - **Monitoring**: CloudWatch / Prometheus
713
+ - **Logging**: Centralized logging to /var/log/
714
+ - **Alerts**: Email notifications enabled
715
+
716
+ ## Backup & Recovery
717
+
718
+ - **Backup Location**: S3 bucket or local path
719
+ - **Recovery Time Objective (RTO)**: < 1 hour
720
+ - **Recovery Point Objective (RPO)**: < 15 minutes
721
+
722
+ ## Access & Credentials
723
+
724
+ **NOTE**: Never commit credentials to this file.
725
+ Document where credentials are stored (e.g., password manager, secrets vault).
726
+
727
+ - **SSH Keys**: Stored in team password manager
728
+ - **API Keys**: Environment variables only
729
+ - **Database Passwords**: AWS Secrets Manager
730
+
731
+ ## Rollback Procedures
732
+
733
+ ### How to Remove/Rollback Infrastructure
734
+
735
+ 1. **Docker Containers**:
736
+ \`\`\`bash
737
+ docker-compose down
738
+ \`\`\`
739
+
740
+ 2. **Servers**:
741
+ - Stop the instance via cloud console
742
+ - Take snapshot before termination
743
+ - Document instance ID and configuration
744
+
745
+ ## Change History
746
+
747
+ ### YYYY-MM-DD - Initial Setup
748
+ - Created base infrastructure
749
+ - Deployed example services
750
+ - Configured networking and security
751
+ `;
752
+ }
753
+
532
754
  /**
533
755
  * Get status of house rules
534
756
  */
@@ -25,6 +25,7 @@ import { execSync, spawn, fork } from 'child_process';
25
25
  import crypto from 'crypto';
26
26
  import readline from 'readline';
27
27
  import { hasDockerConfiguration } from './docker-utils.js';
28
+ import HouseRulesManager from './house-rules-manager.js';
28
29
 
29
30
  const __filename = fileURLToPath(import.meta.url);
30
31
  const __dirname = dirname(__filename);
@@ -150,6 +151,19 @@ class SessionCoordinator {
150
151
  }
151
152
  }
152
153
 
154
+ /**
155
+ * Ensure house rules are set up for the project
156
+ */
157
+ async ensureHouseRulesSetup() {
158
+ const houseRulesManager = new HouseRulesManager(this.repoRoot);
159
+
160
+ // Check if house rules exist
161
+ if (!houseRulesManager.houseRulesPath || !fs.existsSync(houseRulesManager.houseRulesPath)) {
162
+ console.log(`\n${CONFIG.colors.yellow}House rules not found - setting up now...${CONFIG.colors.reset}`);
163
+ await houseRulesManager.initialSetup();
164
+ }
165
+ }
166
+
153
167
  /**
154
168
  * Ensure project-specific version settings are configured
155
169
  */
@@ -463,6 +477,16 @@ class SessionCoordinator {
463
477
  * Prompt for auto-merge configuration
464
478
  */
465
479
  async promptForMergeConfig() {
480
+ // Check if auto-merge setting is already configured
481
+ const projectSettings = this.loadProjectSettings();
482
+ if (projectSettings.autoMergeConfig && projectSettings.autoMergeConfig.alwaysEnabled !== undefined) {
483
+ // Already configured with 'Always', use saved settings
484
+ if (projectSettings.autoMergeConfig.alwaysEnabled) {
485
+ console.log(`\n${CONFIG.colors.dim}Using saved auto-merge configuration${CONFIG.colors.reset}`);
486
+ return projectSettings.autoMergeConfig;
487
+ }
488
+ }
489
+
466
490
  const rl = readline.createInterface({
467
491
  input: process.stdin,
468
492
  output: process.stdout
@@ -476,18 +500,26 @@ class SessionCoordinator {
476
500
  console.log(` • At the end of each day, your work is automatically merged`);
477
501
  console.log(` • This keeps your target branch (main/develop) up to date`);
478
502
  console.log(` • Prevents accumulation of stale feature branches`);
503
+ console.log();
504
+ console.log(`${CONFIG.colors.bright}Options:${CONFIG.colors.reset}`);
505
+ console.log(` ${CONFIG.colors.green}Y${CONFIG.colors.reset}) Yes - Enable for this session only`);
506
+ console.log(` ${CONFIG.colors.red}N${CONFIG.colors.reset}) No - Disable for this session`);
507
+ console.log(` ${CONFIG.colors.blue}A${CONFIG.colors.reset}) Always - Enable and remember for all sessions (24x7 operation)`);
479
508
 
480
509
  // Ask if they want auto-merge
481
- const autoMerge = await new Promise((resolve) => {
482
- rl.question('\nEnable auto-merge at end of day? (y/N): ', (answer) => {
483
- resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
510
+ const answer = await new Promise((resolve) => {
511
+ rl.question('\nEnable auto-merge? (Y/N/A) [N]: ', (ans) => {
512
+ resolve(ans.trim().toLowerCase());
484
513
  });
485
514
  });
486
515
 
516
+ const autoMerge = answer === 'y' || answer === 'yes' || answer === 'a' || answer === 'always';
517
+ const alwaysAutoMerge = answer === 'a' || answer === 'always';
518
+
487
519
  if (!autoMerge) {
488
520
  rl.close();
489
521
  console.log(`${CONFIG.colors.dim}Auto-merge disabled. You'll need to manually merge your work.${CONFIG.colors.reset}`);
490
- return { autoMerge: false };
522
+ return { autoMerge: false, alwaysEnabled: false };
491
523
  }
492
524
 
493
525
  // Get available branches
@@ -549,12 +581,23 @@ class SessionCoordinator {
549
581
  autoMerge: true,
550
582
  targetBranch,
551
583
  strategy,
552
- requireTests: strategy !== 'pull-request'
584
+ requireTests: strategy !== 'pull-request',
585
+ alwaysEnabled: alwaysAutoMerge
553
586
  };
554
587
 
555
588
  console.log(`\n${CONFIG.colors.green}✓${CONFIG.colors.reset} Auto-merge configuration saved:`);
556
589
  console.log(` ${CONFIG.colors.bright}Today's work${CONFIG.colors.reset} → ${CONFIG.colors.bright}${targetBranch}${CONFIG.colors.reset}`);
557
590
  console.log(` Strategy: ${CONFIG.colors.bright}${strategy}${CONFIG.colors.reset}`);
591
+
592
+ if (alwaysAutoMerge) {
593
+ console.log(` ${CONFIG.colors.blue}Mode: Always enabled${CONFIG.colors.reset} (24x7 operation - auto rollover)`);
594
+ // Save to project settings
595
+ projectSettings.autoMergeConfig = config;
596
+ this.saveProjectSettings(projectSettings);
597
+ } else {
598
+ console.log(` ${CONFIG.colors.dim}Mode: This session only${CONFIG.colors.reset}`);
599
+ }
600
+
558
601
  console.log(`${CONFIG.colors.dim} (Daily branches will be merged into ${targetBranch} at end of day)${CONFIG.colors.reset}`);
559
602
 
560
603
  return config;
@@ -677,6 +720,7 @@ class SessionCoordinator {
677
720
  // Ensure both global and project setup are complete
678
721
  await this.ensureGlobalSetup(); // Developer initials (once per user)
679
722
  await this.ensureProjectSetup(); // Version strategy (once per project)
723
+ await this.ensureHouseRulesSetup(); // House rules setup (once per project)
680
724
 
681
725
  const sessionId = this.generateSessionId();
682
726
  const task = options.task || 'development';
@@ -702,7 +746,7 @@ class SessionCoordinator {
702
746
  if (dockerInfo.hasCompose) {
703
747
  console.log(`${CONFIG.colors.dim}Found docker-compose files:${CONFIG.colors.reset}`);
704
748
  dockerInfo.composeFiles.forEach(file => {
705
- console.log(` • ${file.name}`);
749
+ console.log(` • ${file.name} ${CONFIG.colors.dim}(in ${file.location})${CONFIG.colors.reset}`);
706
750
  });
707
751
  }
708
752
 
@@ -711,12 +755,78 @@ class SessionCoordinator {
711
755
  }
712
756
 
713
757
  dockerConfig = await this.promptForDockerConfig();
758
+ } else {
759
+ // No Docker configuration found - prompt user
760
+ const rl = readline.createInterface({
761
+ input: process.stdin,
762
+ output: process.stdout
763
+ });
764
+
765
+ console.log(`\n${CONFIG.colors.yellow}No Docker Configuration Found${CONFIG.colors.reset}`);
766
+ console.log(`${CONFIG.colors.dim}I couldn't find any docker-compose files in:${CONFIG.colors.reset}`);
767
+ console.log(`${CONFIG.colors.dim} • Project directory${CONFIG.colors.reset}`);
768
+ console.log(`${CONFIG.colors.dim} • Parent directory${CONFIG.colors.reset}`);
769
+ console.log(`${CONFIG.colors.dim} • Parent/Infrastructure or parent/infrastructure${CONFIG.colors.reset}`);
770
+
771
+ const hasDocker = await new Promise((resolve) => {
772
+ rl.question(`\nDo you have a Docker setup you'd like to configure? (y/N): `, (answer) => {
773
+ resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
774
+ });
775
+ });
776
+
777
+ if (hasDocker) {
778
+ const dockerPath = await new Promise((resolve) => {
779
+ rl.question(`\nEnter the full path to your docker-compose file: `, (answer) => {
780
+ resolve(answer.trim());
781
+ });
782
+ });
783
+
784
+ if (dockerPath && fs.existsSync(dockerPath)) {
785
+ console.log(`${CONFIG.colors.green}✓${CONFIG.colors.reset} Found docker-compose file at: ${dockerPath}`);
786
+
787
+ // Ask about rebuild and service preferences
788
+ const rebuild = await new Promise((resolve) => {
789
+ rl.question('\nRebuild containers on restart? (y/N): ', (answer) => {
790
+ resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
791
+ });
792
+ });
793
+
794
+ const specificService = await new Promise((resolve) => {
795
+ rl.question('\nSpecific service to restart (leave empty for all): ', (answer) => {
796
+ resolve(answer.trim() || null);
797
+ });
798
+ });
799
+
800
+ dockerConfig = {
801
+ enabled: true,
802
+ composeFile: dockerPath,
803
+ rebuild: rebuild,
804
+ service: specificService,
805
+ forceRecreate: false
806
+ };
807
+
808
+ console.log(`\n${CONFIG.colors.green}✓${CONFIG.colors.reset} Docker restart configuration:`);
809
+ console.log(` ${CONFIG.colors.bright}Auto-restart:${CONFIG.colors.reset} Enabled`);
810
+ console.log(` ${CONFIG.colors.bright}Compose file:${CONFIG.colors.reset} ${path.basename(dockerPath)}`);
811
+ console.log(` ${CONFIG.colors.bright}Rebuild:${CONFIG.colors.reset} ${rebuild ? 'Yes' : 'No'}`);
812
+ if (specificService) {
813
+ console.log(` ${CONFIG.colors.bright}Service:${CONFIG.colors.reset} ${specificService}`);
814
+ }
815
+ } else if (dockerPath) {
816
+ console.log(`${CONFIG.colors.red}✗${CONFIG.colors.reset} File not found: ${dockerPath}`);
817
+ console.log(`${CONFIG.colors.dim}Skipping Docker configuration${CONFIG.colors.reset}`);
818
+ }
819
+ } else {
820
+ console.log(`${CONFIG.colors.dim}Skipping Docker configuration${CONFIG.colors.reset}`);
821
+ }
822
+
823
+ rl.close();
714
824
  }
715
825
 
716
- // Create worktree with developer initials in the name
717
- const worktreeName = `${agentType}-${devInitials}-${sessionId}-${task.replace(/\s+/g, '-')}`;
826
+ // Create worktree with developer initials first in the name
827
+ const worktreeName = `${devInitials}-${agentType}-${sessionId}-${task.replace(/\s+/g, '-')}`;
718
828
  const worktreePath = path.join(this.worktreesPath, worktreeName);
719
- const branchName = `${agentType}/${devInitials}/${sessionId}/${task.replace(/\s+/g, '-')}`;
829
+ const branchName = `${devInitials}/${agentType}/${sessionId}/${task.replace(/\s+/g, '-')}`;
720
830
 
721
831
  try {
722
832
  // Detect if we're in a submodule and get the parent repository
@@ -970,6 +1080,34 @@ The DevOps agent will automatically:
970
1080
  * Create configuration in the worktree
971
1081
  */
972
1082
  createWorktreeConfig(worktreePath, sessionData) {
1083
+ // Create file coordination directory structure
1084
+ const fileCoordDir = path.join(worktreePath, '.file-coordination');
1085
+ const activeEditsDir = path.join(fileCoordDir, 'active-edits');
1086
+ const historyDir = path.join(fileCoordDir, 'history');
1087
+
1088
+ // Create directories if they don't exist
1089
+ [fileCoordDir, activeEditsDir, historyDir].forEach(dir => {
1090
+ if (!fs.existsSync(dir)) {
1091
+ fs.mkdirSync(dir, { recursive: true });
1092
+ }
1093
+ });
1094
+
1095
+ // Create README for file coordination
1096
+ const coordReadme = `# File Coordination System
1097
+
1098
+ This directory manages multi-agent file access coordination.
1099
+
1100
+ ## Structure
1101
+ - \`active-edits/\` - Current file locks by agents
1102
+ - \`history/\` - Completed edits log
1103
+
1104
+ ## Usage
1105
+ Agents must declare files before editing by creating a JSON file in active-edits/.
1106
+ See house rules for details.
1107
+ `;
1108
+ fs.writeFileSync(path.join(fileCoordDir, 'README.md'), coordReadme);
1109
+ console.log(`${CONFIG.colors.green}✓${CONFIG.colors.reset} Created file coordination directory structure`);
1110
+
973
1111
  // Session config file
974
1112
  const configPath = path.join(worktreePath, '.devops-session.json');
975
1113
  fs.writeFileSync(configPath, JSON.stringify(sessionData, null, 2));
@@ -991,7 +1129,7 @@ The DevOps agent will automatically:
991
1129
  'DEVOPS_WORKTREE': path.basename(worktreePath),
992
1130
  'DEVOPS_BRANCH': sessionData.branchName,
993
1131
  'AC_MSG_FILE': `.devops-commit-${sessionData.sessionId}.msg`,
994
- 'AC_BRANCH_PREFIX': `${sessionData.agentType}_${sessionData.sessionId}_`
1132
+ 'AC_BRANCH_PREFIX': `${sessionData.developerInitials || 'dev'}_${sessionData.agentType}_${sessionData.sessionId}_`
995
1133
  }
996
1134
  };
997
1135
 
@@ -1165,12 +1303,12 @@ The DevOps agent is monitoring this worktree for changes.
1165
1303
  ...process.env,
1166
1304
  DEVOPS_SESSION_ID: sessionId,
1167
1305
  AC_MSG_FILE: `.devops-commit-${sessionId}.msg`,
1168
- AC_BRANCH_PREFIX: `${sessionData.agentType}_${devInitials}_${sessionId}_`,
1306
+ AC_BRANCH_PREFIX: `${devInitials}_${sessionData.agentType}_${sessionId}_`,
1169
1307
  AC_WORKING_DIR: sessionData.worktreePath,
1170
1308
  // Don't set AC_BRANCH - let the agent create daily branches within the worktree
1171
1309
  // AC_BRANCH would force a static branch, preventing daily/weekly rollover
1172
1310
  AC_PUSH: 'true', // Enable auto-push for session branches
1173
- AC_DAILY_PREFIX: `${sessionData.agentType}_${devInitials}_${sessionId}_`, // Daily branches with dev initials
1311
+ AC_DAILY_PREFIX: `${devInitials}_${sessionData.agentType}_${sessionId}_`, // Daily branches with dev initials first
1174
1312
  AC_TZ: process.env.AC_TZ || 'Asia/Dubai', // Preserve timezone for daily branches
1175
1313
  AC_DATE_STYLE: process.env.AC_DATE_STYLE || 'dash', // Preserve date style
1176
1314
  // Apply version configuration if set