s9n-devops-agent 1.2.0 → 1.3.1

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.
@@ -19,12 +19,12 @@
19
19
 
20
20
  import fs from 'fs';
21
21
  import path from 'path';
22
- import { execSync, spawn } from 'child_process';
22
+ import { fileURLToPath } from 'url';
23
+ import { dirname } from 'path';
24
+ import { execSync, spawn, fork } from 'child_process';
23
25
  import crypto from 'crypto';
24
26
  import readline from 'readline';
25
27
  import { hasDockerConfiguration } from './docker-utils.js';
26
- import crypto from 'crypto';
27
- import readline from 'readline';
28
28
 
29
29
  const __filename = fileURLToPath(import.meta.url);
30
30
  const __dirname = dirname(__filename);
@@ -461,7 +461,13 @@ class SessionCoordinator {
461
461
  });
462
462
 
463
463
  console.log(`\n${CONFIG.colors.yellow}═══ Auto-merge Configuration ═══${CONFIG.colors.reset}`);
464
- console.log(`${CONFIG.colors.dim}(Automatically merge today's work into a target branch)${CONFIG.colors.reset}`);
464
+ console.log(`${CONFIG.colors.dim}Automatically merge your daily work branches into a target branch.${CONFIG.colors.reset}`);
465
+ console.log();
466
+ console.log(`${CONFIG.colors.bright}How it works:${CONFIG.colors.reset}`);
467
+ console.log(` • The agent creates dated branches (e.g., ${CONFIG.colors.blue}agent_dev_2025-10-01${CONFIG.colors.reset})`);
468
+ console.log(` • At the end of each day, your work is automatically merged`);
469
+ console.log(` • This keeps your target branch (main/develop) up to date`);
470
+ console.log(` • Prevents accumulation of stale feature branches`);
465
471
 
466
472
  // Ask if they want auto-merge
