napcat-plugin-debug-cli 1.2.6 → 1.2.8

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 (3) hide show
  1. package/cli.mjs +59 -25
  2. package/package.json +1 -1
  3. package/vite.mjs +72 -22
package/cli.mjs CHANGED
@@ -5141,7 +5141,7 @@ class RpcClient {
5141
5141
  this.pending.delete(id);
5142
5142
  reject(new Error("RPC timeout"));
5143
5143
  }
5144
- }, 1e4);
5144
+ }, 3e4);
5145
5145
  });
5146
5146
  }
5147
5147
  }
@@ -5251,6 +5251,23 @@ function copyDirRecursive(src, dest) {
5251
5251
  else fs.copyFileSync(srcPath, destPath);
5252
5252
  }
5253
5253
  }
5254
+ function collectFiles(dir, prefix = "") {
5255
+ const files = [];
5256
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
5257
+ const relPath = prefix ? `${prefix}/${entry.name}` : entry.name;
5258
+ const fullPath = path.join(dir, entry.name);
5259
+ if (entry.isDirectory()) {
5260
+ files.push(...collectFiles(fullPath, relPath));
5261
+ } else {
5262
+ files.push({
5263
+ path: relPath,
5264
+ content: fs.readFileSync(fullPath).toString("base64"),
5265
+ encoding: "base64"
5266
+ });
5267
+ }
5268
+ }
5269
+ return files;
5270
+ }
5254
5271
  function countFiles(dir) {
5255
5272
  let count = 0;
5256
5273
  for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
@@ -5259,7 +5276,7 @@ function countFiles(dir) {
5259
5276
  }
5260
5277
  return count;
5261
5278
  }
