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
@@ -1,246 +0,0 @@
1
- import { getDb } from '../db/index.js';
2
- import { listProjects, getProject, ensureCategory, touchProject } from './manager.js';
3
- // Category keywords for non-project routing
4
- const CATEGORY_KEYWORDS = {
5
- research: ['research', 'find out', 'look into', 'compare', 'investigate', 'analyze', 'study'],
6
- planning: ['plan', 'schedule', 'organize', 'roadmap', 'strategy', 'outline', 'agenda'],
7
- };
8
- // Per-user current context tracking (in-memory, resets on daemon restart)
9
- const userContext = new Map();
10
- // Project list cache. listProjects() ran on every inbound message and re-did a
11
- // full SELECT + ORDER BY across the projects table; with N projects each call
12
- // then re-lowercased every name. The cache is invalidated explicitly via
13
- // invalidateProjectCache() at the few sites that mutate the table.
14
- let projectsCache = null;
15
- const PROJECTS_CACHE_TTL_MS = 30_000;
16
- function getUserProjectsCached() {
17
- const now = Date.now();
18
- if (projectsCache && projectsCache.expiresAt > now)
19
- return projectsCache.user;
20
- const user = listProjects()
21
- .filter((p) => p.type === 'user-project')
22
- .map((p) => ({ ...p, nameLower: p.name.toLowerCase() }));
23
- projectsCache = { user, expiresAt: now + PROJECTS_CACHE_TTL_MS };
24
- return user;
25
- }
26
- /** Invalidate the project cache. Call after createProject/discoverProjects/etc. */
27
- export function invalidateProjectCache() {
28
- projectsCache = null;
29
- }
30
- /** Route a message to the right project and tab */
31
- export function routeMessage(message, context) {
32
- const projects = getUserProjectsCached();
33
- const userId = context?.userId || 'default';
34
- const messageLower = message.toLowerCase();
35
- // 1. Check for explicit project mention by name
36
- const mentionedProject = findMentionedProject(messageLower, projects);
37
- if (mentionedProject) {
38
- const { tabName, exists } = resolveTabInProject(mentionedProject);
39
- touchProject(mentionedProject.name);
40
- recordRouting(message, mentionedProject.name);
41
- return {
42
- project: mentionedProject,
43
- tabName,
44
- isNewTab: !exists,
45
- confidence: 0.95,
46
- needsConfirmation: false,
47
- reason: `Message mentions project "${mentionedProject.name}"`,
48
- };
49
- }
50
- // 2. Check if continuing current context
51
- const currentCtx = userContext.get(userId);
52
- if (currentCtx && Date.now() - currentCtx.updatedAt < 10 * 60 * 1000) {
53
- // 10 min window
54
- const project = getProject(currentCtx.projectName);
55
- if (project) {
56
- touchProject(project.name);
57
- return {
58
- project,
59
- tabName: currentCtx.tabName,
60
- isNewTab: false,
61
- confidence: 0.7,
62
- needsConfirmation: false,
63
- reason: `Continuing in "${project.name}" (recent context)`,
64
- };
65
- }
66
- }
67
- // 3. Check routing preferences (learned patterns)
68
- const learned = checkLearnedRouting(messageLower);
69
- if (learned) {
70
- const project = getProject(learned.projectName);
71
- if (project && learned.confidence >= 0.9) {
72
- const { tabName, exists } = resolveTabInProject(project);
73
- touchProject(project.name);
74
- return {
75
- project,
76
- tabName,
77
- isNewTab: !exists,
78
- confidence: learned.confidence,
79
- needsConfirmation: false,
80
- reason: `Learned pattern → "${project.name}"`,
81
- };
82
- }
83
- }
84
- // 4. Multiple projects could match — ask user
85
- const possibleMatches = findPossibleMatches(messageLower, projects);
86
- if (possibleMatches.length > 1) {
87
- return {
88
- project: possibleMatches[0],
89
- tabName: possibleMatches[0].name,
90
- isNewTab: false,
91
- confidence: 0.5,
92
- needsConfirmation: true,
93
- reason: `Multiple projects could match: ${possibleMatches.map((p) => p.name).join(', ')}`,
94
- };
95
- }
96
- // 5. Check for category keywords (non-project)
97
- const category = detectCategory(messageLower);
98
- if (category) {
99
- const project = ensureCategory(category);
100
- const tabName = category;
101
- return {
102
- project,
103
- tabName,
104
- isNewTab: !tabExists(tabName),
105
- confidence: 0.8,
106
- needsConfirmation: false,
107
- reason: `Detected category: ${category}`,
108
- };
109
- }
110
- // 6. Default to general
111
- const general = ensureCategory('general');
112
- return {
113
- project: general,
114
- tabName: 'general',
115
- isNewTab: !tabExists('general'),
116
- confidence: 0.6,
117
- needsConfirmation: false,
118
- reason: 'Default routing to general',
119
- };
120
- }
121
- /** Update current context for a user */
122
- export function setUserContext(userId, projectName, tabName) {
123
- userContext.set(userId, { projectName, tabName, updatedAt: Date.now() });
124
- // Evict oldest entry when map grows too large
125
- if (userContext.size > 1000) {
126
- let oldestKey = '';
127
- let oldestTime = Infinity;
128
- for (const [key, val] of userContext) {
129
- if (val.updatedAt < oldestTime) {
130
- oldestTime = val.updatedAt;
131
- oldestKey = key;
132
- }
133
- }
134
- if (oldestKey)
135
- userContext.delete(oldestKey);
136
- }
137
- }
138
- /** Find a project explicitly mentioned by name in the message (messageLower already lower-cased) */
139
- function findMentionedProject(messageLower, projects) {
140
- for (const project of projects) {
141
- if (messageLower.includes(project.nameLower))
142
- return project;
143
- }
144
- return null;
145
- }
146
- /** Find possible project matches (for ambiguity) */
147
- function findPossibleMatches(messageLower, projects) {
148
- const words = messageLower.split(/\s+/);
149
- return projects.filter((p) => {
150
- const nameParts = p.nameLower.split(/[-_]/);
151
- return nameParts.some((part) => words.includes(part));
152
- });
153
- }
154
- /**
155
- * Resolve which tab to use within a project. Coalesces the previous
156
- * "find tabs + tabExists" into one query — the caller used to fire both
157
- * back-to-back, and the working_dir scan had no covering index.
158
- * (Index added by migration v28; see src/db/migrations.ts.)
159
- */
160
- function resolveTabInProject(project) {
161
- const db = getDb();
162
- const row = db
163
- .prepare('SELECT name FROM tabs WHERE working_dir = ? ORDER BY last_activity_at DESC LIMIT 1')
164
- .get(project.path);
165
- return row ? { tabName: row.name, exists: true } : { tabName: project.name, exists: false };
166
- }
167
- /** Check if a tab exists in the database */
168
- function tabExists(tabName) {
169
- const db = getDb();
170
- const row = db.prepare('SELECT 1 FROM tabs WHERE name = ?').get(tabName);
171
- return !!row;
172
- }
173
- /** Detect a category from keywords (messageLower already lower-cased) */
174
- function detectCategory(messageLower) {
175
- for (const [category, keywords] of Object.entries(CATEGORY_KEYWORDS)) {
176
- if (keywords.some((kw) => messageLower.includes(kw)))
177
- return category;
178
- }
179
- return null;
180
- }
181
- /** Record a successful routing for learning */
182
- function recordRouting(message, projectName) {
183
- const db = getDb();
184
- // Extract key words from message for pattern matching
185
- const words = message
186
- .toLowerCase()
187
- .split(/\s+/)
188
- .filter((w) => w.length > 3)
189
- .slice(0, 5);
190
- const pattern = words.join(' ');
191
- if (!pattern)
192
- return;
193
- db.prepare(`
194
- INSERT INTO routing_preferences (pattern, project_name)
195
- VALUES (?, ?)
196
- ON CONFLICT(pattern, project_name) DO UPDATE SET hit_count = hit_count + 1
197
- `).run(pattern, projectName);
198
- }
199
- /** Check learned routing preferences (messageLower already lower-cased) */
200
- function checkLearnedRouting(messageLower) {
201
- const db = getDb();
202
- const words = messageLower.split(/\s+/).filter((w) => w.length > 3);
203
- if (words.length === 0)
204
- return null;
205
- // Fetch all preferences in a single query and match in JS
206
- const allPrefs = db
207
- .prepare('SELECT pattern, project_name, confidence, hit_count FROM routing_preferences WHERE hit_count >= 3 ORDER BY hit_count DESC LIMIT 200')
208
- .all();
209
- for (const pref of allPrefs) {
210
- // pref.pattern was written via .toLowerCase() in recordRouting(), so no
211
- // re-lowercase here (saves N allocations per inbound message).
212
- const patternLower = pref.pattern;
213
- if (words.some((word) => patternLower.includes(word) || word.includes(patternLower))) {
214
- return { projectName: pref.project_name, confidence: Math.min(pref.confidence, 0.9) };
215
- }
216
- }
217
- return null;
218
- }
219
- /**
220
- * Shared project routing logic — resolves which tab/project to use for a message.
221
- * Pulled out of channels/ so all routing decisions live in one place.
222
- */
223
- export async function resolveProjectRoute(rawPrompt, tabName, text, userId) {
224
- if (tabName !== 'default' || text.startsWith('/tab ')) {
225
- return { effectiveTabName: tabName };
226
- }
227
- try {
228
- const decision = routeMessage(rawPrompt, { userId });
229
- if (decision.needsConfirmation) {
230
- const projects = listProjects().filter((p) => p.type === 'user-project');
231
- const options = projects.map((p, i) => `${i + 1}) ${p.name}`).join('\n');
232
- return {
233
- effectiveTabName: tabName,
234
- confirmationMessage: `Which project?\n${options}\n\nReply with the number, or just send your message with /project <name> first.`,
235
- };
236
- }
237
- setUserContext(userId, decision.project.name, decision.tabName);
238
- return {
239
- effectiveTabName: decision.tabName,
240
- projectPath: decision.project.path,
241
- };
242
- }
243
- catch {
244
- return { effectiveTabName: tabName };
245
- }
246
- }
@@ -1,19 +0,0 @@
1
- export interface Project {
2
- id: string;
3
- name: string;
4
- path: string;
5
- type: 'user-project' | 'category';
6
- lastUsedAt: string;
7
- createdAt: string;
8
- }
9
- export interface RouteDecision {
10
- project: Project;
11
- tabName: string;
12
- isNewTab: boolean;
13
- confidence: number;
14
- needsConfirmation: boolean;
15
- reason: string;
16
- }
17
- export interface RoutingContext {
18
- userId?: string;
19
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,4 +0,0 @@
1
- export declare function installService(): string;
2
- export declare function uninstallService(): string;
3
- export declare function startService(): void;
4
- export declare function stopService(): void;
@@ -1,146 +0,0 @@
1
- import fs from 'node:fs';
2
- import path from 'node:path';
3
- import { execSync } from 'node:child_process';
4
- import { getPlatform } from '../util/platform.js';
5
- import { ensureBeecorkDirs } from '../util/paths.js';
6
- import { getLaunchdPlist, getSystemdUnit, getLaunchdPlistPath, getSystemdUnitPath, } from './templates.js';
7
- import { installWindowsService, startWindowsService, stopWindowsService, uninstallWindowsService, } from './windows.js';
8
- function findNodePath() {
9
- try {
10
- const cmd = process.platform === 'win32' ? 'where node' : 'which node';
11
- return execSync(cmd, { encoding: 'utf-8' }).trim().split(/\r?\n/)[0];
12
- }
13
- catch {
14
- return process.platform === 'win32' ? 'node' : '/usr/local/bin/node';
15
- }
16
- }
17
- function findDaemonPath() {
18
- // import.meta.url is dist/service/install.js — daemon is at dist/daemon.js (one level up)
19
- const thisFileUrl = new URL(import.meta.url);
20
- const thisFile = process.platform === 'win32'
21
- ? thisFileUrl.pathname.replace(/^\/([A-Za-z]:)/, '$1') // strip leading / on Windows drive paths
22
- : thisFileUrl.pathname;
23
- const distDir = path.dirname(path.dirname(thisFile)); // go up from service/ to dist/
24
- const daemonPath = path.join(distDir, 'daemon.js');
25
- if (fs.existsSync(daemonPath))
26
- return daemonPath;
27
- // Fallback: maybe we're in src/ during development
28
- const srcDaemon = path.resolve(distDir, '..', 'dist', 'daemon.js');
29
- if (fs.existsSync(srcDaemon))
30
- return srcDaemon;
31
- throw new Error('Could not find daemon.js. Make sure beecork is built (npm run build).');
32
- }
33
- export function installService() {
34
- ensureBeecorkDirs();
35
- const platform = getPlatform();
36
- const nodePath = findNodePath();
37
- const daemonPath = findDaemonPath();
38
- if (platform === 'windows') {
39
- installWindowsService(`${nodePath}" "${daemonPath}`);
40
- return 'Windows Task Scheduler';
41
- }
42
- else if (platform === 'mac') {
43
- return installLaunchd(nodePath, daemonPath);
44
- }
45
- else {
46
- return installSystemd(nodePath, daemonPath);
47
- }
48
- }
49
- export function uninstallService() {
50
- const platform = getPlatform();
51
- if (platform === 'windows') {
52
- uninstallWindowsService();
53
- return 'Windows Task Scheduler';
54
- }
55
- else if (platform === 'mac') {
56
- return uninstallLaunchd();
57
- }
58
- else {
59
- return uninstallSystemd();
60
- }
61
- }
62
- export function startService() {
63
- const platform = getPlatform();
64
- if (platform === 'windows') {
65
- startWindowsService();
66
- }
67
- else if (platform === 'mac') {
68
- const plistPath = getLaunchdPlistPath();
69
- execSync(`launchctl load "${plistPath}"`, { stdio: 'inherit' });
70
- }
71
- else {
72
- execSync('systemctl --user start beecork', { stdio: 'inherit' });
73
- }
74
- }
75
- export function stopService() {
76
- const platform = getPlatform();
77
- if (platform === 'windows') {
78
- stopWindowsService();
79
- }
80
- else if (platform === 'mac') {
81
- const plistPath = getLaunchdPlistPath();
82
- try {
83
- execSync(`launchctl unload "${plistPath}"`, { stdio: 'inherit' });
84
- }
85
- catch {
86
- /* not loaded */
87
- }
88
- }
89
- else {
90
- try {
91
- execSync('systemctl --user stop beecork', { stdio: 'inherit' });
92
- }
93
- catch {
94
- /* not running */
95
- }
96
- }
97
- }
98
- function installLaunchd(nodePath, daemonPath) {
99
- const plistPath = getLaunchdPlistPath();
100
- const plistDir = path.dirname(plistPath);
101
- fs.mkdirSync(plistDir, { recursive: true });
102
- const content = getLaunchdPlist(nodePath, daemonPath);
103
- fs.writeFileSync(plistPath, content);
104
- return plistPath;
105
- }
106
- function uninstallLaunchd() {
107
- const plistPath = getLaunchdPlistPath();
108
- try {
109
- execSync(`launchctl unload "${plistPath}"`, { stdio: 'pipe' });
110
- }
111
- catch {
112
- /* ok */
113
- }
114
- if (fs.existsSync(plistPath))
115
- fs.unlinkSync(plistPath);
116
- return plistPath;
117
- }
118
- function installSystemd(nodePath, daemonPath) {
119
- const unitPath = getSystemdUnitPath();
120
- const unitDir = path.dirname(unitPath);
121
- fs.mkdirSync(unitDir, { recursive: true });
122
- const content = getSystemdUnit(nodePath, daemonPath);
123
- fs.writeFileSync(unitPath, content);
124
- execSync('systemctl --user daemon-reload', { stdio: 'pipe' });
125
- execSync('systemctl --user enable beecork', { stdio: 'pipe' });
126
- return unitPath;
127
- }
128
- function uninstallSystemd() {
129
- const unitPath = getSystemdUnitPath();
130
- try {
131
- execSync('systemctl --user disable beecork', { stdio: 'pipe' });
132
- }
133
- catch {
134
- /* ok */
135
- }
136
- try {
137
- execSync('systemctl --user stop beecork', { stdio: 'pipe' });
138
- }
139
- catch {
140
- /* ok */
141
- }
142
- if (fs.existsSync(unitPath))
143
- fs.unlinkSync(unitPath);
144
- execSync('systemctl --user daemon-reload', { stdio: 'pipe' });
145
- return unitPath;
146
- }
@@ -1,4 +0,0 @@
1
- export declare function getLaunchdPlist(nodePath: string, daemonPath: string): string;
2
- export declare function getSystemdUnit(nodePath: string, daemonPath: string): string;
3
- export declare function getLaunchdPlistPath(): string;
4
- export declare function getSystemdUnitPath(): string;
@@ -1,52 +0,0 @@
1
- import os from 'node:os';
2
- export function getLaunchdPlist(nodePath, daemonPath) {
3
- const home = os.homedir();
4
- return `<?xml version="1.0" encoding="UTF-8"?>
5
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
6
- <plist version="1.0">
7
- <dict>
8
- <key>Label</key>
9
- <string>com.beecork.daemon</string>
10
- <key>ProgramArguments</key>
11
- <array>
12
- <string>${nodePath}</string>
13
- <string>${daemonPath}</string>
14
- </array>
15
- <key>RunAtLoad</key>
16
- <true/>
17
- <key>KeepAlive</key>
18
- <true/>
19
- <key>StandardOutPath</key>
20
- <string>${home}/.beecork/logs/daemon.stdout.log</string>
21
- <key>StandardErrorPath</key>
22
- <string>${home}/.beecork/logs/daemon.stderr.log</string>
23
- <key>EnvironmentVariables</key>
24
- <dict>
25
- <key>PATH</key>
26
- <string>/usr/local/bin:/usr/bin:/bin:${home}/.local/bin:${home}/.nvm/versions/node/current/bin</string>
27
- <key>HOME</key>
28
- <string>${home}</string>
29
- </dict>
30
- </dict>
31
- </plist>`;
32
- }
33
- export function getSystemdUnit(nodePath, daemonPath) {
34
- return `[Unit]
35
- Description=Beecork - Claude Code always-on infrastructure
36
- After=network.target
37
-
38
- [Service]
39
- ExecStart=${nodePath} ${daemonPath}
40
- Restart=always
41
- RestartSec=5
42
- Environment=PATH=/usr/local/bin:/usr/bin:/bin:%h/.local/bin
43
-
44
- [Install]
45
- WantedBy=default.target`;
46
- }
47
- export function getLaunchdPlistPath() {
48
- return `${os.homedir()}/Library/LaunchAgents/com.beecork.daemon.plist`;
49
- }
50
- export function getSystemdUnitPath() {
51
- return `${os.homedir()}/.config/systemd/user/beecork.service`;
52
- }
@@ -1,8 +0,0 @@
1
- /** Install Beecork as a Windows Task Scheduler task */
2
- export declare function installWindowsService(binPath: string): void;
3
- /** Start the Windows service */
4
- export declare function startWindowsService(): void;
5
- /** Stop the Windows service */
6
- export declare function stopWindowsService(): void;
7
- /** Uninstall the Windows service */
8
- export declare function uninstallWindowsService(): void;
@@ -1,59 +0,0 @@
1
- import fs from 'node:fs';
2
- import path from 'node:path';
3
- import { execSync } from 'node:child_process';
4
- const TASK_NAME = 'BeecorkDaemon';
5
- /** Install Beecork as a Windows Task Scheduler task */
6
- export function installWindowsService(binPath) {
7
- const appData = process.env.APPDATA || path.join(process.env.USERPROFILE || '', 'AppData', 'Roaming');
8
- const logPath = path.join(appData, '.beecork', 'logs', 'daemon.log');
9
- // Ensure log directory exists
10
- fs.mkdirSync(path.dirname(logPath), { recursive: true });
11
- // Create a wrapper script that runs beecork daemon
12
- const wrapperPath = path.join(appData, '.beecork', 'start-daemon.bat');
13
- fs.writeFileSync(wrapperPath, `@echo off\r\n"${binPath}" daemon >> "${logPath}" 2>&1\r\n`);
14
- try {
15
- // Remove existing task if any
16
- execSync(`schtasks /Delete /TN "${TASK_NAME}" /F 2>nul`, { stdio: 'ignore' });
17
- }
18
- catch { }
19
- // Create scheduled task that runs at logon
20
- execSync(`schtasks /Create /TN "${TASK_NAME}" /TR "${wrapperPath}" /SC ONLOGON /RL HIGHEST /F`, {
21
- stdio: 'inherit',
22
- });
23
- console.log(`Windows service installed: ${TASK_NAME}`);
24
- console.log('The daemon will start automatically when you log in.');
25
- }
26
- /** Start the Windows service */
27
- export function startWindowsService() {
28
- try {
29
- execSync(`schtasks /Run /TN "${TASK_NAME}"`, { stdio: 'inherit' });
30
- console.log('Beecork daemon started.');
31
- }
32
- catch {
33
- console.error('Failed to start. Run manually: beecork daemon');
34
- }
35
- }
36
- /** Stop the Windows service */
37
- export function stopWindowsService() {
38
- try {
39
- execSync(`schtasks /End /TN "${TASK_NAME}"`, { stdio: 'inherit' });
40
- console.log('Beecork daemon stopped.');
41
- }
42
- catch {
43
- // Try killing the process directly
44
- try {
45
- execSync('taskkill /F /IM node.exe /FI "WINDOWTITLE eq beecork*"', { stdio: 'ignore' });
46
- }
47
- catch { }
48
- }
49
- }
50
- /** Uninstall the Windows service */
51
- export function uninstallWindowsService() {
52
- try {
53
- execSync(`schtasks /Delete /TN "${TASK_NAME}" /F`, { stdio: 'inherit' });
54
- console.log('Beecork service uninstalled.');
55
- }
56
- catch {
57
- console.error('Failed to uninstall service.');
58
- }
59
- }
@@ -1,20 +0,0 @@
1
- /**
2
- * Per-tab spend budget enforcement, extracted from TabManager.
3
- *
4
- * Pure function (with a tiny stateful wrapper) so it can be unit-tested without
5
- * a database or a running subprocess: feed in current spend + tab name, get a
6
- * decision back. The caller (TabManager.executeMessage) handles the side
7
- * effects (notify + early return).
8
- */
9
- export interface BudgetDecision {
10
- allowed: boolean;
11
- /** When allowed=false, the message to surface to the caller. */
12
- reason?: string;
13
- /** When the tab has crossed the 80% threshold, the warning text to notify. */
14
- warning?: string;
15
- }
16
- export declare class BudgetGuard {
17
- private maxBudgetUsd;
18
- constructor(maxBudgetUsd: number | undefined);
19
- check(currentSpend: number, tabName: string): BudgetDecision;
20
- }
@@ -1,31 +0,0 @@
1
- /**
2
- * Per-tab spend budget enforcement, extracted from TabManager.
3
- *
4
- * Pure function (with a tiny stateful wrapper) so it can be unit-tested without
5
- * a database or a running subprocess: feed in current spend + tab name, get a
6
- * decision back. The caller (TabManager.executeMessage) handles the side
7
- * effects (notify + early return).
8
- */
9
- export class BudgetGuard {
10
- maxBudgetUsd;
11
- constructor(maxBudgetUsd) {
12
- this.maxBudgetUsd = maxBudgetUsd;
13
- }
14
- check(currentSpend, tabName) {
15
- if (!this.maxBudgetUsd)
16
- return { allowed: true };
17
- if (currentSpend >= this.maxBudgetUsd) {
18
- return {
19
- allowed: false,
20
- reason: `Budget limit reached for tab "${tabName}": $${currentSpend.toFixed(2)} / $${this.maxBudgetUsd.toFixed(2)}`,
21
- };
22
- }
23
- if (currentSpend >= this.maxBudgetUsd * 0.8) {
24
- return {
25
- allowed: true,
26
- warning: `⚠️ Budget warning: tab "${tabName}" at $${currentSpend.toFixed(2)} / $${this.maxBudgetUsd.toFixed(2)} (80%)`,
27
- };
28
- }
29
- return { allowed: true };
30
- }
31
- }
@@ -1,19 +0,0 @@
1
- import type { CircuitBreakerConfig, StreamContentToolUse } from '../types.js';
2
- export type CircuitBreakerAction = 'ok' | 'warn' | 'notify' | 'break';
3
- export declare class CircuitBreaker {
4
- private tabName;
5
- private ring;
6
- private ringHead;
7
- private ringSize;
8
- private config;
9
- private tripped;
10
- private warned;
11
- private notified;
12
- private readonly WARN_THRESHOLD;
13
- private readonly NOTIFY_THRESHOLD;
14
- constructor(tabName: string, config?: Partial<CircuitBreakerConfig>);
15
- /** Record a tool call. Returns the action to take. */
16
- recordToolCall(toolUse: StreamContentToolUse): CircuitBreakerAction;
17
- reset(): void;
18
- get isTripped(): boolean;
19
- }