beecork 1.7.0 → 2.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.
Files changed (223) hide show
  1. package/README.md +52 -111
  2. package/dist/index.js +1394 -581
  3. package/package.json +26 -54
  4. package/dist/capabilities/index.d.ts +0 -3
  5. package/dist/capabilities/index.js +0 -2
  6. package/dist/capabilities/manager.d.ts +0 -13
  7. package/dist/capabilities/manager.js +0 -115
  8. package/dist/capabilities/packs.d.ts +0 -2
  9. package/dist/capabilities/packs.js +0 -54
  10. package/dist/capabilities/types.d.ts +0 -21
  11. package/dist/capabilities/types.js +0 -1
  12. package/dist/channels/admin.d.ts +0 -10
  13. package/dist/channels/admin.js +0 -20
  14. package/dist/channels/command-handler.d.ts +0 -19
  15. package/dist/channels/command-handler.js +0 -235
  16. package/dist/channels/discord.d.ts +0 -17
  17. package/dist/channels/discord.js +0 -266
  18. package/dist/channels/index.d.ts +0 -7
  19. package/dist/channels/index.js +0 -6
  20. package/dist/channels/loader.d.ts +0 -7
  21. package/dist/channels/loader.js +0 -87
  22. package/dist/channels/pipeline.d.ts +0 -50
  23. package/dist/channels/pipeline.js +0 -92
  24. package/dist/channels/registry.d.ts +0 -36
  25. package/dist/channels/registry.js +0 -80
  26. package/dist/channels/send-helpers.d.ts +0 -19
  27. package/dist/channels/send-helpers.js +0 -21
  28. package/dist/channels/telegram.d.ts +0 -47
  29. package/dist/channels/telegram.js +0 -649
  30. package/dist/channels/types.d.ts +0 -41
  31. package/dist/channels/types.js +0 -1
  32. package/dist/channels/voice-state.d.ts +0 -29
  33. package/dist/channels/voice-state.js +0 -45
  34. package/dist/channels/webhook.d.ts +0 -16
  35. package/dist/channels/webhook.js +0 -222
  36. package/dist/channels/whatsapp.d.ts +0 -28
  37. package/dist/channels/whatsapp.js +0 -323
  38. package/dist/cli/capabilities.d.ts +0 -3
  39. package/dist/cli/capabilities.js +0 -72
  40. package/dist/cli/channel.d.ts +0 -3
  41. package/dist/cli/channel.js +0 -202
  42. package/dist/cli/commands.d.ts +0 -15
  43. package/dist/cli/commands.js +0 -279
  44. package/dist/cli/doctor.d.ts +0 -1
  45. package/dist/cli/doctor.js +0 -208
  46. package/dist/cli/handoff.d.ts +0 -8
  47. package/dist/cli/handoff.js +0 -33
  48. package/dist/cli/helpers.d.ts +0 -2
  49. package/dist/cli/helpers.js +0 -21
  50. package/dist/cli/mcp.d.ts +0 -3
  51. package/dist/cli/mcp.js +0 -47
  52. package/dist/cli/media.d.ts +0 -2
  53. package/dist/cli/media.js +0 -125
  54. package/dist/cli/setup.d.ts +0 -1
  55. package/dist/cli/setup.js +0 -239
  56. package/dist/cli/store.d.ts +0 -3
  57. package/dist/cli/store.js +0 -108
  58. package/dist/config.d.ts +0 -11
  59. package/dist/config.js +0 -115
  60. package/dist/daemon.d.ts +0 -1
  61. package/dist/daemon.js +0 -345
  62. package/dist/dashboard/html.d.ts +0 -1
  63. package/dist/dashboard/html.js +0 -849
  64. package/dist/dashboard/routes.d.ts +0 -17
  65. package/dist/dashboard/routes.js +0 -623
  66. package/dist/dashboard/server.d.ts +0 -1
  67. package/dist/dashboard/server.js +0 -104
  68. package/dist/db/connection.d.ts +0 -29
  69. package/dist/db/connection.js +0 -37
  70. package/dist/db/index.d.ts +0 -14
  71. package/dist/db/index.js +0 -127
  72. package/dist/db/migrations.d.ts +0 -2
  73. package/dist/db/migrations.js +0 -384
  74. package/dist/delegation/manager.d.ts +0 -18
  75. package/dist/delegation/manager.js +0 -89
  76. package/dist/index.d.ts +0 -2
  77. package/dist/knowledge/index.d.ts +0 -2
  78. package/dist/knowledge/index.js +0 -1
  79. package/dist/knowledge/manager.d.ts +0 -17
  80. package/dist/knowledge/manager.js +0 -160
  81. package/dist/knowledge/types.d.ts +0 -7
  82. package/dist/knowledge/types.js +0 -1
  83. package/dist/mcp/handlers.d.ts +0 -37
  84. package/dist/mcp/handlers.js +0 -520
  85. package/dist/mcp/server.d.ts +0 -2
  86. package/dist/mcp/server.js +0 -86
  87. package/dist/mcp/tool-definitions.d.ts +0 -1225
  88. package/dist/mcp/tool-definitions.js +0 -412
  89. package/dist/mcp/validate.d.ts +0 -23
  90. package/dist/mcp/validate.js +0 -65
  91. package/dist/media/factory.d.ts +0 -6
  92. package/dist/media/factory.js +0 -36
  93. package/dist/media/generators/dall-e.d.ts +0 -10
  94. package/dist/media/generators/dall-e.js +0 -41
  95. package/dist/media/generators/elevenlabs-music.d.ts +0 -9
  96. package/dist/media/generators/elevenlabs-music.js +0 -34
  97. package/dist/media/generators/elevenlabs-sfx.d.ts +0 -9
  98. package/dist/media/generators/elevenlabs-sfx.js +0 -33
  99. package/dist/media/generators/kling.d.ts +0 -9
  100. package/dist/media/generators/kling.js +0 -47
  101. package/dist/media/generators/lyria.d.ts +0 -10
  102. package/dist/media/generators/lyria.js +0 -41
  103. package/dist/media/generators/nano-banana.d.ts +0 -10
  104. package/dist/media/generators/nano-banana.js +0 -45
  105. package/dist/media/generators/poll-util.d.ts +0 -12
  106. package/dist/media/generators/poll-util.js +0 -22
  107. package/dist/media/generators/recraft.d.ts +0 -9
  108. package/dist/media/generators/recraft.js +0 -52
  109. package/dist/media/generators/runway.d.ts +0 -9
  110. package/dist/media/generators/runway.js +0 -49
  111. package/dist/media/generators/stable-diffusion.d.ts +0 -9
  112. package/dist/media/generators/stable-diffusion.js +0 -35
  113. package/dist/media/generators/veo.d.ts +0 -9
  114. package/dist/media/generators/veo.js +0 -32
  115. package/dist/media/index.d.ts +0 -6
  116. package/dist/media/index.js +0 -8
  117. package/dist/media/store.d.ts +0 -17
  118. package/dist/media/store.js +0 -69
  119. package/dist/media/types.d.ts +0 -43
  120. package/dist/media/types.js +0 -1
  121. package/dist/notifications/index.d.ts +0 -4
  122. package/dist/notifications/index.js +0 -21
  123. package/dist/notifications/ntfy.d.ts +0 -9
  124. package/dist/notifications/ntfy.js +0 -25
  125. package/dist/notifications/pushover.d.ts +0 -9
  126. package/dist/notifications/pushover.js +0 -26
  127. package/dist/notifications/types.d.ts +0 -5
  128. package/dist/notifications/types.js +0 -1
  129. package/dist/notifications/webhook-provider.d.ts +0 -9
  130. package/dist/notifications/webhook-provider.js +0 -24
  131. package/dist/observability/analytics.d.ts +0 -30
  132. package/dist/observability/analytics.js +0 -118
  133. package/dist/projects/index.d.ts +0 -4
  134. package/dist/projects/index.js +0 -2
  135. package/dist/projects/manager.d.ts +0 -13
  136. package/dist/projects/manager.js +0 -166
  137. package/dist/projects/router.d.ts +0 -17
  138. package/dist/projects/router.js +0 -246
  139. package/dist/projects/types.d.ts +0 -19
  140. package/dist/projects/types.js +0 -1
  141. package/dist/service/install.d.ts +0 -4
  142. package/dist/service/install.js +0 -146
  143. package/dist/service/templates.d.ts +0 -4
  144. package/dist/service/templates.js +0 -52
  145. package/dist/service/windows.d.ts +0 -8
  146. package/dist/service/windows.js +0 -59
  147. package/dist/session/budget-guard.d.ts +0 -20
  148. package/dist/session/budget-guard.js +0 -31
  149. package/dist/session/circuit-breaker.d.ts +0 -19
  150. package/dist/session/circuit-breaker.js +0 -91
  151. package/dist/session/context-compactor.d.ts +0 -32
  152. package/dist/session/context-compactor.js +0 -45
  153. package/dist/session/context-monitor.d.ts +0 -15
  154. package/dist/session/context-monitor.js +0 -44
  155. package/dist/session/handoff.d.ts +0 -21
  156. package/dist/session/handoff.js +0 -50
  157. package/dist/session/manager.d.ts +0 -60
  158. package/dist/session/manager.js +0 -379
  159. package/dist/session/memory-store.d.ts +0 -29
  160. package/dist/session/memory-store.js +0 -45
  161. package/dist/session/message-queue.d.ts +0 -28
  162. package/dist/session/message-queue.js +0 -52
  163. package/dist/session/pending-dispatcher.d.ts +0 -31
  164. package/dist/session/pending-dispatcher.js +0 -120
  165. package/dist/session/pending-store.d.ts +0 -60
  166. package/dist/session/pending-store.js +0 -118
  167. package/dist/session/stale-session.d.ts +0 -31
  168. package/dist/session/stale-session.js +0 -45
  169. package/dist/session/subprocess.d.ts +0 -25
  170. package/dist/session/subprocess.js +0 -189
  171. package/dist/session/tab-store.d.ts +0 -28
  172. package/dist/session/tab-store.js +0 -78
  173. package/dist/tasks/scheduler.d.ts +0 -45
  174. package/dist/tasks/scheduler.js +0 -329
  175. package/dist/tasks/store.d.ts +0 -11
  176. package/dist/tasks/store.js +0 -103
  177. package/dist/timeline/index.d.ts +0 -3
  178. package/dist/timeline/index.js +0 -2
  179. package/dist/timeline/logger.d.ts +0 -8
  180. package/dist/timeline/logger.js +0 -11
  181. package/dist/timeline/query.d.ts +0 -11
  182. package/dist/timeline/query.js +0 -67
  183. package/dist/timeline/types.d.ts +0 -12
  184. package/dist/timeline/types.js +0 -1
  185. package/dist/types.d.ts +0 -216
  186. package/dist/types.js +0 -3
  187. package/dist/util/auto-heal.d.ts +0 -43
  188. package/dist/util/auto-heal.js +0 -107
  189. package/dist/util/install-info.d.ts +0 -37
  190. package/dist/util/install-info.js +0 -80
  191. package/dist/util/logger.d.ts +0 -18
  192. package/dist/util/logger.js +0 -118
  193. package/dist/util/paths.d.ts +0 -13
  194. package/dist/util/paths.js +0 -55
  195. package/dist/util/platform.d.ts +0 -2
  196. package/dist/util/platform.js +0 -11
  197. package/dist/util/progress.d.ts +0 -34
  198. package/dist/util/progress.js +0 -133
  199. package/dist/util/rate-limiter.d.ts +0 -14
  200. package/dist/util/rate-limiter.js +0 -50
  201. package/dist/util/retry.d.ts +0 -2
  202. package/dist/util/retry.js +0 -18
  203. package/dist/util/text.d.ts +0 -32
  204. package/dist/util/text.js +0 -101
  205. package/dist/version.d.ts +0 -1
  206. package/dist/version.js +0 -4
  207. package/dist/voice/index.d.ts +0 -17
  208. package/dist/voice/index.js +0 -42
  209. package/dist/voice/stt.d.ts +0 -16
  210. package/dist/voice/stt.js +0 -57
  211. package/dist/voice/tts.d.ts +0 -23
  212. package/dist/voice/tts.js +0 -84
  213. package/dist/watchers/evaluator.d.ts +0 -5
  214. package/dist/watchers/evaluator.js +0 -45
  215. package/dist/watchers/index.d.ts +0 -4
  216. package/dist/watchers/index.js +0 -3
  217. package/dist/watchers/scheduler.d.ts +0 -20
  218. package/dist/watchers/scheduler.js +0 -183
  219. package/dist/watchers/store.d.ts +0 -10
  220. package/dist/watchers/store.js +0 -56
  221. package/dist/watchers/types.d.ts +0 -15
  222. package/dist/watchers/types.js +0 -1
  223. package/scripts/postinstall.mjs +0 -50