5262
- async function deployPlugin(projectDir, remotePluginPath, rpc) {
5279
+ async function deployPlugin(projectDir, remotePluginPath, rpc, supportsRemoteTransfer) {
5263
5280
  const distDir = path.resolve(projectDir, "dist");
5264
5281
  if (!fs.existsSync(distDir)) {
5265
5282
  logErr(`dist/ 目录不存在: ${distDir}`);
@@ -5283,34 +5300,44 @@ async function deployPlugin(projectDir, remotePluginPath, rpc) {
5283
5300
  logErr(`解析 dist/package.json 失败: ${e.message}`);
5284
5301
  return false;
5285
5302
  }
5286
- const destDir = path.join(remotePluginPath, pluginName);
5287
- logInfo(`部署 ${co(pluginName, C.bold, C.cyan)} → ${co(destDir, C.dim)}`);
5303
+ logInfo(`部署 ${co(pluginName, C.bold, C.cyan)} → 远程插件目录`);
5288
5304
  try {
5289
- if (fs.existsSync(destDir)) {
5290
- fs.rmSync(destDir, { recursive: true, force: true });
5305
+ if (supportsRemoteTransfer) {
5306
+ await rpc.call("removeDir", pluginName);
5307
+ const files = collectFiles(distDir, pluginName);
5308
+ await rpc.call("writeFiles", files);
5309
+ } else {
5310
+ const destPath = path.join(remotePluginPath, pluginName);
5311
+ if (fs.existsSync(destPath)) {
5312
+ fs.rmSync(destPath, { recursive: true, force: true });
5313
+ }
5314
+ copyDirRecursive(distDir, destPath);
5291
5315
  }
5292
- copyDirRecursive(distDir, destDir);
5293
- logOk(`文件复制完成 (${countFiles(distDir)} 个文件)`);
5316
+ logOk(`文件部署完成 (${countFiles(distDir)} 个文件)`);
5294
5317
  } catch (e) {
5295
- logErr(`复制文件失败: ${e.message}`);
5318
+ logErr(`部署失败: ${e.message}`);
5296
5319
  return false;
5297
5320
  }
5298
5321
  try {
5299
- await rpc.call("reloadPlugin", pluginName);
5300
- logOk(`${co(pluginName, C.green, C.bold)} 重载成功`);
5301
- } catch {
5302
- try {
5303
- logInfo("插件未注册,尝试从目录加载...");
5304
- await rpc.call("loadDirectoryPlugin", pluginName);
5322
+ const ok = await rpc.call("reloadPlugin", pluginName);
5323
+ if (ok) {
5324
+ logOk(`${co(pluginName, C.green, C.bold)} 重载成功`);
5325
+ } else {
5326
+ logInfo("插件未注册或重载失败,尝试从目录加载...");
5305
5327
  try {
5306
- await rpc.call("setPluginStatus", pluginName, true);
5307
- await rpc.call("loadPluginById", pluginName);
5308
- } catch {
5328
+ await rpc.call("loadDirectoryPlugin", pluginName);
5329
+ try {
5330
+ await rpc.call("setPluginStatus", pluginName, true);
5331
+ await rpc.call("loadPluginById", pluginName);
5332
+ } catch {
5333
+ }
5334
+ logOk(`${co(pluginName, C.green, C.bold)} 首次加载成功`);
5335
+ } catch (e2) {
5336
+ logWarn(`自动加载失败: ${e2.message},请手动 load ${pluginName}`);
5309
5337
  }
5310
- logOk(`${co(pluginName, C.green, C.bold)} 首次加载成功`);
5311
- } catch (e2) {
5312
- logWarn(`自动加载失败: ${e2.message},请手动 load ${pluginName}`);
5313
5338
  }
5339
+ } catch (e) {
5340
+ logErr(`重载失败: ${e.message}`);
5314
5341
  }
5315
5342
  return true;
5316
5343
  }
@@ -5329,6 +5356,7 @@ async function main() {
5329
5356
  let rpc = null;
5330
5357
  let watcher = null;
5331
5358
  let remotePluginPath = null;
5359
+ let supportsRemoteTransfer = false;
5332
5360
  const dirToId = /* @__PURE__ */ new Map();
5333
5361
  async function refreshMap() {
5334
5362
  if (!rpc) return;
@@ -5366,8 +5394,14 @@ async function main() {
5366
5394
  } catch (e) {
5367
5395
  logWarn(`获取信息失败: ${e.message}`);
5368
5396
  }
5397
+ try {
5398
+ await rpc.call("removeDir", "__probe_nonexistent__");
5399
+ supportsRemoteTransfer = true;
5400
+ } catch {
5401
+ supportsRemoteTransfer = false;
5402
+ }
5369
5403
  if (opts.deploy && remotePluginPath && rpc) {
5370
- const ok = await deployPlugin(path.resolve(opts.deploy), remotePluginPath, rpc);
5404
+ const ok = await deployPlugin(path.resolve(opts.deploy), remotePluginPath, rpc, supportsRemoteTransfer);
5371
5405
  ws.close(1e3);
5372
5406
  process.exit(ok ? 0 : 1);
5373
5407
  }
@@ -5378,7 +5412,7 @@ async function main() {
5378
5412
  watcher = createWatcher(remotePluginPath, onFileChange);
5379
5413
  watcher.start();
5380
5414
  }
5381
- startRepl(rpc, watcher, remotePluginPath, onFileChange);
5415
+ startRepl(rpc, watcher, remotePluginPath, onFileChange, supportsRemoteTransfer);
5382
5416
  }
5383
5417
  if (msg.method === "event" && opts.verbose) {
5384
5418
  logInfo(`事件: ${JSON.stringify(msg.params).substring(0, 100)}`);
@@ -5399,7 +5433,7 @@ async function main() {
5399
5433
  process.exit(0);
5400
5434
  });
5401
5435
  }
5402
- function startRepl(rpc, watcher, remotePath, onFileChange) {
5436
+ function startRepl(rpc, watcher, remotePath, onFileChange, supportsRemoteTransfer) {
5403
5437
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout, prompt: co("debug> ", C.cyan) });
5404
5438
  rl.prompt();
5405
5439
  rl.on("line", async (line) => {
@@ -5484,7 +5518,7 @@ function startRepl(rpc, watcher, remotePath, onFileChange) {
5484
5518
  break;
5485
5519
  }
5486
5520
  const dir = args[0] || ".";
5487
- await deployPlugin(path.resolve(dir), remotePath, rpc);
5521
+ await deployPlugin(path.resolve(dir), remotePath, rpc, supportsRemoteTransfer);
5488
5522
  break;
5489
5523
  }
5490
5524
  case "watch": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "napcat-plugin-debug-cli",
3
- "version": "1.2.6",
3
+ "version": "1.2.8",
4
4
  "type": "module",
5
5
  "description": "NapCat 插件调试 CLI — 连接调试服务实现热重载",
6
6
  "author": "NapNeko",
package/vite.mjs CHANGED
@@ -52,7 +52,7 @@ class SimpleRpcClient {
52
52
  this.pending.delete(id);
53
53
  reject(new Error("RPC timeout"));
54
54
  }
55
- }, 1e4);
55
+ }, 3e4);
56
56
  });
