pi-cursor-sdk 0.5.3 → 0.5.4

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.
Files changed (94) hide show
  1. package/CHANGELOG.md +40 -1
  2. package/README.md +62 -816
  3. package/dist/context.js +11 -5
  4. package/dist/cursor-agents-context.js +6 -6
  5. package/dist/cursor-api-key.js +1 -1
  6. package/dist/cursor-bridge-contract.js +1 -13
  7. package/dist/cursor-cloud-local-state.js +0 -1
  8. package/dist/cursor-config.js +1 -17
  9. package/dist/cursor-fallback-models.generated.js +264 -1
  10. package/dist/cursor-live-run-coordinator.js +1 -0
  11. package/dist/cursor-mcp-timeout-override.js +6 -17
  12. package/dist/cursor-native-tool-display-replay.js +5 -5
  13. package/dist/cursor-native-tools.js +11 -0
  14. package/dist/cursor-pi-tool-bridge-env.js +25 -2
  15. package/dist/cursor-pi-tool-bridge-server.js +98 -48
  16. package/dist/cursor-pi-tool-bridge-snapshot.js +1 -1
  17. package/dist/cursor-pi-tool-bridge.js +4 -12
  18. package/dist/cursor-provider-errors.js +0 -6
  19. package/dist/cursor-provider-live-run-drain.js +8 -3
  20. package/dist/cursor-provider-overflow.js +7 -21
  21. package/dist/cursor-provider-turn-prepare.js +8 -1
  22. package/dist/cursor-provider-turn-runner.js +17 -6
  23. package/dist/cursor-provider.js +1 -4
  24. package/dist/cursor-runtime-state.js +3 -3
  25. package/dist/cursor-sdk-event-debug.js +2 -2
  26. package/dist/cursor-sdk-output-filter.js +1 -1
  27. package/dist/cursor-sdk-process-error-guard.js +1 -2
  28. package/dist/cursor-session-agent.js +6 -8
  29. package/dist/cursor-session-scope.js +1 -7
  30. package/dist/cursor-session-store.js +1 -1
  31. package/dist/cursor-state.js +9 -23
  32. package/dist/cursor-tool-lifecycle.js +0 -3
  33. package/dist/cursor-tool-manifest.js +3 -1
  34. package/dist/cursor-tool-presentation-registry.js +2 -4
  35. package/dist/cursor-tool-visibility.js +0 -3
  36. package/dist/cursor-transcript-tool-specs.js +1 -2
  37. package/dist/index.js +21 -0
  38. package/dist/model-discovery.js +0 -1
  39. package/dist/model-list-cache.js +4 -9
  40. package/docs/cursor-live-smoke-checklist.md +3 -3
  41. package/docs/cursor-model-ux-spec.md +16 -8
  42. package/docs/cursor-native-tool-replay.md +2 -2
  43. package/docs/cursor-native-tool-visual-audit.md +1 -1
  44. package/docs/cursor-testing-lessons.md +15 -3
  45. package/docs/cursor-tool-surfaces.md +32 -3
  46. package/docs/development.md +93 -0
  47. package/docs/platform-smoke-implementation.md +3 -2
  48. package/docs/reference.md +806 -0
  49. package/package.json +6 -4
  50. package/scripts/platform-smoke/artifact-secrets.mjs +13 -4
  51. package/scripts/platform-smoke/local-resume-runner.mjs +0 -1
  52. package/scripts/platform-smoke/target-runtime.mjs +4 -2
  53. package/scripts/platform-smoke/targets.mjs +0 -1
  54. package/shared/cursor-sdk-output-filter.d.mts +2 -0
  55. package/shared/cursor-sdk-output-filter.mjs +92 -28
  56. package/shared/cursor-sensitive-text.d.mts +1 -0
  57. package/shared/cursor-sensitive-text.mjs +7 -0
  58. package/src/context.ts +16 -9
  59. package/src/cursor-agents-context.ts +6 -6
  60. package/src/cursor-api-key.ts +1 -1
  61. package/src/cursor-bridge-contract.ts +1 -15
  62. package/src/cursor-cloud-local-state.ts +0 -2
  63. package/src/cursor-config.ts +1 -24
  64. package/src/cursor-fallback-models.generated.ts +264 -1
  65. package/src/cursor-live-run-coordinator.ts +5 -0
  66. package/src/cursor-mcp-timeout-override.ts +6 -30
  67. package/src/cursor-native-tool-display-replay.ts +4 -6
  68. package/src/cursor-native-tools.ts +14 -0
  69. package/src/cursor-pi-tool-bridge-env.ts +31 -2
  70. package/src/cursor-pi-tool-bridge-server.ts +89 -45
  71. package/src/cursor-pi-tool-bridge-snapshot.ts +0 -1
  72. package/src/cursor-pi-tool-bridge.ts +2 -18
  73. package/src/cursor-provider-errors.ts +0 -8
  74. package/src/cursor-provider-live-run-drain.ts +8 -2
  75. package/src/cursor-provider-overflow.ts +6 -24
  76. package/src/cursor-provider-turn-prepare.ts +10 -1
  77. package/src/cursor-provider-turn-runner.ts +17 -6
  78. package/src/cursor-provider.ts +0 -5
  79. package/src/cursor-runtime-state.ts +3 -3
  80. package/src/cursor-sdk-event-debug.ts +2 -2
  81. package/src/cursor-sdk-output-filter.ts +2 -1
  82. package/src/cursor-sdk-process-error-guard.ts +1 -3
  83. package/src/cursor-session-agent.ts +8 -8
  84. package/src/cursor-session-scope.ts +1 -9
  85. package/src/cursor-session-store.ts +1 -1
  86. package/src/cursor-state.ts +9 -36
  87. package/src/cursor-tool-lifecycle.ts +0 -4
  88. package/src/cursor-tool-manifest.ts +4 -1
  89. package/src/cursor-tool-presentation-registry.ts +3 -5
  90. package/src/cursor-tool-visibility.ts +0 -4
  91. package/src/cursor-transcript-tool-specs.ts +0 -3
  92. package/src/index.ts +18 -0
  93. package/src/model-discovery.ts +0 -1
  94. package/src/model-list-cache.ts +4 -10
