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,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,4 +0,0 @@
1
- export type { Project, RouteDecision, RoutingContext } from './types.js';
2
- export { discoverProjects, createProject, listProjects, getProject, ensureCategory, touchProject, } from './manager.js';
3
- export { routeMessage, setUserContext, resolveProjectRoute } from './router.js';
4
- export type { RouteResult } from './router.js';
@@ -1,2 +0,0 @@
1
- export { discoverProjects, createProject, listProjects, getProject, ensureCategory, touchProject, } from './manager.js';
2
- export { routeMessage, setUserContext, resolveProjectRoute } from './router.js';
@@ -1,13 +0,0 @@
1
- import type { Project } from './types.js';
2
- /** Discover projects in scan paths (look for git repos, package.json, etc.) */
3
- export declare function discoverProjects(scanPaths?: string[]): Project[];
4
- /** Create a new project. parentDir must resolve under an allowed root. */
5
- export declare function createProject(name: string, parentDir?: string): Project;
6
- /** Ensure a managed category exists (lazy creation) */
7
- export declare function ensureCategory(name: string): Project;
8
- /** List all projects */
9
- export declare function listProjects(): Project[];
10
- /** Get a project by name */
11
- export declare function getProject(name: string): Project | null;
12
- /** Update last used timestamp */
13
- export declare function touchProject(name: string): void;
@@ -1,166 +0,0 @@
1
- import fs from 'node:fs';
2
- import path from 'node:path';
3
- import { v4 as uuidv4 } from 'uuid';
4
- import { getDb } from '../db/index.js';
5
- import { getConfig } from '../config.js';
6
- import { expandHome } from '../util/paths.js';
7
- import { logger } from '../util/logger.js';
8
- import { invalidateProjectCache } from './router.js';
9
- function rowToProject(r) {
10
- return {
11
- id: r.id,
12
- name: r.name,
13
- path: r.path,
14
- type: r.type,
15
- lastUsedAt: r.last_used_at,
16
- createdAt: r.created_at,
17
- };
18
- }
19
- /** Get the workspace root from config (module-local) */
20
- function getWorkspaceRoot() {
21
- const config = getConfig();
22
- // Use the default tab's workingDir as workspace root
23
- const root = config.tabs?.default?.workingDir || process.env.HOME || '';
24
- return expandHome(root);
25
- }
26
- /** Get the managed workspace path (.beecork/ under workspace root) (module-local) */
27
- function getManagedWorkspace() {
28
- return path.join(getWorkspaceRoot(), '.beecork');
29
- }
30
- /** Discover projects in scan paths (look for git repos, package.json, etc.) */
31
- export function discoverProjects(scanPaths) {
32
- const paths = scanPaths || [getWorkspaceRoot()];
33
- const projects = [];
34
- const db = getDb();
35
- for (let scanPath of paths) {
36
- scanPath = expandHome(scanPath);
37
- if (!fs.existsSync(scanPath))
38
- continue;
39
- try {
40
- const entries = fs.readdirSync(scanPath, { withFileTypes: true });
41
- for (const entry of entries) {
42
- if (!entry.isDirectory())
43
- continue;
44
- if (entry.name.startsWith('.'))
45
- continue; // Skip hidden dirs
46
- if (entry.name === 'node_modules')
47
- continue;
48
- const dirPath = path.join(scanPath, entry.name);
49
- // Check if it looks like a project (has .git, package.json, or similar)
50
- const isProject = fs.existsSync(path.join(dirPath, '.git')) ||
51
- fs.existsSync(path.join(dirPath, 'package.json')) ||
52
- fs.existsSync(path.join(dirPath, 'Cargo.toml')) ||
53
- fs.existsSync(path.join(dirPath, 'go.mod')) ||
54
- fs.existsSync(path.join(dirPath, 'requirements.txt')) ||
55
- fs.existsSync(path.join(dirPath, 'pyproject.toml')) ||
56
- fs.existsSync(path.join(dirPath, 'CLAUDE.md'));
57
- if (isProject) {
58
- projects.push({
59
- id: uuidv4(),
60
- name: entry.name,
61
- path: dirPath,
62
- type: 'user-project',
63
- lastUsedAt: new Date().toISOString(),
64
- createdAt: new Date().toISOString(),
65
- });
66
- }
67
- }
68
- }
69
- catch (err) {
70
- logger.warn(`Failed to scan ${scanPath}:`, err);
71
- }
72
- }
73
- // Upsert into database
74
- for (const project of projects) {
75
- db.prepare(`
76
- INSERT INTO projects (id, name, path, type) VALUES (?, ?, ?, ?)
77
- ON CONFLICT(name) DO UPDATE SET path = excluded.path, last_used_at = datetime('now')
78
- `).run(project.id, project.name, project.path, project.type);
79
- }
80
- invalidateProjectCache();
81
- return projects;
82
- }
83
- /** Create a new project. parentDir must resolve under an allowed root. */
84
- export function createProject(name, parentDir) {
85
- const requestedParent = parentDir || getWorkspaceRoot();
86
- const resolvedParent = path.resolve(expandHome(requestedParent));
87
- // Allowlist: parent must resolve under workspace root or one of the configured scan paths.
88
- const config = getConfig();
89
- const allowedRoots = [getWorkspaceRoot(), ...(config.projectScanPaths ?? [])].map((r) => path.resolve(expandHome(r)));
90
- const isAllowed = allowedRoots.some((root) => resolvedParent === root || resolvedParent.startsWith(root + path.sep));
91
- if (!isAllowed) {
92
- throw new Error(`Project parent directory must be under workspace root or a configured scan path. Allowed: ${allowedRoots.join(', ')}`);
93
- }
94
- // Sanitize name to prevent path traversal
95
- const safeName = path.basename(name.replace(/\.\./g, ''));
96
- if (!safeName)
97
- throw new Error('Invalid project name');
98
- const projectPath = path.resolve(resolvedParent, safeName);
99
- // Ensure resolved path is within the parent directory
100
- if (!projectPath.startsWith(resolvedParent)) {
101
- throw new Error('Project path must be within the parent directory');
102
- }
103
- if (fs.existsSync(projectPath)) {
104
- // Folder already exists — just register it
105
- logger.info(`Project folder already exists: ${projectPath}`);
106
- }
107
- else {
108
- fs.mkdirSync(projectPath, { recursive: true });
109
- logger.info(`Created project folder: ${projectPath}`);
110
- }
111
- const db = getDb();
112
- const id = uuidv4();
113
- db.prepare(`
114
- INSERT INTO projects (id, name, path, type) VALUES (?, ?, ?, ?)
115
- ON CONFLICT(name) DO UPDATE SET path = excluded.path
116
- `).run(id, name, projectPath, 'user-project');
117
- invalidateProjectCache();
118
- return {
119
- id,
120
- name,
121
- path: projectPath,
122
- type: 'user-project',
123
- lastUsedAt: new Date().toISOString(),
124
- createdAt: new Date().toISOString(),
125
- };
126
- }
127
- /** Ensure a managed category exists (lazy creation) */
128
- export function ensureCategory(name) {
129
- const categoryPath = path.join(getManagedWorkspace(), name);
130
- fs.mkdirSync(categoryPath, { recursive: true });
131
- const db = getDb();
132
- const existing = db
133
- .prepare('SELECT * FROM projects WHERE name = ? AND type = ?')
134
- .get(name, 'category');
135
- if (existing)
136
- return rowToProject(existing);
137
- const id = uuidv4();
138
- db.prepare('INSERT INTO projects (id, name, path, type) VALUES (?, ?, ?, ?)').run(id, name, categoryPath, 'category');
139
- invalidateProjectCache();
140
- return {
141
- id,
142
- name,
143
- path: categoryPath,
144
- type: 'category',
145
- lastUsedAt: new Date().toISOString(),
146
- createdAt: new Date().toISOString(),
147
- };
148
- }
149
- /** List all projects */
150
- export function listProjects() {
151
- const db = getDb();
152
- const rows = db
153
- .prepare('SELECT * FROM projects ORDER BY type, last_used_at DESC')
154
- .all();
155
- return rows.map(rowToProject);
156
- }
157
- /** Get a project by name */
158
- export function getProject(name) {
159
- const db = getDb();
160
- const row = db.prepare('SELECT * FROM projects WHERE name = ?').get(name);
161
- return row ? rowToProject(row) : null;
162
- }
163
- /** Update last used timestamp */
164
- export function touchProject(name) {
165
- getDb().prepare("UPDATE projects SET last_used_at = datetime('now') WHERE name = ?").run(name);
166
- }
@@ -1,17 +0,0 @@
1
- import type { RouteDecision, RoutingContext } from './types.js';
2
- /** Invalidate the project cache. Call after createProject/discoverProjects/etc. */
3
- export declare function invalidateProjectCache(): void;
4
- /** Route a message to the right project and tab */
5
- export declare function routeMessage(message: string, context?: RoutingContext): RouteDecision;
6
- /** Update current context for a user */
7
- export declare function setUserContext(userId: string, projectName: string, tabName: string): void;
8
- export interface RouteResult {
9
- effectiveTabName: string;
10
- projectPath?: string;
11
- confirmationMessage?: string;
12
- }
13
- /**
14
- * Shared project routing logic — resolves which tab/project to use for a message.
15
- * Pulled out of channels/ so all routing decisions live in one place.
16
- */
17
- export declare function resolveProjectRoute(rawPrompt: string, tabName: string, text: string, userId: string): Promise<RouteResult>;