vibetunnel
Version:
Terminal sharing server with web interface - supports macOS, Linux, and headless environments
633 lines • 82 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.createWorktreeRoutes = createWorktreeRoutes;
const express_1 = require("express");
const path = __importStar(require("path"));
const util_1 = require("util");
const git_error_js_1 = require("../utils/git-error.js");
const git_hooks_js_1 = require("../utils/git-hooks.js");
const logger_js_1 = require("../utils/logger.js");
const control_protocol_js_1 = require("../websocket/control-protocol.js");
const control_unix_handler_js_1 = require("../websocket/control-unix-handler.js");
const logger = (0, logger_js_1.createLogger)('worktree-routes');
const execFile = (0, util_1.promisify)(require('child_process').execFile);
/**
* Execute a git command with proper error handling and security
* @param args Git command arguments
* @param options Execution options
* @returns Command output
*/
async function execGit(args, options = {}) {
try {
const { stdout, stderr } = await execFile('git', args, {
cwd: options.cwd || process.cwd(),
timeout: options.timeout || 10000, // 10s for potentially slow operations
maxBuffer: 10 * 1024 * 1024, // 10MB for large diffs
env: { ...process.env, GIT_TERMINAL_PROMPT: '0' }, // Disable git prompts
});
return { stdout: stdout.toString(), stderr: stderr.toString() };
}
catch (error) {
// Re-throw with more context
throw (0, git_error_js_1.createGitError)(error, 'Git command failed');
}
}
/**
* Detect the repository's default branch
* @param repoPath Repository path
* @returns Default branch name
*/
async function detectDefaultBranch(repoPath) {
try {
// Try to get the default branch from origin
const { stdout } = await execGit(['symbolic-ref', 'refs/remotes/origin/HEAD'], {
cwd: repoPath,
});
// Output format: refs/remotes/origin/main
const match = stdout.trim().match(/refs\/remotes\/origin\/(.+)$/);
if (match) {
return match[1];
}
}
catch (_error) {
logger.debug('Could not detect default branch from origin');
}
// Fallback: check if main exists
try {
await execGit(['rev-parse', '--verify', 'main'], { cwd: repoPath });
return 'main';
}
catch {
// Fallback to master
return 'master';
}
}
/**
* Parse git worktree list --porcelain output
* @param output Git command output
* @returns Parsed worktrees
*/
function parseWorktreePorcelain(output) {
const worktrees = [];
const lines = output.trim().split('\n');
let current = null;
for (const line of lines) {
if (line === '') {
if (current?.path && current.HEAD) {
worktrees.push({
path: current.path,
branch: current.branch || 'HEAD',
HEAD: current.HEAD,
detached: current.detached || false,
prunable: current.prunable,
locked: current.locked,
lockedReason: current.lockedReason,
});
}
current = null;
continue;
}
const [key, ...valueParts] = line.split(' ');
const value = valueParts.join(' ');
if (key === 'worktree') {
current = { path: value };
}
else if (current) {
switch (key) {
case 'HEAD':
current.HEAD = value;
break;
case 'branch':
current.branch = value;
break;
case 'detached':
current.detached = true;
break;
case 'prunable':
current.prunable = true;
break;
case 'locked':
current.locked = true;
if (value) {
current.lockedReason = value;
}
break;
}
}
}
// Handle last worktree if no trailing newline
if (current?.path && current.HEAD) {
worktrees.push({
path: current.path,
branch: current.branch || 'HEAD',
HEAD: current.HEAD,
detached: current.detached || false,
prunable: current.prunable,
locked: current.locked,
lockedReason: current.lockedReason,
});
}
return worktrees;
}
/**
* Get commit and diff stats for a branch
* @param repoPath Repository path
* @param branch Branch name
* @param baseBranch Base branch to compare against
* @returns Stats
*/
async function getBranchStats(repoPath, branch, baseBranch) {
const stats = {
commitsAhead: 0,
filesChanged: 0,
insertions: 0,
deletions: 0,
};
try {
// Get commit count
const { stdout: commitCount } = await execGit(['rev-list', '--count', `${baseBranch}...${branch}`], { cwd: repoPath });
stats.commitsAhead = Number.parseInt(commitCount.trim()) || 0;
}
catch (error) {
logger.debug(`Could not get commit count for ${branch}: ${error}`);
}
try {
// Get diff stats
const { stdout: diffStat } = await execGit(['diff', '--shortstat', `${baseBranch}...${branch}`], { cwd: repoPath });
// Parse output like: "3 files changed, 10 insertions(+), 5 deletions(-)"
const match = diffStat.match(/(\d+) files? changed(?:, (\d+) insertions?\(\+\))?(?:, (\d+) deletions?\(-\))?/);
if (match) {
stats.filesChanged = Number.parseInt(match[1]) || 0;
stats.insertions = Number.parseInt(match[2]) || 0;
stats.deletions = Number.parseInt(match[3]) || 0;
}
}
catch (error) {
logger.debug(`Could not get diff stats for ${branch}: ${error}`);
}
return stats;
}
/**
* Check if a worktree has uncommitted changes
* @param worktreePath Worktree path
* @returns True if there are uncommitted changes
*/
async function hasUncommittedChanges(worktreePath) {
try {
const { stdout } = await execGit(['status', '--porcelain'], { cwd: worktreePath });
return stdout.trim().length > 0;
}
catch (error) {
logger.debug(`Could not check uncommitted changes for ${worktreePath}: ${error}`);
return false;
}
}
/**
* Slugify branch name for directory naming
* @param branch Branch name
* @returns Slugified name
*/
function _slugifyBranch(branch) {
return branch
.replace(/\//g, '-')
.replace(/[^a-zA-Z0-9-_]/g, '_')
.toLowerCase();
}
/**
* Create worktree management routes
*/
function createWorktreeRoutes() {
const router = (0, express_1.Router)();
/**
* GET /api/worktrees
* List all worktrees with extended information
*/
router.get('/worktrees', async (req, res) => {
try {
const { repoPath } = req.query;
if (!repoPath || typeof repoPath !== 'string') {
return res.status(400).json({
error: 'Missing or invalid repoPath parameter',
});
}
const absoluteRepoPath = path.resolve(repoPath);
logger.debug(`Listing worktrees for repo: ${absoluteRepoPath}`);
// Detect default branch
const baseBranch = await detectDefaultBranch(absoluteRepoPath);
logger.debug(`Using base branch: ${baseBranch}`);
// Get follow worktree if configured
let followBranch;
try {
const { stdout } = await execGit(['config', 'vibetunnel.followWorktree'], {
cwd: absoluteRepoPath,
});
const followWorktreePath = stdout.trim();
if (followWorktreePath) {
// Find the branch for this worktree path - we need to parse worktrees first
// This is a bit of a circular dependency, so let's get minimal worktree info
const { stdout: worktreeListOutput } = await execGit(['worktree', 'list', '--porcelain'], {
cwd: absoluteRepoPath,
});
const allWorktrees = parseWorktreePorcelain(worktreeListOutput);
const followWorktree = allWorktrees.find((w) => w.path === followWorktreePath);
if (followWorktree) {
followBranch = followWorktree.branch.replace(/^refs\/heads\//, '');
}
}
}
catch {
// No follow worktree configured
}
// Get worktree list
const { stdout } = await execGit(['worktree', 'list', '--porcelain'], {
cwd: absoluteRepoPath,
});
const allWorktrees = parseWorktreePorcelain(stdout);
// Enrich all worktrees with additional stats (including main repository)
const enrichedWorktrees = await Promise.all(allWorktrees.map(async (worktree) => {
// Skip stats for detached HEAD
if (worktree.detached || !worktree.branch) {
return worktree;
}
// Get branch stats
const stats = await getBranchStats(worktree.path, worktree.branch, baseBranch);
// Check for uncommitted changes
const hasChanges = await hasUncommittedChanges(worktree.path);
return {
...worktree,
...stats,
stats, // Also include stats as a nested object for compatibility
hasUncommittedChanges: hasChanges,
};
}));
return res.json({
worktrees: enrichedWorktrees,
baseBranch,
followBranch,
});
}
catch (error) {
logger.error('Error listing worktrees:', error);
const gitError = error;
// Check if it's a "not a git repository" error or git not found
if (gitError.code === 'ENOENT' || gitError.stderr?.includes('not a git repository')) {
// Return empty worktrees list for non-git directories or when git is not available
return res.json({
worktrees: [],
baseBranch: 'main',
followBranch: undefined,
});
}
return res.status(500).json({
error: 'Failed to list worktrees',
details: gitError.stderr || gitError.message,
});
}
});
/**
* DELETE /api/worktrees/:branch
* Remove a worktree
*/
router.delete('/worktrees/:branch', async (req, res) => {
try {
const { branch } = req.params;
const { repoPath, force } = req.query;
if (!repoPath || typeof repoPath !== 'string') {
return res.status(400).json({
error: 'Missing or invalid repoPath parameter',
});
}
const absoluteRepoPath = path.resolve(repoPath);
const forceDelete = force === 'true';
logger.debug(`Removing worktree for branch: ${branch}, force: ${forceDelete}`);
// First, find the worktree path for this branch
const { stdout: listOutput } = await execGit(['worktree', 'list', '--porcelain'], {
cwd: absoluteRepoPath,
});
const worktrees = parseWorktreePorcelain(listOutput);
const worktree = worktrees.find((w) => {
// Match against both the full ref path and the short branch name
const shortBranch = w.branch?.replace(/^refs\/heads\//, '');
return w.branch === `refs/heads/${branch}` || shortBranch === branch || w.branch === branch;
});
if (!worktree) {
return res.status(404).json({
error: `Worktree for branch '${branch}' not found`,
});
}
// Check for uncommitted changes if not forcing
if (!forceDelete) {
const hasChanges = await hasUncommittedChanges(worktree.path);
if (hasChanges) {
return res.status(409).json({
error: 'Worktree has uncommitted changes',
worktreePath: worktree.path,
});
}
}
// Remove the worktree
const removeArgs = ['worktree', 'remove'];
if (forceDelete) {
removeArgs.push('--force');
}
removeArgs.push(worktree.path);
await execGit(removeArgs, { cwd: absoluteRepoPath });
logger.info(`Successfully removed worktree: ${worktree.path}`);
return res.json({
success: true,
message: 'Worktree removed successfully',
removedPath: worktree.path,
});
}
catch (error) {
logger.error('Error removing worktree:', error);
const gitError = error;
return res.status(500).json({
error: 'Failed to remove worktree',
details: gitError.stderr || gitError.message,
});
}
});
/**
* POST /api/worktrees/prune
* Prune worktree information
*/
router.post('/worktrees/prune', async (req, res) => {
try {
const { repoPath } = req.body;
if (!repoPath || typeof repoPath !== 'string') {
return res.status(400).json({
error: 'Missing or invalid repoPath in request body',
});
}
const absoluteRepoPath = path.resolve(repoPath);
logger.debug(`Pruning worktrees for repo: ${absoluteRepoPath}`);
const { stdout, stderr } = await execGit(['worktree', 'prune'], { cwd: absoluteRepoPath });
logger.info('Successfully pruned worktree information');
return res.json({
success: true,
message: 'Worktree information pruned successfully',
output: stdout || stderr || 'No output',
pruned: stdout || stderr || '',
});
}
catch (error) {
logger.error('Error pruning worktrees:', error);
const gitError = error;
return res.status(500).json({
error: 'Failed to prune worktrees',
details: gitError.stderr || gitError.message,
});
}
});
/**
* POST /api/worktrees
* Create a new worktree
*/
router.post('/worktrees', async (req, res) => {
try {
const { repoPath, branch, path: worktreePath, baseBranch } = req.body;
if (!repoPath || typeof repoPath !== 'string') {
return res.status(400).json({
error: 'Missing or invalid repoPath in request body',
});
}
if (!branch || typeof branch !== 'string') {
return res.status(400).json({
error: 'Missing or invalid branch in request body',
});
}
if (!worktreePath || typeof worktreePath !== 'string') {
return res.status(400).json({
error: 'Missing or invalid path in request body',
});
}
const absoluteRepoPath = path.resolve(repoPath);
const absoluteWorktreePath = path.resolve(worktreePath);
logger.debug(`Creating worktree for branch: ${branch} at path: ${absoluteWorktreePath}`);
// Create the worktree
const createArgs = ['worktree', 'add'];
// If baseBranch is provided, create new branch from it
if (baseBranch) {
createArgs.push('-b', branch, absoluteWorktreePath, baseBranch);
}
else {
// Otherwise just checkout existing branch
createArgs.push(absoluteWorktreePath, branch);
}
await execGit(createArgs, { cwd: absoluteRepoPath });
logger.info(`Successfully created worktree at: ${absoluteWorktreePath}`);
return res.json({
message: 'Worktree created successfully',
worktreePath: absoluteWorktreePath,
branch,
});
}
catch (error) {
logger.error('Error creating worktree:', error);
const gitError = error;
return res.status(500).json({
error: 'Failed to create worktree',
details: gitError.stderr || gitError.message,
});
}
});
/**
* POST /api/worktrees/follow
* Enable or disable follow mode for a branch
*/
router.post('/worktrees/follow', async (req, res) => {
try {
const { repoPath, branch, enable } = req.body;
if (!repoPath || typeof repoPath !== 'string') {
return res.status(400).json({
error: 'Missing or invalid repoPath in request body',
});
}
if (typeof enable !== 'boolean') {
return res.status(400).json({
error: 'Missing or invalid enable flag in request body',
});
}
// Branch is only required when enabling follow mode
if (enable && (!branch || typeof branch !== 'string')) {
return res.status(400).json({
error: 'Missing or invalid branch in request body',
});
}
const absoluteRepoPath = path.resolve(repoPath);
logger.debug(`${enable ? 'Enabling' : 'Disabling'} follow mode${branch ? ` for branch: ${branch}` : ''}`);
if (enable) {
// Check if Git hooks are already installed
const hooksAlreadyInstalled = await (0, git_hooks_js_1.areHooksInstalled)(absoluteRepoPath);
logger.debug(`Git hooks installed: ${hooksAlreadyInstalled}`);
let hooksInstallResult = null;
if (!hooksAlreadyInstalled) {
// Install Git hooks
logger.info('Installing Git hooks for follow mode');
const installResult = await (0, git_hooks_js_1.installGitHooks)(absoluteRepoPath);
hooksInstallResult = installResult;
if (!installResult.success) {
logger.error('Failed to install Git hooks:', installResult.errors);
return res.status(500).json({
error: 'Failed to install Git hooks',
details: installResult.errors,
});
}
logger.info('Git hooks installed successfully');
}
// Get worktree information to find the path for this branch
const { stdout: worktreeListOutput } = await execGit(['worktree', 'list', '--porcelain'], {
cwd: absoluteRepoPath,
});
const allWorktrees = parseWorktreePorcelain(worktreeListOutput);
const worktree = allWorktrees.find((w) => w.branch === branch ||
w.branch === `refs/heads/${branch}` ||
w.branch.replace(/^refs\/heads\//, '') === branch);
if (!worktree) {
return res.status(400).json({
error: `No worktree found for branch: ${branch}`,
});
}
// Set the follow worktree path (not branch name)
await execGit(['config', '--local', 'vibetunnel.followWorktree', worktree.path], {
cwd: absoluteRepoPath,
});
logger.info(`Follow mode enabled for branch: ${branch}`);
// Immediately sync main repository to the followed branch
try {
// Strip refs/heads/ prefix if present
const cleanBranch = branch.replace(/^refs\/heads\//, '');
// Check if the branch exists locally
const { stdout: branchList } = await execGit(['branch', '--list', cleanBranch], {
cwd: absoluteRepoPath,
});
if (branchList.trim()) {
// Branch exists locally, switch to it
await execGit(['checkout', cleanBranch], { cwd: absoluteRepoPath });
logger.info(`Main repository switched to branch: ${cleanBranch}`);
}
else {
// Branch doesn't exist locally, try to fetch and create it
try {
await execGit(['fetch', 'origin', `${cleanBranch}:${cleanBranch}`], {
cwd: absoluteRepoPath,
});
await execGit(['checkout', cleanBranch], { cwd: absoluteRepoPath });
logger.info(`Fetched and switched to branch: ${cleanBranch}`);
}
catch (error) {
logger.warn(`Could not fetch/switch to branch ${cleanBranch}:`, error);
// Don't fail follow mode enable if branch switch fails
}
}
}
catch (error) {
logger.warn(`Could not immediately switch to branch ${branch}:`, error);
// Don't fail follow mode enable if branch switch fails
}
// Send notification to Mac app
if (control_unix_handler_js_1.controlUnixHandler.isMacAppConnected()) {
const notification = (0, control_protocol_js_1.createControlEvent)('system', 'notification', {
level: 'info',
title: 'Follow Mode Enabled',
message: `Now following branch '${branch}' in ${path.basename(absoluteRepoPath)}`,
});
control_unix_handler_js_1.controlUnixHandler.sendToMac(notification);
}
return res.json({
success: true,
enabled: true,
message: 'Follow mode enabled',
branch,
hooksInstalled: true,
hooksInstallResult: hooksInstallResult,
});
}
else {
// Unset the follow worktree config
await execGit(['config', '--local', '--unset', 'vibetunnel.followWorktree'], {
cwd: absoluteRepoPath,
});
// Uninstall Git hooks when disabling follow mode
logger.info('Uninstalling Git hooks');
const uninstallResult = await (0, git_hooks_js_1.uninstallGitHooks)(absoluteRepoPath);
if (!uninstallResult.success) {
logger.warn('Failed to uninstall some Git hooks:', uninstallResult.errors);
// Continue anyway - follow mode is still disabled
}
else {
logger.info('Git hooks uninstalled successfully');
}
logger.info('Follow mode disabled');
// Send notification to Mac app
if (control_unix_handler_js_1.controlUnixHandler.isMacAppConnected()) {
const notification = (0, control_protocol_js_1.createControlEvent)('system', 'notification', {
level: 'info',
title: 'Follow Mode Disabled',
message: `Follow mode has been disabled for ${path.basename(absoluteRepoPath)}`,
});
control_unix_handler_js_1.controlUnixHandler.sendToMac(notification);
}
return res.json({
success: true,
enabled: false,
message: 'Follow mode disabled',
branch,
});
}
}
catch (error) {
// Ignore error if config key doesn't exist when unsetting
if ((0, git_error_js_1.isGitConfigNotFoundError)(error) && !req.body.enable) {
logger.debug('Follow mode was already disabled');
return res.json({
success: true,
enabled: false,
message: 'Follow mode disabled',
});
}
logger.error('Error managing follow mode:', error);
const gitError = error;
return res.status(500).json({
error: 'Failed to manage follow mode',
details: gitError.stderr || gitError.message,
});
}
});
return router;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid29ya3RyZWVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3NlcnZlci9yb3V0ZXMvd29ya3RyZWVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBcVBBLG9EQWdkQztBQXJzQkQscUNBQWlDO0FBQ2pDLDJDQUE2QjtBQUM3QiwrQkFBaUM7QUFDakMsd0RBQWdHO0FBQ2hHLHdEQUE4RjtBQUM5RixrREFBa0Q7QUFDbEQsMEVBQXNFO0FBQ3RFLGtGQUEwRTtBQUUxRSxNQUFNLE1BQU0sR0FBRyxJQUFBLHdCQUFZLEVBQUMsaUJBQWlCLENBQUMsQ0FBQztBQUMvQyxNQUFNLFFBQVEsR0FBRyxJQUFBLGdCQUFTLEVBQUMsT0FBTyxDQUFDLGVBQWUsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0FBeUI5RDs7Ozs7R0FLRztBQUNILEtBQUssVUFBVSxPQUFPLENBQ3BCLElBQWMsRUFDZCxVQUE4QyxFQUFFO0lBRWhELElBQUksQ0FBQztRQUNILE1BQU0sRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLEdBQUcsTUFBTSxRQUFRLENBQUMsS0FBSyxFQUFFLElBQUksRUFBRTtZQUNyRCxHQUFHLEVBQUUsT0FBTyxDQUFDLEdBQUcsSUFBSSxPQUFPLENBQUMsR0FBRyxFQUFFO1lBQ2pDLE9BQU8sRUFBRSxPQUFPLENBQUMsT0FBTyxJQUFJLEtBQUssRUFBRSxzQ0FBc0M7WUFDekUsU0FBUyxFQUFFLEVBQUUsR0FBRyxJQUFJLEdBQUcsSUFBSSxFQUFFLHVCQUF1QjtZQUNwRCxHQUFHLEVBQUUsRUFBRSxHQUFHLE9BQU8sQ0FBQyxHQUFHLEVBQUUsbUJBQW1CLEVBQUUsR0FBRyxFQUFFLEVBQUUsc0JBQXNCO1NBQzFFLENBQUMsQ0FBQztRQUNILE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxDQUFDLFFBQVEsRUFBRSxFQUFFLE1BQU0sRUFBRSxNQUFNLENBQUMsUUFBUSxF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