@mnemonik/cursor-hooks 0.1.0
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/hook.d.ts +2 -0
- package/dist/hook.js +456 -0
- package/dist/hook.js.map +1 -0
- package/dist/install.d.ts +27 -0
- package/dist/install.js +142 -0
- package/dist/install.js.map +1 -0
- package/dist/lib/behavior.d.ts +51 -0
- package/dist/lib/behavior.js +50 -0
- package/dist/lib/behavior.js.map +1 -0
- package/dist/lib/cursorOutput.d.ts +23 -0
- package/dist/lib/cursorOutput.js +58 -0
- package/dist/lib/cursorOutput.js.map +1 -0
- package/dist/lib/env.d.ts +9 -0
- package/dist/lib/env.js +77 -0
- package/dist/lib/env.js.map +1 -0
- package/dist/lib/http.d.ts +83 -0
- package/dist/lib/http.js +257 -0
- package/dist/lib/http.js.map +1 -0
- package/dist/lib/shellTokens.d.ts +15 -0
- package/dist/lib/shellTokens.js +32 -0
- package/dist/lib/shellTokens.js.map +1 -0
- package/dist/lib/types.d.ts +125 -0
- package/dist/lib/types.js +2 -0
- package/dist/lib/types.js.map +1 -0
- package/package.json +33 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package-level behaviour constants for the Cursor hook dispatcher.
|
|
3
|
+
*
|
|
4
|
+
* Why these are constants, not user config:
|
|
5
|
+
*
|
|
6
|
+
* The dogfood-platform model: WE (the package maintainers) decide which
|
|
7
|
+
* gates run in which mode at any given version. Customers install a
|
|
8
|
+
* version of this package and get the contract that version ships with.
|
|
9
|
+
* They do not reason about JSON settings files; they do not flip
|
|
10
|
+
* advisory-vs-enforce switches; the only knobs they ever touch are
|
|
11
|
+
* policy declarations (forbiddenCommand, mustConfirm) which describe
|
|
12
|
+
* their INTENT — Mnemonik honours that intent automatically.
|
|
13
|
+
*
|
|
14
|
+
* When a gate matures, the maintainers flip its constant here, bump
|
|
15
|
+
* the package version, ship. Every customer on the new version gets
|
|
16
|
+
* the new default. No JSON edits, no migration guides.
|
|
17
|
+
*
|
|
18
|
+
* The one exception is MNEMONIK_BYPASS_HOOKS — that's an emergency
|
|
19
|
+
* environment-variable escape hatch, not config.
|
|
20
|
+
*
|
|
21
|
+
* Kept in sync with @mnemonik/codex-hooks and @mnemonik/claude-code-hooks.
|
|
22
|
+
*/
|
|
23
|
+
export type GateMode = 'advisory' | 'enforce' | 'off';
|
|
24
|
+
export type SoftMode = 'advisory' | 'off';
|
|
25
|
+
/**
|
|
26
|
+
* sessionStart + beforeSubmitPrompt context injection (Cursor-equivalent
|
|
27
|
+
* of codex-hooks PROMPT_CONTEXT and claude-code-hooks userPromptContext).
|
|
28
|
+
*/
|
|
29
|
+
export declare const PROMPT_CONTEXT: SoftMode;
|
|
30
|
+
/** preToolUse Edit/Write gate (Cursor matcher "Write" covers all edit-class operations). */
|
|
31
|
+
export declare const PRE_EDIT_GATE: GateMode;
|
|
32
|
+
/** Auto-fetch file_context from the server in PreEdit advisory mode. */
|
|
33
|
+
export declare const PRE_EDIT_ADVISORY_AUTO_FETCH = true;
|
|
34
|
+
/** beforeShellExecution gate. Irreducible deny + server-side policy reminder. */
|
|
35
|
+
export declare const PRE_BASH_GATE: GateMode;
|
|
36
|
+
/**
|
|
37
|
+
* beforeMCPExecution gate. Calls /api/v1/hooks/mcp-precheck for Mnemonik
|
|
38
|
+
* MCP tool calls and forwards the server verdict. The endpoint enforces
|
|
39
|
+
* Cat 1-9 of the ordering-rule taxonomy. Cat 10 enrichment runs server-side
|
|
40
|
+
* via enrichArgs() and is invisible to the hook.
|
|
41
|
+
*/
|
|
42
|
+
export declare const PRE_MCP_GATE: GateMode;
|
|
43
|
+
/**
|
|
44
|
+
* stop continuation pressure ("you made changes but didn't checkpoint").
|
|
45
|
+
* loop_limit: null on stop/subagentStop so this isn't capped at 5.
|
|
46
|
+
*/
|
|
47
|
+
export declare const CHECKPOINT_PRESSURE: SoftMode;
|
|
48
|
+
/** subagentStart / subagentStop observability. */
|
|
49
|
+
export declare const SUBAGENT_TRACK: SoftMode;
|
|
50
|
+
/** preCompact observational telemetry. Cursor does not allow gating on this event. */
|
|
51
|
+
export declare const PRECOMPACT_OBSERVE: SoftMode;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package-level behaviour constants for the Cursor hook dispatcher.
|
|
3
|
+
*
|
|
4
|
+
* Why these are constants, not user config:
|
|
5
|
+
*
|
|
6
|
+
* The dogfood-platform model: WE (the package maintainers) decide which
|
|
7
|
+
* gates run in which mode at any given version. Customers install a
|
|
8
|
+
* version of this package and get the contract that version ships with.
|
|
9
|
+
* They do not reason about JSON settings files; they do not flip
|
|
10
|
+
* advisory-vs-enforce switches; the only knobs they ever touch are
|
|
11
|
+
* policy declarations (forbiddenCommand, mustConfirm) which describe
|
|
12
|
+
* their INTENT — Mnemonik honours that intent automatically.
|
|
13
|
+
*
|
|
14
|
+
* When a gate matures, the maintainers flip its constant here, bump
|
|
15
|
+
* the package version, ship. Every customer on the new version gets
|
|
16
|
+
* the new default. No JSON edits, no migration guides.
|
|
17
|
+
*
|
|
18
|
+
* The one exception is MNEMONIK_BYPASS_HOOKS — that's an emergency
|
|
19
|
+
* environment-variable escape hatch, not config.
|
|
20
|
+
*
|
|
21
|
+
* Kept in sync with @mnemonik/codex-hooks and @mnemonik/claude-code-hooks.
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* sessionStart + beforeSubmitPrompt context injection (Cursor-equivalent
|
|
25
|
+
* of codex-hooks PROMPT_CONTEXT and claude-code-hooks userPromptContext).
|
|
26
|
+
*/
|
|
27
|
+
export const PROMPT_CONTEXT = 'advisory';
|
|
28
|
+
/** preToolUse Edit/Write gate (Cursor matcher "Write" covers all edit-class operations). */
|
|
29
|
+
export const PRE_EDIT_GATE = 'advisory';
|
|
30
|
+
/** Auto-fetch file_context from the server in PreEdit advisory mode. */
|
|
31
|
+
export const PRE_EDIT_ADVISORY_AUTO_FETCH = true;
|
|
32
|
+
/** beforeShellExecution gate. Irreducible deny + server-side policy reminder. */
|
|
33
|
+
export const PRE_BASH_GATE = 'advisory';
|
|
34
|
+
/**
|
|
35
|
+
* beforeMCPExecution gate. Calls /api/v1/hooks/mcp-precheck for Mnemonik
|
|
36
|
+
* MCP tool calls and forwards the server verdict. The endpoint enforces
|
|
37
|
+
* Cat 1-9 of the ordering-rule taxonomy. Cat 10 enrichment runs server-side
|
|
38
|
+
* via enrichArgs() and is invisible to the hook.
|
|
39
|
+
*/
|
|
40
|
+
export const PRE_MCP_GATE = 'advisory';
|
|
41
|
+
/**
|
|
42
|
+
* stop continuation pressure ("you made changes but didn't checkpoint").
|
|
43
|
+
* loop_limit: null on stop/subagentStop so this isn't capped at 5.
|
|
44
|
+
*/
|
|
45
|
+
export const CHECKPOINT_PRESSURE = 'advisory';
|
|
46
|
+
/** subagentStart / subagentStop observability. */
|
|
47
|
+
export const SUBAGENT_TRACK = 'advisory';
|
|
48
|
+
/** preCompact observational telemetry. Cursor does not allow gating on this event. */
|
|
49
|
+
export const PRECOMPACT_OBSERVE = 'advisory';
|
|
50
|
+
//# sourceMappingURL=behavior.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"behavior.js","sourceRoot":"","sources":["../../src/lib/behavior.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAKH;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAa,UAAU,CAAC;AAEnD,4FAA4F;AAC5F,MAAM,CAAC,MAAM,aAAa,GAAa,UAAU,CAAC;AAElD,wEAAwE;AACxE,MAAM,CAAC,MAAM,4BAA4B,GAAG,IAAI,CAAC;AAEjD,iFAAiF;AACjF,MAAM,CAAC,MAAM,aAAa,GAAa,UAAU,CAAC;AAElD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,YAAY,GAAa,UAAU,CAAC;AAEjD;;;GAGG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAa,UAAU,CAAC;AAExD,kDAAkD;AAClD,MAAM,CAAC,MAAM,cAAc,GAAa,UAAU,CAAC;AAEnD,sFAAsF;AACtF,MAAM,CAAC,MAAM,kBAAkB,GAAa,UAAU,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { CursorHookOutput } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Output builders for the Cursor hook contract. Cursor accepts a family
|
|
4
|
+
* of shapes depending on the hook event; we keep them as small builders
|
|
5
|
+
* so the dispatcher reads cleanly.
|
|
6
|
+
*
|
|
7
|
+
* Reference: cursor.com/docs/hooks (verified 2026-05-12, plan §3.2).
|
|
8
|
+
*/
|
|
9
|
+
export declare function allow(): CursorHookOutput;
|
|
10
|
+
export declare function deny(reason: string, userMessage?: string): CursorHookOutput;
|
|
11
|
+
export declare function ask(reason: string, userMessage?: string): CursorHookOutput;
|
|
12
|
+
export declare function continueWith(message?: string): CursorHookOutput;
|
|
13
|
+
export declare function stopWithFollowup(message: string): CursorHookOutput;
|
|
14
|
+
/**
|
|
15
|
+
* sessionStart / postToolUse output. `additional_context` is the documented
|
|
16
|
+
* field for context injection on these events.
|
|
17
|
+
*/
|
|
18
|
+
export declare function additionalContext(text: string): CursorHookOutput;
|
|
19
|
+
/**
|
|
20
|
+
* Truncate a context string to a byte budget while leaving a marker so the
|
|
21
|
+
* agent knows it was clipped.
|
|
22
|
+
*/
|
|
23
|
+
export declare function trimContext(text: string, maxBytes?: number): string;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Output builders for the Cursor hook contract. Cursor accepts a family
|
|
3
|
+
* of shapes depending on the hook event; we keep them as small builders
|
|
4
|
+
* so the dispatcher reads cleanly.
|
|
5
|
+
*
|
|
6
|
+
* Reference: cursor.com/docs/hooks (verified 2026-05-12, plan §3.2).
|
|
7
|
+
*/
|
|
8
|
+
export function allow() {
|
|
9
|
+
return { permission: 'allow' };
|
|
10
|
+
}
|
|
11
|
+
export function deny(reason, userMessage) {
|
|
12
|
+
return {
|
|
13
|
+
permission: 'deny',
|
|
14
|
+
agent_message: reason,
|
|
15
|
+
...(userMessage ? { user_message: userMessage } : {}),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export function ask(reason, userMessage) {
|
|
19
|
+
return {
|
|
20
|
+
permission: 'ask',
|
|
21
|
+
agent_message: reason,
|
|
22
|
+
...(userMessage ? { user_message: userMessage } : {}),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export function continueWith(message) {
|
|
26
|
+
return {
|
|
27
|
+
continue: true,
|
|
28
|
+
...(message ? { user_message: message } : {}),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
export function stopWithFollowup(message) {
|
|
32
|
+
return { followup_message: message };
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* sessionStart / postToolUse output. `additional_context` is the documented
|
|
36
|
+
* field for context injection on these events.
|
|
37
|
+
*/
|
|
38
|
+
export function additionalContext(text) {
|
|
39
|
+
return { additional_context: text };
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Truncate a context string to a byte budget while leaving a marker so the
|
|
43
|
+
* agent knows it was clipped.
|
|
44
|
+
*/
|
|
45
|
+
export function trimContext(text, maxBytes = 12_000) {
|
|
46
|
+
if (Buffer.byteLength(text, 'utf8') <= maxBytes)
|
|
47
|
+
return text;
|
|
48
|
+
const suffix = '\n\n[Mnemonik: context exceeded hook budget. Call memory_get/file_context for full detail if needed.]';
|
|
49
|
+
const budget = Math.max(0, maxBytes - Buffer.byteLength(suffix, 'utf8'));
|
|
50
|
+
let out = '';
|
|
51
|
+
for (const ch of text) {
|
|
52
|
+
if (Buffer.byteLength(out + ch, 'utf8') > budget)
|
|
53
|
+
break;
|
|
54
|
+
out += ch;
|
|
55
|
+
}
|
|
56
|
+
return out + suffix;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=cursorOutput.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursorOutput.js","sourceRoot":"","sources":["../../src/lib/cursorOutput.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AAEH,MAAM,UAAU,KAAK;IACnB,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,MAAc,EAAE,WAAoB;IACvD,OAAO;QACL,UAAU,EAAE,MAAM;QAClB,aAAa,EAAE,MAAM;QACrB,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACtD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,GAAG,CAAC,MAAc,EAAE,WAAoB;IACtD,OAAO;QACL,UAAU,EAAE,KAAK;QACjB,aAAa,EAAE,MAAM;QACrB,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACtD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAAgB;IAC3C,OAAO;QACL,QAAQ,EAAE,IAAI;QACd,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC9C,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,CAAC;AACvC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,EAAE,kBAAkB,EAAE,IAAI,EAAE,CAAC;AACtC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,QAAQ,GAAG,MAAM;IACzD,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC7D,MAAM,MAAM,GACV,uGAAuG,CAAC;IAC1G,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACzE,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC;QACtB,IAAI,MAAM,CAAC,UAAU,CAAC,GAAG,GAAG,EAAE,EAAE,MAAM,CAAC,GAAG,MAAM;YAAE,MAAM;QACxD,GAAG,IAAI,EAAE,CAAC;IACZ,CAAC;IACD,OAAO,GAAG,GAAG,MAAM,CAAC;AACtB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type BypassEnvelope, type HookConfig } from './types.js';
|
|
2
|
+
export declare function isNonInteractive(env?: NodeJS.ProcessEnv): boolean;
|
|
3
|
+
export declare function parseBypass(env?: NodeJS.ProcessEnv): BypassEnvelope;
|
|
4
|
+
/**
|
|
5
|
+
* Resolve hook config: apiKey + server only. `.mnemonik.json` is NOT read
|
|
6
|
+
* here — gate enforcement modes are package-level constants in
|
|
7
|
+
* lib/behavior.ts (plug-and-play per cursor-hooks plan §10).
|
|
8
|
+
*/
|
|
9
|
+
export declare function resolveConfig(_cwd: string, env?: NodeJS.ProcessEnv): Promise<HookConfig>;
|
package/dist/lib/env.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { DEFAULT_SERVER } from './types.js';
|
|
5
|
+
const VALID_BYPASS_TYPES = new Set([
|
|
6
|
+
'typo',
|
|
7
|
+
'formatting',
|
|
8
|
+
'regenerated',
|
|
9
|
+
'already_grounded',
|
|
10
|
+
'other',
|
|
11
|
+
]);
|
|
12
|
+
export function isNonInteractive(env = process.env) {
|
|
13
|
+
if (env.CI === 'true')
|
|
14
|
+
return true;
|
|
15
|
+
if (env.GITHUB_ACTIONS === 'true')
|
|
16
|
+
return true;
|
|
17
|
+
if (env.MNEMONIK_NONINTERACTIVE === '1')
|
|
18
|
+
return true;
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
export function parseBypass(env = process.env) {
|
|
22
|
+
if (env.MNEMONIK_BYPASS_HOOKS !== '1') {
|
|
23
|
+
return { active: false, type: null, detail: null, invalidReason: null };
|
|
24
|
+
}
|
|
25
|
+
const rawType = (env.MNEMONIK_BYPASS_TYPE ?? '').trim().toLowerCase();
|
|
26
|
+
if (!rawType) {
|
|
27
|
+
return {
|
|
28
|
+
active: false,
|
|
29
|
+
type: null,
|
|
30
|
+
detail: null,
|
|
31
|
+
invalidReason: 'MNEMONIK_BYPASS_TYPE is required when MNEMONIK_BYPASS_HOOKS=1',
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
if (!VALID_BYPASS_TYPES.has(rawType)) {
|
|
35
|
+
return {
|
|
36
|
+
active: false,
|
|
37
|
+
type: null,
|
|
38
|
+
detail: null,
|
|
39
|
+
invalidReason: `MNEMONIK_BYPASS_TYPE must be one of ${[...VALID_BYPASS_TYPES].join('|')}`,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const type = rawType;
|
|
43
|
+
if (type === 'other') {
|
|
44
|
+
const detail = (env.MNEMONIK_BYPASS_DETAIL ?? '').trim();
|
|
45
|
+
if (detail.length < 50 || detail.length > 200) {
|
|
46
|
+
return {
|
|
47
|
+
active: false,
|
|
48
|
+
type: null,
|
|
49
|
+
detail: null,
|
|
50
|
+
invalidReason: "MNEMONIK_BYPASS_TYPE='other' requires MNEMONIK_BYPASS_DETAIL of 50-200 chars",
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
return { active: true, type, detail, invalidReason: null };
|
|
54
|
+
}
|
|
55
|
+
return { active: true, type, detail: null, invalidReason: null };
|
|
56
|
+
}
|
|
57
|
+
async function readJson(path) {
|
|
58
|
+
try {
|
|
59
|
+
const raw = await readFile(path, 'utf8');
|
|
60
|
+
return JSON.parse(raw);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Resolve hook config: apiKey + server only. `.mnemonik.json` is NOT read
|
|
68
|
+
* here — gate enforcement modes are package-level constants in
|
|
69
|
+
* lib/behavior.ts (plug-and-play per cursor-hooks plan §10).
|
|
70
|
+
*/
|
|
71
|
+
export async function resolveConfig(_cwd, env = process.env) {
|
|
72
|
+
const scanner = await readJson(join(homedir(), '.mnemonik', 'scanner.json'));
|
|
73
|
+
const apiKey = env.MNEMONIK_API_KEY?.trim() || scanner?.apiKey?.trim() || null;
|
|
74
|
+
const server = (env.MNEMONIK_SERVER?.trim() || scanner?.server?.trim() || DEFAULT_SERVER).replace(/\/$/, '');
|
|
75
|
+
return { apiKey, server };
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=env.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/lib/env.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { HookContextResponse, McpPrecheckResponse, PolicyReminderResponse, SnapshotResponse } from './types.js';
|
|
2
|
+
export interface FetchSnapshotInput {
|
|
3
|
+
server: string;
|
|
4
|
+
apiKey: string;
|
|
5
|
+
cwd: string;
|
|
6
|
+
cursorSessionId: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function fetchSnapshot(input: FetchSnapshotInput): Promise<SnapshotResponse | null>;
|
|
9
|
+
export interface FetchPolicyReminderInput {
|
|
10
|
+
server: string;
|
|
11
|
+
apiKey: string;
|
|
12
|
+
cwd: string;
|
|
13
|
+
cursorSessionId: string;
|
|
14
|
+
tool: string;
|
|
15
|
+
context: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function fetchPolicyReminder(input: FetchPolicyReminderInput): Promise<PolicyReminderResponse | null>;
|
|
18
|
+
export interface FetchHookContextInput {
|
|
19
|
+
server: string;
|
|
20
|
+
apiKey: string;
|
|
21
|
+
cwd: string;
|
|
22
|
+
cursorSessionId: string;
|
|
23
|
+
event: string;
|
|
24
|
+
prompt?: string;
|
|
25
|
+
toolName?: string;
|
|
26
|
+
filePaths?: string[];
|
|
27
|
+
lastAssistantMessage?: string | null;
|
|
28
|
+
}
|
|
29
|
+
export declare function fetchHookContext(input: FetchHookContextInput): Promise<HookContextResponse | null>;
|
|
30
|
+
export interface FetchMcpPrecheckInput {
|
|
31
|
+
server: string;
|
|
32
|
+
apiKey: string;
|
|
33
|
+
cwd: string;
|
|
34
|
+
cursorSessionId: string;
|
|
35
|
+
tool: string;
|
|
36
|
+
args: Record<string, unknown>;
|
|
37
|
+
model?: string;
|
|
38
|
+
}
|
|
39
|
+
export declare function fetchMcpPrecheck(input: FetchMcpPrecheckInput): Promise<McpPrecheckResponse | null>;
|
|
40
|
+
export interface ReportGateFiredInput {
|
|
41
|
+
server: string;
|
|
42
|
+
apiKey: string | null;
|
|
43
|
+
cwd: string;
|
|
44
|
+
cursorSessionId: string;
|
|
45
|
+
tool: string;
|
|
46
|
+
mode: 'advisory' | 'enforce' | 'off';
|
|
47
|
+
outcome: string;
|
|
48
|
+
}
|
|
49
|
+
export declare function reportGateFired(input: ReportGateFiredInput): Promise<void>;
|
|
50
|
+
export interface ReportBypassInput {
|
|
51
|
+
server: string;
|
|
52
|
+
apiKey: string | null;
|
|
53
|
+
cwd: string;
|
|
54
|
+
cursorSessionId: string;
|
|
55
|
+
tool: string;
|
|
56
|
+
bypassType: string;
|
|
57
|
+
detail: string | null;
|
|
58
|
+
}
|
|
59
|
+
export declare function reportBypass(input: ReportBypassInput): Promise<void>;
|
|
60
|
+
export declare function trackIdeEdit(input: {
|
|
61
|
+
server: string;
|
|
62
|
+
apiKey: string | null;
|
|
63
|
+
sessionId: string;
|
|
64
|
+
filePath: string;
|
|
65
|
+
}): Promise<void>;
|
|
66
|
+
export interface ReportSubagentInput {
|
|
67
|
+
server: string;
|
|
68
|
+
apiKey: string | null;
|
|
69
|
+
cwd: string;
|
|
70
|
+
cursorSessionId: string;
|
|
71
|
+
event: 'start' | 'stop';
|
|
72
|
+
subagentId: string;
|
|
73
|
+
subagentType?: string;
|
|
74
|
+
task?: string;
|
|
75
|
+
parentConversationId?: string;
|
|
76
|
+
toolCallId?: string;
|
|
77
|
+
subagentModel?: string;
|
|
78
|
+
isParallelWorker?: boolean;
|
|
79
|
+
gitBranch?: string;
|
|
80
|
+
status?: string;
|
|
81
|
+
durationMs?: number;
|
|
82
|
+
}
|
|
83
|
+
export declare function reportSubagent(input: ReportSubagentInput): Promise<void>;
|
package/dist/lib/http.js
ADDED
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
const FETCH_TIMEOUT_MS = 2000;
|
|
2
|
+
const TELEMETRY_TIMEOUT_MS = 500;
|
|
3
|
+
const POST_TOOL_TIMEOUT_MS = 1500;
|
|
4
|
+
const MCP_PRECHECK_TIMEOUT_MS = 2000;
|
|
5
|
+
function withTimeout(ms) {
|
|
6
|
+
const ac = new AbortController();
|
|
7
|
+
const timer = setTimeout(() => ac.abort(), ms);
|
|
8
|
+
return { signal: ac.signal, cleanup: () => clearTimeout(timer) };
|
|
9
|
+
}
|
|
10
|
+
const HOST = 'cursor';
|
|
11
|
+
export async function fetchSnapshot(input) {
|
|
12
|
+
const url = `${input.server.replace(/\/$/, '')}/api/v1/hooks/snapshot`;
|
|
13
|
+
const { signal, cleanup } = withTimeout(FETCH_TIMEOUT_MS);
|
|
14
|
+
try {
|
|
15
|
+
const res = await fetch(url, {
|
|
16
|
+
method: 'POST',
|
|
17
|
+
headers: {
|
|
18
|
+
'content-type': 'application/json',
|
|
19
|
+
authorization: `Bearer ${input.apiKey}`,
|
|
20
|
+
},
|
|
21
|
+
body: JSON.stringify({
|
|
22
|
+
cwd: input.cwd,
|
|
23
|
+
// The snapshot endpoint accepts claudeSessionId as the historical field
|
|
24
|
+
// name; codex-hooks reuses it for host-agnostic session correlation.
|
|
25
|
+
claudeSessionId: input.cursorSessionId,
|
|
26
|
+
host: HOST,
|
|
27
|
+
}),
|
|
28
|
+
signal,
|
|
29
|
+
});
|
|
30
|
+
if (!res.ok)
|
|
31
|
+
return null;
|
|
32
|
+
return (await res.json());
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
finally {
|
|
38
|
+
cleanup();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export async function fetchPolicyReminder(input) {
|
|
42
|
+
if (!input.context.trim())
|
|
43
|
+
return null;
|
|
44
|
+
const url = `${input.server.replace(/\/$/, '')}/api/v1/hooks/policy-reminder`;
|
|
45
|
+
const { signal, cleanup } = withTimeout(FETCH_TIMEOUT_MS);
|
|
46
|
+
try {
|
|
47
|
+
const res = await fetch(url, {
|
|
48
|
+
method: 'POST',
|
|
49
|
+
headers: {
|
|
50
|
+
'content-type': 'application/json',
|
|
51
|
+
authorization: `Bearer ${input.apiKey}`,
|
|
52
|
+
},
|
|
53
|
+
body: JSON.stringify({
|
|
54
|
+
cwd: input.cwd,
|
|
55
|
+
claudeSessionId: input.cursorSessionId,
|
|
56
|
+
tool: input.tool,
|
|
57
|
+
context: input.context,
|
|
58
|
+
}),
|
|
59
|
+
signal,
|
|
60
|
+
});
|
|
61
|
+
if (!res.ok)
|
|
62
|
+
return null;
|
|
63
|
+
return (await res.json());
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
cleanup();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
export async function fetchHookContext(input) {
|
|
73
|
+
const url = `${input.server.replace(/\/$/, '')}/api/v1/hooks/context`;
|
|
74
|
+
const { signal, cleanup } = withTimeout(FETCH_TIMEOUT_MS);
|
|
75
|
+
try {
|
|
76
|
+
const res = await fetch(url, {
|
|
77
|
+
method: 'POST',
|
|
78
|
+
headers: {
|
|
79
|
+
'content-type': 'application/json',
|
|
80
|
+
authorization: `Bearer ${input.apiKey}`,
|
|
81
|
+
},
|
|
82
|
+
body: JSON.stringify({
|
|
83
|
+
host: HOST,
|
|
84
|
+
event: input.event,
|
|
85
|
+
cwd: input.cwd,
|
|
86
|
+
sessionId: input.cursorSessionId,
|
|
87
|
+
prompt: input.prompt,
|
|
88
|
+
toolName: input.toolName,
|
|
89
|
+
filePaths: input.filePaths,
|
|
90
|
+
lastAssistantMessage: input.lastAssistantMessage,
|
|
91
|
+
}),
|
|
92
|
+
signal,
|
|
93
|
+
});
|
|
94
|
+
if (!res.ok)
|
|
95
|
+
return null;
|
|
96
|
+
return (await res.json());
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
finally {
|
|
102
|
+
cleanup();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
export async function fetchMcpPrecheck(input) {
|
|
106
|
+
const url = `${input.server.replace(/\/$/, '')}/api/v1/hooks/mcp-precheck`;
|
|
107
|
+
const { signal, cleanup } = withTimeout(MCP_PRECHECK_TIMEOUT_MS);
|
|
108
|
+
try {
|
|
109
|
+
const res = await fetch(url, {
|
|
110
|
+
method: 'POST',
|
|
111
|
+
headers: {
|
|
112
|
+
'content-type': 'application/json',
|
|
113
|
+
authorization: `Bearer ${input.apiKey}`,
|
|
114
|
+
},
|
|
115
|
+
body: JSON.stringify({
|
|
116
|
+
cwd: input.cwd,
|
|
117
|
+
cursorSessionId: input.cursorSessionId,
|
|
118
|
+
tool: input.tool,
|
|
119
|
+
args: input.args,
|
|
120
|
+
model: input.model,
|
|
121
|
+
host: HOST,
|
|
122
|
+
}),
|
|
123
|
+
signal,
|
|
124
|
+
});
|
|
125
|
+
if (!res.ok)
|
|
126
|
+
return null;
|
|
127
|
+
return (await res.json());
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
finally {
|
|
133
|
+
cleanup();
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
export async function reportGateFired(input) {
|
|
137
|
+
if (!input.apiKey)
|
|
138
|
+
return;
|
|
139
|
+
const url = `${input.server.replace(/\/$/, '')}/api/v1/hooks/gate-fired`;
|
|
140
|
+
const { signal, cleanup } = withTimeout(TELEMETRY_TIMEOUT_MS);
|
|
141
|
+
try {
|
|
142
|
+
await fetch(url, {
|
|
143
|
+
method: 'POST',
|
|
144
|
+
headers: {
|
|
145
|
+
'content-type': 'application/json',
|
|
146
|
+
authorization: `Bearer ${input.apiKey}`,
|
|
147
|
+
},
|
|
148
|
+
body: JSON.stringify({
|
|
149
|
+
cwd: input.cwd,
|
|
150
|
+
host: HOST,
|
|
151
|
+
cursorSessionId: input.cursorSessionId,
|
|
152
|
+
tool: input.tool,
|
|
153
|
+
mode: input.mode,
|
|
154
|
+
outcome: input.outcome,
|
|
155
|
+
}),
|
|
156
|
+
signal,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
// Telemetry must not crash hooks.
|
|
161
|
+
}
|
|
162
|
+
finally {
|
|
163
|
+
cleanup();
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
export async function reportBypass(input) {
|
|
167
|
+
if (!input.apiKey)
|
|
168
|
+
return;
|
|
169
|
+
const url = `${input.server.replace(/\/$/, '')}/api/v1/hooks/bypass`;
|
|
170
|
+
const { signal, cleanup } = withTimeout(TELEMETRY_TIMEOUT_MS);
|
|
171
|
+
try {
|
|
172
|
+
await fetch(url, {
|
|
173
|
+
method: 'POST',
|
|
174
|
+
headers: {
|
|
175
|
+
'content-type': 'application/json',
|
|
176
|
+
authorization: `Bearer ${input.apiKey}`,
|
|
177
|
+
},
|
|
178
|
+
body: JSON.stringify({
|
|
179
|
+
cwd: input.cwd,
|
|
180
|
+
host: HOST,
|
|
181
|
+
cursorSessionId: input.cursorSessionId,
|
|
182
|
+
tool: input.tool,
|
|
183
|
+
bypassType: input.bypassType,
|
|
184
|
+
detail: input.detail,
|
|
185
|
+
}),
|
|
186
|
+
signal,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
// Telemetry must not crash hooks.
|
|
191
|
+
}
|
|
192
|
+
finally {
|
|
193
|
+
cleanup();
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
export async function trackIdeEdit(input) {
|
|
197
|
+
if (!input.apiKey)
|
|
198
|
+
return;
|
|
199
|
+
const url = `${input.server.replace(/\/$/, '')}/api/v1/session/track-ide-edit`;
|
|
200
|
+
const { signal, cleanup } = withTimeout(POST_TOOL_TIMEOUT_MS);
|
|
201
|
+
try {
|
|
202
|
+
await fetch(url, {
|
|
203
|
+
method: 'POST',
|
|
204
|
+
headers: {
|
|
205
|
+
'content-type': 'application/json',
|
|
206
|
+
authorization: `Bearer ${input.apiKey}`,
|
|
207
|
+
},
|
|
208
|
+
body: JSON.stringify({ sessionId: input.sessionId, filePath: input.filePath, host: HOST }),
|
|
209
|
+
signal,
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
// Best effort only.
|
|
214
|
+
}
|
|
215
|
+
finally {
|
|
216
|
+
cleanup();
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
export async function reportSubagent(input) {
|
|
220
|
+
if (!input.apiKey)
|
|
221
|
+
return;
|
|
222
|
+
const url = `${input.server.replace(/\/$/, '')}/api/v1/hooks/subagent`;
|
|
223
|
+
const { signal, cleanup } = withTimeout(TELEMETRY_TIMEOUT_MS);
|
|
224
|
+
try {
|
|
225
|
+
await fetch(url, {
|
|
226
|
+
method: 'POST',
|
|
227
|
+
headers: {
|
|
228
|
+
'content-type': 'application/json',
|
|
229
|
+
authorization: `Bearer ${input.apiKey}`,
|
|
230
|
+
},
|
|
231
|
+
body: JSON.stringify({
|
|
232
|
+
cwd: input.cwd,
|
|
233
|
+
cursorSessionId: input.cursorSessionId,
|
|
234
|
+
host: HOST,
|
|
235
|
+
event: input.event,
|
|
236
|
+
subagentId: input.subagentId,
|
|
237
|
+
subagentType: input.subagentType,
|
|
238
|
+
task: input.task,
|
|
239
|
+
parentConversationId: input.parentConversationId,
|
|
240
|
+
toolCallId: input.toolCallId,
|
|
241
|
+
subagentModel: input.subagentModel,
|
|
242
|
+
isParallelWorker: input.isParallelWorker,
|
|
243
|
+
gitBranch: input.gitBranch,
|
|
244
|
+
status: input.status,
|
|
245
|
+
durationMs: input.durationMs,
|
|
246
|
+
}),
|
|
247
|
+
signal,
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
catch {
|
|
251
|
+
// Telemetry must not crash hooks.
|
|
252
|
+
}
|
|
253
|
+
finally {
|
|
254
|
+
cleanup();
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
//# sourceMappingURL=http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/lib/http.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Irreducible deny-floor for catastrophic, irreversible commands.
|
|
3
|
+
* Kept in sync with @mnemonik/codex-hooks/src/lib/shellTokens.ts and
|
|
4
|
+
* @mnemonik/claude-code-hooks/src/lib/shellTokens.ts — see those files
|
|
5
|
+
* for the full rationale.
|
|
6
|
+
*
|
|
7
|
+
* Phase 1 / 0.1.0 of cursor-hooks: this is the ONE place the dispatcher
|
|
8
|
+
* does local pattern matching. Every other policy decision lives behind
|
|
9
|
+
* /api/v1/hooks/policy-reminder (Bash) or /api/v1/hooks/mcp-precheck (MCP).
|
|
10
|
+
*/
|
|
11
|
+
export declare const IRREDUCIBLE_DENY: ReadonlyArray<{
|
|
12
|
+
name: string;
|
|
13
|
+
pattern: RegExp;
|
|
14
|
+
}>;
|
|
15
|
+
export declare function matchIrreducibleDeny(command: string): string | null;
|