104 lines
4.6 KiB
TypeScript
104 lines
4.6 KiB
TypeScript
import * as fs from 'fs-extra';
|
|
import * as path from 'path';
|
|
import * as os from 'os';
|
|
import { GlobalConfig, WorkspaceConfig, WorkspaceInfo } from '../types/index';
|
|
import { GitAgentSyncError } from './errors';
|
|
|
|
const GLOBAL_CONFIG_DIR = '.git-agent-sync';
|
|
const GLOBAL_CONFIG_FILE = 'config.json';
|
|
const WORKSPACE_CONFIG_FILE = '.agent-workspace.json';
|
|
|
|
export function getGlobalConfigDir(): string {
|
|
return process.env.GIT_AGENT_SYNC_CONFIG ? path.dirname(process.env.GIT_AGENT_SYNC_CONFIG) : path.join(os.homedir(), GLOBAL_CONFIG_DIR);
|
|
}
|
|
export function getGlobalConfigPath(): string {
|
|
return process.env.GIT_AGENT_SYNC_CONFIG || path.join(getGlobalConfigDir(), GLOBAL_CONFIG_FILE);
|
|
}
|
|
export async function loadGlobalConfig(): Promise<GlobalConfig> {
|
|
const configPath = getGlobalConfigPath();
|
|
if (await fs.pathExists(configPath)) {
|
|
const config = await fs.readJson(configPath);
|
|
return { ...getDefaultGlobalConfig(), ...config };
|
|
}
|
|
return getDefaultGlobalConfig();
|
|
}
|
|
export function getDefaultGlobalConfig(): GlobalConfig {
|
|
return { workspacePath: process.env.GIT_AGENT_SYNC_PATH || './.agent-workspaces', defaultBranch: 'main', autoInstall: process.env.GIT_AGENT_SYNC_AUTO_INSTALL !== 'false', templates: { default: process.env.GIT_AGENT_SYNC_TEMPLATE || path.join(os.homedir(), GLOBAL_CONFIG_DIR, 'templates', 'default') } };
|
|
}
|
|
export async function saveGlobalConfig(config: GlobalConfig): Promise<void> {
|
|
await fs.ensureDir(getGlobalConfigDir());
|
|
await fs.writeJson(getGlobalConfigPath(), config, { spaces: 2 });
|
|
}
|
|
export function getWorkspacePath(basePath: string, agentName: string): string {
|
|
return path.join(basePath, '.agent-workspaces', `agent-${agentName}`);
|
|
}
|
|
export async function loadWorkspaceConfig(workspacePath: string): Promise<WorkspaceConfig | null> {
|
|
const configPath = path.join(workspacePath, WORKSPACE_CONFIG_FILE);
|
|
if (await fs.pathExists(configPath)) {
|
|
return fs.readJson(configPath);
|
|
}
|
|
return null;
|
|
}
|
|
export async function saveWorkspaceConfig(workspacePath: string, config: WorkspaceConfig): Promise<void> {
|
|
const configPath = path.join(workspacePath, WORKSPACE_CONFIG_FILE);
|
|
await fs.writeJson(configPath, config, { spaces: 2 });
|
|
}
|
|
export async function getAllWorkspaces(basePath: string): Promise<WorkspaceInfo[]> {
|
|
const workspaceRoot = path.join(basePath, '.agent-workspaces');
|
|
if (!await fs.pathExists(workspaceRoot)) return [];
|
|
const entries = await fs.readdir(workspaceRoot);
|
|
const workspaces: WorkspaceInfo[] = [];
|
|
for (const entry of entries) {
|
|
if (entry.startsWith('agent-')) {
|
|
const workspacePath = path.join(workspaceRoot, entry);
|
|
const stat = await fs.stat(workspacePath);
|
|
if (stat.isDirectory()) {
|
|
workspaces.push({ name: entry, path: workspacePath, branch: entry, exists: true, hasChanges: false, changeCount: 0 });
|
|
}
|
|
}
|
|
}
|
|
return workspaces;
|
|
}
|
|
export function sanitizeAgentName(name: string): string {
|
|
return name.toLowerCase().replace(/[^a-z0-9-]/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '');
|
|
}
|
|
export function isValidAgentName(name: string): boolean {
|
|
return /^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$/.test(name) && name.length >= 1 && name.length <= 100;
|
|
}
|
|
export async function isGitRepository(basePath: string): Promise<boolean> {
|
|
try {
|
|
await fs.access(path.join(basePath, '.git'), fs.constants.R_OK);
|
|
return true;
|
|
} catch { return false; }
|
|
}
|
|
export async function hasUncommittedChanges(workspacePath: string): Promise<boolean> {
|
|
const { execa } = await import('execa');
|
|
try {
|
|
const result = await execa('git', ['status', '--porcelain'], { cwd: workspacePath });
|
|
return result.stdout.trim().length > 0;
|
|
} catch { return false; }
|
|
}
|
|
export async function detectPackageJson(workspacePath: string): Promise<boolean> {
|
|
return fs.pathExists(path.join(workspacePath, 'package.json'));
|
|
}
|
|
export async function installDependencies(workspacePath: string): Promise<void> {
|
|
const { execa } = await import('execa');
|
|
await execa('npm', ['install'], { cwd: workspacePath });
|
|
}
|
|
export async function readPackageJson(workspacePath: string): Promise<{ scripts?: Record<string, string> } | null> {
|
|
const pkgPath = path.join(workspacePath, 'package.json');
|
|
if (await fs.pathExists(pkgPath)) {
|
|
return fs.readJson(pkgPath);
|
|
}
|
|
return null;
|
|
}
|
|
export async function getGitUserInfo(): Promise<{ name: string; email: string }> {
|
|
const { execa } = await import('execa');
|
|
try {
|
|
const nameResult = await execa('git', ['config', 'user.name']);
|
|
const emailResult = await execa('git', ['config', 'user.email']);
|
|
return { name: nameResult.stdout.trim(), email: emailResult.stdout.trim() };
|
|
} catch {
|
|
return { name: 'Unknown', email: 'unknown@example.com' };
|
|
}
|
|
} |