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 __commonJS = (cb, mod) => function __require() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; 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); // tests/electron-stub.cjs var require_electron_stub = __commonJS({ "tests/electron-stub.cjs"(exports2, module2) { module2.exports = { BrowserWindow: { getAllWindows: () => [] }, app: {}, ipcMain: {}, safeStorage: { isEncryptionAvailable: () => false } }; } }); // src/main/commands.ts var commands_exports = {}; __export(commands_exports, { CommandsStore: () => CommandsStore, defaultCommandsPath: () => defaultCommandsPath }); module.exports = __toCommonJS(commands_exports); var import_electron = __toESM(require_electron_stub()); var import_crypto = require("crypto"); var import_fs = require("fs"); var import_promises = require("fs/promises"); var import_path = require("path"); var HISTORY_CAP = 500; function emptyFile() { return { history: [], library: [] }; } function defaultCommandsPath(userDataPath) { return userDataPath; } function two(n) { return String(n).padStart(2, "0"); } function stamp(d = /* @__PURE__ */ new Date()) { return `${d.getFullYear()}${two(d.getMonth() + 1)}${two(d.getDate())}-${two(d.getHours())}${two(d.getMinutes())}${two(d.getSeconds())}`; } var CommandsStore = class { /** /commands.json */ file; /** /logs */ logsDir; /** /logs/index.json */ indexFile; openPathImpl; /** All known logs keyed by absolute file path (hydrated from index on boot). */ metasByFile = /* @__PURE__ */ new Map(); /** Logs currently accumulating output, keyed by sessionId. */ activeBySession = /* @__PURE__ */ new Map(); constructor(userData, openPathImpl) { const ud = userData ?? import_electron.app.getPath("userData"); this.file = (0, import_path.join)(ud, "commands.json"); this.logsDir = (0, import_path.join)(ud, "logs"); this.indexFile = (0, import_path.join)(this.logsDir, "index.json"); this.openPathImpl = openPathImpl; this.hydrateIndex(); } // ---- commands file (history + library) ----------------------------------- loadCommands() { try { const raw = JSON.parse((0, import_fs.readFileSync)(this.file, "utf8")); if (raw && typeof raw === "object" && Array.isArray(raw.history)) { const data = raw; return { history: Array.isArray(data.history) ? data.history : [], library: Array.isArray(data.library) ? data.library : [] }; } } catch { } return emptyFile(); } saveCommands(data) { (0, import_fs.mkdirSync)((0, import_path.join)(this.file, ".."), { recursive: true }); (0, import_fs.writeFileSync)(this.file, JSON.stringify(data, null, 2), "utf8"); } /** Record one executed command: trim; dedupe vs newest; move to front; cap. */ recordCommand(cmd) { const trimmed = cmd.trim(); if (!trimmed) return; const data = this.loadCommands(); const top = data.history[0]; if (top && top.command === trimmed) { top.lastUsedAt = Date.now(); } else { data.history.unshift({ id: (0, import_crypto.randomUUID)(), command: trimmed, createdAt: Date.now(), lastUsedAt: Date.now() }); if (data.history.length > HISTORY_CAP) data.history.length = HISTORY_CAP; } this.saveCommands(data); } /** History sorted by most recently used. */ listHistory() { return this.loadCommands().history.slice().sort((a, b) => (b.lastUsedAt ?? 0) - (a.lastUsedAt ?? 0)); } clearHistory() { const data = this.loadCommands(); data.history = []; this.saveCommands(data); } /** Library sorted newest first. */ listLibrary() { return this.loadCommands().library.slice().sort((a, b) => b.createdAt - a.createdAt); } /** Insert (no id) or update (has id); returns the stored entry. */ saveLibraryItem(item) { const data = this.loadCommands(); let stored; if (typeof item.id === "string" && item.id.length > 0) { stored = data.library.find((x) => x.id === item.id); } if (stored) { stored.name = item.name; stored.command = item.command; stored.note = item.note; stored.group = item.group; stored.params = item.params; } else { stored = { id: item.id && item.id.length > 0 ? item.id : (0, import_crypto.randomUUID)(), name: item.name, command: item.command, note: item.note, group: item.group, params: item.params, createdAt: Date.now() }; data.library.push(stored); } this.saveCommands(data); return stored; } deleteLibraryItem(id) { const data = this.loadCommands(); const next = data.library.filter((x) => x.id !== id); if (next.length < data.library.length) { data.library = next; this.saveCommands(data); } } // ---- session logs ----------------------------------------------------------- hydrateIndex() { try { if (!(0, import_fs.existsSync)(this.indexFile)) return; const raw = JSON.parse((0, import_fs.readFileSync)(this.indexFile, "utf8")); if (!Array.isArray(raw)) return; for (const x of raw) { if (x && typeof x.sessionId === "string" && typeof x.file === "string") { const meta = x; this.metasByFile.set(meta.file, meta); if (meta.endedAt === void 0) this.activeBySession.set(meta.sessionId, meta); } } } catch { } } /** Write the full log index so listSessionLogs survives restart. */ persistIndex() { try { (0, import_fs.mkdirSync)(this.logsDir, { recursive: true }); const all = Array.from(this.metasByFile.values()).sort( (a, b) => b.startedAt - a.startedAt ); (0, import_fs.writeFileSync)(this.indexFile, JSON.stringify(all, null, 2), "utf8"); } catch { } } /** Finalize a log (set endedAt, drop from active, persist index). */ finishLog(meta) { meta.endedAt = Date.now(); this.activeBySession.delete(meta.sessionId); this.persistIndex(); } /** Start logging a session; any prior active log for the id is stopped first. */ logStart(sessionId) { const prev = this.activeBySession.get(sessionId); if (prev) this.finishLog(prev); (0, import_fs.mkdirSync)(this.logsDir, { recursive: true }); const fileName = `${stamp()}-${sessionId.slice(0, 8)}.log`; const file = (0, import_path.join)(this.logsDir, fileName); describeFile(file); const meta = { sessionId, file, fileName, startedAt: Date.now() }; this.metasByFile.set(file, meta); this.activeBySession.set(sessionId, meta); this.persistIndex(); return meta; } /** Append output for an active session. No-op when not logging (post-stop safe). */ logWrite(sessionId, data) { const meta = this.activeBySession.get(sessionId); if (!meta) { return; } (0, import_promises.appendFile)(meta.file, data, "utf8").catch(() => { }); } /** Stop logging a session, stamping endedAt into the registry + index. */ logStop(sessionId) { const meta = this.activeBySession.get(sessionId); if (!meta) return; this.finishLog(meta); } /** All known session logs (including persisted ones), newest first. */ listSessionLogs() { return Array.from(this.metasByFile.values()).sort((a, b) => b.startedAt - a.startedAt); } /** Reveal the logs directory in the OS file manager. */ openLogsDir() { try { (0, import_fs.mkdirSync)(this.logsDir, { recursive: true }); if (this.openPathImpl) { void this.openPathImpl(this.logsDir); } else { void import_electron.shell.openPath(this.logsDir); } } catch { } } }; function describeFile(p) { try { (0, import_fs.writeFileSync)(p, "", "utf8"); } catch { } } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { CommandsStore, defaultCommandsPath });