pi-cursor-sdk 0.2.0 → 0.3.7

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 (177) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/README.md +55 -51
  3. package/dist/bundled-context-windows.js +39 -0
  4. package/dist/context-window-cache.js +92 -0
  5. package/dist/context.js +353 -0
  6. package/dist/cursor-active-tools.js +3 -0
  7. package/dist/cursor-agent-message-web-tools.js +165 -0
  8. package/dist/cursor-agents-context-registration.js +17 -0
  9. package/dist/cursor-agents-context.js +127 -0
  10. package/dist/cursor-api-key.js +34 -0
  11. package/dist/cursor-bridge-contract.js +27 -0
  12. package/dist/cursor-cloud-lifecycle.js +650 -0
  13. package/dist/cursor-cloud-local-state.js +460 -0
  14. package/dist/cursor-cloud-options.js +145 -0
  15. package/dist/cursor-cloud-reporting.js +222 -0
  16. package/dist/cursor-compact-tool-summary.js +75 -0
  17. package/dist/cursor-config.js +613 -0
  18. package/dist/cursor-context-tools.js +6 -0
  19. package/dist/cursor-display-only-trace.js +11 -0
  20. package/dist/cursor-display-text.js +18 -0
  21. package/dist/cursor-durable-fs.js +53 -0
  22. package/dist/cursor-edit-diff.js +13 -0
  23. package/dist/cursor-env-boolean.js +19 -0
  24. package/dist/cursor-fallback-models.generated.js +7760 -0
  25. package/dist/cursor-fallback-warning.js +15 -0
  26. package/dist/cursor-http1.js +45 -0
  27. package/dist/cursor-incomplete-tool-visibility.js +83 -0
  28. package/dist/cursor-live-run-accounting.js +55 -0
  29. package/dist/cursor-live-run-coordinator.js +409 -0
  30. package/dist/cursor-mcp-timeout-override.js +116 -0
  31. package/dist/cursor-model-lifecycle.js +32 -0
  32. package/dist/cursor-model.js +5 -0
  33. package/dist/cursor-native-replay-routing.js +35 -0
  34. package/dist/cursor-native-replay-trace.js +28 -0
  35. package/dist/cursor-native-tool-display-registration.js +102 -0
  36. package/dist/cursor-native-tool-display-replay.js +428 -0
  37. package/dist/cursor-native-tool-display-state.js +70 -0
  38. package/dist/cursor-native-tool-display-tools.js +123 -0
  39. package/dist/cursor-native-tool-names.js +11 -0
  40. package/dist/cursor-partial-content-emitter.js +130 -0
  41. package/dist/cursor-pi-context.js +30 -0
  42. package/dist/cursor-pi-tool-bridge-abort.js +114 -0
  43. package/dist/cursor-pi-tool-bridge-constants.js +6 -0
  44. package/dist/cursor-pi-tool-bridge-diagnostics.js +125 -0
  45. package/dist/cursor-pi-tool-bridge-env.js +18 -0
  46. package/dist/cursor-pi-tool-bridge-mcp.js +100 -0
  47. package/dist/cursor-pi-tool-bridge-run.js +355 -0
  48. package/dist/cursor-pi-tool-bridge-server.js +163 -0
  49. package/dist/cursor-pi-tool-bridge-snapshot.js +63 -0
  50. package/dist/cursor-pi-tool-bridge-types.js +1 -0
  51. package/dist/cursor-pi-tool-bridge.js +123 -0
  52. package/dist/cursor-provider-errors.js +311 -0
  53. package/dist/cursor-provider-lazy.js +39 -0
  54. package/dist/cursor-provider-live-run-drain.js +420 -0
  55. package/dist/cursor-provider-overflow.js +90 -0
  56. package/dist/cursor-provider-run-finalizer.js +176 -0
  57. package/dist/cursor-provider-run-outcome.js +76 -0
  58. package/dist/cursor-provider-turn-coordinator.js +293 -0
  59. package/dist/cursor-provider-turn-display-router.js +158 -0
  60. package/dist/cursor-provider-turn-emit.js +41 -0
  61. package/dist/cursor-provider-turn-finalize.js +154 -0
  62. package/dist/cursor-provider-turn-lifecycle-emitter.js +126 -0
  63. package/dist/cursor-provider-turn-prepare.js +379 -0
  64. package/dist/cursor-provider-turn-runner.js +146 -0
  65. package/dist/cursor-provider-turn-sdk-normalizer.js +74 -0
  66. package/dist/cursor-provider-turn-send.js +138 -0
  67. package/dist/cursor-provider-turn-shell-output.js +117 -0
  68. package/dist/cursor-provider-turn-tool-ledger.js +99 -0
  69. package/dist/cursor-provider-turn-types.js +1 -0
  70. package/dist/cursor-provider.js +72 -0
  71. package/dist/cursor-question-tool.js +194 -0
  72. package/dist/cursor-record-utils.js +61 -0
  73. package/dist/cursor-replay-activity-builders.js +114 -0
  74. package/dist/cursor-replay-source-names.js +27 -0
  75. package/dist/cursor-replay-summary-args.js +105 -0
  76. package/dist/cursor-replay-tool-details.js +167 -0
  77. package/dist/cursor-ripgrep-path.js +27 -0
  78. package/dist/cursor-run-final-text.js +63 -0
  79. package/dist/cursor-runtime-state.js +380 -0
  80. package/dist/cursor-sdk-billed-usage.js +86 -0
  81. package/dist/cursor-sdk-event-debug-constants.js +33 -0
  82. package/dist/cursor-sdk-event-debug-session.js +107 -0
  83. package/dist/cursor-sdk-event-debug.js +461 -0
  84. package/dist/cursor-sdk-output-filter.js +1 -0
  85. package/dist/cursor-sdk-process-error-guard.js +221 -0
  86. package/dist/cursor-sdk-runtime.js +3 -0
  87. package/dist/cursor-sensitive-text.js +23 -0
  88. package/dist/cursor-session-agent-cleanup.js +311 -0
  89. package/dist/cursor-session-agent-lifecycle.js +32 -0
  90. package/dist/cursor-session-agent-lineage.js +103 -0
  91. package/dist/cursor-session-agent-resume.js +417 -0
  92. package/dist/cursor-session-agent.js +507 -0
  93. package/dist/cursor-session-compaction-prep.js +21 -0
  94. package/dist/cursor-session-scope.js +113 -0
  95. package/dist/cursor-session-send-policy.js +18 -0
  96. package/dist/cursor-session-store.js +105 -0
  97. package/dist/cursor-session-turn-queue.js +50 -0
  98. package/dist/cursor-setting-sources.js +15 -0
  99. package/dist/cursor-skill-tool.js +230 -0
  100. package/dist/cursor-state.js +519 -0
  101. package/dist/cursor-task-presentation.js +59 -0
  102. package/dist/cursor-tool-lifecycle.js +94 -0
  103. package/dist/cursor-tool-manifest.js +34 -0
  104. package/dist/cursor-tool-presentation-registry.js +305 -0
  105. package/dist/cursor-tool-result-display-readers.js +158 -0
  106. package/dist/cursor-tool-transcript.js +32 -0
  107. package/dist/cursor-tool-visibility.js +28 -0
  108. package/dist/cursor-transcript-tool-formatters.js +618 -0
  109. package/dist/cursor-transcript-tool-specs.js +284 -0
  110. package/dist/cursor-transcript-utils.js +170 -0
  111. package/dist/cursor-usage-accounting.js +166 -0
  112. package/dist/cursor-web-tool-activity.js +23 -0
  113. package/dist/cursor-web-tool-args.js +12 -0
  114. package/dist/index.js +82 -0
  115. package/dist/model-discovery.js +305 -0
  116. package/dist/model-list-cache.js +156 -0
  117. package/docs/cursor-dogfood-checklist.md +2 -1
  118. package/docs/cursor-live-smoke-checklist.md +13 -12
  119. package/docs/cursor-model-ux-spec.md +27 -6
  120. package/docs/cursor-native-tool-replay.md +13 -13
  121. package/docs/cursor-native-tool-visual-audit.md +6 -3
  122. package/docs/cursor-testing-lessons.md +14 -8
  123. package/docs/cursor-tool-surfaces.md +5 -5
  124. package/docs/platform-smoke.md +3 -3
  125. package/package.json +19 -7
  126. package/platform-smoke.config.mjs +1 -1
  127. package/scripts/build.mjs +126 -0
  128. package/scripts/cloud-runtime-smoke.mjs +3 -1
  129. package/scripts/debug-provider-events.mjs +3 -1
  130. package/scripts/debug-sdk-events.mjs +1 -1
  131. package/scripts/isolated-cursor-smoke.sh +5 -4
  132. package/scripts/lib/cloud-smoke-cleanup-evidence.mjs +1 -1
  133. package/scripts/lib/cursor-visual-render.mjs +1 -1
  134. package/scripts/lib/ensure-built.mjs +16 -0
  135. package/scripts/lib/local-resume-smoke-harness.mjs +1 -1
  136. package/scripts/local-resume-smoke.mjs +3 -1
  137. package/scripts/platform-smoke/card-detect.mjs +1 -1
  138. package/scripts/platform-smoke/live-suite-runner.mjs +1 -1
  139. package/scripts/platform-smoke/render-ansi.mjs +1 -1
  140. package/scripts/platform-smoke/targets.mjs +2 -2
  141. package/scripts/prepare.mjs +102 -0
  142. package/scripts/steering-rpc-smoke.mjs +4 -2
  143. package/scripts/tmux-live-smoke.sh +11 -11
  144. package/scripts/visual-tui-smoke-self-test.mjs +4 -1
  145. package/scripts/visual-tui-smoke.mjs +51 -7
  146. package/src/bundled-context-windows.ts +4 -1
  147. package/src/context.ts +27 -4
  148. package/src/cursor-agents-context-registration.ts +2 -2
  149. package/src/cursor-agents-context.ts +24 -10
  150. package/src/cursor-api-key.ts +5 -4
  151. package/src/cursor-cloud-reporting.ts +23 -2
  152. package/src/cursor-context-tools.ts +3 -1
  153. package/src/cursor-fallback-models.generated.ts +592 -204
  154. package/src/cursor-live-run-coordinator.ts +11 -6
  155. package/src/cursor-native-tool-display-registration.ts +10 -11
  156. package/src/cursor-partial-content-emitter.ts +13 -0
  157. package/src/cursor-pi-context.ts +44 -0
  158. package/src/cursor-provider-errors.ts +1 -1
  159. package/src/cursor-provider-lazy.ts +5 -4
  160. package/src/cursor-provider-live-run-drain.ts +14 -9
  161. package/src/cursor-provider-run-finalizer.ts +1 -0
  162. package/src/cursor-provider-turn-coordinator.ts +15 -0
  163. package/src/cursor-provider-turn-emit.ts +6 -0
  164. package/src/cursor-provider-turn-finalize.ts +12 -0
  165. package/src/cursor-provider-turn-prepare.ts +10 -5
  166. package/src/cursor-provider-turn-types.ts +2 -0
  167. package/src/cursor-sdk-billed-usage.ts +107 -0
  168. package/src/cursor-sdk-process-error-guard.ts +6 -4
  169. package/src/cursor-session-agent-lifecycle.ts +8 -9
  170. package/src/cursor-session-agent-resume.ts +23 -0
  171. package/src/cursor-session-compaction-prep.ts +4 -0
  172. package/src/cursor-skill-tool.ts +1 -1
  173. package/src/cursor-tool-manifest.ts +1 -1
  174. package/src/cursor-usage-accounting.ts +70 -9
  175. package/src/index.ts +1 -1
  176. package/tsconfig.build.json +8 -0
  177. package/tsconfig.json +16 -0
