@owloops/browserbird 1.0.2 → 1.0.4

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 (56) hide show
  1. package/bin/browserbird +7 -1
  2. package/dist/db-BsYEYsul.mjs +1011 -0
  3. package/dist/index.mjs +4749 -0
  4. package/package.json +6 -3
  5. package/src/channel/blocks.ts +0 -485
  6. package/src/channel/coalesce.ts +0 -79
  7. package/src/channel/commands.ts +0 -216
  8. package/src/channel/handler.ts +0 -272
  9. package/src/channel/slack.ts +0 -573
  10. package/src/channel/types.ts +0 -59
  11. package/src/cli/banner.ts +0 -10
  12. package/src/cli/birds.ts +0 -396
  13. package/src/cli/config.ts +0 -77
  14. package/src/cli/doctor.ts +0 -63
  15. package/src/cli/index.ts +0 -5
  16. package/src/cli/jobs.ts +0 -166
  17. package/src/cli/logs.ts +0 -67
  18. package/src/cli/run.ts +0 -148
  19. package/src/cli/sessions.ts +0 -158
  20. package/src/cli/style.ts +0 -19
  21. package/src/config.ts +0 -291
  22. package/src/core/logger.ts +0 -78
  23. package/src/core/redact.ts +0 -75
  24. package/src/core/types.ts +0 -83
  25. package/src/core/uid.ts +0 -26
  26. package/src/core/utils.ts +0 -137
  27. package/src/cron/parse.ts +0 -146
  28. package/src/cron/scheduler.ts +0 -242
  29. package/src/daemon.ts +0 -169
  30. package/src/db/auth.ts +0 -49
  31. package/src/db/birds.ts +0 -357
  32. package/src/db/core.ts +0 -377
  33. package/src/db/index.ts +0 -10
  34. package/src/db/jobs.ts +0 -289
  35. package/src/db/logs.ts +0 -64
  36. package/src/db/messages.ts +0 -79
  37. package/src/db/path.ts +0 -30
  38. package/src/db/sessions.ts +0 -165
  39. package/src/jobs.ts +0 -140
  40. package/src/provider/claude.test.ts +0 -95
  41. package/src/provider/claude.ts +0 -196
  42. package/src/provider/opencode.test.ts +0 -169
  43. package/src/provider/opencode.ts +0 -248
  44. package/src/provider/session.ts +0 -65
  45. package/src/provider/spawn.ts +0 -173
  46. package/src/provider/stream.ts +0 -67
  47. package/src/provider/types.ts +0 -24
  48. package/src/server/auth.ts +0 -135
  49. package/src/server/health.ts +0 -87
  50. package/src/server/http.ts +0 -132
  51. package/src/server/index.ts +0 -6
  52. package/src/server/lifecycle.ts +0 -135
  53. package/src/server/routes.ts +0 -1199
  54. package/src/server/sse.ts +0 -54
  55. package/src/server/static.ts +0 -45
  56. package/src/server/vnc-proxy.ts +0 -75
