codestate-cli
Version:
CodeState CLI - Configuration, Script, and Git Management
1,377 lines (1,337 loc) • 106 kB
JavaScript
#!/usr/bin/env node
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
// packages/cli-interface/cli.ts
var import_core36 = require("codestate-core");
// packages/cli-interface/commands/index.ts
var import_core35 = require("codestate-core");
// packages/cli-interface/commands/config/showConfig.ts
var import_core = require("codestate-core");
async function showConfigCommand() {
const logger2 = new import_core.ConfigurableLogger();
const getConfig = new import_core.GetConfig();
const result = await getConfig.execute();
if (result.ok) {
const config = result.value;
logger2.plainLog("\n\u{1F4CB} Current Configuration:");
logger2.plainLog("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
logger2.plainLog(`Editor: ${config.ide}`);
logger2.plainLog(`Version: ${config.version}`);
logger2.plainLog(`Encryption: ${config.encryption.enabled ? "Yes" : "No"}`);
logger2.plainLog(`Storage Path: ${config.storagePath}`);
logger2.plainLog(`Log Level: ${config.logger.level}`);
logger2.plainLog(`Log Sinks: ${config.logger.sinks.join(", ")}`);
if (config.experimental && Object.keys(config.experimental).length > 0) {
logger2.plainLog("\n\u{1F52C} Experimental Features:");
Object.entries(config.experimental).forEach(([key, value]) => {
logger2.plainLog(` ${key}: ${value ? "\u2705" : "\u274C"}`);
});
}
if (config.extensions && Object.keys(config.extensions).length > 0) {
logger2.plainLog("\n\u{1F50C} Extensions:");
Object.keys(config.extensions).forEach((key) => {
logger2.plainLog(` ${key}`);
});
}
logger2.plainLog("");
} else {
logger2.error("Failed to load config", { error: result.error });
}
}
// packages/cli-interface/tui/config/showConfigTui.ts
async function showConfigTui() {
await showConfigCommand();
}
// packages/cli-interface/utils/inquirer.ts
var import_core2 = require("codestate-core");
var import_inquirer = __toESM(require("inquirer"));
var inquirer = {
...import_inquirer.default,
customPrompt: async function(questions) {
try {
return await import_inquirer.default.prompt(questions);
} catch (error) {
if (error.message?.includes("SIGINT") || error.message?.includes("force closed")) {
const logger2 = new import_core2.ConfigurableLogger();
logger2.plainLog("\n\u{1F44B} You have exited CodeState CLI");
process.exit(0);
}
throw error;
}
}
};
var inquirer_default = inquirer;
// packages/cli-interface/commands/config/updateConfig.ts
var import_core3 = require("codestate-core");
async function updateConfigCommand(partial) {
const logger2 = new import_core3.ConfigurableLogger();
const updateConfig = new import_core3.UpdateConfig();
const result = await updateConfig.execute(partial);
if (result.ok) {
const config = result.value;
logger2.log("Configuration updated successfully!");
logger2.plainLog("\n\u{1F4CB} Current Configuration:");
logger2.plainLog("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
logger2.plainLog(`Editor: ${config.ide}`);
logger2.plainLog(`Version: ${config.version}`);
logger2.plainLog(`Encryption: ${config.encryption.enabled ? "Yes" : "No"}`);
logger2.plainLog(`Storage Path: ${config.storagePath}`);
logger2.plainLog(`Log Level: ${config.logger.level}`);
logger2.plainLog(`Log Sinks: ${config.logger.sinks.join(", ")}`);
if (config.experimental && Object.keys(config.experimental).length > 0) {
logger2.plainLog("\n\u{1F52C} Experimental Features:");
Object.entries(config.experimental).forEach(([key, value]) => {
logger2.plainLog(` ${key}: ${value ? "\u2705" : "\u274C"}`);
});
}
if (config.extensions && Object.keys(config.extensions).length > 0) {
logger2.plainLog("\n\u{1F50C} Extensions:");
Object.keys(config.extensions).forEach((key) => {
logger2.plainLog(` ${key}`);
});
}
logger2.plainLog("");
} else {
logger2.error("Failed to update config", { error: result.error });
}
}
// packages/cli-interface/tui/config/updateConfigTui.ts
async function updateConfigTui() {
const answers = await inquirer_default.customPrompt([
{
name: "ide",
message: "Default IDE:",
type: "list",
choices: ["cursor", "vscode"]
},
{ name: "encryption", message: "Enable encryption?", type: "confirm" }
]);
let encryptionKey = void 0;
if (answers.encryption) {
const keyAnswer = await inquirer_default.customPrompt([
{
name: "encryptionKey",
message: "Encryption key:",
type: "password",
mask: "*"
}
]);
encryptionKey = keyAnswer.encryptionKey;
}
const partial = {
ide: answers.ide,
encryption: { enabled: answers.encryption, encryptionKey }
};
await updateConfigCommand(partial);
}
// packages/cli-interface/commands/config/resetConfig.ts
var import_core4 = require("codestate-core");
async function resetConfigCommand() {
const logger2 = new import_core4.ConfigurableLogger();
const resetConfig = new import_core4.ResetConfig();
const result = await resetConfig.execute();
if (result.ok) {
logger2.log("Config reset to defaults:", { config: result.value });
} else {
logger2.error("Failed to reset config", { error: result.error });
}
}
// packages/cli-interface/tui/config/resetConfigTui.ts
async function resetConfigTui() {
const { confirm } = await inquirer_default.customPrompt([
{ name: "confirm", message: "Are you sure you want to reset config to defaults?", type: "confirm" }
]);
if (confirm) {
await resetConfigCommand();
}
}
// packages/cli-interface/tui/config/exportConfigTui.ts
var import_core6 = require("codestate-core");
var fs = __toESM(require("fs/promises"));
// packages/cli-interface/commands/config/exportConfig.ts
var import_core5 = require("codestate-core");
async function exportConfigCommand() {
const logger2 = new import_core5.ConfigurableLogger();
const exportConfig = new import_core5.ExportConfig();
const result = await exportConfig.execute();
if (result.ok) {
logger2.log("Exported config:", { config: result.value });
} else {
logger2.error("Failed to export config", { error: result.error });
}
}
// packages/cli-interface/tui/config/exportConfigTui.ts
async function exportConfigTui() {
const logger2 = new import_core6.ConfigurableLogger();
const { filePath } = await inquirer_default.customPrompt([
{
name: "filePath",
message: "Export to file (leave blank to print to console):",
type: "input"
}
]);
let output = "";
const originalLog = logger2.log;
logger2.log = (msg, meta) => {
if (typeof msg === "string" && msg.startsWith("Exported config:")) {
output = meta?.config || "";
} else {
originalLog(msg, meta);
}
};
await exportConfigCommand();
logger2.log = originalLog;
if (filePath && output) {
await fs.writeFile(filePath, output, "utf8");
logger2.plainLog(`Config exported to ${filePath}`);
} else if (output) {
logger2.plainLog(output);
}
}
// packages/cli-interface/commands/config/importConfig.ts
var import_core7 = require("codestate-core");
async function importConfigCommand(json) {
const logger2 = new import_core7.ConfigurableLogger();
const importConfig = new import_core7.ImportConfig();
const result = await importConfig.execute(json);
if (result.ok) {
logger2.log("Config imported:", { config: result.value });
} else {
logger2.error("Failed to import config", { error: result.error });
}
}
// packages/cli-interface/tui/config/importConfigTui.ts
var fs2 = __toESM(require("fs/promises"));
async function importConfigTui() {
const { importType } = await inquirer_default.customPrompt([
{ name: "importType", message: "Import from:", type: "list", choices: ["File", "Paste JSON"] }
]);
let json = "";
if (importType === "File") {
const { filePath } = await inquirer_default.customPrompt([
{ name: "filePath", message: "Path to config file:", type: "input" }
]);
json = await fs2.readFile(filePath, "utf8");
} else {
const { jsonString } = await inquirer_default.customPrompt([
{ name: "jsonString", message: "Paste config JSON:", type: "editor" }
]);
json = jsonString;
}
await importConfigCommand(json);
}
// packages/cli-interface/tui/config/cliHandler.ts
var import_core8 = require("codestate-core");
async function handleConfigCommand(subcommand, options) {
const logger2 = new import_core8.ConfigurableLogger();
switch (subcommand) {
case "show":
await showConfigTui();
break;
case "edit":
await updateConfigTui();
break;
case "reset":
await resetConfigTui();
break;
case "export":
await exportConfigTui();
break;
case "import":
const fileIndex = options.indexOf("--file");
if (fileIndex === -1 || fileIndex === options.length - 1) {
logger2.error("Error: --file option is required for import command");
logger2.plainLog("Usage: codestate config import --file <path>");
process.exit(1);
}
const filePath = options[fileIndex + 1];
await importConfigTui();
break;
default:
logger2.error(`Error: Unknown config subcommand '${subcommand}'`);
logger2.plainLog(
"Available config subcommands: show, edit, reset, export, import"
);
process.exit(1);
}
}
// packages/cli-interface/commands/scripts/showScripts.ts
var import_core9 = require("codestate-core");
async function showScriptsCommand() {
const logger2 = new import_core9.ConfigurableLogger();
const getScripts = new import_core9.GetScripts();
const result = await getScripts.execute();
if (result.ok) {
const scripts = result.value;
if (scripts.length === 0) {
logger2.plainLog("\n\u{1F4DD} No scripts found.");
logger2.plainLog(
"Use `codestate scripts create` to add your first script.\n"
);
return;
}
const scriptsByPath = /* @__PURE__ */ new Map();
scripts.forEach((script) => {
if (!scriptsByPath.has(script.rootPath)) {
scriptsByPath.set(script.rootPath, []);
}
scriptsByPath.get(script.rootPath).push(script);
});
logger2.plainLog("\n\u{1F4DD} Scripts by Project Path:");
logger2.plainLog("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
scriptsByPath.forEach((pathScripts, rootPath) => {
logger2.plainLog(
`
\u{1F4C1} ${rootPath} (${pathScripts.length} script${pathScripts.length > 1 ? "s" : ""})`
);
logger2.plainLog("\u2500".repeat(rootPath.length + 10));
pathScripts.forEach((script) => {
const executionMode = script.executionMode || "same-terminal";
const modeIcon = executionMode === "new-terminals" ? "\u{1F4F1}" : "\u{1F5A5}\uFE0F";
const modeText = executionMode === "new-terminals" ? "new terminal" : "same terminal";
let closeInfo = "";
if (executionMode === "new-terminals") {
const closeAfterExecution = script.closeTerminalAfterExecution || false;
closeInfo = closeAfterExecution ? " (auto-close)" : " (keep open)";
}
if (script.script) {
logger2.plainLog(` \u2022 ${script.name} - ${script.script} ${modeIcon} (${modeText}${closeInfo})`);
} else if (script.commands && script.commands.length > 0) {
logger2.plainLog(` \u2022 ${script.name} ${modeIcon} (${modeText}${closeInfo}):`);
script.commands.sort((a, b) => a.priority - b.priority).forEach((cmd) => {
logger2.plainLog(` ${cmd.priority}. ${cmd.name} - ${cmd.command}`);
});
} else {
logger2.plainLog(` \u2022 ${script.name} - (no commands)`);
}
});
});
logger2.plainLog("");
} else {
logger2.error("Failed to load scripts", { error: result.error });
}
}
// packages/cli-interface/tui/scripts/showScriptsTui.ts
async function showScriptsTui() {
await showScriptsCommand();
}
// packages/cli-interface/commands/scripts/createScript.ts
var import_core10 = require("codestate-core");
async function createScriptCommand(scripts) {
const logger2 = new import_core10.ConfigurableLogger();
const createScripts = new import_core10.CreateScripts();
const scriptsArray = Array.isArray(scripts) ? scripts : [scripts];
const result = await createScripts.execute(scriptsArray);
if (result.ok) {
const scriptNames = scriptsArray.map((s) => s.name).join(", ");
if (scriptsArray.length === 1) {
logger2.log(`Script '${scriptNames}' created successfully`);
} else {
logger2.log(`Scripts created successfully: ${scriptNames}`);
}
} else {
logger2.error("Failed to create scripts", {
error: result.error,
count: scriptsArray.length
});
}
}
// packages/cli-interface/tui/scripts/createScriptTui.ts
var import_crypto = require("crypto");
async function createScriptTui() {
await createScriptsInteractively();
}
async function createScriptsInteractively() {
const scripts = [];
let continueAdding = true;
const currentPath = process.cwd();
while (continueAdding) {
const answers = await inquirer_default.customPrompt([
{
name: "name",
message: `Script name (${scripts.length + 1}):`,
type: "input",
validate: (input) => input.trim() ? true : "Script name is required"
},
{
name: "rootPath",
message: `Root path (current: ${currentPath}):`,
type: "input",
default: currentPath,
validate: (input) => input.trim() ? true : "Root path is required"
},
{
name: "scriptType",
message: "Script type:",
type: "list",
choices: [
{ name: "Single command (legacy)", value: "single" },
{ name: "Multiple commands with priority", value: "multiple" }
],
default: "single"
}
]);
if (answers.scriptType === "single") {
const scriptAnswer = await inquirer_default.customPrompt([
{
name: "script",
message: "Script command:",
type: "input",
validate: (input) => input.trim() ? true : "Script command is required"
}
]);
const executionModeAnswer = await inquirer_default.customPrompt([
{
name: "executionMode",
message: "How should this command be executed?",
type: "list",
choices: [
{ name: "Same terminal (run in current terminal)", value: "same-terminal" },
{ name: "New terminal (open new terminal window and run)", value: "new-terminals" }
],
default: "same-terminal"
}
]);
let closeTerminalAfterExecution = false;
if (executionModeAnswer.executionMode === "new-terminals") {
const closeAnswer = await inquirer_default.customPrompt([
{
name: "closeTerminalAfterExecution",
message: "Should the terminal close after running the command?",
type: "list",
choices: [
{ name: "Keep terminal open (useful for debugging, manual follow-up)", value: false },
{ name: "Close terminal automatically (clean exit)", value: true }
],
default: false
}
]);
closeTerminalAfterExecution = closeAnswer.closeTerminalAfterExecution;
}
scripts.push({
id: (0, import_crypto.randomUUID)(),
name: answers.name.trim(),
rootPath: answers.rootPath.trim(),
script: scriptAnswer.script.trim(),
executionMode: executionModeAnswer.executionMode,
closeTerminalAfterExecution
});
} else {
const commands = [];
let continueAddingCommands = true;
let commandPriority = 1;
while (continueAddingCommands) {
const commandAnswers = await inquirer_default.customPrompt([
{
name: "commandName",
message: `Command name (${commandPriority}):`,
type: "input",
validate: (input) => input.trim() ? true : "Command name is required"
},
{
name: "command",
message: `Command (${commandPriority}):`,
type: "input",
validate: (input) => input.trim() ? true : "Command is required"
},
{
name: "addAnotherCommand",
message: "Add another command?",
type: "confirm",
default: true
}
]);
commands.push({
name: commandAnswers.commandName.trim(),
command: commandAnswers.command.trim(),
priority: commandPriority
});
commandPriority++;
continueAddingCommands = commandAnswers.addAnotherCommand;
}
const executionModeAnswer = await inquirer_default.customPrompt([
{
name: "executionMode",
message: "How should these commands be executed?",
type: "list",
choices: [
{ name: "Same terminal (run all commands in sequence)", value: "same-terminal" },
{ name: "New terminal (open new terminal window and run all commands in sequence)", value: "new-terminals" }
],
default: "same-terminal"
}
]);
let closeTerminalAfterExecution = false;
if (executionModeAnswer.executionMode === "new-terminals") {
const closeAnswer = await inquirer_default.customPrompt([
{
name: "closeTerminalAfterExecution",
message: "Should the terminal close after running all commands?",
type: "list",
choices: [
{ name: "Keep terminal open (useful for debugging, manual follow-up)", value: false },
{ name: "Close terminal automatically (clean exit)", value: true }
],
default: false
}
]);
closeTerminalAfterExecution = closeAnswer.closeTerminalAfterExecution;
}
scripts.push({
id: (0, import_crypto.randomUUID)(),
name: answers.name.trim(),
rootPath: answers.rootPath.trim(),
commands,
executionMode: executionModeAnswer.executionMode,
closeTerminalAfterExecution
});
}
const addAnotherAnswer = await inquirer_default.customPrompt([
{
name: "addAnother",
message: "Add another script?",
type: "confirm",
default: true
}
]);
continueAdding = addAnotherAnswer.addAnother;
}
if (scripts.length > 0) {
await createScriptCommand(scripts);
}
}
// packages/cli-interface/commands/scripts/updateScript.ts
var import_core11 = require("codestate-core");
async function updateScriptCommand(name, rootPath, scriptUpdate) {
const logger2 = new import_core11.ConfigurableLogger();
const updateScript = new import_core11.UpdateScript();
const result = await updateScript.execute(name, rootPath, scriptUpdate);
if (result.ok) {
const updatedFields = Object.keys(scriptUpdate).join(", ");
logger2.log(`Script '${name}' updated successfully (${updatedFields})`);
} else {
logger2.error(`Failed to update script '${name}'`, { error: result.error });
}
}
// packages/cli-interface/tui/scripts/updateScriptTui.ts
async function updateScriptTui() {
const currentPath = process.cwd();
const answers = await inquirer_default.customPrompt([
{
name: "name",
message: "Script name to update:",
type: "input",
validate: (input) => input.trim() ? true : "Script name is required"
},
{
name: "rootPath",
message: `Root path (current: ${currentPath}):`,
type: "input",
default: currentPath,
validate: (input) => input.trim() ? true : "Root path is required"
},
{
name: "newName",
message: "New script name (leave empty to keep current):",
type: "input"
},
{
name: "updateType",
message: "What would you like to update?",
type: "list",
choices: [
{ name: "Single command (legacy)", value: "single" },
{ name: "Multiple commands with priority", value: "multiple" }
],
default: "single"
}
]);
const scriptUpdate = {};
if (answers.newName.trim()) {
scriptUpdate.name = answers.newName.trim();
}
if (answers.updateType === "single") {
const scriptAnswer = await inquirer_default.customPrompt([
{
name: "newScript",
message: "New script command (leave empty to keep current):",
type: "input"
}
]);
if (scriptAnswer.newScript.trim()) {
scriptUpdate.script = scriptAnswer.newScript.trim();
}
const executionModeAnswer = await inquirer_default.customPrompt([
{
name: "executionMode",
message: "How should this command be executed?",
type: "list",
choices: [
{ name: "Same terminal (run in current terminal)", value: "same-terminal" },
{ name: "New terminal (open new terminal window and run)", value: "new-terminals" }
],
default: "same-terminal"
}
]);
scriptUpdate.executionMode = executionModeAnswer.executionMode;
if (executionModeAnswer.executionMode === "new-terminals") {
const closeAnswer = await inquirer_default.customPrompt([
{
name: "closeTerminalAfterExecution",
message: "Should the terminal close after running the command?",
type: "list",
choices: [
{ name: "Keep terminal open (useful for debugging, manual follow-up)", value: false },
{ name: "Close terminal automatically (clean exit)", value: true }
],
default: false
}
]);
scriptUpdate.closeTerminalAfterExecution = closeAnswer.closeTerminalAfterExecution;
}
} else {
const commands = [];
let continueAddingCommands = true;
let commandPriority = 1;
while (continueAddingCommands) {
const commandAnswers = await inquirer_default.customPrompt([
{
name: "commandName",
message: `Command name (${commandPriority}):`,
type: "input",
validate: (input) => input.trim() ? true : "Command name is required"
},
{
name: "command",
message: `Command (${commandPriority}):`,
type: "input",
validate: (input) => input.trim() ? true : "Command is required"
},
{
name: "addAnotherCommand",
message: "Add another command?",
type: "confirm",
default: true
}
]);
commands.push({
name: commandAnswers.commandName.trim(),
command: commandAnswers.command.trim(),
priority: commandPriority
});
commandPriority++;
continueAddingCommands = commandAnswers.addAnotherCommand;
}
if (commands.length > 0) {
scriptUpdate.commands = commands;
}
const executionModeAnswer = await inquirer_default.customPrompt([
{
name: "executionMode",
message: "How should these commands be executed?",
type: "list",
choices: [
{ name: "Same terminal (run all commands in sequence)", value: "same-terminal" },
{ name: "New terminal (open new terminal window and run all commands in sequence)", value: "new-terminals" }
],
default: "same-terminal"
}
]);
scriptUpdate.executionMode = executionModeAnswer.executionMode;
if (executionModeAnswer.executionMode === "new-terminals") {
const closeAnswer = await inquirer_default.customPrompt([
{
name: "closeTerminalAfterExecution",
message: "Should the terminal close after running all commands?",
type: "list",
choices: [
{ name: "Keep terminal open (useful for debugging, manual follow-up)", value: false },
{ name: "Close terminal automatically (clean exit)", value: true }
],
default: false
}
]);
scriptUpdate.closeTerminalAfterExecution = closeAnswer.closeTerminalAfterExecution;
}
}
await updateScriptCommand(
answers.name.trim(),
answers.rootPath.trim(),
scriptUpdate
);
}
// packages/cli-interface/tui/scripts/deleteScriptTui.ts
var import_core13 = require("codestate-core");
// packages/cli-interface/commands/scripts/deleteScript.ts
var import_core12 = require("codestate-core");
async function deleteScriptCommand(name, rootPath) {
const logger2 = new import_core12.ConfigurableLogger();
const deleteScript = new import_core12.DeleteScript();
const result = await deleteScript.execute(name, rootPath);
if (result.ok) {
logger2.log(`Script '${name}' deleted successfully`);
} else {
logger2.error(`Failed to delete script '${name}'`, { error: result.error });
}
}
// packages/cli-interface/tui/scripts/deleteScriptTui.ts
async function deleteScriptTui() {
const logger2 = new import_core13.ConfigurableLogger();
const currentPath = process.cwd();
const answers = await inquirer_default.customPrompt([
{
name: "name",
message: "Script name to delete:",
type: "input",
validate: (input) => input.trim() ? true : "Script name is required"
},
{
name: "rootPath",
message: `Root path (current: ${currentPath}):`,
type: "input",
default: currentPath,
validate: (input) => input.trim() ? true : "Root path is required"
},
{
name: "confirm",
message: "Are you sure you want to delete this script?",
type: "confirm",
default: false
}
]);
if (answers.confirm) {
await deleteScriptCommand(answers.name.trim(), answers.rootPath.trim());
} else {
logger2.plainLog("Script deletion cancelled.");
}
}
// packages/cli-interface/tui/scripts/deleteScriptsByRootPathTui.ts
var import_core15 = require("codestate-core");
// packages/cli-interface/commands/scripts/deleteScriptsByRootPath.ts
var import_core14 = require("codestate-core");
async function deleteScriptsByRootPathCommand(rootPath) {
const logger2 = new import_core14.ConfigurableLogger();
const deleteScriptsByRootPath = new import_core14.DeleteScriptsByRootPath();
const result = await deleteScriptsByRootPath.execute(rootPath);
if (result.ok) {
logger2.log("Scripts deleted for root path successfully", { rootPath });
} else {
logger2.error("Failed to delete scripts for root path", {
error: result.error,
rootPath
});
}
}
// packages/cli-interface/tui/scripts/deleteScriptsByRootPathTui.ts
async function deleteScriptsByRootPathTui() {
const logger2 = new import_core15.ConfigurableLogger();
const currentPath = process.cwd();
const answers = await inquirer_default.customPrompt([
{
name: "rootPath",
message: `Root path to delete all scripts from (current: ${currentPath}):`,
type: "input",
default: currentPath,
validate: (input) => input.trim() ? true : "Root path is required"
},
{
name: "confirm",
message: "Are you sure you want to delete ALL scripts for this root path?",
type: "confirm",
default: false
}
]);
if (answers.confirm) {
await deleteScriptsByRootPathCommand(answers.rootPath.trim());
} else {
logger2.plainLog("Script deletion cancelled.");
}
}
// packages/cli-interface/commands/scripts/exportScripts.ts
var import_core16 = require("codestate-core");
async function exportScriptsCommand() {
const logger2 = new import_core16.ConfigurableLogger();
const exportScripts = new import_core16.ExportScripts();
const result = await exportScripts.execute();
if (result.ok) {
logger2.log("Scripts exported successfully:", { scripts: result.value });
} else {
logger2.error("Failed to export scripts", { error: result.error });
}
}
// packages/cli-interface/tui/scripts/exportScriptsTui.ts
async function exportScriptsTui() {
await exportScriptsCommand();
}
// packages/cli-interface/commands/scripts/importScripts.ts
var import_core17 = require("codestate-core");
async function importScriptsCommand(json) {
const logger2 = new import_core17.ConfigurableLogger();
const importScripts = new import_core17.ImportScripts();
const result = await importScripts.execute(json);
if (result.ok) {
logger2.log("Scripts imported successfully");
} else {
logger2.error("Failed to import scripts", { error: result.error });
}
}
// packages/cli-interface/tui/scripts/importScriptsTui.ts
var fs3 = __toESM(require("fs/promises"));
async function importScriptsTui() {
const { importType } = await inquirer_default.customPrompt([
{ name: "importType", message: "Import from:", type: "list", choices: ["File", "Paste JSON"] }
]);
let json = "";
if (importType === "File") {
const { filePath } = await inquirer_default.customPrompt([
{ name: "filePath", message: "Path to scripts file:", type: "input" }
]);
json = await fs3.readFile(filePath, "utf8");
} else {
const { jsonString } = await inquirer_default.customPrompt([
{ name: "jsonString", message: "Paste scripts JSON:", type: "editor" }
]);
json = jsonString;
}
await importScriptsCommand(json);
}
// packages/cli-interface/tui/scripts/cliHandler.ts
var import_core20 = require("codestate-core");
// packages/cli-interface/commands/scripts/showScriptsByRootPath.ts
var import_core18 = require("codestate-core");
async function showScriptsByRootPathCommand(rootPath) {
const logger2 = new import_core18.ConfigurableLogger();
const getScriptsByRootPath = new import_core18.GetScriptsByRootPath();
const result = await getScriptsByRootPath.execute(rootPath);
if (result.ok) {
const scripts = result.value;
if (scripts.length === 0) {
logger2.plainLog(`
\u{1F4DD} No scripts found for ${rootPath}.`);
return;
}
logger2.plainLog(`
\u{1F4DD} Scripts for ${rootPath}:`);
logger2.plainLog("\u2500".repeat(rootPath.length + 15));
scripts.forEach((script) => {
if (script.script) {
logger2.plainLog(` \u2022 ${script.name} - ${script.script}`);
} else if (script.commands && script.commands.length > 0) {
logger2.plainLog(` \u2022 ${script.name}:`);
script.commands.sort((a, b) => a.priority - b.priority).forEach((cmd) => {
logger2.plainLog(` ${cmd.priority}. ${cmd.name} - ${cmd.command}`);
});
} else {
logger2.plainLog(` \u2022 ${script.name} - (no commands)`);
}
});
logger2.plainLog("");
} else {
logger2.error("Failed to load scripts for root path", {
error: result.error,
rootPath
});
}
}
// packages/cli-interface/commands/scripts/resumeScript.ts
var import_core19 = require("codestate-core");
async function resumeScriptCommand(scriptName, rootPath) {
const logger2 = new import_core19.ConfigurableLogger();
const getScriptsByRootPath = new import_core19.GetScriptsByRootPath();
const terminal = new import_core19.Terminal();
try {
let targetScriptName = scriptName;
let targetRootPath = rootPath || process.cwd();
if (!targetScriptName) {
const scriptsResult2 = await getScriptsByRootPath.execute(targetRootPath);
if (!scriptsResult2.ok || scriptsResult2.value.length === 0) {
logger2.warn("No scripts found for the current directory.");
return;
}
const scripts = scriptsResult2.value;
const { selectedScript } = await inquirer_default.customPrompt([
{
type: "list",
name: "selectedScript",
message: "Select a script to resume:",
choices: scripts.map((s) => ({
name: `${s.name} - ${s.script || "Multi-command script"}`,
value: s.name
}))
}
]);
targetScriptName = selectedScript || "";
}
if (!targetScriptName || !targetScriptName.trim()) {
logger2.plainLog("No script specified. Resume cancelled.");
return;
}
const scriptsResult = await getScriptsByRootPath.execute(targetRootPath);
if (!scriptsResult.ok) {
logger2.error("Failed to get scripts", { error: scriptsResult.error });
return;
}
const targetScript = scriptsResult.value.find((s) => s.name === targetScriptName);
if (!targetScript) {
logger2.error(`Script '${targetScriptName}' not found in ${targetRootPath}`);
return;
}
logger2.plainLog(`\u{1F4DC} Resuming script: "${targetScript.name}"`);
const executionMode = targetScript.executionMode || "same-terminal";
if (targetScript.script) {
if (executionMode === "new-terminals") {
const closeAfterExecution = targetScript.closeTerminalAfterExecution || false;
let finalCommand = targetScript.script;
if (closeAfterExecution) {
finalCommand = `${targetScript.script} && echo "Script execution completed. Closing terminal..." && sleep 2 && exit`;
} else {
finalCommand = `${targetScript.script} && echo 'Script execution completed. Terminal will remain open.'`;
}
const spawnResult = await terminal.spawnTerminal(finalCommand, {
cwd: targetRootPath,
timeout: 5e3
});
if (spawnResult.ok) {
logger2.plainLog(`\u2705 Script executed in new terminal`);
} else {
logger2.error(`\u274C Failed to spawn terminal`, { error: spawnResult.error });
}
} else {
const scriptResult = await terminal.execute(targetScript.script, {
cwd: targetRootPath,
timeout: 3e4
});
if (scriptResult.ok && scriptResult.value.success) {
logger2.plainLog(`\u2705 Script completed successfully`);
} else {
logger2.error(`\u274C Script failed`, { error: scriptResult.ok ? scriptResult.value : scriptResult.error });
}
}
} else if (targetScript.commands && targetScript.commands.length > 0) {
const commands = targetScript.commands.sort((a, b) => a.priority - b.priority);
if (executionMode === "new-terminals") {
const combinedCommand = commands.sort((a, b) => a.priority - b.priority).map((cmd) => cmd.command).join(" && ");
const closeAfterExecution = targetScript.closeTerminalAfterExecution || false;
let finalCommand = combinedCommand;
if (closeAfterExecution) {
finalCommand = `${combinedCommand} && echo "Script execution completed. Closing terminal..." && sleep 2 && exit`;
} else {
finalCommand = `${combinedCommand} && echo 'Script execution completed. Terminal will remain open.'`;
}
const spawnResult = await terminal.spawnTerminal(finalCommand, {
cwd: targetRootPath,
timeout: 5e3
});
if (spawnResult.ok) {
logger2.plainLog(`\u2705 Script executed in new terminal`);
} else {
logger2.error(`\u274C Failed to spawn terminal`, { error: spawnResult.error });
}
} else {
for (const cmd of commands) {
const cmdResult = await terminal.execute(cmd.command, {
cwd: targetRootPath,
timeout: 3e4
});
if (!cmdResult.ok || !cmdResult.value.success) {
logger2.error(`\u274C Command '${cmd.name}' failed`, {
error: cmdResult.ok ? cmdResult.value : cmdResult.error
});
}
if (cmd.priority < commands.length) {
await new Promise((resolve) => setTimeout(resolve, 1e3));
}
}
logger2.plainLog(`\u2705 Script completed successfully`);
}
} else {
logger2.warn(`\u26A0\uFE0F Script has no commands to execute`);
}
} catch (error) {
logger2.error("Unexpected error during script resume", { error });
}
}
// packages/cli-interface/tui/scripts/resumeScriptTui.ts
async function resumeScriptTui() {
await resumeScriptCommand();
}
// packages/cli-interface/tui/scripts/cliHandler.ts
async function handleScriptCommand(subcommand, options) {
const logger2 = new import_core20.ConfigurableLogger();
switch (subcommand) {
case "show":
await showScriptsTui();
break;
case "show-by-path":
if (options.length === 0) {
logger2.error("Error: root path is required for show-by-path command");
logger2.plainLog("Usage: codestate scripts show-by-path <root-path>");
process.exit(1);
}
await showScriptsByRootPathCommand(options[0]);
break;
case "create":
await createScriptTui();
break;
case "update":
await updateScriptTui();
break;
case "delete":
await deleteScriptTui();
break;
case "delete-by-path":
await deleteScriptsByRootPathTui();
break;
case "export":
await exportScriptsTui();
break;
case "import":
await importScriptsTui();
break;
case "resume":
if (options.length > 0) {
await resumeScriptCommand(options[0]);
} else {
await resumeScriptTui();
}
break;
default:
logger2.error(`Error: Unknown scripts subcommand '${subcommand}'`);
logger2.plainLog(
"Available scripts subcommands: show, show-by-path, create, update, delete, delete-by-path, export, import, resume"
);
process.exit(1);
}
}
// packages/cli-interface/tui/session/cliHandler.ts
var import_core26 = require("codestate-core");
// packages/cli-interface/commands/session/saveSession.ts
var import_core21 = require("codestate-core");
// packages/cli-interface/commands/session/utils.ts
async function promptSessionDetails(defaults) {
const prompts = [
{
type: "input",
name: "sessionName",
message: "Enter session name:",
default: defaults?.name || "",
validate: (input) => {
if (!input.trim()) {
return "Session name is required";
}
return true;
}
},
{
type: "input",
name: "sessionNotes",
message: "Enter session notes (optional):",
default: defaults?.notes || ""
},
{
type: "input",
name: "sessionTags",
message: "Enter session tags (comma-separated, optional):",
default: defaults?.tags || ""
}
];
if (defaults?.terminalCollectionChoices && defaults.terminalCollectionChoices.length > 0) {
prompts.push({
type: "checkbox",
name: "terminalCollections",
message: "Select terminal collections to include in this session:",
choices: defaults.terminalCollectionChoices,
default: []
});
}
if (defaults?.scriptChoices && defaults.scriptChoices.length > 0) {
prompts.push({
type: "checkbox",
name: "scripts",
message: "Select individual scripts to include in this session:",
choices: defaults.scriptChoices,
default: []
});
}
const result = await inquirer_default.customPrompt(prompts);
if (!result.terminalCollections) {
result.terminalCollections = [];
}
if (!result.scripts) {
result.scripts = [];
}
return result;
}
async function promptDirtyState(gitStatus, canStash) {
const choices = [{ name: "Commit changes", value: "commit" }];
choices.push({ name: "Cancel", value: "cancel" });
return inquirer_default.customPrompt([
{
type: "list",
name: "dirtyAction",
message: "How would you like to handle these changes?",
choices
}
]);
}
async function getCurrentGitState(gitService, logger2) {
const currentBranchResult = await gitService.getCurrentBranch();
const currentCommitResult = await gitService.getCurrentCommit();
const isDirtyResult = await gitService.getIsDirty();
if (!currentBranchResult.ok || !currentCommitResult.ok || !isDirtyResult.ok) {
logger2.error("Failed to get Git state", {
branchError: currentBranchResult.ok ? void 0 : currentBranchResult.error,
commitError: currentCommitResult.ok ? void 0 : currentCommitResult.error,
isDirtyError: isDirtyResult.ok ? void 0 : isDirtyResult.error
});
return null;
}
return {
branch: currentBranchResult.value,
commit: currentCommitResult.value,
isDirty: isDirtyResult.value,
stashId: null
// No stash ID for current state
};
}
async function handleSessionSave({
sessionDetails,
projectRoot,
git,
saveSession,
logger: logger2
}) {
const result = await saveSession.execute({
name: sessionDetails.sessionName,
projectRoot,
notes: sessionDetails.sessionNotes || "",
tags: sessionDetails.sessionTags.split(",").map((tag) => tag.trim()).filter((tag) => tag.length > 0),
files: [],
git,
extensions: {},
terminalCollections: sessionDetails.terminalCollections || [],
scripts: sessionDetails.scripts || []
});
if (result.ok) {
logger2.log(
`\u2705 Session "${sessionDetails.sessionName}" saved successfully!`
);
} else {
logger2.error("Failed to save session", { error: result.error });
}
return result;
}
// packages/cli-interface/commands/session/saveSession.ts
async function saveSessionCommand() {
const logger2 = new import_core21.ConfigurableLogger();
const saveSession = new import_core21.SaveSession();
const gitService = new import_core21.GitService();
try {
const isRepoResult = await gitService.isGitRepository();
if (!isRepoResult.ok || !isRepoResult.value) {
logger2.warn("Current directory is not a Git repository.");
const { continueWithoutGit } = await inquirer_default.customPrompt([
{
type: "confirm",
name: "continueWithoutGit",
message: "Do you want to continue without Git integration?",
default: false
}
]);
if (!continueWithoutGit) {
logger2.warn("Session save cancelled.");
return;
}
const listTerminalCollections2 = new import_core21.ListTerminalCollections();
const terminalCollectionsResult2 = await listTerminalCollections2.execute();
const terminalCollectionChoices2 = terminalCollectionsResult2.ok ? terminalCollectionsResult2.value.map((tc) => ({
name: `${tc.name} (${tc.rootPath})`,
value: tc.id
})) : [];
const { GetScripts: GetScripts4 } = await import("codestate-core");
const getScripts2 = new GetScripts4();
const scriptsResult2 = await getScripts2.execute();
const scriptChoices2 = scriptsResult2.ok ? scriptsResult2.value.map((script) => ({
name: `${script.name} (${script.rootPath})`,
value: script.id
})) : [];
const sessionDetails2 = await promptSessionDetails({
terminalCollectionChoices: terminalCollectionChoices2,
scriptChoices: scriptChoices2
});
const projectRoot2 = process.cwd();
await handleSessionSave({
sessionDetails: sessionDetails2,
projectRoot: projectRoot2,
git: {
branch: "no-git",
commit: "no-git",
isDirty: false,
stashId: null
},
saveSession,
logger: logger2
});
return;
}
const gitStatusResult = await gitService.getStatus();
if (!gitStatusResult.ok) {
logger2.error("Failed to get Git status", {
error: gitStatusResult.error
});
return;
}
const gitStatus = gitStatusResult.value;
if (gitStatus.isDirty) {
logger2.warn("\u26A0\uFE0F Repository has uncommitted changes:");
gitStatus.dirtyFiles.forEach((file) => {
logger2.plainLog(` ${file.status}: ${file.path}`);
});
const hasNewFiles = gitStatus.newFiles.length > 0;
const hasDeletedFiles = gitStatus.deletedFiles.length > 0;
const hasUntrackedFiles = gitStatus.untrackedFiles.length > 0;
const canStash = !hasNewFiles && !hasDeletedFiles && !hasUntrackedFiles;
const { dirtyAction } = await promptDirtyState(gitStatus, canStash);
if (dirtyAction === "cancel") {
logger2.warn("Session save cancelled.");
return;
}
if (dirtyAction === "commit") {
const configResult = await gitService.isGitConfigured();
if (!configResult.ok) {
logger2.error("Failed to check Git configuration", {
error: configResult.error
});
logger2.warn("Session save cancelled.");
return;
}
if (!configResult.value) {
logger2.error("Git is not properly configured for commits.");
logger2.warn("Please configure Git with your name and email:");
logger2.warn(' git config --global user.name "Your Name"');
logger2.warn(
' git config --global user.email "your.email@example.com"'
);
const { configureGit } = await inquirer_default.customPrompt([
{
type: "confirm",
name: "configureGit",
message: "Would you like to configure Git now?",
default: false
}
]);
if (configureGit) {
const { userName, userEmail } = await inquirer_default.customPrompt([
{
type: "input",
name: "userName",
message: "Enter your name for Git:",
validate: (input) => {
if (!input.trim()) {
return "Name is required";
}
return true;
}
},
{
type: "input",
name: "userEmail",
message: "Enter your email for Git:",
validate: (input) => {
if (!input.trim()) {
return "Email is required";
}
return true;
}
}
]);
const terminal = new import_core21.Terminal();
await terminal.execute(`git config user.name "${userName}"`);
await terminal.execute(`git config user.email "${userEmail}"`);
logger2.plainLog("Git configured successfully.");
} else {
logger2.warn("Session save cancelled.");
return;
}
}
const { commitMessage } = await inquirer_default.customPrompt([
{
type: "input",
name: "commitMessage",
message: "Enter commit message:",
validate: (input) => {
if (!input.trim()) {
return "Commit message is required";
}
return true;
}
}
]);
logger2.plainLog(" Committing changes...");
const commitResult = await gitService.commitChanges(commitMessage);
if (!commitResult.ok) {
logger2.error("Failed to commit changes", {
error: commitResult.error,
message: commitResult.error.message
});
logger2.warn("Git commit failed. This might be due to:");
logger2.warn(" - No changes to commit");
logger2.warn(" - Git configuration issues");
logger2.warn(" - Repository permissions");
logger2.warn(
'Consider using "stash" instead or check your git status.'
);
const { retryAction } = await inquirer_default.customPrompt([
{
type: "list",
name: "retryAction",
message: "What would you like to do?",
choices: [
{ name: "Try stashing instead", value: "stash" },
{ name: "Cancel session save", value: "cancel" }
]
}
]);
if (retryAction === "stash") {
logger2.plainLog("Attempting to stash changes...");
const stashResult = await gitService.createStash(
"Session save stash"
);
if (!stashResult.ok) {
logger2.error("Failed to stash changes", {
error: stashResult.error
});
logger2.warn("Session save cancelled.");
return;
}
logger2.plainLog("Changes stashed successfully.");
} else {
logger2.warn("Session save cancelled.");
return;
}
} else {
logger2.plainLog(" Changes committed successfully.");
}
} else if (dirtyAction === "stash") {
const stashResult = await gitService.createSt