package/dist/context.js CHANGED
@@ -11,7 +11,9 @@ export function getCursorPlanModeToolGuidanceText(agentMode, options = {}) {
11
11
  return undefined;
12
12
  return [
13
13
  "Cursor SDK mode is plan for this run. In pi-cursor-sdk, plan mode may still use available Cursor SDK/MCP tools for inspection when needed.",
14
- "Safe/read-only shell commands that inspect or print information are allowed when Cursor chooses to call Shell; do not say Shell is blocked by plan mode and then call it anyway.",
14
+ options.nativeToolsEnabled === false
15
+ ? "Only MCP tools exposed in this run are callable; native Shell and task/subagents are disabled."
16
+ : "Safe/read-only shell commands that inspect or print information are allowed when Cursor chooses to call Shell; do not say Shell is blocked by plan mode and then call it anyway.",
15
17
  options.includePiBridgeGuidance === false
16
18
  ? undefined
17
19
  : "Exposed pi__* bridge tools are also callable in plan mode when the user asks for them or they are needed to answer.",
@@ -19,14 +21,16 @@ export function getCursorPlanModeToolGuidanceText(agentMode, options = {}) {
19
21
  }
20
22
  export function getCursorToolTailGuardText(options = {}) {
21
23
  return [
22
- "Shell: use explicit `cd` to repo path for project commands; session cwd may differ from tool args.",
24
+ options.nativeToolsEnabled === false ? undefined : "Shell: use explicit `cd` to repo path for project commands; session cwd may differ from tool args.",
23
25
  options.includePlanModeGuidance === false
24
26
  ? undefined
25
- : getCursorPlanModeToolGuidanceText(options.agentMode, { includePiBridgeGuidance: options.includePiBridgeGuidance }),
27
+ : getCursorPlanModeToolGuidanceText(options.agentMode, { includePiBridgeGuidance: options.includePiBridgeGuidance, nativeToolsEnabled: options.nativeToolsEnabled }),
26
28
  "Exact-output requests: output exactly the requested text; no preamble or checks unless asked.",
27
29
  "Tools: call available Cursor SDK/MCP tools; never print tool cards as assistant text.",
28
30
  "Do not comment on GitHub issues or PRs unless the user asked.",
29
- options.includePiBridgeGuidance === false ? undefined : CURSOR_PI_BRIDGE_PREFERENCE_TEXT,
31
+ options.includePiBridgeGuidance === false ? undefined : options.nativeToolsEnabled === false
32
+ ? "Use only exposed pi__* MCP names for Pi work; native task/subagents are disabled."
33
+ : CURSOR_PI_BRIDGE_PREFERENCE_TEXT,
30
34
  ].filter((line) => line !== undefined).join("\n");
31
35
  }
32
36
  function getCursorToolBoundaryText(options = {}) {
@@ -35,12 +39,13 @@ function getCursorToolBoundaryText(options = {}) {
35
39
  const lines = [
36
40
  "Cursor SDK tool boundary:",
37
41
  "Call only Cursor SDK/MCP tools exposed in this run; pi history names, replay labels, and transcript names are not callable.",
42
+ options.nativeToolsEnabled === false ? "Cursor native tools (including task/subagents): disabled. Only exposed MCP tools are callable." : undefined,
38
43
  includePiBridgeGuidance
39
44
  ? "For exposed pi bridge tools, call pi__* MCP names, not pi card/history names."
40
45
  : undefined,
41
46
  "Do not claim pi-side or WebSearch/WebFetch tools unless Cursor ran an equivalent tool.",
42
47
  includePiAskQuestionGuidance ? "Use pi__cursor_ask_question only if the user asked to be prompted." : undefined,
43
- getCursorPlanModeToolGuidanceText(options.agentMode, { includePiBridgeGuidance }),
48
+ getCursorPlanModeToolGuidanceText(options.agentMode, { includePiBridgeGuidance, nativeToolsEnabled: options.nativeToolsEnabled }),
44
49
  "Images: only latest user images are sent; ask to reattach prior images.",
45
50
  ].filter((line) => line !== undefined);
46
51
  if (options.hasToolManifest) {
@@ -354,6 +359,7 @@ export function buildCursorPrompt(context, options = {}) {
354
359
  agentMode: options.agentMode,
355
360
  hasToolManifest: Boolean(options.toolManifest),
356
361
  includePiBridgeGuidance: options.includePiBridgeGuidance,
362
+ nativeToolsEnabled: options.nativeToolsEnabled,
357
363
  includePiAskQuestionGuidance: options.includePiAskQuestionGuidance,
358
364
  })];
359
365
  if (options.toolManifest) {
@@ -17,7 +17,7 @@ function normalizeDirPath(dirPath) {
17
17
  }
18
18
  /** Pi context filenames that can overlap Cursor project/user ambient rules. */
19
19
  const CURSOR_OVERLAPPING_CONTEXT_BASE_NAMES = new Set(["agents.md", "claude.md"]);
20
- export function getAgentsContextFileBaseName(filePath) {
20
+ function getAgentsContextFileBaseName(filePath) {
21
21
  const normalized = normalizeContextPath(filePath);
22
22
  return normalized.slice(normalized.lastIndexOf("/") + 1).toLowerCase();
23
23
  }
@@ -27,11 +27,11 @@ function isPiAgentDirContextFilePath(filePath, fileName, agentDir = getAgentDir(
27
27
  return normalized.toLowerCase() === expectedPath.toLowerCase();
28
28
  }
29
29
  /** Actual pi agent dir `AGENTS.md` — overlaps Cursor `user` setting source (global agent instructions). */
30
- export function isPiAgentDirAgentsMdPath(filePath, agentDir = getAgentDir()) {
30
+ function isPiAgentDirAgentsMdPath(filePath, agentDir = getAgentDir()) {
31
31
  return isPiAgentDirContextFilePath(filePath, "agents.md", agentDir);
32
32
  }
33
33
  /** Actual pi agent dir `CLAUDE.md` — kept because Cursor user rules use `~/.claude/CLAUDE.md`. */
34
- export function isPiAgentDirClaudeMdPath(filePath, agentDir = getAgentDir()) {
34
+ function isPiAgentDirClaudeMdPath(filePath, agentDir = getAgentDir()) {
35
35
  return isPiAgentDirContextFilePath(filePath, "claude.md", agentDir);
36
36
  }
37
37
  /**
@@ -40,7 +40,7 @@ export function isPiAgentDirClaudeMdPath(filePath, agentDir = getAgentDir()) {
40
40
  * Only the actual pi agent dir `AGENTS.md` overlaps Cursor `user`; agent-dir `CLAUDE.md` is kept
41
41
  * because Cursor user rules use `~/.claude/CLAUDE.md`, not pi's agent dir path.
42
42
  */
43
- export function classifyContextFileOverlap(filePath, agentDir = getAgentDir()) {
43
+ function classifyContextFileOverlap(filePath, agentDir = getAgentDir()) {
44
44
  const base = getAgentsContextFileBaseName(filePath);
45
45
  if (!CURSOR_OVERLAPPING_CONTEXT_BASE_NAMES.has(base))
46
46
  return "none";
@@ -50,7 +50,7 @@ export function classifyContextFileOverlap(filePath, agentDir = getAgentDir()) {
50
50
  return "none";
51
51
  return "cursor-project-rules";
52
52
  }
53
- export function shouldRemovePiAgentsContextFile(file, settingSources, agentDir) {
53
+ function shouldRemovePiAgentsContextFile(file, settingSources, agentDir) {
54
54
  switch (classifyContextFileOverlap(file.path, agentDir)) {
55
55
  case "cursor-user-agents":
56
56
  return cursorSettingSourcesIncludes(settingSources, "user");
@@ -60,7 +60,7 @@ export function shouldRemovePiAgentsContextFile(file, settingSources, agentDir)
60
60
  return false;
61
61
  }
62
62
  }
63
- export function shouldSuppressPiAgentsContext(model, contextFiles, settingSources, agentDir) {
63
+ function shouldSuppressPiAgentsContext(model, contextFiles, settingSources, agentDir) {
64
64
  if (!isCursorModel(model))
65
65
  return false;
66
66
  if (parseEnvBoolean(process.env[CURSOR_PRESERVE_PI_AGENTS_MD_ENV], false))
@@ -2,7 +2,7 @@ import { envApiKeyAuth } from "@earendil-works/pi-ai";
2
2
  import { parseEnvBoolean } from "./cursor-env-boolean.js";
3
3
  export const CURSOR_API_KEY_ENV_VAR = "CURSOR_API_KEY";
4
4
  // Legacy no-auth availability policy only; never a configured models.json key.
5
- export const CURSOR_API_KEY_CONFIG_VALUE = "pi-cursor-sdk-cursor-api-key-placeholder";
5
+ const CURSOR_API_KEY_CONFIG_VALUE = "pi-cursor-sdk-cursor-api-key-placeholder";
6
6
  const CURSOR_API_KEY_PLACEHOLDERS = new Set([
7
7
  CURSOR_API_KEY_ENV_VAR,
8
8
  `$${CURSOR_API_KEY_ENV_VAR}`,
@@ -1,17 +1,5 @@
1
1
  export const CURSOR_PI_BRIDGE_MCP_TOOL_PREFIX = "pi__";
2
- export const CURSOR_PI_BRIDGE_PREFERENCE_TEXT = "When exposed, prefer pi__mcp for MCP work and pi__subagent for delegation; use Cursor-configured MCP or Cursor-native subagents only when the matching pi__ tool is not exposed or unavailable.";
3
- const CURSOR_PI_BRIDGE_CONTRACT_LINES = [
4
- "Pi bridge contract:",
5
- `${CURSOR_PI_BRIDGE_MCP_TOOL_PREFIX}* names are live Cursor MCP bridge tool names only when exposed in the current run.`,
6
- `Call the ${CURSOR_PI_BRIDGE_MCP_TOOL_PREFIX}* MCP tool name, not the real pi tool name shown in pi history or transcripts.`,
7
- CURSOR_PI_BRIDGE_PREFERENCE_TEXT,
8
- "Bridged calls execute through normal pi tool flow, so pi shows the real pi tool name and returns a normal pi tool result.",
9
- "Replay IDs, replay labels, and transcript tool names are display-only/context-only, not callable tools.",
10
- "Cursor-native host tools, settings, plugins, and configured MCP servers are separate from the pi bridge.",
11
- ];
12
- export function getCursorPiBridgeContractText() {
13
- return CURSOR_PI_BRIDGE_CONTRACT_LINES.join("\n");
14
- }
2
+ export const CURSOR_PI_BRIDGE_PREFERENCE_TEXT = "For MCP work and delegation, prefer matching exposed pi__* tools using their listed names, schemas, and prompt guidelines; use Cursor-configured MCP or Cursor-native subagents only when the matching pi tool is not exposed or unavailable.";
15
3
  function formatPromptGuidelines(promptGuidelines) {
16
4
  const guidelines = promptGuidelines?.map((guideline) => guideline.trim()).filter(Boolean) ?? [];
17
5
  if (guidelines.length === 0)
@@ -457,4 +457,3 @@ export function inspectCursorCloudLocalState(cwd, target = {}, runGit = runCurso
457
457
  }
458
458
  return { insideGitRepo: true, dirty: dirty, comparison: aheadCount > 0 ? "unpushed" : "contains_head" };
459
459
  }
460
- export const __testUtils = { sourceForDestination };
@@ -231,7 +231,7 @@ function readCursorSdkConfigFile(path) {
231
231
  return {};
232
232
  }
233
233
  }
234
- export function loadCursorSdkConfigForUpdate(path) {
234
+ function loadCursorSdkConfigForUpdate(path) {
235
235
  if (!existsSync(path))
236
236
  return {};
237
237
  let source;
@@ -342,16 +342,6 @@ export function updateCursorSdkConfig(path, update, options = {}) {
342
342
  return updated;
343
343
  });
344
344
  }
345
- export function saveCursorSdkUserConfig(config, path = getCursorSdkUserConfigPath()) {
346
- updateCursorSdkConfig(path, () => ({ ...config }), { newFileMode: 0o600 });
347
- }
348
- export function saveCursorSdkProjectConfig(cwd, config, configDirName = CONFIG_DIR_NAME) {
349
- const path = getCursorSdkProjectConfigPath(cwd, configDirName);
350
- updateCursorSdkConfig(path, () => ({ ...config }));
351
- }
352
- export function mergeCursorSdkConfig(base, patch) {
353
- return mergeCursorSdkConfigForUpdate({ ...base }, patch);
354
- }
355
345
  export function mergeCursorSdkConfigForUpdate(base, patch) {
356
346
  const baseCloud = asRecord(base.cloud);
357
347
  const baseLocal = asRecord(base.local);
@@ -378,12 +368,6 @@ export function mergeCursorSdkConfigForUpdate(base, patch) {
378
368
  export function cursorFastDefaultsFromConfig(config) {
379
369
  return new Map(Object.entries(config?.fastDefaults ?? {}));
380
370
  }
381
- export function withCursorFastDefaults(config, fastDefaults) {
382
- return {
383
- ...config,
384
- fastDefaults: Object.fromEntries([...fastDefaults.entries()].sort(([a], [b]) => a.localeCompare(b))),
385
- };
386
- }
387
371
  function resolved(source, value, cappedBy) {
388
372
  return { value, source, trustLevel: TRUST_LEVELS[source], ...(cappedBy ? { cappedBy } : {}) };
389
373
  }
@@ -1,4 +1,4 @@
1
- // Generated with @cursor/sdk@1.0.37 from 46 Cursor models.
1
+ // Generated with @cursor/sdk@1.0.37 from 48 Cursor models.
2
2
  // Refresh with: npm run refresh:cursor-snapshots -- --write
3
3
  // Do not add secrets; this file stores public model metadata only.
4
4
  export const FALLBACK_MODEL_ITEMS = [
@@ -6516,6 +6516,60 @@ export const FALLBACK_MODEL_ITEMS = [
6516
6516
  }
6517
6517
  ]
6518
6518
  },
6519
+ {
6520
+ id: "gemini-4-argon",
6521
+ displayName: "Gemini 4 Argon",
6522
+ parameters: [
6523
+ {
6524
+ id: "reasoning_effort",
6525
+ displayName: "Effort",
6526
+ values: [
6527
+ {
6528
+ value: "low",
6529
+ displayName: "Low"
6530
+ },
6531
+ {
6532
+ value: "medium",
6533
+ displayName: "Medium"
6534
+ },
6535
+ {
6536
+ value: "high",
6537
+ displayName: "High"
6538
+ }
6539
+ ]
6540
+ }
6541
+ ],
6542
+ variants: [
6543
+ {
6544
+ params: [
6545
+ {
6546
+ id: "reasoning_effort",
6547
+ value: "low"
6548
+ }
6549
+ ],
6550
+ displayName: "Gemini 4 Argon Low"
6551
+ },
6552
+ {
6553
+ params: [
6554
+ {
6555
+ id: "reasoning_effort",
6556
+ value: "medium"
6557
+ }
6558
+ ],
6559
+ displayName: "Gemini 4 Argon Medium",
6560
+ isDefault: true
6561
+ },
6562
+ {
6563
+ params: [
6564
+ {
6565
+ id: "reasoning_effort",
6566
+ value: "high"
6567
+ }
6568
+ ],
6569
+ displayName: "Gemini 4 Argon High"
6570
+ }
6571
+ ]
6572
+ },
6519
6573
  {
6520
6574
  id: "glm-5.2",
6521
6575
  displayName: "GLM 5.2",
@@ -10155,5 +10209,214 @@ export const FALLBACK_MODEL_ITEMS = [
10155
10209
  displayName: "Muse Spark 1.3"
10156
10210
  }
10157
10211
  ]
10212
+ },
10213
+ {
10214
+ id: "muse-wonder-1.0",
10215
+ displayName: "Muse Wonder",
10216
+ parameters: [
10217
+ {
10218
+ id: "context",
10219
+ displayName: "Context",
10220
+ values: [
10221
+ {
10222
+ value: "300k",
10223
+ displayName: "300K"
10224
+ },
10225
+ {
10226
+ value: "1m",
10227
+ displayName: "1M"
10228
+ }
10229
+ ]
10230
+ },
10231
+ {
10232
+ id: "reasoning_effort",
10233
+ displayName: "Reasoning",
10234
+ values: [
10235
+ {
10236
+ value: "minimal",
10237
+ displayName: "Minimal"
10238
+ },
10239
+ {
10240
+ value: "low",
10241
+ displayName: "Low"
10242
+ },
10243
+ {
10244
+ value: "medium",
10245
+ displayName: "Medium"
10246
+ },
10247
+ {
10248
+ value: "high",
10249
+ displayName: "High"
10250
+ },
10251
+ {
10252
+ value: "xhigh",
10253
+ displayName: "Extra High"
10254
+ },
10255
+ {
10256
+ value: "max",
10257
+ displayName: "Max"
10258
+ }
10259
+ ]
10260
+ }
10261
+ ],
10262
+ variants: [
10263
+ {
10264
+ params: [
10265
+ {
10266
+ id: "context",
10267
+ value: "300k"
10268
+ },
10269
+ {
10270
+ id: "reasoning_effort",
10271
+ value: "minimal"
10272
+ }
10273
+ ],
10274
+ displayName: "Muse Wonder Minimal"
10275
+ },
10276
+ {
10277
+ params: [
10278
+ {
10279
+ id: "context",
10280
+ value: "300k"
10281
+ },
10282
+ {
10283
+ id: "reasoning_effort",
10284
+ value: "low"
10285
+ }
10286
+ ],
10287
+ displayName: "Muse Wonder Low"
10288
+ },
10289
+ {
10290
+ params: [
10291
+ {
10292
+ id: "context",
10293
+ value: "300k"
10294
+ },
10295
+ {
10296
+ id: "reasoning_effort",
10297
+ value: "medium"
10298
+ }
10299
+ ],
10300
+ displayName: "Muse Wonder Medium"
10301
+ },
10302
+ {
10303
+ params: [
10304
+ {
10305
+ id: "context",
10306
+ value: "300k"
10307
+ },
10308
+ {
10309
+ id: "reasoning_effort",
10310
+ value: "high"
10311
+ }
10312
+ ],
10313
+ displayName: "Muse Wonder High"
10314
+ },
10315
+ {
10316
+ params: [
10317
+ {
10318
+ id: "context",
10319
+ value: "300k"
10320
+ },
10321
+ {
10322
+ id: "reasoning_effort",
10323
+ value: "xhigh"
10324
+ }
10325
+ ],
10326
+ displayName: "Muse Wonder Extra High"
10327
+ },
10328
+ {
10329
+ params: [
10330
+ {
10331
+ id: "context",
10332
+ value: "300k"
10333
+ },
10334
+ {
10335
+ id: "reasoning_effort",
10336
+ value: "max"
10337
+ }
10338
+ ],
10339
+ displayName: "Muse Wonder Max"
10340
+ },
10341
+ {
10342
+ params: [
10343
+ {
10344
+ id: "context",
10345
+ value: "1m"
10346
+ },
10347
+ {
10348
+ id: "reasoning_effort",
10349
+ value: "minimal"
10350
+ }
10351
+ ],
10352
+ displayName: "Muse Wonder 1M Minimal"
10353
+ },
10354
+ {
10355
+ params: [
10356
+ {
10357
+ id: "context",
10358
+ value: "1m"
10359
+ },
10360
+ {
10361
+ id: "reasoning_effort",
10362
+ value: "low"
10363
+ }
10364
+ ],
10365
+ displayName: "Muse Wonder 1M Low"
10366
+ },
10367
+ {
10368
+ params: [
10369
+ {
10370
+ id: "context",
10371
+ value: "1m"
10372
+ },
10373
+ {
10374
+ id: "reasoning_effort",
10375
+ value: "medium"
10376
+ }
10377
+ ],
10378
+ displayName: "Muse Wonder 1M Medium"
10379
+ },
10380
+ {
10381
+ params: [
10382
+ {
10383
+ id: "context",
10384
+ value: "1m"
10385
+ },
10386
+ {
10387
+ id: "reasoning_effort",
10388
+ value: "high"
10389
+ }
10390
+ ],
10391
+ displayName: "Muse Wonder 1M High"
10392
+ },
10393
+ {
10394
+ params: [
10395
+ {
10396
+ id: "context",
10397
+ value: "1m"
10398
+ },
10399
+ {
10400
+ id: "reasoning_effort",
10401
+ value: "xhigh"
10402
+ }
10403
+ ],
10404
+ displayName: "Muse Wonder 1M Extra High",
10405
+ isDefault: true
10406
+ },
10407
+ {
10408
+ params: [
10409
+ {
10410
+ id: "context",
10411
+ value: "1m"
10412
+ },
10413
+ {
10414
+ id: "reasoning_effort",
10415
+ value: "max"
10416
+ }
10417
+ ],
10418
+ displayName: "Muse Wonder 1M Max"
10419
+ }
10420
+ ]
10158
10421
  }
10159
10422
  ];
@@ -150,6 +150,7 @@ export function createCursorLiveRunCoordinator(deps) {
150
150
  const run = {
151
151
  id: params.id,
152
152
  agent: params.agent,
153
+ nativeToolsEnabled: params.nativeToolsEnabled !== false,
153
154
  bridgeRun: params.bridgeRun,
154
155
  sessionBridgeRun: params.sessionBridgeRun,
155
156
  sessionAgentScopeKey,
@@ -36,7 +36,7 @@ function normalizeConnectTimeoutMs(timeoutMs) {
36
36
  return DEFAULT_CURSOR_MCP_CONNECT_TIMEOUT_MS;
37
37
  return Math.min(Math.max(Math.trunc(timeoutMs), MIN_CURSOR_MCP_CONNECT_TIMEOUT_MS), CURSOR_SDK_MCP_DEFAULT_TIMEOUT_MS);
38
38
  }
39
- export function resolveCursorMcpConnectTimeoutMs(env = process.env) {
39
+ function resolveCursorMcpConnectTimeoutMs(env = process.env) {
40
40
  const explicitMs = parsePositiveNumber(env[CURSOR_MCP_CONNECT_TIMEOUT_MS_ENV]);
41
41
  if (explicitMs !== undefined)
42
42
  return normalizeConnectTimeoutMs(explicitMs);
@@ -51,13 +51,13 @@ function isCursorSdkMcpProtocolTimeoutStack(stack) {
51
51
  return (/(?:node_modules[/\\]@cursor[/\\]sdk|node_modules\/\@cursor\/sdk|@cursor\/sdk\/dist)/.test(stack) &&
52
52
  /\b_setupTimeout\b|\bProtocol\._setupTimeout\b/.test(stack));
53
53
  }
54
- export function isCursorSdkMcpToolTimeoutStack(stack) {
54
+ function isCursorSdkMcpToolTimeoutStack(stack) {
55
55
  if (!stack)
56
56
  return false;
57
57
  return (isCursorSdkMcpProtocolTimeoutStack(stack) &&
58
58
  /\bcallTool\b|\bClient\.callTool\b|\bMcpSdkClient\.callTool\b/.test(stack));
59
59
  }
60
- export function isCursorSdkMcpConnectTimeoutStack(stack) {
60
+ function isCursorSdkMcpConnectTimeoutStack(stack) {
61
61
  if (!stack || !isCursorSdkMcpProtocolTimeoutStack(stack))
62
62
  return false;
63
63
  // The SDK minifies the Client class name; the protocol method and SDK
@@ -83,9 +83,9 @@ function patchedSetTimeout(handler, delay, ...args) {
83
83
  }
84
84
  return Reflect.apply(delegate, globalThis, [handler, nextDelay, ...args]);
85
85
  }
86
- export function installCursorMcpToolTimeoutOverride(options = {}) {
87
- installedToolTimeoutMs = normalizeOverrideTimeoutMs(options.timeoutMs ?? resolveCursorMcpToolTimeoutMs(options.env));
88
- installedConnectTimeoutMs = normalizeConnectTimeoutMs(options.connectTimeoutMs ?? resolveCursorMcpConnectTimeoutMs(options.env));
86
+ export function installCursorMcpToolTimeoutOverride() {
87
+ installedToolTimeoutMs = resolveCursorMcpToolTimeoutMs();
88
+ installedConnectTimeoutMs = resolveCursorMcpConnectTimeoutMs();
89
89
  if (!originalSetTimeout) {
90
90
  originalSetTimeout = globalThis.setTimeout;
91
91
  globalThis.setTimeout = patchedSetTimeout;
@@ -105,14 +105,3 @@ export function restoreCursorMcpToolTimeoutOverride() {
105
105
  installedToolTimeoutMs = DEFAULT_CURSOR_MCP_TOOL_TIMEOUT_MS;
106
106
  installedConnectTimeoutMs = DEFAULT_CURSOR_MCP_CONNECT_TIMEOUT_MS;
107
107
  }
108
- export const cursorMcpToolTimeoutOverrideDefaults = {
109
- cursorSdkDefaultTimeoutMs: CURSOR_SDK_MCP_DEFAULT_TIMEOUT_MS,
110
- defaultOverrideTimeoutMs: DEFAULT_CURSOR_MCP_TOOL_TIMEOUT_MS,
111
- defaultConnectTimeoutMs: DEFAULT_CURSOR_MCP_CONNECT_TIMEOUT_MS,
112
- minConnectTimeoutMs: MIN_CURSOR_MCP_CONNECT_TIMEOUT_MS,
113
- maxNodeTimerDelayMs: MAX_NODE_TIMER_DELAY_MS,
114
- timeoutMsEnv: CURSOR_MCP_TOOL_TIMEOUT_MS_ENV,
115
- timeoutSecondsEnv: CURSOR_MCP_TOOL_TIMEOUT_SECONDS_ENV,
116
- connectTimeoutMsEnv: CURSOR_MCP_CONNECT_TIMEOUT_MS_ENV,
117
- connectTimeoutSecondsEnv: CURSOR_MCP_CONNECT_TIMEOUT_SECONDS_ENV,
118
- };
@@ -8,9 +8,9 @@ import { inferImageMimeType } from "./cursor-tool-result-display-readers.js";
8
8
  import { LOCAL_READ_PREVIEW_NOTICE, isLocalReadPreviewContent } from "./cursor-transcript-utils.js";
9
9
  import { CURSOR_REPLAY_ACTIVITY_TOOL_NAME, getCursorReplayCallSummary, shouldShowCursorReplayCollapsedExpandHint, } from "./cursor-tool-presentation-registry.js";
10
10
  import { CURSOR_REPLAY_GENERATE_IMAGE_RESULT_TITLE, isCursorReplayGenerateImageDetails, isCursorReplayActivityDetails, parseCursorReplayToolDetails, } from "./cursor-replay-tool-details.js";
11
- export { isCursorReplayNativeEditDetails, isCursorReplayGenerateImageDetails, isCursorReplayActivityDetails, isCursorReplayNativeWriteDetails, parseCursorReplayToolDetails, } from "./cursor-replay-tool-details.js";
11
+ export { isCursorReplayNativeEditDetails, isCursorReplayNativeWriteDetails, parseCursorReplayToolDetails, } from "./cursor-replay-tool-details.js";
12
12
  export const CURSOR_REPLAY_COLLAPSED_PREVIEW_LINES = 8;
13
- export const CURSOR_REPLAY_PREVIEW_MAX_CHARS = 4000;
13
+ const CURSOR_REPLAY_PREVIEW_MAX_CHARS = 4000;
14
14
  export const CURSOR_REPLAY_PREVIEW_MAX_LINE_CHARS = 240;
15
15
  const CURSOR_REPLAY_HIGHLIGHT_MAX_CHARS = 12000;
16
16
  export const cursorReplayToolSchema = Type.Object({}, { additionalProperties: true });
@@ -40,7 +40,7 @@ function buildImageReplayComponent(text, imageData, mimeType, filename, theme) {
40
40
  },
41
41
  };
42
42
  }
43
- export function getCursorReplayPath(args, details) {
43
+ function getCursorReplayPath(args, details) {
44
44
  const argPath = args?.path;
45
45
  return details?.path ?? (typeof argPath === "string" && argPath.trim() ? argPath : "unknown");
46
46
  }
@@ -202,7 +202,7 @@ function formatCursorReplayActivityPreview(details, text, theme, maxLines, strip
202
202
  }
203
203
  return stripHeader ? formatCursorReplayPreview(text, theme, maxLines, true) : formatMutedBlock(text, theme);
204
204
  }
205
- export function formatCursorReplayPreview(text, theme, maxLines = CURSOR_REPLAY_COLLAPSED_PREVIEW_LINES, stripHeader = true) {
205
+ function formatCursorReplayPreview(text, theme, maxLines = CURSOR_REPLAY_COLLAPSED_PREVIEW_LINES, stripHeader = true) {
206
206
  const body = (stripHeader ? stripCursorReplayHeader(text) : text).trimEnd();
207
207
  if (!body)
208
208
  return undefined;
@@ -240,7 +240,7 @@ function getCursorReplayCardTitle(toolName, args) {
240
240
  }
241
241
  return "Cursor activity";
242
242
  }
243
- export function renderCursorReplayCall(toolName, args, theme, isPartial) {
243
+ function renderCursorReplayCall(toolName, args, theme, isPartial) {
244
244
  if (!isPartial)
245
245
  return new Text("", 0, 0);
246
246
  let text = theme.fg("toolTitle", theme.bold(`${getCursorReplayCardTitle(toolName, args)} `));
@@ -0,0 +1,11 @@
1
+ import { parseEnvBoolean } from "./cursor-env-boolean.js";
2
+ export const CURSOR_NATIVE_TOOLS_ENV = "PI_CURSOR_NATIVE_TOOLS";
3
+ /** Default preserves the SDK toolset; false selects the public MCP-only main loop. */
4
+ export function resolveCursorNativeToolsEnabled(env = process.env) {
5
+ return parseEnvBoolean(env[CURSOR_NATIVE_TOOLS_ENV], true);
6
+ }
7
+ export function assertCursorNativeToolsRuntime(runtime, nativeToolsEnabled) {
8
+ if (runtime === "cloud" && !nativeToolsEnabled) {
9
+ throw new Error("PI_CURSOR_NATIVE_TOOLS=0 requires local runtime; Cursor Cloud does not support the SDK tools restriction. Select local runtime or remove the opt-out.");
10
+ }
11
+ }
@@ -1,8 +1,8 @@
1
1
  import { parseEnvBoolean } from "./cursor-env-boolean.js";
2
2
  import { resolveCursorMcpToolTimeoutMs } from "./cursor-mcp-timeout-override.js";
3
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";
4
+ const CURSOR_PI_TOOL_BRIDGE_BUILTINS_ENV = "PI_CURSOR_EXPOSE_BUILTIN_TOOLS";
5
+ const CURSOR_PI_TOOL_BRIDGE_CALL_TIMEOUT_MS_ENV = "PI_CURSOR_PI_BRIDGE_CALL_TIMEOUT_MS";
6
6
  export function resolveCursorPiToolBridgeEnabled(env = process.env) {
7
7
  return parseEnvBoolean(env[CURSOR_PI_TOOL_BRIDGE_ENV], true);
8
8
  }
@@ -16,3 +16,26 @@ export function resolveCursorPiToolBridgeCallTimeoutMs(env = process.env) {
16
16
  return mcpToolTimeoutMs;
17
17
  return Math.min(Math.max(Math.trunc(parsed), 1), mcpToolTimeoutMs);
18
18
  }
19
+ const CURSOR_PI_TOOL_BRIDGE_HOST_ENV = "PI_CURSOR_PI_TOOL_BRIDGE_HOST";
20
+ const CURSOR_PI_TOOL_BRIDGE_PORT_ENV = "PI_CURSOR_PI_TOOL_BRIDGE_PORT";
21
+ const DEFAULT_URL_HOST = "127.0.0.1";
22
+ const PORT_PATTERN = /^\d{1,5}$/;
23
+ export function resolveCursorPiToolBridgeUrlHost(env = process.env) {
24
+ return env[CURSOR_PI_TOOL_BRIDGE_HOST_ENV]?.trim().toLowerCase() === "localhost" ? "localhost" : DEFAULT_URL_HOST;
25
+ }
26
+ function parsePort(text) {
27
+ if (!PORT_PATTERN.test(text))
28
+ return undefined;
29
+ const port = Number(text);
30
+ return port >= 1 && port <= 65535 ? port : undefined;
31
+ }
32
+ export function resolveCursorPiToolBridgePortRange(env = process.env) {
33
+ const parts = env[CURSOR_PI_TOOL_BRIDGE_PORT_ENV]?.trim().split("-");
34
+ if (!parts || parts.length > 2)
35
+ return undefined;
36
+ const first = parsePort(parts[0]);
37
+ const last = parts.length === 2 ? parsePort(parts[1]) : first;
38
+ if (first === undefined || last === undefined || first > last)
39
+ return undefined;
40
+ return { first, last };
41
+ }