@holdpoint/engine-cursor 0.1.0-alpha.13 → 0.1.0-alpha.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  // src/engine.ts
2
+ import { buildSecurityScanScript } from "@holdpoint/types";
2
3
  var HOLDPOINT_CURSOR_HOOK_MARKER = "HOLDPOINT_MANAGED=cursor";
3
4
  var HOOK_COMMAND = `node .cursor/holdpoint-hook.mjs # ${HOLDPOINT_CURSOR_HOOK_MARKER}`;
4
5
  function hook(options = {}) {
@@ -23,12 +24,10 @@ function buildHooksJson(config) {
23
24
  subagentStop: [hook({ timeout: 600, loop_limit: 5 })],
24
25
  preCompact: [hook({ timeout: 30 })],
25
26
  afterAgentResponse: [hook({ timeout: 30 })],
26
- stop: [hook({ timeout: 600, loop_limit: 5 })]
27
+ stop: [hook({ timeout: 600, loop_limit: 5 })],
28
+ sessionStart: [hook({ timeout: 30 })]
27
29
  };
28
- const seedsSession = (config.session_context_files?.length ?? 0) > 0 || config.checks.some((c) => (c.on ?? "before_done") === "session_start");
29
- if (seedsSession) {
30
- hooks.sessionStart = [hook({ timeout: 30 })];
31
- }
30
+ void config;
32
31
  return JSON.stringify({ version: 1, hooks }, null, 2) + "\n";
33
32
  }
