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.
- package/CHANGELOG.md +85 -0
- package/README.md +57 -53
- package/dist/bundled-context-windows.js +39 -0
- package/dist/context-window-cache.js +92 -0
- package/dist/context.js +338 -0
- package/dist/cursor-active-tools.js +3 -0
- package/dist/cursor-agent-message-web-tools.js +165 -0
- package/dist/cursor-agents-context-registration.js +17 -0
- package/dist/cursor-agents-context.js +113 -0
- package/dist/cursor-api-key.js +34 -0
- package/dist/cursor-bridge-contract.js +27 -0
- package/dist/cursor-cloud-lifecycle.js +650 -0
- package/dist/cursor-cloud-local-state.js +460 -0
- package/dist/cursor-cloud-options.js +145 -0
- package/dist/cursor-cloud-reporting.js +222 -0
- package/dist/cursor-compact-tool-summary.js +75 -0
- package/dist/cursor-config.js +613 -0
- package/dist/cursor-context-tools.js +4 -0
- package/dist/cursor-display-only-trace.js +11 -0
- package/dist/cursor-display-text.js +18 -0
- package/dist/cursor-durable-fs.js +53 -0
- package/dist/cursor-edit-diff.js +13 -0
- package/dist/cursor-env-boolean.js +19 -0
- package/dist/cursor-fallback-models.generated.js +7760 -0
- package/dist/cursor-fallback-warning.js +15 -0
- package/dist/cursor-http1.js +45 -0
- package/dist/cursor-incomplete-tool-visibility.js +83 -0
- package/dist/cursor-live-run-accounting.js +55 -0
- package/dist/cursor-live-run-coordinator.js +406 -0
- package/dist/cursor-mcp-timeout-override.js +116 -0
- package/dist/cursor-model-lifecycle.js +32 -0
- package/dist/cursor-model.js +5 -0
- package/dist/cursor-native-replay-routing.js +35 -0
- package/dist/cursor-native-replay-trace.js +28 -0
- package/dist/cursor-native-tool-display-registration.js +102 -0
- package/dist/cursor-native-tool-display-replay.js +428 -0
- package/dist/cursor-native-tool-display-state.js +70 -0
- package/dist/cursor-native-tool-display-tools.js +123 -0
- package/dist/cursor-native-tool-names.js +11 -0
- package/dist/cursor-partial-content-emitter.js +118 -0
- package/dist/cursor-pi-tool-bridge-abort.js +114 -0
- package/dist/cursor-pi-tool-bridge-constants.js +6 -0
- package/dist/cursor-pi-tool-bridge-diagnostics.js +125 -0
- package/dist/cursor-pi-tool-bridge-env.js +18 -0
- package/dist/cursor-pi-tool-bridge-mcp.js +100 -0
- package/dist/cursor-pi-tool-bridge-run.js +355 -0
- package/dist/cursor-pi-tool-bridge-server.js +163 -0
- package/dist/cursor-pi-tool-bridge-snapshot.js +63 -0
- package/dist/cursor-pi-tool-bridge-types.js +1 -0
- package/dist/cursor-pi-tool-bridge.js +123 -0
- package/dist/cursor-provider-errors.js +311 -0
- package/dist/cursor-provider-lazy.js +39 -0
- package/dist/cursor-provider-live-run-drain.js +412 -0
- package/dist/cursor-provider-overflow.js +90 -0
- package/dist/cursor-provider-run-finalizer.js +176 -0
- package/dist/cursor-provider-run-outcome.js +76 -0
- package/dist/cursor-provider-turn-coordinator.js +275 -0
- package/dist/cursor-provider-turn-display-router.js +158 -0
- package/dist/cursor-provider-turn-emit.js +35 -0
- package/dist/cursor-provider-turn-finalize.js +154 -0
- package/dist/cursor-provider-turn-lifecycle-emitter.js +126 -0
- package/dist/cursor-provider-turn-prepare.js +374 -0
- package/dist/cursor-provider-turn-runner.js +146 -0
- package/dist/cursor-provider-turn-sdk-normalizer.js +74 -0
- package/dist/cursor-provider-turn-send.js +138 -0
- package/dist/cursor-provider-turn-shell-output.js +117 -0
- package/dist/cursor-provider-turn-tool-ledger.js +99 -0
- package/dist/cursor-provider-turn-types.js +1 -0
- package/dist/cursor-provider.js +72 -0
- package/dist/cursor-question-tool.js +194 -0
- package/dist/cursor-record-utils.js +61 -0
- package/dist/cursor-replay-activity-builders.js +114 -0
- package/dist/cursor-replay-source-names.js +27 -0
- package/dist/cursor-replay-summary-args.js +105 -0
- package/dist/cursor-replay-tool-details.js +167 -0
- package/dist/cursor-ripgrep-path.js +27 -0
- package/dist/cursor-run-final-text.js +63 -0
- package/dist/cursor-runtime-state.js +380 -0
- package/dist/cursor-sdk-billed-usage.js +86 -0
- package/dist/cursor-sdk-event-debug-constants.js +33 -0
- package/dist/cursor-sdk-event-debug-session.js +107 -0
- package/dist/cursor-sdk-event-debug.js +461 -0
- package/dist/cursor-sdk-output-filter.js +1 -0
- package/dist/cursor-sdk-process-error-guard.js +221 -0
- package/dist/cursor-sdk-runtime.js +3 -0
- package/dist/cursor-sensitive-text.js +23 -0
- package/dist/cursor-session-agent-cleanup.js +311 -0
- package/dist/cursor-session-agent-lifecycle.js +32 -0
- package/dist/cursor-session-agent-lineage.js +103 -0
- package/dist/cursor-session-agent-resume.js +417 -0
- package/dist/cursor-session-agent.js +507 -0
- package/dist/cursor-session-compaction-prep.js +21 -0
- package/dist/cursor-session-scope.js +113 -0
- package/dist/cursor-session-send-policy.js +18 -0
- package/dist/cursor-session-store.js +105 -0
- package/dist/cursor-session-turn-queue.js +50 -0
- package/dist/cursor-setting-sources.js +15 -0
- package/dist/cursor-skill-tool.js +230 -0
- package/dist/cursor-state.js +519 -0
- package/dist/cursor-task-presentation.js +59 -0
- package/dist/cursor-tool-lifecycle.js +94 -0
- package/dist/cursor-tool-manifest.js +34 -0
- package/dist/cursor-tool-presentation-registry.js +305 -0
- package/dist/cursor-tool-result-display-readers.js +158 -0
- package/dist/cursor-tool-transcript.js +32 -0
- package/dist/cursor-tool-visibility.js +28 -0
- package/dist/cursor-transcript-tool-formatters.js +618 -0
- package/dist/cursor-transcript-tool-specs.js +284 -0
- package/dist/cursor-transcript-utils.js +170 -0
- package/dist/cursor-usage-accounting.js +166 -0
- package/dist/cursor-web-tool-activity.js +23 -0
- package/dist/cursor-web-tool-args.js +12 -0
- package/dist/index.js +82 -0
- package/dist/model-discovery.js +305 -0
- package/dist/model-list-cache.js +156 -0
- package/docs/cursor-dogfood-checklist.md +2 -1
- package/docs/cursor-live-smoke-checklist.md +15 -14
- package/docs/cursor-model-ux-spec.md +29 -8
- package/docs/cursor-native-tool-replay.md +13 -13
- package/docs/cursor-native-tool-visual-audit.md +6 -3
- package/docs/cursor-testing-lessons.md +7 -7
- package/docs/cursor-tool-surfaces.md +5 -5
- package/docs/platform-smoke.md +6 -6
- package/node_modules/fast-uri/index.js +37 -1
- package/node_modules/fast-uri/package.json +1 -1
- package/node_modules/fast-uri/test/security.test.js +136 -0
- package/node_modules/hono/dist/cjs/context.js +28 -13
- package/node_modules/hono/dist/cjs/helper/proxy/index.js +4 -0
- package/node_modules/hono/dist/cjs/helper/streaming/sse.js +1 -1
- package/node_modules/hono/dist/cjs/hono-base.js +3 -2
- package/node_modules/hono/dist/cjs/jsx/base.js +27 -23
- package/node_modules/hono/dist/cjs/jsx/hooks/index.js +16 -13
- package/node_modules/hono/dist/cjs/middleware/cache/index.js +103 -8
- package/node_modules/hono/dist/cjs/middleware/compress/index.js +5 -0
- package/node_modules/hono/dist/cjs/middleware/cors/index.js +2 -2
- package/node_modules/hono/dist/cjs/middleware/etag/index.js +1 -1
- package/node_modules/hono/dist/cjs/middleware/jwk/jwk.js +9 -4
- package/node_modules/hono/dist/cjs/middleware/jwt/jwt.js +9 -4
- package/node_modules/hono/dist/cjs/middleware/language/language.js +10 -6
- package/node_modules/hono/dist/cjs/middleware/method-not-allowed/index.js +90 -0
- package/node_modules/hono/dist/cjs/middleware/secure-headers/secure-headers.js +10 -4
- package/node_modules/hono/dist/cjs/request.js +7 -9
- package/node_modules/hono/dist/cjs/router/reg-exp-router/node.js +55 -56
- package/node_modules/hono/dist/cjs/router/reg-exp-router/router.js +64 -85
- package/node_modules/hono/dist/cjs/router/reg-exp-router/trie.js +13 -5
- package/node_modules/hono/dist/cjs/router.js +1 -1
- package/node_modules/hono/dist/cjs/utils/accept.js +1 -1
- package/node_modules/hono/dist/cjs/utils/cookie.js +3 -2
- package/node_modules/hono/dist/cjs/utils/url.js +8 -8
- package/node_modules/hono/dist/context.js +28 -13
- package/node_modules/hono/dist/helper/proxy/index.js +4 -0
- package/node_modules/hono/dist/helper/streaming/sse.js +1 -1
- package/node_modules/hono/dist/hono-base.js +3 -2
- package/node_modules/hono/dist/jsx/base.js +27 -23
- package/node_modules/hono/dist/jsx/hooks/index.js +16 -13
- package/node_modules/hono/dist/middleware/cache/index.js +103 -8
- package/node_modules/hono/dist/middleware/compress/index.js +5 -0
- package/node_modules/hono/dist/middleware/cors/index.js +2 -2
- package/node_modules/hono/dist/middleware/etag/index.js +1 -1
- package/node_modules/hono/dist/middleware/jwk/jwk.js +9 -4
- package/node_modules/hono/dist/middleware/jwt/jwt.js +9 -4
- package/node_modules/hono/dist/middleware/language/language.js +10 -6
- package/node_modules/hono/dist/middleware/method-not-allowed/index.js +68 -0
- package/node_modules/hono/dist/middleware/secure-headers/secure-headers.js +10 -4
- package/node_modules/hono/dist/request.js +8 -10
- package/node_modules/hono/dist/router/reg-exp-router/node.js +55 -56
- package/node_modules/hono/dist/router/reg-exp-router/router.js +64 -85
- package/node_modules/hono/dist/router/reg-exp-router/trie.js +13 -5
- package/node_modules/hono/dist/router.js +1 -1
- package/node_modules/hono/dist/types/adapter/aws-lambda/types.d.ts +9 -0
- package/node_modules/hono/dist/types/client/types.d.ts +1 -1
- package/node_modules/hono/dist/types/hono-base.d.ts +4 -3
- package/node_modules/hono/dist/types/jsx/base.d.ts +4 -2
- package/node_modules/hono/dist/types/jsx/dom/index.d.ts +5 -5
- package/node_modules/hono/dist/types/jsx/dom/intrinsic-element/components.d.ts +2 -2
- package/node_modules/hono/dist/types/jsx/dom/server.d.ts +5 -5
- package/node_modules/hono/dist/types/jsx/hooks/index.d.ts +8 -6
- package/node_modules/hono/dist/types/jsx/index.d.ts +5 -5
- package/node_modules/hono/dist/types/middleware/cache/index.d.ts +6 -4
- package/node_modules/hono/dist/types/middleware/cors/index.d.ts +1 -1
- package/node_modules/hono/dist/types/middleware/jsx-renderer/index.d.ts +2 -2
- package/node_modules/hono/dist/types/middleware/jwk/jwk.d.ts +2 -0
- package/node_modules/hono/dist/types/middleware/jwt/jwt.d.ts +2 -0
- package/node_modules/hono/dist/types/middleware/method-not-allowed/index.d.ts +49 -0
- package/node_modules/hono/dist/types/router/reg-exp-router/node.d.ts +1 -1
- package/node_modules/hono/dist/types/router/reg-exp-router/trie.d.ts +2 -1
- package/node_modules/hono/dist/types/router.d.ts +1 -1
- package/node_modules/hono/dist/types/utils/headers.d.ts +2 -2
- package/node_modules/hono/dist/types/utils/url.d.ts +1 -0
- package/node_modules/hono/dist/utils/accept.js +1 -1
- package/node_modules/hono/dist/utils/cookie.js +4 -3
- package/node_modules/hono/dist/utils/url.js +6 -7
- package/node_modules/hono/package.json +10 -3
- package/node_modules/ip-address/README.md +146 -126
- package/node_modules/ip-address/dist/common.d.ts +29 -0
- package/node_modules/ip-address/dist/common.js +44 -5
- package/node_modules/ip-address/dist/common.js.map +1 -1
- package/node_modules/ip-address/dist/ipv4.d.ts +8 -1
- package/node_modules/ip-address/dist/ipv4.js +24 -20
- package/node_modules/ip-address/dist/ipv4.js.map +1 -1
- package/node_modules/ip-address/dist/ipv6.d.ts +68 -3
- package/node_modules/ip-address/dist/ipv6.js +180 -53
- package/node_modules/ip-address/dist/ipv6.js.map +1 -1
- package/node_modules/ip-address/dist/v4/constants.js +5 -1
- package/node_modules/ip-address/dist/v4/constants.js.map +1 -1
- package/node_modules/ip-address/dist/v6/constants.js +3 -2
- package/node_modules/ip-address/dist/v6/constants.js.map +1 -1
- package/node_modules/ip-address/package.json +6 -4
- package/package.json +23 -11
- package/platform-smoke.config.mjs +1 -1
- package/scripts/build.mjs +126 -0
- package/scripts/cloud-runtime-smoke.mjs +3 -1
- package/scripts/debug-provider-events.mjs +3 -1
- package/scripts/debug-sdk-events.mjs +1 -1
- package/scripts/isolated-cursor-smoke.sh +5 -4
- package/scripts/lib/cloud-smoke-cleanup-evidence.mjs +1 -1
- package/scripts/lib/cursor-visual-render.mjs +1 -1
- package/scripts/lib/ensure-built.mjs +16 -0
- package/scripts/lib/local-resume-smoke-harness.mjs +1 -1
- package/scripts/local-resume-smoke.mjs +3 -1
- package/scripts/platform-smoke/card-detect.mjs +1 -1
- package/scripts/platform-smoke/live-suite-runner.mjs +16 -40
- package/scripts/platform-smoke/platform-build-windows.ps1 +1 -1
- package/scripts/platform-smoke/render-ansi.mjs +1 -1
- package/scripts/platform-smoke/scenarios.mjs +1 -1
- package/scripts/platform-smoke/targets.mjs +2 -2
- package/scripts/platform-smoke.mjs +5 -5
- package/scripts/prepare.mjs +102 -0
- package/scripts/refresh-cursor-model-snapshots.mjs +16 -7
- package/scripts/steering-rpc-smoke.mjs +4 -2
- package/scripts/tmux-live-smoke.sh +11 -11
- package/scripts/visual-tui-smoke-self-test.mjs +4 -1
- package/scripts/visual-tui-smoke.mjs +51 -7
- package/shared/cursor-model-selection-identities.d.mts +21 -0
- package/shared/cursor-model-selection-identities.mjs +95 -0
- package/src/bundled-context-windows.ts +21 -12
- package/src/context.ts +1 -1
- package/src/cursor-agents-context-registration.ts +2 -2
- package/src/cursor-agents-context.ts +0 -2
- package/src/cursor-api-key.ts +5 -4
- package/src/cursor-cloud-reporting.ts +23 -2
- package/src/cursor-context-tools.ts +1 -1
- package/src/cursor-display-only-trace.ts +1 -1
- package/src/cursor-fallback-models.generated.ts +1726 -824
- package/src/cursor-live-run-accounting.ts +1 -1
- package/src/cursor-live-run-coordinator.ts +2 -1
- package/src/cursor-native-replay-routing.ts +1 -1
- package/src/cursor-native-tool-display-registration.ts +10 -11
- package/src/cursor-partial-content-emitter.ts +1 -1
- package/src/cursor-pi-tool-bridge-mcp.ts +1 -1
- package/src/cursor-pi-tool-bridge-run.ts +1 -1
- package/src/cursor-pi-tool-bridge-types.ts +1 -1
- package/src/cursor-provider-errors.ts +1 -1
- package/src/cursor-provider-lazy.ts +6 -5
- package/src/cursor-provider-live-run-drain.ts +2 -1
- package/src/cursor-provider-overflow.ts +1 -1
- package/src/cursor-provider-run-finalizer.ts +2 -1
- package/src/cursor-provider-turn-coordinator.ts +1 -1
- package/src/cursor-provider-turn-finalize.ts +12 -0
- package/src/cursor-provider-turn-lifecycle-emitter.ts +1 -1
- package/src/cursor-provider-turn-prepare.ts +1 -1
- package/src/cursor-provider-turn-types.ts +3 -1
- package/src/cursor-provider.ts +1 -1
- package/src/cursor-run-final-text.ts +1 -1
- package/src/cursor-sdk-billed-usage.ts +107 -0
- package/src/cursor-sdk-event-debug.ts +1 -1
- package/src/cursor-sdk-process-error-guard.ts +6 -4
- package/src/cursor-session-agent-lifecycle.ts +8 -9
- package/src/cursor-session-agent-resume.ts +23 -0
- package/src/cursor-session-agent.ts +1 -1
- package/src/cursor-session-compaction-prep.ts +4 -0
- package/src/cursor-session-send-policy.ts +1 -1
- package/src/cursor-tool-manifest.ts +1 -1
- package/src/cursor-usage-accounting.ts +71 -10
- package/src/index.ts +1 -1
- package/src/model-discovery.ts +32 -89
- package/tsconfig.build.json +8 -0
- package/tsconfig.json +16 -0
- package/node_modules/cross-spawn/node_modules/which/CHANGELOG.md +0 -166
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
const DEFAULT_THINKING_TRACE_MAX_CHARS = 50000;
|
|
2
|
+
export class CursorPartialContentEmitter {
|
|
3
|
+
stream;
|
|
4
|
+
partial;
|
|
5
|
+
thinkingMaxChars;
|
|
6
|
+
mutuallyExclusive;
|
|
7
|
+
thinkingContentIndex = -1;
|
|
8
|
+
textContentIndex = -1;
|
|
9
|
+
activityTraceChars = 0;
|
|
10
|
+
activityTraceTruncated = false;
|
|
11
|
+
constructor(stream, partial, thinkingMaxChars = DEFAULT_THINKING_TRACE_MAX_CHARS, mutuallyExclusive = true) {
|
|
12
|
+
this.stream = stream;
|
|
13
|
+
this.partial = partial;
|
|
14
|
+
this.thinkingMaxChars = thinkingMaxChars;
|
|
15
|
+
this.mutuallyExclusive = mutuallyExclusive;
|
|
16
|
+
}
|
|
17
|
+
closeThinking() {
|
|
18
|
+
if (this.thinkingContentIndex < 0)
|
|
19
|
+
return;
|
|
20
|
+
const block = this.partial.content[this.thinkingContentIndex];
|
|
21
|
+
if (block.type === "thinking") {
|
|
22
|
+
this.stream.push({
|
|
23
|
+
type: "thinking_end",
|
|
24
|
+
contentIndex: this.thinkingContentIndex,
|
|
25
|
+
content: block.thinking,
|
|
26
|
+
partial: this.partial,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
this.thinkingContentIndex = -1;
|
|
30
|
+
}
|
|
31
|
+
closeText() {
|
|
32
|
+
if (this.textContentIndex < 0)
|
|
33
|
+
return "";
|
|
34
|
+
const contentIndex = this.textContentIndex;
|
|
35
|
+
const block = this.partial.content[contentIndex];
|
|
36
|
+
this.textContentIndex = -1;
|
|
37
|
+
if (block.type !== "text")
|
|
38
|
+
return "";
|
|
39
|
+
this.stream.push({
|
|
40
|
+
type: "text_end",
|
|
41
|
+
contentIndex,
|
|
42
|
+
content: block.text,
|
|
43
|
+
partial: this.partial,
|
|
44
|
+
});
|
|
45
|
+
return block.text;
|
|
46
|
+
}
|
|
47
|
+
closeAll() {
|
|
48
|
+
this.closeThinking();
|
|
49
|
+
return this.closeText();
|
|
50
|
+
}
|
|
51
|
+
appendThinkingDelta(delta, options) {
|
|
52
|
+
const closeText = options?.closeText ?? this.mutuallyExclusive;
|
|
53
|
+
if (closeText)
|
|
54
|
+
this.closeText();
|
|
55
|
+
if (this.activityTraceTruncated || !delta)
|
|
56
|
+
return;
|
|
57
|
+
let text = delta;
|
|
58
|
+
if (this.thinkingMaxChars >= 0 && this.activityTraceChars + text.length > this.thinkingMaxChars) {
|
|
59
|
+
const remainingChars = Math.max(this.thinkingMaxChars - this.activityTraceChars, 0);
|
|
60
|
+
text = `${text.slice(0, remainingChars)}\n[Cursor activity trace truncated]\n`;
|
|
61
|
+
this.activityTraceTruncated = true;
|
|
62
|
+
}
|
|
63
|
+
if (!text)
|
|
64
|
+
return;
|
|
65
|
+
if (this.thinkingContentIndex < 0) {
|
|
66
|
+
this.thinkingContentIndex = this.partial.content.length;
|
|
67
|
+
this.partial.content.push({ type: "thinking", thinking: "" });
|
|
68
|
+
this.stream.push({ type: "thinking_start", contentIndex: this.thinkingContentIndex, partial: this.partial });
|
|
69
|
+
}
|
|
70
|
+
const block = this.partial.content[this.thinkingContentIndex];
|
|
71
|
+
if (block.type !== "thinking")
|
|
72
|
+
return;
|
|
73
|
+
block.thinking += text;
|
|
74
|
+
this.activityTraceChars += text.length;
|
|
75
|
+
this.stream.push({
|
|
76
|
+
type: "thinking_delta",
|
|
77
|
+
contentIndex: this.thinkingContentIndex,
|
|
78
|
+
delta: text,
|
|
79
|
+
partial: this.partial,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
appendTextDelta(delta, options) {
|
|
83
|
+
const closeThinking = options?.closeThinking ?? this.mutuallyExclusive;
|
|
84
|
+
if (closeThinking)
|
|
85
|
+
this.closeThinking();
|
|
86
|
+
if (!delta)
|
|
87
|
+
return;
|
|
88
|
+
if (this.textContentIndex < 0) {
|
|
89
|
+
this.textContentIndex = this.partial.content.length;
|
|
90
|
+
this.partial.content.push({ type: "text", text: "" });
|
|
91
|
+
this.stream.push({ type: "text_start", contentIndex: this.textContentIndex, partial: this.partial });
|
|
92
|
+
}
|
|
93
|
+
const block = this.partial.content[this.textContentIndex];
|
|
94
|
+
if (block.type !== "text")
|
|
95
|
+
return;
|
|
96
|
+
block.text += delta;
|
|
97
|
+
this.stream.push({
|
|
98
|
+
type: "text_delta",
|
|
99
|
+
contentIndex: this.textContentIndex,
|
|
100
|
+
delta,
|
|
101
|
+
partial: this.partial,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
appendThinkingBlock(text, options) {
|
|
105
|
+
const closeText = options?.closeText ?? this.mutuallyExclusive;
|
|
106
|
+
if (closeText)
|
|
107
|
+
this.closeAll();
|
|
108
|
+
else
|
|
109
|
+
this.closeThinking();
|
|
110
|
+
this.appendThinkingDelta(text.endsWith("\n") ? text : `${text}\n`, { closeText: false });
|
|
111
|
+
this.closeThinking();
|
|
112
|
+
}
|
|
113
|
+
flushText(deltas) {
|
|
114
|
+
for (const delta of deltas)
|
|
115
|
+
this.appendTextDelta(delta);
|
|
116
|
+
return this.closeText();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
class CursorPiToolBridgeToolExecutionAbortTracker {
|
|
2
|
+
activeExecutions = new Map();
|
|
3
|
+
processSignalHandlersInstalled = false;
|
|
4
|
+
track(toolCallId, options) {
|
|
5
|
+
this.finish(toolCallId);
|
|
6
|
+
const execution = {
|
|
7
|
+
toolCallId,
|
|
8
|
+
abort: options.abort,
|
|
9
|
+
cancelPending: options.cancelPending,
|
|
10
|
+
signal: options.signal,
|
|
11
|
+
};
|
|
12
|
+
if (options.signal?.aborted) {
|
|
13
|
+
this.cancelExecution(execution, "Cursor pi bridge tool execution was already aborted");
|
|
14
|
+
this.abortExecution(execution);
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
execution.onAbort = () => {
|
|
18
|
+
this.cancelExecution(execution, "Cursor pi bridge tool execution was aborted");
|
|
19
|
+
this.abortExecution(execution);
|
|
20
|
+
this.finish(toolCallId);
|
|
21
|
+
};
|
|
22
|
+
execution.signal?.addEventListener("abort", execution.onAbort, { once: true });
|
|
23
|
+
this.activeExecutions.set(toolCallId, execution);
|
|
24
|
+
this.installProcessSignalHandlers();
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
finish(toolCallId) {
|
|
28
|
+
const execution = this.activeExecutions.get(toolCallId);
|
|
29
|
+
if (!execution)
|
|
30
|
+
return;
|
|
31
|
+
if (execution.onAbort)
|
|
32
|
+
execution.signal?.removeEventListener("abort", execution.onAbort);
|
|
33
|
+
this.activeExecutions.delete(toolCallId);
|
|
34
|
+
this.uninstallProcessSignalHandlersIfIdle();
|
|
35
|
+
}
|
|
36
|
+
finishAll() {
|
|
37
|
+
for (const toolCallId of [...this.activeExecutions.keys()])
|
|
38
|
+
this.finish(toolCallId);
|
|
39
|
+
}
|
|
40
|
+
abort(toolCallId, reason) {
|
|
41
|
+
const execution = this.activeExecutions.get(toolCallId);
|
|
42
|
+
if (!execution)
|
|
43
|
+
return false;
|
|
44
|
+
this.cancelExecution(execution, reason);
|
|
45
|
+
this.abortExecution(execution);
|
|
46
|
+
this.finish(toolCallId);
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
abortAll(reason) {
|
|
50
|
+
for (const execution of [...this.activeExecutions.values()]) {
|
|
51
|
+
this.abort(execution.toolCallId, reason);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
getActiveCount() {
|
|
55
|
+
return this.activeExecutions.size;
|
|
56
|
+
}
|
|
57
|
+
emitProcessAbortSignalForTests(signal) {
|
|
58
|
+
this.abortActiveExecutions(signal, { preserveProcessSignalBehavior: true });
|
|
59
|
+
}
|
|
60
|
+
handleSigint = () => {
|
|
61
|
+
this.abortActiveExecutions("SIGINT");
|
|
62
|
+
};
|
|
63
|
+
handleSigterm = () => {
|
|
64
|
+
this.abortActiveExecutions("SIGTERM");
|
|
65
|
+
};
|
|
66
|
+
installProcessSignalHandlers() {
|
|
67
|
+
if (this.processSignalHandlersInstalled)
|
|
68
|
+
return;
|
|
69
|
+
this.processSignalHandlersInstalled = true;
|
|
70
|
+
process.on("SIGINT", this.handleSigint);
|
|
71
|
+
process.on("SIGTERM", this.handleSigterm);
|
|
72
|
+
}
|
|
73
|
+
uninstallProcessSignalHandlersIfIdle() {
|
|
74
|
+
if (!this.processSignalHandlersInstalled || this.activeExecutions.size > 0)
|
|
75
|
+
return;
|
|
76
|
+
this.processSignalHandlersInstalled = false;
|
|
77
|
+
process.off("SIGINT", this.handleSigint);
|
|
78
|
+
process.off("SIGTERM", this.handleSigterm);
|
|
79
|
+
}
|
|
80
|
+
abortActiveExecutions(signal, options = {}) {
|
|
81
|
+
if (this.activeExecutions.size === 0)
|
|
82
|
+
return;
|
|
83
|
+
const shouldRestoreDefaultSignalBehavior = options.preserveProcessSignalBehavior !== true && !this.hasExternalProcessSignalListeners(signal);
|
|
84
|
+
this.abortAll(`Cursor pi bridge tool execution interrupted by ${signal}`);
|
|
85
|
+
if (shouldRestoreDefaultSignalBehavior)
|
|
86
|
+
this.restoreDefaultProcessSignalBehavior(signal);
|
|
87
|
+
}
|
|
88
|
+
cancelExecution(execution, reason) {
|
|
89
|
+
try {
|
|
90
|
+
execution.cancelPending(reason);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
// Cancellation is best-effort during process abort/shutdown cleanup; keep aborting siblings.
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
abortExecution(execution) {
|
|
97
|
+
try {
|
|
98
|
+
Promise.resolve(execution.abort()).catch(() => undefined);
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
// Abort is best-effort during process abort/shutdown cleanup; keep aborting siblings.
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
hasExternalProcessSignalListeners(signal) {
|
|
105
|
+
const ownHandler = signal === "SIGINT" ? this.handleSigint : this.handleSigterm;
|
|
106
|
+
return process.listeners(signal).some((listener) => listener !== ownHandler);
|
|
107
|
+
}
|
|
108
|
+
restoreDefaultProcessSignalBehavior(signal) {
|
|
109
|
+
setImmediate(() => {
|
|
110
|
+
process.kill(process.pid, signal);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
export const bridgeToolExecutionAbortTracker = new CursorPiToolBridgeToolExecutionAbortTracker();
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export const MCP_SERVER_NAME = "pi_tools";
|
|
2
|
+
export const MCP_ENDPOINT_ROOT = "/cursor-pi-tool-bridge";
|
|
3
|
+
const CURSOR_PI_BRIDGE_TOOL_CALL_ID_PATTERN = /^cursor-pi-bridge-run-[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}-tool-\d+$/i;
|
|
4
|
+
export function isCursorPiBridgeToolCallId(toolCallId) {
|
|
5
|
+
return CURSOR_PI_BRIDGE_TOOL_CALL_ID_PATTERN.test(toolCallId);
|
|
6
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { appendFileSync } from "node:fs";
|
|
2
|
+
import { stableNameHash } from "./cursor-pi-tool-bridge-mcp.js";
|
|
3
|
+
import { parseEnvBoolean } from "./cursor-env-boolean.js";
|
|
4
|
+
export const CURSOR_PI_TOOL_BRIDGE_DEBUG_ENV = "PI_CURSOR_PI_TOOL_BRIDGE_DEBUG";
|
|
5
|
+
export const CURSOR_PI_TOOL_BRIDGE_DEBUG_FILE_ENV = "PI_CURSOR_PI_TOOL_BRIDGE_DEBUG_FILE";
|
|
6
|
+
export const CURSOR_PI_TOOL_BRIDGE_DIAGNOSTIC_PREFIX = "[pi-cursor-sdk:bridge]";
|
|
7
|
+
export function resolveCursorPiToolBridgeDebugEnabled(env = process.env) {
|
|
8
|
+
return parseEnvBoolean(env[CURSOR_PI_TOOL_BRIDGE_DEBUG_ENV], false);
|
|
9
|
+
}
|
|
10
|
+
function createCursorMcpCallDiagnosticId(cursorMcpCallId) {
|
|
11
|
+
return cursorMcpCallId ? `cursor-mcp-call-${stableNameHash(cursorMcpCallId)}` : undefined;
|
|
12
|
+
}
|
|
13
|
+
function assertNeverDiagnosticEvent(_event) {
|
|
14
|
+
throw new Error("Unhandled Cursor pi tool bridge diagnostic event");
|
|
15
|
+
}
|
|
16
|
+
export function serializeCursorPiToolBridgeDiagnostic(event) {
|
|
17
|
+
switch (event.event) {
|
|
18
|
+
case "run_created":
|
|
19
|
+
return {
|
|
20
|
+
event: event.event,
|
|
21
|
+
runId: event.runId,
|
|
22
|
+
enabled: event.enabled,
|
|
23
|
+
exposedToolCount: event.exposedToolCount,
|
|
24
|
+
pendingCount: event.pendingCount,
|
|
25
|
+
};
|
|
26
|
+
case "run_skipped":
|
|
27
|
+
return {
|
|
28
|
+
event: event.event,
|
|
29
|
+
runId: event.runId,
|
|
30
|
+
enabled: event.enabled,
|
|
31
|
+
exposedToolCount: event.exposedToolCount,
|
|
32
|
+
pendingCount: event.pendingCount,
|
|
33
|
+
reason: event.reason,
|
|
34
|
+
};
|
|
35
|
+
case "tools_exposed":
|
|
36
|
+
return {
|
|
37
|
+
event: event.event,
|
|
38
|
+
runId: event.runId,
|
|
39
|
+
enabled: event.enabled,
|
|
40
|
+
exposedToolCount: event.exposedToolCount,
|
|
41
|
+
pendingCount: event.pendingCount,
|
|
42
|
+
pairs: event.pairs.map((pair) => ({ piToolName: pair.piToolName, mcpToolName: pair.mcpToolName })),
|
|
43
|
+
};
|
|
44
|
+
case "run_cancelled":
|
|
45
|
+
return {
|
|
46
|
+
event: event.event,
|
|
47
|
+
runId: event.runId,
|
|
48
|
+
enabled: event.enabled,
|
|
49
|
+
exposedToolCount: event.exposedToolCount,
|
|
50
|
+
pendingCount: event.pendingCount,
|
|
51
|
+
queuedCount: event.queuedCount,
|
|
52
|
+
cancelledRequestCount: event.cancelledRequestCount,
|
|
53
|
+
};
|
|
54
|
+
case "run_disposed":
|
|
55
|
+
return {
|
|
56
|
+
event: event.event,
|
|
57
|
+
runId: event.runId,
|
|
58
|
+
enabled: event.enabled,
|
|
59
|
+
exposedToolCount: event.exposedToolCount,
|
|
60
|
+
pendingCount: event.pendingCount,
|
|
61
|
+
};
|
|
62
|
+
case "request_queued":
|
|
63
|
+
return {
|
|
64
|
+
event: event.event,
|
|
65
|
+
runId: event.runId,
|
|
66
|
+
bridgeCallId: event.bridgeCallId,
|
|
67
|
+
cursorMcpCallId: createCursorMcpCallDiagnosticId(event.cursorMcpCallId),
|
|
68
|
+
piToolCallId: event.piToolCallId,
|
|
69
|
+
mcpToolName: event.mcpToolName,
|
|
70
|
+
piToolName: event.piToolName,
|
|
71
|
+
pendingCount: event.pendingCount,
|
|
72
|
+
};
|
|
73
|
+
case "request_resolved":
|
|
74
|
+
return {
|
|
75
|
+
event: event.event,
|
|
76
|
+
runId: event.runId,
|
|
77
|
+
bridgeCallId: event.bridgeCallId,
|
|
78
|
+
cursorMcpCallId: createCursorMcpCallDiagnosticId(event.cursorMcpCallId),
|
|
79
|
+
piToolCallId: event.piToolCallId,
|
|
80
|
+
mcpToolName: event.mcpToolName,
|
|
81
|
+
piToolName: event.piToolName,
|
|
82
|
+
pendingCount: event.pendingCount,
|
|
83
|
+
isError: event.isError,
|
|
84
|
+
};
|
|
85
|
+
case "request_rejected":
|
|
86
|
+
return {
|
|
87
|
+
event: event.event,
|
|
88
|
+
runId: event.runId,
|
|
89
|
+
bridgeCallId: event.bridgeCallId,
|
|
90
|
+
cursorMcpCallId: createCursorMcpCallDiagnosticId(event.cursorMcpCallId),
|
|
91
|
+
piToolCallId: event.piToolCallId,
|
|
92
|
+
mcpToolName: event.mcpToolName,
|
|
93
|
+
piToolName: event.piToolName,
|
|
94
|
+
pendingCount: event.pendingCount,
|
|
95
|
+
rejectionKind: event.rejectionKind,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
return assertNeverDiagnosticEvent(event);
|
|
99
|
+
}
|
|
100
|
+
export function writeCursorPiToolBridgeDiagnostic(env, event, debugRecorder) {
|
|
101
|
+
try {
|
|
102
|
+
debugRecorder?.recordBridgeDiagnostic(event);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
// Diagnostics must never affect bridge execution.
|
|
106
|
+
}
|
|
107
|
+
const serialized = serializeCursorPiToolBridgeDiagnostic(event);
|
|
108
|
+
const debugFile = env[CURSOR_PI_TOOL_BRIDGE_DEBUG_FILE_ENV];
|
|
109
|
+
if (debugFile) {
|
|
110
|
+
try {
|
|
111
|
+
appendFileSync(debugFile, `${JSON.stringify(serialized)}\n`);
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
// Diagnostics must never affect bridge execution.
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (!resolveCursorPiToolBridgeDebugEnabled(env))
|
|
118
|
+
return;
|
|
119
|
+
try {
|
|
120
|
+
process.stderr.write(`${CURSOR_PI_TOOL_BRIDGE_DIAGNOSTIC_PREFIX} ${JSON.stringify(serialized)}\n`);
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
// Diagnostics must never affect bridge execution.
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { parseEnvBoolean } from "./cursor-env-boolean.js";
|
|
2
|
+
import { resolveCursorMcpToolTimeoutMs } from "./cursor-mcp-timeout-override.js";
|
|
3
|
+
export const CURSOR_PI_TOOL_BRIDGE_ENV = "PI_CURSOR_PI_TOOL_BRIDGE";
|
|
4
|
+
export const CURSOR_PI_TOOL_BRIDGE_BUILTINS_ENV = "PI_CURSOR_EXPOSE_BUILTIN_TOOLS";
|
|
5
|
+
export const CURSOR_PI_TOOL_BRIDGE_CALL_TIMEOUT_MS_ENV = "PI_CURSOR_PI_BRIDGE_CALL_TIMEOUT_MS";
|
|
6
|
+
export function resolveCursorPiToolBridgeEnabled(env = process.env) {
|
|
7
|
+
return parseEnvBoolean(env[CURSOR_PI_TOOL_BRIDGE_ENV], true);
|
|
8
|
+
}
|
|
9
|
+
export function resolveCursorPiToolBridgeBuiltinsEnabled(env = process.env) {
|
|
10
|
+
return parseEnvBoolean(env[CURSOR_PI_TOOL_BRIDGE_BUILTINS_ENV], false);
|
|
11
|
+
}
|
|
12
|
+
export function resolveCursorPiToolBridgeCallTimeoutMs(env = process.env) {
|
|
13
|
+
const mcpToolTimeoutMs = resolveCursorMcpToolTimeoutMs(env);
|
|
14
|
+
const parsed = Number(env[CURSOR_PI_TOOL_BRIDGE_CALL_TIMEOUT_MS_ENV]?.trim());
|
|
15
|
+
if (!Number.isFinite(parsed) || parsed <= 0)
|
|
16
|
+
return mcpToolTimeoutMs;
|
|
17
|
+
return Math.min(Math.max(Math.trunc(parsed), 1), mcpToolTimeoutMs);
|
|
18
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { buildCursorPiBridgeMcpToolDescription, CURSOR_PI_BRIDGE_MCP_TOOL_PREFIX } from "./cursor-bridge-contract.js";
|
|
3
|
+
import { asRecord, stringifyUnknown } from "./cursor-record-utils.js";
|
|
4
|
+
export function normalizeMcpInputSchema(schema) {
|
|
5
|
+
const record = asRecord(schema);
|
|
6
|
+
if (record?.type === "object")
|
|
7
|
+
return record;
|
|
8
|
+
return { type: "object", properties: {} };
|
|
9
|
+
}
|
|
10
|
+
export function normalizeMcpArgs(args) {
|
|
11
|
+
const record = asRecord(args);
|
|
12
|
+
return record ? { ...record } : {};
|
|
13
|
+
}
|
|
14
|
+
export function waitForProtocolFlush() {
|
|
15
|
+
return new Promise((resolve) => setTimeout(resolve, 0));
|
|
16
|
+
}
|
|
17
|
+
function sanitizeMcpToolNameStem(toolName) {
|
|
18
|
+
const stem = toolName
|
|
19
|
+
.trim()
|
|
20
|
+
.replace(/[^A-Za-z0-9_-]+/g, "_")
|
|
21
|
+
.replace(/^_+|_+$/g, "");
|
|
22
|
+
return stem || "tool";
|
|
23
|
+
}
|
|
24
|
+
export function stableNameHash(value) {
|
|
25
|
+
return createHash("sha256").update(value).digest("hex").slice(0, 8);
|
|
26
|
+
}
|
|
27
|
+
export function createMcpToolName(piToolName, usedMcpToolNames) {
|
|
28
|
+
const baseName = `${CURSOR_PI_BRIDGE_MCP_TOOL_PREFIX}${sanitizeMcpToolNameStem(piToolName)}`;
|
|
29
|
+
if (!usedMcpToolNames.has(baseName)) {
|
|
30
|
+
usedMcpToolNames.add(baseName);
|
|
31
|
+
return baseName;
|
|
32
|
+
}
|
|
33
|
+
const hashedName = `${baseName}__${stableNameHash(piToolName)}`;
|
|
34
|
+
if (!usedMcpToolNames.has(hashedName)) {
|
|
35
|
+
usedMcpToolNames.add(hashedName);
|
|
36
|
+
return hashedName;
|
|
37
|
+
}
|
|
38
|
+
let counter = 2;
|
|
39
|
+
let candidate = `${hashedName}_${counter}`;
|
|
40
|
+
while (usedMcpToolNames.has(candidate)) {
|
|
41
|
+
counter += 1;
|
|
42
|
+
candidate = `${hashedName}_${counter}`;
|
|
43
|
+
}
|
|
44
|
+
usedMcpToolNames.add(candidate);
|
|
45
|
+
return candidate;
|
|
46
|
+
}
|
|
47
|
+
export function snapshotToolToMcpTool(tool) {
|
|
48
|
+
return {
|
|
49
|
+
name: tool.mcpToolName,
|
|
50
|
+
description: buildCursorPiBridgeMcpToolDescription({
|
|
51
|
+
piToolName: tool.piToolName,
|
|
52
|
+
mcpToolName: tool.mcpToolName,
|
|
53
|
+
piToolDescription: tool.description,
|
|
54
|
+
piToolPromptGuidelines: tool.promptGuidelines,
|
|
55
|
+
}),
|
|
56
|
+
inputSchema: tool.inputSchema,
|
|
57
|
+
_meta: { piToolName: tool.piToolName },
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export function convertPiContentToMcpContent(content) {
|
|
61
|
+
if (!Array.isArray(content)) {
|
|
62
|
+
return [{ type: "text", text: stringifyUnknown(content) }];
|
|
63
|
+
}
|
|
64
|
+
const mcpContent = [];
|
|
65
|
+
for (const block of content) {
|
|
66
|
+
const record = asRecord(block);
|
|
67
|
+
if (record?.type === "text" && typeof record.text === "string") {
|
|
68
|
+
mcpContent.push({ type: "text", text: record.text });
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (record?.type === "image" && typeof record.data === "string" && typeof record.mimeType === "string") {
|
|
72
|
+
mcpContent.push({ type: "image", data: record.data, mimeType: record.mimeType });
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
mcpContent.push({ type: "text", text: stringifyUnknown(block) });
|
|
76
|
+
}
|
|
77
|
+
return mcpContent.length > 0 ? mcpContent : [{ type: "text", text: "" }];
|
|
78
|
+
}
|
|
79
|
+
export function asToolResultMessage(value) {
|
|
80
|
+
return value.role === "toolResult" ? value : undefined;
|
|
81
|
+
}
|
|
82
|
+
export function containsKnownMcpToolName(value, knownMcpToolNames, depth = 0) {
|
|
83
|
+
if (depth > 4)
|
|
84
|
+
return false;
|
|
85
|
+
if (Array.isArray(value))
|
|
86
|
+
return value.some((entry) => containsKnownMcpToolName(entry, knownMcpToolNames, depth + 1));
|
|
87
|
+
const record = asRecord(value);
|
|
88
|
+
if (!record)
|
|
89
|
+
return false;
|
|
90
|
+
for (const field of ["tool", "toolName", "name", "mcpToolName", "serverToolName"]) {
|
|
91
|
+
const fieldValue = record[field];
|
|
92
|
+
if (typeof fieldValue === "string" && knownMcpToolNames.has(fieldValue))
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
for (const nestedField of ["args", "arguments", "input"]) {
|
|
96
|
+
if (containsKnownMcpToolName(record[nestedField], knownMcpToolNames, depth + 1))
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
return false;
|
|
100
|
+
}
|