@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.
- package/dist/index.js +51 -10
- 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
|
-
|
|
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
|
-
|
|
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
|
|
1426
|
-
Windows: C:\\Users\\<\u7528\u6237\u540D>\\Downloads\\OptimaConnect\\<\u5E73\u53F0>\\<\u8D27\u54C1
|
|
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
|
-
|
|
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);
|