package/package.json CHANGED
@@ -1,71 +1,37 @@
1
1
  {
2
2
  "name": "beecork",
3
- "version": "1.7.0",
4
- "description": "Claude Code always-on infrastructure — a phone number, a memory, and an alarm clock",
3
+ "version": "2.0.0",
4
+ "description": "beecork — a from-scratch CLI coding agent: multi-model (OpenRouter), BYOK, path-confined tools, built part by part.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "beecork": "dist/index.js"
8
8
  },
9
+ "main": "dist/index.js",
10
+ "files": [
11
+ "dist/"
12
+ ],
9
13
  "engines": {
10
- "node": ">=24"
14
+ "node": ">=20.12"
11
15
  },
12
16
  "scripts": {
13
- "build": "tsc -p tsconfig.build.json && node -e \"require('fs').chmodSync('dist/index.js', 0o755)\"",
14
17
  "dev": "tsx src/index.ts",
15
- "dev:daemon": "tsx src/daemon.ts",
16
- "test": "vitest",
17
- "lint": "eslint src/",
18
- "format": "prettier --write \"src/**/*.ts\"",
19
- "format:check": "prettier --check \"src/**/*.ts\"",
20
- "build:css": "tailwindcss --content src/dashboard/html.ts --minify",
21
- "prepublishOnly": "npm test && npm run build",
22
- "postinstall": "node scripts/postinstall.mjs"
23
- },
24
- "dependencies": {
25
- "@modelcontextprotocol/sdk": "^1.29.0",
26
- "@whiskeysockets/baileys": "^7.0.0-rc11",
27
- "better-sqlite3": "^12.10.0",
28
- "commander": "^14.0.3",
29
- "cron-parser": "^5.5.0",
30
- "discord.js": "^14.26.4",
31
- "node-telegram-bot-api": "^0.67.0",
32
- "pino": "^10.3.1",
33
- "qrcode-terminal": "^0.12.0",
34
- "uuid": "^14.0.0"
35
- },
36
- "devDependencies": {
37
- "@tailwindcss/cli": "^4.3.0",
38
- "@types/better-sqlite3": "^7.6.13",
39
- "@types/node": "^24.12.4",
40
- "@types/node-telegram-bot-api": "^0.64.14",
41
- "eslint": "^10.4.0",
42
- "eslint-config-prettier": "^10.1.8",
43
- "prettier": "^3.8.3",
44
- "tailwindcss": "^4.3.0",
45
- "tsx": "^4.22.0",
46
- "typescript": "^6.0.3",
47
- "typescript-eslint": "^8.59.3",
48
- "vitest": "^4.1.6"
18
+ "typecheck": "tsc --noEmit",
19
+ "test": "tsx --test src/*.test.ts",
20
+ "eval": "tsx eval/run.ts",
21
+ "build": "esbuild src/index.ts --bundle --platform=node --format=esm --target=node20 --outfile=dist/index.js --banner:js='#!/usr/bin/env node' && node -e \"require('fs').chmodSync('dist/index.js', 0o755)\"",
22
+ "prepublishOnly": "npm run typecheck && npm test && npm run build"
49
23
  },
