@actant/rest-api 0.2.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.
@@ -0,0 +1,49 @@
1
+ import { RequestListener, IncomingMessage, ServerResponse } from 'node:http';
2
+
3
+ declare class RpcBridge {
4
+ private readonly socketPath;
5
+ constructor(socketPath: string);
6
+ call(method: string, params?: Record<string, unknown>): Promise<unknown>;
7
+ ping(): Promise<boolean>;
8
+ private send;
9
+ }
10
+
11
+ interface ServerConfig {
12
+ bridge: RpcBridge;
13
+ apiKey?: string;
14
+ }
15
+ declare function createApiHandler(config: ServerConfig): RequestListener;
16
+
17
+ interface RouteContext {
18
+ bridge: RpcBridge;
19
+ params: Record<string, string>;
20
+ query: URLSearchParams;
21
+ body: Record<string, unknown>;
22
+ }
23
+ type RouteHandler = (ctx: RouteContext, req: IncomingMessage, res: ServerResponse) => Promise<void>;
24
+ declare class Router {
25
+ private routes;
26
+ get(pattern: string, handler: RouteHandler): void;
27
+ post(pattern: string, handler: RouteHandler): void;
28
+ put(pattern: string, handler: RouteHandler): void;
29
+ delete(pattern: string, handler: RouteHandler): void;
30
+ private add;
31
+ match(method: string, pathname: string): {
32
+ handler: RouteHandler;
33
+ params: Record<string, string>;
34
+ } | null;
35
+ }
36
+
37
+ interface ApiServerOptions {
38
+ port?: number;
39
+ host?: string;
40
+ socketPath: string;
41
+ apiKey?: string;
42
+ open?: boolean;
43
+ }
44
+ declare function startApiServer(options: ApiServerOptions): Promise<{
45
+ url: string;
46
+ close: () => void;
47
+ }>;
48
+
49
+ export { type ApiServerOptions, Router, RpcBridge, type ServerConfig, createApiHandler, startApiServer };
package/dist/index.js ADDED
@@ -0,0 +1,829 @@
1
+ // src/index.ts
2
+ import { createServer } from "http";
3
+ import { createLogger } from "@actant/shared";
4
+
5
+ // src/router.ts
6
+ var Router = class {
7
+ routes = [];
8
+ get(pattern, handler) {
9
+ this.add("GET", pattern, handler);
10
+ }
11
+ post(pattern, handler) {
12
+ this.add("POST", pattern, handler);
13
+ }
14
+ put(pattern, handler) {
15
+ this.add("PUT", pattern, handler);
16
+ }
17
+ delete(pattern, handler) {
18
+ this.add("DELETE", pattern, handler);
19
+ }
20
+ add(method, pattern, handler) {
21
+ this.routes.push({
22
+ method,
23
+ pattern,
24
+ segments: pattern.split("/").filter(Boolean),
25
+ handler
26
+ });
27
+ }
28
+ match(method, pathname) {
29
+ const parts = pathname.split("/").filter(Boolean);
30
+ for (const route of this.routes) {
31
+ if (route.method !== method) continue;
32
+ const params = matchSegments(route.segments, parts);
33
+ if (params) return { handler: route.handler, params };
34
+ }
35
+ return null;
36
+ }
37
+ };
38
+ function matchSegments(pattern, actual) {
39
+ if (pattern.length !== actual.length) return null;
40
+ const params = {};
41
+ for (let i = 0; i < pattern.length; i++) {
42
+ const seg = pattern[i];
43
+ const val = actual[i];
44
+ if (!seg || !val) return null;
45
+ if (seg.startsWith(":")) {
46
+ params[seg.slice(1)] = decodeURIComponent(val);
47
+ } else if (seg !== val) {
48
+ return null;
49
+ }
50
+ }
51
+ return params;
52
+ }
53
+ function json(res, data, status = 200) {
54
+ res.writeHead(status, { "Content-Type": "application/json" });
55
+ res.end(JSON.stringify(data));
56
+ }
57
+ function error(res, message, status = 500) {
58
+ json(res, { error: message, status }, status);
59
+ }
60
+ function readBody(req) {
61
+ return new Promise((resolve, reject) => {
62
+ const chunks = [];
63
+ req.on("data", (c) => chunks.push(c));
64
+ req.on("end", () => {
65
+ const raw = Buffer.concat(chunks).toString("utf-8");
66
+ try {
67
+ resolve(raw ? JSON.parse(raw) : {});
68
+ } catch {
69
+ resolve({});
70
+ }
71
+ });
72
+ req.on("error", reject);
73
+ });
74
+ }
75
+
76
+ // src/middleware.ts
77
+ function applyCors(res, origin = "*") {
78
+ res.setHeader("Access-Control-Allow-Origin", origin);
79
+ res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
80
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, X-API-Key");
81
+ res.setHeader("Access-Control-Max-Age", "86400");
82
+ }
83
+ function handlePreflight(req, res) {
84
+ if (req.method === "OPTIONS") {
85
+ applyCors(res);
86
+ res.writeHead(204);
87
+ res.end();
88
+ return true;
89
+ }
90
+ return false;
91
+ }
92
+ function checkAuth(req, apiKey) {
93
+ if (!apiKey) return { ok: true };
94
+ const header = req.headers["authorization"] ?? req.headers["x-api-key"];
95
+ if (!header) {
96
+ return { ok: false, message: "Missing API key. Set Authorization: Bearer <key> or X-API-Key header." };
97
+ }
98
+ const token = typeof header === "string" ? header.replace(/^Bearer\s+/i, "").trim() : "";
99
+ if (token !== apiKey) {
100
+ return { ok: false, message: "Invalid API key." };
101
+ }
102
+ return { ok: true };
103
+ }
104
+
105
+ // src/routes/agents.ts
106
+ function registerAgentRoutes(router) {
107
+ router.get("/v1/agents", async (ctx, _req, res) => {
108
+ const result = await ctx.bridge.call("agent.list");
109
+ json(res, result);
110
+ });
111
+ router.post("/v1/agents", async (ctx, _req, res) => {
112
+ const { name, template, overrides } = ctx.body;
113
+ if (!name || !template) {
114
+ return error(res, "name and template are required", 400);
115
+ }
116
+ const result = await ctx.bridge.call("agent.create", {
117
+ name,
118
+ template,
119
+ ...overrides ? { overrides } : {}
120
+ });
121
+ json(res, result, 201);
122
+ });
123
+ router.get("/v1/agents/:name", async (ctx, _req, res) => {
124
+ const result = await ctx.bridge.call("agent.status", { name: ctx.params.name });
125
+ json(res, result);
126
+ });
127
+ router.delete("/v1/agents/:name", async (ctx, _req, res) => {
128
+ const force = ctx.query.get("force") === "true";
129
+ const result = await ctx.bridge.call("agent.destroy", { name: ctx.params.name, force });
130
+ json(res, result);
131
+ });
132
+ router.post("/v1/agents/:name/start", async (ctx, _req, res) => {
133
+ const autoInstall = ctx.body.autoInstall;
134
+ const result = await ctx.bridge.call("agent.start", {
135
+ name: ctx.params.name,
136
+ ...autoInstall != null ? { autoInstall } : {}
137
+ });
138
+ json(res, result);
139
+ });
140
+ router.post("/v1/agents/:name/stop", async (ctx, _req, res) => {
141
+ const result = await ctx.bridge.call("agent.stop", { name: ctx.params.name });
142
+ json(res, result);
143
+ });
144
+ router.post("/v1/agents/:name/prompt", async (ctx, _req, res) => {
145
+ const { message, sessionId } = ctx.body;
146
+ if (!message) {
147
+ return error(res, "message is required", 400);
148
+ }
149
+ const result = await ctx.bridge.call("agent.prompt", {
150
+ name: ctx.params.name,
151
+ message,
152
+ ...sessionId ? { sessionId } : {}
153
+ });
154
+ json(res, result);
155
+ });
156
+ router.post("/v1/agents/:name/run", async (ctx, _req, res) => {
157
+ const { prompt, options } = ctx.body;
158
+ if (!prompt) {
159
+ return error(res, "prompt is required", 400);
160
+ }
161
+ const result = await ctx.bridge.call("agent.run", {
162
+ name: ctx.params.name,
163
+ prompt,
164
+ ...options ? { options } : {}
165
+ });
166
+ json(res, result);
167
+ });
168
+ router.post("/v1/agents/:name/dispatch", async (ctx, _req, res) => {
169
+ const { prompt } = ctx.body;
170
+ if (!prompt) {
171
+ return error(res, "prompt is required", 400);
172
+ }
173
+ const result = await ctx.bridge.call("agent.dispatch", {
174
+ name: ctx.params.name,
175
+ prompt
176
+ });
177
+ json(res, result);
178
+ });
179
+ router.put("/v1/agents/:name/permissions", async (ctx, _req, res) => {
180
+ const { permissions } = ctx.body;
181
+ if (!permissions) {
182
+ return error(res, "permissions object is required", 400);
183
+ }
184
+ const result = await ctx.bridge.call("agent.updatePermissions", {
185
+ name: ctx.params.name,
186
+ permissions
187
+ });
188
+ json(res, result);
189
+ });
190
+ router.get("/v1/agents/:name/sessions", async (ctx, _req, res) => {
191
+ const result = await ctx.bridge.call("activity.sessions", { agentName: ctx.params.name });
192
+ json(res, result);
193
+ });
194
+ router.get("/v1/agents/:name/sessions/:sessionId", async (ctx, _req, res) => {
195
+ const result = await ctx.bridge.call("activity.conversation", {
196
+ agentName: ctx.params.name,
197
+ sessionId: ctx.params.sessionId
198
+ });
199
+ json(res, result);
200
+ });
201
+ router.get("/v1/agents/:name/logs", async (ctx, _req, res) => {
202
+ const stream = ctx.query.get("stream") ?? "stdout";
203
+ const lines = parseInt(ctx.query.get("lines") ?? "200", 10);
204
+ try {
205
+ const result = await ctx.bridge.call("agent.processLogs", {
206
+ name: ctx.params.name,
207
+ stream,
208
+ lines
209
+ });
210
+ json(res, result);
211
+ } catch {
212
+ json(res, { lines: [], stream, logDir: "" });
213
+ }
214
+ });
215
+ router.get("/v1/agents/:name/tasks", async (ctx, _req, res) => {
216
+ const result = await ctx.bridge.call("agent.tasks", { name: ctx.params.name });
217
+ json(res, result);
218
+ });
219
+ router.get("/v1/agents/:name/schedule", async (ctx, _req, res) => {
220
+ const result = await ctx.bridge.call("schedule.list", { name: ctx.params.name });
221
+ json(res, result);
222
+ });
223
+ router.post("/v1/agents/:name/attach", async (ctx, _req, res) => {
224
+ const { pid, metadata } = ctx.body;
225
+ if (!pid) {
226
+ return error(res, "pid is required", 400);
227
+ }
228
+ const result = await ctx.bridge.call("agent.attach", {
229
+ name: ctx.params.name,
230
+ pid,
231
+ ...metadata ? { metadata } : {}
232
+ });
233
+ json(res, result);
234
+ });
235
+ router.post("/v1/agents/:name/detach", async (ctx, _req, res) => {
236
+ const { cleanup } = ctx.body;
237
+ const result = await ctx.bridge.call("agent.detach", {
238
+ name: ctx.params.name,
239
+ ...cleanup != null ? { cleanup } : {}
240
+ });
241
+ json(res, result);
242
+ });
243
+ }
244
+
245
+ // src/routes/templates.ts
246
+ function registerTemplateRoutes(router) {
247
+ router.get("/v1/templates", async (ctx, _req, res) => {
248
+ const result = await ctx.bridge.call("template.list");
249
+ json(res, result);
250
+ });
251
+ router.get("/v1/templates/:name", async (ctx, _req, res) => {
252
+ const result = await ctx.bridge.call("template.get", { name: ctx.params.name });
253
+ json(res, result);
254
+ });
255
+ router.post("/v1/templates/:name/load", async (ctx, _req, res) => {
256
+ const result = await ctx.bridge.call("template.load", { name: ctx.params.name });
257
+ json(res, result);
258
+ });
259
+ router.post("/v1/templates/:name/unload", async (ctx, _req, res) => {
260
+ const result = await ctx.bridge.call("template.unload", { name: ctx.params.name });
261
+ json(res, result);
262
+ });
263
+ router.post("/v1/templates/:name/validate", async (ctx, _req, res) => {
264
+ const result = await ctx.bridge.call("template.validate", { name: ctx.params.name });
265
+ json(res, result);
266
+ });
267
+ }
268
+
269
+ // src/routes/events.ts
270
+ function registerEventRoutes(router) {
271
+ router.get("/v1/events", async (ctx, _req, res) => {
272
+ const limit = parseInt(ctx.query.get("limit") ?? "50", 10);
273
+ try {
274
+ const result = await ctx.bridge.call("events.recent", { limit });
275
+ json(res, result);
276
+ } catch {
277
+ json(res, { events: [] });
278
+ }
279
+ });
280
+ }
281
+
282
+ // src/routes/canvas.ts
283
+ function registerCanvasRoutes(router) {
284
+ router.get("/v1/canvas", async (ctx, _req, res) => {
285
+ const result = await ctx.bridge.call("canvas.list");
286
+ json(res, result);
287
+ });
288
+ router.get("/v1/canvas/:agentName", async (ctx, _req, res) => {
289
+ try {
290
+ const result = await ctx.bridge.call("canvas.get", { agentName: ctx.params.agentName });
291
+ json(res, result);
292
+ } catch {
293
+ error(res, `No canvas for agent "${ctx.params.agentName}"`, 404);
294
+ }
295
+ });
296
+ router.post("/v1/canvas/:agentName", async (ctx, _req, res) => {
297
+ const { html, title } = ctx.body;
298
+ if (!html) {
299
+ return error(res, "html is required", 400);
300
+ }
301
+ const result = await ctx.bridge.call("canvas.update", {
302
+ agentName: ctx.params.agentName,
303
+ html,
304
+ ...title ? { title } : {}
305
+ });
306
+ json(res, result);
307
+ });
308
+ router.delete("/v1/canvas/:agentName", async (ctx, _req, res) => {
309
+ const result = await ctx.bridge.call("canvas.clear", { agentName: ctx.params.agentName });
310
+ json(res, result);
311
+ });
312
+ }
313
+
314
+ // src/routes/status.ts
315
+ function registerStatusRoutes(router) {
316
+ router.get("/v1/status", async (ctx, _req, res) => {
317
+ const result = await ctx.bridge.call("daemon.ping");
318
+ json(res, result);
319
+ });
320
+ router.post("/v1/shutdown", async (ctx, _req, res) => {
321
+ const result = await ctx.bridge.call("daemon.shutdown");
322
+ json(res, result);
323
+ });
324
+ }
325
+
326
+ // src/routes/domain.ts
327
+ function registerDomainRoutes(router) {
328
+ router.get("/v1/skills", async (ctx, _req, res) => {
329
+ const result = await ctx.bridge.call("skill.list");
330
+ json(res, result);
331
+ });
332
+ router.get("/v1/skills/:name", async (ctx, _req, res) => {
333
+ const result = await ctx.bridge.call("skill.get", { name: ctx.params.name });
334
+ json(res, result);
335
+ });
336
+ router.get("/v1/prompts", async (ctx, _req, res) => {
337
+ const result = await ctx.bridge.call("prompt.list");
338
+ json(res, result);
339
+ });
340
+ router.get("/v1/prompts/:name", async (ctx, _req, res) => {
341
+ const result = await ctx.bridge.call("prompt.get", { name: ctx.params.name });
342
+ json(res, result);
343
+ });
344
+ router.get("/v1/mcp-servers", async (ctx, _req, res) => {
345
+ const result = await ctx.bridge.call("mcp.list");
346
+ json(res, result);
347
+ });
348
+ router.get("/v1/mcp-servers/:name", async (ctx, _req, res) => {
349
+ const result = await ctx.bridge.call("mcp.get", { name: ctx.params.name });
350
+ json(res, result);
351
+ });
352
+ router.get("/v1/workflows", async (ctx, _req, res) => {
353
+ const result = await ctx.bridge.call("workflow.list");
354
+ json(res, result);
355
+ });
356
+ router.get("/v1/workflows/:name", async (ctx, _req, res) => {
357
+ const result = await ctx.bridge.call("workflow.get", { name: ctx.params.name });
358
+ json(res, result);
359
+ });
360
+ router.get("/v1/plugins", async (ctx, _req, res) => {
361
+ const result = await ctx.bridge.call("plugin.list");
362
+ json(res, result);
363
+ });
364
+ router.get("/v1/plugins/:name", async (ctx, _req, res) => {
365
+ const result = await ctx.bridge.call("plugin.get", { name: ctx.params.name });
366
+ json(res, result);
367
+ });
368
+ }
369
+
370
+ // src/routes/sources.ts
371
+ function registerSourceRoutes(router) {
372
+ router.get("/v1/sources", async (ctx, _req, res) => {
373
+ const result = await ctx.bridge.call("source.list");
374
+ json(res, result);
375
+ });
376
+ router.post("/v1/sources", async (ctx, _req, res) => {
377
+ const result = await ctx.bridge.call("source.add", ctx.body);
378
+ json(res, result, 201);
379
+ });
380
+ router.delete("/v1/sources/:name", async (ctx, _req, res) => {
381
+ const result = await ctx.bridge.call("source.remove", { name: ctx.params.name });
382
+ json(res, result);
383
+ });
384
+ router.post("/v1/sources/:name/sync", async (ctx, _req, res) => {
385
+ const result = await ctx.bridge.call("source.sync", { name: ctx.params.name });
386
+ json(res, result);
387
+ });
388
+ router.post("/v1/sources/:name/validate", async (ctx, _req, res) => {
389
+ const result = await ctx.bridge.call("source.validate", { name: ctx.params.name });
390
+ json(res, result);
391
+ });
392
+ router.get("/v1/presets", async (ctx, _req, res) => {
393
+ const result = await ctx.bridge.call("preset.list");
394
+ json(res, result);
395
+ });
396
+ router.get("/v1/presets/:name", async (ctx, _req, res) => {
397
+ const result = await ctx.bridge.call("preset.show", { name: ctx.params.name });
398
+ json(res, result);
399
+ });
400
+ router.post("/v1/presets/:name/apply", async (ctx, _req, res) => {
401
+ const result = await ctx.bridge.call("preset.apply", { name: ctx.params.name, ...ctx.body });
402
+ json(res, result);
403
+ });
404
+ }
405
+
406
+ // src/routes/sessions.ts
407
+ import { URL as URL2 } from "url";
408
+ function registerSessionRoutes(router) {
409
+ router.get("/v1/sessions", async (ctx, req, res) => {
410
+ const url = new URL2(req.url ?? "", `http://${req.headers.host}`);
411
+ const agentName = url.searchParams.get("agentName") ?? void 0;
412
+ const result = await ctx.bridge.call("session.list", { agentName });
413
+ json(res, result);
414
+ });
415
+ router.post("/v1/sessions", async (ctx, _req, res) => {
416
+ const result = await ctx.bridge.call("session.create", ctx.body);
417
+ json(res, result, 201);
418
+ });
419
+ router.post("/v1/sessions/:id/prompt", async (ctx, _req, res) => {
420
+ const { message } = ctx.body;
421
+ if (!message) {
422
+ return error(res, "message is required", 400);
423
+ }
424
+ const result = await ctx.bridge.call("session.prompt", {
425
+ sessionId: ctx.params.id,
426
+ text: message
427
+ });
428
+ json(res, result);
429
+ });
430
+ router.post("/v1/sessions/:id/cancel", async (ctx, _req, res) => {
431
+ const result = await ctx.bridge.call("session.cancel", { sessionId: ctx.params.id });
432
+ json(res, result);
433
+ });
434
+ router.delete("/v1/sessions/:id", async (ctx, _req, res) => {
435
+ const result = await ctx.bridge.call("session.close", { sessionId: ctx.params.id });
436
+ json(res, result);
437
+ });
438
+ }
439
+
440
+ // src/routes/webhooks.ts
441
+ function registerWebhookRoutes(router) {
442
+ router.post("/v1/webhooks/message", async (ctx, _req, res) => {
443
+ const { agent, message, metadata } = ctx.body;
444
+ if (!agent || !message) {
445
+ return error(res, "agent and message are required", 400);
446
+ }
447
+ const agentName = String(agent);
448
+ const text = String(message);
449
+ try {
450
+ const result = await ctx.bridge.call("agent.prompt", {
451
+ name: agentName,
452
+ message: text
453
+ });
454
+ json(res, {
455
+ agent: agentName,
456
+ response: result.response,
457
+ sessionId: result.sessionId,
458
+ ...metadata ? { metadata } : {}
459
+ });
460
+ } catch (err) {
461
+ const msg = err instanceof Error ? err.message : String(err);
462
+ error(res, `Agent "${agentName}" error: ${msg}`, 502);
463
+ }
464
+ });
465
+ router.post("/v1/webhooks/run", async (ctx, _req, res) => {
466
+ const { agent, prompt, template } = ctx.body;
467
+ if (!agent || !prompt) {
468
+ return error(res, "agent and prompt are required", 400);
469
+ }
470
+ const agentName = String(agent);
471
+ const promptText = String(prompt);
472
+ const RUN_TIMEOUT_MS = 12e4;
473
+ try {
474
+ const rpcPromise = ctx.bridge.call("agent.run", {
475
+ name: agentName,
476
+ prompt: promptText,
477
+ ...template ? { template: String(template) } : {}
478
+ });
479
+ const timeoutPromise = new Promise(
480
+ (_, reject) => setTimeout(() => reject(new Error("agent.run timed out after 120s")), RUN_TIMEOUT_MS)
481
+ );
482
+ const result = await Promise.race([rpcPromise, timeoutPromise]);
483
+ json(res, {
484
+ agent: agentName,
485
+ response: result.text,
486
+ sessionId: result.sessionId ?? null
487
+ });
488
+ } catch (err) {
489
+ const msg = err instanceof Error ? err.message : String(err);
490
+ error(res, `Agent "${agentName}" error: ${msg}`, 502);
491
+ }
492
+ });
493
+ router.post("/v1/webhooks/event", async (ctx, _req, res) => {
494
+ const { event, agentName, payload } = ctx.body;
495
+ if (!event) {
496
+ return error(res, "event is required", 400);
497
+ }
498
+ if (!agentName) {
499
+ return error(res, "agentName is required for event routing", 400);
500
+ }
501
+ try {
502
+ const result = await ctx.bridge.call("gateway.lease", {
503
+ event: String(event),
504
+ agentName: String(agentName),
505
+ ...payload ? { payload } : {}
506
+ });
507
+ json(res, result);
508
+ } catch (err) {
509
+ const msg = err instanceof Error ? err.message : String(err);
510
+ error(res, msg, 502);
511
+ }
512
+ });
513
+ }
514
+
515
+ // src/routes/index.ts
516
+ function registerAllRoutes(router) {
517
+ registerStatusRoutes(router);
518
+ registerAgentRoutes(router);
519
+ registerTemplateRoutes(router);
520
+ registerEventRoutes(router);
521
+ registerCanvasRoutes(router);
522
+ registerDomainRoutes(router);
523
+ registerSourceRoutes(router);
524
+ registerSessionRoutes(router);
525
+ registerWebhookRoutes(router);
526
+ }
527
+
528
+ // src/routes/sse.ts
529
+ function handleSSE(bridge, res) {
530
+ res.writeHead(200, {
531
+ "Content-Type": "text/event-stream",
532
+ "Cache-Control": "no-cache",
533
+ Connection: "keep-alive"
534
+ });
535
+ const send = (event, data) => {
536
+ res.write(`event: ${event}
537
+ data: ${JSON.stringify(data)}
538
+
539
+ `);
540
+ };
541
+ const poll = async () => {
542
+ const [statusR, agentsR, eventsR, canvasR] = await Promise.allSettled([
543
+ bridge.call("daemon.ping"),
544
+ bridge.call("agent.list"),
545
+ bridge.call("events.recent", { limit: 50 }),
546
+ bridge.call("canvas.list")
547
+ ]);
548
+ if (statusR.status === "fulfilled") {
549
+ send("status", statusR.value);
550
+ } else {
551
+ send("error", { message: "Daemon connection lost" });
552
+ return;
553
+ }
554
+ if (agentsR.status === "fulfilled") send("agents", agentsR.value);
555
+ if (eventsR.status === "fulfilled") send("events", eventsR.value);
556
+ else send("events", { events: [] });
557
+ if (canvasR.status === "fulfilled") send("canvas", canvasR.value);
558
+ };
559
+ poll();
560
+ const timer = setInterval(poll, 2e3);
561
+ res.on("close", () => {
562
+ clearInterval(timer);
563
+ });
564
+ }
565
+
566
+ // src/server.ts
567
+ function createApiHandler(config) {
568
+ const { bridge, apiKey } = config;
569
+ const router = new Router();
570
+ registerAllRoutes(router);
571
+ return async (req, res) => {
572
+ const url = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
573
+ const method = req.method ?? "GET";
574
+ const pathname = url.pathname;
575
+ applyCors(res);
576
+ if (handlePreflight(req, res)) return;
577
+ if (pathname !== "/v1/sse") {
578
+ const auth = checkAuth(req, apiKey);
579
+ if (!auth.ok) {
580
+ return error(res, auth.message ?? "Unauthorized", 401);
581
+ }
582
+ }
583
+ try {
584
+ if (pathname === "/v1/sse" || pathname === "/sse") {
585
+ return handleSSE(bridge, res);
586
+ }
587
+ if (pathname === "/" || pathname === "/v1") {
588
+ return json(res, {
589
+ name: "Actant REST API",
590
+ version: "v1",
591
+ docs: "/v1/openapi",
592
+ endpoints: {
593
+ status: "/v1/status",
594
+ agents: "/v1/agents",
595
+ templates: "/v1/templates",
596
+ events: "/v1/events",
597
+ canvas: "/v1/canvas",
598
+ skills: "/v1/skills",
599
+ prompts: "/v1/prompts",
600
+ mcpServers: "/v1/mcp-servers",
601
+ workflows: "/v1/workflows",
602
+ plugins: "/v1/plugins",
603
+ sources: "/v1/sources",
604
+ presets: "/v1/presets",
605
+ sessions: "/v1/sessions",
606
+ webhooks: "/v1/webhooks/message",
607
+ sse: "/v1/sse"
608
+ }
609
+ });
610
+ }
611
+ if (pathname === "/v1/openapi") {
612
+ return json(res, generateOpenApiSummary());
613
+ }
614
+ const body = method === "GET" || method === "HEAD" ? {} : await readBody(req);
615
+ const match = router.match(method, pathname);
616
+ if (!match) {
617
+ return error(res, `${method} ${pathname} not found`, 404);
618
+ }
619
+ await match.handler(
620
+ { bridge, params: match.params, query: url.searchParams, body },
621
+ req,
622
+ res
623
+ );
624
+ } catch (err) {
625
+ const message = err instanceof Error ? err.message : String(err);
626
+ const code = err.code;
627
+ let httpStatus = 500;
628
+ if (code) {
629
+ if (code === -32001 || code === -32003) httpStatus = 404;
630
+ else if (code === -32002 || code === -32602) httpStatus = 400;
631
+ else if (code === -32004 || code === -32009) httpStatus = 409;
632
+ else if (code === -32601) httpStatus = 404;
633
+ }
634
+ if (httpStatus === 500) {
635
+ const lower = message.toLowerCase();
636
+ if (/not found|does not exist|no such/.test(lower)) httpStatus = 404;
637
+ else if (/required|missing|invalid|must be|cannot be empty/.test(lower)) httpStatus = 400;
638
+ else if (/not running|no .* connection|already exists|no attached|has no/.test(lower)) httpStatus = 409;
639
+ else if (/not supported|not implemented/.test(lower)) httpStatus = 501;
640
+ }
641
+ error(res, message, httpStatus);
642
+ }
643
+ };
644
+ }
645
+ function generateOpenApiSummary() {
646
+ return {
647
+ openapi: "3.0.3",
648
+ info: {
649
+ title: "Actant REST API",
650
+ version: "1.0.0",
651
+ description: "RESTful API for the Actant AI agent platform. Serves dashboard, n8n, and IM integrations."
652
+ },
653
+ servers: [{ url: "/v1", description: "API v1" }],
654
+ paths: {
655
+ "/status": { get: { summary: "Daemon status", tags: ["System"] } },
656
+ "/shutdown": { post: { summary: "Shutdown daemon", tags: ["System"] } },
657
+ "/agents": {
658
+ get: { summary: "List all agents", tags: ["Agents"] },
659
+ post: { summary: "Create agent", tags: ["Agents"], requestBody: { required: true, content: { "application/json": { schema: { type: "object", required: ["name", "template"], properties: { name: { type: "string" }, template: { type: "string" }, overrides: { type: "object" } } } } } } }
660
+ },
661
+ "/agents/{name}": {
662
+ get: { summary: "Agent status", tags: ["Agents"] },
663
+ delete: { summary: "Destroy agent", tags: ["Agents"] }
664
+ },
665
+ "/agents/{name}/start": { post: { summary: "Start agent", tags: ["Agents"] } },
666
+ "/agents/{name}/stop": { post: { summary: "Stop agent", tags: ["Agents"] } },
667
+ "/agents/{name}/prompt": { post: { summary: "Send prompt", tags: ["Agents"], requestBody: { required: true, content: { "application/json": { schema: { type: "object", required: ["message"], properties: { message: { type: "string" }, sessionId: { type: "string" } } } } } } } },
668
+ "/agents/{name}/run": { post: { summary: "One-shot run", tags: ["Agents"] } },
669
+ "/agents/{name}/sessions": { get: { summary: "List conversation sessions", tags: ["Activity"] } },
670
+ "/agents/{name}/sessions/{sessionId}": { get: { summary: "Get conversation", tags: ["Activity"] } },
671
+ "/agents/{name}/logs": { get: { summary: "Process logs", tags: ["Activity"] } },
672
+ "/agents/{name}/tasks": { get: { summary: "Agent tasks", tags: ["Schedule"] } },
673
+ "/agents/{name}/schedule": { get: { summary: "Agent schedule", tags: ["Schedule"] } },
674
+ "/agents/{name}/permissions": { put: { summary: "Update permissions", tags: ["Agents"] } },
675
+ "/agents/{name}/dispatch": { post: { summary: "Dispatch task", tags: ["Schedule"] } },
676
+ "/agents/{name}/attach": { post: { summary: "Attach process", tags: ["Agents"] } },
677
+ "/agents/{name}/detach": { post: { summary: "Detach process", tags: ["Agents"] } },
678
+ "/templates": { get: { summary: "List templates", tags: ["Templates"] } },
679
+ "/templates/{name}": { get: { summary: "Get template", tags: ["Templates"] } },
680
+ "/templates/{name}/load": { post: { summary: "Load template", tags: ["Templates"] } },
681
+ "/templates/{name}/unload": { post: { summary: "Unload template", tags: ["Templates"] } },
682
+ "/templates/{name}/validate": { post: { summary: "Validate template", tags: ["Templates"] } },
683
+ "/events": { get: { summary: "Recent events", tags: ["Events"] } },
684
+ "/canvas": { get: { summary: "List canvas", tags: ["Canvas"] } },
685
+ "/canvas/{agentName}": {
686
+ get: { summary: "Get canvas", tags: ["Canvas"] },
687
+ post: { summary: "Update canvas", tags: ["Canvas"] },
688
+ delete: { summary: "Clear canvas", tags: ["Canvas"] }
689
+ },
690
+ "/skills": { get: { summary: "List skills", tags: ["Domain"] } },
691
+ "/skills/{name}": { get: { summary: "Get skill", tags: ["Domain"] } },
692
+ "/prompts": { get: { summary: "List prompts", tags: ["Domain"] } },
693
+ "/prompts/{name}": { get: { summary: "Get prompt", tags: ["Domain"] } },
694
+ "/mcp-servers": { get: { summary: "List MCP servers", tags: ["Domain"] } },
695
+ "/mcp-servers/{name}": { get: { summary: "Get MCP server", tags: ["Domain"] } },
696
+ "/workflows": { get: { summary: "List workflows", tags: ["Domain"] } },
697
+ "/workflows/{name}": { get: { summary: "Get workflow", tags: ["Domain"] } },
698
+ "/plugins": { get: { summary: "List plugins", tags: ["Domain"] } },
699
+ "/plugins/{name}": { get: { summary: "Get plugin", tags: ["Domain"] } },
700
+ "/sources": {
701
+ get: { summary: "List sources", tags: ["Sources"] },
702
+ post: { summary: "Add source", tags: ["Sources"] }
703
+ },
704
+ "/sources/{name}": { delete: { summary: "Remove source", tags: ["Sources"] } },
705
+ "/sources/{name}/sync": { post: { summary: "Sync source", tags: ["Sources"] } },
706
+ "/sources/{name}/validate": { post: { summary: "Validate source", tags: ["Sources"] } },
707
+ "/presets": { get: { summary: "List presets", tags: ["Sources"] } },
708
+ "/presets/{name}": { get: { summary: "Show preset", tags: ["Sources"] } },
709
+ "/presets/{name}/apply": { post: { summary: "Apply preset", tags: ["Sources"] } },
710
+ "/sessions": {
711
+ get: { summary: "List sessions", tags: ["Sessions"] },
712
+ post: { summary: "Create session", tags: ["Sessions"] }
713
+ },
714
+ "/sessions/{id}/prompt": { post: { summary: "Prompt session", tags: ["Sessions"] } },
715
+ "/sessions/{id}/cancel": { post: { summary: "Cancel session", tags: ["Sessions"] } },
716
+ "/sessions/{id}": { delete: { summary: "Close session", tags: ["Sessions"] } },
717
+ "/webhooks/message": { post: { summary: "Universal message webhook", tags: ["Webhooks"] } },
718
+ "/webhooks/run": { post: { summary: "One-shot run webhook", tags: ["Webhooks"] } },
719
+ "/webhooks/event": { post: { summary: "External event webhook", tags: ["Webhooks"] } },
720
+ "/sse": { get: { summary: "SSE real-time stream", tags: ["System"] } }
721
+ }
722
+ };
723
+ }
724
+
725
+ // src/rpc-bridge.ts
726
+ import { createConnection } from "net";
727
+ var requestId = 0;
728
+ var RpcBridge = class {
729
+ constructor(socketPath) {
730
+ this.socketPath = socketPath;
731
+ }
732
+ async call(method, params = {}) {
733
+ const id = ++requestId;
734
+ const request = { jsonrpc: "2.0", id, method, params };
735
+ const response = await this.send(request);
736
+ if (response.error) {
737
+ const err = new Error(response.error.message);
738
+ err.code = response.error.code;
739
+ err.data = response.error.data;
740
+ throw err;
741
+ }
742
+ return response.result;
743
+ }
744
+ async ping() {
745
+ try {
746
+ await this.call("daemon.ping");
747
+ return true;
748
+ } catch {
749
+ return false;
750
+ }
751
+ }
752
+ send(request) {
753
+ return new Promise((resolve, reject) => {
754
+ const socket = createConnection(this.socketPath, () => {
755
+ socket.write(JSON.stringify(request) + "\n");
756
+ });
757
+ let buffer = "";
758
+ socket.on("data", (chunk) => {
759
+ buffer += chunk.toString();
760
+ const lines = buffer.split("\n");
761
+ for (const line of lines) {
762
+ const trimmed = line.trim();
763
+ if (!trimmed) continue;
764
+ try {
765
+ const response = JSON.parse(trimmed);
766
+ socket.end();
767
+ resolve(response);
768
+ return;
769
+ } catch {
770
+ }
771
+ }
772
+ });
773
+ socket.on("error", (err) => {
774
+ reject(new Error(`Cannot connect to daemon at ${this.socketPath}: ${err.message}`));
775
+ });
776
+ socket.setTimeout(3e4, () => {
777
+ socket.destroy();
778
+ reject(new Error("RPC call timed out after 30s"));
779
+ });
780
+ });
781
+ }
782
+ };
783
+
784
+ // src/index.ts
785
+ var logger = createLogger("rest-api");
786
+ async function startApiServer(options) {
787
+ const port = options.port ?? 3100;
788
+ const host = options.host ?? "0.0.0.0";
789
+ const bridge = new RpcBridge(options.socketPath);
790
+ const alive = await bridge.ping();
791
+ if (!alive) {
792
+ throw new Error("Cannot connect to Actant daemon. Is it running?");
793
+ }
794
+ const handler = createApiHandler({
795
+ bridge,
796
+ apiKey: options.apiKey
797
+ });
798
+ const server = createServer(handler);
799
+ return new Promise((resolve) => {
800
+ server.listen(port, host, () => {
801
+ const url = `http://${host === "0.0.0.0" ? "localhost" : host}:${port}`;
802
+ logger.info({ port, host, url, auth: !!options.apiKey }, "REST API server started");
803
+ logger.info(`Actant REST API: ${url}`);
804
+ logger.info(`OpenAPI spec: ${url}/v1/openapi`);
805
+ logger.info(`SSE stream: ${url}/v1/sse`);
806
+ if (options.apiKey) {
807
+ logger.info("Auth: API key required (X-API-Key header)");
808
+ }
809
+ const signals = ["SIGINT", "SIGTERM"];
810
+ for (const sig of signals) {
811
+ process.on(sig, () => {
812
+ server.close();
813
+ process.exit(0);
814
+ });
815
+ }
816
+ resolve({
817
+ url,
818
+ close: () => server.close()
819
+ });
820
+ });
821
+ });
822
+ }
823
+ export {
824
+ Router,
825
+ RpcBridge,
826
+ createApiHandler,
827
+ startApiServer
828
+ };
829
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/router.ts","../src/middleware.ts","../src/routes/agents.ts","../src/routes/templates.ts","../src/routes/events.ts","../src/routes/canvas.ts","../src/routes/status.ts","../src/routes/domain.ts","../src/routes/sources.ts","../src/routes/sessions.ts","../src/routes/webhooks.ts","../src/routes/index.ts","../src/routes/sse.ts","../src/server.ts","../src/rpc-bridge.ts"],"sourcesContent":["import { createServer } from \"node:http\";\nimport { createLogger } from \"@actant/shared\";\nimport { createApiHandler } from \"./server\";\nimport { RpcBridge } from \"./rpc-bridge\";\n\nexport { createApiHandler, type ServerConfig } from \"./server\";\nexport { RpcBridge } from \"./rpc-bridge\";\nexport { Router } from \"./router\";\n\nconst logger = createLogger(\"rest-api\");\n\nexport interface ApiServerOptions {\n port?: number;\n host?: string;\n socketPath: string;\n apiKey?: string;\n open?: boolean;\n}\n\nexport async function startApiServer(options: ApiServerOptions): Promise<{\n url: string;\n close: () => void;\n}> {\n const port = options.port ?? 3100;\n const host = options.host ?? \"0.0.0.0\";\n const bridge = new RpcBridge(options.socketPath);\n\n const alive = await bridge.ping();\n if (!alive) {\n throw new Error(\"Cannot connect to Actant daemon. Is it running?\");\n }\n\n const handler = createApiHandler({\n bridge,\n apiKey: options.apiKey,\n });\n const server = createServer(handler);\n\n return new Promise((resolve) => {\n server.listen(port, host, () => {\n const url = `http://${host === \"0.0.0.0\" ? \"localhost\" : host}:${port}`;\n logger.info({ port, host, url, auth: !!options.apiKey }, \"REST API server started\");\n logger.info(`Actant REST API: ${url}`);\n logger.info(`OpenAPI spec: ${url}/v1/openapi`);\n logger.info(`SSE stream: ${url}/v1/sse`);\n if (options.apiKey) {\n logger.info(\"Auth: API key required (X-API-Key header)\");\n }\n\n // Graceful shutdown\n const signals: NodeJS.Signals[] = [\"SIGINT\", \"SIGTERM\"];\n for (const sig of signals) {\n process.on(sig, () => {\n server.close();\n process.exit(0);\n });\n }\n\n resolve({\n url,\n close: () => server.close(),\n });\n });\n });\n}\n","import type { IncomingMessage, ServerResponse } from \"node:http\";\nimport type { RpcBridge } from \"./rpc-bridge\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface RouteContext {\n bridge: RpcBridge;\n params: Record<string, string>;\n query: URLSearchParams;\n body: Record<string, unknown>;\n}\n\nexport type RouteHandler = (ctx: RouteContext, req: IncomingMessage, res: ServerResponse) => Promise<void>;\n\ninterface RouteEntry {\n method: string;\n pattern: string;\n segments: string[];\n handler: RouteHandler;\n}\n\n// ---------------------------------------------------------------------------\n// Router\n// ---------------------------------------------------------------------------\n\nexport class Router {\n private routes: RouteEntry[] = [];\n\n get(pattern: string, handler: RouteHandler): void {\n this.add(\"GET\", pattern, handler);\n }\n\n post(pattern: string, handler: RouteHandler): void {\n this.add(\"POST\", pattern, handler);\n }\n\n put(pattern: string, handler: RouteHandler): void {\n this.add(\"PUT\", pattern, handler);\n }\n\n delete(pattern: string, handler: RouteHandler): void {\n this.add(\"DELETE\", pattern, handler);\n }\n\n private add(method: string, pattern: string, handler: RouteHandler): void {\n this.routes.push({\n method,\n pattern,\n segments: pattern.split(\"/\").filter(Boolean),\n handler,\n });\n }\n\n match(method: string, pathname: string): { handler: RouteHandler; params: Record<string, string> } | null {\n const parts = pathname.split(\"/\").filter(Boolean);\n\n for (const route of this.routes) {\n if (route.method !== method) continue;\n const params = matchSegments(route.segments, parts);\n if (params) return { handler: route.handler, params };\n }\n return null;\n }\n}\n\nfunction matchSegments(\n pattern: string[],\n actual: string[],\n): Record<string, string> | null {\n if (pattern.length !== actual.length) return null;\n const params: Record<string, string> = {};\n\n for (let i = 0; i < pattern.length; i++) {\n const seg = pattern[i];\n const val = actual[i];\n if (!seg || !val) return null;\n if (seg.startsWith(\":\")) {\n params[seg.slice(1)] = decodeURIComponent(val);\n } else if (seg !== val) {\n return null;\n }\n }\n return params;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nexport function json(res: ServerResponse, data: unknown, status = 200): void {\n res.writeHead(status, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(data));\n}\n\nexport function error(res: ServerResponse, message: string, status = 500): void {\n json(res, { error: message, status }, status);\n}\n\nexport function readBody(req: IncomingMessage): Promise<Record<string, unknown>> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n req.on(\"data\", (c: Buffer) => chunks.push(c));\n req.on(\"end\", () => {\n const raw = Buffer.concat(chunks).toString(\"utf-8\");\n try {\n resolve(raw ? JSON.parse(raw) : {});\n } catch {\n resolve({});\n }\n });\n req.on(\"error\", reject);\n });\n}\n","import type { IncomingMessage, ServerResponse } from \"node:http\";\n\n// ---------------------------------------------------------------------------\n// CORS\n// ---------------------------------------------------------------------------\n\nexport function applyCors(res: ServerResponse, origin = \"*\"): void {\n res.setHeader(\"Access-Control-Allow-Origin\", origin);\n res.setHeader(\"Access-Control-Allow-Methods\", \"GET, POST, PUT, DELETE, OPTIONS\");\n res.setHeader(\"Access-Control-Allow-Headers\", \"Content-Type, Authorization, X-API-Key\");\n res.setHeader(\"Access-Control-Max-Age\", \"86400\");\n}\n\nexport function handlePreflight(req: IncomingMessage, res: ServerResponse): boolean {\n if (req.method === \"OPTIONS\") {\n applyCors(res);\n res.writeHead(204);\n res.end();\n return true;\n }\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// API Key Auth (optional — skipped when no key configured)\n// ---------------------------------------------------------------------------\n\nexport function checkAuth(\n req: IncomingMessage,\n apiKey: string | undefined,\n): { ok: boolean; message?: string } {\n if (!apiKey) return { ok: true };\n\n const header = req.headers[\"authorization\"] ?? req.headers[\"x-api-key\"];\n if (!header) {\n return { ok: false, message: \"Missing API key. Set Authorization: Bearer <key> or X-API-Key header.\" };\n }\n\n const token = typeof header === \"string\"\n ? header.replace(/^Bearer\\s+/i, \"\").trim()\n : \"\";\n\n if (token !== apiKey) {\n return { ok: false, message: \"Invalid API key.\" };\n }\n\n return { ok: true };\n}\n","import type { Router } from \"../router\";\nimport { json, error } from \"../router\";\n\nexport function registerAgentRoutes(router: Router): void {\n // -----------------------------------------------------------------------\n // GET /v1/agents — List all agents\n // -----------------------------------------------------------------------\n router.get(\"/v1/agents\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"agent.list\");\n json(res, result);\n });\n\n // -----------------------------------------------------------------------\n // POST /v1/agents — Create a new agent\n // Body: { name, template, overrides? }\n // -----------------------------------------------------------------------\n router.post(\"/v1/agents\", async (ctx, _req, res) => {\n const { name, template, overrides } = ctx.body;\n if (!name || !template) {\n return error(res, \"name and template are required\", 400);\n }\n const result = await ctx.bridge.call(\"agent.create\", {\n name,\n template,\n ...(overrides ? { overrides } : {}),\n });\n json(res, result, 201);\n });\n\n // -----------------------------------------------------------------------\n // GET /v1/agents/:name — Agent status / details\n // -----------------------------------------------------------------------\n router.get(\"/v1/agents/:name\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"agent.status\", { name: ctx.params.name });\n json(res, result);\n });\n\n // -----------------------------------------------------------------------\n // DELETE /v1/agents/:name — Destroy an agent\n // Query: ?force=true\n // -----------------------------------------------------------------------\n router.delete(\"/v1/agents/:name\", async (ctx, _req, res) => {\n const force = ctx.query.get(\"force\") === \"true\";\n const result = await ctx.bridge.call(\"agent.destroy\", { name: ctx.params.name, force });\n json(res, result);\n });\n\n // -----------------------------------------------------------------------\n // POST /v1/agents/:name/start — Start an agent\n // -----------------------------------------------------------------------\n router.post(\"/v1/agents/:name/start\", async (ctx, _req, res) => {\n const autoInstall = ctx.body.autoInstall as boolean | undefined;\n const result = await ctx.bridge.call(\"agent.start\", {\n name: ctx.params.name,\n ...(autoInstall != null ? { autoInstall } : {}),\n });\n json(res, result);\n });\n\n // -----------------------------------------------------------------------\n // POST /v1/agents/:name/stop — Stop an agent\n // -----------------------------------------------------------------------\n router.post(\"/v1/agents/:name/stop\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"agent.stop\", { name: ctx.params.name });\n json(res, result);\n });\n\n // -----------------------------------------------------------------------\n // POST /v1/agents/:name/prompt — Send a prompt to an agent\n // Body: { message, sessionId? }\n // -----------------------------------------------------------------------\n router.post(\"/v1/agents/:name/prompt\", async (ctx, _req, res) => {\n const { message, sessionId } = ctx.body;\n if (!message) {\n return error(res, \"message is required\", 400);\n }\n const result = await ctx.bridge.call(\"agent.prompt\", {\n name: ctx.params.name,\n message,\n ...(sessionId ? { sessionId } : {}),\n });\n json(res, result);\n });\n\n // -----------------------------------------------------------------------\n // POST /v1/agents/:name/run — Run a one-shot prompt (fire-and-wait)\n // Body: { prompt, options? }\n // -----------------------------------------------------------------------\n router.post(\"/v1/agents/:name/run\", async (ctx, _req, res) => {\n const { prompt, options } = ctx.body;\n if (!prompt) {\n return error(res, \"prompt is required\", 400);\n }\n const result = await ctx.bridge.call(\"agent.run\", {\n name: ctx.params.name,\n prompt,\n ...(options ? { options } : {}),\n });\n json(res, result);\n });\n\n // -----------------------------------------------------------------------\n // POST /v1/agents/:name/dispatch — Dispatch a scheduled task\n // Body: { prompt }\n // -----------------------------------------------------------------------\n router.post(\"/v1/agents/:name/dispatch\", async (ctx, _req, res) => {\n const { prompt } = ctx.body;\n if (!prompt) {\n return error(res, \"prompt is required\", 400);\n }\n const result = await ctx.bridge.call(\"agent.dispatch\", {\n name: ctx.params.name,\n prompt,\n });\n json(res, result);\n });\n\n // -----------------------------------------------------------------------\n // PUT /v1/agents/:name/permissions — Update agent permissions\n // Body: { permissions }\n // -----------------------------------------------------------------------\n router.put(\"/v1/agents/:name/permissions\", async (ctx, _req, res) => {\n const { permissions } = ctx.body;\n if (!permissions) {\n return error(res, \"permissions object is required\", 400);\n }\n const result = await ctx.bridge.call(\"agent.updatePermissions\", {\n name: ctx.params.name,\n permissions,\n });\n json(res, result);\n });\n\n // -----------------------------------------------------------------------\n // GET /v1/agents/:name/sessions — List conversation sessions\n // -----------------------------------------------------------------------\n router.get(\"/v1/agents/:name/sessions\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"activity.sessions\", { agentName: ctx.params.name });\n json(res, result);\n });\n\n // -----------------------------------------------------------------------\n // GET /v1/agents/:name/sessions/:sessionId — Get conversation turns\n // -----------------------------------------------------------------------\n router.get(\"/v1/agents/:name/sessions/:sessionId\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"activity.conversation\", {\n agentName: ctx.params.name,\n sessionId: ctx.params.sessionId,\n });\n json(res, result);\n });\n\n // -----------------------------------------------------------------------\n // GET /v1/agents/:name/logs — Get process logs\n // Query: ?stream=stdout|stderr&lines=100\n // -----------------------------------------------------------------------\n router.get(\"/v1/agents/:name/logs\", async (ctx, _req, res) => {\n const stream = ctx.query.get(\"stream\") ?? \"stdout\";\n const lines = parseInt(ctx.query.get(\"lines\") ?? \"200\", 10);\n try {\n const result = await ctx.bridge.call(\"agent.processLogs\", {\n name: ctx.params.name,\n stream,\n lines,\n });\n json(res, result);\n } catch {\n json(res, { lines: [], stream, logDir: \"\" });\n }\n });\n\n // -----------------------------------------------------------------------\n // GET /v1/agents/:name/tasks — Get agent tasks (schedule)\n // -----------------------------------------------------------------------\n router.get(\"/v1/agents/:name/tasks\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"agent.tasks\", { name: ctx.params.name });\n json(res, result);\n });\n\n // -----------------------------------------------------------------------\n // GET /v1/agents/:name/schedule — Get agent schedule config\n // -----------------------------------------------------------------------\n router.get(\"/v1/agents/:name/schedule\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"schedule.list\", { name: ctx.params.name });\n json(res, result);\n });\n\n // -----------------------------------------------------------------------\n // POST /v1/agents/:name/attach — Attach a running process\n // Body: { pid, metadata? }\n // -----------------------------------------------------------------------\n router.post(\"/v1/agents/:name/attach\", async (ctx, _req, res) => {\n const { pid, metadata } = ctx.body;\n if (!pid) {\n return error(res, \"pid is required\", 400);\n }\n const result = await ctx.bridge.call(\"agent.attach\", {\n name: ctx.params.name,\n pid,\n ...(metadata ? { metadata } : {}),\n });\n json(res, result);\n });\n\n // -----------------------------------------------------------------------\n // POST /v1/agents/:name/detach — Detach process\n // Body: { cleanup? }\n // -----------------------------------------------------------------------\n router.post(\"/v1/agents/:name/detach\", async (ctx, _req, res) => {\n const { cleanup } = ctx.body;\n const result = await ctx.bridge.call(\"agent.detach\", {\n name: ctx.params.name,\n ...(cleanup != null ? { cleanup } : {}),\n });\n json(res, result);\n });\n}\n","import type { Router } from \"../router\";\nimport { json } from \"../router\";\n\nexport function registerTemplateRoutes(router: Router): void {\n router.get(\"/v1/templates\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"template.list\");\n json(res, result);\n });\n\n router.get(\"/v1/templates/:name\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"template.get\", { name: ctx.params.name });\n json(res, result);\n });\n\n router.post(\"/v1/templates/:name/load\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"template.load\", { name: ctx.params.name });\n json(res, result);\n });\n\n router.post(\"/v1/templates/:name/unload\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"template.unload\", { name: ctx.params.name });\n json(res, result);\n });\n\n router.post(\"/v1/templates/:name/validate\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"template.validate\", { name: ctx.params.name });\n json(res, result);\n });\n}\n","import type { Router } from \"../router\";\nimport { json } from \"../router\";\n\nexport function registerEventRoutes(router: Router): void {\n router.get(\"/v1/events\", async (ctx, _req, res) => {\n const limit = parseInt(ctx.query.get(\"limit\") ?? \"50\", 10);\n try {\n const result = await ctx.bridge.call(\"events.recent\", { limit });\n json(res, result);\n } catch {\n json(res, { events: [] });\n }\n });\n}\n","import type { Router } from \"../router\";\nimport { json, error } from \"../router\";\n\nexport function registerCanvasRoutes(router: Router): void {\n // GET /v1/canvas — List all canvas entries\n router.get(\"/v1/canvas\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"canvas.list\");\n json(res, result);\n });\n\n // GET /v1/canvas/:agentName — Get canvas for a specific agent\n router.get(\"/v1/canvas/:agentName\", async (ctx, _req, res) => {\n try {\n const result = await ctx.bridge.call(\"canvas.get\", { agentName: ctx.params.agentName });\n json(res, result);\n } catch {\n error(res, `No canvas for agent \"${ctx.params.agentName}\"`, 404);\n }\n });\n\n // POST /v1/canvas/:agentName — Update canvas (used by MCP tools)\n router.post(\"/v1/canvas/:agentName\", async (ctx, _req, res) => {\n const { html, title } = ctx.body;\n if (!html) {\n return error(res, \"html is required\", 400);\n }\n const result = await ctx.bridge.call(\"canvas.update\", {\n agentName: ctx.params.agentName,\n html,\n ...(title ? { title } : {}),\n });\n json(res, result);\n });\n\n // DELETE /v1/canvas/:agentName — Clear canvas\n router.delete(\"/v1/canvas/:agentName\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"canvas.clear\", { agentName: ctx.params.agentName });\n json(res, result);\n });\n}\n","import type { Router } from \"../router\";\nimport { json } from \"../router\";\n\nexport function registerStatusRoutes(router: Router): void {\n // GET /v1/status — Daemon status (ping)\n router.get(\"/v1/status\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"daemon.ping\");\n json(res, result);\n });\n\n // POST /v1/shutdown — Graceful daemon shutdown\n router.post(\"/v1/shutdown\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"daemon.shutdown\");\n json(res, result);\n });\n}\n","import type { Router } from \"../router\";\nimport { json } from \"../router\";\n\nexport function registerDomainRoutes(router: Router): void {\n // -----------------------------------------------------------------------\n // Skills\n // -----------------------------------------------------------------------\n router.get(\"/v1/skills\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"skill.list\");\n json(res, result);\n });\n\n router.get(\"/v1/skills/:name\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"skill.get\", { name: ctx.params.name });\n json(res, result);\n });\n\n // -----------------------------------------------------------------------\n // Prompts\n // -----------------------------------------------------------------------\n router.get(\"/v1/prompts\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"prompt.list\");\n json(res, result);\n });\n\n router.get(\"/v1/prompts/:name\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"prompt.get\", { name: ctx.params.name });\n json(res, result);\n });\n\n // -----------------------------------------------------------------------\n // MCP Servers\n // -----------------------------------------------------------------------\n router.get(\"/v1/mcp-servers\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"mcp.list\");\n json(res, result);\n });\n\n router.get(\"/v1/mcp-servers/:name\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"mcp.get\", { name: ctx.params.name });\n json(res, result);\n });\n\n // -----------------------------------------------------------------------\n // Workflows\n // -----------------------------------------------------------------------\n router.get(\"/v1/workflows\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"workflow.list\");\n json(res, result);\n });\n\n router.get(\"/v1/workflows/:name\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"workflow.get\", { name: ctx.params.name });\n json(res, result);\n });\n\n // -----------------------------------------------------------------------\n // Plugins\n // -----------------------------------------------------------------------\n router.get(\"/v1/plugins\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"plugin.list\");\n json(res, result);\n });\n\n router.get(\"/v1/plugins/:name\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"plugin.get\", { name: ctx.params.name });\n json(res, result);\n });\n}\n","import type { Router } from \"../router\";\nimport { json } from \"../router\";\n\nexport function registerSourceRoutes(router: Router): void {\n router.get(\"/v1/sources\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"source.list\");\n json(res, result);\n });\n\n router.post(\"/v1/sources\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"source.add\", ctx.body);\n json(res, result, 201);\n });\n\n router.delete(\"/v1/sources/:name\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"source.remove\", { name: ctx.params.name });\n json(res, result);\n });\n\n router.post(\"/v1/sources/:name/sync\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"source.sync\", { name: ctx.params.name });\n json(res, result);\n });\n\n router.post(\"/v1/sources/:name/validate\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"source.validate\", { name: ctx.params.name });\n json(res, result);\n });\n\n router.get(\"/v1/presets\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"preset.list\");\n json(res, result);\n });\n\n router.get(\"/v1/presets/:name\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"preset.show\", { name: ctx.params.name });\n json(res, result);\n });\n\n router.post(\"/v1/presets/:name/apply\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"preset.apply\", { name: ctx.params.name, ...ctx.body });\n json(res, result);\n });\n}\n","import type { Router } from \"../router\";\nimport { json, error } from \"../router\";\nimport { URL } from \"node:url\";\n\nexport function registerSessionRoutes(router: Router): void {\n router.get(\"/v1/sessions\", async (ctx, req, res) => {\n const url = new URL(req.url ?? \"\", `http://${req.headers.host}`);\n const agentName = url.searchParams.get(\"agentName\") ?? undefined;\n const result = await ctx.bridge.call(\"session.list\", { agentName });\n json(res, result);\n });\n\n router.post(\"/v1/sessions\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"session.create\", ctx.body);\n json(res, result, 201);\n });\n\n router.post(\"/v1/sessions/:id/prompt\", async (ctx, _req, res) => {\n const { message } = ctx.body;\n if (!message) {\n return error(res, \"message is required\", 400);\n }\n const result = await ctx.bridge.call(\"session.prompt\", {\n sessionId: ctx.params.id,\n text: message,\n });\n json(res, result);\n });\n\n router.post(\"/v1/sessions/:id/cancel\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"session.cancel\", { sessionId: ctx.params.id });\n json(res, result);\n });\n\n router.delete(\"/v1/sessions/:id\", async (ctx, _req, res) => {\n const result = await ctx.bridge.call(\"session.close\", { sessionId: ctx.params.id });\n json(res, result);\n });\n}\n","import type { Router } from \"../router\";\nimport { json, error } from \"../router\";\n\n/**\n * Webhook endpoints for external integrations (n8n, Slack, Discord, WeChat, etc.)\n *\n * These provide simplified interfaces that map to internal agent operations,\n * designed for easy HTTP-based automation without needing to know agent internals.\n */\nexport function registerWebhookRoutes(router: Router): void {\n // -----------------------------------------------------------------------\n // POST /v1/webhooks/message — Universal message ingress\n //\n // Accepts a message and routes it to a named agent.\n // Designed for n8n HTTP Request nodes, Slack slash commands, etc.\n //\n // Body: { agent, message, metadata? }\n // Returns: { response, sessionId, agent }\n // -----------------------------------------------------------------------\n router.post(\"/v1/webhooks/message\", async (ctx, _req, res) => {\n const { agent, message, metadata } = ctx.body;\n if (!agent || !message) {\n return error(res, \"agent and message are required\", 400);\n }\n\n const agentName = String(agent);\n const text = String(message);\n\n try {\n const result = await ctx.bridge.call(\"agent.prompt\", {\n name: agentName,\n message: text,\n }) as { response: string; sessionId: string };\n\n json(res, {\n agent: agentName,\n response: result.response,\n sessionId: result.sessionId,\n ...(metadata ? { metadata } : {}),\n });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n error(res, `Agent \"${agentName}\" error: ${msg}`, 502);\n }\n });\n\n // -----------------------------------------------------------------------\n // POST /v1/webhooks/run — Fire-and-wait one-shot prompt\n //\n // Like /message but uses agent.run (creates + starts agent if needed).\n // Body: { agent, prompt, template? }\n // -----------------------------------------------------------------------\n router.post(\"/v1/webhooks/run\", async (ctx, _req, res) => {\n const { agent, prompt, template } = ctx.body;\n if (!agent || !prompt) {\n return error(res, \"agent and prompt are required\", 400);\n }\n\n const agentName = String(agent);\n const promptText = String(prompt);\n\n const RUN_TIMEOUT_MS = 120_000;\n try {\n const rpcPromise = ctx.bridge.call(\"agent.run\", {\n name: agentName,\n prompt: promptText,\n ...(template ? { template: String(template) } : {}),\n }) as Promise<{ text: string; sessionId?: string }>;\n\n const timeoutPromise = new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error(\"agent.run timed out after 120s\")), RUN_TIMEOUT_MS),\n );\n\n const result = await Promise.race([rpcPromise, timeoutPromise]);\n\n json(res, {\n agent: agentName,\n response: result.text,\n sessionId: result.sessionId ?? null,\n });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n error(res, `Agent \"${agentName}\" error: ${msg}`, 502);\n }\n });\n\n // -----------------------------------------------------------------------\n // POST /v1/webhooks/event — Receive external events\n //\n // Allows external systems to inject events into the EventBus.\n // Can be used to trigger hook-based agent workflows.\n // Body: { event, agentName?, payload? }\n // -----------------------------------------------------------------------\n router.post(\"/v1/webhooks/event\", async (ctx, _req, res) => {\n const { event, agentName, payload } = ctx.body;\n if (!event) {\n return error(res, \"event is required\", 400);\n }\n if (!agentName) {\n return error(res, \"agentName is required for event routing\", 400);\n }\n\n try {\n const result = await ctx.bridge.call(\"gateway.lease\", {\n event: String(event),\n agentName: String(agentName),\n ...(payload ? { payload } : {}),\n });\n json(res, result);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n error(res, msg, 502);\n }\n });\n}\n","import type { Router } from \"../router\";\nimport { registerAgentRoutes } from \"./agents\";\nimport { registerTemplateRoutes } from \"./templates\";\nimport { registerEventRoutes } from \"./events\";\nimport { registerCanvasRoutes } from \"./canvas\";\nimport { registerStatusRoutes } from \"./status\";\nimport { registerDomainRoutes } from \"./domain\";\nimport { registerSourceRoutes } from \"./sources\";\nimport { registerSessionRoutes } from \"./sessions\";\nimport { registerWebhookRoutes } from \"./webhooks\";\n\nexport function registerAllRoutes(router: Router): void {\n registerStatusRoutes(router);\n registerAgentRoutes(router);\n registerTemplateRoutes(router);\n registerEventRoutes(router);\n registerCanvasRoutes(router);\n registerDomainRoutes(router);\n registerSourceRoutes(router);\n registerSessionRoutes(router);\n registerWebhookRoutes(router);\n}\n","import type { ServerResponse } from \"node:http\";\nimport type { RpcBridge } from \"../rpc-bridge\";\n\nexport function handleSSE(bridge: RpcBridge, res: ServerResponse): void {\n res.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n });\n\n const send = (event: string, data: unknown) => {\n res.write(`event: ${event}\\ndata: ${JSON.stringify(data)}\\n\\n`);\n };\n\n const poll = async () => {\n const [statusR, agentsR, eventsR, canvasR] = await Promise.allSettled([\n bridge.call(\"daemon.ping\"),\n bridge.call(\"agent.list\"),\n bridge.call(\"events.recent\", { limit: 50 }),\n bridge.call(\"canvas.list\"),\n ]);\n\n if (statusR.status === \"fulfilled\") {\n send(\"status\", statusR.value);\n } else {\n send(\"error\", { message: \"Daemon connection lost\" });\n return;\n }\n\n if (agentsR.status === \"fulfilled\") send(\"agents\", agentsR.value);\n if (eventsR.status === \"fulfilled\") send(\"events\", eventsR.value);\n else send(\"events\", { events: [] });\n if (canvasR.status === \"fulfilled\") send(\"canvas\", canvasR.value);\n };\n\n poll();\n const timer = setInterval(poll, 2000);\n\n res.on(\"close\", () => {\n clearInterval(timer);\n });\n}\n","import type { IncomingMessage, ServerResponse, RequestListener } from \"node:http\";\nimport { Router, readBody, json, error } from \"./router\";\nimport type { RpcBridge } from \"./rpc-bridge\";\nimport { applyCors, handlePreflight, checkAuth } from \"./middleware\";\nimport { registerAllRoutes } from \"./routes/index\";\nimport { handleSSE } from \"./routes/sse\";\n\nexport interface ServerConfig {\n bridge: RpcBridge;\n apiKey?: string;\n}\n\nexport function createApiHandler(config: ServerConfig): RequestListener {\n const { bridge, apiKey } = config;\n const router = new Router();\n registerAllRoutes(router);\n\n return async (req: IncomingMessage, res: ServerResponse) => {\n const url = new URL(req.url ?? \"/\", `http://${req.headers.host ?? \"localhost\"}`);\n const method = req.method ?? \"GET\";\n const pathname = url.pathname;\n\n applyCors(res);\n\n if (handlePreflight(req, res)) return;\n\n // Auth check (skip for SSE — browsers can't set headers on EventSource)\n if (pathname !== \"/v1/sse\") {\n const auth = checkAuth(req, apiKey);\n if (!auth.ok) {\n return error(res, auth.message ?? \"Unauthorized\", 401);\n }\n }\n\n try {\n // SSE endpoint\n if (pathname === \"/v1/sse\" || pathname === \"/sse\") {\n return handleSSE(bridge, res);\n }\n\n // Discovery endpoint\n if (pathname === \"/\" || pathname === \"/v1\") {\n return json(res, {\n name: \"Actant REST API\",\n version: \"v1\",\n docs: \"/v1/openapi\",\n endpoints: {\n status: \"/v1/status\",\n agents: \"/v1/agents\",\n templates: \"/v1/templates\",\n events: \"/v1/events\",\n canvas: \"/v1/canvas\",\n skills: \"/v1/skills\",\n prompts: \"/v1/prompts\",\n mcpServers: \"/v1/mcp-servers\",\n workflows: \"/v1/workflows\",\n plugins: \"/v1/plugins\",\n sources: \"/v1/sources\",\n presets: \"/v1/presets\",\n sessions: \"/v1/sessions\",\n webhooks: \"/v1/webhooks/message\",\n sse: \"/v1/sse\",\n },\n });\n }\n\n // OpenAPI spec (minimal self-describing)\n if (pathname === \"/v1/openapi\") {\n return json(res, generateOpenApiSummary());\n }\n\n // Route matching\n const body = method === \"GET\" || method === \"HEAD\" ? {} : await readBody(req);\n const match = router.match(method, pathname);\n\n if (!match) {\n return error(res, `${method} ${pathname} not found`, 404);\n }\n\n await match.handler(\n { bridge, params: match.params, query: url.searchParams, body },\n req,\n res,\n );\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n const code = (err as { code?: number }).code;\n\n // Map RPC error codes to HTTP status\n let httpStatus = 500;\n if (code) {\n if (code === -32001 || code === -32003) httpStatus = 404;\n else if (code === -32002 || code === -32602) httpStatus = 400;\n else if (code === -32004 || code === -32009) httpStatus = 409;\n else if (code === -32601) httpStatus = 404;\n }\n\n // Fallback: infer HTTP status from error message patterns when no RPC code\n if (httpStatus === 500) {\n const lower = message.toLowerCase();\n if (/not found|does not exist|no such/.test(lower)) httpStatus = 404;\n else if (/required|missing|invalid|must be|cannot be empty/.test(lower)) httpStatus = 400;\n else if (/not running|no .* connection|already exists|no attached|has no/.test(lower)) httpStatus = 409;\n else if (/not supported|not implemented/.test(lower)) httpStatus = 501;\n }\n\n error(res, message, httpStatus);\n }\n };\n}\n\nfunction generateOpenApiSummary(): object {\n return {\n openapi: \"3.0.3\",\n info: {\n title: \"Actant REST API\",\n version: \"1.0.0\",\n description: \"RESTful API for the Actant AI agent platform. Serves dashboard, n8n, and IM integrations.\",\n },\n servers: [{ url: \"/v1\", description: \"API v1\" }],\n paths: {\n \"/status\": { get: { summary: \"Daemon status\", tags: [\"System\"] } },\n \"/shutdown\": { post: { summary: \"Shutdown daemon\", tags: [\"System\"] } },\n \"/agents\": {\n get: { summary: \"List all agents\", tags: [\"Agents\"] },\n post: { summary: \"Create agent\", tags: [\"Agents\"], requestBody: { required: true, content: { \"application/json\": { schema: { type: \"object\", required: [\"name\", \"template\"], properties: { name: { type: \"string\" }, template: { type: \"string\" }, overrides: { type: \"object\" } } } } } } },\n },\n \"/agents/{name}\": {\n get: { summary: \"Agent status\", tags: [\"Agents\"] },\n delete: { summary: \"Destroy agent\", tags: [\"Agents\"] },\n },\n \"/agents/{name}/start\": { post: { summary: \"Start agent\", tags: [\"Agents\"] } },\n \"/agents/{name}/stop\": { post: { summary: \"Stop agent\", tags: [\"Agents\"] } },\n \"/agents/{name}/prompt\": { post: { summary: \"Send prompt\", tags: [\"Agents\"], requestBody: { required: true, content: { \"application/json\": { schema: { type: \"object\", required: [\"message\"], properties: { message: { type: \"string\" }, sessionId: { type: \"string\" } } } } } } } },\n \"/agents/{name}/run\": { post: { summary: \"One-shot run\", tags: [\"Agents\"] } },\n \"/agents/{name}/sessions\": { get: { summary: \"List conversation sessions\", tags: [\"Activity\"] } },\n \"/agents/{name}/sessions/{sessionId}\": { get: { summary: \"Get conversation\", tags: [\"Activity\"] } },\n \"/agents/{name}/logs\": { get: { summary: \"Process logs\", tags: [\"Activity\"] } },\n \"/agents/{name}/tasks\": { get: { summary: \"Agent tasks\", tags: [\"Schedule\"] } },\n \"/agents/{name}/schedule\": { get: { summary: \"Agent schedule\", tags: [\"Schedule\"] } },\n \"/agents/{name}/permissions\": { put: { summary: \"Update permissions\", tags: [\"Agents\"] } },\n \"/agents/{name}/dispatch\": { post: { summary: \"Dispatch task\", tags: [\"Schedule\"] } },\n \"/agents/{name}/attach\": { post: { summary: \"Attach process\", tags: [\"Agents\"] } },\n \"/agents/{name}/detach\": { post: { summary: \"Detach process\", tags: [\"Agents\"] } },\n \"/templates\": { get: { summary: \"List templates\", tags: [\"Templates\"] } },\n \"/templates/{name}\": { get: { summary: \"Get template\", tags: [\"Templates\"] } },\n \"/templates/{name}/load\": { post: { summary: \"Load template\", tags: [\"Templates\"] } },\n \"/templates/{name}/unload\": { post: { summary: \"Unload template\", tags: [\"Templates\"] } },\n \"/templates/{name}/validate\": { post: { summary: \"Validate template\", tags: [\"Templates\"] } },\n \"/events\": { get: { summary: \"Recent events\", tags: [\"Events\"] } },\n \"/canvas\": { get: { summary: \"List canvas\", tags: [\"Canvas\"] } },\n \"/canvas/{agentName}\": {\n get: { summary: \"Get canvas\", tags: [\"Canvas\"] },\n post: { summary: \"Update canvas\", tags: [\"Canvas\"] },\n delete: { summary: \"Clear canvas\", tags: [\"Canvas\"] },\n },\n \"/skills\": { get: { summary: \"List skills\", tags: [\"Domain\"] } },\n \"/skills/{name}\": { get: { summary: \"Get skill\", tags: [\"Domain\"] } },\n \"/prompts\": { get: { summary: \"List prompts\", tags: [\"Domain\"] } },\n \"/prompts/{name}\": { get: { summary: \"Get prompt\", tags: [\"Domain\"] } },\n \"/mcp-servers\": { get: { summary: \"List MCP servers\", tags: [\"Domain\"] } },\n \"/mcp-servers/{name}\": { get: { summary: \"Get MCP server\", tags: [\"Domain\"] } },\n \"/workflows\": { get: { summary: \"List workflows\", tags: [\"Domain\"] } },\n \"/workflows/{name}\": { get: { summary: \"Get workflow\", tags: [\"Domain\"] } },\n \"/plugins\": { get: { summary: \"List plugins\", tags: [\"Domain\"] } },\n \"/plugins/{name}\": { get: { summary: \"Get plugin\", tags: [\"Domain\"] } },\n \"/sources\": {\n get: { summary: \"List sources\", tags: [\"Sources\"] },\n post: { summary: \"Add source\", tags: [\"Sources\"] },\n },\n \"/sources/{name}\": { delete: { summary: \"Remove source\", tags: [\"Sources\"] } },\n \"/sources/{name}/sync\": { post: { summary: \"Sync source\", tags: [\"Sources\"] } },\n \"/sources/{name}/validate\": { post: { summary: \"Validate source\", tags: [\"Sources\"] } },\n \"/presets\": { get: { summary: \"List presets\", tags: [\"Sources\"] } },\n \"/presets/{name}\": { get: { summary: \"Show preset\", tags: [\"Sources\"] } },\n \"/presets/{name}/apply\": { post: { summary: \"Apply preset\", tags: [\"Sources\"] } },\n \"/sessions\": {\n get: { summary: \"List sessions\", tags: [\"Sessions\"] },\n post: { summary: \"Create session\", tags: [\"Sessions\"] },\n },\n \"/sessions/{id}/prompt\": { post: { summary: \"Prompt session\", tags: [\"Sessions\"] } },\n \"/sessions/{id}/cancel\": { post: { summary: \"Cancel session\", tags: [\"Sessions\"] } },\n \"/sessions/{id}\": { delete: { summary: \"Close session\", tags: [\"Sessions\"] } },\n \"/webhooks/message\": { post: { summary: \"Universal message webhook\", tags: [\"Webhooks\"] } },\n \"/webhooks/run\": { post: { summary: \"One-shot run webhook\", tags: [\"Webhooks\"] } },\n \"/webhooks/event\": { post: { summary: \"External event webhook\", tags: [\"Webhooks\"] } },\n \"/sse\": { get: { summary: \"SSE real-time stream\", tags: [\"System\"] } },\n },\n };\n}\n","import { createConnection } from \"node:net\";\nimport type { RpcRequest, RpcResponse } from \"@actant/shared\";\n\nlet requestId = 0;\n\nexport class RpcBridge {\n constructor(private readonly socketPath: string) {}\n\n async call(method: string, params: Record<string, unknown> = {}): Promise<unknown> {\n const id = ++requestId;\n const request: RpcRequest = { jsonrpc: \"2.0\", id, method, params };\n const response = await this.send(request);\n if (response.error) {\n const err = new Error(response.error.message) as Error & { code: number; data?: unknown };\n err.code = response.error.code;\n err.data = response.error.data;\n throw err;\n }\n return response.result;\n }\n\n async ping(): Promise<boolean> {\n try {\n await this.call(\"daemon.ping\");\n return true;\n } catch {\n return false;\n }\n }\n\n private send(request: RpcRequest): Promise<RpcResponse> {\n return new Promise((resolve, reject) => {\n const socket = createConnection(this.socketPath, () => {\n socket.write(JSON.stringify(request) + \"\\n\");\n });\n\n let buffer = \"\";\n\n socket.on(\"data\", (chunk) => {\n buffer += chunk.toString();\n const lines = buffer.split(\"\\n\");\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n const response = JSON.parse(trimmed) as RpcResponse;\n socket.end();\n resolve(response);\n return;\n } catch {\n // partial data, keep buffering\n }\n }\n });\n\n socket.on(\"error\", (err) => {\n reject(new Error(`Cannot connect to daemon at ${this.socketPath}: ${err.message}`));\n });\n\n socket.setTimeout(30_000, () => {\n socket.destroy();\n reject(new Error(\"RPC call timed out after 30s\"));\n });\n });\n }\n}\n"],"mappings":"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","names":["URL"]}
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@actant/rest-api",
3
+ "version": "0.2.4",
4
+ "description": "Standalone RESTful API server for Actant — serves dashboard, n8n, and IM integrations",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "publishConfig": {
19
+ "access": "public"
20
+ },
21
+ "dependencies": {
22
+ "@actant/shared": "0.2.4"
23
+ },
24
+ "devDependencies": {
25
+ "@types/node": "^22",
26
+ "tsup": "^8.5.0",
27
+ "typescript": "^5.9.0"
28
+ },
29
+ "scripts": {
30
+ "build": "tsup",
31
+ "dev": "tsx --watch src/index.ts",
32
+ "type-check": "tsc --noEmit",
33
+ "clean": "rimraf dist"
34
+ }
35
+ }