klaus-ai 0.1.10
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 +135 -0
- package/dist/chunk-ATARP4LY.js +270 -0
- package/dist/chunk-ATARP4LY.js.map +1 -0
- package/dist/chunk-L3U6MK73.js +50 -0
- package/dist/chunk-L3U6MK73.js.map +1 -0
- package/dist/doctor-VY6HXIRP.js +90 -0
- package/dist/doctor-VY6HXIRP.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +691 -0
- package/dist/index.js.map +1 -0
- package/dist/setup-wizard-6EXAQOEV.js +268 -0
- package/dist/setup-wizard-6EXAQOEV.js.map +1 -0
- package/install.sh +142 -0
- package/package.json +47 -0
package/README.md
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# Klaus
|
|
2
|
+
|
|
3
|
+
在 QQ / 企业微信 中使用 Claude Code。
|
|
4
|
+
|
|
5
|
+
Klaus 基于 [Claude Code SDK](https://www.npmjs.com/package/@anthropic-ai/claude-code),将 Claude Code 接入即时通讯平台。自动处理多轮对话、会话管理、消息合并(Collect 模式),并支持图片、文件、语音等富媒体消息。
|
|
6
|
+
|
|
7
|
+
## 安装
|
|
8
|
+
|
|
9
|
+
> 包名是 `klaus-ai`,安装后使用 `klaus` 命令。
|
|
10
|
+
|
|
11
|
+
### npm(推荐)
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install -g klaus-ai
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### 一键脚本
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
curl -fsSL https://raw.githubusercontent.com/meitianwang/klaus/main/install.sh | bash
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
脚本会自动安装 Node.js(如缺失)、Claude Code CLI 和 Klaus。
|
|
24
|
+
|
|
25
|
+
## 前置条件
|
|
26
|
+
|
|
27
|
+
- **Node.js >= 18**
|
|
28
|
+
- **Claude Code CLI** — `npm install -g @anthropic-ai/claude-code`
|
|
29
|
+
- 已登录的 Claude Code 账号(运行 `claude` 完成登录)
|
|
30
|
+
|
|
31
|
+
## 快速开始
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# 首次运行自动进入配置向导
|
|
35
|
+
klaus start
|
|
36
|
+
|
|
37
|
+
# 单独运行配置
|
|
38
|
+
klaus setup
|
|
39
|
+
|
|
40
|
+
# 诊断环境问题
|
|
41
|
+
klaus doctor
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## 支持的通道
|
|
45
|
+
|
|
46
|
+
| 通道 | 传输方式 | 需要公网 IP | 富媒体支持 |
|
|
47
|
+
|------|---------|------------|-----------|
|
|
48
|
+
| QQ Bot | WebSocket | 不需要 | ✅ |
|
|
49
|
+
| 企业微信 | HTTP 回调 | 需要 | ✅ |
|
|
50
|
+
|
|
51
|
+
### QQ Bot
|
|
52
|
+
|
|
53
|
+
1. 前往 [QQ 开放平台](https://q.qq.com/) 创建机器人
|
|
54
|
+
2. 在 开发 > 开发设置 中获取 AppID 和 AppSecret
|
|
55
|
+
3. 运行 `klaus setup`,选择 QQ
|
|
56
|
+
4. 在 开发 > 沙箱配置 添加测试用户
|
|
57
|
+
5. 用手机 QQ 扫描沙箱二维码即可开始聊天
|
|
58
|
+
|
|
59
|
+
> `qq-group-bot` SDK 会在首次使用时自动安装。
|
|
60
|
+
|
|
61
|
+
#### 支持的消息类型
|
|
62
|
+
|
|
63
|
+
| 类型 | 说明 |
|
|
64
|
+
|------|------|
|
|
65
|
+
| 文本 | 直接识别 |
|
|
66
|
+
| 图片 | 下载到本地,Claude 通过 Read 工具查看 |
|
|
67
|
+
| 文件(PDF、Excel 等) | 下载到本地,Claude 通过 Read 工具查看 |
|
|
68
|
+
| 视频 / 语音 | 提示用户发送文字(暂不支持) |
|
|
69
|
+
| 表情 | 识别为 `[表情:描述]` |
|
|
70
|
+
| @提及 | 识别为 `[@用户:id]` |
|
|
71
|
+
| 引用回复 | 自动获取被引用消息的内容 |
|
|
72
|
+
|
|
73
|
+
### 企业微信 (WeCom)
|
|
74
|
+
|
|
75
|
+
1. 登录 [work.weixin.qq.com](https://work.weixin.qq.com/)
|
|
76
|
+
2. 在 我的企业 获取 Corp ID
|
|
77
|
+
3. 创建自建应用,获取 Agent ID + Secret
|
|
78
|
+
4. 在 接收消息 设置回调 URL
|
|
79
|
+
5. 运行 `klaus setup`,选择企业微信
|
|
80
|
+
|
|
81
|
+
**提示**:使用 [Cloudflare Tunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/) 将本地端口暴露到公网:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
cloudflared tunnel --url http://localhost:8080
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## 配置
|
|
88
|
+
|
|
89
|
+
配置文件:`~/.klaus/config.yaml`
|
|
90
|
+
|
|
91
|
+
```yaml
|
|
92
|
+
channel: qq # 或 wecom
|
|
93
|
+
persona: "You are a helpful AI assistant."
|
|
94
|
+
|
|
95
|
+
qq:
|
|
96
|
+
appid: "your-appid"
|
|
97
|
+
secret: "your-secret"
|
|
98
|
+
|
|
99
|
+
wecom:
|
|
100
|
+
corp_id: "your-corp-id"
|
|
101
|
+
corp_secret: "your-secret"
|
|
102
|
+
agent_id: 1000002
|
|
103
|
+
token: "callback-token"
|
|
104
|
+
encoding_aes_key: "aes-key"
|
|
105
|
+
port: 8080
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
环境变量(`QQ_BOT_APPID`、`WECOM_CORP_ID` 等)可覆盖配置文件中的值。
|
|
109
|
+
|
|
110
|
+
## 聊天命令
|
|
111
|
+
|
|
112
|
+
| 命令 | 效果 |
|
|
113
|
+
|------|------|
|
|
114
|
+
| `/new` `/reset` `/clear` | 重置当前对话 |
|
|
115
|
+
| `/help` | 显示可用命令列表 |
|
|
116
|
+
| `/session` | 查看当前会话信息(状态、模型) |
|
|
117
|
+
| `/model` | 查看当前使用的模型 |
|
|
118
|
+
| `/model <名称>` | 切换模型(sonnet / opus / haiku) |
|
|
119
|
+
|
|
120
|
+
## 工作原理
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
用户消息 → 通道 (QQ/WeCom) → 会话管理器 → ClaudeChat → Claude Code SDK
|
|
124
|
+
↑
|
|
125
|
+
LRU 淘汰
|
|
126
|
+
(最多 20 个会话)
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
- **Collect 模式**:Claude 处理中时,后续消息自动排队并合并为一条 prompt,处理完毕后一并发送。
|
|
130
|
+
- **LRU 会话管理**:最多维持 20 个并发会话,空闲最久的会话优先淘汰。
|
|
131
|
+
- **富媒体解析**:图片和文件下载到临时目录,以文件路径传递给 Claude,Claude 通过 Read 工具直接查看图片和 PDF 内容。
|
|
132
|
+
|
|
133
|
+
## License
|
|
134
|
+
|
|
135
|
+
MIT
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/i18n.ts
|
|
4
|
+
var TEXTS = {
|
|
5
|
+
// ── Setup ──
|
|
6
|
+
setup_title: {
|
|
7
|
+
en: " Klaus Setup ",
|
|
8
|
+
zh: " Klaus \u5B89\u88C5\u5F15\u5BFC "
|
|
9
|
+
},
|
|
10
|
+
config_exists: {
|
|
11
|
+
en: "Config already exists at {path}\nCurrent channel: {channel}",
|
|
12
|
+
zh: "\u914D\u7F6E\u6587\u4EF6\u5DF2\u5B58\u5728: {path}\n\u5F53\u524D\u901A\u9053: {channel}"
|
|
13
|
+
},
|
|
14
|
+
overwrite: {
|
|
15
|
+
en: "Overwrite existing config?",
|
|
16
|
+
zh: "\u662F\u5426\u8986\u76D6\u73B0\u6709\u914D\u7F6E?"
|
|
17
|
+
},
|
|
18
|
+
setup_cancelled: {
|
|
19
|
+
en: "Setup cancelled. Existing config preserved.",
|
|
20
|
+
zh: "\u5DF2\u53D6\u6D88\u3002\u4FDD\u7559\u73B0\u6709\u914D\u7F6E\u3002"
|
|
21
|
+
},
|
|
22
|
+
checking: {
|
|
23
|
+
en: "Checking prerequisites...",
|
|
24
|
+
zh: "\u68C0\u67E5\u73AF\u5883..."
|
|
25
|
+
},
|
|
26
|
+
node_ok: {
|
|
27
|
+
en: "Node.js {version}",
|
|
28
|
+
zh: "Node.js {version}"
|
|
29
|
+
},
|
|
30
|
+
node_need: {
|
|
31
|
+
en: "Node.js >= 18 required",
|
|
32
|
+
zh: "\u9700\u8981 Node.js >= 18"
|
|
33
|
+
},
|
|
34
|
+
cli_ok: {
|
|
35
|
+
en: "Claude Code CLI found",
|
|
36
|
+
zh: "Claude Code CLI \u5DF2\u5B89\u88C5"
|
|
37
|
+
},
|
|
38
|
+
cli_not_found: {
|
|
39
|
+
en: "Claude Code CLI not found. Install: npm i -g @anthropic-ai/claude-code",
|
|
40
|
+
zh: "\u672A\u627E\u5230 Claude Code CLI\u3002\u5B89\u88C5: npm i -g @anthropic-ai/claude-code"
|
|
41
|
+
},
|
|
42
|
+
checks_passed: {
|
|
43
|
+
en: "All checks passed",
|
|
44
|
+
zh: "\u6240\u6709\u68C0\u67E5\u901A\u8FC7"
|
|
45
|
+
},
|
|
46
|
+
checks_failed: {
|
|
47
|
+
en: "Some checks failed. Please fix them before continuing.",
|
|
48
|
+
zh: "\u90E8\u5206\u68C0\u67E5\u672A\u901A\u8FC7\u3002\u8BF7\u5148\u4FEE\u590D\u4EE5\u4E0A\u95EE\u9898\u3002"
|
|
49
|
+
},
|
|
50
|
+
choose_channel: {
|
|
51
|
+
en: "Choose a channel",
|
|
52
|
+
zh: "\u9009\u62E9\u901A\u9053"
|
|
53
|
+
},
|
|
54
|
+
channel_qq: {
|
|
55
|
+
en: "QQ Bot (WebSocket, no public IP needed)",
|
|
56
|
+
zh: "QQ \u673A\u5668\u4EBA (WebSocket, \u65E0\u9700\u516C\u7F51 IP)"
|
|
57
|
+
},
|
|
58
|
+
channel_wecom: {
|
|
59
|
+
en: "WeChat Work (Webhook, needs public URL)",
|
|
60
|
+
zh: "\u4F01\u4E1A\u5FAE\u4FE1 (Webhook, \u9700\u8981\u516C\u7F51\u5730\u5740)"
|
|
61
|
+
},
|
|
62
|
+
// ── QQ Guide ──
|
|
63
|
+
qq_title: {
|
|
64
|
+
en: "QQ Bot Setup",
|
|
65
|
+
zh: "QQ \u673A\u5668\u4EBA\u914D\u7F6E"
|
|
66
|
+
},
|
|
67
|
+
qq_guide: {
|
|
68
|
+
en: "How to get your QQ Bot credentials:\n\n1. Open QQ Bot Platform: https://q.qq.com/\n2. Log in with your QQ account\n3. Click 'Create Bot', fill in name and description\n4. Go to 'Development' > 'Development Settings'\n5. Find AppID and AppSecret on that page\n (AppSecret may need to click 'Reset' to reveal)\n\n\u2500\u2500 After setup, how to use the bot \u2500\u2500\n\nBots are in SANDBOX MODE by default (no review needed).\nYou CANNOT search for the bot in QQ like a normal contact.\n\nTo add users who can chat with the bot:\n1. Go to 'Development' > 'Sandbox Config' on q.qq.com\n2. Add QQ numbers of yourself and friends (up to ~20)\n3. A sandbox bot QR code / link will appear on that page\n4. Scan the QR code with your phone QQ to start chatting\n\nNote: In sandbox mode, the bot name will have a suffix\nlike 'YourBot-Testing'. This is added by QQ platform and\ncannot be removed. It does NOT affect any functionality.\nThe suffix disappears after passing the review process.\n\nFor public use (unlimited users, no name suffix):\ngo through the review at 'Management' > 'Publish'.",
|
|
69
|
+
zh: "\u5982\u4F55\u83B7\u53D6 QQ \u673A\u5668\u4EBA\u51ED\u8BC1:\n\n1. \u6253\u5F00 QQ \u5F00\u653E\u5E73\u53F0: https://q.qq.com/\n2. \u7528\u4F60\u7684 QQ \u53F7\u767B\u5F55\n3. \u70B9\u51FB\u300C\u521B\u5EFA\u673A\u5668\u4EBA\u300D, \u586B\u5199\u540D\u79F0\u548C\u7B80\u4ECB\n4. \u8FDB\u5165\u300C\u5F00\u53D1\u300D>\u300C\u5F00\u53D1\u8BBE\u7F6E\u300D\u9875\u9762\n5. \u5728\u9875\u9762\u4E0A\u627E\u5230 AppID \u548C AppSecret\n (AppSecret \u53EF\u80FD\u9700\u8981\u70B9\u300C\u91CD\u7F6E\u300D\u624D\u80FD\u770B\u5230)\n\n\u2500\u2500 \u914D\u7F6E\u5B8C\u6210\u540E, \u5982\u4F55\u4F7F\u7528\u673A\u5668\u4EBA \u2500\u2500\n\n\u673A\u5668\u4EBA\u9ED8\u8BA4\u4E3A\u300C\u6C99\u7BB1\u6A21\u5F0F\u300D, \u65E0\u9700\u63D0\u5BA1\u5373\u53EF\u4F7F\u7528\u3002\n\u6CE8\u610F: \u5728 QQ \u91CC\u641C\u7D22\u4E0D\u5230\u673A\u5668\u4EBA, \u5FC5\u987B\u901A\u8FC7\u4EE5\u4E0B\u65B9\u5F0F\u6DFB\u52A0:\n\n1. \u5728 q.qq.com \u8FDB\u5165\u300C\u5F00\u53D1\u300D>\u300C\u6C99\u7BB1\u914D\u7F6E\u300D\n2. \u6DFB\u52A0\u4F60\u81EA\u5DF1\u548C\u670B\u53CB\u7684 QQ \u53F7\u4E3A\u6D4B\u8BD5\u7528\u6237 (\u6700\u591A\u7EA6 20 \u4EBA)\n3. \u9875\u9762\u4E0A\u4F1A\u51FA\u73B0\u6C99\u7BB1\u673A\u5668\u4EBA\u7684\u4E8C\u7EF4\u7801/\u94FE\u63A5\n4. \u7528\u624B\u673A QQ \u626B\u7801\u5373\u53EF\u5F00\u59CB\u79C1\u804A\n\n\u6CE8\u610F: \u6C99\u7BB1\u6A21\u5F0F\u4E0B, \u673A\u5668\u4EBA\u540D\u5B57\u4F1A\u5E26\u300C\u6D4B\u8BD5\u4E2D\u300D\u540E\u7F00\n(\u5982\u300C\u6211\u7684Bot-\u6D4B\u8BD5\u4E2D\u300D), \u8FD9\u662F QQ \u5E73\u53F0\u5F3A\u5236\u6DFB\u52A0\u7684,\n\u65E0\u6CD5\u53BB\u6389, \u4F46\u4E0D\u5F71\u54CD\u4EFB\u4F55\u529F\u80FD\u3002\n\u901A\u8FC7\u5BA1\u6838\u540E\u540E\u7F00\u4F1A\u81EA\u52A8\u6D88\u5931\u3002\n\n\u5982\u9700\u516C\u5F00\u4F7F\u7528 (\u4E0D\u9650\u7528\u6237\u6570, \u65E0\u540D\u79F0\u540E\u7F00):\n\u5728\u300C\u7BA1\u7406\u300D>\u300C\u53D1\u5E03\u4E0A\u67B6\u300D\u63D0\u5BA1\u3002"
|
|
70
|
+
},
|
|
71
|
+
installing_qq_dep: {
|
|
72
|
+
en: "Installing qq-group-bot...",
|
|
73
|
+
zh: "\u6B63\u5728\u5B89\u88C5 qq-group-bot..."
|
|
74
|
+
},
|
|
75
|
+
qq_dep_ok: {
|
|
76
|
+
en: "qq-group-bot installed",
|
|
77
|
+
zh: "qq-group-bot \u5B89\u88C5\u5B8C\u6210"
|
|
78
|
+
},
|
|
79
|
+
qq_dep_fail: {
|
|
80
|
+
en: "Failed to install qq-group-bot. Run manually: npm install -g qq-group-bot",
|
|
81
|
+
zh: "qq-group-bot \u5B89\u88C5\u5931\u8D25\u3002\u8BF7\u624B\u52A8\u8FD0\u884C: npm install -g qq-group-bot"
|
|
82
|
+
},
|
|
83
|
+
qq_appid: {
|
|
84
|
+
en: "AppID",
|
|
85
|
+
zh: "AppID"
|
|
86
|
+
},
|
|
87
|
+
qq_secret: {
|
|
88
|
+
en: "AppSecret",
|
|
89
|
+
zh: "AppSecret"
|
|
90
|
+
},
|
|
91
|
+
// ── WeCom Guide ──
|
|
92
|
+
wecom_title: {
|
|
93
|
+
en: "WeChat Work (WeCom) Setup",
|
|
94
|
+
zh: "\u4F01\u4E1A\u5FAE\u4FE1\u914D\u7F6E"
|
|
95
|
+
},
|
|
96
|
+
wecom_guide: {
|
|
97
|
+
en: "How to get your WeCom credentials:\n\nStep 1: Get Corp ID\n - Login: https://work.weixin.qq.com/wework_admin/loginpage_wx\n - Go to 'My Enterprise' at bottom of sidebar\n - Corp ID is at the bottom of that page\n\nStep 2: Create App & Get Agent ID + Secret\n - Go to 'App Management' > 'Create App'\n - Set app name, logo, and visibility scope\n - After creation, find Agent ID and Secret on the app page\n - Secret may need to click 'View' and verify via admin's WeCom\n\nStep 3: Set Callback URL\n - On app page, find 'Receive Messages' section\n - Click 'Set API Receive'\n - Enter your callback URL: https://<your-domain>/callback\n - Set a Token (any random string)\n - Set an EncodingAESKey (click 'Random' to generate)\n - Save \u2014 WeCom will verify the URL immediately\n\nTip: Use Cloudflare Tunnel for public URL:\n cloudflared tunnel --url http://localhost:8080",
|
|
98
|
+
zh: "\u5982\u4F55\u83B7\u53D6\u4F01\u4E1A\u5FAE\u4FE1\u51ED\u8BC1:\n\n\u7B2C\u4E00\u6B65: \u83B7\u53D6 Corp ID (\u4F01\u4E1A ID)\n - \u767B\u5F55\u7BA1\u7406\u540E\u53F0: https://work.weixin.qq.com/wework_admin/loginpage_wx\n - \u70B9\u51FB\u5DE6\u4FA7\u8FB9\u680F\u5E95\u90E8\u7684\u300C\u6211\u7684\u4F01\u4E1A\u300D\n - \u9875\u9762\u6700\u4E0B\u65B9\u5C31\u662F\u300C\u4F01\u4E1A ID\u300D\n\n\u7B2C\u4E8C\u6B65: \u521B\u5EFA\u5E94\u7528, \u83B7\u53D6 Agent ID \u548C Secret\n - \u8FDB\u5165\u300C\u5E94\u7528\u7BA1\u7406\u300D>\u300C\u521B\u5EFA\u5E94\u7528\u300D\n - \u8BBE\u7F6E\u5E94\u7528\u540D\u79F0\u3001\u56FE\u6807\u3001\u53EF\u89C1\u8303\u56F4\n - \u521B\u5EFA\u5B8C\u6210\u540E, \u5728\u5E94\u7528\u8BE6\u60C5\u9875\u627E\u5230 AgentId \u548C Secret\n - Secret \u53EF\u80FD\u9700\u8981\u70B9\u300C\u67E5\u770B\u300D\u5E76\u901A\u8FC7\u7BA1\u7406\u5458\u7684\u4F01\u4E1A\u5FAE\u4FE1\u9A8C\u8BC1\n\n\u7B2C\u4E09\u6B65: \u8BBE\u7F6E\u56DE\u8C03\u5730\u5740\n - \u5728\u5E94\u7528\u8BE6\u60C5\u9875\u627E\u5230\u300C\u63A5\u6536\u6D88\u606F\u300D\u677F\u5757\n - \u70B9\u51FB\u300C\u8BBE\u7F6EAPI\u63A5\u6536\u300D\n - \u586B\u5165\u56DE\u8C03\u5730\u5740: https://<\u4F60\u7684\u57DF\u540D>/callback\n - \u8BBE\u7F6E\u4E00\u4E2A Token (\u968F\u610F\u5B57\u7B26\u4E32\u5373\u53EF)\n - \u8BBE\u7F6E EncodingAESKey (\u70B9\u300C\u968F\u673A\u83B7\u53D6\u300D\u81EA\u52A8\u751F\u6210)\n - \u4FDD\u5B58 \u2014 \u4F01\u4E1A\u5FAE\u4FE1\u4F1A\u7ACB\u5373\u9A8C\u8BC1\u8BE5\u5730\u5740\n\n\u63D0\u793A: \u7528 Cloudflare Tunnel \u66B4\u9732\u672C\u5730\u7AEF\u53E3\u5230\u516C\u7F51:\n cloudflared tunnel --url http://localhost:8080"
|
|
99
|
+
},
|
|
100
|
+
wecom_corp_id: {
|
|
101
|
+
en: "Corp ID",
|
|
102
|
+
zh: "\u4F01\u4E1A ID (Corp ID)"
|
|
103
|
+
},
|
|
104
|
+
wecom_secret: {
|
|
105
|
+
en: "Corp Secret",
|
|
106
|
+
zh: "\u5E94\u7528 Secret"
|
|
107
|
+
},
|
|
108
|
+
wecom_agent_id: {
|
|
109
|
+
en: "Agent ID",
|
|
110
|
+
zh: "\u5E94\u7528 ID (Agent ID)"
|
|
111
|
+
},
|
|
112
|
+
wecom_token: {
|
|
113
|
+
en: "Callback Token",
|
|
114
|
+
zh: "\u56DE\u8C03 Token"
|
|
115
|
+
},
|
|
116
|
+
wecom_aes_key: {
|
|
117
|
+
en: "Encoding AES Key",
|
|
118
|
+
zh: "EncodingAESKey"
|
|
119
|
+
},
|
|
120
|
+
wecom_port: {
|
|
121
|
+
en: "Port (default 8080)",
|
|
122
|
+
zh: "\u7AEF\u53E3 (\u9ED8\u8BA4 8080)"
|
|
123
|
+
},
|
|
124
|
+
wecom_verify: {
|
|
125
|
+
en: "Testing WeCom access_token...",
|
|
126
|
+
zh: "\u6D4B\u8BD5\u4F01\u4E1A\u5FAE\u4FE1 access_token..."
|
|
127
|
+
},
|
|
128
|
+
wecom_verify_ok: {
|
|
129
|
+
en: "Access token obtained successfully!",
|
|
130
|
+
zh: "access_token \u83B7\u53D6\u6210\u529F!"
|
|
131
|
+
},
|
|
132
|
+
// ── Persona ──
|
|
133
|
+
persona_title: {
|
|
134
|
+
en: "Bot Persona",
|
|
135
|
+
zh: "\u673A\u5668\u4EBA\u4EBA\u8BBE"
|
|
136
|
+
},
|
|
137
|
+
persona_method: {
|
|
138
|
+
en: "How do you want to set the persona?",
|
|
139
|
+
zh: "\u5982\u4F55\u8BBE\u7F6E\u4EBA\u8BBE?"
|
|
140
|
+
},
|
|
141
|
+
persona_from_clipboard: {
|
|
142
|
+
en: "Paste from clipboard (recommended \u2014 copy text first, then select this)",
|
|
143
|
+
zh: "\u4ECE\u526A\u8D34\u677F\u7C98\u8D34 (\u63A8\u8350 \u2014 \u5148\u590D\u5236\u5185\u5BB9\uFF0C\u518D\u9009\u6B64\u9879)"
|
|
144
|
+
},
|
|
145
|
+
persona_clipboard_preview: {
|
|
146
|
+
en: "Clipboard content preview:",
|
|
147
|
+
zh: "\u526A\u8D34\u677F\u5185\u5BB9\u9884\u89C8:"
|
|
148
|
+
},
|
|
149
|
+
persona_clipboard_confirm: {
|
|
150
|
+
en: "Use this as persona?",
|
|
151
|
+
zh: "\u4F7F\u7528\u8FD9\u6BB5\u5185\u5BB9\u4F5C\u4E3A\u4EBA\u8BBE?"
|
|
152
|
+
},
|
|
153
|
+
persona_clipboard_empty: {
|
|
154
|
+
en: "Clipboard is empty. Skipping persona.",
|
|
155
|
+
zh: "\u526A\u8D34\u677F\u4E3A\u7A7A\uFF0C\u8DF3\u8FC7\u4EBA\u8BBE\u8BBE\u7F6E\u3002"
|
|
156
|
+
},
|
|
157
|
+
persona_lines: {
|
|
158
|
+
en: "lines",
|
|
159
|
+
zh: "\u884C"
|
|
160
|
+
},
|
|
161
|
+
persona_from_file: {
|
|
162
|
+
en: "From file",
|
|
163
|
+
zh: "\u4ECE\u6587\u4EF6\u8BFB\u53D6"
|
|
164
|
+
},
|
|
165
|
+
persona_direct: {
|
|
166
|
+
en: "Type directly (single line only)",
|
|
167
|
+
zh: "\u76F4\u63A5\u8F93\u5165 (\u4EC5\u652F\u6301\u5355\u884C)"
|
|
168
|
+
},
|
|
169
|
+
persona_skip_option: {
|
|
170
|
+
en: "Skip (use default Claude behavior)",
|
|
171
|
+
zh: "\u8DF3\u8FC7 (\u4F7F\u7528\u9ED8\u8BA4 Claude \u884C\u4E3A)"
|
|
172
|
+
},
|
|
173
|
+
persona_file_prompt: {
|
|
174
|
+
en: "Path to persona file (text/markdown)",
|
|
175
|
+
zh: "\u4EBA\u8BBE\u6587\u4EF6\u8DEF\u5F84 (\u6587\u672C\u6216 Markdown \u6587\u4EF6)"
|
|
176
|
+
},
|
|
177
|
+
persona_file_required: {
|
|
178
|
+
en: "File path is required",
|
|
179
|
+
zh: "\u8BF7\u8F93\u5165\u6587\u4EF6\u8DEF\u5F84"
|
|
180
|
+
},
|
|
181
|
+
persona_file_not_found: {
|
|
182
|
+
en: "File not found",
|
|
183
|
+
zh: "\u6587\u4EF6\u4E0D\u5B58\u5728"
|
|
184
|
+
},
|
|
185
|
+
persona_prompt: {
|
|
186
|
+
en: "Enter system prompt (single line)",
|
|
187
|
+
zh: "\u8F93\u5165 system prompt (\u5355\u884C)"
|
|
188
|
+
},
|
|
189
|
+
persona_placeholder: {
|
|
190
|
+
en: "You are a helpful AI assistant...",
|
|
191
|
+
zh: "\u4F60\u662F\u4E00\u4E2A\u53CB\u597D\u7684 AI \u52A9\u624B..."
|
|
192
|
+
},
|
|
193
|
+
persona_saved: {
|
|
194
|
+
en: "Persona configured",
|
|
195
|
+
zh: "\u4EBA\u8BBE\u5DF2\u914D\u7F6E"
|
|
196
|
+
},
|
|
197
|
+
persona_skipped: {
|
|
198
|
+
en: "Using default Claude behavior",
|
|
199
|
+
zh: "\u4F7F\u7528\u9ED8\u8BA4 Claude \u884C\u4E3A"
|
|
200
|
+
},
|
|
201
|
+
qq_verify_ok: {
|
|
202
|
+
en: "Credentials saved (will verify on first start)",
|
|
203
|
+
zh: "\u51ED\u8BC1\u5DF2\u4FDD\u5B58 (\u5C06\u5728\u9996\u6B21\u542F\u52A8\u65F6\u9A8C\u8BC1)"
|
|
204
|
+
},
|
|
205
|
+
// ── Chat Commands ──
|
|
206
|
+
cmd_reset: {
|
|
207
|
+
en: "Session reset.",
|
|
208
|
+
zh: "\u4F1A\u8BDD\u5DF2\u91CD\u7F6E\u3002"
|
|
209
|
+
},
|
|
210
|
+
cmd_help: {
|
|
211
|
+
en: "Available commands:\n/new /reset /clear \u2014 Reset conversation\n/help \u2014 Show this help\n/session \u2014 Show session info\n/model \u2014 Show current model\n/model <name> \u2014 Switch model (sonnet/opus/haiku)",
|
|
212
|
+
zh: "\u53EF\u7528\u547D\u4EE4:\n/new /reset /clear \u2014 \u91CD\u7F6E\u5BF9\u8BDD\n/help \u2014 \u663E\u793A\u5E2E\u52A9\n/session \u2014 \u67E5\u770B\u4F1A\u8BDD\u4FE1\u606F\n/model \u2014 \u67E5\u770B\u5F53\u524D\u6A21\u578B\n/model <\u540D\u79F0> \u2014 \u5207\u6362\u6A21\u578B (sonnet/opus/haiku)"
|
|
213
|
+
},
|
|
214
|
+
cmd_session_info: {
|
|
215
|
+
en: "Session: {key}\nStatus: {status}\nModel: {model}",
|
|
216
|
+
zh: "\u4F1A\u8BDD: {key}\n\u72B6\u6001: {status}\n\u6A21\u578B: {model}"
|
|
217
|
+
},
|
|
218
|
+
cmd_session_active: {
|
|
219
|
+
en: "active",
|
|
220
|
+
zh: "\u6D3B\u8DC3"
|
|
221
|
+
},
|
|
222
|
+
cmd_session_idle: {
|
|
223
|
+
en: "idle",
|
|
224
|
+
zh: "\u7A7A\u95F2"
|
|
225
|
+
},
|
|
226
|
+
cmd_model_current: {
|
|
227
|
+
en: "Current model: {model}",
|
|
228
|
+
zh: "\u5F53\u524D\u6A21\u578B: {model}"
|
|
229
|
+
},
|
|
230
|
+
cmd_model_switched: {
|
|
231
|
+
en: "Model switched to: {model}",
|
|
232
|
+
zh: "\u6A21\u578B\u5DF2\u5207\u6362\u4E3A: {model}"
|
|
233
|
+
},
|
|
234
|
+
cmd_model_unknown: {
|
|
235
|
+
en: "Unknown model: {name}\nAvailable: sonnet, opus, haiku",
|
|
236
|
+
zh: "\u672A\u77E5\u6A21\u578B: {name}\n\u53EF\u9009: sonnet, opus, haiku"
|
|
237
|
+
},
|
|
238
|
+
cmd_default_model: {
|
|
239
|
+
en: "default",
|
|
240
|
+
zh: "\u9ED8\u8BA4"
|
|
241
|
+
},
|
|
242
|
+
// ── Done ──
|
|
243
|
+
config_saved: {
|
|
244
|
+
en: "Config saved to {path}",
|
|
245
|
+
zh: "\u914D\u7F6E\u5DF2\u4FDD\u5B58\u5230 {path}"
|
|
246
|
+
},
|
|
247
|
+
setup_done: {
|
|
248
|
+
en: "Setup complete! Run: klaus start",
|
|
249
|
+
zh: "\u5B89\u88C5\u5B8C\u6210! \u8FD0\u884C: klaus start"
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
var currentLang = "en";
|
|
253
|
+
function setLang(lang) {
|
|
254
|
+
currentLang = lang;
|
|
255
|
+
}
|
|
256
|
+
function t(key, vars) {
|
|
257
|
+
let text = TEXTS[key]?.[currentLang] ?? key;
|
|
258
|
+
if (vars) {
|
|
259
|
+
for (const [k, v] of Object.entries(vars)) {
|
|
260
|
+
text = text.replaceAll(`{${k}}`, v);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return text;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
export {
|
|
267
|
+
setLang,
|
|
268
|
+
t
|
|
269
|
+
};
|
|
270
|
+
//# sourceMappingURL=chunk-ATARP4LY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/i18n.ts"],"sourcesContent":["type Lang = \"en\" | \"zh\";\n\nconst TEXTS: Record<string, Record<Lang, string>> = {\n // ── Setup ──\n setup_title: {\n en: \" Klaus Setup \",\n zh: \" Klaus 安装引导 \",\n },\n config_exists: {\n en: \"Config already exists at {path}\\nCurrent channel: {channel}\",\n zh: \"配置文件已存在: {path}\\n当前通道: {channel}\",\n },\n overwrite: {\n en: \"Overwrite existing config?\",\n zh: \"是否覆盖现有配置?\",\n },\n setup_cancelled: {\n en: \"Setup cancelled. Existing config preserved.\",\n zh: \"已取消。保留现有配置。\",\n },\n checking: {\n en: \"Checking prerequisites...\",\n zh: \"检查环境...\",\n },\n node_ok: {\n en: \"Node.js {version}\",\n zh: \"Node.js {version}\",\n },\n node_need: {\n en: \"Node.js >= 18 required\",\n zh: \"需要 Node.js >= 18\",\n },\n cli_ok: {\n en: \"Claude Code CLI found\",\n zh: \"Claude Code CLI 已安装\",\n },\n cli_not_found: {\n en: \"Claude Code CLI not found. Install: npm i -g @anthropic-ai/claude-code\",\n zh: \"未找到 Claude Code CLI。安装: npm i -g @anthropic-ai/claude-code\",\n },\n checks_passed: {\n en: \"All checks passed\",\n zh: \"所有检查通过\",\n },\n checks_failed: {\n en: \"Some checks failed. Please fix them before continuing.\",\n zh: \"部分检查未通过。请先修复以上问题。\",\n },\n choose_channel: {\n en: \"Choose a channel\",\n zh: \"选择通道\",\n },\n channel_qq: {\n en: \"QQ Bot (WebSocket, no public IP needed)\",\n zh: \"QQ 机器人 (WebSocket, 无需公网 IP)\",\n },\n channel_wecom: {\n en: \"WeChat Work (Webhook, needs public URL)\",\n zh: \"企业微信 (Webhook, 需要公网地址)\",\n },\n // ── QQ Guide ──\n qq_title: {\n en: \"QQ Bot Setup\",\n zh: \"QQ 机器人配置\",\n },\n qq_guide: {\n en:\n \"How to get your QQ Bot credentials:\\n\\n\" +\n \"1. Open QQ Bot Platform: https://q.qq.com/\\n\" +\n \"2. Log in with your QQ account\\n\" +\n \"3. Click 'Create Bot', fill in name and description\\n\" +\n \"4. Go to 'Development' > 'Development Settings'\\n\" +\n \"5. Find AppID and AppSecret on that page\\n\" +\n \" (AppSecret may need to click 'Reset' to reveal)\\n\\n\" +\n \"── After setup, how to use the bot ──\\n\\n\" +\n \"Bots are in SANDBOX MODE by default (no review needed).\\n\" +\n \"You CANNOT search for the bot in QQ like a normal contact.\\n\\n\" +\n \"To add users who can chat with the bot:\\n\" +\n \"1. Go to 'Development' > 'Sandbox Config' on q.qq.com\\n\" +\n \"2. Add QQ numbers of yourself and friends (up to ~20)\\n\" +\n \"3. A sandbox bot QR code / link will appear on that page\\n\" +\n \"4. Scan the QR code with your phone QQ to start chatting\\n\\n\" +\n \"Note: In sandbox mode, the bot name will have a suffix\\n\" +\n \"like 'YourBot-Testing'. This is added by QQ platform and\\n\" +\n \"cannot be removed. It does NOT affect any functionality.\\n\" +\n \"The suffix disappears after passing the review process.\\n\\n\" +\n \"For public use (unlimited users, no name suffix):\\n\" +\n \"go through the review at 'Management' > 'Publish'.\",\n zh:\n \"如何获取 QQ 机器人凭证:\\n\\n\" +\n \"1. 打开 QQ 开放平台: https://q.qq.com/\\n\" +\n \"2. 用你的 QQ 号登录\\n\" +\n \"3. 点击「创建机器人」, 填写名称和简介\\n\" +\n \"4. 进入「开发」>「开发设置」页面\\n\" +\n \"5. 在页面上找到 AppID 和 AppSecret\\n\" +\n \" (AppSecret 可能需要点「重置」才能看到)\\n\\n\" +\n \"── 配置完成后, 如何使用机器人 ──\\n\\n\" +\n \"机器人默认为「沙箱模式」, 无需提审即可使用。\\n\" +\n \"注意: 在 QQ 里搜索不到机器人, 必须通过以下方式添加:\\n\\n\" +\n \"1. 在 q.qq.com 进入「开发」>「沙箱配置」\\n\" +\n \"2. 添加你自己和朋友的 QQ 号为测试用户 (最多约 20 人)\\n\" +\n \"3. 页面上会出现沙箱机器人的二维码/链接\\n\" +\n \"4. 用手机 QQ 扫码即可开始私聊\\n\\n\" +\n \"注意: 沙箱模式下, 机器人名字会带「测试中」后缀\\n\" +\n \"(如「我的Bot-测试中」), 这是 QQ 平台强制添加的,\\n\" +\n \"无法去掉, 但不影响任何功能。\\n\" +\n \"通过审核后后缀会自动消失。\\n\\n\" +\n \"如需公开使用 (不限用户数, 无名称后缀):\\n\" +\n \"在「管理」>「发布上架」提审。\",\n },\n installing_qq_dep: {\n en: \"Installing qq-group-bot...\",\n zh: \"正在安装 qq-group-bot...\",\n },\n qq_dep_ok: {\n en: \"qq-group-bot installed\",\n zh: \"qq-group-bot 安装完成\",\n },\n qq_dep_fail: {\n en: \"Failed to install qq-group-bot. Run manually: npm install -g qq-group-bot\",\n zh: \"qq-group-bot 安装失败。请手动运行: npm install -g qq-group-bot\",\n },\n qq_appid: {\n en: \"AppID\",\n zh: \"AppID\",\n },\n qq_secret: {\n en: \"AppSecret\",\n zh: \"AppSecret\",\n },\n // ── WeCom Guide ──\n wecom_title: {\n en: \"WeChat Work (WeCom) Setup\",\n zh: \"企业微信配置\",\n },\n wecom_guide: {\n en:\n \"How to get your WeCom credentials:\\n\\n\" +\n \"Step 1: Get Corp ID\\n\" +\n \" - Login: https://work.weixin.qq.com/wework_admin/loginpage_wx\\n\" +\n \" - Go to 'My Enterprise' at bottom of sidebar\\n\" +\n \" - Corp ID is at the bottom of that page\\n\\n\" +\n \"Step 2: Create App & Get Agent ID + Secret\\n\" +\n \" - Go to 'App Management' > 'Create App'\\n\" +\n \" - Set app name, logo, and visibility scope\\n\" +\n \" - After creation, find Agent ID and Secret on the app page\\n\" +\n \" - Secret may need to click 'View' and verify via admin's WeCom\\n\\n\" +\n \"Step 3: Set Callback URL\\n\" +\n \" - On app page, find 'Receive Messages' section\\n\" +\n \" - Click 'Set API Receive'\\n\" +\n \" - Enter your callback URL: https://<your-domain>/callback\\n\" +\n \" - Set a Token (any random string)\\n\" +\n \" - Set an EncodingAESKey (click 'Random' to generate)\\n\" +\n \" - Save — WeCom will verify the URL immediately\\n\\n\" +\n \"Tip: Use Cloudflare Tunnel for public URL:\\n\" +\n \" cloudflared tunnel --url http://localhost:8080\",\n zh:\n \"如何获取企业微信凭证:\\n\\n\" +\n \"第一步: 获取 Corp ID (企业 ID)\\n\" +\n \" - 登录管理后台: https://work.weixin.qq.com/wework_admin/loginpage_wx\\n\" +\n \" - 点击左侧边栏底部的「我的企业」\\n\" +\n \" - 页面最下方就是「企业 ID」\\n\\n\" +\n \"第二步: 创建应用, 获取 Agent ID 和 Secret\\n\" +\n \" - 进入「应用管理」>「创建应用」\\n\" +\n \" - 设置应用名称、图标、可见范围\\n\" +\n \" - 创建完成后, 在应用详情页找到 AgentId 和 Secret\\n\" +\n \" - Secret 可能需要点「查看」并通过管理员的企业微信验证\\n\\n\" +\n \"第三步: 设置回调地址\\n\" +\n \" - 在应用详情页找到「接收消息」板块\\n\" +\n \" - 点击「设置API接收」\\n\" +\n \" - 填入回调地址: https://<你的域名>/callback\\n\" +\n \" - 设置一个 Token (随意字符串即可)\\n\" +\n \" - 设置 EncodingAESKey (点「随机获取」自动生成)\\n\" +\n \" - 保存 — 企业微信会立即验证该地址\\n\\n\" +\n \"提示: 用 Cloudflare Tunnel 暴露本地端口到公网:\\n\" +\n \" cloudflared tunnel --url http://localhost:8080\",\n },\n wecom_corp_id: {\n en: \"Corp ID\",\n zh: \"企业 ID (Corp ID)\",\n },\n wecom_secret: {\n en: \"Corp Secret\",\n zh: \"应用 Secret\",\n },\n wecom_agent_id: {\n en: \"Agent ID\",\n zh: \"应用 ID (Agent ID)\",\n },\n wecom_token: {\n en: \"Callback Token\",\n zh: \"回调 Token\",\n },\n wecom_aes_key: {\n en: \"Encoding AES Key\",\n zh: \"EncodingAESKey\",\n },\n wecom_port: {\n en: \"Port (default 8080)\",\n zh: \"端口 (默认 8080)\",\n },\n wecom_verify: {\n en: \"Testing WeCom access_token...\",\n zh: \"测试企业微信 access_token...\",\n },\n wecom_verify_ok: {\n en: \"Access token obtained successfully!\",\n zh: \"access_token 获取成功!\",\n },\n // ── Persona ──\n persona_title: {\n en: \"Bot Persona\",\n zh: \"机器人人设\",\n },\n persona_method: {\n en: \"How do you want to set the persona?\",\n zh: \"如何设置人设?\",\n },\n persona_from_clipboard: {\n en: \"Paste from clipboard (recommended — copy text first, then select this)\",\n zh: \"从剪贴板粘贴 (推荐 — 先复制内容,再选此项)\",\n },\n persona_clipboard_preview: {\n en: \"Clipboard content preview:\",\n zh: \"剪贴板内容预览:\",\n },\n persona_clipboard_confirm: {\n en: \"Use this as persona?\",\n zh: \"使用这段内容作为人设?\",\n },\n persona_clipboard_empty: {\n en: \"Clipboard is empty. Skipping persona.\",\n zh: \"剪贴板为空,跳过人设设置。\",\n },\n persona_lines: {\n en: \"lines\",\n zh: \"行\",\n },\n persona_from_file: {\n en: \"From file\",\n zh: \"从文件读取\",\n },\n persona_direct: {\n en: \"Type directly (single line only)\",\n zh: \"直接输入 (仅支持单行)\",\n },\n persona_skip_option: {\n en: \"Skip (use default Claude behavior)\",\n zh: \"跳过 (使用默认 Claude 行为)\",\n },\n persona_file_prompt: {\n en: \"Path to persona file (text/markdown)\",\n zh: \"人设文件路径 (文本或 Markdown 文件)\",\n },\n persona_file_required: {\n en: \"File path is required\",\n zh: \"请输入文件路径\",\n },\n persona_file_not_found: {\n en: \"File not found\",\n zh: \"文件不存在\",\n },\n persona_prompt: {\n en: \"Enter system prompt (single line)\",\n zh: \"输入 system prompt (单行)\",\n },\n persona_placeholder: {\n en: \"You are a helpful AI assistant...\",\n zh: \"你是一个友好的 AI 助手...\",\n },\n persona_saved: {\n en: \"Persona configured\",\n zh: \"人设已配置\",\n },\n persona_skipped: {\n en: \"Using default Claude behavior\",\n zh: \"使用默认 Claude 行为\",\n },\n qq_verify_ok: {\n en: \"Credentials saved (will verify on first start)\",\n zh: \"凭证已保存 (将在首次启动时验证)\",\n },\n // ── Chat Commands ──\n cmd_reset: {\n en: \"Session reset.\",\n zh: \"会话已重置。\",\n },\n cmd_help: {\n en:\n \"Available commands:\\n\" +\n \"/new /reset /clear — Reset conversation\\n\" +\n \"/help — Show this help\\n\" +\n \"/session — Show session info\\n\" +\n \"/model — Show current model\\n\" +\n \"/model <name> — Switch model (sonnet/opus/haiku)\",\n zh:\n \"可用命令:\\n\" +\n \"/new /reset /clear — 重置对话\\n\" +\n \"/help — 显示帮助\\n\" +\n \"/session — 查看会话信息\\n\" +\n \"/model — 查看当前模型\\n\" +\n \"/model <名称> — 切换模型 (sonnet/opus/haiku)\",\n },\n cmd_session_info: {\n en: \"Session: {key}\\nStatus: {status}\\nModel: {model}\",\n zh: \"会话: {key}\\n状态: {status}\\n模型: {model}\",\n },\n cmd_session_active: {\n en: \"active\",\n zh: \"活跃\",\n },\n cmd_session_idle: {\n en: \"idle\",\n zh: \"空闲\",\n },\n cmd_model_current: {\n en: \"Current model: {model}\",\n zh: \"当前模型: {model}\",\n },\n cmd_model_switched: {\n en: \"Model switched to: {model}\",\n zh: \"模型已切换为: {model}\",\n },\n cmd_model_unknown: {\n en: \"Unknown model: {name}\\nAvailable: sonnet, opus, haiku\",\n zh: \"未知模型: {name}\\n可选: sonnet, opus, haiku\",\n },\n cmd_default_model: {\n en: \"default\",\n zh: \"默认\",\n },\n // ── Done ──\n config_saved: {\n en: \"Config saved to {path}\",\n zh: \"配置已保存到 {path}\",\n },\n setup_done: {\n en: \"Setup complete! Run: klaus start\",\n zh: \"安装完成! 运行: klaus start\",\n },\n};\n\nlet currentLang: Lang = \"en\";\n\nexport function setLang(lang: Lang): void {\n currentLang = lang;\n}\n\nexport function getLang(): Lang {\n return currentLang;\n}\n\nexport function t(key: string, vars?: Record<string, string>): string {\n let text = TEXTS[key]?.[currentLang] ?? key;\n if (vars) {\n for (const [k, v] of Object.entries(vars)) {\n text = text.replaceAll(`{${k}}`, v);\n }\n }\n return text;\n}\n"],"mappings":";;;AAEA,IAAM,QAA8C;AAAA;AAAA,EAElD,aAAa;AAAA,IACX,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,eAAe;AAAA,IACb,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,WAAW;AAAA,IACT,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,iBAAiB;AAAA,IACf,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,SAAS;AAAA,IACP,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,WAAW;AAAA,IACT,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,QAAQ;AAAA,IACN,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,eAAe;AAAA,IACb,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,eAAe;AAAA,IACb,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,eAAe;AAAA,IACb,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,gBAAgB;AAAA,IACd,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,YAAY;AAAA,IACV,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,eAAe;AAAA,IACb,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA;AAAA,EAEA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,UAAU;AAAA,IACR,IACE;AAAA,IAqBF,IACE;AAAA,EAoBJ;AAAA,EACA,mBAAmB;AAAA,IACjB,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,WAAW;AAAA,IACT,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,aAAa;AAAA,IACX,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,WAAW;AAAA,IACT,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA;AAAA,EAEA,aAAa;AAAA,IACX,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,aAAa;AAAA,IACX,IACE;AAAA,IAmBF,IACE;AAAA,EAmBJ;AAAA,EACA,eAAe;AAAA,IACb,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,cAAc;AAAA,IACZ,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,gBAAgB;AAAA,IACd,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,aAAa;AAAA,IACX,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,eAAe;AAAA,IACb,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,YAAY;AAAA,IACV,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,cAAc;AAAA,IACZ,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,iBAAiB;AAAA,IACf,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA;AAAA,EAEA,eAAe;AAAA,IACb,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,gBAAgB;AAAA,IACd,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,wBAAwB;AAAA,IACtB,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,2BAA2B;AAAA,IACzB,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,2BAA2B;AAAA,IACzB,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,yBAAyB;AAAA,IACvB,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,eAAe;AAAA,IACb,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,mBAAmB;AAAA,IACjB,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,gBAAgB;AAAA,IACd,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,qBAAqB;AAAA,IACnB,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,qBAAqB;AAAA,IACnB,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,uBAAuB;AAAA,IACrB,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,wBAAwB;AAAA,IACtB,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,gBAAgB;AAAA,IACd,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,qBAAqB;AAAA,IACnB,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,eAAe;AAAA,IACb,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,iBAAiB;AAAA,IACf,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,cAAc;AAAA,IACZ,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA;AAAA,EAEA,WAAW;AAAA,IACT,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,UAAU;AAAA,IACR,IACE;AAAA,IAMF,IACE;AAAA,EAMJ;AAAA,EACA,kBAAkB;AAAA,IAChB,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,oBAAoB;AAAA,IAClB,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,kBAAkB;AAAA,IAChB,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,mBAAmB;AAAA,IACjB,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,oBAAoB;AAAA,IAClB,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,mBAAmB;AAAA,IACjB,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,mBAAmB;AAAA,IACjB,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA;AAAA,EAEA,cAAc;AAAA,IACZ,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EACA,YAAY;AAAA,IACV,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AACF;AAEA,IAAI,cAAoB;AAEjB,SAAS,QAAQ,MAAkB;AACxC,gBAAc;AAChB;AAMO,SAAS,EAAE,KAAa,MAAuC;AACpE,MAAI,OAAO,MAAM,GAAG,IAAI,WAAW,KAAK;AACxC,MAAI,MAAM;AACR,eAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,IAAI,GAAG;AACzC,aAAO,KAAK,WAAW,IAAI,CAAC,KAAK,CAAC;AAAA,IACpC;AAAA,EACF;AACA,SAAO;AACT;","names":[]}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/config.ts
|
|
4
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
|
|
5
|
+
import { join } from "path";
|
|
6
|
+
import { homedir } from "os";
|
|
7
|
+
import yaml from "js-yaml";
|
|
8
|
+
var CONFIG_DIR = join(homedir(), ".klaus");
|
|
9
|
+
var CONFIG_FILE = join(CONFIG_DIR, "config.yaml");
|
|
10
|
+
function loadConfig() {
|
|
11
|
+
if (!existsSync(CONFIG_FILE)) return {};
|
|
12
|
+
const content = readFileSync(CONFIG_FILE, "utf-8");
|
|
13
|
+
return yaml.load(content) ?? {};
|
|
14
|
+
}
|
|
15
|
+
function saveConfig(data) {
|
|
16
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
17
|
+
writeFileSync(CONFIG_FILE, yaml.dump(data, { flowLevel: -1 }), "utf-8");
|
|
18
|
+
}
|
|
19
|
+
function getChannelName() {
|
|
20
|
+
const cfg = loadConfig();
|
|
21
|
+
return cfg.channel ?? "qq";
|
|
22
|
+
}
|
|
23
|
+
function loadQQBotConfig() {
|
|
24
|
+
const cfg = loadConfig().qq ?? {};
|
|
25
|
+
return {
|
|
26
|
+
appid: cfg.appid ?? process.env.QQ_BOT_APPID ?? "",
|
|
27
|
+
secret: cfg.secret ?? process.env.QQ_BOT_SECRET ?? ""
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function loadWeComConfig() {
|
|
31
|
+
const cfg = loadConfig().wecom ?? {};
|
|
32
|
+
return {
|
|
33
|
+
corpId: cfg.corp_id ?? process.env.WECOM_CORP_ID ?? "",
|
|
34
|
+
corpSecret: cfg.corp_secret ?? process.env.WECOM_CORP_SECRET ?? "",
|
|
35
|
+
agentId: Number(cfg.agent_id ?? process.env.WECOM_AGENT_ID ?? 0),
|
|
36
|
+
token: cfg.token ?? process.env.WECOM_TOKEN ?? "",
|
|
37
|
+
encodingAesKey: cfg.encoding_aes_key ?? process.env.WECOM_ENCODING_AES_KEY ?? "",
|
|
38
|
+
port: Number(cfg.port ?? process.env.WECOM_PORT ?? 8080)
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export {
|
|
43
|
+
CONFIG_FILE,
|
|
44
|
+
loadConfig,
|
|
45
|
+
saveConfig,
|
|
46
|
+
getChannelName,
|
|
47
|
+
loadQQBotConfig,
|
|
48
|
+
loadWeComConfig
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=chunk-L3U6MK73.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/config.ts"],"sourcesContent":["import { readFileSync, writeFileSync, mkdirSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport yaml from \"js-yaml\";\nimport type { QQBotConfig, WeComConfig } from \"./types.js\";\n\nexport const CONFIG_DIR = join(homedir(), \".klaus\");\nexport const CONFIG_FILE = join(CONFIG_DIR, \"config.yaml\");\n\nexport function loadConfig(): Record<string, unknown> {\n if (!existsSync(CONFIG_FILE)) return {};\n const content = readFileSync(CONFIG_FILE, \"utf-8\");\n return (yaml.load(content) as Record<string, unknown>) ?? {};\n}\n\nexport function saveConfig(data: Record<string, unknown>): void {\n mkdirSync(CONFIG_DIR, { recursive: true });\n writeFileSync(CONFIG_FILE, yaml.dump(data, { flowLevel: -1 }), \"utf-8\");\n}\n\nexport function getChannelName(): string {\n const cfg = loadConfig();\n return (cfg.channel as string) ?? \"qq\";\n}\n\nexport function loadQQBotConfig(): QQBotConfig {\n const cfg = (loadConfig().qq as Record<string, string>) ?? {};\n return {\n appid: cfg.appid ?? process.env.QQ_BOT_APPID ?? \"\",\n secret: cfg.secret ?? process.env.QQ_BOT_SECRET ?? \"\",\n };\n}\n\nexport function loadWeComConfig(): WeComConfig {\n const cfg = (loadConfig().wecom as Record<string, unknown>) ?? {};\n return {\n corpId: (cfg.corp_id as string) ?? process.env.WECOM_CORP_ID ?? \"\",\n corpSecret:\n (cfg.corp_secret as string) ?? process.env.WECOM_CORP_SECRET ?? \"\",\n agentId: Number(cfg.agent_id ?? process.env.WECOM_AGENT_ID ?? 0),\n token: (cfg.token as string) ?? process.env.WECOM_TOKEN ?? \"\",\n encodingAesKey:\n (cfg.encoding_aes_key as string) ??\n process.env.WECOM_ENCODING_AES_KEY ??\n \"\",\n port: Number(cfg.port ?? process.env.WECOM_PORT ?? 8080),\n };\n}\n"],"mappings":";;;AAAA,SAAS,cAAc,eAAe,WAAW,kBAAkB;AACnE,SAAS,YAAY;AACrB,SAAS,eAAe;AACxB,OAAO,UAAU;AAGV,IAAM,aAAa,KAAK,QAAQ,GAAG,QAAQ;AAC3C,IAAM,cAAc,KAAK,YAAY,aAAa;AAElD,SAAS,aAAsC;AACpD,MAAI,CAAC,WAAW,WAAW,EAAG,QAAO,CAAC;AACtC,QAAM,UAAU,aAAa,aAAa,OAAO;AACjD,SAAQ,KAAK,KAAK,OAAO,KAAiC,CAAC;AAC7D;AAEO,SAAS,WAAW,MAAqC;AAC9D,YAAU,YAAY,EAAE,WAAW,KAAK,CAAC;AACzC,gBAAc,aAAa,KAAK,KAAK,MAAM,EAAE,WAAW,GAAG,CAAC,GAAG,OAAO;AACxE;AAEO,SAAS,iBAAyB;AACvC,QAAM,MAAM,WAAW;AACvB,SAAQ,IAAI,WAAsB;AACpC;AAEO,SAAS,kBAA+B;AAC7C,QAAM,MAAO,WAAW,EAAE,MAAiC,CAAC;AAC5D,SAAO;AAAA,IACL,OAAO,IAAI,SAAS,QAAQ,IAAI,gBAAgB;AAAA,IAChD,QAAQ,IAAI,UAAU,QAAQ,IAAI,iBAAiB;AAAA,EACrD;AACF;AAEO,SAAS,kBAA+B;AAC7C,QAAM,MAAO,WAAW,EAAE,SAAqC,CAAC;AAChE,SAAO;AAAA,IACL,QAAS,IAAI,WAAsB,QAAQ,IAAI,iBAAiB;AAAA,IAChE,YACG,IAAI,eAA0B,QAAQ,IAAI,qBAAqB;AAAA,IAClE,SAAS,OAAO,IAAI,YAAY,QAAQ,IAAI,kBAAkB,CAAC;AAAA,IAC/D,OAAQ,IAAI,SAAoB,QAAQ,IAAI,eAAe;AAAA,IAC3D,gBACG,IAAI,oBACL,QAAQ,IAAI,0BACZ;AAAA,IACF,MAAM,OAAO,IAAI,QAAQ,QAAQ,IAAI,cAAc,IAAI;AAAA,EACzD;AACF;","names":[]}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
CONFIG_FILE,
|
|
4
|
+
loadConfig
|
|
5
|
+
} from "./chunk-L3U6MK73.js";
|
|
6
|
+
|
|
7
|
+
// src/doctor.ts
|
|
8
|
+
import { execSync } from "child_process";
|
|
9
|
+
import { existsSync } from "fs";
|
|
10
|
+
import pc from "picocolors";
|
|
11
|
+
function which(cmd) {
|
|
12
|
+
try {
|
|
13
|
+
return execSync(`which ${cmd}`, { encoding: "utf-8" }).trim();
|
|
14
|
+
} catch {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function check(label, ok, hint = "") {
|
|
19
|
+
const mark = ok ? pc.green("\u2713") : pc.red("\u2717");
|
|
20
|
+
const suffix = !ok && hint ? ` \u2192 ${hint}` : "";
|
|
21
|
+
console.log(` ${mark} ${label}${suffix}`);
|
|
22
|
+
return ok;
|
|
23
|
+
}
|
|
24
|
+
function runDoctor() {
|
|
25
|
+
console.log("\nKlaus Doctor\n");
|
|
26
|
+
let allOk = true;
|
|
27
|
+
const [major] = process.versions.node.split(".").map(Number);
|
|
28
|
+
allOk &&= check(
|
|
29
|
+
`Node.js ${process.version}`,
|
|
30
|
+
major >= 18,
|
|
31
|
+
"need Node.js >= 18"
|
|
32
|
+
);
|
|
33
|
+
const claudePath = which("claude");
|
|
34
|
+
allOk &&= check(
|
|
35
|
+
"Claude Code CLI",
|
|
36
|
+
claudePath !== null,
|
|
37
|
+
"npm i -g @anthropic-ai/claude-code"
|
|
38
|
+
);
|
|
39
|
+
const cfgExists = existsSync(CONFIG_FILE);
|
|
40
|
+
allOk &&= check(
|
|
41
|
+
`Config file (${CONFIG_FILE})`,
|
|
42
|
+
cfgExists,
|
|
43
|
+
"run: klaus setup"
|
|
44
|
+
);
|
|
45
|
+
if (cfgExists) {
|
|
46
|
+
const cfg = loadConfig();
|
|
47
|
+
const channel = cfg.channel ?? "";
|
|
48
|
+
allOk &&= check(
|
|
49
|
+
`Channel configured: ${channel}`,
|
|
50
|
+
channel === "qq" || channel === "wecom",
|
|
51
|
+
"unknown channel"
|
|
52
|
+
);
|
|
53
|
+
if (channel === "qq") {
|
|
54
|
+
const qqCfg = cfg.qq ?? {};
|
|
55
|
+
allOk &&= check(
|
|
56
|
+
"QQ Bot credentials",
|
|
57
|
+
Boolean(qqCfg.appid && qqCfg.secret),
|
|
58
|
+
"missing appid or secret"
|
|
59
|
+
);
|
|
60
|
+
} else if (channel === "wecom") {
|
|
61
|
+
const wc = cfg.wecom ?? {};
|
|
62
|
+
const required = [
|
|
63
|
+
"corp_id",
|
|
64
|
+
"corp_secret",
|
|
65
|
+
"agent_id",
|
|
66
|
+
"token",
|
|
67
|
+
"encoding_aes_key"
|
|
68
|
+
];
|
|
69
|
+
const missing = required.filter((k) => !wc[k]);
|
|
70
|
+
allOk &&= check(
|
|
71
|
+
"WeCom credentials",
|
|
72
|
+
missing.length === 0,
|
|
73
|
+
`missing: ${missing.join(", ")}`
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
console.log();
|
|
78
|
+
if (allOk) {
|
|
79
|
+
console.log(` ${pc.green("All checks passed!")} Run: klaus start
|
|
80
|
+
`);
|
|
81
|
+
} else {
|
|
82
|
+
console.log(
|
|
83
|
+
" Some checks failed. Fix the issues above and re-run doctor.\n"
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
export {
|
|
88
|
+
runDoctor
|
|
89
|
+
};
|
|
90
|
+
//# sourceMappingURL=doctor-VY6HXIRP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/doctor.ts"],"sourcesContent":["import { execSync } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport pc from \"picocolors\";\nimport { CONFIG_FILE, loadConfig } from \"./config.js\";\n\nfunction which(cmd: string): string | null {\n try {\n return execSync(`which ${cmd}`, { encoding: \"utf-8\" }).trim();\n } catch {\n return null;\n }\n}\n\nfunction check(label: string, ok: boolean, hint = \"\"): boolean {\n const mark = ok ? pc.green(\"✓\") : pc.red(\"✗\");\n const suffix = !ok && hint ? ` → ${hint}` : \"\";\n console.log(` ${mark} ${label}${suffix}`);\n return ok;\n}\n\nexport function runDoctor(): void {\n console.log(\"\\nKlaus Doctor\\n\");\n let allOk = true;\n\n // Node.js version\n const [major] = process.versions.node.split(\".\").map(Number);\n allOk &&= check(\n `Node.js ${process.version}`,\n major >= 18,\n \"need Node.js >= 18\",\n );\n\n // Claude CLI\n const claudePath = which(\"claude\");\n allOk &&= check(\n \"Claude Code CLI\",\n claudePath !== null,\n \"npm i -g @anthropic-ai/claude-code\",\n );\n\n // Config file\n const cfgExists = existsSync(CONFIG_FILE);\n allOk &&= check(\n `Config file (${CONFIG_FILE})`,\n cfgExists,\n \"run: klaus setup\",\n );\n\n if (cfgExists) {\n const cfg = loadConfig();\n const channel = (cfg.channel as string) ?? \"\";\n allOk &&= check(\n `Channel configured: ${channel}`,\n channel === \"qq\" || channel === \"wecom\",\n \"unknown channel\",\n );\n\n if (channel === \"qq\") {\n const qqCfg = (cfg.qq as Record<string, string>) ?? {};\n allOk &&= check(\n \"QQ Bot credentials\",\n Boolean(qqCfg.appid && qqCfg.secret),\n \"missing appid or secret\",\n );\n } else if (channel === \"wecom\") {\n const wc = (cfg.wecom as Record<string, unknown>) ?? {};\n const required = [\n \"corp_id\",\n \"corp_secret\",\n \"agent_id\",\n \"token\",\n \"encoding_aes_key\",\n ];\n const missing = required.filter((k) => !wc[k]);\n allOk &&= check(\n \"WeCom credentials\",\n missing.length === 0,\n `missing: ${missing.join(\", \")}`,\n );\n }\n }\n\n console.log();\n if (allOk) {\n console.log(` ${pc.green(\"All checks passed!\")} Run: klaus start\\n`);\n } else {\n console.log(\n \" Some checks failed. Fix the issues above and re-run doctor.\\n\",\n );\n }\n}\n"],"mappings":";;;;;;;AAAA,SAAS,gBAAgB;AACzB,SAAS,kBAAkB;AAC3B,OAAO,QAAQ;AAGf,SAAS,MAAM,KAA4B;AACzC,MAAI;AACF,WAAO,SAAS,SAAS,GAAG,IAAI,EAAE,UAAU,QAAQ,CAAC,EAAE,KAAK;AAAA,EAC9D,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,MAAM,OAAe,IAAa,OAAO,IAAa;AAC7D,QAAM,OAAO,KAAK,GAAG,MAAM,QAAG,IAAI,GAAG,IAAI,QAAG;AAC5C,QAAM,SAAS,CAAC,MAAM,OAAO,YAAO,IAAI,KAAK;AAC7C,UAAQ,IAAI,KAAK,IAAI,IAAI,KAAK,GAAG,MAAM,EAAE;AACzC,SAAO;AACT;AAEO,SAAS,YAAkB;AAChC,UAAQ,IAAI,kBAAkB;AAC9B,MAAI,QAAQ;AAGZ,QAAM,CAAC,KAAK,IAAI,QAAQ,SAAS,KAAK,MAAM,GAAG,EAAE,IAAI,MAAM;AAC3D,YAAU;AAAA,IACR,WAAW,QAAQ,OAAO;AAAA,IAC1B,SAAS;AAAA,IACT;AAAA,EACF;AAGA,QAAM,aAAa,MAAM,QAAQ;AACjC,YAAU;AAAA,IACR;AAAA,IACA,eAAe;AAAA,IACf;AAAA,EACF;AAGA,QAAM,YAAY,WAAW,WAAW;AACxC,YAAU;AAAA,IACR,gBAAgB,WAAW;AAAA,IAC3B;AAAA,IACA;AAAA,EACF;AAEA,MAAI,WAAW;AACb,UAAM,MAAM,WAAW;AACvB,UAAM,UAAW,IAAI,WAAsB;AAC3C,cAAU;AAAA,MACR,uBAAuB,OAAO;AAAA,MAC9B,YAAY,QAAQ,YAAY;AAAA,MAChC;AAAA,IACF;AAEA,QAAI,YAAY,MAAM;AACpB,YAAM,QAAS,IAAI,MAAiC,CAAC;AACrD,gBAAU;AAAA,QACR;AAAA,QACA,QAAQ,MAAM,SAAS,MAAM,MAAM;AAAA,QACnC;AAAA,MACF;AAAA,IACF,WAAW,YAAY,SAAS;AAC9B,YAAM,KAAM,IAAI,SAAqC,CAAC;AACtD,YAAM,WAAW;AAAA,QACf;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA,YAAM,UAAU,SAAS,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AAC7C,gBAAU;AAAA,QACR;AAAA,QACA,QAAQ,WAAW;AAAA,QACnB,YAAY,QAAQ,KAAK,IAAI,CAAC;AAAA,MAChC;AAAA,IACF;AAAA,EACF;AAEA,UAAQ,IAAI;AACZ,MAAI,OAAO;AACT,YAAQ,IAAI,KAAK,GAAG,MAAM,oBAAoB,CAAC;AAAA,CAAqB;AAAA,EACtE,OAAO;AACL,YAAQ;AAAA,MACN;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
|
package/dist/index.d.ts
ADDED