beercan 0.1.0 → 0.2.1

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 (97) hide show
  1. package/README.md +96 -2
  2. package/dist/api/handlers/bloops.d.ts +4 -0
  3. package/dist/api/handlers/bloops.d.ts.map +1 -0
  4. package/dist/api/handlers/bloops.js +96 -0
  5. package/dist/api/handlers/bloops.js.map +1 -0
  6. package/dist/api/handlers/jobs.d.ts +4 -0
  7. package/dist/api/handlers/jobs.d.ts.map +1 -0
  8. package/dist/api/handlers/jobs.js +34 -0
  9. package/dist/api/handlers/jobs.js.map +1 -0
  10. package/dist/api/handlers/projects.d.ts +4 -0
  11. package/dist/api/handlers/projects.d.ts.map +1 -0
  12. package/dist/api/handlers/projects.js +75 -0
  13. package/dist/api/handlers/projects.js.map +1 -0
  14. package/dist/api/handlers/schedules.d.ts +4 -0
  15. package/dist/api/handlers/schedules.d.ts.map +1 -0
  16. package/dist/api/handlers/schedules.js +19 -0
  17. package/dist/api/handlers/schedules.js.map +1 -0
  18. package/dist/api/handlers/status.d.ts +4 -0
  19. package/dist/api/handlers/status.d.ts.map +1 -0
  20. package/dist/api/handlers/status.js +21 -0
  21. package/dist/api/handlers/status.js.map +1 -0
  22. package/dist/api/index.d.ts +8 -0
  23. package/dist/api/index.d.ts.map +1 -0
  24. package/dist/api/index.js +17 -0
  25. package/dist/api/index.js.map +1 -0
  26. package/dist/api/utils.d.ts +5 -0
  27. package/dist/api/utils.d.ts.map +1 -0
  28. package/dist/api/utils.js +24 -0
  29. package/dist/api/utils.js.map +1 -0
  30. package/dist/chat/formatter.d.ts +43 -0
  31. package/dist/chat/formatter.d.ts.map +1 -0
  32. package/dist/chat/formatter.js +144 -0
  33. package/dist/chat/formatter.js.map +1 -0
  34. package/dist/chat/index.d.ts +33 -0
  35. package/dist/chat/index.d.ts.map +1 -0
  36. package/dist/chat/index.js +253 -0
  37. package/dist/chat/index.js.map +1 -0
  38. package/dist/chat/intent.d.ts +12 -0
  39. package/dist/chat/intent.d.ts.map +1 -0
  40. package/dist/chat/intent.js +256 -0
  41. package/dist/chat/intent.js.map +1 -0
  42. package/dist/chat/providers/slack.d.ts +17 -0
  43. package/dist/chat/providers/slack.d.ts.map +1 -0
  44. package/dist/chat/providers/slack.js +90 -0
  45. package/dist/chat/providers/slack.js.map +1 -0
  46. package/dist/chat/providers/telegram.d.ts +15 -0
  47. package/dist/chat/providers/telegram.d.ts.map +1 -0
  48. package/dist/chat/providers/telegram.js +76 -0
  49. package/dist/chat/providers/telegram.js.map +1 -0
  50. package/dist/chat/providers/terminal.d.ts +14 -0
  51. package/dist/chat/providers/terminal.d.ts.map +1 -0
  52. package/dist/chat/providers/terminal.js +77 -0
  53. package/dist/chat/providers/terminal.js.map +1 -0
  54. package/dist/chat/providers/websocket.d.ts +16 -0
  55. package/dist/chat/providers/websocket.d.ts.map +1 -0
  56. package/dist/chat/providers/websocket.js +125 -0
  57. package/dist/chat/providers/websocket.js.map +1 -0
  58. package/dist/chat/skippy.d.ts +3 -0
  59. package/dist/chat/skippy.d.ts.map +1 -0
  60. package/dist/chat/skippy.js +47 -0
  61. package/dist/chat/skippy.js.map +1 -0
  62. package/dist/chat/types.d.ts +50 -0
  63. package/dist/chat/types.d.ts.map +1 -0
  64. package/dist/chat/types.js +2 -0
  65. package/dist/chat/types.js.map +1 -0
  66. package/dist/cli.js +232 -8
  67. package/dist/cli.js.map +1 -1
  68. package/dist/config.d.ts +9 -0
  69. package/dist/config.d.ts.map +1 -1
  70. package/dist/config.js +16 -2
  71. package/dist/config.js.map +1 -1
  72. package/dist/core/job-queue.d.ts +9 -1
  73. package/dist/core/job-queue.d.ts.map +1 -1
  74. package/dist/core/job-queue.js +33 -0
  75. package/dist/core/job-queue.js.map +1 -1
  76. package/dist/core/runner.d.ts +2 -0
  77. package/dist/core/runner.d.ts.map +1 -1
  78. package/dist/core/runner.js +37 -7
  79. package/dist/core/runner.js.map +1 -1
  80. package/dist/events/daemon.d.ts +1 -1
  81. package/dist/events/daemon.d.ts.map +1 -1
  82. package/dist/events/daemon.js +35 -1
  83. package/dist/events/daemon.js.map +1 -1
  84. package/dist/events/sources/webhook-source.d.ts +2 -1
  85. package/dist/events/sources/webhook-source.d.ts.map +1 -1
  86. package/dist/events/sources/webhook-source.js +77 -5
  87. package/dist/events/sources/webhook-source.js.map +1 -1
  88. package/dist/index.d.ts +54 -0
  89. package/dist/index.d.ts.map +1 -1
  90. package/dist/index.js +64 -2
  91. package/dist/index.js.map +1 -1
  92. package/dist/storage/database.d.ts +20 -0
  93. package/dist/storage/database.d.ts.map +1 -1
  94. package/dist/storage/database.js +46 -0
  95. package/dist/storage/database.js.map +1 -1
  96. package/package.json +14 -4
  97. package/src/dashboard/index.html +1092 -0
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # 🍺 BeerCan
2
2
 
