golembot 0.1.0
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/LICENSE +21 -0
- package/README.md +191 -0
- package/dist/channel.d.ts +22 -0
- package/dist/channel.d.ts.map +1 -0
- package/dist/channel.js +14 -0
- package/dist/channel.js.map +1 -0
- package/dist/channels/dingtalk.d.ts +12 -0
- package/dist/channels/dingtalk.d.ts.map +1 -0
- package/dist/channels/dingtalk.js +66 -0
- package/dist/channels/dingtalk.js.map +1 -0
- package/dist/channels/feishu.d.ts +13 -0
- package/dist/channels/feishu.d.ts.map +1 -0
- package/dist/channels/feishu.js +73 -0
- package/dist/channels/feishu.js.map +1 -0
- package/dist/channels/wecom.d.ts +15 -0
- package/dist/channels/wecom.d.ts.map +1 -0
- package/dist/channels/wecom.js +152 -0
- package/dist/channels/wecom.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +303 -0
- package/dist/cli.js.map +1 -0
- package/dist/engine.d.ts +65 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +747 -0
- package/dist/engine.js.map +1 -0
- package/dist/gateway.d.ts +11 -0
- package/dist/gateway.d.ts.map +1 -0
- package/dist/gateway.js +118 -0
- package/dist/gateway.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +114 -0
- package/dist/index.js.map +1 -0
- package/dist/onboard.d.ts +7 -0
- package/dist/onboard.d.ts.map +1 -0
- package/dist/onboard.js +285 -0
- package/dist/onboard.js.map +1 -0
- package/dist/server.d.ts +10 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +112 -0
- package/dist/server.js.map +1 -0
- package/dist/session.d.ts +4 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +45 -0
- package/dist/session.js.map +1 -0
- package/dist/workspace.d.ts +52 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/workspace.js +168 -0
- package/dist/workspace.js.map +1 -0
- package/package.json +91 -0
- package/skills/general/SKILL.md +63 -0
- package/skills/im-adapter/SKILL.md +48 -0
- package/templates/code-reviewer/README.md +14 -0
- package/templates/code-reviewer/golem.yaml +6 -0
- package/templates/code-reviewer/skills/code-review/SKILL.md +39 -0
- package/templates/customer-support/README.md +15 -0
- package/templates/customer-support/faq.md +10 -0
- package/templates/customer-support/golem.yaml +11 -0
- package/templates/customer-support/skills/faq-support/SKILL.md +34 -0
- package/templates/data-analyst/README.md +15 -0
- package/templates/data-analyst/golem.yaml +6 -0
- package/templates/data-analyst/skills/data-analysis/SKILL.md +45 -0
- package/templates/data-analyst/skills/data-analysis/calc.py +62 -0
- package/templates/meeting-notes/README.md +14 -0
- package/templates/meeting-notes/golem.yaml +6 -0
- package/templates/meeting-notes/skills/meeting/SKILL.md +51 -0
- package/templates/ops-assistant/README.md +16 -0
- package/templates/ops-assistant/golem.yaml +11 -0
- package/templates/ops-assistant/skills/ops/SKILL.md +29 -0
- package/templates/research/README.md +14 -0
- package/templates/research/golem.yaml +6 -0
- package/templates/research/skills/research/SKILL.md +56 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 GolemBot Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# GolemBot — Local-First AI Assistant Platform
|
|
2
|
+
|
|
3
|
+
> **Coding Agent = the soul, GolemBot = the body of clay.**
|
|
4
|
+
>
|
|
5
|
+
> Use the Coding Agents you already have (Cursor / Claude Code / OpenCode) as the brain — so they can do more than just chat, they can actually get things done.
|
|
6
|
+
|
|
7
|
+
GolemBot is a TypeScript library + CLI that wraps Coding Agent CLIs into a unified AI assistant engine. One command spins up an intelligent assistant connected to Feishu, DingTalk, or WeCom — running locally, fully transparent, and engine-swappable.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **Three Engines** — Cursor / Claude Code / OpenCode, switch with a single config line
|
|
12
|
+
- **Built-in IM Channels** — Native adapters for Feishu, DingTalk, and WeCom, no code required
|
|
13
|
+
- **Library First** — `createAssistant()` API embeds into any Node.js project
|
|
14
|
+
- **Directory = Assistant** — `ls` the directory to see what the assistant knows, what it can do, and what it has done
|
|
15
|
+
- **Skill = Capability** — Drop Markdown + scripts into the `skills/` directory, and the assistant gains new abilities automatically
|
|
16
|
+
- **Multi-User Isolation** — Routes by sessionKey, each user gets an independent session
|
|
17
|
+
- **HTTP Service** — Built-in SSE streaming API with Bearer token auth
|
|
18
|
+
- **Docker Deployment** — One-click deploy to the cloud
|
|
19
|
+
|
|
20
|
+
## Quick Start
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# Install
|
|
24
|
+
npm install -g golembot
|
|
25
|
+
|
|
26
|
+
# Guided setup (recommended)
|
|
27
|
+
mkdir my-assistant && cd my-assistant
|
|
28
|
+
golembot onboard
|
|
29
|
+
|
|
30
|
+
# Or initialize manually
|
|
31
|
+
golembot init
|
|
32
|
+
|
|
33
|
+
# Start the gateway (IM channels + HTTP service)
|
|
34
|
+
golembot gateway
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Try it in 30 seconds:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
mkdir my-bot && cd my-bot
|
|
41
|
+
golembot init -e claude-code -n my-bot
|
|
42
|
+
golembot run
|
|
43
|
+
# > Write a Python script to calculate file sizes in the current directory
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Architecture
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
Feishu / DingTalk / WeCom / HTTP API
|
|
50
|
+
│
|
|
51
|
+
▼
|
|
52
|
+
┌─────────────────────────┐
|
|
53
|
+
│ Gateway Service │
|
|
54
|
+
│ (Channel adapters + │
|
|
55
|
+
│ HTTP service) │
|
|
56
|
+
└────────────┬────────────┘
|
|
57
|
+
│
|
|
58
|
+
createAssistant()
|
|
59
|
+
│
|
|
60
|
+
┌───────┼───────┐
|
|
61
|
+
▼ ▼ ▼
|
|
62
|
+
Cursor Claude OpenCode
|
|
63
|
+
Code
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Core design: The Gateway is a long-running service that reuses the `createAssistant()` library API internally, with an IM channel adapter layer on top.
|
|
67
|
+
|
|
68
|
+
## Engine Comparison
|
|
69
|
+
|
|
70
|
+
| | Cursor | Claude Code | OpenCode |
|
|
71
|
+
|---|---|---|---|
|
|
72
|
+
| Spawn Method | child_process.spawn | child_process.spawn | child_process.spawn |
|
|
73
|
+
| Skill Injection | `.cursor/skills/` | `.claude/skills/` + CLAUDE.md | `.opencode/skills/` + opencode.json |
|
|
74
|
+
| Session Resume | `--resume` | `--resume` | `--session` |
|
|
75
|
+
| API Key | CURSOR_API_KEY | ANTHROPIC_API_KEY | Depends on Provider |
|
|
76
|
+
|
|
77
|
+
The exposed `StreamEvent` interface is identical across engines — switching engines requires zero changes to your application code.
|
|
78
|
+
|
|
79
|
+
## Usage
|
|
80
|
+
|
|
81
|
+
### Option 1: CLI (fastest way to get started)
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
golembot init # Initialize an assistant
|
|
85
|
+
golembot run # REPL conversation
|
|
86
|
+
golembot gateway # Start IM + HTTP service
|
|
87
|
+
golembot onboard # Guided setup
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Option 2: Library Import
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
import { createAssistant } from 'golembot';
|
|
94
|
+
|
|
95
|
+
const assistant = createAssistant({ dir: './my-agent' });
|
|
96
|
+
|
|
97
|
+
for await (const event of assistant.chat('Analyze the competitor data')) {
|
|
98
|
+
if (event.type === 'text') process.stdout.write(event.content);
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Option 3: Embed Anywhere
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
import { createAssistant } from 'golembot';
|
|
106
|
+
const bot = createAssistant({ dir: './slack-bot' });
|
|
107
|
+
|
|
108
|
+
slackApp.message(async ({ message, say }) => {
|
|
109
|
+
let reply = '';
|
|
110
|
+
for await (const event of bot.chat(message.text, {
|
|
111
|
+
sessionKey: `slack:${message.user}`,
|
|
112
|
+
})) {
|
|
113
|
+
if (event.type === 'text') reply += event.content;
|
|
114
|
+
}
|
|
115
|
+
await say(reply);
|
|
116
|
+
});
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Configuration
|
|
120
|
+
|
|
121
|
+
`golem.yaml` — the single config file for an assistant:
|
|
122
|
+
|
|
123
|
+
```yaml
|
|
124
|
+
name: my-assistant
|
|
125
|
+
engine: claude-code
|
|
126
|
+
model: openrouter/anthropic/claude-sonnet-4
|
|
127
|
+
|
|
128
|
+
channels:
|
|
129
|
+
feishu:
|
|
130
|
+
appId: ${FEISHU_APP_ID}
|
|
131
|
+
appSecret: ${FEISHU_APP_SECRET}
|
|
132
|
+
dingtalk:
|
|
133
|
+
clientId: ${DINGTALK_CLIENT_ID}
|
|
134
|
+
clientSecret: ${DINGTALK_CLIENT_SECRET}
|
|
135
|
+
|
|
136
|
+
gateway:
|
|
137
|
+
port: 3000
|
|
138
|
+
token: ${GOLEM_TOKEN}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Sensitive fields support `${ENV_VAR}` references to environment variables.
|
|
142
|
+
|
|
143
|
+
## Skill System
|
|
144
|
+
|
|
145
|
+
A Skill is the unit of assistant capability — a directory containing `SKILL.md` (knowledge and instructions) and optional supporting files (scripts, templates, etc.).
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
skills/
|
|
149
|
+
├── general/ # General assistant (built-in)
|
|
150
|
+
│ └── SKILL.md
|
|
151
|
+
├── im-adapter/ # IM reply conventions (built-in)
|
|
152
|
+
│ └── SKILL.md
|
|
153
|
+
└── my-custom-skill/ # Your own Skill
|
|
154
|
+
├── SKILL.md
|
|
155
|
+
└── analyze.py
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Want to add a capability? Drop a folder into `skills/`. Want to remove one? Delete the folder. `ls skills/` is the complete list of what the assistant can do.
|
|
159
|
+
|
|
160
|
+
## Docker Deployment
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
# In the assistant directory
|
|
164
|
+
docker compose up -d
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Or use a Dockerfile:
|
|
168
|
+
|
|
169
|
+
```dockerfile
|
|
170
|
+
FROM node:22-slim
|
|
171
|
+
RUN npm install -g golembot
|
|
172
|
+
WORKDIR /assistant
|
|
173
|
+
COPY . .
|
|
174
|
+
EXPOSE 3000
|
|
175
|
+
CMD ["golembot", "gateway"]
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Development
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
git clone https://github.com/0xranx/golembot.git
|
|
182
|
+
cd golembot
|
|
183
|
+
pnpm install
|
|
184
|
+
pnpm run build
|
|
185
|
+
pnpm run test # Unit tests
|
|
186
|
+
pnpm run e2e:opencode # End-to-end tests (requires API Key)
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## License
|
|
190
|
+
|
|
191
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface ChannelMessage {
|
|
2
|
+
channelType: string;
|
|
3
|
+
senderId: string;
|
|
4
|
+
senderName?: string;
|
|
5
|
+
chatId: string;
|
|
6
|
+
chatType: 'dm' | 'group';
|
|
7
|
+
text: string;
|
|
8
|
+
raw: unknown;
|
|
9
|
+
}
|
|
10
|
+
export interface ChannelAdapter {
|
|
11
|
+
readonly name: string;
|
|
12
|
+
start(onMessage: (msg: ChannelMessage) => void): Promise<void>;
|
|
13
|
+
reply(msg: ChannelMessage, text: string): Promise<void>;
|
|
14
|
+
stop(): Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
export declare function buildSessionKey(msg: ChannelMessage): string;
|
|
17
|
+
/**
|
|
18
|
+
* Strip @mention tags from the text, returning only the user's actual message.
|
|
19
|
+
* Handles common IM @mention formats: `@BotName`, `<at user_id="xxx">BotName</at>` etc.
|
|
20
|
+
*/
|
|
21
|
+
export declare function stripMention(text: string): string;
|
|
22
|
+
//# sourceMappingURL=channel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,IAAI,GAAG,OAAO,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,OAAO,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/D,KAAK,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,CAE3D;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKjD"}
|
package/dist/channel.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function buildSessionKey(msg) {
|
|
2
|
+
return `${msg.channelType}:${msg.chatId}:${msg.senderId}`;
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* Strip @mention tags from the text, returning only the user's actual message.
|
|
6
|
+
* Handles common IM @mention formats: `@BotName`, `<at user_id="xxx">BotName</at>` etc.
|
|
7
|
+
*/
|
|
8
|
+
export function stripMention(text) {
|
|
9
|
+
return text
|
|
10
|
+
.replace(/<at[^>]*>.*?<\/at>/gi, '')
|
|
11
|
+
.replace(/@\S+/g, '')
|
|
12
|
+
.trim();
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=channel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel.js","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AAiBA,MAAM,UAAU,eAAe,CAAC,GAAmB;IACjD,OAAO,GAAG,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;AAC5D,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,OAAO,IAAI;SACR,OAAO,CAAC,sBAAsB,EAAE,EAAE,CAAC;SACnC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;SACpB,IAAI,EAAE,CAAC;AACZ,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ChannelAdapter, ChannelMessage } from '../channel.js';
|
|
2
|
+
import type { DingtalkChannelConfig } from '../workspace.js';
|
|
3
|
+
export declare class DingtalkAdapter implements ChannelAdapter {
|
|
4
|
+
readonly name = "dingtalk";
|
|
5
|
+
private config;
|
|
6
|
+
private dwClient;
|
|
7
|
+
constructor(config: DingtalkChannelConfig);
|
|
8
|
+
start(onMessage: (msg: ChannelMessage) => void): Promise<void>;
|
|
9
|
+
reply(msg: ChannelMessage, text: string): Promise<void>;
|
|
10
|
+
stop(): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=dingtalk.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dingtalk.d.ts","sourceRoot":"","sources":["../../src/channels/dingtalk.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAE7D,qBAAa,eAAgB,YAAW,cAAc;IACpD,QAAQ,CAAC,IAAI,cAAc;IAC3B,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,QAAQ,CAAM;gBAEV,MAAM,EAAE,qBAAqB;IAInC,KAAK,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IA8C9D,KAAK,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBvD,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAG5B"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export class DingtalkAdapter {
|
|
2
|
+
name = 'dingtalk';
|
|
3
|
+
config;
|
|
4
|
+
dwClient;
|
|
5
|
+
constructor(config) {
|
|
6
|
+
this.config = config;
|
|
7
|
+
}
|
|
8
|
+
async start(onMessage) {
|
|
9
|
+
let sdk;
|
|
10
|
+
try {
|
|
11
|
+
sdk = await import('dingtalk-stream');
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
throw new Error('DingTalk adapter requires dingtalk-stream. Install it: npm install dingtalk-stream');
|
|
15
|
+
}
|
|
16
|
+
const { DWClient, TOPIC_ROBOT } = sdk;
|
|
17
|
+
this.dwClient = new DWClient({
|
|
18
|
+
clientId: this.config.clientId,
|
|
19
|
+
clientSecret: this.config.clientSecret,
|
|
20
|
+
});
|
|
21
|
+
this.dwClient.registerCallbackListener(TOPIC_ROBOT, async (res) => {
|
|
22
|
+
const data = JSON.parse(res.data);
|
|
23
|
+
const text = data.text?.content?.trim() || '';
|
|
24
|
+
if (!text)
|
|
25
|
+
return;
|
|
26
|
+
const isGroup = data.conversationType === '2';
|
|
27
|
+
const channelMsg = {
|
|
28
|
+
channelType: 'dingtalk',
|
|
29
|
+
senderId: data.senderStaffId || data.senderId || '',
|
|
30
|
+
senderName: data.senderNick,
|
|
31
|
+
chatId: data.conversationId || '',
|
|
32
|
+
chatType: isGroup ? 'group' : 'dm',
|
|
33
|
+
text,
|
|
34
|
+
raw: { ...data, _sessionWebhook: data.sessionWebhook },
|
|
35
|
+
};
|
|
36
|
+
onMessage(channelMsg);
|
|
37
|
+
this.dwClient.socketCallBackResponse(res.headers.messageId, { status: 'SUCCESS' });
|
|
38
|
+
});
|
|
39
|
+
await this.dwClient.connect();
|
|
40
|
+
console.log(`[dingtalk] Stream connection established`);
|
|
41
|
+
}
|
|
42
|
+
async reply(msg, text) {
|
|
43
|
+
const raw = msg.raw;
|
|
44
|
+
const webhook = raw?._sessionWebhook;
|
|
45
|
+
if (!webhook)
|
|
46
|
+
return;
|
|
47
|
+
const body = {
|
|
48
|
+
msgtype: 'text',
|
|
49
|
+
text: { content: text },
|
|
50
|
+
};
|
|
51
|
+
const accessToken = await this.dwClient?.getAccessToken?.();
|
|
52
|
+
const headers = { 'Content-Type': 'application/json' };
|
|
53
|
+
if (accessToken) {
|
|
54
|
+
headers['x-acs-dingtalk-access-token'] = accessToken;
|
|
55
|
+
}
|
|
56
|
+
await fetch(webhook, {
|
|
57
|
+
method: 'POST',
|
|
58
|
+
headers,
|
|
59
|
+
body: JSON.stringify(body),
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
async stop() {
|
|
63
|
+
this.dwClient = null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=dingtalk.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dingtalk.js","sourceRoot":"","sources":["../../src/channels/dingtalk.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ChannelAdapter, ChannelMessage } from '../channel.js';
|
|
2
|
+
import type { FeishuChannelConfig } from '../workspace.js';
|
|
3
|
+
export declare class FeishuAdapter implements ChannelAdapter {
|
|
4
|
+
readonly name = "feishu";
|
|
5
|
+
private config;
|
|
6
|
+
private client;
|
|
7
|
+
private wsClient;
|
|
8
|
+
constructor(config: FeishuChannelConfig);
|
|
9
|
+
start(onMessage: (msg: ChannelMessage) => void): Promise<void>;
|
|
10
|
+
reply(msg: ChannelMessage, text: string): Promise<void>;
|
|
11
|
+
stop(): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=feishu.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feishu.d.ts","sourceRoot":"","sources":["../../src/channels/feishu.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAE3D,qBAAa,aAAc,YAAW,cAAc;IAClD,QAAQ,CAAC,IAAI,YAAY;IACzB,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,QAAQ,CAAM;gBAEV,MAAM,EAAE,mBAAmB;IAIjC,KAAK,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAuD9D,KAAK,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYvD,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAM5B"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
export class FeishuAdapter {
|
|
2
|
+
name = 'feishu';
|
|
3
|
+
config;
|
|
4
|
+
client;
|
|
5
|
+
wsClient;
|
|
6
|
+
constructor(config) {
|
|
7
|
+
this.config = config;
|
|
8
|
+
}
|
|
9
|
+
async start(onMessage) {
|
|
10
|
+
let lark;
|
|
11
|
+
try {
|
|
12
|
+
lark = await import('@larksuiteoapi/node-sdk');
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
throw new Error('Feishu adapter requires @larksuiteoapi/node-sdk. Install it: npm install @larksuiteoapi/node-sdk');
|
|
16
|
+
}
|
|
17
|
+
const baseConfig = {
|
|
18
|
+
appId: this.config.appId,
|
|
19
|
+
appSecret: this.config.appSecret,
|
|
20
|
+
};
|
|
21
|
+
this.client = new lark.Client(baseConfig);
|
|
22
|
+
const eventDispatcher = new lark.EventDispatcher({}).register({
|
|
23
|
+
'im.message.receive_v1': async (data) => {
|
|
24
|
+
const { message, sender } = data;
|
|
25
|
+
if (message.message_type !== 'text')
|
|
26
|
+
return;
|
|
27
|
+
let text = '';
|
|
28
|
+
try {
|
|
29
|
+
text = JSON.parse(message.content).text;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const chatType = message.chat_type === 'p2p' ? 'dm' : 'group';
|
|
35
|
+
const channelMsg = {
|
|
36
|
+
channelType: 'feishu',
|
|
37
|
+
senderId: sender.sender_id?.open_id || sender.sender_id?.user_id || '',
|
|
38
|
+
senderName: sender.sender_id?.open_id,
|
|
39
|
+
chatId: message.chat_id,
|
|
40
|
+
chatType,
|
|
41
|
+
text,
|
|
42
|
+
raw: data,
|
|
43
|
+
};
|
|
44
|
+
onMessage(channelMsg);
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
this.wsClient = new lark.WSClient({
|
|
48
|
+
...baseConfig,
|
|
49
|
+
loggerLevel: lark.LoggerLevel.info,
|
|
50
|
+
});
|
|
51
|
+
await this.wsClient.start({ eventDispatcher });
|
|
52
|
+
console.log(`[feishu] WebSocket connection established`);
|
|
53
|
+
}
|
|
54
|
+
async reply(msg, text) {
|
|
55
|
+
if (!this.client)
|
|
56
|
+
return;
|
|
57
|
+
await this.client.im.v1.message.create({
|
|
58
|
+
params: { receive_id_type: 'chat_id' },
|
|
59
|
+
data: {
|
|
60
|
+
receive_id: msg.chatId,
|
|
61
|
+
content: JSON.stringify({ text }),
|
|
62
|
+
msg_type: 'text',
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
async stop() {
|
|
67
|
+
// WSClient doesn't expose a clean close method in current SDK version;
|
|
68
|
+
// setting to null allows GC to collect.
|
|
69
|
+
this.wsClient = null;
|
|
70
|
+
this.client = null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=feishu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feishu.js","sourceRoot":"","sources":["../../src/channels/feishu.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ChannelAdapter, ChannelMessage } from '../channel.js';
|
|
2
|
+
import type { WecomChannelConfig } from '../workspace.js';
|
|
3
|
+
export declare class WecomAdapter implements ChannelAdapter {
|
|
4
|
+
readonly name = "wecom";
|
|
5
|
+
private config;
|
|
6
|
+
private server;
|
|
7
|
+
private accessToken;
|
|
8
|
+
private tokenExpiresAt;
|
|
9
|
+
constructor(config: WecomChannelConfig);
|
|
10
|
+
private getAccessToken;
|
|
11
|
+
start(onMessage: (msg: ChannelMessage) => void): Promise<void>;
|
|
12
|
+
reply(msg: ChannelMessage, text: string): Promise<void>;
|
|
13
|
+
stop(): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=wecom.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wecom.d.ts","sourceRoot":"","sources":["../../src/channels/wecom.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAW1D,qBAAa,YAAa,YAAW,cAAc;IACjD,QAAQ,CAAC,IAAI,WAAW;IACxB,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,MAAM,CAAgD;IAC9D,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,cAAc,CAAa;gBAEvB,MAAM,EAAE,kBAAkB;YAIxB,cAAc;IAetB,KAAK,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IA2G9D,KAAK,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBvD,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAS5B"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { createServer } from 'node:http';
|
|
2
|
+
function readBody(req) {
|
|
3
|
+
return new Promise((resolve, reject) => {
|
|
4
|
+
const chunks = [];
|
|
5
|
+
req.on('data', (c) => chunks.push(c));
|
|
6
|
+
req.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
|
|
7
|
+
req.on('error', reject);
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
export class WecomAdapter {
|
|
11
|
+
name = 'wecom';
|
|
12
|
+
config;
|
|
13
|
+
server = null;
|
|
14
|
+
accessToken = '';
|
|
15
|
+
tokenExpiresAt = 0;
|
|
16
|
+
constructor(config) {
|
|
17
|
+
this.config = config;
|
|
18
|
+
}
|
|
19
|
+
async getAccessToken() {
|
|
20
|
+
if (this.accessToken && Date.now() < this.tokenExpiresAt) {
|
|
21
|
+
return this.accessToken;
|
|
22
|
+
}
|
|
23
|
+
const url = `https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=${this.config.corpId}&corpsecret=${this.config.secret}`;
|
|
24
|
+
const res = await fetch(url);
|
|
25
|
+
const data = await res.json();
|
|
26
|
+
if (data.errcode && data.errcode !== 0) {
|
|
27
|
+
throw new Error(`WeCom getAccessToken failed: ${data.errmsg}`);
|
|
28
|
+
}
|
|
29
|
+
this.accessToken = data.access_token;
|
|
30
|
+
this.tokenExpiresAt = Date.now() + (data.expires_in - 300) * 1000;
|
|
31
|
+
return this.accessToken;
|
|
32
|
+
}
|
|
33
|
+
async start(onMessage) {
|
|
34
|
+
let wecomCrypto;
|
|
35
|
+
let xml2js;
|
|
36
|
+
try {
|
|
37
|
+
wecomCrypto = await import('@wecom/crypto');
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
throw new Error('WeCom adapter requires @wecom/crypto. Install it: npm install @wecom/crypto');
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
xml2js = await import('xml2js');
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
throw new Error('WeCom adapter requires xml2js. Install it: npm install xml2js');
|
|
47
|
+
}
|
|
48
|
+
const { getSignature, decrypt } = wecomCrypto;
|
|
49
|
+
this.server = createServer(async (req, res) => {
|
|
50
|
+
const url = new URL(req.url || '/', `http://${req.headers.host || 'localhost'}`);
|
|
51
|
+
if (!url.pathname.startsWith('/wecom')) {
|
|
52
|
+
res.writeHead(404);
|
|
53
|
+
res.end();
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const msgSignature = url.searchParams.get('msg_signature') || '';
|
|
57
|
+
const timestamp = url.searchParams.get('timestamp') || '';
|
|
58
|
+
const nonce = url.searchParams.get('nonce') || '';
|
|
59
|
+
if (req.method === 'GET') {
|
|
60
|
+
const echostr = url.searchParams.get('echostr') || '';
|
|
61
|
+
try {
|
|
62
|
+
const signature = getSignature(this.config.token, timestamp, nonce, echostr);
|
|
63
|
+
if (signature === msgSignature) {
|
|
64
|
+
const { message } = decrypt(this.config.encodingAESKey, echostr);
|
|
65
|
+
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
|
66
|
+
res.end(message);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
res.writeHead(403);
|
|
70
|
+
res.end('Signature mismatch');
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
res.writeHead(500);
|
|
75
|
+
res.end('Verification failed');
|
|
76
|
+
}
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (req.method === 'POST') {
|
|
80
|
+
try {
|
|
81
|
+
const body = await readBody(req);
|
|
82
|
+
const parsed = await xml2js.parseStringPromise(body, { explicitArray: false });
|
|
83
|
+
const xmlRoot = parsed.xml;
|
|
84
|
+
const encryptedMsg = xmlRoot.Encrypt;
|
|
85
|
+
const signature = getSignature(this.config.token, timestamp, nonce, encryptedMsg);
|
|
86
|
+
if (signature !== msgSignature) {
|
|
87
|
+
res.writeHead(403);
|
|
88
|
+
res.end('Signature mismatch');
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const { message } = decrypt(this.config.encodingAESKey, encryptedMsg);
|
|
92
|
+
const msgParsed = await xml2js.parseStringPromise(message, { explicitArray: false });
|
|
93
|
+
const msgXml = msgParsed.xml;
|
|
94
|
+
if (msgXml.MsgType !== 'text') {
|
|
95
|
+
res.writeHead(200);
|
|
96
|
+
res.end('ok');
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const channelMsg = {
|
|
100
|
+
channelType: 'wecom',
|
|
101
|
+
senderId: msgXml.FromUserName || '',
|
|
102
|
+
chatId: msgXml.FromUserName || '',
|
|
103
|
+
chatType: 'dm',
|
|
104
|
+
text: msgXml.Content || '',
|
|
105
|
+
raw: msgXml,
|
|
106
|
+
};
|
|
107
|
+
onMessage(channelMsg);
|
|
108
|
+
res.writeHead(200);
|
|
109
|
+
res.end('ok');
|
|
110
|
+
}
|
|
111
|
+
catch (e) {
|
|
112
|
+
console.error('[wecom] Failed to process message:', e);
|
|
113
|
+
res.writeHead(500);
|
|
114
|
+
res.end('Internal error');
|
|
115
|
+
}
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
res.writeHead(405);
|
|
119
|
+
res.end();
|
|
120
|
+
});
|
|
121
|
+
const port = 9000;
|
|
122
|
+
this.server.listen(port, () => {
|
|
123
|
+
console.log(`[wecom] Webhook server started on port ${port}, callback path: /wecom`);
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
async reply(msg, text) {
|
|
127
|
+
const token = await this.getAccessToken();
|
|
128
|
+
const url = `https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=${token}`;
|
|
129
|
+
const body = {
|
|
130
|
+
touser: msg.senderId,
|
|
131
|
+
msgtype: 'text',
|
|
132
|
+
agentid: Number(this.config.agentId),
|
|
133
|
+
text: { content: text },
|
|
134
|
+
};
|
|
135
|
+
await fetch(url, {
|
|
136
|
+
method: 'POST',
|
|
137
|
+
headers: { 'Content-Type': 'application/json' },
|
|
138
|
+
body: JSON.stringify(body),
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
async stop() {
|
|
142
|
+
return new Promise((resolve) => {
|
|
143
|
+
if (this.server) {
|
|
144
|
+
this.server.close(() => resolve());
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
resolve();
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=wecom.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wecom.js","sourceRoot":"","sources":["../../src/channels/wecom.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|