codestate-core
Version:
Core domain models, use cases, and services for CodeState
1,450 lines (1,434 loc) • 131 kB
JavaScript
"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 __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
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
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// packages/core/index.ts
var core_exports = {};
__export(core_exports, {
AppError: () => AppError,
ApplyStash: () => ApplyStash,
CommitChanges: () => CommitChanges,
ConfigError: () => ConfigError,
ConfigurableLogger: () => CLILoggerFacade,
CreateScript: () => CreateScript,
CreateScripts: () => CreateScripts,
CreateStash: () => CreateStash,
DeleteScript: () => DeleteScript,
DeleteScriptsByRootPath: () => DeleteScriptsByRootPath,
DeleteSession: () => DeleteSession,
DeleteStash: () => DeleteStash,
EncryptionError: () => EncryptionError,
ErrorCode: () => ErrorCode,
ErrorRegistry: () => ErrorRegistry,
ExportConfig: () => ExportConfig,
ExportScripts: () => ExportScripts,
GetAvailableIDEs: () => GetAvailableIDEs,
GetConfig: () => GetConfig,
GetCurrentCommit: () => GetCurrentCommit,
GetDirtyData: () => GetDirtyData,
GetGitStatus: () => GetGitStatus,
GetIsDirty: () => GetIsDirty,
GetScripts: () => GetScripts,
GetScriptsByRootPath: () => GetScriptsByRootPath,
GitError: () => GitError,
GitService: () => GitFacade,
IDEService: () => IDEFacade,
ImportConfig: () => ImportConfig,
ImportScripts: () => ImportScripts,
ListSessions: () => ListSessions,
ListStashes: () => ListStashes,
OpenFiles: () => OpenFiles,
OpenIDE: () => OpenIDE,
ResetConfig: () => ResetConfig,
ResumeSession: () => ResumeSession,
SaveSession: () => SaveSession,
ScriptError: () => ScriptError,
StorageError: () => StorageError,
Terminal: () => TerminalFacade,
TerminalError: () => TerminalError,
UpdateConfig: () => UpdateConfig,
UpdateScript: () => UpdateScript,
UpdateSession: () => UpdateSession,
getExitCodeForErrorCode: () => getExitCodeForErrorCode,
getUserMessageForErrorCode: () => getUserMessageForErrorCode,
isFailure: () => isFailure,
isSuccess: () => isSuccess
});
module.exports = __toCommonJS(core_exports);
// packages/core/domain/models/Result.ts
function isSuccess(result) {
return result.ok === true;
}
function isFailure(result) {
return result.ok === false;
}
// packages/core/services/config/ConfigService.ts
var ConfigService = class {
constructor(repository, logger) {
this.repository = repository;
this.logger = logger;
}
async getConfig() {
this.logger.debug("ConfigService.getConfig called");
const result = await this.repository.load();
if (isFailure(result)) {
this.logger.error("Failed to get config", { error: result.error });
} else {
this.logger.log("Config loaded", {});
}
return result;
}
async setConfig(config) {
this.logger.debug("ConfigService.setConfig called");
const result = await this.repository.save(config);
if (isFailure(result)) {
this.logger.error("Failed to save config", { error: result.error });
} else {
this.logger.log("Config saved", {});
}
return result;
}
async updateConfig(partial) {
this.logger.debug("ConfigService.updateConfig called", { partial });
const current = await this.repository.load();
if (isFailure(current)) {
this.logger.error("Failed to load config for update", { error: current.error });
return current;
}
const merged = { ...current.value, ...partial };
const saveResult = await this.repository.save(merged);
if (isFailure(saveResult)) {
this.logger.error("Failed to save updated config", { error: saveResult.error });
return { ok: false, error: saveResult.error };
}
this.logger.log("Config updated", {});
return { ok: true, value: merged };
}
};
// packages/core/domain/schemas/SchemaRegistry.ts
var import_zod = require("zod");
var LogLevelSchema = import_zod.z.enum(["ERROR", "WARN", "LOG", "DEBUG"]);
var LoggerConfigSchema = import_zod.z.object({
level: LogLevelSchema,
sinks: import_zod.z.array(import_zod.z.enum(["console", "file"])),
filePath: import_zod.z.string().optional()
});
var FileStorageConfigSchema = import_zod.z.object({
encryptionEnabled: import_zod.z.boolean(),
encryptionKey: import_zod.z.string().optional(),
dataDir: import_zod.z.string()
});
var FeatureFlagsSchema = import_zod.z.object({
experimentalTui: import_zod.z.boolean(),
experimentalIde: import_zod.z.boolean(),
advancedSearch: import_zod.z.boolean(),
cloudSync: import_zod.z.boolean()
});
var PluginEnvironmentSchema = import_zod.z.enum(["cli", "tui", "ide"]);
var ErrorCodeSchema = import_zod.z.enum([
"UNKNOWN",
"CONFIG_INVALID",
"STORAGE_INVALID_PATH",
"STORAGE_DECRYPTION_FAILED",
"STORAGE_READ_FAILED",
"STORAGE_WRITE_FAILED",
"STORAGE_DELETE_FAILED",
"ENCRYPTION_FAILED",
"ENCRYPTION_INVALID_FORMAT",
"SCRIPT_INVALID",
"SCRIPT_DUPLICATE",
"SCRIPT_NOT_FOUND",
"SCRIPT_PATH_INVALID",
"SCRIPT_MALICIOUS",
"GIT_NOT_REPOSITORY",
"GIT_COMMAND_FAILED",
"GIT_STASH_NOT_FOUND",
"GIT_STASH_CONFLICT",
"TERMINAL_COMMAND_FAILED",
"TERMINAL_TIMEOUT",
"TERMINAL_COMMAND_NOT_FOUND"
]);
var EncryptionConfigSchema = import_zod.z.object({
enabled: import_zod.z.boolean(),
encryptionKey: import_zod.z.string().optional()
});
var ConfigSchema = import_zod.z.object({
version: import_zod.z.string(),
ide: import_zod.z.string(),
encryption: EncryptionConfigSchema,
storagePath: import_zod.z.string(),
logger: LoggerConfigSchema,
experimental: import_zod.z.record(import_zod.z.string(), import_zod.z.boolean()).optional(),
extensions: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional()
});
var ScriptSchema = import_zod.z.object({
name: import_zod.z.string().min(1, "Script name is required"),
rootPath: import_zod.z.string().min(1, "Root path is required"),
script: import_zod.z.string().min(1, "Script command is required")
});
var ScriptIndexEntrySchema = import_zod.z.object({
rootPath: import_zod.z.string().min(1, "Root path is required"),
referenceFile: import_zod.z.string().min(1, "Reference file path is required")
});
var ScriptIndexSchema = import_zod.z.object({
entries: import_zod.z.array(ScriptIndexEntrySchema)
});
var ScriptCollectionSchema = import_zod.z.object({
scripts: import_zod.z.array(ScriptSchema)
});
var GitFileStatusSchema = import_zod.z.enum(["modified", "added", "deleted", "untracked", "renamed", "copied", "updated"]);
var GitFileSchema = import_zod.z.object({
path: import_zod.z.string(),
status: GitFileStatusSchema,
staged: import_zod.z.boolean()
});
var GitStatusSchema = import_zod.z.object({
isDirty: import_zod.z.boolean(),
dirtyFiles: import_zod.z.array(GitFileSchema),
newFiles: import_zod.z.array(GitFileSchema),
modifiedFiles: import_zod.z.array(GitFileSchema),
deletedFiles: import_zod.z.array(GitFileSchema),
untrackedFiles: import_zod.z.array(GitFileSchema)
});
var GitStashSchema = import_zod.z.object({
id: import_zod.z.string(),
name: import_zod.z.string(),
message: import_zod.z.string(),
timestamp: import_zod.z.number(),
branch: import_zod.z.string()
});
var GitStashResultSchema = import_zod.z.object({
success: import_zod.z.boolean(),
stashId: import_zod.z.string().optional(),
error: import_zod.z.string().optional()
});
var GitStashApplyResultSchema = import_zod.z.object({
success: import_zod.z.boolean(),
conflicts: import_zod.z.array(import_zod.z.string()).optional(),
error: import_zod.z.string().optional()
});
var TerminalCommandSchema = import_zod.z.object({
command: import_zod.z.string(),
args: import_zod.z.array(import_zod.z.string()).optional(),
cwd: import_zod.z.string().optional(),
env: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional(),
timeout: import_zod.z.number().optional()
});
var TerminalResultSchema = import_zod.z.object({
success: import_zod.z.boolean(),
exitCode: import_zod.z.number(),
stdout: import_zod.z.string(),
stderr: import_zod.z.string(),
duration: import_zod.z.number(),
error: import_zod.z.string().optional()
});
var TerminalOptionsSchema = import_zod.z.object({
cwd: import_zod.z.string().optional(),
env: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional(),
timeout: import_zod.z.number().optional(),
shell: import_zod.z.string().optional()
});
var FileStateSchema = import_zod.z.object({
path: import_zod.z.string(),
cursor: import_zod.z.object({ line: import_zod.z.number(), column: import_zod.z.number() }).optional(),
scroll: import_zod.z.object({ top: import_zod.z.number(), left: import_zod.z.number() }).optional(),
isActive: import_zod.z.boolean()
});
var GitStateSchema = import_zod.z.object({
branch: import_zod.z.string(),
commit: import_zod.z.string(),
isDirty: import_zod.z.boolean(),
stashId: import_zod.z.string().nullable().optional()
});
var SessionSchema = import_zod.z.object({
id: import_zod.z.string(),
name: import_zod.z.string(),
projectRoot: import_zod.z.string(),
createdAt: import_zod.z.union([import_zod.z.string(), import_zod.z.date()]).transform((val) => typeof val === "string" ? new Date(val) : val),
updatedAt: import_zod.z.union([import_zod.z.string(), import_zod.z.date()]).transform((val) => typeof val === "string" ? new Date(val) : val),
tags: import_zod.z.array(import_zod.z.string()),
notes: import_zod.z.string().optional(),
files: import_zod.z.array(FileStateSchema),
git: GitStateSchema,
extensions: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional()
});
var SessionIndexEntrySchema = import_zod.z.object({
id: import_zod.z.string(),
name: import_zod.z.string(),
projectRoot: import_zod.z.string(),
createdAt: import_zod.z.union([import_zod.z.string(), import_zod.z.date()]),
updatedAt: import_zod.z.union([import_zod.z.string(), import_zod.z.date()]),
tags: import_zod.z.array(import_zod.z.string()),
notes: import_zod.z.string().optional(),
referenceFile: import_zod.z.string()
});
var SessionIndexSchema = import_zod.z.object({
version: import_zod.z.string(),
sessions: import_zod.z.array(SessionIndexEntrySchema)
});
function validateFileStorageConfig(data) {
return FileStorageConfigSchema.parse(data);
}
function validateConfig(data) {
return ConfigSchema.parse(data);
}
function validateScript(data) {
return ScriptSchema.parse(data);
}
function validateScriptIndex(data) {
return ScriptIndexSchema.parse(data);
}
function validateScriptCollection(data) {
return ScriptCollectionSchema.parse(data);
}
function validateSession(data) {
return SessionSchema.parse(data);
}
function validateSessionIndex(data) {
return SessionIndexSchema.parse(data);
}
// packages/core/domain/types/ErrorTypes.ts
var ErrorCode = /* @__PURE__ */ ((ErrorCode2) => {
ErrorCode2["UNKNOWN"] = "UNKNOWN";
ErrorCode2["CONFIG_INVALID"] = "CONFIG_INVALID";
ErrorCode2["STORAGE_INVALID_PATH"] = "STORAGE_INVALID_PATH";
ErrorCode2["STORAGE_DECRYPTION_FAILED"] = "STORAGE_DECRYPTION_FAILED";
ErrorCode2["STORAGE_READ_FAILED"] = "STORAGE_READ_FAILED";
ErrorCode2["STORAGE_WRITE_FAILED"] = "STORAGE_WRITE_FAILED";
ErrorCode2["STORAGE_DELETE_FAILED"] = "STORAGE_DELETE_FAILED";
ErrorCode2["ENCRYPTION_FAILED"] = "ENCRYPTION_FAILED";
ErrorCode2["ENCRYPTION_INVALID_FORMAT"] = "ENCRYPTION_INVALID_FORMAT";
ErrorCode2["SCRIPT_INVALID"] = "SCRIPT_INVALID";
ErrorCode2["SCRIPT_DUPLICATE"] = "SCRIPT_DUPLICATE";
ErrorCode2["SCRIPT_NOT_FOUND"] = "SCRIPT_NOT_FOUND";
ErrorCode2["SCRIPT_PATH_INVALID"] = "SCRIPT_PATH_INVALID";
ErrorCode2["SCRIPT_MALICIOUS"] = "SCRIPT_MALICIOUS";
ErrorCode2["GIT_NOT_REPOSITORY"] = "GIT_NOT_REPOSITORY";
ErrorCode2["GIT_COMMAND_FAILED"] = "GIT_COMMAND_FAILED";
ErrorCode2["GIT_STASH_NOT_FOUND"] = "GIT_STASH_NOT_FOUND";
ErrorCode2["GIT_STASH_CONFLICT"] = "GIT_STASH_CONFLICT";
ErrorCode2["TERMINAL_COMMAND_FAILED"] = "TERMINAL_COMMAND_FAILED";
ErrorCode2["TERMINAL_TIMEOUT"] = "TERMINAL_TIMEOUT";
ErrorCode2["TERMINAL_COMMAND_NOT_FOUND"] = "TERMINAL_COMMAND_NOT_FOUND";
return ErrorCode2;
})(ErrorCode || {});
var AppError = class extends Error {
constructor(message, code = "UNKNOWN" /* UNKNOWN */, meta) {
super(message);
this.name = "AppError";
this.code = code;
this.meta = meta;
}
};
var ConfigError = class extends AppError {
constructor(message, meta) {
super(message, "CONFIG_INVALID" /* CONFIG_INVALID */, meta);
this.name = "ConfigError";
}
};
var StorageError = class extends AppError {
constructor(message, code = "STORAGE_READ_FAILED" /* STORAGE_READ_FAILED */, meta) {
super(message, code, meta);
this.name = "StorageError";
}
};
var EncryptionError = class extends AppError {
constructor(message, code = "ENCRYPTION_FAILED" /* ENCRYPTION_FAILED */, meta) {
super(message, code, meta);
this.name = "EncryptionError";
}
};
var ScriptError = class extends AppError {
constructor(message, code = "SCRIPT_INVALID" /* SCRIPT_INVALID */, meta) {
super(message, code, meta);
this.name = "ScriptError";
}
};
var GitError = class extends AppError {
constructor(message, code = "GIT_COMMAND_FAILED" /* GIT_COMMAND_FAILED */, meta) {
super(message, code, meta);
this.name = "GitError";
}
};
var TerminalError = class extends AppError {
constructor(message, code = "TERMINAL_COMMAND_FAILED" /* TERMINAL_COMMAND_FAILED */, meta) {
super(message, code, meta);
this.name = "TerminalError";
}
};
// packages/core/infrastructure/repositories/ConfigRepository.ts
var fs = __toESM(require("fs/promises"));
var path = __toESM(require("path"));
var DEFAULT_CONFIG_PATH = path.join(
process.env.HOME || process.env.USERPROFILE || ".",
".codestate",
"config.json"
);
var TEMP_SUFFIX = ".tmp";
var BACKUP_SUFFIX = ".bak";
function getDefaultConfig() {
return {
version: "1.0.0",
ide: "vscode",
encryption: { enabled: false },
storagePath: path.join(
process.env.HOME || process.env.USERPROFILE || ".",
".codestate"
),
logger: {
level: "LOG",
sinks: ["file"],
filePath: path.join(
process.env.HOME || process.env.USERPROFILE || ".",
".codestate",
"logs",
"codestate.log"
)
},
experimental: {},
extensions: {}
};
}
var ConfigRepository = class {
constructor(logger, encryption, configPath = DEFAULT_CONFIG_PATH) {
this.logger = logger;
this.encryption = encryption;
this.configPath = configPath;
}
async load() {
try {
await this.ensureDir();
this.logger.debug("Attempting to load config", { path: this.configPath });
const raw = await fs.readFile(this.configPath, { encoding: "utf8" });
let data = raw;
if (raw.startsWith("ENCRYPTED_v1")) {
this.logger.log("Config file is encrypted. Attempting decryption.", {
path: this.configPath
});
const key = "";
const decrypted = await this.encryption.decrypt(raw, key);
if (isFailure(decrypted)) {
this.logger.error("Decryption failed", { error: decrypted.error });
return { ok: false, error: decrypted.error };
}
data = decrypted.value;
}
let parsed;
try {
parsed = JSON.parse(data);
} catch (parseErr) {
this.logger.error(
"Config file is corrupt (invalid JSON). Backing up and creating default.",
{ path: this.configPath }
);
await this.backupCorruptConfig();
const defaults = getDefaultConfig();
await this.save(defaults);
return { ok: true, value: defaults };
}
let config;
try {
config = validateConfig(parsed);
} catch (validationErr) {
this.logger.error(
"Config file is corrupt (schema validation failed). Backing up and creating default.",
{ path: this.configPath }
);
await this.backupCorruptConfig();
const defaults = getDefaultConfig();
await this.save(defaults);
return { ok: true, value: defaults };
}
this.logger.log("Config loaded successfully", {
path: this.configPath,
encrypted: raw.startsWith("ENCRYPTED_v1")
});
return { ok: true, value: config };
} catch (err) {
if (err.code === "ENOENT") {
this.logger.warn("Config file not found. Creating default config.", {
path: this.configPath
});
const defaults = getDefaultConfig();
await this.save(defaults);
return { ok: true, value: defaults };
}
this.logger.error("Failed to load config", {
error: err.message,
path: this.configPath
});
return { ok: false, error: new ConfigError(err.message) };
}
}
async save(config) {
try {
await this.ensureDir();
this.logger.debug("Attempting to save config", { path: this.configPath });
const validated = validateConfig(config);
let data = JSON.stringify(validated, null, 2);
let encrypted = false;
if (config.encryption?.enabled && config.encryption.encryptionKey) {
this.logger.log("Encrypting config before save", {
path: this.configPath
});
const encResult = await this.encryption.encrypt(
data,
config.encryption.encryptionKey
);
if (isFailure(encResult)) {
this.logger.error("Encryption failed", { error: encResult.error });
return { ok: false, error: encResult.error };
}
data = encResult.value;
encrypted = true;
}
const tempPath = this.configPath + TEMP_SUFFIX;
await fs.writeFile(tempPath, data, { encoding: "utf8", mode: 384 });
this.logger.debug("Temp config file written", { tempPath });
await fs.rename(this.configPath, this.configPath + BACKUP_SUFFIX).then(() => {
this.logger.log("Config backup created", {
backupPath: this.configPath + BACKUP_SUFFIX
});
}).catch(() => {
});
await fs.rename(tempPath, this.configPath);
this.logger.log("Config saved successfully", {
path: this.configPath,
encrypted
});
return { ok: true, value: void 0 };
} catch (err) {
this.logger.error("Failed to save config", {
error: err.message,
path: this.configPath
});
return { ok: false, error: new ConfigError(err.message) };
}
}
async ensureDir() {
const dir = path.dirname(this.configPath);
await fs.mkdir(dir, { recursive: true, mode: 448 }).then(() => {
this.logger.debug("Ensured config directory exists", { dir });
}).catch(() => {
});
}
async backupCorruptConfig() {
try {
const backupPath = this.configPath + ".bak." + Date.now();
await fs.rename(this.configPath, backupPath);
this.logger.warn("Backed up corrupt config file", { backupPath });
} catch (err) {
this.logger.error("Failed to backup corrupt config file", {
error: err.message
});
}
}
};
// packages/core/infrastructure/services/FileLogger.ts
var import_fs = require("fs");
var path2 = __toESM(require("path"));
var LOG_LEVEL_PRIORITY = {
"ERROR": 0,
"WARN": 1,
"LOG": 2,
"DEBUG": 3
};
var FileLogger = class {
constructor(config) {
if (!config.filePath)
throw new Error("FileLogger requires filePath in LoggerConfig");
this.level = config.level;
this.filePath = config.filePath;
this.ensureLogDirectory();
}
plainLog(message, meta) {
const entry = {
level: "plain",
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
message,
...meta ? { meta } : {}
};
(0, import_fs.appendFileSync)(this.filePath, JSON.stringify(entry) + "\n", { encoding: "utf8" });
}
ensureLogDirectory() {
const logDir = path2.dirname(this.filePath);
try {
(0, import_fs.mkdirSync)(logDir, { recursive: true });
} catch (error) {
}
}
shouldLog(messageLevel) {
return LOG_LEVEL_PRIORITY[this.level] >= LOG_LEVEL_PRIORITY[messageLevel];
}
write(level, message, meta) {
const entry = {
level,
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
message,
...meta ? { meta } : {}
};
(0, import_fs.appendFileSync)(this.filePath, JSON.stringify(entry) + "\n", { encoding: "utf8" });
}
log(message, meta) {
if (!this.shouldLog("LOG"))
return;
this.write("log", message, meta);
}
error(message, meta) {
if (!this.shouldLog("ERROR"))
return;
this.write("error", message, meta);
}
warn(message, meta) {
if (!this.shouldLog("WARN"))
return;
this.write("warn", message, meta);
}
debug(message, meta) {
if (!this.shouldLog("DEBUG"))
return;
this.write("debug", message, meta);
}
};
// packages/core/infrastructure/services/BasicEncryption.ts
var import_crypto = require("crypto");
var HEADER = "ENCRYPTED_v1";
var SALT_LENGTH = 16;
var IV_LENGTH = 12;
var KEY_LENGTH = 32;
var PBKDF2_ITER = 1e5;
var BasicEncryption = class {
constructor(logger) {
this.logger = logger;
}
async encrypt(data, key) {
try {
const salt = (0, import_crypto.randomBytes)(SALT_LENGTH);
const iv = (0, import_crypto.randomBytes)(IV_LENGTH);
const derivedKey = (0, import_crypto.pbkdf2Sync)(
key,
salt,
PBKDF2_ITER,
KEY_LENGTH,
"sha512"
);
const cipher = (0, import_crypto.createCipheriv)("aes-256-gcm", derivedKey, iv);
const ciphertext = Buffer.concat([
cipher.update(data, "utf8"),
cipher.final()
]);
const authTag = cipher.getAuthTag();
this.logger.debug("Data encrypted", {
algorithm: "AES-256-GCM",
operation: "encrypt"
});
return {
ok: true,
value: [
HEADER,
iv.toString("base64"),
salt.toString("base64"),
ciphertext.toString("base64"),
authTag.toString("base64")
].join(":")
};
} catch (err) {
this.logger.error("Encryption failed", {
error: err instanceof Error ? err.message : err,
operation: "encrypt"
});
return {
ok: false,
error: new EncryptionError(
"Encryption failed",
"ENCRYPTION_FAILED" /* ENCRYPTION_FAILED */,
{
originalError: err instanceof Error ? err.message : err,
operation: "encrypt"
}
)
};
}
}
async decrypt(data, key) {
try {
const parts = data.split(":");
if (parts[0] !== HEADER || parts.length !== 5) {
this.logger.error("Invalid encrypted data format", {
operation: "decrypt"
});
return {
ok: false,
error: new EncryptionError(
"Invalid encrypted data format",
"ENCRYPTION_INVALID_FORMAT" /* ENCRYPTION_INVALID_FORMAT */,
{ operation: "decrypt" }
)
};
}
const [, ivB64, saltB64, ciphertextB64, authTagB64] = parts;
const iv = Buffer.from(ivB64, "base64");
const salt = Buffer.from(saltB64, "base64");
const ciphertext = Buffer.from(ciphertextB64, "base64");
const authTag = Buffer.from(authTagB64, "base64");
const derivedKey = (0, import_crypto.pbkdf2Sync)(
key,
salt,
PBKDF2_ITER,
KEY_LENGTH,
"sha512"
);
const decipher = (0, import_crypto.createDecipheriv)("aes-256-gcm", derivedKey, iv);
decipher.setAuthTag(authTag);
const plaintext = Buffer.concat([
decipher.update(ciphertext),
decipher.final()
]);
this.logger.debug("Data decrypted", {
algorithm: "AES-256-GCM",
operation: "decrypt"
});
return { ok: true, value: plaintext.toString("utf8") };
} catch (err) {
this.logger.error("Decryption failed", {
error: err instanceof Error ? err.message : err,
operation: "decrypt"
});
return {
ok: false,
error: new EncryptionError(
"Decryption failed",
"ENCRYPTION_FAILED" /* ENCRYPTION_FAILED */,
{
originalError: err instanceof Error ? err.message : err,
operation: "decrypt"
}
)
};
}
}
};
// packages/core/services/config/ConfigFacade.ts
var path3 = __toESM(require("path"));
var ConfigFacade = class {
constructor(configPath, logger, encryption) {
const _logger = logger || new FileLogger({
level: "LOG",
sinks: ["file"],
filePath: path3.join(process.env.HOME || process.env.USERPROFILE || ".", ".codestate", "logs", "codestate.log")
});
const _encryption = encryption || new BasicEncryption(_logger);
const repository = new ConfigRepository(_logger, _encryption, configPath);
this.service = new ConfigService(repository, _logger);
}
async getConfig(...args) {
return this.service.getConfig(...args);
}
async setConfig(...args) {
return this.service.setConfig(...args);
}
async updateConfig(...args) {
return this.service.updateConfig(...args);
}
};
// packages/core/use-cases/config/GetConfig.ts
var GetConfig = class {
constructor(configService) {
this.configService = configService || new ConfigFacade();
}
async execute() {
return this.configService.getConfig();
}
};
// packages/core/use-cases/config/UpdateConfig.ts
var UpdateConfig = class {
constructor(configService) {
this.configService = configService || new ConfigFacade();
}
async execute(partial) {
return this.configService.updateConfig(partial);
}
};
// packages/core/use-cases/config/ResetConfig.ts
var path4 = __toESM(require("path"));
function getDefaultConfig2() {
return {
version: "1.0.0",
ide: "vscode",
encryption: { enabled: false },
storagePath: path4.join(process.env.HOME || process.env.USERPROFILE || ".", ".codestate"),
logger: {
level: "LOG",
sinks: ["file"],
filePath: path4.join(process.env.HOME || process.env.USERPROFILE || ".", ".codestate", "logs", "codestate.log")
},
experimental: {},
extensions: {}
};
}
var ResetConfig = class {
constructor(configService) {
this.configService = configService || new ConfigFacade();
}
async execute() {
const result = await this.configService.setConfig(getDefaultConfig2());
if (isFailure(result))
return { ok: false, error: result.error };
return { ok: true, value: getDefaultConfig2() };
}
};
// packages/core/use-cases/config/ExportConfig.ts
var ExportConfig = class {
constructor(configService) {
this.configService = configService || new ConfigFacade();
}
async execute() {
const result = await this.configService.getConfig();
if (isFailure(result))
return { ok: false, error: result.error };
return { ok: true, value: JSON.stringify(result.value, null, 2) };
}
};
// packages/core/use-cases/config/ImportConfig.ts
var ImportConfig = class {
constructor(configService) {
this.configService = configService || new ConfigFacade();
}
async execute(json) {
let parsed;
try {
parsed = validateConfig(JSON.parse(json));
} catch (err) {
return { ok: false, error: err };
}
const result = await this.configService.setConfig(parsed);
if (isFailure(result))
return { ok: false, error: result.error };
return { ok: true, value: parsed };
}
};
// packages/core/services/scripts/ScriptService.ts
var ScriptService = class {
constructor(repository, logger) {
this.repository = repository;
this.logger = logger;
}
async createScript(script) {
this.logger.debug("ScriptService.createScript called", { script });
const result = await this.repository.createScript(script);
if (isFailure(result)) {
this.logger.error("Failed to create script", { error: result.error, script });
} else {
this.logger.log("Script created successfully", { script });
}
return result;
}
async createScripts(scripts) {
this.logger.debug("ScriptService.createScripts called", { count: scripts.length });
const result = await this.repository.createScripts(scripts);
if (isFailure(result)) {
this.logger.error("Failed to create scripts", { error: result.error, count: scripts.length });
} else {
this.logger.log("Scripts created successfully", { count: scripts.length });
}
return result;
}
async getScriptsByRootPath(rootPath) {
this.logger.debug("ScriptService.getScriptsByRootPath called", { rootPath });
const result = await this.repository.getScriptsByRootPath(rootPath);
if (isFailure(result)) {
this.logger.error("Failed to get scripts by root path", { error: result.error, rootPath });
} else {
this.logger.log("Scripts retrieved by root path", { rootPath, count: result.value.length });
}
return result;
}
async getAllScripts() {
this.logger.debug("ScriptService.getAllScripts called");
const result = await this.repository.getAllScripts();
if (isFailure(result)) {
this.logger.error("Failed to get all scripts", { error: result.error });
} else {
this.logger.log("All scripts retrieved", { count: result.value.length });
}
return result;
}
async updateScript(name, rootPath, scriptUpdate) {
this.logger.debug("ScriptService.updateScript called", { name, rootPath, scriptUpdate });
const result = await this.repository.updateScript(name, rootPath, scriptUpdate);
if (isFailure(result)) {
this.logger.error("Failed to update script", { error: result.error, name, rootPath });
} else {
this.logger.log("Script updated successfully", { name, rootPath });
}
return result;
}
async updateScripts(updates) {
this.logger.debug("ScriptService.updateScripts called", { count: updates.length });
const result = await this.repository.updateScripts(updates);
if (isFailure(result)) {
this.logger.error("Failed to update scripts", { error: result.error, count: updates.length });
} else {
this.logger.log("Scripts updated successfully", { count: updates.length });
}
return result;
}
async deleteScript(name, rootPath) {
this.logger.debug("ScriptService.deleteScript called", { name, rootPath });
const result = await this.repository.deleteScript(name, rootPath);
if (isFailure(result)) {
this.logger.error("Failed to delete script", { error: result.error, name, rootPath });
} else {
this.logger.log("Script deleted successfully", { name, rootPath });
}
return result;
}
async deleteScripts(scripts) {
this.logger.debug("ScriptService.deleteScripts called", { count: scripts.length });
const result = await this.repository.deleteScripts(scripts);
if (isFailure(result)) {
this.logger.error("Failed to delete scripts", { error: result.error, count: scripts.length });
} else {
this.logger.log("Scripts deleted successfully", { count: scripts.length });
}
return result;
}
async deleteScriptsByRootPath(rootPath) {
this.logger.debug("ScriptService.deleteScriptsByRootPath called", { rootPath });
const result = await this.repository.deleteScriptsByRootPath(rootPath);
if (isFailure(result)) {
this.logger.error("Failed to delete scripts by root path", { error: result.error, rootPath });
} else {
this.logger.log("Scripts deleted by root path successfully", { rootPath });
}
return result;
}
async getScriptIndex() {
this.logger.debug("ScriptService.getScriptIndex called");
const result = await this.repository.loadScriptIndex();
if (isFailure(result)) {
this.logger.error("Failed to get script index", { error: result.error });
} else {
this.logger.log("Script index retrieved", { entryCount: result.value.entries.length });
}
return result;
}
async updateScriptIndex(index) {
this.logger.debug("ScriptService.updateScriptIndex called");
const result = await this.repository.saveScriptIndex(index);
if (isFailure(result)) {
this.logger.error("Failed to update script index", { error: result.error });
} else {
this.logger.log("Script index updated successfully");
}
return result;
}
};
// packages/core/infrastructure/repositories/ScriptRepository.ts
var fs2 = __toESM(require("fs/promises"));
var path5 = __toESM(require("path"));
var DEFAULT_SCRIPTS_DIR = path5.join(
process.env.HOME || process.env.USERPROFILE || ".",
".codestate",
"scripts"
);
var INDEX_FILE = "index.json";
var TEMP_SUFFIX2 = ".tmp";
var BACKUP_SUFFIX2 = ".bak";
var ScriptRepository = class {
constructor(logger, encryption, configService, scriptsDir = DEFAULT_SCRIPTS_DIR) {
this.logger = logger;
this.encryption = encryption;
this.configService = configService;
this.scriptsDir = scriptsDir;
}
async createScript(script) {
try {
await this.ensureScriptsDir();
const validatedScript = validateScript(script);
if (!await this.pathExists(validatedScript.rootPath)) {
this.logger.error("Root path does not exist", {
rootPath: validatedScript.rootPath
});
return {
ok: false,
error: new ScriptError(
"Root path does not exist",
"SCRIPT_PATH_INVALID" /* SCRIPT_PATH_INVALID */,
{ rootPath: validatedScript.rootPath }
)
};
}
const existingScripts = await this.getScriptsByRootPath(
validatedScript.rootPath
);
if (existingScripts.ok) {
const duplicate = existingScripts.value.find(
(s) => s.script === validatedScript.script
);
if (duplicate) {
this.logger.error("Duplicate script command found", {
script: validatedScript.script,
rootPath: validatedScript.rootPath
});
return {
ok: false,
error: new ScriptError(
"Script command already exists",
"SCRIPT_DUPLICATE" /* SCRIPT_DUPLICATE */,
{
script: validatedScript.script,
rootPath: validatedScript.rootPath
}
)
};
}
}
const collection = await this.getOrCreateScriptCollection(
validatedScript.rootPath
);
if (isFailure(collection)) {
return { ok: false, error: collection.error };
}
collection.value.scripts.push(validatedScript);
const saveResult = await this.saveScriptCollection(
validatedScript.rootPath,
collection.value
);
if (isFailure(saveResult)) {
return { ok: false, error: saveResult.error };
}
await this.updateIndexForRootPath(validatedScript.rootPath);
this.logger.log("Script created successfully", {
name: validatedScript.name,
rootPath: validatedScript.rootPath
});
return { ok: true, value: void 0 };
} catch (err) {
this.logger.error("Failed to create script", {
error: err.message,
script
});
return {
ok: false,
error: new ScriptError(err.message, "SCRIPT_INVALID" /* SCRIPT_INVALID */, {
originalError: err.message
})
};
}
}
async createScripts(scripts) {
try {
if (scripts.length === 0) {
return { ok: true, value: void 0 };
}
this.logger.debug("Creating multiple scripts", { count: scripts.length });
const scriptsByRootPath = /* @__PURE__ */ new Map();
for (const script of scripts) {
const validatedScript = validateScript(script);
if (!await this.pathExists(validatedScript.rootPath)) {
this.logger.error("Root path does not exist", {
rootPath: validatedScript.rootPath
});
return {
ok: false,
error: new ScriptError(
"Root path does not exist",
"SCRIPT_PATH_INVALID" /* SCRIPT_PATH_INVALID */,
{ rootPath: validatedScript.rootPath }
)
};
}
if (!scriptsByRootPath.has(validatedScript.rootPath)) {
scriptsByRootPath.set(validatedScript.rootPath, []);
}
scriptsByRootPath.get(validatedScript.rootPath).push(validatedScript);
}
for (const [rootPath, rootScripts] of scriptsByRootPath) {
const existingScripts = await this.getScriptsByRootPath(rootPath);
const existingCollection = existingScripts.ok ? existingScripts.value : [];
const allScripts = [...existingCollection, ...rootScripts];
const scriptCommands = /* @__PURE__ */ new Set();
const duplicates = [];
for (const script of allScripts) {
if (scriptCommands.has(script.script)) {
duplicates.push(script.script);
} else {
scriptCommands.add(script.script);
}
}
if (duplicates.length > 0) {
this.logger.error("Duplicate script commands found", {
duplicates,
rootPath
});
return {
ok: false,
error: new ScriptError(
"Duplicate script commands found",
"SCRIPT_DUPLICATE" /* SCRIPT_DUPLICATE */,
{ duplicates, rootPath }
)
};
}
const collection = { scripts: allScripts };
const saveResult = await this.saveScriptCollection(
rootPath,
collection
);
if (isFailure(saveResult)) {
return { ok: false, error: saveResult.error };
}
await this.updateIndexForRootPath(rootPath);
}
this.logger.log("Multiple scripts created successfully", {
count: scripts.length
});
return { ok: true, value: void 0 };
} catch (err) {
this.logger.error("Failed to create multiple scripts", {
error: err.message,
count: scripts.length
});
return {
ok: false,
error: new ScriptError(err.message, "SCRIPT_INVALID" /* SCRIPT_INVALID */, {
originalError: err.message
})
};
}
}
async getScriptsByRootPath(rootPath) {
try {
const collection = await this.loadScriptCollection(rootPath);
if (isFailure(collection)) {
return { ok: true, value: [] };
}
return { ok: true, value: collection.value.scripts };
} catch (err) {
this.logger.error("Failed to get scripts by root path", {
error: err.message,
rootPath
});
return {
ok: false,
error: new ScriptError(err.message, "SCRIPT_INVALID" /* SCRIPT_INVALID */, {
originalError: err.message
})
};
}
}
async getAllScripts() {
try {
const index = await this.loadScriptIndex();
if (isFailure(index)) {
return { ok: true, value: [] };
}
const allScripts = [];
for (const entry of index.value.entries) {
const scripts = await this.getScriptsByRootPath(entry.rootPath);
if (scripts.ok) {
allScripts.push(...scripts.value);
}
}
return { ok: true, value: allScripts };
} catch (err) {
this.logger.error("Failed to get all scripts", { error: err.message });
return {
ok: false,
error: new ScriptError(err.message, "SCRIPT_INVALID" /* SCRIPT_INVALID */, {
originalError: err.message
})
};
}
}
async updateScript(name, rootPath, scriptUpdate) {
try {
const scripts = await this.getScriptsByRootPath(rootPath);
if (isFailure(scripts)) {
return { ok: false, error: scripts.error };
}
const scriptIndex = scripts.value.findIndex((s) => s.name === name);
if (scriptIndex === -1) {
this.logger.error("Script not found", { name, rootPath });
return {
ok: false,
error: new ScriptError(
"Script not found",
"SCRIPT_NOT_FOUND" /* SCRIPT_NOT_FOUND */,
{ name, rootPath }
)
};
}
const updatedScript = { ...scripts.value[scriptIndex], ...scriptUpdate };
const validatedScript = validateScript(updatedScript);
const duplicate = scripts.value.find(
(s) => s.script === validatedScript.script && s.name !== name
);
if (duplicate) {
this.logger.error("Duplicate script command found", {
script: validatedScript.script,
rootPath
});
return {
ok: false,
error: new ScriptError(
"Script command already exists",
"SCRIPT_DUPLICATE" /* SCRIPT_DUPLICATE */,
{ script: validatedScript.script, rootPath }
)
};
}
scripts.value[scriptIndex] = validatedScript;
const collection = { scripts: scripts.value };
const saveResult = await this.saveScriptCollection(rootPath, collection);
if (isFailure(saveResult)) {
return { ok: false, error: saveResult.error };
}
this.logger.log("Script updated successfully", { name, rootPath });
return { ok: true, value: void 0 };
} catch (err) {
this.logger.error("Failed to update script", {
error: err.message,
name,
rootPath
});
return {
ok: false,
error: new ScriptError(err.message, "SCRIPT_INVALID" /* SCRIPT_INVALID */, {
originalError: err.message
})
};
}
}
async updateScripts(updates) {
try {
if (updates.length === 0) {
return { ok: true, value: void 0 };
}
this.logger.debug("Updating multiple scripts", { count: updates.length });
const updatesByRootPath = /* @__PURE__ */ new Map();
for (const update of updates) {
if (!updatesByRootPath.has(update.rootPath)) {
updatesByRootPath.set(update.rootPath, []);
}
updatesByRootPath.get(update.rootPath).push({ name: update.name, script: update.script });
}
for (const [rootPath, rootUpdates] of updatesByRootPath) {
const scripts = await this.getScriptsByRootPath(rootPath);
if (isFailure(scripts)) {
return { ok: false, error: scripts.error };
}
const updatedScripts = [...scripts.value];
const updatedNames = /* @__PURE__ */ new Set();
for (const update of rootUpdates) {
const scriptIndex = updatedScripts.findIndex(
(s) => s.name === update.name
);
if (scriptIndex === -1) {
this.logger.error("Script not found for update", {
name: update.name,
rootPath
});
return {
ok: false,
error: new ScriptError(
"Script not found",
"SCRIPT_NOT_FOUND" /* SCRIPT_NOT_FOUND */,
{ name: update.name, rootPath }
)
};
}
const updatedScript = {
...updatedScripts[scriptIndex],
...update.script
};
const validatedScript = validateScript(updatedScript);
updatedScripts[scriptIndex] = validatedScript;
updatedNames.add(update.name);
}
const scriptCommands = /* @__PURE__ */ new Set();
const duplicates = [];
for (const script of updatedScripts) {
if (scriptCommands.has(script.script)) {
if (!updatedNames.has(script.name)) {
duplicates.push(script.script);
}
} else {
scriptCommands.add(script.script);
}
}
if (duplicates.length > 0) {
this.logger.error("Duplicate script commands found after updates", {
duplicates,
rootPath
});
return {
ok: false,
error: new ScriptError(
"Duplicate script commands found",
"SCRIPT_DUPLICATE" /* SCRIPT_DUPLICATE */,
{ duplicates, rootPath }
)
};
}
const collection = { scripts: updatedScripts };
const saveResult = await this.saveScriptCollection(
rootPath,
collection
);
if (isFailure(saveResult)) {
return { ok: false, error: saveResult.error };
}
}
this.logger.log("Multiple scripts updated successfully", {
count: updates.length
});
return { ok: true, value: void 0 };
} catch (err) {
this.logger.error("Failed to update multiple scripts", {
error: err.message,
count: updates.length
});
return {
ok: false,
error: new ScriptError(err.message, "SCRIPT_INVALID" /* SCRIPT_INVALID */, {
originalError: err.message
})
};
}
}
async deleteScript(name, rootPath) {
try {
const scripts = await this.getScriptsByRootPath(rootPath);
if (isFailure(scripts)) {
return { ok: false, error: scripts.error };
}
const scriptIndex = scripts.value.findIndex((s) => s.name === name);
if (scriptIndex === -1) {
this.logger.error("Script not found", { name, rootPath });
return {
ok: false,
error: new ScriptError(
"Script not found",
"SCRIPT_NOT_FOUND" /* SCRIPT_NOT_FOUND */,
{ name, rootPath }
)
};
}
scripts.value.splice(scriptIndex, 1);
const collection = { scripts: scripts.value };
const saveResult = await this.saveScriptCollection(rootPath, collection);
if (isFailure(saveResult)) {
return { ok: false, error: saveResult.error };
}
this.logger.log("Script deleted successfully", { name, rootPath });
return { ok: true, value: void 0 };
} catch (err) {
this.logger.error("Failed to delete script", {
error: err.message,
name,
rootPath
});
return {
ok: false,
error: new ScriptError(err.message, "SCRIPT_INVALID" /* SCRIPT_INVALID */, {
originalError: err.message
})
};
}
}
async deleteScripts(scripts) {
try {
if (scripts.length === 0) {
return { ok: true, value: void 0 };
}
this.logger.debug("Deleting multiple scripts", { count: scripts.length });
const deletionsByRootPath = /* @__PURE__ */ new Map();
for (const script of scripts) {
if (!deletionsByRootPath.has(script.rootPath)) {
deletionsByRootPath.set(script.rootPath, []);
}
deletionsByRootPath.get(script.rootPath).push(script.name);
}
for (const [rootPath, scriptNames] of deletionsByRootPath) {
const existingScripts = await this.getScriptsByRootPath(rootPath);
if (isFailure(existingScripts)) {
return { ok: false, error: existingScripts.error };
}
const remainingScripts = existingScripts.value.filter(
(script) => !scriptNames.includes(script.name)
);
const foundNames = existingScripts.value.filter((script) => scriptNames.includes(script.name)).map((s) => s.name);
const missingNames = scriptNames.filter(
(name) => !foundNames.includes(name)
);
if (missingNames.length > 0) {
this.logger.error("Some scripts not found for deletion", {
missingNames,
rootPath
});
return {
ok: false,
error: new ScriptError(
"Some scripts not found",
"SCRIPT_NOT_FOUND" /* SCRIPT_NOT_FOUND */,
{ missingNames, rootPath }
)
};
}
const collection = { scripts: remainingScripts };
const saveResult = await this.saveScriptCollection(
rootPath,
collection
);
if (isFailure(saveResult)) {
return { ok: false, error: saveResult.error };
}
}
this.logger.log("Multiple scripts deleted successfully", {
count: scripts.length
});
return { ok: true, value: void 0 };
} catch (err) {
this.logger.error("Failed to delete multiple scripts", {
error: err.message,
count: scripts.length
});
return {
ok: false,
error: new ScriptError(err.message, "SCRIPT_INVALID" /* SCRIPT_INVALID */, {
originalError: err.message
})
};
}
}
async deleteScriptsByRootPath(rootPath) {
try {
const referenceFile = await this.getReferenceFilePath(rootPath);
if (referenceFile) {
await fs2.unlink(referenceFi