helixlife-v5-cli 1.2.8 → 1.2.9
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 +33 -58
- package/helix-cli.js +7 -2
- package/lib/.cli.runtime.generated.json +10 -1
- package/lib/automation-file-chooser-guard.js +182 -0
- package/lib/automation-overlay.init.js +332 -68
- package/lib/browser-css-cache-guard.init-page.js +49 -0
- package/lib/browser-window-maximize.init-page.js +64 -0
- package/lib/cli.js +316 -14
- package/lib/helix-reload-bypass-cache.run-code.js +7 -0
- package/lib/helix-styles-guard.js +77 -0
- package/lib/hide-nested-skills.js +120 -0
- package/lib/native-mode-patch.js +288 -0
- package/lib/postinstall.js +39 -0
- package/lib/profile-lock-guard.js +187 -0
- package/lib/runtime-config.js +90 -0
- package/lib/token-file.js +189 -0
- package/lib/visual-page-wrap.js +311 -0
- package/lib/visual.js +255 -86
- package/package.json +9 -21
- package/scripts/README.md +81 -0
- package/scripts/{analysis-detail-upload-file.js → analysis/detail-upload-file.js} +1 -1
- package/scripts/{jigsaw-inspect-dom.js → analysis/jigsaw-inspect-dom.js} +15 -15
- package/scripts/{jigsaw-verify-enumerate.js → analysis/jigsaw-verify-enumerate.js} +1 -1
- package/scripts/common/.gitkeep +0 -0
- package/scripts/{chrome-pdf-enumerate-a11y.js → edu/chrome-pdf-enumerate-a11y.js} +1 -1
- package/scripts/{chrome-pdf-goto-page.js → edu/chrome-pdf-goto-page.js} +1 -1
- package/scripts/{chrome-pdf-zoom-out.js → edu/chrome-pdf-zoom-out.js} +1 -1
- package/scripts/{hover-partial-chapter-match.js → edu/hover-partial-chapter-match.js} +1 -1
- package/scripts/maintainer/strip-extra-skills.ps1 +27 -0
- package/scripts/workbench/jova/outline-edit-root-title.js +33 -0
- package/scripts/workbench/jova/outline-keyword-edit.js +122 -0
- package/scripts/workbench/jova/outline-ops.js +344 -0
- package/scripts/workbench/jova/outline-probe-hover.js +56 -0
- package/scripts/workbench/jova/proofread-ai-rewrite-section.js +94 -0
- package/scripts/workbench/jova/proofread-ops.js +261 -0
- package/scripts/workbench/jova/writing-ops.js +376 -0
- package/scripts/workbench/jova/writing-proofread-abstract.js +103 -0
- package/lib/cli.runtime.config.json +0 -5
- package/references/vip.helixlife.cn.site-ops.md +0 -1469
- package/scripts/workbench-jova-outline-regenerate-node.js +0 -173
- package/scripts/workbench-jova-proofread-section.js +0 -262
- package/scripts/workbench-jova-writing-tool.js +0 -308
- /package/scripts/{analysis-detail-upload-both.js → analysis/detail-upload-both.js} +0 -0
- /package/scripts/{jigsaw-verify-bio-tools.js → analysis/jigsaw-verify-bio-tools.js} +0 -0
- /package/scripts/{jigsaw-verify-drag-tool.js → analysis/jigsaw-verify-drag-tool.js} +0 -0
- /package/scripts/{jigsaw-verify-reference-lines.js → analysis/jigsaw-verify-reference-lines.js} +0 -0
package/lib/visual.js
CHANGED
|
@@ -1,66 +1,185 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
2
|
|
|
3
|
-
const fs = require(
|
|
4
|
-
const path = require(
|
|
3
|
+
const fs = require("node:fs");
|
|
4
|
+
const path = require("node:path");
|
|
5
5
|
|
|
6
|
-
const
|
|
7
|
-
const
|
|
6
|
+
const { wrapRunCodeTokens } = require("./visual-page-wrap");
|
|
7
|
+
const { applyNativeBrowserOverrides } = require("./runtime-config");
|
|
8
|
+
const { runUploadCommandWithGuard } = require("./automation-file-chooser-guard");
|
|
9
|
+
|
|
10
|
+
const INIT_SCRIPT_PATH = path.join(__dirname, "automation-overlay.init.js");
|
|
11
|
+
const INIT_PAGE_MAXIMIZE_PATH = path.join(
|
|
12
|
+
__dirname,
|
|
13
|
+
"browser-window-maximize.init-page.js",
|
|
14
|
+
);
|
|
15
|
+
const INIT_PAGE_CSS_GUARD_PATH = path.join(
|
|
16
|
+
__dirname,
|
|
17
|
+
"browser-css-cache-guard.init-page.js",
|
|
18
|
+
);
|
|
19
|
+
const GENERATED_CONFIG_PATH = path.join(
|
|
20
|
+
__dirname,
|
|
21
|
+
".cli.runtime.generated.json",
|
|
22
|
+
);
|
|
8
23
|
|
|
9
24
|
/** 默认开启页面内视觉反馈;HELIX_VISUAL=0 可全局关闭 */
|
|
10
|
-
const DEFAULT_VISUAL_ENABLED = process.env.HELIX_VISUAL !==
|
|
25
|
+
const DEFAULT_VISUAL_ENABLED = process.env.HELIX_VISUAL !== "0";
|
|
26
|
+
/** 反馈层常驻不消失;HELIX_VISUAL_PERSIST=1 或 --visual-persist */
|
|
27
|
+
const DEFAULT_VISUAL_PERSIST = process.env.HELIX_VISUAL_PERSIST === "1";
|
|
11
28
|
|
|
12
29
|
const VISUAL_COMMANDS = {
|
|
13
|
-
click: {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
30
|
+
click: {
|
|
31
|
+
pending: "正在点击",
|
|
32
|
+
success: "已点击",
|
|
33
|
+
pendingTone: "pending",
|
|
34
|
+
successTone: "success",
|
|
35
|
+
},
|
|
36
|
+
dblclick: {
|
|
37
|
+
pending: "正在双击",
|
|
38
|
+
success: "已双击",
|
|
39
|
+
pendingTone: "pending",
|
|
40
|
+
successTone: "success",
|
|
41
|
+
},
|
|
42
|
+
fill: {
|
|
43
|
+
pending: "正在填写",
|
|
44
|
+
success: "已填写",
|
|
45
|
+
pendingTone: "pending",
|
|
46
|
+
successTone: "success",
|
|
47
|
+
},
|
|
48
|
+
hover: {
|
|
49
|
+
pending: "正在悬停",
|
|
50
|
+
success: "已悬停",
|
|
51
|
+
pendingTone: "info",
|
|
52
|
+
successTone: "info",
|
|
53
|
+
},
|
|
54
|
+
check: {
|
|
55
|
+
pending: "正在勾选",
|
|
56
|
+
success: "已勾选",
|
|
57
|
+
pendingTone: "pending",
|
|
58
|
+
successTone: "success",
|
|
59
|
+
},
|
|
60
|
+
uncheck: {
|
|
61
|
+
pending: "正在取消勾选",
|
|
62
|
+
success: "已取消勾选",
|
|
63
|
+
pendingTone: "pending",
|
|
64
|
+
successTone: "info",
|
|
65
|
+
},
|
|
66
|
+
select: {
|
|
67
|
+
pending: "正在选择",
|
|
68
|
+
success: "已选择",
|
|
69
|
+
pendingTone: "pending",
|
|
70
|
+
successTone: "success",
|
|
71
|
+
},
|
|
72
|
+
drag: {
|
|
73
|
+
pending: "正在拖拽",
|
|
74
|
+
success: "已拖拽",
|
|
75
|
+
pendingTone: "pending",
|
|
76
|
+
successTone: "success",
|
|
77
|
+
},
|
|
78
|
+
drop: {
|
|
79
|
+
pending: "正在放置",
|
|
80
|
+
success: "已放置",
|
|
81
|
+
pendingTone: "pending",
|
|
82
|
+
successTone: "success",
|
|
83
|
+
},
|
|
84
|
+
upload: {
|
|
85
|
+
hudOnly: true,
|
|
86
|
+
pending: "正在上传",
|
|
87
|
+
success: "已上传",
|
|
88
|
+
pendingTone: "pending",
|
|
89
|
+
successTone: "success",
|
|
90
|
+
},
|
|
91
|
+
press: {
|
|
92
|
+
hudOnly: true,
|
|
93
|
+
pending: "按键",
|
|
94
|
+
success: "按键完成",
|
|
95
|
+
pendingTone: "info",
|
|
96
|
+
successTone: "success",
|
|
97
|
+
},
|
|
98
|
+
type: {
|
|
99
|
+
hudOnly: true,
|
|
100
|
+
pending: "正在输入",
|
|
101
|
+
success: "输入完成",
|
|
102
|
+
pendingTone: "pending",
|
|
103
|
+
successTone: "success",
|
|
104
|
+
},
|
|
105
|
+
"run-code": {
|
|
106
|
+
hudOnly: true,
|
|
107
|
+
pending: "脚本执行中",
|
|
108
|
+
success: "脚本完成",
|
|
109
|
+
pendingTone: "pending",
|
|
110
|
+
successTone: "success",
|
|
111
|
+
},
|
|
25
112
|
};
|
|
26
113
|
|
|
27
|
-
const SESSION_START_COMMANDS = new Set([
|
|
114
|
+
const SESSION_START_COMMANDS = new Set(["open", "attach"]);
|
|
28
115
|
|
|
29
116
|
function readInitScriptSource() {
|
|
30
|
-
return fs.readFileSync(INIT_SCRIPT_PATH,
|
|
117
|
+
return fs.readFileSync(INIT_SCRIPT_PATH, "utf8");
|
|
31
118
|
}
|
|
32
119
|
|
|
33
|
-
function
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
};
|
|
39
|
-
|
|
120
|
+
function isHeadedOpen(tokens) {
|
|
121
|
+
return tokens.some((t) => t === "--headed" || t.startsWith("--headed="));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function buildRuntimeBrowserConfig(visualEnabled, tokens) {
|
|
125
|
+
let browser = {};
|
|
126
|
+
const cmd = resolveCommandName(tokens);
|
|
127
|
+
if (cmd === "open" && isHeadedOpen(tokens)) {
|
|
128
|
+
browser.launchOptions = { args: ["--start-maximized"] };
|
|
129
|
+
browser.initPage = [
|
|
130
|
+
INIT_PAGE_MAXIMIZE_PATH.replace(/\\/g, "/"),
|
|
131
|
+
INIT_PAGE_CSS_GUARD_PATH.replace(/\\/g, "/"),
|
|
132
|
+
];
|
|
133
|
+
}
|
|
134
|
+
if (visualEnabled) {
|
|
135
|
+
browser.initScript = [INIT_SCRIPT_PATH.replace(/\\/g, "/")];
|
|
136
|
+
}
|
|
137
|
+
// 合并原生交互模式 overrides(acceptDownloads / chromiumSandbox / downloadsPath)。
|
|
138
|
+
// applyNativeBrowserOverrides 不会覆盖已显式设值的字段。
|
|
139
|
+
browser = applyNativeBrowserOverrides(browser);
|
|
140
|
+
return browser;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function resolveGeneratedConfigPath(
|
|
144
|
+
visualEnabled = DEFAULT_VISUAL_ENABLED,
|
|
145
|
+
tokens = [],
|
|
146
|
+
) {
|
|
147
|
+
const browser = buildRuntimeBrowserConfig(visualEnabled, tokens);
|
|
148
|
+
const payload = Object.keys(browser).length > 0 ? { browser } : {};
|
|
149
|
+
fs.writeFileSync(
|
|
150
|
+
GENERATED_CONFIG_PATH,
|
|
151
|
+
JSON.stringify(payload, null, 2),
|
|
152
|
+
"utf8",
|
|
153
|
+
);
|
|
40
154
|
return GENERATED_CONFIG_PATH;
|
|
41
155
|
}
|
|
42
156
|
|
|
43
157
|
/**
|
|
44
158
|
* 从 argv 中提取并剥离 --visual / --no-visual / --visual-ms。
|
|
45
|
-
* @returns {{ tokens: string[], visual: { enabled: boolean, durationMs: number | null } }}
|
|
159
|
+
* @returns {{ tokens: string[], visual: { enabled: boolean, durationMs: number | null, persist?: boolean } }}
|
|
46
160
|
*/
|
|
47
161
|
function parseVisualFlags(tokens) {
|
|
48
162
|
const visual = {
|
|
49
163
|
enabled: DEFAULT_VISUAL_ENABLED,
|
|
50
164
|
durationMs: null,
|
|
51
165
|
};
|
|
166
|
+
if (DEFAULT_VISUAL_PERSIST) visual.persist = true;
|
|
52
167
|
const out = [];
|
|
53
168
|
for (let i = 0; i < tokens.length; i += 1) {
|
|
54
169
|
const t = tokens[i];
|
|
55
|
-
if (t ===
|
|
170
|
+
if (t === "--visual") {
|
|
56
171
|
visual.enabled = true;
|
|
57
|
-
} else if (t ===
|
|
172
|
+
} else if (t === "--no-visual") {
|
|
58
173
|
visual.enabled = false;
|
|
59
|
-
} else if (t ===
|
|
174
|
+
} else if (t === "--visual-persist") {
|
|
175
|
+
visual.persist = true;
|
|
176
|
+
} else if (t === "--no-visual-persist") {
|
|
177
|
+
visual.persist = false;
|
|
178
|
+
} else if (t === "--visual-ms") {
|
|
60
179
|
visual.durationMs = tokens[i + 1];
|
|
61
180
|
i += 1;
|
|
62
|
-
} else if (t.startsWith(
|
|
63
|
-
visual.durationMs = t.slice(
|
|
181
|
+
} else if (t.startsWith("--visual-ms=")) {
|
|
182
|
+
visual.durationMs = t.slice("--visual-ms=".length);
|
|
64
183
|
} else {
|
|
65
184
|
out.push(t);
|
|
66
185
|
}
|
|
@@ -68,7 +187,12 @@ function parseVisualFlags(tokens) {
|
|
|
68
187
|
if (visual.durationMs != null) {
|
|
69
188
|
const n = Number(visual.durationMs);
|
|
70
189
|
if (!Number.isFinite(n) || n <= 0) {
|
|
71
|
-
throw Object.assign(
|
|
190
|
+
throw Object.assign(
|
|
191
|
+
new Error(
|
|
192
|
+
`--visual-ms 需要正数,收到 ${JSON.stringify(visual.durationMs)}`,
|
|
193
|
+
),
|
|
194
|
+
{ code: "E_BAD_ARG" },
|
|
195
|
+
);
|
|
72
196
|
}
|
|
73
197
|
visual.durationMs = Math.round(n);
|
|
74
198
|
}
|
|
@@ -76,36 +200,35 @@ function parseVisualFlags(tokens) {
|
|
|
76
200
|
}
|
|
77
201
|
|
|
78
202
|
function hasConfigFlag(tokens) {
|
|
79
|
-
return tokens.some((t) => t ===
|
|
203
|
+
return tokens.some((t) => t === "--config" || t.startsWith("--config="));
|
|
80
204
|
}
|
|
81
205
|
|
|
82
206
|
/**
|
|
83
|
-
* open / attach
|
|
207
|
+
* open / attach 时注入运行时配置:有头 open 最大化窗口;visual 开启时预装视觉层 initScript。
|
|
84
208
|
*/
|
|
85
209
|
function injectVisualConfig(tokens, visual) {
|
|
86
|
-
if (!visual.enabled) return tokens;
|
|
87
210
|
const cmd = resolveCommandName(tokens);
|
|
88
211
|
if (!SESSION_START_COMMANDS.has(cmd) || hasConfigFlag(tokens)) {
|
|
89
212
|
return tokens;
|
|
90
213
|
}
|
|
91
|
-
const configPath = resolveGeneratedConfigPath();
|
|
214
|
+
const configPath = resolveGeneratedConfigPath(visual.enabled, tokens);
|
|
92
215
|
return [...tokens, `--config=${configPath}`];
|
|
93
216
|
}
|
|
94
217
|
|
|
95
218
|
function resolveCommandName(tokens) {
|
|
96
219
|
let i = 0;
|
|
97
|
-
if (tokens[i] ===
|
|
98
|
-
if (tokens[i] ===
|
|
99
|
-
if (tokens[i] && tokens[i].startsWith(
|
|
100
|
-
return tokens[i] ||
|
|
220
|
+
if (tokens[i] === "--raw") i += 1;
|
|
221
|
+
if (tokens[i] === "--json") i += 1;
|
|
222
|
+
if (tokens[i] && tokens[i].startsWith("-s=")) i += 1;
|
|
223
|
+
return tokens[i] || "";
|
|
101
224
|
}
|
|
102
225
|
|
|
103
226
|
function isElementRef(token) {
|
|
104
|
-
if (!token || token.startsWith(
|
|
227
|
+
if (!token || token.startsWith("-")) return false;
|
|
105
228
|
if (/^e\d+$/.test(token)) return true;
|
|
106
229
|
if (token.startsWith('"') || token.startsWith("'")) return true;
|
|
107
|
-
if (token.startsWith(
|
|
108
|
-
if (token.startsWith(
|
|
230
|
+
if (token.startsWith("#") || token.startsWith(".")) return true;
|
|
231
|
+
if (token.startsWith("getBy")) return true;
|
|
109
232
|
return false;
|
|
110
233
|
}
|
|
111
234
|
|
|
@@ -119,29 +242,33 @@ function extractElementTarget(tokens) {
|
|
|
119
242
|
if (def.hudOnly) return null;
|
|
120
243
|
|
|
121
244
|
let i = 0;
|
|
122
|
-
if (tokens[i] ===
|
|
123
|
-
if (tokens[i] ===
|
|
124
|
-
if (tokens[i] && tokens[i].startsWith(
|
|
245
|
+
if (tokens[i] === "--raw") i += 1;
|
|
246
|
+
if (tokens[i] === "--json") i += 1;
|
|
247
|
+
if (tokens[i] && tokens[i].startsWith("-s=")) i += 1;
|
|
125
248
|
i += 1; // skip command name
|
|
126
249
|
|
|
127
250
|
const positional = [];
|
|
128
251
|
for (; i < tokens.length; i += 1) {
|
|
129
252
|
const t = tokens[i];
|
|
130
|
-
if (t.startsWith(
|
|
131
|
-
if (t.includes(
|
|
253
|
+
if (t.startsWith("--")) {
|
|
254
|
+
if (t.includes("=")) continue;
|
|
132
255
|
const next = tokens[i + 1];
|
|
133
|
-
if (next !== undefined && !next.startsWith(
|
|
256
|
+
if (next !== undefined && !next.startsWith("-")) i += 1;
|
|
134
257
|
continue;
|
|
135
258
|
}
|
|
136
259
|
positional.push(t);
|
|
137
260
|
}
|
|
138
261
|
|
|
139
|
-
if (cmd ===
|
|
140
|
-
if (cmd ===
|
|
141
|
-
if (cmd ===
|
|
142
|
-
if (cmd ===
|
|
143
|
-
if (positional.length >= 1 && isElementRef(positional[0]))
|
|
144
|
-
|
|
262
|
+
if (cmd === "drag" && positional.length >= 1) return positional[0];
|
|
263
|
+
if (cmd === "fill" && positional.length >= 1) return positional[0];
|
|
264
|
+
if (cmd === "select" && positional.length >= 1) return positional[0];
|
|
265
|
+
if (cmd === "drop" && positional.length >= 1) return positional[0];
|
|
266
|
+
if (positional.length >= 1 && isElementRef(positional[0]))
|
|
267
|
+
return positional[0];
|
|
268
|
+
if (
|
|
269
|
+
positional.length >= 2 &&
|
|
270
|
+
isElementRef(positional[positional.length - 1])
|
|
271
|
+
) {
|
|
145
272
|
return positional[positional.length - 1];
|
|
146
273
|
}
|
|
147
274
|
return null;
|
|
@@ -150,7 +277,7 @@ function extractElementTarget(tokens) {
|
|
|
150
277
|
function buildFlashEval(target, options) {
|
|
151
278
|
const optsLit = JSON.stringify(options);
|
|
152
279
|
return [
|
|
153
|
-
|
|
280
|
+
"eval",
|
|
154
281
|
`el => { const v = window.__helix_visual__; if (!v) return false; return v.flash(el, ${optsLit}); }`,
|
|
155
282
|
target,
|
|
156
283
|
];
|
|
@@ -158,24 +285,32 @@ function buildFlashEval(target, options) {
|
|
|
158
285
|
|
|
159
286
|
function buildHudEval(options) {
|
|
160
287
|
const optsLit = JSON.stringify(options);
|
|
161
|
-
return [
|
|
288
|
+
return [
|
|
289
|
+
"eval",
|
|
290
|
+
`() => { const v = window.__helix_visual__; if (!v) return false; return v.showHud(${optsLit}); }`,
|
|
291
|
+
];
|
|
162
292
|
}
|
|
163
293
|
|
|
164
294
|
function buildSetOptionsEval(visual) {
|
|
165
|
-
const payload =
|
|
295
|
+
const payload = {
|
|
166
296
|
enabled: visual.enabled,
|
|
167
297
|
durationMs: visual.durationMs,
|
|
168
|
-
}
|
|
169
|
-
|
|
298
|
+
};
|
|
299
|
+
if (typeof visual.persist === "boolean") payload.persist = visual.persist;
|
|
300
|
+
const payloadLit = JSON.stringify(payload);
|
|
301
|
+
return [
|
|
302
|
+
"eval",
|
|
303
|
+
`() => { const v = window.__helix_visual__; if (!v) return null; return v.setVisualOptions(${payloadLit}); }`,
|
|
304
|
+
];
|
|
170
305
|
}
|
|
171
306
|
|
|
172
307
|
function buildInstallEval() {
|
|
173
308
|
const src = readInitScriptSource();
|
|
174
|
-
return [
|
|
309
|
+
return ["eval", src];
|
|
175
310
|
}
|
|
176
311
|
|
|
177
312
|
function buildBridgeCheckEval() {
|
|
178
|
-
return [
|
|
313
|
+
return ["eval", "--raw", "Boolean(window.__helix_visual__)"];
|
|
179
314
|
}
|
|
180
315
|
|
|
181
316
|
function shouldWrapWithVisual(tokens, visual) {
|
|
@@ -193,56 +328,90 @@ function shouldWrapWithVisual(tokens, visual) {
|
|
|
193
328
|
async function runWithVisualFeedback(tokens, visual, runPassthrough) {
|
|
194
329
|
const cmd = resolveCommandName(tokens);
|
|
195
330
|
const def = VISUAL_COMMANDS[cmd];
|
|
196
|
-
const target = extractElementTarget(tokens);
|
|
197
331
|
|
|
198
332
|
const runCapture = (args) => runPassthrough(args, { capture: true });
|
|
199
333
|
|
|
200
334
|
const check = runCapture(buildBridgeCheckEval());
|
|
201
|
-
if (String(check.stdout ||
|
|
335
|
+
if (String(check.stdout || "").trim() !== "true") {
|
|
202
336
|
runCapture(buildInstallEval());
|
|
203
337
|
}
|
|
338
|
+
|
|
339
|
+
if (cmd === "run-code") {
|
|
340
|
+
runCapture(
|
|
341
|
+
buildSetOptionsEval({
|
|
342
|
+
enabled: visual.enabled,
|
|
343
|
+
durationMs: visual.durationMs,
|
|
344
|
+
}),
|
|
345
|
+
);
|
|
346
|
+
let wrappedTokens;
|
|
347
|
+
try {
|
|
348
|
+
wrappedTokens = wrapRunCodeTokens(tokens, readInitScriptSource());
|
|
349
|
+
} catch (e) {
|
|
350
|
+
console.error(`[helixlife-v5-cli] run-code 视觉包装失败: ${e.message}`);
|
|
351
|
+
return runPassthrough(tokens);
|
|
352
|
+
}
|
|
353
|
+
return runPassthrough(wrappedTokens);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
const target = extractElementTarget(tokens);
|
|
204
357
|
runCapture(buildSetOptionsEval(visual));
|
|
205
358
|
|
|
206
|
-
const hudBase = { action: cmd, target: target ||
|
|
359
|
+
const hudBase = { action: cmd, target: target || "", status: "pending" };
|
|
207
360
|
runCapture(buildHudEval({ ...hudBase, detail: def.pending }));
|
|
208
361
|
|
|
209
362
|
if (target) {
|
|
210
|
-
runCapture(
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
363
|
+
runCapture(
|
|
364
|
+
buildFlashEval(target, {
|
|
365
|
+
tone: def.pendingTone || "pending",
|
|
366
|
+
label: def.pending,
|
|
367
|
+
durationMs: visual.durationMs,
|
|
368
|
+
}),
|
|
369
|
+
);
|
|
215
370
|
}
|
|
216
371
|
|
|
217
|
-
const
|
|
372
|
+
const nativeFileChooser =
|
|
373
|
+
process.env.HELIX_NATIVE_FILE_CHOOSER === undefined ||
|
|
374
|
+
process.env.HELIX_NATIVE_FILE_CHOOSER === "1";
|
|
375
|
+
|
|
376
|
+
const code =
|
|
377
|
+
nativeFileChooser && (cmd === "upload" || cmd === "drop")
|
|
378
|
+
? runUploadCommandWithGuard(tokens, runPassthrough)
|
|
379
|
+
: runPassthrough(tokens);
|
|
218
380
|
|
|
219
|
-
const successTone = code === 0 ?
|
|
220
|
-
const successLabel = code === 0 ? def.success :
|
|
381
|
+
const successTone = code === 0 ? def.successTone || "success" : "danger";
|
|
382
|
+
const successLabel = code === 0 ? def.success : "错误";
|
|
221
383
|
runCapture(buildSetOptionsEval(visual));
|
|
222
384
|
if (target) {
|
|
223
|
-
runCapture(
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
385
|
+
runCapture(
|
|
386
|
+
buildFlashEval(target, {
|
|
387
|
+
tone: successTone,
|
|
388
|
+
label: successLabel,
|
|
389
|
+
durationMs: visual.durationMs,
|
|
390
|
+
}),
|
|
391
|
+
);
|
|
228
392
|
}
|
|
229
|
-
runCapture(
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
393
|
+
runCapture(
|
|
394
|
+
buildHudEval({
|
|
395
|
+
action: cmd,
|
|
396
|
+
target: target || "",
|
|
397
|
+
status: code === 0 ? "success" : "danger",
|
|
398
|
+
detail: successLabel,
|
|
399
|
+
}),
|
|
400
|
+
);
|
|
235
401
|
|
|
236
402
|
return code;
|
|
237
403
|
}
|
|
238
404
|
|
|
239
405
|
module.exports = {
|
|
240
406
|
INIT_SCRIPT_PATH,
|
|
407
|
+
INIT_PAGE_MAXIMIZE_PATH,
|
|
241
408
|
VISUAL_COMMANDS,
|
|
242
409
|
DEFAULT_VISUAL_ENABLED,
|
|
410
|
+
DEFAULT_VISUAL_PERSIST,
|
|
243
411
|
parseVisualFlags,
|
|
244
412
|
injectVisualConfig,
|
|
245
413
|
shouldWrapWithVisual,
|
|
246
414
|
runWithVisualFeedback,
|
|
415
|
+
resolveCommandName,
|
|
247
416
|
resolveGeneratedConfigPath,
|
|
248
417
|
};
|
package/package.json
CHANGED
|
@@ -1,34 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "helixlife-v5-cli",
|
|
3
|
-
"version": "1.2.
|
|
4
|
-
"description": "Helix
|
|
5
|
-
"main": "helix-cli.js",
|
|
3
|
+
"version": "1.2.9",
|
|
4
|
+
"description": "Helix site (vip.helixlife.cn) browser automation CLI",
|
|
6
5
|
"bin": {
|
|
7
6
|
"helixlife-v5-cli": "helix-cli.js"
|
|
8
7
|
},
|
|
8
|
+
"files": [
|
|
9
|
+
"helix-cli.js",
|
|
10
|
+
"lib/",
|
|
11
|
+
"scripts/"
|
|
12
|
+
],
|
|
9
13
|
"engines": {
|
|
10
14
|
"node": ">=18"
|
|
11
15
|
},
|
|
12
|
-
"keywords": [
|
|
13
|
-
"helixlife",
|
|
14
|
-
"cli",
|
|
15
|
-
"playwright",
|
|
16
|
-
"cdp"
|
|
17
|
-
],
|
|
18
|
-
"author": "",
|
|
19
|
-
"license": "ISC",
|
|
20
|
-
"type": "commonjs",
|
|
21
16
|
"scripts": {
|
|
22
|
-
"
|
|
17
|
+
"postinstall": "node lib/postinstall.js"
|
|
23
18
|
},
|
|
24
|
-
"files": [
|
|
25
|
-
"references",
|
|
26
|
-
"scripts",
|
|
27
|
-
"helix-cli.js",
|
|
28
|
-
"lib",
|
|
29
|
-
"README.md"
|
|
30
|
-
],
|
|
31
19
|
"dependencies": {
|
|
32
|
-
"@playwright/cli": "
|
|
20
|
+
"@playwright/cli": "0.1.14"
|
|
33
21
|
}
|
|
34
22
|
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Helix 可复用 `run-code` 脚本目录
|
|
2
|
+
|
|
3
|
+
> 均通过 `helixlife-v5-cli run-code --filename="<CLI_PKG_ROOT>/scripts/<模块>/<脚本>"` 调用。
|
|
4
|
+
> `<CLI_PKG_ROOT>` 为全局安装的 npm 包根目录(见 Skill 仓库 `SKILL.md` 路径解析)。
|
|
5
|
+
|
|
6
|
+
**Agent 选用规则**:勿扫描本目录猜脚本。先 `Read` Skill 仓库 `references/vip.helixlife.cn.site-ops.md` → 定向读目标模块 `references/*.md` → 按模块文档内的脚本表调用;本文件仅为总索引。
|
|
7
|
+
|
|
8
|
+
## 目录结构
|
|
9
|
+
|
|
10
|
+
| 目录 | 对应 references 模块 | 说明 |
|
|
11
|
+
| --- | --- | --- |
|
|
12
|
+
| [`common/`](./common/) | `vip.helixlife.cn.common.md` | 跨模块通用脚本(当前为空,预留) |
|
|
13
|
+
| [`edu/`](./edu/) | `vip.helixlife.cn.edu.md` | 学习中心 · 课件 PDF、搜索卡片 hover |
|
|
14
|
+
| [`analysis/`](./analysis/) | `analysis/browser.md` | 数据分析 · 浏览器通道:工具详情上传、拼图工具(后台 CLI 见 `references/analysis/backend-cli.md`) |
|
|
15
|
+
| [`workbench/jova/`](./workbench/jova/) | `workbench/jova/MODULE.md` | 综述工作台全流程 |
|
|
16
|
+
|
|
17
|
+
## 脚本清单
|
|
18
|
+
|
|
19
|
+
### `common/`
|
|
20
|
+
|
|
21
|
+
(暂无)
|
|
22
|
+
|
|
23
|
+
### `edu/`
|
|
24
|
+
|
|
25
|
+
| 脚本 | 作用 |
|
|
26
|
+
| --- | --- |
|
|
27
|
+
| `chrome-pdf-goto-page.js` | PDF 页码跳转(改 `target`) |
|
|
28
|
+
| `chrome-pdf-zoom-out.js` | PDF 缩小 |
|
|
29
|
+
| `chrome-pdf-enumerate-a11y.js` | 枚举 PDF 阅读器 `aria-label`(排障) |
|
|
30
|
+
| `hover-partial-chapter-match.js` | 搜索结果「部分章节匹配」hover |
|
|
31
|
+
|
|
32
|
+
### `analysis/`(仅浏览器通道 · 后台 CLI 勿用)
|
|
33
|
+
|
|
34
|
+
> 细则见 `references/analysis/browser.md`。后台 `xt` 任务见 `references/analysis/backend-cli.md`,**禁止**调用本目录脚本。
|
|
35
|
+
|
|
36
|
+
| 脚本 | 作用 |
|
|
37
|
+
| --- | --- |
|
|
38
|
+
| `detail-upload-file.js` | 工具详情 · 单参数上传(filechooser) |
|
|
39
|
+
| `detail-upload-both.js` | 工具详情 · 多参数顺序上传(setInputFiles) |
|
|
40
|
+
| `jigsaw-verify-drag-tool.js` | 拼图 · 拖图并验收下载解禁 |
|
|
41
|
+
| `jigsaw-verify-enumerate.js` | 拼图 · ABC 字段枚举 |
|
|
42
|
+
| `jigsaw-verify-reference-lines.js` | 拼图 · 参考线操作 |
|
|
43
|
+
| `jigsaw-verify-bio-tools.js` | 拼图 · 生信工具枚举 |
|
|
44
|
+
| `jigsaw-inspect-dom.js` | 拼图 · DOM 排障 |
|
|
45
|
+
|
|
46
|
+
### `workbench/jova/`
|
|
47
|
+
|
|
48
|
+
| 脚本 | 作用 |
|
|
49
|
+
| --- | --- |
|
|
50
|
+
| `outline-ops.js` | 提纲树标准操作(含节点重新生成,CONFIG) |
|
|
51
|
+
| `outline-edit-root-title.js` | 编辑根标题 |
|
|
52
|
+
| `outline-keyword-edit.js` | 关键词编辑 |
|
|
53
|
+
| `outline-probe-hover.js` | 节点 hover 探测(排障) |
|
|
54
|
+
| `proofread-ops.js` | 校对页标准操作(含单段确认校对,CONFIG) |
|
|
55
|
+
| `proofread-ai-rewrite-section.js` | 单段 AI 改写 / 段落重写面板 |
|
|
56
|
+
| `writing-ops.js` | 精修页标准操作(含右侧功能面板,CONFIG) |
|
|
57
|
+
| `writing-proofread-abstract.js` | 摘要段校对/精修 |
|
|
58
|
+
|
|
59
|
+
完整说明见 [`references/workbench/jova/MODULE.md`](../references/workbench/jova/MODULE.md) 末尾表格。
|
|
60
|
+
|
|
61
|
+
#### 计划提供(`workbench/jova/` · 暂未落地)
|
|
62
|
+
|
|
63
|
+
| 计划脚本 | 作用 | 当前临时替代 |
|
|
64
|
+
| --- | --- | --- |
|
|
65
|
+
| `outline-regenerate-node.js` | 节点级「重新生成」 | `outline-ops.js` CONFIG |
|
|
66
|
+
| `proofread-section.js` | 单段确认校对 | `proofread-ops.js` CONFIG |
|
|
67
|
+
| `writing-tool.js` | 右侧功能面板单脚本 | `writing-ops.js` CONFIG |
|
|
68
|
+
|
|
69
|
+
磁盘暂无上述文件,**勿调用**;落地后移入上表「已提供」并删本小节。
|
|
70
|
+
|
|
71
|
+
## 维护者专用(Agent 勿用)
|
|
72
|
+
|
|
73
|
+
| 路径 | 说明 |
|
|
74
|
+
| --- | --- |
|
|
75
|
+
| `maintainer/strip-extra-skills.ps1` | 打包时剔除 `node_modules` 内多余 `SKILL.md`,非站点自动化 |
|
|
76
|
+
|
|
77
|
+
## 扩展约定
|
|
78
|
+
|
|
79
|
+
- 新增脚本放入对应模块目录;跨模块复用放 `common/`。
|
|
80
|
+
- AI 工作台其他子工作台(sci / nsfc / clinical)后续脚本放 `workbench/<slug>/`。
|
|
81
|
+
- 文件名去掉模块前缀(目录已表达归属),例如 `outline-ops.js` 而非 `workbench-jova-outline-ops.js`。
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* 3) 弹窗内 button「确认」
|
|
7
7
|
*
|
|
8
8
|
* 修改 filePath / paramLabel 后执行:
|
|
9
|
-
* helixlife-v5-cli run-code --filename=scripts/analysis
|
|
9
|
+
* helixlife-v5-cli run-code --filename=scripts/analysis/detail-upload-file.js
|
|
10
10
|
*/
|
|
11
11
|
async page => {
|
|
12
12
|
const filePath = 'C:/Users/zouyh/Desktop/helix-test-upload.csv';
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
async page => {
|
|
2
|
-
return page.evaluate(() => {
|
|
3
|
-
const root = document.querySelector('.jigsaw');
|
|
4
|
-
if (!root) return null;
|
|
5
|
-
const walk = (el, depth = 0) => {
|
|
6
|
-
if (depth > 4) return null;
|
|
7
|
-
return {
|
|
8
|
-
tag: el.tagName,
|
|
9
|
-
cls: (el.className || '').toString().slice(0, 80),
|
|
10
|
-
ch: [...el.children].slice(0, 8).map(c => walk(c, depth + 1)),
|
|
11
|
-
};
|
|
12
|
-
};
|
|
13
|
-
return [...root.children].map(c => walk(c, 0));
|
|
14
|
-
});
|
|
15
|
-
}
|
|
1
|
+
async page => {
|
|
2
|
+
return page.evaluate(() => {
|
|
3
|
+
const root = document.querySelector('.jigsaw');
|
|
4
|
+
if (!root) return null;
|
|
5
|
+
const walk = (el, depth = 0) => {
|
|
6
|
+
if (depth > 4) return null;
|
|
7
|
+
return {
|
|
8
|
+
tag: el.tagName,
|
|
9
|
+
cls: (el.className || '').toString().slice(0, 80),
|
|
10
|
+
ch: [...el.children].slice(0, 8).map(c => walk(c, depth + 1)),
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
return [...root.children].map(c => walk(c, 0));
|
|
14
|
+
});
|
|
15
|
+
}
|
|
File without changes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 枚举当前 PDF 阅读器帧内带 aria-label 的节点(排障 / 对照 site-ops 控件表)。
|
|
3
|
-
* 运行:helixlife-v5-cli run-code --filename=scripts/chrome-pdf-enumerate-a11y.js
|
|
3
|
+
* 运行:helixlife-v5-cli run-code --filename=scripts/edu/chrome-pdf-enumerate-a11y.js
|
|
4
4
|
*/
|
|
5
5
|
async page => {
|
|
6
6
|
const PDF_VIEWER_PREFIX = 'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai';
|