felo-ai 0.2.7 → 0.2.9
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/.github/workflows/publish-npm.yml +39 -0
- package/CHANGELOG.md +30 -30
- package/CONTRIBUTING.md +346 -346
- package/README.en.md +129 -129
- package/README.md +435 -414
- package/docs/EXAMPLES.md +632 -632
- package/docs/FAQ.md +479 -479
- package/felo-search/LICENSE +21 -21
- package/felo-search/README.md +440 -440
- package/felo-search/SKILL.md +291 -291
- package/felo-slides/LICENSE +21 -21
- package/felo-slides/README.md +87 -87
- package/felo-slides/SKILL.md +166 -166
- package/felo-slides/scripts/run_ppt_task.mjs +251 -251
- package/felo-superAgent/LICENSE +21 -0
- package/felo-superAgent/README.md +125 -0
- package/felo-superAgent/SKILL.md +165 -0
- package/felo-web-fetch/README.md +127 -78
- package/felo-web-fetch/SKILL.md +204 -200
- package/felo-web-fetch/scripts/run_web_fetch.mjs +316 -232
- package/felo-x-search/SKILL.md +204 -0
- package/felo-x-search/scripts/run_x_search.mjs +385 -0
- package/felo-youtube-subtitling/README.md +59 -59
- package/felo-youtube-subtitling/SKILL.md +161 -161
- package/felo-youtube-subtitling/scripts/run_youtube_subtitling.mjs +239 -239
- package/package.json +37 -35
- package/src/cli.js +370 -252
- package/src/config.js +66 -66
- package/src/search.js +142 -142
- package/src/slides.js +332 -332
- package/src/superAgent.js +609 -0
- package/src/webFetch.js +148 -148
- package/src/xSearch.js +366 -0
- package/src/youtubeSubtitling.js +179 -179
- package/tests/config.test.js +78 -78
- package/tests/search.test.js +100 -100
|
@@ -1,232 +1,316 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const DEFAULT_API_BASE = 'https://openapi.felo.ai';
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
'
|
|
31
|
-
'
|
|
32
|
-
'',
|
|
33
|
-
'
|
|
34
|
-
'
|
|
35
|
-
'
|
|
36
|
-
' --
|
|
37
|
-
' --
|
|
38
|
-
' --
|
|
39
|
-
' --
|
|
40
|
-
' --
|
|
41
|
-
' --json
|
|
42
|
-
' --
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
if (
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
if (
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
if (!
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const DEFAULT_API_BASE = 'https://openapi.felo.ai';
|
|
4
|
+
const DEFAULT_TIMEOUT_SEC = 60;
|
|
5
|
+
const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
6
|
+
const SPINNER_INTERVAL_MS = 80;
|
|
7
|
+
const STATUS_PAD = 56;
|
|
8
|
+
|
|
9
|
+
function startSpinner(message) {
|
|
10
|
+
const start = Date.now();
|
|
11
|
+
let i = 0;
|
|
12
|
+
const id = setInterval(() => {
|
|
13
|
+
const elapsed = Math.floor((Date.now() - start) / 1000);
|
|
14
|
+
const line = `${message} ${SPINNER_FRAMES[i % SPINNER_FRAMES.length]} ${elapsed}s`;
|
|
15
|
+
process.stderr.write(`\r${line.padEnd(STATUS_PAD, ' ')}`);
|
|
16
|
+
i += 1;
|
|
17
|
+
}, SPINNER_INTERVAL_MS);
|
|
18
|
+
return id;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function stopSpinner(id) {
|
|
22
|
+
if (id != null) clearInterval(id);
|
|
23
|
+
process.stderr.write(`\r${' '.repeat(STATUS_PAD)}\r`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function usage() {
|
|
27
|
+
console.error(
|
|
28
|
+
[
|
|
29
|
+
'Usage:',
|
|
30
|
+
' node felo-web-fetch/scripts/run_web_fetch.mjs --url <url> [options]',
|
|
31
|
+
'',
|
|
32
|
+
'Required:',
|
|
33
|
+
' --url <url> Target page URL',
|
|
34
|
+
'',
|
|
35
|
+
'Options:',
|
|
36
|
+
' --output-format <format> html | markdown | text',
|
|
37
|
+
' --crawl-mode <mode> fast | fine',
|
|
38
|
+
' --target-selector <selector> CSS selector for target extraction',
|
|
39
|
+
' --wait-for-selector <selector> Wait until selector appears',
|
|
40
|
+
' --cookie <cookie> Add cookie entry (repeatable)',
|
|
41
|
+
' --set-cookies-json <json> JSON array for set_cookies',
|
|
42
|
+
' --user-agent <ua> Custom user-agent',
|
|
43
|
+
' --timeout <seconds> Request timeout in seconds (default 60)',
|
|
44
|
+
' --request-timeout-ms <ms> API timeout parameter in milliseconds',
|
|
45
|
+
' --with-readability <bool> true | false',
|
|
46
|
+
' --with-links-summary <bool> true | false',
|
|
47
|
+
' --with-images-summary <bool> true | false',
|
|
48
|
+
' --with-images-readability <bool> true | false',
|
|
49
|
+
' --with-images <bool> true | false',
|
|
50
|
+
' --with-links <bool> true | false',
|
|
51
|
+
' --ignore-empty-text-image <bool> true | false',
|
|
52
|
+
' --with-cache <bool> true | false',
|
|
53
|
+
' --with-stypes <bool> true | false',
|
|
54
|
+
' --json Print full JSON response',
|
|
55
|
+
' --help Show this help',
|
|
56
|
+
].join('\n')
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function parseBool(v, name) {
|
|
61
|
+
if (typeof v !== 'string') {
|
|
62
|
+
throw new Error(`Missing value for ${name}`);
|
|
63
|
+
}
|
|
64
|
+
const normalized = v.trim().toLowerCase();
|
|
65
|
+
if (normalized === 'true') return true;
|
|
66
|
+
if (normalized === 'false') return false;
|
|
67
|
+
throw new Error(`Invalid boolean for ${name}: ${v}. Use true or false.`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function parseArgs(argv) {
|
|
71
|
+
const out = {
|
|
72
|
+
url: '',
|
|
73
|
+
outputFormat: '',
|
|
74
|
+
crawlMode: '',
|
|
75
|
+
targetSelector: '',
|
|
76
|
+
waitForSelector: '',
|
|
77
|
+
cookies: [],
|
|
78
|
+
cookiesJson: '',
|
|
79
|
+
userAgent: '',
|
|
80
|
+
timeoutSec: DEFAULT_TIMEOUT_SEC,
|
|
81
|
+
requestTimeoutMs: null,
|
|
82
|
+
withReadability: null,
|
|
83
|
+
withLinksSummary: null,
|
|
84
|
+
withImagesSummary: null,
|
|
85
|
+
withImagesReadability: null,
|
|
86
|
+
withImages: null,
|
|
87
|
+
withLinks: null,
|
|
88
|
+
ignoreEmptyTextImage: null,
|
|
89
|
+
withCache: null,
|
|
90
|
+
withStypes: null,
|
|
91
|
+
json: false,
|
|
92
|
+
help: false,
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
96
|
+
const a = argv[i];
|
|
97
|
+
if (a === '--help' || a === '-h') {
|
|
98
|
+
out.help = true;
|
|
99
|
+
} else if (a === '--json') {
|
|
100
|
+
out.json = true;
|
|
101
|
+
} else if (a === '--url') {
|
|
102
|
+
out.url = argv[i + 1] ?? '';
|
|
103
|
+
i += 1;
|
|
104
|
+
} else if (a === '--output-format') {
|
|
105
|
+
out.outputFormat = (argv[i + 1] ?? '').trim().toLowerCase();
|
|
106
|
+
i += 1;
|
|
107
|
+
} else if (a === '--crawl-mode') {
|
|
108
|
+
out.crawlMode = (argv[i + 1] ?? '').trim().toLowerCase();
|
|
109
|
+
i += 1;
|
|
110
|
+
} else if (a === '--target-selector') {
|
|
111
|
+
out.targetSelector = argv[i + 1] ?? '';
|
|
112
|
+
i += 1;
|
|
113
|
+
} else if (a === '--wait-for-selector') {
|
|
114
|
+
out.waitForSelector = argv[i + 1] ?? '';
|
|
115
|
+
i += 1;
|
|
116
|
+
} else if (a === '--cookie') {
|
|
117
|
+
const value = argv[i + 1] ?? '';
|
|
118
|
+
if (value) out.cookies.push(value);
|
|
119
|
+
i += 1;
|
|
120
|
+
} else if (a === '--set-cookies-json') {
|
|
121
|
+
out.cookiesJson = argv[i + 1] ?? '';
|
|
122
|
+
i += 1;
|
|
123
|
+
} else if (a === '--user-agent') {
|
|
124
|
+
out.userAgent = argv[i + 1] ?? '';
|
|
125
|
+
i += 1;
|
|
126
|
+
} else if (a === '--timeout') {
|
|
127
|
+
out.timeoutSec = Number.parseInt(argv[i + 1] ?? '', 10);
|
|
128
|
+
i += 1;
|
|
129
|
+
} else if (a === '--request-timeout-ms') {
|
|
130
|
+
out.requestTimeoutMs = Number.parseInt(argv[i + 1] ?? '', 10);
|
|
131
|
+
i += 1;
|
|
132
|
+
} else if (a === '--with-readability') {
|
|
133
|
+
out.withReadability = parseBool(argv[i + 1], '--with-readability');
|
|
134
|
+
i += 1;
|
|
135
|
+
} else if (a === '--with-links-summary') {
|
|
136
|
+
out.withLinksSummary = parseBool(argv[i + 1], '--with-links-summary');
|
|
137
|
+
i += 1;
|
|
138
|
+
} else if (a === '--with-images-summary') {
|
|
139
|
+
out.withImagesSummary = parseBool(argv[i + 1], '--with-images-summary');
|
|
140
|
+
i += 1;
|
|
141
|
+
} else if (a === '--with-images-readability') {
|
|
142
|
+
out.withImagesReadability = parseBool(argv[i + 1], '--with-images-readability');
|
|
143
|
+
i += 1;
|
|
144
|
+
} else if (a === '--with-images') {
|
|
145
|
+
out.withImages = parseBool(argv[i + 1], '--with-images');
|
|
146
|
+
i += 1;
|
|
147
|
+
} else if (a === '--with-links') {
|
|
148
|
+
out.withLinks = parseBool(argv[i + 1], '--with-links');
|
|
149
|
+
i += 1;
|
|
150
|
+
} else if (a === '--ignore-empty-text-image') {
|
|
151
|
+
out.ignoreEmptyTextImage = parseBool(argv[i + 1], '--ignore-empty-text-image');
|
|
152
|
+
i += 1;
|
|
153
|
+
} else if (a === '--with-cache') {
|
|
154
|
+
out.withCache = parseBool(argv[i + 1], '--with-cache');
|
|
155
|
+
i += 1;
|
|
156
|
+
} else if (a === '--with-stypes') {
|
|
157
|
+
out.withStypes = parseBool(argv[i + 1], '--with-stypes');
|
|
158
|
+
i += 1;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (!Number.isFinite(out.timeoutSec) || out.timeoutSec <= 0) {
|
|
163
|
+
out.timeoutSec = DEFAULT_TIMEOUT_SEC;
|
|
164
|
+
}
|
|
165
|
+
if (out.requestTimeoutMs !== null && (!Number.isFinite(out.requestTimeoutMs) || out.requestTimeoutMs <= 0)) {
|
|
166
|
+
out.requestTimeoutMs = null;
|
|
167
|
+
}
|
|
168
|
+
return out;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function ensureInSet(value, allowed, fieldName) {
|
|
172
|
+
if (!value) return;
|
|
173
|
+
if (!allowed.includes(value)) {
|
|
174
|
+
throw new Error(`Invalid ${fieldName}: ${value}. Allowed values: ${allowed.join(', ')}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function isApiError(payload) {
|
|
179
|
+
if (typeof payload?.code === 'number') {
|
|
180
|
+
return payload.code !== 0;
|
|
181
|
+
}
|
|
182
|
+
if (typeof payload?.status === 'string') {
|
|
183
|
+
return payload.status.toLowerCase() === 'error';
|
|
184
|
+
}
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function getMessage(payload) {
|
|
189
|
+
return String(payload?.message || payload?.error || payload?.msg || 'Unknown error');
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
async function fetchJson(url, init, timeoutMs) {
|
|
193
|
+
const controller = new AbortController();
|
|
194
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
195
|
+
try {
|
|
196
|
+
const res = await fetch(url, { ...init, signal: controller.signal });
|
|
197
|
+
let body = {};
|
|
198
|
+
try {
|
|
199
|
+
body = await res.json();
|
|
200
|
+
} catch {
|
|
201
|
+
body = {};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (!res.ok) {
|
|
205
|
+
throw new Error(`HTTP ${res.status}: ${getMessage(body)}`);
|
|
206
|
+
}
|
|
207
|
+
if (isApiError(body)) {
|
|
208
|
+
throw new Error(getMessage(body));
|
|
209
|
+
}
|
|
210
|
+
return body;
|
|
211
|
+
} finally {
|
|
212
|
+
clearTimeout(timer);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function buildPayload(args) {
|
|
217
|
+
const payload = {
|
|
218
|
+
url: args.url,
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
if (args.outputFormat) payload.output_format = args.outputFormat;
|
|
222
|
+
if (args.crawlMode) payload.crawl_mode = args.crawlMode;
|
|
223
|
+
if (args.targetSelector) payload.target_selector = args.targetSelector;
|
|
224
|
+
if (args.waitForSelector) payload.wait_for_selector = args.waitForSelector;
|
|
225
|
+
if (args.userAgent) payload.user_agent = args.userAgent;
|
|
226
|
+
if (args.requestTimeoutMs !== null) payload.timeout = args.requestTimeoutMs;
|
|
227
|
+
|
|
228
|
+
if (args.cookies.length) payload.set_cookies = args.cookies;
|
|
229
|
+
if (args.cookiesJson) {
|
|
230
|
+
try {
|
|
231
|
+
const parsed = JSON.parse(args.cookiesJson);
|
|
232
|
+
if (!Array.isArray(parsed)) {
|
|
233
|
+
throw new Error('set_cookies JSON must be an array');
|
|
234
|
+
}
|
|
235
|
+
payload.set_cookies = parsed;
|
|
236
|
+
} catch (err) {
|
|
237
|
+
throw new Error(`Invalid --set-cookies-json: ${String(err.message || err)}`);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (args.withReadability !== null) payload.with_readability = args.withReadability;
|
|
242
|
+
if (args.withLinksSummary !== null) payload.with_links_summary = args.withLinksSummary;
|
|
243
|
+
if (args.withImagesSummary !== null) payload.with_images_summary = args.withImagesSummary;
|
|
244
|
+
if (args.withImagesReadability !== null) payload.with_images_readability = args.withImagesReadability;
|
|
245
|
+
if (args.withImages !== null) payload.with_images = args.withImages;
|
|
246
|
+
if (args.withLinks !== null) payload.with_links = args.withLinks;
|
|
247
|
+
if (args.ignoreEmptyTextImage !== null) payload.ignore_empty_text_image = args.ignoreEmptyTextImage;
|
|
248
|
+
if (args.withCache !== null) payload.with_cache = args.withCache;
|
|
249
|
+
if (args.withStypes !== null) payload.with_stypes = args.withStypes;
|
|
250
|
+
|
|
251
|
+
return payload;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
async function main() {
|
|
255
|
+
const args = parseArgs(process.argv.slice(2));
|
|
256
|
+
if (args.help) {
|
|
257
|
+
usage();
|
|
258
|
+
process.exit(0);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (!args.url) {
|
|
262
|
+
usage();
|
|
263
|
+
process.exit(1);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
ensureInSet(args.outputFormat, ['html', 'markdown', 'text'], 'output-format');
|
|
267
|
+
ensureInSet(args.crawlMode, ['fast', 'fine'], 'crawl-mode');
|
|
268
|
+
|
|
269
|
+
const apiKey = process.env.FELO_API_KEY?.trim();
|
|
270
|
+
if (!apiKey) {
|
|
271
|
+
console.error('ERROR: FELO_API_KEY not set');
|
|
272
|
+
process.exit(1);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const apiBase = (process.env.FELO_API_BASE?.trim() || DEFAULT_API_BASE).replace(/\/$/, '');
|
|
276
|
+
const payload = buildPayload(args);
|
|
277
|
+
|
|
278
|
+
const shortUrl = args.url.length > 45 ? args.url.slice(0, 42) + '...' : args.url;
|
|
279
|
+
const spinnerId = startSpinner(`Fetching ${shortUrl}`);
|
|
280
|
+
|
|
281
|
+
try {
|
|
282
|
+
const response = await fetchJson(
|
|
283
|
+
`${apiBase}/v2/web/extract`,
|
|
284
|
+
{
|
|
285
|
+
method: 'POST',
|
|
286
|
+
headers: {
|
|
287
|
+
Accept: 'application/json',
|
|
288
|
+
Authorization: `Bearer ${apiKey}`,
|
|
289
|
+
'Content-Type': 'application/json',
|
|
290
|
+
},
|
|
291
|
+
body: JSON.stringify(payload),
|
|
292
|
+
},
|
|
293
|
+
args.timeoutSec * 1000
|
|
294
|
+
);
|
|
295
|
+
|
|
296
|
+
if (args.json) {
|
|
297
|
+
console.log(JSON.stringify(response, null, 2));
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const content = response?.data?.content;
|
|
302
|
+
if (typeof content === 'string') {
|
|
303
|
+
console.log(content);
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
console.log(JSON.stringify(content ?? response?.data ?? response, null, 2));
|
|
308
|
+
} catch (err) {
|
|
309
|
+
console.error(`ERROR: ${String(err?.message || err || 'Unknown error')}`);
|
|
310
|
+
process.exit(1);
|
|
311
|
+
} finally {
|
|
312
|
+
stopSpinner(spinnerId);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
main();
|