3
- Autonomous AI agent system — smarter than you, and it knows it.
3
+ Autonomous AI agent system — powered by Skippy the Magnificent.
4
4
 
5
- Sandboxed projects, multi-agent pipelines with dynamic team composition, 4-layer hybrid RAG memory, SQLite-backed job queue, 13 built-in tools, and Cloudflare Browser Rendering for web fetching.
5
+ Sandboxed projects, multi-agent pipelines with dynamic team composition, 4-layer hybrid RAG memory, conversational chat interface (terminal, Telegram, Slack, WebSocket), REST API with auth, and a magnificently sarcastic AI overlord.
6
6
 
7
7
  ## Install
8
8
 
@@ -30,6 +30,37 @@ beercan result <bloop-id>
30
30
  beercan status
31
31
  ```
32
32
 
33
+ ## Chat with Skippy
34
+
35
+ ```bash
36
+ # Interactive terminal chat (Skippy manages everything)
37
+ beercan chat
38
+
39
+ # Scoped to a project
40
+ beercan chat my-project
41
+ ```
42
+
43
+ ```
44
+ 🍺 Skippy the Magnificent
45
+ Elder AI | Beer Can | Your intellectual superior
46
+
47
+ skippy> create a project for my-api at ~/work/my-api
48
+ Project my-api created. Another domain under my glorious rule.
49
+
50
+ skippy> analyze the codebase for bugs
51
+ ▸ Phase: plan (planner)
52
+ ⚙ read_file • list_directory
53
+ ▸ Phase: review (reviewer)
54
+ ✦ APPROVE
55
+ ✓ Bloop completed — 8,421 tokens
56
+
57
+ skippy> /status
58
+ Skippy's Magnificent Status Report
59
+ Uptime: 2h 15m | Projects: 3 | Running: 1
60
+ ```
61
+
62
+ Natural language or slash commands — Skippy understands both.
63
+
33
64
  ## What It Does
34
65
 
35
66
  You describe a goal. BeerCan figures out the rest:
@@ -121,6 +152,61 @@ beercan daemon
121
152
  - Cron-based scheduling
122
153
  - Graceful shutdown with job queue drain
123
154
 
155
+ ## REST API
156
+
157
+ Submit tasks, monitor jobs, and control bloops via HTTP:
158
+
159
+ ```bash
160
+ # Start API server
161
+ beercan serve
162
+
163
+ # Submit a task
164
+ curl -X POST http://localhost:3939/api/bloops \
165
+ -H "Content-Type: application/json" \
166
+ -H "Authorization: Bearer $BEERCAN_API_KEY" \
167
+ -d '{"projectSlug": "my-project", "goal": "Refactor auth module"}'
168
+
169
+ # Check status
170
+ curl http://localhost:3939/api/status
171
+
172
+ # Cancel a job
173
+ curl -X DELETE http://localhost:3939/api/jobs/<job-id>
174
+ ```
175
+
176
+ | Endpoint | Description |
177
+ |----------|-------------|
178
+ | `GET /api/status` | System overview |
179
+ | `GET /api/projects` | All projects with stats |
180
+ | `POST /api/bloops` | Submit a new task |
181
+ | `GET /api/bloops/recent` | Recent bloops |
182
+ | `GET /api/bloops/:id` | Bloop detail |
183
+ | `GET /api/jobs` | Job queue |
184
+ | `DELETE /api/jobs/:id` | Cancel a job |
185
+ | `GET /api/schedules` | Schedules |
186
+
187
+ ## Chat Providers
188
+
189
+ BeerCan's conversational interface is provider-agnostic:
190
+
191
+ | Provider | Setup | Description |
192
+ |----------|-------|-------------|
193
+ | Terminal | `beercan chat` | Interactive REPL |
194
+ | Telegram | Set `BEERCAN_TELEGRAM_TOKEN` | Bot auto-starts in daemon |
195
+ | Slack | Set `BEERCAN_SLACK_TOKEN` + `BEERCAN_SLACK_SIGNING_SECRET` | Socket mode bot |
196
+ | WebSocket | `ws://localhost:3940` | Generic JSON protocol |
197
+
198
+ All providers share the same ChatBridge — slash commands and natural language work everywhere.
199
+
200
+ ## Production Features
201
+
202
+ - **Crash recovery** — stale "running" jobs auto-recovered on startup
203
+ - **Timeout enforcement** — `BEERCAN_BLOOP_TIMEOUT_MS` kills stuck bloops (default 10min)
204
+ - **Job cancellation** — cancel pending or abort running jobs via API
205
+ - **API key auth** — `BEERCAN_API_KEY` secures all endpoints
206
+ - **Rate limiting** — per-IP sliding window on all requests
207
+ - **Auto-notifications** — desktop notifications + webhook callbacks on completion/failure
208
+ - **Status dashboard** — live web UI at `beercan-site/status.html`
209
+
124
210
  ## CLI Reference
