fix: make Cursor hooks transactional

This commit is contained in:
ZacharyZhang-NY committed 2026-07-20 00:48:33 -04:00
1 parent 6d36f557b1
commit 6a7fdb7595
15 files changed
+1686 -665

No files matched your search

+24 -23
View File
@@ -1,20 +1,18 @@
import os from 'node:os';
import path from 'node:path';
import { resolvePrivateChildDirectory } from '../runtime-paths.js';
import type { AgentPlugin, InstallConfig, PluginStatus } from './base.js';
import {
AGENT_KEY,
AUDIT_SCRIPT,
GUARD_SCRIPT,
buildHandler,
removeManagedHooks,
renderDocument,
runtimeContracts,
samePath,
} from './cursor-contract.js';
import {
commitCursorInstallation,
preflightCursorInstallation,
prepareCursorInstallation,
} from './cursor-installation.js';
import {
readDocument,
requireRuntime,
runtimeFilesExist,
writeDocument,
} from './cursor-io.js';
@@ -23,26 +21,29 @@ import { SUPPORTED_AGENTS } from './registry.js';
const entry = SUPPORTED_AGENTS.get(AGENT_KEY)!;
export const cursorPlugin: AgentPlugin = {
managesRuntime: true,
async preflightInstall(config: InstallConfig): Promise<void> {
await readDocument();
await preflightCursorInstallation(config);
},
async install(config: InstallConfig): Promise<void> {
if (!config.agentId) throw new Error('agentId is required');
const document = await readDocument();
const runtimeRoot = path.join(os.homedir(), '.elydora');
const agentDirectory = resolvePrivateChildDirectory(runtimeRoot, config.agentId);
const expectedGuard = path.join(agentDirectory, GUARD_SCRIPT);
const expectedAudit = path.join(agentDirectory, AUDIT_SCRIPT);
if (!samePath(config.guardScriptPath, expectedGuard)) {
throw new Error(`Elydora guard runtime must use the managed agent directory: ${expectedGuard}`);
}
if (!samePath(config.hookScriptPath, expectedAudit)) {
throw new Error(`Elydora audit runtime must use the managed agent directory: ${expectedAudit}`);
}
await requireRuntime(expectedGuard, 'Elydora guard runtime');
await requireRuntime(expectedAudit, 'Elydora audit runtime');
const paths = await preflightCursorInstallation(config);
const hooks = removeManagedHooks(document.hooks);
hooks.preToolUse = [...(hooks.preToolUse ?? []), buildHandler(expectedGuard)];
hooks.postToolUse = [...(hooks.postToolUse ?? []), buildHandler(expectedAudit)];
await writeDocument(renderDocument(document, hooks));
hooks.preToolUse = [...(hooks.preToolUse ?? []), buildHandler(paths.guardPath)];
hooks.postToolUse = [...(hooks.postToolUse ?? []), buildHandler(paths.auditPath)];
hooks.postToolUseFailure = [
...(hooks.postToolUseFailure ?? []),
buildHandler(paths.auditPath),
];
const prepared = await prepareCursorInstallation(
config,
renderDocument(document, hooks),
);
await commitCursorInstallation(prepared);
console.log(` Cursor hooks: ${document.filePath}`);
},