tt-help-cli-ycl 1.4.158 → 1.4.159

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tt-help-cli-ycl",
3
- "version": "1.4.158",
3
+ "version": "1.4.159",
4
4
  "description": "TikTok user & video data scraper - extract ttSeller, verified, locationCreated from HTML source",
5
5
  "type": "module",
6
6
  "bin": {
@@ -342,6 +342,12 @@ export class ClashDaemon {
342
342
  error: "等待控制端就绪",
343
343
  meta: this._buildMeta(null),
344
344
  });
345
+ // 等待期也消费订阅命令:setSubscription 不依赖控制器上下文,应用成功即落盘,
346
+ // 下轮重试 readStoredSubscriptions 即可拉起实例 → 解除"无订阅↔无控制端"死锁
347
+ // (全新机器首次后台配置订阅的场景:没有它,命令永远无人消费)
348
+ try {
349
+ await this._pollCommands({ subscriptionOnly: true });
350
+ } catch {}
345
351
  this._running = false;
346
352
  this._waitTimer = setTimeout(() => this.start(), 10_000);
347
353
  return;
@@ -836,18 +842,31 @@ export class ClashDaemon {
836
842
 
837
843
  // ── 命令轮询(多通道:默认通道 + 每端口通道) ──
838
844
 
839
- _pollCommands() {
845
+ /**
846
+ * 命令轮询消费
847
+ * @param {object} [opts]
848
+ * @param {boolean} [opts.subscriptionOnly] 等待控制端就绪期:只消费不依赖控制器上下文的命令
849
+ * (setSubscription),其余保留在通道内待就绪后处理,避免丢失
850
+ */
851
+ _pollCommands({ subscriptionOnly = false } = {}) {
840
852
  if (!this._running) return;
841
- this._withLock(async () => {
853
+ return this._withLock(async () => {
842
854
  for (const ch of ipc.listCommandChannels()) {
843
855
  let cmds = null;
844
856
  try {
845
857
  cmds = ipc.readCommand(ch);
846
858
  } catch {}
847
859
  if (!cmds) continue;
860
+ const kept = [];
848
861
  for (const cmd of cmds) {
849
862
  const target = this._routeController(cmd);
850
- this._useController(target);
863
+ // 无控制端(等待就绪期/命令目标缺失)时,仅 setSubscription 可脱离控制器上下文执行,
864
+ // 其余命令保留,防止误消费后丢失
865
+ if ((!target || subscriptionOnly) && cmd.action !== "setSubscription") {
866
+ kept.push(cmd);
867
+ continue;
868
+ }
869
+ if (target) this._useController(target);
851
870
  const handler = this._cmdHandlers[cmd.action];
852
871
  if (handler) {
853
872
  await handler(cmd, target);
@@ -855,9 +874,10 @@ export class ClashDaemon {
855
874
  this._log(`📋 未知命令: ${JSON.stringify(cmd)}`);
856
875
  }
857
876
  }
858
- ipc.clearCommand(ch);
877
+ if (kept.length) ipc.writeCommand(kept, ch);
878
+ else ipc.clearCommand(ch);
859
879
  }
860
- }).catch(() => {});
880
+ }).catch((e) => this._log(`命令消费异常: ${e.message}`));
861
881
  }
862
882
 
863
883
  async _handleSwitchNode(cmd, c) {
@@ -1015,6 +1035,9 @@ export class ClashDaemon {
1015
1035
  * 保证 daemon/机器重启后自动恢复,不依赖服务端可达
1016
1036
  */
1017
1037
  async _handleSetSubscription(cmd, c) {
1038
+ // 等待就绪期 _primary 为 null:用哑控制器上下文(proxyPort=0 → 默认通道)
1039
+ // 保证订阅应用/落盘/健康上报不中断
1040
+ c = c || { proxyPort: 0, clientName: "mihomo(内置)", _meta: {} };
1018
1041
  try {
1019
1042
  const subs = runtime.normalizeSubscriptions(cmd.subscriptions);
1020
1043
  if (!subs.length) {