@tiny-fish/cli 0.12.1-next.139 → 0.12.1-next.142

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.
@@ -9,7 +9,6 @@ import { detectHumanInitiated } from "../lib/harness.js";
9
9
  import { errLine } from "../lib/output.js";
10
10
  import { telemetryDisabled, telemetryHeaders } from "../lib/setup-telemetry.js";
11
11
  import { verifyMcpAuth } from "../lib/verify.js";
12
- import { recordInstalledVersion } from "../lib/version-marker.js";
13
12
  export const DEFAULT_MCP_URL = "https://agent.tinyfish.ai/mcp";
14
13
  const NON_INTERACTIVE_TIMEOUT_MS = 10_000;
15
14
  const SKILL_INSTALL_TIMEOUT_MS = 120_000;
@@ -591,7 +590,6 @@ async function connectNativeMcpClient(client, options) {
591
590
  // Persist once here (skill installed + authenticated) so both success paths, launch
592
591
  // or not, record the install; buildConnectHeaders reads it on subsequent requests.
593
592
  saveConnectContext(client.connectClient, telemetry.attemptId);
594
- recordInstalledVersion();
595
593
  errLine(UPGRADE_HINT);
596
594
  if (!options.launch) {
597
595
  errLine(`TinyFish is connected. Open ${client.displayName} to start using it.`);
@@ -662,7 +660,6 @@ export async function connectOpenClaw(options) {
662
660
  }
663
661
  telemetry.track("checkpoint", { phase: "authenticated" });
664
662
  saveConnectContext("openclaw", telemetry.attemptId);
665
- recordInstalledVersion();
666
663
  errLine(UPGRADE_HINT);
667
664
  if (!options.launch) {
668
665
  errLine("TinyFish is connected. Open OpenClaw to start using it.");
@@ -706,7 +703,6 @@ export async function connectCursor(options) {
706
703
  }
707
704
  telemetry.track("checkpoint", { phase: "registered" });
708
705
  saveConnectContext("cursor", telemetry.attemptId);
709
- recordInstalledVersion();
710
706
  if (resolvedKey) {
711
707
  // Deeplink would embed the key in a URL (process args, LaunchServices logs) — reload instead.
712
708
  const verify = await verifyMcpAuth(resolvedKey);
@@ -8,7 +8,6 @@ import { removeCursorMcpServer, planCursorWrite } from "./cursor-config.js";
8
8
  import { errLine, outLine } from "./output.js";
9
9
  import { sendSetupCompleted } from "./setup-telemetry.js";
10
10
  import { verifyMcpAuth, verifyMcpHealth } from "./verify.js";
11
- import { printUpdateNoticeIfDrifted, recordInstalledVersion } from "./version-marker.js";
12
11
  const DISPLAY_NAMES = {
13
12
  "claude-code": "Claude Code",
14
13
  codex: "Codex",
@@ -153,7 +152,6 @@ async function processHarness(detection, opts, prompt) {
153
152
  if (!interruptedBefore && process.exitCode === 130) {
154
153
  return { ...base, outcome: "interrupted", fixCommand: `tinyfish connect ${harness}` };
155
154
  }
156
- recordInstalledVersion();
157
155
  const verify = await verifyHarness(harness, opts.mcpUrl, resolvedApiKey(opts.apiKey));
158
156
  return {
159
157
  ...base,
@@ -292,7 +290,6 @@ export async function runConnectAll(opts) {
292
290
  verify_ok: r.verifyOk ?? null,
293
291
  }));
294
292
  await sendSetupCompleted(opts.mcpUrl, harnessTelemetry, resolvedApiKey(opts.apiKey));
295
- await printUpdateNoticeIfDrifted();
296
293
  }
297
294
  const exitCode = computeExitCode(results);
298
295
  const interrupted = results.some((r) => r.outcome === "interrupted");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiny-fish/cli",
3
- "version": "0.12.1-next.139",
3
+ "version": "0.12.1-next.142",
4
4
  "description": "TinyFish CLI — run web automations from your terminal",
5
5
  "type": "module",
6
6
  "bin": {
@@ -32,7 +32,7 @@
32
32
  "prepublishOnly": "npm run build"
33
33
  },
34
34
  "dependencies": {
35
- "@tiny-fish/sdk": "^0.2.0",
35
+ "@tiny-fish/sdk": "^0.3.0",
36
36
  "chrome-cookies-secure": "^3.0.2",
37
37
  "commander": "^12.0.0",
38
38
  "cross-spawn": "^7.0.6",
@@ -56,6 +56,7 @@
56
56
  "brace-expansion": "^5.0.9",
57
57
  "ip-address": ">=10.3.1",
58
58
  "postcss": ">=8.5.23",
59
+ "nanoid": "^3.3.17",
59
60
  "tar": "^7.5.21"
60
61
  },
61
62
  "engines": {
@@ -1,10 +0,0 @@
1
- /** Install-time, offline-safe; best-effort — never fails a finished install. */
2
- export declare function recordInstalledVersion(): void;
3
- interface UpdateCheckResult {
4
- updateAvailable: boolean;
5
- latest?: string;
6
- }
7
- /** Throttled npm-currency check; never auto-mutates the install. */
8
- export declare function checkForCliUpdate(now?: number): Promise<UpdateCheckResult>;
9
- export declare function printUpdateNoticeIfDrifted(): Promise<void>;
10
- export {};
@@ -1,109 +0,0 @@
1
- import * as fs from "fs";
2
- import * as path from "path";
3
- import { z } from "zod";
4
- import { configDir } from "./auth.js";
5
- import { CLI_VERSION } from "./constants.js";
6
- import { errLine } from "./output.js";
7
- import { telemetryDisabled } from "./setup-telemetry.js";
8
- const MARKER_FILE = "skill-version-marker.json";
9
- const THROTTLE_MS = 24 * 60 * 60 * 1000;
10
- const CHECK_TIMEOUT_MS = 5_000;
11
- // npm is the only currency signal with a publisher behind it: the cookbook repo has no
12
- // releases and no release automation, so a tag check would report "up to date" forever.
13
- const REGISTRY_URL = "https://registry.npmjs.org/@tiny-fish/cli/latest";
14
- const markerSchema = z.object({
15
- last_checked_at: z.number().optional(),
16
- last_known_latest: z.string().optional(),
17
- });
18
- function markerPath() {
19
- return path.join(configDir(), MARKER_FILE);
20
- }
21
- function readMarker() {
22
- try {
23
- const parsed = markerSchema.safeParse(JSON.parse(fs.readFileSync(markerPath(), "utf8")));
24
- return parsed.success ? parsed.data : undefined;
25
- }
26
- catch {
27
- return undefined;
28
- }
29
- }
30
- function writeMarker(state) {
31
- fs.mkdirSync(configDir(), { recursive: true, mode: 0o700 });
32
- const tmpPath = `${markerPath()}.tmp-${process.pid}`;
33
- fs.writeFileSync(tmpPath, JSON.stringify(state), { mode: 0o600 });
34
- fs.renameSync(tmpPath, markerPath());
35
- }
36
- /** Install-time, offline-safe; best-effort — never fails a finished install. */
37
- export function recordInstalledVersion() {
38
- try {
39
- writeMarker({ ...readMarker() });
40
- }
41
- catch {
42
- // marker is a nice-to-have
43
- }
44
- }
45
- const SEMVER = /^v?(\d+)\.(\d+)\.(\d+)$/;
46
- /** Strictly newer; false on unparsable input. */
47
- function isNewer(current, latest) {
48
- const c = SEMVER.exec(current);
49
- const l = SEMVER.exec(latest);
50
- if (!c || !l)
51
- return false;
52
- for (let i = 1; i <= 3; i++) {
53
- const cn = Number(c[i]);
54
- const ln = Number(l[i]);
55
- if (ln !== cn)
56
- return ln > cn;
57
- }
58
- return false;
59
- }
60
- /** Throttled npm-currency check; never auto-mutates the install. */
61
- export async function checkForCliUpdate(now = Date.now()) {
62
- const marker = readMarker();
63
- // No marker means the CLI never installed anything — nothing to nag about.
64
- if (!marker || telemetryDisabled())
65
- return { updateAvailable: false };
66
- const cached = () => ({
67
- updateAvailable: marker.last_known_latest !== undefined && isNewer(CLI_VERSION, marker.last_known_latest),
68
- ...(marker.last_known_latest !== undefined ? { latest: marker.last_known_latest } : {}),
69
- });
70
- // Time-based only — failed fetch must not stall every invocation.
71
- if (marker.last_checked_at !== undefined && now - marker.last_checked_at < THROTTLE_MS) {
72
- return cached();
73
- }
74
- let latest;
75
- try {
76
- const response = await fetch(REGISTRY_URL, {
77
- headers: { accept: "application/json" },
78
- signal: AbortSignal.timeout(CHECK_TIMEOUT_MS),
79
- });
80
- if (response.ok) {
81
- const body = (await response.json());
82
- if (typeof body.version === "string")
83
- latest = body.version;
84
- }
85
- }
86
- catch {
87
- // Unreachable registry — don't fail setup, don't erase the cache.
88
- }
89
- try {
90
- writeMarker({
91
- ...marker,
92
- last_checked_at: now,
93
- last_known_latest: latest ?? marker.last_known_latest,
94
- });
95
- }
96
- catch {
97
- // best-effort
98
- }
99
- // Fall back to the cache so consecutive invocations can't disagree.
100
- if (!latest)
101
- return cached();
102
- return { updateAvailable: isNewer(CLI_VERSION, latest), latest };
103
- }
104
- export async function printUpdateNoticeIfDrifted() {
105
- const { updateAvailable } = await checkForCliUpdate();
106
- if (updateAvailable) {
107
- errLine("a newer TinyFish CLI is available — re-run `npx @tiny-fish/cli connect --all`");
108
- }
109
- }