termcode
Version:
Superior terminal AI coding agent with enterprise-grade security, intelligent error recovery, performance monitoring, and plugin system - Advanced Claude Code alternative
136 lines (135 loc) âĸ 4.1 kB
JavaScript
import { addMacro } from "./storage.js";
import { log } from "../util/logging.js";
// Active recording sessions per project
const activeRecordings = new Map();
// Start recording a macro
export async function startRecording(name, description, projectPath, scope = "project") {
if (activeRecordings.has(projectPath)) {
throw new Error("Already recording a macro for this project");
}
const session = {
name,
description,
steps: [],
startTime: new Date().toISOString(),
isRecording: true,
scope
};
activeRecordings.set(projectPath, session);
log.info(`đ´ Recording macro: ${name}`);
}
// Stop recording and save macro
export async function stopRecording(projectPath) {
const session = activeRecordings.get(projectPath);
if (!session || !session.isRecording) {
return null;
}
session.isRecording = false;
activeRecordings.delete(projectPath);
if (session.steps.length === 0) {
log.warn("No steps recorded, macro not saved");
return null;
}
const macro = {
name: session.name,
description: session.description,
steps: session.steps,
tags: ["recorded"],
scope: session.scope,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
usageCount: 0
};
await addMacro(macro, session.scope === "project" ? projectPath : undefined);
log.success(`âšī¸ Macro saved: ${macro.name} (${macro.steps.length} steps)`);
return macro;
}
// Cancel recording
export async function cancelRecording(projectPath) {
const session = activeRecordings.get(projectPath);
if (!session)
return false;
activeRecordings.delete(projectPath);
log.info("đ Recording cancelled");
return true;
}
// Add step to current recording
export async function recordStep(projectPath, type, action, args, description) {
const session = activeRecordings.get(projectPath);
if (!session || !session.isRecording) {
return; // Silently ignore if not recording
}
const step = {
type,
action,
args,
description: description || action
};
session.steps.push(step);
log.raw(` đ Recorded: ${type} ${action}`);
}
// Check if recording is active
export function isRecording(projectPath) {
const session = activeRecordings.get(projectPath);
return session?.isRecording || false;
}
// Get current recording session
export function getRecordingSession(projectPath) {
return activeRecordings.get(projectPath) || null;
}
// Pause recording
export function pauseRecording(projectPath) {
const session = activeRecordings.get(projectPath);
if (!session)
return false;
session.isRecording = false;
log.info("â¸ī¸ Recording paused");
return true;
}
// Resume recording
export function resumeRecording(projectPath) {
const session = activeRecordings.get(projectPath);
if (!session)
return false;
session.isRecording = true;
log.info("âļī¸ Recording resumed");
return true;
}
// Auto-detect command type from input
export function detectCommandType(input) {
// Git commands
if (input.startsWith("git ")) {
return {
type: "git",
action: input.substring(4),
args: input.substring(4).split(" ")
};
}
// Shell commands (common patterns)
if (input.match(/^(npm|yarn|pnpm|pip|cargo|go|make|docker|kubectl|helm)/)) {
return {
type: "shell",
action: input,
args: input.split(" ")
};
}
// TermCode commands (starting with /)
if (input.startsWith("/")) {
return {
type: "command",
action: input.substring(1)
};
}
// Built-in commands
if (["test", "lint", "build", "rollback"].includes(input)) {
return {
type: "command",
action: input
};
}
// Default to task (AI task)
return {
type: "task",
action: input
};
}