beercan 0.1.0 → 0.2.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.
- package/README.md +96 -2
- package/dist/api/handlers/bloops.d.ts +4 -0
- package/dist/api/handlers/bloops.d.ts.map +1 -0
- package/dist/api/handlers/bloops.js +96 -0
- package/dist/api/handlers/bloops.js.map +1 -0
- package/dist/api/handlers/jobs.d.ts +4 -0
- package/dist/api/handlers/jobs.d.ts.map +1 -0
- package/dist/api/handlers/jobs.js +34 -0
- package/dist/api/handlers/jobs.js.map +1 -0
- package/dist/api/handlers/projects.d.ts +4 -0
- package/dist/api/handlers/projects.d.ts.map +1 -0
- package/dist/api/handlers/projects.js +75 -0
- package/dist/api/handlers/projects.js.map +1 -0
- package/dist/api/handlers/schedules.d.ts +4 -0
- package/dist/api/handlers/schedules.d.ts.map +1 -0
- package/dist/api/handlers/schedules.js +19 -0
- package/dist/api/handlers/schedules.js.map +1 -0
- package/dist/api/handlers/status.d.ts +4 -0
- package/dist/api/handlers/status.d.ts.map +1 -0
- package/dist/api/handlers/status.js +21 -0
- package/dist/api/handlers/status.js.map +1 -0
- package/dist/api/index.d.ts +8 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +17 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/utils.d.ts +5 -0
- package/dist/api/utils.d.ts.map +1 -0
- package/dist/api/utils.js +24 -0
- package/dist/api/utils.js.map +1 -0
- package/dist/chat/formatter.d.ts +43 -0
- package/dist/chat/formatter.d.ts.map +1 -0
- package/dist/chat/formatter.js +144 -0
- package/dist/chat/formatter.js.map +1 -0
- package/dist/chat/index.d.ts +33 -0
- package/dist/chat/index.d.ts.map +1 -0
- package/dist/chat/index.js +253 -0
- package/dist/chat/index.js.map +1 -0
- package/dist/chat/intent.d.ts +12 -0
- package/dist/chat/intent.d.ts.map +1 -0
- package/dist/chat/intent.js +256 -0
- package/dist/chat/intent.js.map +1 -0
- package/dist/chat/providers/slack.d.ts +17 -0
- package/dist/chat/providers/slack.d.ts.map +1 -0
- package/dist/chat/providers/slack.js +90 -0
- package/dist/chat/providers/slack.js.map +1 -0
- package/dist/chat/providers/telegram.d.ts +15 -0
- package/dist/chat/providers/telegram.d.ts.map +1 -0
- package/dist/chat/providers/telegram.js +76 -0
- package/dist/chat/providers/telegram.js.map +1 -0
- package/dist/chat/providers/terminal.d.ts +14 -0
- package/dist/chat/providers/terminal.d.ts.map +1 -0
- package/dist/chat/providers/terminal.js +77 -0
- package/dist/chat/providers/terminal.js.map +1 -0
- package/dist/chat/providers/websocket.d.ts +16 -0
- package/dist/chat/providers/websocket.d.ts.map +1 -0
- package/dist/chat/providers/websocket.js +125 -0
- package/dist/chat/providers/websocket.js.map +1 -0
- package/dist/chat/skippy.d.ts +3 -0
- package/dist/chat/skippy.d.ts.map +1 -0
- package/dist/chat/skippy.js +47 -0
- package/dist/chat/skippy.js.map +1 -0
- package/dist/chat/types.d.ts +50 -0
- package/dist/chat/types.d.ts.map +1 -0
- package/dist/chat/types.js +2 -0
- package/dist/chat/types.js.map +1 -0
- package/dist/cli.js +112 -7
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +9 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +8 -0
- package/dist/config.js.map +1 -1
- package/dist/core/job-queue.d.ts +9 -1
- package/dist/core/job-queue.d.ts.map +1 -1
- package/dist/core/job-queue.js +33 -0
- package/dist/core/job-queue.js.map +1 -1
- package/dist/core/runner.d.ts +2 -0
- package/dist/core/runner.d.ts.map +1 -1
- package/dist/core/runner.js +37 -7
- package/dist/core/runner.js.map +1 -1
- package/dist/events/daemon.d.ts +1 -1
- package/dist/events/daemon.d.ts.map +1 -1
- package/dist/events/daemon.js +35 -1
- package/dist/events/daemon.js.map +1 -1
- package/dist/events/sources/webhook-source.d.ts +2 -1
- package/dist/events/sources/webhook-source.d.ts.map +1 -1
- package/dist/events/sources/webhook-source.js +77 -5
- package/dist/events/sources/webhook-source.js.map +1 -1
- package/dist/index.d.ts +54 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +64 -2
- package/dist/index.js.map +1 -1
- package/dist/storage/database.d.ts +20 -0
- package/dist/storage/database.d.ts.map +1 -1
- package/dist/storage/database.js +46 -0
- package/dist/storage/database.js.map +1 -1
- package/package.json +14 -4
- 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 —
|
|
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,
|
|
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 @@
|
|
|
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":"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"}
|
|
@@ -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 @@
|
|
|
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"}
|