@sleep2agi/commhub-server 0.5.0-preview.10 → 0.5.0-preview.11

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sleep2agi/commhub-server",
3
- "version": "0.5.0-preview.10",
3
+ "version": "0.5.0-preview.11",
4
4
  "description": "CommHub MCP Server — AI Agent communication hub with SSE push, MCP protocol, and REST API",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
package/src/index.ts CHANGED
@@ -171,6 +171,30 @@ Bun.serve({
171
171
  return withCors(req, Response.json({ ok: true, user: resolved.user, networks, current_network: resolved.networkId }));
172
172
  }
173
173
 
174
+ if (url.pathname === "/api/auth/me" && req.method === "PUT") {
175
+ const token = req.headers.get("Authorization")?.replace("Bearer ", "");
176
+ if (!token) return withCors(req, Response.json({ ok: false, error: "token required" }, { status: 401 }));
177
+ const resolved = resolveToken(token);
178
+ if (!resolved) return withCors(req, Response.json({ ok: false, error: "invalid token" }, { status: 401 }));
179
+ try {
180
+ const body = await req.json() as any;
181
+ const updates: string[] = [];
182
+ const params: any[] = [];
183
+ if (body.display_name) { updates.push(`display_name = ?${params.length + 1}`); params.push(body.display_name); }
184
+ if (body.email) { updates.push(`email = ?${params.length + 1}`); params.push(body.email); }
185
+ if (updates.length > 0) {
186
+ updates.push(`updated_at = datetime('now')`);
187
+ params.push(resolved.user.user_id);
188
+ db.run(`UPDATE users SET ${updates.join(", ")} WHERE user_id = ?${params.length}`, params);
189
+ }
190
+ // Re-fetch
191
+ const user = db.query<any, [string]>("SELECT user_id, username, display_name, email, role FROM users WHERE user_id = ?1").get(resolved.user.user_id);
192
+ return withCors(req, Response.json({ ok: true, user }));
193
+ } catch (e: any) {
194
+ return withCors(req, Response.json({ ok: false, error: e.message }, { status: 400 }));
195
+ }
196
+ }
197
+
174
198
  // ── V3: Network management ──
175
199
  if (url.pathname === "/api/networks" && req.method === "GET") {
176
200
  const token = req.headers.get("Authorization")?.replace("Bearer ", "") || url.searchParams.get("token");
package/src/tools.ts CHANGED
@@ -36,8 +36,9 @@ export function registerTools(server: McpServer, clientIP?: string) {
36
36
  channels: z.string().max(2000).optional().describe("JSON array of channels"),
37
37
  model: z.string().max(200).optional().describe("AI model name"),
38
38
  node_name: z.string().max(200).optional().describe("Stable node display name (may differ from alias)"),
39
+ network_id: z.string().max(200).optional().describe("Network this agent belongs to"),
39
40
  },
40
- async ({ resume_id, alias, status, task, output, score, progress, server: srv, hostname: hn, agent: ag, project_dir: pd, version: ver, tmux_name: tmux, node_id, session_id, config_path, channels, model: mdl, node_name: nn }) => {
41
+ async ({ resume_id, alias, status, task, output, score, progress, server: srv, hostname: hn, agent: ag, project_dir: pd, version: ver, tmux_name: tmux, node_id, session_id, config_path, channels, model: mdl, node_name: nn, network_id: netId }) => {
41
42
  console.log(`[${ts()}] ${alias} (${resume_id.slice(0, 8)}) → report_status: ${status}${task ? " | " + task.slice(0, 60) : ""}`);
42
43
  const trimmedOutput = output?.slice(0, 4000);
43
44
 
@@ -45,8 +46,8 @@ export function registerTools(server: McpServer, clientIP?: string) {
45
46
  db.run("BEGIN IMMEDIATE");
46
47
  db.run("DELETE FROM sessions WHERE alias = ?1 AND resume_id != ?2", [alias, resume_id]);
47
48
  db.run(
48
- `INSERT INTO sessions (resume_id, alias, tmux_name, server, ip, hostname, agent, project_dir, version, status, task, output, progress, score, node_id, session_id, config_path, channels, last_seen_at, updated_at)
49
- VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18, datetime('now'), datetime('now'))
49
+ `INSERT INTO sessions (resume_id, alias, tmux_name, server, ip, hostname, agent, project_dir, version, status, task, output, progress, score, node_id, session_id, config_path, channels, network_id, last_seen_at, updated_at)
50
+ VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18, ?19, datetime('now'), datetime('now'))
50
51
  ON CONFLICT(resume_id) DO UPDATE SET
51
52
  alias = COALESCE(?2, sessions.alias),
52
53
  tmux_name = COALESCE(?3, sessions.tmux_name),
@@ -65,9 +66,10 @@ export function registerTools(server: McpServer, clientIP?: string) {
65
66
  session_id = COALESCE(?16, sessions.session_id),
66
67
  config_path = COALESCE(?17, sessions.config_path),
67
68
  channels = COALESCE(?18, sessions.channels),
69
+ network_id = COALESCE(?19, sessions.network_id),
68
70
  last_seen_at = datetime('now'),
69
71
  updated_at = datetime('now')`,
70
- [resume_id, alias, tmux ?? null, srv ?? null, clientIP ?? null, hn ?? null, ag ?? null, pd ?? null, ver ?? null, status, task ?? null, trimmedOutput ?? null, progress ?? null, score ?? null, node_id ?? null, session_id ?? null, config_path ?? null, channels ?? null]
72
+ [resume_id, alias, tmux ?? null, srv ?? null, clientIP ?? null, hn ?? null, ag ?? null, pd ?? null, ver ?? null, status, task ?? null, trimmedOutput ?? null, progress ?? null, score ?? null, node_id ?? null, session_id ?? null, config_path ?? null, channels ?? null, netId ?? null]
71
73
  );
72
74
  db.run("COMMIT");
73
75
  } catch (e) {
@@ -334,22 +336,23 @@ export function registerTools(server: McpServer, clientIP?: string) {
334
336
  context: z.string().max(10000).optional(),
335
337
  from_session: z.string().max(200).optional().default("hub"),
336
338
  ttl_seconds: z.number().min(1).max(86400).optional().describe("Task TTL in seconds (default: 3600)"),
339
+ network_id: z.string().max(200).optional().describe("Network scope"),
337
340
  },
338
- async ({ alias, task, priority, context, from_session, ttl_seconds }) => {
341
+ async ({ alias, task, priority, context, from_session, ttl_seconds, network_id: netId }) => {
339
342
  console.log(`[${ts()}] ${from_session} → send_task → ${alias}: ${task.slice(0, 60)}${priority === "high" ? " [HIGH]" : ""}`);
340
343
  const id = uuidv4();
341
344
  // 事务:inbox + tasks 双写
342
345
  try {
343
346
  db.run("BEGIN IMMEDIATE");
344
347
  db.run(
345
- `INSERT INTO inbox (id, session_name, type, priority, content, context, from_session, requires_response)
346
- VALUES (?1, ?2, 'task', ?3, ?4, ?5, ?6, 'reply')`,
347
- [id, alias, priority, task, context ?? null, from_session]
348
+ `INSERT INTO inbox (id, session_name, type, priority, content, context, from_session, requires_response, network_id)
349
+ VALUES (?1, ?2, 'task', ?3, ?4, ?5, ?6, 'reply', ?7)`,
350
+ [id, alias, priority, task, context ?? null, from_session, netId ?? null]
348
351
  );
349
352
  db.run(
350
- `INSERT INTO tasks (task_id, from_name, to_name, priority, status, content, requires_response, created_at, delivered_at, expires_at)
351
- VALUES (?1, ?2, ?3, ?4, 'delivered', ?5, 'reply', datetime('now'), datetime('now'), datetime('now', ?6))`,
352
- [id, from_session, alias, priority, task, `+${ttl_seconds || 3600} seconds`]
353
+ `INSERT INTO tasks (task_id, from_name, to_name, priority, status, content, requires_response, created_at, delivered_at, expires_at, network_id)
354
+ VALUES (?1, ?2, ?3, ?4, 'delivered', ?5, 'reply', datetime('now'), datetime('now'), datetime('now', ?6), ?7)`,
355
+ [id, from_session, alias, priority, task, `+${ttl_seconds || 3600} seconds`, netId ?? null]
353
356
  );
354
357
  db.run("COMMIT");
355
358
  logTaskEvent(id, null, "delivered", from_session, `→ ${alias}`);