@tiny-fish/cli 0.43.0 → 0.44.0

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.
@@ -163,6 +163,12 @@ declare const doctorCompletedPayloadSchema: z.ZodObject<{
163
163
  detected: z.ZodBoolean;
164
164
  registered: z.ZodEnum<typeof Registered>;
165
165
  auth_mode: z.ZodEnum<typeof AuthMode>;
166
+ recorded_auth_mode: z.ZodOptional<z.ZodEnum<{
167
+ keyless: "keyless";
168
+ "api-key": "api-key";
169
+ oauth: "oauth";
170
+ deferred: "deferred";
171
+ }>>;
166
172
  proves_harness_reach: z.ZodBoolean;
167
173
  }, z.core.$strip>>;
168
174
  duration_ms: z.ZodInt;
@@ -266,6 +272,12 @@ declare const doctorPayloadSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
266
272
  detected: z.ZodBoolean;
267
273
  registered: z.ZodEnum<typeof Registered>;
268
274
  auth_mode: z.ZodEnum<typeof AuthMode>;
275
+ recorded_auth_mode: z.ZodOptional<z.ZodEnum<{
276
+ keyless: "keyless";
277
+ "api-key": "api-key";
278
+ oauth: "oauth";
279
+ deferred: "deferred";
280
+ }>>;
269
281
  proves_harness_reach: z.ZodBoolean;
270
282
  }, z.core.$strip>>;
271
283
  duration_ms: z.ZodInt;
@@ -265,6 +265,7 @@ const doctorCompletedPayloadSchema = z.object({
265
265
  detected: z.boolean(),
266
266
  registered: z.enum(Registered),
267
267
  auth_mode: z.enum(AuthMode),
268
+ recorded_auth_mode: z.enum(['api-key', 'keyless', 'oauth', 'deferred']).optional(),
268
269
  proves_harness_reach: z.boolean(),
269
270
  }))
270
271
  .max(16),
@@ -9,6 +9,6 @@ export interface VerifyResult {
9
9
  status?: number;
10
10
  }
11
11
  /** Reachability check. Verify failure is a warning, never install failure. */
12
- export declare function verifyMcpHealth(mcpUrl: string): Promise<VerifyResult>;
12
+ export declare function verifyMcpHealth(mcpUrl: string, keyless?: boolean): Promise<VerifyResult>;
13
13
  /** Authenticated check — where the CLI holds the key (Cursor, OpenClaw, Hermes). */
14
14
  export declare function verifyMcpAuth(apiKey: string, apiBaseUrl?: string): Promise<VerifyResult>;
@@ -1,6 +1,16 @@
1
1
  import { listRuns } from './client.js';
2
+ import { TINYFISH_ACCESS_MODE_HEADER, TINYFISH_KEYLESS_ACCESS_MODE } from './constants.js';
2
3
  import { ApiError } from './output.js';
4
+ import { z } from 'zod';
3
5
  const VERIFY_TIMEOUT_MS = 5_000;
6
+ const keylessInitializeSchema = z.object({
7
+ jsonrpc: z.literal('2.0'),
8
+ id: z.literal(1),
9
+ result: z.object({
10
+ capabilities: z.object({}),
11
+ serverInfo: z.object({ name: z.literal('tinyfish') }),
12
+ }),
13
+ });
4
14
  // `fetch` collapses every network fault to "fetch failed" and hides the cause on `e.cause`.
5
15
  function networkCode(e) {
6
16
  const cause = e?.cause;
@@ -32,24 +42,34 @@ function authCode(e) {
32
42
  return 'rate limited';
33
43
  return e.status >= 500 ? 'TinyFish returned a server error' : `the API returned HTTP ${e.status}`;
34
44
  }
45
+ function failedHealth(reason) {
46
+ return { depth: 'health', ok: false, reason, code: reason };
47
+ }
35
48
  /** Reachability check. Verify failure is a warning, never install failure. */
36
- export async function verifyMcpHealth(mcpUrl) {
49
+ export async function verifyMcpHealth(mcpUrl, keyless = false) {
37
50
  try {
38
51
  const response = await fetch(mcpUrl, {
39
- method: 'GET',
52
+ method: keyless ? 'POST' : 'GET',
53
+ ...(keyless
54
+ ? {
55
+ headers: {
56
+ [TINYFISH_ACCESS_MODE_HEADER]: TINYFISH_KEYLESS_ACCESS_MODE,
57
+ 'Content-Type': 'application/json',
58
+ Accept: 'application/json, text/event-stream',
59
+ },
60
+ body: '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18"}}',
61
+ }
62
+ : {}),
40
63
  // Redirect (captive portal, typo'd --url) is not healthy.
41
64
  redirect: 'error',
42
65
  signal: AbortSignal.timeout(VERIFY_TIMEOUT_MS),
43
66
  });
44
67
  // MCP rejects bare GET with 4xx — still proves endpoint routed.
45
- if (response.status >= 500) {
46
- return {
47
- depth: 'health',
48
- ok: false,
49
- reason: `endpoint returned HTTP ${response.status}`,
50
- code: `the endpoint returned HTTP ${response.status}`,
51
- };
68
+ if (response.status >= 500 || (keyless && response.status !== 200)) {
69
+ return failedHealth(`endpoint returned HTTP ${response.status}`);
52
70
  }
71
+ if (keyless && !keylessInitializeSchema.safeParse(await response.json()).success)
72
+ return failedHealth('endpoint returned an invalid MCP initialize response');
53
73
  return { depth: 'health', ok: true };
54
74
  }
55
75
  catch (e) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiny-fish/cli",
3
- "version": "0.43.0",
3
+ "version": "0.44.0",
4
4
  "description": "TinyFish CLI — run web automations from your terminal",
5
5
  "type": "module",
6
6
  "bin": {
@@ -35,7 +35,7 @@
35
35
  "format:check": "oxfmt --check ."
36
36
  },
37
37
  "dependencies": {
38
- "@tiny-fish/sdk": "^0.6.0",
38
+ "@tiny-fish/sdk": "^0.7.0",
39
39
  "commander": "^12.0.0",
40
40
  "cross-spawn": "^7.0.6",
41
41
  "tldts": "^6.1.86",