pi-cursor-sdk 0.1.51 → 0.1.52
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,18 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.1.52 - 2026-06-28
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Serialize Cursor provider turns per pi session scope so parallel same-session Cursor model evaluations cannot supersede each other's SDK session agent or drain the wrong live run. Queued aborts now return an aborted stream without creating a Cursor SDK agent or leaking the turn queue.
|
|
10
|
+
|
|
11
|
+
### Validation
|
|
12
|
+
|
|
13
|
+
- `npm run check:platform-smoke`, `npm run typecheck`, `npm test` (796 tests), and `npm publish --dry-run` pass locally.
|
|
14
|
+
- `npm run smoke:platform:all` passes on macOS, Ubuntu, and Windows native with Cursor auth. Artifact index: `.artifacts/platform-smoke/latest.json`.
|
|
15
|
+
- Subagent review/fix loop and thermo-nuclear release review completed with final `NO FINDINGS`.
|
|
16
|
+
|
|
5
17
|
## 0.1.51 - 2026-06-25
|
|
6
18
|
|
|
7
19
|
### Changed
|
package/package.json
CHANGED
|
@@ -46,7 +46,6 @@ export class CursorProviderTurnRunner {
|
|
|
46
46
|
});
|
|
47
47
|
|
|
48
48
|
try {
|
|
49
|
-
stream.push({ type: "start", partial });
|
|
50
49
|
this.throwIfAborted();
|
|
51
50
|
const cwd = getCursorSessionCwd();
|
|
52
51
|
this.sdkEventDebug = CursorSdkEventDebugSink.maybeCreate({
|
|
@@ -62,6 +61,7 @@ export class CursorProviderTurnRunner {
|
|
|
62
61
|
) {
|
|
63
62
|
return;
|
|
64
63
|
}
|
|
64
|
+
this.throwIfAborted();
|
|
65
65
|
|
|
66
66
|
this.resolvedApiKey = requireCursorApiKey(options);
|
|
67
67
|
prepared = await prepareCursorProviderTurn({
|
package/src/cursor-provider.ts
CHANGED
|
@@ -22,6 +22,8 @@ import { installCursorSdkProcessErrorGuard } from "./cursor-sdk-process-error-gu
|
|
|
22
22
|
import { sanitizeCursorProviderError } from "./cursor-provider-errors.js";
|
|
23
23
|
import { resolveCursorApiKey } from "./cursor-api-key.js";
|
|
24
24
|
import { CursorProviderTurnRunner } from "./cursor-provider-turn-runner.js";
|
|
25
|
+
import { getCursorSessionScopeKey } from "./cursor-session-scope.js";
|
|
26
|
+
import { runExclusiveCursorSessionTurn, __testUtils as cursorSessionTurnQueueTestUtils } from "./cursor-session-turn-queue.js";
|
|
25
27
|
|
|
26
28
|
function makeInitialMessage(model: Model<Api>): AssistantMessage {
|
|
27
29
|
return {
|
|
@@ -54,7 +56,6 @@ export function streamCursor(
|
|
|
54
56
|
|
|
55
57
|
(async () => {
|
|
56
58
|
const partial = makeInitialMessage(model);
|
|
57
|
-
const sdkProcessErrorGuard = installCursorSdkProcessErrorGuard();
|
|
58
59
|
|
|
59
60
|
const runner = new CursorProviderTurnRunner({
|
|
60
61
|
model,
|
|
@@ -66,7 +67,12 @@ export function streamCursor(
|
|
|
66
67
|
});
|
|
67
68
|
|
|
68
69
|
try {
|
|
69
|
-
|
|
70
|
+
stream.push({ type: "start", partial });
|
|
71
|
+
await runExclusiveCursorSessionTurn(
|
|
72
|
+
getCursorSessionScopeKey(),
|
|
73
|
+
() => runner.run(installCursorSdkProcessErrorGuard()),
|
|
74
|
+
options?.signal,
|
|
75
|
+
);
|
|
70
76
|
} catch (error) {
|
|
71
77
|
await runner.handleOuterCatch(error);
|
|
72
78
|
}
|
|
@@ -93,4 +99,5 @@ export const __testUtils = {
|
|
|
93
99
|
resetCursorNativeReplayIdleDisposeMs,
|
|
94
100
|
releaseAllPendingCursorLiveRunsForTests,
|
|
95
101
|
resetSessionCursorAgents: () => disposeAllSessionCursorAgents(),
|
|
102
|
+
resetSessionTurnQueue: cursorSessionTurnQueueTestUtils.reset,
|
|
96
103
|
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { CursorLiveRunAbortError } from "./cursor-live-run-coordinator.js";
|
|
2
|
+
|
|
3
|
+
const turnQueuesByScope = new Map<string, Promise<void>>();
|
|
4
|
+
|
|
5
|
+
async function waitForPreviousTurn(previous: Promise<void>, signal?: AbortSignal): Promise<void> {
|
|
6
|
+
if (!signal) {
|
|
7
|
+
await previous.catch(() => undefined);
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
if (signal.aborted) throw new CursorLiveRunAbortError();
|
|
11
|
+
await new Promise<void>((resolve, reject) => {
|
|
12
|
+
const onAbort = (): void => {
|
|
13
|
+
reject(new CursorLiveRunAbortError());
|
|
14
|
+
};
|
|
15
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
16
|
+
previous.catch(() => undefined).then(() => {
|
|
17
|
+
signal.removeEventListener("abort", onAbort);
|
|
18
|
+
resolve();
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function runExclusiveCursorSessionTurn<T>(scopeKey: string, body: () => Promise<T>, signal?: AbortSignal): Promise<T> {
|
|
24
|
+
const previous = turnQueuesByScope.get(scopeKey);
|
|
25
|
+
let releaseCurrent!: () => void;
|
|
26
|
+
const current = new Promise<void>((resolve) => {
|
|
27
|
+
releaseCurrent = resolve;
|
|
28
|
+
});
|
|
29
|
+
const tail = (previous ?? Promise.resolve()).catch(() => undefined).then(() => current);
|
|
30
|
+
turnQueuesByScope.set(scopeKey, tail);
|
|
31
|
+
void tail.finally(() => {
|
|
32
|
+
if (turnQueuesByScope.get(scopeKey) === tail) {
|
|
33
|
+
turnQueuesByScope.delete(scopeKey);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
if (previous) await waitForPreviousTurn(previous, signal);
|
|
39
|
+
return await body();
|
|
40
|
+
} finally {
|
|
41
|
+
releaseCurrent();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export const __testUtils = {
|
|
46
|
+
reset(): void {
|
|
47
|
+
turnQueuesByScope.clear();
|
|
48
|
+
},
|
|
49
|
+
count(): number {
|
|
50
|
+
return turnQueuesByScope.size;
|
|
51
|
+
},
|
|
52
|
+
};
|