beecork 1.7.1 → 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 (253) 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/cron/scheduler.d.ts +0 -22
  61. package/dist/cron/scheduler.js +0 -220
  62. package/dist/cron/store.d.ts +0 -12
  63. package/dist/cron/store.js +0 -83
  64. package/dist/daemon.d.ts +0 -1
  65. package/dist/daemon.js +0 -345
  66. package/dist/dashboard/html.d.ts +0 -1
  67. package/dist/dashboard/html.js +0 -849
  68. package/dist/dashboard/routes.d.ts +0 -17
  69. package/dist/dashboard/routes.js +0 -623
  70. package/dist/dashboard/server.d.ts +0 -1
  71. package/dist/dashboard/server.js +0 -104
  72. package/dist/db/connection.d.ts +0 -29
  73. package/dist/db/connection.js +0 -37
  74. package/dist/db/index.d.ts +0 -14
  75. package/dist/db/index.js +0 -127
  76. package/dist/db/migrations.d.ts +0 -2
  77. package/dist/db/migrations.js +0 -384
  78. package/dist/delegation/manager.d.ts +0 -18
  79. package/dist/delegation/manager.js +0 -89
  80. package/dist/index.d.ts +0 -2
  81. package/dist/knowledge/index.d.ts +0 -2
  82. package/dist/knowledge/index.js +0 -1
  83. package/dist/knowledge/manager.d.ts +0 -17
  84. package/dist/knowledge/manager.js +0 -160
  85. package/dist/knowledge/types.d.ts +0 -7
  86. package/dist/knowledge/types.js +0 -1
  87. package/dist/machines/forwarder.d.ts +0 -7
  88. package/dist/machines/forwarder.js +0 -35
  89. package/dist/machines/index.d.ts +0 -1
  90. package/dist/machines/index.js +0 -1
  91. package/dist/machines/registry.d.ts +0 -15
  92. package/dist/machines/registry.js +0 -46
  93. package/dist/mcp/handlers.d.ts +0 -37
  94. package/dist/mcp/handlers.js +0 -520
  95. package/dist/mcp/server.d.ts +0 -2
  96. package/dist/mcp/server.js +0 -86
  97. package/dist/mcp/tool-definitions.d.ts +0 -1225
  98. package/dist/mcp/tool-definitions.js +0 -412
  99. package/dist/mcp/validate.d.ts +0 -23
  100. package/dist/mcp/validate.js +0 -65
  101. package/dist/media/factory.d.ts +0 -6
  102. package/dist/media/factory.js +0 -36
  103. package/dist/media/generators/dall-e.d.ts +0 -10
  104. package/dist/media/generators/dall-e.js +0 -41
  105. package/dist/media/generators/elevenlabs-music.d.ts +0 -9
  106. package/dist/media/generators/elevenlabs-music.js +0 -34
  107. package/dist/media/generators/elevenlabs-sfx.d.ts +0 -9
  108. package/dist/media/generators/elevenlabs-sfx.js +0 -33
  109. package/dist/media/generators/kling.d.ts +0 -9
  110. package/dist/media/generators/kling.js +0 -47
  111. package/dist/media/generators/lyria.d.ts +0 -10
  112. package/dist/media/generators/lyria.js +0 -41
  113. package/dist/media/generators/nano-banana.d.ts +0 -10
  114. package/dist/media/generators/nano-banana.js +0 -45
  115. package/dist/media/generators/poll-util.d.ts +0 -12
  116. package/dist/media/generators/poll-util.js +0 -22
  117. package/dist/media/generators/recraft.d.ts +0 -9
  118. package/dist/media/generators/recraft.js +0 -52
  119. package/dist/media/generators/runway.d.ts +0 -9
  120. package/dist/media/generators/runway.js +0 -49
  121. package/dist/media/generators/stable-diffusion.d.ts +0 -9
  122. package/dist/media/generators/stable-diffusion.js +0 -35
  123. package/dist/media/generators/veo.d.ts +0 -9
  124. package/dist/media/generators/veo.js +0 -32
  125. package/dist/media/index.d.ts +0 -6
  126. package/dist/media/index.js +0 -8
  127. package/dist/media/loader.d.ts +0 -8
  128. package/dist/media/loader.js +0 -46
  129. package/dist/media/store.d.ts +0 -17
  130. package/dist/media/store.js +0 -69
  131. package/dist/media/types.d.ts +0 -43
  132. package/dist/media/types.js +0 -1
  133. package/dist/memory/extractor.d.ts +0 -5
  134. package/dist/memory/extractor.js +0 -157
  135. package/dist/notifications/index.d.ts +0 -4
  136. package/dist/notifications/index.js +0 -21
  137. package/dist/notifications/ntfy.d.ts +0 -9
  138. package/dist/notifications/ntfy.js +0 -25
  139. package/dist/notifications/pushover.d.ts +0 -9
  140. package/dist/notifications/pushover.js +0 -26
  141. package/dist/notifications/types.d.ts +0 -5
  142. package/dist/notifications/types.js +0 -1
  143. package/dist/notifications/webhook-provider.d.ts +0 -9
  144. package/dist/notifications/webhook-provider.js +0 -24
  145. package/dist/observability/analytics.d.ts +0 -30
  146. package/dist/observability/analytics.js +0 -118
  147. package/dist/pipe/anthropic-client.d.ts +0 -9
  148. package/dist/pipe/anthropic-client.js +0 -50
  149. package/dist/pipe/brain.d.ts +0 -16
  150. package/dist/pipe/brain.js +0 -89
  151. package/dist/pipe/memory-store.d.ts +0 -8
  152. package/dist/pipe/memory-store.js +0 -39
  153. package/dist/pipe/project-scanner.d.ts +0 -6
  154. package/dist/pipe/project-scanner.js +0 -26
  155. package/dist/pipe/types.d.ts +0 -34
  156. package/dist/pipe/types.js +0 -1
  157. package/dist/projects/index.d.ts +0 -4
  158. package/dist/projects/index.js +0 -2
  159. package/dist/projects/manager.d.ts +0 -13
  160. package/dist/projects/manager.js +0 -166
  161. package/dist/projects/router.d.ts +0 -17
  162. package/dist/projects/router.js +0 -246
  163. package/dist/projects/types.d.ts +0 -19
  164. package/dist/projects/types.js +0 -1
  165. package/dist/service/install.d.ts +0 -4
  166. package/dist/service/install.js +0 -146
  167. package/dist/service/templates.d.ts +0 -4
  168. package/dist/service/templates.js +0 -52
  169. package/dist/service/windows.d.ts +0 -8
  170. package/dist/service/windows.js +0 -59
  171. package/dist/session/budget-guard.d.ts +0 -20
  172. package/dist/session/budget-guard.js +0 -31
  173. package/dist/session/circuit-breaker.d.ts +0 -19
  174. package/dist/session/circuit-breaker.js +0 -91
  175. package/dist/session/context-compactor.d.ts +0 -32
  176. package/dist/session/context-compactor.js +0 -45
  177. package/dist/session/context-monitor.d.ts +0 -15
  178. package/dist/session/context-monitor.js +0 -44
  179. package/dist/session/handoff.d.ts +0 -21
  180. package/dist/session/handoff.js +0 -50
  181. package/dist/session/manager.d.ts +0 -60
  182. package/dist/session/manager.js +0 -416
  183. package/dist/session/memory-store.d.ts +0 -29
  184. package/dist/session/memory-store.js +0 -45
  185. package/dist/session/message-queue.d.ts +0 -28
  186. package/dist/session/message-queue.js +0 -52
  187. package/dist/session/pending-dispatcher.d.ts +0 -31
  188. package/dist/session/pending-dispatcher.js +0 -120
  189. package/dist/session/pending-store.d.ts +0 -60
  190. package/dist/session/pending-store.js +0 -118
  191. package/dist/session/stale-session.d.ts +0 -31
  192. package/dist/session/stale-session.js +0 -45
  193. package/dist/session/subprocess.d.ts +0 -32
  194. package/dist/session/subprocess.js +0 -230
  195. package/dist/session/tab-store.d.ts +0 -28
  196. package/dist/session/tab-store.js +0 -78
  197. package/dist/session/tool-classifier.d.ts +0 -4
  198. package/dist/session/tool-classifier.js +0 -56
  199. package/dist/tasks/scheduler.d.ts +0 -45
  200. package/dist/tasks/scheduler.js +0 -329
  201. package/dist/tasks/store.d.ts +0 -11
  202. package/dist/tasks/store.js +0 -103
  203. package/dist/timeline/index.d.ts +0 -3
  204. package/dist/timeline/index.js +0 -2
  205. package/dist/timeline/logger.d.ts +0 -8
  206. package/dist/timeline/logger.js +0 -11
  207. package/dist/timeline/query.d.ts +0 -11
  208. package/dist/timeline/query.js +0 -67
  209. package/dist/timeline/types.d.ts +0 -12
  210. package/dist/timeline/types.js +0 -1
  211. package/dist/types.d.ts +0 -225
  212. package/dist/types.js +0 -3
  213. package/dist/users/index.d.ts +0 -2
  214. package/dist/users/index.js +0 -1
  215. package/dist/users/service.d.ts +0 -17
  216. package/dist/users/service.js +0 -46
  217. package/dist/util/auto-heal.d.ts +0 -43
  218. package/dist/util/auto-heal.js +0 -107
  219. package/dist/util/install-info.d.ts +0 -37
  220. package/dist/util/install-info.js +0 -80
  221. package/dist/util/logger.d.ts +0 -18
  222. package/dist/util/logger.js +0 -118
  223. package/dist/util/paths.d.ts +0 -13
  224. package/dist/util/paths.js +0 -55
  225. package/dist/util/platform.d.ts +0 -2
  226. package/dist/util/platform.js +0 -11
  227. package/dist/util/progress.d.ts +0 -34
  228. package/dist/util/progress.js +0 -133
  229. package/dist/util/rate-limiter.d.ts +0 -14
  230. package/dist/util/rate-limiter.js +0 -50
  231. package/dist/util/retry.d.ts +0 -2
  232. package/dist/util/retry.js +0 -18
  233. package/dist/util/text.d.ts +0 -32
  234. package/dist/util/text.js +0 -101
  235. package/dist/version.d.ts +0 -1
  236. package/dist/version.js +0 -4
  237. package/dist/voice/index.d.ts +0 -17
  238. package/dist/voice/index.js +0 -42
  239. package/dist/voice/stt.d.ts +0 -16
  240. package/dist/voice/stt.js +0 -57
  241. package/dist/voice/tts.d.ts +0 -23
  242. package/dist/voice/tts.js +0 -84
  243. package/dist/watchers/evaluator.d.ts +0 -5
  244. package/dist/watchers/evaluator.js +0 -45
  245. package/dist/watchers/index.d.ts +0 -4
  246. package/dist/watchers/index.js +0 -3
  247. package/dist/watchers/scheduler.d.ts +0 -20
  248. package/dist/watchers/scheduler.js +0 -183
  249. package/dist/watchers/store.d.ts +0 -10
  250. package/dist/watchers/store.js +0 -56
  251. package/dist/watchers/types.d.ts +0 -15
  252. package/dist/watchers/types.js +0 -1
  253. package/scripts/postinstall.mjs +0 -50
