pi-cursor-sdk 0.1.62 → 0.3.6

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.
Files changed (279) hide show
  1. package/CHANGELOG.md +85 -0
  2. package/README.md +57 -53
  3. package/dist/bundled-context-windows.js +39 -0
  4. package/dist/context-window-cache.js +92 -0
  5. package/dist/context.js +338 -0
  6. package/dist/cursor-active-tools.js +3 -0
  7. package/dist/cursor-agent-message-web-tools.js +165 -0
  8. package/dist/cursor-agents-context-registration.js +17 -0
  9. package/dist/cursor-agents-context.js +113 -0
  10. package/dist/cursor-api-key.js +34 -0
  11. package/dist/cursor-bridge-contract.js +27 -0
  12. package/dist/cursor-cloud-lifecycle.js +650 -0
  13. package/dist/cursor-cloud-local-state.js +460 -0
  14. package/dist/cursor-cloud-options.js +145 -0
  15. package/dist/cursor-cloud-reporting.js +222 -0
  16. package/dist/cursor-compact-tool-summary.js +75 -0
  17. package/dist/cursor-config.js +613 -0
  18. package/dist/cursor-context-tools.js +4 -0
  19. package/dist/cursor-display-only-trace.js +11 -0
  20. package/dist/cursor-display-text.js +18 -0
  21. package/dist/cursor-durable-fs.js +53 -0
  22. package/dist/cursor-edit-diff.js +13 -0
  23. package/dist/cursor-env-boolean.js +19 -0
  24. package/dist/cursor-fallback-models.generated.js +7760 -0
  25. package/dist/cursor-fallback-warning.js +15 -0
  26. package/dist/cursor-http1.js +45 -0
  27. package/dist/cursor-incomplete-tool-visibility.js +83 -0
  28. package/dist/cursor-live-run-accounting.js +55 -0
  29. package/dist/cursor-live-run-coordinator.js +406 -0
  30. package/dist/cursor-mcp-timeout-override.js +116 -0
  31. package/dist/cursor-model-lifecycle.js +32 -0
  32. package/dist/cursor-model.js +5 -0
  33. package/dist/cursor-native-replay-routing.js +35 -0
  34. package/dist/cursor-native-replay-trace.js +28 -0
  35. package/dist/cursor-native-tool-display-registration.js +102 -0
  36. package/dist/cursor-native-tool-display-replay.js +428 -0
  37. package/dist/cursor-native-tool-display-state.js +70 -0
  38. package/dist/cursor-native-tool-display-tools.js +123 -0
  39. package/dist/cursor-native-tool-names.js +11 -0
  40. package/dist/cursor-partial-content-emitter.js +118 -0
  41. package/dist/cursor-pi-tool-bridge-abort.js +114 -0
  42. package/dist/cursor-pi-tool-bridge-constants.js +6 -0
  43. package/dist/cursor-pi-tool-bridge-diagnostics.js +125 -0
  44. package/dist/cursor-pi-tool-bridge-env.js +18 -0
  45. package/dist/cursor-pi-tool-bridge-mcp.js +100 -0
  46. package/dist/cursor-pi-tool-bridge-run.js +355 -0
  47. package/dist/cursor-pi-tool-bridge-server.js +163 -0
  48. package/dist/cursor-pi-tool-bridge-snapshot.js +63 -0
  49. package/dist/cursor-pi-tool-bridge-types.js +1 -0
  50. package/dist/cursor-pi-tool-bridge.js +123 -0
  51. package/dist/cursor-provider-errors.js +311 -0
  52. package/dist/cursor-provider-lazy.js +39 -0
  53. package/dist/cursor-provider-live-run-drain.js +412 -0
  54. package/dist/cursor-provider-overflow.js +90 -0
  55. package/dist/cursor-provider-run-finalizer.js +176 -0
  56. package/dist/cursor-provider-run-outcome.js +76 -0
  57. package/dist/cursor-provider-turn-coordinator.js +275 -0
  58. package/dist/cursor-provider-turn-display-router.js +158 -0
  59. package/dist/cursor-provider-turn-emit.js +35 -0
  60. package/dist/cursor-provider-turn-finalize.js +154 -0
  61. package/dist/cursor-provider-turn-lifecycle-emitter.js +126 -0
  62. package/dist/cursor-provider-turn-prepare.js +374 -0
  63. package/dist/cursor-provider-turn-runner.js +146 -0
  64. package/dist/cursor-provider-turn-sdk-normalizer.js +74 -0
  65. package/dist/cursor-provider-turn-send.js +138 -0
  66. package/dist/cursor-provider-turn-shell-output.js +117 -0
  67. package/dist/cursor-provider-turn-tool-ledger.js +99 -0
  68. package/dist/cursor-provider-turn-types.js +1 -0
  69. package/dist/cursor-provider.js +72 -0
  70. package/dist/cursor-question-tool.js +194 -0
  71. package/dist/cursor-record-utils.js +61 -0
  72. package/dist/cursor-replay-activity-builders.js +114 -0
  73. package/dist/cursor-replay-source-names.js +27 -0
  74. package/dist/cursor-replay-summary-args.js +105 -0
  75. package/dist/cursor-replay-tool-details.js +167 -0
  76. package/dist/cursor-ripgrep-path.js +27 -0
  77. package/dist/cursor-run-final-text.js +63 -0
  78. package/dist/cursor-runtime-state.js +380 -0
  79. package/dist/cursor-sdk-billed-usage.js +86 -0
  80. package/dist/cursor-sdk-event-debug-constants.js +33 -0
  81. package/dist/cursor-sdk-event-debug-session.js +107 -0
  82. package/dist/cursor-sdk-event-debug.js +461 -0
  83. package/dist/cursor-sdk-output-filter.js +1 -0
  84. package/dist/cursor-sdk-process-error-guard.js +221 -0
  85. package/dist/cursor-sdk-runtime.js +3 -0
  86. package/dist/cursor-sensitive-text.js +23 -0
  87. package/dist/cursor-session-agent-cleanup.js +311 -0
  88. package/dist/cursor-session-agent-lifecycle.js +32 -0
  89. package/dist/cursor-session-agent-lineage.js +103 -0
  90. package/dist/cursor-session-agent-resume.js +417 -0
  91. package/dist/cursor-session-agent.js +507 -0
  92. package/dist/cursor-session-compaction-prep.js +21 -0
  93. package/dist/cursor-session-scope.js +113 -0
  94. package/dist/cursor-session-send-policy.js +18 -0
  95. package/dist/cursor-session-store.js +105 -0
  96. package/dist/cursor-session-turn-queue.js +50 -0
  97. package/dist/cursor-setting-sources.js +15 -0
  98. package/dist/cursor-skill-tool.js +230 -0
  99. package/dist/cursor-state.js +519 -0
  100. package/dist/cursor-task-presentation.js +59 -0
  101. package/dist/cursor-tool-lifecycle.js +94 -0
  102. package/dist/cursor-tool-manifest.js +34 -0
  103. package/dist/cursor-tool-presentation-registry.js +305 -0
  104. package/dist/cursor-tool-result-display-readers.js +158 -0
  105. package/dist/cursor-tool-transcript.js +32 -0
  106. package/dist/cursor-tool-visibility.js +28 -0
  107. package/dist/cursor-transcript-tool-formatters.js +618 -0
  108. package/dist/cursor-transcript-tool-specs.js +284 -0
  109. package/dist/cursor-transcript-utils.js +170 -0
  110. package/dist/cursor-usage-accounting.js +166 -0
  111. package/dist/cursor-web-tool-activity.js +23 -0
  112. package/dist/cursor-web-tool-args.js +12 -0
  113. package/dist/index.js +82 -0
  114. package/dist/model-discovery.js +305 -0
  115. package/dist/model-list-cache.js +156 -0
  116. package/docs/cursor-dogfood-checklist.md +2 -1
  117. package/docs/cursor-live-smoke-checklist.md +15 -14
  118. package/docs/cursor-model-ux-spec.md +29 -8
  119. package/docs/cursor-native-tool-replay.md +13 -13
  120. package/docs/cursor-native-tool-visual-audit.md +6 -3
  121. package/docs/cursor-testing-lessons.md +7 -7
  122. package/docs/cursor-tool-surfaces.md +5 -5
  123. package/docs/platform-smoke.md +6 -6
  124. package/node_modules/fast-uri/index.js +37 -1
  125. package/node_modules/fast-uri/package.json +1 -1
  126. package/node_modules/fast-uri/test/security.test.js +136 -0
  127. package/node_modules/hono/dist/cjs/context.js +28 -13
  128. package/node_modules/hono/dist/cjs/helper/proxy/index.js +4 -0
  129. package/node_modules/hono/dist/cjs/helper/streaming/sse.js +1 -1
  130. package/node_modules/hono/dist/cjs/hono-base.js +3 -2
  131. package/node_modules/hono/dist/cjs/jsx/base.js +27 -23
  132. package/node_modules/hono/dist/cjs/jsx/hooks/index.js +16 -13
  133. package/node_modules/hono/dist/cjs/middleware/cache/index.js +103 -8
  134. package/node_modules/hono/dist/cjs/middleware/compress/index.js +5 -0
  135. package/node_modules/hono/dist/cjs/middleware/cors/index.js +2 -2
  136. package/node_modules/hono/dist/cjs/middleware/etag/index.js +1 -1
  137. package/node_modules/hono/dist/cjs/middleware/jwk/jwk.js +9 -4
  138. package/node_modules/hono/dist/cjs/middleware/jwt/jwt.js +9 -4
  139. package/node_modules/hono/dist/cjs/middleware/language/language.js +10 -6
  140. package/node_modules/hono/dist/cjs/middleware/method-not-allowed/index.js +90 -0
  141. package/node_modules/hono/dist/cjs/middleware/secure-headers/secure-headers.js +10 -4
  142. package/node_modules/hono/dist/cjs/request.js +7 -9
  143. package/node_modules/hono/dist/cjs/router/reg-exp-router/node.js +55 -56
  144. package/node_modules/hono/dist/cjs/router/reg-exp-router/router.js +64 -85
  145. package/node_modules/hono/dist/cjs/router/reg-exp-router/trie.js +13 -5
  146. package/node_modules/hono/dist/cjs/router.js +1 -1
  147. package/node_modules/hono/dist/cjs/utils/accept.js +1 -1
  148. package/node_modules/hono/dist/cjs/utils/cookie.js +3 -2
  149. package/node_modules/hono/dist/cjs/utils/url.js +8 -8
  150. package/node_modules/hono/dist/context.js +28 -13
  151. package/node_modules/hono/dist/helper/proxy/index.js +4 -0
  152. package/node_modules/hono/dist/helper/streaming/sse.js +1 -1
  153. package/node_modules/hono/dist/hono-base.js +3 -2
  154. package/node_modules/hono/dist/jsx/base.js +27 -23
  155. package/node_modules/hono/dist/jsx/hooks/index.js +16 -13
  156. package/node_modules/hono/dist/middleware/cache/index.js +103 -8
  157. package/node_modules/hono/dist/middleware/compress/index.js +5 -0
  158. package/node_modules/hono/dist/middleware/cors/index.js +2 -2
  159. package/node_modules/hono/dist/middleware/etag/index.js +1 -1
  160. package/node_modules/hono/dist/middleware/jwk/jwk.js +9 -4
  161. package/node_modules/hono/dist/middleware/jwt/jwt.js +9 -4
  162. package/node_modules/hono/dist/middleware/language/language.js +10 -6
  163. package/node_modules/hono/dist/middleware/method-not-allowed/index.js +68 -0
  164. package/node_modules/hono/dist/middleware/secure-headers/secure-headers.js +10 -4
  165. package/node_modules/hono/dist/request.js +8 -10
  166. package/node_modules/hono/dist/router/reg-exp-router/node.js +55 -56
  167. package/node_modules/hono/dist/router/reg-exp-router/router.js +64 -85
  168. package/node_modules/hono/dist/router/reg-exp-router/trie.js +13 -5
  169. package/node_modules/hono/dist/router.js +1 -1
  170. package/node_modules/hono/dist/types/adapter/aws-lambda/types.d.ts +9 -0
  171. package/node_modules/hono/dist/types/client/types.d.ts +1 -1
  172. package/node_modules/hono/dist/types/hono-base.d.ts +4 -3
  173. package/node_modules/hono/dist/types/jsx/base.d.ts +4 -2
  174. package/node_modules/hono/dist/types/jsx/dom/index.d.ts +5 -5
  175. package/node_modules/hono/dist/types/jsx/dom/intrinsic-element/components.d.ts +2 -2
  176. package/node_modules/hono/dist/types/jsx/dom/server.d.ts +5 -5
  177. package/node_modules/hono/dist/types/jsx/hooks/index.d.ts +8 -6
  178. package/node_modules/hono/dist/types/jsx/index.d.ts +5 -5
  179. package/node_modules/hono/dist/types/middleware/cache/index.d.ts +6 -4
  180. package/node_modules/hono/dist/types/middleware/cors/index.d.ts +1 -1
  181. package/node_modules/hono/dist/types/middleware/jsx-renderer/index.d.ts +2 -2
  182. package/node_modules/hono/dist/types/middleware/jwk/jwk.d.ts +2 -0
  183. package/node_modules/hono/dist/types/middleware/jwt/jwt.d.ts +2 -0
  184. package/node_modules/hono/dist/types/middleware/method-not-allowed/index.d.ts +49 -0
  185. package/node_modules/hono/dist/types/router/reg-exp-router/node.d.ts +1 -1
  186. package/node_modules/hono/dist/types/router/reg-exp-router/trie.d.ts +2 -1
  187. package/node_modules/hono/dist/types/router.d.ts +1 -1
  188. package/node_modules/hono/dist/types/utils/headers.d.ts +2 -2
  189. package/node_modules/hono/dist/types/utils/url.d.ts +1 -0
  190. package/node_modules/hono/dist/utils/accept.js +1 -1
  191. package/node_modules/hono/dist/utils/cookie.js +4 -3
  192. package/node_modules/hono/dist/utils/url.js +6 -7
  193. package/node_modules/hono/package.json +10 -3
  194. package/node_modules/ip-address/README.md +146 -126
  195. package/node_modules/ip-address/dist/common.d.ts +29 -0
  196. package/node_modules/ip-address/dist/common.js +44 -5
  197. package/node_modules/ip-address/dist/common.js.map +1 -1
  198. package/node_modules/ip-address/dist/ipv4.d.ts +8 -1
  199. package/node_modules/ip-address/dist/ipv4.js +24 -20
  200. package/node_modules/ip-address/dist/ipv4.js.map +1 -1
  201. package/node_modules/ip-address/dist/ipv6.d.ts +68 -3
  202. package/node_modules/ip-address/dist/ipv6.js +180 -53
  203. package/node_modules/ip-address/dist/ipv6.js.map +1 -1
  204. package/node_modules/ip-address/dist/v4/constants.js +5 -1
  205. package/node_modules/ip-address/dist/v4/constants.js.map +1 -1
  206. package/node_modules/ip-address/dist/v6/constants.js +3 -2
  207. package/node_modules/ip-address/dist/v6/constants.js.map +1 -1
  208. package/node_modules/ip-address/package.json +6 -4
  209. package/package.json +23 -11
  210. package/platform-smoke.config.mjs +1 -1
  211. package/scripts/build.mjs +126 -0
  212. package/scripts/cloud-runtime-smoke.mjs +3 -1
  213. package/scripts/debug-provider-events.mjs +3 -1
  214. package/scripts/debug-sdk-events.mjs +1 -1
  215. package/scripts/isolated-cursor-smoke.sh +5 -4
  216. package/scripts/lib/cloud-smoke-cleanup-evidence.mjs +1 -1
  217. package/scripts/lib/cursor-visual-render.mjs +1 -1
  218. package/scripts/lib/ensure-built.mjs +16 -0
  219. package/scripts/lib/local-resume-smoke-harness.mjs +1 -1
  220. package/scripts/local-resume-smoke.mjs +3 -1
  221. package/scripts/platform-smoke/card-detect.mjs +1 -1
  222. package/scripts/platform-smoke/live-suite-runner.mjs +16 -40
  223. package/scripts/platform-smoke/platform-build-windows.ps1 +1 -1
  224. package/scripts/platform-smoke/render-ansi.mjs +1 -1
  225. package/scripts/platform-smoke/scenarios.mjs +1 -1
  226. package/scripts/platform-smoke/targets.mjs +2 -2
  227. package/scripts/platform-smoke.mjs +5 -5
  228. package/scripts/prepare.mjs +102 -0
  229. package/scripts/refresh-cursor-model-snapshots.mjs +16 -7
  230. package/scripts/steering-rpc-smoke.mjs +4 -2
  231. package/scripts/tmux-live-smoke.sh +11 -11
  232. package/scripts/visual-tui-smoke-self-test.mjs +4 -1
  233. package/scripts/visual-tui-smoke.mjs +51 -7
  234. package/shared/cursor-model-selection-identities.d.mts +21 -0
  235. package/shared/cursor-model-selection-identities.mjs +95 -0
  236. package/src/bundled-context-windows.ts +21 -12
  237. package/src/context.ts +1 -1
  238. package/src/cursor-agents-context-registration.ts +2 -2
  239. package/src/cursor-agents-context.ts +0 -2
  240. package/src/cursor-api-key.ts +5 -4
  241. package/src/cursor-cloud-reporting.ts +23 -2
  242. package/src/cursor-context-tools.ts +1 -1
  243. package/src/cursor-display-only-trace.ts +1 -1
  244. package/src/cursor-fallback-models.generated.ts +1726 -824
  245. package/src/cursor-live-run-accounting.ts +1 -1
  246. package/src/cursor-live-run-coordinator.ts +2 -1
  247. package/src/cursor-native-replay-routing.ts +1 -1
  248. package/src/cursor-native-tool-display-registration.ts +10 -11
  249. package/src/cursor-partial-content-emitter.ts +1 -1
  250. package/src/cursor-pi-tool-bridge-mcp.ts +1 -1
  251. package/src/cursor-pi-tool-bridge-run.ts +1 -1
  252. package/src/cursor-pi-tool-bridge-types.ts +1 -1
  253. package/src/cursor-provider-errors.ts +1 -1
  254. package/src/cursor-provider-lazy.ts +6 -5
  255. package/src/cursor-provider-live-run-drain.ts +2 -1
  256. package/src/cursor-provider-overflow.ts +1 -1
  257. package/src/cursor-provider-run-finalizer.ts +2 -1
  258. package/src/cursor-provider-turn-coordinator.ts +1 -1
  259. package/src/cursor-provider-turn-finalize.ts +12 -0
  260. package/src/cursor-provider-turn-lifecycle-emitter.ts +1 -1
  261. package/src/cursor-provider-turn-prepare.ts +1 -1
  262. package/src/cursor-provider-turn-types.ts +3 -1
  263. package/src/cursor-provider.ts +1 -1
  264. package/src/cursor-run-final-text.ts +1 -1
  265. package/src/cursor-sdk-billed-usage.ts +107 -0
  266. package/src/cursor-sdk-event-debug.ts +1 -1
  267. package/src/cursor-sdk-process-error-guard.ts +6 -4
  268. package/src/cursor-session-agent-lifecycle.ts +8 -9
  269. package/src/cursor-session-agent-resume.ts +23 -0
  270. package/src/cursor-session-agent.ts +1 -1
  271. package/src/cursor-session-compaction-prep.ts +4 -0
  272. package/src/cursor-session-send-policy.ts +1 -1
  273. package/src/cursor-tool-manifest.ts +1 -1
  274. package/src/cursor-usage-accounting.ts +71 -10
  275. package/src/index.ts +1 -1
  276. package/src/model-discovery.ts +32 -89
  277. package/tsconfig.build.json +8 -0
  278. package/tsconfig.json +16 -0
  279. package/node_modules/cross-spawn/node_modules/which/CHANGELOG.md +0 -166
