pi-cursor-sdk 0.1.34 → 0.1.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,23 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.1.36 - 2026-06-05
6
+
7
+ ### Fixed
8
+
9
+ - Classify Cursor backend `ConnectError: [unavailable] Error` failures with code 14 and `aiserver.v1.ErrorDetails` as recoverable network/service errors, preventing duplicate process-level uncaught exceptions from crashing pi while still surfacing scrubbed retry guidance.
10
+
11
+ ## 0.1.35 - 2026-06-05
12
+
13
+ ### Changed
14
+
15
+ - Share the Cursor SDK startup-output filter through one published `shared/` helper while preserving the existing provider and maintainer-script import paths.
16
+ - Add prompt snippets for the Cursor bridge question and skill activation tools so their pi-native prompt metadata matches their existing schemas and guidelines.
17
+
18
+ ### Fixed
19
+
20
+ - Scope fileless/in-memory Cursor session agents by pi session ID instead of the process-wide anonymous fallback, so terminal shutdown of one ephemeral session does not poison later no-session replacements.
21
+
5
22
  ## 0.1.34 - 2026-06-04
6
23
 
7
24
  ### Changed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-cursor-sdk",
3
- "version": "0.1.34",
3
+ "version": "0.1.36",
4
4
  "description": "pi provider extension backed by @cursor/sdk local agents",
5
5
  "author": "Mitch Fultz (https://github.com/fitchmultz)",
6
6
  "license": "MIT",
