@tiny-fish/cli 0.30.2-next.257 → 0.30.2-next.259

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 (77) hide show
  1. package/dist/commands/auth.d.ts +1 -1
  2. package/dist/commands/auth.js +52 -52
  3. package/dist/commands/batch.d.ts +1 -1
  4. package/dist/commands/batch.js +54 -46
  5. package/dist/commands/browser.d.ts +1 -1
  6. package/dist/commands/browser.js +14 -14
  7. package/dist/commands/config-claude.d.ts +1 -1
  8. package/dist/commands/config-claude.js +22 -22
  9. package/dist/commands/connect.d.ts +3 -3
  10. package/dist/commands/connect.js +150 -150
  11. package/dist/commands/doctor.d.ts +4 -4
  12. package/dist/commands/doctor.js +104 -104
  13. package/dist/commands/fetch.d.ts +1 -1
  14. package/dist/commands/fetch.js +24 -27
  15. package/dist/commands/onboard.d.ts +1 -1
  16. package/dist/commands/onboard.js +50 -50
  17. package/dist/commands/profile.d.ts +3 -3
  18. package/dist/commands/profile.js +45 -45
  19. package/dist/commands/run.d.ts +1 -1
  20. package/dist/commands/run.js +78 -65
  21. package/dist/commands/runs.d.ts +1 -1
  22. package/dist/commands/runs.js +63 -50
  23. package/dist/commands/search.d.ts +1 -1
  24. package/dist/commands/search.js +16 -16
  25. package/dist/commands/upgrade.d.ts +2 -2
  26. package/dist/commands/upgrade.js +36 -36
  27. package/dist/commands/vault.d.ts +1 -1
  28. package/dist/commands/vault.js +48 -45
  29. package/dist/commands/wallet.d.ts +1 -1
  30. package/dist/commands/wallet.js +14 -14
  31. package/dist/index.js +2 -2
  32. package/dist/lib/auth.d.ts +5 -5
  33. package/dist/lib/auth.js +56 -56
  34. package/dist/lib/batch-store.d.ts +1 -1
  35. package/dist/lib/batch-store.js +4 -4
  36. package/dist/lib/chrome-cookies.d.ts +1 -1
  37. package/dist/lib/chrome-cookies.js +24 -24
  38. package/dist/lib/claude-config.js +37 -37
  39. package/dist/lib/cli-install.js +12 -12
  40. package/dist/lib/client.d.ts +2 -2
  41. package/dist/lib/client.js +61 -61
  42. package/dist/lib/connect-all.js +140 -134
  43. package/dist/lib/connect-auth.d.ts +2 -2
  44. package/dist/lib/connect-auth.js +15 -15
  45. package/dist/lib/connect-clients.d.ts +6 -6
  46. package/dist/lib/connect-clients.js +143 -143
  47. package/dist/lib/connect-fallback.d.ts +1 -1
  48. package/dist/lib/connect-fallback.js +38 -38
  49. package/dist/lib/connect-picker.d.ts +4 -4
  50. package/dist/lib/connect-picker.js +28 -28
  51. package/dist/lib/connect-runtime.d.ts +7 -7
  52. package/dist/lib/connect-runtime.js +61 -61
  53. package/dist/lib/constants.js +13 -13
  54. package/dist/lib/cursor-config.d.ts +1 -1
  55. package/dist/lib/cursor-config.js +30 -30
  56. package/dist/lib/doctor-report.d.ts +2 -2
  57. package/dist/lib/doctor-report.js +22 -22
  58. package/dist/lib/harness-detect.js +39 -39
  59. package/dist/lib/harness.js +9 -9
  60. package/dist/lib/hermes-env.js +26 -23
  61. package/dist/lib/install-root.js +12 -12
  62. package/dist/lib/notice.d.ts +1 -1
  63. package/dist/lib/notice.js +12 -12
  64. package/dist/lib/output.js +14 -14
  65. package/dist/lib/registration-detect.d.ts +3 -3
  66. package/dist/lib/registration-detect.js +82 -82
  67. package/dist/lib/setup-telemetry.d.ts +4 -4
  68. package/dist/lib/setup-telemetry.js +34 -34
  69. package/dist/lib/signals.js +1 -1
  70. package/dist/lib/skill-install.d.ts +3 -3
  71. package/dist/lib/skill-install.js +40 -40
  72. package/dist/lib/types.d.ts +8 -8
  73. package/dist/lib/verify.d.ts +1 -1
  74. package/dist/lib/verify.js +28 -28
  75. package/dist/program.d.ts +1 -1
  76. package/dist/program.js +28 -28
  77. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
- import { type AgentClient } from "./connect-runtime.js";
1
+ import { type AgentClient } from './connect-runtime.js';
2
2
  export declare const TINYFISH_CLI_NOT_FOUND_MESSAGE = "TinyFish CLI installed but is not available on PATH. Open a new terminal and retry.";
