pi-cursor-sdk 0.1.56 → 0.1.58

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 (85) hide show
  1. package/CHANGELOG.md +49 -1
  2. package/README.md +104 -29
  3. package/docs/cursor-live-smoke-checklist.md +7 -7
  4. package/docs/cursor-model-ux-spec.md +55 -44
  5. package/docs/cursor-native-tool-replay.md +2 -2
  6. package/docs/cursor-native-tool-visual-audit.md +1 -1
  7. package/docs/cursor-testing-lessons.md +20 -7
  8. package/docs/cursor-tool-surfaces.md +13 -2
  9. package/docs/platform-smoke-implementation.md +220 -0
  10. package/docs/platform-smoke.md +183 -247
  11. package/package.json +38 -6
  12. package/platform-smoke.config.mjs +5 -1
  13. package/scripts/cloud-runtime-smoke.d.mts +3 -0
  14. package/scripts/cloud-runtime-smoke.mjs +502 -0
  15. package/scripts/debug-provider-events.mjs +8 -3
  16. package/scripts/isolated-cursor-smoke.sh +4 -6
  17. package/scripts/lib/cursor-child-process.d.mts +1 -0
  18. package/scripts/lib/cursor-child-process.mjs +137 -7
  19. package/scripts/lib/local-resume-smoke-harness.mjs +543 -0
  20. package/scripts/local-resume-cleanup-smoke.mjs +108 -0
  21. package/scripts/local-resume-smoke.d.mts +1 -0
  22. package/scripts/local-resume-smoke.mjs +642 -0
  23. package/scripts/platform-smoke/artifact-anchored-extract.d.mts +10 -0
  24. package/scripts/platform-smoke/artifact-anchored-extract.mjs +111 -0
  25. package/scripts/platform-smoke/artifact-bundle-chunk.mjs +57 -0
  26. package/scripts/platform-smoke/artifact-bundle-contract.mjs +34 -0
  27. package/scripts/platform-smoke/artifact-fs-safety.mjs +311 -0
  28. package/scripts/platform-smoke/artifact-openat-extract.c +335 -0
  29. package/scripts/platform-smoke/artifact-secrets.mjs +155 -0
  30. package/scripts/platform-smoke/artifacts.mjs +293 -65
  31. package/scripts/platform-smoke/card-detect.mjs +16 -4
  32. package/scripts/platform-smoke/crabbox-runner.mjs +45 -3
  33. package/scripts/platform-smoke/doctor.mjs +20 -10
  34. package/scripts/platform-smoke/live-suite-runner.mjs +18 -57
  35. package/scripts/platform-smoke/local-resume-runner.mjs +252 -0
  36. package/scripts/platform-smoke/local-resume-suites.d.mts +15 -0
  37. package/scripts/platform-smoke/local-resume-suites.mjs +104 -0
  38. package/scripts/platform-smoke/scenarios.mjs +16 -2
  39. package/scripts/platform-smoke/target-runtime.mjs +206 -0
  40. package/scripts/platform-smoke/targets.mjs +33 -141
  41. package/scripts/platform-smoke/visual-evidence.mjs +6 -7
  42. package/scripts/platform-smoke/wrapped-line-match.mjs +9 -0
  43. package/scripts/platform-smoke.mjs +40 -27
  44. package/scripts/refresh-cursor-model-snapshots.mjs +18 -6
  45. package/scripts/steering-rpc-smoke.mjs +16 -6
  46. package/scripts/tmux-live-smoke.sh +3 -5
  47. package/shared/cursor-cloud-lifecycle-constants.d.mts +3 -0
  48. package/shared/cursor-cloud-lifecycle-constants.mjs +7 -0
  49. package/shared/cursor-sensitive-text.mjs +7 -1
  50. package/src/context.ts +5 -2
  51. package/src/cursor-agents-context-registration.ts +7 -0
  52. package/src/cursor-agents-context.ts +3 -1
  53. package/src/cursor-api-key.ts +15 -1
  54. package/src/cursor-bridge-contract.ts +3 -0
  55. package/src/cursor-cloud-lifecycle.ts +733 -0
  56. package/src/cursor-cloud-options.ts +206 -0
  57. package/src/cursor-cloud-reporting.ts +246 -0
  58. package/src/cursor-config.ts +659 -0
  59. package/src/cursor-display-only-trace.ts +14 -0
  60. package/src/cursor-display-text.ts +8 -2
  61. package/src/cursor-durable-fs.ts +49 -0
  62. package/src/cursor-fallback-models.generated.ts +2045 -485
  63. package/src/cursor-live-run-accounting.ts +7 -1
  64. package/src/cursor-live-run-coordinator.ts +1 -0
  65. package/src/cursor-pi-tool-bridge-run.ts +14 -4
  66. package/src/cursor-provider-live-run-drain.ts +5 -0
  67. package/src/cursor-provider-run-finalizer.ts +36 -28
  68. package/src/cursor-provider-turn-finalize.ts +72 -6
  69. package/src/cursor-provider-turn-prepare.ts +228 -12
  70. package/src/cursor-provider-turn-runner.ts +41 -13
  71. package/src/cursor-provider-turn-send.ts +59 -16
  72. package/src/cursor-provider-turn-types.ts +44 -10
  73. package/src/cursor-runtime-state.ts +478 -0
  74. package/src/cursor-sdk-event-debug.ts +46 -6
  75. package/src/cursor-sdk-process-error-guard.ts +101 -30
  76. package/src/cursor-session-agent-cleanup.ts +328 -0
  77. package/src/cursor-session-agent-resume.ts +439 -0
  78. package/src/cursor-session-agent.ts +109 -13
  79. package/src/cursor-session-scope.ts +35 -2
  80. package/src/cursor-session-send-policy.ts +1 -1
  81. package/src/cursor-skill-tool.ts +30 -11
  82. package/src/cursor-state.ts +112 -69
  83. package/src/cursor-usage-accounting.ts +14 -4
  84. package/src/index.ts +11 -2
  85. package/src/model-discovery.ts +13 -57
