daybrain 0.3.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 (51) hide show
  1. package/bin/daybrain.js +18 -0
  2. package/dist/aw.d.ts +30 -0
  3. package/dist/aw.d.ts.map +1 -0
  4. package/dist/aw.js +145 -0
  5. package/dist/aw.js.map +1 -0
  6. package/dist/baseline.d.ts +31 -0
  7. package/dist/baseline.d.ts.map +1 -0
  8. package/dist/baseline.js +130 -0
  9. package/dist/baseline.js.map +1 -0
  10. package/dist/config.d.ts +36 -0
  11. package/dist/config.d.ts.map +1 -0
  12. package/dist/config.js +139 -0
  13. package/dist/config.js.map +1 -0
  14. package/dist/db.d.ts +72 -0
  15. package/dist/db.d.ts.map +1 -0
  16. package/dist/db.js +261 -0
  17. package/dist/db.js.map +1 -0
  18. package/dist/http.d.ts +5 -0
  19. package/dist/http.d.ts.map +1 -0
  20. package/dist/http.js +411 -0
  21. package/dist/http.js.map +1 -0
  22. package/dist/index.d.ts +16 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +908 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/insights.d.ts +68 -0
  27. package/dist/insights.d.ts.map +1 -0
  28. package/dist/insights.js +523 -0
  29. package/dist/insights.js.map +1 -0
  30. package/dist/onboard.d.ts +2 -0
  31. package/dist/onboard.d.ts.map +1 -0
  32. package/dist/onboard.js +121 -0
  33. package/dist/onboard.js.map +1 -0
  34. package/dist/scheduler.d.ts +8 -0
  35. package/dist/scheduler.d.ts.map +1 -0
  36. package/dist/scheduler.js +214 -0
  37. package/dist/scheduler.js.map +1 -0
  38. package/dist/screenpipe.d.ts +25 -0
  39. package/dist/screenpipe.d.ts.map +1 -0
  40. package/dist/screenpipe.js +71 -0
  41. package/dist/screenpipe.js.map +1 -0
  42. package/dist/transport.d.ts +12 -0
  43. package/dist/transport.d.ts.map +1 -0
  44. package/dist/transport.js +152 -0
  45. package/dist/transport.js.map +1 -0
  46. package/dist/watcher.d.ts +15 -0
  47. package/dist/watcher.d.ts.map +1 -0
  48. package/dist/watcher.js +173 -0
  49. package/dist/watcher.js.map +1 -0
  50. package/package.json +58 -0
  51. package/watcher.py +139 -0
