@ebowwa/stack 0.1.2 → 0.1.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.
- package/dist/index.js +79 -1
- package/package.json +1 -1
- package/src/index.ts +100 -7
package/dist/index.js
CHANGED
|
@@ -57488,8 +57488,19 @@ class Stack {
|
|
|
57488
57488
|
const channel = channelId.platform;
|
|
57489
57489
|
const text = message.text;
|
|
57490
57490
|
console.log(`[${channel}] ${text.slice(0, 50)}...`);
|
|
57491
|
+
const telegramChannel = this.channels.get("telegram");
|
|
57492
|
+
const chatId = channelId.metadata?.chatId;
|
|
57493
|
+
if (channel === "telegram" && telegramChannel?.startTypingIndicator && chatId) {
|
|
57494
|
+
telegramChannel.startTypingIndicator(chatId);
|
|
57495
|
+
}
|
|
57496
|
+
const stopTyping = () => {
|
|
57497
|
+
if (channel === "telegram" && telegramChannel?.stopTypingIndicator && chatId) {
|
|
57498
|
+
telegramChannel.stopTypingIndicator(chatId);
|
|
57499
|
+
}
|
|
57500
|
+
};
|
|
57491
57501
|
const cmdResult = parseMemoryCommand(this.memory, channel, text);
|
|
57492
57502
|
if (cmdResult.handled) {
|
|
57503
|
+
stopTyping();
|
|
57493
57504
|
return {
|
|
57494
57505
|
content: { text: cmdResult.response || "Done" },
|
|
57495
57506
|
replyTo: { messageId: message.messageId, channelId: message.channelId }
|
|
@@ -57497,6 +57508,7 @@ class Stack {
|
|
|
57497
57508
|
}
|
|
57498
57509
|
const ralphResult = await this.handleRalphCommand(channel, text);
|
|
57499
57510
|
if (ralphResult) {
|
|
57511
|
+
stopTyping();
|
|
57500
57512
|
return {
|
|
57501
57513
|
content: { text: ralphResult },
|
|
57502
57514
|
replyTo: { messageId: message.messageId, channelId: message.channelId }
|
|
@@ -57512,12 +57524,14 @@ class Stack {
|
|
|
57512
57524
|
maxTokens: this.config.ai.maxTokens
|
|
57513
57525
|
});
|
|
57514
57526
|
this.memory.addMessage(channel, { role: "assistant", content: result.content });
|
|
57527
|
+
stopTyping();
|
|
57515
57528
|
return {
|
|
57516
57529
|
content: { text: result.content },
|
|
57517
57530
|
replyTo: { messageId: message.messageId, channelId: message.channelId }
|
|
57518
57531
|
};
|
|
57519
57532
|
} catch (error) {
|
|
57520
57533
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
57534
|
+
stopTyping();
|
|
57521
57535
|
return {
|
|
57522
57536
|
content: { text: `Error: ${errorMsg}` },
|
|
57523
57537
|
replyTo: { messageId: message.messageId, channelId: message.channelId }
|
|
@@ -57619,7 +57633,71 @@ Prompt: ${prompt.slice(0, 100)}...`;
|
|
|
57619
57633
|
if (!this.config.api)
|
|
57620
57634
|
return;
|
|
57621
57635
|
const port = this.config.api.port ?? 8911;
|
|
57622
|
-
|
|
57636
|
+
const host = this.config.api.host ?? "0.0.0.0";
|
|
57637
|
+
const server = Bun.serve({
|
|
57638
|
+
port,
|
|
57639
|
+
host,
|
|
57640
|
+
fetch: async (req) => {
|
|
57641
|
+
const url = new URL(req.url);
|
|
57642
|
+
const path = url.pathname;
|
|
57643
|
+
const corsHeaders = {
|
|
57644
|
+
"Access-Control-Allow-Origin": "*",
|
|
57645
|
+
"Access-Control-Allow-Methods": "GET, POST, DELETE, OPTIONS",
|
|
57646
|
+
"Access-Control-Allow-Headers": "Content-Type"
|
|
57647
|
+
};
|
|
57648
|
+
if (req.method === "OPTIONS") {
|
|
57649
|
+
return new Response(null, { headers: corsHeaders });
|
|
57650
|
+
}
|
|
57651
|
+
try {
|
|
57652
|
+
if (path === "/api/status" && req.method === "GET") {
|
|
57653
|
+
return Response.json(this.getStatusJSON(), { headers: corsHeaders });
|
|
57654
|
+
}
|
|
57655
|
+
if (path === "/api/ralph-loops" && req.method === "GET") {
|
|
57656
|
+
return Response.json(this.listRalphLoopsJSON(), { headers: corsHeaders });
|
|
57657
|
+
}
|
|
57658
|
+
if (path === "/api/ralph-loops" && req.method === "POST") {
|
|
57659
|
+
const body = await req.json();
|
|
57660
|
+
const prompt = body.prompt;
|
|
57661
|
+
if (!prompt) {
|
|
57662
|
+
return Response.json({ error: "Missing prompt" }, { status: 400, headers: corsHeaders });
|
|
57663
|
+
}
|
|
57664
|
+
const result = await this.startRalphLoop(prompt);
|
|
57665
|
+
return Response.json({ message: result }, { headers: corsHeaders });
|
|
57666
|
+
}
|
|
57667
|
+
const match = path.match(/^\/api\/ralph-loops\/(.+)$/);
|
|
57668
|
+
if (match && req.method === "DELETE") {
|
|
57669
|
+
const result = await this.stopRalphLoop(match[1]);
|
|
57670
|
+
return Response.json({ message: result }, { headers: corsHeaders });
|
|
57671
|
+
}
|
|
57672
|
+
if (path === "/health") {
|
|
57673
|
+
return Response.json({ status: "ok" }, { headers: corsHeaders });
|
|
57674
|
+
}
|
|
57675
|
+
return Response.json({ error: "Not found" }, { status: 404, headers: corsHeaders });
|
|
57676
|
+
} catch (error) {
|
|
57677
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
57678
|
+
return Response.json({ error: errorMsg }, { status: 500, headers: corsHeaders });
|
|
57679
|
+
}
|
|
57680
|
+
}
|
|
57681
|
+
});
|
|
57682
|
+
console.log(`[Stack] API running on http://${host}:${port}`);
|
|
57683
|
+
}
|
|
57684
|
+
getStatusJSON() {
|
|
57685
|
+
return {
|
|
57686
|
+
node: this.config.node.name,
|
|
57687
|
+
channels: {
|
|
57688
|
+
ssh: this.state.channels.ssh,
|
|
57689
|
+
telegram: this.state.channels.telegram
|
|
57690
|
+
},
|
|
57691
|
+
api: {
|
|
57692
|
+
enabled: this.state.api.enabled,
|
|
57693
|
+
port: this.state.api.port
|
|
57694
|
+
},
|
|
57695
|
+
ralphLoops: this.state.ralphLoops.size,
|
|
57696
|
+
uptime: Math.floor((Date.now() - this.state.started.getTime()) / 1000)
|
|
57697
|
+
};
|
|
57698
|
+
}
|
|
57699
|
+
listRalphLoopsJSON() {
|
|
57700
|
+
return Array.from(this.state.ralphLoops.values());
|
|
57623
57701
|
}
|
|
57624
57702
|
async start() {
|
|
57625
57703
|
console.log(`[Stack] Starting ${this.config.node.name}...`);
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -213,9 +213,23 @@ export class Stack {
|
|
|
213
213
|
|
|
214
214
|
console.log(`[${channel}] ${text.slice(0, 50)}...`);
|
|
215
215
|
|
|
216
|
+
// Start typing indicator for Telegram
|
|
217
|
+
const telegramChannel = this.channels.get("telegram") as { startTypingIndicator?: (chatId: string) => void; stopTypingIndicator?: (chatId: string) => void } | undefined;
|
|
218
|
+
const chatId = channelId.metadata?.chatId as string | undefined;
|
|
219
|
+
if (channel === "telegram" && telegramChannel?.startTypingIndicator && chatId) {
|
|
220
|
+
telegramChannel.startTypingIndicator(chatId);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const stopTyping = () => {
|
|
224
|
+
if (channel === "telegram" && telegramChannel?.stopTypingIndicator && chatId) {
|
|
225
|
+
telegramChannel.stopTypingIndicator(chatId);
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
|
|
216
229
|
// Check for memory commands
|
|
217
230
|
const cmdResult = parseMemoryCommand(this.memory, channel, text);
|
|
218
231
|
if (cmdResult.handled) {
|
|
232
|
+
stopTyping();
|
|
219
233
|
return {
|
|
220
234
|
content: { text: cmdResult.response || "Done" },
|
|
221
235
|
replyTo: { messageId: message.messageId, channelId: message.channelId },
|
|
@@ -225,6 +239,7 @@ export class Stack {
|
|
|
225
239
|
// Check for Ralph commands
|
|
226
240
|
const ralphResult = await this.handleRalphCommand(channel, text);
|
|
227
241
|
if (ralphResult) {
|
|
242
|
+
stopTyping();
|
|
228
243
|
return {
|
|
229
244
|
content: { text: ralphResult },
|
|
230
245
|
replyTo: { messageId: message.messageId, channelId: message.channelId },
|
|
@@ -252,6 +267,7 @@ export class Stack {
|
|
|
252
267
|
});
|
|
253
268
|
|
|
254
269
|
this.memory.addMessage(channel, { role: "assistant", content: result.content });
|
|
270
|
+
stopTyping();
|
|
255
271
|
|
|
256
272
|
return {
|
|
257
273
|
content: { text: result.content },
|
|
@@ -259,6 +275,7 @@ export class Stack {
|
|
|
259
275
|
};
|
|
260
276
|
} catch (error) {
|
|
261
277
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
278
|
+
stopTyping();
|
|
262
279
|
return {
|
|
263
280
|
content: { text: `Error: ${errorMsg}` },
|
|
264
281
|
replyTo: { messageId: message.messageId, channelId: message.channelId },
|
|
@@ -367,20 +384,96 @@ export class Stack {
|
|
|
367
384
|
}
|
|
368
385
|
|
|
369
386
|
// ============================================================
|
|
370
|
-
// HTTP API
|
|
387
|
+
// HTTP API
|
|
371
388
|
// ============================================================
|
|
372
389
|
|
|
373
390
|
private startAPI(): void {
|
|
374
391
|
if (!this.config.api) return;
|
|
375
392
|
|
|
376
393
|
const port = this.config.api.port ?? 8911;
|
|
377
|
-
|
|
394
|
+
const host = this.config.api.host ?? "0.0.0.0";
|
|
395
|
+
|
|
396
|
+
const server = Bun.serve({
|
|
397
|
+
port,
|
|
398
|
+
host,
|
|
399
|
+
fetch: async (req) => {
|
|
400
|
+
const url = new URL(req.url);
|
|
401
|
+
const path = url.pathname;
|
|
402
|
+
|
|
403
|
+
// CORS headers
|
|
404
|
+
const corsHeaders = {
|
|
405
|
+
"Access-Control-Allow-Origin": "*",
|
|
406
|
+
"Access-Control-Allow-Methods": "GET, POST, DELETE, OPTIONS",
|
|
407
|
+
"Access-Control-Allow-Headers": "Content-Type",
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
if (req.method === "OPTIONS") {
|
|
411
|
+
return new Response(null, { headers: corsHeaders });
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
try {
|
|
415
|
+
// GET /api/status
|
|
416
|
+
if (path === "/api/status" && req.method === "GET") {
|
|
417
|
+
return Response.json(this.getStatusJSON(), { headers: corsHeaders });
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// GET /api/ralph-loops
|
|
421
|
+
if (path === "/api/ralph-loops" && req.method === "GET") {
|
|
422
|
+
return Response.json(this.listRalphLoopsJSON(), { headers: corsHeaders });
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// POST /api/ralph-loops
|
|
426
|
+
if (path === "/api/ralph-loops" && req.method === "POST") {
|
|
427
|
+
const body = await req.json();
|
|
428
|
+
const prompt = body.prompt;
|
|
429
|
+
if (!prompt) {
|
|
430
|
+
return Response.json({ error: "Missing prompt" }, { status: 400, headers: corsHeaders });
|
|
431
|
+
}
|
|
432
|
+
const result = await this.startRalphLoop(prompt);
|
|
433
|
+
return Response.json({ message: result }, { headers: corsHeaders });
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// DELETE /api/ralph-loops/:id
|
|
437
|
+
const match = path.match(/^\/api\/ralph-loops\/(.+)$/);
|
|
438
|
+
if (match && req.method === "DELETE") {
|
|
439
|
+
const result = await this.stopRalphLoop(match[1]);
|
|
440
|
+
return Response.json({ message: result }, { headers: corsHeaders });
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// GET /health
|
|
444
|
+
if (path === "/health") {
|
|
445
|
+
return Response.json({ status: "ok" }, { headers: corsHeaders });
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
return Response.json({ error: "Not found" }, { status: 404, headers: corsHeaders });
|
|
449
|
+
} catch (error) {
|
|
450
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
451
|
+
return Response.json({ error: errorMsg }, { status: 500, headers: corsHeaders });
|
|
452
|
+
}
|
|
453
|
+
},
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
console.log(`[Stack] API running on http://${host}:${port}`);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
private getStatusJSON(): object {
|
|
460
|
+
return {
|
|
461
|
+
node: this.config.node.name,
|
|
462
|
+
channels: {
|
|
463
|
+
ssh: this.state.channels.ssh,
|
|
464
|
+
telegram: this.state.channels.telegram,
|
|
465
|
+
},
|
|
466
|
+
api: {
|
|
467
|
+
enabled: this.state.api.enabled,
|
|
468
|
+
port: this.state.api.port,
|
|
469
|
+
},
|
|
470
|
+
ralphLoops: this.state.ralphLoops.size,
|
|
471
|
+
uptime: Math.floor((Date.now() - this.state.started.getTime()) / 1000),
|
|
472
|
+
};
|
|
473
|
+
}
|
|
378
474
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
// GET /api/ralph-loops - List Ralph loops
|
|
382
|
-
// POST /api/ralph-loops - Start Ralph loop
|
|
383
|
-
// DELETE /api/ralph-loops/:id - Stop Ralph loop
|
|
475
|
+
private listRalphLoopsJSON(): object[] {
|
|
476
|
+
return Array.from(this.state.ralphLoops.values());
|
|
384
477
|
}
|
|
385
478
|
|
|
386
479
|
// ============================================================
|