@@ -8,7 +8,8 @@ import type { ProviderModelConfig } from "@earendil-works/pi-coding-agent";
8
8
  import type { ModelThinkingLevel, ThinkingLevelMap } from "@earendil-works/pi-ai/compat";
9
9
  import { loadContextWindowCache } from "./context-window-cache.js";
10
10
  import { loadCursorSdk } from "./cursor-sdk-runtime.js";
11
- import { resolveCursorApiKey } from "./cursor-api-key.js";
11
+ import { resolveCursorApiKey, resolveCursorRuntimeApiKey } from "./cursor-api-key.js";
12
+ import { scrubSensitiveText } from "./cursor-sensitive-text.js";
12
13
  import {
13
14
  fingerprintApiKey,
14
15
  loadAnyCachedModelCatalog,
@@ -16,12 +17,11 @@ import {
16
17
  saveModelListCache,
17
18
  } from "./model-list-cache.js";
18
19
 
19
- const CURSOR_PROVIDER_ID = "cursor";
20
20
  const FALLBACK_CONTEXT_WINDOW = 128000;
21
21
  const FALLBACK_MAX_TOKENS = 16384;
22
22
  const ZERO_COST = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
23
23
  const TEXT_AND_IMAGE_INPUT: ProviderModelConfig["input"] = ["text", "image"];
24
- const AUTH_SETUP_HINT = "/login (Use an API key -> Cursor), CURSOR_API_KEY, or --api-key with a Cursor SDK API key; Cursor Agent CLI/Desktop login is not reused";
24
+ const AUTH_SETUP_HINT = "/login (Use an API key -> Cursor) or CURSOR_API_KEY; startup discovery does not parse Pi CLI arguments, and Cursor Agent CLI/Desktop login is not reused";
25
25
  const CATALOG_REFRESH_HINT =
26
26
  "After adding auth to an already-started pi session, run /cursor-refresh-models to refresh the full live Cursor model catalog without restarting pi.";
27
27
 
@@ -35,47 +35,15 @@ export interface CursorModelFallbackIssue {
35
35
 
36
36
  export interface DiscoverModelsOptions {
37
37
  onFallback?: (issue: CursorModelFallbackIssue) => void;
38
+ apiKey?: string;
38
39
  // Bypass the on-disk model cache and always hit the live catalog. Used by the
39
40
  // /cursor-refresh-models command; the startup path leaves this false so warm
40
41
  // boots skip the slow network round-trip.
41
42
  forceRefresh?: boolean;
42
43
  }
43
44
 
44
- function getCliApiKeyFromArgv(argv: string[] = process.argv): string | undefined {
45
- for (let index = 0; index < argv.length; index++) {
46
- const arg = argv[index];
47
- if (arg === "--api-key") {
48
- const value = argv[index + 1];
49
- if (!value || value.startsWith("--")) return undefined;
50
- const trimmed = value.trim();
51
- return trimmed || undefined;
52
- }
53
- const prefix = "--api-key=";
54
- if (arg.startsWith(prefix)) {
55
- const trimmed = arg.slice(prefix.length).trim();
56
- return trimmed || undefined;
57
- }
58
- }
59
- return undefined;
60
- }
61
-
62
- async function getStoredCursorApiKey(): Promise<string | undefined> {
63
- try {
64
- const { AuthStorage } = await import("@earendil-works/pi-coding-agent");
65
- return resolveCursorApiKey(await AuthStorage.create().getApiKey(CURSOR_PROVIDER_ID, { includeFallback: false }));
66
- } catch {
67
- return undefined;
68
- }
69
- }
70
-
71
- async function getDiscoveryApiKey(): Promise<string | undefined> {
72
- const cliApiKey = resolveCursorApiKey(getCliApiKeyFromArgv());
73
- if (cliApiKey) return cliApiKey;
74
-
75
- const storedApiKey = await getStoredCursorApiKey();
76
- if (storedApiKey) return storedApiKey;
77
-
78
- return resolveCursorApiKey(process.env.CURSOR_API_KEY);
45
+ async function getDiscoveryApiKey(apiKey?: string): Promise<string | undefined> {
46
+ return resolveCursorApiKey(apiKey) ?? resolveCursorRuntimeApiKey();
79
47
  }
80
48
 
81
49
  export interface CursorModelMetadata {
@@ -136,7 +104,7 @@ function mapComparableLevel(
136
104
  level: Exclude<ModelThinkingLevel, "off">,
137
105
  ): string | null {
138
106
  if (level === "xhigh") {
139
- return getPreferredParameterValue(parameter, ["xhigh", "max", "extra-high"]);
107
+ return getPreferredParameterValue(parameter, ["xhigh", "extra-high"]);
140
108
  }
141
109
  return getParameterValue(parameter, level);
142
110
  }
@@ -156,6 +124,7 @@ function getThinkingLevelMap(item: ModelListItem): ThinkingLevelMap | undefined
156
124
  medium: null,
157
125
  high: getParameterValue(valueParameter, "true"),
158
126
  xhigh: null,
127
+ max: null,
159
128
  };
160
129
  }
161
130
 
@@ -169,6 +138,7 @@ function getThinkingLevelMap(item: ModelListItem): ThinkingLevelMap | undefined
169
138
  medium: mapComparableLevel(valueParameter, "medium"),
170
139
  high: mapComparableLevel(valueParameter, "high"),
171
140
  xhigh: mapComparableLevel(valueParameter, "xhigh"),
141
+ max: mapComparableLevel(valueParameter, "max"),
172
142
  };
173
143
  }
