@tiny-fish/cli 0.4.1-next.92 → 0.5.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.
package/README.md CHANGED
@@ -49,6 +49,18 @@ npx -y @tiny-fish/cli@latest connect hermes --launch
49
49
  Hermes completes OAuth while adding the MCP server. After setup, the command starts the walkthrough
50
50
  in a Hermes session and leaves that session open for your replies.
51
51
 
52
+ ### Connect OpenClaw
53
+
54
+ Install the TinyFish skill, sign in with an API key, and start an interactive walkthrough with one
55
+ command:
56
+
57
+ ```bash
58
+ npx -y @tiny-fish/cli@latest connect openclaw --launch
59
+ ```
60
+
61
+ OpenClaw must already be installed. The command installs the TinyFish skill for all local OpenClaw
62
+ agents and guides you through Search, Fetch, and Agent one step at a time.
63
+
52
64
  ## Authentication
53
65
 
54
66
  Get your API key from [agent.tinyfish.ai](https://agent.tinyfish.ai).
@@ -1,5 +1,6 @@
1
1
  import { Command } from "commander";
2
2
  export declare const DEFAULT_ONBOARDING_PROMPT: string;
3
+ export declare const OPENCLAW_ONBOARDING_PROMPT: string;
3
4
  export declare function connectClaudeCode(options: {
4
5
  mcpUrl: string;
5
6
  launch: boolean;
@@ -12,4 +13,7 @@ export declare function connectHermes(options: {
12
13
  mcpUrl: string;
13
14
  launch: boolean;
14
15
  }): void;
16
+ export declare function connectOpenClaw(options: {
17
+ launch: boolean;
18
+ }): void;
15
19
  export declare function registerConnect(program: Command): void;
@@ -10,15 +10,23 @@ const CODEX_OAUTH_RESOURCE_UNAVAILABLE_MESSAGE = "This Codex installation does n
10
10
  "retry, or add TinyFish manually with `codex mcp add`.";
11
11
  const HERMES_OAUTH_UNAVAILABLE_MESSAGE = "This Hermes installation does not support one-command MCP authentication. Update Hermes and " +
12
12
  "retry, or add TinyFish manually with `hermes mcp add`.";
13
+ const OPENCLAW_SKILL_UNAVAILABLE_MESSAGE = "This OpenClaw installation does not support global skill installation. Update OpenClaw and " +
14
+ "retry.";
15
+ const TINYFISH_CLI_NOT_FOUND_MESSAGE = "TinyFish CLI installed but is not available on PATH. Open a new terminal and retry.";
16
+ const OPENCLAW_SKILL = "@tinyfish/tinyfish";
13
17
  export const DEFAULT_ONBOARDING_PROMPT = "I just connected TinyFish. Call the guide_next_step tool now to begin. Then follow its " +
14
18
  "instructions one step at a time. Ask for my input and wait for my reply before each subsequent " +
15
19
  "TinyFish tool call.";
20
+ export const OPENCLAW_ONBOARDING_PROMPT = "I just installed the TinyFish skill. Guide me through it interactively: first ask what topic I " +
21
+ "want to search and wait for my reply before using TinyFish Search. Show me the results, ask " +
22
+ "which result I want to read, and wait before using TinyFish Fetch. Then ask what browser task " +
23
+ "I want to complete and wait before using TinyFish Agent. Never skip ahead or choose for me.";
16
24
  const CLAUDE_CODE = {
17
25
  command: "claude",
18
26
  displayName: "Claude Code",
19
27
  supportCheck: {
20
28
  args: ["mcp", "--help"],
21
- pattern: /^\s*login(?:\s|\[)/m,
29
+ patterns: [/^\s*login(?:\s|\[)/m],
22
30
  unavailableMessage: MCP_LOGIN_UNAVAILABLE_MESSAGE,
23
31
  },
24
32
  loginArgs: ["mcp", "login", "tinyfish"],
@@ -37,7 +45,7 @@ const CODEX = {
37
45
  displayName: "Codex",
38
46
  supportCheck: {
39
47
  args: ["mcp", "add", "--help"],
40
- pattern: /--oauth-resource(?:\s|<)/,
48
+ patterns: [/--oauth-resource(?:\s|<)/],
41
49
  unavailableMessage: CODEX_OAUTH_RESOURCE_UNAVAILABLE_MESSAGE,
42
50
  },
43
51
  removals: [{ args: ["mcp", "remove", "tinyfish"], label: "TinyFish registration from Codex" }],
@@ -72,7 +80,7 @@ const HERMES = {
72
80
  displayName: "Hermes",
73
81
  supportCheck: {
74
82
  args: ["mcp", "add", "--help"],
75
- pattern: /--auth\s+\{[^}]*oauth[^}]*\}/,
83
+ patterns: [/--auth\s+\{[^}]*oauth[^}]*\}/],
76
84
  unavailableMessage: HERMES_OAUTH_UNAVAILABLE_MESSAGE,
77
85
  },
78
86
  removals: [{ args: ["mcp", "remove", "tinyfish"], label: "TinyFish registration from Hermes" }],
@@ -80,12 +88,21 @@ const HERMES = {
80
88
  addArgs: (mcpUrl) => ["mcp", "add", "tinyfish", "--url", mcpUrl, "--auth", "oauth"],
81
89
  launchWalkthrough: launchHermesWalkthrough,
82
90
  };
83
- function requireNativeMcpSupport(client) {
91
+ const OPENCLAW = {
92
+ command: "openclaw",
93
+ displayName: "OpenClaw",
94
+ supportCheck: {
95
+ args: ["skills", "install", "--help"],
96
+ patterns: [/--global(?:\s|$)/, /--acknowledge-clawhub-risk(?:\s|$)/],
97
+ unavailableMessage: OPENCLAW_SKILL_UNAVAILABLE_MESSAGE,
98
+ },
99
+ };
100
+ function requireCommandSupport(client) {
84
101
  const result = spawn.sync(client.command, client.supportCheck.args, {
85
102
  encoding: "utf8",
86
103
  timeout: NON_INTERACTIVE_TIMEOUT_MS,
87
104
  });
88
- if (result.error?.code === "ENOENT") {
105
+ if (commandNotFound(result.error)) {
89
106
  throw new Error(`${client.displayName} is not installed or not available on PATH.`, {
90
107
  cause: result.error,
91
108
  });
@@ -94,10 +111,13 @@ function requireNativeMcpSupport(client) {
94
111
  throw new Error(client.supportCheck.unavailableMessage, { cause: result.error });
95
112
  }
96
113
  const output = `${result.stdout ?? ""}\n${result.stderr ?? ""}`;
97
- if (!client.supportCheck.pattern.test(output)) {
114
+ if (!client.supportCheck.patterns.every((pattern) => pattern.test(output))) {
98
115
  throw new Error(client.supportCheck.unavailableMessage);
99
116
  }
100
117
  }
118
+ function commandNotFound(error) {
119
+ return error?.code === "ENOENT";
120
+ }
101
121
  function removeExistingRegistration(client, removal) {
102
122
  const result = spawn.sync(client.command, removal.args, {
103
123
  encoding: "utf8",
@@ -116,7 +136,7 @@ function removeExistingRegistration(client, removal) {
116
136
  throw new Error(`Could not remove existing ${removal.label}: ${details}`);
117
137
  }
118
138
  function connectNativeMcpClient(client, options) {
119
- requireNativeMcpSupport(client);
139
+ requireCommandSupport(client);
120
140
  for (const removal of client.removals)
121
141
  removeExistingRegistration(client, removal);
122
142
  errLine(`Adding TinyFish to ${client.displayName}...`);
@@ -167,11 +187,63 @@ export function connectCodex(options) {
167
187
  export function connectHermes(options) {
168
188
  connectNativeMcpClient(HERMES, options);
169
189
  }
190
+ export function connectOpenClaw(options) {
191
+ requireCommandSupport(OPENCLAW);
192
+ errLine("Installing the TinyFish CLI...");
193
+ const cliInstallResult = spawn.sync("npm", ["install", "--global", "@tiny-fish/cli@latest"], { stdio: "inherit" });
194
+ if (cliInstallResult.error || cliInstallResult.status !== 0) {
195
+ throw new Error("Could not install the TinyFish CLI", { cause: cliInstallResult.error });
196
+ }
197
+ errLine("Installing the TinyFish skill in OpenClaw...");
198
+ const skillInstallResult = spawn.sync("openclaw", [
199
+ "skills",
200
+ "install",
201
+ OPENCLAW_SKILL,
202
+ "--global",
203
+ "--force",
204
+ "--acknowledge-clawhub-risk",
205
+ ], { stdio: "inherit" });
206
+ if (skillInstallResult.error || skillInstallResult.status !== 0) {
207
+ throw new Error("Could not install the TinyFish skill in OpenClaw", {
208
+ cause: skillInstallResult.error,
209
+ });
210
+ }
211
+ const authStatus = spawn.sync("tinyfish", ["auth", "status"], { stdio: "ignore" });
212
+ if (commandNotFound(authStatus.error)) {
213
+ throw new Error(TINYFISH_CLI_NOT_FOUND_MESSAGE, { cause: authStatus.error });
214
+ }
215
+ if (authStatus.status !== 0) {
216
+ errLine("Signing in to TinyFish...");
217
+ const loginResult = spawn.sync("tinyfish", ["auth", "login", "--source", "openclaw"], { stdio: "inherit" });
218
+ if (commandNotFound(loginResult.error)) {
219
+ throw new Error(TINYFISH_CLI_NOT_FOUND_MESSAGE, { cause: loginResult.error });
220
+ }
221
+ if (loginResult.error || loginResult.status !== 0) {
222
+ throw new Error("Could not authenticate TinyFish for OpenClaw", {
223
+ cause: loginResult.error,
224
+ });
225
+ }
226
+ }
227
+ if (!options.launch) {
228
+ errLine("TinyFish is connected. Open OpenClaw to start using it.");
229
+ return;
230
+ }
231
+ errLine("Starting the TinyFish walkthrough in OpenClaw...");
232
+ const launchResult = spawn.sync("openclaw", ["chat", "--message", OPENCLAW_ONBOARDING_PROMPT], { stdio: "inherit" });
233
+ if (launchResult.error) {
234
+ throw new Error("Could not launch OpenClaw", { cause: launchResult.error });
235
+ }
236
+ if (launchResult.signal === "SIGINT" || launchResult.signal === "SIGTERM")
237
+ return;
238
+ if (launchResult.status !== 0) {
239
+ throw new Error(`OpenClaw walkthrough exited with status ${launchResult.status ?? "unknown"}`);
240
+ }
241
+ }
170
242
  export function registerConnect(program) {
171
243
  program
172
244
  .command("connect")
173
245
  .description("Connect TinyFish to an AI agent")
174
- .argument("<client>", "Agent client to connect (claude-code, codex, or hermes)")
246
+ .argument("<client>", "Agent client to connect (claude-code, codex, hermes, or openclaw)")
175
247
  .option("--launch", "Launch the agent and start the TinyFish walkthrough")
176
248
  .option("--url <mcpUrl>", "MCP endpoint override")
177
249
  .action((client, options) => {
@@ -199,8 +271,11 @@ export function registerConnect(program) {
199
271
  else if (client === "hermes") {
200
272
  connectHermes(connectOptions);
201
273
  }
274
+ else if (client === "openclaw") {
275
+ connectOpenClaw({ launch: connectOptions.launch });
276
+ }
202
277
  else {
203
- throw new Error(`Unsupported client: ${client}. Supported clients: claude-code, codex, hermes`);
278
+ throw new Error(`Unsupported client: ${client}. Supported clients: claude-code, codex, hermes, openclaw`);
204
279
  }
205
280
  });
206
281
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiny-fish/cli",
3
- "version": "0.4.1-next.92",
3
+ "version": "0.5.0",
4
4
  "description": "TinyFish CLI — run web automations from your terminal",
5
5
  "type": "module",
6
6
  "bin": {