57
57
  }
58
58
  get connected() {
@@ -82,6 +82,23 @@ function countFiles(dir) {
82
82
  }
83
83
  return count;
84
84
  }
85
+ function collectFiles(dir, prefix = "") {
86
+ const files = [];
87
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
88
+ const relPath = prefix ? `${prefix}/${entry.name}` : entry.name;
89
+ const fullPath = path.join(dir, entry.name);
90
+ if (entry.isDirectory()) {
91
+ files.push(...collectFiles(fullPath, relPath));
92
+ } else {
93
+ files.push({
94
+ path: relPath,
95
+ content: fs.readFileSync(fullPath).toString("base64"),
96
+ encoding: "base64"
97
+ });
98
+ }
99
+ }
100
+ return files;
101
+ }
85
102
  function napcatHmrPlugin(options = {}) {
86
103
  const {
87
104
  wsUrl = "ws://127.0.0.1:8998",
@@ -93,6 +110,7 @@ function napcatHmrPlugin(options = {}) {
93
110
  const webuiConfigs = webui ? Array.isArray(webui) ? webui : [webui] : [];
94
111
  let rpc = null;
95
112
  let remotePluginPath = null;
113
+ let supportsRemoteTransfer = false;
96
114
  let connecting = false;
97
115
  let config;
98
116
  let isFirstBuild = true;
@@ -134,6 +152,12 @@ function napcatHmrPlugin(options = {}) {
134
152
  log(`远程插件目录: ${co(info.pluginPath, C.dim)}`);
135
153
  } catch {
136
154
  }
155
+ try {
156
+ await rpc.call("removeDir", "__probe_nonexistent__");
157
+ supportsRemoteTransfer = true;
158
+ } catch {
159
+ supportsRemoteTransfer = false;
160
+ }
137
161
  connecting = false;
138
162
  resolve(true);
139
163
  }
@@ -148,6 +172,7 @@ function napcatHmrPlugin(options = {}) {
148
172
  ws.on("close", () => {
149
173
  rpc = null;
150
174
  remotePluginPath = null;
175
+ supportsRemoteTransfer = false;
151
176
  connecting = false;
152
177
  });
153
178
  });
@@ -178,15 +203,31 @@ function napcatHmrPlugin(options = {}) {
178
203
  logErr("解析 dist/package.json 失败");
179
204
  return;
180
205
  }
181
- const destDir = path.join(remotePluginPath, pluginName);
182
- try {
183
- if (fs.existsSync(destDir)) {
184
- fs.rmSync(destDir, { recursive: true, force: true });
206
+ if (supportsRemoteTransfer) {
207
+ try {
208
+ await rpc.call("removeDir", pluginName);
209
+ } catch (e) {
210
+ logErr(`清理远程目录失败: ${e.message}`);
211
+ return;
212
+ }
213
+ try {
214
+ const files = collectFiles(distDir, pluginName);
215
+ await rpc.call("writeFiles", files);
216
+ } catch (e) {
217
+ logErr(`传输文件失败: ${e.message}`);
218
+ return;
219
+ }
220
+ } else {
221
+ const destDir = path.join(remotePluginPath, pluginName);
222
+ try {
223
+ if (fs.existsSync(destDir)) {
224
+ fs.rmSync(destDir, { recursive: true, force: true });
225
+ }
226
+ copyDirRecursive(distDir, destDir);
227
+ } catch (e) {
228
+ logErr(`复制文件失败: ${e.message}`);
229
+ return;
185
230
  }
186
- copyDirRecursive(distDir, destDir);
187
- } catch (e) {
188
- logErr(`复制文件失败: ${e.message}`);
189
- return;
190
231
  }
191
232
  const projectRoot = config.root || process.cwd();
192
233
  for (const wc of webuiConfigs) {
@@ -214,20 +255,23 @@ function napcatHmrPlugin(options = {}) {
214
255
  continue;
215
256
  }
216
257
  try {
217
- const webuiDestDir = path.join(destDir, webuiTargetDir);
218
- copyDirRecursive(webuiDistDir, webuiDestDir);
258
+ if (supportsRemoteTransfer) {
259
+ const webuiFiles = collectFiles(webuiDistDir, `${pluginName}/${webuiTargetDir}`);
260
+ await rpc.call("writeFiles", webuiFiles);
261
+ } else {
262
+ const destDir = path.join(remotePluginPath, pluginName);
263
+ const webuiDestDir = path.join(destDir, webuiTargetDir);
264
+ copyDirRecursive(webuiDistDir, webuiDestDir);
265
+ }
219
266
  logOk(`WebUI (${webuiTargetDir}) 已部署 (${countFiles(webuiDistDir)} 个文件)`);
220
267
  } catch (e) {
221
268
  logErr(`WebUI (${webuiTargetDir}) 部署失败: ${e.message}`);
222
269
  }
223
270
  }
224
- try {
225
- const reloaded = await rpc.call("reloadPlugin", pluginName);
226
- if (reloaded === false) {
227
- throw new Error("not registered");
228
- }
271
+ const reloaded = await rpc.call("reloadPlugin", pluginName);
272
+ if (reloaded) {
229
273
  logHmr(`${co(pluginName, C.green, C.bold)} 已重载 (${countFiles(distDir)} 个文件)`);
230
- } catch {
274
+ } else {
231
275
  try {
232
276
  await rpc.call("loadDirectoryPlugin", pluginName);
233
277
  try {
@@ -260,7 +304,6 @@ function napcatHmrPlugin(options = {}) {
260
304
  } catch {
261
305
  return;
262
306
  }
263
- const destDir = path.join(remotePluginPath, pluginName);
264
307
  const projectRoot = config.root || process.cwd();
265
308
  let hasChanges = false;
266
309
  for (const wc of webuiConfigs) {
@@ -288,11 +331,18 @@ function napcatHmrPlugin(options = {}) {
288
331
  continue;
289
332
  }
290
333
  try {
291
- const webuiDestDir = path.join(destDir, webuiTargetDir);
292
- if (fs.existsSync(webuiDestDir)) {
293
- fs.rmSync(webuiDestDir, { recursive: true, force: true });
334
+ if (supportsRemoteTransfer) {
335
+ await rpc.call("removeDir", `${pluginName}/${webuiTargetDir}`);
336
+ const webuiFiles = collectFiles(webuiDistDir, `${pluginName}/${webuiTargetDir}`);
337
+ await rpc.call("writeFiles", webuiFiles);
338
+ } else {
339
+ const destDir = path.join(remotePluginPath, pluginName);
340
+ const webuiDestDir = path.join(destDir, webuiTargetDir);
341
+ if (fs.existsSync(webuiDestDir)) {
342
+ fs.rmSync(webuiDestDir, { recursive: true, force: true });
343
+ }
344
+ copyDirRecursive(webuiDistDir, webuiDestDir);
294
345
  }
295
- copyDirRecursive(webuiDistDir, webuiDestDir);
296
346
  logOk(`WebUI (${webuiTargetDir}) 已部署 (${countFiles(webuiDistDir)} 个文件)`);
297
347
  hasChanges = true;
298
348
  } catch (e) {