174
144
 
@@ -444,22 +414,9 @@ export function buildCursorModelSelection(
444
414
  return params.length > 0 ? { id: metadata.selectionModelId, params } : { id: metadata.selectionModelId };
445
415
  }
446
416
 
447
- function scrubDiscoveryErrorText(text: string, apiKey: string): string {
448
- let scrubbed = text.replace(new RegExp(apiKey.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g"), "[redacted]");
449
- return scrubbed
450
- .replace(/Bearer\s+[A-Za-z0-9._~+/=-]+/gi, "Bearer [redacted]")
451
- .replace(/((?:^|[\s,{])cookie["']?\s*[:=]\s*["']?)[^\n]+/gi, "$1[redacted]")
452
- .replace(
453
- /((?:authorization|api[_-]?key|apiKey|token|session(?:[_-]?id)?)["']?\s*[:=]\s*["']?)[^"'\s,;}]+/gi,
454
- "$1[redacted]",
455
- )
456
- .trim();
457
- }
458
-
459
417
  function sanitizeDiscoveryError(error: unknown, apiKey: string): string | undefined {
460
418
  const message = error instanceof Error ? error.message : typeof error === "string" ? error : "";
461
- const scrubbed = scrubDiscoveryErrorText(message, apiKey);
462
- return scrubbed || undefined;
419
+ return scrubSensitiveText(message, apiKey).trim() || undefined;
463
420
  }
464
421
 
465
422
  async function useFallbackModels(options: DiscoverModelsOptions, issue: CursorModelFallbackIssue): Promise<ProviderModelConfig[]> {
@@ -469,7 +426,7 @@ async function useFallbackModels(options: DiscoverModelsOptions, issue: CursorMo
469
426
  }
470
427
 
471
428
  export async function discoverModels(options: DiscoverModelsOptions = {}): Promise<ProviderModelConfig[]> {
472
- const apiKey = await getDiscoveryApiKey();
429
+ const apiKey = await getDiscoveryApiKey(options.apiKey);
473
430
  if (!apiKey) {
474
431
  return useFallbackModels(options, {
475
432
  reason: "missing-api-key",
@@ -506,8 +463,8 @@ export async function discoverModels(options: DiscoverModelsOptions = {}): Promi
506
463
  if (cachedCatalog && cachedCatalog.models.length > 0) {
507
464
  options.onFallback?.({
508
465
  reason: "cached-after-error",
509
- message: `Cursor model discovery failed; using cached Cursor model catalog from ${new Date(cachedCatalog.fetchedAt).toISOString()}. ${errorMessage}`,
510
- errorMessage,
466
+ message: `Cursor model discovery failed; using cached Cursor model catalog from ${new Date(cachedCatalog.fetchedAt).toISOString()}.${errorMessage ? ` ${errorMessage}` : ""}`,
467
+ ...(errorMessage ? { errorMessage } : {}),
511
468
  });
512
469
  return registerModelItems(cachedCatalog.models);
513
470
  }
@@ -522,6 +479,5 @@ export async function discoverModels(options: DiscoverModelsOptions = {}): Promi
522
479
  export const __testUtils = {
523
480
  parseContextWindow,
524
481
  registerModelItems,
525
- getCliApiKeyFromArgv,
526
482
  normalizeApiKey: resolveCursorApiKey,
527
483
  };