pretticlaw 0.1.1 → 0.1.2

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.
@@ -10,6 +10,7 @@ export declare abstract class BaseChannel<TConfig = unknown> {
10
10
  abstract stop(): Promise<void>;
11
11
  abstract send(msg: OutboundMessage): Promise<void>;
12
12
  protected isAllowed(senderId: string): boolean;
13
+ private static readonly channelColors;
13
14
  protected handleMessage(input: {
14
15
  senderId: string;
15
16
  chatId: string;
@@ -16,9 +16,21 @@ export class BaseChannel {
16
16
  return String(senderId).split("|").some((p) => allowFrom.includes(p));
17
17
  return false;
18
18
  }
19
+ static channelColors = {
20
+ telegram: "\x1b[36m",
21
+ discord: "\x1b[35m",
22
+ whatsapp: "\x1b[32m",
23
+ slack: "\x1b[33m",
24
+ email: "\x1b[34m",
25
+ };
19
26
  async handleMessage(input) {
20
- if (!this.isAllowed(input.senderId))
27
+ const color = BaseChannel.channelColors[this.name] ?? "\x1b[0m";
28
+ const preview = input.content.length > 80 ? input.content.slice(0, 80) + "…" : input.content;
29
+ if (!this.isAllowed(input.senderId)) {
30
+ console.log(`[${color}${this.name}\x1b[0m] \x1b[31mBLOCKED\x1b[0m from=${input.senderId}`);
21
31
  return;
32
+ }
33
+ console.log(`[${color}${this.name}\x1b[0m] from=${input.senderId} chat=${input.chatId} "${preview}"`);
22
34
  await this.bus.publishInbound({
23
35
  channel: this.name,
24
36
  senderId: String(input.senderId),
@@ -51,12 +51,20 @@ function contentType(file) {
51
51
  return "image/svg+xml";
52
52
  return "application/octet-stream";
53
53
  }
54
+ const METHOD_COLORS = {
55
+ GET: "\x1b[32m",
56
+ POST: "\x1b[34m",
57
+ PUT: "\x1b[33m",
58
+ DELETE: "\x1b[31m",
59
+ };
54
60
  export function startDashboardServer(input) {
55
61
  const staticDir = dashboardDir();
56
62
  const server = createServer(async (req, res) => {
57
63
  const method = req.method || "GET";
58
64
  const url = new URL(req.url || "/", `http://${req.headers.host || "localhost"}`);
59
65
  const pathname = url.pathname;
66
+ const color = METHOD_COLORS[method] ?? "\x1b[0m";
67
+ console.log(`[gateway] ${color}${method}\x1b[0m ${pathname}`);
60
68
  if (method === "GET" && pathname === "/api/status") {
61
69
  const cfg = loadConfig();
62
70
  return sendJson(res, 200, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pretticlaw",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Lightweight AI Assistant That Lives in Your Computer",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,36 +1,50 @@
1
- import type { MessageBus } from "../bus/queue.js";
2
- import type { OutboundMessage } from "../bus/events.js";
3
-
4
- export abstract class BaseChannel<TConfig = unknown> {
5
- protected running = false;
6
- constructor(protected readonly config: TConfig, protected readonly bus: MessageBus) {}
7
- abstract readonly name: string;
8
- abstract start(): Promise<void>;
9
- abstract stop(): Promise<void>;
10
- abstract send(msg: OutboundMessage): Promise<void>;
11
-
12
- protected isAllowed(senderId: string): boolean {
13
- const allowFrom: string[] = ((this.config as any)?.allowFrom ?? []) as string[];
14
- if (!allowFrom.length) return true;
15
- if (allowFrom.includes(String(senderId))) return true;
16
- if (String(senderId).includes("|")) return String(senderId).split("|").some((p) => allowFrom.includes(p));
17
- return false;
18
- }
19
-
20
- protected async handleMessage(input: { senderId: string; chatId: string; content: string; media?: string[]; metadata?: Record<string, unknown>; sessionKey?: string }): Promise<void> {
21
- if (!this.isAllowed(input.senderId)) return;
22
- await this.bus.publishInbound({
23
- channel: this.name,
24
- senderId: String(input.senderId),
25
- chatId: String(input.chatId),
26
- content: input.content,
27
- media: input.media ?? [],
28
- metadata: input.metadata ?? {},
29
- sessionKeyOverride: input.sessionKey,
30
- });
31
- }
32
-
33
- get isRunning(): boolean {
34
- return this.running;
35
- }
1
+ import type { MessageBus } from "../bus/queue.js";
2
+ import type { OutboundMessage } from "../bus/events.js";
3
+
4
+ export abstract class BaseChannel<TConfig = unknown> {
5
+ protected running = false;
6
+ constructor(protected readonly config: TConfig, protected readonly bus: MessageBus) {}
7
+ abstract readonly name: string;
8
+ abstract start(): Promise<void>;
9
+ abstract stop(): Promise<void>;
10
+ abstract send(msg: OutboundMessage): Promise<void>;
11
+
12
+ protected isAllowed(senderId: string): boolean {
13
+ const allowFrom: string[] = ((this.config as any)?.allowFrom ?? []) as string[];
14
+ if (!allowFrom.length) return true;
15
+ if (allowFrom.includes(String(senderId))) return true;
16
+ if (String(senderId).includes("|")) return String(senderId).split("|").some((p) => allowFrom.includes(p));
17
+ return false;
18
+ }
19
+
20
+ private static readonly channelColors: Record<string, string> = {
21
+ telegram: "\x1b[36m",
22
+ discord: "\x1b[35m",
23
+ whatsapp: "\x1b[32m",
24
+ slack: "\x1b[33m",
25
+ email: "\x1b[34m",
26
+ };
27
+
28
+ protected async handleMessage(input: { senderId: string; chatId: string; content: string; media?: string[]; metadata?: Record<string, unknown>; sessionKey?: string }): Promise<void> {
29
+ const color = BaseChannel.channelColors[this.name] ?? "\x1b[0m";
30
+ const preview = input.content.length > 80 ? input.content.slice(0, 80) + "…" : input.content;
31
+ if (!this.isAllowed(input.senderId)) {
32
+ console.log(`[${color}${this.name}\x1b[0m] \x1b[31mBLOCKED\x1b[0m from=${input.senderId}`);
33
+ return;
34
+ }
35
+ console.log(`[${color}${this.name}\x1b[0m] from=${input.senderId} chat=${input.chatId} "${preview}"`);
36
+ await this.bus.publishInbound({
37
+ channel: this.name,
38
+ senderId: String(input.senderId),
39
+ chatId: String(input.chatId),
40
+ content: input.content,
41
+ media: input.media ?? [],
42
+ metadata: input.metadata ?? {},
43
+ sessionKeyOverride: input.sessionKey,
44
+ });
45
+ }
46
+
47
+ get isRunning(): boolean {
48
+ return this.running;
49
+ }
36
50
  }
package/src/web/server.ts CHANGED
@@ -55,6 +55,13 @@ function contentType(file: string): string {
55
55
  return "application/octet-stream";
56
56
  }
57
57
 
58
+ const METHOD_COLORS: Record<string, string> = {
59
+ GET: "\x1b[32m",
60
+ POST: "\x1b[34m",
61
+ PUT: "\x1b[33m",
62
+ DELETE: "\x1b[31m",
63
+ };
64
+
58
65
  export function startDashboardServer(input: {
59
66
  agent: AgentLoop;
60
67
  cron: CronService;
@@ -70,6 +77,9 @@ export function startDashboardServer(input: {
70
77
  const url = new URL(req.url || "/", `http://${req.headers.host || "localhost"}`);
71
78
  const pathname = url.pathname;
72
79
 
80
+ const color = METHOD_COLORS[method] ?? "\x1b[0m";
81
+ console.log(`[gateway] ${color}${method}\x1b[0m ${pathname}`);
82
+
73
83
  if (method === "GET" && pathname === "/api/status") {
74
84
  const cfg = loadConfig();
75
85
  return sendJson(res, 200, {