@tiny-fish/cli 0.40.0 → 0.40.1-next.318
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 +7 -0
- package/dist/commands/fetch.js +79 -24
- package/dist/index.js +7 -2
- package/dist/lib/client.d.ts +113 -3
- package/dist/lib/client.js +14 -3
- package/dist/lib/hermes-env.d.ts +2 -0
- package/dist/lib/hermes-env.js +16 -0
- package/dist/lib/types.d.ts +10 -1
- package/dist/program.d.ts +2 -2
- package/dist/program.js +48 -36
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -278,6 +278,13 @@ tinyfish fetch content get https://agentql.com --links --image-links
|
|
|
278
278
|
# Bound each URL independently
|
|
279
279
|
tinyfish fetch content get https://agentql.com --per-url-timeout-ms 45000
|
|
280
280
|
|
|
281
|
+
# Ranked verbatim snippets answering a query (beta; markdown only, max 10 URLs)
|
|
282
|
+
tinyfish fetch content get https://agentql.com --highlights "pricing tiers"
|
|
283
|
+
|
|
284
|
+
# Tune snippets: count (1-20, default 5), total characters, keep full-page text
|
|
285
|
+
tinyfish fetch content get https://agentql.com --highlights "pricing tiers" \
|
|
286
|
+
--max-snippets 3 --max-characters 1200 --include-full-page-text
|
|
287
|
+
|
|
281
288
|
# Human-readable output
|
|
282
289
|
tinyfish fetch content get https://agentql.com --pretty
|
|
283
290
|
```
|
package/dist/commands/fetch.js
CHANGED
|
@@ -4,14 +4,64 @@ import { fetchContentGet } from '../lib/client.js';
|
|
|
4
4
|
import { err, handleApiError, out, outLine } from '../lib/output.js';
|
|
5
5
|
const MIN_PER_URL_TIMEOUT_MS = 1;
|
|
6
6
|
const MAX_PER_URL_TIMEOUT_MS = 110000;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
const MIN_HIGHLIGHT_SNIPPETS = 1;
|
|
8
|
+
const MAX_HIGHLIGHT_SNIPPETS = 20;
|
|
9
|
+
const MAX_URLS = 10;
|
|
10
|
+
function integerInRange(min, max) {
|
|
11
|
+
return (value) => {
|
|
12
|
+
const parsed = Number(value);
|
|
13
|
+
if (!Number.isSafeInteger(parsed) || parsed < min || (max !== undefined && parsed > max)) {
|
|
14
|
+
throw new InvalidArgumentError(max === undefined
|
|
15
|
+
? 'must be a positive integer'
|
|
16
|
+
: `must be an integer between ${min} and ${max}`);
|
|
17
|
+
}
|
|
18
|
+
return parsed;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function validateHighlightsOptions(opts) {
|
|
22
|
+
const hasSubFlag = opts.maxSnippets !== undefined ||
|
|
23
|
+
opts.maxCharacters !== undefined ||
|
|
24
|
+
opts.includeFullPageText !== undefined;
|
|
25
|
+
if (opts.highlights === undefined) {
|
|
26
|
+
return hasSubFlag
|
|
27
|
+
? '--max-snippets, --max-characters and --include-full-page-text require --highlights'
|
|
28
|
+
: null;
|
|
29
|
+
}
|
|
30
|
+
if (opts.highlights.trim() === '') {
|
|
31
|
+
return '--highlights requires a non-empty query';
|
|
13
32
|
}
|
|
14
|
-
|
|
33
|
+
if (opts.format !== undefined && opts.format !== 'markdown') {
|
|
34
|
+
return '--highlights requires --format markdown';
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
function buildHighlightsParams(opts) {
|
|
39
|
+
if (opts.highlights === undefined)
|
|
40
|
+
return undefined;
|
|
41
|
+
return {
|
|
42
|
+
query: opts.highlights,
|
|
43
|
+
...(opts.maxSnippets !== undefined ? { max_snippets: opts.maxSnippets } : {}),
|
|
44
|
+
...(opts.maxCharacters !== undefined ? { max_characters: opts.maxCharacters } : {}),
|
|
45
|
+
...(opts.includeFullPageText !== undefined
|
|
46
|
+
? { include_full_page_text: opts.includeFullPageText }
|
|
47
|
+
: {}),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function buildFetchParams(urls, opts) {
|
|
51
|
+
const highlights = buildHighlightsParams(opts);
|
|
52
|
+
return {
|
|
53
|
+
urls,
|
|
54
|
+
...(opts.format !== undefined ? { format: opts.format } : {}),
|
|
55
|
+
...(opts.links !== undefined ? { links: opts.links } : {}),
|
|
56
|
+
...(opts.imageLinks !== undefined ? { image_links: opts.imageLinks } : {}),
|
|
57
|
+
...(opts.perUrlTimeoutMs !== undefined ? { per_url_timeout_ms: opts.perUrlTimeoutMs } : {}),
|
|
58
|
+
...(opts.ifNoneMatch !== undefined ? { if_none_match: opts.ifNoneMatch } : {}),
|
|
59
|
+
...(opts.ifModifiedSince !== undefined ? { if_modified_since: opts.ifModifiedSince } : {}),
|
|
60
|
+
...(opts.includeEtagAndLastModified !== undefined
|
|
61
|
+
? { include_etag_and_last_modified: opts.includeEtagAndLastModified }
|
|
62
|
+
: {}),
|
|
63
|
+
...(highlights !== undefined ? { highlights } : {}),
|
|
64
|
+
};
|
|
15
65
|
}
|
|
16
66
|
function printPrettyFetch(response) {
|
|
17
67
|
outLine(`Results: ${response.results.length}`);
|
|
@@ -32,6 +82,12 @@ function printPrettyFetch(response) {
|
|
|
32
82
|
outLine(` ETag: ${result.etag}`);
|
|
33
83
|
if (result.last_modified)
|
|
34
84
|
outLine(` Last-Modified: ${result.last_modified}`);
|
|
85
|
+
if (result.highlights && result.highlights.length > 0) {
|
|
86
|
+
outLine(' Highlights:');
|
|
87
|
+
result.highlights.forEach((snippet, index) => {
|
|
88
|
+
outLine(` ${index + 1}. ${snippet.text}`);
|
|
89
|
+
});
|
|
90
|
+
}
|
|
35
91
|
outLine('');
|
|
36
92
|
}
|
|
37
93
|
}
|
|
@@ -57,12 +113,26 @@ export function registerFetch(program) {
|
|
|
57
113
|
.option('--format <format>', 'Output format: markdown, html, or json')
|
|
58
114
|
.option('--links', 'Include extracted links')
|
|
59
115
|
.option('--image-links', 'Include extracted image links')
|
|
60
|
-
.option('--per-url-timeout-ms <milliseconds>', 'Per-URL timeout budget in milliseconds',
|
|
116
|
+
.option('--per-url-timeout-ms <milliseconds>', 'Per-URL timeout budget in milliseconds', integerInRange(MIN_PER_URL_TIMEOUT_MS, MAX_PER_URL_TIMEOUT_MS))
|
|
61
117
|
.option('--if-none-match <etag>', 'ETag validator for a conditional GET (single URL only)')
|
|
62
118
|
.option('--if-modified-since <http-date>', 'Last-Modified validator for a conditional GET (single URL only)')
|
|
63
119
|
.option('--include-etag-and-last-modified', 'Include etag / last_modified validators on each result')
|
|
120
|
+
.option('--highlights <query>', '(beta) Return ranked verbatim snippets answering the query instead of full-page text (markdown only, max 10 URLs)')
|
|
121
|
+
.option('--max-snippets <n>', 'Maximum snippets per URL, 1-20 (default 5; requires --highlights)', integerInRange(MIN_HIGHLIGHT_SNIPPETS, MAX_HIGHLIGHT_SNIPPETS))
|
|
122
|
+
.option('--max-characters <n>', 'Maximum total characters across snippets (requires --highlights)', integerInRange(1))
|
|
123
|
+
.option('--include-full-page-text', 'Also return full-page text alongside snippets (requires --highlights)')
|
|
64
124
|
.option('--pretty', 'Human-readable output')
|
|
65
125
|
.action(async (urls, opts) => {
|
|
126
|
+
// Mirrors the SDK cap the raw post path no longer enforces.
|
|
127
|
+
if (urls.length > MAX_URLS) {
|
|
128
|
+
err({ error: `urls must contain at most ${MAX_URLS} items` });
|
|
129
|
+
process.exit(1);
|
|
130
|
+
}
|
|
131
|
+
const highlightsError = validateHighlightsOptions(opts);
|
|
132
|
+
if (highlightsError !== null) {
|
|
133
|
+
err({ error: highlightsError });
|
|
134
|
+
process.exit(1);
|
|
135
|
+
}
|
|
66
136
|
if ((opts.ifNoneMatch !== undefined || opts.ifModifiedSince !== undefined) &&
|
|
67
137
|
urls.length > 1) {
|
|
68
138
|
err({
|
|
@@ -72,22 +142,7 @@ export function registerFetch(program) {
|
|
|
72
142
|
}
|
|
73
143
|
const apiKey = getApiKey();
|
|
74
144
|
try {
|
|
75
|
-
const response = await fetchContentGet(
|
|
76
|
-
urls,
|
|
77
|
-
...(opts.format !== undefined ? { format: opts.format } : {}),
|
|
78
|
-
...(opts.links !== undefined ? { links: opts.links } : {}),
|
|
79
|
-
...(opts.imageLinks !== undefined ? { image_links: opts.imageLinks } : {}),
|
|
80
|
-
...(opts.perUrlTimeoutMs !== undefined
|
|
81
|
-
? { per_url_timeout_ms: opts.perUrlTimeoutMs }
|
|
82
|
-
: {}),
|
|
83
|
-
...(opts.ifNoneMatch !== undefined ? { if_none_match: opts.ifNoneMatch } : {}),
|
|
84
|
-
...(opts.ifModifiedSince !== undefined
|
|
85
|
-
? { if_modified_since: opts.ifModifiedSince }
|
|
86
|
-
: {}),
|
|
87
|
-
...(opts.includeEtagAndLastModified !== undefined
|
|
88
|
-
? { include_etag_and_last_modified: opts.includeEtagAndLastModified }
|
|
89
|
-
: {}),
|
|
90
|
-
}, apiKey);
|
|
145
|
+
const response = await fetchContentGet(buildFetchParams(urls, opts), apiKey);
|
|
91
146
|
if (opts.pretty) {
|
|
92
147
|
printPrettyFetch(response);
|
|
93
148
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { buildProgram } from './program.js';
|
|
3
|
-
const { program } = buildProgram();
|
|
4
3
|
// Await parseAsync so async command handlers complete before the process exits
|
|
5
|
-
|
|
4
|
+
buildProgram()
|
|
5
|
+
.then(({ program }) => program.parseAsync(process.argv))
|
|
6
|
+
.catch((e) => {
|
|
6
7
|
process.stderr.write(JSON.stringify({ error: e instanceof Error ? e.message : String(e) }) + '\n');
|
|
8
|
+
// A failed command import reads as a bare message; the stack names the module.
|
|
9
|
+
if (process.env['TINYFISH_DEBUG'] && e instanceof Error && e.stack) {
|
|
10
|
+
process.stderr.write(e.stack + '\n');
|
|
11
|
+
}
|
|
7
12
|
process.exit(1);
|
|
8
13
|
});
|
package/dist/lib/client.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { type AgentRunAsyncResponse, type AgentRunResponse, type AgentRunWithStreamingResponse, type
|
|
2
|
-
import type { BatchCancelResponse, BatchGetResponse, BatchRunRequest, BatchRunResponse, CancelRunResponse, CliAgentRunParams, CliBrowserSessionCreateParams, CookieRecord, ProfileCreateResponse, ProfileUploadResponse, RunStepsResponse, VaultConnectRequest, VaultConnectResponse, VaultConnectionsListResponse, VaultDisconnectResponse, VaultItemsListResponse, VaultItemsSyncResponse } from './types.js';
|
|
1
|
+
import { type AgentRunAsyncResponse, type AgentRunResponse, type AgentRunWithStreamingResponse, type BrowserSession, type Run, type RunListParams, type RunListResponse, type SearchQueryParams, type SearchQueryResponse, type WalletResponse } from '@tiny-fish/sdk';
|
|
2
|
+
import type { BatchCancelResponse, BatchGetResponse, BatchRunRequest, BatchRunResponse, CancelRunResponse, CliAgentRunParams, CliBrowserSessionCreateParams, CliFetchGetContentsParams, CookieRecord, ProfileCreateResponse, ProfileUploadResponse, RunStepsResponse, VaultConnectRequest, VaultConnectResponse, VaultConnectionsListResponse, VaultDisconnectResponse, VaultItemsListResponse, VaultItemsSyncResponse } from './types.js';
|
|
3
|
+
import { z } from 'zod';
|
|
3
4
|
type ConnectMap = Record<string, {
|
|
4
5
|
attempt_id: string;
|
|
5
6
|
}> | undefined;
|
|
@@ -12,7 +13,116 @@ export declare function listRuns(opts: RunListParams, apiKey: string, timeout?:
|
|
|
12
13
|
export declare function getRun(runId: string, apiKey: string): Promise<Run>;
|
|
13
14
|
export declare function getRunSteps(runId: string, apiKey: string): Promise<RunStepsResponse>;
|
|
14
15
|
export declare function searchQuery(params: SearchQueryParams, apiKey: string): Promise<SearchQueryResponse>;
|
|
15
|
-
|
|
16
|
+
declare const cliFetchResponseSchema: z.ZodObject<{
|
|
17
|
+
results: z.ZodArray<z.ZodIntersection<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
18
|
+
url: z.ZodString;
|
|
19
|
+
final_url: z.ZodNullable<z.ZodString>;
|
|
20
|
+
title: z.ZodNullable<z.ZodString>;
|
|
21
|
+
description: z.ZodNullable<z.ZodString>;
|
|
22
|
+
language: z.ZodNullable<z.ZodString>;
|
|
23
|
+
author: z.ZodNullable<z.ZodString>;
|
|
24
|
+
published_date: z.ZodNullable<z.ZodString>;
|
|
25
|
+
links: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
26
|
+
image_links: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
27
|
+
latency_ms: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
28
|
+
not_modified: z.ZodOptional<z.ZodBoolean>;
|
|
29
|
+
etag: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
30
|
+
last_modified: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
31
|
+
format: z.ZodLiteral<"markdown">;
|
|
32
|
+
text: z.ZodNullable<z.ZodString>;
|
|
33
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
34
|
+
url: z.ZodString;
|
|
35
|
+
final_url: z.ZodNullable<z.ZodString>;
|
|
36
|
+
title: z.ZodNullable<z.ZodString>;
|
|
37
|
+
description: z.ZodNullable<z.ZodString>;
|
|
38
|
+
language: z.ZodNullable<z.ZodString>;
|
|
39
|
+
author: z.ZodNullable<z.ZodString>;
|
|
40
|
+
published_date: z.ZodNullable<z.ZodString>;
|
|
41
|
+
links: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
42
|
+
image_links: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
43
|
+
latency_ms: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
44
|
+
not_modified: z.ZodOptional<z.ZodBoolean>;
|
|
45
|
+
etag: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
46
|
+
last_modified: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
47
|
+
format: z.ZodLiteral<"html">;
|
|
48
|
+
text: z.ZodNullable<z.ZodString>;
|
|
49
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
50
|
+
url: z.ZodString;
|
|
51
|
+
final_url: z.ZodNullable<z.ZodString>;
|
|
52
|
+
title: z.ZodNullable<z.ZodString>;
|
|
53
|
+
description: z.ZodNullable<z.ZodString>;
|
|
54
|
+
language: z.ZodNullable<z.ZodString>;
|
|
55
|
+
author: z.ZodNullable<z.ZodString>;
|
|
56
|
+
published_date: z.ZodNullable<z.ZodString>;
|
|
57
|
+
links: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
58
|
+
image_links: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
59
|
+
latency_ms: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
60
|
+
not_modified: z.ZodOptional<z.ZodBoolean>;
|
|
61
|
+
etag: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
62
|
+
last_modified: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
63
|
+
format: z.ZodLiteral<"json">;
|
|
64
|
+
text: z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodType<string | number | boolean | {
|
|
65
|
+
[key: string]: string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | /*elided*/ any | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null;
|
|
66
|
+
} | (string | number | boolean | {
|
|
67
|
+
[key: string]: string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | /*elided*/ any | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null;
|
|
68
|
+
} | (string | number | boolean | {
|
|
69
|
+
[key: string]: string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | /*elided*/ any | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null;
|
|
70
|
+
} | (string | number | boolean | {
|
|
71
|
+
[key: string]: string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | /*elided*/ any | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null;
|
|
72
|
+
} | (string | number | boolean | {
|
|
73
|
+
[key: string]: string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | /*elided*/ any | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null;
|
|
74
|
+
} | (string | number | boolean | {
|
|
75
|
+
[key: string]: string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | /*elided*/ any | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null;
|
|
76
|
+
} | (string | number | boolean | {
|
|
77
|
+
[key: string]: string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | /*elided*/ any | null)[] | null)[] | null)[] | null)[] | null)[] | null;
|
|
78
|
+
} | (string | number | boolean | {
|
|
79
|
+
[key: string]: string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | /*elided*/ any | null)[] | null)[] | null)[] | null)[] | null;
|
|
80
|
+
} | (string | number | boolean | {
|
|
81
|
+
[key: string]: string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | /*elided*/ any | null)[] | null)[] | null)[] | null;
|
|
82
|
+
} | (string | number | boolean | {
|
|
83
|
+
[key: string]: string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | /*elided*/ any | null)[] | null)[] | null;
|
|
84
|
+
} | (string | number | boolean | {
|
|
85
|
+
[key: string]: string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | /*elided*/ any | null)[] | null;
|
|
86
|
+
} | (string | number | boolean | {
|
|
87
|
+
[key: string]: string | number | boolean | /*elided*/ any | /*elided*/ any | null;
|
|
88
|
+
} | /*elided*/ any | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null, unknown, z.core.$ZodTypeInternals<string | number | boolean | {
|
|
89
|
+
[key: string]: string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | /*elided*/ any | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null;
|
|
90
|
+
} | (string | number | boolean | {
|
|
91
|
+
[key: string]: string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | /*elided*/ any | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null;
|
|
92
|
+
} | (string | number | boolean | {
|
|
93
|
+
[key: string]: string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | /*elided*/ any | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null;
|
|
94
|
+
} | (string | number | boolean | {
|
|
95
|
+
[key: string]: string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | /*elided*/ any | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null;
|
|
96
|
+
} | (string | number | boolean | {
|
|
97
|
+
[key: string]: string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | /*elided*/ any | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null;
|
|
98
|
+
} | (string | number | boolean | {
|
|
99
|
+
[key: string]: string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | /*elided*/ any | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null;
|
|
100
|
+
} | (string | number | boolean | {
|
|
101
|
+
[key: string]: string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | /*elided*/ any | null)[] | null)[] | null)[] | null)[] | null)[] | null;
|
|
102
|
+
} | (string | number | boolean | {
|
|
103
|
+
[key: string]: string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | /*elided*/ any | null)[] | null)[] | null)[] | null)[] | null;
|
|
104
|
+
} | (string | number | boolean | {
|
|
105
|
+
[key: string]: string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | /*elided*/ any | null)[] | null)[] | null)[] | null;
|
|
106
|
+
} | (string | number | boolean | {
|
|
107
|
+
[key: string]: string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | /*elided*/ any | null)[] | null)[] | null;
|
|
108
|
+
} | (string | number | boolean | {
|
|
109
|
+
[key: string]: string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | /*elided*/ any | null)[] | null;
|
|
110
|
+
} | (string | number | boolean | {
|
|
111
|
+
[key: string]: string | number | boolean | /*elided*/ any | /*elided*/ any | null;
|
|
112
|
+
} | /*elided*/ any | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null, unknown>>>>;
|
|
113
|
+
}, z.core.$strip>], "format">, z.ZodObject<{
|
|
114
|
+
highlights: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
|
|
115
|
+
text: z.ZodString;
|
|
116
|
+
rank: z.ZodNumber;
|
|
117
|
+
}, z.core.$strip>>>>;
|
|
118
|
+
}, z.core.$strip>>>;
|
|
119
|
+
errors: z.ZodArray<z.ZodObject<{
|
|
120
|
+
url: z.ZodString;
|
|
121
|
+
error: z.ZodString;
|
|
122
|
+
}, z.core.$strip>>;
|
|
123
|
+
}, z.core.$strip>;
|
|
124
|
+
export type CliFetchResponse = z.infer<typeof cliFetchResponseSchema>;
|
|
125
|
+
export declare function fetchContentGet(params: CliFetchGetContentsParams, apiKey: string): Promise<CliFetchResponse>;
|
|
16
126
|
export declare function browserSessionCreate(params: CliBrowserSessionCreateParams, apiKey: string): Promise<BrowserSession>;
|
|
17
127
|
export declare function cancelRun(runId: string, apiKey: string): Promise<CancelRunResponse>;
|
|
18
128
|
export declare function getWallet(apiKey: string): Promise<WalletResponse>;
|
package/dist/lib/client.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { APIStatusError, agentRunAsyncResponseSchema, agentRunResponseSchema, agentRunWithStreamingResponseSchema,
|
|
1
|
+
import { APIStatusError, agentRunAsyncResponseSchema, agentRunResponseSchema, agentRunWithStreamingResponseSchema, fetchErrorSchema, fetchResultSchema, browserSessionSchema, searchQueryResponseSchema, TinyFish, runSchema, runStatusSchema, } from '@tiny-fish/sdk';
|
|
2
2
|
import { CONNECT_SOURCE, loadConfig } from './auth.js';
|
|
3
3
|
import { API_URL_OVERRIDE, CLI_AGENT_IDENTITY, CLI_VERSION } from './constants.js';
|
|
4
4
|
import { detectHarness, detectHumanInitiated } from './harness.js';
|
|
@@ -281,10 +281,21 @@ export function searchQuery(params, apiKey) {
|
|
|
281
281
|
return searchQueryResponseSchema.parse(response);
|
|
282
282
|
});
|
|
283
283
|
}
|
|
284
|
+
const highlightSnippetSchema = z.object({
|
|
285
|
+
text: z.string(),
|
|
286
|
+
rank: z.number().int().min(1),
|
|
287
|
+
});
|
|
288
|
+
// Published SDK result schema strips `highlights`; intersect to keep it.
|
|
289
|
+
// nullish, not optional: a null must not fail the whole response parse.
|
|
290
|
+
const cliFetchResponseSchema = z.object({
|
|
291
|
+
results: z.array(z.intersection(fetchResultSchema, z.object({ highlights: z.array(highlightSnippetSchema).nullish() }))),
|
|
292
|
+
errors: z.array(fetchErrorSchema),
|
|
293
|
+
});
|
|
284
294
|
export function fetchContentGet(params, apiKey) {
|
|
285
295
|
return sdk(apiKey, async (client) => {
|
|
286
|
-
|
|
287
|
-
|
|
296
|
+
// TODO(PROD-4260): use client.fetch.getContents once #4786 lands in an SDK release.
|
|
297
|
+
const response = await client.post(client.productUrl('fetch'), { json: params });
|
|
298
|
+
return parseWithSchema(cliFetchResponseSchema, response, 'Invalid fetch response');
|
|
288
299
|
});
|
|
289
300
|
}
|
|
290
301
|
export function browserSessionCreate(params, apiKey) {
|
package/dist/lib/hermes-env.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ export type HermesHomeReason = 'timeout' | 'exit' | 'no_line' | 'relative';
|
|
|
4
4
|
export interface HermesHomeFailure {
|
|
5
5
|
reason: HermesHomeReason;
|
|
6
6
|
}
|
|
7
|
+
/** Tests share one process; the resolver result must not. */
|
|
8
|
+
export declare function resetHermesHomeCache(): void;
|
|
7
9
|
/** Asking Hermes beats reimplementing its profile override, which we'd drift from. */
|
|
8
10
|
export declare function resolveHermesHome(): string | HermesHomeFailure;
|
|
9
11
|
export declare const HERMES_KEY_VAR = "MCP_TINYFISH_API_KEY";
|
package/dist/lib/hermes-env.js
CHANGED
|
@@ -7,8 +7,24 @@ import { HARNESS_PROBE_TIMEOUT_MS } from './constants.js';
|
|
|
7
7
|
import { sanitizeLine } from './output.js';
|
|
8
8
|
// display_hermes_home() abbreviates under $HOME, so the value is not always absolute.
|
|
9
9
|
const HERMES_HOME_LINE = /^\s*hermes_home:\s*(\S.*?)\s*$/m;
|
|
10
|
+
// Cached: `hermes dump` starts Python, and doctor asks repeatedly.
|
|
11
|
+
let cachedHermesHome;
|
|
12
|
+
/** Tests share one process; the resolver result must not. */
|
|
13
|
+
export function resetHermesHomeCache() {
|
|
14
|
+
cachedHermesHome = undefined;
|
|
15
|
+
}
|
|
10
16
|
/** Asking Hermes beats reimplementing its profile override, which we'd drift from. */
|
|
11
17
|
export function resolveHermesHome() {
|
|
18
|
+
if (cachedHermesHome)
|
|
19
|
+
return cachedHermesHome.value;
|
|
20
|
+
const value = probeHermesHome();
|
|
21
|
+
// A timeout is load-dependent; caching it would sink a run a retry still saves.
|
|
22
|
+
if (typeof value === 'string' || value.reason !== 'timeout') {
|
|
23
|
+
cachedHermesHome = { value };
|
|
24
|
+
}
|
|
25
|
+
return value;
|
|
26
|
+
}
|
|
27
|
+
function probeHermesHome() {
|
|
12
28
|
const result = spawn.sync('hermes', ['dump'], {
|
|
13
29
|
encoding: 'utf8',
|
|
14
30
|
env: { ...process.env, FORCE_COLOR: '0', NO_COLOR: '1' },
|
package/dist/lib/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AgentRunParams, BrowserProfile, Run, RunStatus } from '@tiny-fish/sdk';
|
|
1
|
+
import type { AgentRunParams, BrowserProfile, FetchGetContentsParams, Run, RunStatus } from '@tiny-fish/sdk';
|
|
2
2
|
export type OutputSchema = Record<string, unknown>;
|
|
3
3
|
export interface CliAgentRunParams extends AgentRunParams {
|
|
4
4
|
output_schema?: OutputSchema;
|
|
@@ -91,6 +91,15 @@ export interface RunStepsResponse {
|
|
|
91
91
|
status: RunStatus;
|
|
92
92
|
steps: RunStep[];
|
|
93
93
|
}
|
|
94
|
+
export interface CliFetchHighlightsParams {
|
|
95
|
+
query: string;
|
|
96
|
+
max_snippets?: number;
|
|
97
|
+
max_characters?: number;
|
|
98
|
+
include_full_page_text?: boolean;
|
|
99
|
+
}
|
|
100
|
+
export interface CliFetchGetContentsParams extends FetchGetContentsParams {
|
|
101
|
+
highlights?: CliFetchHighlightsParams;
|
|
102
|
+
}
|
|
94
103
|
export interface CliBrowserSessionCreateParams {
|
|
95
104
|
url?: string;
|
|
96
105
|
browser_profile?: 'lite' | 'stealth';
|
package/dist/program.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
/** Split from index.ts so tests can drive the real program instead of hand-assembling one. */
|
|
3
|
-
export declare function buildProgram(): {
|
|
3
|
+
export declare function buildProgram(argv?: string[]): Promise<{
|
|
4
4
|
program: Command;
|
|
5
5
|
uninstallNotice: () => void;
|
|
6
|
-
}
|
|
6
|
+
}>;
|
package/dist/program.js
CHANGED
|
@@ -1,28 +1,55 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
import { CLI_VERSION } from './lib/constants.js';
|
|
3
|
-
import { registerAuth } from './commands/auth.js';
|
|
4
|
-
import { registerBatch } from './commands/batch.js';
|
|
5
|
-
import { registerFetch } from './commands/fetch.js';
|
|
6
|
-
import { registerBrowser } from './commands/browser.js';
|
|
7
|
-
import { registerProfile } from './commands/profile.js';
|
|
8
|
-
import { registerVault } from './commands/vault.js';
|
|
9
|
-
import { registerWallet } from './commands/wallet.js';
|
|
10
|
-
import { registerRun } from './commands/run.js';
|
|
11
|
-
import { registerRuns } from './commands/runs.js';
|
|
12
|
-
import { registerConfigureClaude } from './commands/config-claude.js';
|
|
13
|
-
import { registerSearch } from './commands/search.js';
|
|
14
|
-
import { registerConnect } from './commands/connect.js';
|
|
15
|
-
import { registerDoctor } from './commands/doctor.js';
|
|
16
|
-
import { registerUpgrade } from './commands/upgrade.js';
|
|
17
|
-
import { registerOnboard } from './commands/onboard.js';
|
|
18
3
|
import { installNoticeEmit } from './lib/notice.js';
|
|
4
|
+
// Loaded on demand: static imports pull zod, yaml, which, cross-spawn always.
|
|
5
|
+
const GROUPS = {
|
|
6
|
+
auth: async (p) => (await import('./commands/auth.js')).registerAuth(p),
|
|
7
|
+
onboard: async (p) => (await import('./commands/onboard.js')).registerOnboard(p),
|
|
8
|
+
connect: async (p) => (await import('./commands/connect.js')).registerConnect(p),
|
|
9
|
+
doctor: async (p) => (await import('./commands/doctor.js')).registerDoctor(p),
|
|
10
|
+
upgrade: async (p) => (await import('./commands/upgrade.js')).registerUpgrade(p),
|
|
11
|
+
'config-claude': async (p) => (await import('./commands/config-claude.js')).registerConfigureClaude(p),
|
|
12
|
+
browser: async (p) => (await import('./commands/browser.js')).registerBrowser(p),
|
|
13
|
+
profile: async (p) => (await import('./commands/profile.js')).registerProfile(p),
|
|
14
|
+
vault: async (p) => (await import('./commands/vault.js')).registerVault(p),
|
|
15
|
+
wallet: async (p) => (await import('./commands/wallet.js')).registerWallet(p),
|
|
16
|
+
agent: async (p) => {
|
|
17
|
+
const agentCmd = p
|
|
18
|
+
.command('agent')
|
|
19
|
+
.description('Agent automation commands')
|
|
20
|
+
.enablePositionalOptions();
|
|
21
|
+
// Measured: Promise.all is slower here; ESM loading is CPU-bound.
|
|
22
|
+
// registerRuns hangs off the `run` command registerRun returns.
|
|
23
|
+
const runCmd = (await import('./commands/run.js')).registerRun(agentCmd);
|
|
24
|
+
(await import('./commands/runs.js')).registerRuns(runCmd);
|
|
25
|
+
(await import('./commands/batch.js')).registerBatch(agentCmd);
|
|
26
|
+
},
|
|
27
|
+
search: async (p) => (await import('./commands/search.js')).registerSearch(p),
|
|
28
|
+
fetch: async (p) => (await import('./commands/fetch.js')).registerFetch(p),
|
|
29
|
+
};
|
|
30
|
+
/** Commander answers these before routing, so no command module is needed. */
|
|
31
|
+
const VERSION_FLAGS = ['-V', '--version'];
|
|
32
|
+
// Unknown names need the full list to suggest against.
|
|
33
|
+
/** First bare token is the command. Assumes no global option takes a value. */
|
|
34
|
+
function groupsFor(argv) {
|
|
35
|
+
for (const arg of argv.slice(2)) {
|
|
36
|
+
if (arg === '--')
|
|
37
|
+
break;
|
|
38
|
+
if (!arg.startsWith('-')) {
|
|
39
|
+
return Object.hasOwn(GROUPS, arg) ? [arg] : Object.keys(GROUPS);
|
|
40
|
+
}
|
|
41
|
+
if (VERSION_FLAGS.includes(arg))
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
return Object.keys(GROUPS);
|
|
45
|
+
}
|
|
19
46
|
/** Split from index.ts so tests can drive the real program instead of hand-assembling one. */
|
|
20
|
-
export function buildProgram() {
|
|
47
|
+
export async function buildProgram(argv = process.argv) {
|
|
21
48
|
const program = new Command();
|
|
22
49
|
program
|
|
23
50
|
.name('tinyfish')
|
|
24
51
|
.description('TinyFish CLI — run web automations from your terminal or agent.')
|
|
25
|
-
.version(CLI_VERSION, '
|
|
52
|
+
.version(CLI_VERSION, VERSION_FLAGS.join(', '), 'Show version')
|
|
26
53
|
.helpOption('-h, --help', 'Show help')
|
|
27
54
|
.addHelpCommand(false)
|
|
28
55
|
.enablePositionalOptions()
|
|
@@ -32,25 +59,10 @@ export function buildProgram() {
|
|
|
32
59
|
process.env['TINYFISH_DEBUG'] = '1';
|
|
33
60
|
}
|
|
34
61
|
});
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
registerUpgrade(program);
|
|
40
|
-
registerConfigureClaude(program);
|
|
41
|
-
registerBrowser(program);
|
|
42
|
-
registerProfile(program);
|
|
43
|
-
registerVault(program);
|
|
44
|
-
registerWallet(program);
|
|
45
|
-
const agentCmd = program
|
|
46
|
-
.command('agent')
|
|
47
|
-
.description('Agent automation commands')
|
|
48
|
-
.enablePositionalOptions();
|
|
49
|
-
const runCmd = registerRun(agentCmd);
|
|
50
|
-
registerRuns(runCmd);
|
|
51
|
-
registerBatch(agentCmd);
|
|
52
|
-
registerSearch(program);
|
|
53
|
-
registerFetch(program);
|
|
62
|
+
// Order is user-visible: help lists commands as registered.
|
|
63
|
+
for (const name of groupsFor(argv)) {
|
|
64
|
+
await GROUPS[name](program);
|
|
65
|
+
}
|
|
54
66
|
const uninstallNotice = installNoticeEmit(program);
|
|
55
67
|
return { program, uninstallNotice };
|
|
56
68
|
}
|