@stackmemoryai/stackmemory
Version:
Project-scoped memory for AI coding tools. Durable context across sessions with MCP integration, frames, smart retrieval, Claude Code skills, and automatic hooks.
151 lines (150 loc) • 4.39 kB
JavaScript
import { fileURLToPath as __fileURLToPath } from 'url';
import { dirname as __pathDirname } from 'path';
const __filename = __fileURLToPath(import.meta.url);
const __dirname = __pathDirname(__filename);
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
import { join, dirname } from "path";
const DEFAULT_CONFIG = {
version: "1.0.0",
daemon: {
enabled: true,
log_level: "info",
pid_file: join(process.env.HOME || "/tmp", ".stackmemory", "hooks.pid"),
log_file: join(process.env.HOME || "/tmp", ".stackmemory", "hooks.log")
},
file_watch: {
enabled: true,
paths: ["."],
ignore: ["node_modules", ".git", "dist", "build", ".next", "__pycache__"],
extensions: [".ts", ".tsx", ".js", ".jsx", ".py", ".go", ".rs", ".java"]
},
hooks: {
file_change: {
enabled: true,
handler: "sweep-predict",
output: "log",
debounce_ms: 2e3,
cooldown_ms: 1e4
},
session_start: {
enabled: true,
handler: "context-load",
output: "silent"
},
suggestion_ready: {
enabled: true,
handler: "display-suggestion",
output: "overlay"
}
}
};
function getConfigPath() {
return join(process.env.HOME || "/tmp", ".stackmemory", "hooks.yaml");
}
function loadConfig() {
const configPath = getConfigPath();
if (!existsSync(configPath)) {
return DEFAULT_CONFIG;
}
try {
const content = readFileSync(configPath, "utf-8");
const parsed = parseYaml(content);
return mergeConfig(DEFAULT_CONFIG, parsed);
} catch {
return DEFAULT_CONFIG;
}
}
function saveConfig(config) {
const configPath = getConfigPath();
const dir = dirname(configPath);
if (!existsSync(dir)) {
mkdirSync(dir, { recursive: true });
}
const yaml = toYaml(config);
writeFileSync(configPath, yaml);
}
function initConfig() {
const configPath = getConfigPath();
if (existsSync(configPath)) {
return loadConfig();
}
saveConfig(DEFAULT_CONFIG);
return DEFAULT_CONFIG;
}
function parseYaml(content) {
const result = {};
const lines = content.split("\n");
const stack = [
{ indent: -1, obj: result }
];
for (const line of lines) {
if (!line.trim() || line.trim().startsWith("#")) continue;
const indent = line.search(/\S/);
const trimmed = line.trim();
while (stack.length > 1 && stack[stack.length - 1].indent >= indent) {
stack.pop();
}
const colonIdx = trimmed.indexOf(":");
if (colonIdx === -1) continue;
const key = trimmed.slice(0, colonIdx).trim();
const value = trimmed.slice(colonIdx + 1).trim();
const current = stack[stack.length - 1].obj;
if (value === "" || value === "|") {
current[key] = {};
stack.push({ indent, obj: current[key] });
} else if (value.startsWith("[") && value.endsWith("]")) {
current[key] = value.slice(1, -1).split(",").map((s) => s.trim().replace(/['"]/g, ""));
} else if (value === "true") {
current[key] = true;
} else if (value === "false") {
current[key] = false;
} else if (/^\d+$/.test(value)) {
current[key] = parseInt(value, 10);
} else {
current[key] = value.replace(/['"]/g, "");
}
}
return result;
}
function toYaml(obj, indent = 0) {
const spaces = " ".repeat(indent);
let result = "";
if (Array.isArray(obj)) {
result += `[${obj.map((v) => typeof v === "string" ? `'${v}'` : v).join(", ")}]
`;
} else if (typeof obj === "object" && obj !== null) {
for (const [key, value] of Object.entries(obj)) {
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
result += `${spaces}${key}:
${toYaml(value, indent + 1)}`;
} else {
result += `${spaces}${key}: ${toYaml(value, indent)}`;
}
}
} else if (typeof obj === "string") {
result += `${obj}
`;
} else if (typeof obj === "boolean" || typeof obj === "number") {
result += `${obj}
`;
} else {
result += "\n";
}
return result;
}
function mergeConfig(defaults, overrides) {
return {
...defaults,
...overrides,
daemon: { ...defaults.daemon, ...overrides.daemon || {} },
file_watch: { ...defaults.file_watch, ...overrides.file_watch || {} },
hooks: { ...defaults.hooks, ...overrides.hooks || {} }
};
}
export {
getConfigPath,
initConfig,
loadConfig,
saveConfig
};
//# sourceMappingURL=config.js.map