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,12 +0,0 @@
1
- export type EventType = 'task_started' | 'task_completed' | 'task_failed' | 'watcher_triggered' | 'media_generated' | 'delegation_completed' | 'user_command' | 'system_event';
2
- export interface ActivityEvent {
3
- id: string;
4
- eventType: EventType;
5
- projectName: string | null;
6
- tabName: string | null;
7
- summary: string;
8
- details: string | null;
9
- durationMs: number | null;
10
- costUsd: number | null;
11
- createdAt: string;
12
- }
@@ -1 +0,0 @@
1
- export {};
package/dist/types.d.ts DELETED
@@ -1,216 +0,0 @@
1
- export interface TelegramConfig {
2
- token: string;
3
- allowedUserIds: number[];
4
- adminUserId?: number;
5
- }
6
- export interface ClaudeCodeConfig {
7
- bin: string;
8
- defaultFlags: string[];
9
- maxBudgetUsd?: number;
10
- computerUse?: boolean;
11
- /** Hard timeout per subprocess turn. Default 30 min. Set to 0 to disable. */
12
- maxRuntimeMs?: number;
13
- }
14
- export interface MemoryConfig {
15
- dbPath: string;
16
- }
17
- export interface TabConfig {
18
- workingDir: string;
19
- }
20
- export interface TabTemplate {
21
- workingDir?: string;
22
- systemPrompt?: string;
23
- }
24
- export interface WhatsAppConfig {
25
- enabled: boolean;
26
- mode: 'baileys';
27
- sessionPath: string;
28
- allowedNumbers: string[];
29
- /** Optional admin phone number. Defaults to allowedNumbers[0]. */
30
- adminNumber?: string;
31
- }
32
- export interface VoiceConfig {
33
- sttProvider: 'whisper-api' | 'none';
34
- sttApiKey?: string;
35
- ttsProvider: 'openai' | 'elevenlabs' | 'none';
36
- ttsApiKey?: string;
37
- ttsVoice?: string;
38
- replyMode: 'text' | 'voice' | 'both';
39
- }
40
- export interface DiscordConfig {
41
- token: string;
42
- allowedUserIds?: string[];
43
- /** Optional admin user ID. Defaults to allowedUserIds[0]. */
44
- adminUserId?: string;
45
- }
46
- /**
47
- * Webhook channel auth semantics:
48
- *
49
- * - When both `authToken` and `hmacSecret` are configured, EITHER mode
50
- * satisfies authentication (OR semantics). A valid Bearer token is enough
51
- * even if the HMAC signature is missing. There is no AND mode today.
52
- * - Replay protection is NOT implemented. Callers must keep their payloads
53
- * idempotent — see L10 in the audit. Acceptable while the server binds to
54
- * 127.0.0.1 only; revisit if remote exposure becomes a thing.
55
- * - `allowUnauthLocalhost` is the explicit opt-in to run with no auth at all.
56
- * Useful for `curl localhost` from a trusted shell, but on a multi-user
57
- * host any local process can inject prompts into your tabs.
58
- */
59
- export interface WebhookConfig {
60
- enabled: boolean;
61
- port: number;
62
- authToken?: string;
63
- hmacSecret?: string;
64
- /** Set to true to skip the fail-secure auth check at start. NOT recommended on shared hosts. */
65
- allowUnauthLocalhost?: boolean;
66
- }
67
- export interface GroupConfig {
68
- activationMode: 'mention' | 'reply' | 'keyword' | 'always';
69
- maxResponsesPerMinute: number;
70
- tabPerGroup: boolean;
71
- keywords?: string[];
72
- }
73
- /**
74
- * Discriminated union of notification provider configs. The `type` field
75
- * narrows which fields are required so callers get full type safety instead
76
- * of treating every field as optional. createNotificationProvider switches
77
- * exhaustively on `type`.
78
- */
79
- export type NotificationConfig = {
80
- type: 'pushover';
81
- userKey: string;
82
- appToken: string;
83
- } | {
84
- type: 'ntfy';
85
- topic: string;
86
- server?: string;
87
- } | {
88
- type: 'webhook';
89
- url: string;
90
- headers?: Record<string, string>;
91
- };
92
- export interface MediaGeneratorConfig {
93
- provider: string;
94
- apiKey?: string;
95
- model?: string;
96
- style?: string;
97
- }
98
- /** A media file attached to a message. Shared by channels + util/text + media. */
99
- export interface MediaAttachment {
100
- type: 'image' | 'audio' | 'video' | 'document' | 'voice';
101
- mimeType: string;
102
- filePath: string;
103
- fileName?: string;
104
- caption?: string;
105
- }
106
- export interface BeecorkConfig {
107
- telegram: TelegramConfig;
108
- whatsapp?: WhatsAppConfig;
109
- webhook?: WebhookConfig;
110
- discord?: DiscordConfig;
111
- claudeCode: ClaudeCodeConfig;
112
- tabs: Record<string, TabConfig>;
113
- tabTemplates?: Record<string, TabTemplate>;
114
- memory: MemoryConfig;
115
- /** Directories to scan for projects on startup (defaults to ~/Coding, ~/Projects, etc.) */
116
- projectScanPaths: string[];
117
- voice?: VoiceConfig;
118
- groups?: GroupConfig;
119
- notifications?: NotificationConfig[];
120
- mediaGenerators?: MediaGeneratorConfig[];
121
- communityChannels?: string[];
122
- /** Capability packs enabled via `beecork capabilities enable`. Owned by src/capabilities. */
123
- capabilities?: import('./capabilities/types.js').EnabledCapability[];
124
- deployment: 'local' | 'vps';
125
- }
126
- export type TabStatus = 'idle' | 'running' | 'error' | 'stopped';
127
- export interface Tab {
128
- id: string;
129
- name: string;
130
- sessionId: string;
131
- status: TabStatus;
132
- workingDir: string;
133
- createdAt: string;
134
- lastActivityAt: string;
135
- pid: number | null;
136
- systemPrompt: string | null;
137
- }
138
- export interface StreamInit {
139
- type: 'system';
140
- subtype: 'init';
141
- session_id: string;
142
- tools: string[];
143
- mcp_servers: string[];
144
- model: string;
145
- }
146
- export interface StreamContentText {
147
- type: 'text';
148
- text: string;
149
- }
150
- export interface StreamContentToolUse {
151
- type: 'tool_use';
152
- id: string;
153
- name: string;
154
- input: Record<string, unknown>;
155
- }
156
- export interface StreamContentToolResult {
157
- type: 'tool_result';
158
- tool_use_id: string;
159
- content: string;
160
- }
161
- export type StreamContentBlock = StreamContentText | StreamContentToolUse | StreamContentToolResult;
162
- export interface StreamAssistant {
163
- type: 'assistant';
164
- message: {
165
- id: string;
166
- role: 'assistant';
167
- content: StreamContentBlock[];
168
- stop_reason: string;
169
- usage: StreamUsage;
170
- };
171
- session_id: string;
172
- }
173
- export interface StreamResult {
174
- type: 'result';
175
- subtype: 'success' | 'error' | 'error_during_execution';
176
- is_error: boolean;
177
- duration_ms: number;
178
- result?: string;
179
- errors?: string[];
180
- session_id: string;
181
- total_cost_usd?: number;
182
- usage?: StreamUsage;
183
- }
184
- export interface StreamUsage {
185
- input_tokens: number;
186
- output_tokens: number;
187
- cache_creation_input_tokens: number;
188
- cache_read_input_tokens: number;
189
- }
190
- export type StreamEvent = StreamInit | StreamAssistant | StreamResult;
191
- export type TaskScheduleType = 'at' | 'every' | 'cron';
192
- export type TaskPayloadType = 'agentTurn' | 'systemEvent';
193
- export interface Task {
194
- id: string;
195
- name: string;
196
- scheduleType: TaskScheduleType;
197
- schedule: string;
198
- tabName: string;
199
- message: string;
200
- payloadType: TaskPayloadType;
201
- enabled: boolean;
202
- createdAt: string;
203
- lastRunAt: string | null;
204
- nextRunAt: string | null;
205
- }
206
- export interface Memory {
207
- id: number;
208
- content: string;
209
- tabName: string | null;
210
- createdAt: string;
211
- source: 'tool' | 'auto';
212
- }
213
- export interface CircuitBreakerConfig {
214
- maxRepeats: number;
215
- windowSize: number;
216
- }
package/dist/types.js DELETED
@@ -1,3 +0,0 @@
1
- // ─── Config ───
2
- export {};
3
- // Channel interface: see src/channels/types.ts
@@ -1,43 +0,0 @@
1
- /**
2
- * Auto-heal install-path divergence between the CLI (this process) and the
3
- * running daemon. Triggered both from the npm postinstall hook and from the
4
- * CLI entry on every invocation — both paths converge here so the policy is
5
- * single-sourced and idempotent.
6
- *
7
- * What "divergence" means:
8
- * The daemon's launchd plist (or systemd unit) hard-codes an absolute path
9
- * to dist/daemon.js. If `npm install -g beecork@<new>` lands in a different
10
- * npm prefix than the one the unit file points at, the daemon keeps running
11
- * the old code while the CLI shows the new version. Bug reports get
12
- * misdiagnosed because the user thinks both are on the new version.
13
- *
14
- * What this function does:
15
- * 1. Rewrite the unit file's daemon path if it doesn't point at us.
16
- * 2. SIGTERM the running daemon (KeepAlive / Restart=always brings it back
17
- * on the new code) only when its runtime.json shows it was launched from
18
- * a different install root than ours.
19
- *
20
- * Returns a Result describing what happened, for the caller to surface (or not)
21
- * to the user. The auto-heal NEVER throws — failures degrade to {action:'skip'}.
22
- */
23
- export interface HealResult {
24
- action: 'noop' | 'rewrote-unit' | 'signaled-daemon' | 'rewrote-and-signaled' | 'skip';
25
- reason?: string;
26
- unitPath?: string;
27
- oldDaemonScript?: string;
28
- newDaemonScript?: string;
29
- }
30
- export declare function autoHealInstall(fromFileUrl: string): HealResult;
31
- /**
32
- * Extract the daemon-script absolute path from a launchd plist or systemd unit.
33
- * Returns null if the file shape isn't recognized — caller treats that as "skip".
34
- *
35
- * launchd: looks inside <key>ProgramArguments</key><array> for the .js entry.
36
- * systemd: looks for ExecStart=<node> <daemon.js> on a single line.
37
- */
38
- export declare function extractDaemonScript(content: string): string | null;
39
- /** Rewrite-only variant used by tests and the postinstall hook in dry-run mode. */
40
- export declare function rewriteUnitDaemonScript(unitPath: string, newDaemonScript: string): {
41
- rewrote: boolean;
42
- oldDaemonScript: string | null;
43
- };
@@ -1,107 +0,0 @@
1
- import fs from 'node:fs';
2
- import { findInstallRoot, getDaemonScript, readRuntimeInfo, isPidAlive, getServiceUnitPath, } from './install-info.js';
3
- export function autoHealInstall(fromFileUrl) {
4
- try {
5
- const currentRoot = findInstallRoot(fromFileUrl);
6
- const currentDaemonScript = getDaemonScript(currentRoot);
7
- const unitPath = getServiceUnitPath();
8
- if (!unitPath || !fs.existsSync(unitPath)) {
9
- // No installed service — beecork has been npm-installed but `beecork setup` (or
10
- // equivalent) hasn't been run yet. Nothing to heal.
11
- return { action: 'skip', reason: 'no service unit file present' };
12
- }
13
- const unitContent = fs.readFileSync(unitPath, 'utf-8');
14
- const oldDaemonScript = extractDaemonScript(unitContent);
15
- let rewroteUnit = false;
16
- if (oldDaemonScript && oldDaemonScript !== currentDaemonScript) {
17
- // Validate the new path actually exists before rewriting — never break the daemon
18
- // by pointing it at a missing file.
19
- if (!fs.existsSync(currentDaemonScript)) {
20
- return { action: 'skip', reason: `current install missing daemon: ${currentDaemonScript}` };
21
- }
22
- const next = unitContent.split(oldDaemonScript).join(currentDaemonScript);
23
- const tmp = unitPath + '.tmp';
24
- fs.writeFileSync(tmp, next);
25
- fs.renameSync(tmp, unitPath);
26
- rewroteUnit = true;
27
- }
28
- // Restart the daemon if it's currently running from a stale install. This is
29
- // separate from the unit-file rewrite so we also catch the case where the unit
30
- // file is already current but the running process predates the latest install.
31
- const runtime = readRuntimeInfo();
32
- let signaledDaemon = false;
33
- if (runtime && runtime.installRoot !== currentRoot && isPidAlive(runtime.pid)) {
34
- try {
35
- process.kill(runtime.pid, 'SIGTERM');
36
- signaledDaemon = true;
37
- }
38
- catch {
39
- // Permission denied (different user, or already gone). Surface as skip;
40
- // we still rewrote the unit file so the next start picks up the new path.
41
- }
42
- }
43
- if (rewroteUnit && signaledDaemon) {
44
- return {
45
- action: 'rewrote-and-signaled',
46
- unitPath,
47
- oldDaemonScript: oldDaemonScript,
48
- newDaemonScript: currentDaemonScript,
49
- };
50
- }
51
- if (rewroteUnit)
52
- return {
53
- action: 'rewrote-unit',
54
- unitPath,
55
- oldDaemonScript: oldDaemonScript,
56
- newDaemonScript: currentDaemonScript,
57
- };
58
- if (signaledDaemon)
59
- return { action: 'signaled-daemon', unitPath };
60
- return { action: 'noop' };
61
- }
62
- catch (err) {
63
- return { action: 'skip', reason: err instanceof Error ? err.message : String(err) };
64
- }
65
- }
66
- /**
67
- * Extract the daemon-script absolute path from a launchd plist or systemd unit.
68
- * Returns null if the file shape isn't recognized — caller treats that as "skip".
69
- *
70
- * launchd: looks inside <key>ProgramArguments</key><array> for the .js entry.
71
- * systemd: looks for ExecStart=<node> <daemon.js> on a single line.
72
- */
73
- export function extractDaemonScript(content) {
74
- // launchd plist: pull the second <string> inside ProgramArguments
75
- const launchdMatch = content.match(/<key>\s*ProgramArguments\s*<\/key>\s*<array>([\s\S]*?)<\/array>/);
76
- if (launchdMatch) {
77
- const args = Array.from(launchdMatch[1].matchAll(/<string>([^<]+)<\/string>/g)).map((m) => m[1]);
78
- const jsArg = args.find((a) => a.endsWith('daemon.js'));
79
- if (jsArg)
80
- return jsArg;
81
- }
82
- // systemd unit: ExecStart=<node> <daemon.js> [args...]
83
- const systemdMatch = content.match(/^ExecStart\s*=\s*(.+)$/m);
84
- if (systemdMatch) {
85
- const parts = systemdMatch[1].split(/\s+/);
86
- const jsArg = parts.find((p) => p.endsWith('daemon.js'));
87
- if (jsArg)
88
- return jsArg;
89
- }
90
- return null;
91
- }
92
- /** Rewrite-only variant used by tests and the postinstall hook in dry-run mode. */
93
- export function rewriteUnitDaemonScript(unitPath, newDaemonScript) {
94
- if (!fs.existsSync(unitPath))
95
- return { rewrote: false, oldDaemonScript: null };
96
- const content = fs.readFileSync(unitPath, 'utf-8');
97
- const oldDaemonScript = extractDaemonScript(content);
98
- if (!oldDaemonScript)
99
- return { rewrote: false, oldDaemonScript: null };
100
- if (oldDaemonScript === newDaemonScript)
101
- return { rewrote: false, oldDaemonScript };
102
- const next = content.split(oldDaemonScript).join(newDaemonScript);
103
- const tmp = unitPath + '.tmp';
104
- fs.writeFileSync(tmp, next);
105
- fs.renameSync(tmp, unitPath);
106
- return { rewrote: true, oldDaemonScript };
107
- }
@@ -1,37 +0,0 @@
1
- /**
2
- * Metadata the daemon writes to ~/.beecork/runtime.json at startup so the CLI
3
- * (and postinstall hook) can detect when daemon and CLI are running from
4
- * different physical installs of beecork — the most common silent-staleness
5
- * mode after `npm install -g beecork@<new>` lands in a prefix the daemon's
6
- * launchd plist doesn't point at.
7
- */
8
- export interface RuntimeInfo {
9
- pid: number;
10
- version: string;
11
- /** The package root: <prefix>/lib/node_modules/beecork. Single canonical key. */
12
- installRoot: string;
13
- /** Absolute path to dist/daemon.js — derived from installRoot. */
14
- daemonScript: string;
15
- /** ISO timestamp. */
16
- startedAt: string;
17
- /** process.version (e.g. "v20.11.0") */
18
- nodeVersion: string;
19
- }
20
- /**
21
- * Walk up from a given file (typically import.meta.url) to find the directory
22
- * containing package.json — i.e. the beecork install root. Works for both:
23
- * - source dev runs (.../src/util/install-info.ts → .../ )
24
- * - built/installed runs (.../dist/util/install-info.js → .../ )
25
- */
26
- export declare function findInstallRoot(fromFileUrl: string): string;
27
- export declare function getDaemonScript(installRoot: string): string;
28
- export declare function writeRuntimeInfo(info: RuntimeInfo): void;
29
- export declare function readRuntimeInfo(): RuntimeInfo | null;
30
- export declare function removeRuntimeInfo(): void;
31
- export declare function isPidAlive(pid: number): boolean;
32
- /**
33
- * Cross-platform path to the service-manager unit file that launches the daemon.
34
- * Returns null if beecork doesn't manage one on this OS (currently Windows uses
35
- * Task Scheduler and is out of scope for the auto-heal flow).
36
- */
37
- export declare function getServiceUnitPath(): string | null;
@@ -1,80 +0,0 @@
1
- import fs from 'node:fs';
2
- import path from 'node:path';
3
- import os from 'node:os';
4
- import { fileURLToPath } from 'node:url';
5
- import { getRuntimeInfoPath } from './paths.js';
6
- /**
7
- * Walk up from a given file (typically import.meta.url) to find the directory
8
- * containing package.json — i.e. the beecork install root. Works for both:
9
- * - source dev runs (.../src/util/install-info.ts → .../ )
10
- * - built/installed runs (.../dist/util/install-info.js → .../ )
11
- */
12
- export function findInstallRoot(fromFileUrl) {
13
- const fromPath = fileURLToPath(fromFileUrl);
14
- let dir = path.dirname(fromPath);
15
- for (let i = 0; i < 6; i++) {
16
- if (fs.existsSync(path.join(dir, 'package.json')))
17
- return dir;
18
- const parent = path.dirname(dir);
19
- if (parent === dir)
20
- break;
21
- dir = parent;
22
- }
23
- throw new Error(`Could not locate beecork install root walking up from ${fromPath}`);
24
- }
25
- export function getDaemonScript(installRoot) {
26
- return path.join(installRoot, 'dist', 'daemon.js');
27
- }
28
- export function writeRuntimeInfo(info) {
29
- const filePath = getRuntimeInfoPath();
30
- // Atomic-ish write: temp + rename so a partial write never confuses a reader.
31
- const tmp = filePath + '.tmp';
32
- fs.writeFileSync(tmp, JSON.stringify(info, null, 2));
33
- fs.renameSync(tmp, filePath);
34
- }
35
- export function readRuntimeInfo() {
36
- const filePath = getRuntimeInfoPath();
37
- if (!fs.existsSync(filePath))
38
- return null;
39
- try {
40
- const data = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
41
- if (typeof data?.pid === 'number' && typeof data?.installRoot === 'string') {
42
- return data;
43
- }
44
- return null;
45
- }
46
- catch {
47
- return null;
48
- }
49
- }
50
- export function removeRuntimeInfo() {
51
- const filePath = getRuntimeInfoPath();
52
- try {
53
- fs.unlinkSync(filePath);
54
- }
55
- catch {
56
- /* not present, fine */
57
- }
58
- }
59
- export function isPidAlive(pid) {
60
- try {
61
- process.kill(pid, 0);
62
- return true;
63
- }
64
- catch {
65
- return false;
66
- }
67
- }
68
- /**
69
- * Cross-platform path to the service-manager unit file that launches the daemon.
70
- * Returns null if beecork doesn't manage one on this OS (currently Windows uses
71
- * Task Scheduler and is out of scope for the auto-heal flow).
72
- */
73
- export function getServiceUnitPath() {
74
- const home = os.homedir();
75
- if (process.platform === 'darwin')
76
- return path.join(home, 'Library', 'LaunchAgents', 'com.beecork.daemon.plist');
77
- if (process.platform === 'linux')
78
- return path.join(home, '.config', 'systemd', 'user', 'beecork.service');
79
- return null;
80
- }
@@ -1,18 +0,0 @@
1
- type LogLevel = 'debug' | 'info' | 'warn' | 'error';
2
- declare class Logger {
3
- private minLevel;
4
- private logFile;
5
- private stream;
6
- private bytesWritten;
7
- setLevel(level: LogLevel): void;
8
- setLogFile(name: string): void;
9
- private write;
10
- debug(msg: string, ...args: unknown[]): void;
11
- info(msg: string, ...args: unknown[]): void;
12
- warn(msg: string, ...args: unknown[]): void;
13
- error(msg: string, ...args: unknown[]): void;
14
- private checkRotation;
15
- close(): void;
16
- }
17
- export declare const logger: Logger;
18
- export {};
@@ -1,118 +0,0 @@
1
- import fs from 'node:fs';
2
- import path from 'node:path';
3
- import { getLogsDir } from './paths.js';
4
- const LEVEL_PRIORITY = {
5
- debug: 0,
6
- info: 1,
7
- warn: 2,
8
- error: 3,
9
- };
10
- // Patterns that should never reach disk or stdout. Each channel uses a per-call
11
- // sanitizer too (defense-in-depth), but the Logger is the last line of defense
12
- // for any third-party error object that happens to embed a secret in its message.
13
- const REDACTION_PATTERNS = [
14
- { re: /bot\d+:[A-Za-z0-9_-]+/g, replacement: 'bot<REDACTED>' }, // Telegram bot token
15
- ];
16
- function redact(s) {
17
- let out = s;
18
- for (const { re, replacement } of REDACTION_PATTERNS)
19
- out = out.replace(re, replacement);
20
- return out;
21
- }
22
- const ROTATE_BYTES = 10 * 1024 * 1024;
23
- class Logger {
24
- minLevel = 'info';
25
- logFile = null;
26
- stream = null;
27
- bytesWritten = 0;
28
- setLevel(level) {
29
- this.minLevel = level;
30
- }
31
- setLogFile(name) {
32
- const dir = getLogsDir();
33
- fs.mkdirSync(dir, { recursive: true });
34
- this.logFile = path.join(dir, name);
35
- this.stream = fs.createWriteStream(this.logFile, { flags: 'a' });
36
- // Seed bytesWritten from the existing file size so we don't reset the
37
- // rotation counter on every daemon restart.
38
- try {
39
- this.bytesWritten = fs.statSync(this.logFile).size;
40
- }
41
- catch {
42
- this.bytesWritten = 0;
43
- }
44
- }
45
- write(level, msg, ...args) {
46
- if (LEVEL_PRIORITY[level] < LEVEL_PRIORITY[this.minLevel])
47
- return;
48
- const timestamp = new Date().toISOString();
49
- const prefix = `[${timestamp}] [${level.toUpperCase()}]`;
50
- const raw = args.length > 0
51
- ? `${prefix} ${msg} ${args.map((a) => (typeof a === 'string' ? a : JSON.stringify(a))).join(' ')}`
52
- : `${prefix} ${msg}`;
53
- const line = redact(raw);
54
- if (this.stream) {
55
- const out = line + '\n';
56
- this.stream.write(out);
57
- this.bytesWritten += out.length;
58
- if (this.bytesWritten > ROTATE_BYTES)
59
- this.checkRotation();
60
- }
61
- if (level === 'error') {
62
- console.error(line);
63
- }
64
- else if (level === 'warn') {
65
- console.warn(line);
66
- }
67
- else if (level !== 'debug') {
68
- console.log(line);
69
- }
70
- }
71
- debug(msg, ...args) {
72
- this.write('debug', msg, ...args);
73
- }
74
- info(msg, ...args) {
75
- this.write('info', msg, ...args);
76
- }
77
- warn(msg, ...args) {
78
- this.write('warn', msg, ...args);
79
- }
80
- error(msg, ...args) {
81
- this.write('error', msg, ...args);
82
- }
83
- checkRotation() {
84
- if (!this.logFile || !this.stream)
85
- return;
86
- // bytesWritten-based gate already triggered us; rotate without statSync.
87
- try {
88
- this.stream.end();
89
- const rotated = this.logFile + '.1';
90
- try {
91
- fs.unlinkSync(rotated);
92
- }
93
- catch {
94
- /* not fatal */
95
- }
96
- fs.renameSync(this.logFile, rotated);
97
- this.stream = fs.createWriteStream(this.logFile, { flags: 'a' });
98
- this.bytesWritten = 0;
99
- }
100
- catch {
101
- /* rotation failure shouldn't kill the daemon */
102
- }
103
- }
104
- close() {
105
- if (this.stream) {
106
- this.stream.end();
107
- this.stream = null;
108
- }
109
- }
110
- }
111
- export const logger = new Logger();
112
- // Allow operators to bump verbosity at runtime without recompiling.
113
- // e.g. `BEECORK_LOG_LEVEL=debug beecork start` surfaces every claude subprocess
114
- // stdout/stderr line via the logger.debug calls.
115
- const envLevel = process.env.BEECORK_LOG_LEVEL?.toLowerCase();
116
- if (envLevel === 'debug' || envLevel === 'info' || envLevel === 'warn' || envLevel === 'error') {
117
- logger.setLevel(envLevel);
118
- }
@@ -1,13 +0,0 @@
1
- export declare function getBeecorkHome(): string;
2
- export declare function getConfigPath(): string;
3
- export declare function getDbPath(): string;
4
- export declare function getCrontabPath(): string;
5
- export declare function getMcpConfigPath(): string;
6
- export declare function getLogsDir(): string;
7
- export declare function getPidPath(): string;
8
- export declare function getRuntimeInfoPath(): string;
9
- export declare function getCronReloadSignalPath(): string;
10
- export declare function getWatcherReloadSignalPath(): string;
11
- export declare function getWhatsappSessionPath(): string;
12
- export declare function ensureBeecorkDirs(): void;
13
- export declare function expandHome(p: string): string;