@sleep2agi/commhub-server 0.5.0-preview.1 → 0.5.0-preview.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.
- package/package.json +1 -1
- package/src/db.ts +20 -0
- package/src/index.ts +13 -0
- package/src/tools.ts +25 -1
package/package.json
CHANGED
package/src/db.ts
CHANGED
|
@@ -115,6 +115,26 @@ db.exec(`
|
|
|
115
115
|
CREATE INDEX IF NOT EXISTS idx_tasks_created ON tasks(created_at);
|
|
116
116
|
`);
|
|
117
117
|
|
|
118
|
+
// nodes table (V2 Sprint 2) — persistent node identity, separate from runtime sessions
|
|
119
|
+
db.exec(`
|
|
120
|
+
CREATE TABLE IF NOT EXISTS nodes (
|
|
121
|
+
node_id TEXT PRIMARY KEY,
|
|
122
|
+
node_name TEXT NOT NULL,
|
|
123
|
+
alias TEXT,
|
|
124
|
+
runtime TEXT,
|
|
125
|
+
model TEXT,
|
|
126
|
+
config_path TEXT,
|
|
127
|
+
channels TEXT,
|
|
128
|
+
server TEXT,
|
|
129
|
+
hostname TEXT,
|
|
130
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
131
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
CREATE INDEX IF NOT EXISTS idx_nodes_name ON nodes(node_name);
|
|
135
|
+
CREATE INDEX IF NOT EXISTS idx_nodes_alias ON nodes(alias);
|
|
136
|
+
`);
|
|
137
|
+
|
|
118
138
|
// Helpers
|
|
119
139
|
export function uuidv4(): string {
|
|
120
140
|
return crypto.randomUUID();
|
package/src/index.ts
CHANGED
|
@@ -281,6 +281,19 @@ Bun.serve({
|
|
|
281
281
|
return withCors(req, Response.json({ ok: true, messages: rows }));
|
|
282
282
|
}
|
|
283
283
|
|
|
284
|
+
// ── REST: nodes table (V2 Sprint 2) ──
|
|
285
|
+
if (url.pathname === "/api/nodes") {
|
|
286
|
+
const nodeId = url.searchParams.get("node_id");
|
|
287
|
+
const alias = url.searchParams.get("alias");
|
|
288
|
+
let sql = "SELECT * FROM nodes WHERE 1=1";
|
|
289
|
+
const params: any[] = [];
|
|
290
|
+
if (nodeId) { sql += ` AND node_id = ?${params.length + 1}`; params.push(nodeId); }
|
|
291
|
+
if (alias) { sql += ` AND alias = ?${params.length + 1}`; params.push(alias); }
|
|
292
|
+
sql += " ORDER BY updated_at DESC";
|
|
293
|
+
const rows = db.query(sql).all(...params);
|
|
294
|
+
return withCors(req, Response.json({ ok: true, nodes: rows, count: rows.length }));
|
|
295
|
+
}
|
|
296
|
+
|
|
284
297
|
// ── REST: tasks table (V2) ──
|
|
285
298
|
if (url.pathname === "/api/tasks") {
|
|
286
299
|
const taskId = url.searchParams.get("task_id");
|
package/src/tools.ts
CHANGED
|
@@ -34,8 +34,9 @@ export function registerTools(server: McpServer, clientIP?: string) {
|
|
|
34
34
|
session_id: z.string().max(200).optional().describe("Runtime session/thread ID"),
|
|
35
35
|
config_path: z.string().max(1000).optional().describe("Config file path"),
|
|
36
36
|
channels: z.string().max(2000).optional().describe("JSON array of channels"),
|
|
37
|
+
model: z.string().max(200).optional().describe("AI model name"),
|
|
37
38
|
},
|
|
38
|
-
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 }) => {
|
|
39
|
+
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 }) => {
|
|
39
40
|
console.log(`[${ts()}] ${alias} (${resume_id.slice(0, 8)}) → report_status: ${status}${task ? " | " + task.slice(0, 60) : ""}`);
|
|
40
41
|
const trimmedOutput = output?.slice(0, 4000);
|
|
41
42
|
|
|
@@ -84,6 +85,29 @@ export function registerTools(server: McpServer, clientIP?: string) {
|
|
|
84
85
|
} catch {}
|
|
85
86
|
}
|
|
86
87
|
|
|
88
|
+
// V2: upsert nodes table for persistent node identity
|
|
89
|
+
if (node_id) {
|
|
90
|
+
try {
|
|
91
|
+
// Extract runtime from agent field (e.g., "agent-node:codex" → "codex-sdk")
|
|
92
|
+
const nodeRuntime = ag?.includes(":") ? ag.split(":")[1] + "-sdk" : ag ?? null;
|
|
93
|
+
db.run(
|
|
94
|
+
`INSERT INTO nodes (node_id, node_name, alias, runtime, model, config_path, channels, server, hostname, updated_at)
|
|
95
|
+
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, datetime('now'))
|
|
96
|
+
ON CONFLICT(node_id) DO UPDATE SET
|
|
97
|
+
node_name = COALESCE(?2, nodes.node_name),
|
|
98
|
+
alias = COALESCE(?3, nodes.alias),
|
|
99
|
+
runtime = COALESCE(?4, nodes.runtime),
|
|
100
|
+
model = COALESCE(?5, nodes.model),
|
|
101
|
+
config_path = COALESCE(?6, nodes.config_path),
|
|
102
|
+
channels = COALESCE(?7, nodes.channels),
|
|
103
|
+
server = COALESCE(?8, nodes.server),
|
|
104
|
+
hostname = COALESCE(?9, nodes.hostname),
|
|
105
|
+
updated_at = datetime('now')`,
|
|
106
|
+
[node_id, alias, alias, nodeRuntime, mdl ?? null, config_path ?? null, channels ?? null, srv ?? null, hn ?? null]
|
|
107
|
+
);
|
|
108
|
+
} catch {}
|
|
109
|
+
}
|
|
110
|
+
|
|
87
111
|
// inbox uses alias for routing
|
|
88
112
|
const row = db.query<{ cnt: number }, [string]>(
|
|
89
113
|
"SELECT COUNT(*) as cnt FROM inbox WHERE session_name = ?1 AND acked = 0"
|