@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.
152 lines (151 loc) • 3.5 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 } from "fs";
import { join } from "path";
import { homedir } from "os";
import { writeFileSecure, ensureSecureDir } from "./secure-fs.js";
import { AutoBackgroundConfigSchema, parseConfigSafe } from "./schemas.js";
const DEFAULT_CONFIG = {
enabled: true,
timeoutMs: 5e3,
// 5 seconds
alwaysBackground: [
// Package managers
"npm install",
"npm ci",
"yarn install",
"pnpm install",
"bun install",
// Builds
"npm run build",
"yarn build",
"pnpm build",
"cargo build",
"go build",
"make",
"cmake",
// Tests
"npm test",
"npm run test",
"yarn test",
"pnpm test",
"pytest",
"jest",
"vitest",
"cargo test",
"go test",
// Docker
"docker build",
"docker-compose up",
"docker compose up",
// Git operations that can be slow
"git clone",
"git fetch --all",
"git pull --all",
// Type checking
"npx tsc",
"tsc --noEmit",
// Linting large codebases
"eslint .",
"npm run lint"
],
neverBackground: [
// Interactive commands
"vim",
"nvim",
"nano",
"less",
"more",
"top",
"htop",
// Quick commands
"echo",
"cat",
"ls",
"pwd",
"cd",
"which",
"git status",
"git diff",
"git log"
],
verbose: false
};
const CONFIG_PATH = join(homedir(), ".stackmemory", "auto-background.json");
function loadConfig() {
try {
if (existsSync(CONFIG_PATH)) {
const data = readFileSync(CONFIG_PATH, "utf8");
const parsed = JSON.parse(data);
return parseConfigSafe(
AutoBackgroundConfigSchema,
{ ...DEFAULT_CONFIG, ...parsed },
DEFAULT_CONFIG,
"auto-background"
);
}
} catch {
}
return DEFAULT_CONFIG;
}
function saveConfig(config) {
try {
ensureSecureDir(join(homedir(), ".stackmemory"));
writeFileSecure(CONFIG_PATH, JSON.stringify(config, null, 2));
} catch {
}
}
function shouldAutoBackground(command, config) {
const cfg = config || loadConfig();
if (!cfg.enabled) return false;
const normalizedCmd = command.trim().toLowerCase();
for (const pattern of cfg.neverBackground) {
if (normalizedCmd.startsWith(pattern.toLowerCase())) {
return false;
}
}
for (const pattern of cfg.alwaysBackground) {
if (normalizedCmd.startsWith(pattern.toLowerCase())) {
return true;
}
}
return false;
}
function processToolUse(toolName, toolInput) {
if (toolName !== "Bash") {
return { decision: "allow" };
}
const command = toolInput.command;
if (!command) {
return { decision: "allow" };
}
if (toolInput.run_in_background === true) {
return { decision: "allow" };
}
const config = loadConfig();
if (shouldAutoBackground(command, config)) {
if (config.verbose) {
console.error(
`[auto-background] Backgrounding: ${command.substring(0, 50)}...`
);
}
return {
decision: "modify",
modifiedInput: {
...toolInput,
run_in_background: true
},
reason: `Auto-backgrounded: matches pattern`
};
}
return { decision: "allow" };
}
export {
loadConfig,
processToolUse,
saveConfig,
shouldAutoBackground
};
//# sourceMappingURL=auto-background.js.map