package/dist/db.js ADDED
@@ -0,0 +1,261 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getDb = getDb;
7
+ exports.insertRawEvents = insertRawEvents;
8
+ exports.getRawEvents = getRawEvents;
9
+ exports.insertInsight = insertInsight;
10
+ exports.insertInsights = insertInsights;
11
+ exports.getInsights = getInsights;
12
+ exports.updateInsightStatus = updateInsightStatus;
13
+ exports.markInsightPushed = markInsightPushed;
14
+ exports.upsertDailySummary = upsertDailySummary;
15
+ exports.getDailySummary = getDailySummary;
16
+ exports.getRecentDailySummaries = getRecentDailySummaries;
17
+ exports.closeDb = closeDb;
18
+ const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
19
+ const path_1 = __importDefault(require("path"));
20
+ const config_1 = require("./config");
21
+ let db = null;
22
+ function getDb() {
23
+ if (db)
24
+ return db;
25
+ const dataDir = (0, config_1.getDataDir)();
26
+ const dbPath = path_1.default.join(dataDir, 'opencontext.db');
27
+ db = new better_sqlite3_1.default(dbPath);
28
+ db.pragma('journal_mode = WAL');
29
+ db.pragma('busy_timeout = 5000');
30
+ initializeSchema(db);
31
+ return db;
32
+ }
33
+ function initializeSchema(database) {
34
+ database.exec(`
35
+ CREATE TABLE IF NOT EXISTS raw_events (
36
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
37
+ source TEXT NOT NULL,
38
+ bucket_id TEXT NOT NULL,
39
+ timestamp TEXT NOT NULL,
40
+ duration REAL NOT NULL DEFAULT 0,
41
+ app TEXT NOT NULL DEFAULT '',
42
+ title TEXT NOT NULL DEFAULT '',
43
+ url TEXT NOT NULL DEFAULT '',
44
+ raw_data TEXT NOT NULL DEFAULT '{}',
45
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
46
+ );
47
+
48
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_raw_events_dedup
49
+ ON raw_events(timestamp, source, bucket_id, app, title);
50
+
51
+ CREATE INDEX IF NOT EXISTS idx_raw_events_timestamp ON raw_events(timestamp);
52
+ CREATE INDEX IF NOT EXISTS idx_raw_events_app ON raw_events(app);
53
+ CREATE INDEX IF NOT EXISTS idx_raw_events_source ON raw_events(source);
54
+
55
+ CREATE TABLE IF NOT EXISTS insights (
56
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
57
+ type TEXT NOT NULL,
58
+ period_start TEXT NOT NULL,
59
+ period_end TEXT NOT NULL,
60
+ title TEXT NOT NULL,
61
+ description TEXT NOT NULL DEFAULT '',
62
+ confidence REAL NOT NULL DEFAULT 0.5,
63
+ evidence TEXT NOT NULL DEFAULT '[]',
64
+ action_text TEXT NOT NULL DEFAULT '',
65
+ status TEXT NOT NULL DEFAULT 'new',
66
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
67
+ pushed_to TEXT,
68
+ pushed_at TEXT
69
+ );
70
+
71
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_insights_dedup
72
+ ON insights(type, title, period_start);
73
+
74
+ CREATE INDEX IF NOT EXISTS idx_insights_type ON insights(type);
75
+ CREATE INDEX IF NOT EXISTS idx_insights_period ON insights(period_start, period_end);
76
+ CREATE INDEX IF NOT EXISTS idx_insights_created ON insights(created_at);
77
+ CREATE INDEX IF NOT EXISTS idx_insights_status ON insights(status);
78
+
79
+ CREATE TABLE IF NOT EXISTS daily_summaries (
80
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
81
+ date TEXT NOT NULL UNIQUE,
82
+ total_active_time REAL NOT NULL DEFAULT 0,
83
+ top_apps TEXT NOT NULL DEFAULT '[]',
84
+ switch_count INTEGER NOT NULL DEFAULT 0,
85
+ insight_count INTEGER NOT NULL DEFAULT 0,
86
+ raw_summary TEXT NOT NULL DEFAULT '',
87
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
88
+ );
89
+
90
+ CREATE TABLE IF NOT EXISTS config (
91
+ key TEXT PRIMARY KEY,
92
+ value TEXT NOT NULL,
93
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
94
+ );
95
+ `);
96
+ }
97
+ function insertRawEvents(events) {
98
+ const database = getDb();
99
+ const stmt = database.prepare(`
100
+ INSERT INTO raw_events (source, bucket_id, timestamp, duration, app, title, url, raw_data)
101
+ VALUES (@source, @bucket_id, @timestamp, @duration, @app, @title, @url, @raw_data)
102
+ `);
103
+ const insertMany = database.transaction((evts) => {
104
+ let count = 0;
105
+ for (const evt of evts) {
106
+ try {
107
+ stmt.run(evt);
108
+ count++;
109
+ }
110
+ catch {
111
+ // duplicate event, skip silently
112
+ }
113
+ }
114
+ return count;
115
+ });
116
+ return insertMany(events);
117
+ }
118
+ function getRawEvents(options) {
119
+ const database = getDb();
120
+ const conditions = [];
121
+ const values = [];
122
+ if (options.periodStart) {
123
+ conditions.push('timestamp >= ?');
124
+ values.push(options.periodStart);
125
+ }
126
+ if (options.periodEnd) {
127
+ conditions.push('timestamp <= ?');
128
+ values.push(options.periodEnd);
129
+ }
130
+ if (options.source) {
131
+ conditions.push('source = ?');
132
+ values.push(options.source);
133
+ }
134
+ if (options.app) {
135
+ conditions.push('app LIKE ?');
136
+ values.push(`%${options.app}%`);
137
+ }
138
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
139
+ const limit = Math.min(options.limit || 1000, 5000);
140
+ const offset = options.offset || 0;
141
+ return database
142
+ .prepare(`SELECT * FROM raw_events ${where} ORDER BY timestamp DESC LIMIT ? OFFSET ?`)
143
+ .all(...values, limit, offset);
144
+ }
145
+ function insertInsight(insight) {
146
+ const database = getDb();
147
+ try {
148
+ const result = database
149
+ .prepare(`INSERT INTO insights (type, period_start, period_end, title, description, confidence, evidence, action_text)
150
+ VALUES (@type, @period_start, @period_end, @title, @description, @confidence, @evidence, @action_text)`)
151
+ .run(insight);
152
+ return database
153
+ .prepare('SELECT * FROM insights WHERE id = ?')
154
+ .get(result.lastInsertRowid);
155
+ }
156
+ catch {
157
+ return null; // duplicate insight
158
+ }
159
+ }
160
+ function insertInsights(insights) {
161
+ const database = getDb();
162
+ const stmt = database.prepare(`
163
+ INSERT INTO insights (type, period_start, period_end, title, description, confidence, evidence, action_text)
164
+ VALUES (@type, @period_start, @period_end, @title, @description, @confidence, @evidence, @action_text)
165
+ `);
166
+ const insertMany = database.transaction((items) => {
167
+ let count = 0;
168
+ for (const item of items) {
169
+ try {
170
+ stmt.run(item);
171
+ count++;
172
+ }
173
+ catch {
174
+ // duplicate insight, skip silently
175
+ }
176
+ }
177
+ return count;
178
+ });
179
+ return insertMany(insights);
180
+ }
181
+ function getInsights(options) {
182
+ const database = getDb();
183
+ const conditions = [];
184
+ const values = [];
185
+ if (options.type) {
186
+ conditions.push('type = ?');
187
+ values.push(options.type);
188
+ }
189
+ if (options.periodStart) {
190
+ conditions.push('period_start >= ?');
191
+ values.push(options.periodStart);
192
+ }
193
+ if (options.periodEnd) {
194
+ conditions.push('period_end <= ?');
195
+ values.push(options.periodEnd);
196
+ }
197
+ if (options.minConfidence) {
198
+ conditions.push('confidence >= ?');
199
+ values.push(options.minConfidence);
200
+ }
201
+ if (!options.includePushed) {
202
+ conditions.push('pushed_to IS NULL');
203
+ }
204
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
205
+ const limit = options.limit || 50;
206
+ return database
207
+ .prepare(`SELECT * FROM insights ${where} ORDER BY confidence DESC, created_at DESC LIMIT ?`)
208
+ .all(...values, limit);
209
+ }
210
+ function updateInsightStatus(id, status) {
211
+ const database = getDb();
212
+ database
213
+ .prepare("UPDATE insights SET status = ? WHERE id = ?")
214
+ .run(status, id);
215
+ }
216
+ function markInsightPushed(id, target) {
217
+ const database = getDb();
218
+ const insight = database.prepare('SELECT * FROM insights WHERE id = ?').get(id);
219
+ if (!insight)
220
+ return;
221
+ const existing = insight.pushed_to ? insight.pushed_to.split(',').map((s) => s.trim()) : [];
222
+ if (!existing.includes(target)) {
223
+ existing.push(target);
224
+ }
225
+ database
226
+ .prepare('UPDATE insights SET pushed_to = ?, pushed_at = datetime(\'now\') WHERE id = ?')
227
+ .run(existing.join(','), id);
228
+ }
229
+ function upsertDailySummary(summary) {
230
+ const database = getDb();
231
+ database
232
+ .prepare(`INSERT INTO daily_summaries (date, total_active_time, top_apps, switch_count, insight_count, raw_summary)
233
+ VALUES (@date, @total_active_time, @top_apps, @switch_count, @insight_count, @raw_summary)
234
+ ON CONFLICT(date) DO UPDATE SET
235
+ total_active_time = excluded.total_active_time,
236
+ top_apps = excluded.top_apps,
237
+ switch_count = excluded.switch_count,
238
+ insight_count = daily_summaries.insight_count + excluded.insight_count,
239
+ raw_summary = excluded.raw_summary,
240
+ created_at = datetime('now')`)
241
+ .run(summary);
242
+ }
243
+ function getDailySummary(date) {
244
+ const database = getDb();
245
+ return database
246
+ .prepare('SELECT * FROM daily_summaries WHERE date = ?')
247
+ .get(date);
248
+ }
249
+ function getRecentDailySummaries(days) {
250
+ const database = getDb();
251
+ return database
252
+ .prepare(`SELECT * FROM daily_summaries WHERE date >= date('now', ?) ORDER BY date DESC`)
253
+ .all(`-${days} days`);
254
+ }
255
+ function closeDb() {
256
+ if (db) {
257
+ db.close();
258
+ db = null;
259
+ }
260
+ }
261
+ //# sourceMappingURL=db.js.map
package/dist/db.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.js","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"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"}
package/dist/http.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ declare const EVENT_PORT = 19840;
2
+ export declare function startHttpServer(port?: number): void;
3
+ export declare function stopHttpServer(): void;
4
+ export { EVENT_PORT };
5
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAcA,QAAA,MAAM,UAAU,QAAQ,CAAC;AAEzB,wBAAgB,eAAe,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAmDnD;AAED,wBAAgB,cAAc,IAAI,IAAI,CAKrC;AA2VD,OAAO,EAAE,UAAU,EAAE,CAAC"}
package/dist/http.js ADDED
@@ -0,0 +1,411 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.EVENT_PORT = void 0;
37
+ exports.startHttpServer = startHttpServer;
38
+ exports.stopHttpServer = stopHttpServer;
39
+ const http = __importStar(require("http"));
40
+ const db_1 = require("./db");
41
+ const insights_1 = require("./insights");
42
+ const baseline_1 = require("./baseline");
43
+ let httpServer = null;
44
+ const EVENT_PORT = 19840;
45
+ exports.EVENT_PORT = EVENT_PORT;
46
+ function startHttpServer(port) {
47
+ if (httpServer)
48
+ return;
49
+ const listenPort = port || EVENT_PORT;
50
+ httpServer = http.createServer(async (req, res) => {
51
+ res.setHeader('Access-Control-Allow-Origin', '*');
52
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
53
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
54
+ if (req.method === 'OPTIONS') {
55
+ res.writeHead(204);
56
+ res.end();
57
+ return;
58
+ }
59
+ try {
60
+ const url = new URL(req.url || '/', `http://localhost:${listenPort}`);
61
+ switch (url.pathname) {
62
+ case '/health':
63
+ return handleHealth(res);
64
+ case '/events':
65
+ return await handlePostEvents(req, res);
66
+ case '/summary':
67
+ return await handleGetSummary(url, res);
68
+ case '/insights':
69
+ return await handleGetInsights(url, res);
70
+ case '/context':
71
+ return await handleGetContext(res);
72
+ case '/baseline':
73
+ return await handleGetBaseline(res);
74
+ case '/insight-status':
75
+ return await handleUpdateInsightStatus(req, res);
76
+ case '/sync/push':
77
+ return await handleSyncPush(req, res);
78
+ case '/sync/pull':
79
+ return await handleSyncPull(req, res);
80
+ default:
81
+ res.writeHead(404);
82
+ res.end(JSON.stringify({ error: 'not found' }));
83
+ }
84
+ }
85
+ catch (err) {
86
+ res.writeHead(500);
87
+ res.end(JSON.stringify({ error: String(err) }));
88
+ }
89
+ });
90
+ httpServer.listen(listenPort, '127.0.0.1', () => {
91
+ console.error(`[daybrain] HTTP API on http://127.0.0.1:${listenPort} (for browser extension)`);
92
+ });
93
+ }
94
+ function stopHttpServer() {
95
+ if (httpServer) {
96
+ httpServer.close();
97
+ httpServer = null;
98
+ }
99
+ }
100
+ function handleHealth(res) {
101
+ res.writeHead(200, { 'Content-Type': 'application/json' });
102
+ res.end(JSON.stringify({ status: 'ok', version: '0.2.0' }));
103
+ }
104
+ async function handlePostEvents(req, res) {
105
+ const body = await readBody(req);
106
+ try {
107
+ const parsed = JSON.parse(body);
108
+ if (Array.isArray(parsed)) {
109
+ const events = parsed.map((e) => ({
110
+ source: 'native',
111
+ bucket_id: 'browser-extension',
112
+ timestamp: e.timestamp || new Date().toISOString(),
113
+ duration: e.duration || 0,
114
+ app: e.app || 'Chrome',
115
+ title: e.title || '',
116
+ url: e.url || '',
117
+ raw_data: JSON.stringify(e),
118
+ }));
119
+ const count = (0, db_1.insertRawEvents)(events);
120
+ res.writeHead(200, { 'Content-Type': 'application/json' });
121
+ res.end(JSON.stringify({ stored: count }));
122
+ }
123
+ else if (parsed.url || parsed.title) {
124
+ const count = (0, db_1.insertRawEvents)([{
125
+ source: 'native',
126
+ bucket_id: 'browser-extension',
127
+ timestamp: parsed.timestamp || new Date().toISOString(),
128
+ duration: parsed.duration || 0,
129
+ app: parsed.app || 'Chrome',
130
+ title: parsed.title || '',
131
+ url: parsed.url || '',
132
+ raw_data: JSON.stringify(parsed),
133
+ }]);
134
+ res.writeHead(200, { 'Content-Type': 'application/json' });
135
+ res.end(JSON.stringify({ stored: count }));
136
+ }
137
+ else {
138
+ res.writeHead(400);
139
+ res.end(JSON.stringify({ error: 'missing url or title' }));
140
+ }
141
+ }
142
+ catch {
143
+ res.writeHead(400);
144
+ res.end(JSON.stringify({ error: 'invalid JSON body' }));
145
+ }
146
+ }
147
+ async function handleGetSummary(url, res) {
148
+ const dateParam = url.searchParams.get('date');
149
+ const now = new Date();
150
+ let startOfDay;
151
+ let endOfDay;
152
+ if (dateParam && /^\d{4}-\d{2}-\d{2}$/.test(dateParam)) {
153
+ const [y, m, d] = dateParam.split('-').map(Number);
154
+ startOfDay = new Date(y, m - 1, d, 0, 0, 0, 0);
155
+ endOfDay = new Date(y, m - 1, d, 23, 59, 59, 999);
156
+ }
157
+ else {
158
+ startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0);
159
+ endOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59, 999);
160
+ }
161
+ const dateStr = `${startOfDay.getFullYear()}-${String(startOfDay.getMonth() + 1).padStart(2, '0')}-${String(startOfDay.getDate()).padStart(2, '0')}`;
162
+ const summary = (0, db_1.getDailySummary)(dateStr);
163
+ const events = (0, db_1.getRawEvents)({
164
+ periodStart: startOfDay.toISOString(),
165
+ periodEnd: endOfDay.toISOString(),
166
+ limit: 5000,
167
+ });
168
+ if (!summary) {
169
+ const engine = (0, insights_1.createInsightEngine)();
170
+ const events = (0, db_1.getRawEvents)({
171
+ periodStart: startOfDay.toISOString(),
172
+ periodEnd: endOfDay.toISOString(),
173
+ limit: 5000,
174
+ });
175
+ if (events.length === 0) {
176
+ res.writeHead(200, { 'Content-Type': 'application/json' });
177
+ res.end(JSON.stringify({
178
+ date: dateStr,
179
+ active_time: 0,
180
+ top_apps: [],
181
+ insights: [],
182
+ message: 'No activity recorded yet today.',
183
+ }));
184
+ return;
185
+ }
186
+ const mapped = events.map((e) => ({
187
+ timestamp: e.timestamp,
188
+ duration: e.duration,
189
+ data: { app: e.app, title: e.title, url: e.url },
190
+ }));
191
+ const result = engine.runFullAnalysis(mapped);
192
+ res.writeHead(200, { 'Content-Type': 'application/json' });
193
+ res.end(JSON.stringify({
194
+ date: dateStr,
195
+ active_time: Math.round(result.totalActiveTime / 6) / 10,
196
+ top_apps: result.appSummaries.slice(0, 8).map((a) => ({
197
+ app: a.app,
198
+ minutes: Math.round(a.totalDuration / 6) / 10,
199
+ percentage: Math.round(a.percentage),
200
+ })),
201
+ switch_count: result.contextSwitches.reduce((s, c) => s + c.count, 0),
202
+ insights: result.insights.slice(0, 6).map((i, idx) => ({
203
+ id: idx,
204
+ type: i.type,
205
+ title: i.title,
206
+ description: i.description,
207
+ confidence: Math.round(i.confidence * 100),
208
+ action_text: i.action_text,
209
+ })),
210
+ raw_summary: result.summary,
211
+ }));
212
+ return;
213
+ }
214
+ const storedInsights = (0, db_1.getInsights)({
215
+ periodStart: dateStr,
216
+ periodEnd: dateStr + 'T23:59:59.999Z',
217
+ limit: 10,
218
+ });
219
+ res.writeHead(200, { 'Content-Type': 'application/json' });
220
+ res.end(JSON.stringify({
221
+ date: dateStr,
222
+ active_time: Math.round(summary.total_active_time / 6) / 10,
223
+ top_apps: JSON.parse(summary.top_apps || '[]'),
224
+ switch_count: summary.switch_count,
225
+ insights: storedInsights.map((i) => ({
226
+ id: i.id,
227
+ type: i.type,
228
+ title: i.title,
229
+ description: i.description,
230
+ confidence: Math.round(i.confidence * 100),
231
+ action_text: i.action_text,
232
+ status: i.status,
233
+ })),
234
+ raw_summary: summary.raw_summary,
235
+ }));
236
+ }
237
+ async function handleGetInsights(url, res) {
238
+ const stored = (0, db_1.getInsights)({
239
+ limit: 20,
240
+ includePushed: true,
241
+ });
242
+ res.writeHead(200, { 'Content-Type': 'application/json' });
243
+ res.end(JSON.stringify({
244
+ insights: stored.map((i) => ({
245
+ id: i.id,
246
+ type: i.type,
247
+ title: i.title,
248
+ description: i.description,
249
+ confidence: Math.round(i.confidence * 100),
250
+ action_text: i.action_text,
251
+ created_at: i.created_at,
252
+ })),
253
+ }));
254
+ }
255
+ async function handleGetContext(res) {
256
+ const now = new Date();
257
+ const dateStr = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`;
258
+ const summary = (0, db_1.getDailySummary)(dateStr);
259
+ const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0);
260
+ const endOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59, 999);
261
+ const storedInsights = (0, db_1.getInsights)({
262
+ periodStart: dateStr,
263
+ periodEnd: dateStr + 'T23:59:59.999Z',
264
+ limit: 10,
265
+ });
266
+ let totalMinutes;
267
+ let topApps;
268
+ let insightsList = storedInsights;
269
+ if (summary) {
270
+ totalMinutes = Math.round(summary.total_active_time / 60);
271
+ topApps = JSON.parse(summary.top_apps || '[]');
272
+ }
273
+ else {
274
+ const events = (0, db_1.getRawEvents)({
275
+ periodStart: startOfDay.toISOString(),
276
+ periodEnd: endOfDay.toISOString(),
277
+ limit: 5000,
278
+ });
279
+ if (events.length > 0) {
280
+ const engine = (0, insights_1.createInsightEngine)();
281
+ const mapped = events.map((e) => ({
282
+ timestamp: e.timestamp,
283
+ duration: e.duration,
284
+ data: { app: e.app, title: e.title, url: e.url },
285
+ }));
286
+ const result = engine.runFullAnalysis(mapped);
287
+ totalMinutes = Math.round(result.totalActiveTime / 60);
288
+ topApps = result.appSummaries.slice(0, 6).map((a) => ({
289
+ app: a.app,
290
+ minutes: Math.round(a.totalDuration / 6) / 10,
291
+ }));
292
+ if (insightsList.length === 0) {
293
+ insightsList = result.insights.map((i) => ({
294
+ ...i,
295
+ created_at: new Date().toISOString(),
296
+ }));
297
+ }
298
+ }
299
+ else {
300
+ totalMinutes = 0;
301
+ topApps = [];
302
+ }
303
+ }
304
+ let text = `Here is my activity context for today:\n\n`;
305
+ if (totalMinutes > 0) {
306
+ text += `I've been active for ${totalMinutes} minutes across ${topApps.length} applications.\n\n`;
307
+ text += `Top apps:\n`;
308
+ for (const a of topApps.slice(0, 6)) {
309
+ text += `- ${a.app}: ${a.minutes} min\n`;
310
+ }
311
+ }
312
+ else {
313
+ text += `No activity recorded yet today.\n`;
314
+ }
315
+ if (storedInsights.length > 0) {
316
+ text += `\nDetected insights:\n`;
317
+ for (const i of storedInsights.slice(0, 5)) {
318
+ text += `- [${i.type}] ${i.title}\n ${i.description}\n`;
319
+ }
320
+ }
321
+ text += `\n(Generated by DayBrain — local AI memory engine)`;
322
+ res.writeHead(200, { 'Content-Type': 'application/json' });
323
+ res.end(JSON.stringify({ text, total_minutes: totalMinutes, insights: storedInsights.length }));
324
+ }
325
+ async function handleGetBaseline(res) {
326
+ const now = new Date();
327
+ const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0);
328
+ const endOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59, 999);
329
+ const events = (0, db_1.getRawEvents)({
330
+ periodStart: startOfDay.toISOString(),
331
+ periodEnd: endOfDay.toISOString(),
332
+ limit: 10000,
333
+ });
334
+ if (events.length === 0) {
335
+ res.writeHead(200, { 'Content-Type': 'application/json' });
336
+ res.end(JSON.stringify({ anomalies: [], message: 'No activity today yet.' }));
337
+ return;
338
+ }
339
+ const mapped = events.map((e) => ({
340
+ timestamp: e.timestamp,
341
+ duration: e.duration,
342
+ data: { app: e.app, title: e.title, url: e.url },
343
+ }));
344
+ const engine = (0, insights_1.createInsightEngine)();
345
+ const baseline = (0, baseline_1.generateBaseline)(mapped, engine);
346
+ res.writeHead(200, { 'Content-Type': 'application/json' });
347
+ res.end(JSON.stringify(baseline));
348
+ }
349
+ async function handleUpdateInsightStatus(req, res) {
350
+ const body = await readBody(req);
351
+ try {
352
+ const { id, status } = JSON.parse(body);
353
+ if (!id || !status) {
354
+ res.writeHead(400);
355
+ res.end(JSON.stringify({ error: 'id and status required' }));
356
+ return;
357
+ }
358
+ (0, db_1.updateInsightStatus)(Number(id), String(status));
359
+ res.writeHead(200, { 'Content-Type': 'application/json' });
360
+ res.end(JSON.stringify({ ok: true }));
361
+ }
362
+ catch (err) {
363
+ res.writeHead(400);
364
+ res.end(JSON.stringify({ error: String(err) }));
365
+ }
366
+ }
367
+ async function handleSyncPush(req, res) {
368
+ const body = await readBody(req);
369
+ try {
370
+ const parsed = JSON.parse(body);
371
+ const deviceId = req.headers['x-daybrain-device'] || 'remote';
372
+ const events = Array.isArray(parsed) ? parsed : [parsed];
373
+ const rawEvents = events.map((e) => ({
374
+ source: 'native',
375
+ bucket_id: `sync-${deviceId}`,
376
+ timestamp: e.timestamp || new Date().toISOString(),
377
+ duration: e.duration || 0,
378
+ app: e.app || 'Unknown',
379
+ title: e.title || '',
380
+ url: e.url || '',
381
+ raw_data: JSON.stringify({ ...e, deviceId }),
382
+ }));
383
+ const count = (0, db_1.insertRawEvents)(rawEvents);
384
+ res.writeHead(200, { 'Content-Type': 'application/json' });
385
+ res.end(JSON.stringify({ stored: count, device: deviceId }));
386
+ }
387
+ catch {
388
+ res.writeHead(400);
389
+ res.end(JSON.stringify({ error: 'invalid JSON body' }));
390
+ }
391
+ }
392
+ async function handleSyncPull(req, res) {
393
+ const url = new URL(req.url || '/', `http://localhost`);
394
+ const since = url.searchParams.get('since') || new Date(Date.now() - 86400000).toISOString();
395
+ const limit = Math.min(Number(url.searchParams.get('limit')) || 1000, 5000);
396
+ const events = (0, db_1.getRawEvents)({
397
+ periodStart: since,
398
+ limit,
399
+ });
400
+ res.writeHead(200, { 'Content-Type': 'application/json' });
401
+ res.end(JSON.stringify({ events, count: events.length, since }));
402
+ }
403
+ function readBody(req) {
404
+ return new Promise((resolve, reject) => {
405
+ let data = '';
406
+ req.on('data', chunk => { data += chunk; });
407
+ req.on('end', () => resolve(data));
408
+ req.on('error', reject);
409
+ });
410
+ }
411
+ //# sourceMappingURL=http.js.map