@yoooclaw/phone-notifications 1.7.3 → 1.7.5

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 CHANGED
@@ -50,13 +50,13 @@ OpenClaw / QClaw 手机通知同步插件:接收手机通知并写入本地 JS
50
50
  ### 通过 OpenClaw CLI 安装(OpenClaw)
51
51
 
52
52
  ```bash
53
- openclaw plugin install @yoooclaw/phone-notifications
53
+ openclaw plugins install @yoooclaw/phone-notifications
54
54
  ```
55
55
 
56
56
  ### 更新
57
57
 
58
58
  ```bash
59
- openclaw plugin update @yoooclaw/phone-notifications
59
+ openclaw plugins update @yoooclaw/phone-notifications
60
60
  ```
61
61
 
62
62
  ### 通过一键脚本安装(推荐给 QClaw,备选给 OpenClaw)
@@ -321,6 +321,10 @@ openclaw ntf monitor delete boss-alert --yes
321
321
  ### 灯效控制
322
322
 
323
323
  ```bash
324
+
325
+ # 启用灯效控制工具
326
+ openclaw ntf light setup
327
+
324
328
  # 直接发送灯效指令到硬件设备(需要先 set-api-key)
325
329
  openclaw ntf light send \
326
330
  --segments '[{"mode":"wave","duration_s":4,"brightness":192,"color":{"r":255,"g":0,"b":0}}]'
package/dist/index.js CHANGED
@@ -3647,8 +3647,8 @@ var require_websocket_server = __commonJS({
3647
3647
  });
3648
3648
 
3649
3649
  // src/index.ts
3650
- import { readFileSync as readFileSync14 } from "fs";
3651
- import { basename as basename2, dirname as dirname6 } from "path";
3650
+ import { readFileSync as readFileSync15 } from "fs";
3651
+ import { basename as basename2, dirname as dirname7 } from "path";
3652
3652
 
3653
3653
  // src/light/protocol.ts
3654
3654
  var MAX_LIGHT_SEGMENTS = 12;
@@ -5271,16 +5271,93 @@ function registerLightSend(light) {
5271
5271
  });
5272
5272
  }
5273
5273
 
5274
+ // src/cli/light-setup-tools.ts
5275
+ import { existsSync as existsSync11, mkdirSync as mkdirSync6, readFileSync as readFileSync10, writeFileSync as writeFileSync8 } from "fs";
5276
+ import { homedir } from "os";
5277
+ import { dirname as dirname4, join as join8 } from "path";
5278
+ function isObject(value) {
5279
+ return !!value && typeof value === "object" && !Array.isArray(value);
5280
+ }
5281
+ function ensureArray(obj, key) {
5282
+ const current = obj[key];
5283
+ if (Array.isArray(current)) return current;
5284
+ const next = [];
5285
+ obj[key] = next;
5286
+ return next;
5287
+ }
5288
+ function resolveConfigPath2() {
5289
+ const fromEnv = process.env.OPENCLAW_CONFIG_PATH?.trim();
5290
+ if (fromEnv) return fromEnv;
5291
+ return join8(homedir(), ".openclaw", "openclaw.json");
5292
+ }
5293
+ function upsertLightControlAlsoAllow(cfg) {
5294
+ if (!isObject(cfg.tools)) cfg.tools = {};
5295
+ const toolsAlsoAllow = ensureArray(cfg.tools, "alsoAllow");
5296
+ const hasGlobal = toolsAlsoAllow.includes("light_control");
5297
+ if (!hasGlobal) toolsAlsoAllow.push("light_control");
5298
+ if (!isObject(cfg.agents)) cfg.agents = {};
5299
+ const agents = cfg.agents;
5300
+ const list = ensureArray(agents, "list");
5301
+ let mainAgent = list.find(
5302
+ (item) => isObject(item) && item.id === "main"
5303
+ );
5304
+ if (!mainAgent) {
5305
+ mainAgent = { id: "main" };
5306
+ list.push(mainAgent);
5307
+ }
5308
+ if (!isObject(mainAgent.tools)) mainAgent.tools = {};
5309
+ const mainAlsoAllow = ensureArray(mainAgent.tools, "alsoAllow");
5310
+ const hasMain = mainAlsoAllow.includes("light_control");
5311
+ if (!hasMain) mainAlsoAllow.push("light_control");
5312
+ return {
5313
+ globalChanged: !hasGlobal,
5314
+ mainAgentChanged: !hasMain
5315
+ };
5316
+ }
5317
+ function registerLightSetupTools(light) {
5318
+ light.command("setup").description("\u81EA\u52A8\u653E\u884C light_control\uFF08\u5199\u5165 tools.alsoAllow \u4E0E agents.main.tools.alsoAllow\uFF09").action(() => {
5319
+ const configPath = resolveConfigPath2();
5320
+ if (!existsSync11(configPath)) {
5321
+ exitError("CONFIG_NOT_FOUND", `\u672A\u627E\u5230\u914D\u7F6E\u6587\u4EF6: ${configPath}`);
5322
+ }
5323
+ let cfg = {};
5324
+ try {
5325
+ const raw = readFileSync10(configPath, "utf-8");
5326
+ const parsed = JSON.parse(raw);
5327
+ if (isObject(parsed)) cfg = parsed;
5328
+ } catch (err) {
5329
+ exitError("CONFIG_INVALID", `\u8BFB\u53D6/\u89E3\u6790\u914D\u7F6E\u5931\u8D25: ${err?.message ?? String(err)}`);
5330
+ }
5331
+ const result = upsertLightControlAlsoAllow(cfg);
5332
+ try {
5333
+ mkdirSync6(dirname4(configPath), { recursive: true });
5334
+ writeFileSync8(configPath, JSON.stringify(cfg, null, 2) + "\n", "utf-8");
5335
+ } catch (err) {
5336
+ exitError("WRITE_FAILED", `\u5199\u5165\u914D\u7F6E\u5931\u8D25: ${err?.message ?? String(err)}`);
5337
+ }
5338
+ output({
5339
+ ok: true,
5340
+ configPath,
5341
+ changed: result.globalChanged || result.mainAgentChanged,
5342
+ updates: {
5343
+ toolsAlsoAllow: result.globalChanged ? "added" : "already_exists",
5344
+ mainAgentAlsoAllow: result.mainAgentChanged ? "added" : "already_exists"
5345
+ },
5346
+ next: "\u8BF7\u6267\u884C: openclaw gateway restart"
5347
+ });
5348
+ });
5349
+ }
5350
+
5274
5351
  // src/cli/tunnel-status.ts
5275
- import { existsSync as existsSync11, readFileSync as readFileSync10 } from "fs";
5276
- import { join as join8 } from "path";
5277
- var STATUS_REL_PATH = join8("plugins", "phone-notifications", "tunnel-status.json");
5352
+ import { existsSync as existsSync12, readFileSync as readFileSync11 } from "fs";
5353
+ import { join as join9 } from "path";
5354
+ var STATUS_REL_PATH = join9("plugins", "phone-notifications", "tunnel-status.json");
5278
5355
  function readTunnelStatus(ctx) {
5279
5356
  if (!ctx.stateDir) return null;
5280
- const filePath = join8(ctx.stateDir, STATUS_REL_PATH);
5281
- if (!existsSync11(filePath)) return null;
5357
+ const filePath = join9(ctx.stateDir, STATUS_REL_PATH);
5358
+ if (!existsSync12(filePath)) return null;
5282
5359
  try {
5283
- return JSON.parse(readFileSync10(filePath, "utf-8"));
5360
+ return JSON.parse(readFileSync11(filePath, "utf-8"));
5284
5361
  } catch {
5285
5362
  return null;
5286
5363
  }
@@ -5348,17 +5425,17 @@ function registerNtfStoragePath(ntf, ctx) {
5348
5425
  }
5349
5426
 
5350
5427
  // src/cli/log-search.ts
5351
- import { existsSync as existsSync12, readFileSync as readFileSync11, readdirSync as readdirSync4 } from "fs";
5352
- import { join as join9 } from "path";
5428
+ import { existsSync as existsSync13, readFileSync as readFileSync12, readdirSync as readdirSync4 } from "fs";
5429
+ import { join as join10 } from "path";
5353
5430
  function resolveLogsDir(ctx) {
5354
5431
  if (ctx.stateDir) {
5355
- const dir = join9(
5432
+ const dir = join10(
5356
5433
  ctx.stateDir,
5357
5434
  "plugins",
5358
5435
  "phone-notifications",
5359
5436
  "logs"
5360
5437
  );
5361
- if (existsSync12(dir)) return dir;
5438
+ if (existsSync13(dir)) return dir;
5362
5439
  }
5363
5440
  return null;
5364
5441
  }
@@ -5373,9 +5450,9 @@ function listLogDateKeys(dir) {
5373
5450
  return keys.sort().reverse();
5374
5451
  }
5375
5452
  function collectLogLines(dir, dateKey, keyword, limit, collected) {
5376
- const filePath = join9(dir, `${dateKey}.log`);
5377
- if (!existsSync12(filePath)) return;
5378
- const content = readFileSync11(filePath, "utf-8");
5453
+ const filePath = join10(dir, `${dateKey}.log`);
5454
+ if (!existsSync13(filePath)) return;
5455
+ const content = readFileSync12(filePath, "utf-8");
5379
5456
  const lowerKeyword = keyword?.toLowerCase();
5380
5457
  for (const line of content.split("\n")) {
5381
5458
  if (collected.length >= limit) return;
@@ -5441,12 +5518,12 @@ function registerEnvCli(ntf) {
5441
5518
  }
5442
5519
 
5443
5520
  // src/version.ts
5444
- import { readFileSync as readFileSync12 } from "fs";
5521
+ import { readFileSync as readFileSync13 } from "fs";
5445
5522
  function readPluginVersion() {
5446
5523
  try {
5447
5524
  const packageJsonUrl = new URL("../package.json", import.meta.url);
5448
5525
  const packageJson = JSON.parse(
5449
- readFileSync12(packageJsonUrl, "utf-8")
5526
+ readFileSync13(packageJsonUrl, "utf-8")
5450
5527
  );
5451
5528
  return packageJson.version ?? "unknown";
5452
5529
  } catch {
@@ -5465,6 +5542,7 @@ function registerAllCli(program, ctx, rootCommandName = "ntf") {
5465
5542
  registerNtfMonitor(ntf, ctx);
5466
5543
  const light = registerLightRules(ntf, ctx);
5467
5544
  registerLightSend(light);
5545
+ registerLightSetupTools(light);
5468
5546
  registerNtfStoragePath(ntf, ctx);
5469
5547
  registerLogSearch(ntf, ctx);
5470
5548
  registerTunnelStatus(ntf, ctx);
@@ -5474,17 +5552,17 @@ function registerAllCli(program, ctx, rootCommandName = "ntf") {
5474
5552
  // src/tunnel/service.ts
5475
5553
  import {
5476
5554
  closeSync,
5477
- mkdirSync as mkdirSync7,
5555
+ mkdirSync as mkdirSync8,
5478
5556
  openSync,
5479
- readFileSync as readFileSync13,
5557
+ readFileSync as readFileSync14,
5480
5558
  unlinkSync,
5481
- writeFileSync as writeFileSync9
5559
+ writeFileSync as writeFileSync10
5482
5560
  } from "fs";
5483
- import { dirname as dirname5, join as join10 } from "path";
5561
+ import { dirname as dirname6, join as join11 } from "path";
5484
5562
 
5485
5563
  // src/tunnel/relay-client.ts
5486
- import { writeFileSync as writeFileSync8, mkdirSync as mkdirSync6 } from "fs";
5487
- import { dirname as dirname4 } from "path";
5564
+ import { writeFileSync as writeFileSync9, mkdirSync as mkdirSync7 } from "fs";
5565
+ import { dirname as dirname5 } from "path";
5488
5566
 
5489
5567
  // node_modules/.pnpm/ws@8.19.0/node_modules/ws/wrapper.mjs
5490
5568
  var import_stream = __toESM(require_stream(), 1);
@@ -5526,8 +5604,8 @@ var RelayClient = class {
5526
5604
  lastDisconnectReason
5527
5605
  };
5528
5606
  try {
5529
- mkdirSync6(dirname4(this.opts.statusFilePath), { recursive: true });
5530
- writeFileSync8(this.opts.statusFilePath, JSON.stringify(info, null, 2));
5607
+ mkdirSync7(dirname5(this.opts.statusFilePath), { recursive: true });
5608
+ writeFileSync9(this.opts.statusFilePath, JSON.stringify(info, null, 2));
5531
5609
  } catch {
5532
5610
  }
5533
5611
  }
@@ -6598,7 +6676,7 @@ function createTunnelService(opts) {
6598
6676
  }
6599
6677
  function readLockOwner(filePath) {
6600
6678
  try {
6601
- const parsed = JSON.parse(readFileSync13(filePath, "utf-8"));
6679
+ const parsed = JSON.parse(readFileSync14(filePath, "utf-8"));
6602
6680
  return typeof parsed.pid === "number" ? parsed.pid : null;
6603
6681
  } catch {
6604
6682
  return null;
@@ -6623,11 +6701,11 @@ function createTunnelService(opts) {
6623
6701
  }
6624
6702
  }
6625
6703
  function acquireLock(filePath) {
6626
- mkdirSync7(dirname5(filePath), { recursive: true });
6704
+ mkdirSync8(dirname6(filePath), { recursive: true });
6627
6705
  for (let attempt = 0; attempt < 2; attempt++) {
6628
6706
  try {
6629
6707
  const fd = openSync(filePath, "wx", 384);
6630
- writeFileSync9(
6708
+ writeFileSync10(
6631
6709
  fd,
6632
6710
  JSON.stringify({
6633
6711
  pid: process.pid,
@@ -6684,12 +6762,12 @@ function createTunnelService(opts) {
6684
6762
  return;
6685
6763
  }
6686
6764
  const { logger } = opts;
6687
- const baseStateDir = join10(ctx.stateDir, "plugins", "phone-notifications");
6765
+ const baseStateDir = join11(ctx.stateDir, "plugins", "phone-notifications");
6688
6766
  logger.info(
6689
6767
  `Relay tunnel: starting (pid=${process.pid}, url=${opts.tunnelUrl}, heartbeat=${opts.heartbeatSec ?? DEFAULT_HEARTBEAT_SEC}s, backoff=${opts.reconnectBackoffMs ?? DEFAULT_RECONNECT_BACKOFF_MS}ms, gateway=${opts.gatewayBaseUrl}, hasGatewayToken=${!!opts.gatewayToken}, hasGatewayPwd=${!!opts.gatewayPassword})`
6690
6768
  );
6691
- const statusFilePath = join10(baseStateDir, "tunnel-status.json");
6692
- const lockPath = join10(baseStateDir, "relay-tunnel.lock");
6769
+ const statusFilePath = join11(baseStateDir, "tunnel-status.json");
6770
+ const lockPath = join11(baseStateDir, "relay-tunnel.lock");
6693
6771
  if (!acquireLock(lockPath)) {
6694
6772
  return;
6695
6773
  }
@@ -6738,13 +6816,13 @@ function createTunnelService(opts) {
6738
6816
  }
6739
6817
 
6740
6818
  // src/logger.ts
6741
- import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync8 } from "fs";
6742
- import { join as join11 } from "path";
6819
+ import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync9 } from "fs";
6820
+ import { join as join12 } from "path";
6743
6821
  var PluginFileLogger = class {
6744
6822
  constructor(upstream, stateDir) {
6745
6823
  this.upstream = upstream;
6746
- this.logsDir = join11(stateDir, "plugins", "phone-notifications", "logs");
6747
- mkdirSync8(this.logsDir, { recursive: true });
6824
+ this.logsDir = join12(stateDir, "plugins", "phone-notifications", "logs");
6825
+ mkdirSync9(this.logsDir, { recursive: true });
6748
6826
  }
6749
6827
  logsDir;
6750
6828
  info(msg) {
@@ -6766,7 +6844,7 @@ var PluginFileLogger = class {
6766
6844
  const line = `${time} [${level}] ${msg}