@@ -0,0 +1,107 @@
1
+ import { createHash } from "node:crypto";
2
+ import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
+ import { basename, join, resolve } from "node:path";
4
+ import { CURSOR_SDK_EVENT_DEBUG_RUN_DIR_ENV, CURSOR_SDK_EVENT_DEBUG_SESSION_DIR_ENV, SESSION_MANIFEST, resolveCursorSdkEventDebugBaseDir, } from "./cursor-sdk-event-debug-constants.js";
5
+ import { getCursorSessionFile, getCursorSessionScopeKey } from "./cursor-session-scope.js";
6
+ const ANONYMOUS_SESSION_SCOPE_KEY = "__anonymous__";
7
+ const sessionDebugStates = new Map();
8
+ function sanitizePathSegment(value) {
9
+ return value.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "session";
10
+ }
11
+ export function slugSessionKey(scopeKey) {
12
+ if (scopeKey === ANONYMOUS_SESSION_SCOPE_KEY) {
13
+ return `anonymous-${process.pid}`;
14
+ }
15
+ const fileBase = sanitizePathSegment(basename(scopeKey).replace(/\.jsonl?$/i, "") || "session");
16
+ const hash = createHash("sha256").update(scopeKey).digest("hex").slice(0, 8);
17
+ return `${fileBase}-${hash}`;
18
+ }
19
+ function resolvePinnedRunArtifactDir(runDirOverride) {
20
+ const trimmed = runDirOverride?.trim();
21
+ if (!trimmed)
22
+ return undefined;
23
+ const dir = resolve(trimmed);
24
+ mkdirSync(dir, { recursive: true });
25
+ return dir;
26
+ }
27
+ function readSessionManifest(sessionDir) {
28
+ try {
29
+ return JSON.parse(readFileSync(join(sessionDir, SESSION_MANIFEST), "utf8"));
30
+ }
31
+ catch {
32
+ return undefined;
33
+ }
34
+ }
35
+ function writeSessionManifest(sessionDir, manifest) {
36
+ writeFileSync(join(sessionDir, SESSION_MANIFEST), `${JSON.stringify(manifest, null, 2)}\n`);
37
+ }
38
+ function maxTurnFromManifest(manifest) {
39
+ if (!manifest || manifest.turns.length === 0)
40
+ return 0;
41
+ return manifest.turns.reduce((max, entry) => Math.max(max, entry.turn), 0);
42
+ }
43
+ function resolveSessionDebugDir(cwd, env, scopeKey) {
44
+ const pinned = env[CURSOR_SDK_EVENT_DEBUG_SESSION_DIR_ENV]?.trim();
45
+ if (pinned)
46
+ return resolve(pinned);
47
+ return join(resolveCursorSdkEventDebugBaseDir(cwd, env), "sessions", slugSessionKey(scopeKey));
48
+ }
49
+ export function allocateCursorSdkEventDebugTurn(cwd, env) {
50
+ const pinnedRunDir = resolvePinnedRunArtifactDir(env[CURSOR_SDK_EVENT_DEBUG_RUN_DIR_ENV]);
51
+ if (pinnedRunDir) {
52
+ return { artifactDir: pinnedRunDir, pinnedRun: true };
53
+ }
54
+ const scopeKey = getCursorSessionScopeKey();
55
+ const sessionDir = resolveSessionDebugDir(cwd, env, scopeKey);
56
+ mkdirSync(sessionDir, { recursive: true });
57
+ let state = sessionDebugStates.get(scopeKey);
58
+ if (!state || state.sessionDir !== sessionDir) {
59
+ const existing = readSessionManifest(sessionDir);
60
+ state = { sessionKey: scopeKey, sessionDir, turnCounter: maxTurnFromManifest(existing) };
61
+ sessionDebugStates.set(scopeKey, state);
62
+ }
63
+ state.turnCounter += 1;
64
+ const stamp = new Date().toISOString().replace(/[:.]/g, "-");
65
+ const artifactDir = join(sessionDir, `turn-${String(state.turnCounter).padStart(3, "0")}-${stamp}`);
66
+ mkdirSync(artifactDir, { recursive: true });
67
+ const existing = readSessionManifest(sessionDir);
68
+ const manifest = existing ?? {
69
+ sessionKey: scopeKey,
70
+ sessionFile: getCursorSessionFile(),
71
+ sessionDir,
72
+ createdAt: new Date().toISOString(),
73
+ updatedAt: new Date().toISOString(),
74
+ turns: [],
75
+ };
76
+ manifest.sessionFile = getCursorSessionFile();
77
+ manifest.updatedAt = new Date().toISOString();
78
+ manifest.turns.push({
79
+ turn: state.turnCounter,
80
+ artifactDir,
81
+ startedAt: new Date().toISOString(),
82
+ });
83
+ writeSessionManifest(sessionDir, manifest);
84
+ return {
85
+ artifactDir,
86
+ sessionDir,
87
+ turn: state.turnCounter,
88
+ sessionKey: scopeKey,
89
+ pinnedRun: false,
90
+ };
91
+ }
92
+ export function updateCursorSdkEventDebugSessionManifest(sessionDir, artifactDir, summary) {
93
+ const manifest = readSessionManifest(sessionDir);
94
+ if (!manifest)
95
+ return;
96
+ const turnEntry = manifest.turns.find((entry) => entry.artifactDir === artifactDir);
97
+ if (!turnEntry)
98
+ return;
99
+ turnEntry.finalizedAt = new Date().toISOString();
100
+ turnEntry.summary = summary;
101
+ manifest.updatedAt = new Date().toISOString();
102
+ manifest.sessionFile = getCursorSessionFile();
103
+ writeSessionManifest(sessionDir, manifest);
104
+ }
105
+ export function resetCursorSdkEventDebugSessionStateForTests() {
106
+ sessionDebugStates.clear();
107
+ }
@@ -0,0 +1,461 @@
1
+ import { createHash } from "node:crypto";
2
+ import { copyFileSync, existsSync, unlinkSync, writeFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { serializeCursorPiToolBridgeDiagnostic } from "./cursor-pi-tool-bridge-diagnostics.js";
5
+ import { asRecord } from "./cursor-record-utils.js";
6
+ import { getCursorSessionFile } from "./cursor-session-scope.js";
7
+ import { parseEnvBoolean } from "./cursor-env-boolean.js";
8
+ import { ARTIFACTS, CURSOR_SDK_EVENT_DEBUG_ENV, CURSOR_SDK_EVENT_DEBUG_LOG_PREFIX, CURSOR_SDK_EVENT_DEBUG_STDERR_ENV, SESSION_MANIFEST, SESSION_PI_SESSION_SNAPSHOT, } from "./cursor-sdk-event-debug-constants.js";
9
+ import { allocateCursorSdkEventDebugTurn, resetCursorSdkEventDebugSessionStateForTests, slugSessionKey, updateCursorSdkEventDebugSessionManifest, } from "./cursor-sdk-event-debug-session.js";
10
+ export { CURSOR_SDK_EVENT_DEBUG_DIR_ENV, CURSOR_SDK_EVENT_DEBUG_ENV, CURSOR_SDK_EVENT_DEBUG_LOG_PREFIX, CURSOR_SDK_EVENT_DEBUG_RUN_DIR_ENV, CURSOR_SDK_EVENT_DEBUG_SESSION_DIR_ENV, CURSOR_SDK_EVENT_DEBUG_STDERR_ENV, resolveCursorSdkEventDebugBaseDir, } from "./cursor-sdk-event-debug-constants.js";
11
+ const MAX_CURSOR_SDK_EVENT_DEBUG_JSONL_BYTES = 2 * 1024 * 1024;
12
+ function eventType(value) {
13
+ const record = asRecord(value);
14
+ if (typeof record?.type === "string")
15
+ return record.type;
16
+ if (typeof record?.event === "string")
17
+ return record.event;
18
+ if (typeof record?.kind === "string")
19
+ return record.kind;
20
+ return "unknown";
21
+ }
22
+ function resolveCursorSdkEventDebugStderrEnabled(env = process.env) {
23
+ return parseEnvBoolean(env[CURSOR_SDK_EVENT_DEBUG_STDERR_ENV], false);
24
+ }
25
+ function isNodeErrorWithCode(error, code) {
26
+ return asRecord(error)?.code === code;
27
+ }
28
+ function snapshotCursorSdkEventDebugRecord(record) {
29
+ try {
30
+ return structuredClone(record);
31
+ }
32
+ catch {
33
+ try {
34
+ return JSON.parse(JSON.stringify(record));
35
+ }
36
+ catch {
37
+ return record;
38
+ }
39
+ }
40
+ }
41
+ function serializeCursorSdkEventDebugRecord(record) {
42
+ try {
43
+ const seen = new WeakSet();
44
+ return JSON.stringify(snapshotCursorSdkEventDebugRecord(record), (_key, value) => {
45
+ if (typeof value === "bigint")
46
+ return value.toString();
47
+ if (value && typeof value === "object") {
48
+ if (seen.has(value))
49
+ return "[Circular]";
50
+ seen.add(value);
51
+ }
52
+ return value;
53
+ }) ?? JSON.stringify({ type: "artifact_serialization_error" });
54
+ }
55
+ catch {
56
+ return JSON.stringify({ type: "artifact_serialization_error" });
57
+ }
58
+ }
59
+ export function resolveCursorSdkEventDebugEnabled(env = process.env) {
60
+ return parseEnvBoolean(env[CURSOR_SDK_EVENT_DEBUG_ENV], false);
61
+ }
62
+ export const DISCARDED_INCOMPLETE_TOOL_CALL_REASON = "no-completion-at-run-end";
63
+ export function hashCursorSdkCallId(callId) {
64
+ return createHash("sha256").update(callId).digest("hex").slice(0, 8);
65
+ }
66
+ export function serializeDiscardedIncompleteStartedToolCall(record) {
67
+ return {
68
+ event: "discarded-incomplete-started-tool-call",
69
+ toolName: record.toolName,
70
+ callIdHash: hashCursorSdkCallId(record.callId),
71
+ reason: record.reason ?? DISCARDED_INCOMPLETE_TOOL_CALL_REASON,
72
+ };
73
+ }
74
+ export function recordDiscardedIncompleteStartedToolCall(recorder, env, record) {
75
+ if (!recorder && !resolveCursorSdkEventDebugEnabled(env))
76
+ return;
77
+ try {
78
+ const payload = serializeDiscardedIncompleteStartedToolCall(record);
79
+ recorder?.recordCoordinatorEvent("discarded-incomplete-started-tool-call", payload);
80
+ if (resolveCursorSdkEventDebugStderrEnabled(env) && resolveCursorSdkEventDebugEnabled(env)) {
81
+ process.stderr.write(`${CURSOR_SDK_EVENT_DEBUG_LOG_PREFIX} ${JSON.stringify(payload)}\n`);
82
+ }
83
+ }
84
+ catch {
85
+ // Debug logging must never affect provider execution.
86
+ }
87
+ }
88
+ export function attachCursorSdkEventDebugPiStreamTap(stream, sinkRef) {
89
+ if (!resolveCursorSdkEventDebugEnabled())
90
+ return;
91
+ const originalPush = stream.push.bind(stream);
92
+ stream.push = (event) => {
93
+ try {
94
+ sinkRef.current?.recordPiStreamEvent(event);
95
+ }
96
+ catch {
97
+ // Debug capture must never block the underlying stream.
98
+ }
99
+ return originalPush(event);
100
+ };
101
+ }
102
+ export class CursorSdkEventDebugSink {
103
+ artifactDir;
104
+ sessionDir;
105
+ turn;
106
+ sessionKey;
107
+ pinnedRun;
108
+ env;
109
+ startedAt = Date.now();
110
+ counts = {
111
+ onDelta: {},
112
+ onStep: {},
113
+ stream: {},
114
+ piStream: {},
115
+ provider: {},
116
+ liveRun: {},
117
+ bridge: {},
118
+ bridgeRaw: {},
119
+ displayDecisions: {},
120
+ coordinator: {},
121
+ drain: {},
122
+ timeline: {},
123
+ errors: 0,
124
+ };
125
+ metadata;
126
+ jsonlBuffers = new Map();
127
+ jsonlBufferBytes = new Map();
128
+ truncatedJsonlFiles = new Set();
129
+ finalized = false;
130
+ finalizationPromise;
131
+ waitResultRecorded = false;
132
+ streamCapturePromise;
133
+ streamCaptureErrors = [];
134
+ static maybeCreate(options) {
135
+ const env = options.env ?? process.env;
136
+ if (!resolveCursorSdkEventDebugEnabled(env))
137
+ return undefined;
138
+ const allocation = allocateCursorSdkEventDebugTurn(options.cwd, env);
139
+ return new CursorSdkEventDebugSink(allocation, options, env);
140
+ }
141
+ constructor(allocation, options, env) {
142
+ this.artifactDir = allocation.artifactDir;
143
+ this.sessionDir = allocation.sessionDir;
144
+ this.turn = allocation.turn;
145
+ this.sessionKey = allocation.sessionKey;
146
+ this.pinnedRun = allocation.pinnedRun;
147
+ this.env = env;
148
+ this.metadata = {
149
+ capturedAt: new Date().toISOString(),
150
+ modelId: options.modelId,
151
+ provider: options.provider,
152
+ cwd: options.cwd,
153
+ sessionDir: allocation.sessionDir,
154
+ sessionKey: allocation.sessionKey,
155
+ sessionFile: getCursorSessionFile(),
156
+ turn: allocation.turn,
157
+ pinnedRun: allocation.pinnedRun,
158
+ artifacts: ARTIFACTS,
159
+ warnings: [
160
+ "Raw artifact files may contain local paths, project text, tool args/results, or secrets from the workspace. Do not commit or share them.",
161
+ ],
162
+ };
163
+ this.clearKnownArtifactFiles();
164
+ writeFileSync(join(this.artifactDir, ARTIFACTS.metadata), `${JSON.stringify(this.metadata, null, 2)}\n`);
165
+ }
166
+ recordProviderMeta(meta) {
167
+ this.metadata = {
168
+ ...this.metadata,
169
+ providerMeta: meta,
170
+ };
171
+ writeFileSync(join(this.artifactDir, ARTIFACTS.metadata), `${JSON.stringify(this.metadata, null, 2)}\n`);
172
+ }
173
+ recordSendMeta(meta) {
174
+ this.metadata = {
175
+ ...this.metadata,
176
+ send: meta,
177
+ };
178
+ writeFileSync(join(this.artifactDir, ARTIFACTS.metadata), `${JSON.stringify(this.metadata, null, 2)}\n`);
179
+ }
180
+ recordSendPayload(payload) {
181
+ writeFileSync(join(this.artifactDir, ARTIFACTS.sendPayload), `${JSON.stringify(payload, null, 2)}\n`);
182
+ }
183
+ recordContextSnapshot(context) {
184
+ writeFileSync(join(this.artifactDir, ARTIFACTS.contextSnapshot), `${JSON.stringify(context, null, 2)}\n`);
185
+ }
186
+ recordRunMeta(meta) {
187
+ this.metadata = {
188
+ ...this.metadata,
189
+ run: meta,
190
+ };
191
+ writeFileSync(join(this.artifactDir, ARTIFACTS.metadata), `${JSON.stringify(this.metadata, null, 2)}\n`);
192
+ }
193
+ recordOnDelta(update) {
194
+ this.appendJsonl(ARTIFACTS.onDelta, "update", update, this.counts.onDelta);
195
+ }
196
+ recordOnStep(step) {
197
+ this.appendJsonl(ARTIFACTS.onStep, "step", step, this.counts.onStep);
198
+ }
199
+ recordStreamEvent(event) {
200
+ this.appendJsonl(ARTIFACTS.streamEvents, "event", event, this.counts.stream);
201
+ }
202
+ recordPiStreamEvent(event) {
203
+ this.appendJsonl(ARTIFACTS.piStreamEvents, "event", event, this.counts.piStream);
204
+ }
205
+ recordProviderEvent(phase, payload) {
206
+ this.appendProviderJsonl(phase, payload);
207
+ }
208
+ recordLiveRunEvent(event) {
209
+ this.appendJsonl(ARTIFACTS.liveRunEvents, "event", event, this.counts.liveRun);
210
+ }
211
+ recordBridgeDiagnostic(event) {
212
+ const serialized = serializeCursorPiToolBridgeDiagnostic(event);
213
+ this.appendJsonl(ARTIFACTS.bridgeEvents, "event", serialized, this.counts.bridge, String(serialized.event));
214
+ }
215
+ recordBridgeRaw(payload) {
216
+ this.appendJsonl(ARTIFACTS.bridgeRaw, "bridgeRaw", payload, this.counts.bridgeRaw, payload.kind);
217
+ }
218
+ recordDisplayDecision(decision) {
219
+ this.appendJsonl(ARTIFACTS.displayDecisions, "decision", decision, this.counts.displayDecisions, decision.action);
220
+ }
221
+ recordCoordinatorEvent(phase, payload) {
222
+ this.appendCoordinatorJsonl(phase, payload);
223
+ }
224
+ recordDrainEvent(phase, payload) {
225
+ this.appendDrainJsonl(phase, payload);
226
+ }
227
+ recordFinalPartial(partial) {
228
+ writeFileSync(join(this.artifactDir, ARTIFACTS.finalPartial), `${JSON.stringify(partial, null, 2)}\n`);
229
+ this.recordTimeline("finalPartial", "snapshot", partial);
230
+ }
231
+ recordError(label, error) {
232
+ this.counts.errors += 1;
233
+ const payload = {
234
+ label,
235
+ message: error instanceof Error ? error.message : String(error),
236
+ stack: error instanceof Error ? error.stack : undefined,
237
+ value: error,
238
+ };
239
+ this.appendJsonl(ARTIFACTS.errors, "error", payload, { [label]: 1 }, label);
240
+ }
241
+ attachRunStream(run) {
242
+ const sdkRun = run;
243
+ if (typeof sdkRun.stream !== "function") {
244
+ this.recordProviderEvent("run_stream_unavailable", { runId: sdkRun.id, requestId: sdkRun.requestId });
245
+ return;
246
+ }
247
+ this.streamCapturePromise = (async () => {
248
+ try {
249
+ for await (const event of sdkRun.stream()) {
250
+ this.recordStreamEvent(event);
251
+ }
252
+ }
253
+ catch (error) {
254
+ this.streamCaptureErrors.push(error);
255
+ this.recordError("run_stream", error);
256
+ }
257
+ })();
258
+ }
259
+ async captureRunArtifacts(run) {
260
+ const sdkRun = run;
261
+ if (this.streamCapturePromise) {
262
+ await this.streamCapturePromise.catch(() => undefined);
263
+ }
264
+ if (typeof sdkRun.conversation === "function" && sdkRun.supports?.("conversation")) {
265
+ try {
266
+ const conversation = await sdkRun.conversation();
267
+ writeFileSync(join(this.artifactDir, ARTIFACTS.conversation), `${JSON.stringify(conversation, null, 2)}\n`);
268
+ this.recordProviderEvent("conversation_captured", { supported: true });
269
+ }
270
+ catch (error) {
271
+ this.recordError("conversation", error);
272
+ }
273
+ }
274
+ else {
275
+ writeFileSync(join(this.artifactDir, ARTIFACTS.conversation), `${JSON.stringify({
276
+ skipped: true,
277
+ reason: sdkRun.unsupportedReason?.("conversation") ?? "conversation unsupported",
278
+ }, null, 2)}\n`);
279
+ }
280
+ }
281
+ recordWaitResult(result) {
282
+ if (this.waitResultRecorded)
283
+ return;
284
+ this.waitResultRecorded = true;
285
+ writeFileSync(join(this.artifactDir, ARTIFACTS.waitResult), `${JSON.stringify(result, null, 2)}\n`);
286
+ }
287
+ capturePiSessionSnapshot() {
288
+ const sessionFile = getCursorSessionFile();
289
+ if (!sessionFile) {
290
+ return { copied: false, reason: "session file unknown" };
291
+ }
292
+ if (!existsSync(sessionFile)) {
293
+ return { copied: false, sessionFile, reason: "session file not found at debug finalization" };
294
+ }
295
+ try {
296
+ copyFileSync(sessionFile, join(this.artifactDir, ARTIFACTS.piSessionSnapshot));
297
+ if (this.sessionDir) {
298
+ copyFileSync(sessionFile, join(this.sessionDir, SESSION_PI_SESSION_SNAPSHOT));
299
+ }
300
+ this.recordTimeline("piSession", "snapshot", { sessionFile, artifact: ARTIFACTS.piSessionSnapshot });
301
+ return { copied: true, sessionFile };
302
+ }
303
+ catch (error) {
304
+ if (isNodeErrorWithCode(error, "ENOENT")) {
305
+ return { copied: false, sessionFile, reason: "session file not found at debug finalization" };
306
+ }
307
+ this.recordError("pi_session_snapshot", error);
308
+ return {
309
+ copied: false,
310
+ sessionFile,
311
+ reason: error instanceof Error ? error.message : String(error),
312
+ };
313
+ }
314
+ }
315
+ updateSessionManifest(summary) {
316
+ if (this.pinnedRun || !this.sessionDir || this.turn === undefined)
317
+ return;
318
+ updateCursorSdkEventDebugSessionManifest(this.sessionDir, this.artifactDir, summary);
319
+ }
320
+ clearKnownArtifactFiles() {
321
+ for (const fileName of Object.values(ARTIFACTS)) {
322
+ try {
323
+ unlinkSync(join(this.artifactDir, fileName));
324
+ }
325
+ catch {
326
+ // Ignore missing prior artifacts when reusing a pinned run directory.
327
+ }
328
+ }
329
+ }
330
+ async finalize() {
331
+ this.finalizationPromise ??= this.finalizeOnce();
332
+ await this.finalizationPromise;
333
+ }
334
+ async finalizeOnce() {
335
+ if (this.finalized)
336
+ return;
337
+ if (this.streamCapturePromise) {
338
+ await this.streamCapturePromise.catch(() => undefined);
339
+ }
340
+ const piSessionSnapshot = this.capturePiSessionSnapshot();
341
+ const summary = {
342
+ artifactDir: this.artifactDir,
343
+ sessionDir: this.sessionDir,
344
+ sessionKey: this.sessionKey,
345
+ sessionFile: getCursorSessionFile(),
346
+ turn: this.turn,
347
+ elapsedMs: Date.now() - this.startedAt,
348
+ counts: {
349
+ onDelta: { ...this.counts.onDelta },
350
+ onStep: { ...this.counts.onStep },
351
+ stream: { ...this.counts.stream },
352
+ piStream: { ...this.counts.piStream },
353
+ provider: { ...this.counts.provider },
354
+ liveRun: { ...this.counts.liveRun },
355
+ bridge: { ...this.counts.bridge },
356
+ bridgeRaw: { ...this.counts.bridgeRaw },
357
+ displayDecisions: { ...this.counts.displayDecisions },
358
+ coordinator: { ...this.counts.coordinator },
359
+ drain: { ...this.counts.drain },
360
+ timeline: { ...this.counts.timeline },
361
+ errors: this.counts.errors,
362
+ },
363
+ piSessionSnapshot,
364
+ artifacts: Object.fromEntries(Object.entries(ARTIFACTS).map(([key, name]) => [key, join(this.artifactDir, name)])),
365
+ waitResultRecorded: this.waitResultRecorded,
366
+ streamCaptureErrors: this.streamCaptureErrors.map((error) => error instanceof Error ? error.message : String(error)),
367
+ jsonlByteLimit: MAX_CURSOR_SDK_EVENT_DEBUG_JSONL_BYTES,
368
+ truncatedJsonlFiles: [...this.truncatedJsonlFiles].sort(),
369
+ };
370
+ this.flushJsonlBuffers();
371
+ writeFileSync(join(this.artifactDir, ARTIFACTS.summary), `${JSON.stringify(summary, null, 2)}\n`);
372
+ this.updateSessionManifest(summary);
373
+ if (resolveCursorSdkEventDebugStderrEnabled(this.env)) {
374
+ process.stderr.write(`${CURSOR_SDK_EVENT_DEBUG_LOG_PREFIX} ${JSON.stringify(summary)}\n`);
375
+ }
376
+ this.finalized = true;
377
+ }
378
+ appendProviderJsonl(phase, payload) {
379
+ const elapsedMs = Date.now() - this.startedAt;
380
+ const record = { ts: new Date().toISOString(), elapsedMs, turn: this.turn, phase, payload };
381
+ this.bufferJsonl(ARTIFACTS.providerEvents, record);
382
+ this.counts.provider[phase] = (this.counts.provider[phase] ?? 0) + 1;
383
+ this.recordTimeline("provider", phase, payload);
384
+ }
385
+ appendCoordinatorJsonl(phase, payload) {
386
+ const elapsedMs = Date.now() - this.startedAt;
387
+ const record = { ts: new Date().toISOString(), elapsedMs, turn: this.turn, phase, payload };
388
+ this.bufferJsonl(ARTIFACTS.coordinatorEvents, record);
389
+ this.counts.coordinator[phase] = (this.counts.coordinator[phase] ?? 0) + 1;
390
+ this.recordTimeline("coordinator", phase, payload);
391
+ }
392
+ appendDrainJsonl(phase, payload) {
393
+ const elapsedMs = Date.now() - this.startedAt;
394
+ const record = { ts: new Date().toISOString(), elapsedMs, turn: this.turn, phase, payload };
395
+ this.bufferJsonl(ARTIFACTS.drainEvents, record);
396
+ this.counts.drain[phase] = (this.counts.drain[phase] ?? 0) + 1;
397
+ this.recordTimeline("drain", phase, payload);
398
+ }
399
+ recordTimeline(layer, kind, payload) {
400
+ const elapsedMs = Date.now() - this.startedAt;
401
+ const record = {
402
+ ts: new Date().toISOString(),
403
+ elapsedMs,
404
+ turn: this.turn,
405
+ layer,
406
+ kind,
407
+ payload,
408
+ };
409
+ this.bufferJsonl(ARTIFACTS.timeline, record);
410
+ const timelineKey = `${layer}:${kind}`;
411
+ this.counts.timeline[timelineKey] = (this.counts.timeline[timelineKey] ?? 0) + 1;
412
+ }
413
+ appendJsonl(fileName, recordKey, value, counts, countKey) {
414
+ const elapsedMs = Date.now() - this.startedAt;
415
+ const record = {
416
+ ts: new Date().toISOString(),
417
+ elapsedMs,
418
+ turn: this.turn,
419
+ [recordKey]: value,
420
+ };
421
+ this.bufferJsonl(fileName, record);
422
+ const type = countKey ?? eventType(value);
423
+ counts[type] = (counts[type] ?? 0) + 1;
424
+ const layer = fileName.replace(/\.jsonl$/, "");
425
+ this.recordTimeline(layer, type, value);
426
+ }
427
+ bufferJsonl(fileName, record) {
428
+ if (this.finalized || this.truncatedJsonlFiles.has(fileName))
429
+ return;
430
+ const line = `${serializeCursorSdkEventDebugRecord(record)}\n`;
431
+ const marker = `${JSON.stringify({ type: "artifact_truncated", limitBytes: MAX_CURSOR_SDK_EVENT_DEBUG_JSONL_BYTES })}\n`;
432
+ const usedBytes = this.jsonlBufferBytes.get(fileName) ?? 0;
433
+ const lineBytes = Buffer.byteLength(line);
434
+ const markerBytes = Buffer.byteLength(marker);
435
+ const records = this.jsonlBuffers.get(fileName) ?? [];
436
+ if (usedBytes + lineBytes > MAX_CURSOR_SDK_EVENT_DEBUG_JSONL_BYTES - markerBytes) {
437
+ records.push(marker);
438
+ this.jsonlBuffers.set(fileName, records);
439
+ this.jsonlBufferBytes.set(fileName, usedBytes + markerBytes);
440
+ this.truncatedJsonlFiles.add(fileName);
441
+ return;
442
+ }
443
+ records.push(line);
444
+ this.jsonlBuffers.set(fileName, records);
445
+ this.jsonlBufferBytes.set(fileName, usedBytes + lineBytes);
446
+ }
447
+ flushJsonlBuffers() {
448
+ for (const [fileName, records] of this.jsonlBuffers) {
449
+ writeFileSync(join(this.artifactDir, fileName), records.join(""));
450
+ }
451
+ this.jsonlBuffers.clear();
452
+ this.jsonlBufferBytes.clear();
453
+ }
454
+ }
455
+ export const __testUtils = {
456
+ ARTIFACTS,
457
+ SESSION_MANIFEST,
458
+ MAX_CURSOR_SDK_EVENT_DEBUG_JSONL_BYTES,
459
+ slugSessionKey,
460
+ resetSessionDebugState: resetCursorSdkEventDebugSessionStateForTests,
461
+ };
@@ -0,0 +1 @@
1
+ export { CURSOR_SDK_STARTUP_NOISE_PATTERNS, installCursorSdkOutputFilter, isCursorSdkOutputSuppressed, isCursorSdkStartupNoise, suppressCursorSdkOutput, } from "../shared/cursor-sdk-output-filter.mjs";