3
- export declare function ensureCliAuthenticated(source: AgentClient | "cli", apiKey?: string, opts?: {
3
+ export declare function ensureCliAuthenticated(source: AgentClient | 'cli', apiKey?: string, opts?: {
4
4
  interactiveLogin?: boolean;
5
5
  }): void;
@@ -1,22 +1,22 @@
1
- import spawn from "cross-spawn";
2
- import { TINYFISH_API_KEY_VAR } from "./constants.js";
3
- import { persistApiKeyToEnvironment, validateKeyFormat, writeConfig } from "./auth.js";
4
- import { commandNotFound, ConnectStepError, spawnStepError, throwIfInterrupted, NON_INTERACTIVE_TIMEOUT_MS, } from "./connect-runtime.js";
5
- import { errLine } from "./output.js";
6
- export const TINYFISH_CLI_NOT_FOUND_MESSAGE = "TinyFish CLI installed but is not available on PATH. Open a new terminal and retry.";
1
+ import spawn from 'cross-spawn';
2
+ import { TINYFISH_API_KEY_VAR } from './constants.js';
3
+ import { persistApiKeyToEnvironment, validateKeyFormat, writeConfig } from './auth.js';
4
+ import { commandNotFound, ConnectStepError, spawnStepError, throwIfInterrupted, NON_INTERACTIVE_TIMEOUT_MS, } from './connect-runtime.js';
5
+ import { errLine } from './output.js';
6
+ export const TINYFISH_CLI_NOT_FOUND_MESSAGE = 'TinyFish CLI installed but is not available on PATH. Open a new terminal and retry.';
7
7
  export function ensureCliAuthenticated(source, apiKey, opts) {
8
8
  const envKey = apiKey ?? process.env[TINYFISH_API_KEY_VAR];
9
9
  if (envKey) {
10
10
  if (!validateKeyFormat(envKey)) {
11
- throw new ConnectStepError("TINYFISH_API_KEY has invalid format", "invalid_config");
11
+ throw new ConnectStepError('TINYFISH_API_KEY has invalid format', 'invalid_config');
12
12
  }
13
13
  // Throwing variant: a write failure must reach connect's catch/flush, not exit(1) past it.
14
14
  writeConfig(envKey);
15
15
  persistApiKeyToEnvironment(envKey);
16
16
  return;
17
17
  }
18
- const authStatus = spawn.sync("tinyfish", ["auth", "status"], {
19
- stdio: "ignore",
18
+ const authStatus = spawn.sync('tinyfish', ['auth', 'status'], {
19
+ stdio: 'ignore',
20
20
  timeout: NON_INTERACTIVE_TIMEOUT_MS,
21
21
  });
22
22
  if (commandNotFound(authStatus.error)) {
@@ -28,19 +28,19 @@ export function ensureCliAuthenticated(source, apiKey, opts) {
28
28
  // "not signed in" and drop the user into an interactive login they never asked for.
29
29
  throwIfInterrupted(authStatus);
30
30
  if (authStatus.error) {
31
- throw spawnStepError("Could not read TinyFish CLI auth status", authStatus);
31
+ throw spawnStepError('Could not read TinyFish CLI auth status', authStatus);
32
32
  }
33
33
  if (opts?.interactiveLogin === false) {
34
- throw new Error("The TinyFish CLI is not signed in. Run: tinyfish auth login");
34
+ throw new Error('The TinyFish CLI is not signed in. Run: tinyfish auth login');
35
35
  }
36
- errLine("Signing in to the TinyFish CLI...");
37
- const loginResult = spawn.sync("tinyfish", ["auth", "login", "--source", source], {
38
- stdio: "inherit",
36
+ errLine('Signing in to the TinyFish CLI...');
37
+ const loginResult = spawn.sync('tinyfish', ['auth', 'login', '--source', source], {
38
+ stdio: 'inherit',
39
39
  });
40
40
  if (commandNotFound(loginResult.error)) {
41
41
  throw spawnStepError(TINYFISH_CLI_NOT_FOUND_MESSAGE, loginResult);
42
42
  }
43
43
  if (loginResult.error || loginResult.status !== 0) {
44
- throw spawnStepError("Could not authenticate the TinyFish CLI", loginResult);
44
+ throw spawnStepError('Could not authenticate the TinyFish CLI', loginResult);
45
45
  }
46
46
  }
@@ -1,6 +1,6 @@
1
- import spawn from "cross-spawn";
2
- import { type Harness } from "./harness-detect.js";
3
- import { type AgentClient, type SupportedCommand } from "./connect-runtime.js";
1
+ import spawn from 'cross-spawn';
2
+ import { type Harness } from './harness-detect.js';
3
+ import { type AgentClient, type SupportedCommand } from './connect-runtime.js';
4
4
  export declare const OPENCLAW_SKILL_INSTALL_ARGS: readonly string[];
5
5
  /** `openclaw skills` has no uninstall; ClawHub removes from the global dir. */
6
6
  export declare function openclawSkillUninstall(): {
@@ -12,14 +12,14 @@ export declare function openclawSkillUninstall(): {
12
12
  export declare const DEFAULT_ONBOARDING_PROMPT: string;
13
13
  export declare const OPENCLAW_ONBOARDING_PROMPT: string;
14
14
  /** The `skills` CLI's own agent names — not ours, and not every harness has one. */
15
- export type SkillAgent = "claude-code" | "codex" | "cursor" | "hermes-agent" | "opencode";
15
+ export type SkillAgent = 'claude-code' | 'codex' | 'cursor' | 'hermes-agent' | 'opencode';
16
16
  /** Cursor writes its own MCP config, so it has no descriptor to carry this. */
17
17
  export declare const CURSOR_SKILL_TARGET: {
18
18
  readonly skillAgent: "cursor";
19
19
  readonly displayName: "Cursor";
20
20
  };
21
21
  export interface NativeMcpClient extends SupportedCommand {
22
- connectClient: Exclude<AgentClient, "openclaw">;
22
+ connectClient: Exclude<AgentClient, 'openclaw'>;
23
23
  /** Omitted where the `skills` CLI has no agent for this harness (Grok ships its own plugin). */
24
24
  skillAgent?: SkillAgent;
25
25
  /** Capturable: this `mcp add` never runs OAuth inline; unset stays inherited. */
@@ -84,7 +84,7 @@ export interface HarnessCapabilities {
84
84
  /** Required booleans: a new harness or new flag fails to compile undecided. */
85
85
  export declare const HARNESS_CAPABILITIES: Record<Harness, HarnessCapabilities>;
86
86
  /** "printed" = handed to the user to paste; the walkthrough was never started for them. */
87
- export type WalkthroughOutcome = "launched" | "printed";
87
+ export type WalkthroughOutcome = 'launched' | 'printed';
88
88
  /** Awaited before the handover; track+flush must land pre-block. */
89
89
  type OnWalkthroughDecided = (outcome: WalkthroughOutcome) => void | Promise<void>;
90
90
  export declare function launchNativeMcpClient(client: NativeMcpClient, onDecided?: OnWalkthroughDecided): Promise<WalkthroughOutcome>;
@@ -1,136 +1,136 @@
1
- import spawn from "cross-spawn";
2
- import { SKILL_INSTALL_TIMEOUT_MS } from "./cli-install.js";
3
- import { detectHumanInitiated } from "./harness.js";
4
- import { harnessConfigPath } from "./harness-detect.js";
5
- import { errLine, sanitizeLine } from "./output.js";
6
- import { spawnStepError, } from "./connect-runtime.js";
7
- import { TINYFISH_API_KEY_VAR } from "./constants.js";
1
+ import spawn from 'cross-spawn';
2
+ import { SKILL_INSTALL_TIMEOUT_MS } from './cli-install.js';
3
+ import { detectHumanInitiated } from './harness.js';
4
+ import { harnessConfigPath } from './harness-detect.js';
5
+ import { errLine, sanitizeLine } from './output.js';
6
+ import { spawnStepError } from './connect-runtime.js';
7
+ import { TINYFISH_API_KEY_VAR } from './constants.js';
8
8
  const HERMES_SEED_TIMEOUT_MS = 120_000;
9
9
  // An old install is only one reason a flag can go unseen, so no message asserts the cause.
10
- const SUPPORT_CHECK_DEBUG_HINT = " Set TINYFISH_DEBUG=1 and retry to print the help output TinyFish read.";
11
- const MCP_ADD_UNAVAILABLE_MESSAGE = "Could not confirm this Claude Code installation exposes `claude mcp add`: `claude mcp " +
12
- "--help` did not list it. Update Claude Code with `claude update` and retry." +
10
+ const SUPPORT_CHECK_DEBUG_HINT = ' Set TINYFISH_DEBUG=1 and retry to print the help output TinyFish read.';
11
+ const MCP_ADD_UNAVAILABLE_MESSAGE = 'Could not confirm this Claude Code installation exposes `claude mcp add`: `claude mcp ' +
12
+ '--help` did not list it. Update Claude Code with `claude update` and retry.' +
13
13
  SUPPORT_CHECK_DEBUG_HINT;
14
14
  // `claude mcp login` only exists upstream from Claude Code 2.1.186; older installs still register.
15
- const CLAUDE_CODE_KEYED_FALLBACK_NOTE = "Using your stored TinyFish API key: this Claude Code predates one-command sign-in " +
16
- "(`claude mcp login`), so no browser sign-in is needed.";
17
- const CLAUDE_CODE_DEFERRED_AUTH_NOTE = "TinyFish is registered in Claude Code but not signed in: this Claude Code predates " +
18
- "one-command sign-in (`claude mcp login`). Open Claude Code and run `/mcp` to sign in to " +
19
- "TinyFish. `claude update` gets you one-command sign-in. Already have a TinyFish API key? " +
20
- "Run `tinyfish connect claude-code --api-key <key>` instead.";
21
- const CODEX_OAUTH_RESOURCE_UNAVAILABLE_MESSAGE = "Could not confirm this Codex installation supports one-command MCP authentication: `codex " +
22
- "mcp add --help` did not list `--oauth-resource`. Update Codex and retry, or add TinyFish " +
23
- "manually with `codex mcp add`." +
15
+ const CLAUDE_CODE_KEYED_FALLBACK_NOTE = 'Using your stored TinyFish API key: this Claude Code predates one-command sign-in ' +
16
+ '(`claude mcp login`), so no browser sign-in is needed.';
17
+ const CLAUDE_CODE_DEFERRED_AUTH_NOTE = 'TinyFish is registered in Claude Code but not signed in: this Claude Code predates ' +
18
+ 'one-command sign-in (`claude mcp login`). Open Claude Code and run `/mcp` to sign in to ' +
19
+ 'TinyFish. `claude update` gets you one-command sign-in. Already have a TinyFish API key? ' +
20
+ 'Run `tinyfish connect claude-code --api-key <key>` instead.';
21
+ const CODEX_OAUTH_RESOURCE_UNAVAILABLE_MESSAGE = 'Could not confirm this Codex installation supports one-command MCP authentication: `codex ' +
22
+ 'mcp add --help` did not list `--oauth-resource`. Update Codex and retry, or add TinyFish ' +
23
+ 'manually with `codex mcp add`.' +
24
24
  SUPPORT_CHECK_DEBUG_HINT;
25
- const HERMES_OAUTH_UNAVAILABLE_MESSAGE = "Could not confirm this Hermes installation supports one-command MCP authentication: `hermes " +
26
- "mcp add --help` did not list `--auth oauth`. Update Hermes and retry, or add TinyFish " +
27
- "manually with `hermes mcp add`." +
25
+ const HERMES_OAUTH_UNAVAILABLE_MESSAGE = 'Could not confirm this Hermes installation supports one-command MCP authentication: `hermes ' +
26
+ 'mcp add --help` did not list `--auth oauth`. Update Hermes and retry, or add TinyFish ' +
27
+ 'manually with `hermes mcp add`.' +
28
28
  SUPPORT_CHECK_DEBUG_HINT;
29
- const GROK_HTTP_UNAVAILABLE_MESSAGE = "Could not confirm this Grok installation supports remote MCP servers: `grok mcp add --help` " +
30
- "did not list `--transport`. Update Grok and retry, or add TinyFish manually with " +
31
- "`grok mcp add`." +
29
+ const GROK_HTTP_UNAVAILABLE_MESSAGE = 'Could not confirm this Grok installation supports remote MCP servers: `grok mcp add --help` ' +
30
+ 'did not list `--transport`. Update Grok and retry, or add TinyFish manually with ' +
31
+ '`grok mcp add`.' +
32
32
  SUPPORT_CHECK_DEBUG_HINT;
33
33
  // Grok has no `mcp login`; sign-in only happens inside the TUI. No key nudge here: a revoked
34
34
  // key leaves Grok with no OAuth fallback, and doctor cannot spot that yet (PF-3618).
35
- const GROK_SIGN_IN_HINT = "TinyFish is registered in Grok. Open Grok, run `/mcps`, select tinyfish, and press `i` to " +
36
- "sign in.";
37
- const OPENCLAW_SKILL_UNAVAILABLE_MESSAGE = "Could not confirm this OpenClaw installation supports global skill installation: `openclaw " +
38
- "skills install --help` did not list `--global` and `--acknowledge-clawhub-risk`. Update " +
39
- "OpenClaw and retry, or install manually with `openclaw skills install @tinyfish/tinyfish " +
40
- "--global --acknowledge-clawhub-risk`." +
35
+ const GROK_SIGN_IN_HINT = 'TinyFish is registered in Grok. Open Grok, run `/mcps`, select tinyfish, and press `i` to ' +
36
+ 'sign in.';
37
+ const OPENCLAW_SKILL_UNAVAILABLE_MESSAGE = 'Could not confirm this OpenClaw installation supports global skill installation: `openclaw ' +
38
+ 'skills install --help` did not list `--global` and `--acknowledge-clawhub-risk`. Update ' +
39
+ 'OpenClaw and retry, or install manually with `openclaw skills install @tinyfish/tinyfish ' +
40
+ '--global --acknowledge-clawhub-risk`.' +
41
41
  SUPPORT_CHECK_DEBUG_HINT;
42
- const OPENCODE_MCP_ADD_UNAVAILABLE_MESSAGE = "Could not confirm this OpenCode installation supports one-command MCP setup: `opencode mcp " +
43
- "add --help` did not list `--url`. Update OpenCode and retry, or add TinyFish manually with " +
44
- "`opencode mcp add`." +
42
+ const OPENCODE_MCP_ADD_UNAVAILABLE_MESSAGE = 'Could not confirm this OpenCode installation supports one-command MCP setup: `opencode mcp ' +
43
+ 'add --help` did not list `--url`. Update OpenCode and retry, or add TinyFish manually with ' +
44
+ '`opencode mcp add`.' +
45
45
  SUPPORT_CHECK_DEBUG_HINT;
46
46
  // OpenCode is model-agnostic (unlike Claude Code / Codex), so a fresh install can default to a
47
47
  // model with no tool support — TinyFish runs entirely on tool calls, so it would fail there.
48
- const OPENCODE_MODEL_NOTE = "Note: TinyFish runs on tool calls, so OpenCode needs a model that supports tool use. Image-only " +
48
+ const OPENCODE_MODEL_NOTE = 'Note: TinyFish runs on tool calls, so OpenCode needs a model that supports tool use. Image-only ' +
49
49
  'models (e.g. Nano Banana Pro) will show "No endpoints found that support tool use" — switch ' +
50
50
  "OpenCode's model if the walkthrough can't start.";
51
- const OPENCLAW_SKILL = "@tinyfish/tinyfish";
51
+ const OPENCLAW_SKILL = '@tinyfish/tinyfish';
52
52
  // --force makes this an unconditional overwrite, so the same call installs and refreshes.
53
53
  export const OPENCLAW_SKILL_INSTALL_ARGS = [
54
- "skills",
55
- "install",
54
+ 'skills',
55
+ 'install',
56
56
  OPENCLAW_SKILL,
57
- "--global",
58
- "--force",
59
- "--acknowledge-clawhub-risk",
57
+ '--global',
58
+ '--force',
59
+ '--acknowledge-clawhub-risk',
60
60
  ];
61
61
  /** `openclaw skills` has no uninstall; ClawHub removes from the global dir. */
62
62
  export function openclawSkillUninstall() {
63
63
  return {
64
- command: "npx",
64
+ command: 'npx',
65
65
  args: [
66
- "-y",
66
+ '-y',
67
67
  // Pinned: npx would otherwise execute whatever is newest at run time.
68
- "clawhub@0.23.3",
69
- "--workdir",
70
- harnessConfigPath("openclaw"),
71
- "uninstall",
68
+ 'clawhub@0.23.3',
69
+ '--workdir',
70
+ harnessConfigPath('openclaw'),
71
+ 'uninstall',
72
72
  OPENCLAW_SKILL,
73
- "--yes",
73
+ '--yes',
74
74
  ],
75
75
  timeoutMs: SKILL_INSTALL_TIMEOUT_MS,
76
76
  };
77
77
  }
78
- export const DEFAULT_ONBOARDING_PROMPT = "I just connected TinyFish. Use the MCP server named `tinyfish` for every TinyFish tool call; " +
79
- "if another TinyFish server is also registered, still use `tinyfish` and do not ask me which. " +
80
- "Start by asking me what I want to look up on the web, and wait for my reply. Then call " +
81
- "`guide_next_step` and follow its instructions one step at a time, asking for my input and " +
82
- "waiting for my reply before each subsequent TinyFish tool call. If a tool call comes back " +
83
- "blocked or not approved, tell me which tool needs approval and how to grant it, then wait for " +
84
- "me instead of ending the walkthrough.";
85
- export const OPENCLAW_ONBOARDING_PROMPT = "I just installed the TinyFish skill. Guide me through it interactively: first ask what topic I " +
86
- "want to search and wait for my reply before using TinyFish Search. Show me the results, ask " +
87
- "which result I want to read, and wait before using TinyFish Fetch. Then ask what browser task " +
88
- "I want to complete and wait before using TinyFish Agent. Never skip ahead or choose for me.";
78
+ export const DEFAULT_ONBOARDING_PROMPT = 'I just connected TinyFish. Use the MCP server named `tinyfish` for every TinyFish tool call; ' +
79
+ 'if another TinyFish server is also registered, still use `tinyfish` and do not ask me which. ' +
80
+ 'Start by asking me what I want to look up on the web, and wait for my reply. Then call ' +
81
+ '`guide_next_step` and follow its instructions one step at a time, asking for my input and ' +
82
+ 'waiting for my reply before each subsequent TinyFish tool call. If a tool call comes back ' +
83
+ 'blocked or not approved, tell me which tool needs approval and how to grant it, then wait for ' +
84
+ 'me instead of ending the walkthrough.';
85
+ export const OPENCLAW_ONBOARDING_PROMPT = 'I just installed the TinyFish skill. Guide me through it interactively: first ask what topic I ' +
86
+ 'want to search and wait for my reply before using TinyFish Search. Show me the results, ask ' +
87
+ 'which result I want to read, and wait before using TinyFish Fetch. Then ask what browser task ' +
88
+ 'I want to complete and wait before using TinyFish Agent. Never skip ahead or choose for me.';
89
89
  /** Cursor writes its own MCP config, so it has no descriptor to carry this. */
90
- export const CURSOR_SKILL_TARGET = { skillAgent: "cursor", displayName: "Cursor" };
90
+ export const CURSOR_SKILL_TARGET = { skillAgent: 'cursor', displayName: 'Cursor' };
91
91
  const HEADER_FLAG = /(?:^|\s)--header(?:[\s<=]|$)/m;
92
92
  const claudeAddArgs = (mcpUrl) => [
93
- "mcp",
94
- "add",
95
- "--scope",
96
- "user",
97
- "--transport",
98
- "http",
99
- "tinyfish",
93
+ 'mcp',
94
+ 'add',
95
+ '--scope',
96
+ 'user',
97
+ '--transport',
98
+ 'http',
99
+ 'tinyfish',
100
100
  mcpUrl,
101
101
  ];
102
- const urlAddArgs = (mcpUrl) => ["mcp", "add", "tinyfish", "--url", mcpUrl];
102
+ const urlAddArgs = (mcpUrl) => ['mcp', 'add', 'tinyfish', '--url', mcpUrl];
103
103
  // OpenCode takes `--header NAME=VALUE`, not Claude Code's `NAME: VALUE`.
104
104
  const headerKeyAuth = {
105
- addArgs: (mcpUrl, apiKey) => [...urlAddArgs(mcpUrl), "--header", `X-API-Key=${apiKey}`],
105
+ addArgs: (mcpUrl, apiKey) => [...urlAddArgs(mcpUrl), '--header', `X-API-Key=${apiKey}`],
106
106
  };
107
107
  export const CLAUDE_CODE = {
108
- command: "claude",
109
- connectClient: "claude-code",
110
- skillAgent: "claude-code",
108
+ command: 'claude',
109
+ connectClient: 'claude-code',
110
+ skillAgent: 'claude-code',
111
111
  nonInteractiveAdd: true,
112
- displayName: "Claude Code",
112
+ displayName: 'Claude Code',
113
113
  supportCheck: {
114
- args: ["mcp", "--help"],
114
+ args: ['mcp', '--help'],
115
115
  patterns: [/^\s*add(?:\s|\[)/m],
116
116
  optionalPatterns: [/^\s*login(?:\s|\[)/m],
117
117
  keyAuthPattern: HEADER_FLAG,
118
118
  unavailableMessage: MCP_ADD_UNAVAILABLE_MESSAGE,
119
119
  },
120
120
  keyAuth: {
121
- addArgs: (mcpUrl, apiKey) => [...claudeAddArgs(mcpUrl), "--header", `X-API-Key: ${apiKey}`],
121
+ addArgs: (mcpUrl, apiKey) => [...claudeAddArgs(mcpUrl), '--header', `X-API-Key: ${apiKey}`],
122
122
  },
123
- loginArgs: ["mcp", "login", "tinyfish"],
123
+ loginArgs: ['mcp', 'login', 'tinyfish'],
124
124
  degradedAuthNotes: {
125
125
  keyed: CLAUDE_CODE_KEYED_FALLBACK_NOTE,
126
126
  deferred: CLAUDE_CODE_DEFERRED_AUTH_NOTE,
127
127
  },
128
128
  // Project scope is shared in .mcp.json; a user setup command must not rewrite it.
129
129
  removals: [
130
- { args: ["mcp", "remove", "tinyfish", "--scope", "user"], label: "user TinyFish registration" },
130
+ { args: ['mcp', 'remove', 'tinyfish', '--scope', 'user'], label: 'user TinyFish registration' },
131
131
  {
132
- args: ["mcp", "remove", "tinyfish", "--scope", "local"],
133
- label: "local TinyFish registration",
132
+ args: ['mcp', 'remove', 'tinyfish', '--scope', 'local'],
133
+ label: 'local TinyFish registration',
134
134
  },
135
135
  ],
136
136
  addArgs: (mcpUrl) => claudeAddArgs(mcpUrl),
@@ -141,36 +141,36 @@ export const CLAUDE_CODE = {
141
141
  * quotes back out. Untested on Windows.
142
142
  */
143
143
  export function openExternalUrl(url) {
144
- if (process.platform === "darwin")
145
- return spawn.sync("open", [url], { stdio: "ignore" });
146
- if (process.platform === "win32") {
147
- return spawn.sync("cmd", ["/c", "start", '""', `"${url}"`], {
148
- stdio: "ignore",
144
+ if (process.platform === 'darwin')
145
+ return spawn.sync('open', [url], { stdio: 'ignore' });
146
+ if (process.platform === 'win32') {
147
+ return spawn.sync('cmd', ['/c', 'start', '""', `"${url}"`], {
148
+ stdio: 'ignore',
149
149
  windowsVerbatimArguments: true,
150
150
  });
151
151
  }
152
- return spawn.sync("xdg-open", [url], { stdio: "ignore" });
152
+ return spawn.sync('xdg-open', [url], { stdio: 'ignore' });
153
153
  }
154
154
  function launchCodexWalkthrough() {
155
- const deepLink = new URL("codex://new");
156
- deepLink.searchParams.set("prompt", DEFAULT_ONBOARDING_PROMPT);
157
- deepLink.searchParams.set("path", process.cwd());
155
+ const deepLink = new URL('codex://new');
156
+ deepLink.searchParams.set('prompt', DEFAULT_ONBOARDING_PROMPT);
157
+ deepLink.searchParams.set('path', process.cwd());
158
158
  const result = openExternalUrl(deepLink.toString());
159
159
  if (result.error || result.status !== 0) {
160
160
  // Headless box: nothing can open a window; recover like the gated clients.
161
- printPromptForHandoff("Codex", "codex", DEFAULT_ONBOARDING_PROMPT, "Codex could not be opened here (no `codex://` handler)");
162
- return "printed";
161
+ printPromptForHandoff('Codex', 'codex', DEFAULT_ONBOARDING_PROMPT, 'Codex could not be opened here (no `codex://` handler)');
162
+ return 'printed';
163
163
  }
164
- errLine("Codex opened with the TinyFish walkthrough ready. Send the prompt to start.");
165
- return "launched";
164
+ errLine('Codex opened with the TinyFish walkthrough ready. Send the prompt to start.');
165
+ return 'launched';
166
166
  }
167
167
  export const CODEX = {
168
- command: "codex",
169
- connectClient: "codex",
170
- skillAgent: "codex",
171
- displayName: "Codex",
168
+ command: 'codex',
169
+ connectClient: 'codex',
170
+ skillAgent: 'codex',
171
+ displayName: 'Codex',
172
172
  supportCheck: {
173
- args: ["mcp", "add", "--help"],
173
+ args: ['mcp', 'add', '--help'],
174
174
  patterns: [/--oauth-resource(?:\s|<)/],
175
175
  keyAuthPattern: /(?:^|\s)--bearer-token-env-var(?:[\s<=]|$)/m,
176
176
  unavailableMessage: CODEX_OAUTH_RESOURCE_UNAVAILABLE_MESSAGE,
@@ -179,29 +179,29 @@ export const CODEX = {
179
179
  // Omitting `--oauth-resource` is what keeps `mcp add` from running OAuth.
180
180
  keyAuth: {
181
181
  envVar: TINYFISH_API_KEY_VAR,
182
- addArgs: (mcpUrl) => [...urlAddArgs(mcpUrl), "--bearer-token-env-var", TINYFISH_API_KEY_VAR],
182
+ addArgs: (mcpUrl) => [...urlAddArgs(mcpUrl), '--bearer-token-env-var', TINYFISH_API_KEY_VAR],
183
183
  },
184
184
  detachedLaunch: launchCodexWalkthrough,
185
185
  // Retry only: running it after a finished inline OAuth is a second browser hop.
186
- loginArgs: ["mcp", "login", "tinyfish"],
187
- removals: [{ args: ["mcp", "remove", "tinyfish"], label: "TinyFish registration from Codex" }],
188
- addArgs: (mcpUrl, oauthResource) => [...urlAddArgs(mcpUrl), "--oauth-resource", oauthResource],
186
+ loginArgs: ['mcp', 'login', 'tinyfish'],
187
+ removals: [{ args: ['mcp', 'remove', 'tinyfish'], label: 'TinyFish registration from Codex' }],
188
+ addArgs: (mcpUrl, oauthResource) => [...urlAddArgs(mcpUrl), '--oauth-resource', oauthResource],
189
189
  };
190
190
  const grokAddArgs = (mcpUrl) => [
191
- "mcp",
192
- "add",
193
- "--transport",
194
- "http",
195
- "tinyfish",
191
+ 'mcp',
192
+ 'add',
193
+ '--transport',
194
+ 'http',
195
+ 'tinyfish',
196
196
  mcpUrl,
197
197
  ];
198
198
  export const GROK = {
199
- command: "grok",
200
- connectClient: "grok",
199
+ command: 'grok',
200
+ connectClient: 'grok',
201
201
  nonInteractiveAdd: true,
202
- displayName: "Grok",
202
+ displayName: 'Grok',
203
203
  supportCheck: {
204
- args: ["mcp", "add", "--help"],
204
+ args: ['mcp', 'add', '--help'],
205
205
  patterns: [/--transport(?:[\s<=]|$)/m],
206
206
  keyAuthPattern: HEADER_FLAG,
207
207
  unavailableMessage: GROK_HTTP_UNAVAILABLE_MESSAGE,
@@ -212,67 +212,67 @@ export const GROK = {
212
212
  envVar: TINYFISH_API_KEY_VAR,
213
213
  addArgs: (mcpUrl) => [
214
214
  ...grokAddArgs(mcpUrl),
215
- "--header",
215
+ '--header',
216
216
  `Authorization: Bearer \${${TINYFISH_API_KEY_VAR}}`,
217
217
  ],
218
218
  },
219
219
  signInHint: GROK_SIGN_IN_HINT,
220
- removals: [{ args: ["mcp", "remove", "tinyfish"], label: "TinyFish registration from Grok" }],
220
+ removals: [{ args: ['mcp', 'remove', 'tinyfish'], label: 'TinyFish registration from Grok' }],
221
221
  addArgs: grokAddArgs,
222
222
  };
223
223
  // Handover: spawn errors are ours; the exit is the user's.
224
224
  function handOverTerminal(command, args, displayName) {
225
- const result = spawn.sync(command, args, { stdio: "inherit" });
225
+ const result = spawn.sync(command, args, { stdio: 'inherit' });
226
226
  if (result.error) {
227
227
  throw spawnStepError(`Could not launch ${displayName}`, result);
228
228
  }
229
229
  }
230
230
  function launchHermesWalkthrough() {
231
- const seedResult = spawn.sync("hermes", ["chat", "-Q", "-q", DEFAULT_ONBOARDING_PROMPT], {
232
- encoding: "utf8",
231
+ const seedResult = spawn.sync('hermes', ['chat', '-Q', '-q', DEFAULT_ONBOARDING_PROMPT], {
232
+ encoding: 'utf8',
233
233
  timeout: HERMES_SEED_TIMEOUT_MS,
234
234
  });
235
235
  if (seedResult.error || seedResult.status !== 0) {
236
- throw spawnStepError("Could not start the TinyFish walkthrough in Hermes", seedResult);
236
+ throw spawnStepError('Could not start the TinyFish walkthrough in Hermes', seedResult);
237
237
  }
238
238
  // A colourised id would carry its trailing escape sequence into `--resume` (PF-3452).
239
- const sessionId = sanitizeLine(seedResult.stderr ?? "").match(/session_id:\s*([^\s]+)/i)?.[1];
239
+ const sessionId = sanitizeLine(seedResult.stderr ?? '').match(/session_id:\s*([^\s]+)/i)?.[1];
240
240
  if (!sessionId) {
241
- throw new Error("Hermes did not return a walkthrough session ID");
241
+ throw new Error('Hermes did not return a walkthrough session ID');
242
242
  }
243
- handOverTerminal("hermes", ["--resume", sessionId], "Hermes");
243
+ handOverTerminal('hermes', ['--resume', sessionId], 'Hermes');
244
244
  }
245
245
  export const HERMES = {
246
- command: "hermes",
247
- connectClient: "hermes",
248
- skillAgent: "hermes-agent",
249
- displayName: "Hermes",
246
+ command: 'hermes',
247
+ connectClient: 'hermes',
248
+ skillAgent: 'hermes-agent',
249
+ displayName: 'Hermes',
250
250
  supportCheck: {
251
- args: ["mcp", "add", "--help"],
251
+ args: ['mcp', 'add', '--help'],
252
252
  patterns: [/--auth\s+\{[^}]*oauth[^}]*\}/],
253
253
  unavailableMessage: HERMES_OAUTH_UNAVAILABLE_MESSAGE,
254
254
  },
255
255
  // No `keyAuth`: `hermes mcp add` has no --header, and `--auth header` prompts interactively.
256
- removals: [{ args: ["mcp", "remove", "tinyfish"], label: "TinyFish registration from Hermes" }],
256
+ removals: [{ args: ['mcp', 'remove', 'tinyfish'], label: 'TinyFish registration from Hermes' }],
257
257
  // Hermes completes OAuth while adding the server; a separate `mcp login` would authenticate twice.
258
258
  oauthInAdd: true,
259
- addArgs: (mcpUrl) => [...urlAddArgs(mcpUrl), "--auth", "oauth"],
259
+ addArgs: (mcpUrl) => [...urlAddArgs(mcpUrl), '--auth', 'oauth'],
260
260
  launchWalkthrough: launchHermesWalkthrough,
261
261
  };
262
262
  // OpenCode's TUI takes a positional as a project directory, so a bare `opencode "<prompt>"`
263
263
  // would be read as a folder. The `--prompt` flag seeds the interactive TUI with a first message
264
264
  // (opencode.ai/docs/cli), so the onboarding guide fires just like the other agents.
265
265
  function launchOpencode() {
266
- handOverTerminal("opencode", ["--prompt", DEFAULT_ONBOARDING_PROMPT], "OpenCode");
266
+ handOverTerminal('opencode', ['--prompt', DEFAULT_ONBOARDING_PROMPT], 'OpenCode');
267
267
  }
268
268
  export const OPENCODE = {
269
- command: "opencode",
270
- connectClient: "opencode",
271
- skillAgent: "opencode",
269
+ command: 'opencode',
270
+ connectClient: 'opencode',
271
+ skillAgent: 'opencode',
272
272
  nonInteractiveAdd: true,
273
- displayName: "OpenCode",
273
+ displayName: 'OpenCode',
274
274
  supportCheck: {
275
- args: ["mcp", "add", "--help"],
275
+ args: ['mcp', 'add', '--help'],
276
276
  patterns: [/--url(?:\s|$)/m],
277
277
  keyAuthPattern: HEADER_FLAG,
278
278
  unavailableMessage: OPENCODE_MCP_ADD_UNAVAILABLE_MESSAGE,
@@ -282,7 +282,7 @@ export const OPENCODE = {
282
282
  removals: [],
283
283
  // OpenCode writes ~/.config/opencode/opencode.json itself; `mcp auth` is the separate OAuth step.
284
284
  addArgs: (mcpUrl) => urlAddArgs(mcpUrl),
285
- loginArgs: ["mcp", "auth", "tinyfish"],
285
+ loginArgs: ['mcp', 'auth', 'tinyfish'],
286
286
  launchWalkthrough: launchOpencode,
287
287
  postConnectNote: OPENCODE_MODEL_NOTE,
288
288
  };
@@ -297,17 +297,17 @@ export const NATIVE_MCP_CLIENTS = [
297
297
  /** Native descriptor by harness id; Cursor and OpenClaw have none. */
298
298
  export const NATIVE_BY_HARNESS = new Map(NATIVE_MCP_CLIENTS.map((client) => [client.connectClient, client]));
299
299
  export const OPENCLAW = {
300
- command: "openclaw",
301
- displayName: "OpenClaw",
300
+ command: 'openclaw',
301
+ displayName: 'OpenClaw',
302
302
  supportCheck: {
303
- args: ["skills", "install", "--help"],
303
+ args: ['skills', 'install', '--help'],
304
304
  patterns: [/--global(?:\s|$)/, /--acknowledge-clawhub-risk(?:\s|$)/],
305
305
  unavailableMessage: OPENCLAW_SKILL_UNAVAILABLE_MESSAGE,
306
306
  },
307
307
  };
308
308
  /** Required booleans: a new harness or new flag fails to compile undecided. */
309
309
  export const HARNESS_CAPABILITIES = {
310
- "claude-code": {
310
+ 'claude-code': {
311
311
  signInViaCliLogin: false,
312
312
  canVerifyAuth: false,
313
313
  keyHeldByCli: false,
@@ -363,22 +363,22 @@ function printPromptForHandoff(displayName, command, prompt, reason) {
363
363
  errLine(`TinyFish is set up in ${displayName}.`);
364
364
  errLine(`${reason}, so TinyFish did not launch it. Start ${displayName} (\`${command}\`) yourself ` +
365
365
  `and paste this first message:`);
366
- errLine("");
366
+ errLine('');
367
367
  errLine(prompt);
368
368
  }
369
369
  /** One gate + one decide-before-block path for every terminal handover. */
370
370
  async function deliverWalkthrough(displayName, command, prompt, handover, onDecided) {
371
371
  // Inherited-stdio handover: a non-TTY parent cannot approve tool calls.
372
372
  if (!detectHumanInitiated()) {
373
- await onDecided?.("printed");
373
+ await onDecided?.('printed');
374
374
  printPromptForHandoff(displayName, command, prompt, `This terminal cannot answer ${displayName}'s tool-approval prompts`);
375
- return "printed";
375
+ return 'printed';
376
376
  }
377
377
  // Decided and delivered first: the handover blocks for the whole session.
378
- await onDecided?.("launched");
378
+ await onDecided?.('launched');
379
379
  errLine(`Starting the TinyFish walkthrough in ${displayName}...`);
380
380
  handover();
381
- return "launched";
381
+ return 'launched';
382
382
  }
383
383
  export async function launchNativeMcpClient(client, onDecided) {
384
384
  if (client.detachedLaunch) {
@@ -393,5 +393,5 @@ export async function launchNativeMcpClient(client, onDecided) {
393
393
  : handOverTerminal(client.command, [DEFAULT_ONBOARDING_PROMPT], client.displayName), onDecided);
394
394
  }
395
395
  export function launchOpenClawWalkthrough(onDecided) {
396
- return deliverWalkthrough("OpenClaw", "openclaw", OPENCLAW_ONBOARDING_PROMPT, () => handOverTerminal("openclaw", ["chat", "--message", OPENCLAW_ONBOARDING_PROMPT], "OpenClaw"), onDecided);
396
+ return deliverWalkthrough('OpenClaw', 'openclaw', OPENCLAW_ONBOARDING_PROMPT, () => handOverTerminal('openclaw', ['chat', '--message', OPENCLAW_ONBOARDING_PROMPT], 'OpenClaw'), onDecided);
397
397
  }
@@ -1,4 +1,4 @@
1
- import { type CliFallbackOutcome, type ConnectCheckpoint, type ConnectFailureStage } from "./connect-runtime.js";
1
+ import { type CliFallbackOutcome, type ConnectCheckpoint, type ConnectFailureStage } from './connect-runtime.js';
2
2
  export type Prompt = (question: string) => Promise<string>;
3
3
  export declare const SEARCH_RETRY = "tinyfish search query --pretty -- \"<your query>\"";
4
4
  export declare const DEFAULT_VERIFICATION_QUERY = "today's top Hacker News story";