@tiny-fish/cli 0.26.1-next.225 → 0.26.1-next.226

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.
@@ -5,7 +5,7 @@ import { HoistedFailureReportedError, installTinyFishCli, SKILL_INSTALL_TIMEOUT_
5
5
  import { ensureCliAuthenticated } from "../lib/connect-auth.js";
6
6
  import { installWebSkill } from "../lib/skill-install.js";
7
7
  import { ConnectInterruptedError, ConnectStepError, createConnectTelemetry, finishSetupCommand, requireCommandSupport, runGuarded, settle, spawnStepError, throwIfInterrupted, NON_INTERACTIVE_TIMEOUT_MS, } from "../lib/connect-runtime.js";
8
- import { cursorInstallDeeplink, cursorMcpPath, writeCursorMcpConfig, } from "../lib/cursor-config.js";
8
+ import { cursorInstallDeeplink, cursorMcpPath, readCursorTinyfishEntry, writeCursorMcpConfig, } from "../lib/cursor-config.js";
9
9
  import { runConnectAll } from "../lib/connect-all.js";
10
10
  import { AuthMode } from "../lib/harness-detect.js";
11
11
  import { detectHumanInitiated } from "../lib/harness.js";
@@ -319,7 +319,36 @@ export async function connectOpenClaw(options) {
319
319
  }
320
320
  /** Writes mcp.json directly — no `cursor mcp add` exists. */
321
321
  export async function connectCursor(options) {
322
- const telemetry = createConnectTelemetry(options.mcpUrl, "cursor", options);
322
+ let fallbackAttemptId;
323
+ const registeredUrl = readCursorTinyfishEntry().url;
324
+ if (registeredUrl) {
325
+ try {
326
+ const registered = new URL(registeredUrl);
327
+ const requested = new URL(options.mcpUrl);
328
+ const registeredId = registered.searchParams.get("connect_attempt_id");
329
+ const registeredSource = registered.searchParams.get("source");
330
+ const registeredClient = registered.searchParams.get("client");
331
+ for (const key of ["source", "client", "connect_attempt_id"]) {
332
+ registered.searchParams.delete(key);
333
+ requested.searchParams.delete(key);
334
+ }
335
+ registered.searchParams.sort();
336
+ requested.searchParams.sort();
337
+ if (registered.toString() === requested.toString() &&
338
+ registeredSource === CONNECT_SOURCE &&
339
+ registeredClient === "cursor" &&
340
+ z.uuid().safeParse(registeredId).success) {
341
+ fallbackAttemptId = registeredId ?? undefined;
342
+ }
343
+ }
344
+ catch {
345
+ // A hand-edited invalid URL is repaired below with a fresh attempt id.
346
+ }
347
+ }
348
+ const telemetry = createConnectTelemetry(options.mcpUrl, "cursor", {
349
+ ...options,
350
+ fallbackAttemptId,
351
+ });
323
352
  // Never degraded: no sign-in command to be missing. False, not absent, so a `= false`
324
353
  // filter still catches Cursor.
325
354
  const state = {
@@ -347,7 +376,7 @@ export async function connectCursor(options) {
347
376
  const mcpUrl = new URL(options.mcpUrl);
348
377
  mcpUrl.searchParams.set("source", CONNECT_SOURCE);
349
378
  mcpUrl.searchParams.set("client", "cursor");
350
- // Attempt id rides telemetry only; persisting it would break idempotency.
379
+ mcpUrl.searchParams.set("connect_attempt_id", telemetry.attemptId);
351
380
  const result = writeCursorMcpConfig(mcpUrl.toString(), resolvedKey);
352
381
  if (result.status === "corrupt_skip") {
353
382
  throw new ConnectStepError(`Could not update ${cursorMcpPath()}: existing file could not be read or is not valid JSON (${result.error}). ` +
@@ -84,5 +84,6 @@ export declare function requireCommandSupport(client: SupportedCommand): {
84
84
  export declare function createConnectTelemetry(mcpUrl: string, client: AgentClient, opts?: {
85
85
  apiKey?: string;
86
86
  attemptId?: string;
87
+ fallbackAttemptId?: string;
87
88
  }): ConnectTelemetry;
88
89
  export {};
@@ -193,7 +193,7 @@ export function createConnectTelemetry(mcpUrl, client, opts) {
193
193
  const seeded = takeSeedAttemptId();
194
194
  // A setup-page id (via --url, the env var, or one parked by login) joins "copied the
195
195
  // command" to this install attempt.
196
- const attemptId = opts?.attemptId ?? seeded ?? randomUUID();
196
+ const attemptId = opts?.attemptId ?? seeded ?? opts?.fallbackAttemptId ?? randomUUID();
197
197
  const endpoint = new URL("/api/cli/connect-event", mcpUrl).toString();
198
198
  const pending = [];
199
199
  let lastTrackAt;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiny-fish/cli",
3
- "version": "0.26.1-next.225",
3
+ "version": "0.26.1-next.226",
4
4
  "description": "TinyFish CLI — run web automations from your terminal",
5
5
  "type": "module",
6
6
  "bin": {