@optima-chat/browser-cli 0.7.0 → 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.
Files changed (2) hide show
  1. package/dist/index.js +46 -21
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -174,10 +174,9 @@ async function requestBinary(path) {
174
174
  return Buffer.from(arrayBuffer);
175
175
  }
176
176
  var BrowserAPI = class {
177
- async createSession(url, profileId, force, connector, ziniaoProfileId, bitbrowserProfileId) {
177
+ async createSession(url, force, connector, ziniaoProfileId, bitbrowserProfileId) {
178
178
  const body = {};
179
179
  if (url) body.url = url;
180
- if (profileId) body.profile_id = profileId;
181
180
  if (force) body.force = true;
182
181
  if (connector) body.connector = connector;
183
182
  if (ziniaoProfileId) body.ziniao_profile_id = ziniaoProfileId;
@@ -258,22 +257,29 @@ var BrowserAPI = class {
258
257
  async getScreenshot(sessionId) {
259
258
  return requestBinary(`/api/sessions/${sessionId}/screenshot`);
260
259
  }
261
- async runRecipeScript(name, params, pollMs = 2e3) {
260
+ async runRecipeScript(name, params, pollMs = 2e3, timeoutMs = 36e4) {
262
261
  const started = await request(`/api/scripts/${name}/run`, {
263
262
  method: "POST",
264
263
  body: JSON.stringify({ params })
265
264
  });
265
+ const deadline = Date.now() + timeoutMs;
266
266
  for (; ; ) {
267
- const task = await request(
268
- `/api/script-tasks/${started.id}`
269
- );
267
+ const task = await request(`/api/script-tasks/${started.id}`);
270
268
  if (task.status === "completed") return task.output;
271
269
  if (task.status === "failed" || task.status === "needs_fallback") {
272
- throw new Error(task.error || `recipe ${task.status}`);
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
+ );
273
276
  }
274
277
  await new Promise((r) => setTimeout(r, pollMs));
275
278
  }
276
279
  }
280
+ async fetchArtifact(artifactPath) {
281
+ return requestBinary(artifactPath);
282
+ }
277
283
  async search(sessionId, pattern) {
278
284
  return request(`/api/sessions/${sessionId}/search`, {
279
285
  method: "POST",
@@ -328,10 +334,10 @@ var BrowserAPI = class {
328
334
  async deleteScript(name) {
329
335
  await request(`/api/scripts/${encodeURIComponent(name)}`, { method: "DELETE" });
330
336
  }
331
- async runScript(scriptName, params = {}, profileId, connector, bitbrowserProfileId) {
337
+ async runScript(scriptName, params = {}, connector, ziniaoProfileId, bitbrowserProfileId) {
332
338
  const payload = { params };
333
- if (profileId) payload.profile_id = profileId;
334
339
  if (connector) payload.connector = connector;
340
+ if (ziniaoProfileId) payload.ziniao_profile_id = ziniaoProfileId;
335
341
  if (bitbrowserProfileId) payload.bitbrowser_profile_id = bitbrowserProfileId;
336
342
  return request(`/api/scripts/${encodeURIComponent(scriptName)}/run`, {
337
343
  method: "POST",
@@ -463,9 +469,9 @@ function formatProfileDelete(profileId) {
463
469
 
464
470
  // src/commands/lifecycle.ts
465
471
  function registerLifecycleCommands(program2) {
466
- program2.command("launch").description("Launch a browser session").option("--url <url>", "Navigate to URL after launch").option("--profile <id>", "Use a named browser profile").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) => {
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) => {
467
473
  try {
468
- const state = await api.createSession(opts.url, opts.profile, opts.force, opts.connector, opts.ziniaoProfile, opts.bitbrowserProfile);
474
+ const state = await api.createSession(opts.url, opts.force, opts.connector, opts.ziniaoProfile, opts.bitbrowserProfile);
469
475
  saveSessionId(state.session_id);
470
476
  console.log(formatLaunch(state));
471
477
  } catch (err) {
@@ -781,7 +787,7 @@ function registerScriptCommands(program2) {
781
787
  process.exit(1);
782
788
  }
783
789
  });
784
- program2.command("runscript").argument("<name>", "Script name").description("Run a script (polls until complete)").option("--param <params...>", "Parameters as key=value").option("--profile <id>", "Use a named browser profile").option("--connector <type>", "Browser connector: chrome, ziniao, or bitbrowser").option("--bitbrowser-profile <id>", "BitBrowser profile ID (with --connector bitbrowser)").option("--no-poll", "Return immediately without polling").action(async (name, opts) => {
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) => {
785
791
  try {
786
792
  const params = {};
787
793
  if (opts.param) {
@@ -791,7 +797,7 @@ function registerScriptCommands(program2) {
791
797
  }
792
798
  }
793
799
  clearSessionId();
794
- const task = await api.runScript(name, params, opts.profile, opts.connector, opts.bitbrowserProfile);
800
+ const task = await api.runScript(name, params, opts.connector, opts.ziniaoProfile, opts.bitbrowserProfile);
795
801
  console.log(`Script started (task: ${task.id})`);
796
802
  if (!opts.poll) {
797
803
  console.log(`Poll with: browser-cli script-task ${task.id}`);
@@ -828,7 +834,7 @@ function registerScriptCommands(program2) {
828
834
  });
829
835
  }
830
836
  function sleep(ms) {
831
- return new Promise((resolve) => setTimeout(resolve, ms));
837
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
832
838
  }
833
839
 
834
840
  // src/commands/profile.ts
@@ -999,7 +1005,8 @@ function registerZiNiaoCommands(program2) {
999
1005
  console.log(`ZiNiao profiles (${result.profiles.length}):
1000
1006
  `);
1001
1007
  for (const p of result.profiles) {
1002
- console.log(` ${p.id} ${p.name}`);
1008
+ const site = p.platform_name ? ` [${p.platform_name}]` : "";
1009
+ console.log(` ${p.id} ${p.name}${site}`);
1003
1010
  }
1004
1011
  console.log("\nUse: browser-cli launch --connector ziniao --ziniao-profile <id> --url <url>");
1005
1012
  } catch (err) {
@@ -1027,14 +1034,32 @@ function registerZiNiaoCommands(program2) {
1027
1034
 
1028
1035
  // src/commands/recipes.ts
1029
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
+ }
1030
1046
  function registerRecipeCommands(program2) {
1031
- 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("--out <path>", "Output CSV path", "./tt_video_ad_7d.csv").action(async (opts) => {
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) => {
1032
1048
  try {
1033
- const out = await api.runRecipeScript("tiktok_video_ad_export", {
1034
- ziniao_profile_id: opts.ziniaoProfile
1035
- });
1036
- writeFileSync3(opts.out, Buffer.from(out.content_b64, "base64"));
1037
- console.log(`Saved ${out.filename} -> ${opts.out} (${out.size} bytes)`);
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);
1038
1063
  } catch (err) {
1039
1064
  console.error(formatError(err));
1040
1065
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optima-chat/browser-cli",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "bin": {