50
- "files": [
51
- "dist/",
52
- "scripts/postinstall.mjs"
53
- ],
54
24
  "keywords": [
55
25
  "claude",
56
- "claude-code",
57
- "telegram",
58
- "whatsapp",
59
- "discord",
60
- "mcp",
61
- "model-context-protocol",
62
- "ai",
26
+ "coding-agent",
63
27
  "ai-agent",
64
- "automation",
65
- "cron",
66
28
  "cli",
67
- "chatbot",
68
- "scheduling"
29
+ "openrouter",
30
+ "llm",
31
+ "ai",
32
+ "code",
33
+ "developer-tools",
34
+ "byok"
69
35
  ],
70
36
  "repository": {
71
37
  "type": "git",
@@ -76,5 +42,11 @@
76
42
  "url": "https://github.com/beecork/beecork/issues"
77
43
  },
78
44
  "author": "Beecork <hello@beecork.com>",
79
- "license": "MIT"
45
+ "license": "MIT",
46
+ "devDependencies": {
47
+ "@types/node": "^26.0.1",
48
+ "esbuild": "^0.28.1",
49
+ "tsx": "^4.22.4",
50
+ "typescript": "^6.0.3"
51
+ }
80
52
  }
@@ -1,3 +0,0 @@
1
- export type { CapabilityPack, EnabledCapability } from './types.js';
2
- export { CAPABILITY_PACKS } from './packs.js';
3
- export { getAvailablePacks, getEnabledCapabilities, isEnabled, enablePack, disablePack, updateMcpConfig, } from './manager.js';
@@ -1,2 +0,0 @@
1
- export { CAPABILITY_PACKS } from './packs.js';
2
- export { getAvailablePacks, getEnabledCapabilities, isEnabled, enablePack, disablePack, updateMcpConfig, } from './manager.js';
@@ -1,13 +0,0 @@
1
- import type { CapabilityPack, EnabledCapability } from './types.js';
2
- /** Get all available packs */
3
- export declare function getAvailablePacks(): CapabilityPack[];
4
- /** Get enabled capabilities from config */
5
- export declare function getEnabledCapabilities(): EnabledCapability[];
6
- /** Check if a pack is enabled */
7
- export declare function isEnabled(packId: string): boolean;
8
- /** Enable a capability pack */
9
- export declare function enablePack(packId: string, apiKey?: string): void;
10
- /** Disable a capability pack */
11
- export declare function disablePack(packId: string): void;
12
- /** Regenerate MCP config based on enabled capabilities */
13
- export declare function updateMcpConfig(): void;
@@ -1,115 +0,0 @@
1
- import fs from 'node:fs';
2
- import { execFileSync } from 'node:child_process';
3
- import { getConfig, saveConfig } from '../config.js';
4
- const SAFE_NPM_PACKAGE = /^[@a-zA-Z0-9_/.-]+$/;
5
- import { getMcpConfigPath } from '../util/paths.js';
6
- import { logger } from '../util/logger.js';
7
- import { CAPABILITY_PACKS } from './packs.js';
8
- /** Get all available packs */
9
- export function getAvailablePacks() {
10
- return CAPABILITY_PACKS;
11
- }
12
- /** Get enabled capabilities from config */
13
- export function getEnabledCapabilities() {
14
- const config = getConfig();
15
- return config.capabilities || [];
16
- }
17
- /** Check if a pack is enabled */
18
- export function isEnabled(packId) {
19
- return getEnabledCapabilities().some((c) => c.packId === packId);
20
- }
21
- /** Enable a capability pack */
22
- export function enablePack(packId, apiKey) {
23
- const pack = CAPABILITY_PACKS.find((p) => p.id === packId);
24
- if (!pack)
25
- throw new Error(`Unknown capability: ${packId}. Use 'beecork capabilities' to list.`);
26
- if (pack.requiresApiKey && !apiKey) {
27
- throw new Error(`${pack.name} requires an API key. Hint: ${pack.apiKeyHint}`);
28
- }
29
- // Install the MCP server package
30
- if (!SAFE_NPM_PACKAGE.test(pack.mcpServer.package)) {
31
- throw new Error(`Invalid package name in capability pack: ${pack.mcpServer.package}`);
32
- }
33
- try {
34
- console.log(`Installing ${pack.mcpServer.package}...`);
35
- execFileSync('npm', ['install', '-g', pack.mcpServer.package], { stdio: 'pipe' });
36
- }
37
- catch {
38
- logger.warn(`Package install skipped (may already be available via npx): ${pack.mcpServer.package}`);
39
- }
40
- // Update config
41
- const config = getConfig();
42
- const capabilities = config.capabilities || [];
43
- const existing = capabilities.findIndex((c) => c.packId === packId);
44
- const entry = { packId, apiKey, enabledAt: new Date().toISOString() };
45
- if (existing >= 0) {
46
- capabilities[existing] = entry;
47
- }
48
- else {
49
- capabilities.push(entry);
50
- }
51
- config.capabilities = capabilities;
52
- saveConfig(config);
53
- // Update MCP config
54
- updateMcpConfig();
55
- logger.info(`Capability enabled: ${pack.name}`);
56
- }
57
- /** Disable a capability pack */
58
- export function disablePack(packId) {
59
- const config = getConfig();
60
- const capabilities = config.capabilities || [];
61
- config.capabilities = capabilities.filter((c) => c.packId !== packId);
62
- saveConfig(config);
63
- updateMcpConfig();
64
- logger.info(`Capability disabled: ${packId}`);
65
- }
66
- /** Regenerate MCP config based on enabled capabilities */
67
- export function updateMcpConfig() {
68
- const mcpConfigPath = getMcpConfigPath();
69
- let mcpConfig = { mcpServers: {} };
70
- // Load existing MCP config (preserves beecork's own MCP server)
71
- if (fs.existsSync(mcpConfigPath)) {
72
- try {
73
- mcpConfig = JSON.parse(fs.readFileSync(mcpConfigPath, 'utf-8'));
74
- }
75
- catch { }
76
- }
77
- // Remove old capability servers (they start with 'cap-')
78
- for (const key of Object.keys(mcpConfig.mcpServers)) {
79
- if (key.startsWith('cap-'))
80
- delete mcpConfig.mcpServers[key];
81
- }
82
- // Add enabled capability servers
83
- const capabilities = getEnabledCapabilities();
84
- for (const cap of capabilities) {
85
- const pack = CAPABILITY_PACKS.find((p) => p.id === cap.packId);
86
- if (!pack)
87
- continue;
88
- // Resolve env vars
89
- const env = {};
90
- if (pack.mcpServer.env) {
91
- for (const [key, template] of Object.entries(pack.mcpServer.env)) {
92
- env[key] = template.replace(/\$\{(\w+)\}/g, (_, varName) => {
93
- if (varName === pack.apiKeyEnvVar)
94
- return cap.apiKey || '';
95
- return process.env[varName] || '';
96
- });
97
- }
98
- }
99
- if (cap.apiKey && pack.apiKeyEnvVar) {
100
- env[pack.apiKeyEnvVar] = cap.apiKey;
101
- }
102
- // Resolve args templates
103
- const args = (pack.mcpServer.args || []).map((arg) => arg.replace(/\$\{(\w+)\}/g, (_, varName) => {
104
- if (varName === pack.apiKeyEnvVar)
105
- return cap.apiKey || '';
106
- return process.env[varName] || '';
107
- }));
108
- mcpConfig.mcpServers[`cap-${cap.packId}`] = {
109
- command: pack.mcpServer.command,
110
- args,
111
- ...(Object.keys(env).length > 0 ? { env } : {}),
112
- };
113
- }
114
- fs.writeFileSync(mcpConfigPath, JSON.stringify(mcpConfig, null, 2) + '\n', { mode: 0o600 });
115
- }
@@ -1,2 +0,0 @@
1
- import type { CapabilityPack } from './types.js';
2
- export declare const CAPABILITY_PACKS: CapabilityPack[];
@@ -1,54 +0,0 @@
1
- export const CAPABILITY_PACKS = [
2
- // Productivity
3
- {
4
- id: 'notion',
5
- name: 'Notion',
6
- description: 'Read and write pages, databases, notes in Notion',
7
- category: 'productivity',
8
- mcpServer: {
9
- package: '@notionhq/notion-mcp-server',
10
- command: 'npx',
11
- args: ['-y', '@notionhq/notion-mcp-server'],
12
- env: {
13
- OPENAPI_MCP_HEADERS: '{"Authorization":"Bearer ${NOTION_API_KEY}","Notion-Version":"2022-06-28"}',
14
- },
15
- },
16
- requiresApiKey: true,
17
- apiKeyHint: 'Notion integration token (from notion.so/my-integrations)',
18
- apiKeyEnvVar: 'NOTION_API_KEY',
19
- setupUrl: 'https://github.com/beecork/beecork/blob/main/docs/use-cases.md',
20
- },
21
- // Development
22
- {
23
- id: 'github',
24
- name: 'GitHub',
25
- description: 'Manage repos, PRs, issues, CI/CD workflows',
26
- category: 'development',
27
- mcpServer: {
28
- package: '@modelcontextprotocol/server-github',
29
- command: 'npx',
30
- args: ['-y', '@modelcontextprotocol/server-github'],
31
- env: { GITHUB_PERSONAL_ACCESS_TOKEN: '${GITHUB_TOKEN}' },
32
- },
33
- requiresApiKey: true,
34
- apiKeyHint: 'GitHub personal access token (from github.com/settings/tokens)',
35
- apiKeyEnvVar: 'GITHUB_TOKEN',
36
- setupUrl: 'https://github.com/beecork/beecork/blob/main/docs/use-cases.md',
37
- },
38
- // Data
39
- {
40
- id: 'database',
41
- name: 'Database (PostgreSQL)',
42
- description: 'Query databases, inspect schemas, analyze data',
43
- category: 'data',
44
- mcpServer: {
45
- package: '@modelcontextprotocol/server-postgres',
46
- command: 'npx',
47
- args: ['-y', '@modelcontextprotocol/server-postgres', '${DATABASE_URL}'],
48
- },
49
- requiresApiKey: true,
50
- apiKeyHint: 'PostgreSQL connection string (e.g., postgresql://user:pass@host:5432/db)',
51
- apiKeyEnvVar: 'DATABASE_URL',
52
- setupUrl: 'https://github.com/beecork/beecork/blob/main/docs/use-cases.md',
53
- },
54
- ];
@@ -1,21 +0,0 @@
1
- export interface CapabilityPack {
2
- id: string;
3
- name: string;
4
- description: string;
5
- category: 'productivity' | 'development' | 'data' | 'web';
6
- mcpServer: {
7
- package: string;
8
- command: string;
9
- args?: string[];
10
- env?: Record<string, string>;
11
- };
12
- requiresApiKey: boolean;
13
- apiKeyHint?: string;
14
- apiKeyEnvVar?: string;
15
- setupUrl?: string;
16
- }
17
- export interface EnabledCapability {
18
- packId: string;
19
- apiKey?: string;
20
- enabledAt: string;
21
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,10 +0,0 @@
1
- /**
2
- * Shared admin check for channel commands. Single source of truth so the
3
- * "who can run admin commands?" rule doesn't drift between channels.
4
- *
5
- * Policy:
6
- * - If an explicit admin peer ID is configured, only they are admin.
7
- * - Else the first allowed peer in the allowlist is admin.
8
- * - If the allowlist is empty, no one is admin (fail closed).
9
- */
10
- export declare function isChannelAdmin(allowList: Iterable<string | number>, peerId: string | number | undefined, explicitAdmin?: string | number): boolean;
@@ -1,20 +0,0 @@
1
- /**
2
- * Shared admin check for channel commands. Single source of truth so the
3
- * "who can run admin commands?" rule doesn't drift between channels.
4
- *
5
- * Policy:
6
- * - If an explicit admin peer ID is configured, only they are admin.
7
- * - Else the first allowed peer in the allowlist is admin.
8
- * - If the allowlist is empty, no one is admin (fail closed).
9
- */
10
- export function isChannelAdmin(allowList, peerId, explicitAdmin) {
11
- if (peerId === undefined || peerId === null)
12
- return false;
13
- if (explicitAdmin !== undefined && explicitAdmin !== null) {
14
- return String(peerId) === String(explicitAdmin);
15
- }
16
- const first = [...allowList][0];
17
- if (first === undefined)
18
- return false;
19
- return String(peerId) === String(first);
20
- }
@@ -1,19 +0,0 @@
1
- import type { TabManager } from '../session/manager.js';
2
- export interface CommandContext {
3
- userId: string;
4
- text: string;
5
- isAdmin: boolean;
6
- channelId: string;
7
- }
8
- export interface CommandResult {
9
- handled: boolean;
10
- response?: string;
11
- }
12
- export type { RouteResult } from '../projects/router.js';
13
- /**
14
- * Handle shared commands that work identically across all channels.
15
- * Returns { handled: true, response } if a command was matched.
16
- * The channel is responsible for sending the response via its own API.
17
- */
18
- export declare function handleSharedCommand(ctx: CommandContext, tabManager: TabManager): Promise<CommandResult>;
19
- export { resolveProjectRoute } from '../projects/router.js';
@@ -1,235 +0,0 @@
1
- /**
2
- * Shared command handler for all channels.
3
- * Extracts command logic so it's defined once and called from Telegram, WhatsApp, Discord, etc.
4
- */
5
- import { timeAgo } from '../util/text.js';
6
- import { validateTabName } from '../config.js';
7
- import { exportTab, formatHandoffInfo } from '../session/handoff.js';
8
- import { logActivity } from '../timeline/index.js';
9
- /**
10
- * Handle shared commands that work identically across all channels.
11
- * Returns { handled: true, response } if a command was matched.
12
- * The channel is responsible for sending the response via its own API.
13
- */
14
- export async function handleSharedCommand(ctx, tabManager) {
15
- const { text, userId, isAdmin } = ctx;
16
- // /tabs
17
- if (text === '/tabs' || text.startsWith('/tabs@')) {
18
- const tabs = tabManager.listTabs();
19
- if (tabs.length === 0)
20
- return { handled: true, response: 'No tabs.' };
21
- const list = tabs
22
- .map((t) => `• ${t.name} [${t.status}] — ${timeAgo(t.lastActivityAt)}`)
23
- .join('\n');
24
- return { handled: true, response: list };
25
- }
26
- // /stop <name>
27
- if (text.startsWith('/stop ')) {
28
- if (!isAdmin)
29
- return { handled: true, response: 'Only admin can stop tabs.' };
30
- const tabName = text.slice(6).trim();
31
- tabManager.stopTab(tabName);
32
- return { handled: true, response: `Stopped tab: ${tabName}` };
33
- }
34
- // /tab <name> --set-prompt "..."
35
- if (text.startsWith('/tab ')) {
36
- const rest = text.slice(5);
37
- const setPromptMatch = rest.match(/^(\S+)\s+--set-prompt\s+"([^"]+)"/);
38
- if (setPromptMatch) {
39
- if (!isAdmin)
40
- return { handled: true, response: 'Only admin can change system prompts.' };
41
- const tabName = setPromptMatch[1];
42
- if (tabName !== 'default') {
43
- const nameErr = validateTabName(tabName);
44
- if (nameErr)
45
- return { handled: true, response: `Invalid tab name: ${nameErr}` };
46
- }
47
- const systemPrompt = setPromptMatch[2];
48
- const updated = tabManager.setSystemPrompt(tabName, systemPrompt);
49
- return {
50
- handled: true,
51
- response: updated
52
- ? `System prompt updated for tab "${tabName}"`
53
- : `Tab "${tabName}" not found.`,
54
- };
55
- }
56
- const spaceIdx = rest.indexOf(' ');
57
- if (spaceIdx === -1) {
58
- return { handled: true, response: 'Usage: /tab <name> <message>' };
59
- }
60
- const tabName = rest.slice(0, spaceIdx);
61
- const validationError = validateTabName(tabName);
62
- if (validationError) {
63
- return { handled: true, response: `Invalid tab name: ${validationError}` };
64
- }
65
- // /tab with a valid name + message — not handled here, falls through to message handling
66
- return { handled: false };
67
- }
68
- // /register, /link, /users were part of unused multi-user scaffolding —
69
- // removed in the audit fix pass. Beecork is single-user; admin is the first
70
- // allowedUserId on Telegram (or config.telegram.adminUserId).
71
- // /watches
72
- if (text === '/watches' || text.startsWith('/watches@')) {
73
- const { getDb } = await import('../db/index.js');
74
- const db = getDb();
75
- const watchers = db.prepare('SELECT * FROM watchers ORDER BY created_at').all();
76
- if (watchers.length === 0)
77
- return { handled: true, response: 'No watchers configured.' };
78
- const watchList = watchers
79
- .map((w) => {
80
- const status = w.enabled ? 'active' : 'disabled';
81
- return `[${status}] ${w.name} -- ${w.schedule} (triggers: ${w.trigger_count})`;
82
- })
83
- .join('\n');
84
- return { handled: true, response: `Watchers:\n${watchList}` };
85
- }
86
- // /tasks
87
- if (text === '/tasks' || text.startsWith('/tasks@')) {
88
- const { getDb } = await import('../db/index.js');
89
- const db = getDb();
90
- const tasks = db.prepare('SELECT * FROM tasks ORDER BY created_at').all();
91
- if (tasks.length === 0)
92
- return { handled: true, response: 'No tasks scheduled.' };
93
- const taskList = tasks
94
- .map((t) => {
95
- const status = t.enabled ? 'enabled' : 'disabled';
96
- return `[${status}] ${t.name} (${t.schedule_type}: ${t.schedule}) -> tab:${t.tab_name}`;
97
- })
98
- .join('\n');
99
- return { handled: true, response: `Tasks:\n${taskList}` };
100
- }
101
- // /cost
102
- if (text === '/cost' || text.startsWith('/cost ')) {
103
- const { getCostSummary, formatCostSummary } = await import('../observability/analytics.js');
104
- return { handled: true, response: formatCostSummary(getCostSummary()) };
105
- }
106
- // /activity [hours]
107
- if (text === '/activity' || text.startsWith('/activity ')) {
108
- const hours = parseInt(text.slice(10).trim()) || 24;
109
- const { getActivitySummary, formatActivitySummary } = await import('../observability/analytics.js');
110
- return { handled: true, response: formatActivitySummary(getActivitySummary(hours)) };
111
- }
112
- // /handoff [tab]
113
- if (text.startsWith('/handoff')) {
114
- const tabName = text.slice(9).trim() || 'default';
115
- const info = exportTab(tabName);
116
- if (!info)
117
- return { handled: true, response: `Tab "${tabName}" not found.` };
118
- logActivity('user_command', '/handoff', { tabName });
119
- return { handled: true, response: formatHandoffInfo(info) };
120
- }
121
- // /folders (also accept legacy /projects)
122
- if (text === '/folders' ||
123
- text === '/projects' ||
124
- text.startsWith('/folders@') ||
125
- text.startsWith('/projects@')) {
126
- const { listProjects } = await import('../projects/index.js');
127
- const projects = listProjects();
128
- if (projects.length === 0)
129
- return { handled: true, response: 'No folders found. Create one with /newfolder <name>' };
130
- const userProjects = projects.filter((p) => p.type === 'user-project');
131
- const categories = projects.filter((p) => p.type === 'category');
132
- let msg = 'šŸ“ Folders:\n';
133
- if (userProjects.length > 0)
134
- msg += userProjects.map((p) => ` • ${p.name} — ${p.path}`).join('\n');
135
- if (categories.length > 0) {
136
- msg += '\n\nšŸ“‚ Categories:\n';
137
- msg += categories.map((p) => ` • ${p.name}`).join('\n');
138
- }
139
- return { handled: true, response: msg };
140
- }
141
- // /folder <name> (also accept legacy /project <name>)
142
- if ((text.startsWith('/folder ') && !text.startsWith('/folders')) ||
143
- (text.startsWith('/project ') && !text.startsWith('/projects'))) {
144
- const prefix = text.startsWith('/folder ') ? '/folder ' : '/project ';
145
- const name = text.slice(prefix.length).trim();
146
- const { getProject, setUserContext } = await import('../projects/index.js');
147
- const project = getProject(name);
148
- if (!project)
149
- return {
150
- handled: true,
151
- response: `Folder "${name}" not found. Use /folders to list or /newfolder to create.`,
152
- };
153
- setUserContext(userId, project.name, project.name);
154
- return {
155
- handled: true,
156
- response: `Switched to folder: ${project.name}\nPath: ${project.path}\n\nNext messages will work in this folder.`,
157
- };
158
- }
159
- // /newfolder <name> [path] (also accept legacy /newproject)
160
- if (text.startsWith('/newfolder ') || text.startsWith('/newproject ')) {
161
- const prefix = text.startsWith('/newfolder ') ? '/newfolder ' : '/newproject ';
162
- const parts = text.slice(prefix.length).trim().split(/\s+/);
163
- const name = parts[0];
164
- const customPath = parts[1] || undefined;
165
- if (!name)
166
- return { handled: true, response: 'Usage: /newfolder <name> [path]' };
167
- const { createProject, setUserContext } = await import('../projects/index.js');
168
- const project = createProject(name, customPath);
169
- setUserContext(userId, project.name, project.name);
170
- return {
171
- handled: true,
172
- response: `āœ“ Folder "${name}" created at ${project.path}\nSwitched to this folder.`,
173
- };
174
- }
175
- // /close <tab>
176
- if (text.startsWith('/close ')) {
177
- const tabNameToClose = text.slice(7).trim();
178
- if (!tabNameToClose)
179
- return { handled: true, response: 'Usage: /close <tabname>' };
180
- const closed = tabManager.closeTab(tabNameToClose);
181
- return {
182
- handled: true,
183
- response: closed
184
- ? `Tab "${tabNameToClose}" permanently closed. History deleted.`
185
- : `Tab "${tabNameToClose}" not found.`,
186
- };
187
- }
188
- // /fresh <folder>
189
- if (text.startsWith('/fresh ')) {
190
- const folderName = text.slice(7).trim();
191
- const { getProject, setUserContext } = await import('../projects/index.js');
192
- const project = getProject(folderName);
193
- if (!project)
194
- return { handled: true, response: `Folder "${folderName}" not found.` };
195
- const freshTabName = `${folderName}-${Date.now().toString(36).slice(-4)}`;
196
- setUserContext(userId, project.name, freshTabName);
197
- return {
198
- handled: true,
199
- response: `Fresh start in "${folderName}" (tab: ${freshTabName})\nSend your message now.`,
200
- };
201
- }
202
- // /history [date|yesterday]
203
- if (text === '/history' || text.startsWith('/history ')) {
204
- const dateArg = text.slice(9).trim();
205
- const { getTimeline, formatTimeline } = await import('../timeline/index.js');
206
- let date;
207
- if (dateArg === 'yesterday') {
208
- date = new Date(Date.now() - 86400000).toISOString().slice(0, 10);
209
- }
210
- else if (dateArg) {
211
- date = dateArg;
212
- }
213
- else {
214
- date = new Date().toISOString().slice(0, 10);
215
- }
216
- const events = getTimeline({ date, limit: 30 });
217
- return { handled: true, response: formatTimeline(events) };
218
- }
219
- // /knowledge
220
- if (text === '/knowledge') {
221
- const { getAllKnowledge, formatKnowledgeForContext } = await import('../knowledge/index.js');
222
- const entries = getAllKnowledge();
223
- if (entries.length === 0) {
224
- return {
225
- handled: true,
226
- response: 'No knowledge stored yet. Beecork learns from your conversations.',
227
- };
228
- }
229
- return { handled: true, response: formatKnowledgeForContext(entries).slice(0, 4000) };
230
- }
231
- return { handled: false };
232
- }
233
- // resolveProjectRoute lives at src/projects/router.ts — re-exported here so
234
- // existing callers (channels/pipeline.ts) don't need to update their import path.
235
- export { resolveProjectRoute } from '../projects/router.js';
@@ -1,17 +0,0 @@
1
- import type { Channel, ChannelContext, SendOptions } from './types.js';
2
- export declare class DiscordChannel implements Channel {
3
- readonly id = "discord";
4
- readonly name = "Discord";
5
- readonly maxMessageLength = 2000;
6
- private client;
7
- private ctx;
8
- private allowedUserIds;
9
- private voice;
10
- constructor(ctx: ChannelContext);
11
- start(): Promise<void>;
12
- stop(): void;
13
- sendMessage(peerId: string, text: string, _options?: SendOptions): Promise<void>;
14
- sendNotification(message: string, _urgent?: boolean): Promise<void>;
15
- setTyping(peerId: string, active: boolean): Promise<void>;
16
- private sendResponse;
17
- }