@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.
package/dist/commands/connect.js
CHANGED
|
@@ -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);
|
package/dist/lib/connect-all.js
CHANGED
|
@@ -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.
|
|
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.
|
|
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
|
-
}
|