125
211
 
126
212
  ```
@@ -136,6 +222,8 @@ beercan schedule:list [project]
136
222
  beercan trigger:add <project> <type> <filter> <goal>
137
223
  beercan mcp:add <project> <name> <cmd> [args]
138
224
  beercan daemon Run scheduler + events
225
+ beercan chat [project] Interactive Skippy chat
226
+ beercan serve [port] API server (default: 3939)
139
227
  beercan bootstrap [goal] Self-improvement bloop
140
228
  ```
141
229
 
@@ -176,6 +264,12 @@ Set in `.env` file:
176
264
  | `BEERCAN_BLOOP_TIMEOUT_MS` | `600000` | Per-bloop timeout (10 min) |
177
265
  | `CLOUDFLARE_API_TOKEN` | — | For web_fetch (Browser Rendering) |
178
266
  | `CLOUDFLARE_ACCOUNT_ID` | — | For web_fetch (Browser Rendering) |
267
+ | `BEERCAN_API_KEY` | — | Bearer token for API auth |
268
+ | `BEERCAN_NOTIFY_ON_COMPLETE` | `true` | Desktop notification on completion |
269
+ | `BEERCAN_NOTIFY_WEBHOOK_URL` | — | POST results to this URL |
270
+ | `BEERCAN_TELEGRAM_TOKEN` | — | Telegram bot token |
271
+ | `BEERCAN_SLACK_TOKEN` | — | Slack bot token |
272
+ | `BEERCAN_SLACK_SIGNING_SECRET` | — | Slack signing secret |
179
273
 
180
274
  ## Architecture
181
275
 
