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 +17 -0
- package/package.json +1 -1
- package/scripts/lib/cursor-sdk-output-filter.d.mts +7 -5
- package/scripts/lib/cursor-sdk-output-filter.mjs +7 -86
- package/scripts/platform-smoke/scenarios.mjs +2 -2
- package/shared/cursor-sdk-output-filter.d.mts +5 -0
- package/shared/cursor-sdk-output-filter.mjs +86 -0
- package/src/cursor-provider-errors.ts +12 -3
- package/src/cursor-question-tool.ts +1 -0
- package/src/cursor-sdk-output-filter.ts +7 -100
- package/src/cursor-session-scope.ts +14 -3
- package/src/cursor-skill-tool.ts +1 -0
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,5 +1,7 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
};
|
package/src/cursor-skill-tool.ts
CHANGED
|
@@ -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
|
}),
|