@rk0429/agentic-relay 21.2.3 → 22.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/application/chat/chat-daemon-service.d.ts +81 -0
- package/dist/application/chat/chat-daemon-service.js +382 -0
- package/dist/application/chat/chat-daemon-service.js.map +1 -0
- package/dist/application/chat/chat-inbound-handler.d.ts +35 -0
- package/dist/application/chat/chat-inbound-handler.js +175 -0
- package/dist/application/chat/chat-inbound-handler.js.map +1 -0
- package/dist/application/chat/chat-logging.d.ts +8 -0
- package/dist/application/chat/chat-logging.js +16 -0
- package/dist/application/chat/chat-logging.js.map +1 -0
- package/dist/application/chat/chat-outbound-handler.d.ts +16 -0
- package/dist/application/chat/chat-outbound-handler.js +190 -0
- package/dist/application/chat/chat-outbound-handler.js.map +1 -0
- package/dist/application/chat/chat-question-service.d.ts +37 -0
- package/dist/application/chat/chat-question-service.js +135 -0
- package/dist/application/chat/chat-question-service.js.map +1 -0
- package/dist/application/chat/chat-setup-service.d.ts +27 -0
- package/dist/application/chat/chat-setup-service.js +183 -0
- package/dist/application/chat/chat-setup-service.js.map +1 -0
- package/dist/application/chat/message-queue-manager.d.ts +13 -0
- package/dist/application/chat/message-queue-manager.js +34 -0
- package/dist/application/chat/message-queue-manager.js.map +1 -0
- package/dist/application/routine-status-query-service.d.ts +17 -0
- package/dist/application/routine-status-query-service.js +111 -0
- package/dist/application/routine-status-query-service.js.map +1 -1
- package/dist/bin/relay.d.ts +9 -2
- package/dist/bin/relay.js +296 -18
- package/dist/bin/relay.js.map +1 -1
- package/dist/core/chat-types.d.ts +18 -0
- package/dist/core/chat-types.js +14 -0
- package/dist/core/chat-types.js.map +1 -0
- package/dist/core/types.d.ts +7 -0
- package/dist/domain/chat/message-cleaner.d.ts +11 -0
- package/dist/domain/chat/message-cleaner.js +45 -0
- package/dist/domain/chat/message-cleaner.js.map +1 -0
- package/dist/domain/chat/message-router.d.ts +8 -0
- package/dist/domain/chat/message-router.js +93 -0
- package/dist/domain/chat/message-router.js.map +1 -0
- package/dist/domain/chat/message-splitter.d.ts +3 -0
- package/dist/domain/chat/message-splitter.js +148 -0
- package/dist/domain/chat/message-splitter.js.map +1 -0
- package/dist/domain/chat/platform-connection.d.ts +31 -0
- package/dist/domain/chat/platform-connection.js +67 -0
- package/dist/domain/chat/platform-connection.js.map +1 -0
- package/dist/domain/chat/ports.d.ts +31 -0
- package/dist/domain/chat/ports.js +2 -0
- package/dist/domain/chat/ports.js.map +1 -0
- package/dist/domain/chat/session-bridge.d.ts +41 -0
- package/dist/domain/chat/session-bridge.js +93 -0
- package/dist/domain/chat/session-bridge.js.map +1 -0
- package/dist/domain/chat/types.d.ts +83 -0
- package/dist/domain/chat/types.js +2 -0
- package/dist/domain/chat/types.js.map +1 -0
- package/dist/domain/chat/user-question.d.ts +33 -0
- package/dist/domain/chat/user-question.js +73 -0
- package/dist/domain/chat/user-question.js.map +1 -0
- package/dist/domain/config.d.ts +3 -1
- package/dist/domain/config.js +9 -0
- package/dist/domain/config.js.map +1 -1
- package/dist/domain/routine-loader.d.ts +2 -0
- package/dist/domain/routine-loader.js +3 -0
- package/dist/domain/routine-loader.js.map +1 -1
- package/dist/infrastructure/chat/adapter-factory.d.ts +5 -0
- package/dist/infrastructure/chat/adapter-factory.js +15 -0
- package/dist/infrastructure/chat/adapter-factory.js.map +1 -0
- package/dist/infrastructure/chat/adapters/discord-adapter.d.ts +23 -0
- package/dist/infrastructure/chat/adapters/discord-adapter.js +199 -0
- package/dist/infrastructure/chat/adapters/discord-adapter.js.map +1 -0
- package/dist/infrastructure/chat/adapters/slack-adapter.d.ts +24 -0
- package/dist/infrastructure/chat/adapters/slack-adapter.js +155 -0
- package/dist/infrastructure/chat/adapters/slack-adapter.js.map +1 -0
- package/dist/infrastructure/chat/agent-gateway-impl.d.ts +21 -0
- package/dist/infrastructure/chat/agent-gateway-impl.js +101 -0
- package/dist/infrastructure/chat/agent-gateway-impl.js.map +1 -0
- package/dist/infrastructure/chat/chat-ipc-client.d.ts +33 -0
- package/dist/infrastructure/chat/chat-ipc-client.js +70 -0
- package/dist/infrastructure/chat/chat-ipc-client.js.map +1 -0
- package/dist/infrastructure/chat/chat-ipc-server.d.ts +19 -0
- package/dist/infrastructure/chat/chat-ipc-server.js +125 -0
- package/dist/infrastructure/chat/chat-ipc-server.js.map +1 -0
- package/dist/infrastructure/chat/chat-logger.d.ts +24 -0
- package/dist/infrastructure/chat/chat-logger.js +86 -0
- package/dist/infrastructure/chat/chat-logger.js.map +1 -0
- package/dist/infrastructure/chat/credentials-repository.d.ts +8 -0
- package/dist/infrastructure/chat/credentials-repository.js +84 -0
- package/dist/infrastructure/chat/credentials-repository.js.map +1 -0
- package/dist/infrastructure/chat/session-bridge-repository.d.ts +13 -0
- package/dist/infrastructure/chat/session-bridge-repository.js +120 -0
- package/dist/infrastructure/chat/session-bridge-repository.js.map +1 -0
- package/dist/infrastructure/chat/token-masking.d.ts +3 -0
- package/dist/infrastructure/chat/token-masking.js +22 -0
- package/dist/infrastructure/chat/token-masking.js.map +1 -0
- package/dist/infrastructure/store/relay-store.js +3 -1
- package/dist/infrastructure/store/relay-store.js.map +1 -1
- package/dist/interfaces/cli/chat-cli.d.ts +34 -0
- package/dist/interfaces/cli/chat-cli.js +68 -0
- package/dist/interfaces/cli/chat-cli.js.map +1 -0
- package/dist/interfaces/cli/relay-cli-args.d.ts +16 -1
- package/dist/interfaces/cli/relay-cli-args.js +135 -2
- package/dist/interfaces/cli/relay-cli-args.js.map +1 -1
- package/dist/interfaces/mcp/chat-tools.d.ts +33 -0
- package/dist/interfaces/mcp/chat-tools.js +129 -0
- package/dist/interfaces/mcp/chat-tools.js.map +1 -0
- package/dist/interfaces/mcp/relay-mcp-server.d.ts +2 -0
- package/dist/interfaces/mcp/relay-mcp-server.js +194 -1
- package/dist/interfaces/mcp/relay-mcp-server.js.map +1 -1
- package/package.json +3 -1
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { BackendUnavailableError, ValidationError } from "../../core/errors.js";
|
|
3
|
+
export class AgentGatewayImpl {
|
|
4
|
+
spawnService;
|
|
5
|
+
taskService;
|
|
6
|
+
store;
|
|
7
|
+
backendRegistry;
|
|
8
|
+
actorId;
|
|
9
|
+
constructor(spawnService, taskService, store, backendRegistry, actorId = "chat-daemon") {
|
|
10
|
+
this.spawnService = spawnService;
|
|
11
|
+
this.taskService = taskService;
|
|
12
|
+
this.store = store;
|
|
13
|
+
this.backendRegistry = backendRegistry;
|
|
14
|
+
this.actorId = actorId;
|
|
15
|
+
}
|
|
16
|
+
async startSession(prompt, backend) {
|
|
17
|
+
const taskId = await this.createChatTask(prompt);
|
|
18
|
+
const resolvedBackend = backend?.backend ?? await this.resolveDefaultBackend();
|
|
19
|
+
const [result] = await this.spawnService.spawnAgents({
|
|
20
|
+
agents: [
|
|
21
|
+
{
|
|
22
|
+
task_id: taskId,
|
|
23
|
+
backend: resolvedBackend,
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
summary_length: 4_000,
|
|
27
|
+
});
|
|
28
|
+
if (!result) {
|
|
29
|
+
throw new ValidationError("Chat session agent did not produce a result.");
|
|
30
|
+
}
|
|
31
|
+
return this.toAgentResult(result);
|
|
32
|
+
}
|
|
33
|
+
async continueSession(sessionId, prompt) {
|
|
34
|
+
const metadata = await this.store.readSessionMetadata(sessionId);
|
|
35
|
+
const taskId = await this.createChatTask(prompt);
|
|
36
|
+
const resolvedBackend = metadata?.backend ?? await this.resolveDefaultBackend();
|
|
37
|
+
const [result] = await this.spawnService.spawnAgents({
|
|
38
|
+
agents: [
|
|
39
|
+
{
|
|
40
|
+
task_id: taskId,
|
|
41
|
+
resume_from_relay_session_id: sessionId,
|
|
42
|
+
backend: resolvedBackend,
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
summary_length: 4_000,
|
|
46
|
+
});
|
|
47
|
+
if (!result) {
|
|
48
|
+
throw new ValidationError("Chat session continuation did not produce a result.");
|
|
49
|
+
}
|
|
50
|
+
return this.toAgentResult(result);
|
|
51
|
+
}
|
|
52
|
+
async createChatTask(prompt) {
|
|
53
|
+
const task = await this.taskService.createTask({
|
|
54
|
+
title: buildChatTaskTitle(prompt),
|
|
55
|
+
description: prompt,
|
|
56
|
+
acceptance_criteria: "Respond to the chat message with a helpful answer.",
|
|
57
|
+
labels: ["chat"],
|
|
58
|
+
}, { actorId: this.actorId });
|
|
59
|
+
await this.taskService.updateTaskStatus({
|
|
60
|
+
task_id: task.task_id,
|
|
61
|
+
status: "ready",
|
|
62
|
+
}, { actorId: this.actorId });
|
|
63
|
+
return task.task_id;
|
|
64
|
+
}
|
|
65
|
+
// Chat messages have no taskType, so domain/routing.ts resolveBackend() cannot be used.
|
|
66
|
+
// Fall back to the first installed backend in BACKEND_TYPES order (claude > codex > gemini).
|
|
67
|
+
// If config.json gains a chat-specific routing key, this should be updated accordingly.
|
|
68
|
+
async resolveDefaultBackend() {
|
|
69
|
+
const availableBackends = await this.backendRegistry.detectInstalled();
|
|
70
|
+
const backend = availableBackends[0];
|
|
71
|
+
if (!backend) {
|
|
72
|
+
throw new BackendUnavailableError("agentic-relay: no supported backend CLI is installed.");
|
|
73
|
+
}
|
|
74
|
+
return backend;
|
|
75
|
+
}
|
|
76
|
+
async toAgentResult(result) {
|
|
77
|
+
if (result.process_status !== "success") {
|
|
78
|
+
throw new ValidationError(result.summary || "Agent execution failed.", {
|
|
79
|
+
recoveryHint: result.recovery_hint,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
const [metadata, response] = await Promise.all([
|
|
83
|
+
this.store.readSessionMetadata(result.relay_session_id),
|
|
84
|
+
readFile(result.full_response_path, "utf8").catch(() => result.summary),
|
|
85
|
+
]);
|
|
86
|
+
return {
|
|
87
|
+
relaySessionId: result.relay_session_id,
|
|
88
|
+
backendSessionId: metadata?.backendSessionId,
|
|
89
|
+
response,
|
|
90
|
+
backend: result.backend,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
export function buildChatTaskTitle(prompt) {
|
|
95
|
+
const trimmed = prompt.trim();
|
|
96
|
+
if (!trimmed) {
|
|
97
|
+
return "Chat session";
|
|
98
|
+
}
|
|
99
|
+
return `Chat: ${trimmed.slice(0, 60)}`;
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=agent-gateway-impl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-gateway-impl.js","sourceRoot":"","sources":["../../../src/infrastructure/chat/agent-gateway-impl.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { PlatformType } from "../../core/chat-types.js";
|
|
2
|
+
import type { SendResult } from "../../domain/chat/types.js";
|
|
3
|
+
import type { ChatIpcAskUserResult } from "./chat-ipc-server.js";
|
|
4
|
+
export declare class ChatIpcClient {
|
|
5
|
+
private readonly socketPath;
|
|
6
|
+
constructor(rootDir: string);
|
|
7
|
+
sendMessage(params: {
|
|
8
|
+
platform?: PlatformType;
|
|
9
|
+
channel?: string;
|
|
10
|
+
user_id?: string;
|
|
11
|
+
message: string;
|
|
12
|
+
thread_id?: string;
|
|
13
|
+
}): Promise<SendResult>;
|
|
14
|
+
replyThread(params: {
|
|
15
|
+
platform?: PlatformType;
|
|
16
|
+
channel: string;
|
|
17
|
+
thread_id: string;
|
|
18
|
+
message: string;
|
|
19
|
+
}): Promise<SendResult>;
|
|
20
|
+
askUser(params: {
|
|
21
|
+
platform?: PlatformType;
|
|
22
|
+
user_id: string;
|
|
23
|
+
question: string;
|
|
24
|
+
timeout_seconds?: number;
|
|
25
|
+
channel?: string;
|
|
26
|
+
}): Promise<ChatIpcAskUserResult>;
|
|
27
|
+
listChannels(params: {
|
|
28
|
+
platform?: PlatformType;
|
|
29
|
+
}): Promise<{
|
|
30
|
+
channels: Array<Record<string, unknown>>;
|
|
31
|
+
}>;
|
|
32
|
+
private request;
|
|
33
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { createConnection } from "node:net";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { ValidationError } from "../../core/errors.js";
|
|
4
|
+
export class ChatIpcClient {
|
|
5
|
+
socketPath;
|
|
6
|
+
constructor(rootDir) {
|
|
7
|
+
this.socketPath = path.join(rootDir, "chat.sock");
|
|
8
|
+
}
|
|
9
|
+
async sendMessage(params) {
|
|
10
|
+
return this.request("chat/sendMessage", params);
|
|
11
|
+
}
|
|
12
|
+
async replyThread(params) {
|
|
13
|
+
return this.request("chat/replyThread", params);
|
|
14
|
+
}
|
|
15
|
+
async askUser(params) {
|
|
16
|
+
return this.request("chat/askUser", params);
|
|
17
|
+
}
|
|
18
|
+
async listChannels(params) {
|
|
19
|
+
return this.request("chat/listChannels", params);
|
|
20
|
+
}
|
|
21
|
+
async request(method, params) {
|
|
22
|
+
const id = `${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
23
|
+
const socket = createConnection(this.socketPath);
|
|
24
|
+
socket.setEncoding("utf8");
|
|
25
|
+
return new Promise((resolve, reject) => {
|
|
26
|
+
let buffer = "";
|
|
27
|
+
socket.once("error", (error) => {
|
|
28
|
+
reject(new ValidationError("Chat daemon is not running.", {
|
|
29
|
+
recoveryHint: "Run `relay chat start` before using chat MCP tools.",
|
|
30
|
+
causeData: {
|
|
31
|
+
error: error.message,
|
|
32
|
+
},
|
|
33
|
+
}));
|
|
34
|
+
});
|
|
35
|
+
socket.on("data", (chunk) => {
|
|
36
|
+
buffer += chunk;
|
|
37
|
+
while (buffer.includes("\n")) {
|
|
38
|
+
const newlineIndex = buffer.indexOf("\n");
|
|
39
|
+
const line = buffer.slice(0, newlineIndex).trim();
|
|
40
|
+
buffer = buffer.slice(newlineIndex + 1);
|
|
41
|
+
if (!line) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
const response = JSON.parse(line);
|
|
45
|
+
if (response.id !== id) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
socket.end();
|
|
49
|
+
if (response.error) {
|
|
50
|
+
reject(new ValidationError(response.error.message, {
|
|
51
|
+
causeData: response.error.data,
|
|
52
|
+
}));
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
resolve(response.result);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
socket.on("connect", () => {
|
|
60
|
+
socket.write(`${JSON.stringify({
|
|
61
|
+
jsonrpc: "2.0",
|
|
62
|
+
id,
|
|
63
|
+
method,
|
|
64
|
+
params,
|
|
65
|
+
})}\n`);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=chat-ipc-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-ipc-client.js","sourceRoot":"","sources":["../../../src/infrastructure/chat/chat-ipc-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ChatOutboundHandler } from "../../application/chat/chat-outbound-handler.js";
|
|
2
|
+
import type { AskUserResult } from "../../application/chat/chat-question-service.js";
|
|
3
|
+
import { ChatQuestionService } from "../../application/chat/chat-question-service.js";
|
|
4
|
+
export declare class ChatIpcServer {
|
|
5
|
+
private readonly deps;
|
|
6
|
+
private readonly socketPath;
|
|
7
|
+
private server?;
|
|
8
|
+
constructor(deps: {
|
|
9
|
+
rootDir: string;
|
|
10
|
+
outboundHandler: ChatOutboundHandler;
|
|
11
|
+
questionService: ChatQuestionService;
|
|
12
|
+
});
|
|
13
|
+
listen(): Promise<void>;
|
|
14
|
+
close(): Promise<void>;
|
|
15
|
+
private handleSocket;
|
|
16
|
+
private handleLine;
|
|
17
|
+
private dispatch;
|
|
18
|
+
}
|
|
19
|
+
export type ChatIpcAskUserResult = AskUserResult;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { createServer } from "node:net";
|
|
2
|
+
import { chmod, mkdir, rm } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { ValidationError } from "../../core/errors.js";
|
|
5
|
+
import { PlatformType } from "../../core/chat-types.js";
|
|
6
|
+
export class ChatIpcServer {
|
|
7
|
+
deps;
|
|
8
|
+
socketPath;
|
|
9
|
+
server;
|
|
10
|
+
constructor(deps) {
|
|
11
|
+
this.deps = deps;
|
|
12
|
+
this.socketPath = path.join(deps.rootDir, "chat.sock");
|
|
13
|
+
}
|
|
14
|
+
async listen() {
|
|
15
|
+
await mkdir(path.dirname(this.socketPath), { recursive: true });
|
|
16
|
+
await rm(this.socketPath, { force: true });
|
|
17
|
+
this.server = createServer((socket) => {
|
|
18
|
+
this.handleSocket(socket);
|
|
19
|
+
});
|
|
20
|
+
await new Promise((resolve, reject) => {
|
|
21
|
+
this.server.once("error", reject);
|
|
22
|
+
this.server.listen(this.socketPath, () => {
|
|
23
|
+
this.server.off("error", reject);
|
|
24
|
+
resolve();
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
await chmod(this.socketPath, 0o700);
|
|
28
|
+
}
|
|
29
|
+
async close() {
|
|
30
|
+
if (this.server) {
|
|
31
|
+
await new Promise((resolve) => this.server.close(() => resolve()));
|
|
32
|
+
this.server = undefined;
|
|
33
|
+
}
|
|
34
|
+
await rm(this.socketPath, { force: true });
|
|
35
|
+
}
|
|
36
|
+
handleSocket(socket) {
|
|
37
|
+
let buffer = "";
|
|
38
|
+
socket.setEncoding("utf8");
|
|
39
|
+
socket.on("data", (chunk) => {
|
|
40
|
+
buffer += chunk;
|
|
41
|
+
while (buffer.includes("\n")) {
|
|
42
|
+
const newlineIndex = buffer.indexOf("\n");
|
|
43
|
+
const line = buffer.slice(0, newlineIndex).trim();
|
|
44
|
+
buffer = buffer.slice(newlineIndex + 1);
|
|
45
|
+
if (!line) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
void this.handleLine(socket, line);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
async handleLine(socket, line) {
|
|
53
|
+
let request;
|
|
54
|
+
try {
|
|
55
|
+
request = JSON.parse(line);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
socket.write(`${JSON.stringify(buildErrorResponse(null, -32700, "Parse error"))}\n`);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
const result = await this.dispatch(request.method, request.params ?? {});
|
|
63
|
+
socket.write(`${JSON.stringify({ jsonrpc: "2.0", id: request.id, result })}\n`);
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
67
|
+
socket.write(`${JSON.stringify(buildErrorResponse(request.id, -32000, message))}\n`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async dispatch(method, params) {
|
|
71
|
+
switch (method) {
|
|
72
|
+
case "chat/sendMessage":
|
|
73
|
+
return this.deps.outboundHandler.sendResponse(asOptionalPlatform(params.platform), {
|
|
74
|
+
channelId: asOptionalString(params.channel),
|
|
75
|
+
userId: asOptionalString(params.user_id),
|
|
76
|
+
threadId: asOptionalString(params.thread_id),
|
|
77
|
+
}, asRequiredString(params.message, "message"));
|
|
78
|
+
case "chat/replyThread":
|
|
79
|
+
return this.deps.outboundHandler.sendResponse(asOptionalPlatform(params.platform), {
|
|
80
|
+
channelId: asRequiredString(params.channel, "channel"),
|
|
81
|
+
threadId: asRequiredString(params.thread_id, "thread_id"),
|
|
82
|
+
}, asRequiredString(params.message, "message"));
|
|
83
|
+
case "chat/askUser":
|
|
84
|
+
return this.deps.questionService.ask(asRequiredString(params.user_id, "user_id"), asRequiredString(params.question, "question"), asOptionalNumber(params.timeout_seconds) ?? 300, asOptionalPlatform(params.platform), asOptionalString(params.channel));
|
|
85
|
+
case "chat/listChannels":
|
|
86
|
+
return {
|
|
87
|
+
channels: await this.deps.outboundHandler.listChannels(asOptionalPlatform(params.platform)),
|
|
88
|
+
};
|
|
89
|
+
default:
|
|
90
|
+
throw new ValidationError(`Unsupported chat IPC method: ${method}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function buildErrorResponse(id, code, message) {
|
|
95
|
+
return {
|
|
96
|
+
jsonrpc: "2.0",
|
|
97
|
+
id,
|
|
98
|
+
error: {
|
|
99
|
+
code,
|
|
100
|
+
message,
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function asRequiredString(value, field) {
|
|
105
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
106
|
+
throw new ValidationError(`${field} must be a non-empty string.`);
|
|
107
|
+
}
|
|
108
|
+
return value;
|
|
109
|
+
}
|
|
110
|
+
function asOptionalString(value) {
|
|
111
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
112
|
+
}
|
|
113
|
+
function asOptionalNumber(value) {
|
|
114
|
+
return typeof value === "number" ? value : undefined;
|
|
115
|
+
}
|
|
116
|
+
function asOptionalPlatform(value) {
|
|
117
|
+
if (value === PlatformType.Slack) {
|
|
118
|
+
return PlatformType.Slack;
|
|
119
|
+
}
|
|
120
|
+
if (value === PlatformType.Discord) {
|
|
121
|
+
return PlatformType.Discord;
|
|
122
|
+
}
|
|
123
|
+
return undefined;
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=chat-ipc-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-ipc-server.js","sourceRoot":"","sources":["../../../src/infrastructure/chat/chat-ipc-server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ChatConfig } from "../../core/types.js";
|
|
2
|
+
import type { ChatStructuredLogger } from "../../application/chat/chat-logging.js";
|
|
3
|
+
export interface ChatLogEntry {
|
|
4
|
+
ts: string;
|
|
5
|
+
level: "info" | "warn" | "error";
|
|
6
|
+
event: string;
|
|
7
|
+
[key: string]: unknown;
|
|
8
|
+
}
|
|
9
|
+
export declare class ChatLogger implements ChatStructuredLogger {
|
|
10
|
+
private readonly deps;
|
|
11
|
+
private readonly level;
|
|
12
|
+
constructor(deps: {
|
|
13
|
+
rootDir: string;
|
|
14
|
+
ensureLayout?: () => Promise<void>;
|
|
15
|
+
now?: () => Date;
|
|
16
|
+
logLevel?: ChatConfig["log_level"];
|
|
17
|
+
});
|
|
18
|
+
info(message: string, metadata?: Record<string, unknown>): Promise<void>;
|
|
19
|
+
warn(message: string, metadata?: Record<string, unknown>): Promise<void>;
|
|
20
|
+
error(message: string, metadata?: Record<string, unknown>): Promise<void>;
|
|
21
|
+
private write;
|
|
22
|
+
private ensureLogsDir;
|
|
23
|
+
private logPath;
|
|
24
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { appendFile, mkdir } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { maskCredentials, maskToken } from "./token-masking.js";
|
|
4
|
+
const PRIVATE_FILE_MODE = 0o600;
|
|
5
|
+
const LOG_LEVEL_ORDER = {
|
|
6
|
+
info: 0,
|
|
7
|
+
warn: 1,
|
|
8
|
+
error: 2,
|
|
9
|
+
};
|
|
10
|
+
export class ChatLogger {
|
|
11
|
+
deps;
|
|
12
|
+
level;
|
|
13
|
+
constructor(deps) {
|
|
14
|
+
this.deps = deps;
|
|
15
|
+
this.level = deps.logLevel ?? "info";
|
|
16
|
+
}
|
|
17
|
+
async info(message, metadata) {
|
|
18
|
+
await this.write("info", message, metadata);
|
|
19
|
+
}
|
|
20
|
+
async warn(message, metadata) {
|
|
21
|
+
await this.write("warn", message, metadata);
|
|
22
|
+
}
|
|
23
|
+
async error(message, metadata) {
|
|
24
|
+
await this.write("error", message, metadata);
|
|
25
|
+
}
|
|
26
|
+
async write(level, message, metadata) {
|
|
27
|
+
if (LOG_LEVEL_ORDER[level] < LOG_LEVEL_ORDER[this.level]) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const now = this.deps.now?.() ?? new Date();
|
|
31
|
+
const sanitizedMetadata = sanitizeMetadata(metadata);
|
|
32
|
+
const entry = {
|
|
33
|
+
...(sanitizedMetadata ?? {}),
|
|
34
|
+
ts: now.toISOString(),
|
|
35
|
+
level,
|
|
36
|
+
event: message,
|
|
37
|
+
};
|
|
38
|
+
await this.ensureLogsDir();
|
|
39
|
+
await appendFile(this.logPath(now), `${JSON.stringify(entry)}\n`, {
|
|
40
|
+
encoding: "utf8",
|
|
41
|
+
mode: PRIVATE_FILE_MODE,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
async ensureLogsDir() {
|
|
45
|
+
await this.deps.ensureLayout?.();
|
|
46
|
+
await mkdir(path.join(this.deps.rootDir, "logs"), { recursive: true });
|
|
47
|
+
}
|
|
48
|
+
logPath(date) {
|
|
49
|
+
return path.join(this.deps.rootDir, "logs", `chat-${date.toISOString().slice(0, 10)}.jsonl`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function sanitizeMetadata(metadata) {
|
|
53
|
+
if (!metadata) {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
return Object.fromEntries(Object.entries(metadata).map(([key, value]) => [key, sanitizeValue(key, value)]));
|
|
57
|
+
}
|
|
58
|
+
function sanitizeValue(key, value) {
|
|
59
|
+
if (value == null) {
|
|
60
|
+
return value;
|
|
61
|
+
}
|
|
62
|
+
if (typeof value === "string") {
|
|
63
|
+
return /token|secret/i.test(key) ? maskToken(value) : value;
|
|
64
|
+
}
|
|
65
|
+
if (Array.isArray(value)) {
|
|
66
|
+
return value.map((item) => sanitizeValue(key, item));
|
|
67
|
+
}
|
|
68
|
+
if (isChatCredentials(value)) {
|
|
69
|
+
return maskCredentials(value);
|
|
70
|
+
}
|
|
71
|
+
if (typeof value === "object") {
|
|
72
|
+
return Object.fromEntries(Object.entries(value).map(([nestedKey, nestedValue]) => [
|
|
73
|
+
nestedKey,
|
|
74
|
+
sanitizeValue(nestedKey, nestedValue),
|
|
75
|
+
]));
|
|
76
|
+
}
|
|
77
|
+
return value;
|
|
78
|
+
}
|
|
79
|
+
function isChatCredentials(value) {
|
|
80
|
+
if (!value || typeof value !== "object") {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
const candidate = value;
|
|
84
|
+
return "slack" in candidate || "discord" in candidate;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=chat-logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-logger.js","sourceRoot":"","sources":["../../../src/infrastructure/chat/chat-logger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { CredentialsRepository } from "../../domain/chat/ports.js";
|
|
2
|
+
import type { ChatCredentials } from "../../domain/chat/types.js";
|
|
3
|
+
export declare class CredentialsFileRepository implements CredentialsRepository {
|
|
4
|
+
private readonly filePath;
|
|
5
|
+
constructor(rootDir: string);
|
|
6
|
+
load(): Promise<ChatCredentials | null>;
|
|
7
|
+
save(credentials: ChatCredentials): Promise<void>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { chmod, mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { ValidationError } from "../../core/errors.js";
|
|
4
|
+
const PRIVATE_FILE_MODE = 0o600;
|
|
5
|
+
export class CredentialsFileRepository {
|
|
6
|
+
filePath;
|
|
7
|
+
constructor(rootDir) {
|
|
8
|
+
this.filePath = path.join(rootDir, "chat-credentials.json");
|
|
9
|
+
}
|
|
10
|
+
async load() {
|
|
11
|
+
try {
|
|
12
|
+
const [raw, info] = await Promise.all([
|
|
13
|
+
readFile(this.filePath, "utf8"),
|
|
14
|
+
stat(this.filePath),
|
|
15
|
+
]);
|
|
16
|
+
if ((info.mode & 0o777) !== PRIVATE_FILE_MODE) {
|
|
17
|
+
throw new ValidationError("chat-credentials.json must have 0600 permissions.", {
|
|
18
|
+
recoveryHint: "Run `chmod 600 .relay/chat-credentials.json` and retry.",
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
return deserializeCredentials(JSON.parse(raw));
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
if (typeof error === "object" &&
|
|
25
|
+
error !== null &&
|
|
26
|
+
"code" in error &&
|
|
27
|
+
error.code === "ENOENT") {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
async save(credentials) {
|
|
34
|
+
await mkdir(path.dirname(this.filePath), { recursive: true });
|
|
35
|
+
await writeFile(this.filePath, `${JSON.stringify(serializeCredentials(credentials), null, 2)}\n`, {
|
|
36
|
+
encoding: "utf8",
|
|
37
|
+
mode: PRIVATE_FILE_MODE,
|
|
38
|
+
});
|
|
39
|
+
await chmod(this.filePath, PRIVATE_FILE_MODE);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function serializeCredentials(credentials) {
|
|
43
|
+
return {
|
|
44
|
+
slack: credentials.slack && serializeSlack(credentials.slack),
|
|
45
|
+
discord: credentials.discord && serializeDiscord(credentials.discord),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function deserializeCredentials(value) {
|
|
49
|
+
return {
|
|
50
|
+
slack: value.slack && deserializeSlack(value.slack),
|
|
51
|
+
discord: value.discord && deserializeDiscord(value.discord),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function serializeSlack(credentials) {
|
|
55
|
+
return {
|
|
56
|
+
bot_token: credentials.botToken,
|
|
57
|
+
app_token: credentials.appToken,
|
|
58
|
+
team_id: credentials.teamId,
|
|
59
|
+
bot_user_id: credentials.botUserId,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function serializeDiscord(credentials) {
|
|
63
|
+
return {
|
|
64
|
+
bot_token: credentials.botToken,
|
|
65
|
+
application_id: credentials.applicationId,
|
|
66
|
+
bot_user_id: credentials.botUserId,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function deserializeSlack(credentials) {
|
|
70
|
+
return {
|
|
71
|
+
botToken: credentials.bot_token,
|
|
72
|
+
appToken: credentials.app_token,
|
|
73
|
+
teamId: credentials.team_id,
|
|
74
|
+
botUserId: credentials.bot_user_id,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function deserializeDiscord(credentials) {
|
|
78
|
+
return {
|
|
79
|
+
botToken: credentials.bot_token,
|
|
80
|
+
applicationId: credentials.application_id,
|
|
81
|
+
botUserId: credentials.bot_user_id,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=credentials-repository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials-repository.js","sourceRoot":"","sources":["../../../src/infrastructure/chat/credentials-repository.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { SessionBridgeRepository } from "../../domain/chat/ports.js";
|
|
2
|
+
import { SessionBridge, ThreadKey } from "../../domain/chat/session-bridge.js";
|
|
3
|
+
export declare class SessionBridgeFileRepository implements SessionBridgeRepository {
|
|
4
|
+
private readonly directoryPath;
|
|
5
|
+
private loaded;
|
|
6
|
+
private readonly bridges;
|
|
7
|
+
constructor(rootDir: string);
|
|
8
|
+
findByThreadKey(key: ThreadKey): SessionBridge | null;
|
|
9
|
+
save(bridge: SessionBridge): void;
|
|
10
|
+
findAllActive(timeoutMinutes: number): SessionBridge[];
|
|
11
|
+
private ensureLoaded;
|
|
12
|
+
private persistGroup;
|
|
13
|
+
}
|