tickflow-assist 0.2.1 → 0.2.2
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 +12 -3
- package/dist/dev/tickflow-assist-cli.js +149 -7
- package/docs/installation.md +32 -30
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -37,9 +37,18 @@ TickFlow Assist 面向一条完整的“自选管理 -> 数据抓取 -> 综合
|
|
|
37
37
|
|
|
38
38
|
## 🛠 安装与配置
|
|
39
39
|
|
|
40
|
-
###
|
|
40
|
+
### 社区安装(推荐)
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
如果你不需改动源码,可直接通过 OpenClaw 插件市场或 npm 安装:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
openclaw plugins install tickflow-assist
|
|
46
|
+
npx -y tickflow-assist configure-openclaw
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 一键安装脚本
|
|
50
|
+
|
|
51
|
+
如果你已经安装了 `git`、`node`、`npm`、`uv`、`openclaw` 与 `jq`,并且想要从源码运行,可以直接运行安装向导:
|
|
43
52
|
|
|
44
53
|
```bash
|
|
45
54
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/robinspt/tickflow-assist/main/setup-tickflow.sh)"
|
|
@@ -49,7 +58,7 @@ bash -c "$(curl -fsSL https://raw.githubusercontent.com/robinspt/tickflow-assist
|
|
|
49
58
|
|
|
50
59
|
如果你已经装过旧版本,优先直接执行“升级”。具体升级与重装边界见 [docs/installation.md](docs/installation.md)。
|
|
51
60
|
|
|
52
|
-
###
|
|
61
|
+
### 手动源码安装
|
|
53
62
|
|
|
54
63
|
```bash
|
|
55
64
|
git clone https://github.com/robinspt/tickflow-assist.git
|
|
@@ -19,7 +19,7 @@ const DEFAULTS = {
|
|
|
19
19
|
dailyUpdateNotify: true,
|
|
20
20
|
alertChannel: "telegram",
|
|
21
21
|
openclawCliBin: "openclaw",
|
|
22
|
-
alertAccount: "",
|
|
22
|
+
alertAccount: "default",
|
|
23
23
|
pythonBin: "uv",
|
|
24
24
|
pythonArgs: ["run", "python"],
|
|
25
25
|
};
|
|
@@ -37,6 +37,7 @@ Options:
|
|
|
37
37
|
--non-interactive Use existing config / flags only, no prompts
|
|
38
38
|
--no-enable Do not run 'openclaw plugins enable'
|
|
39
39
|
--no-restart Do not run 'openclaw gateway restart'
|
|
40
|
+
--no-python-setup Do not run 'uv sync' for Python dependencies
|
|
40
41
|
--openclaw-bin <path> OpenClaw CLI binary, default: openclaw
|
|
41
42
|
--tickflow-api-key <key>
|
|
42
43
|
--tickflow-api-key-level <Free|Start|Pro|Expert>
|
|
@@ -59,6 +60,7 @@ function parseArgs(argv) {
|
|
|
59
60
|
nonInteractive: false,
|
|
60
61
|
restart: true,
|
|
61
62
|
enable: true,
|
|
63
|
+
pythonSetup: true,
|
|
62
64
|
openclawBin: DEFAULTS.openclawCliBin,
|
|
63
65
|
overrides: {},
|
|
64
66
|
};
|
|
@@ -110,6 +112,9 @@ function parseArgs(argv) {
|
|
|
110
112
|
case "--no-restart":
|
|
111
113
|
options.restart = false;
|
|
112
114
|
break;
|
|
115
|
+
case "--no-python-setup":
|
|
116
|
+
options.pythonSetup = false;
|
|
117
|
+
break;
|
|
113
118
|
case "--no-enable":
|
|
114
119
|
options.enable = false;
|
|
115
120
|
break;
|
|
@@ -281,7 +286,99 @@ function inferAllowTarget(root, options) {
|
|
|
281
286
|
}
|
|
282
287
|
return { type: "global" };
|
|
283
288
|
}
|
|
284
|
-
async function
|
|
289
|
+
async function discoverConfiguredChannels(configPath) {
|
|
290
|
+
try {
|
|
291
|
+
const root = await readConfigFile(configPath);
|
|
292
|
+
const channels = typeof root.channels === "object" && root.channels !== null
|
|
293
|
+
? root.channels
|
|
294
|
+
: {};
|
|
295
|
+
const results = [];
|
|
296
|
+
for (const [name, value] of Object.entries(channels)) {
|
|
297
|
+
if (typeof value !== "object" || value === null)
|
|
298
|
+
continue;
|
|
299
|
+
const entry = value;
|
|
300
|
+
if (entry.enabled === false)
|
|
301
|
+
continue;
|
|
302
|
+
const accounts = [];
|
|
303
|
+
if (typeof entry.accounts === "object" && entry.accounts !== null) {
|
|
304
|
+
for (const [acctName, acctValue] of Object.entries(entry.accounts)) {
|
|
305
|
+
if (typeof acctValue !== "object" || acctValue === null)
|
|
306
|
+
continue;
|
|
307
|
+
if (acctValue.enabled === false)
|
|
308
|
+
continue;
|
|
309
|
+
accounts.push(acctName);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
results.push({ channel: name, accounts });
|
|
313
|
+
}
|
|
314
|
+
return results;
|
|
315
|
+
}
|
|
316
|
+
catch {
|
|
317
|
+
return [];
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
async function promptSelect(rl, label, choices, defaultValue) {
|
|
321
|
+
const defaultIndex = Math.max(0, choices.findIndex((c) => c.value === defaultValue));
|
|
322
|
+
console.log(` ${label}`);
|
|
323
|
+
for (let i = 0; i < choices.length; i++) {
|
|
324
|
+
const marker = i === defaultIndex ? " (默认)" : "";
|
|
325
|
+
console.log(` ${i + 1}) ${choices[i].label}${marker}`);
|
|
326
|
+
}
|
|
327
|
+
while (true) {
|
|
328
|
+
const answer = (await rl.question(` 请选择 (1-${choices.length}) [${defaultIndex + 1}]: `)).trim();
|
|
329
|
+
if (!answer) {
|
|
330
|
+
return choices[defaultIndex].value;
|
|
331
|
+
}
|
|
332
|
+
const num = Number(answer);
|
|
333
|
+
if (Number.isInteger(num) && num >= 1 && num <= choices.length) {
|
|
334
|
+
return choices[num - 1].value;
|
|
335
|
+
}
|
|
336
|
+
console.error(` 请输入 1-${choices.length}`);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
async function promptAlertChannel(rl, configPath, defaultChannel) {
|
|
340
|
+
const configured = await discoverConfiguredChannels(configPath);
|
|
341
|
+
let selectedChannel = defaultChannel;
|
|
342
|
+
if (configured.length > 0) {
|
|
343
|
+
console.log(" 检测到 openclaw.json 中已有通道配置:");
|
|
344
|
+
const choices = configured.map((c) => {
|
|
345
|
+
const acctLabel = c.accounts.length > 0 ? ` (accounts: ${c.accounts.join(", ")})` : "";
|
|
346
|
+
return { value: c.channel, label: `${c.channel}${acctLabel}` };
|
|
347
|
+
});
|
|
348
|
+
choices.push({ value: "__manual__", label: "手动输入其他通道" });
|
|
349
|
+
selectedChannel = await promptSelect(rl, "推送通道", choices, defaultChannel);
|
|
350
|
+
if (selectedChannel === "__manual__") {
|
|
351
|
+
selectedChannel = await promptString(rl, "Alert Channel", defaultChannel, true);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
else {
|
|
355
|
+
const knownChannels = [
|
|
356
|
+
{ value: "telegram", label: "telegram" },
|
|
357
|
+
{ value: "qqbot", label: "qqbot" },
|
|
358
|
+
{ value: "wecom", label: "wecom" },
|
|
359
|
+
];
|
|
360
|
+
selectedChannel = await promptSelect(rl, "推送通道", knownChannels, defaultChannel);
|
|
361
|
+
}
|
|
362
|
+
// Resolve account
|
|
363
|
+
const channelAccounts = configured.find((c) => c.channel === selectedChannel)?.accounts ?? [];
|
|
364
|
+
let selectedAccount = "";
|
|
365
|
+
if (channelAccounts.length === 1) {
|
|
366
|
+
selectedAccount = channelAccounts[0];
|
|
367
|
+
console.log(` 已自动选择账号: ${selectedAccount}`);
|
|
368
|
+
}
|
|
369
|
+
else if (channelAccounts.length > 1) {
|
|
370
|
+
const acctChoices = channelAccounts.map((a) => ({ value: a, label: a }));
|
|
371
|
+
selectedAccount = await promptSelect(rl, "选择账号", acctChoices, channelAccounts[0]);
|
|
372
|
+
}
|
|
373
|
+
else {
|
|
374
|
+
// Default for channels that typically need an account
|
|
375
|
+
if (["qqbot", "wecom"].includes(selectedChannel)) {
|
|
376
|
+
selectedAccount = "default";
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
return { channel: selectedChannel, account: selectedAccount };
|
|
380
|
+
}
|
|
381
|
+
async function promptForConfig(options, existing, pluginDir, configPath) {
|
|
285
382
|
const defaults = {
|
|
286
383
|
tickflowApiUrl: DEFAULTS.tickflowApiUrl,
|
|
287
384
|
tickflowApiKey: "",
|
|
@@ -319,17 +416,28 @@ async function promptForConfig(options, existing, pluginDir) {
|
|
|
319
416
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
320
417
|
try {
|
|
321
418
|
console.log("TickFlow Assist 社区安装配置向导");
|
|
322
|
-
console.log(`OpenClaw 配置文件: ${
|
|
419
|
+
console.log(`OpenClaw 配置文件: ${configPath}`);
|
|
323
420
|
console.log(`插件目录: ${pluginDir}`);
|
|
324
421
|
console.log("");
|
|
325
422
|
seed.tickflowApiKey = await promptString(rl, "TickFlow API Key", seed.tickflowApiKey, true);
|
|
326
|
-
seed.tickflowApiKeyLevel = normalizeApiKeyLevel(await
|
|
423
|
+
seed.tickflowApiKeyLevel = normalizeApiKeyLevel(await promptSelect(rl, "TickFlow 订阅等级", [
|
|
424
|
+
{ value: "Free", label: "Free" },
|
|
425
|
+
{ value: "Start", label: "Start" },
|
|
426
|
+
{ value: "Pro", label: "Pro" },
|
|
427
|
+
{ value: "Expert", label: "Expert" },
|
|
428
|
+
], seed.tickflowApiKeyLevel));
|
|
327
429
|
seed.mxSearchApiKey = await promptString(rl, "MX Search API Key (可留空)", seed.mxSearchApiKey, false);
|
|
328
430
|
seed.llmBaseUrl = await promptString(rl, "LLM Base URL", seed.llmBaseUrl, true);
|
|
329
431
|
seed.llmApiKey = await promptString(rl, "LLM API Key", seed.llmApiKey, true);
|
|
330
432
|
seed.llmModel = await promptString(rl, "LLM Model", seed.llmModel, true);
|
|
331
|
-
|
|
332
|
-
|
|
433
|
+
console.log("");
|
|
434
|
+
const alertResult = await promptAlertChannel(rl, configPath, seed.alertChannel);
|
|
435
|
+
seed.alertChannel = alertResult.channel;
|
|
436
|
+
seed.alertAccount = alertResult.account;
|
|
437
|
+
console.log(` 已选择通道: ${seed.alertChannel}`);
|
|
438
|
+
if (seed.alertAccount) {
|
|
439
|
+
console.log(` 已选择账号: ${seed.alertAccount}`);
|
|
440
|
+
}
|
|
333
441
|
seed.alertTarget = await promptString(rl, "Alert Target", seed.alertTarget, true);
|
|
334
442
|
seed.requestInterval = await promptInteger(rl, "Request Interval (seconds)", seed.requestInterval, 5);
|
|
335
443
|
seed.dailyUpdateNotify = await promptBoolean(rl, "Daily Update Notify", seed.dailyUpdateNotify);
|
|
@@ -481,6 +589,37 @@ function runOpenClaw(bin, args, description) {
|
|
|
481
589
|
console.warn(`Warning: ${description} exited with status ${result.status}`);
|
|
482
590
|
}
|
|
483
591
|
}
|
|
592
|
+
function setupPythonDeps(pythonWorkdir) {
|
|
593
|
+
let uvBin = "uv";
|
|
594
|
+
try {
|
|
595
|
+
const which = spawnSync("which", ["uv"], { encoding: "utf-8" });
|
|
596
|
+
if (which.status !== 0) {
|
|
597
|
+
console.warn("Warning: uv not found in PATH, skipping Python dependency setup.");
|
|
598
|
+
console.warn("Please install uv (https://docs.astral.sh/uv/) and run 'uv sync' manually in:");
|
|
599
|
+
console.warn(` ${pythonWorkdir}`);
|
|
600
|
+
return;
|
|
601
|
+
}
|
|
602
|
+
uvBin = which.stdout.trim() || "uv";
|
|
603
|
+
}
|
|
604
|
+
catch {
|
|
605
|
+
// fall through with default "uv"
|
|
606
|
+
}
|
|
607
|
+
console.log(`Setting up Python dependencies in ${pythonWorkdir} ...`);
|
|
608
|
+
const result = spawnSync(uvBin, ["sync"], { cwd: pythonWorkdir, stdio: "inherit" });
|
|
609
|
+
if (result.error) {
|
|
610
|
+
console.warn(`Warning: failed to run uv sync: ${result.error.message}`);
|
|
611
|
+
console.warn("Please run 'uv sync' manually in:");
|
|
612
|
+
console.warn(` ${pythonWorkdir}`);
|
|
613
|
+
return;
|
|
614
|
+
}
|
|
615
|
+
if (result.status !== 0) {
|
|
616
|
+
console.warn(`Warning: uv sync exited with status ${result.status}`);
|
|
617
|
+
console.warn("Please check the output above and run 'uv sync' manually if needed in:");
|
|
618
|
+
console.warn(` ${pythonWorkdir}`);
|
|
619
|
+
return;
|
|
620
|
+
}
|
|
621
|
+
console.log("Python dependencies installed successfully.");
|
|
622
|
+
}
|
|
484
623
|
async function configureOpenClaw(options) {
|
|
485
624
|
const configPath = resolveOpenClawConfigPath(options.configPath);
|
|
486
625
|
const stateDir = resolveStateDir(configPath);
|
|
@@ -488,9 +627,12 @@ async function configureOpenClaw(options) {
|
|
|
488
627
|
const root = await readConfigFile(configPath);
|
|
489
628
|
const target = inferAllowTarget(root, options);
|
|
490
629
|
const existing = getExistingPluginConfig(root);
|
|
491
|
-
const config = await promptForConfig(options, existing, pluginDir);
|
|
630
|
+
const config = await promptForConfig(options, existing, pluginDir, configPath);
|
|
492
631
|
await ensurePathNotice(config.calendarFile, "calendarFile");
|
|
493
632
|
await ensurePathNotice(config.pythonWorkdir, "pythonWorkdir");
|
|
633
|
+
if (options.pythonSetup) {
|
|
634
|
+
setupPythonDeps(config.pythonWorkdir);
|
|
635
|
+
}
|
|
494
636
|
applyPluginConfig(root, config, target);
|
|
495
637
|
const backupPath = await writeConfig(configPath, root);
|
|
496
638
|
console.log("");
|
package/docs/installation.md
CHANGED
|
@@ -39,11 +39,31 @@ bash -c "$(curl -fsSL https://raw.githubusercontent.com/robinspt/tickflow-assist
|
|
|
39
39
|
- 安装并启用 `tickflow-assist`
|
|
40
40
|
- 重启 OpenClaw Gateway
|
|
41
41
|
|
|
42
|
-
如果你只是日常升级,重新运行同一条命令并在菜单里选择“升级”即可。更具体的升级与重装说明见下文 [
|
|
42
|
+
如果你只是日常升级,重新运行同一条命令并在菜单里选择“升级”即可。更具体的升级与重装说明见下文 [7.2 升级](#72-升级) 与 [7.3 禁用重装与清理](#73-禁用重装与清理)。
|
|
43
43
|
|
|
44
|
-
## 3.
|
|
44
|
+
## 3. 社区安装(推荐)
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
如果你不需改动源码,可直接通过 OpenClaw 插件市场或 npm 安装:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
openclaw plugins install tickflow-assist
|
|
50
|
+
npx -y tickflow-assist configure-openclaw
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
第二条命令会自动:
|
|
54
|
+
|
|
55
|
+
- 安装 Python 依赖(`uv sync`)
|
|
56
|
+
- 写入 `plugins.entries["tickflow-assist"].config`
|
|
57
|
+
- 给顶层 `tools.allow` 或推断出的目标 Agent 补 `tickflow-assist` allowlist
|
|
58
|
+
- 执行 `openclaw plugins enable tickflow-assist`
|
|
59
|
+
- 执行 `openclaw config validate`
|
|
60
|
+
- 执行 `openclaw gateway restart`
|
|
61
|
+
|
|
62
|
+
如果你已经手动启用插件,或暂时不想重启 Gateway,可追加 `--no-enable` 或 `--no-restart`。如果 Python 已经装好或不需要自动安装,可追加 `--no-python-setup`。
|
|
63
|
+
|
|
64
|
+
## 4. 源码安装
|
|
65
|
+
|
|
66
|
+
### 4.1 拉取源码
|
|
47
67
|
|
|
48
68
|
推荐把项目放在普通开发目录,不要放到 `~/.openclaw/workspace/...` 下面。
|
|
49
69
|
|
|
@@ -53,7 +73,7 @@ git clone https://github.com/robinspt/tickflow-assist.git
|
|
|
53
73
|
cd tickflow-assist
|
|
54
74
|
```
|
|
55
75
|
|
|
56
|
-
###
|
|
76
|
+
### 4.2 安装依赖并构建
|
|
57
77
|
|
|
58
78
|
```bash
|
|
59
79
|
npm install
|
|
@@ -64,33 +84,14 @@ npm run check
|
|
|
64
84
|
npm run build
|
|
65
85
|
```
|
|
66
86
|
|
|
67
|
-
###
|
|
87
|
+
### 4.3 安装并启用插件(源码安装)
|
|
68
88
|
|
|
69
89
|
```bash
|
|
70
90
|
openclaw plugins install -l /path/to/tickflow-assist
|
|
71
91
|
openclaw plugins enable tickflow-assist
|
|
72
92
|
```
|
|
73
93
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
发布到 npm 后,社区安装不需要源码目录,也不需要 `setup-tickflow.sh`:
|
|
77
|
-
|
|
78
|
-
```bash
|
|
79
|
-
openclaw plugins install tickflow-assist
|
|
80
|
-
npx -y tickflow-assist configure-openclaw
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
第二条命令会自动:
|
|
84
|
-
|
|
85
|
-
- 写入 `plugins.entries["tickflow-assist"].config`
|
|
86
|
-
- 给顶层 `tools.allow` 或推断出的目标 Agent 补 `tickflow-assist` allowlist
|
|
87
|
-
- 执行 `openclaw plugins enable tickflow-assist`
|
|
88
|
-
- 执行 `openclaw config validate`
|
|
89
|
-
- 执行 `openclaw gateway restart`
|
|
90
|
-
|
|
91
|
-
如果你已经手动启用插件,或暂时不想重启 Gateway,可追加 `--no-enable` 或 `--no-restart`。
|
|
92
|
-
|
|
93
|
-
## 4. 插件配置
|
|
94
|
+
## 5. 插件配置
|
|
94
95
|
|
|
95
96
|
正式插件运行读取:
|
|
96
97
|
|
|
@@ -243,7 +244,7 @@ openclaw gateway restart
|
|
|
243
244
|
|
|
244
245
|
</details>
|
|
245
246
|
|
|
246
|
-
##
|
|
247
|
+
## 6. 消息通道配置(可选)
|
|
247
248
|
|
|
248
249
|
TickFlow Assist 当前通过 `openclaw message send` 投递告警,因此前提是目标通道本身已经能在 OpenClaw 中正常工作。
|
|
249
250
|
|
|
@@ -266,6 +267,7 @@ TickFlow Assist 当前通过 `openclaw message send` 投递告警,因此前提
|
|
|
266
267
|
| 通道 | 官方项目 / 接入方式 | `alertAccount` | `alertTarget` 示例 | 说明 |
|
|
267
268
|
|---|---|---|---|---|
|
|
268
269
|
| `telegram` | `openclaw channels add --channel telegram` | 通常留空 | `-1001234567890` | 直接使用群组 / 会话 ID |
|
|
270
|
+
| `discord` | `openclaw channels add --channel discord` | 通常留空 | `user:1234567890` | 优先在目标会话发送 `/whoami`,读取 `User id`,拼装成 `user:User id` |
|
|
269
271
|
| `qqbot`(QQ机器人) | [@tencent-connect/openclaw-qqbot](https://www.npmjs.com/package/@tencent-connect/openclaw-qqbot) | 推荐 `default` | `qqbot:c2c:YOUR_OPENID` | 优先在目标会话发送 `/whoami`,读取 `User id` |
|
|
270
272
|
| `wecom`(企业微信) | [@wecom/wecom-openclaw-plugin](https://www.npmjs.com/package/@wecom/wecom-openclaw-plugin) | 常见为 `default` | `YOUR_USER_ID_OR_CHAT_ID` | 优先在目标会话发送 `/whoami`,再区分单聊 `userId` / 群聊 `chatId` |
|
|
271
273
|
| `weixin`(微信) | [@tencent-weixin/openclaw-weixin](https://www.npmjs.com/package/@tencent-weixin/openclaw-weixin) | 视插件配置 | `YOUR_TARGET` | 预留通道,当前 TickFlow Assist 尚未做专门适配,建议先用 `test_alert` 验证 |
|
|
@@ -316,9 +318,9 @@ TickFlow Assist 当前通过 `openclaw message send` 投递告警,因此前提
|
|
|
316
318
|
|
|
317
319
|
</details>
|
|
318
320
|
|
|
319
|
-
##
|
|
321
|
+
## 7. 运维与日常管理
|
|
320
322
|
|
|
321
|
-
###
|
|
323
|
+
### 7.1 重启与验收
|
|
322
324
|
|
|
323
325
|
完成安装或修改配置后,建议按下面顺序做一次验收:
|
|
324
326
|
|
|
@@ -338,7 +340,7 @@ npm run tool -- test_alert
|
|
|
338
340
|
|
|
339
341
|
或者直接在 OpenClaw 对话里发送“测试告警”。
|
|
340
342
|
|
|
341
|
-
###
|
|
343
|
+
### 7.2 升级
|
|
342
344
|
|
|
343
345
|
推荐继续使用安装向导,在菜单里选择“升级”。
|
|
344
346
|
|
|
@@ -360,7 +362,7 @@ openclaw plugins enable tickflow-assist
|
|
|
360
362
|
openclaw gateway restart
|
|
361
363
|
```
|
|
362
364
|
|
|
363
|
-
###
|
|
365
|
+
### 7.3 禁用、重装与清理
|
|
364
366
|
|
|
365
367
|
禁用插件:
|
|
366
368
|
|
package/openclaw.plugin.json
CHANGED