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
|
@@ -4,6 +4,7 @@ import { Cursor } from "@cursor/sdk";
|
|
|
4
4
|
import { defaultApiKeyFromEnv, parseArgv } from "./lib/cursor-cli-args.mjs";
|
|
5
5
|
import { scrubSensitiveText } from "../shared/cursor-sensitive-text.mjs";
|
|
6
6
|
import { createScriptFail } from "./lib/cursor-script-fail.mjs";
|
|
7
|
+
import { normalizeCursorContextWindowEntries } from "../shared/cursor-model-selection-identities.mjs";
|
|
7
8
|
|
|
8
9
|
const FALLBACK_MODELS_PATH = "src/cursor-fallback-models.generated.ts";
|
|
9
10
|
const CONTEXT_WINDOWS_PATH = "src/bundled-context-windows.ts";
|
|
@@ -40,7 +41,9 @@ Notes:
|
|
|
40
41
|
- This script prints model IDs/counts only; it never prints API keys.
|
|
41
42
|
- Cursor.models.list() is the source of truth for fallback catalog metadata.
|
|
42
43
|
- Checkpoint-derived context windows are optional input because collecting them
|
|
43
|
-
requires successful local SDK runs; this script does not start agents
|
|
44
|
+
requires successful local SDK runs; this script does not start agents.
|
|
45
|
+
- Context-window keys are limited to current selectable model IDs. Redundant
|
|
46
|
+
:fast/:slow aliases that send the default parameters collapse to one key.`);
|
|
44
47
|
}
|
|
45
48
|
|
|
46
49
|
const fail = createScriptFail("refresh-cursor-snapshots");
|
|
@@ -156,9 +159,10 @@ function hasContextParameter(model) {
|
|
|
156
159
|
}
|
|
157
160
|
|
|
158
161
|
function formatContextWindows(models, checkpointWindows, fallbackContextWindow) {
|
|
159
|
-
const
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
+
const merged = normalizeCursorContextWindowEntries(models, parseExistingContextWindows(), "existing bundled context windows");
|
|
163
|
+
for (const [modelId, contextWindow] of normalizeCursorContextWindowEntries(models, checkpointWindows, "checkpoint context windows")) {
|
|
164
|
+
merged.set(modelId, contextWindow);
|
|
165
|
+
}
|
|
162
166
|
for (const model of models) {
|
|
163
167
|
if (!hasContextParameter(model) && !merged.has(model.id)) merged.set(model.id, fallbackContextWindow);
|
|
164
168
|
}
|
|
@@ -167,7 +171,7 @@ function formatContextWindows(models, checkpointWindows, fallbackContextWindow)
|
|
|
167
171
|
const date = new Date().toISOString().slice(0, 10);
|
|
168
172
|
const sorted = [...merged.entries()].sort(([a], [b]) => (a === "default" ? -1 : b === "default" ? 1 : a.localeCompare(b)));
|
|
169
173
|
const lines = sorted.map(([modelId, contextWindow]) => `\t${JSON.stringify(modelId)}: ${contextWindow},`);
|
|
170
|
-
return `// Generated from Cursor SDK checkpoint tokenDetails.maxTokens on ${date}.\n// Refresh with: npm run refresh:cursor-snapshots -- --write --context-windows ~/.pi/agent/cursor-sdk-context-windows.json\n//
|
|
174
|
+
return `// Generated from Cursor SDK checkpoint tokenDetails.maxTokens on ${date}.\n// Refresh with: npm run refresh:cursor-snapshots -- --write --context-windows ~/.pi/agent/cursor-sdk-context-windows.json\n// Keys are current selectable model IDs. Equivalent default :fast/:slow selections\n// collapse to one key; stale and ambiguous aliases are omitted. Values are observed\n// or conservative default/non-Max-mode limits and may override a catalog context\n// label when the completed SDK checkpoint reports a different effective limit.\nexport const BUNDLED_CONTEXT_WINDOWS = {\n${lines.join("\n")}\n} as const satisfies Record<string, number>;\n`;
|
|
171
175
|
}
|
|
172
176
|
|
|
173
177
|
const args = parseRefreshArgs(process.argv.slice(2));
|
|
@@ -184,11 +188,16 @@ if (!Array.isArray(rawModels) || rawModels.length === 0) fail("Cursor.models.lis
|
|
|
184
188
|
const models = rawModels.map(sanitizeModelItem).sort((a, b) => a.id.localeCompare(b.id));
|
|
185
189
|
const checkpointWindows = parseContextWindowsFile(args.contextWindowsPath);
|
|
186
190
|
const fallbackSource = formatFallbackModels(models, sdkVersion);
|
|
187
|
-
|
|
191
|
+
let contextWindowSource;
|
|
192
|
+
try {
|
|
193
|
+
contextWindowSource = args.contextWindowsPath ? formatContextWindows(models, checkpointWindows, args.fallbackContextWindow) : undefined;
|
|
194
|
+
} catch (error) {
|
|
195
|
+
fail(error instanceof Error ? error.message : String(error));
|
|
196
|
+
}
|
|
188
197
|
const existingContextWindowCount = parseExistingContextWindows().size;
|
|
189
198
|
|
|
190
199
|
console.log(`Fetched ${models.length} Cursor models with @cursor/sdk@${sdkVersion}.`);
|
|
191
|
-
console.log(`Context windows: ${checkpointWindows.size} checkpoint
|
|
200
|
+
console.log(`Context windows: ${checkpointWindows.size} checkpoint input(s), ${existingContextWindowCount} existing bundled entr${existingContextWindowCount === 1 ? "y" : "ies"}.`);
|
|
192
201
|
console.log(`First models: ${models.slice(0, 8).map((model) => model.id).join(", ")}${models.length > 8 ? ", ..." : ""}`);
|
|
193
202
|
|
|
194
203
|
if (args.check) {
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
} from "./lib/cursor-child-process.mjs";
|
|
17
17
|
import { apiKeySecretsFromProcess } from "./lib/cursor-cli-args.mjs";
|
|
18
18
|
import { buildCursorSmokeEnv, CURSOR_SDK_EVENT_DEBUG_ENV_NAMES } from "./lib/cursor-smoke-env.mjs";
|
|
19
|
+
import { ensureBuilt } from "./lib/ensure-built.mjs";
|
|
19
20
|
import { scrubSensitiveText } from "../shared/cursor-sensitive-text.mjs";
|
|
20
21
|
|
|
21
22
|
const root = fileURLToPath(new URL("..", import.meta.url));
|
|
@@ -170,7 +171,7 @@ function buildPiRpcEnv(baseEnv = process.env, nodePath = process.execPath) {
|
|
|
170
171
|
}
|
|
171
172
|
|
|
172
173
|
async function runPiRpcSmoke(sessionDir, piBin) {
|
|
173
|
-
const args = ["--approve", "-e", root, "--cursor-no-fast", "--model", "cursor/
|
|
174
|
+
const args = ["--approve", "-e", root, "--cursor-no-fast", "--model", "cursor/grok-4.6", "--mode", "rpc", "--session-dir", sessionDir];
|
|
174
175
|
const env = buildPiRpcEnv();
|
|
175
176
|
|
|
176
177
|
const child = spawn(piBin, args, {
|
|
@@ -263,7 +264,7 @@ async function runSelfTest() {
|
|
|
263
264
|
const envCapture = join(tempDir, "fake-pi.env");
|
|
264
265
|
writeFileSync(
|
|
265
266
|
fakePi,
|
|
266
|
-
`#!/usr/bin/env node\
|
|
267
|
+
`#!/usr/bin/env node\nimport { writeFileSync } from "node:fs";\nwriteFileSync(${JSON.stringify(envCapture)}, Object.entries(process.env).map(([key, value]) => key + "=" + (value ?? "")).join("\\n") + "\\n", "utf8");\n`,
|
|
267
268
|
"utf8",
|
|
268
269
|
);
|
|
269
270
|
writeFileSync(fakeNode, `#!/bin/sh\necho fake-node-used > ${JSON.stringify(fakeNodeMarker)}\nexit 99\n`, "utf8");
|
|
@@ -332,6 +333,7 @@ async function main() {
|
|
|
332
333
|
printHelp();
|
|
333
334
|
return;
|
|
334
335
|
}
|
|
336
|
+
ensureBuilt();
|
|
335
337
|
if (process.argv.includes("--self-test")) {
|
|
336
338
|
await runSelfTest();
|
|
337
339
|
return;
|
|
@@ -243,7 +243,7 @@ exec %s
|
|
|
243
243
|
"$TMUX_BIN" capture-pane -pt "$session" >"$capture" 2>/dev/null || true
|
|
244
244
|
missing=""
|
|
245
245
|
"$RG_BIN" -q "SUM=42" "$capture" || missing="${missing} SUM=42"
|
|
246
|
-
"$RG_BIN" -q "\\(cursor\\)
|
|
246
|
+
"$RG_BIN" -q "\\(cursor\\) grok-4\\.6" "$capture" || missing="${missing} footer (cursor) grok-4.6"
|
|
247
247
|
if [[ -z "$missing" ]]; then
|
|
248
248
|
"$TMUX_BIN" kill-session -t "$session" 2>/dev/null || true
|
|
249
249
|
log "$name PASS"
|
|
@@ -311,14 +311,14 @@ printf '\''%%s\n'\'' "$code" > %q
|
|
|
311
311
|
model_listed() {
|
|
312
312
|
local file="$1"
|
|
313
313
|
if [[ -n "${RG_BIN:-}" ]]; then
|
|
314
|
-
"$RG_BIN" -q "
|
|
314
|
+
"$RG_BIN" -q "grok-4\.6" "$file"
|
|
315
315
|
else
|
|
316
|
-
grep -q "
|
|
316
|
+
grep -q "grok-4\.6" "$file"
|
|
317
317
|
fi
|
|
318
318
|
}
|
|
319
319
|
|
|
320
320
|
# Capture full catalog then search. Never pipe list-models into rg -q under pipefail.
|
|
321
|
-
|
|
321
|
+
capture_and_require_default_model() {
|
|
322
322
|
local list_cmd=("$@")
|
|
323
323
|
local models_out="$SMOKE_DIR/prereq.models.txt"
|
|
324
324
|
local models_err="$SMOKE_DIR/prereq.stderr.txt"
|
|
@@ -326,7 +326,7 @@ capture_and_require_composer_model() {
|
|
|
326
326
|
fail "pi --list-models cursor failed"
|
|
327
327
|
fi
|
|
328
328
|
if ! model_listed "$models_out" && ! model_listed "$models_err"; then
|
|
329
|
-
fail "cursor/
|
|
329
|
+
fail "cursor/grok-4.6 not listed"
|
|
330
330
|
fi
|
|
331
331
|
}
|
|
332
332
|
|
|
@@ -343,7 +343,7 @@ run_self_test() {
|
|
|
343
343
|
env_capture="$temp_dir/fake-pi.env"
|
|
344
344
|
cat >"$fake_pi" <<EOF_SELFTEST_PI
|
|
345
345
|
#!/usr/bin/env node
|
|
346
|
-
|
|
346
|
+
import { writeFileSync } from "node:fs";
|
|
347
347
|
writeFileSync("$env_capture", Object.entries(process.env).map(([key, value]) => key + "=" + (value ?? "")).join("\\n") + "\\n", "utf8");
|
|
348
348
|
EOF_SELFTEST_PI
|
|
349
349
|
cat >"$fake_node" <<EOF_SELFTEST_NODE
|
|
@@ -383,7 +383,7 @@ EOF_SELFTEST_NODE
|
|
|
383
383
|
if grep -q '^PI_CURSOR_SETTING_SOURCES=' "$env_capture"; then
|
|
384
384
|
fail "self-test failed: default-settings env did not unset PI_CURSOR_SETTING_SOURCES"
|
|
385
385
|
fi
|
|
386
|
-
# Large-catalog prereq: exercise the same
|
|
386
|
+
# Large-catalog prereq: exercise the same capture_and_require_default_model helper.
|
|
387
387
|
fake_list_pi="$bin_dir/pi-list-models"
|
|
388
388
|
cat >"$fake_list_pi" <<'EOF_FAKE_LIST'
|
|
389
389
|
#!/usr/bin/env bash
|
|
@@ -392,11 +392,11 @@ while [[ $i -lt 20000 ]]; do
|
|
|
392
392
|
printf 'cursor/model-%s\n' "$i"
|
|
393
393
|
i=$((i + 1))
|
|
394
394
|
done
|
|
395
|
-
printf 'cursor/
|
|
395
|
+
printf 'cursor/grok-4.6\n'
|
|
396
396
|
exit 0
|
|
397
397
|
EOF_FAKE_LIST
|
|
398
398
|
chmod +x "$fake_list_pi"
|
|
399
|
-
SMOKE_DIR="$temp_dir"
|
|
399
|
+
SMOKE_DIR="$temp_dir" capture_and_require_default_model "$fake_list_pi"
|
|
400
400
|
if [[ "$(wc -l <"$temp_dir/prereq.models.txt" | tr -d ' ')" -lt 20000 ]]; then
|
|
401
401
|
fail "self-test failed: large catalog was truncated before search"
|
|
402
402
|
fi
|
|
@@ -428,7 +428,7 @@ fi
|
|
|
428
428
|
PI_BASE=(
|
|
429
429
|
"$PI_BIN" --approve -e "$ROOT"
|
|
430
430
|
--cursor-no-fast
|
|
431
|
-
--model cursor/
|
|
431
|
+
--model cursor/grok-4.6
|
|
432
432
|
)
|
|
433
433
|
|
|
434
434
|
if [[ -z "${CURSOR_API_KEY:-}" ]]; then
|
|
@@ -448,7 +448,7 @@ log "partial live smoke: prereq, basic, default-settings, noninteractive-math, t
|
|
|
448
448
|
"${BASE_ENV[@]}" "$PI_BIN" --version | tee "$SMOKE_DIR/prereq.pi-version.txt"
|
|
449
449
|
"${BASE_ENV[@]}" "$NPM_BIN" --prefix "$ROOT" ls @cursor/sdk @earendil-works/pi-coding-agent @earendil-works/pi-ai @earendil-works/pi-tui | tee "$SMOKE_DIR/prereq.npm-ls.txt"
|
|
450
450
|
|
|
451
|
-
|
|
451
|
+
capture_and_require_default_model "${NONE_ENV[@]}" "${PI_BASE[@]}" --list-models cursor
|
|
452
452
|
log "prereq PASS"
|
|
453
453
|
|
|
454
454
|
run_direct basic 600 retry-empty-output "PI_CURSOR_SMOKE_OK" "PI_CURSOR_SMOKE_OK" \
|
|
@@ -35,7 +35,7 @@ export function runVisualSmokeSelfTest(deps) {
|
|
|
35
35
|
const envCapture = join(tempDir, "fake-pi.env");
|
|
36
36
|
writeFileSync(
|
|
37
37
|
fakePi,
|
|
38
|
-
`#!/usr/bin/env node\
|
|
38
|
+
`#!/usr/bin/env node\nimport { writeFileSync } from "node:fs";\nwriteFileSync(${JSON.stringify(envCapture)}, Object.entries(process.env).map(([key, value]) => key + "=" + (value ?? "")).join("\\n") + "\\n", "utf8");\n`,
|
|
39
39
|
"utf8",
|
|
40
40
|
);
|
|
41
41
|
writeFileSync(fakeNode, `#!/bin/sh\necho fake-node-used > ${shellQuote(fakeNodeMarker)}\nexit 99\n`, "utf8");
|
|
@@ -89,6 +89,9 @@ export function runVisualSmokeSelfTest(deps) {
|
|
|
89
89
|
assertSelfTest(defaults.get("PI_CURSOR_SETTING_SOURCES") === "none", "setting sources must default to none");
|
|
90
90
|
assertSelfTest(defaults.get("PI_CURSOR_PI_TOOL_BRIDGE") === "0", "bridge must default off");
|
|
91
91
|
assertSelfTest(defaults.get("PI_CURSOR_EXPOSE_BUILTIN_TOOLS") === "0", "built-in exposure must default off");
|
|
92
|
+
assertSelfTest(defaults.get("PI_CODING_AGENT_DIR") === join(tempDir, "pi-agent"), "agent dir must be isolated under out-dir");
|
|
93
|
+
assertSelfTest(defaults.get("PI_OFFLINE") === "1", "startup network operations must be off");
|
|
94
|
+
assertSelfTest(defaults.get("PI_SKIP_VERSION_CHECK") === "1", "pi.dev version check must be off");
|
|
92
95
|
for (const name of DEBUG_ENV_NAMES) {
|
|
93
96
|
assertSelfTest(plan.clearEnvNames.includes(name), `${name} must be cleared by default`);
|
|
94
97
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { spawnSync } from "node:child_process";
|
|
3
|
-
import { accessSync, constants, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { accessSync, chmodSync, constants, copyFileSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { homedir } from "node:os";
|
|
4
5
|
import { delimiter, dirname, join, resolve } from "node:path";
|
|
5
6
|
import { fileURLToPath } from "node:url";
|
|
6
7
|
import { commonBooleanFlag, commonRepeatStringFlag, parseArgv } from "./lib/cursor-cli-args.mjs";
|
|
@@ -15,7 +16,7 @@ const DEFAULT_HEIGHT = 45;
|
|
|
15
16
|
const DEFAULT_WAIT_MS = 60_000;
|
|
16
17
|
const DEFAULT_STARTUP_MS = 5_000;
|
|
17
18
|
const DEFAULT_HISTORY_LINES = 3_000;
|
|
18
|
-
const DEFAULT_MODEL = "cursor/
|
|
19
|
+
const DEFAULT_MODEL = "cursor/grok-4.6";
|
|
19
20
|
const DEFAULT_MODE = "plan";
|
|
20
21
|
const DEFAULT_SETTING_SOURCES = "none";
|
|
21
22
|
const DEBUG_ENV_NAMES = CURSOR_SDK_EVENT_DEBUG_ENV_NAMES;
|
|
@@ -44,7 +45,7 @@ Common options:
|
|
|
44
45
|
--model MODEL Cursor model. Default: ${DEFAULT_MODEL}.
|
|
45
46
|
--mode agent|plan Cursor SDK mode. Default: ${DEFAULT_MODE}.
|
|
46
47
|
--session-dir PATH pi session directory. Default: <out-dir>/<label>.session.
|
|
47
|
-
--session-id ID pi session id. Default:
|
|
48
|
+
--session-id ID pi session id; pass to resume a prior capture session. Default: pi-assigned, so fresh captures avoid the new-session warning line.
|
|
48
49
|
--width N PTY columns. Default: ${DEFAULT_WIDTH}.
|
|
49
50
|
--height N PTY rows. Default: ${DEFAULT_HEIGHT}.
|
|
50
51
|
--history-lines N tmux capture history lines. Default: ${DEFAULT_HISTORY_LINES}.
|
|
@@ -63,7 +64,11 @@ Native replay isolation defaults:
|
|
|
63
64
|
PI_CURSOR_SETTING_SOURCES=none
|
|
64
65
|
PI_CURSOR_PI_TOOL_BRIDGE=0
|
|
65
66
|
PI_CURSOR_EXPOSE_BUILTIN_TOOLS=0
|
|
67
|
+
PI_CODING_AGENT_DIR=<out-dir>/pi-agent (seeded auth.json + quietStartup; host extensions stay out)
|
|
68
|
+
PI_OFFLINE=1
|
|
69
|
+
PI_SKIP_VERSION_CHECK=1
|
|
66
70
|
TERM=xterm-256color
|
|
71
|
+
tmux starts in --cwd with a non-login shell so a stale tmux-server cwd cannot print getcwd errors
|
|
67
72
|
Debug artifact env is cleared before each run; --event-debug sets a deterministic debug dir.
|
|
68
73
|
|
|
69
74
|
Artifacts written:
|
|
@@ -194,10 +199,26 @@ function parseArgs(argv) {
|
|
|
194
199
|
options.safeLabel = sanitizeLabel(options.label);
|
|
195
200
|
options.outDir ??= resolve(`/tmp/pi-cursor-sdk-visual-smoke-${timestamp()}`);
|
|
196
201
|
options.sessionDir ??= resolve(options.outDir, `${options.safeLabel}.session`);
|
|
197
|
-
options.
|
|
202
|
+
options.agentDir ??= resolve(options.outDir, "pi-agent");
|
|
198
203
|
return options;
|
|
199
204
|
}
|
|
200
205
|
|
|
206
|
+
function seedVisualAgentDir(agentDir) {
|
|
207
|
+
mkdirSync(agentDir, { recursive: true });
|
|
208
|
+
const srcAuth = join(homedir(), ".pi", "agent", "auth.json");
|
|
209
|
+
const destAuth = join(agentDir, "auth.json");
|
|
210
|
+
try {
|
|
211
|
+
copyFileSync(srcAuth, destAuth);
|
|
212
|
+
chmodSync(destAuth, 0o600);
|
|
213
|
+
} catch {
|
|
214
|
+
// CURSOR_API_KEY remains the fallback when host auth.json is absent.
|
|
215
|
+
}
|
|
216
|
+
writeFileSync(
|
|
217
|
+
join(agentDir, "settings.json"),
|
|
218
|
+
`${JSON.stringify({ quietStartup: true, enableInstallTelemetry: false })}\n`,
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
|
|
201
222
|
function sanitizeLabel(label) {
|
|
202
223
|
const safe = label.trim().replace(/[^A-Za-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
203
224
|
return safe || "visual-smoke";
|
|
@@ -359,7 +380,13 @@ function buildLaunchPlan(options, commands, shell) {
|
|
|
359
380
|
eventDebugDir: options.eventDebug ? resolve(options.outDir, `${options.safeLabel ?? "visual-smoke"}.cursor-sdk-events`) : undefined,
|
|
360
381
|
});
|
|
361
382
|
const sealedPath = commands.sealedPath ?? smokeEnvPlan.sealedPath;
|
|
362
|
-
const
|
|
383
|
+
const agentDir = options.agentDir ?? resolve(options.outDir, "pi-agent");
|
|
384
|
+
const envAssignments = [
|
|
385
|
+
...smokeEnvPlan.envEntries,
|
|
386
|
+
["PI_CODING_AGENT_DIR", agentDir],
|
|
387
|
+
["PI_OFFLINE", "1"],
|
|
388
|
+
["PI_SKIP_VERSION_CHECK", "1"],
|
|
389
|
+
];
|
|
363
390
|
const clearEnvNames = smokeEnvPlan.clearEnvNames;
|
|
364
391
|
const command = [
|
|
365
392
|
...envAssignments.map(([name, value]) => `${name}=${shellQuote(value)}`),
|
|
@@ -370,7 +397,7 @@ function buildLaunchPlan(options, commands, shell) {
|
|
|
370
397
|
"--cursor-no-fast",
|
|
371
398
|
"--cursor-mode", shellQuote(options.mode),
|
|
372
399
|
"--session-dir", shellQuote(options.sessionDir),
|
|
373
|
-
"--session-id", shellQuote(options.sessionId),
|
|
400
|
+
...(options.sessionId ? ["--session-id", shellQuote(options.sessionId)] : []),
|
|
374
401
|
"--model", shellQuote(options.model),
|
|
375
402
|
].join(" ");
|
|
376
403
|
const clearLines = clearEnvNames.map((name) => `unset ${name}`).join("\n");
|
|
@@ -397,6 +424,8 @@ function runVisualSmoke(options) {
|
|
|
397
424
|
|
|
398
425
|
mkdirSync(options.outDir, { recursive: true });
|
|
399
426
|
mkdirSync(options.sessionDir, { recursive: true });
|
|
427
|
+
options.agentDir ??= resolve(options.outDir, "pi-agent");
|
|
428
|
+
seedVisualAgentDir(options.agentDir);
|
|
400
429
|
|
|
401
430
|
const sessionName = `pi-visual-${options.safeLabel}-${process.pid}`;
|
|
402
431
|
const bufferName = `pi-visual-prompt-${process.pid}`;
|
|
@@ -418,7 +447,22 @@ function runVisualSmoke(options) {
|
|
|
418
447
|
const jsonlMtimesBeforeRun = snapshotJsonlMtimes(options.sessionDir);
|
|
419
448
|
const runStartedAtMs = Date.now();
|
|
420
449
|
try {
|
|
421
|
-
const start = run(commands.tmux, [
|
|
450
|
+
const start = run(commands.tmux, [
|
|
451
|
+
"new-session",
|
|
452
|
+
"-d",
|
|
453
|
+
"-s",
|
|
454
|
+
sessionName,
|
|
455
|
+
"-c",
|
|
456
|
+
options.cwd,
|
|
457
|
+
"-x",
|
|
458
|
+
String(options.width),
|
|
459
|
+
"-y",
|
|
460
|
+
String(options.height),
|
|
461
|
+
"--",
|
|
462
|
+
shell,
|
|
463
|
+
"-c",
|
|
464
|
+
script,
|
|
465
|
+
]);
|
|
422
466
|
if (start.status !== 0) throw new Error(`tmux new-session failed: ${start.stderr?.toString().trim() || start.status}`);
|
|
423
467
|
sessionStarted = true;
|
|
424
468
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ModelListItem } from "@cursor/sdk";
|
|
2
|
+
|
|
3
|
+
export interface CursorModelSelectionIdentity {
|
|
4
|
+
model: ModelListItem;
|
|
5
|
+
selectionModelId: string;
|
|
6
|
+
context?: string;
|
|
7
|
+
fastOverride?: boolean;
|
|
8
|
+
piModelId: string;
|
|
9
|
+
contextWindowKey: string;
|
|
10
|
+
baseContextWindowKey: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export declare function getCursorModelSelectionIdentities(
|
|
14
|
+
models: readonly ModelListItem[],
|
|
15
|
+
): CursorModelSelectionIdentity[];
|
|
16
|
+
|
|
17
|
+
export declare function normalizeCursorContextWindowEntries(
|
|
18
|
+
models: readonly ModelListItem[],
|
|
19
|
+
entries: ReadonlyMap<string, number>,
|
|
20
|
+
source?: string,
|
|
21
|
+
): Map<string, number>;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
function getParameter(model, id) {
|
|
2
|
+
return (model.parameters ?? []).find((parameter) => parameter.id === id);
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
function getDefaultParam(model, id) {
|
|
6
|
+
const variant = (model.variants ?? []).find((candidate) => candidate.isDefault) ?? model.variants?.[0];
|
|
7
|
+
return variant?.params?.find((param) => param.id === id)?.value.toLowerCase();
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function getAmbiguousAliases(models) {
|
|
11
|
+
const ownersByAlias = new Map();
|
|
12
|
+
for (const model of models) {
|
|
13
|
+
for (const rawAlias of model.aliases ?? []) {
|
|
14
|
+
const alias = rawAlias.trim();
|
|
15
|
+
if (!alias || alias === model.id) continue;
|
|
16
|
+
const owners = ownersByAlias.get(alias) ?? new Set();
|
|
17
|
+
owners.add(model.id);
|
|
18
|
+
ownersByAlias.set(alias, owners);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return new Set([...ownersByAlias].filter(([, owners]) => owners.size > 1).map(([alias]) => alias));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function getSelectableIds(model, reservedIds, ambiguousAliases) {
|
|
25
|
+
const ids = [model.id];
|
|
26
|
+
for (const rawAlias of model.aliases ?? []) {
|
|
27
|
+
const alias = rawAlias.trim();
|
|
28
|
+
if (!alias || alias === model.id || ids.includes(alias) || reservedIds.has(alias) || ambiguousAliases.has(alias)) continue;
|
|
29
|
+
ids.push(alias);
|
|
30
|
+
}
|
|
31
|
+
return ids;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function encodePiModelId(modelId, context, fastOverride) {
|
|
35
|
+
const contextQualified = context ? `${modelId}@${context}` : modelId;
|
|
36
|
+
if (fastOverride === true) return `${contextQualified}:fast`;
|
|
37
|
+
if (fastOverride === false) return `${contextQualified}:slow`;
|
|
38
|
+
return contextQualified;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function getCursorModelSelectionIdentities(models) {
|
|
42
|
+
const sortedModels = [...models].sort((a, b) => a.id.localeCompare(b.id));
|
|
43
|
+
const reservedIds = new Set(models.map((model) => model.id));
|
|
44
|
+
const ambiguousAliases = getAmbiguousAliases(models);
|
|
45
|
+
const usedPiModelIds = new Set();
|
|
46
|
+
const identities = [];
|
|
47
|
+
|
|
48
|
+
for (const model of sortedModels) {
|
|
49
|
+
const contextValues = getParameter(model, "context")?.values?.map(({ value }) => value) ?? [];
|
|
50
|
+
const contexts = contextValues.length > 0 ? contextValues : [undefined];
|
|
51
|
+
const hasFast = getParameter(model, "fast") !== undefined;
|
|
52
|
+
const fastOverrides = hasFast ? [undefined, true, false] : [undefined];
|
|
53
|
+
const defaultFast = getDefaultParam(model, "fast");
|
|
54
|
+
|
|
55
|
+
for (const selectionModelId of getSelectableIds(model, reservedIds, ambiguousAliases)) {
|
|
56
|
+
for (const context of contexts) {
|
|
57
|
+
for (const fastOverride of fastOverrides) {
|
|
58
|
+
const piModelId = encodePiModelId(selectionModelId, context, fastOverride);
|
|
59
|
+
if (usedPiModelIds.has(piModelId)) continue;
|
|
60
|
+
usedPiModelIds.add(piModelId);
|
|
61
|
+
const defaultEquivalent =
|
|
62
|
+
(fastOverride === true && defaultFast === "true") || (fastOverride === false && defaultFast === "false");
|
|
63
|
+
identities.push({
|
|
64
|
+
model,
|
|
65
|
+
selectionModelId,
|
|
66
|
+
...(context ? { context } : {}),
|
|
67
|
+
...(fastOverride !== undefined ? { fastOverride } : {}),
|
|
68
|
+
piModelId,
|
|
69
|
+
contextWindowKey: defaultEquivalent ? encodePiModelId(selectionModelId, context) : piModelId,
|
|
70
|
+
baseContextWindowKey: encodePiModelId(model.id, context, defaultEquivalent ? undefined : fastOverride),
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return identities;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function normalizeCursorContextWindowEntries(models, entries, source = "context windows") {
|
|
81
|
+
const canonicalBySelectableId = new Map(
|
|
82
|
+
getCursorModelSelectionIdentities(models).map(({ piModelId, contextWindowKey }) => [piModelId, contextWindowKey]),
|
|
83
|
+
);
|
|
84
|
+
const normalized = new Map();
|
|
85
|
+
for (const [modelId, contextWindow] of entries) {
|
|
86
|
+
const canonicalId = modelId === "default" ? modelId : canonicalBySelectableId.get(modelId);
|
|
87
|
+
if (!canonicalId) continue;
|
|
88
|
+
const existing = normalized.get(canonicalId);
|
|
89
|
+
if (existing !== undefined && existing !== contextWindow) {
|
|
90
|
+
throw new Error(`${source} assigns conflicting windows to equivalent selection ${canonicalId}: ${existing} and ${contextWindow}`);
|
|
91
|
+
}
|
|
92
|
+
normalized.set(canonicalId, contextWindow);
|
|
93
|
+
}
|
|
94
|
+
return normalized;
|
|
95
|
+
}
|
|
@@ -1,30 +1,39 @@
|
|
|
1
|
-
// Generated from Cursor SDK checkpoint tokenDetails.maxTokens on 2026-
|
|
1
|
+
// Generated from Cursor SDK checkpoint tokenDetails.maxTokens on 2026-08-18.
|
|
2
2
|
// Refresh with: npm run refresh:cursor-snapshots -- --write --context-windows ~/.pi/agent/cursor-sdk-context-windows.json
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
3
|
+
// Keys are current selectable model IDs. Equivalent default :fast/:slow selections
|
|
4
|
+
// collapse to one key; stale and ambiguous aliases are omitted. Values are observed
|
|
5
|
+
// or conservative default/non-Max-mode limits and may override a catalog context
|
|
6
|
+
// label when the completed SDK checkpoint reports a different effective limit.
|
|
7
7
|
export const BUNDLED_CONTEXT_WINDOWS = {
|
|
8
8
|
"default": 200000,
|
|
9
|
+
"auto-smart": 200000,
|
|
10
|
+
"claude-fable-5@300k": 300000,
|
|
9
11
|
"claude-haiku-4-5": 200000,
|
|
10
12
|
"claude-opus-4-5": 200000,
|
|
11
|
-
"
|
|
13
|
+
"claude-opus-4-8@1m": 300000,
|
|
12
14
|
"composer-2": 200000,
|
|
13
15
|
"composer-2.5": 200000,
|
|
14
16
|
"gemini-2.5-flash": 200000,
|
|
15
17
|
"gemini-3-flash": 200000,
|
|
16
18
|
"gemini-3.1-pro": 200000,
|
|
19
|
+
"gemini-3.5-flash": 200000,
|
|
20
|
+
"gemini-3.6-flash": 200000,
|
|
21
|
+
"gemini-3.7-flash": 200000,
|
|
22
|
+
"glm-5.2": 200000,
|
|
23
|
+
"gpt-5-5@272k": 272000,
|
|
17
24
|
"gpt-5-mini": 272000,
|
|
18
25
|
"gpt-5.1": 272000,
|
|
19
|
-
"gpt-5.1-codex-max": 272000,
|
|
20
|
-
"gpt-5.1-codex-mini": 272000,
|
|
21
26
|
"gpt-5.2": 272000,
|
|
22
|
-
"gpt-5.2-codex": 272000,
|
|
23
27
|
"gpt-5.3-codex": 272000,
|
|
24
|
-
"gpt-5.3-codex-spark": 128000,
|
|
25
28
|
"gpt-5.4-mini": 272000,
|
|
26
29
|
"gpt-5.4-nano": 272000,
|
|
27
30
|
"gpt-5.5@272k": 272000,
|
|
28
|
-
"
|
|
29
|
-
"
|
|
31
|
+
"gpt-5.6@1m": 272000,
|
|
32
|
+
"grok-4.5": 256000,
|
|
33
|
+
"grok-4.5:slow": 256000,
|
|
34
|
+
"grok-4.6": 256000,
|
|
35
|
+
"kimi-k2.7-code": 200000,
|
|
36
|
+
"kimi-k3": 200000,
|
|
37
|
+
"opus-4.8@1m": 300000,
|
|
38
|
+
"opus-4.8@300k": 300000,
|
|
30
39
|
} as const satisfies Record<string, number>;
|
package/src/context.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import type { Context, Message, ToolCall } from "@earendil-works/pi-ai
|
|
2
|
+
import type { Context, Message, ToolCall } from "@earendil-works/pi-ai";
|
|
3
3
|
import { convertToLlm } from "@earendil-works/pi-coding-agent";
|
|
4
4
|
import type { AgentModeOption, SDKImage } from "@cursor/sdk";
|
|
5
5
|
import { CURSOR_PI_BRIDGE_PREFERENCE_TEXT } from "./cursor-bridge-contract.js";
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { isCursorModel } from "./cursor-model.js";
|
|
2
2
|
import { registerCursorModelLifecycle, type CursorModelLifecycleExtensionApi } from "./cursor-model-lifecycle.js";
|
|
3
3
|
import { resolveEffectiveCursorConfigForContext } from "./cursor-runtime-state.js";
|
|
4
|
+
import { resolveCursorFacingSystemPrompt } from "./cursor-agents-context.js";
|
|
4
5
|
|
|
5
6
|
export type CursorAgentsContextExtensionApi = CursorModelLifecycleExtensionApi;
|
|
6
7
|
|
|
7
8
|
export function registerCursorAgentsContextDedup(pi: CursorAgentsContextExtensionApi): void {
|
|
8
9
|
registerCursorModelLifecycle(pi, {
|
|
9
|
-
beforeAgentStart:
|
|
10
|
+
beforeAgentStart: (event, ctx) => {
|
|
10
11
|
if (!isCursorModel(ctx.model)) return undefined;
|
|
11
|
-
const { resolveCursorFacingSystemPrompt } = await import("./cursor-agents-context.js");
|
|
12
12
|
const runtime = resolveEffectiveCursorConfigForContext(ctx).runtime.value;
|
|
13
13
|
const resolved = resolveCursorFacingSystemPrompt(
|
|
14
14
|
event.systemPrompt,
|
|
@@ -12,8 +12,6 @@ import {
|
|
|
12
12
|
} from "./cursor-setting-sources.js";
|
|
13
13
|
import type { SettingSource } from "@cursor/sdk";
|
|
14
14
|
import type { CursorRuntime } from "./cursor-config.js";
|
|
15
|
-
export { registerCursorAgentsContextDedup, type CursorAgentsContextExtensionApi } from "./cursor-agents-context-registration.js";
|
|
16
|
-
|
|
17
15
|
export const CURSOR_PRESERVE_PI_AGENTS_MD_ENV = "PI_CURSOR_PRESERVE_PI_AGENTS_MD";
|
|
18
16
|
|
|
19
17
|
/** Opening tag prefix pi `buildSystemPrompt()` uses for each context file (path attribute only). */
|
package/src/cursor-api-key.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { readStoredCredential } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
|
|
1
3
|
export const CURSOR_API_KEY_ENV_VAR = "CURSOR_API_KEY";
|
|
2
4
|
const CURSOR_PROVIDER_ID = "cursor";
|
|
3
5
|
|
|
@@ -21,9 +23,8 @@ export function resolveCursorApiKey(apiKey?: string): string | undefined {
|
|
|
21
23
|
return trimmed;
|
|
22
24
|
}
|
|
23
25
|
|
|
24
|
-
|
|
26
|
+
function getStoredCursorApiKey(): string | undefined {
|
|
25
27
|
try {
|
|
26
|
-
const { readStoredCredential } = await import("@earendil-works/pi-coding-agent");
|
|
27
28
|
const credential = readStoredCredential(CURSOR_PROVIDER_ID);
|
|
28
29
|
return resolveCursorApiKey(credential?.type === "api_key" ? credential.key : undefined);
|
|
29
30
|
} catch {
|
|
@@ -31,6 +32,6 @@ async function getStoredCursorApiKey(): Promise<string | undefined> {
|
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
export
|
|
35
|
-
return (
|
|
35
|
+
export function resolveCursorRuntimeApiKey(): Promise<string | undefined> {
|
|
36
|
+
return Promise.resolve(getStoredCursorApiKey() ?? resolveCursorApiKey(process.env.CURSOR_API_KEY));
|
|
36
37
|
}
|
|
@@ -170,17 +170,38 @@ export async function fetchCursorCloudRawUsage(
|
|
|
170
170
|
}
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
+
function mapCursorSdkAgentUsageToCloudReport(value: unknown, runId?: string): CursorCloudUsageReport | undefined {
|
|
174
|
+
const record = asRecord(value);
|
|
175
|
+
const runs = (getArray(record, "runs") ?? []).map(asRecord);
|
|
176
|
+
const matchingRun = runId ? runs.find((run) => getString(run, "runId") === runId) : undefined;
|
|
177
|
+
return normalizeUsage({
|
|
178
|
+
totalUsage: getRecord(record, "usage"),
|
|
179
|
+
runUsage: getRecord(matchingRun, "usage"),
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
173
183
|
export async function collectCursorCloudRunReport(options: {
|
|
174
184
|
agent: SDKAgent;
|
|
175
185
|
run: Run;
|
|
176
186
|
waitResult: RunResult;
|
|
177
187
|
apiKey: string | undefined;
|
|
188
|
+
agentUsage?: unknown;
|
|
178
189
|
}): Promise<CursorCloudRunReport> {
|
|
179
190
|
const listArtifacts = options.agent.listArtifacts;
|
|
180
|
-
const
|
|
191
|
+
const sdkUsage =
|
|
192
|
+
options.agentUsage !== undefined
|
|
193
|
+
? mapCursorSdkAgentUsageToCloudReport(options.agentUsage, options.run.id)
|
|
194
|
+
: typeof options.agent.getUsage === "function"
|
|
195
|
+
? mapCursorSdkAgentUsageToCloudReport(
|
|
196
|
+
await withTimeout(Promise.resolve(options.agent.getUsage({ runId: options.run.id }))),
|
|
197
|
+
options.run.id,
|
|
198
|
+
)
|
|
199
|
+
: undefined;
|
|
200
|
+
const [artifactResult, restUsage] = await Promise.all([
|
|
181
201
|
typeof listArtifacts === "function" ? withTimeout(listArtifacts.call(options.agent)) : undefined,
|
|
182
|
-
fetchCursorCloudRawUsage({ agentId: options.run.agentId, runId: options.run.id, apiKey: options.apiKey }),
|
|
202
|
+
sdkUsage ? undefined : fetchCursorCloudRawUsage({ agentId: options.run.agentId, runId: options.run.id, apiKey: options.apiKey }),
|
|
183
203
|
]);
|
|
204
|
+
const usage = sdkUsage ?? restUsage;
|
|
184
205
|
const waitBranches = getArray(getRecord(asRecord(options.waitResult), "git"), "branches");
|
|
185
206
|
const runBranches = getArray(getRecord(asRecord(options.run), "git"), "branches");
|
|
186
207
|
return {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Context } from "@earendil-works/pi-ai
|
|
1
|
+
import type { Context } from "@earendil-works/pi-ai";
|
|
2
2
|
|
|
3
3
|
/** Tool names from the provider context snapshot at stream start (not live pi.getActiveTools()). */
|
|
4
4
|
export function getActiveContextToolNames(context: Context): ReadonlySet<string> | undefined {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AssistantMessage, AssistantMessageEventStream } from "@earendil-works/pi-ai
|
|
1
|
+
import type { AssistantMessage, AssistantMessageEventStream } from "@earendil-works/pi-ai";
|
|
2
2
|
|
|
3
3
|
function withDisplayOnlyThinking(partial: AssistantMessage, thinking: string): AssistantMessage {
|
|
4
4
|
return { ...partial, content: [...partial.content, { type: "thinking", thinking }] };
|