beecork 1.4.10 → 1.4.11

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.
@@ -1,3 +1,4 @@
1
+ import type Database from 'better-sqlite3';
1
2
  export interface CostSummary {
2
3
  today: number;
3
4
  last7Days: number;
@@ -19,6 +20,11 @@ export interface ActivitySummary {
19
20
  }
20
21
  export declare function getCostSummary(): CostSummary;
21
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;
22
28
  export declare function checkAnomalies(): string | null;
23
29
  export declare function formatCostSummary(summary: CostSummary): string;
24
30
  export declare function formatActivitySummary(summary: ActivitySummary): string;
@@ -30,8 +30,12 @@ export function getActivitySummary(hours = 24) {
30
30
  activeTabsCount,
31
31
  };
32
32
  }
33
- export function checkAnomalies() {
34
- const db = getDb();
33
+ const ANOMALY_STATE_KEY = 'anomaly_spend_state';
34
+ /**
35
+ * Returns a notification only on state transitions (ok↔breach), persisting
36
+ * the state in the `preferences` table so daemon restarts don't re-fire.
37
+ */
38
+ export function checkAnomaliesWithDb(db) {
35
39
  // Today's spend
36
40
  const todaySpend = db.prepare("SELECT COALESCE(SUM(cost_usd), 0) as total FROM messages WHERE created_at > date('now')").get().total;
37
41
  // 7-day rolling average (excluding today)
@@ -43,10 +47,21 @@ export function checkAnomalies() {
43
47
  GROUP BY date(created_at)
44
48
  )
45
49
  `).get().avg;
46
- if (avgSpend > 0 && todaySpend > avgSpend * 2) {
50
+ const isBreach = avgSpend > 0 && todaySpend > avgSpend * 2;
51
+ const newState = isBreach ? 'breach' : 'ok';
52
+ const prevRow = db.prepare('SELECT value FROM preferences WHERE key = ?').get(ANOMALY_STATE_KEY);
53
+ const prevState = prevRow?.value ?? 'ok';
54
+ if (newState === prevState)
55
+ return null;
56
+ db.prepare(`INSERT INTO preferences (key, value, updated_at) VALUES (?, ?, datetime('now'))
57
+ ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = datetime('now')`).run(ANOMALY_STATE_KEY, newState);
58
+ if (isBreach) {
47
59
  return `⚠️ Anomaly: Today's spend ($${todaySpend.toFixed(4)}) exceeds 2x your 7-day average ($${avgSpend.toFixed(4)}/day)`;
48
60
  }
49
- return null;
61
+ return `✅ Recovered: Today's spend ($${todaySpend.toFixed(4)}) is back within 2x your 7-day average ($${avgSpend.toFixed(4)}/day)`;
62
+ }
63
+ export function checkAnomalies() {
64
+ return checkAnomaliesWithDb(getDb());
50
65
  }
51
66
  export function formatCostSummary(summary) {
52
67
  const lines = [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "beecork",
3
- "version": "1.4.10",
3
+ "version": "1.4.11",
4
4
  "description": "Claude Code always-on infrastructure — a phone number, a memory, and an alarm clock",
5
5
  "type": "module",
6
6
  "bin": {