@@ -10,6 +10,7 @@ import { tmpdir } from "node:os";
10
10
  import { dirname, join, resolve } from "node:path";
11
11
  import { fileURLToPath, pathToFileURL } from "node:url";
12
12
  import { terminateChild } from "./lib/cursor-child-process.mjs";
13
+ import { ensureBuilt } from "./lib/ensure-built.mjs";
13
14
  import { buildCursorSmokeEnv } from "./lib/cursor-smoke-env.mjs";
14
15
  import {
15
16
  checkpointCloudSmokeShutdown,
@@ -50,7 +51,7 @@ import { scrubSensitiveText } from "../shared/cursor-sensitive-text.mjs";
50
51
 
51
52
  const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
52
53
  const EVIDENCE_PATH = join(root, "docs", "evidence", "cursor-cloud-smoke-matrix-latest.json");
53
- const MODEL = "cursor/composer-2-5";
54
+ const MODEL = "cursor/grok-4.6";
54
55
  const CLOUD_RUN_ID_PATTERN = /^run-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
55
56
  const cloudSmokeShutdown = createCloudSmokeShutdownController((child) => terminateChild(child, { graceMs: 15_000 }));
56
57
  const argv = process.argv.slice(2);
@@ -614,6 +615,7 @@ async function main() {
614
615
  }
615
616
 
616
617
  if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
618
+ ensureBuilt();
617
619
  main().catch((error) => {
618
620
  reportFailure(error);
619
621
  process.exit(1);
@@ -23,6 +23,7 @@ import {
23
23
  } from "./lib/cursor-child-process.mjs";
24
24
  import { scrubSensitiveText } from "../shared/cursor-sensitive-text.mjs";
25
25
  import { createScriptFail } from "./lib/cursor-script-fail.mjs";
26
+ import { ensureBuilt } from "./lib/ensure-built.mjs";
26
27
  import { serializeCursorSettingSources } from "../shared/cursor-setting-sources.mjs";
27
28
 
28
29
  function isMainModule() {
@@ -35,7 +36,7 @@ function isMainModule() {
35
36
  const require = createRequire(import.meta.url);
36
37
  const root = fileURLToPath(new URL("..", import.meta.url));
37
38
  const packageJson = require("../package.json");
38
- const DEFAULT_MODEL = "cursor/composer-2-5";
39
+ const DEFAULT_MODEL = "cursor/grok-4.6";
39
40
  const DEFAULT_OUT_BASE = ".debug/cursor-sdk-events";
40
41
  const SDK_EVENT_DEBUG_LOG_PREFIX = "[pi-cursor-sdk:sdk-events]";
41
42
  const PI_SESSION_SNAPSHOT_ARTIFACT = "pi-session-snapshot.jsonl";
@@ -301,6 +302,7 @@ async function main(argv = process.argv.slice(2), env = process.env) {
301
302
  printHelp();
302
303
  return;
303
304
  }
305
+ ensureBuilt();
304
306
  console.log(JSON.stringify(await runDebugProviderEvents(args, env)));
305
307
  }
306
308
 
@@ -39,7 +39,7 @@ const ARTIFACTS = {
39
39
  summary: "summary.json",
40
40
  };
41
41
 
42
- const DEFAULT_MODEL = "composer-2.5";
42
+ const DEFAULT_MODEL = "grok-4.6";
43
43
  const RAW_ARTIFACT_WARNING =
44
44
  "Raw artifact files may contain local paths, project text, tool args/results, or secrets from the workspace. Do not commit or share them.";
45
45
 
@@ -134,7 +134,7 @@ run_self_test() {
134
134
  env_capture="$temp_dir/fake-pi.env"
135
135
  cat >"$fake_pi" <<EOF_SELFTEST_PI
136
136
  #!/usr/bin/env node
137
- const { writeFileSync } = require("node:fs");
137
+ import { writeFileSync } from "node:fs";
138
138
  writeFileSync("$env_capture", Object.entries(process.env).map(([key, value]) => key + "=" + (value ?? "")).join("\\n") + "\\n", "utf8");
139
139
  EOF_SELFTEST_PI
140
140
  cat >"$fake_node" <<EOF_SELFTEST_NODE
@@ -359,13 +359,14 @@ log "check: list-models"
359
359
  LIST_OUT="$ISOLATED/list-models.txt"
360
360
  run_in_dir_capture_combined "list-models" 30 "$PROJECT_DIR" "$LIST_OUT" "${PI_CURSOR_ENV[@]}" \
361
361
  "$PI_BIN" --approve --cursor-no-fast --list-models cursor
362
+ "$RG_BIN" -q "grok-4\\.6" "$LIST_OUT" || fail "grok-4.6 not listed (see $LIST_OUT)"
362
363
  "$RG_BIN" -q "composer-2\\.5|composer-2-5" "$LIST_OUT" || fail "composer-2-5 not listed (see $LIST_OUT)"
363
364
 
364
365
  log "check: basic provider prompt"
365
366
  BASIC_DIR="$SESSION_ROOT/basic"
366
367
  mkdir -p "$BASIC_DIR"
367
368
  run_in_dir_capture_split "basic prompt" "$PI_LIVE_TIMEOUT" "$PROJECT_DIR" "$ISOLATED/basic.stdout.txt" "$ISOLATED/basic.stderr.txt" "${PI_CURSOR_ENV[@]}" \
368
- "$PI_BIN" --approve --cursor-no-fast --model cursor/composer-2-5 --session-dir "$BASIC_DIR" --no-tools -p 'Reply exactly: PI_CURSOR_ISOLATED_OK'
369
+ "$PI_BIN" --approve --cursor-no-fast --model cursor/grok-4.6 --session-dir "$BASIC_DIR" --no-tools -p 'Reply exactly: PI_CURSOR_ISOLATED_OK'
369
370
  "$RG_BIN" -q "PI_CURSOR_ISOLATED_OK" "$ISOLATED/basic.stdout.txt" || fail "basic prompt missing PI_CURSOR_ISOLATED_OK"
370
371
  validate_replay_jsonl "$BASIC_DIR"
371
372
 
@@ -373,14 +374,14 @@ log "check: native replay"
373
374
  REPLAY_DIR="$SESSION_ROOT/native-replay"
374
375
  mkdir -p "$REPLAY_DIR"
375
376
  run_in_dir_capture_split "native replay" "$PI_LIVE_TIMEOUT" "$PROJECT_DIR" "$ISOLATED/replay.stdout.txt" "$ISOLATED/replay.stderr.txt" "${PI_CURSOR_ENV[@]}" PI_CURSOR_NATIVE_TOOL_DISPLAY=1 \
376
- "$PI_BIN" --approve --cursor-no-fast --model cursor/composer-2-5 --session-dir "$REPLAY_DIR" -p 'Read ./README.md briefly, then answer README_SEEN=yes if it mentions pi-cursor-sdk.'
377
+ "$PI_BIN" --approve --cursor-no-fast --model cursor/grok-4.6 --session-dir "$REPLAY_DIR" -p 'Read ./README.md briefly, then answer README_SEEN=yes if it mentions pi-cursor-sdk.'
377
378
  validate_replay_jsonl "$REPLAY_DIR"
378
379
 
379
380
  log "check: plan-strip shim (plan-mode execute reset)"
380
381
  PLAN_DIR="$SESSION_ROOT/plan-strip"
381
382
  mkdir -p "$PLAN_DIR"
382
383
  run_in_dir_capture_split "plan-strip replay" "$PI_LIVE_TIMEOUT" "$PROJECT_DIR" "$ISOLATED/plan.stdout.txt" "$ISOLATED/plan.stderr.txt" "${PI_CURSOR_ENV[@]}" PI_CURSOR_NATIVE_TOOL_DISPLAY=1 \
383
- "$PI_BIN" --approve -e "$SHIM_DIR" --cursor-no-fast --model cursor/composer-2-5 --session-dir "$PLAN_DIR" -p 'After reset, read README.md and answer PLAN_STRIP_OK=yes.'
384
+ "$PI_BIN" --approve -e "$SHIM_DIR" --cursor-no-fast --model cursor/grok-4.6 --session-dir "$PLAN_DIR" -p 'After reset, read README.md and answer PLAN_STRIP_OK=yes.'
384
385
  validate_replay_jsonl "$PLAN_DIR"
385
386
 
386
387
  log "PASS isolated install smoke: $ISOLATED"
@@ -360,7 +360,7 @@ function buildCloudSmokeMatrixEvidence(input, laneProjector, allowDefaultTimesta
360
360
  } = data;
361
361
  const timestamp = data.timestamp ?? (allowDefaultTimestamp ? new Date().toISOString() : undefined);
362
362
  if (schemaVersion !== 1) fail("cloud smoke evidence schemaVersion must be 1");
363
- if (model !== "cursor/composer-2-5") fail("cloud smoke evidence model must be cursor/composer-2-5");
363
+ if (model !== "cursor/grok-4.6") fail("cloud smoke evidence model must be cursor/grok-4.6");
364
364
  if (!Array.isArray(lanes) || lanes.length !== LANE_NAMES.length) fail("cloud smoke evidence lanes must contain the complete required matrix");
365
365
  if (!Array.isArray(cleanup) || cleanup.length === 0) fail("cloud smoke evidence cleanup must be a non-empty array");
366
366
  const projectedLanes = lanes.map((lane, index) => laneProjector(lane, index));
@@ -66,7 +66,7 @@ header code { color: #d8dee9; }
66
66
  <header>
67
67
  <div><strong>pi-cursor-sdk visual smoke</strong> <code>${escapeHtml(options.label)}</code></div>
68
68
  <div>model <code>${escapeHtml(options.model)}</code> · mode <code>${escapeHtml(options.mode)}</code> · cwd <code>${escapeHtml(options.cwd)}</code></div>
69
- <div>session <code>${escapeHtml(options.sessionId)}</code> · captured ${new Date().toISOString()}</div>
69
+ <div>session <code>${escapeHtml(options.sessionId ?? "pi-assigned")}</code> · captured ${new Date().toISOString()}</div>
70
70
  </header>
71
71
  <div id="terminal"></div>
72
72
  <noscript><pre class="fallback">${escapeHtml(plain)}</pre></noscript>
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Rebuild dist/ before a launcher loads the repo-root extension, so direct
3
+ * `node scripts/<launcher>.mjs` invocations can never exercise stale code.
4
+ */
5
+
6
+ import { execFileSync } from "node:child_process";
7
+ import { fileURLToPath } from "node:url";
8
+
9
+ export function ensureBuilt() {
10
+ execFileSync(process.execPath, [fileURLToPath(new URL("../build.mjs", import.meta.url))], {
11
+ // build.mjs anchors tsc/dist/staging to its cwd; pin it to the repo root so
12
+ // direct launcher invocations work from any directory.
13
+ cwd: fileURLToPath(new URL("../..", import.meta.url)),
14
+ stdio: "inherit",
15
+ });
16
+ }
@@ -152,7 +152,7 @@ export function startRpc({
152
152
  baseEnv = process.env,
153
153
  }) {
154
154
  const model =
155
- process.env.CURSOR_LOCAL_RESUME_SMOKE_MODEL || "cursor/composer-2-5:slow";
155
+ process.env.CURSOR_LOCAL_RESUME_SMOKE_MODEL || "cursor/grok-4.6:slow";
156
156
  const workspaceDir = join(artifactDir, "workspace");
157
157
  mkdirSync(workspaceDir, { recursive: true });
158
158
  const pi = findPiCommand();
@@ -26,6 +26,7 @@ import {
26
26
  withRpc,
27
27
  writeTreeCommandExtension,
28
28
  } from "./lib/local-resume-smoke-harness.mjs";
29
+ import { ensureBuilt } from "./lib/ensure-built.mjs";
29
30
  import { runCleanupSmoke } from "./local-resume-cleanup-smoke.mjs";
30
31
  import { writePlatformArtifactBundle } from "./platform-smoke/artifacts.mjs";
31
32
  import { LOCAL_RESUME_SUITES } from "./platform-smoke/local-resume-suites.mjs";
@@ -45,7 +46,7 @@ ${npmUsage}
45
46
  ${nodeUsage}
46
47
 
47
48
  Environment:
48
- CURSOR_LOCAL_RESUME_SMOKE_MODEL Cursor model id (default: cursor/composer-2-5:slow).
49
+ CURSOR_LOCAL_RESUME_SMOKE_MODEL Cursor model id (default: cursor/grok-4.6:slow).
49
50
  CURSOR_LOCAL_RESUME_SMOKE_TIMEOUT_MS Timeout in ms per model turn (default: 300000).
50
51
  CURSOR_LOCAL_RESUME_SMOKE_KEEP_ARTIFACTS Keep temp artifacts when set to 1.
51
52
  CURSOR_LOCAL_RESUME_SMOKE_EXTENSION_PATH Packed extension path override (platform runner only).
@@ -627,6 +628,7 @@ function selectedRun() {
627
628
  }
628
629
 
629
630
  if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
631
+ ensureBuilt();
630
632
  const run = selectedRun();
631
633
  run()
632
634
  .catch((error) => {
@@ -31,7 +31,7 @@ const CARD_PATTERNS = [
31
31
  { id: "bridge-read-failure", pattern: /^\s*(?:read \.\/definitely-missing-platform-smoke-file\.txt|ENOENT: no such file)\s*/i },
32
32
  { id: "bridge-shell-success", pattern: /^\s*bridge visual smoke\s*$/i },
33
33
  { id: "http1-status", pattern: /\bcursor:local\b.*\bhttp1\b/i },
34
- { id: "footer-status", pattern: /\bcomposer-2-5\b|\bcomposer-2\.5\b/i },
34
+ { id: "footer-status", pattern: /\bgrok-4\.6\b|\bcomposer-2-5\b|\bcomposer-2\.5\b/i },
35
35
  ];
36
36
 
37
37
  function cleanLine(line) {
@@ -17,7 +17,7 @@ import { redactSecrets, writePlatformArtifactBundle } from "./artifacts.mjs";
17
17
  import { extractContentText, jsonlHasAssistantFinalTextMarker } from "./jsonl-text.mjs";
18
18
  import { getScenario, renderPrompt } from "./scenarios.mjs";
19
19
 
20
- const DEFAULT_MODEL = "cursor/composer-2-5";
20
+ const DEFAULT_MODEL = "cursor/grok-4.6";
21
21
  const DEFAULT_WAIT_MS = 240_000;
22
22
  const SESSION_JSONL_WAIT_MS = 60_000;
23
23
  const COLS = 150;
@@ -27,7 +27,7 @@ export async function renderHTML(ansiPath, htmlPath, options = {}) {
27
27
  plain,
28
28
  options: {
29
29
  label: options.label ?? "platform-smoke",
30
- model: options.model ?? "cursor/composer-2-5",
30
+ model: options.model ?? "cursor/grok-4.6",
31
31
  mode: options.mode ?? "agent",
32
32
  cwd: options.cwd ?? process.cwd(),
33
33
  sessionId: options.sessionId ?? "platform-smoke",
@@ -413,7 +413,7 @@ export function buildPlatformBuildCommand(targetName, packageName = "pi-cursor-s
413
413
  lines.push(...posixSection("CHECK_PLATFORM_SMOKE_STDERR", 'cat "$PACK_DIR/check-platform-smoke.stderr.txt" 2>/dev/null || true'));
414
414
  lines.push("");
415
415
  lines.push('echo "=== npm test ==="');
416
- lines.push('npm test >"$PACK_DIR/npm-test.stdout.txt" 2>"$PACK_DIR/npm-test.stderr.txt"');
416
+ lines.push('npm test -- --testTimeout=15000 >"$PACK_DIR/npm-test.stdout.txt" 2>"$PACK_DIR/npm-test.stderr.txt"');
417
417
  lines.push("TEST_EXIT=$?");
418
418
  lines.push('echo "PLATFORM_NPM_TEST_EXIT=$TEST_EXIT"');
419
419
  lines.push(...posixSection("NPM_TEST_STDOUT", 'cat "$PACK_DIR/npm-test.stdout.txt" 2>/dev/null || true'));
@@ -662,7 +662,7 @@ async function executeLiveSuite(config, targetName, suiteName, suiteDir, slug, l
662
662
  }
663
663
 
664
664
  function buildLiveSuiteCommand(config, targetName, suiteName, prepDir) {
665
- const model = config.cursorModel ?? "cursor/composer-2-5";
665
+ const model = config.cursorModel ?? "cursor/grok-4.6";
666
666
  const packageName = config.packageName ?? "pi-cursor-sdk";
667
667
  const prepArgs = prepDir ? ` --prep-dir ${platformFor(targetName) === "powershell" ? prepDir : shellQuote(prepDir)}` : "";
668
668
  if (platformFor(targetName) === "powershell") {
@@ -0,0 +1,102 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Purpose: Build generated dist output for GitHub/source installs even when Pi invokes npm install --omit=dev.
4
+ * Responsibilities: Detect missing source-build dependencies via the local node_modules tree, install dev
5
+ * dependencies with lifecycle scripts disabled, run the canonical build, then prune the dev tree so installs
6
+ * keep a runtime-only footprint.
7
+ * Scope: Package install lifecycle only; runtime behavior remains owned by scripts/build.mjs.
8
+ * Usage: package.json prepare script.
9
+ */
10
+
11
+ import { execFile as execFileCallback } from "node:child_process";
12
+ import { existsSync } from "node:fs";
13
+ import { join } from "node:path";
14
+ import process from "node:process";
15
+ import { promisify } from "node:util";
16
+
17
+ const execFile = promisify(execFileCallback);
18
+
19
+ // Checked as literal node_modules paths: require.resolve() is unusable here because
20
+ // several @earendil-works packages expose import-only "exports" maps and throw
21
+ // ERR_PACKAGE_PATH_NOT_EXPORTED even when installed.
22
+ const REQUIRED_SOURCE_BUILD_MODULES = [
23
+ "typescript",
24
+ "typebox",
25
+ "@earendil-works/pi-ai",
26
+ "@earendil-works/pi-coding-agent",
27
+ "@earendil-works/pi-tui",
28
+ ];
29
+
30
+ function hasBuildDependencies() {
31
+ return REQUIRED_SOURCE_BUILD_MODULES.every((moduleName) =>
32
+ existsSync(join(process.cwd(), "node_modules", ...moduleName.split("/"), "package.json")),
33
+ );
34
+ }
35
+
36
+ async function runNpm(args) {
37
+ const npmExecPath = process.env.npm_execpath;
38
+ if (!npmExecPath) {
39
+ throw new Error(
40
+ `npm_execpath is not set; run "npm ${args.join(" ")}" manually in ${process.cwd()} and retry.`,
41
+ );
42
+ }
43
+ // No shell: process.execPath runs npm's cli.js directly, which is safe for paths
44
+ // containing spaces on every platform (shell:true concatenates args unescaped).
45
+ await execFile(process.execPath, [npmExecPath, ...args], {
46
+ cwd: process.cwd(),
47
+ maxBuffer: 20 * 1024 * 1024,
48
+ });
49
+ }
50
+
51
+ async function runBuild() {
52
+ const { stderr, stdout } = await execFile(process.execPath, [join(process.cwd(), "scripts", "build.mjs")], {
53
+ cwd: process.cwd(),
54
+ maxBuffer: 20 * 1024 * 1024,
55
+ });
56
+ // Forward build output on success too: install-time diagnostics such as the
57
+ // concurrent-swap race-loss warning are otherwise swallowed.
58
+ if (stdout) process.stdout.write(stdout);
59
+ if (stderr) process.stderr.write(stderr);
60
+ }
61
+
62
+ async function pruneDevDependencies() {
63
+ await runNpm(["prune", "--omit=dev", "--ignore-scripts"]);
64
+ }
65
+
66
+ async function pruneQuietly() {
67
+ try {
68
+ await pruneDevDependencies();
69
+ } catch (error) {
70
+ console.warn(`npm prune failed after a failed build: ${error?.message ?? error}`);
71
+ }
72
+ }
73
+
74
+ function reportError(error) {
75
+ if (error?.stdout) process.stdout.write(error.stdout);
76
+ if (error?.stderr) process.stderr.write(error.stderr);
77
+ console.error(error instanceof Error ? error.message : String(error));
78
+ }
79
+
80
+ async function main() {
81
+ if (hasBuildDependencies()) {
82
+ await runBuild();
83
+ return;
84
+ }
85
+ await runNpm(["install", "--include=dev", "--ignore-scripts"]);
86
+ try {
87
+ await runBuild();
88
+ } catch (buildError) {
89
+ // Report the build first; cleanup can warn afterward but never mask it.
90
+ reportError(buildError);
91
+ await pruneQuietly();
92
+ process.exitCode = 1;
93
+ return;
94
+ }
95
+ // A prune failure after a successful build still fails the install.
96
+ await pruneDevDependencies();
97
+ }
98
+
99
+ main().catch((error) => {
100
+ reportError(error);
101
+ process.exitCode = 1;
102
+ });
@@ -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/composer-2-5", "--mode", "rpc", "--session-dir", sessionDir];
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\nconst { writeFileSync } = require("node:fs");\nwriteFileSync(${JSON.stringify(envCapture)}, Object.entries(process.env).map(([key, value]) => key + "=" + (value ?? "")).join("\\n") + "\\n", "utf8");\n`,
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\\) composer-2[-.]5" "$capture" || missing="${missing} footer (cursor) composer-2-5"
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 "composer-2\.5" "$file"
314
+ "$RG_BIN" -q "grok-4\.6" "$file"
315
315
  else
316
- grep -q "composer-2\.5" "$file"
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
- capture_and_require_composer_model() {
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/composer-2-5 not listed"
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
- const { writeFileSync } = require("node:fs");
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 capture_and_require_composer_model helper.
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/composer-2.5\n'
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" capture_and_require_composer_model "$fake_list_pi"
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/composer-2-5
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
- capture_and_require_composer_model "${NONE_ENV[@]}" "${PI_BASE[@]}" --list-models cursor
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\nconst { writeFileSync } = require("node:fs");\nwriteFileSync(${JSON.stringify(envCapture)}, Object.entries(process.env).map(([key, value]) => key + "=" + (value ?? "")).join("\\n") + "\\n", "utf8");\n`,
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/composer-2-5";
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: visual-<label>-<timestamp>.
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.sessionId ??= `visual-${options.safeLabel}-${Date.now()}`;
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 envAssignments = smokeEnvPlan.envEntries;
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, ["new-session", "-d", "-s", sessionName, "-x", String(options.width), "-y", String(options.height), "--", shell, "-lc", script]);
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
 
@@ -1,4 +1,4 @@
1
- // Generated from Cursor SDK checkpoint tokenDetails.maxTokens on 2026-08-02.
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
3
  // Keys are current selectable model IDs. Equivalent default :fast/:slow selections
4
4
  // collapse to one key; stale and ambiguous aliases are omitted. Values are observed
@@ -6,6 +6,7 @@
6
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,
9
10
  "claude-fable-5@300k": 300000,
10
11
  "claude-haiku-4-5": 200000,
11
12
  "claude-opus-4-5": 200000,
@@ -17,6 +18,7 @@ export const BUNDLED_CONTEXT_WINDOWS = {
17
18
  "gemini-3.1-pro": 200000,
18
19
  "gemini-3.5-flash": 200000,
19
20
  "gemini-3.6-flash": 200000,
21
+ "gemini-3.7-flash": 200000,
20
22
  "glm-5.2": 200000,
21
23
  "gpt-5-5@272k": 272000,
22
24
  "gpt-5-mini": 272000,
@@ -29,6 +31,7 @@ export const BUNDLED_CONTEXT_WINDOWS = {
29
31
  "gpt-5.6@1m": 272000,
30
32
  "grok-4.5": 256000,
31
33
  "grok-4.5:slow": 256000,
34
+ "grok-4.6": 256000,
32
35
  "kimi-k2.7-code": 200000,
33
36
  "kimi-k3": 200000,
34
37
  "opus-4.8@1m": 300000,