@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.
@@ -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
+ }