import { SSHManager } from './ssh-manager.js'
import chalk from 'chalk'
export class GitSyncManager {
constructor(agentConfigs, options = {}) {
this.agents = agentConfigs
this.bareRepoPath = options.bareRepoPath || '/home/fleeky/git-repos/hypercore-kb.git'
this.sshManagers = new Map()
// Initialize SSH managers
for (const config of agentConfigs) {
this.sshManagers.set(config.name, new SSHManager(config))
}
}
async connect() {
console.log(chalk.blue('🔌 Connecting to agents...\n'))
for (const manager of this.sshManagers.values()) {
await manager.connect()
}
}
async syncAll() {
console.log(chalk.blue('\n📦 Starting git sync...\n'))
// Step 1: Check tabertron has clean working directory
await this.verifyCleanWorkingDir('tabertron')
// Step 2: Push from tabertron to bare repo
await this.pushToBareRepo('tabertron')
// Step 3: Pull on all other agents
for (const agent of this.agents) {
if (agent.name !== 'tabertron') {
await this.pullFromRemote(agent.name)
}
}
// Step 4: Verify all agents are on same commit
await this.verifySync()
console.log(chalk.green('\n✅ Git sync complete!\n'))
}
async verifyCleanWorkingDir(agentName) {
const manager = this.sshManagers.get(agentName)
// Use parent directory (hypercore-kb) not subdirectory (hyper-fleeky)
const workDir = manager.config.workDir.replace('/hyper-fleeky', '')
console.log(chalk.cyan(`📋 Checking ${agentName} working directory...`))
const result = await manager.exec(`cd ${workDir} && git status --porcelain`)
if (result.stdout.trim() !== '') {
console.log(chalk.yellow(`⚠️ ${agentName} has uncommitted changes:`))
console.log(result.stdout)
throw new Error(
`${agentName} has uncommitted changes. Please commit or stash first.\n` +
`Run: cd ${workDir} && git status`
)
}
console.log(chalk.green(`✅ ${agentName} working directory is clean`))
}
async pushToBareRepo(agentName) {
const manager = this.sshManagers.get(agentName)
// Use parent directory (hypercore-kb) not subdirectory (hyper-fleeky)
const workDir = manager.config.workDir.replace('/hyper-fleeky', '')
console.log(chalk.cyan(`📤 Pushing from ${agentName} to bare repo...`))
// Get current branch
const branchResult = await manager.exec(`cd ${workDir} && git rev-parse --abbrev-ref HEAD`)
const branch = branchResult.stdout.trim()
// Push to bare repo
const result = await manager.exec(
`cd ${workDir} && git push ${this.bareRepoPath} ${branch}:master 2>&1`
)
if (result.exitCode !== 0 && !result.stdout.includes('Everything up-to-date')) {
throw new Error(`Git push failed on ${agentName}:\n${result.stderr || result.stdout}`)
}
console.log(chalk.green(`✅ Pushed from ${agentName}`))
}
async pullFromRemote(agentName) {
const manager = this.sshManagers.get(agentName)
// Use parent directory (hypercore-kb) not subdirectory (hyper-fleeky)
const workDir = manager.config.workDir.replace('/hyper-fleeky', '')
console.log(chalk.cyan(`📥 Pulling on ${agentName}...`))
// Pull from remote (origin)
const result = await manager.exec(
`cd ${workDir} && git fetch origin && git reset --hard origin/master 2>&1`
)
if (result.exitCode !== 0) {
throw new Error(`Git pull failed on ${agentName}:\n${result.stderr || result.stdout}`)
}
console.log(chalk.green(`✅ Pulled on ${agentName}`))
}
async verifySync() {
console.log(chalk.cyan('\n🔍 Verifying all agents on same commit...\n'))
const commits = new Map()
// Get commit hash from each agent
for (const agent of this.agents) {
const manager = this.sshManagers.get(agent.name)
// Use parent directory (hypercore-kb) not subdirectory (hyper-fleeky)
const workDir = manager.config.workDir.replace('/hyper-fleeky', '')
const result = await manager.exec(`cd ${workDir} && git rev-parse HEAD`)
const commit = result.stdout.trim()
commits.set(agent.name, commit)
console.log(` ${agent.name}: ${commit.substring(0, 8)}`)
}
// Check all commits match
const commitHashes = Array.from(commits.values())
const allMatch = commitHashes.every(c => c === commitHashes[0])
if (!allMatch) {
console.log(chalk.red('\n❌ Agents are on different commits!'))
for (const [name, commit] of commits) {
console.log(` ${name}: ${commit}`)
}
throw new Error('Git sync verification failed - agents on different commits')
}
console.log(chalk.green('\n✅ All agents on same commit\n'))
}
async disconnect() {
for (const manager of this.sshManagers.values()) {
await manager.disconnect()
}
}
}