@@ -0,0 +1,4 @@
1
+ import type { BeerCanEngine } from "../../index.js";
2
+ import type { WebhookSource } from "../../events/sources/webhook-source.js";
3
+ export declare function registerBloopHandlers(webhook: WebhookSource, engine: BeerCanEngine): void;
4
+ //# sourceMappingURL=bloops.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bloops.d.ts","sourceRoot":"","sources":["../../../src/api/handlers/bloops.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAC;AAW5E,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,CA0FzF"}
@@ -0,0 +1,96 @@
1
+ import { z } from "zod";
2
+ import { json, parseQuery, readJsonBody } from "../utils.js";
3
+ const CreateBloopSchema = z.object({
4
+ projectSlug: z.string().min(1),
5
+ goal: z.string().min(1),
6
+ team: z.string().optional(),
7
+ priority: z.number().int().min(0).max(100).optional(),
8
+ extraContext: z.string().optional(),
9
+ });
10
+ export function registerBloopHandlers(webhook, engine) {
11
+ // POST /api/bloops — enqueue a new bloop
12
+ webhook.registerApiHandler("POST", "/api/bloops", async (req, res) => {
13
+ try {
14
+ const body = await readJsonBody(req);
15
+ const input = CreateBloopSchema.parse(body);
16
+ const project = engine.getProject(input.projectSlug);
17
+ if (!project) {
18
+ json(res, 404, { error: `Project not found: ${input.projectSlug}` });
19
+ return;
20
+ }
21
+ const jobId = engine.enqueueBloop({
22
+ projectSlug: input.projectSlug,
23
+ goal: input.goal,
24
+ team: input.team,
25
+ priority: input.priority,
26
+ source: "manual",
27
+ extraContext: input.extraContext,
28
+ });
29
+ json(res, 202, { jobId, accepted: true });
30
+ }
31
+ catch (err) {
32
+ if (err instanceof z.ZodError) {
33
+ json(res, 400, { error: "Validation failed", details: err.errors });
34
+ }
35
+ else {
36
+ json(res, 400, { error: err.message });
37
+ }
38
+ }
39
+ });
40
+ // GET /api/bloops/recent — recent bloops across all projects
41
+ // IMPORTANT: Register before /api/bloops/:id to avoid route conflict
42
+ webhook.registerApiHandler("GET", "/api/bloops/recent", (req, res) => {
43
+ const query = parseQuery(req);
44
+ const limit = parseInt(query.get("limit") ?? "20", 10);
45
+ const statusFilter = query.get("status") ?? undefined;
46
+ const bloops = engine.getRecentBloops(limit, statusFilter).map((b) => ({
47
+ id: b.id,
48
+ projectId: b.projectId,
49
+ status: b.status,
50
+ goal: b.goal,
51
+ trigger: b.trigger,
52
+ tokensUsed: b.tokensUsed,
53
+ iterations: b.iterations,
54
+ toolCallCount: b.toolCalls.length,
55
+ createdAt: b.createdAt,
56
+ completedAt: b.completedAt,
57
+ }));
58
+ json(res, 200, { bloops });
59
+ });
60
+ // GET /api/bloops/:id — single bloop detail
61
+ webhook.registerApiHandler("GET", "/api/bloops/:id", (_req, res, params) => {
62
+ let bloop = engine.getBloop(params.id);
63
+ // Try partial ID match
64
+ if (!bloop) {
65
+ for (const p of engine.listProjects()) {
66
+ const pBloops = engine.getProjectBloops(p.slug);
67
+ const match = pBloops.find((b) => b.id.startsWith(params.id));
68
+ if (match) {
69
+ bloop = match;
70
+ break;
71
+ }
72
+ }
73
+ }
74
+ if (!bloop) {
75
+ json(res, 404, { error: `Bloop not found: ${params.id}` });
76
+ return;
77
+ }
78
+ json(res, 200, {
79
+ id: bloop.id,
80
+ projectId: bloop.projectId,
81
+ parentBloopId: bloop.parentBloopId,
82
+ status: bloop.status,
83
+ goal: bloop.goal,
84
+ trigger: bloop.trigger,
85
+ result: bloop.result,
86
+ toolCalls: bloop.toolCalls,
87
+ tokensUsed: bloop.tokensUsed,
88
+ iterations: bloop.iterations,
89
+ maxIterations: bloop.maxIterations,
90
+ createdAt: bloop.createdAt,
91
+ updatedAt: bloop.updatedAt,
92
+ completedAt: bloop.completedAt,
93
+ });
94
+ });
95
+ }
96
+ //# sourceMappingURL=bloops.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bloops.js","sourceRoot":"","sources":["../../../src/api/handlers/bloops.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE7D,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACjC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACvB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IACrD,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACpC,CAAC,CAAC;AAEH,MAAM,UAAU,qBAAqB,CAAC,OAAsB,EAAE,MAAqB;IACjF,yCAAyC;IACzC,OAAO,CAAC,kBAAkB,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,GAAyB,EAAE,GAAwB,EAAE,EAAE;QAC9G,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,GAAG,CAAC,CAAC;YACrC,MAAM,KAAK,GAAG,iBAAiB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAE5C,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;YACrD,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,sBAAsB,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;gBACrE,OAAO;YACT,CAAC;YAED,MAAM,KAAK,GAAG,MAAM,CAAC,YAAY,CAAC;gBAChC,WAAW,EAAE,KAAK,CAAC,WAAW;gBAC9B,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,MAAM,EAAE,QAAQ;gBAChB,YAAY,EAAE,KAAK,CAAC,YAAY;aACjC,CAAC,CAAC;YAEH,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5C,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,IAAI,GAAG,YAAY,CAAC,CAAC,QAAQ,EAAE,CAAC;gBAC9B,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,mBAAmB,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;YACtE,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;YACzC,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,6DAA6D;IAC7D,qEAAqE;IACrE,OAAO,CAAC,kBAAkB,CAAC,KAAK,EAAE,oBAAoB,EAAE,CAAC,GAAyB,EAAE,GAAwB,EAAE,EAAE;QAC9G,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;QAC9B,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC;QACvD,MAAM,YAAY,GAAG,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,SAAS,CAAC;QAEtD,MAAM,MAAM,GAAG,MAAM,CAAC,eAAe,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACrE,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,UAAU,EAAE,CAAC,CAAC,UAAU;YACxB,UAAU,EAAE,CAAC,CAAC,UAAU;YACxB,aAAa,EAAE,CAAC,CAAC,SAAS,CAAC,MAAM;YACjC,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,WAAW,EAAE,CAAC,CAAC,WAAW;SAC3B,CAAC,CAAC,CAAC;QAEJ,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;IAEH,4CAA4C;IAC5C,OAAO,CAAC,kBAAkB,CAAC,KAAK,EAAE,iBAAiB,EAAE,CAAC,IAA0B,EAAE,GAAwB,EAAE,MAA8B,EAAE,EAAE;QAC5I,IAAI,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAEvC,uBAAuB;QACvB,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,YAAY,EAAE,EAAE,CAAC;gBACtC,MAAM,OAAO,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;gBAChD,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;gBAC9D,IAAI,KAAK,EAAE,CAAC;oBAAC,KAAK,GAAG,KAAK,CAAC;oBAAC,MAAM;gBAAC,CAAC;YACtC,CAAC;QACH,CAAC;QAED,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,oBAAoB,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;YAC3D,OAAO;QACT,CAAC;QAED,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE;YACb,EAAE,EAAE,KAAK,CAAC,EAAE;YACZ,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,aAAa,EAAE,KAAK,CAAC,aAAa;YAClC,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,aAAa,EAAE,KAAK,CAAC,aAAa;YAClC,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,WAAW,EAAE,KAAK,CAAC,WAAW;SAC/B,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { BeerCanEngine } from "../../index.js";
2
+ import type { WebhookSource } from "../../events/sources/webhook-source.js";
3
+ export declare function registerJobHandlers(webhook: WebhookSource, engine: BeerCanEngine): void;
4
+ //# sourceMappingURL=jobs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jobs.d.ts","sourceRoot":"","sources":["../../../src/api/handlers/jobs.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAC;AAG5E,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,CAiCvF"}
@@ -0,0 +1,34 @@
1
+ import { json, parseQuery } from "../utils.js";
2
+ export function registerJobHandlers(webhook, engine) {
3
+ webhook.registerApiHandler("GET", "/api/jobs", (req, res) => {
4
+ const query = parseQuery(req);
5
+ const statusFilter = query.get("status") ?? undefined;
6
+ const limit = parseInt(query.get("limit") ?? "20", 10);
7
+ const stats = engine.getJobQueue().getStats();
8
+ const jobs = engine.getJobQueue().listJobs(statusFilter, limit).map((j) => ({
9
+ id: j.id,
10
+ projectSlug: j.projectSlug,
11
+ goal: j.goal,
12
+ team: j.team,
13
+ status: j.status,
14
+ source: j.source,
15
+ bloopId: j.bloopId,
16
+ error: j.error,
17
+ createdAt: j.createdAt,
18
+ startedAt: j.startedAt,
19
+ completedAt: j.completedAt,
20
+ }));
21
+ json(res, 200, { stats, jobs });
22
+ });
23
+ // DELETE /api/jobs/:id — cancel a job
24
+ webhook.registerApiHandler("DELETE", "/api/jobs/:id", (_req, res, params) => {
25
+ const result = engine.getJobQueue().cancelJob(params.id);
26
+ if (result.cancelled) {
27
+ json(res, 200, { cancelled: true, jobId: params.id, status: result.status });
28
+ }
29
+ else {
30
+ json(res, 409, { cancelled: false, jobId: params.id, reason: result.reason, status: result.status });
31
+ }
32
+ });
33
+ }
34
+ //# sourceMappingURL=jobs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jobs.js","sourceRoot":"","sources":["../../../src/api/handlers/jobs.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,UAAU,mBAAmB,CAAC,OAAsB,EAAE,MAAqB;IAC/E,OAAO,CAAC,kBAAkB,CAAC,KAAK,EAAE,WAAW,EAAE,CAAC,GAAyB,EAAE,GAAwB,EAAE,EAAE;QACrG,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;QAC9B,MAAM,YAAY,GAAG,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,SAAS,CAAC;QACtD,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC;QAEvD,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE,CAAC;QAC9C,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC1E,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,WAAW,EAAE,CAAC,CAAC,WAAW;YAC1B,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,WAAW,EAAE,CAAC,CAAC,WAAW;SAC3B,CAAC,CAAC,CAAC;QAEJ,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,sCAAsC;IACtC,OAAO,CAAC,kBAAkB,CAAC,QAAQ,EAAE,eAAe,EAAE,CAAC,IAA0B,EAAE,GAAwB,EAAE,MAA8B,EAAE,EAAE;QAC7I,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACzD,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;YACrB,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QAC/E,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QACvG,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { BeerCanEngine } from "../../index.js";
2
+ import type { WebhookSource } from "../../events/sources/webhook-source.js";
3
+ export declare function registerProjectHandlers(webhook: WebhookSource, engine: BeerCanEngine): void;
4
+ //# sourceMappingURL=projects.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../../src/api/handlers/projects.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAC;AAG5E,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,CA8E3F"}
@@ -0,0 +1,75 @@
1
+ import { json, parseQuery } from "../utils.js";
2
+ export function registerProjectHandlers(webhook, engine) {
3
+ // GET /api/projects — all projects with bloop summaries
4
+ webhook.registerApiHandler("GET", "/api/projects", (_req, res) => {
5
+ const projects = engine.listProjects();
6
+ const result = projects.map((p) => {
7
+ const stats = engine.getProjectBloopStats(p.slug);
8
+ return {
9
+ slug: p.slug,
10
+ name: p.name,
11
+ workDir: p.workDir,
12
+ description: p.description,
13
+ bloops: stats ? { completed: stats.completed, failed: stats.failed, running: stats.running, total: stats.total } : { completed: 0, failed: 0, running: 0, total: 0 },
14
+ totalTokens: stats?.totalTokens ?? 0,
15
+ createdAt: p.createdAt,
16
+ };
17
+ });
18
+ json(res, 200, { projects: result });
19
+ });
20
+ // GET /api/projects/:slug — single project detail
21
+ webhook.registerApiHandler("GET", "/api/projects/:slug", (req, res, params) => {
22
+ const project = engine.getProject(params.slug);
23
+ if (!project) {
24
+ json(res, 404, { error: `Project not found: ${params.slug}` });
25
+ return;
26
+ }
27
+ const stats = engine.getProjectBloopStats(params.slug);
28
+ const recentBloops = engine.getProjectBloops(params.slug).slice(0, 10).map((b) => ({
29
+ id: b.id,
30
+ status: b.status,
31
+ goal: b.goal,
32
+ tokensUsed: b.tokensUsed,
33
+ iterations: b.iterations,
34
+ toolCallCount: b.toolCalls.length,
35
+ createdAt: b.createdAt,
36
+ completedAt: b.completedAt,
37
+ }));
38
+ json(res, 200, {
39
+ project: {
40
+ slug: project.slug,
41
+ name: project.name,
42
+ workDir: project.workDir,
43
+ description: project.description,
44
+ context: project.context,
45
+ tokenBudget: project.tokenBudget,
46
+ createdAt: project.createdAt,
47
+ },
48
+ bloops: stats ? { completed: stats.completed, failed: stats.failed, running: stats.running, total: stats.total } : { completed: 0, failed: 0, running: 0, total: 0 },
49
+ totalTokens: stats?.totalTokens ?? 0,
50
+ recentBloops,
51
+ });
52
+ });
53
+ // GET /api/projects/:slug/bloops — bloops for a project
54
+ webhook.registerApiHandler("GET", "/api/projects/:slug/bloops", (req, res, params) => {
55
+ const project = engine.getProject(params.slug);
56
+ if (!project) {
57
+ json(res, 404, { error: `Project not found: ${params.slug}` });
58
+ return;
59
+ }
60
+ const query = parseQuery(req);
61
+ const statusFilter = query.get("status") ?? undefined;
62
+ const bloops = engine.getProjectBloops(params.slug, statusFilter).map((b) => ({
63
+ id: b.id,
64
+ status: b.status,
65
+ goal: b.goal,
66
+ tokensUsed: b.tokensUsed,
67
+ iterations: b.iterations,
68
+ toolCallCount: b.toolCalls.length,
69
+ createdAt: b.createdAt,
70
+ completedAt: b.completedAt,
71
+ }));
72
+ json(res, 200, { bloops });
73
+ });
74
+ }
75
+ //# sourceMappingURL=projects.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projects.js","sourceRoot":"","sources":["../../../src/api/handlers/projects.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { BeerCanEngine } from "../../index.js";
2
+ import type { WebhookSource } from "../../events/sources/webhook-source.js";
3
+ export declare function registerScheduleHandlers(webhook: WebhookSource, engine: BeerCanEngine): void;
4
+ //# sourceMappingURL=schedules.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schedules.d.ts","sourceRoot":"","sources":["../../../src/api/handlers/schedules.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAC;AAG5E,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,CAkB5F"}
@@ -0,0 +1,19 @@
1
+ import { json, parseQuery } from "../utils.js";
2
+ export function registerScheduleHandlers(webhook, engine) {
3
+ webhook.registerApiHandler("GET", "/api/schedules", (req, res) => {
4
+ const query = parseQuery(req);
5
+ const projectFilter = query.get("project") ?? undefined;
6
+ const schedules = engine.getScheduler().listSchedules(projectFilter).map((s) => ({
7
+ id: s.id,
8
+ projectSlug: s.projectSlug,
9
+ cronExpression: s.cronExpression,
10
+ goal: s.goal,
11
+ team: s.team,
12
+ enabled: s.enabled,
13
+ lastRunAt: s.lastRunAt,
14
+ createdAt: s.createdAt,
15
+ }));
16
+ json(res, 200, { schedules });
17
+ });
18
+ }
19
+ //# sourceMappingURL=schedules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schedules.js","sourceRoot":"","sources":["../../../src/api/handlers/schedules.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,UAAU,wBAAwB,CAAC,OAAsB,EAAE,MAAqB;IACpF,OAAO,CAAC,kBAAkB,CAAC,KAAK,EAAE,gBAAgB,EAAE,CAAC,GAAyB,EAAE,GAAwB,EAAE,EAAE;QAC1G,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;QAC9B,MAAM,aAAa,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC;QAExD,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC/E,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,WAAW,EAAE,CAAC,CAAC,WAAW;YAC1B,cAAc,EAAE,CAAC,CAAC,cAAc;YAChC,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,SAAS,EAAE,CAAC,CAAC,SAAS;SACvB,CAAC,CAAC,CAAC;QAEJ,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { BeerCanEngine } from "../../index.js";
2
+ import type { WebhookSource } from "../../events/sources/webhook-source.js";
3
+ export declare function registerStatusHandlers(webhook: WebhookSource, engine: BeerCanEngine): void;
4
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/api/handlers/status.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAC;AAG5E,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,CAmB1F"}
@@ -0,0 +1,21 @@
1
+ import { json } from "../utils.js";
2
+ export function registerStatusHandlers(webhook, engine) {
3
+ webhook.registerApiHandler("GET", "/api/status", (_req, res) => {
4
+ const bloopStats = engine.getBloopStats();
5
+ const jobStats = engine.getJobQueue().getStats();
6
+ const projects = engine.listProjects();
7
+ const schedules = engine.getScheduler().listSchedules();
8
+ json(res, 200, {
9
+ uptime: process.uptime(),
10
+ timestamp: new Date().toISOString(),
11
+ projects: { total: projects.length },
12
+ bloops: bloopStats,
13
+ jobs: jobStats,
14
+ schedules: {
15
+ total: schedules.length,
16
+ enabled: schedules.filter((s) => s.enabled).length,
17
+ },
18
+ });
19
+ });
20
+ }
21
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/api/handlers/status.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAEnC,MAAM,UAAU,sBAAsB,CAAC,OAAsB,EAAE,MAAqB;IAClF,OAAO,CAAC,kBAAkB,CAAC,KAAK,EAAE,aAAa,EAAE,CAAC,IAA0B,EAAE,GAAwB,EAAE,EAAE;QACxG,MAAM,UAAU,GAAG,MAAM,CAAC,aAAa,EAAE,CAAC;QAC1C,MAAM,QAAQ,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE,CAAC;QACjD,MAAM,QAAQ,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC;QACvC,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC,aAAa,EAAE,CAAC;QAExD,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE;YACb,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE;YACxB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,QAAQ,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,MAAM,EAAE;YACpC,MAAM,EAAE,UAAU;YAClB,IAAI,EAAE,QAAQ;YACd,SAAS,EAAE;gBACT,KAAK,EAAE,SAAS,CAAC,MAAM;gBACvB,OAAO,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM;aACnD;SACF,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { WebhookSource } from "../events/sources/webhook-source.js";
2
+ import type { BeerCanEngine } from "../index.js";
3
+ /**
4
+ * Register all Status API routes on the webhook HTTP server.
5
+ * Call this before starting the server.
6
+ */
7
+ export declare function registerStatusApi(webhookSource: WebhookSource, engine: BeerCanEngine): void;
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAOjD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,aAAa,EAAE,aAAa,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,CAM3F"}
@@ -0,0 +1,17 @@
1
+ import { registerStatusHandlers } from "./handlers/status.js";
2
+ import { registerProjectHandlers } from "./handlers/projects.js";
3
+ import { registerJobHandlers } from "./handlers/jobs.js";
4
+ import { registerScheduleHandlers } from "./handlers/schedules.js";
5
+ import { registerBloopHandlers } from "./handlers/bloops.js";
6
+ /**
7
+ * Register all Status API routes on the webhook HTTP server.
8
+ * Call this before starting the server.
9
+ */
10
+ export function registerStatusApi(webhookSource, engine) {
11
+ registerStatusHandlers(webhookSource, engine);
12
+ registerProjectHandlers(webhookSource, engine);
13
+ registerJobHandlers(webhookSource, engine);
14
+ registerScheduleHandlers(webhookSource, engine);
15
+ registerBloopHandlers(webhookSource, engine);
16
+ }
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAE7D;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,aAA4B,EAAE,MAAqB;IACnF,sBAAsB,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;IAC9C,uBAAuB,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;IAC/C,mBAAmB,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;IAC3C,wBAAwB,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;IAChD,qBAAqB,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;AAC/C,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type http from "http";
2
+ export declare function json(res: http.ServerResponse, status: number, data: unknown): void;
3
+ export declare function parseQuery(req: http.IncomingMessage): URLSearchParams;
4
+ export declare function readJsonBody(req: http.IncomingMessage): Promise<unknown>;
5
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/api/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B,wBAAgB,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAGlF;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,GAAG,eAAe,CAGrE;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC,CAUxE"}
@@ -0,0 +1,24 @@
1
+ export function json(res, status, data) {
2
+ res.writeHead(status, { "Content-Type": "application/json" });
3
+ res.end(JSON.stringify(data));
4
+ }
5
+ export function parseQuery(req) {
6
+ const url = new URL(req.url ?? "/", "http://localhost");
7
+ return url.searchParams;
8
+ }
9
+ export function readJsonBody(req) {
10
+ return new Promise((resolve, reject) => {
11
+ let body = "";
12
+ req.on("data", (chunk) => (body += chunk));
13
+ req.on("end", () => {
14
+ try {
15
+ resolve(JSON.parse(body));
16
+ }
17
+ catch {
18
+ reject(new Error("Invalid JSON body"));
19
+ }
20
+ });
21
+ req.on("error", reject);
22
+ });
23
+ }
24
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/api/utils.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,IAAI,CAAC,GAAwB,EAAE,MAAc,EAAE,IAAa;IAC1E,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;IAC9D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,GAAyB;IAClD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,kBAAkB,CAAC,CAAC;IACxD,OAAO,GAAG,CAAC,YAAY,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,GAAyB;IACpD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAsB,EAAE,EAAE,CAAC,CAAC,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC;QAC5D,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YACjB,IAAI,CAAC;gBAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;YAAC,CAAC;YAClC,MAAM,CAAC;gBAAC,MAAM,CAAC,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC,CAAC;YAAC,CAAC;QACnD,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,43 @@
1
+ import type { BloopEvent } from "../core/runner.js";
2
+ import type { Bloop, Project } from "../schemas.js";
3
+ import type { JobStats } from "../core/job-queue.js";
4
+ /**
5
+ * Formats a BloopEvent into a human-readable string for chat output.
6
+ * Returns null for events that should not be shown (e.g., tool_result).
7
+ */
8
+ export declare function formatBloopEvent(event: BloopEvent): string | null;
9
+ /**
10
+ * Formats a completed or failed Bloop into a markdown summary.
11
+ */
12
+ export declare function formatBloopResult(bloop: Bloop): string;
13
+ /**
14
+ * Formats a system status overview.
15
+ */
16
+ export declare function formatStatus(bloopStats: {
17
+ running: number;
18
+ completed: number;
19
+ failed: number;
20
+ total: number;
21
+ }, jobStats: JobStats, projectCount: number, uptime: string): string;
22
+ /**
23
+ * Formats a list of projects with their bloop stats.
24
+ */
25
+ export declare function formatProjects(projects: Array<{
26
+ project: Project;
27
+ stats: {
28
+ running: number;
29
+ completed: number;
30
+ failed: number;
31
+ total: number;
32
+ totalTokens: number;
33
+ } | null;
34
+ }>): string;
35
+ /**
36
+ * Formats a list of recent bloops.
37
+ */
38
+ export declare function formatHistory(bloops: Bloop[]): string;
39
+ /**
40
+ * Returns help text listing all available chat commands.
41
+ */
42
+ export declare function formatHelp(): string;
43
+ //# sourceMappingURL=formatter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatter.d.ts","sourceRoot":"","sources":["../../src/chat/formatter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAIrD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CA8BjE;AAID;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAuBtD;AAID;;GAEG;AACH,wBAAgB,YAAY,CAC1B,UAAU,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EACjF,QAAQ,EAAE,QAAQ,EAClB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,GACb,MAAM,CAiBR;AAID;;GAEG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,KAAK,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAC1G,CAAC,GACD,MAAM,CAgBR;AAID;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAkBrD;AAID;;GAEG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAwBnC"}