34
33
  function buildCheckScript() {
@@ -37,7 +36,7 @@ function buildCheckScript() {
37
36
  import { execSync } from "node:child_process";
38
37
  import { existsSync, readFileSync, writeFileSync } from "node:fs";
39
38
  import { isAbsolute, join, relative, resolve } from "node:path";
40
-
39
+ ${buildSecurityScanScript()}
41
40
  const CHECK_COMMAND = "node_modules/.bin/holdpoint check --staged";
42
41
  const LIVE_COMMAND = "node_modules/.bin/holdpoint event --engine cursor --from-hook";
43
42
  const MAX_CONTEXT_CHARS = 100_000;
@@ -129,6 +128,10 @@ function gatherHookContext(repoRoot, hook) {
129
128
  if (hook === "session_start") {
130
129
  const files = Array.isArray(cfg.session_context_files) ? cfg.session_context_files : [];
131
130
  for (const f of files) { const c = readFileContext(repoRoot, f); if (c) parts.push(c); }
131
+ if (cfg.security_scan !== false) {
132
+ const scan = formatSecurityScan(repoRoot);
133
+ if (scan) parts.push(scan);
134
+ }
132
135
  }
133
136
  for (const c of checks) {
134
137
  const on = typeof c.on === "string" ? c.on : "before_done";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/engine.ts","../src/live-adapter.ts","../src/manifest.ts"],"sourcesContent":["import type { HoldpointConfig } from \"@holdpoint/types\";\n\nexport const HOLDPOINT_CURSOR_HOOK_MARKER = \"HOLDPOINT_MANAGED=cursor\";\n\nconst HOOK_COMMAND = `node .cursor/holdpoint-hook.mjs # ${HOLDPOINT_CURSOR_HOOK_MARKER}`;\n\ninterface CursorHook {\n command: string;\n timeout?: number;\n matcher?: string;\n loop_limit?: number;\n failClosed?: boolean;\n}\n\ninterface CursorHooksJson {\n version: 1;\n hooks: Record<string, CursorHook[]>;\n}\n\nfunction hook(options: Omit<CursorHook, \"command\"> = {}): CursorHook {\n return {\n command: HOOK_COMMAND,\n ...options,\n };\n}\n\n/**\n * Generate project-level Cursor hooks.\n *\n * Cursor project hooks live at `.cursor/hooks.json`, run from the project root,\n * and can observe, inject context, or auto-continue the agent loop. Holdpoint\n * uses a single generated script so hook behavior stays in sync with\n * `checks.yaml` after every `holdpoint update`.\n */\nexport function buildHooksJson(config: HoldpointConfig): string {\n const hooks: CursorHooksJson[\"hooks\"] = {\n beforeSubmitPrompt: [hook({ timeout: 30 })],\n preToolUse: [hook({ timeout: 30, matcher: \"Shell|Read|Write|Grep|Task|MCP:.*\" })],\n postToolUse: [hook({ timeout: 30 })],\n postToolUseFailure: [hook({ timeout: 30 })],\n beforeShellExecution: [hook({ timeout: 30 })],\n afterShellExecution: [hook({ timeout: 30 })],\n beforeMCPExecution: [hook({ timeout: 30 })],\n afterMCPExecution: [hook({ timeout: 30 })],\n beforeReadFile: [hook({ timeout: 30 })],\n afterFileEdit: [hook({ timeout: 30 })],\n subagentStart: [hook({ timeout: 30 })],\n subagentStop: [hook({ timeout: 600, loop_limit: 5 })],\n preCompact: [hook({ timeout: 30 })],\n afterAgentResponse: [hook({ timeout: 30 })],\n stop: [hook({ timeout: 600, loop_limit: 5 })],\n };\n\n const seedsSession =\n (config.session_context_files?.length ?? 0) > 0 ||\n config.checks.some((c) => (c.on ?? \"before_done\") === \"session_start\");\n if (seedsSession) {\n hooks.sessionStart = [hook({ timeout: 30 })];\n }\n\n return JSON.stringify({ version: 1, hooks }, null, 2) + \"\\n\";\n}\n\n/**\n * Generate `.cursor/holdpoint-hook.mjs`.\n *\n * The script speaks Cursor's native hook protocol:\n * - `sessionStart` returns `additional_context` when session_context_files exist.\n * - `stop` and completed `subagentStop` run Holdpoint checks and return a\n * `followup_message` on failure so Cursor keeps iterating.\n * - all other hooks are used for Live telemetry and emit either an allow\n * response or no output, depending on that hook's schema.\n */\nexport function buildCheckScript(): string {\n return `#!/usr/bin/env node\n// AUTO-GENERATED by Holdpoint — do not edit. Re-generate: npx holdpoint update\nimport { execSync } from \"node:child_process\";\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { isAbsolute, join, relative, resolve } from \"node:path\";\n\nconst CHECK_COMMAND = \"node_modules/.bin/holdpoint check --staged\";\nconst LIVE_COMMAND = \"node_modules/.bin/holdpoint event --engine cursor --from-hook\";\nconst MAX_CONTEXT_CHARS = 100_000;\nconst MAX_CHECK_OUTPUT_CHARS = 60_000;\nconst CHECK_MAX_BUFFER_BYTES = 1024 * 1024 * 10;\n\nfunction readInput() {\n try {\n const raw = readFileSync(0, \"utf8\").trim();\n return raw ? JSON.parse(raw) : {};\n } catch {\n return {};\n }\n}\n\nfunction resolveRepoRoot(cwd = process.cwd()) {\n try {\n return execSync(\"git rev-parse --show-toplevel\", {\n cwd,\n encoding: \"utf8\",\n stdio: [\"pipe\", \"pipe\", \"ignore\"],\n }).trim();\n } catch {\n return cwd;\n }\n}\n\nfunction eventName(input) {\n return String(input && input.hook_event_name ? input.hook_event_name : \"\");\n}\n\nfunction truncateText(value, maxChars) {\n const text = String(value || \"\");\n if (text.length <= maxChars) return { text, truncated: false, originalLength: text.length };\n return {\n text: text.slice(0, maxChars) + \"\\\\n\\\\n[Holdpoint output truncated to \" + maxChars + \" chars.]\",\n truncated: true,\n originalLength: text.length,\n };\n}\n\nfunction isPathInsideRoot(repoRoot, absPath) {\n const rel = relative(repoRoot, absPath);\n return rel === \"\" || (!rel.startsWith(\"..\") && !isAbsolute(rel));\n}\n\nfunction sendLiveEvent(input) {\n try {\n execSync(LIVE_COMMAND, {\n input: JSON.stringify(input),\n encoding: \"utf8\",\n stdio: [\"pipe\", \"ignore\", \"ignore\"],\n });\n } catch {\n // Live telemetry is best-effort and must never break Cursor's hook flow.\n }\n}\n\nfunction readConfig(repoRoot) {\n const configPath = join(repoRoot, \".github/holdpoint/generated/checks.immutable.json\");\n if (!existsSync(configPath)) return {};\n try { return JSON.parse(readFileSync(configPath, \"utf8\")); } catch { return {}; }\n}\n\nfunction readFileContext(repoRoot, file) {\n if (typeof file !== \"string\" || !file.trim()) return null;\n const abs = resolve(repoRoot, file);\n if (!isPathInsideRoot(repoRoot, abs) || !existsSync(abs)) return null;\n try { return \"<!-- \" + file + \" -->\\\\n\" + readFileSync(abs, \"utf8\"); } catch { return null; }\n}\n\nconst DATETIME_TEXT = () =>\n \"Current date and time: \" + new Date().toISOString() + \" (UTC)\\\\n\" +\n \"Provided by Holdpoint — use this to avoid knowledge-cutoff confusion.\";\n\n// Gather agent context for a Holdpoint hook. NOTE: Cursor's beforeSubmitPrompt\n// cannot inject context (it only gates submission), so the top-level datetime\n// and message_submit checks are surfaced at sessionStart instead — the only\n// Cursor stage that accepts additional_context per the hooks API.\nfunction gatherHookContext(repoRoot, hook) {\n const cfg = readConfig(repoRoot);\n const checks = Array.isArray(cfg.checks) ? cfg.checks : [];\n const parts = [];\n let hasDatetime = false;\n const addDatetime = () => { if (!hasDatetime) { hasDatetime = true; parts.push(DATETIME_TEXT()); } };\n\n const includeHooks = hook === \"session_start\" ? [\"session_start\", \"message_submit\"] : [hook];\n\n if (hook === \"session_start\") {\n const files = Array.isArray(cfg.session_context_files) ? cfg.session_context_files : [];\n for (const f of files) { const c = readFileContext(repoRoot, f); if (c) parts.push(c); }\n }\n for (const c of checks) {\n const on = typeof c.on === \"string\" ? c.on : \"before_done\";\n if (!includeHooks.includes(on)) continue;\n if (c.inject && typeof c.inject === \"object\") {\n if (c.inject.datetime === true) addDatetime();\n if (typeof c.inject.text === \"string\" && c.inject.text.trim()) parts.push(c.inject.text);\n if (Array.isArray(c.inject.files)) for (const f of c.inject.files) { const x = readFileContext(repoRoot, f); if (x) parts.push(x); }\n } else if (typeof c.prompt === \"string\" && c.prompt.trim()) {\n parts.push(\"Holdpoint reminder [\" + (c.label || c.id || \"check\") + \"]: \" + c.prompt);\n }\n }\n // Cursor can only inject once (sessionStart), so fold the per-message datetime in here.\n if (hook === \"session_start\" && cfg.inject_datetime !== false) addDatetime();\n\n if (parts.length === 0) return undefined;\n const context = truncateText(parts.join(\"\\\\n\\\\n\"), MAX_CONTEXT_CHARS);\n return {\n additional_context: context.text,\n truncated: context.truncated,\n originalLength: context.originalLength,\n emittedLength: context.text.length,\n };\n}\n\nfunction hasCmdAt(repoRoot, hook) {\n const cfg = readConfig(repoRoot);\n const checks = Array.isArray(cfg.checks) ? cfg.checks : [];\n return checks.some((c) => typeof c.cmd === \"string\" && (typeof c.on === \"string\" ? c.on : \"before_done\") === hook);\n}\n\nfunction runHoldpointChecks(repoRoot, command = CHECK_COMMAND) {\n const startedAt = Date.now();\n try {\n const output = execSync(command, {\n cwd: repoRoot,\n stdio: \"pipe\",\n encoding: \"utf8\",\n maxBuffer: CHECK_MAX_BUFFER_BYTES,\n });\n return {\n ok: true,\n durationMs: Date.now() - startedAt,\n output: String(output || \"\").trim(),\n };\n } catch (error) {\n const output = [error && error.stdout, error && error.stderr, error && error.message]\n .filter(Boolean)\n .join(\"\\\\n\")\n .trim();\n const truncated = truncateText(output, MAX_CHECK_OUTPUT_CHARS);\n return {\n ok: false,\n durationMs: Date.now() - startedAt,\n output: truncated.text || \"Holdpoint checks failed. Fix the issues above, then re-attempt.\",\n truncated: truncated.truncated,\n originalLength: truncated.originalLength,\n };\n }\n}\n\nfunction shouldRunCompletionChecks(input) {\n const name = eventName(input);\n if (name === \"stop\") return true;\n if (name === \"subagentStop\") {\n return input && input.status === \"completed\";\n }\n return false;\n}\n\nconst input = readInput();\nconst cwd = typeof input.cwd === \"string\" ? input.cwd : process.cwd();\nconst repoRoot = resolveRepoRoot(cwd);\nconst name = eventName(input);\n\nif (name === \"sessionStart\") {\n const context = gatherHookContext(repoRoot, \"session_start\");\n sendLiveEvent({\n ...input,\n holdpoint_context: context\n ? {\n truncated: context.truncated,\n originalLength: context.originalLength,\n emittedLength: context.emittedLength,\n }\n : undefined,\n });\n if (context?.additional_context) {\n writeFileSync(1, JSON.stringify({ additional_context: context.additional_context }) + \"\\\\n\");\n }\n process.exit(0);\n}\n\nif (shouldRunCompletionChecks(input)) {\n const result = runHoldpointChecks(repoRoot);\n sendLiveEvent({ ...input, holdpoint_check: result });\n if (result.ok) {\n process.exit(0);\n }\n process.stdout.write(\n JSON.stringify({\n followup_message:\n result.output +\n \"\\\\n\\\\nHoldpoint checks failed. Fix the issues above, then run the checks again before finishing.\",\n }) + \"\\\\n\",\n );\n process.exit(0);\n}\n\nsendLiveEvent(input);\n\nif (name === \"preToolUse\") {\n // Gate on before_tool cmd checks; deny the tool if they fail.\n if (hasCmdAt(repoRoot, \"before_tool\")) {\n const result = runHoldpointChecks(repoRoot, CHECK_COMMAND + \" --hook before_tool\");\n if (!result.ok) {\n process.stdout.write(\n JSON.stringify({ permission: \"deny\", agentMessage: result.output }) + \"\\\\n\",\n );\n process.exit(0);\n }\n }\n process.stdout.write(JSON.stringify({ permission: \"allow\" }) + \"\\\\n\");\n} else if (\n name === \"beforeShellExecution\" ||\n name === \"beforeMCPExecution\" ||\n name === \"beforeReadFile\" ||\n name === \"subagentStart\"\n) {\n process.stdout.write(JSON.stringify({ permission: \"allow\" }) + \"\\\\n\");\n} else if (name === \"beforeSubmitPrompt\") {\n // Cursor's beforeSubmitPrompt cannot inject context — only allow/deny the\n // submission. Per-message context is folded into sessionStart instead.\n process.stdout.write(JSON.stringify({ continue: true }) + \"\\\\n\");\n}\nprocess.exit(0);\n`;\n}\n\n/**\n * Generate a standalone context-injection script for sessionStart tests.\n * Cursor uses the same generated dispatcher for context, telemetry, and gates.\n */\nexport function buildContextScript(): string {\n return buildCheckScript();\n}\n\n/**\n * Generate .cursorrules additions from a HoldpointConfig.\n *\n * Cursor now enforces Holdpoint through `.cursor/hooks.json`; this rules block\n * remains useful context for the agent and for Cursor cloud cases where not all\n * local hook stages are available.\n */\nexport function buildEngine(config: HoldpointConfig): string {\n const deterministicList = config.checks\n .filter((c) => c.cmd !== undefined)\n .map((c) => ` - [${c.when ?? \"always\"}] ${c.label}: \\`${c.cmd ?? \"(no cmd)\"}\\``)\n .join(\"\\n\");\n\n const promptList = config.checks\n .filter((c) => c.prompt !== undefined)\n .map((c) => ` - [${c.when ?? \"always\"}] ${c.label}: ${c.prompt ?? \"\"}`)\n .join(\"\\n\");\n\n return `# ─── Holdpoint Rules (auto-generated) ─────────────────────────────────────────\n# DO NOT EDIT this block manually. Re-generate with: npx holdpoint update\n\n## Mandatory pre-completion checks\n\nHoldpoint also installed Cursor project hooks in \\`.cursor/hooks.json\\`. Before\nmarking ANY task as done or making a final commit, you MUST:\n\n1. Run all Holdpoint tasks and confirm they pass:\n${deterministicList || \" (no tasks configured)\"}\n\n2. Act on all matching agent prompts:\n${promptList || \" (no prompt checks configured)\"}\n\n3. If any task exits non-zero, fix the underlying issue before\n proceeding. Do NOT suppress errors or skip tasks.\n\n4. For prompt checks, explicitly state in your response that you have acted on\n each item before marking the task complete.\n\n## Running checks\n Run: \\`node_modules/.bin/holdpoint check --staged\\` to execute all tasks.\n Fix all failures before proceeding.\n\n# ─── End Holdpoint Rules ───────────────────────────────────────────────────────\n`;\n}\n","import { execFileSync } from \"node:child_process\";\nimport { createHash, randomUUID } from \"node:crypto\";\nimport { existsSync, realpathSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport type { EventV1 } from \"@holdpoint/live-protocol\";\nimport type { TranslateHookInputOptions } from \"@holdpoint/sdk\";\n\ninterface CursorHookInput {\n conversation_id?: string;\n generation_id?: string;\n session_id?: string;\n hook_event_name?: string;\n cwd?: string;\n workspace_roots?: string[];\n model?: string;\n prompt?: string;\n tool_name?: string;\n tool_input?: unknown;\n tool_output?: string;\n tool_use_id?: string;\n duration?: number;\n duration_ms?: number;\n error_message?: string;\n failure_type?: string;\n status?: string;\n reason?: string;\n command?: string;\n output?: string;\n file_path?: string;\n modified_files?: string[];\n subagent_id?: string;\n subagent_type?: string;\n task?: string;\n holdpoint_check?: {\n ok?: boolean;\n durationMs?: number;\n output?: string;\n };\n holdpoint_context?: {\n truncated?: boolean;\n originalLength?: number;\n emittedLength?: number;\n };\n}\n\nfunction asObject(value: unknown): Record<string, unknown> {\n return value != null && typeof value === \"object\" && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : {};\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim() ? value : undefined;\n}\n\nfunction asNumber(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n}\n\nfunction sha12(value: string): string {\n return createHash(\"sha256\").update(value).digest(\"hex\").slice(0, 12);\n}\n\nfunction resolveRepoRoot(cwd: string): string {\n try {\n return realpathSync(\n execFileSync(\"git\", [\"rev-parse\", \"--show-toplevel\"], {\n cwd,\n encoding: \"utf8\",\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n }).trim(),\n );\n } catch {\n try {\n return realpathSync(cwd);\n } catch {\n return resolve(cwd);\n }\n }\n}\n\nfunction extractStringArray(value: unknown): string[] {\n return Array.isArray(value)\n ? value.filter((entry): entry is string => typeof entry === \"string\")\n : [];\n}\n\nfunction normalizeWriteTarget(cwd: string, target: string): string {\n const resolved = resolve(cwd, target);\n return existsSync(resolved) ? realpathSync.native(resolved) : resolved;\n}\n\nfunction extractWriteTargets(input: CursorHookInput, cwd: string): string[] | undefined {\n const candidates = new Set<string>();\n const toolInput = asObject(input.tool_input);\n\n for (const key of [\"file_path\", \"filePath\", \"path\"]) {\n const value = toolInput[key] ?? (input as Record<string, unknown>)[key];\n if (typeof value === \"string\" && value.trim()) {\n candidates.add(normalizeWriteTarget(cwd, value));\n }\n }\n\n for (const key of [\"paths\", \"file_paths\", \"modified_files\"]) {\n for (const value of extractStringArray(\n toolInput[key] ?? (input as Record<string, unknown>)[key],\n )) {\n if (value.trim()) {\n candidates.add(normalizeWriteTarget(cwd, value));\n }\n }\n }\n\n return candidates.size > 0 ? [...candidates] : undefined;\n}\n\nfunction truncate(value: string, max: number): { value: string; truncatedAt?: number } {\n if (value.length <= max) return { value };\n return { value: value.slice(0, max), truncatedAt: max };\n}\n\nfunction sessionId(input: CursorHookInput): string | undefined {\n return input.conversation_id ?? input.session_id ?? input.generation_id;\n}\n\nfunction mapSessionEndReason(\n reason: string | undefined,\n): \"user\" | \"completed\" | \"error\" | undefined {\n if (reason === \"completed\" || reason === \"error\") return reason;\n if (reason === \"aborted\" || reason === \"window_close\" || reason === \"user_close\") return \"user\";\n return reason ? \"completed\" : undefined;\n}\n\nfunction buildCursorHookEvent(raw: unknown, options?: TranslateHookInputOptions): EventV1 | null {\n const input = asObject(raw) as CursorHookInput;\n const id = sessionId(input);\n const hookEventName = asString(input.hook_event_name);\n if (!id || !hookEventName) {\n return null;\n }\n\n const cwd = asString(input.cwd) ?? input.workspace_roots?.[0] ?? options?.cwd ?? process.cwd();\n const repoRoot = resolveRepoRoot(cwd);\n const base = {\n v: 1 as const,\n id: randomUUID(),\n ts: Date.now(),\n engine: \"cursor\",\n session_id: id,\n project_hash: sha12(repoRoot),\n cwd: repoRoot,\n };\n const toolName = asString(input.tool_name) ?? (input.command ? \"Shell\" : undefined);\n const toolUseId = input.tool_use_id ?? input.generation_id ?? randomUUID();\n const writeTargets = extractWriteTargets(input, cwd);\n\n switch (hookEventName) {\n case \"sessionStart\":\n return {\n ...base,\n type: \"session_start\",\n payload: {\n ...(input.holdpoint_context?.truncated ? { tools_available: [\"context_truncated\"] } : {}),\n },\n };\n case \"sessionEnd\":\n return {\n ...base,\n type: \"session_end\",\n payload: {\n ...(mapSessionEndReason(asString(input.reason) ?? asString(input.status))\n ? { reason: mapSessionEndReason(asString(input.reason) ?? asString(input.status)) }\n : {}),\n },\n };\n case \"beforeSubmitPrompt\": {\n const prompt = asString(input.prompt) ?? \"\";\n const { value, truncatedAt } = truncate(prompt, 10_000);\n return {\n ...base,\n type: \"prompt_submit\",\n payload: {\n prompt: value,\n ...(truncatedAt ? { truncated_at: truncatedAt } : {}),\n },\n };\n }\n case \"preToolUse\":\n return {\n ...base,\n type: \"tool_pre\",\n payload: {\n tool_name: toolName ?? \"unknown\",\n tool_use_id: toolUseId,\n tool_input: asObject(input.tool_input),\n ...(writeTargets ? { write_targets: writeTargets } : {}),\n },\n };\n case \"postToolUse\":\n case \"afterShellExecution\":\n case \"afterMCPExecution\":\n return {\n ...base,\n type: \"tool_post\",\n payload: {\n tool_name: toolName ?? (hookEventName === \"afterShellExecution\" ? \"Shell\" : \"unknown\"),\n tool_use_id: toolUseId,\n success: true,\n duration_ms: asNumber(input.duration) ?? asNumber(input.duration_ms) ?? 0,\n ...((input.output ?? input.tool_output)\n ? { output_summary: truncate(String(input.output ?? input.tool_output), 2_000).value }\n : {}),\n ...(writeTargets ? { write_targets: writeTargets } : {}),\n },\n };\n case \"postToolUseFailure\":\n return {\n ...base,\n type: \"tool_failure\",\n payload: {\n tool_name: toolName ?? \"unknown\",\n tool_use_id: toolUseId,\n error:\n asString(input.error_message) ?? asString(input.failure_type) ?? \"Cursor tool failed\",\n },\n };\n case \"beforeShellExecution\":\n case \"beforeMCPExecution\":\n case \"beforeReadFile\":\n return {\n ...base,\n type: \"tool_pre\",\n payload: {\n tool_name:\n hookEventName === \"beforeShellExecution\"\n ? \"Shell\"\n : hookEventName === \"beforeMCPExecution\"\n ? \"MCP\"\n : hookEventName === \"beforeReadFile\"\n ? \"Read\"\n : \"unknown\",\n tool_use_id: toolUseId,\n tool_input:\n hookEventName === \"beforeShellExecution\" && input.command\n ? { command: input.command }\n : hookEventName === \"beforeReadFile\" && input.file_path\n ? { file_path: input.file_path }\n : asObject(input.tool_input),\n ...(writeTargets ? { write_targets: writeTargets } : {}),\n },\n };\n case \"afterFileEdit\":\n return {\n ...base,\n type: \"tool_post\",\n payload: {\n tool_name: \"Write\",\n tool_use_id: toolUseId,\n success: true,\n duration_ms: asNumber(input.duration) ?? asNumber(input.duration_ms) ?? 0,\n ...(writeTargets ? { write_targets: writeTargets } : {}),\n },\n };\n case \"stop\": {\n const check = input.holdpoint_check;\n if (check?.ok === false) {\n return {\n ...base,\n type: \"stop_block\",\n payload: {\n reason: check.output ?? \"Holdpoint checks failed\",\n failing_checks: [],\n },\n };\n }\n return {\n ...base,\n type: \"stop_pass\",\n payload: {\n duration_ms: check?.durationMs ?? asNumber(input.duration_ms) ?? 0,\n },\n };\n }\n case \"subagentStart\":\n case \"subagentStop\":\n case \"preCompact\":\n case \"afterAgentResponse\":\n return {\n ...base,\n type: \"meta\",\n payload: {\n kind: \"cursor_lifecycle\",\n hook_event_name: hookEventName,\n status: input.status,\n subagent_type: input.subagent_type,\n },\n };\n default:\n return {\n ...base,\n type: \"meta\",\n payload: {\n kind: \"cursor_hook\",\n hook_event_name: hookEventName,\n },\n };\n }\n}\n\nexport const adapter = {\n id: \"cursor\",\n displayName: \"Cursor\",\n capabilities: {\n can_stream: true,\n },\n generateBridgeCommand(): string {\n return \"node_modules/.bin/holdpoint event --engine cursor --from-hook\";\n },\n translateHookInput(raw: unknown, options?: TranslateHookInputOptions) {\n return buildCursorHookEvent(raw, options);\n },\n};\n","export const manifest = {\n manifestVersion: 1,\n id: \"cursor\",\n displayName: \"Cursor\",\n} as const;\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/engine.ts","../src/live-adapter.ts","../src/manifest.ts"],"sourcesContent":["import { buildSecurityScanScript } from \"@holdpoint/types\";\nimport type { HoldpointConfig } from \"@holdpoint/types\";\n\nexport const HOLDPOINT_CURSOR_HOOK_MARKER = \"HOLDPOINT_MANAGED=cursor\";\n\nconst HOOK_COMMAND = `node .cursor/holdpoint-hook.mjs # ${HOLDPOINT_CURSOR_HOOK_MARKER}`;\n\ninterface CursorHook {\n command: string;\n timeout?: number;\n matcher?: string;\n loop_limit?: number;\n failClosed?: boolean;\n}\n\ninterface CursorHooksJson {\n version: 1;\n hooks: Record<string, CursorHook[]>;\n}\n\nfunction hook(options: Omit<CursorHook, \"command\"> = {}): CursorHook {\n return {\n command: HOOK_COMMAND,\n ...options,\n };\n}\n\n/**\n * Generate project-level Cursor hooks.\n *\n * Cursor project hooks live at `.cursor/hooks.json`, run from the project root,\n * and can observe, inject context, or auto-continue the agent loop. Holdpoint\n * uses a single generated script so hook behavior stays in sync with\n * `checks.yaml` after every `holdpoint update`.\n */\nexport function buildHooksJson(config: HoldpointConfig): string {\n const hooks: CursorHooksJson[\"hooks\"] = {\n beforeSubmitPrompt: [hook({ timeout: 30 })],\n preToolUse: [hook({ timeout: 30, matcher: \"Shell|Read|Write|Grep|Task|MCP:.*\" })],\n postToolUse: [hook({ timeout: 30 })],\n postToolUseFailure: [hook({ timeout: 30 })],\n beforeShellExecution: [hook({ timeout: 30 })],\n afterShellExecution: [hook({ timeout: 30 })],\n beforeMCPExecution: [hook({ timeout: 30 })],\n afterMCPExecution: [hook({ timeout: 30 })],\n beforeReadFile: [hook({ timeout: 30 })],\n afterFileEdit: [hook({ timeout: 30 })],\n subagentStart: [hook({ timeout: 30 })],\n subagentStop: [hook({ timeout: 600, loop_limit: 5 })],\n preCompact: [hook({ timeout: 30 })],\n afterAgentResponse: [hook({ timeout: 30 })],\n stop: [hook({ timeout: 600, loop_limit: 5 })],\n sessionStart: [hook({ timeout: 30 })],\n };\n\n void config;\n return JSON.stringify({ version: 1, hooks }, null, 2) + \"\\n\";\n}\n\n/**\n * Generate `.cursor/holdpoint-hook.mjs`.\n *\n * The script speaks Cursor's native hook protocol:\n * - `sessionStart` returns `additional_context` when session_context_files exist.\n * - `stop` and completed `subagentStop` run Holdpoint checks and return a\n * `followup_message` on failure so Cursor keeps iterating.\n * - all other hooks are used for Live telemetry and emit either an allow\n * response or no output, depending on that hook's schema.\n */\nexport function buildCheckScript(): string {\n return `#!/usr/bin/env node\n// AUTO-GENERATED by Holdpoint — do not edit. Re-generate: npx holdpoint update\nimport { execSync } from \"node:child_process\";\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { isAbsolute, join, relative, resolve } from \"node:path\";\n${buildSecurityScanScript()}\nconst CHECK_COMMAND = \"node_modules/.bin/holdpoint check --staged\";\nconst LIVE_COMMAND = \"node_modules/.bin/holdpoint event --engine cursor --from-hook\";\nconst MAX_CONTEXT_CHARS = 100_000;\nconst MAX_CHECK_OUTPUT_CHARS = 60_000;\nconst CHECK_MAX_BUFFER_BYTES = 1024 * 1024 * 10;\n\nfunction readInput() {\n try {\n const raw = readFileSync(0, \"utf8\").trim();\n return raw ? JSON.parse(raw) : {};\n } catch {\n return {};\n }\n}\n\nfunction resolveRepoRoot(cwd = process.cwd()) {\n try {\n return execSync(\"git rev-parse --show-toplevel\", {\n cwd,\n encoding: \"utf8\",\n stdio: [\"pipe\", \"pipe\", \"ignore\"],\n }).trim();\n } catch {\n return cwd;\n }\n}\n\nfunction eventName(input) {\n return String(input && input.hook_event_name ? input.hook_event_name : \"\");\n}\n\nfunction truncateText(value, maxChars) {\n const text = String(value || \"\");\n if (text.length <= maxChars) return { text, truncated: false, originalLength: text.length };\n return {\n text: text.slice(0, maxChars) + \"\\\\n\\\\n[Holdpoint output truncated to \" + maxChars + \" chars.]\",\n truncated: true,\n originalLength: text.length,\n };\n}\n\nfunction isPathInsideRoot(repoRoot, absPath) {\n const rel = relative(repoRoot, absPath);\n return rel === \"\" || (!rel.startsWith(\"..\") && !isAbsolute(rel));\n}\n\nfunction sendLiveEvent(input) {\n try {\n execSync(LIVE_COMMAND, {\n input: JSON.stringify(input),\n encoding: \"utf8\",\n stdio: [\"pipe\", \"ignore\", \"ignore\"],\n });\n } catch {\n // Live telemetry is best-effort and must never break Cursor's hook flow.\n }\n}\n\nfunction readConfig(repoRoot) {\n const configPath = join(repoRoot, \".github/holdpoint/generated/checks.immutable.json\");\n if (!existsSync(configPath)) return {};\n try { return JSON.parse(readFileSync(configPath, \"utf8\")); } catch { return {}; }\n}\n\nfunction readFileContext(repoRoot, file) {\n if (typeof file !== \"string\" || !file.trim()) return null;\n const abs = resolve(repoRoot, file);\n if (!isPathInsideRoot(repoRoot, abs) || !existsSync(abs)) return null;\n try { return \"<!-- \" + file + \" -->\\\\n\" + readFileSync(abs, \"utf8\"); } catch { return null; }\n}\n\nconst DATETIME_TEXT = () =>\n \"Current date and time: \" + new Date().toISOString() + \" (UTC)\\\\n\" +\n \"Provided by Holdpoint — use this to avoid knowledge-cutoff confusion.\";\n\n// Gather agent context for a Holdpoint hook. NOTE: Cursor's beforeSubmitPrompt\n// cannot inject context (it only gates submission), so the top-level datetime\n// and message_submit checks are surfaced at sessionStart instead — the only\n// Cursor stage that accepts additional_context per the hooks API.\nfunction gatherHookContext(repoRoot, hook) {\n const cfg = readConfig(repoRoot);\n const checks = Array.isArray(cfg.checks) ? cfg.checks : [];\n const parts = [];\n let hasDatetime = false;\n const addDatetime = () => { if (!hasDatetime) { hasDatetime = true; parts.push(DATETIME_TEXT()); } };\n\n const includeHooks = hook === \"session_start\" ? [\"session_start\", \"message_submit\"] : [hook];\n\n if (hook === \"session_start\") {\n const files = Array.isArray(cfg.session_context_files) ? cfg.session_context_files : [];\n for (const f of files) { const c = readFileContext(repoRoot, f); if (c) parts.push(c); }\n if (cfg.security_scan !== false) {\n const scan = formatSecurityScan(repoRoot);\n if (scan) parts.push(scan);\n }\n }\n for (const c of checks) {\n const on = typeof c.on === \"string\" ? c.on : \"before_done\";\n if (!includeHooks.includes(on)) continue;\n if (c.inject && typeof c.inject === \"object\") {\n if (c.inject.datetime === true) addDatetime();\n if (typeof c.inject.text === \"string\" && c.inject.text.trim()) parts.push(c.inject.text);\n if (Array.isArray(c.inject.files)) for (const f of c.inject.files) { const x = readFileContext(repoRoot, f); if (x) parts.push(x); }\n } else if (typeof c.prompt === \"string\" && c.prompt.trim()) {\n parts.push(\"Holdpoint reminder [\" + (c.label || c.id || \"check\") + \"]: \" + c.prompt);\n }\n }\n // Cursor can only inject once (sessionStart), so fold the per-message datetime in here.\n if (hook === \"session_start\" && cfg.inject_datetime !== false) addDatetime();\n\n if (parts.length === 0) return undefined;\n const context = truncateText(parts.join(\"\\\\n\\\\n\"), MAX_CONTEXT_CHARS);\n return {\n additional_context: context.text,\n truncated: context.truncated,\n originalLength: context.originalLength,\n emittedLength: context.text.length,\n };\n}\n\nfunction hasCmdAt(repoRoot, hook) {\n const cfg = readConfig(repoRoot);\n const checks = Array.isArray(cfg.checks) ? cfg.checks : [];\n return checks.some((c) => typeof c.cmd === \"string\" && (typeof c.on === \"string\" ? c.on : \"before_done\") === hook);\n}\n\nfunction runHoldpointChecks(repoRoot, command = CHECK_COMMAND) {\n const startedAt = Date.now();\n try {\n const output = execSync(command, {\n cwd: repoRoot,\n stdio: \"pipe\",\n encoding: \"utf8\",\n maxBuffer: CHECK_MAX_BUFFER_BYTES,\n });\n return {\n ok: true,\n durationMs: Date.now() - startedAt,\n output: String(output || \"\").trim(),\n };\n } catch (error) {\n const output = [error && error.stdout, error && error.stderr, error && error.message]\n .filter(Boolean)\n .join(\"\\\\n\")\n .trim();\n const truncated = truncateText(output, MAX_CHECK_OUTPUT_CHARS);\n return {\n ok: false,\n durationMs: Date.now() - startedAt,\n output: truncated.text || \"Holdpoint checks failed. Fix the issues above, then re-attempt.\",\n truncated: truncated.truncated,\n originalLength: truncated.originalLength,\n };\n }\n}\n\nfunction shouldRunCompletionChecks(input) {\n const name = eventName(input);\n if (name === \"stop\") return true;\n if (name === \"subagentStop\") {\n return input && input.status === \"completed\";\n }\n return false;\n}\n\nconst input = readInput();\nconst cwd = typeof input.cwd === \"string\" ? input.cwd : process.cwd();\nconst repoRoot = resolveRepoRoot(cwd);\nconst name = eventName(input);\n\nif (name === \"sessionStart\") {\n const context = gatherHookContext(repoRoot, \"session_start\");\n sendLiveEvent({\n ...input,\n holdpoint_context: context\n ? {\n truncated: context.truncated,\n originalLength: context.originalLength,\n emittedLength: context.emittedLength,\n }\n : undefined,\n });\n if (context?.additional_context) {\n writeFileSync(1, JSON.stringify({ additional_context: context.additional_context }) + \"\\\\n\");\n }\n process.exit(0);\n}\n\nif (shouldRunCompletionChecks(input)) {\n const result = runHoldpointChecks(repoRoot);\n sendLiveEvent({ ...input, holdpoint_check: result });\n if (result.ok) {\n process.exit(0);\n }\n process.stdout.write(\n JSON.stringify({\n followup_message:\n result.output +\n \"\\\\n\\\\nHoldpoint checks failed. Fix the issues above, then run the checks again before finishing.\",\n }) + \"\\\\n\",\n );\n process.exit(0);\n}\n\nsendLiveEvent(input);\n\nif (name === \"preToolUse\") {\n // Gate on before_tool cmd checks; deny the tool if they fail.\n if (hasCmdAt(repoRoot, \"before_tool\")) {\n const result = runHoldpointChecks(repoRoot, CHECK_COMMAND + \" --hook before_tool\");\n if (!result.ok) {\n process.stdout.write(\n JSON.stringify({ permission: \"deny\", agentMessage: result.output }) + \"\\\\n\",\n );\n process.exit(0);\n }\n }\n process.stdout.write(JSON.stringify({ permission: \"allow\" }) + \"\\\\n\");\n} else if (\n name === \"beforeShellExecution\" ||\n name === \"beforeMCPExecution\" ||\n name === \"beforeReadFile\" ||\n name === \"subagentStart\"\n) {\n process.stdout.write(JSON.stringify({ permission: \"allow\" }) + \"\\\\n\");\n} else if (name === \"beforeSubmitPrompt\") {\n // Cursor's beforeSubmitPrompt cannot inject context — only allow/deny the\n // submission. Per-message context is folded into sessionStart instead.\n process.stdout.write(JSON.stringify({ continue: true }) + \"\\\\n\");\n}\nprocess.exit(0);\n`;\n}\n\n/**\n * Generate a standalone context-injection script for sessionStart tests.\n * Cursor uses the same generated dispatcher for context, telemetry, and gates.\n */\nexport function buildContextScript(): string {\n return buildCheckScript();\n}\n\n/**\n * Generate .cursorrules additions from a HoldpointConfig.\n *\n * Cursor now enforces Holdpoint through `.cursor/hooks.json`; this rules block\n * remains useful context for the agent and for Cursor cloud cases where not all\n * local hook stages are available.\n */\nexport function buildEngine(config: HoldpointConfig): string {\n const deterministicList = config.checks\n .filter((c) => c.cmd !== undefined)\n .map((c) => ` - [${c.when ?? \"always\"}] ${c.label}: \\`${c.cmd ?? \"(no cmd)\"}\\``)\n .join(\"\\n\");\n\n const promptList = config.checks\n .filter((c) => c.prompt !== undefined)\n .map((c) => ` - [${c.when ?? \"always\"}] ${c.label}: ${c.prompt ?? \"\"}`)\n .join(\"\\n\");\n\n return `# ─── Holdpoint Rules (auto-generated) ─────────────────────────────────────────\n# DO NOT EDIT this block manually. Re-generate with: npx holdpoint update\n\n## Mandatory pre-completion checks\n\nHoldpoint also installed Cursor project hooks in \\`.cursor/hooks.json\\`. Before\nmarking ANY task as done or making a final commit, you MUST:\n\n1. Run all Holdpoint tasks and confirm they pass:\n${deterministicList || \" (no tasks configured)\"}\n\n2. Act on all matching agent prompts:\n${promptList || \" (no prompt checks configured)\"}\n\n3. If any task exits non-zero, fix the underlying issue before\n proceeding. Do NOT suppress errors or skip tasks.\n\n4. For prompt checks, explicitly state in your response that you have acted on\n each item before marking the task complete.\n\n## Running checks\n Run: \\`node_modules/.bin/holdpoint check --staged\\` to execute all tasks.\n Fix all failures before proceeding.\n\n# ─── End Holdpoint Rules ───────────────────────────────────────────────────────\n`;\n}\n","import { execFileSync } from \"node:child_process\";\nimport { createHash, randomUUID } from \"node:crypto\";\nimport { existsSync, realpathSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport type { EventV1 } from \"@holdpoint/live-protocol\";\nimport type { TranslateHookInputOptions } from \"@holdpoint/sdk\";\n\ninterface CursorHookInput {\n conversation_id?: string;\n generation_id?: string;\n session_id?: string;\n hook_event_name?: string;\n cwd?: string;\n workspace_roots?: string[];\n model?: string;\n prompt?: string;\n tool_name?: string;\n tool_input?: unknown;\n tool_output?: string;\n tool_use_id?: string;\n duration?: number;\n duration_ms?: number;\n error_message?: string;\n failure_type?: string;\n status?: string;\n reason?: string;\n command?: string;\n output?: string;\n file_path?: string;\n modified_files?: string[];\n subagent_id?: string;\n subagent_type?: string;\n task?: string;\n holdpoint_check?: {\n ok?: boolean;\n durationMs?: number;\n output?: string;\n };\n holdpoint_context?: {\n truncated?: boolean;\n originalLength?: number;\n emittedLength?: number;\n };\n}\n\nfunction asObject(value: unknown): Record<string, unknown> {\n return value != null && typeof value === \"object\" && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : {};\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim() ? value : undefined;\n}\n\nfunction asNumber(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n}\n\nfunction sha12(value: string): string {\n return createHash(\"sha256\").update(value).digest(\"hex\").slice(0, 12);\n}\n\nfunction resolveRepoRoot(cwd: string): string {\n try {\n return realpathSync(\n execFileSync(\"git\", [\"rev-parse\", \"--show-toplevel\"], {\n cwd,\n encoding: \"utf8\",\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n }).trim(),\n );\n } catch {\n try {\n return realpathSync(cwd);\n } catch {\n return resolve(cwd);\n }\n }\n}\n\nfunction extractStringArray(value: unknown): string[] {\n return Array.isArray(value)\n ? value.filter((entry): entry is string => typeof entry === \"string\")\n : [];\n}\n\nfunction normalizeWriteTarget(cwd: string, target: string): string {\n const resolved = resolve(cwd, target);\n return existsSync(resolved) ? realpathSync.native(resolved) : resolved;\n}\n\nfunction extractWriteTargets(input: CursorHookInput, cwd: string): string[] | undefined {\n const candidates = new Set<string>();\n const toolInput = asObject(input.tool_input);\n\n for (const key of [\"file_path\", \"filePath\", \"path\"]) {\n const value = toolInput[key] ?? (input as Record<string, unknown>)[key];\n if (typeof value === \"string\" && value.trim()) {\n candidates.add(normalizeWriteTarget(cwd, value));\n }\n }\n\n for (const key of [\"paths\", \"file_paths\", \"modified_files\"]) {\n for (const value of extractStringArray(\n toolInput[key] ?? (input as Record<string, unknown>)[key],\n )) {\n if (value.trim()) {\n candidates.add(normalizeWriteTarget(cwd, value));\n }\n }\n }\n\n return candidates.size > 0 ? [...candidates] : undefined;\n}\n\nfunction truncate(value: string, max: number): { value: string; truncatedAt?: number } {\n if (value.length <= max) return { value };\n return { value: value.slice(0, max), truncatedAt: max };\n}\n\nfunction sessionId(input: CursorHookInput): string | undefined {\n return input.conversation_id ?? input.session_id ?? input.generation_id;\n}\n\nfunction mapSessionEndReason(\n reason: string | undefined,\n): \"user\" | \"completed\" | \"error\" | undefined {\n if (reason === \"completed\" || reason === \"error\") return reason;\n if (reason === \"aborted\" || reason === \"window_close\" || reason === \"user_close\") return \"user\";\n return reason ? \"completed\" : undefined;\n}\n\nfunction buildCursorHookEvent(raw: unknown, options?: TranslateHookInputOptions): EventV1 | null {\n const input = asObject(raw) as CursorHookInput;\n const id = sessionId(input);\n const hookEventName = asString(input.hook_event_name);\n if (!id || !hookEventName) {\n return null;\n }\n\n const cwd = asString(input.cwd) ?? input.workspace_roots?.[0] ?? options?.cwd ?? process.cwd();\n const repoRoot = resolveRepoRoot(cwd);\n const base = {\n v: 1 as const,\n id: randomUUID(),\n ts: Date.now(),\n engine: \"cursor\",\n session_id: id,\n project_hash: sha12(repoRoot),\n cwd: repoRoot,\n };\n const toolName = asString(input.tool_name) ?? (input.command ? \"Shell\" : undefined);\n const toolUseId = input.tool_use_id ?? input.generation_id ?? randomUUID();\n const writeTargets = extractWriteTargets(input, cwd);\n\n switch (hookEventName) {\n case \"sessionStart\":\n return {\n ...base,\n type: \"session_start\",\n payload: {\n ...(input.holdpoint_context?.truncated ? { tools_available: [\"context_truncated\"] } : {}),\n },\n };\n case \"sessionEnd\":\n return {\n ...base,\n type: \"session_end\",\n payload: {\n ...(mapSessionEndReason(asString(input.reason) ?? asString(input.status))\n ? { reason: mapSessionEndReason(asString(input.reason) ?? asString(input.status)) }\n : {}),\n },\n };\n case \"beforeSubmitPrompt\": {\n const prompt = asString(input.prompt) ?? \"\";\n const { value, truncatedAt } = truncate(prompt, 10_000);\n return {\n ...base,\n type: \"prompt_submit\",\n payload: {\n prompt: value,\n ...(truncatedAt ? { truncated_at: truncatedAt } : {}),\n },\n };\n }\n case \"preToolUse\":\n return {\n ...base,\n type: \"tool_pre\",\n payload: {\n tool_name: toolName ?? \"unknown\",\n tool_use_id: toolUseId,\n tool_input: asObject(input.tool_input),\n ...(writeTargets ? { write_targets: writeTargets } : {}),\n },\n };\n case \"postToolUse\":\n case \"afterShellExecution\":\n case \"afterMCPExecution\":\n return {\n ...base,\n type: \"tool_post\",\n payload: {\n tool_name: toolName ?? (hookEventName === \"afterShellExecution\" ? \"Shell\" : \"unknown\"),\n tool_use_id: toolUseId,\n success: true,\n duration_ms: asNumber(input.duration) ?? asNumber(input.duration_ms) ?? 0,\n ...((input.output ?? input.tool_output)\n ? { output_summary: truncate(String(input.output ?? input.tool_output), 2_000).value }\n : {}),\n ...(writeTargets ? { write_targets: writeTargets } : {}),\n },\n };\n case \"postToolUseFailure\":\n return {\n ...base,\n type: \"tool_failure\",\n payload: {\n tool_name: toolName ?? \"unknown\",\n tool_use_id: toolUseId,\n error:\n asString(input.error_message) ?? asString(input.failure_type) ?? \"Cursor tool failed\",\n },\n };\n case \"beforeShellExecution\":\n case \"beforeMCPExecution\":\n case \"beforeReadFile\":\n return {\n ...base,\n type: \"tool_pre\",\n payload: {\n tool_name:\n hookEventName === \"beforeShellExecution\"\n ? \"Shell\"\n : hookEventName === \"beforeMCPExecution\"\n ? \"MCP\"\n : hookEventName === \"beforeReadFile\"\n ? \"Read\"\n : \"unknown\",\n tool_use_id: toolUseId,\n tool_input:\n hookEventName === \"beforeShellExecution\" && input.command\n ? { command: input.command }\n : hookEventName === \"beforeReadFile\" && input.file_path\n ? { file_path: input.file_path }\n : asObject(input.tool_input),\n ...(writeTargets ? { write_targets: writeTargets } : {}),\n },\n };\n case \"afterFileEdit\":\n return {\n ...base,\n type: \"tool_post\",\n payload: {\n tool_name: \"Write\",\n tool_use_id: toolUseId,\n success: true,\n duration_ms: asNumber(input.duration) ?? asNumber(input.duration_ms) ?? 0,\n ...(writeTargets ? { write_targets: writeTargets } : {}),\n },\n };\n case \"stop\": {\n const check = input.holdpoint_check;\n if (check?.ok === false) {\n return {\n ...base,\n type: \"stop_block\",\n payload: {\n reason: check.output ?? \"Holdpoint checks failed\",\n failing_checks: [],\n },\n };\n }\n return {\n ...base,\n type: \"stop_pass\",\n payload: {\n duration_ms: check?.durationMs ?? asNumber(input.duration_ms) ?? 0,\n },\n };\n }\n case \"subagentStart\":\n case \"subagentStop\":\n case \"preCompact\":\n case \"afterAgentResponse\":\n return {\n ...base,\n type: \"meta\",\n payload: {\n kind: \"cursor_lifecycle\",\n hook_event_name: hookEventName,\n status: input.status,\n subagent_type: input.subagent_type,\n },\n };\n default:\n return {\n ...base,\n type: \"meta\",\n payload: {\n kind: \"cursor_hook\",\n hook_event_name: hookEventName,\n },\n };\n }\n}\n\nexport const adapter = {\n id: \"cursor\",\n displayName: \"Cursor\",\n capabilities: {\n can_stream: true,\n },\n generateBridgeCommand(): string {\n return \"node_modules/.bin/holdpoint event --engine cursor --from-hook\";\n },\n translateHookInput(raw: unknown, options?: TranslateHookInputOptions) {\n return buildCursorHookEvent(raw, options);\n },\n};\n","export const manifest = {\n manifestVersion: 1,\n id: \"cursor\",\n displayName: \"Cursor\",\n} as const;\n"],"mappings":";AAAA,SAAS,+BAA+B;AAGjC,IAAM,+BAA+B;AAE5C,IAAM,eAAe,qCAAqC,4BAA4B;AAetF,SAAS,KAAK,UAAuC,CAAC,GAAe;AACnE,SAAO;AAAA,IACL,SAAS;AAAA,IACT,GAAG;AAAA,EACL;AACF;AAUO,SAAS,eAAe,QAAiC;AAC9D,QAAM,QAAkC;AAAA,IACtC,oBAAoB,CAAC,KAAK,EAAE,SAAS,GAAG,CAAC,CAAC;AAAA,IAC1C,YAAY,CAAC,KAAK,EAAE,SAAS,IAAI,SAAS,oCAAoC,CAAC,CAAC;AAAA,IAChF,aAAa,CAAC,KAAK,EAAE,SAAS,GAAG,CAAC,CAAC;AAAA,IACnC,oBAAoB,CAAC,KAAK,EAAE,SAAS,GAAG,CAAC,CAAC;AAAA,IAC1C,sBAAsB,CAAC,KAAK,EAAE,SAAS,GAAG,CAAC,CAAC;AAAA,IAC5C,qBAAqB,CAAC,KAAK,EAAE,SAAS,GAAG,CAAC,CAAC;AAAA,IAC3C,oBAAoB,CAAC,KAAK,EAAE,SAAS,GAAG,CAAC,CAAC;AAAA,IAC1C,mBAAmB,CAAC,KAAK,EAAE,SAAS,GAAG,CAAC,CAAC;AAAA,IACzC,gBAAgB,CAAC,KAAK,EAAE,SAAS,GAAG,CAAC,CAAC;AAAA,IACtC,eAAe,CAAC,KAAK,EAAE,SAAS,GAAG,CAAC,CAAC;AAAA,IACrC,eAAe,CAAC,KAAK,EAAE,SAAS,GAAG,CAAC,CAAC;AAAA,IACrC,cAAc,CAAC,KAAK,EAAE,SAAS,KAAK,YAAY,EAAE,CAAC,CAAC;AAAA,IACpD,YAAY,CAAC,KAAK,EAAE,SAAS,GAAG,CAAC,CAAC;AAAA,IAClC,oBAAoB,CAAC,KAAK,EAAE,SAAS,GAAG,CAAC,CAAC;AAAA,IAC1C,MAAM,CAAC,KAAK,EAAE,SAAS,KAAK,YAAY,EAAE,CAAC,CAAC;AAAA,IAC5C,cAAc,CAAC,KAAK,EAAE,SAAS,GAAG,CAAC,CAAC;AAAA,EACtC;AAEA,OAAK;AACL,SAAO,KAAK,UAAU,EAAE,SAAS,GAAG,MAAM,GAAG,MAAM,CAAC,IAAI;AAC1D;AAYO,SAAS,mBAA2B;AACzC,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA,EAKP,wBAAwB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyO3B;AAMO,SAAS,qBAA6B;AAC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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@holdpoint/engine-cursor",
3
- "version": "0.1.0-alpha.13",
3
+ "version": "0.1.0-alpha.15",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -47,15 +47,15 @@
47
47
  "LICENSE"
48
48
  ],
49
49
  "dependencies": {
50
- "@holdpoint/sdk": "0.1.0-alpha.4",
51
50
  "@holdpoint/live-protocol": "0.1.0-alpha.4",
52
- "@holdpoint/types": "0.1.0-alpha.10"
51
+ "@holdpoint/sdk": "0.1.0-alpha.4",
52
+ "@holdpoint/types": "0.1.0-alpha.11"
53
53
  },
54
54
  "devDependencies": {
55
- "@types/node": "^25.9.1",
55
+ "@types/node": "^25.9.2",
56
56
  "tsup": "^8.3.5",
57
57
  "typescript": "^6.0.3",
58
- "vitest": "^4.1.7"
58
+ "vitest": "^4.1.8"
59
59
  },
60
60
  "scripts": {
61
61
  "build": "tsup",