@web-auto/webauto 0.1.18 → 0.1.19
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/README.md +122 -53
- package/apps/desktop-console/dist/main/index.mjs +227 -12
- package/apps/desktop-console/dist/renderer/index.js +237 -8
- package/apps/desktop-console/entry/ui-cli.mjs +282 -16
- package/apps/desktop-console/entry/ui-console.mjs +46 -15
- package/apps/webauto/entry/account.mjs +126 -27
- package/apps/webauto/entry/lib/account-detect.mjs +399 -9
- package/apps/webauto/entry/lib/account-store.mjs +201 -109
- package/apps/webauto/entry/lib/iflow-reply.mjs +194 -0
- package/apps/webauto/entry/lib/profile-policy.mjs +48 -0
- package/apps/webauto/entry/lib/profilepool.mjs +12 -0
- package/apps/webauto/entry/lib/schedule-store.mjs +29 -2
- package/apps/webauto/entry/lib/session-init.mjs +227 -0
- package/apps/webauto/entry/lib/upgrade-check.mjs +269 -0
- package/apps/webauto/entry/lib/xhs-unified-blocks.mjs +160 -0
- package/apps/webauto/entry/lib/xhs-unified-output-blocks.mjs +83 -0
- package/apps/webauto/entry/lib/xhs-unified-plan-blocks.mjs +55 -0
- package/apps/webauto/entry/lib/xhs-unified-profile-blocks.mjs +542 -0
- package/apps/webauto/entry/lib/xhs-unified-runtime-blocks.mjs +436 -0
- package/apps/webauto/entry/profilepool.mjs +56 -9
- package/apps/webauto/entry/smart-reply-cli.mjs +267 -0
- package/apps/webauto/entry/weibo-unified.mjs +84 -11
- package/apps/webauto/entry/xhs-orchestrate.mjs +43 -1
- package/apps/webauto/entry/xhs-unified.mjs +92 -997
- package/bin/webauto.mjs +22 -4
- package/dist/modules/camo-backend/src/index.js +33 -0
- package/dist/modules/camo-backend/src/internal/BrowserSession.js +232 -49
- package/dist/modules/camo-backend/src/internal/engine-manager.js +14 -13
- package/dist/modules/camo-backend/src/internal/ws-server.js +16 -19
- package/dist/modules/camo-runtime/src/utils/browser-service.mjs +38 -6
- package/dist/modules/workflow/blocks/EnsureSession.js +0 -8
- package/dist/modules/workflow/blocks/WeiboCollectFromLinksBlock.js +78 -6
- package/dist/modules/workflow/blocks/WeiboCollectSearchLinksBlock.js +266 -192
- package/dist/modules/workflow/definitions/weibo-search-workflow-v1.js +2 -0
- package/dist/modules/workflow/src/runner.js +2 -0
- package/dist/modules/xiaohongshu/app/src/blocks/ReplyInteractBlock.js +150 -37
- package/dist/modules/xiaohongshu/app/src/blocks/SmartReplyBlock.js +491 -0
- package/modules/camo-backend/src/index.ts +31 -0
- package/modules/camo-backend/src/internal/BrowserSession.ts +224 -53
- package/modules/camo-backend/src/internal/engine-manager.ts +14 -15
- package/modules/camo-backend/src/internal/ws-server.ts +17 -17
- package/modules/camo-runtime/src/autoscript/action-providers/xhs/common.mjs +12 -2
- package/modules/camo-runtime/src/autoscript/action-providers/xhs/persistence.mjs +57 -0
- package/modules/camo-runtime/src/autoscript/action-providers/xhs.mjs +2475 -243
- package/modules/camo-runtime/src/autoscript/runtime.mjs +35 -30
- package/modules/camo-runtime/src/autoscript/xhs-unified-template.mjs +80 -443
- package/modules/camo-runtime/src/container/runtime-core/checkpoint.mjs +39 -6
- package/modules/camo-runtime/src/container/runtime-core/operations/index.mjs +206 -39
- package/modules/camo-runtime/src/container/runtime-core/operations/tab-pool.mjs +0 -79
- package/modules/camo-runtime/src/container/runtime-core/operations/viewport.mjs +46 -0
- package/modules/camo-runtime/src/utils/browser-service.mjs +41 -6
- package/modules/camo-runtime/src/utils/js-policy.mjs +28 -0
- package/modules/workflow/blocks/EnsureSession.ts +0 -4
- package/modules/workflow/blocks/WeiboCollectFromLinksBlock.ts +81 -6
- package/modules/workflow/blocks/WeiboCollectSearchLinksBlock.ts +316 -0
- package/modules/workflow/definitions/weibo-search-workflow-v1.ts +2 -0
- package/modules/workflow/src/runner.ts +2 -0
- package/modules/xiaohongshu/app/src/blocks/ReplyInteractBlock.ts +198 -53
- package/modules/xiaohongshu/app/src/blocks/SmartReplyBlock.ts +706 -0
- package/package.json +2 -2
- package/modules/camo-runtime/src/autoscript/action-providers/xhs/comments.mjs +0 -498
- package/modules/camo-runtime/src/autoscript/action-providers/xhs/detail.mjs +0 -181
- package/modules/camo-runtime/src/autoscript/action-providers/xhs/interaction.mjs +0 -691
- package/modules/camo-runtime/src/autoscript/action-providers/xhs/search.mjs +0 -388
- package/modules/camo-runtime/src/container/runtime-core/operations/selector-scripts.mjs +0 -135
|
@@ -2133,9 +2133,7 @@ var PLATFORM_TASKS = {
|
|
|
2133
2133
|
{ type: "xhs-unified", label: "\u641C\u7D22\u4EFB\u52A1", icon: "\u{1F4D5}", platform: "xiaohongshu" }
|
|
2134
2134
|
],
|
|
2135
2135
|
weibo: [
|
|
2136
|
-
{ type: "weibo-
|
|
2137
|
-
{ type: "weibo-search", label: "\u641C\u7D22\u4EFB\u52A1", icon: "\u{1F50D}", platform: "weibo" },
|
|
2138
|
-
{ type: "weibo-monitor", label: "\u76D1\u63A7\u4E2A\u4EBA\u4E3B\u9875", icon: "\u{1F441}\uFE0F", platform: "weibo" }
|
|
2136
|
+
{ type: "weibo-search", label: "\u641C\u7D22\u4EFB\u52A1", icon: "\u{1F50D}", platform: "weibo" }
|
|
2139
2137
|
],
|
|
2140
2138
|
"1688": [
|
|
2141
2139
|
{ type: "1688-search", label: "\u641C\u7D22\u4EFB\u52A1", icon: "\u{1F6D2}", platform: "1688" }
|
|
@@ -2249,6 +2247,16 @@ function parseSortableTime(value) {
|
|
|
2249
2247
|
const ts = Date.parse(String(value || ""));
|
|
2250
2248
|
return Number.isFinite(ts) ? ts : 0;
|
|
2251
2249
|
}
|
|
2250
|
+
function normalizeCsvKeywords(value) {
|
|
2251
|
+
return String(value || "").split(",").map((item) => item.trim()).filter(Boolean).join(",");
|
|
2252
|
+
}
|
|
2253
|
+
function normalizeIsoOrNull(value) {
|
|
2254
|
+
const text = String(value || "").trim();
|
|
2255
|
+
if (!text) return null;
|
|
2256
|
+
const ts = Date.parse(text);
|
|
2257
|
+
if (!Number.isFinite(ts)) return text;
|
|
2258
|
+
return new Date(ts).toISOString();
|
|
2259
|
+
}
|
|
2252
2260
|
function renderTasksPanel(root, ctx2) {
|
|
2253
2261
|
root.innerHTML = "";
|
|
2254
2262
|
const pageIndicator = createEl("div", { className: "page-indicator" }, [
|
|
@@ -2411,6 +2419,11 @@ function renderTasksPanel(root, ctx2) {
|
|
|
2411
2419
|
<button id="task-history-edit-btn" class="secondary">\u8F7D\u5165\u7F16\u8F91</button>
|
|
2412
2420
|
<button id="task-history-clone-btn" class="secondary">\u8F7D\u5165\u53E6\u5B58</button>
|
|
2413
2421
|
<button id="task-history-run-btn">\u7ACB\u5373\u6267\u884C</button>
|
|
2422
|
+
<label style="display:flex;align-items:center;gap:6px;margin-left:6px;">
|
|
2423
|
+
<input id="task-select-all" type="checkbox" />
|
|
2424
|
+
<span style="font-size:12px;">\u5168\u9009</span>
|
|
2425
|
+
</label>
|
|
2426
|
+
<button id="task-history-delete-btn" class="secondary">\u6279\u91CF\u5220\u9664</button>
|
|
2414
2427
|
<button id="task-history-refresh-btn" class="secondary">\u5237\u65B0</button>
|
|
2415
2428
|
</div>
|
|
2416
2429
|
<div class="muted" style="font-size:12px; margin-bottom:6px;">\u53CC\u51FB\u5217\u8868\u9879\u53EF\u76F4\u63A5\u5207\u6362\u4E3A\u5F53\u524D\u4EFB\u52A1\u3002</div>
|
|
@@ -2451,6 +2464,8 @@ function renderTasksPanel(root, ctx2) {
|
|
|
2451
2464
|
const historyEditBtn = recentCard.querySelector("#task-history-edit-btn");
|
|
2452
2465
|
const historyCloneBtn = recentCard.querySelector("#task-history-clone-btn");
|
|
2453
2466
|
const historyRunBtn = recentCard.querySelector("#task-history-run-btn");
|
|
2467
|
+
const taskSelectAll = recentCard.querySelector("#task-select-all");
|
|
2468
|
+
const historyDeleteBtn = recentCard.querySelector("#task-history-delete-btn");
|
|
2454
2469
|
const historyRefreshBtn = recentCard.querySelector("#task-history-refresh-btn");
|
|
2455
2470
|
const recentTasksList = recentCard.querySelector("#recent-tasks-list");
|
|
2456
2471
|
const statRunning = statsCard.querySelector("#stat-running");
|
|
@@ -2459,6 +2474,7 @@ function renderTasksPanel(root, ctx2) {
|
|
|
2459
2474
|
let tasks = [];
|
|
2460
2475
|
let accountRows = [];
|
|
2461
2476
|
const activeRunIds = /* @__PURE__ */ new Set();
|
|
2477
|
+
const selectedTaskIds = /* @__PURE__ */ new Set();
|
|
2462
2478
|
let unsubscribeActiveRuns = null;
|
|
2463
2479
|
const joinPath2 = (...parts) => {
|
|
2464
2480
|
if (typeof ctx2?.api?.pathJoin === "function") return ctx2.api.pathJoin(...parts);
|
|
@@ -2659,21 +2675,49 @@ function renderTasksPanel(root, ctx2) {
|
|
|
2659
2675
|
historySelect.value = previous;
|
|
2660
2676
|
}
|
|
2661
2677
|
}
|
|
2678
|
+
function updateSelectionUi(rows) {
|
|
2679
|
+
const availableIds = new Set(rows.map((row) => row.id));
|
|
2680
|
+
for (const id of Array.from(selectedTaskIds)) {
|
|
2681
|
+
if (!availableIds.has(id)) selectedTaskIds.delete(id);
|
|
2682
|
+
}
|
|
2683
|
+
const total = rows.length;
|
|
2684
|
+
const selected = rows.filter((row) => selectedTaskIds.has(row.id)).length;
|
|
2685
|
+
taskSelectAll.checked = total > 0 && selected === total;
|
|
2686
|
+
taskSelectAll.indeterminate = selected > 0 && selected < total;
|
|
2687
|
+
historyDeleteBtn.disabled = selected === 0;
|
|
2688
|
+
historyDeleteBtn.textContent = selected > 0 ? `\u6279\u91CF\u5220\u9664(${selected})` : "\u6279\u91CF\u5220\u9664";
|
|
2689
|
+
}
|
|
2662
2690
|
function renderRecentTasks() {
|
|
2663
2691
|
const rows = sortedTasksByRecent();
|
|
2664
2692
|
if (rows.length === 0) {
|
|
2665
2693
|
recentTasksList.innerHTML = '<div class="muted" style="font-size:12px;">\u6682\u65E0\u4EFB\u52A1</div>';
|
|
2694
|
+
updateSelectionUi([]);
|
|
2666
2695
|
return;
|
|
2667
2696
|
}
|
|
2668
2697
|
recentTasksList.innerHTML = rows.map((task) => `
|
|
2669
2698
|
<div class="task-row task-item" data-id="${task.id}" style="display:flex;gap:var(--gap-sm);padding:var(--gap-xs)0;border-bottom:1px solid var(--border-subtle);align-items:center;cursor:pointer;">
|
|
2699
|
+
<input class="task-select-checkbox" data-id="${task.id}" type="checkbox" style="margin:0;" ${selectedTaskIds.has(task.id) ? "checked" : ""} />
|
|
2670
2700
|
<span style="flex:1;font-size:12px;">${task.name || task.id}</span>
|
|
2671
2701
|
<span style="font-size:11px;color:var(--text-tertiary);">${task.commandType}</span>
|
|
2672
2702
|
<span style="font-size:11px;color:${task.enabled ? "var(--accent-success)" : "var(--text-muted)"};">${task.enabled ? "\u542F\u7528" : "\u7981\u7528"}</span>
|
|
2673
2703
|
<button class="secondary edit-task-btn" data-id="${task.id}" style="padding:2px 6px;font-size:10px;height:auto;">\u7F16\u8F91</button>
|
|
2674
2704
|
<button class="run-task-btn" data-id="${task.id}" style="padding:2px 6px;font-size:10px;height:auto;">\u7ACB\u5373\u6267\u884C</button>
|
|
2705
|
+
<button class="secondary delete-task-btn" data-id="${task.id}" style="padding:2px 6px;font-size:10px;height:auto;">\u5220\u9664</button>
|
|
2675
2706
|
</div>
|
|
2676
2707
|
`).join("");
|
|
2708
|
+
recentTasksList.querySelectorAll(".task-select-checkbox").forEach((checkbox) => {
|
|
2709
|
+
checkbox.addEventListener("click", (event) => {
|
|
2710
|
+
event.stopPropagation();
|
|
2711
|
+
});
|
|
2712
|
+
checkbox.addEventListener("change", () => {
|
|
2713
|
+
const input = checkbox;
|
|
2714
|
+
const taskId = String(input.dataset.id || "").trim();
|
|
2715
|
+
if (!taskId) return;
|
|
2716
|
+
if (input.checked) selectedTaskIds.add(taskId);
|
|
2717
|
+
else selectedTaskIds.delete(taskId);
|
|
2718
|
+
updateSelectionUi(rows);
|
|
2719
|
+
});
|
|
2720
|
+
});
|
|
2677
2721
|
recentTasksList.querySelectorAll(".task-item").forEach((item) => {
|
|
2678
2722
|
item.addEventListener("dblclick", () => {
|
|
2679
2723
|
const taskId = item.dataset.id || "";
|
|
@@ -2700,6 +2744,14 @@ function renderTasksPanel(root, ctx2) {
|
|
|
2700
2744
|
void runTaskImmediately(task);
|
|
2701
2745
|
});
|
|
2702
2746
|
});
|
|
2747
|
+
recentTasksList.querySelectorAll(".delete-task-btn").forEach((btn) => {
|
|
2748
|
+
btn.addEventListener("click", () => {
|
|
2749
|
+
const taskId = String(btn.dataset.id || "").trim();
|
|
2750
|
+
if (!taskId) return;
|
|
2751
|
+
void deleteTasks([taskId]);
|
|
2752
|
+
});
|
|
2753
|
+
});
|
|
2754
|
+
updateSelectionUi(rows);
|
|
2703
2755
|
}
|
|
2704
2756
|
function updateStats() {
|
|
2705
2757
|
statSaved.textContent = String(tasks.length);
|
|
@@ -2771,6 +2823,8 @@ function renderTasksPanel(root, ctx2) {
|
|
|
2771
2823
|
"max-notes": data.targetCount,
|
|
2772
2824
|
target: data.targetCount,
|
|
2773
2825
|
env: data.env,
|
|
2826
|
+
// Desktop-triggered runs must keep UI alive; service reset would call ui cli stop/start.
|
|
2827
|
+
"service-reset": false,
|
|
2774
2828
|
"do-comments": data.collectComments,
|
|
2775
2829
|
"fetch-body": data.collectBody,
|
|
2776
2830
|
"do-likes": data.doLikes,
|
|
@@ -2839,7 +2893,7 @@ function renderTasksPanel(root, ctx2) {
|
|
|
2839
2893
|
};
|
|
2840
2894
|
}
|
|
2841
2895
|
async function runSavedTask(taskId, data) {
|
|
2842
|
-
const out = await invokeSchedule({ action: "run", taskId, timeoutMs: 0 });
|
|
2896
|
+
const out = await invokeSchedule({ action: "run", taskId, timeoutMs: 0, background: true });
|
|
2843
2897
|
const runId = String(
|
|
2844
2898
|
out?.result?.runResult?.lastRunId || out?.result?.runResult?.runId || out?.runResult?.runId || ""
|
|
2845
2899
|
).trim();
|
|
@@ -2868,24 +2922,140 @@ function renderTasksPanel(root, ctx2) {
|
|
|
2868
2922
|
applyTaskToForm(task, "edit");
|
|
2869
2923
|
await runSavedTask(taskId, taskToRunMeta(task));
|
|
2870
2924
|
}
|
|
2925
|
+
function toTaskDedupFingerprintFromForm(data) {
|
|
2926
|
+
const scheduleMode = data.scheduleMode;
|
|
2927
|
+
const periodicType = scheduleMode === "periodic" ? data.periodicType : "interval";
|
|
2928
|
+
const intervalMinutes = scheduleMode === "periodic" ? Math.max(1, Number(data.intervalMinutes || 30) || 30) : 0;
|
|
2929
|
+
const runAt = scheduleMode === "scheduled" || scheduleMode === "periodic" && (periodicType === "daily" || periodicType === "weekly") ? normalizeIsoOrNull(data.runAt) : null;
|
|
2930
|
+
const maxRuns = scheduleMode === "periodic" ? Number.isFinite(Number(data.maxRuns || 0)) && Number(data.maxRuns) > 0 ? Math.max(1, Math.floor(Number(data.maxRuns))) : null : null;
|
|
2931
|
+
return {
|
|
2932
|
+
taskType: String(data.taskType || "xhs-unified").trim() || "xhs-unified",
|
|
2933
|
+
profileId: String(data.profileId || "").trim(),
|
|
2934
|
+
keyword: String(data.keyword || "").trim(),
|
|
2935
|
+
targetCount: Math.max(1, Number(data.targetCount || 50) || 50),
|
|
2936
|
+
env: String(data.env || "debug").trim() === "prod" ? "prod" : "debug",
|
|
2937
|
+
userId: String(data.userId || "").trim(),
|
|
2938
|
+
collectComments: data.collectComments !== false,
|
|
2939
|
+
collectBody: data.collectBody !== false,
|
|
2940
|
+
doLikes: data.doLikes === true,
|
|
2941
|
+
likeKeywords: normalizeCsvKeywords(data.likeKeywords),
|
|
2942
|
+
scheduleMode,
|
|
2943
|
+
periodicType,
|
|
2944
|
+
intervalMinutes,
|
|
2945
|
+
runAt,
|
|
2946
|
+
maxRuns
|
|
2947
|
+
};
|
|
2948
|
+
}
|
|
2949
|
+
function toTaskDedupFingerprintFromTask(task) {
|
|
2950
|
+
const uiSchedule = inferUiScheduleEditorState(task);
|
|
2951
|
+
const scheduleMode = uiSchedule.mode;
|
|
2952
|
+
const periodicType = uiSchedule.periodicType;
|
|
2953
|
+
const intervalMinutes = scheduleMode === "periodic" ? Math.max(1, Number(task.intervalMinutes || 30) || 30) : 0;
|
|
2954
|
+
const runAt = scheduleMode === "scheduled" || scheduleMode === "periodic" && (periodicType === "daily" || periodicType === "weekly") ? normalizeIsoOrNull(task.runAt) : null;
|
|
2955
|
+
const maxRuns = scheduleMode === "periodic" ? Number.isFinite(Number(task.maxRuns || 0)) && Number(task.maxRuns) > 0 ? Math.max(1, Math.floor(Number(task.maxRuns))) : null : null;
|
|
2956
|
+
return {
|
|
2957
|
+
taskType: String(task.commandType || "xhs-unified").trim() || "xhs-unified",
|
|
2958
|
+
profileId: String(task.commandArgv?.profile || task.commandArgv?.profileId || "").trim(),
|
|
2959
|
+
keyword: String(task.commandArgv?.keyword || task.commandArgv?.k || "").trim(),
|
|
2960
|
+
targetCount: Math.max(1, Number(task.commandArgv?.["max-notes"] ?? task.commandArgv?.target ?? 50) || 50),
|
|
2961
|
+
env: String(task.commandArgv?.env || "debug").trim() === "prod" ? "prod" : "debug",
|
|
2962
|
+
userId: String(task.commandArgv?.["user-id"] || task.commandArgv?.userId || "").trim(),
|
|
2963
|
+
collectComments: task.commandArgv?.["do-comments"] !== false,
|
|
2964
|
+
collectBody: task.commandArgv?.["fetch-body"] !== false,
|
|
2965
|
+
doLikes: task.commandArgv?.["do-likes"] === true,
|
|
2966
|
+
likeKeywords: normalizeCsvKeywords(String(task.commandArgv?.["like-keywords"] || "").trim()),
|
|
2967
|
+
scheduleMode,
|
|
2968
|
+
periodicType,
|
|
2969
|
+
intervalMinutes,
|
|
2970
|
+
runAt,
|
|
2971
|
+
maxRuns
|
|
2972
|
+
};
|
|
2973
|
+
}
|
|
2974
|
+
function toDedupKey(fingerprint) {
|
|
2975
|
+
return JSON.stringify(fingerprint);
|
|
2976
|
+
}
|
|
2977
|
+
function findDuplicateTaskByParams(data) {
|
|
2978
|
+
const editingId = String(data.id || "").trim();
|
|
2979
|
+
if (editingId) return getTaskById(editingId);
|
|
2980
|
+
const dedupKey = toDedupKey(toTaskDedupFingerprintFromForm(data));
|
|
2981
|
+
const rows = sortedTasksByRecent();
|
|
2982
|
+
for (const row of rows) {
|
|
2983
|
+
if (toDedupKey(toTaskDedupFingerprintFromTask(row)) === dedupKey) return row;
|
|
2984
|
+
}
|
|
2985
|
+
return null;
|
|
2986
|
+
}
|
|
2987
|
+
async function deleteTasks(taskIds) {
|
|
2988
|
+
const uniqueIds = Array.from(new Set(taskIds.map((item) => String(item || "").trim()).filter(Boolean)));
|
|
2989
|
+
if (uniqueIds.length === 0) {
|
|
2990
|
+
alert("\u8BF7\u5148\u9009\u62E9\u8981\u5220\u9664\u7684\u4EFB\u52A1");
|
|
2991
|
+
return;
|
|
2992
|
+
}
|
|
2993
|
+
const confirmed = window.confirm(`\u786E\u8BA4\u5220\u9664 ${uniqueIds.length} \u4E2A\u4EFB\u52A1\u5417\uFF1F\u6B64\u64CD\u4F5C\u4E0D\u53EF\u64A4\u9500\u3002`);
|
|
2994
|
+
if (!confirmed) return;
|
|
2995
|
+
historyDeleteBtn.disabled = true;
|
|
2996
|
+
try {
|
|
2997
|
+
const failed = [];
|
|
2998
|
+
const deleted = /* @__PURE__ */ new Set();
|
|
2999
|
+
for (const taskId of uniqueIds) {
|
|
3000
|
+
try {
|
|
3001
|
+
await invokeSchedule({ action: "delete", taskId });
|
|
3002
|
+
deleted.add(taskId);
|
|
3003
|
+
} catch {
|
|
3004
|
+
failed.push(taskId);
|
|
3005
|
+
}
|
|
3006
|
+
}
|
|
3007
|
+
for (const taskId of deleted) {
|
|
3008
|
+
selectedTaskIds.delete(taskId);
|
|
3009
|
+
}
|
|
3010
|
+
if (deleted.has(String(editingIdInput.value || "").trim())) {
|
|
3011
|
+
resetForm();
|
|
3012
|
+
}
|
|
3013
|
+
if (deleted.has(String(historySelect.value || "").trim())) {
|
|
3014
|
+
historySelect.value = "";
|
|
3015
|
+
}
|
|
3016
|
+
await loadTasks();
|
|
3017
|
+
if (failed.length > 0) {
|
|
3018
|
+
alert(`\u5DF2\u5220\u9664 ${deleted.size} \u4E2A\u4EFB\u52A1\uFF0C\u5931\u8D25 ${failed.length} \u4E2A`);
|
|
3019
|
+
}
|
|
3020
|
+
} finally {
|
|
3021
|
+
historyDeleteBtn.disabled = false;
|
|
3022
|
+
}
|
|
3023
|
+
}
|
|
2871
3024
|
async function saveTask(runImmediately = false) {
|
|
3025
|
+
await loadTasks();
|
|
2872
3026
|
const data = collectFormData();
|
|
3027
|
+
if (!String(data.id || "").trim()) {
|
|
3028
|
+
const duplicate = findDuplicateTaskByParams(data);
|
|
3029
|
+
if (duplicate) {
|
|
3030
|
+
data.id = duplicate.id;
|
|
3031
|
+
editingIdInput.value = duplicate.id;
|
|
3032
|
+
updateFormTitle("edit");
|
|
3033
|
+
}
|
|
3034
|
+
}
|
|
2873
3035
|
saveBtn.disabled = true;
|
|
2874
3036
|
runBtn.disabled = true;
|
|
2875
3037
|
runEphemeralBtn.disabled = true;
|
|
3038
|
+
let savedTaskId = "";
|
|
3039
|
+
let resolvedProfile = String(data.profileId || "").trim();
|
|
2876
3040
|
try {
|
|
2877
3041
|
const out = await invokeSchedule({ action: "save", payload: toSchedulePayload(data) });
|
|
2878
3042
|
const taskId = String(out?.task?.id || data.id || "").trim();
|
|
2879
3043
|
if (!taskId) {
|
|
2880
3044
|
throw new Error("task id missing after save");
|
|
2881
3045
|
}
|
|
3046
|
+
savedTaskId = taskId;
|
|
2882
3047
|
editingIdInput.value = taskId;
|
|
2883
3048
|
updateFormTitle("edit");
|
|
2884
3049
|
await loadTasks();
|
|
2885
3050
|
historySelect.value = taskId;
|
|
3051
|
+
resolvedProfile = String(out?.task?.commandArgv?.profile || data.profileId || "").trim();
|
|
3052
|
+
} catch (err) {
|
|
3053
|
+
alert(`\u4FDD\u5B58\u5931\u8D25: ${err?.message || String(err)}`);
|
|
3054
|
+
return;
|
|
3055
|
+
}
|
|
3056
|
+
try {
|
|
2886
3057
|
if (runImmediately) {
|
|
2887
|
-
|
|
2888
|
-
await runSavedTask(taskId, {
|
|
3058
|
+
await runSavedTask(savedTaskId, {
|
|
2889
3059
|
taskType: data.taskType,
|
|
2890
3060
|
profileId: resolvedProfile,
|
|
2891
3061
|
keyword: data.keyword,
|
|
@@ -2895,7 +3065,11 @@ function renderTasksPanel(root, ctx2) {
|
|
|
2895
3065
|
alert("\u4EFB\u52A1\u5DF2\u4FDD\u5B58");
|
|
2896
3066
|
}
|
|
2897
3067
|
} catch (err) {
|
|
2898
|
-
|
|
3068
|
+
if (runImmediately) {
|
|
3069
|
+
alert(`\u4EFB\u52A1\u5DF2\u4FDD\u5B58\uFF0C\u4F46\u6267\u884C\u5931\u8D25: ${err?.message || String(err)}`);
|
|
3070
|
+
} else {
|
|
3071
|
+
alert(`\u6267\u884C\u5931\u8D25: ${err?.message || String(err)}`);
|
|
3072
|
+
}
|
|
2899
3073
|
} finally {
|
|
2900
3074
|
saveBtn.disabled = false;
|
|
2901
3075
|
runBtn.disabled = false;
|
|
@@ -2979,6 +3153,18 @@ function renderTasksPanel(root, ctx2) {
|
|
|
2979
3153
|
historyRefreshBtn.addEventListener("click", () => {
|
|
2980
3154
|
void loadTasks();
|
|
2981
3155
|
});
|
|
3156
|
+
taskSelectAll.addEventListener("change", () => {
|
|
3157
|
+
const rows = sortedTasksByRecent();
|
|
3158
|
+
if (taskSelectAll.checked) {
|
|
3159
|
+
for (const row of rows) selectedTaskIds.add(row.id);
|
|
3160
|
+
} else {
|
|
3161
|
+
selectedTaskIds.clear();
|
|
3162
|
+
}
|
|
3163
|
+
renderRecentTasks();
|
|
3164
|
+
});
|
|
3165
|
+
historyDeleteBtn.addEventListener("click", () => {
|
|
3166
|
+
void deleteTasks(Array.from(selectedTaskIds));
|
|
3167
|
+
});
|
|
2982
3168
|
historyEditBtn.addEventListener("click", () => {
|
|
2983
3169
|
const task = selectedHistoryTask();
|
|
2984
3170
|
if (!task) {
|
|
@@ -3233,6 +3419,36 @@ function renderDashboard(root, ctx2) {
|
|
|
3233
3419
|
const normalizeStatus = (value) => String(value || "").trim().toLowerCase();
|
|
3234
3420
|
const isRunningStatus = (value) => ["running", "queued", "pending", "starting"].includes(normalizeStatus(value));
|
|
3235
3421
|
const isTerminalStatus = (value) => ["completed", "done", "success", "succeeded", "failed", "error", "stopped", "canceled"].includes(normalizeStatus(value));
|
|
3422
|
+
const resolveUnifiedPhaseFromOp = (operationId, fallback = "\u8FD0\u884C\u4E2D") => {
|
|
3423
|
+
const op = String(operationId || "").trim();
|
|
3424
|
+
if (!op) return fallback;
|
|
3425
|
+
if (op === "sync_window_viewport" || op === "goto_home" || op === "fill_keyword" || op === "submit_search" || op === "xhs_assert_logged_in" || op === "abort_on_login_guard" || op === "abort_on_risk_guard") {
|
|
3426
|
+
return "\u767B\u5F55\u6821\u9A8C";
|
|
3427
|
+
}
|
|
3428
|
+
if (op === "ensure_tab_pool" || op === "verify_subscriptions_all_pages") {
|
|
3429
|
+
return "\u91C7\u96C6\u94FE\u63A5";
|
|
3430
|
+
}
|
|
3431
|
+
if (op === "open_first_detail" || op === "open_next_detail" || op === "wait_between_notes" || op === "switch_tab_round_robin") {
|
|
3432
|
+
return "\u6253\u5F00\u8BE6\u60C5";
|
|
3433
|
+
}
|
|
3434
|
+
if (op === "detail_harvest" || op === "expand_replies" || op === "comments_harvest" || op === "comment_match_gate" || op === "comment_like" || op === "comment_reply" || op === "close_detail") {
|
|
3435
|
+
return "\u8BE6\u60C5\u91C7\u96C6\u70B9\u8D5E";
|
|
3436
|
+
}
|
|
3437
|
+
return fallback;
|
|
3438
|
+
};
|
|
3439
|
+
const resolveUnifiedActionFromEvent = (eventName, payload, fallback = "-") => {
|
|
3440
|
+
const opId = String(payload?.operationId || "").trim();
|
|
3441
|
+
if (opId) {
|
|
3442
|
+
if (eventName === "autoscript:operation_error" || eventName === "autoscript:operation_recovery_failed") {
|
|
3443
|
+
const err = String(payload?.error || payload?.message || payload?.code || "").trim();
|
|
3444
|
+
return err ? `${opId}: ${err}` : `${opId}: failed`;
|
|
3445
|
+
}
|
|
3446
|
+
const stage = String(payload?.stage || "").trim();
|
|
3447
|
+
return stage ? `${opId}:${stage}` : opId;
|
|
3448
|
+
}
|
|
3449
|
+
const message = String(payload?.message || payload?.reason || "").trim();
|
|
3450
|
+
return message || fallback;
|
|
3451
|
+
};
|
|
3236
3452
|
const isXhsCommandTitle = (title) => {
|
|
3237
3453
|
const normalized = String(title || "").trim().toLowerCase();
|
|
3238
3454
|
if (!normalized) return false;
|
|
@@ -3695,9 +3911,16 @@ function renderDashboard(root, ctx2) {
|
|
|
3695
3911
|
renderRunSummary();
|
|
3696
3912
|
return;
|
|
3697
3913
|
}
|
|
3914
|
+
if (event === "autoscript:operation_start" || event === "autoscript:operation_progress") {
|
|
3915
|
+
const opId = String(payload?.operationId || "").trim();
|
|
3916
|
+
currentPhase.textContent = resolveUnifiedPhaseFromOp(opId, currentPhase.textContent || "\u8FD0\u884C\u4E2D");
|
|
3917
|
+
currentAction.textContent = resolveUnifiedActionFromEvent(event, payload, currentAction.textContent || "-");
|
|
3918
|
+
return;
|
|
3919
|
+
}
|
|
3698
3920
|
if (event === "autoscript:operation_done") {
|
|
3699
3921
|
const opId = String(payload.operationId || "").trim();
|
|
3700
|
-
|
|
3922
|
+
currentPhase.textContent = resolveUnifiedPhaseFromOp(opId, currentPhase.textContent || "\u8FD0\u884C\u4E2D");
|
|
3923
|
+
currentAction.textContent = resolveUnifiedActionFromEvent(event, payload, currentAction.textContent || "-");
|
|
3701
3924
|
const result = payload.result && typeof payload.result === "object" ? payload.result : {};
|
|
3702
3925
|
const opResult = result && typeof result === "object" && "result" in result ? result.result : result;
|
|
3703
3926
|
if (opId === "open_first_detail" || opId === "open_next_detail") {
|
|
@@ -3755,6 +3978,10 @@ function renderDashboard(root, ctx2) {
|
|
|
3755
3978
|
const failed = Number(statFailed.textContent || "0") || 0;
|
|
3756
3979
|
statFailed.textContent = String(failed + 1);
|
|
3757
3980
|
const opId = String(payload?.operationId || "").trim();
|
|
3981
|
+
if (opId) {
|
|
3982
|
+
currentPhase.textContent = resolveUnifiedPhaseFromOp(opId, currentPhase.textContent || "\u8FD0\u884C\u4E2D");
|
|
3983
|
+
}
|
|
3984
|
+
currentAction.textContent = resolveUnifiedActionFromEvent(event, payload, currentAction.textContent || "-");
|
|
3758
3985
|
const err = String(payload?.error || payload?.message || payload?.code || event).trim();
|
|
3759
3986
|
pushRecentError(opId ? `${opId}: ${err}` : err, event, payload);
|
|
3760
3987
|
return;
|
|
@@ -4370,6 +4597,8 @@ Profile ID: ${acc.profileId}
|
|
|
4370
4597
|
ctx2.api.pathJoin("apps", "webauto", "entry", "account.mjs"),
|
|
4371
4598
|
"sync",
|
|
4372
4599
|
profileId,
|
|
4600
|
+
"--platform",
|
|
4601
|
+
normalizePlatform(account.platform || "xiaohongshu"),
|
|
4373
4602
|
...options.pendingWhileLogin ? ["--pending-while-login"] : [],
|
|
4374
4603
|
...options.resolveAlias ? ["--resolve-alias"] : [],
|
|
4375
4604
|
"--json"
|