@naisys/hub 3.0.0-beta.15 → 3.0.0-beta.17
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/.env.example +5 -0
- package/dist/handlers/hubConfigService.js +25 -0
- package/dist/handlers/hubHostService.js +14 -6
- package/dist/handlers/hubModelsService.js +9 -0
- package/dist/naisysHub.js +2 -1
- package/dist/services/agentRegistrar.js +17 -4
- package/dist/services/naisysConnection.js +2 -1
- package/dist/services/naisysServer.js +5 -2
- package/dist/version.js +12 -0
- package/package.json +8 -7
package/.env.example
ADDED
|
@@ -29,6 +29,13 @@ export async function createHubConfigService(naisysServer, { hubDb }, logService
|
|
|
29
29
|
}
|
|
30
30
|
logService.log(`[Hub:Config] Seeded ${entries.length} variables from .env file into database`);
|
|
31
31
|
}
|
|
32
|
+
// Ensure well-known variables exist so they show up in supervisor UI
|
|
33
|
+
await ensureVariables(hubDb, [
|
|
34
|
+
{ key: "GOOGLE_SEARCH_ENGINE_ID" },
|
|
35
|
+
{ key: "SPEND_LIMIT_DOLLARS" },
|
|
36
|
+
{ key: "SPEND_LIMIT_HOURS" },
|
|
37
|
+
{ key: "TARGET_VERSION" },
|
|
38
|
+
]);
|
|
32
39
|
/** Read variables from DB and build a ConfigResponse */
|
|
33
40
|
async function buildConfigPayload() {
|
|
34
41
|
const rows = await hubDb.variables.findMany();
|
|
@@ -82,4 +89,22 @@ export async function createHubConfigService(naisysServer, { hubDb }, logService
|
|
|
82
89
|
getConfig: () => cachedConfig,
|
|
83
90
|
};
|
|
84
91
|
}
|
|
92
|
+
/** Create variable placeholders if they don't already exist */
|
|
93
|
+
export async function ensureVariables(hubDb, keys) {
|
|
94
|
+
for (const { key, sensitive } of keys) {
|
|
95
|
+
const existing = await hubDb.variables.findUnique({ where: { key } });
|
|
96
|
+
if (!existing) {
|
|
97
|
+
await hubDb.variables.create({
|
|
98
|
+
data: {
|
|
99
|
+
key,
|
|
100
|
+
value: "",
|
|
101
|
+
sensitive: sensitive ?? false,
|
|
102
|
+
export_to_shell: false,
|
|
103
|
+
created_by: "hub",
|
|
104
|
+
updated_by: "hub",
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
85
110
|
//# sourceMappingURL=hubConfigService.js.map
|
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
import { HubEvents } from "@naisys/hub-protocol";
|
|
2
|
+
import { getHubVersion } from "../version.js";
|
|
2
3
|
/** Pushes the host list to all connections when connected hosts change */
|
|
3
4
|
export function createHubHostService(naisysServer, hostRegistrar, logService) {
|
|
4
5
|
let cachedHostListJson = "";
|
|
5
6
|
function broadcastHostList(newConnection) {
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
// Index connected clients by hostId for O(1) lookup of online + version
|
|
8
|
+
const clientByHostId = new Map(naisysServer
|
|
9
|
+
.getConnectedClients()
|
|
10
|
+
.map((c) => [c.getHostId(), c]));
|
|
11
|
+
const hosts = hostRegistrar.getAllHosts().map((h) => {
|
|
12
|
+
const client = clientByHostId.get(h.hostId);
|
|
13
|
+
return {
|
|
14
|
+
...h,
|
|
15
|
+
online: !!client,
|
|
16
|
+
version: client?.getClientVersion() || "",
|
|
17
|
+
};
|
|
18
|
+
});
|
|
19
|
+
const payload = { hubVersion: getHubVersion(), hosts };
|
|
12
20
|
const json = JSON.stringify(payload);
|
|
13
21
|
// Send to the newly connecting client directly
|
|
14
22
|
if (newConnection) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { builtInImageModels, builtInLlmModels, dbFieldsToImageModel, dbFieldsToLlmModel, imageModelToDbFields, llmModelToDbFields, } from "@naisys/common";
|
|
2
2
|
import { loadCustomModels } from "@naisys/common-node";
|
|
3
3
|
import { HubEvents } from "@naisys/hub-protocol";
|
|
4
|
+
import { ensureVariables } from "./hubConfigService.js";
|
|
4
5
|
/** Hub handler that seeds models on startup, pushes them on connect, and broadcasts on change */
|
|
5
6
|
export async function createHubModelsService(naisysServer, { hubDb }, logService) {
|
|
6
7
|
// Seed models table from built-in + YAML custom models (one-time, skips if non-empty)
|
|
@@ -102,5 +103,13 @@ async function seedModels(hubDb, logService) {
|
|
|
102
103
|
else {
|
|
103
104
|
logService.log(`[Hub:Models] Models already seeded`);
|
|
104
105
|
}
|
|
106
|
+
// Ensure API key variables referenced by built-in models exist in the variables table
|
|
107
|
+
// so they show up in the supervisor UI for the user to configure
|
|
108
|
+
const apiKeyVars = [
|
|
109
|
+
...new Set([...builtInLlmModels, ...builtInImageModels]
|
|
110
|
+
.map((m) => m.apiKeyVar)
|
|
111
|
+
.filter(Boolean)),
|
|
112
|
+
];
|
|
113
|
+
await ensureVariables(hubDb, apiKeyVars.map((key) => ({ key, sensitive: true })));
|
|
105
114
|
}
|
|
106
115
|
//# sourceMappingURL=hubModelsService.js.map
|
package/dist/naisysHub.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { expandNaisysFolder } from "@naisys/common-node";
|
|
1
|
+
import { ensureDotEnv, expandNaisysFolder } from "@naisys/common-node";
|
|
2
2
|
import { createHubDatabaseService } from "@naisys/hub-database";
|
|
3
3
|
import { program } from "commander";
|
|
4
4
|
import dotenv from "dotenv";
|
|
@@ -112,6 +112,7 @@ export const startHub = async (startupType, startSupervisor, plugins, startupAge
|
|
|
112
112
|
// Start server if this file is run directly
|
|
113
113
|
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
|
114
114
|
dotenv.config({ quiet: true });
|
|
115
|
+
await ensureDotEnv(new URL("../.env.example", import.meta.url));
|
|
115
116
|
expandNaisysFolder();
|
|
116
117
|
program
|
|
117
118
|
.argument("[agent-path]", "Path to agent configuration file to seed the database (optional)")
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { toUrlSafeKey } from "@naisys/common";
|
|
1
|
+
import { adminAgentConfig, toUrlSafeKey } from "@naisys/common";
|
|
2
2
|
import { loadAgentConfigs } from "@naisys/common-node";
|
|
3
3
|
import { randomBytes, randomUUID } from "crypto";
|
|
4
4
|
/** Seeds agent configs from YAML files into an empty database. Skips if users already exist. */
|
|
@@ -10,9 +10,22 @@ export async function seedAgentConfigs({ hubDb }, logService, startupAgentPath)
|
|
|
10
10
|
logService.log("[Hub:AgentRegistrar] Agents already seeded");
|
|
11
11
|
return;
|
|
12
12
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
if (startupAgentPath) {
|
|
14
|
+
const users = loadAgentConfigs(startupAgentPath);
|
|
15
|
+
await seedUsersToDatabase(hubDb, logService, users);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
// No seed path: just create the admin agent
|
|
19
|
+
const adminUsers = new Map();
|
|
20
|
+
adminUsers.set(1, {
|
|
21
|
+
userId: 1,
|
|
22
|
+
username: adminAgentConfig.username,
|
|
23
|
+
enabled: true,
|
|
24
|
+
leadUserId: undefined,
|
|
25
|
+
config: adminAgentConfig,
|
|
26
|
+
});
|
|
27
|
+
await seedUsersToDatabase(hubDb, logService, adminUsers);
|
|
28
|
+
}
|
|
16
29
|
}
|
|
17
30
|
async function seedUsersToDatabase(hubDb, logService, users) {
|
|
18
31
|
// First pass: create all users, build loader userId → DB id map
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Each connected NAISYS instance gets its own NaisysConnection instance.
|
|
4
4
|
*/
|
|
5
5
|
export function createNaisysConnection(socket, connectionInfo, raiseEvent, logService) {
|
|
6
|
-
const { hostId, hostName, connectedAt, hostType } = connectionInfo;
|
|
6
|
+
const { hostId, hostName, connectedAt, hostType, clientVersion } = connectionInfo;
|
|
7
7
|
logService.log(`[Hub:Connection] NAISYS instance connected: ${hostName} (${hostId})`);
|
|
8
8
|
// Forward all socket events to hub's emit function
|
|
9
9
|
// Note: Socket.IO passes (eventName, ...args) where last arg may be an ack callback
|
|
@@ -40,6 +40,7 @@ export function createNaisysConnection(socket, connectionInfo, raiseEvent, logSe
|
|
|
40
40
|
getConnectedAt: () => connectedAt,
|
|
41
41
|
getSocketId: () => socket.id,
|
|
42
42
|
getHostType: () => hostType,
|
|
43
|
+
getClientVersion: () => clientVersion,
|
|
43
44
|
};
|
|
44
45
|
}
|
|
45
46
|
//# sourceMappingURL=naisysConnection.js.map
|
|
@@ -59,7 +59,7 @@ export function createNaisysServer(nsp, initialHubAccessKey, logService, hostReg
|
|
|
59
59
|
}
|
|
60
60
|
// Authentication middleware
|
|
61
61
|
nsp.use(async (socket, next) => {
|
|
62
|
-
const { hubAccessKey: clientAccessKey, hostName, hostType: rawHostType, } = socket.handshake.auth;
|
|
62
|
+
const { hubAccessKey: clientAccessKey, hostName, hostType: rawHostType, clientVersion, } = socket.handshake.auth;
|
|
63
63
|
if (!clientAccessKey || clientAccessKey !== hubAccessKey) {
|
|
64
64
|
logService.log(`[Hub] Connection rejected: invalid access key from ${socket.handshake.address}`);
|
|
65
65
|
return next(new Error("Invalid access key"));
|
|
@@ -79,6 +79,8 @@ export function createNaisysServer(nsp, initialHubAccessKey, logService, hostReg
|
|
|
79
79
|
socket.data.hostId = hostId;
|
|
80
80
|
socket.data.hostName = hostName;
|
|
81
81
|
socket.data.hostType = hostType;
|
|
82
|
+
socket.data.clientVersion =
|
|
83
|
+
typeof clientVersion === "string" ? clientVersion : "";
|
|
82
84
|
next();
|
|
83
85
|
}
|
|
84
86
|
catch (err) {
|
|
@@ -88,13 +90,14 @@ export function createNaisysServer(nsp, initialHubAccessKey, logService, hostReg
|
|
|
88
90
|
});
|
|
89
91
|
// Handle new connections
|
|
90
92
|
nsp.on("connection", (socket) => {
|
|
91
|
-
const { hostId, hostName, hostType } = socket.data;
|
|
93
|
+
const { hostId, hostName, hostType, clientVersion } = socket.data;
|
|
92
94
|
// Create connection handler for this socket, passing our emit function
|
|
93
95
|
const connection = createNaisysConnection(socket, {
|
|
94
96
|
hostId,
|
|
95
97
|
hostName,
|
|
96
98
|
connectedAt: new Date(),
|
|
97
99
|
hostType,
|
|
100
|
+
clientVersion,
|
|
98
101
|
}, raiseEvent, logService);
|
|
99
102
|
if (hostType === "supervisor") {
|
|
100
103
|
supervisorConnections.push(connection);
|
package/dist/version.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { getGitCommitHash } from "@naisys/common-node";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
// Read the hub's own package.json (one level up from dist/)
|
|
7
|
+
const pkg = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf-8"));
|
|
8
|
+
const commitHash = getGitCommitHash(__dirname);
|
|
9
|
+
export function getHubVersion() {
|
|
10
|
+
return commitHash ? `${pkg.version}/${commitHash}` : pkg.version;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=version.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@naisys/hub",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.17",
|
|
4
4
|
"description": "NAISYS Hub - Adds persistence and multi-instance coordination to NAISYS",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/naisysHub.js",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"./services/runnerServer": "./dist/services/runnerServer.js"
|
|
14
14
|
},
|
|
15
15
|
"scripts": {
|
|
16
|
-
"clean": "rimraf dist",
|
|
16
|
+
"clean": "npx rimraf dist",
|
|
17
17
|
"dev": "tsx watch src/naisysHub.ts",
|
|
18
18
|
"start": "node dist/naisysHub.js",
|
|
19
19
|
"build": "tsc",
|
|
@@ -24,12 +24,13 @@
|
|
|
24
24
|
"files": [
|
|
25
25
|
"dist",
|
|
26
26
|
"bin",
|
|
27
|
+
".env.example",
|
|
27
28
|
"!dist/**/*.map",
|
|
28
29
|
"!dist/**/*.d.ts",
|
|
29
30
|
"!dist/**/*.d.ts.map"
|
|
30
31
|
],
|
|
31
32
|
"peerDependencies": {
|
|
32
|
-
"@naisys/supervisor": "3.0.0-beta.
|
|
33
|
+
"@naisys/supervisor": "3.0.0-beta.17"
|
|
33
34
|
},
|
|
34
35
|
"peerDependenciesMeta": {
|
|
35
36
|
"@naisys/supervisor": {
|
|
@@ -37,10 +38,10 @@
|
|
|
37
38
|
}
|
|
38
39
|
},
|
|
39
40
|
"dependencies": {
|
|
40
|
-
"@naisys/common": "3.0.0-beta.
|
|
41
|
-
"@naisys/common-node": "3.0.0-beta.
|
|
42
|
-
"@naisys/hub-database": "3.0.0-beta.
|
|
43
|
-
"@naisys/hub-protocol": "3.0.0-beta.
|
|
41
|
+
"@naisys/common": "3.0.0-beta.17",
|
|
42
|
+
"@naisys/common-node": "3.0.0-beta.17",
|
|
43
|
+
"@naisys/hub-database": "3.0.0-beta.17",
|
|
44
|
+
"@naisys/hub-protocol": "3.0.0-beta.17",
|
|
44
45
|
"commander": "^14.0.3",
|
|
45
46
|
"dotenv": "^17.3.1",
|
|
46
47
|
"pino": "^10.3.1",
|