@optima-chat/browser-cli 0.20.0 → 0.22.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 +51 -10
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -789,10 +789,21 @@ var WAIT_DEFAULT_TIMEOUT_S = 90;
789
789
  var WAIT_MAX_TIMEOUT_S = 570;
790
790
  var EXIT_TASK_STOPPED = 2;
791
791
  var EXIT_STILL_RUNNING = 3;
792
- async function waitForScriptTask(taskId, timeoutMs, first) {
792
+ var EXIT_WAITING_HUMAN = 4;
793
+ function waitingHumanLine(task) {
794
+ const w = task.waiting_human;
795
+ if (!w) return null;
796
+ return `WAITING_HUMAN kind=${w.kind} since=${w.since} message=${JSON.stringify(w.message)}`;
797
+ }
798
+ function waitingHumanMessage(task) {
799
+ return `${waitingHumanLine(task)}
800
+ The script is paused waiting for the store owner to act in their browser. Tell the owner now, then call as a separate command: browser-cli script-task ${task.id} --wait --through-human`;
801
+ }
802
+ async function waitForScriptTask(taskId, timeoutMs, first, throughHuman = false) {
793
803
  const deadline = Date.now() + timeoutMs;
794
804
  let task = first ?? await api.getScriptTask(taskId);
795
805
  while (task.status === "running") {
806
+ if (task.waiting_human && !throughHuman) return { task, timedOut: false, waitingHuman: true };
796
807
  const left = deadline - Date.now();
797
808
  if (left <= 0) return { task, timedOut: true };
798
809
  await sleep(Math.min(POLL_INTERVAL_MS, left));
@@ -811,7 +822,9 @@ function stillRunningMessage(task, waitedS, nowMs = Date.now()) {
811
822
  const started = task.created_at ? Date.parse(task.created_at) : Number.NaN;
812
823
  const elapsed = Number.isFinite(started) ? `running for ${Math.max(0, Math.round((nowMs - started) / 1e3))}s` : `waited ${waitedS}s`;
813
824
  const step = task.total_steps ? `, step ${task.current_step}/${task.total_steps}` : "";
814
- return `Still running (${elapsed}${step}). Call again as a separate command: browser-cli script-task ${task.id} --wait`;
825
+ const waiting = waitingHumanLine(task);
826
+ return `Still running (${elapsed}${step}). Call again as a separate command: browser-cli script-task ${task.id} --wait` + (waiting ? ` --through-human
827
+ ${waiting}` : "");
815
828
  }
816
829
  var REQUIRED_ARG_FLAG = {
817
830
  ziniao_profile_id: "--ziniao-profile <id>",
@@ -974,6 +987,8 @@ function formatScriptTask(task) {
974
987
  }
975
988
  lines.push(...haltOutputFields(task));
976
989
  } else {
990
+ const waiting = waitingHumanLine(task);
991
+ if (waiting) lines.push(waiting);
977
992
  lines.push(`Script status: ${task.status} (step ${task.current_step}/${task.total_steps})`);
978
993
  }
979
994
  return lines.join("\n");
@@ -1049,7 +1064,12 @@ function registerScriptCommands(program2) {
1049
1064
  console.log(`Wait with: browser-cli script-task ${task.id} --wait`);
1050
1065
  return;
1051
1066
  }
1052
- const { task: result, timedOut } = await waitForScriptTask(task.id, POLL_TIMEOUT_MS, task);
1067
+ const { task: result, timedOut, waitingHuman } = await waitForScriptTask(task.id, POLL_TIMEOUT_MS, task);
1068
+ if (waitingHuman) {
1069
+ console.log(waitingHumanMessage(result));
1070
+ process.exit(EXIT_WAITING_HUMAN);
1071
+ return;
1072
+ }
1053
1073
  if (timedOut) {
1054
1074
  console.log(`Polling timed out. Task ${task.id} still running.`);
1055
1075
  console.log(`Wait with: browser-cli script-task ${task.id} --wait`);
@@ -1084,18 +1104,25 @@ ${downloadHint(result)}`);
1084
1104
  });
1085
1105
  program2.command("script-task").argument("<task-id>", "Task ID").description("Check script task status").option("--download [path]", "Save the task's exported file (default: ./<filename>)").option("--json", "Print the raw task (status / error / full output) as JSON").option(
1086
1106
  "--wait",
1087
- `Block until the task finishes (completed / failed / needs_fallback), at most --timeout seconds. Exit code: 0 completed, 2 failed / needs_fallback, 3 still running (call again), 1 error`
1088
- ).option("--timeout <seconds>", `With --wait: max seconds to wait (default ${WAIT_DEFAULT_TIMEOUT_S}, max ${WAIT_MAX_TIMEOUT_S})`).action(async (taskId, opts) => {
1107
+ `Block until the task finishes (completed / failed / needs_fallback), at most --timeout seconds. Exit code: 0 completed, 2 failed / needs_fallback, 3 still running (call again), 4 waiting for the store owner (e.g. captcha; tell them, then --wait --through-human), 1 error`
1108
+ ).option("--through-human", "With --wait: keep waiting while the script waits for the store owner (exit 4 otherwise)").option("--timeout <seconds>", `With --wait: max seconds to wait (default ${WAIT_DEFAULT_TIMEOUT_S}, max ${WAIT_MAX_TIMEOUT_S})`).action(async (taskId, opts) => {
1089
1109
  try {
1090
1110
  if (opts.json && opts.download !== void 0) {
1091
1111
  throw new Error("--json \u4E0E --download \u53EA\u80FD\u7ED9\u4E00\u4E2A");
1092
1112
  }
1093
1113
  if (opts.timeout !== void 0 && !opts.wait) throw new Error("--timeout \u53EA\u80FD\u548C --wait \u4E00\u8D77\u7528");
1114
+ if (opts.throughHuman && !opts.wait) throw new Error("--through-human \u53EA\u80FD\u548C --wait \u4E00\u8D77\u7528");
1094
1115
  const timeoutS = opts.timeout === void 0 ? WAIT_DEFAULT_TIMEOUT_S : parseWaitTimeout(opts.timeout);
1095
1116
  let task;
1096
1117
  if (opts.wait) {
1097
- const waited = await waitForScriptTask(taskId, timeoutS * 1e3);
1118
+ const waited = await waitForScriptTask(taskId, timeoutS * 1e3, void 0, opts.throughHuman);
1098
1119
  task = waited.task;
1120
+ if (waited.waitingHuman) {
1121
+ if (opts.json) console.log(JSON.stringify(task, null, 2));
1122
+ (opts.json ? console.error : console.log)(waitingHumanMessage(task));
1123
+ process.exit(EXIT_WAITING_HUMAN);
1124
+ return;
1125
+ }
1099
1126
  if (waited.timedOut) {
1100
1127
  if (opts.json) console.log(JSON.stringify(task, null, 2));
1101
1128
  (opts.json ? console.error : console.log)(stillRunningMessage(task, timeoutS));
@@ -1422,8 +1449,8 @@ function registerFeikuaCommands(program2) {
1422
1449
  function formatVideoList(videos) {
1423
1450
  if (videos.length === 0) {
1424
1451
  return `No videos found. Videos are listed from your OptimaConnect folder:
1425
- macOS/Linux: ~/Downloads/OptimaConnect/<\u5E73\u53F0>/<\u8D27\u54C1>/\u89C6\u9891/ (older files: ~/Downloads/OptimaConnect/videos)
1426
- Windows: C:\\Users\\<\u7528\u6237\u540D>\\Downloads\\OptimaConnect\\<\u5E73\u53F0>\\<\u8D27\u54C1>\\\u89C6\u9891\\ (older files: ...\\OptimaConnect\\videos)
1452
+ macOS/Linux: ~/Downloads/OptimaConnect/<\u5E73\u53F0>/<\u8D27\u54C1>/videos/ (older files: ~/Downloads/OptimaConnect/videos)
1453
+ Windows: C:\\Users\\<\u7528\u6237\u540D>\\Downloads\\OptimaConnect\\<\u5E73\u53F0>\\<\u8D27\u54C1>\\videos\\ (older files: ...\\OptimaConnect\\videos)
1427
1454
  Then try again.`;
1428
1455
  }
1429
1456
  return videos.map((v) => {
@@ -1433,12 +1460,26 @@ Then try again.`;
1433
1460
  }).join("\n");
1434
1461
  }
1435
1462
  function mediaRefLine(result) {
1436
- return result.media_ref ? `media_ref: ${result.media_ref} (\u4E0A\u4F20\u53C2\u6570\u586B\u8FD9\u4E2A)` : null;
1463
+ if (!result.media_ref) return null;
1464
+ return `\u4E0A\u4F20\u53C2\u6570\u586B\u4E0B\u4E00\u884C\u5F15\u53F7\u91CC\u7684\u5B8C\u6574\u503C(\u53EF\u80FD\u542B\u7A7A\u683C,\u522B\u81EA\u5DF1\u62FC\u6216\u8865\u6269\u5C55\u540D):
1465
+ media_ref=${JSON.stringify(result.media_ref)}`;
1466
+ }
1467
+ function collisionWarning(dest, localPath) {
1468
+ const wanted = dest.split(/[\\/]/).pop();
1469
+ const landed = localPath.split(/[\\/]/).pop();
1470
+ if (wanted === landed) return null;
1471
+ return `\u6CE8\u610F:\u672C\u673A\u5DF2\u6709\u540C\u540D\u6587\u4EF6 ${wanted}(\u65E7\u6587\u4EF6,\u4E0D\u662F\u8FD9\u6B21\u9001\u7684),\u8FD9\u6B21\u843D\u4E3A ${landed}\u3002\u5F15\u7528\u8FD9\u6B21\u7684\u6587\u4EF6\u522B\u7528 ${wanted}\u3002`;
1437
1472
  }
1438
1473
  function registerFileCommands(program2) {
1439
- program2.command("send-file").description("Send a file from your workspace to your local download folder").requiredOption("--src <path>", "Source path in your workspace (e.g. ~/output/report.pdf)").requiredOption("--dest <path>", "Destination path relative to the download folder").action(async (opts) => {
1474
+ program2.command("send-file").description("Send a file from your workspace to your local download folder").requiredOption("--src <path>", "Source path in your workspace (e.g. ~/output/report.pdf)").requiredOption("--dest <path>", "Destination path relative to the download folder").option("--json", "Print {local_path, media_ref} as JSON \u2014 read media_ref from here instead of parsing text").action(async (opts) => {
1440
1475
  try {
1441
1476
  const result = await api.sendFile(opts.src, opts.dest);
1477
+ const warning = collisionWarning(opts.dest, result.local_path);
1478
+ if (warning) console.error(warning);
1479
+ if (opts.json) {
1480
+ console.log(JSON.stringify(result));
1481
+ return;
1482
+ }
1442
1483
  console.log(result.local_path);
1443
1484
  const hint = mediaRefLine(result);
1444
1485
  if (hint) console.error(hint);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optima-chat/browser-cli",
3
- "version": "0.20.0",
3
+ "version": "0.22.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "bin": {