package/src/db/birds.ts DELETED
@@ -1,357 +0,0 @@
1
- /** @fileoverview Bird (cron job) and flight (cron run) persistence. */
2
-
3
- import type { PaginatedResult } from './core.ts';
4
- import {
5
- getDb,
6
- paginate,
7
- parseSort,
8
- buildSearchClause,
9
- DEFAULT_PER_PAGE,
10
- MAX_PER_PAGE,
11
- } from './core.ts';
12
- import { generateUid, UID_PREFIX } from '../core/uid.ts';
13
-
14
- export const SYSTEM_CRON_PREFIX = '__bb_';
15
-
16
- export interface CronJobRow {
17
- uid: string;
18
- name: string;
19
- agent_id: string;
20
- schedule: string;
21
- prompt: string;
22
- target_channel_id: string | null;
23
- active_hours_start: string | null;
24
- active_hours_end: string | null;
25
- timezone: string;
26
- enabled: number;
27
- failure_count: number;
28
- last_run: string | null;
29
- last_status: string | null;
30
- created_at: string;
31
- }
32
-
33
- export interface CronRunRow {
34
- uid: string;
35
- job_uid: string;
36
- started_at: string;
37
- finished_at: string | null;
38
- status: 'running' | 'success' | 'error';
39
- result: string | null;
40
- error: string | null;
41
- }
42
-
43
- export interface FlightRow {
44
- uid: string;
45
- job_uid: string;
46
- bird_uid: string;
47
- bird_name: string;
48
- started_at: string;
49
- finished_at: string | null;
50
- status: 'running' | 'success' | 'error';
51
- result: string | null;
52
- error: string | null;
53
- }
54
-
55
- export interface ListFlightsFilters {
56
- birdUid?: string;
57
- status?: string;
58
- system?: boolean;
59
- }
60
-
61
- export interface UpdateCronJobFields {
62
- name?: string;
63
- schedule?: string;
64
- prompt?: string;
65
- targetChannelId?: string | null;
66
- agentId?: string;
67
- timezone?: string;
68
- activeHoursStart?: string | null;
69
- activeHoursEnd?: string | null;
70
- }
71
-
72
- const CRON_SORT_COLUMNS = new Set([
73
- 'uid',
74
- 'name',
75
- 'schedule',
76
- 'agent_id',
77
- 'enabled',
78
- 'last_run',
79
- 'created_at',
80
- ]);
81
- const CRON_SEARCH_COLUMNS = ['uid', 'name', 'prompt', 'schedule'] as const;
82
-
83
- export function listCronJobs(
84
- page = 1,
85
- perPage = DEFAULT_PER_PAGE,
86
- includeSystem = false,
87
- sort?: string,
88
- search?: string,
89
- ): PaginatedResult<CronJobRow> {
90
- const where = includeSystem ? '' : `name NOT LIKE '${SYSTEM_CRON_PREFIX}%'`;
91
- return paginate<CronJobRow>('cron_jobs', page, perPage, {
92
- where,
93
- defaultSort: 'created_at ASC',
94
- sort,
95
- search,
96
- allowedSortColumns: CRON_SORT_COLUMNS,
97
- searchColumns: CRON_SEARCH_COLUMNS,
98
- });
99
- }
100
-
101
- export function getEnabledCronJobs(): CronJobRow[] {
102
- return getDb()
103
- .prepare('SELECT * FROM cron_jobs WHERE enabled = 1 ORDER BY created_at')
104
- .all() as unknown as CronJobRow[];
105
- }
106
-
107
- export function createCronJob(
108
- name: string,
109
- schedule: string,
110
- prompt: string,
111
- targetChannelId?: string,
112
- agentId?: string,
113
- timezone?: string,
114
- activeHoursStart?: string,
115
- activeHoursEnd?: string,
116
- ): CronJobRow {
117
- const uid = generateUid(UID_PREFIX.bird);
118
- const stmt = getDb().prepare(
119
- `INSERT INTO cron_jobs (uid, name, schedule, prompt, target_channel_id, agent_id, timezone, active_hours_start, active_hours_end)
120
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
121
- RETURNING *`,
122
- );
123
- return stmt.get(
124
- uid,
125
- name,
126
- schedule,
127
- prompt,
128
- targetChannelId ?? null,
129
- agentId ?? 'default',
130
- timezone ?? 'UTC',
131
- activeHoursStart ?? null,
132
- activeHoursEnd ?? null,
133
- ) as unknown as CronJobRow;
134
- }
135
-
136
- export function updateCronJobStatus(jobUid: string, status: string, failureCount: number): void {
137
- const stmt = getDb().prepare(
138
- `UPDATE cron_jobs SET last_run = datetime('now'), last_status = ?, failure_count = ? WHERE uid = ?`,
139
- );
140
- stmt.run(status, failureCount, jobUid);
141
- }
142
-
143
- export function getCronJob(jobUid: string): CronJobRow | undefined {
144
- return getDb().prepare('SELECT * FROM cron_jobs WHERE uid = ?').get(jobUid) as unknown as
145
- | CronJobRow
146
- | undefined;
147
- }
148
-
149
- export function setCronJobEnabled(jobUid: string, enabled: boolean): boolean {
150
- const result = getDb()
151
- .prepare('UPDATE cron_jobs SET enabled = ? WHERE uid = ?')
152
- .run(enabled ? 1 : 0, jobUid);
153
- return Number(result.changes) > 0;
154
- }
155
-
156
- export function updateCronJob(jobUid: string, fields: UpdateCronJobFields): CronJobRow | undefined {
157
- const sets: string[] = [];
158
- const params: (string | number | null)[] = [];
159
-
160
- if (fields.name !== undefined) {
161
- sets.push('name = ?');
162
- params.push(fields.name);
163
- }
164
- if (fields.schedule !== undefined) {
165
- sets.push('schedule = ?');
166
- params.push(fields.schedule);
167
- }
168
- if (fields.prompt !== undefined) {
169
- sets.push('prompt = ?');
170
- params.push(fields.prompt);
171
- }
172
- if (fields.targetChannelId !== undefined) {
173
- sets.push('target_channel_id = ?');
174
- params.push(fields.targetChannelId);
175
- }
176
- if (fields.agentId !== undefined) {
177
- sets.push('agent_id = ?');
178
- params.push(fields.agentId);
179
- }
180
- if (fields.timezone !== undefined) {
181
- sets.push('timezone = ?');
182
- params.push(fields.timezone);
183
- }
184
- if (fields.activeHoursStart !== undefined) {
185
- sets.push('active_hours_start = ?');
186
- params.push(fields.activeHoursStart);
187
- }
188
- if (fields.activeHoursEnd !== undefined) {
189
- sets.push('active_hours_end = ?');
190
- params.push(fields.activeHoursEnd);
191
- }
192
-
193
- if (sets.length === 0) return getCronJob(jobUid);
194
-
195
- params.push(jobUid);
196
- return getDb()
197
- .prepare(`UPDATE cron_jobs SET ${sets.join(', ')} WHERE uid = ? RETURNING *`)
198
- .get(...params) as unknown as CronJobRow | undefined;
199
- }
200
-
201
- export function deleteCronJob(jobUid: string): boolean {
202
- const d = getDb();
203
- d.exec('BEGIN');
204
- try {
205
- d.prepare('DELETE FROM cron_runs WHERE job_uid = ?').run(jobUid);
206
- d.prepare('UPDATE jobs SET cron_job_uid = NULL WHERE cron_job_uid = ?').run(jobUid);
207
- const result = d.prepare('DELETE FROM cron_jobs WHERE uid = ?').run(jobUid);
208
- d.exec('COMMIT');
209
- return Number(result.changes) > 0;
210
- } catch (err) {
211
- d.exec('ROLLBACK');
212
- throw err;
213
- }
214
- }
215
-
216
- const FLIGHT_SORT_COLUMNS = new Set(['uid', 'started_at', 'finished_at', 'status', 'bird_name']);
217
- const FLIGHT_SORT_MAP: Record<string, string> = { bird_name: 'j.name' };
218
- const FLIGHT_SEARCH_COLUMNS = [
219
- 'r.uid',
220
- 'r.job_uid',
221
- 'j.uid',
222
- 'j.name',
223
- 'r.error',
224
- 'r.result',
225
- ] as const;
226
-
227
- export function listFlights(
228
- page = 1,
229
- perPage = DEFAULT_PER_PAGE,
230
- filters: ListFlightsFilters = {},
231
- sort?: string,
232
- search?: string,
233
- ): PaginatedResult<FlightRow> {
234
- const pp = Math.min(Math.max(perPage, 1), MAX_PER_PAGE);
235
- const p = Math.max(page, 1);
236
- const offset = (p - 1) * pp;
237
-
238
- const conditions: string[] = [];
239
- const params: (string | number)[] = [];
240
-
241
- if (!filters.system) {
242
- conditions.push(`j.name NOT LIKE '${SYSTEM_CRON_PREFIX}%'`);
243
- }
244
- if (filters.birdUid != null) {
245
- conditions.push('r.job_uid = ?');
246
- params.push(filters.birdUid);
247
- }
248
- if (filters.status) {
249
- conditions.push('r.status = ?');
250
- params.push(filters.status);
251
- }
252
-
253
- if (search) {
254
- const sc = buildSearchClause(search, FLIGHT_SEARCH_COLUMNS);
255
- if (sc.sql) {
256
- conditions.push(sc.sql);
257
- params.push(...sc.params);
258
- }
259
- }
260
-
261
- const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
262
-
263
- let orderBy = parseSort(sort, FLIGHT_SORT_COLUMNS, 'r.started_at DESC');
264
- for (const [key, qualified] of Object.entries(FLIGHT_SORT_MAP)) {
265
- orderBy = orderBy.replaceAll(key, qualified);
266
- }
267
- orderBy = orderBy.replace(/(?<![a-z.])\b(uid|started_at|finished_at|status)\b/g, 'r.$1');
268
-
269
- const countRow = getDb()
270
- .prepare(
271
- `SELECT COUNT(*) as count FROM cron_runs r JOIN cron_jobs j ON j.uid = r.job_uid ${where}`,
272
- )
273
- .get(...params) as unknown as { count: number };
274
- const totalItems = countRow.count;
275
- const totalPages = Math.max(Math.ceil(totalItems / pp), 1);
276
-
277
- const items = getDb()
278
- .prepare(
279
- `SELECT r.uid, r.job_uid, j.uid as bird_uid, j.name as bird_name,
280
- r.started_at, r.finished_at, r.status, r.result, r.error
281
- FROM cron_runs r
282
- JOIN cron_jobs j ON j.uid = r.job_uid
283
- ${where}
284
- ORDER BY ${orderBy}
285
- LIMIT ? OFFSET ?`,
286
- )
287
- .all(...params, pp, offset) as unknown as FlightRow[];
288
-
289
- return { items, page: p, perPage: pp, totalItems, totalPages };
290
- }
291
-
292
- export function createCronRun(jobUid: string): CronRunRow {
293
- const uid = generateUid(UID_PREFIX.flight);
294
- const stmt = getDb().prepare('INSERT INTO cron_runs (uid, job_uid) VALUES (?, ?) RETURNING *');
295
- return stmt.get(uid, jobUid) as unknown as CronRunRow;
296
- }
297
-
298
- export function completeCronRun(
299
- runUid: string,
300
- status: 'success' | 'error',
301
- result?: string,
302
- error?: string,
303
- ): void {
304
- const stmt = getDb().prepare(
305
- `UPDATE cron_runs SET finished_at = datetime('now'), status = ?, result = ?, error = ? WHERE uid = ?`,
306
- );
307
- stmt.run(status, result ?? null, error ?? null, runUid);
308
- }
309
-
310
- export interface FlightStats {
311
- running: number;
312
- completed: number;
313
- failed: number;
314
- total: number;
315
- }
316
-
317
- export function getFlightStats(): FlightStats {
318
- const rows = getDb()
319
- .prepare(
320
- `SELECT r.status, COUNT(*) as count
321
- FROM cron_runs r
322
- JOIN cron_jobs j ON j.uid = r.job_uid
323
- WHERE j.name NOT LIKE '${SYSTEM_CRON_PREFIX}%'
324
- GROUP BY r.status`,
325
- )
326
- .all() as unknown as Array<{ status: string; count: number }>;
327
-
328
- const stats: FlightStats = { running: 0, completed: 0, failed: 0, total: 0 };
329
- for (const row of rows) {
330
- if (row.status === 'running') stats.running = row.count;
331
- else if (row.status === 'success') stats.completed = row.count;
332
- else if (row.status === 'error') stats.failed = row.count;
333
- stats.total += row.count;
334
- }
335
- return stats;
336
- }
337
-
338
- export function deleteOldCronRuns(retentionDays: number): number {
339
- const stmt = getDb().prepare(
340
- `DELETE FROM cron_runs WHERE started_at < datetime('now', ? || ' days')`,
341
- );
342
- const result = stmt.run(`-${retentionDays}`);
343
- return Number(result.changes);
344
- }
345
-
346
- export function ensureSystemCronJob(name: string, schedule: string, prompt: string): void {
347
- const existing = getDb().prepare('SELECT uid FROM cron_jobs WHERE name = ?').get(name) as
348
- | unknown
349
- | undefined;
350
- if (existing) return;
351
- const uid = generateUid(UID_PREFIX.bird);
352
- getDb()
353
- .prepare(
354
- `INSERT INTO cron_jobs (uid, name, schedule, prompt, agent_id) VALUES (?, ?, ?, ?, 'system')`,
355
- )
356
- .run(uid, name, schedule, prompt);
357
- }