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,221 @@
1
+ import { classifyCursorConnectError, isCursorSdkAbortConnectError, isCursorSdkConnectionStalledError } from "./cursor-provider-errors.js";
2
+ // Cursor SDK controlled-exec tasks can reject after their originating provider turn
3
+ // has ended. The exact closed-writable failure is therefore session-scoped; existing
4
+ // ConnectRPC suppression remains scoped to active provider turns.
5
+ const activeProviderTurns = new Set();
6
+ const activeSessions = new Set();
7
+ let activeLifecycleSessionGuard;
8
+ let originalProcessEmit;
9
+ let cursorProcessEmit;
10
+ let bunUnhandledRejectionListenerInstalled = false;
11
+ function hasActiveGuard() {
12
+ return activeProviderTurns.size > 0 || activeSessions.size > 0;
13
+ }
14
+ function hasActiveAbortSuppression() {
15
+ for (const turn of activeProviderTurns) {
16
+ if (turn.suppressAbortErrors)
17
+ return true;
18
+ }
19
+ return false;
20
+ }
21
+ function isCursorProvenance(source) {
22
+ return source === "cursor-sdk-stack" || source === "cursor-extension-connect-stack" || source === "cursor-backend-details";
23
+ }
24
+ function isCursorSdkWriteIterableClosedError(error) {
25
+ return (error instanceof Error &&
26
+ error.name === "WriteIterableClosedError" &&
27
+ error.message === "WritableIterable is closed" &&
28
+ /(?:^|[\\/])node_modules[\\/]@cursor[\\/]sdk[\\/]dist[\\/]/.test(error.stack ?? ""));
29
+ }
30
+ // The Cursor SDK aborts an in-flight controlled-exec turn via its internal
31
+ // `AbortController.abort()` (user interrupt or stall-detector cancellation),
32
+ // which surfaces as a raw `DOMException [AbortError]` rather than a
33
+ // `ConnectError`. `classifyCursorConnectError` returns undefined for it, so it
34
+ // otherwise falls through the emit patch and terminates the process. A
35
+ // DOMException is not `instanceof Error`, so match structurally on the
36
+ // `AbortError` name plus the same `@cursor/sdk/dist` stack provenance the
37
+ // WriteIterableClosedError recognizer uses, keeping unrelated AbortErrors fatal.
38
+ function isCursorSdkAbortError(error) {
39
+ if (typeof error !== "object" || error === null)
40
+ return false;
41
+ const { name, stack } = error;
42
+ return (name === "AbortError" &&
43
+ typeof stack === "string" &&
44
+ /(?:^|[\\/])node_modules[\\/]@cursor[\\/]sdk[\\/]dist[\\/]/.test(stack));
45
+ }
46
+ // The exact observed incident: the Cursor SDK 1.0.23 local shell executor writes a
47
+ // spawned child's stdin without a stream 'error' listener, so a child exiting while
48
+ // a write is in flight surfaces a raw `write EPIPE` uncaught exception whose stack
49
+ // is exactly the single async pipe-write completion frame. Installed 1.0.27 attaches
50
+ // a no-op `error` listener before that write; keep this guard as defense in depth.
51
+ // Pi's own piped-stdout or dead-terminal EPIPE normally surfaces through the
52
+ // synchronous write-dispatch path with multiple frames (afterWriteDispatched /
53
+ // Socket._writeGeneric) and must stay fatal per Unix convention, so anything beyond
54
+ // this one-frame contract is rejected.
55
+ const OBSERVED_CLOSED_PIPE_STACK_FRAME = /^\s+at WriteWrap\.onWriteComplete \[as oncomplete\] \(node:internal\/stream_base_commons:\d+:\d+\)$/;
56
+ function isObservedLocalTransportClosedPipeWriteError(error) {
57
+ if (!(error instanceof Error) || error.name !== "Error")
58
+ return false;
59
+ const { code, syscall } = error;
60
+ if (code !== "EPIPE" || syscall !== "write" || !error.message.startsWith("write EPIPE"))
61
+ return false;
62
+ const frames = (error.stack ?? "").split("\n").filter((line) => /^\s+at /.test(line));
63
+ return frames.length === 1 && OBSERVED_CLOSED_PIPE_STACK_FRAME.test(frames[0] ?? "");
64
+ }
65
+ // Contained only while a provider turn that declared a local transport is active;
66
+ // each contained turn invalidates its own session-agent scope for recreation.
67
+ function containLocalTransportClosedPipeError() {
68
+ let contained = false;
69
+ for (const turn of [...activeProviderTurns]) {
70
+ if (!turn.onLocalTransportClosedPipe)
71
+ continue;
72
+ contained = true;
73
+ try {
74
+ turn.onLocalTransportClosedPipe();
75
+ }
76
+ catch {
77
+ // stale-agent invalidation must not throw inside process error handling
78
+ }
79
+ }
80
+ return contained;
81
+ }
82
+ function shouldSuppressProcessError(event, args) {
83
+ if (event !== "uncaughtException" && event !== "unhandledRejection")
84
+ return false;
85
+ const error = args[0];
86
+ if (isObservedLocalTransportClosedPipeWriteError(error)) {
87
+ return containLocalTransportClosedPipeError();
88
+ }
89
+ if (isCursorSdkWriteIterableClosedError(error))
90
+ return activeSessions.size > 0;
91
+ // SDK stall timers and inter-turn teardown aborts never call suppressAbortErrors();
92
+ // any active provider turn or session is enough — stack provenance already gates SDK-only AbortErrors.
93
+ if (isCursorSdkAbortError(error))
94
+ return hasActiveGuard();
95
+ // RetriableError "Connection stalled" / "Connection stalled repeatedly" is not a ConnectError; suppress during active turns only.
96
+ if (isCursorSdkConnectionStalledError(error))
97
+ return activeProviderTurns.size > 0;
98
+ const classification = classifyCursorConnectError(error);
99
+ if (!classification)
100
+ return false;
101
+ if (classification.kind === "abort")
102
+ return hasActiveAbortSuppression();
103
+ if (activeProviderTurns.size === 0)
104
+ return false;
105
+ if (classification.kind === "network")
106
+ return isCursorProvenance(classification.source) || classification.source === "connect-node-stack";
107
+ return isCursorProvenance(classification.source);
108
+ }
109
+ function installProcessEmitPatch() {
110
+ if (cursorProcessEmit) {
111
+ if (process.emit === cursorProcessEmit)
112
+ return;
113
+ if (process.emit !== originalProcessEmit)
114
+ return;
115
+ cursorProcessEmit = undefined;
116
+ originalProcessEmit = undefined;
117
+ }
118
+ const forwardEmit = process.emit;
119
+ originalProcessEmit = forwardEmit;
120
+ cursorProcessEmit = function patchedCursorSdkProcessErrorEmit(event, ...args) {
121
+ if (shouldSuppressProcessError(event, args))
122
+ return true;
123
+ return forwardEmit.call(this, event, ...args);
124
+ };
125
+ process.emit = cursorProcessEmit;
126
+ }
127
+ function isBunRuntime() {
128
+ return typeof process.versions.bun === "string";
129
+ }
130
+ function handleBunUnhandledRejection(error) {
131
+ if (shouldSuppressProcessError("unhandledRejection", [error]))
132
+ return;
133
+ // Without another rejection listener, retain Bun's default fatal behavior.
134
+ if (process.listenerCount("unhandledRejection") === 1)
135
+ throw error;
136
+ }
137
+ function installBunUnhandledRejectionListener() {
138
+ if (!isBunRuntime() || bunUnhandledRejectionListenerInstalled)
139
+ return;
140
+ process.prependListener("unhandledRejection", handleBunUnhandledRejection);
141
+ bunUnhandledRejectionListenerInstalled = true;
142
+ }
143
+ function uninstallBunUnhandledRejectionListenerIfIdle() {
144
+ if (hasActiveGuard() || !bunUnhandledRejectionListenerInstalled)
145
+ return;
146
+ process.off("unhandledRejection", handleBunUnhandledRejection);
147
+ bunUnhandledRejectionListenerInstalled = false;
148
+ }
149
+ function uninstallProcessHooksIfIdle() {
150
+ if (hasActiveGuard())
151
+ return;
152
+ uninstallBunUnhandledRejectionListenerIfIdle();
153
+ if (!originalProcessEmit || !cursorProcessEmit || process.emit !== cursorProcessEmit)
154
+ return;
155
+ process.emit = originalProcessEmit;
156
+ originalProcessEmit = undefined;
157
+ cursorProcessEmit = undefined;
158
+ }
159
+ function installProcessHooks() {
160
+ installProcessEmitPatch();
161
+ installBunUnhandledRejectionListener();
162
+ }
163
+ export const __testUtils = {
164
+ activeProviderTurnCount: () => activeProviderTurns.size,
165
+ activeSessionCount: () => activeSessions.size,
166
+ resetLifecycleSessionGuard() {
167
+ activeLifecycleSessionGuard?.dispose();
168
+ activeLifecycleSessionGuard = undefined;
169
+ },
170
+ };
171
+ export { isCursorSdkAbortConnectError };
172
+ export function installCursorSdkProcessErrorGuard() {
173
+ const token = { suppressAbortErrors: false };
174
+ activeProviderTurns.add(token);
175
+ installProcessHooks();
176
+ let disposed = false;
177
+ return {
178
+ suppressAbortErrors() {
179
+ if (disposed)
180
+ return;
181
+ token.suppressAbortErrors = true;
182
+ },
183
+ containLocalTransportClosedPipe(onClosedPipe) {
184
+ if (disposed)
185
+ return;
186
+ token.onLocalTransportClosedPipe = onClosedPipe;
187
+ },
188
+ dispose() {
189
+ if (disposed)
190
+ return;
191
+ disposed = true;
192
+ activeProviderTurns.delete(token);
193
+ uninstallProcessHooksIfIdle();
194
+ },
195
+ };
196
+ }
197
+ export function installCursorSdkSessionProcessErrorGuard() {
198
+ const token = {};
199
+ activeSessions.add(token);
200
+ installProcessHooks();
201
+ let disposed = false;
202
+ return {
203
+ dispose() {
204
+ if (disposed)
205
+ return;
206
+ disposed = true;
207
+ activeSessions.delete(token);
208
+ uninstallProcessHooksIfIdle();
209
+ },
210
+ };
211
+ }
212
+ export function registerCursorSdkSessionProcessErrorGuard(pi) {
213
+ pi.on("session_start", () => {
214
+ activeLifecycleSessionGuard?.dispose();
215
+ activeLifecycleSessionGuard = installCursorSdkSessionProcessErrorGuard();
216
+ });
217
+ pi.on("session_shutdown", () => {
218
+ activeLifecycleSessionGuard?.dispose();
219
+ activeLifecycleSessionGuard = undefined;
220
+ });
221
+ }
@@ -0,0 +1,3 @@
1
+ export async function loadCursorSdk() {
2
+ return import("@cursor/sdk");
3
+ }
@@ -0,0 +1,23 @@
1
+ import { asRecord } from "./cursor-record-utils.js";
2
+ /** Provider-facing wrapper; canonical scrubbing lives in shared/cursor-sensitive-text.mjs. */
3
+ import { scrubSensitiveText as scrubSensitiveTextJs } from "../shared/cursor-sensitive-text.mjs";
4
+ export function scrubSensitiveText(text, apiKey) {
5
+ return scrubSensitiveTextJs(text, apiKey);
6
+ }
7
+ function scrubDisplayValue(value, apiKey) {
8
+ if (typeof value === "string")
9
+ return scrubSensitiveText(value, apiKey);
10
+ if (Array.isArray(value))
11
+ return value.map((entry) => scrubDisplayValue(entry, apiKey));
12
+ const record = asRecord(value);
13
+ if (!record)
14
+ return value;
15
+ return Object.fromEntries(Object.entries(record).map(([key, entry]) => [key, scrubDisplayValue(entry, apiKey)]));
16
+ }
17
+ export function scrubPiToolDisplay(display, apiKey) {
18
+ return {
19
+ ...display,
20
+ args: scrubDisplayValue(display.args, apiKey),
21
+ result: scrubDisplayValue(display.result, apiKey),
22
+ };
23
+ }
@@ -0,0 +1,311 @@
1
+ import { asRecord, getString } from "./cursor-record-utils.js";
2
+ import { fsyncExistingRegularFile } from "./cursor-durable-fs.js";
3
+ import { scrubSensitiveText } from "./cursor-sensitive-text.js";
4
+ import { loadCursorSdk } from "./cursor-sdk-runtime.js";
5
+ import { getCursorSessionScopeKey } from "./cursor-session-scope.js";
6
+ import { CURSOR_SESSION_AGENT_RESUME_ENTRY_TYPE, isCursorLocalAgentId, parseCursorSessionAgentResumeEntryData, readResumableCursorSessionAgentIds, resolveCursorSessionRepoRoot, } from "./cursor-session-agent-resume.js";
7
+ import { cursorSessionStoreIdentitiesEqual, getCursorSessionStoreIdentities, openCursorSessionStore, } from "./cursor-session-store.js";
8
+ export const CURSOR_SESSION_AGENT_CLEANUP_ENTRY_TYPE = "cursor-sdk-agent-cleanup";
9
+ class InvalidCursorSessionStoreIdentityError extends Error {
10
+ }
11
+ // ponytail: grows for the process lifetime, but its ceiling is the exact agent IDs this process
12
+ // attempted to delete (never global) — it only fills the gap until this process exits; the durable
13
+ // intent entry, not this Set, is the authority a restarted process relies on to block retries.
14
+ // Tests must call __testUtils.reset() between cases.
15
+ const nondurableCleanupResultAgentIds = new Set();
16
+ let appendDurabilityForTests;
17
+ let sdkOperationsForTests;
18
+ function uniqueSorted(values) {
19
+ return [...new Set(values)].sort((a, b) => a.localeCompare(b));
20
+ }
21
+ function readResumeEntries(entries) {
22
+ const records = [];
23
+ for (const entry of entries) {
24
+ if (entry.type !== "custom" || entry.customType !== CURSOR_SESSION_AGENT_RESUME_ENTRY_TYPE)
25
+ continue;
26
+ const data = parseCursorSessionAgentResumeEntryData(entry.data);
27
+ if (data)
28
+ records.push(data);
29
+ }
30
+ return records;
31
+ }
32
+ function resumeEntryMatchesCleanupScope(data, scope) {
33
+ return data.scopeKey === scope.scopeKey &&
34
+ data.sessionFile === scope.sessionFile &&
35
+ data.sessionId === scope.sessionId &&
36
+ data.cwd === scope.cwd &&
37
+ data.repoRoot === scope.repoRoot;
38
+ }
39
+ function getCurrentCleanupScope(ctx) {
40
+ const sessionFile = ctx.sessionManager.getSessionFile();
41
+ const sessionId = ctx.sessionManager.getSessionId();
42
+ const repoRoot = resolveCursorSessionRepoRoot(ctx.cwd);
43
+ return {
44
+ scopeKey: getCursorSessionScopeKey(),
45
+ ...(sessionFile ? { sessionFile } : {}),
46
+ ...(sessionId ? { sessionId } : {}),
47
+ cwd: ctx.cwd,
48
+ ...(repoRoot ? { repoRoot } : {}),
49
+ };
50
+ }
51
+ function parseCleanupEntryData(value) {
52
+ const record = asRecord(value);
53
+ if (!record || (record.action !== "dry-run" && record.action !== "delete") || record.runtime !== "local")
54
+ return undefined;
55
+ if (typeof record.timestamp !== "string")
56
+ return undefined;
57
+ if (record.phase !== undefined && record.phase !== "intent" && record.phase !== "result")
58
+ return undefined;
59
+ if (record.action === "dry-run" && record.phase !== undefined)
60
+ return undefined;
61
+ const candidateAgentIds = Array.isArray(record.candidateAgentIds) ? record.candidateAgentIds.filter((id) => typeof id === "string") : [];
62
+ const protectedAgentIds = Array.isArray(record.protectedAgentIds) ? record.protectedAgentIds.filter((id) => typeof id === "string") : undefined;
63
+ const deletedAgentIds = Array.isArray(record.deletedAgentIds) ? record.deletedAgentIds.filter((id) => typeof id === "string") : undefined;
64
+ const failedAgentIds = Array.isArray(record.failedAgentIds)
65
+ ? record.failedAgentIds.flatMap((item) => {
66
+ const failure = asRecord(item);
67
+ return isCursorLocalAgentId(failure?.agentId) && typeof failure.error === "string"
68
+ ? [{ agentId: failure.agentId, error: failure.error, ...(failure.retryable === false ? { retryable: false } : {}) }]
69
+ : [];
70
+ })
71
+ : undefined;
72
+ return {
73
+ action: record.action,
74
+ ...(record.phase ? { phase: record.phase } : {}),
75
+ runtime: "local",
76
+ timestamp: record.timestamp,
77
+ candidateAgentIds: uniqueSorted(candidateAgentIds.filter(isCursorLocalAgentId)),
78
+ ...(protectedAgentIds?.length ? { protectedAgentIds: uniqueSorted(protectedAgentIds.filter(isCursorLocalAgentId)) } : {}),
79
+ ...(deletedAgentIds?.length ? { deletedAgentIds: uniqueSorted(deletedAgentIds.filter(isCursorLocalAgentId)) } : {}),
80
+ ...(failedAgentIds?.length ? { failedAgentIds } : {}),
81
+ };
82
+ }
83
+ function readUnavailableAgentIds(entries) {
84
+ const deleted = new Set();
85
+ const pending = new Set();
86
+ const permanentlyFailed = new Set();
87
+ for (const entry of entries) {
88
+ if (entry.type !== "custom" || entry.customType !== CURSOR_SESSION_AGENT_CLEANUP_ENTRY_TYPE)
89
+ continue;
90
+ const data = parseCleanupEntryData(entry.data);
91
+ if (data?.action !== "delete")
92
+ continue;
93
+ if (data.phase === "intent") {
94
+ for (const agentId of data.candidateAgentIds) {
95
+ if (!deleted.has(agentId))
96
+ pending.add(agentId);
97
+ }
98
+ continue;
99
+ }
100
+ for (const agentId of data.deletedAgentIds ?? []) {
101
+ deleted.add(agentId);
102
+ pending.delete(agentId);
103
+ }
104
+ if (data.phase === "result") {
105
+ for (const failure of data.failedAgentIds ?? []) {
106
+ pending.delete(failure.agentId);
107
+ if (failure.retryable === false)
108
+ permanentlyFailed.add(failure.agentId);
109
+ }
110
+ }
111
+ }
112
+ return new Set([...deleted, ...pending, ...permanentlyFailed, ...nondurableCleanupResultAgentIds]);
113
+ }
114
+ function readLatestBranchAgentId(branch, scope) {
115
+ return readResumeEntries(branch).filter((entry) => resumeEntryMatchesCleanupScope(entry, scope)).at(-1)?.agentId;
116
+ }
117
+ function readCursorSessionAgentCleanupPlanDetails(entries, branch, scope) {
118
+ const unavailable = readUnavailableAgentIds(entries);
119
+ const latestBranchAgentId = readLatestBranchAgentId(branch, scope);
120
+ const protectedAgentIds = new Set(readResumableCursorSessionAgentIds(entries, scope));
121
+ if (latestBranchAgentId && isCursorLocalAgentId(latestBranchAgentId))
122
+ protectedAgentIds.add(latestBranchAgentId);
123
+ const candidates = new Map();
124
+ for (const resume of readResumeEntries(entries)) {
125
+ if (!resumeEntryMatchesCleanupScope(resume, scope))
126
+ continue;
127
+ const recordedCandidates = [
128
+ ...(resume.cleanupCandidateAgentIds ?? []).map((agentId) => ({ agentId })),
129
+ ...(resume.cleanupCandidates ?? []),
130
+ ];
131
+ for (const candidate of recordedCandidates) {
132
+ if (!isCursorLocalAgentId(candidate.agentId) || protectedAgentIds.has(candidate.agentId) || unavailable.has(candidate.agentId))
133
+ continue;
134
+ const existing = candidates.get(candidate.agentId);
135
+ if (!existing?.storeIdentity || candidate.storeIdentity)
136
+ candidates.set(candidate.agentId, candidate);
137
+ }
138
+ }
139
+ return {
140
+ candidates: [...candidates.values()].sort((left, right) => left.agentId.localeCompare(right.agentId)),
141
+ candidateAgentIds: uniqueSorted([...candidates.values()].map((candidate) => candidate.agentId)),
142
+ protectedAgentIds: uniqueSorted(protectedAgentIds),
143
+ };
144
+ }
145
+ export function readCursorSessionAgentCleanupPlan(entries, branch, scope) {
146
+ const { candidates: _, ...plan } = readCursorSessionAgentCleanupPlanDetails(entries, branch, scope);
147
+ return plan;
148
+ }
149
+ function formatCleanupPlan(plan) {
150
+ if (plan.candidateAgentIds.length === 0)
151
+ return "No recorded superseded local Cursor SDK agents are cleanup-eligible.";
152
+ return [
153
+ "Recorded superseded local Cursor SDK agents eligible for cleanup:",
154
+ ...plan.candidateAgentIds.map((agentId) => `- ${agentId}`),
155
+ "Run /cursor-local-resume-cleanup --yes to delete exactly these recorded agent IDs.",
156
+ ].join("\n");
157
+ }
158
+ async function getSdkOperations() {
159
+ if (sdkOperationsForTests)
160
+ return sdkOperationsForTests;
161
+ const { Agent } = await loadCursorSdk();
162
+ return {
163
+ delete: (agentId, options) => Agent.delete(agentId, options),
164
+ };
165
+ }
166
+ function cleanupEntryVerificationKey(data) {
167
+ return JSON.stringify({
168
+ action: data.action,
169
+ phase: data.phase,
170
+ runtime: data.runtime,
171
+ timestamp: data.timestamp,
172
+ candidateAgentIds: data.candidateAgentIds,
173
+ protectedAgentIds: data.protectedAgentIds ?? [],
174
+ deletedAgentIds: data.deletedAgentIds ?? [],
175
+ failedAgentIds: data.failedAgentIds ?? [],
176
+ });
177
+ }
178
+ function cleanupEntriesMatch(left, right) {
179
+ return cleanupEntryVerificationKey(left) === cleanupEntryVerificationKey(right);
180
+ }
181
+ function appendCleanupEntry(pi, data) {
182
+ pi.appendEntry(CURSOR_SESSION_AGENT_CLEANUP_ENTRY_TYPE, data);
183
+ }
184
+ function appendDurableCleanupEntry(pi, ctx, data) {
185
+ const sessionFile = ctx.sessionManager.getSessionFile();
186
+ const previousEntryId = ctx.sessionManager.getBranch().at(-1)?.id;
187
+ try {
188
+ appendCleanupEntry(pi, data);
189
+ }
190
+ catch {
191
+ return false;
192
+ }
193
+ if (appendDurabilityForTests)
194
+ return appendDurabilityForTests(data);
195
+ const anchor = ctx.sessionManager.getBranch().at(-1);
196
+ const persisted = anchor?.type === "custom" &&
197
+ anchor.customType === CURSOR_SESSION_AGENT_CLEANUP_ENTRY_TYPE &&
198
+ anchor.id !== previousEntryId
199
+ ? parseCleanupEntryData(anchor.data)
200
+ : undefined;
201
+ if (!sessionFile || !persisted || !cleanupEntriesMatch(persisted, data))
202
+ return false;
203
+ return fsyncExistingRegularFile(sessionFile);
204
+ }
205
+ export async function runCursorSessionAgentCleanupCommand(pi, args, ctx) {
206
+ const usage = "Usage: /cursor-local-resume-cleanup [--dry-run|--yes]";
207
+ const tokens = args.trim().split(/\s+/).filter(Boolean);
208
+ const dryRun = tokens.length === 0 || (tokens.length === 1 && tokens[0] === "--dry-run");
209
+ const deleteNow = tokens.length === 1 && tokens[0] === "--yes";
210
+ if (!dryRun && !deleteNow) {
211
+ ctx.ui.notify(`Invalid Cursor local resume cleanup arguments. ${usage}`, "error");
212
+ return;
213
+ }
214
+ const entries = ctx.sessionManager.getEntries();
215
+ const branch = ctx.sessionManager.getBranch();
216
+ const scope = getCurrentCleanupScope(ctx);
217
+ const plan = readCursorSessionAgentCleanupPlanDetails(entries, branch, scope);
218
+ const baseEntry = {
219
+ runtime: "local",
220
+ timestamp: new Date().toISOString(),
221
+ candidateAgentIds: plan.candidateAgentIds,
222
+ ...(plan.protectedAgentIds.length ? { protectedAgentIds: plan.protectedAgentIds } : {}),
223
+ };
224
+ if (dryRun) {
225
+ appendCleanupEntry(pi, { action: "dry-run", ...baseEntry });
226
+ ctx.ui.notify(formatCleanupPlan(plan), "info");
227
+ return;
228
+ }
229
+ if (plan.candidateAgentIds.length === 0) {
230
+ try {
231
+ appendCleanupEntry(pi, { action: "delete", phase: "result", ...baseEntry, deletedAgentIds: [] });
232
+ ctx.ui.notify("No recorded superseded local Cursor SDK agents to delete.", "info");
233
+ }
234
+ catch {
235
+ ctx.ui.notify("No agents were deleted, but the no-op cleanup result could not be recorded.", "error");
236
+ }
237
+ return;
238
+ }
239
+ if (!appendDurableCleanupEntry(pi, ctx, { action: "delete", phase: "intent", ...baseEntry })) {
240
+ ctx.ui.notify("Cleanup intent could not be durably recorded. No agents were deleted.", "error");
241
+ return;
242
+ }
243
+ const deletedAgentIds = [];
244
+ const failedAgentIds = [];
245
+ const openedStores = new Map();
246
+ try {
247
+ const operations = await getSdkOperations();
248
+ const identities = await getCursorSessionStoreIdentities(ctx.cwd, scope.scopeKey, scope.sessionFile !== undefined);
249
+ for (const candidate of plan.candidates) {
250
+ const { agentId } = candidate;
251
+ try {
252
+ const identity = candidate.storeIdentity ?? identities.defaultStore;
253
+ if (!cursorSessionStoreIdentitiesEqual(identity, identities.defaultStore) &&
254
+ !cursorSessionStoreIdentitiesEqual(identity, identities.sessionStore))
255
+ throw new InvalidCursorSessionStoreIdentityError("Recorded Cursor local store identity is not valid for this pi session");
256
+ let openedStore = openedStores.get(identity.stateRoot);
257
+ if (!openedStore) {
258
+ openedStore = await openCursorSessionStore(ctx.cwd, identity);
259
+ openedStores.set(identity.stateRoot, openedStore);
260
+ }
261
+ await operations.delete(agentId, { cwd: ctx.cwd, store: openedStore.store });
262
+ deletedAgentIds.push(agentId);
263
+ }
264
+ catch (error) {
265
+ failedAgentIds.push({
266
+ agentId,
267
+ error: scrubSensitiveText(getString(asRecord(error), "message") ?? String(error)),
268
+ ...(error instanceof InvalidCursorSessionStoreIdentityError ? { retryable: false } : {}),
269
+ });
270
+ }
271
+ }
272
+ }
273
+ catch (error) {
274
+ const message = scrubSensitiveText(getString(asRecord(error), "message") ?? String(error));
275
+ failedAgentIds.push(...plan.candidateAgentIds.map((agentId) => ({ agentId, error: message })));
276
+ }
277
+ finally {
278
+ await Promise.all([...openedStores.values()].map((store) => store.dispose().catch(() => undefined)));
279
+ }
280
+ if (!appendDurableCleanupEntry(pi, ctx, {
281
+ action: "delete",
282
+ phase: "result",
283
+ ...baseEntry,
284
+ deletedAgentIds,
285
+ ...(failedAgentIds.length ? { failedAgentIds } : {}),
286
+ })) {
287
+ for (const agentId of plan.candidateAgentIds)
288
+ nondurableCleanupResultAgentIds.add(agentId);
289
+ ctx.ui.notify(`Deleted ${deletedAgentIds.length} recorded local Cursor SDK agent(s). The cleanup ledger is partial because its result could not be durably recorded; the durable intent blocks automatic retries.`, "error");
290
+ return;
291
+ }
292
+ if (failedAgentIds.length > 0) {
293
+ ctx.ui.notify(`Deleted ${deletedAgentIds.length} recorded local Cursor SDK agent(s); ${failedAgentIds.length} failed.`, "error");
294
+ return;
295
+ }
296
+ ctx.ui.notify(`Deleted ${deletedAgentIds.length} recorded local Cursor SDK agent(s).`, "info");
297
+ }
298
+ export const __testUtils = {
299
+ reset: () => {
300
+ nondurableCleanupResultAgentIds.clear();
301
+ appendDurabilityForTests = undefined;
302
+ sdkOperationsForTests = undefined;
303
+ },
304
+ setAppendDurability: (appendDurability) => {
305
+ appendDurabilityForTests = appendDurability;
306
+ },
307
+ setSdkOperations: (operations) => {
308
+ sdkOperationsForTests = operations;
309
+ },
310
+ parseCleanupEntryData,
311
+ };
@@ -0,0 +1,32 @@
1
+ import { clearCursorSdkHttp1 } from "./cursor-http1.js";
2
+ import { onCursorSessionScopeKeyChange } from "./cursor-session-scope.js";
3
+ import { disposeSessionCursorAgent, invalidateSessionAgent, resetSessionCursorAgent, } from "./cursor-session-agent.js";
4
+ export function registerCursorSessionAgentLifecycle(pi) {
5
+ onCursorSessionScopeKeyChange(async (previousScopeKey) => {
6
+ await disposeSessionCursorAgent(previousScopeKey);
7
+ });
8
+ pi.on("session_shutdown", async (event) => {
9
+ try {
10
+ if (event.reason === "reload") {
11
+ await resetSessionCursorAgent();
12
+ return;
13
+ }
14
+ await disposeSessionCursorAgent();
15
+ }
16
+ finally {
17
+ clearCursorSdkHttp1();
18
+ }
19
+ });
20
+ pi.on("session_compact", () => {
21
+ invalidateSessionAgent();
22
+ });
23
+ pi.on("session_before_tree", () => {
24
+ invalidateSessionAgent();
25
+ });
26
+ pi.on("session_tree", async () => {
27
+ await resetSessionCursorAgent();
28
+ });
29
+ pi.on("model_select", () => {
30
+ invalidateSessionAgent();
31
+ });
32
+ }