@ascenda-one/cursor-hooks 0.1.16
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/LICENSE +202 -0
- package/README.md +73 -0
- package/dist/cli.js +3847 -0
- package/dist/cli.js.map +1 -0
- package/dist/mapCursorEvent.js +151 -0
- package/dist/mapCursorEvent.js.map +1 -0
- package/dist/setup.js +28 -0
- package/dist/setup.js.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/examples/hooks.json +45 -0
- package/package.json +30 -0
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { bucketDurationMs, classifyCommand, getNestedString, getNumber, getString, inferOutcome, isVerificationCommand, looksLikeCorrection } from "@ascenda-one/tool-kit";
|
|
2
|
+
import { CURSOR_HOST } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Maps Cursor agent hooks to the canonical Ascenda event catalog.
|
|
5
|
+
* Catalog values only; hooks without a catalog counterpart map to nothing.
|
|
6
|
+
* See docs/CURSOR_MAPPING.md.
|
|
7
|
+
*/
|
|
8
|
+
export function mapCursorEvent(hookName, input, turnDurationMs) {
|
|
9
|
+
switch (hookName) {
|
|
10
|
+
case "sessionStart": return [{ eventType: "create_focus_session", severity: "low", metadata: withHost({ activity: "session_started" }) }];
|
|
11
|
+
case "sessionEnd": return [{ eventType: "recovery_offline_period", severity: "low", metadata: withHost({ activity: "session_ended" }) }];
|
|
12
|
+
case "beforeSubmitPrompt": return mapPrompt(input);
|
|
13
|
+
case "preToolUse": return [{ eventType: "ai_tool_call_started", severity: "low", metadata: withHost({ toolName: sanitiseToolName(getToolName(input)) }) }];
|
|
14
|
+
case "postToolUse": return mapPostToolUse(input);
|
|
15
|
+
case "postToolUseFailure": return mapPostToolUseFailure(input);
|
|
16
|
+
case "preCompact": return mapPreCompact(input);
|
|
17
|
+
case "stop": return mapStop(turnDurationMs);
|
|
18
|
+
// Deliberately unmapped. The shell / MCP / file-edit hooks are specialised
|
|
19
|
+
// views of tool calls that preToolUse and postToolUse already report, so
|
|
20
|
+
// registering them would double-count every command and edit. The rest
|
|
21
|
+
// (subagent lifecycle, agent thoughts, Tab completions, workspaceOpen)
|
|
22
|
+
// have no catalog counterpart.
|
|
23
|
+
default: return [];
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function mapPrompt(input) {
|
|
27
|
+
const prompt = getString(input, ["prompt"]);
|
|
28
|
+
const events = [{ eventType: "ai_prompt_submitted", severity: "low", metadata: withHost({ promptClass: "unknown" }) }];
|
|
29
|
+
if (looksLikeCorrection(prompt)) {
|
|
30
|
+
events.push({ eventType: "ai_correction_prompt", severity: "medium", metadata: withHost({ reason: "repeated_reprompting", trigger: "inferred" }) });
|
|
31
|
+
}
|
|
32
|
+
return events;
|
|
33
|
+
}
|
|
34
|
+
function mapPostToolUse(input) {
|
|
35
|
+
const toolName = getToolName(input);
|
|
36
|
+
const safeToolName = sanitiseToolName(toolName);
|
|
37
|
+
const commandClass = classifyCommand(getCommand(input));
|
|
38
|
+
const durationBucket = bucketDurationMs(getNumber(input, ["duration"]));
|
|
39
|
+
const outcome = inferOutcome(withParsedToolOutput(input));
|
|
40
|
+
if (outcome === "failure") {
|
|
41
|
+
if (isShell(toolName) && isVerificationCommand(commandClass)) {
|
|
42
|
+
return [{ eventType: "compile_error", severity: "medium", metadata: withHost({ toolName: safeToolName, commandClass, outcome, durationBucket, reason: "test_failure" }) }];
|
|
43
|
+
}
|
|
44
|
+
return [{ eventType: "ai_tool_call_failed", severity: "medium", metadata: withHost({ toolName: safeToolName, commandClass, outcome, durationBucket, reason: "tool_failure" }) }];
|
|
45
|
+
}
|
|
46
|
+
if (isWriteTool(toolName)) {
|
|
47
|
+
return [{ eventType: toolName?.toLowerCase() === "write" ? "ai_file_write" : "ai_file_edit", severity: "low", metadata: withHost({ toolName: safeToolName, outcome, durationBucket }) }];
|
|
48
|
+
}
|
|
49
|
+
if (isShell(toolName) && isVerificationCommand(commandClass)) {
|
|
50
|
+
return [{ eventType: "editor_verification_activity", severity: "low", metadata: withHost({ toolName: safeToolName, commandClass, outcome, durationBucket, activity: "ai_test_or_build_run" }) }];
|
|
51
|
+
}
|
|
52
|
+
return [{ eventType: "ai_tool_call_completed", severity: "low", metadata: withHost({ toolName: safeToolName, commandClass, outcome, durationBucket }) }];
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Cursor reports failures on their own hook rather than through an exit code,
|
|
56
|
+
* so outcome is known without inspecting output. `is_interrupt` separates a
|
|
57
|
+
* user cancelling the agent from the tool genuinely failing.
|
|
58
|
+
*/
|
|
59
|
+
function mapPostToolUseFailure(input) {
|
|
60
|
+
const toolName = getToolName(input);
|
|
61
|
+
const safeToolName = sanitiseToolName(toolName);
|
|
62
|
+
const commandClass = classifyCommand(getCommand(input));
|
|
63
|
+
const durationBucket = bucketDurationMs(getNumber(input, ["duration"]));
|
|
64
|
+
const interrupted = input.is_interrupt === true;
|
|
65
|
+
const outcome = interrupted ? "cancelled" : "failure";
|
|
66
|
+
if (!interrupted && isShell(toolName) && isVerificationCommand(commandClass)) {
|
|
67
|
+
return [{ eventType: "compile_error", severity: "medium", metadata: withHost({ toolName: safeToolName, commandClass, outcome, durationBucket, reason: "test_failure" }) }];
|
|
68
|
+
}
|
|
69
|
+
return [{
|
|
70
|
+
eventType: "ai_tool_call_failed",
|
|
71
|
+
severity: interrupted ? "low" : "medium",
|
|
72
|
+
metadata: withHost({ toolName: safeToolName, commandClass, outcome, durationBucket, reason: interrupted ? "manual_interrupt" : "tool_failure" })
|
|
73
|
+
}];
|
|
74
|
+
}
|
|
75
|
+
function mapPreCompact(input) {
|
|
76
|
+
const isManual = getString(input, ["trigger"])?.toLowerCase().includes("manual") ?? false;
|
|
77
|
+
return [{
|
|
78
|
+
eventType: isManual ? "context_compression_manual" : "context_compression_auto",
|
|
79
|
+
severity: isManual ? "medium" : "high",
|
|
80
|
+
metadata: withHost({ trigger: isManual ? "manual" : "auto", reason: "context_limit", ...contextOccupancy(input) })
|
|
81
|
+
}];
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Cursor's compaction payload carries the composer's context occupancy as a
|
|
85
|
+
* percent. It leaves under `contextWindowPeakPct`, the canonical fraction key
|
|
86
|
+
* every reader resolves — never under an improvised spelling, and never under
|
|
87
|
+
* Cursor's own column name: `contextUsagePercent` is registered only so rows
|
|
88
|
+
* already imported under it stay readable. Compaction fires at the high-water
|
|
89
|
+
* mark, so the reading is the peak that key names. An absent field is an
|
|
90
|
+
* absent key: no reading must never arrive as 0.
|
|
91
|
+
*/
|
|
92
|
+
function contextOccupancy(input) {
|
|
93
|
+
const percent = getNumber(input, ["context_usage_percent", "contextUsagePercent"]);
|
|
94
|
+
if (percent === undefined || percent < 0)
|
|
95
|
+
return {};
|
|
96
|
+
return { contextWindowPeakPct: percent / 100 };
|
|
97
|
+
}
|
|
98
|
+
function mapStop(turnDurationMs) {
|
|
99
|
+
const durationBucket = bucketDurationMs(turnDurationMs);
|
|
100
|
+
if (durationBucket === "30-60m" || durationBucket === "60m+") {
|
|
101
|
+
return [{ eventType: "agent_loop_long", severity: durationBucket === "60m+" ? "high" : "medium", metadata: withHost({ durationBucket, reason: "long_session", trigger: "inferred" }) }];
|
|
102
|
+
}
|
|
103
|
+
return [];
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* `tool_output` is a JSON *string*, not an object, so the shared outcome
|
|
107
|
+
* inference cannot see the exit code inside it. Parse it into the `result`
|
|
108
|
+
* shape the helper already probes.
|
|
109
|
+
*/
|
|
110
|
+
function withParsedToolOutput(input) {
|
|
111
|
+
const raw = input.tool_output;
|
|
112
|
+
if (typeof raw !== "string")
|
|
113
|
+
return input;
|
|
114
|
+
try {
|
|
115
|
+
const parsed = JSON.parse(raw);
|
|
116
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
117
|
+
return input;
|
|
118
|
+
return { ...input, result: parsed };
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
return input;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
function getCommand(input) {
|
|
125
|
+
return getString(input, ["command"]) ?? getNestedString(input, [["tool_input", "command"]]);
|
|
126
|
+
}
|
|
127
|
+
function getToolName(input) {
|
|
128
|
+
return getString(input, ["tool_name", "toolName"]);
|
|
129
|
+
}
|
|
130
|
+
function isShell(toolName) {
|
|
131
|
+
const value = toolName?.toLowerCase();
|
|
132
|
+
return value === "shell" || value === "bash" || value === "terminal";
|
|
133
|
+
}
|
|
134
|
+
function isWriteTool(toolName) {
|
|
135
|
+
const value = toolName?.toLowerCase();
|
|
136
|
+
return value === "write" || value === "edit" || value === "multiedit" || value === "search_replace" || value === "apply_patch";
|
|
137
|
+
}
|
|
138
|
+
function sanitiseToolName(toolName) {
|
|
139
|
+
if (!toolName)
|
|
140
|
+
return "unknown";
|
|
141
|
+
return toolName.replace(/[^a-zA-Z0-9_-]/g, "").slice(0, 40) || "unknown";
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Typed against the wire's metadata shape rather than cast to it, so a value
|
|
145
|
+
* outside the contract's vocabulary — an outcome or reason the catalog does
|
|
146
|
+
* not spell — is a compile error here, not an unclassified row later.
|
|
147
|
+
*/
|
|
148
|
+
function withHost(metadata) {
|
|
149
|
+
return { host: CURSOR_HOST, ...metadata };
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=mapCursorEvent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mapCursorEvent.js","sourceRoot":"","sources":["../src/mapCursorEvent.ts"],"names":[],"mappings":"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"}
|
package/dist/setup.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import * as os from "os";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
import { ASCENDA_TOOL_TYPE, CURSOR_HOST } from "./types.js";
|
|
4
|
+
/**
|
|
5
|
+
* Only the hooks that map to a catalog event. The shell / MCP / file-edit
|
|
6
|
+
* hooks are specialised views of tool calls `preToolUse`/`postToolUse`
|
|
7
|
+
* already report; registering them would double-count every command.
|
|
8
|
+
*/
|
|
9
|
+
export const HOOK_EVENTS = ["sessionStart", "sessionEnd", "beforeSubmitPrompt", "preToolUse", "postToolUse", "postToolUseFailure", "preCompact", "stop"];
|
|
10
|
+
export const SETUP = {
|
|
11
|
+
host: CURSOR_HOST,
|
|
12
|
+
displayName: "Cursor",
|
|
13
|
+
toolType: ASCENDA_TOOL_TYPE,
|
|
14
|
+
packageName: "@ascenda-one/cursor-hooks",
|
|
15
|
+
binaryName: "ascenda-cursor-hook",
|
|
16
|
+
hookEvents: HOOK_EVENTS,
|
|
17
|
+
restartHint: "Restart Cursor to load the hooks.",
|
|
18
|
+
settings: {
|
|
19
|
+
settingsPath: (scope, projectDir) => scope === "user" ? path.join(os.homedir(), ".cursor", "hooks.json") : path.join(projectDir, ".cursor", "hooks.json"),
|
|
20
|
+
// Cursor's hooks.json is versioned; a file we create must say which.
|
|
21
|
+
scaffold: { version: 1 },
|
|
22
|
+
// Cursor passes the event on stdin too, but this adapter reads argv, so
|
|
23
|
+
// each entry names its event.
|
|
24
|
+
entry: (command, event) => ({ command: `${command} ${event}` }),
|
|
25
|
+
commandOf: (entry) => (entry && typeof entry === "object" ? entry.command : undefined)
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=setup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE5D;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,cAAc,EAAE,YAAY,EAAE,oBAAoB,EAAE,YAAY,EAAE,aAAa,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,CAAU,CAAC;AAElK,MAAM,CAAC,MAAM,KAAK,GAAsB;IACtC,IAAI,EAAE,WAAW;IACjB,WAAW,EAAE,QAAQ;IACrB,QAAQ,EAAE,iBAAiB;IAC3B,WAAW,EAAE,2BAA2B;IACxC,UAAU,EAAE,qBAAqB;IACjC,UAAU,EAAE,WAAW;IACvB,WAAW,EAAE,mCAAmC;IAChD,QAAQ,EAAE;QACR,YAAY,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,CAClC,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,EAAE,YAAY,CAAC;QACtH,qEAAqE;QACrE,QAAQ,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE;QACxB,wEAAwE;QACxE,8BAA8B;QAC9B,KAAK,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,IAAI,KAAK,EAAE,EAAE,CAAC;QAC/D,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAE,KAA+B,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAuB;KACxI;CACF,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backend toolType/source registry has no cursor-agent value yet. The Cursor
|
|
3
|
+
* *extension* already owns `cursor_mcp`, so the agent hooks ride `cli_agent`
|
|
4
|
+
* like Codex, with metadata.host separating them for later disaggregation.
|
|
5
|
+
*/
|
|
6
|
+
export const ASCENDA_TOOL_TYPE = "cli_agent";
|
|
7
|
+
export const CURSOR_HOST = "cursor";
|
|
8
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAyBA;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,WAAW,CAAC;AAC7C,MAAM,CAAC,MAAM,WAAW,GAAG,QAAQ,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"hooks": {
|
|
4
|
+
"sessionStart": [
|
|
5
|
+
{
|
|
6
|
+
"command": "ascenda-cursor-hook sessionStart"
|
|
7
|
+
}
|
|
8
|
+
],
|
|
9
|
+
"sessionEnd": [
|
|
10
|
+
{
|
|
11
|
+
"command": "ascenda-cursor-hook sessionEnd"
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"beforeSubmitPrompt": [
|
|
15
|
+
{
|
|
16
|
+
"command": "ascenda-cursor-hook beforeSubmitPrompt"
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"preToolUse": [
|
|
20
|
+
{
|
|
21
|
+
"command": "ascenda-cursor-hook preToolUse"
|
|
22
|
+
}
|
|
23
|
+
],
|
|
24
|
+
"postToolUse": [
|
|
25
|
+
{
|
|
26
|
+
"command": "ascenda-cursor-hook postToolUse"
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
"postToolUseFailure": [
|
|
30
|
+
{
|
|
31
|
+
"command": "ascenda-cursor-hook postToolUseFailure"
|
|
32
|
+
}
|
|
33
|
+
],
|
|
34
|
+
"preCompact": [
|
|
35
|
+
{
|
|
36
|
+
"command": "ascenda-cursor-hook preCompact"
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
"stop": [
|
|
40
|
+
{
|
|
41
|
+
"command": "ascenda-cursor-hook stop"
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"publishConfig": { "access": "public" },
|
|
3
|
+
"name": "@ascenda-one/cursor-hooks",
|
|
4
|
+
"version": "0.1.16",
|
|
5
|
+
"description": "Cursor agent hooks adapter for Ascenda AI workload telemetry",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/ascendaone-com/ai-engineer-tools.git",
|
|
9
|
+
"directory": "ascenda-cursor-hooks"
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
12
|
+
"files": ["dist", "examples"],
|
|
13
|
+
"license": "Apache-2.0",
|
|
14
|
+
"bin": {
|
|
15
|
+
"ascenda-cursor-hook": "./dist/cli.js"
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc -p ./ && npm run bundle",
|
|
19
|
+
"bundle": "esbuild src/cli.ts --bundle --platform=node --format=esm --banner:js=\"import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);\" --outfile=dist/cli.js",
|
|
20
|
+
"watch": "tsc -w -p ./",
|
|
21
|
+
"test": "node --test"
|
|
22
|
+
},
|
|
23
|
+
"engines": { "node": ">=20" },
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@ascenda-one/tool-contract": "*",
|
|
26
|
+
"@ascenda-one/tool-kit": "*",
|
|
27
|
+
"@types/node": "^20.14.10",
|
|
28
|
+
"typescript": "^5.5.0"
|
|
29
|
+
}
|
|
30
|
+
}
|