tickflow-assist 0.2.0 → 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 CHANGED
@@ -37,9 +37,18 @@ TickFlow Assist 面向一条完整的“自选管理 -> 数据抓取 -> 综合
37
37
 
38
38
  ## 🛠 安装与配置
39
39
 
40
- ### 一键安装
40
+ ### 社区安装(推荐)
41
41
 
42
- 如果你已经安装了 `git`、`node`、`npm`、`uv`、`openclaw` 与 `jq`,可以直接运行安装向导:
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
@@ -65,20 +74,7 @@ openclaw plugins enable tickflow-assist
65
74
  openclaw gateway restart
66
75
  ```
67
76
 
68
- ### 社区安装(npm / 社区插件)
69
-
70
- 发布到 npm 后,社区安装不需要源码目录,也不需要 `setup-tickflow.sh`:
71
-
72
- ```bash
73
- openclaw plugins install tickflow-assist
74
- npx -y tickflow-assist configure-openclaw
75
- ```
76
-
77
- 第二条命令会自动写入 `plugins.entries["tickflow-assist"].config`、补 `tools.allow += ["tickflow-assist"]`,并默认执行 `openclaw plugins enable`、`openclaw config validate` 与 `openclaw gateway restart`。如需保留手动控制,可追加 `--no-enable` 或 `--no-restart`。
78
-
79
- 正式插件运行读取 `~/.openclaw/openclaw.json` 中的 `plugins.entries["tickflow-assist"].config`。本地调试与 CLI 读取项目根目录 `local.config.json` 下的 `plugin` 字段,两套配置互不共享。
80
77
 
81
- 从 `0.2.0` 起,`add_stock`、`remove_stock`、`start_monitor`、`stop_monitor`、`start_daily_update`、`stop_daily_update`、`update_all`、`test_alert` 以及自选资料刷新工具按 OpenClaw 官方建议注册为 optional agent tools。若你给 Agent 显式配置了 `tools.allow`,请把插件 id `tickflow-assist` 或这些工具名加入允许列表;Slash Command 不受影响。
82
78
 
83
79
  ## 🚀 使用方式
84
80
 
@@ -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 promptForConfig(options, existing, pluginDir) {
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 配置文件: ${resolveOpenClawConfigPath(options.configPath)}`);
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 promptString(rl, "TickFlow API Key Level [Free/Start/Pro/Expert]", seed.tickflowApiKeyLevel, true));
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
- seed.alertChannel = await promptString(rl, "Alert Channel", seed.alertChannel, true);
332
- seed.alertAccount = await promptString(rl, "Alert Account (可留空)", seed.alertAccount, false);
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/dist/plugin.d.ts CHANGED
@@ -1,8 +1,2 @@
1
- declare const _default: {
2
- id: string;
3
- name: string;
4
- description: string;
5
- configSchema: import("openclaw/plugin-sdk").OpenClawPluginConfigSchema;
6
- register: NonNullable<import("openclaw/plugin-sdk/core").OpenClawPluginDefinition["register"]>;
7
- } & Pick<import("openclaw/plugin-sdk/core").OpenClawPluginDefinition, "kind">;
1
+ declare const _default: import("./runtime/plugin-api.js").PluginEntryResult;
8
2
  export default _default;
@@ -1,7 +1,21 @@
1
- import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
2
- import type { AnyAgentTool, OpenClawConfig, OpenClawPluginApi, OpenClawPluginCommandDefinition, OpenClawPluginService, OpenClawPluginServiceContext, PluginCommandContext, PluginLogger } from "openclaw/plugin-sdk/plugin-entry";
1
+ import type { AnyAgentTool, OpenClawConfig, OpenClawPluginApi, OpenClawPluginCommandDefinition, OpenClawPluginDefinition, OpenClawPluginService, OpenClawPluginServiceContext, PluginCommandContext, PluginLogger } from "openclaw/plugin-sdk/plugin-entry";
3
2
  import type { PluginRuntime } from "openclaw/plugin-sdk/runtime-store";
4
- export { definePluginEntry };
3
+ interface DefinePluginEntryOptions {
4
+ id: string;
5
+ name: string;
6
+ description: string;
7
+ kind?: OpenClawPluginDefinition["kind"];
8
+ configSchema?: unknown;
9
+ register: (api: OpenClawPluginApi) => void;
10
+ }
11
+ export interface PluginEntryResult {
12
+ id: string;
13
+ name: string;
14
+ description: string;
15
+ kind?: string;
16
+ register: (api: OpenClawPluginApi) => void;
17
+ }
18
+ export declare function definePluginEntry({ id, name, description, kind, register, }: DefinePluginEntryOptions): PluginEntryResult;
5
19
  export interface ToolContext {
6
20
  rawInput?: unknown;
7
21
  }
@@ -20,3 +34,4 @@ export type CommandContext = PluginCommandContext;
20
34
  export type OpenClawPluginConfig = OpenClawConfig;
21
35
  export type OpenClawPluginRuntime = PluginRuntime;
22
36
  export type OpenClawPluginLogger = PluginLogger;
37
+ export {};
@@ -1,2 +1,9 @@
1
- import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
2
- export { definePluginEntry };
1
+ export function definePluginEntry({ id, name, description, kind, register, }) {
2
+ return {
3
+ id,
4
+ name,
5
+ description,
6
+ ...(kind ? { kind } : {}),
7
+ register,
8
+ };
9
+ }
@@ -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
- 如果你只是日常升级,重新运行同一条命令并在菜单里选择“升级”即可。更具体的升级与重装说明见下文 [6.2 升级](#62-升级) 与 [6.3 禁用重装与清理](#63-禁用重装与清理)。
42
+ 如果你只是日常升级,重新运行同一条命令并在菜单里选择“升级”即可。更具体的升级与重装说明见下文 [7.2 升级](#72-升级) 与 [7.3 禁用重装与清理](#73-禁用重装与清理)。
43
43
 
44
- ## 3. 手动安装
44
+ ## 3. 社区安装(推荐)
45
45
 
46
- ### 3.1 拉取源码
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
- ### 3.2 安装依赖并构建
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
- ### 3.3 安装并启用插件(源码安装)
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
- ### 3.4 社区安装(npm / 社区插件)
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
- ## 5. 消息通道配置(可选)
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
- ## 6. 运维与日常管理
321
+ ## 7. 运维与日常管理
320
322
 
321
- ### 6.1 重启与验收
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
- ### 6.2 升级
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
- ### 6.3 禁用、重装与清理
365
+ ### 7.3 禁用、重装与清理
364
366
 
365
367
  禁用插件:
366
368
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "tickflow-assist",
3
3
  "name": "TickFlow Assist",
4
- "version": "0.2.0",
4
+ "version": "0.2.2",
5
5
  "description": "A-share watchlist analysis, monitoring, and alert delivery powered by TickFlow and OpenClaw.",
6
6
  "skills": [
7
7
  "skills"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tickflow-assist",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "OpenClaw plugin for TickFlow-based A-share analysis, monitoring, and alerting.",
5
5
  "license": "MIT",
6
6
  "type": "module",