@hmawla/co-assistant 1.0.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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Hussein Al Mawla
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,396 @@
1
+ # 🤖 Co-Assistant
2
+
3
+ AI-powered Telegram personal assistant built on the GitHub Copilot SDK.
4
+
5
+ Chat with state-of-the-art AI models (GPT-5, Claude Sonnet 4, o3, and more) directly from Telegram. Extend it with plugins for Gmail, Google Calendar, or build your own.
6
+
7
+ ---
8
+
9
+ ## Setup
10
+
11
+ ### Prerequisites
12
+
13
+ | Requirement | How to get it |
14
+ |------------|---------------|
15
+ | **Node.js 20+** | [nodejs.org](https://nodejs.org/) |
16
+ | **Telegram Bot Token** | Message [@BotFather](https://t.me/BotFather) → `/newbot` → copy the token |
17
+ | **Telegram User ID** | Message [@userinfobot](https://t.me/userinfobot) → copy the numeric ID |
18
+ | **GitHub Token** | [github.com/settings/tokens](https://github.com/settings/tokens) — create a token with Copilot access |
19
+
20
+ ### Install & Configure
21
+
22
+ ```bash
23
+ git clone https://github.com/your-username/co-assistant.git
24
+ cd co-assistant
25
+ npm install
26
+ ```
27
+
28
+ Run the interactive setup wizard — it walks you through every credential and preference:
29
+
30
+ ```bash
31
+ npx tsx src/cli/index.ts setup
32
+ ```
33
+
34
+ The wizard creates your `.env` file and `config.json`. You can re-run it at any time to update settings.
35
+
36
+ ### Personalise
37
+
38
+ Two markdown files control how the AI behaves and who it knows you are:
39
+
40
+ | File | Purpose | Committed? |
41
+ |------|---------|------------|
42
+ | `personality.md` | Defines the assistant's tone, style, and behaviour | ✅ Yes |
43
+ | `user.md` | Your personal profile (name, role, timezone, preferences) | ❌ Gitignored |
44
+
45
+ **Set up your user profile** (copy the template and fill in your details):
46
+
47
+ ```bash
48
+ cp user.md.example user.md
49
+ ```
50
+
51
+ Both files are read fresh on each message — edit them anytime without restarting.
52
+
53
+ ### Start
54
+
55
+ ```bash
56
+ npx tsx src/cli/index.ts start
57
+ ```
58
+
59
+ Open Telegram, find your bot, and send a message. That's it.
60
+
61
+ **Verbose mode** (shows incoming/outgoing messages and debug logs in the terminal):
62
+
63
+ ```bash
64
+ npx tsx src/cli/index.ts start -v
65
+ ```
66
+
67
+ ---
68
+
69
+ ## Production Deployment
70
+
71
+ For running Co-Assistant permanently on a server (VPS, Raspberry Pi, etc.).
72
+
73
+ ### 1. Build
74
+
75
+ ```bash
76
+ npm run build
77
+ ```
78
+
79
+ This compiles TypeScript to `dist/` via tsup.
80
+
81
+ ### 2. Run with systemd (recommended for Linux)
82
+
83
+ Create a service file:
84
+
85
+ ```bash
86
+ sudo nano /etc/systemd/system/co-assistant.service
87
+ ```
88
+
89
+ ```ini
90
+ [Unit]
91
+ Description=Co-Assistant Telegram Bot
92
+ After=network-online.target
93
+ Wants=network-online.target
94
+
95
+ [Service]
96
+ Type=simple
97
+ User=your-username
98
+ WorkingDirectory=/path/to/co-assistant
99
+ ExecStart=/usr/bin/node dist/index.js start
100
+ Restart=always
101
+ RestartSec=10
102
+ Environment=NODE_ENV=production
103
+
104
+ [Install]
105
+ WantedBy=multi-user.target
106
+ ```
107
+
108
+ Enable and start:
109
+
110
+ ```bash
111
+ sudo systemctl daemon-reload
112
+ sudo systemctl enable co-assistant
113
+ sudo systemctl start co-assistant
114
+ ```
115
+
116
+ **Useful commands:**
117
+
118
+ ```bash
119
+ sudo systemctl status co-assistant # Check if running
120
+ sudo journalctl -u co-assistant -f # Live logs
121
+ sudo systemctl restart co-assistant # Restart after config changes
122
+ ```
123
+
124
+ ### 3. Alternative: PM2
125
+
126
+ ```bash
127
+ npm install -g pm2
128
+ pm2 start dist/index.js --name co-assistant -- start
129
+ pm2 save
130
+ pm2 startup # generates command to auto-start on boot
131
+ ```
132
+
133
+ ### 4. Alternative: Docker
134
+
135
+ ```dockerfile
136
+ FROM node:20-slim
137
+ WORKDIR /app
138
+ COPY package*.json ./
139
+ RUN npm ci --production
140
+ COPY dist/ dist/
141
+ COPY plugins/ plugins/
142
+ COPY heartbeats/ heartbeats/
143
+ COPY personality.md ./
144
+ COPY config.json .env ./
145
+ # Optional — only if you created a user.md:
146
+ # COPY user.md ./
147
+ CMD ["node", "dist/index.js", "start"]
148
+ ```
149
+
150
+ ```bash
151
+ docker build -t co-assistant .
152
+ docker run -d --restart=always --name co-assistant co-assistant
153
+ ```
154
+
155
+ ---
156
+
157
+ ## Environment Variables
158
+
159
+ All configured via `.env` (the setup wizard handles this):
160
+
161
+ | Variable | Required | Default | Description |
162
+ |----------|----------|---------|-------------|
163
+ | `TELEGRAM_BOT_TOKEN` | ✅ | — | Bot token from @BotFather |
164
+ | `TELEGRAM_USER_ID` | ✅ | — | Your Telegram numeric user ID |
165
+ | `GITHUB_TOKEN` | ✅ | — | GitHub token with Copilot access |
166
+ | `DEFAULT_MODEL` | — | `gpt-4.1` | AI model to use on startup |
167
+ | `LOG_LEVEL` | — | `info` | Logging level (`debug`, `info`, `warn`, `error`) |
168
+ | `HEARTBEAT_INTERVAL_MINUTES` | — | `0` | Scheduled heartbeat interval (0 = disabled) |
169
+ | `AI_SESSION_POOL_SIZE` | — | `3` | Number of parallel AI sessions |
170
+
171
+ ---
172
+
173
+ ## CLI Commands
174
+
175
+ **How to run commands:**
176
+
177
+ ```bash
178
+ # During development (runs TypeScript directly):
179
+ npx tsx src/cli/index.ts setup
180
+ npx tsx src/cli/index.ts start -v
181
+
182
+ # After building (npm run build):
183
+ node dist/cli/index.js setup
184
+ node dist/cli/index.js start
185
+
186
+ # After global install (npm install -g .):
187
+ co-assistant setup
188
+ co-assistant start
189
+ ```
190
+
191
+ | Command | Description |
192
+ |---------|-------------|
193
+ | `setup` | Interactive setup wizard |
194
+ | `start` | Start the bot (`-v` for verbose) |
195
+ | `model` | Show current model |
196
+ | `model <name>` | Switch AI model |
197
+ | `plugin list` | List discovered plugins |
198
+ | `plugin enable <name>` | Enable a plugin |
199
+ | `plugin disable <name>` | Disable a plugin |
200
+ | `plugin configure <name>` | Set up plugin credentials |
201
+ | `heartbeat list` | List heartbeat events |
202
+ | `heartbeat add` | Create a new heartbeat event |
203
+ | `heartbeat remove <name>` | Delete a heartbeat event |
204
+ | `heartbeat run [name]` | Test heartbeat(s) on demand |
205
+ | `status` | Show bot and system status |
206
+
207
+ ---
208
+
209
+ ## Telegram Commands
210
+
211
+ | Command | Description |
212
+ |---------|-------------|
213
+ | `/help` | List available commands |
214
+ | `/heartbeat [name]` | Run heartbeat event(s) on demand |
215
+ | `/hb [name]` | Shorthand for `/heartbeat` |
216
+
217
+ Anything else you type is a conversation with the AI.
218
+
219
+ ---
220
+
221
+ ## Available Models
222
+
223
+ Models are grouped by rate consumption (requests per prompt):
224
+
225
+ | Tier | Models | Rate |
226
+ |------|--------|------|
227
+ | **Premium** | `gpt-5`, `o3`, `claude-opus-4` | 3x |
228
+ | **Standard** | `gpt-4.1`, `gpt-4o`, `o4-mini`, `claude-sonnet-4` | 1x |
229
+ | **Low** | `gpt-4o-mini`, `gpt-4.1-mini`, `gpt-5-mini`, `o3-mini`, `claude-haiku-4.5` | 0.33x |
230
+ | **Free** | `gpt-4.1-nano` | 0x |
231
+
232
+ Switch via CLI (`co-assistant model claude-sonnet-4`) or in the setup wizard.
233
+
234
+ ---
235
+
236
+ ## Personality & User Profile
237
+
238
+ ### `personality.md` — How the AI behaves
239
+
240
+ Defines the assistant's identity, tone, formatting rules, and boundaries. This file is committed to the repo so your team shares the same base personality. Edit it to change the assistant's style.
241
+
242
+ ### `user.md` — Who you are
243
+
244
+ Contains your personal details so the AI can address you correctly and understand your context. This file is gitignored — each user creates their own from the template.
245
+
246
+ Both files are injected as system-level context on every message. The AI sees:
247
+ 1. Personality instructions (how to behave)
248
+ 2. User profile (who it's talking to)
249
+ 3. Your actual message
250
+
251
+ ---
252
+
253
+ ## Plugins
254
+
255
+ ### Included Plugins
256
+
257
+ | Plugin | Tools provided |
258
+ |--------|---------------|
259
+ | **Gmail** | Search emails, read email, send email, send reply |
260
+ | **Google Calendar** | List events, create event, update event, delete event |
261
+
262
+ ### Enable a Plugin
263
+
264
+ ```bash
265
+ npx tsx src/cli/index.ts plugin enable gmail
266
+ npx tsx src/cli/index.ts plugin configure gmail
267
+ ```
268
+
269
+ The configure command walks you through setting up OAuth credentials. For Google plugins, it includes an automated local OAuth flow to obtain refresh tokens.
270
+
271
+ ### Create Your Own Plugin
272
+
273
+ Create a directory under `plugins/` with:
274
+
275
+ ```
276
+ plugins/my-plugin/
277
+ ├── plugin.json # Manifest (id, name, version, credentials)
278
+ └── index.ts # Entry point exporting createPlugin()
279
+ ```
280
+
281
+ **`plugin.json`:**
282
+
283
+ ```json
284
+ {
285
+ "id": "my-plugin",
286
+ "name": "My Plugin",
287
+ "version": "1.0.0",
288
+ "description": "What it does",
289
+ "requiredCredentials": [
290
+ { "key": "API_KEY", "description": "API key for the service" }
291
+ ]
292
+ }
293
+ ```
294
+
295
+ **`index.ts`:**
296
+
297
+ ```typescript
298
+ import type { CoAssistantPlugin, PluginContext } from "../../src/plugins/types.js";
299
+
300
+ export default function createPlugin(): CoAssistantPlugin {
301
+ return {
302
+ id: "my-plugin",
303
+ name: "My Plugin",
304
+ version: "1.0.0",
305
+ description: "What it does",
306
+ requiredCredentials: [{ key: "API_KEY", description: "API key" }],
307
+
308
+ async initialize(context: PluginContext) {
309
+ // Set up connections, validate credentials
310
+ },
311
+
312
+ getTools() {
313
+ return [{
314
+ name: "do_something",
315
+ description: "Does something useful",
316
+ parameters: {
317
+ type: "object",
318
+ properties: {
319
+ input: { type: "string", description: "The input" },
320
+ },
321
+ required: ["input"],
322
+ },
323
+ handler: async (args: Record<string, unknown>) => {
324
+ return `Result for: ${args.input}`;
325
+ },
326
+ }];
327
+ },
328
+
329
+ async destroy() {},
330
+ async healthCheck() { return true; },
331
+ };
332
+ }
333
+ ```
334
+
335
+ Tool names are automatically prefixed with the plugin ID (e.g., `my-plugin_do_something`) to prevent collisions. Plugins run in a sandbox — failures are isolated and auto-disabled after 5 consecutive errors.
336
+
337
+ > 📖 See [docs/plugin-development.md](docs/plugin-development.md) for the full guide.
338
+
339
+ ---
340
+
341
+ ## Heartbeat Events
342
+
343
+ Heartbeats are scheduled AI prompts that run every N minutes. Use them for periodic checks like "do I have unread emails that need a reply?"
344
+
345
+ ### Setup
346
+
347
+ 1. Set the interval in `.env`: `HEARTBEAT_INTERVAL_MINUTES=5`
348
+ 2. Add a heartbeat event:
349
+
350
+ ```bash
351
+ npx tsx src/cli/index.ts heartbeat add
352
+ ```
353
+
354
+ 3. Or trigger manually via Telegram: `/heartbeat`
355
+
356
+ Heartbeat prompts are stored as `.heartbeat.md` files in the `heartbeats/` directory. They support deduplication via `{{DEDUP_STATE}}` placeholders and `<!-- PROCESSED: id1, id2 -->` markers.
357
+
358
+ ---
359
+
360
+ ## Architecture
361
+
362
+ ```
363
+ co-assistant/
364
+ ├── src/
365
+ │ ├── ai/ # Copilot SDK client, session pool, model registry
366
+ │ ├── bot/ # Telegraf bot, handlers, middleware (auth, logging)
367
+ │ ├── cli/ # Commander.js CLI (setup, start, plugin, model, heartbeat)
368
+ │ ├── core/ # App orchestrator, config, logger, heartbeat, GC
369
+ │ ├── plugins/ # Plugin registry, manager, sandbox, credentials
370
+ │ ├── storage/ # SQLite database, migrations, repositories
371
+ │ └── utils/ # Google OAuth helper
372
+ ├── plugins/ # Installed plugins (gmail, google-calendar)
373
+ ├── heartbeats/ # Heartbeat prompt files (.heartbeat.md)
374
+ ├── data/ # SQLite database (auto-created)
375
+ ├── personality.md # AI personality & behaviour instructions
376
+ ├── user.md # Your personal profile (gitignored)
377
+ ├── user.md.example # User profile template
378
+ ├── config.json # Plugin & runtime configuration (gitignored)
379
+ └── config.json.example
380
+ ```
381
+
382
+ **Key internals:**
383
+
384
+ - **Session pool** — Multiple parallel AI sessions so messages don't queue behind each other
385
+ - **System context** — `personality.md` + `user.md` injected into every AI prompt as system instructions
386
+ - **Plugin sandbox** — Every plugin call wrapped in try/catch with auto-disable after 5 failures
387
+ - **Plugin loader** — Uses `tsx/esm/api` to dynamically import TypeScript plugins from `plugins/`
388
+ - **Garbage collector** — Prunes old conversations (30 days) and health records (7 days); logs memory stats
389
+ - **Heartbeat deduplication** — State files track processed item IDs to avoid duplicate notifications
390
+ - **Reply threading** — Each AI response threads back to the user's original Telegram message
391
+
392
+ ---
393
+
394
+ ## License
395
+
396
+ MIT
@@ -0,0 +1,32 @@
1
+ {
2
+ "plugins": {
3
+ "gmail": {
4
+ "enabled": false,
5
+ "credentials": {
6
+ "GMAIL_CLIENT_ID": "",
7
+ "GMAIL_CLIENT_SECRET": "",
8
+ "GMAIL_REFRESH_TOKEN": ""
9
+ }
10
+ },
11
+ "google-calendar": {
12
+ "enabled": false,
13
+ "credentials": {
14
+ "GCAL_CLIENT_ID": "",
15
+ "GCAL_CLIENT_SECRET": "",
16
+ "GCAL_REFRESH_TOKEN": ""
17
+ }
18
+ }
19
+ },
20
+ "bot": {
21
+ "maxMessageLength": 4096,
22
+ "typingIndicator": true
23
+ },
24
+ "ai": {
25
+ "maxRetries": 3,
26
+ "sessionTimeout": 3600000
27
+ },
28
+ "pluginHealth": {
29
+ "maxFailures": 5,
30
+ "checkInterval": 60000
31
+ }
32
+ }