@cloud411716/fancy-webnovel 0.1.82 → 0.1.84
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/infra.js +48 -5
- package/package.json +1 -1
- package/plugins/fancy-scan/index.js +9 -2
package/infra.js
CHANGED
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
* 提供:
|
|
5
5
|
* notify(session, text) — 打印消息给用户(不触发 LLM)
|
|
6
6
|
* llmFollowup(invocation, prompt) — 发送消息给 LLM,让 LLM 继续处理
|
|
7
|
-
* spawnScript(cmd, args, opts) — spawn 子进程,解析 stdout JSON
|
|
8
7
|
* startActivity(session) — 开始 Activity Line 计时,返回 stop 函数
|
|
8
|
+
* onUserCancel(session, onCancel) — 监听 CTRL+C / ESC 取消信号,返回 stop 函数
|
|
9
|
+
* spawnScript(cmd, args, opts) — spawn 子进程,解析 stdout JSON
|
|
9
10
|
*
|
|
10
11
|
* 所有 fancy-* 插件均直接 import 此文件。
|
|
11
12
|
*/
|
|
@@ -41,15 +42,57 @@ export function llmFollowup(invocation, content) {
|
|
|
41
42
|
// 调用 startActivity() 返回 stop 函数,进入新阶段时先 stop 再 start
|
|
42
43
|
// --------------------------------------------------------------------------
|
|
43
44
|
|
|
44
|
-
/**
|
|
45
|
-
* @param {import('@deepseek-ai/dsh-session').Session} session
|
|
46
|
-
* @returns {() => void} stop — 调用后停止计时
|
|
47
|
-
*/
|
|
48
45
|
export function startActivity(session) {
|
|
49
46
|
session.append('turn/start', { source: 'fancy-plugin' });
|
|
50
47
|
return () => session.append('turn/end', { source: 'fancy-plugin' });
|
|
51
48
|
}
|
|
52
49
|
|
|
50
|
+
// --------------------------------------------------------------------------
|
|
51
|
+
// onUserCancel — 监听用户按 CTRL+C 或 ESC 取消信号
|
|
52
|
+
//
|
|
53
|
+
// 调用时传入 session + onCancel 回调(清理函数,如 kill 子进程、停止计时等)
|
|
54
|
+
// 返回 stop 函数(调用以移除监听器,流程正常结束时调用)
|
|
55
|
+
// 注意:不在弹窗场景下使用(弹窗自身有取消逻辑)
|
|
56
|
+
// --------------------------------------------------------------------------
|
|
57
|
+
const _cancelHandlers = new Map(); // session → { stopFn, onCancel }
|
|
58
|
+
|
|
59
|
+
export function onUserCancel(session, onCancel) {
|
|
60
|
+
if (_cancelHandlers.has(session)) {
|
|
61
|
+
const existing = _cancelHandlers.get(session);
|
|
62
|
+
const orig = existing.onCancel;
|
|
63
|
+
existing.onCancel = () => { orig?.(); onCancel?.(); };
|
|
64
|
+
return existing.stopFn;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
let cancelled = false;
|
|
68
|
+
|
|
69
|
+
const handler = () => {
|
|
70
|
+
if (cancelled) return;
|
|
71
|
+
cancelled = true;
|
|
72
|
+
for (const fn of stopFns) { try { fn(); } catch (_) {} }
|
|
73
|
+
cleanup();
|
|
74
|
+
notify(session, '🚫 操作已取消。');
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const cleanup = () => {
|
|
78
|
+
process.removeListener('SIGINT', handler);
|
|
79
|
+
_cancelHandlers.delete(session);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const stopFns = [onCancel].filter(Boolean);
|
|
83
|
+
process.on('SIGINT', handler);
|
|
84
|
+
|
|
85
|
+
const stopFn = () => {
|
|
86
|
+
if (!cancelled) {
|
|
87
|
+
for (const fn of stopFns) { try { fn(); } catch (_) {} }
|
|
88
|
+
cleanup();
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
_cancelHandlers.set(session, { stopFn });
|
|
93
|
+
return stopFn;
|
|
94
|
+
}
|
|
95
|
+
|
|
53
96
|
// --------------------------------------------------------------------------
|
|
54
97
|
// spawnScript — spawn 子进程,stdout 只收集 JSON,stderr 单独收集
|
|
55
98
|
// opts.stop() 会在进程终止时自动调用(用于清理 turn/start)
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { fileURLToPath } from 'url';
|
|
5
5
|
import { dirname, join } from 'path';
|
|
6
6
|
import { existsSync } from 'fs';
|
|
7
|
-
import { notify, llmFollowup, spawnScript, startActivity } from '../../infra.js';
|
|
7
|
+
import { notify, llmFollowup, spawnScript, startActivity, onUserCancel } from '../../infra.js';
|
|
8
8
|
import { scan, PLATFORM_TABLE, platformLabel } from './templates.js';
|
|
9
9
|
|
|
10
10
|
export const inject = ['commands', 'userQuestions'];
|
|
@@ -162,15 +162,22 @@ async function runScanWithChromiumFix(ctx, session, invocation, { platform, leng
|
|
|
162
162
|
notify(session, '⏳ 正在下载 Chromium 浏览器(首次约 2-3 分钟),请耐心等待...\n');
|
|
163
163
|
const installStop = startActivity(session);
|
|
164
164
|
|
|
165
|
-
const installProc = spawn('npx', ['playwright', 'install', 'chromium'], {
|
|
165
|
+
const installProc = spawn('npx', ['playwright', 'install', 'chromium', '--registry', 'https://registry.npmmirror.com'], {
|
|
166
166
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
167
167
|
});
|
|
168
168
|
const installOut = [];
|
|
169
169
|
installProc.stdout.on('data', d => { installOut.push(d.toString()); });
|
|
170
170
|
installProc.stderr.on('data', d => { installOut.push(d.toString()); });
|
|
171
171
|
|
|
172
|
+
// 注册 CTRL+C 取消处理:kill 安装进程
|
|
173
|
+
const stopCancel = onUserCancel(session, () => {
|
|
174
|
+
installProc.kill('SIGTERM');
|
|
175
|
+
installStop();
|
|
176
|
+
});
|
|
177
|
+
|
|
172
178
|
return new Promise((resolve) => {
|
|
173
179
|
installProc.on('close', async (code) => {
|
|
180
|
+
stopCancel(); // 移除取消监听
|
|
174
181
|
installStop();
|
|
175
182
|
if (code === 0) {
|
|
176
183
|
notify(session, '✅ Chromium 安装完成,正在重新采集...\n');
|