@@ -1,43 +0,0 @@
1
- export type MediaType = 'image' | 'video' | 'audio' | 'music';
2
- export interface GenerateOptions {
3
- style?: string;
4
- model?: string;
5
- width?: number;
6
- height?: number;
7
- duration?: number;
8
- format?: string;
9
- }
10
- export interface GenerateResult {
11
- filePath: string;
12
- mimeType: string;
13
- durationMs?: number;
14
- metadata?: Record<string, unknown>;
15
- }
16
- export interface MediaGenerator {
17
- readonly id: string;
18
- readonly name: string;
19
- readonly supportedTypes: MediaType[];
20
- generate(type: MediaType, prompt: string, options?: GenerateOptions): Promise<GenerateResult>;
21
- }
22
- /** Gemini `:generateContent` response shape (used by lyria + nano-banana). */
23
- export interface GeminiInlineDataPart {
24
- inlineData?: {
25
- mimeType?: string;
26
- data: string;
27
- };
28
- }
29
- export interface GeminiCandidate {
30
- content?: {
31
- parts?: GeminiInlineDataPart[];
32
- };
33
- }
34
- export interface GeminiGenerateContentResponse {
35
- candidates?: GeminiCandidate[];
36
- }
37
- /** Recraft `/v1/images/generations` response. */
38
- export interface RecraftGenerateResponse {
39
- data?: Array<{
40
- url?: string;
41
- b64_json?: string;
42
- }>;
43
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,5 +0,0 @@
1
- import type { BeecorkConfig } from '../types.js';
2
- /** Auto-extract memories from a completed session */
3
- export declare function extractMemories(config: BeecorkConfig, tabName: string, sessionText: string, durationMs: number): Promise<void>;
4
- /** Inject relevant memories into a prompt */
5
- export declare function getRelevantMemories(tabName: string): string[];
@@ -1,157 +0,0 @@
1
- import { spawn } from 'node:child_process';
2
- import { getDb } from '../db/index.js';
3
- import { logger } from '../util/logger.js';
4
- const EXTRACTION_PROMPT = `Extract 0-5 key facts, decisions, or outcomes from this session transcript that would be useful in future sessions. Output ONLY a JSON array of strings. If nothing is worth remembering, output an empty array [].
5
-
6
- Examples of what to extract:
7
- - Server addresses, credentials, file paths
8
- - User preferences ("prefers deployments after 11pm")
9
- - Decisions made ("chose PostgreSQL over MySQL for X reason")
10
- - Outcomes ("deploy succeeded", "bug was in auth middleware")
11
-
12
- Session transcript:
13
- `;
14
- /** Auto-extract memories from a completed session */
15
- export async function extractMemories(config, tabName, sessionText, durationMs) {
16
- // Only extract from non-trivial sessions
17
- if (durationMs < 10000 || sessionText.length < 200)
18
- return;
19
- // Rate limit: check if we extracted recently for this tab
20
- const db = getDb();
21
- const recent = db.prepare(`SELECT COUNT(*) as count FROM memories
22
- WHERE tab_name = ? AND source = 'auto'
23
- AND created_at > datetime('now', '-5 minutes')`).get(tabName);
24
- if (recent.count > 0) {
25
- logger.debug(`[${tabName}] Skipping memory extraction — too recent`);
26
- return;
27
- }
28
- try {
29
- const prompt = EXTRACTION_PROMPT + sessionText.slice(0, 5000); // Limit transcript size
30
- const facts = await runExtractionSession(config, prompt);
31
- if (facts.length === 0)
32
- return;
33
- for (const fact of facts) {
34
- db.prepare('INSERT INTO memories (content, tab_name, source) VALUES (?, ?, ?)').run(fact, tabName, 'auto');
35
- }
36
- // Enforce maxLongTermEntries limit
37
- const maxEntries = config.memory.maxLongTermEntries ?? 1000;
38
- const count = db.prepare('SELECT COUNT(*) as c FROM memories').get().c;
39
- if (count > maxEntries) {
40
- const excess = count - maxEntries;
41
- db.prepare('DELETE FROM memories WHERE rowid IN (SELECT rowid FROM memories ORDER BY created_at ASC LIMIT ?)').run(excess);
42
- logger.info(`[${tabName}] Evicted ${excess} oldest memories (limit: ${maxEntries})`);
43
- }
44
- logger.info(`[${tabName}] Auto-extracted ${facts.length} memories`);
45
- }
46
- catch (err) {
47
- logger.error(`[${tabName}] Memory extraction failed:`, err);
48
- }
49
- }
50
- /** Inject relevant memories into a prompt */
51
- export function getRelevantMemories(tabName) {
52
- const db = getDb();
53
- // Get recent global memories + tab-specific memories
54
- const memories = db.prepare(`SELECT content FROM memories
55
- WHERE tab_name IS NULL OR tab_name = ?
56
- ORDER BY created_at DESC LIMIT 20`).all(tabName);
57
- return memories.map(m => m.content);
58
- }
59
- async function runExtractionSession(config, prompt) {
60
- // Prefer direct API call (cheaper, faster) when API key is available
61
- if (config.pipe?.anthropicApiKey) {
62
- return runExtractionViaApi(config.pipe.anthropicApiKey, config.pipe.routingModel, prompt);
63
- }
64
- // Fallback: spawn Claude Code subprocess
65
- return runExtractionViaSubprocess(config, prompt);
66
- }
67
- function parseFactsFromText(text) {
68
- const jsonMatch = text.match(/\[[\s\S]*?\]/);
69
- if (jsonMatch) {
70
- const facts = JSON.parse(jsonMatch[0]);
71
- if (Array.isArray(facts) && facts.every(f => typeof f === 'string')) {
72
- return facts.slice(0, 5);
73
- }
74
- }
75
- return [];
76
- }
77
- let cachedClient = null;
78
- let cachedApiKey = '';
79
- async function runExtractionViaApi(apiKey, model, prompt) {
80
- const { default: Anthropic } = await import('@anthropic-ai/sdk');
81
- if (!cachedClient || cachedApiKey !== apiKey) {
82
- cachedClient = new Anthropic({ apiKey });
83
- cachedApiKey = apiKey;
84
- }
85
- const client = cachedClient;
86
- try {
87
- const response = await client.messages.create({
88
- model,
89
- max_tokens: 500,
90
- system: 'Extract 0-5 key facts from this session transcript worth remembering across sessions. Output ONLY a JSON array of strings. If nothing is worth remembering, output [].',
91
- messages: [{ role: 'user', content: prompt }],
92
- }, { timeout: 15000 });
93
- const text = response.content.find((b) => b.type === 'text')?.text ?? '[]';
94
- return parseFactsFromText(text);
95
- }
96
- catch (err) {
97
- logger.warn('API-based memory extraction failed, falling back to subprocess:', err);
98
- return [];
99
- }
100
- }
101
- async function runExtractionViaSubprocess(config, prompt) {
102
- return new Promise((resolve, reject) => {
103
- let resolved = false;
104
- const safeResolve = (val) => { if (!resolved) {
105
- resolved = true;
106
- resolve(val);
107
- } };
108
- const safeReject = (err) => { if (!resolved) {
109
- resolved = true;
110
- reject(err);
111
- } };
112
- const args = [
113
- '-p',
114
- '--output-format', 'stream-json',
115
- '--verbose',
116
- ...config.claudeCode.defaultFlags,
117
- '--no-session-persistence',
118
- prompt,
119
- ];
120
- const proc = spawn(config.claudeCode.bin, args, {
121
- cwd: process.cwd(),
122
- stdio: ['ignore', 'pipe', 'pipe'],
123
- });
124
- let output = '';
125
- let stdoutBuffer = '';
126
- proc.stdout.on('data', (chunk) => {
127
- stdoutBuffer += chunk.toString();
128
- const lines = stdoutBuffer.split('\n');
129
- stdoutBuffer = lines.pop() || '';
130
- for (const line of lines) {
131
- if (!line.trim())
132
- continue;
133
- try {
134
- const event = JSON.parse(line);
135
- if (event.type === 'result' && event.result) {
136
- output = event.result;
137
- }
138
- }
139
- catch { /* skip non-JSON */ }
140
- }
141
- });
142
- proc.on('exit', () => {
143
- clearTimeout(timer);
144
- try {
145
- safeResolve(parseFactsFromText(output));
146
- }
147
- catch {
148
- safeResolve([]);
149
- }
150
- });
151
- proc.on('error', safeReject);
152
- const timer = setTimeout(() => {
153
- proc.kill('SIGTERM');
154
- safeResolve([]);
155
- }, 30000);
156
- });
157
- }
@@ -1,4 +0,0 @@
1
- export type { NotificationProvider } from './types.js';
2
- import type { NotificationProvider } from './types.js';
3
- import type { NotificationConfig } from '../types.js';
4
- export declare function createNotificationProvider(config: NotificationConfig): NotificationProvider | null;
@@ -1,21 +0,0 @@
1
- import { logger } from '../util/logger.js';
2
- import { PushoverProvider } from './pushover.js';
3
- import { NtfyProvider } from './ntfy.js';
4
- import { WebhookNotificationProvider } from './webhook-provider.js';
5
- export function createNotificationProvider(config) {
6
- switch (config.type) {
7
- case 'pushover':
8
- return new PushoverProvider(config.userKey, config.appToken);
9
- case 'ntfy':
10
- return new NtfyProvider(config.topic, config.server);
11
- case 'webhook':
12
- return new WebhookNotificationProvider(config.url, config.headers);
13
- default: {
14
- // Exhaustiveness check — TS will error here if NotificationConfig gains
15
- // a new variant without a matching case above.
16
- const _exhaustive = config;
17
- logger.warn(`Unknown notification provider: ${JSON.stringify(_exhaustive)}`);
18
- return null;
19
- }
20
- }
21
- }
@@ -1,9 +0,0 @@
1
- import type { NotificationProvider } from './types.js';
2
- export declare class NtfyProvider implements NotificationProvider {
3
- private topic;
4
- private server;
5
- readonly id = "ntfy";
6
- readonly name = "ntfy.sh";
7
- constructor(topic: string, server?: string);
8
- send(message: string, urgent?: boolean): Promise<void>;
9
- }
@@ -1,25 +0,0 @@
1
- export class NtfyProvider {
2
- topic;
3
- server;
4
- id = 'ntfy';
5
- name = 'ntfy.sh';
6
- constructor(topic, server = 'https://ntfy.sh') {
7
- this.topic = topic;
8
- this.server = server;
9
- }
10
- async send(message, urgent) {
11
- const response = await fetch(`${this.server}/${this.topic}`, {
12
- method: 'POST',
13
- headers: {
14
- Title: 'Beecork',
15
- Priority: urgent ? '5' : '3',
16
- Tags: urgent ? 'warning' : 'robot',
17
- },
18
- body: message,
19
- signal: AbortSignal.timeout(10000),
20
- });
21
- if (!response.ok) {
22
- throw new Error(`ntfy error: ${response.status}`);
23
- }
24
- }
25
- }
@@ -1,9 +0,0 @@
1
- import type { NotificationProvider } from './types.js';
2
- export declare class PushoverProvider implements NotificationProvider {
3
- private userKey;
4
- private appToken;
5
- readonly id = "pushover";
6
- readonly name = "Pushover";
7
- constructor(userKey: string, appToken: string);
8
- send(message: string, urgent?: boolean): Promise<void>;
9
- }
@@ -1,26 +0,0 @@
1
- export class PushoverProvider {
2
- userKey;
3
- appToken;
4
- id = 'pushover';
5
- name = 'Pushover';
6
- constructor(userKey, appToken) {
7
- this.userKey = userKey;
8
- this.appToken = appToken;
9
- }
10
- async send(message, urgent) {
11
- const response = await fetch('https://api.pushover.net/1/messages.json', {
12
- method: 'POST',
13
- headers: { 'Content-Type': 'application/json' },
14
- body: JSON.stringify({
15
- token: this.appToken,
16
- user: this.userKey,
17
- message: message.slice(0, 1024),
18
- priority: urgent ? 1 : 0,
19
- }),
20
- signal: AbortSignal.timeout(10000),
21
- });
22
- if (!response.ok) {
23
- throw new Error(`Pushover API error: ${response.status}`);
24
- }
25
- }
26
- }
@@ -1,5 +0,0 @@
1
- export interface NotificationProvider {
2
- readonly id: string;
3
- readonly name: string;
4
- send(message: string, urgent?: boolean): Promise<void>;
5
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,9 +0,0 @@
1
- import type { NotificationProvider } from './types.js';
2
- export declare class WebhookNotificationProvider implements NotificationProvider {
3
- private url;
4
- private headers?;
5
- readonly id = "webhook-notify";
6
- readonly name = "Webhook";
7
- constructor(url: string, headers?: Record<string, string> | undefined);
8
- send(message: string, urgent?: boolean): Promise<void>;
9
- }
@@ -1,24 +0,0 @@
1
- export class WebhookNotificationProvider {
2
- url;
3
- headers;
4
- id = 'webhook-notify';
5
- name = 'Webhook';
6
- constructor(url, headers) {
7
- this.url = url;
8
- this.headers = headers;
9
- }
10
- async send(message, urgent) {
11
- const response = await fetch(this.url, {
12
- method: 'POST',
13
- headers: {
14
- 'Content-Type': 'application/json',
15
- ...this.headers,
16
- },
17
- body: JSON.stringify({ message, urgent: !!urgent, timestamp: new Date().toISOString() }),
18
- signal: AbortSignal.timeout(10000),
19
- });
20
- if (!response.ok) {
21
- throw new Error(`Webhook notification error: ${response.status}`);
22
- }
23
- }
24
- }
@@ -1,30 +0,0 @@
1
- import type Database from 'better-sqlite3';
2
- export interface CostSummary {
3
- today: number;
4
- last7Days: number;
5
- last30Days: number;
6
- perTab: Array<{
7
- name: string;
8
- cost: number;
9
- messages: number;
10
- }>;
11
- }
12
- export interface ActivitySummary {
13
- period: string;
14
- messagesReceived: number;
15
- messagesFromAssistant: number;
16
- tasksFired: number;
17
- memoriesCreated: number;
18
- totalCost: number;
19
- activeTabsCount: number;
20
- }
21
- export declare function getCostSummary(): CostSummary;
22
- export declare function getActivitySummary(hours?: number): ActivitySummary;
23
- /**
24
- * Returns a notification only on state transitions (ok↔breach), persisting
25
- * the state in the `preferences` table so daemon restarts don't re-fire.
26
- */
27
- export declare function checkAnomaliesWithDb(db: Database.Database): string | null;
28
- export declare function checkAnomalies(): string | null;
29
- export declare function formatCostSummary(summary: CostSummary): string;
30
- export declare function formatActivitySummary(summary: ActivitySummary): string;
@@ -1,118 +0,0 @@
1
- import { getDb } from '../db/index.js';
2
- export function getCostSummary() {
3
- const db = getDb();
4
- const today = db
5
- .prepare("SELECT COALESCE(SUM(cost_usd), 0) as total FROM messages WHERE created_at > date('now')")
6
- .get().total;
7
- const last7 = db
8
- .prepare("SELECT COALESCE(SUM(cost_usd), 0) as total FROM messages WHERE created_at > date('now', '-7 days')")
9
- .get().total;
10
- const last30 = db
11
- .prepare("SELECT COALESCE(SUM(cost_usd), 0) as total FROM messages WHERE created_at > date('now', '-30 days')")
12
- .get().total;
13
- // Per-tab summed over the last 30 days only — the unbounded version grew
14
- // linearly with the messages table and made /cost noticeably slow over time.
15
- const perTab = db
16
- .prepare(`
17
- SELECT t.name, COALESCE(SUM(m.cost_usd), 0) as cost, COUNT(m.id) as messages
18
- FROM tabs t LEFT JOIN messages m ON m.tab_id = t.id
19
- AND m.created_at > date('now', '-30 days')
20
- GROUP BY t.id ORDER BY cost DESC
21
- `)
22
- .all();
23
- return { today, last7Days: last7, last30Days: last30, perTab };
24
- }
25
- export function getActivitySummary(hours = 24) {
26
- const db = getDb();
27
- const sinceDate = new Date(Date.now() - hours * 3600000).toISOString();
28
- const messagesReceived = db
29
- .prepare('SELECT COUNT(*) as c FROM messages WHERE role = ? AND created_at > ?')
30
- .get('user', sinceDate).c;
31
- const messagesFromAssistant = db
32
- .prepare('SELECT COUNT(*) as c FROM messages WHERE role = ? AND created_at > ?')
33
- .get('assistant', sinceDate).c;
34
- const tasksFired = db.prepare('SELECT COUNT(*) as c FROM tasks WHERE last_run_at > ?').get(sinceDate).c;
35
- const memoriesCreated = db.prepare('SELECT COUNT(*) as c FROM memories WHERE created_at > ?').get(sinceDate).c;
36
- const totalCost = db
37
- .prepare('SELECT COALESCE(SUM(cost_usd), 0) as total FROM messages WHERE created_at > ?')
38
- .get(sinceDate).total;
39
- const activeTabsCount = db
40
- .prepare('SELECT COUNT(DISTINCT tab_id) as c FROM messages WHERE created_at > ?')
41
- .get(sinceDate).c;
42
- return {
43
- period: `Last ${hours} hours`,
44
- messagesReceived,
45
- messagesFromAssistant,
46
- tasksFired,
47
- memoriesCreated,
48
- totalCost,
49
- activeTabsCount,
50
- };
51
- }
52
- const ANOMALY_STATE_KEY = 'anomaly_spend_state';
53
- /**
54
- * Returns a notification only on state transitions (ok↔breach), persisting
55
- * the state in the `preferences` table so daemon restarts don't re-fire.
56
- */
57
- export function checkAnomaliesWithDb(db) {
58
- // Today's spend
59
- const todaySpend = db
60
- .prepare("SELECT COALESCE(SUM(cost_usd), 0) as total FROM messages WHERE created_at > date('now')")
61
- .get().total;
62
- // 7-day rolling average (excluding today)
63
- const avgSpend = db
64
- .prepare(`
65
- SELECT COALESCE(AVG(daily_total), 0) as avg FROM (
66
- SELECT date(created_at) as day, SUM(cost_usd) as daily_total
67
- FROM messages
68
- WHERE created_at > date('now', '-7 days') AND created_at < date('now')
69
- GROUP BY date(created_at)
70
- )
71
- `)
72
- .get().avg;
73
- const isBreach = avgSpend > 0 && todaySpend > avgSpend * 2;
74
- const newState = isBreach ? 'breach' : 'ok';
75
- const prevRow = db
76
- .prepare('SELECT value FROM preferences WHERE key = ?')
77
- .get(ANOMALY_STATE_KEY);
78
- const prevState = prevRow?.value ?? 'ok';
79
- if (newState === prevState)
80
- return null;
81
- db.prepare(`INSERT INTO preferences (key, value, updated_at) VALUES (?, ?, datetime('now'))
82
- ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = datetime('now')`).run(ANOMALY_STATE_KEY, newState);
83
- if (isBreach) {
84
- return `⚠️ Anomaly: Today's spend ($${todaySpend.toFixed(4)}) exceeds 2x your 7-day average ($${avgSpend.toFixed(4)}/day)`;
85
- }
86
- return `✅ Recovered: Today's spend ($${todaySpend.toFixed(4)}) is back within 2x your 7-day average ($${avgSpend.toFixed(4)}/day)`;
87
- }
88
- export function checkAnomalies() {
89
- return checkAnomaliesWithDb(getDb());
90
- }
91
- export function formatCostSummary(summary) {
92
- const lines = [
93
- `💰 Cost Summary`,
94
- ` Today: $${summary.today.toFixed(4)}`,
95
- ` 7 days: $${summary.last7Days.toFixed(4)}`,
96
- ` 30 days: $${summary.last30Days.toFixed(4)}`,
97
- ];
98
- if (summary.perTab.length > 0) {
99
- lines.push('', ' Per tab:');
100
- for (const tab of summary.perTab.slice(0, 10)) {
101
- if (tab.cost > 0) {
102
- lines.push(` ${tab.name}: $${tab.cost.toFixed(4)} (${tab.messages} msgs)`);
103
- }
104
- }
105
- }
106
- return lines.join('\n');
107
- }
108
- export function formatActivitySummary(summary) {
109
- return [
110
- `📊 Activity (${summary.period})`,
111
- ` Messages in: ${summary.messagesReceived}`,
112
- ` Messages out: ${summary.messagesFromAssistant}`,
113
- ` Tasks fired: ${summary.tasksFired}`,
114
- ` Memories created: ${summary.memoriesCreated}`,
115
- ` Active tabs: ${summary.activeTabsCount}`,
116
- ` Cost: $${summary.totalCost.toFixed(4)}`,
117
- ].join('\n');
118
- }
@@ -1,9 +0,0 @@
1
- import type { RouteDecision, Project } from './types.js';
2
- export declare class PipeAnthropicClient {
3
- private client;
4
- private routingModel;
5
- constructor(apiKey: string, routingModel: string);
6
- /** Route a message to the right project/tab (Haiku — fast, cheap) */
7
- route(message: string, projects: Project[], recentRouting: string[]): Promise<RouteDecision>;
8
- private complete;
9
- }
@@ -1,50 +0,0 @@
1
- import Anthropic from '@anthropic-ai/sdk';
2
- import { logger } from '../util/logger.js';
3
- import { retryWithBackoff } from '../util/retry.js';
4
- export class PipeAnthropicClient {
5
- client;
6
- routingModel;
7
- constructor(apiKey, routingModel) {
8
- this.client = new Anthropic({ apiKey });
9
- this.routingModel = routingModel;
10
- }
11
- /** Route a message to the right project/tab (Haiku — fast, cheap) */
12
- async route(message, projects, recentRouting) {
13
- const projectList = projects.map(p => `- ${p.name}: ${p.path}${p.languages?.length ? ` (${p.languages.join(', ')})` : ''}${p.description ? ` — ${p.description}` : ''}`).join('\n');
14
- const response = await this.complete(`You are a message router. Given a user message, determine which project it relates to.
15
-
16
- Available projects:
17
- ${projectList || '(no projects discovered yet)'}
18
-
19
- Recent routing decisions:
20
- ${recentRouting.slice(0, 5).join('\n') || '(none)'}
21
-
22
- Respond with ONLY valid JSON: {"tabName": "project-name", "projectPath": "/path", "confidence": 0.0-1.0, "reason": "brief explanation", "needsConfirmation": false}
23
-
24
- If the message is a general question not related to any project, use tabName "default" with the user's home directory.
25
- If unsure which project, set confidence below 0.5 and needsConfirmation to true.`, message);
26
- try {
27
- return JSON.parse(response);
28
- }
29
- catch {
30
- logger.warn('Failed to parse routing response:', response);
31
- return { tabName: 'default', projectPath: null, confidence: 0.3, reason: 'Could not parse routing', needsConfirmation: true };
32
- }
33
- }
34
- async complete(systemPrompt, userMessage) {
35
- try {
36
- const response = await retryWithBackoff(() => this.client.messages.create({
37
- model: this.routingModel,
38
- max_tokens: 500,
39
- system: systemPrompt,
40
- messages: [{ role: 'user', content: userMessage }],
41
- }, { timeout: 30000 }), [1000, 5000, 15000], `Pipe API call (routing)`);
42
- const textBlock = response.content.find(b => b.type === 'text');
43
- return textBlock?.text ?? '';
44
- }
45
- catch (err) {
46
- logger.error(`Pipe API call failed (routing):`, err);
47
- throw err;
48
- }
49
- }
50
- }
@@ -1,16 +0,0 @@
1
- import type { TabManager } from '../session/manager.js';
2
- import type { BeecorkConfig } from '../types.js';
3
- import type { ChatContext, PipeResult } from './types.js';
4
- export declare class PipeBrain {
5
- private client;
6
- private memory;
7
- private config;
8
- private tabManager;
9
- constructor(config: BeecorkConfig, tabManager: TabManager);
10
- /** Main entry point: route a message to the right tab and send it to Claude. */
11
- process(message: string, _context: ChatContext): Promise<PipeResult>;
12
- /** Route a message to the right project/tab */
13
- private route;
14
- /** Discover projects on the filesystem */
15
- discoverProjects(): Promise<number>;
16
- }