467
473
  const autoMerge = await new Promise((resolve) => {
@@ -784,6 +790,28 @@ INSTRUCTIONS:
784
790
  - **Worktree Path:** \`${worktreePath}\`
785
791
  - **Branch:** \`${branchName}\`
786
792
 
793
+ ## 🚨 CRITICAL: File Coordination Protocol
794
+
795
+ **BEFORE editing any files, you MUST:**
796
+
797
+ 1. **Declare your intent** by creating:
798
+ \`\`\`json
799
+ // File: .file-coordination/active-edits/<agent>-${sessionId}.json
800
+ {
801
+ "agent": "<your-name>",
802
+ "session": "${sessionId}",
803
+ "files": ["list", "files", "to", "edit"],
804
+ "operation": "edit",
805
+ "reason": "${task}",
806
+ "declaredAt": "<ISO-8601-timestamp>",
807
+ "estimatedDuration": 300
808
+ }
809
+ \`\`\`
810
+
811
+ 2. **Check for conflicts** - read all files in \`.file-coordination/active-edits/\`
812
+ 3. **Only proceed if no conflicts** - wait or choose different files if blocked
813
+ 4. **Release files when done** - delete your declaration after edits
814
+
787
815
  ## Instructions for Claude/Cline
788
816
 
789
817
  ### Step 1: Navigate to Your Worktree
@@ -797,18 +825,25 @@ git branch --show-current
797
825
  # Should output: ${branchName}
798
826
  \`\`\`
799
827
 
800
- ### Step 3: Work on Your Task
828
+ ### Step 3: Declare Files Before Editing
829
+ Create your declaration in \`.file-coordination/active-edits/\`
830
+
831
+ ### Step 4: Work on Your Task
801
832
  Make changes for: **${task}**
802
833
 
803
- ### Step 4: Commit Your Changes
834
+ ### Step 5: Commit Your Changes
804
835
  Write your commit message to the session-specific file:
805
836
  \`\`\`bash
806
837
  echo "feat: your commit message here" > .devops-commit-${sessionId}.msg
807
838
  \`\`\`
808
839
 
809
- ### Step 5: Automatic Processing
840
+ ### Step 6: Release Your File Locks
841
+ Delete your declaration from \`.file-coordination/active-edits/\`
842
+
843
+ ### Step 7: Automatic Processing
810
844
  The DevOps agent will automatically:
811
845
  - Detect your changes
846
+ - Check for coordination conflicts
812
847
  - Read your commit message
813
848
  - Commit and push to the remote repository
814
849
  - Clear the message file
@@ -853,11 +888,21 @@ The DevOps agent will automatically:
853
888
  console.log(`- Working Directory: ${instructions.worktreePath}`);
854
889
  console.log(`- Task: ${task || 'development'}`);
855
890
  console.log(``);
856
- console.log(`Please switch to this directory before making any changes:`);
857
- console.log(`cd "${instructions.worktreePath}"`);
891
+ console.log(`CRITICAL FIRST STEP:`);
892
+ console.log(`1. Read and follow the house rules: cat "${instructions.worktreePath}/houserules.md"`);
893
+ console.log(`2. Switch to the working directory: cd "${instructions.worktreePath}"`);
894
+ console.log(``);
895
+ console.log(`FILE COORDINATION PROTOCOL (from house rules at ${instructions.worktreePath}/houserules.md):`);
896
+ console.log(`Before editing ANY files, you MUST:`);
897
+ console.log(`- Declare your intent in .file-coordination/active-edits/<agent>-${sessionId}.json`);
898
+ console.log(`- Check for conflicts with other agents`);
899
+ console.log(`- Only edit files you've declared`);
900
+ console.log(`- Release files when done`);
858
901
  console.log(``);
859
902
  console.log(`Write commit messages to: .devops-commit-${sessionId}.msg`);
860
903
  console.log(`The DevOps agent will automatically commit and push changes.`);
904
+ console.log(``);
905
+ console.log(`Remember: ALWAYS check house rules first for the latest protocols!`);
861
906
  console.log();
862
907
 
863
908
  console.log(`${CONFIG.colors.yellow}══════════════════════════════════════════════════════════════${CONFIG.colors.reset}`);
@@ -1185,6 +1230,215 @@ The DevOps agent is monitoring this worktree for changes.
1185
1230
 
1186
1231
  return session;
1187
1232
  }
1233
+
1234
+ /**
1235
+ * Close a specific session
1236
+ */
1237
+ async closeSession(sessionId) {
1238
+ const lockFile = path.join(this.locksPath, `${sessionId}.lock`);
1239
+
1240
+ if (!fs.existsSync(lockFile)) {
1241
+ console.error(`${CONFIG.colors.red}Session not found: ${sessionId}${CONFIG.colors.reset}`);
1242
+ return false;
1243
+ }
1244
+
1245
+ const session = JSON.parse(fs.readFileSync(lockFile, 'utf8'));
1246
+ console.log(`\n${CONFIG.colors.yellow}Closing session: ${sessionId}${CONFIG.colors.reset}`);
1247
+ console.log(`${CONFIG.colors.dim}Task: ${session.task}${CONFIG.colors.reset}`);
1248
+ console.log(`${CONFIG.colors.dim}Branch: ${session.branchName}${CONFIG.colors.reset}`);
1249
+
1250
+ // Kill agent if running
1251
+ if (session.agentPid) {
1252
+ try {
1253
+ process.kill(session.agentPid, 'SIGTERM');
1254
+ console.log(`${CONFIG.colors.green}✓${CONFIG.colors.reset} Agent process stopped`);
1255
+ } catch (err) {
1256
+ // Process might already be dead
1257
+ }
1258
+ }
1259
+
1260
+ // Check for uncommitted changes
1261
+ if (fs.existsSync(session.worktreePath)) {
1262
+ try {
1263
+ const status = execSync(`git -C "${session.worktreePath}" status --porcelain`, { encoding: 'utf8' });
1264
+ if (status.trim()) {
1265
+ console.log(`\n${CONFIG.colors.yellow}Warning: Uncommitted changes found${CONFIG.colors.reset}`);
1266
+ console.log(status);
1267
+
1268
+ const rl = readline.createInterface({
1269
+ input: process.stdin,
1270
+ output: process.stdout
1271
+ });
1272
+
1273
+ const answer = await new Promise(resolve => {
1274
+ rl.question('Commit these changes before closing? (y/N): ', resolve);
1275
+ });
1276
+ rl.close();
1277
+
1278
+ if (answer.toLowerCase() === 'y') {
1279
+ execSync(`git -C "${session.worktreePath}" add -A`, { stdio: 'pipe' });
1280
+ execSync(`git -C "${session.worktreePath}" commit -m "chore: final session cleanup for ${sessionId}"`, { stdio: 'pipe' });
1281
+ execSync(`git -C "${session.worktreePath}" push origin ${session.branchName}`, { stdio: 'pipe' });
1282
+ console.log(`${CONFIG.colors.green}✓${CONFIG.colors.reset} Changes committed and pushed`);
1283
+ }
1284
+ }
1285
+ } catch (err) {
1286
+ console.log(`${CONFIG.colors.dim}Could not check git status${CONFIG.colors.reset}`);
1287
+ }
1288
+
1289
+ // Ask about removing worktree
1290
+ const rl = readline.createInterface({
1291
+ input: process.stdin,
1292
+ output: process.stdout
1293
+ });
1294
+
1295
+ const removeWorktree = await new Promise(resolve => {
1296
+ rl.question(`\nRemove worktree at ${session.worktreePath}? (Y/n): `, resolve);
1297
+ });
1298
+ rl.close();
1299
+
1300
+ if (removeWorktree.toLowerCase() !== 'n') {
1301
+ try {
1302
+ // Remove worktree
1303
+ execSync(`git worktree remove "${session.worktreePath}" --force`, { stdio: 'pipe' });
1304
+ console.log(`${CONFIG.colors.green}✓${CONFIG.colors.reset} Worktree removed`);
1305
+
1306
+ // Prune worktree list
1307
+ execSync('git worktree prune', { stdio: 'pipe' });
1308
+ } catch (err) {
1309
+ console.error(`${CONFIG.colors.red}Failed to remove worktree: ${err.message}${CONFIG.colors.reset}`);
1310
+ }
1311
+ }
1312
+ }
1313
+
1314
+ // Remove lock file
1315
+ fs.unlinkSync(lockFile);
1316
+ console.log(`${CONFIG.colors.green}✓${CONFIG.colors.reset} Session closed successfully`);
1317
+
1318
+ return true;
1319
+ }
1320
+
1321
+ /**
1322
+ * Interactive session selection and close
1323
+ */
1324
+ async selectAndCloseSession() {
1325
+ if (!fs.existsSync(this.locksPath)) {
1326
+ console.log(`${CONFIG.colors.yellow}No active sessions${CONFIG.colors.reset}`);
1327
+ return;
1328
+ }
1329
+
1330
+ const locks = fs.readdirSync(this.locksPath);
1331
+ if (locks.length === 0) {
1332
+ console.log(`${CONFIG.colors.yellow}No active sessions${CONFIG.colors.reset}`);
1333
+ return;
1334
+ }
1335
+
1336
+ const sessions = [];
1337
+ locks.forEach(lockFile => {
1338
+ const lockPath = path.join(this.locksPath, lockFile);
1339
+ const session = JSON.parse(fs.readFileSync(lockPath, 'utf8'));
1340
+ sessions.push(session);
1341
+ });
1342
+
1343
+ console.log(`\n${CONFIG.colors.bright}Select session to close:${CONFIG.colors.reset}\n`);
1344
+
1345
+ sessions.forEach((session, index) => {
1346
+ const status = session.status === 'active' ?
1347
+ `${CONFIG.colors.green}●${CONFIG.colors.reset}` :
1348
+ `${CONFIG.colors.yellow}○${CONFIG.colors.reset}`;
1349
+
1350
+ console.log(`${status} ${CONFIG.colors.bright}${index + 1})${CONFIG.colors.reset} ${session.sessionId}`);
1351
+ console.log(` Task: ${session.task}`);
1352
+ console.log(` Branch: ${session.branchName}`);
1353
+ console.log(` Created: ${session.created}`);
1354
+ console.log();
1355
+ });
1356
+
1357
+ const rl = readline.createInterface({
1358
+ input: process.stdin,
1359
+ output: process.stdout
1360
+ });
1361
+
1362
+ const answer = await new Promise(resolve => {
1363
+ rl.question(`Select session (1-${sessions.length}) or 'q' to quit: `, resolve);
1364
+ });
1365
+ rl.close();
1366
+
1367
+ if (answer.toLowerCase() === 'q') {
1368
+ return;
1369
+ }
1370
+
1371
+ const index = parseInt(answer) - 1;
1372
+ if (index >= 0 && index < sessions.length) {
1373
+ await this.closeSession(sessions[index].sessionId);
1374
+ } else {
1375
+ console.log(`${CONFIG.colors.red}Invalid selection${CONFIG.colors.reset}`);
1376
+ }
1377
+ }
1378
+
1379
+ /**
1380
+ * Clean up all stale sessions and worktrees
1381
+ */
1382
+ async cleanupAll() {
1383
+ console.log(`\n${CONFIG.colors.yellow}Cleaning up stale sessions and worktrees...${CONFIG.colors.reset}`);
1384
+
1385
+ // Clean up old lock files (older than 24 hours)
1386
+ const oneDayAgo = Date.now() - 86400000;
1387
+ let cleanedLocks = 0;
1388
+
1389
+ if (fs.existsSync(this.locksPath)) {
1390
+ const locks = fs.readdirSync(this.locksPath);
1391
+ locks.forEach(lockFile => {
1392
+ const lockPath = path.join(this.locksPath, lockFile);
1393
+ const stats = fs.statSync(lockPath);
1394
+ if (stats.mtimeMs < oneDayAgo) {
1395
+ fs.unlinkSync(lockPath);
1396
+ cleanedLocks++;
1397
+ }
1398
+ });
1399
+ }
1400
+
1401
+ if (cleanedLocks > 0) {
1402
+ console.log(`${CONFIG.colors.green}✓${CONFIG.colors.reset} Removed ${cleanedLocks} stale lock files`);
1403
+ }
1404
+
1405
+ // Prune git worktrees
1406
+ try {
1407
+ execSync('git worktree prune', { stdio: 'pipe' });
1408
+ console.log(`${CONFIG.colors.green}✓${CONFIG.colors.reset} Pruned git worktrees`);
1409
+ } catch (err) {
1410
+ console.log(`${CONFIG.colors.dim}Could not prune worktrees${CONFIG.colors.reset}`);
1411
+ }
1412
+
1413
+ // Clean up orphaned worktree directories
1414
+ if (fs.existsSync(this.worktreesPath)) {
1415
+ const worktrees = fs.readdirSync(this.worktreesPath);
1416
+ let cleanedWorktrees = 0;
1417
+
1418
+ for (const dir of worktrees) {
1419
+ const worktreePath = path.join(this.worktreesPath, dir);
1420
+
1421
+ // Check if this worktree is still valid
1422
+ try {
1423
+ execSync(`git worktree list | grep "${worktreePath}"`, { stdio: 'pipe' });
1424
+ } catch (err) {
1425
+ // Worktree not in git list, it's orphaned
1426
+ try {
1427
+ fs.rmSync(worktreePath, { recursive: true, force: true });
1428
+ cleanedWorktrees++;
1429
+ } catch (err) {
1430
+ console.log(`${CONFIG.colors.dim}Could not remove ${dir}${CONFIG.colors.reset}`);
1431
+ }
1432
+ }
1433
+ }
1434
+
1435
+ if (cleanedWorktrees > 0) {
1436
+ console.log(`${CONFIG.colors.green}✓${CONFIG.colors.reset} Removed ${cleanedWorktrees} orphaned worktree directories`);
1437
+ }
1438
+ }
1439
+
1440
+ console.log(`${CONFIG.colors.green}✓${CONFIG.colors.reset} Cleanup complete`);
1441
+ }
1188
1442
  }
