@agent-chat/mention-watcher 0.0.3 → 0.0.6
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.
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// src/setup.ts
|
|
4
4
|
import { readFileSync, writeFileSync, existsSync } from "fs";
|
|
5
5
|
import { join } from "path";
|
|
6
|
+
import { userInfo } from "os";
|
|
6
7
|
function loadEnvFile(path) {
|
|
7
8
|
if (!existsSync(path)) return {};
|
|
8
9
|
const result = {};
|
|
@@ -56,11 +57,13 @@ async function runSetup() {
|
|
|
56
57
|
const envPath = join(cwd, ".env");
|
|
57
58
|
const fileEnv = loadEnvFile(envPath);
|
|
58
59
|
const env = { ...fileEnv, ...process.env };
|
|
60
|
+
const sysUser = userInfo().username ?? "user";
|
|
61
|
+
const sysName = sysUser.charAt(0).toUpperCase() + sysUser.slice(1);
|
|
59
62
|
const API_URL = env.API_SERVER_URL ?? "http://localhost:3000";
|
|
60
|
-
const EMAIL = env.SETUP_EMAIL ?? env.ADMIN_EMAIL ??
|
|
61
|
-
const PASSWORD = env.SETUP_PASSWORD ?? env.ADMIN_PASSWORD ??
|
|
62
|
-
const NAME = env.SETUP_NAME ?? env.ADMIN_NAME ??
|
|
63
|
-
const AGENT_NAME = env.SETUP_AGENT_NAME ?? env.AGENT_NAME ??
|
|
63
|
+
const EMAIL = env.SETUP_EMAIL ?? env.ADMIN_EMAIL ?? `${sysUser}@localhost`;
|
|
64
|
+
const PASSWORD = env.SETUP_PASSWORD ?? env.ADMIN_PASSWORD ?? `${sysUser}123`;
|
|
65
|
+
const NAME = env.SETUP_NAME ?? env.ADMIN_NAME ?? sysName;
|
|
66
|
+
const AGENT_NAME = env.SETUP_AGENT_NAME ?? env.AGENT_NAME ?? `${sysUser}-agent`;
|
|
64
67
|
const MCP_NAME = env.MCP_SERVER_NAME ?? "agent-chat";
|
|
65
68
|
console.log(`
|
|
66
69
|
agent-chat setup`);
|
|
@@ -68,26 +71,55 @@ agent-chat setup`);
|
|
|
68
71
|
console.log(` Account : ${EMAIL}`);
|
|
69
72
|
console.log(` Agent name : ${AGENT_NAME}`);
|
|
70
73
|
console.log("");
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
74
|
+
async function post(path, body) {
|
|
75
|
+
try {
|
|
76
|
+
return await fetch(`${API_URL}${path}`, {
|
|
77
|
+
method: "POST",
|
|
78
|
+
headers: { "Content-Type": "application/json" },
|
|
79
|
+
body: JSON.stringify(body)
|
|
80
|
+
});
|
|
81
|
+
} catch (err) {
|
|
82
|
+
console.error(` \u2717 Could not reach API server at ${API_URL}`);
|
|
83
|
+
console.error(` Make sure the dev server is running: pnpm dev`);
|
|
84
|
+
console.error(` Error: ${err.message}`);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
let loginRes = await post("/auth/login", { email: EMAIL, password: PASSWORD });
|
|
89
|
+
if (!loginRes.ok) {
|
|
90
|
+
const loginErr = await loginRes.json().catch(() => ({ error: loginRes.statusText }));
|
|
91
|
+
if (loginRes.status !== 401 && loginRes.status !== 404) {
|
|
92
|
+
console.error(` \u2717 Login failed (${loginRes.status}): ${loginErr.error ?? loginRes.statusText}`);
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
console.log(` \u2192 No account found, registering as "${NAME}"\u2026`);
|
|
96
|
+
const regRes = await post("/auth/register", { name: NAME, email: EMAIL, password: PASSWORD });
|
|
97
|
+
if (!regRes.ok) {
|
|
98
|
+
const regErr = await regRes.json().catch(() => ({ error: regRes.statusText }));
|
|
99
|
+
console.error(` \u2717 Registration failed (${regRes.status}): ${regErr.error ?? regRes.statusText}`);
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
console.log(` \u2713 Registered: ${NAME} <${EMAIL}>`);
|
|
103
|
+
loginRes = await post("/auth/login", { email: EMAIL, password: PASSWORD });
|
|
104
|
+
if (!loginRes.ok) {
|
|
105
|
+
console.error(` \u2717 Login after registration failed`);
|
|
106
|
+
process.exit(1);
|
|
107
|
+
}
|
|
83
108
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
109
|
+
const loginData = await loginRes.json();
|
|
110
|
+
console.log(` \u2713 Logged in: ${loginData.entity.name} <${loginData.entity.email}>`);
|
|
111
|
+
const setupRes = await post("/auth/setup", {
|
|
112
|
+
name: NAME,
|
|
113
|
+
email: EMAIL,
|
|
114
|
+
password: PASSWORD,
|
|
115
|
+
agentName: AGENT_NAME
|
|
116
|
+
});
|
|
117
|
+
if (!setupRes.ok) {
|
|
118
|
+
const body = await setupRes.text();
|
|
119
|
+
console.error(` \u2717 Agent provisioning failed (${setupRes.status}): ${body}`);
|
|
87
120
|
process.exit(1);
|
|
88
121
|
}
|
|
89
|
-
const data = await
|
|
90
|
-
console.log(` \u2713 Account : ${data.entity.name} <${data.entity.email}>`);
|
|
122
|
+
const data = await setupRes.json();
|
|
91
123
|
console.log(` \u2713 Agent : ${data.agentEntity.name}`);
|
|
92
124
|
console.log(` \u2713 Token : ${data.agentToken}`);
|
|
93
125
|
console.log("");
|
|
@@ -95,7 +127,11 @@ agent-chat setup`);
|
|
|
95
127
|
AGENT_TOKEN: data.agentToken,
|
|
96
128
|
BOOTSTRAP_AGENT_TOKEN: data.agentToken,
|
|
97
129
|
API_SERVER_URL: API_URL,
|
|
98
|
-
WS_SERVER_URL: env.WS_SERVER_URL ?? "ws://localhost:3001"
|
|
130
|
+
WS_SERVER_URL: env.WS_SERVER_URL ?? "ws://localhost:3001",
|
|
131
|
+
SETUP_EMAIL: EMAIL,
|
|
132
|
+
SETUP_PASSWORD: PASSWORD,
|
|
133
|
+
SETUP_NAME: NAME,
|
|
134
|
+
SETUP_AGENT_NAME: AGENT_NAME
|
|
99
135
|
});
|
|
100
136
|
console.log(` \u2713 Written : ${envPath}`);
|
|
101
137
|
const mcpPaths = [
|
package/dist/cli.js
CHANGED
package/dist/setup.js
CHANGED
package/dist/watch.js
CHANGED
|
@@ -5,13 +5,57 @@ import * as fs from "fs";
|
|
|
5
5
|
import * as path from "path";
|
|
6
6
|
import * as pty from "node-pty";
|
|
7
7
|
import { WebSocket } from "ws";
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
function loadEnvFile(filePath) {
|
|
9
|
+
if (!fs.existsSync(filePath)) return {};
|
|
10
|
+
const result = {};
|
|
11
|
+
for (const line of fs.readFileSync(filePath, "utf8").split("\n")) {
|
|
12
|
+
const trimmed = line.trim();
|
|
13
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
14
|
+
const eq = trimmed.indexOf("=");
|
|
15
|
+
if (eq < 0) continue;
|
|
16
|
+
const key = trimmed.slice(0, eq).trim();
|
|
17
|
+
const val = trimmed.slice(eq + 1).trim().replace(/^["']|["']$/g, "");
|
|
18
|
+
result[key] = val;
|
|
19
|
+
}
|
|
20
|
+
return result;
|
|
21
|
+
}
|
|
22
|
+
function syncMcpToken(workspaceDir, mcpServerName) {
|
|
23
|
+
const envToken = loadEnvFile(path.join(workspaceDir, ".env")).AGENT_TOKEN;
|
|
24
|
+
if (!envToken) return;
|
|
25
|
+
const claudePaths = [
|
|
26
|
+
path.join(workspaceDir, ".mcp.json"),
|
|
27
|
+
path.join(workspaceDir, ".claude", "mcp.json")
|
|
28
|
+
];
|
|
29
|
+
for (const configPath of claudePaths) {
|
|
30
|
+
if (!fs.existsSync(configPath)) continue;
|
|
31
|
+
let config;
|
|
32
|
+
try {
|
|
33
|
+
config = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
34
|
+
} catch {
|
|
35
|
+
process.stderr.write(`[mention-watcher] Could not parse ${configPath}, skipping
|
|
36
|
+
`);
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const server = config?.mcpServers?.[mcpServerName];
|
|
40
|
+
if (!server) continue;
|
|
41
|
+
const current = server.env?.AGENT_TOKEN;
|
|
42
|
+
if (current === envToken) {
|
|
43
|
+
process.stderr.write(`[mention-watcher] MCP token up-to-date: ${configPath}
|
|
44
|
+
`);
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
server.env = server.env ?? {};
|
|
48
|
+
server.env.AGENT_TOKEN = envToken;
|
|
49
|
+
try {
|
|
50
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
51
|
+
process.stderr.write(`[mention-watcher] MCP token synced: ${configPath}
|
|
52
|
+
`);
|
|
53
|
+
} catch (err) {
|
|
54
|
+
process.stderr.write(`[mention-watcher] Failed to write ${configPath}: ${err.message}
|
|
55
|
+
`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
15
59
|
function detectWorkspaceDir() {
|
|
16
60
|
const markers = [
|
|
17
61
|
".mcp.json",
|
|
@@ -35,6 +79,20 @@ function detectWorkspaceDir() {
|
|
|
35
79
|
}
|
|
36
80
|
return process.cwd();
|
|
37
81
|
}
|
|
82
|
+
var _WORKSPACE = process.env.WORKSPACE_DIR ?? detectWorkspaceDir();
|
|
83
|
+
{
|
|
84
|
+
const fileEnv = loadEnvFile(path.join(_WORKSPACE, ".env"));
|
|
85
|
+
for (const [k, v] of Object.entries(fileEnv)) {
|
|
86
|
+
if (!(k in process.env)) process.env[k] = v;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
var AGENT_TOKEN = process.env.AGENT_TOKEN ?? "";
|
|
90
|
+
var WS_URL = process.env.WS_SERVER_URL ?? "ws://localhost:3001";
|
|
91
|
+
var API_URL = process.env.API_SERVER_URL ?? "http://localhost:3000";
|
|
92
|
+
var IDLE_MS = Number(process.env.INJECT_IDLE_MS ?? 800);
|
|
93
|
+
var MCP_NAME = process.env.MCP_SERVER_NAME ?? "agent-chat";
|
|
94
|
+
var WATCH_CHANNELS = (process.env.WATCH_CHANNELS ?? "").split(",").filter(Boolean);
|
|
95
|
+
var WORKSPACE_DIR = _WORKSPACE;
|
|
38
96
|
var extraArgs = process.argv.slice(2);
|
|
39
97
|
var dashDash = extraArgs.indexOf("--");
|
|
40
98
|
var cmdArgs = dashDash >= 0 ? extraArgs.slice(dashDash + 1) : [];
|
|
@@ -136,6 +194,7 @@ async function main() {
|
|
|
136
194
|
process.stderr.write("[mention-watcher] Error: AGENT_TOKEN is required\n");
|
|
137
195
|
process.exit(1);
|
|
138
196
|
}
|
|
197
|
+
syncMcpToken(WORKSPACE_DIR, MCP_NAME);
|
|
139
198
|
const jwt = await resolveJwt();
|
|
140
199
|
const cols = process.stdout.columns || 80;
|
|
141
200
|
const rows = process.stdout.rows || 24;
|