@optima-chat/browser-cli 0.6.1 → 0.8.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/dist/index.js +227 -15
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -98,6 +98,16 @@ var BrowserAPIError = class extends Error {
|
|
|
98
98
|
this.name = "BrowserAPIError";
|
|
99
99
|
}
|
|
100
100
|
};
|
|
101
|
+
function toAPIError(status, statusText, body) {
|
|
102
|
+
const detail = body.detail ?? body;
|
|
103
|
+
if (typeof detail === "string") {
|
|
104
|
+
return new BrowserAPIError(status, "http_error", `HTTP ${status}: ${detail}`);
|
|
105
|
+
}
|
|
106
|
+
if (detail?.message) {
|
|
107
|
+
return new BrowserAPIError(status, detail.error ?? "unknown", detail.message);
|
|
108
|
+
}
|
|
109
|
+
return new BrowserAPIError(status, "unknown", `HTTP ${status}: ${statusText}`);
|
|
110
|
+
}
|
|
101
111
|
async function request(path, options = {}) {
|
|
102
112
|
const url = `${BROWSER_API_URL}${path}`;
|
|
103
113
|
let response;
|
|
@@ -126,8 +136,7 @@ async function request(path, options = {}) {
|
|
|
126
136
|
`HTTP ${response.status}: ${response.statusText}`
|
|
127
137
|
);
|
|
128
138
|
}
|
|
129
|
-
|
|
130
|
-
throw new BrowserAPIError(response.status, detail.error, detail.message);
|
|
139
|
+
throw toAPIError(response.status, response.statusText, body);
|
|
131
140
|
}
|
|
132
141
|
if (response.status === 204) {
|
|
133
142
|
return void 0;
|
|
@@ -159,20 +168,19 @@ async function requestBinary(path) {
|
|
|
159
168
|
`HTTP ${response.status}: ${response.statusText}`
|
|
160
169
|
);
|
|
161
170
|
}
|
|
162
|
-
|
|
163
|
-
throw new BrowserAPIError(response.status, detail.error, detail.message);
|
|
171
|
+
throw toAPIError(response.status, response.statusText, body);
|
|
164
172
|
}
|
|
165
173
|
const arrayBuffer = await response.arrayBuffer();
|
|
166
174
|
return Buffer.from(arrayBuffer);
|
|
167
175
|
}
|
|
168
176
|
var BrowserAPI = class {
|
|
169
|
-
async createSession(url,
|
|
177
|
+
async createSession(url, force, connector, ziniaoProfileId, bitbrowserProfileId) {
|
|
170
178
|
const body = {};
|
|
171
179
|
if (url) body.url = url;
|
|
172
|
-
if (profileId) body.profile_id = profileId;
|
|
173
180
|
if (force) body.force = true;
|
|
174
181
|
if (connector) body.connector = connector;
|
|
175
182
|
if (ziniaoProfileId) body.ziniao_profile_id = ziniaoProfileId;
|
|
183
|
+
if (bitbrowserProfileId) body.bitbrowser_profile_id = bitbrowserProfileId;
|
|
176
184
|
return request("/api/sessions", {
|
|
177
185
|
method: "POST",
|
|
178
186
|
body: JSON.stringify(body)
|
|
@@ -201,6 +209,9 @@ var BrowserAPI = class {
|
|
|
201
209
|
async getZiNiaoProfiles() {
|
|
202
210
|
return request("/api/user/ziniao-profiles");
|
|
203
211
|
}
|
|
212
|
+
async getBitBrowserProfiles() {
|
|
213
|
+
return request("/api/user/bitbrowser-profiles");
|
|
214
|
+
}
|
|
204
215
|
async closeSession(sessionId) {
|
|
205
216
|
await request(`/api/sessions/${sessionId}`, { method: "DELETE" });
|
|
206
217
|
}
|
|
@@ -246,6 +257,29 @@ var BrowserAPI = class {
|
|
|
246
257
|
async getScreenshot(sessionId) {
|
|
247
258
|
return requestBinary(`/api/sessions/${sessionId}/screenshot`);
|
|
248
259
|
}
|
|
260
|
+
async runRecipeScript(name, params, pollMs = 2e3, timeoutMs = 36e4) {
|
|
261
|
+
const started = await request(`/api/scripts/${name}/run`, {
|
|
262
|
+
method: "POST",
|
|
263
|
+
body: JSON.stringify({ params })
|
|
264
|
+
});
|
|
265
|
+
const deadline = Date.now() + timeoutMs;
|
|
266
|
+
for (; ; ) {
|
|
267
|
+
const task = await request(`/api/script-tasks/${started.id}`);
|
|
268
|
+
if (task.status === "completed") return task.output;
|
|
269
|
+
if (task.status === "failed" || task.status === "needs_fallback") {
|
|
270
|
+
throw new Error(task.error || task.output?.error || `recipe ${task.status}`);
|
|
271
|
+
}
|
|
272
|
+
if (Date.now() >= deadline) {
|
|
273
|
+
throw new Error(
|
|
274
|
+
`recipe ${name} did not finish within ${Math.round(timeoutMs / 1e3)}s (task ${started.id})`
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
await new Promise((r) => setTimeout(r, pollMs));
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
async fetchArtifact(artifactPath) {
|
|
281
|
+
return requestBinary(artifactPath);
|
|
282
|
+
}
|
|
249
283
|
async search(sessionId, pattern) {
|
|
250
284
|
return request(`/api/sessions/${sessionId}/search`, {
|
|
251
285
|
method: "POST",
|
|
@@ -300,9 +334,11 @@ var BrowserAPI = class {
|
|
|
300
334
|
async deleteScript(name) {
|
|
301
335
|
await request(`/api/scripts/${encodeURIComponent(name)}`, { method: "DELETE" });
|
|
302
336
|
}
|
|
303
|
-
async runScript(scriptName, params = {},
|
|
337
|
+
async runScript(scriptName, params = {}, connector, ziniaoProfileId, bitbrowserProfileId) {
|
|
304
338
|
const payload = { params };
|
|
305
|
-
if (
|
|
339
|
+
if (connector) payload.connector = connector;
|
|
340
|
+
if (ziniaoProfileId) payload.ziniao_profile_id = ziniaoProfileId;
|
|
341
|
+
if (bitbrowserProfileId) payload.bitbrowser_profile_id = bitbrowserProfileId;
|
|
306
342
|
return request(`/api/scripts/${encodeURIComponent(scriptName)}/run`, {
|
|
307
343
|
method: "POST",
|
|
308
344
|
body: JSON.stringify(payload)
|
|
@@ -404,6 +440,9 @@ function formatFind(result) {
|
|
|
404
440
|
}
|
|
405
441
|
return lines.join("\n");
|
|
406
442
|
}
|
|
443
|
+
function formatDesktopNotConnected(result) {
|
|
444
|
+
return result.message ?? "\u684C\u9762\u5E94\u7528\u672A\u8FDE\u63A5\uFF0C\u8BF7\u5148\u5B89\u88C5\u5E76\u542F\u52A8\u684C\u9762\u5E94\u7528\u540E\u91CD\u8BD5\u3002";
|
|
445
|
+
}
|
|
407
446
|
function formatError(err) {
|
|
408
447
|
if (err instanceof Error) {
|
|
409
448
|
return `\u2717 Error: ${err.message}`;
|
|
@@ -430,9 +469,9 @@ function formatProfileDelete(profileId) {
|
|
|
430
469
|
|
|
431
470
|
// src/commands/lifecycle.ts
|
|
432
471
|
function registerLifecycleCommands(program2) {
|
|
433
|
-
program2.command("launch").description("Launch a browser session").option("--url <url>", "Navigate to URL after launch").option("--
|
|
472
|
+
program2.command("launch").description("Launch a browser session").option("--url <url>", "Navigate to URL after launch").option("--force", "Close existing session before launching").option("--connector <type>", "Browser connector: chrome, ziniao, or bitbrowser").option("--ziniao-profile <id>", "ZiNiao browser profile ID").option("--bitbrowser-profile <id>", "BitBrowser profile ID").action(async (opts) => {
|
|
434
473
|
try {
|
|
435
|
-
const state = await api.createSession(opts.url, opts.
|
|
474
|
+
const state = await api.createSession(opts.url, opts.force, opts.connector, opts.ziniaoProfile, opts.bitbrowserProfile);
|
|
436
475
|
saveSessionId(state.session_id);
|
|
437
476
|
console.log(formatLaunch(state));
|
|
438
477
|
} catch (err) {
|
|
@@ -748,7 +787,7 @@ function registerScriptCommands(program2) {
|
|
|
748
787
|
process.exit(1);
|
|
749
788
|
}
|
|
750
789
|
});
|
|
751
|
-
program2.command("runscript").argument("<name>", "Script name").description("Run a script (polls until complete)").option("--param <params...>", "Parameters as key=value").option("--profile <id>", "
|
|
790
|
+
program2.command("runscript").argument("<name>", "Script name").description("Run a script (polls until complete)").option("--param <params...>", "Parameters as key=value").option("--connector <type>", "Browser connector: chrome, ziniao, or bitbrowser").option("--ziniao-profile <id>", "ZiNiao browser profile ID (with --connector ziniao)").option("--bitbrowser-profile <id>", "BitBrowser profile ID (with --connector bitbrowser)").option("--no-poll", "Return immediately without polling").action(async (name, opts) => {
|
|
752
791
|
try {
|
|
753
792
|
const params = {};
|
|
754
793
|
if (opts.param) {
|
|
@@ -758,7 +797,7 @@ function registerScriptCommands(program2) {
|
|
|
758
797
|
}
|
|
759
798
|
}
|
|
760
799
|
clearSessionId();
|
|
761
|
-
const task = await api.runScript(name, params, opts.
|
|
800
|
+
const task = await api.runScript(name, params, opts.connector, opts.ziniaoProfile, opts.bitbrowserProfile);
|
|
762
801
|
console.log(`Script started (task: ${task.id})`);
|
|
763
802
|
if (!opts.poll) {
|
|
764
803
|
console.log(`Poll with: browser-cli script-task ${task.id}`);
|
|
@@ -795,7 +834,7 @@ function registerScriptCommands(program2) {
|
|
|
795
834
|
});
|
|
796
835
|
}
|
|
797
836
|
function sleep(ms) {
|
|
798
|
-
return new Promise((
|
|
837
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
799
838
|
}
|
|
800
839
|
|
|
801
840
|
// src/commands/profile.ts
|
|
@@ -820,6 +859,105 @@ function registerProfileCommands(program2) {
|
|
|
820
859
|
});
|
|
821
860
|
}
|
|
822
861
|
|
|
862
|
+
// src/ziniao-doctor.ts
|
|
863
|
+
var ZINIAO_WEBDRIVER_DOC_URL = "https://open.ziniao.com/docSupport?docId=99#%E7%AC%AC%E4%B8%80%E6%AD%A5%EF%BC%9A%E7%99%BB%E5%BD%95%E5%BC%80%E6%94%BE%E5%B9%B3%E5%8F%B0%E6%8E%A7%E5%88%B6%E5%8F%B00";
|
|
864
|
+
var BOSS_GUIDANCE = [
|
|
865
|
+
"\u9700\u8981\u7D2B\u9E1F BOSS \u8D26\u53F7\u5B8C\u6210\u5F00\u901A\uFF08\u4E00\u6B21\u6027\u914D\u7F6E\uFF09\uFF1A",
|
|
866
|
+
" 1. \u767B\u5F55\u7D2B\u9E1F\u5F00\u653E\u5E73\u53F0\u63A7\u5236\u53F0\uFF0C\u5F00\u901A Webdriver \u6743\u9650\uFF1B",
|
|
867
|
+
" 2. \u521B\u5EFA\u4E13\u7528\u81EA\u52A8\u5316\u6210\u5458\u8D26\u53F7\uFF08robot\uFF09\uFF0C\u89D2\u8272\u9700\u542B\u300C\u67E5\u770B\u8D26\u53F7\u300D\u6743\u9650\uFF1B",
|
|
868
|
+
" 3. \u4E3A\u8BE5\u8D26\u53F7\u6388\u6743\u9700\u8981\u64CD\u4F5C\u7684\u5E97\u94FA\u3002",
|
|
869
|
+
`\u53C2\u8003\u6587\u6863: ${ZINIAO_WEBDRIVER_DOC_URL}`
|
|
870
|
+
].join("\n");
|
|
871
|
+
function ziniaoErrorHint(message) {
|
|
872
|
+
if (/webdriver|开通|权限|permission/i.test(message)) {
|
|
873
|
+
return `\u7591\u4F3C\u672A\u5F00\u901A Webdriver \u6743\u9650\u6216\u8D26\u53F7\u6743\u9650\u4E0D\u8DB3\u3002${BOSS_GUIDANCE}`;
|
|
874
|
+
}
|
|
875
|
+
if (/错误次数太多/.test(message)) {
|
|
876
|
+
return "\u7D2B\u9E1F\u98CE\u63A7\u5DF2\u4E34\u65F6\u9501\u5B9A\uFF0C\u8BF7\u7B49\u5F85\u7EA6 10 \u5206\u949F\u540E\u91CD\u8BD5\uFF08\u7EE7\u7EED\u5931\u8D25\u4F1A\u5EF6\u957F\u9501\u5B9A\uFF09\u3002";
|
|
877
|
+
}
|
|
878
|
+
if (/用户名或密码错误|密码错误/.test(message)) {
|
|
879
|
+
return "\u8BF7\u6838\u5BF9\u51ED\u636E\uFF08company=\u4F01\u4E1A\u540D\u79F0\uFF0Cusername/password=\u6210\u5458\u8D26\u53F7\uFF0C\u63A8\u8350 robot \u8D26\u53F7\uFF09\uFF0C\u7136\u540E\u7528 browser-cli ziniao set \u91CD\u65B0\u914D\u7F6E\u3002";
|
|
880
|
+
}
|
|
881
|
+
return null;
|
|
882
|
+
}
|
|
883
|
+
async function runZiNiaoDoctor(client) {
|
|
884
|
+
const checks = [];
|
|
885
|
+
const done = () => ({ checks, ok: checks.every((c) => c.ok === true) });
|
|
886
|
+
let cfg;
|
|
887
|
+
try {
|
|
888
|
+
cfg = await client.getZiNiaoConfig();
|
|
889
|
+
} catch (err) {
|
|
890
|
+
checks.push({
|
|
891
|
+
name: "\u540E\u7AEF\u8FDE\u63A5",
|
|
892
|
+
ok: false,
|
|
893
|
+
detail: err.message,
|
|
894
|
+
hint: "\u786E\u8BA4 browser-backend \u6B63\u5728\u8FD0\u884C\uFF0C\u4E14 BROWSER_API_URL \u6307\u5411\u6B63\u786E\u5730\u5740\u3002"
|
|
895
|
+
});
|
|
896
|
+
return done();
|
|
897
|
+
}
|
|
898
|
+
checks.push({ name: "\u540E\u7AEF\u8FDE\u63A5", ok: true });
|
|
899
|
+
if (!cfg.configured) {
|
|
900
|
+
checks.push({
|
|
901
|
+
name: "\u7D2B\u9E1F\u51ED\u636E",
|
|
902
|
+
ok: false,
|
|
903
|
+
hint: "browser-cli ziniao set --company <\u4F01\u4E1A\u540D\u79F0> --username <\u6210\u5458\u8D26\u53F7> --password <\u5BC6\u7801>\uFF08\u63A8\u8350\u4F7F\u7528\u4E13\u7528 robot \u6210\u5458\u8D26\u53F7\uFF09"
|
|
904
|
+
});
|
|
905
|
+
return done();
|
|
906
|
+
}
|
|
907
|
+
checks.push({ name: "\u7D2B\u9E1F\u51ED\u636E", ok: true, detail: `${cfg.company} / ${cfg.username}` });
|
|
908
|
+
try {
|
|
909
|
+
const r = await client.getZiNiaoProfiles();
|
|
910
|
+
if (!r.connected) {
|
|
911
|
+
checks.push({
|
|
912
|
+
name: "\u684C\u9762\u5E94\u7528",
|
|
913
|
+
ok: false,
|
|
914
|
+
detail: r.message,
|
|
915
|
+
hint: `\u8BF7\u542F\u52A8 Optima \u684C\u9762\u5E94\u7528\u5E76\u5B8C\u6210\u8FDE\u63A5\u3002${r.download_url ? `\u4E0B\u8F7D: ${r.download_url}` : ""}`.trim()
|
|
916
|
+
});
|
|
917
|
+
return done();
|
|
918
|
+
}
|
|
919
|
+
checks.push({ name: "\u684C\u9762\u5E94\u7528", ok: true });
|
|
920
|
+
if (!r.ziniao_available) {
|
|
921
|
+
checks.push({
|
|
922
|
+
name: "\u7D2B\u9E1F\u5BA2\u6237\u7AEF",
|
|
923
|
+
ok: false,
|
|
924
|
+
hint: "\u684C\u9762\u7AEF\u672A\u68C0\u6D4B\u5230\u53EF\u7528\u7684\u7D2B\u9E1F\uFF1A\u786E\u8BA4\u672C\u673A\u5DF2\u5B89\u88C5\u7D2B\u9E1F\u5BA2\u6237\u7AEF\uFF0C\u4E14\u51ED\u636E\u5DF2\u540C\u6B65\u5230\u684C\u9762\uFF08\u91CD\u542F\u684C\u9762\u5E94\u7528\u53EF\u89E6\u53D1\u540C\u6B65\uFF09\u3002"
|
|
925
|
+
});
|
|
926
|
+
return done();
|
|
927
|
+
}
|
|
928
|
+
checks.push({ name: "\u7D2B\u9E1F\u5BA2\u6237\u7AEF", ok: true });
|
|
929
|
+
if (r.profiles.length === 0) {
|
|
930
|
+
checks.push({
|
|
931
|
+
name: "\u5E97\u94FA\u5217\u8868",
|
|
932
|
+
ok: "warn",
|
|
933
|
+
detail: "\u767B\u5F55\u6210\u529F\uFF0C\u4F46\u5E97\u94FA\u5217\u8868\u4E3A\u7A7A",
|
|
934
|
+
hint: `robot \u8D26\u53F7\u7684\u89D2\u8272\u53EF\u80FD\u7F3A\u300C\u67E5\u770B\u8D26\u53F7\u300D\u6743\u9650\uFF0C\u6216\u5C1A\u672A\u6388\u6743\u4EFB\u4F55\u5E97\u94FA\u3002${BOSS_GUIDANCE}`
|
|
935
|
+
});
|
|
936
|
+
return done();
|
|
937
|
+
}
|
|
938
|
+
checks.push({ name: "\u5E97\u94FA\u5217\u8868", ok: true, detail: `${r.profiles.length} \u4E2A\u5E97\u94FA\u53EF\u7528` });
|
|
939
|
+
} catch (err) {
|
|
940
|
+
checks.push({
|
|
941
|
+
name: "\u7D2B\u9E1F Webdriver \u901A\u9053",
|
|
942
|
+
ok: false,
|
|
943
|
+
detail: err.message,
|
|
944
|
+
hint: ziniaoErrorHint(err.message ?? "") ?? void 0
|
|
945
|
+
});
|
|
946
|
+
}
|
|
947
|
+
return done();
|
|
948
|
+
}
|
|
949
|
+
function formatDoctorReport(checks) {
|
|
950
|
+
const lines = [];
|
|
951
|
+
for (const c of checks) {
|
|
952
|
+
const mark = c.ok === true ? "\u2713" : c.ok === "warn" ? "\u26A0" : "\u2717";
|
|
953
|
+
lines.push(`${mark} ${c.name}${c.detail ? `: ${c.detail}` : ""}`);
|
|
954
|
+
if (c.hint) {
|
|
955
|
+
lines.push(...c.hint.split("\n").map((l) => ` ${l}`));
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
return lines.join("\n");
|
|
959
|
+
}
|
|
960
|
+
|
|
823
961
|
// src/commands/ziniao.ts
|
|
824
962
|
function registerZiNiaoCommands(program2) {
|
|
825
963
|
const ziniao = program2.command("ziniao").description("Manage ZiNiao browser credentials");
|
|
@@ -851,28 +989,38 @@ function registerZiNiaoCommands(program2) {
|
|
|
851
989
|
try {
|
|
852
990
|
const result = await api.getZiNiaoProfiles();
|
|
853
991
|
if (!result.connected) {
|
|
854
|
-
console.log(
|
|
992
|
+
console.log(formatDesktopNotConnected(result));
|
|
855
993
|
process.exit(1);
|
|
856
994
|
}
|
|
857
995
|
if (!result.ziniao_available) {
|
|
858
996
|
console.log("ZiNiao not available on Desktop app. Start ZiNiao WebDriver mode first.");
|
|
997
|
+
console.log("Run: browser-cli ziniao doctor \uFF08\u9010\u9879\u6392\u67E5\u7D2B\u9E1F\u901A\u9053\uFF09");
|
|
859
998
|
process.exit(1);
|
|
860
999
|
}
|
|
861
1000
|
if (result.profiles.length === 0) {
|
|
862
1001
|
console.log("No ZiNiao profiles found.");
|
|
1002
|
+
console.log("Run: browser-cli ziniao doctor \uFF08\u9010\u9879\u6392\u67E5\u7D2B\u9E1F\u901A\u9053\uFF0C\u5E38\u89C1\u539F\u56E0\uFF1Arobot \u8D26\u53F7\u7F3A\u300C\u67E5\u770B\u8D26\u53F7\u300D\u6743\u9650\u6216\u672A\u6388\u6743\u5E97\u94FA\uFF09");
|
|
863
1003
|
return;
|
|
864
1004
|
}
|
|
865
1005
|
console.log(`ZiNiao profiles (${result.profiles.length}):
|
|
866
1006
|
`);
|
|
867
1007
|
for (const p of result.profiles) {
|
|
868
|
-
|
|
1008
|
+
const site = p.platform_name ? ` [${p.platform_name}]` : "";
|
|
1009
|
+
console.log(` ${p.id} ${p.name}${site}`);
|
|
869
1010
|
}
|
|
870
1011
|
console.log("\nUse: browser-cli launch --connector ziniao --ziniao-profile <id> --url <url>");
|
|
871
1012
|
} catch (err) {
|
|
872
1013
|
console.error(formatError(err));
|
|
1014
|
+
const hint = ziniaoErrorHint(err?.message ?? "");
|
|
1015
|
+
if (hint) console.error(hint);
|
|
873
1016
|
process.exit(1);
|
|
874
1017
|
}
|
|
875
1018
|
});
|
|
1019
|
+
ziniao.command("doctor").description("Diagnose the ZiNiao Webdriver chain (credentials / desktop / permission / stores)").action(async () => {
|
|
1020
|
+
const { checks, ok } = await runZiNiaoDoctor(api);
|
|
1021
|
+
console.log(formatDoctorReport(checks));
|
|
1022
|
+
if (!ok) process.exit(1);
|
|
1023
|
+
});
|
|
876
1024
|
ziniao.command("clear").description("Remove ZiNiao credentials").action(async () => {
|
|
877
1025
|
try {
|
|
878
1026
|
await api.deleteZiNiaoConfig();
|
|
@@ -884,6 +1032,68 @@ function registerZiNiaoCommands(program2) {
|
|
|
884
1032
|
});
|
|
885
1033
|
}
|
|
886
1034
|
|
|
1035
|
+
// src/commands/recipes.ts
|
|
1036
|
+
import { writeFileSync as writeFileSync3 } from "fs";
|
|
1037
|
+
import { resolve } from "path";
|
|
1038
|
+
async function runExport(script, params, out, timeoutMs) {
|
|
1039
|
+
const outPath = resolve(out);
|
|
1040
|
+
const result = await api.runRecipeScript(script, { ...params, out_path: outPath }, 2e3, timeoutMs);
|
|
1041
|
+
if (!result.path) {
|
|
1042
|
+
writeFileSync3(outPath, await api.fetchArtifact(result.artifact_path));
|
|
1043
|
+
}
|
|
1044
|
+
console.log(`Saved ${result.filename} -> ${outPath} (${result.size} bytes)`);
|
|
1045
|
+
}
|
|
1046
|
+
function registerRecipeCommands(program2) {
|
|
1047
|
+
program2.command("export-ad-report").description("Export TikTok Shop last-7-days video ad data into the session workspace").requiredOption("--ziniao-profile <id>", "ZiNiao browser profile ID").option("--report-url <url>", "Ad dashboard URL (default: TikTok Shop MY local site)").option("--out <path>", "Output CSV path", "./tt_video_ad_7d.csv").action(async (opts) => {
|
|
1048
|
+
try {
|
|
1049
|
+
const params = { ziniao_profile_id: opts.ziniaoProfile };
|
|
1050
|
+
if (opts.reportUrl) params.report_url = opts.reportUrl;
|
|
1051
|
+
await runExport("tiktok_video_ad_export", params, opts.out, 36e4);
|
|
1052
|
+
} catch (err) {
|
|
1053
|
+
console.error(formatError(err));
|
|
1054
|
+
process.exit(1);
|
|
1055
|
+
}
|
|
1056
|
+
});
|
|
1057
|
+
program2.command("export-order-report").description("Export TikTok Shop order data into the session workspace").requiredOption("--ziniao-profile <id>", "ZiNiao browser profile ID").option("--report-url <url>", "Order list URL (default: TikTok Shop MY local site)").option("--days <n>", "Export the last N days (default: 7, max 365)").option("--out <path>", "Output CSV path", "./tt_orders.csv").action(async (opts) => {
|
|
1058
|
+
try {
|
|
1059
|
+
const params = { ziniao_profile_id: opts.ziniaoProfile };
|
|
1060
|
+
if (opts.reportUrl) params.report_url = opts.reportUrl;
|
|
1061
|
+
if (opts.days) params.days = opts.days;
|
|
1062
|
+
await runExport("tiktok_order_export", params, opts.out, 54e4);
|
|
1063
|
+
} catch (err) {
|
|
1064
|
+
console.error(formatError(err));
|
|
1065
|
+
process.exit(1);
|
|
1066
|
+
}
|
|
1067
|
+
});
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
// src/commands/bitbrowser.ts
|
|
1071
|
+
function registerBitBrowserCommands(program2) {
|
|
1072
|
+
const bitbrowser = program2.command("bitbrowser").description("Manage BitBrowser (\u6BD4\u7279\u6D4F\u89C8\u5668) anti-detect browser");
|
|
1073
|
+
bitbrowser.command("profiles").description("List BitBrowser profiles (requires Desktop app online + BitBrowser running)").action(async () => {
|
|
1074
|
+
try {
|
|
1075
|
+
const result = await api.getBitBrowserProfiles();
|
|
1076
|
+
if (!result.connected) {
|
|
1077
|
+
console.log(formatDesktopNotConnected(result));
|
|
1078
|
+
process.exit(1);
|
|
1079
|
+
}
|
|
1080
|
+
if (result.profiles.length === 0) {
|
|
1081
|
+
console.log("No BitBrowser profiles found. Is BitBrowser running with its local API enabled?");
|
|
1082
|
+
return;
|
|
1083
|
+
}
|
|
1084
|
+
console.log(`BitBrowser profiles (${result.profiles.length}):
|
|
1085
|
+
`);
|
|
1086
|
+
for (const p of result.profiles) {
|
|
1087
|
+
console.log(` ${p.id} ${p.name}`);
|
|
1088
|
+
}
|
|
1089
|
+
console.log("\nUse: browser-cli launch --connector bitbrowser --bitbrowser-profile <id> --url <url>");
|
|
1090
|
+
} catch (err) {
|
|
1091
|
+
console.error(formatError(err));
|
|
1092
|
+
process.exit(1);
|
|
1093
|
+
}
|
|
1094
|
+
});
|
|
1095
|
+
}
|
|
1096
|
+
|
|
887
1097
|
// src/index.ts
|
|
888
1098
|
var require2 = createRequire(import.meta.url);
|
|
889
1099
|
var { version } = require2("../package.json");
|
|
@@ -903,4 +1113,6 @@ registerTabCommands(program);
|
|
|
903
1113
|
registerScriptCommands(program);
|
|
904
1114
|
registerProfileCommands(program);
|
|
905
1115
|
registerZiNiaoCommands(program);
|
|
1116
|
+
registerRecipeCommands(program);
|
|
1117
|
+
registerBitBrowserCommands(program);
|
|
906
1118
|
program.parse();
|