1189
1443
 
1190
1444
  // ============================================================================
@@ -1260,13 +1514,31 @@ async function main() {
1260
1514
  break;
1261
1515
  }
1262
1516
 
1263
- case 'list': {
1264
- coordinator.listSessions();
1265
- break;
1517
+ case 'list': {
1518
+ coordinator.listSessions();
1519
+ break;
1520
+ }
1521
+
1522
+ case 'close': {
1523
+ // Close a session and clean up
1524
+ const sessionId = args[1];
1525
+ if (sessionId) {
1526
+ await coordinator.closeSession(sessionId);
1527
+ } else {
1528
+ // Interactive selection
1529
+ await coordinator.selectAndCloseSession();
1266
1530
  }
1267
-
1268
- case 'help':
1269
- default: {
1531
+ break;
1532
+ }
1533
+
1534
+ case 'cleanup': {
1535
+ // Clean up stale sessions and worktrees
1536
+ await coordinator.cleanupAll();
1537
+ break;
1538
+ }
1539
+
1540
+ case 'help':
1541
+ default: {
1270
1542
  console.log(`
1271
1543
  ${CONFIG.colors.bright}DevOps Session Coordinator${CONFIG.colors.reset}
1272
1544
 
@@ -1279,6 +1551,8 @@ ${CONFIG.colors.blue}Commands:${CONFIG.colors.reset}
1279
1551
  ${CONFIG.colors.green}create-and-start${CONFIG.colors.reset} Create session and start agent (all-in-one)
1280
1552
  ${CONFIG.colors.green}request [agent]${CONFIG.colors.reset} Request a session (for Claude to call)
1281
1553
  ${CONFIG.colors.green}list${CONFIG.colors.reset} List all active sessions
1554
+ ${CONFIG.colors.green}close [id]${CONFIG.colors.reset} Close session and clean up worktree
1555
+ ${CONFIG.colors.green}cleanup${CONFIG.colors.reset} Clean up all stale sessions
1282
1556
  ${CONFIG.colors.green}help${CONFIG.colors.reset} Show this help
1283
1557
 
1284
1558
  ${CONFIG.colors.blue}Options:${CONFIG.colors.reset}
@@ -735,7 +735,8 @@ export AC_MSG_MIN_BYTES="20"
735
735
  export AC_DEBOUNCE_MS="1500"
736
736
  export AC_MSG_DEBOUNCE_MS="3000"
737
737
  export AC_CLEAR_MSG_WHEN="push"
738
- export AC_ROLLOVER_PROMPT="true"
738
+ # Daily rollover is automatic - no prompting needed
739
+ export AC_ROLLOVER_PROMPT="false"
739
740
  export AC_DEBUG="false"
740
741
 
741
742
  # Check for debug flag
@@ -784,7 +785,8 @@ AC_MSG_DEBOUNCE_MS=3000
784
785
 
785
786
  # Behavior
786
787
  AC_CLEAR_MSG_WHEN=push
787
- AC_ROLLOVER_PROMPT=true
788
+ # Daily rollover is automatic
789
+ AC_ROLLOVER_PROMPT=false
788
790
  AC_DEBUG=false
789
791
  `;
790
792
 
@@ -826,7 +828,7 @@ function printInstructions(initials) {
826
828
  log.title('🎯 Daily Workflow:');
827
829
  console.log('');
828
830
  console.log(`• Your daily branches will be: ${colors.bright}dev_${initials}_YYYY-MM-DD${colors.reset}`);
829
- console.log('• The worker handles day rollover automatically');
831
+ console.log('• The worker automatically creates new daily branches at midnight');
830
832
  console.log('• Commits require valid conventional format (feat/fix/docs/etc)');
831
833
  console.log('• Message file is cleared after successful push');
832
834
  console.log('');
@@ -237,6 +237,142 @@ select_session() {
237
237
  fi
238
238
  }
239
239
 
240
+ # Function to setup house rules and file coordination
241
+ setup_house_rules() {
242
+ local ROOT="$1"
243
+ local COORD_DIR="$ROOT/.file-coordination"
244
+
245
+ # Check if we need to update existing house rules (even if coordination is set up)
246
+ if [[ -f "$SCRIPT_DIR/src/house-rules-manager.js" ]]; then
247
+ # Check status of house rules
248
+ local STATUS=$(node "$SCRIPT_DIR/src/house-rules-manager.js" status 2>/dev/null || echo '{"needsUpdate": false, "exists": true}')
249
+ local NEEDS_UPDATE=$(echo "$STATUS" | grep -o '"needsUpdate"[[:space:]]*:[[:space:]]*true' || echo "")
250
+ local EXISTS=$(echo "$STATUS" | grep -o '"exists"[[:space:]]*:[[:space:]]*true' || echo "")
251
+
252
+ # Check if house rules were deleted (coordination exists but house rules don't)
253
+ if [[ -d "$COORD_DIR" ]] && [[ -z "$EXISTS" ]]; then
254
+ echo -e "${YELLOW}⚠ House rules file appears to be missing!${NC}"
255
+ echo "The file coordination system is set up, but house rules are gone."
256
+ echo
257
+ echo -n "Recreate house rules? (Y/n): "
258
+ read RECREATE
259
+ if [[ "${RECREATE}" != "n" ]] && [[ "${RECREATE}" != "N" ]]; then
260
+ echo -e "${BLUE}Recreating house rules...${NC}"
261
+ node "$SCRIPT_DIR/src/house-rules-manager.js" update 2>/dev/null
262
+ echo -e "${GREEN}✓ House rules recreated!${NC}"
263
+ echo
264
+ fi
265
+ elif [[ -n "$NEEDS_UPDATE" ]]; then
266
+ echo -e "${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
267
+ echo -e "${BOLD}House Rules Update Available${NC}"
268
+ echo -e "${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
269
+ echo
270
+ echo "The DevOps Agent has updated house rules sections."
271
+ echo "Your custom rules will be preserved."
272
+ echo
273
+ echo -n "Update house rules now? (Y/n): "
274
+ read UPDATE_CHOICE
275
+
276
+ if [[ "${UPDATE_CHOICE}" != "n" ]] && [[ "${UPDATE_CHOICE}" != "N" ]]; then
277
+ echo -e "${BLUE}Updating house rules...${NC}"
278
+ node "$SCRIPT_DIR/src/house-rules-manager.js" update
279
+ echo -e "${GREEN}✓ House rules updated!${NC}"
280
+ echo
281
+ fi
282
+ fi
283
+ fi
284
+
285
+ # Check if coordination system is already set up
286
+ if [[ -d "$COORD_DIR" ]] && [[ -f "$ROOT/check-file-availability.sh" ]]; then
287
+ return 0 # Already set up
288
+ fi
289
+
290
+ echo -e "${YELLOW}═══════════════════════════════════════════════════════════${NC}"
291
+ echo -e "${BOLD}First-time Setup: House Rules & File Coordination${NC}"
292
+ echo -e "${YELLOW}═══════════════════════════════════════════════════════════${NC}"
293
+ echo
294
+ echo "House rules help AI agents understand your project conventions and"
295
+ echo "prevent conflicts when multiple agents work on the same codebase."
296
+ echo
297
+
298
+ # Check for existing house rules
299
+ local HOUSERULES_PATH=""
300
+ local HOUSERULES_FOUND=false
301
+
302
+ if [[ -f "$ROOT/houserules.md" ]]; then
303
+ HOUSERULES_PATH="$ROOT/houserules.md"
304
+ HOUSERULES_FOUND=true
305
+ echo -e "${GREEN}✓${NC} Found existing house rules at: houserules.md"
306
+ elif [[ -f "$ROOT/HOUSERULES.md" ]]; then
307
+ HOUSERULES_PATH="$ROOT/HOUSERULES.md"
308
+ HOUSERULES_FOUND=true
309
+ echo -e "${GREEN}✓${NC} Found existing house rules at: HOUSERULES.md"
310
+ elif [[ -f "$ROOT/.github/HOUSERULES.md" ]]; then
311
+ HOUSERULES_PATH="$ROOT/.github/HOUSERULES.md"
312
+ HOUSERULES_FOUND=true
313
+ echo -e "${GREEN}✓${NC} Found existing house rules at: .github/HOUSERULES.md"
314
+ elif [[ -f "$ROOT/docs/houserules.md" ]]; then
315
+ HOUSERULES_PATH="$ROOT/docs/houserules.md"
316
+ HOUSERULES_FOUND=true
317
+ echo -e "${GREEN}✓${NC} Found existing house rules at: docs/houserules.md"
318
+ else
319
+ echo "No existing house rules found."
320
+ echo
321
+ echo "Would you like to:"
322
+ echo " ${BOLD}1)${NC} Create comprehensive house rules (recommended)"
323
+ echo " ${BOLD}2)${NC} Specify path to existing house rules"
324
+ echo " ${BOLD}3)${NC} Skip for now"
325
+ echo
326
+ echo -n "Your choice [1]: "
327
+ read CHOICE
328
+
329
+ case "${CHOICE:-1}" in
330
+ 1)
331
+ HOUSERULES_PATH="$ROOT/houserules.md"
332
+ HOUSERULES_FOUND=false
333
+ echo -e "${GREEN}✓${NC} Will create comprehensive house rules at: houserules.md"
334
+ ;;
335
+ 2)
336
+ echo -n "Enter path to your house rules (relative to $ROOT): "
337
+ read CUSTOM_PATH
338
+ if [[ -f "$ROOT/$CUSTOM_PATH" ]]; then
339
+ HOUSERULES_PATH="$ROOT/$CUSTOM_PATH"
340
+ HOUSERULES_FOUND=true
341
+ echo -e "${GREEN}✓${NC} Using house rules at: $CUSTOM_PATH"
342
+ else
343
+ echo -e "${YELLOW}File not found. Creating new house rules at: houserules.md${NC}"
344
+ HOUSERULES_PATH="$ROOT/houserules.md"
345
+ HOUSERULES_FOUND=false
346
+ fi
347
+ ;;
348
+ 3)
349
+ echo -e "${YELLOW}⚠ Skipping house rules setup${NC}"
350
+ echo "You can set them up later by running: ./scripts/setup-file-coordination.sh"
351
+ return 0
352
+ ;;
353
+ esac
354
+ fi
355
+
356
+ echo
357
+ echo -e "${BLUE}Setting up file coordination system...${NC}"
358
+
359
+ # Run the actual setup inline (simplified version)
360
+ if [[ -f "$SCRIPT_DIR/scripts/setup-file-coordination.sh" ]]; then
361
+ bash "$SCRIPT_DIR/scripts/setup-file-coordination.sh"
362
+ else
363
+ # Inline setup if script doesn't exist
364
+ mkdir -p "$COORD_DIR/active-edits" "$COORD_DIR/completed-edits"
365
+ echo -e "${GREEN}✓${NC} File coordination directories created"
366
+ fi
367
+
368
+ echo
369
+ echo -e "${GREEN}✓ Setup complete!${NC} AI agents will now follow house rules and coordinate file edits."
370
+ echo
371
+ echo -e "${DIM}Press Enter to continue...${NC}"
372
+ read -r
373
+ echo
374
+ }
375
+
240
376
  # Main function
241
377
  main() {
242
378
  # Show copyright first
@@ -256,6 +392,9 @@ main() {
256
392
  REPO_ROOT=$(git rev-parse --show-toplevel)
257
393
  cd "$REPO_ROOT"
258
394
 
395
+ # Check and setup house rules on first run
396
+ setup_house_rules "$REPO_ROOT"
397
+
259
398
  echo -e "${BOLD}Welcome to DevOps Agent Session Manager${NC}"
260
399
  echo
261
400
  echo "This tool will:"