@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 +6 -2
- package/dist/index.js +116 -38
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -50,13 +50,13 @@ OpenClaw / QClaw 手机通知同步插件:接收手机通知并写入本地 JS
|
|
|
50
50
|
### 通过 OpenClaw CLI 安装(OpenClaw)
|
|
51
51
|
|
|
52
52
|
```bash
|
|
53
|
-
openclaw
|
|
53
|
+
openclaw plugins install @yoooclaw/phone-notifications
|
|
54
54
|
```
|
|
55
55
|
|
|
56
56
|
### 更新
|
|
57
57
|
|
|
58
58
|
```bash
|
|
59
|
-
openclaw
|
|
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
|
|
3651
|
-
import { basename as basename2, dirname as
|
|
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
|
|
5276
|
-
import { join as
|
|
5277
|
-
var STATUS_REL_PATH =
|
|
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 =
|
|
5281
|
-
if (!
|
|
5357
|
+
const filePath = join9(ctx.stateDir, STATUS_REL_PATH);
|
|
5358
|
+
if (!existsSync12(filePath)) return null;
|
|
5282
5359
|
try {
|
|
5283
|
-
return JSON.parse(
|
|
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
|
|
5352
|
-
import { join as
|
|
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 =
|
|
5432
|
+
const dir = join10(
|
|
5356
5433
|
ctx.stateDir,
|
|
5357
5434
|
"plugins",
|
|
5358
5435
|
"phone-notifications",
|
|
5359
5436
|
"logs"
|
|
5360
5437
|
);
|
|
5361
|
-
if (
|
|
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 =
|
|
5377
|
-
if (!
|
|
5378
|
-
const content =
|
|
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
|
|
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
|
-
|
|
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
|
|
5555
|
+
mkdirSync as mkdirSync8,
|
|
5478
5556
|
openSync,
|
|
5479
|
-
readFileSync as
|
|
5557
|
+
readFileSync as readFileSync14,
|
|
5480
5558
|
unlinkSync,
|
|
5481
|
-
writeFileSync as
|
|
5559
|
+
writeFileSync as writeFileSync10
|
|
5482
5560
|
} from "fs";
|
|
5483
|
-
import { dirname as
|
|
5561
|
+
import { dirname as dirname6, join as join11 } from "path";
|
|
5484
5562
|
|
|
5485
5563
|
// src/tunnel/relay-client.ts
|
|
5486
|
-
import { writeFileSync as
|
|
5487
|
-
import { dirname as
|
|
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
|
-
|
|
5530
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
6692
|
-
const lockPath =
|
|
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
|
|
6742
|
-
import { join as
|
|
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 =
|
|
6747
|
-
|
|
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(
|
|
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(
|
|
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
|
|
7171
|
+
return dirname7(workspaceDir);
|
|
7094
7172
|
};
|
|
7095
7173
|
api.registerCli(
|
|
7096
7174
|
(ctx) => {
|