config-audit/hooks/scripts/auto-backup-config.mjs
Kjell Tore Guttormsen caee558e79 feat(ultraplan-local): v1.6.0 — /ultraresearch-local deep research command
Add /ultraresearch-local for structured research combining local codebase
analysis with external knowledge via parallel agent swarms. Produces research
briefs with triangulation, confidence ratings, and source quality assessment.

New command: /ultraresearch-local with modes --quick, --local, --external, --fg.
New agents: research-orchestrator (opus), docs-researcher, community-researcher,
security-researcher, contrarian-researcher, gemini-bridge (all sonnet).
New template: research-brief-template.md.

Integration: --research flag in /ultraplan-local accepts pre-built research
briefs (up to 3), enriches the interview and exploration phases. Planning
orchestrator cross-references brief findings during synthesis.

Design principle: Context Engineering — right information to right agent at
right time. Research briefs are structured artifacts in the pipeline:
ultraresearch → brief → ultraplan --research → plan → ultraexecute.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-08 08:58:35 +02:00

84 lines
2 KiB
JavaScript

#!/usr/bin/env node
/**
* PreToolUse hook: auto-backup config files before Edit/Write.
* Reads $TOOL_INPUT to check if the target file is a config file.
* If yes, backs it up via scanners/lib/backup.mjs.
* Fast path — no scanner execution.
*/
import { existsSync } from 'node:fs';
import { basename, dirname, sep } from 'node:path';
// Config file patterns to protect
const CONFIG_PATTERNS = [
/CLAUDE\.md$/i,
/CLAUDE\.local\.md$/i,
/settings\.json$/,
/settings\.local\.json$/,
/hooks\.json$/,
/\.mcp\.json$/,
/keybindings\.json$/,
];
const CONFIG_DIRS = ['rules'];
function isConfigFile(filePath) {
if (!filePath) return false;
const name = basename(filePath);
const dir = dirname(filePath);
// Check filename patterns
for (const pattern of CONFIG_PATTERNS) {
if (pattern.test(name)) return true;
}
// Check if inside a rules/ directory
for (const d of CONFIG_DIRS) {
if (dir.includes(`${sep}${d}${sep}`) || dir.endsWith(`${sep}${d}`)) {
if (name.endsWith('.md')) return true;
}
}
return false;
}
/**
* Read all data from stdin asynchronously.
* @returns {Promise<string>}
*/
function readStdin() {
return new Promise((resolve, reject) => {
const chunks = [];
process.stdin.setEncoding('utf-8');
process.stdin.on('data', chunk => chunks.push(chunk));
process.stdin.on('end', () => resolve(chunks.join('')));
process.stdin.on('error', reject);
});
}
async function main() {
let input;
try {
input = await readStdin();
} catch {
process.exit(0);
}
let toolInput;
try {
toolInput = JSON.parse(input);
} catch {
process.exit(0);
}
const filePath = toolInput.file_path || toolInput.path;
if (!filePath || !isConfigFile(filePath) || !existsSync(filePath)) {
process.exit(0);
}
const { createBackup } = await import('../../scanners/lib/backup.mjs');
const { backupPath } = createBackup([filePath]);
process.stderr.write(`[config-audit] Auto-backup: ${basename(filePath)}${backupPath}\n`);
}
main().catch(() => process.exit(0));