@@ -1,5 +1,7 @@
1
- export declare const CURSOR_SDK_STARTUP_NOISE_PATTERNS: readonly string[];
2
- export declare function isCursorSdkOutputSuppressed(): boolean;
3
- export declare function suppressCursorSdkOutput<T>(operation: () => T): T;
4
- export declare function isCursorSdkStartupNoise(text: string): boolean;
5
- export declare function installCursorSdkOutputFilter(): () => void;
1
+ export {
2
+ CURSOR_SDK_STARTUP_NOISE_PATTERNS,
3
+ installCursorSdkOutputFilter,
4
+ isCursorSdkOutputSuppressed,
5
+ isCursorSdkStartupNoise,
6
+ suppressCursorSdkOutput,
7
+ } from "../../shared/cursor-sdk-output-filter.mjs";
@@ -1,86 +1,7 @@
1
- import { AsyncLocalStorage } from "node:async_hooks";
2
-
3
- export const CURSOR_SDK_STARTUP_NOISE_PATTERNS = [
4
- "[hooks]",
5
- "managed_skills.",
6
- "CursorPluginsAgentSkillsService load completed",
7
- "LocalCursorRulesService load completed",
8
- "AgentSkillsCursorRulesService load completed",
9
- "Error initializing ignore mapping for",
10
- "Ripgrep path not configured. Call configureRipgrepPath() at startup.",
11
- ];
12
-
13
- const cursorSdkOutputSuppression = new AsyncLocalStorage();
14
-
15
- export function isCursorSdkOutputSuppressed() {
16
- return cursorSdkOutputSuppression.getStore() === true;
17
- }
18
-
19
- export function suppressCursorSdkOutput(operation) {
20
- return cursorSdkOutputSuppression.run(true, operation);
21
- }
22
-
23
- export function isCursorSdkStartupNoise(text) {
24
- return CURSOR_SDK_STARTUP_NOISE_PATTERNS.some((pattern) => text.includes(pattern));
25
- }
26
-
27
- function createFilteredProcessWrite(write, stream) {
28
- return (chunk, encodingOrCallback, callback) => {
29
- const text = typeof chunk === "string" ? chunk : Buffer.from(chunk).toString("utf8");
30
- if (isCursorSdkOutputSuppressed() || isCursorSdkStartupNoise(text)) {
31
- const done = typeof encodingOrCallback === "function" ? encodingOrCallback : callback;
32
- done?.();
33
- return true;
34
- }
35
- return write.call(stream, chunk, encodingOrCallback, callback);
36
- };
37
- }
38
-
39
- function createFilteredConsoleMethod(method) {
40
- return (...args) => {
41
- const text = args.map((arg) => (typeof arg === "string" ? arg : String(arg))).join(" ");
42
- if (isCursorSdkOutputSuppressed() || isCursorSdkStartupNoise(text)) return;
43
- method(...args);
44
- };
45
- }
46
-
47
- let activeOutputFilterInstalls = 0;
48
- let outputFilterOriginals;
49
-
50
- export function installCursorSdkOutputFilter() {
51
- if (activeOutputFilterInstalls === 0) {
52
- outputFilterOriginals = {
53
- stdoutWrite: process.stdout.write,
54
- stderrWrite: process.stderr.write,
55
- consoleLog: console.log,
56
- consoleInfo: console.info,
57
- consoleWarn: console.warn,
58
- consoleError: console.error,
59
- consoleDebug: console.debug,
60
- };
61
- process.stdout.write = createFilteredProcessWrite(outputFilterOriginals.stdoutWrite, process.stdout);
62
- process.stderr.write = createFilteredProcessWrite(outputFilterOriginals.stderrWrite, process.stderr);
63
- console.log = createFilteredConsoleMethod(outputFilterOriginals.consoleLog);
64
- console.info = createFilteredConsoleMethod(outputFilterOriginals.consoleInfo);
65
- console.warn = createFilteredConsoleMethod(outputFilterOriginals.consoleWarn);
66
- console.error = createFilteredConsoleMethod(outputFilterOriginals.consoleError);
67
- console.debug = createFilteredConsoleMethod(outputFilterOriginals.consoleDebug);
68
- }
69
- activeOutputFilterInstalls += 1;
70
-
71
- let restored = false;
72
- return () => {
73
- if (restored) return;
74
- restored = true;
75
- activeOutputFilterInstalls = Math.max(activeOutputFilterInstalls - 1, 0);
76
- if (activeOutputFilterInstalls > 0 || !outputFilterOriginals) return;
77
- process.stdout.write = outputFilterOriginals.stdoutWrite;
78
- process.stderr.write = outputFilterOriginals.stderrWrite;
79
- console.log = outputFilterOriginals.consoleLog;
80
- console.info = outputFilterOriginals.consoleInfo;
81
- console.warn = outputFilterOriginals.consoleWarn;
82
- console.error = outputFilterOriginals.consoleError;
83
- console.debug = outputFilterOriginals.consoleDebug;
84
- outputFilterOriginals = undefined;
85
- };
86
- }
1
+ export {
2
+ CURSOR_SDK_STARTUP_NOISE_PATTERNS,
3
+ installCursorSdkOutputFilter,
4
+ isCursorSdkOutputSuppressed,
5
+ isCursorSdkStartupNoise,
6
+ suppressCursorSdkOutput,
7
+ } from "../../shared/cursor-sdk-output-filter.mjs";
@@ -48,12 +48,12 @@ Steps:
48
48
  1. read ./package.json and remember the package name.
49
49
  2. grep ./README.md for "pi-cursor-sdk".
50
50
  3. find README.md from repo root.
51
- 4. find src/cursor-provider.ts from repo root.
51
+ 4. find src/cursor-provider.ts from repo root; this is the list=<yes/no> evidence.
52
52
  5. run shell: {{shellSmoke}}
53
53
  6. write .debug/platform-smoke/native.txt with alpha and beta.
54
54
  7. edit beta to gamma in that file.
55
55
  8. run shell and preserve the failure: {{shellFailure}}