6767
6845
  `;
6768
6846
  try {
6769
- appendFileSync2(join11(this.logsDir, `${dateKey}.log`), line);
6847
+ appendFileSync2(join12(this.logsDir, `${dateKey}.log`), line);
6770
6848
  } catch {
6771
6849
  }
6772
6850
  }
@@ -6812,7 +6890,7 @@ function resolveLocalGatewayAuth(params) {
6812
6890
  const configPath = params.stateDir ? resolveConfigPath(params.stateDir) : void 0;
6813
6891
  if (configPath) {
6814
6892
  try {
6815
- const configData = JSON.parse(readFileSync14(configPath, "utf-8"));
6893
+ const configData = JSON.parse(readFileSync15(configPath, "utf-8"));
6816
6894
  const rawGatewayAuthMode = trimToUndefined2(configData?.gateway?.auth?.mode);
6817
6895
  if (rawGatewayAuthMode === "token" || rawGatewayAuthMode === "password") {
6818
6896
  configGatewayAuthMode = rawGatewayAuthMode;
@@ -7090,7 +7168,7 @@ var index_default = {
7090
7168
  if (openclawDir) return openclawDir;
7091
7169
  if (!workspaceDir) return void 0;
7092
7170
  if (basename2(workspaceDir) !== "workspace") return void 0;
7093
- return dirname6(workspaceDir);
7171
+ return dirname7(workspaceDir);
7094
7172
  };
7095
7173
  api.registerCli(
7096
7174
  (ctx) => {