56
- 9. answer exactly:
56
+ 9. stop using tools and answer exactly:
57
57
  NATIVE_MATRIX_OK package=<name> grep=<yes/no> find=<yes/no> list=<yes/no> shell=<yes/no> shell_fail=<yes/no> write=<yes/no> edit=<yes/no>`,
58
58
  finalMarker: "NATIVE_MATRIX_OK package=pi-cursor-sdk",
59
59
  requiredCards: [
@@ -0,0 +1,5 @@
1
+ export declare const CURSOR_SDK_STARTUP_NOISE_PATTERNS: readonly string[];
2
+ export declare function isCursorSdkOutputSuppressed(): boolean;
3
+ export declare function suppressCursorSdkOutput<T>(operation: () => T): T;
4
+ export declare function isCursorSdkStartupNoise(text: string): boolean;
5
+ export declare function installCursorSdkOutputFilter(): () => void;
@@ -0,0 +1,86 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+
3
+ const cursorSdkOutputSuppression = new AsyncLocalStorage();
4
+
5
+ export const CURSOR_SDK_STARTUP_NOISE_PATTERNS = [
6
+ "[hooks]",
7
+ "managed_skills.",
8
+ "CursorPluginsAgentSkillsService load completed",
9
+ "LocalCursorRulesService load completed",
10
+ "AgentSkillsCursorRulesService load completed",
11
+ "Error initializing ignore mapping for",
12
+ "Ripgrep path not configured. Call configureRipgrepPath() at startup.",
13
+ ];
14
+
15
+ export function isCursorSdkOutputSuppressed() {
16
+ return cursorSdkOutputSuppression.getStore() === true;
17
+ }
18
+
19
+ export function suppressCursorSdkOutput(operation) {
20
+ return cursorSdkOutputSuppression.run(true, operation);
21
+ }
22
+
23
+ export function isCursorSdkStartupNoise(text) {
24
+ return CURSOR_SDK_STARTUP_NOISE_PATTERNS.some((pattern) => text.includes(pattern));
25
+ }
26
+
27
+ function createFilteredProcessWrite(write, stream) {
28
+ return (chunk, encodingOrCallback, callback) => {
29
+ const text = typeof chunk === "string" ? chunk : Buffer.from(chunk).toString("utf8");
30
+ if (isCursorSdkOutputSuppressed() || isCursorSdkStartupNoise(text)) {
31
+ const done = typeof encodingOrCallback === "function" ? encodingOrCallback : callback;
32
+ done?.();
33
+ return true;
34
+ }
35
+ return write.call(stream, chunk, encodingOrCallback, callback);
36
+ };
37
+ }
38
+
39
+ function createFilteredConsoleMethod(method) {
40
+ return (...args) => {
41
+ const text = args.map((arg) => (typeof arg === "string" ? arg : String(arg))).join(" ");
42
+ if (isCursorSdkOutputSuppressed() || isCursorSdkStartupNoise(text)) return;
43
+ method(...args);
44
+ };
45
+ }
46
+
47
+ let activeOutputFilterInstalls = 0;
48
+ let outputFilterOriginals;
49
+
50
+ export function installCursorSdkOutputFilter() {
51
+ if (activeOutputFilterInstalls === 0) {
52
+ outputFilterOriginals = {
53
+ stdoutWrite: process.stdout.write,
54
+ stderrWrite: process.stderr.write,
55
+ consoleLog: console.log,
56
+ consoleInfo: console.info,
57
+ consoleWarn: console.warn,
58
+ consoleError: console.error,
59
+ consoleDebug: console.debug,
60
+ };
61
+ process.stdout.write = createFilteredProcessWrite(outputFilterOriginals.stdoutWrite, process.stdout);
62
+ process.stderr.write = createFilteredProcessWrite(outputFilterOriginals.stderrWrite, process.stderr);
63
+ console.log = createFilteredConsoleMethod(outputFilterOriginals.consoleLog);
64
+ console.info = createFilteredConsoleMethod(outputFilterOriginals.consoleInfo);
65
+ console.warn = createFilteredConsoleMethod(outputFilterOriginals.consoleWarn);
66
+ console.error = createFilteredConsoleMethod(outputFilterOriginals.consoleError);
67
+ console.debug = createFilteredConsoleMethod(outputFilterOriginals.consoleDebug);
68
+ }
69
+ activeOutputFilterInstalls += 1;
70
+
71
+ let restored = false;
72
+ return () => {
73
+ if (restored) return;
74
+ restored = true;
75
+ activeOutputFilterInstalls = Math.max(activeOutputFilterInstalls - 1, 0);
76
+ if (activeOutputFilterInstalls > 0 || !outputFilterOriginals) return;
77
+ process.stdout.write = outputFilterOriginals.stdoutWrite;
78
+ process.stderr.write = outputFilterOriginals.stderrWrite;
79
+ console.log = outputFilterOriginals.consoleLog;
80
+ console.info = outputFilterOriginals.consoleInfo;
81
+ console.warn = outputFilterOriginals.consoleWarn;
82
+ console.error = outputFilterOriginals.consoleError;
83
+ console.debug = outputFilterOriginals.consoleDebug;
84
+ outputFilterOriginals = undefined;
85
+ };
86
+ }
@@ -9,7 +9,7 @@ const GENERIC_CURSOR_SDK_ERROR_MESSAGE =
9
9
  const AUTH_CURSOR_SDK_ERROR_MESSAGE =
10
10
  "Cursor SDK request failed because the Cursor SDK API key may be invalid or unauthorized. Cursor Agent CLI/Desktop login is not reused. Run /login -> Use an API key -> Cursor, verify CURSOR_API_KEY, or pass --api-key, then retry.";
11
11
  const NETWORK_CURSOR_SDK_ERROR_MESSAGE =
12
- "Cursor SDK request timed out during network I/O. Check your connection and retry; if this keeps happening, try again later or verify Cursor service availability.";
12
+ "Cursor SDK request failed during network or service I/O. Check your connection and retry; if this keeps happening, try again later or verify Cursor service availability.";
13
13
 
14
14
  const GENERIC_CURSOR_RUN_FAILURE_TEXT = "cursor sdk run failed";
15
15
 
@@ -47,6 +47,10 @@ function isUnauthenticatedConnectCode(code: unknown): boolean {
47
47
  return code === 16 || (typeof code === "string" && /^(?:16|unauthenticated)$/i.test(code));
48
48
  }
49
49
 
50
+ function isUnavailableConnectCode(code: unknown): boolean {
51
+ return code === 14 || (typeof code === "string" && /^(?:14|unavailable)$/i.test(code));
52
+ }
53
+
50
54
  function isCursorExtensionConnectStack(stack: string): boolean {
51
55
  return stack.includes("@connectrpc/connect-node") && /(?:^|[\\/])pi-cursor-sdk(?:[\\/]|$)/.test(stack);
52
56
  }
@@ -101,6 +105,10 @@ export function classifyCursorConnectError(error: unknown): CursorConnectErrorCl
101
105
  return { kind: "unauthenticated", source: getCursorConnectSource(error, record) };
102
106
  }
103
107
 
108
+ if (isUnavailableConnectCode(code)) {
109
+ return { kind: "network", source: getCursorConnectSource(error, record) };
110
+ }
111
+
104
112
  const causeCode = getErrorStringField(cause, "code");
105
113
  const causeSyscall = getErrorStringField(cause, "syscall");
106
114
  if (isLikelyNetworkTimeout(`${message}\n${rawMessage}\n${causeCode ?? ""}\n${causeSyscall ?? ""}`)) {
@@ -179,8 +187,9 @@ export function sanitizeCursorProviderError(error: unknown, apiKey?: string): st
179
187
  const message = error instanceof Error ? error.message : typeof error === "string" ? error : "";
180
188
  if (message === MISSING_CURSOR_API_KEY_MESSAGE) return MISSING_CURSOR_API_KEY_MESSAGE;
181
189
  const scrubbed = scrubSensitiveText(message, apiKey).trim();
182
- if (isUnauthenticatedConnectError(error) || isLikelyAuthError(scrubbed)) return AUTH_CURSOR_SDK_ERROR_MESSAGE;
190
+ const connectClassification = classifyCursorConnectError(error);
191
+ if (connectClassification?.kind === "unauthenticated" || isLikelyAuthError(scrubbed)) return AUTH_CURSOR_SDK_ERROR_MESSAGE;
192
+ if (connectClassification?.kind === "network" || isLikelyNetworkTimeout(scrubbed)) return NETWORK_CURSOR_SDK_ERROR_MESSAGE;
183
193
  if (isGenericErrorMessage(scrubbed)) return GENERIC_CURSOR_SDK_ERROR_MESSAGE;
184
- if (isLikelyNetworkTimeout(scrubbed)) return NETWORK_CURSOR_SDK_ERROR_MESSAGE;
185
194
  return scrubbed || GENERIC_CURSOR_SDK_ERROR_MESSAGE;
186
195
  }
@@ -196,6 +196,7 @@ export function registerCursorQuestionTool(pi: CursorQuestionToolExtensionApi):
196
196
  label: "Cursor question",
197
197
  description:
198
198
  "Ask the user a clarifying question from Cursor. Use when user preferences materially affect the next step; provide options when possible.",
199
+ promptSnippet: "Ask the user a clarifying question through pi UI when material choices affect Cursor's next step",
199
200
  parameters: CursorAskQuestionParamsSchema,
200
201
  promptGuidelines: [
201
202
  "Use cursor_ask_question only when running a Cursor model and user input would materially change the plan, scope, platform, or implementation path.",
@@ -1,100 +1,7 @@
1
- import { AsyncLocalStorage } from "node:async_hooks";
2
-
3
- const cursorSdkOutputSuppression = new AsyncLocalStorage<boolean>();
4
-
5
- export const CURSOR_SDK_STARTUP_NOISE_PATTERNS = [
6
- "[hooks]",
7
- "managed_skills.",
8
- "CursorPluginsAgentSkillsService load completed",
9
- "LocalCursorRulesService load completed",
10
- "AgentSkillsCursorRulesService load completed",
11
- "Error initializing ignore mapping for",
12
- "Ripgrep path not configured. Call configureRipgrepPath() at startup.",
13
- ] as const;
14
-
15
- export function isCursorSdkOutputSuppressed(): boolean {
16
- return cursorSdkOutputSuppression.getStore() === true;
17
- }
18
-
19
- export function suppressCursorSdkOutput<T>(operation: () => Promise<T>): Promise<T> {
20
- return cursorSdkOutputSuppression.run(true, operation);
21
- }
22
-
23
- export function isCursorSdkStartupNoise(text: string): boolean {
24
- return CURSOR_SDK_STARTUP_NOISE_PATTERNS.some((pattern) => text.includes(pattern));
25
- }
26
-
27
- function createFilteredProcessWrite<TWrite extends typeof process.stdout.write>(write: TWrite, stream: NodeJS.WriteStream): TWrite {
28
- return ((
29
- chunk: string | Uint8Array,
30
- encodingOrCallback?: BufferEncoding | ((error?: Error | null) => void),
31
- callback?: (error?: Error | null) => void,
32
- ): boolean => {
33
- const text = typeof chunk === "string" ? chunk : Buffer.from(chunk).toString("utf8");
34
- if (isCursorSdkOutputSuppressed() || isCursorSdkStartupNoise(text)) {
35
- const done = typeof encodingOrCallback === "function" ? encodingOrCallback : callback;
36
- done?.();
37
- return true;
38
- }
39
- return write.call(stream, chunk as string, encodingOrCallback as BufferEncoding, callback);
40
- }) as TWrite;
41
- }
42
-
43
- function createFilteredConsoleMethod<TMethod extends typeof console.log>(method: TMethod): TMethod {
44
- return ((...args: Parameters<TMethod>): void => {
45
- const text = args.map((arg) => (typeof arg === "string" ? arg : String(arg))).join(" ");
46
- if (isCursorSdkOutputSuppressed() || isCursorSdkStartupNoise(text)) return;
47
- method(...args);
48
- }) as TMethod;
49
- }
50
-
51
- interface CursorSdkOutputFilterOriginals {
52
- stdoutWrite: typeof process.stdout.write;
53
- stderrWrite: typeof process.stderr.write;
54
- consoleLog: typeof console.log;
55
- consoleInfo: typeof console.info;
56
- consoleWarn: typeof console.warn;
57
- consoleError: typeof console.error;
58
- consoleDebug: typeof console.debug;
59
- }
60
-
61
- let activeOutputFilterInstalls = 0;
62
- let outputFilterOriginals: CursorSdkOutputFilterOriginals | undefined;
63
-
64
- export function installCursorSdkOutputFilter(): () => void {
65
- if (activeOutputFilterInstalls === 0) {
66
- outputFilterOriginals = {
67
- stdoutWrite: process.stdout.write,
68
- stderrWrite: process.stderr.write,
69
- consoleLog: console.log,
70
- consoleInfo: console.info,
71
- consoleWarn: console.warn,
72
- consoleError: console.error,
73
- consoleDebug: console.debug,
74
- };
75
- process.stdout.write = createFilteredProcessWrite(outputFilterOriginals.stdoutWrite, process.stdout);
76
- process.stderr.write = createFilteredProcessWrite(outputFilterOriginals.stderrWrite, process.stderr) as typeof process.stderr.write;
77
- console.log = createFilteredConsoleMethod(outputFilterOriginals.consoleLog);
78
- console.info = createFilteredConsoleMethod(outputFilterOriginals.consoleInfo);
79
- console.warn = createFilteredConsoleMethod(outputFilterOriginals.consoleWarn);
80
- console.error = createFilteredConsoleMethod(outputFilterOriginals.consoleError);
81
- console.debug = createFilteredConsoleMethod(outputFilterOriginals.consoleDebug);
82
- }
83
- activeOutputFilterInstalls += 1;
84
-
85
- let restored = false;
86
- return () => {
87
- if (restored) return;
88
- restored = true;
89
- activeOutputFilterInstalls = Math.max(activeOutputFilterInstalls - 1, 0);
90
- if (activeOutputFilterInstalls > 0 || !outputFilterOriginals) return;
91
- process.stdout.write = outputFilterOriginals.stdoutWrite;
92
- process.stderr.write = outputFilterOriginals.stderrWrite;
93
- console.log = outputFilterOriginals.consoleLog;
94
- console.info = outputFilterOriginals.consoleInfo;
95
- console.warn = outputFilterOriginals.consoleWarn;
96
- console.error = outputFilterOriginals.consoleError;
97
- console.debug = outputFilterOriginals.consoleDebug;
98
- outputFilterOriginals = undefined;
99
- };
100
- }
1
+ export {
2
+ CURSOR_SDK_STARTUP_NOISE_PATTERNS,
3
+ installCursorSdkOutputFilter,
4
+ isCursorSdkOutputSuppressed,
5
+ isCursorSdkStartupNoise,
6
+ suppressCursorSdkOutput,
7
+ } from "../shared/cursor-sdk-output-filter.mjs";
@@ -5,12 +5,14 @@ interface CursorSessionScopeExtensionApi {
5
5
  }
6
6
 
7
7
  const ANONYMOUS_SESSION_SCOPE_KEY = "__anonymous__";
8
+ const EPHEMERAL_SESSION_SCOPE_PREFIX = "__ephemeral__:";
8
9
 
9
10
  type CursorSessionScopeChangeHandler = (previousScopeKey: string) => void;
10
11
 
11
12
  const state = {
12
13
  sessionCwd: process.cwd(),
13
14
  sessionFile: undefined as string | undefined,
15
+ sessionId: undefined as string | undefined,
14
16
  };
15
17
 
16
18
  let scopeChangeHandler: CursorSessionScopeChangeHandler | undefined;
@@ -27,21 +29,25 @@ export function getCursorSessionFile(): string | undefined {
27
29
  * before the first session_start (tests and early startup).
28
30
  */
29
31
  export function getCursorSessionScopeKey(): string {
30
- return state.sessionFile ?? ANONYMOUS_SESSION_SCOPE_KEY;
32
+ if (state.sessionFile) return state.sessionFile;
33
+ if (state.sessionId) return `${EPHEMERAL_SESSION_SCOPE_PREFIX}${state.sessionId}`;
34
+ return ANONYMOUS_SESSION_SCOPE_KEY;
31
35
  }
32
36
 
33
37
  export function getCursorSessionCwdFromScope(): string {
34
38
  return state.sessionCwd;
35
39
  }
36
40
 
37
- function setCursorSessionScope(cwd: string, sessionFile: string | undefined): void {
41
+ function setCursorSessionScope(cwd: string, sessionFile: string | undefined, sessionId?: string): void {
38
42
  state.sessionCwd = cwd;
39
43
  state.sessionFile = sessionFile;
44
+ state.sessionId = sessionId;
40
45
  }
41
46
 
42
47
  function resetCursorSessionScope(): void {
43
48
  state.sessionCwd = process.cwd();
44
49
  state.sessionFile = undefined;
50
+ state.sessionId = undefined;
45
51
  }
46
52
 
47
53
  export function onCursorSessionScopeKeyChange(handler: CursorSessionScopeChangeHandler): void {
@@ -51,7 +57,11 @@ export function onCursorSessionScopeKeyChange(handler: CursorSessionScopeChangeH
51
57
  export function registerCursorSessionScope(pi: CursorSessionScopeExtensionApi): void {
52
58
  pi.on("session_start", (_event, ctx) => {
53
59
  const previousScopeKey = getCursorSessionScopeKey();
54
- setCursorSessionScope(ctx.cwd, ctx.sessionManager?.getSessionFile?.() ?? undefined);
60
+ setCursorSessionScope(
61
+ ctx.cwd,
62
+ ctx.sessionManager?.getSessionFile?.() ?? undefined,
63
+ ctx.sessionManager?.getSessionId?.() ?? undefined,
64
+ );
55
65
  if (previousScopeKey !== getCursorSessionScopeKey()) {
56
66
  scopeChangeHandler?.(previousScopeKey);
57
67
  }
@@ -60,6 +70,7 @@ export function registerCursorSessionScope(pi: CursorSessionScopeExtensionApi):
60
70
 
61
71
  export const __testUtils = {
62
72
  ANONYMOUS_SESSION_SCOPE_KEY,
73
+ EPHEMERAL_SESSION_SCOPE_PREFIX,
63
74
  set: setCursorSessionScope,
64
75
  reset: resetCursorSessionScope,
65
76
  };
@@ -187,6 +187,7 @@ export function registerCursorSkillTool(pi: CursorSkillToolExtensionApi): void {
187
187
  name: CURSOR_ACTIVATE_SKILL_TOOL_NAME,
188
188
  label: "Cursor skill",
189
189
  description: "Load full pi Agent Skill instructions for Cursor. Use with a skill name from the current <available_skills> catalog before applying that skill.",
190
+ promptSnippet: "Load full pi Agent Skill instructions for a listed skill before Cursor applies that skill",
190
191
  parameters: Type.Object({
191
192
  name: Type.String({ description: "Skill name from the current <available_skills> catalog" }),
192
193
  }),